f338ef
From d5ce2300f77c25b38a076d4dd6a5521e82c56172 Mon Sep 17 00:00:00 2001
f338ef
From: Kotresh HR <khiremat@redhat.com>
f338ef
Date: Mon, 29 Jul 2019 18:30:42 +0530
f338ef
Subject: [PATCH 295/297] ctime/rebalance: Heal ctime xattr on directory during
f338ef
 rebalance
f338ef
f338ef
After add-brick and rebalance, the ctime xattr is not present
f338ef
on rebalanced directories on new brick. This patch fixes the
f338ef
same.
f338ef
f338ef
Note that ctime still doesn't support consistent time across
f338ef
distribute sub-volume.
f338ef
f338ef
This patch also fixes the in-memory inconsistency of time attributes
f338ef
when metadata is self healed.
f338ef
f338ef
Backport of:
f338ef
 > Patch: https://review.gluster.org/23127/
f338ef
 > Change-Id: Ia20506f1839021bf61d4753191e7dc34b31bb2df
f338ef
 > fixes: bz#1734026
f338ef
 > Signed-off-by: Kotresh HR <khiremat@redhat.com>
f338ef
f338ef
Change-Id: Ia20506f1839021bf61d4753191e7dc34b31bb2df
f338ef
BUG: 1728673
f338ef
Signed-off-by: Kotresh HR <khiremat@redhat.com>
f338ef
Reviewed-on: https://code.engineering.redhat.com/gerrit/181105
f338ef
Tested-by: RHGS Build Bot <nigelb@redhat.com>
f338ef
Reviewed-by: Atin Mukherjee <amukherj@redhat.com>
f338ef
---
f338ef
 tests/basic/afr/split-brain-healing-ctime.t        | 253 +++++++++++++++++++++
f338ef
 tests/basic/afr/split-brain-healing.t              |   1 +
f338ef
 tests/basic/ctime/ctime-ec-heal.t                  |  71 ++++++
f338ef
 tests/basic/ctime/ctime-ec-rebalance.t             |  44 ++++
f338ef
 tests/basic/ctime/ctime-rep-heal.t                 |  71 ++++++
f338ef
 tests/basic/ctime/ctime-rep-rebalance.t            |  42 ++++
f338ef
 .../bug-1734370-entry-heal-restore-time.t          |  84 +++++++
f338ef
 tests/volume.rc                                    |  15 +-
f338ef
 xlators/cluster/afr/src/afr-self-heal-common.c     |   3 +-
f338ef
 xlators/cluster/afr/src/afr-self-heal-entry.c      |   2 +
f338ef
 xlators/cluster/dht/src/dht-common.c               |   1 +
f338ef
 xlators/cluster/ec/src/ec-heal.c                   |   7 +-
f338ef
 xlators/storage/posix/src/posix-entry-ops.c        |   8 +-
f338ef
 xlators/storage/posix/src/posix-helpers.c          |  31 ++-
f338ef
 xlators/storage/posix/src/posix-inode-fd-ops.c     |  57 ++---
f338ef
 xlators/storage/posix/src/posix-metadata.c         |  65 +++++-
f338ef
 xlators/storage/posix/src/posix-metadata.h         |   7 +
f338ef
 xlators/storage/posix/src/posix.h                  |   5 +-
f338ef
 18 files changed, 714 insertions(+), 53 deletions(-)
f338ef
 create mode 100644 tests/basic/afr/split-brain-healing-ctime.t
f338ef
 create mode 100644 tests/basic/ctime/ctime-ec-heal.t
f338ef
 create mode 100644 tests/basic/ctime/ctime-ec-rebalance.t
f338ef
 create mode 100644 tests/basic/ctime/ctime-rep-heal.t
f338ef
 create mode 100644 tests/basic/ctime/ctime-rep-rebalance.t
f338ef
 create mode 100644 tests/bugs/replicate/bug-1734370-entry-heal-restore-time.t
f338ef
f338ef
diff --git a/tests/basic/afr/split-brain-healing-ctime.t b/tests/basic/afr/split-brain-healing-ctime.t
f338ef
new file mode 100644
f338ef
index 0000000..1ca18e3
f338ef
--- /dev/null
f338ef
+++ b/tests/basic/afr/split-brain-healing-ctime.t
f338ef
@@ -0,0 +1,253 @@
f338ef
+#!/bin/bash
f338ef
+
f338ef
+#Test the split-brain resolution CLI commands.
f338ef
+. $(dirname $0)/../../include.rc
f338ef
+. $(dirname $0)/../../volume.rc
f338ef
+
f338ef
+function get_replicate_subvol_number {
f338ef
+        local filename=$1
f338ef
+        #get_backend_paths
f338ef
+        if [ -f $B0/${V0}1/$filename ]
f338ef
+        then
f338ef
+                echo 0
f338ef
+        elif [ -f $B0/${V0}3/$filename ]
f338ef
+        then    echo 1
f338ef
+        else
f338ef
+                echo -1
f338ef
+        fi
f338ef
+}
f338ef
+
f338ef
+cleanup;
f338ef
+
f338ef
+AREQUAL_PATH=$(dirname $0)/../../utils
f338ef
+GET_MDATA_PATH=$(dirname $0)/../../utils
f338ef
+CFLAGS=""
f338ef
+test "`uname -s`" != "Linux" && {
f338ef
+    CFLAGS="$CFLAGS -lintl";
f338ef
+}
f338ef
+build_tester $AREQUAL_PATH/arequal-checksum.c $CFLAGS
f338ef
+build_tester $GET_MDATA_PATH/get-mdata-xattr.c
f338ef
+
f338ef
+TEST glusterd
f338ef
+TEST pidof glusterd
f338ef
+TEST $CLI volume create $V0 replica 2 $H0:$B0/${V0}{1,2,3,4}
f338ef
+TEST $CLI volume set $V0 cluster.self-heal-daemon off
f338ef
+TEST $CLI volume set $V0 cluster.data-self-heal off
f338ef
+TEST $CLI volume set $V0 cluster.metadata-self-heal off
f338ef
+TEST $CLI volume set $V0 cluster.entry-self-heal off
f338ef
+TEST $CLI volume set $V0 ctime on
f338ef
+TEST $CLI volume start $V0
f338ef
+TEST $GFS --volfile-id=/$V0 --volfile-server=$H0 $M0
f338ef
+
f338ef
+cd $M0
f338ef
+for i in {1..10}
f338ef
+do
f338ef
+        echo "Initial content">>file$i
f338ef
+done
f338ef
+
f338ef
+replica_0_files_list=(`ls $B0/${V0}1|grep -v '^\.'`)
f338ef
+replica_1_files_list=(`ls $B0/${V0}3|grep -v '^\.'`)
f338ef
+
f338ef
+############ Create data split-brain in the files. ###########################
f338ef
+TEST kill_brick $V0 $H0 $B0/${V0}1
f338ef
+for file in ${!replica_0_files_list[*]}
f338ef
+do
f338ef
+        echo "B1 is down">>${replica_0_files_list[$file]}
f338ef
+done
f338ef
+TEST kill_brick $V0 $H0 $B0/${V0}3
f338ef
+for file in ${!replica_1_files_list[*]}
f338ef
+do
f338ef
+        echo "B3 is down">>${replica_1_files_list[$file]}
f338ef
+done
f338ef
+
f338ef
+SMALLER_FILE_SIZE=$(stat -c %s file1)
f338ef
+
f338ef
+TEST $CLI volume start $V0 force
f338ef
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 0
f338ef
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 2
f338ef
+
f338ef
+TEST kill_brick $V0 $H0 $B0/${V0}2
f338ef
+for file in ${!replica_0_files_list[*]}
f338ef
+do
f338ef
+        echo "B2 is down">>${replica_0_files_list[$file]}
f338ef
+        echo "appending more content to make it the bigger file">>${replica_0_files_list[$file]}
f338ef
+done
f338ef
+TEST kill_brick $V0 $H0 $B0/${V0}4
f338ef
+for file in ${!replica_1_files_list[*]}
f338ef
+do
f338ef
+        echo "B4 is down">>${replica_1_files_list[$file]}
f338ef
+        echo "appending more content to make it the bigger file">>${replica_1_files_list[$file]}
f338ef
+done
f338ef
+
f338ef
+BIGGER_FILE_SIZE=$(stat -c %s file1)
f338ef
+TEST $CLI volume start $V0 force
f338ef
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 1
f338ef
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 3
f338ef
+
f338ef
+
f338ef
+############### Acessing the files should now give EIO. ###############################
f338ef
+TEST ! cat file1
f338ef
+TEST ! cat file2
f338ef
+TEST ! cat file3
f338ef
+TEST ! cat file4
f338ef
+TEST ! cat file5
f338ef
+TEST ! cat file6
f338ef
+TEST ! cat file7
f338ef
+TEST ! cat file8
f338ef
+TEST ! cat file9
f338ef
+TEST ! cat file10
f338ef
+###################
f338ef
+TEST $CLI volume set $V0 cluster.self-heal-daemon on
f338ef
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT "Y" glustershd_up_status
f338ef
+EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 0
f338ef
+EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 1
f338ef
+EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 2
f338ef
+EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 3
f338ef
+
f338ef
+################ Heal file1 using the bigger-file option  ##############
f338ef
+$CLI volume heal $V0 split-brain bigger-file /file1
f338ef
+EXPECT "0" echo $?
f338ef
+EXPECT $BIGGER_FILE_SIZE stat -c %s file1
f338ef
+
f338ef
+################ Heal file2 using the bigger-file option and its gfid ##############
f338ef
+subvolume=$(get_replicate_subvol_number file2)
f338ef
+if [ $subvolume == 0 ]
f338ef
+then
f338ef
+        GFID=$(gf_get_gfid_xattr $B0/${V0}1/file2)
f338ef
+elif [ $subvolume == 1 ]
f338ef
+then
f338ef
+        GFID=$(gf_get_gfid_xattr $B0/${V0}3/file2)
f338ef
+fi
f338ef
+GFIDSTR="gfid:$(gf_gfid_xattr_to_str $GFID)"
f338ef
+$CLI volume heal $V0 split-brain bigger-file $GFIDSTR
f338ef
+EXPECT "0" echo $?
f338ef
+
f338ef
+################ Heal file3 using the source-brick option  ##############
f338ef
+################ Use the brick having smaller file size as source #######
f338ef
+subvolume=$(get_replicate_subvol_number file3)
f338ef
+if [ $subvolume == 0 ]
f338ef
+then
f338ef
+        $CLI volume heal $V0 split-brain source-brick $H0:$B0/${V0}2 /file3
f338ef
+elif [ $subvolume == 1 ]
f338ef
+then
f338ef
+        $CLI volume heal $V0 split-brain source-brick $H0:$B0/${V0}4 /file3
f338ef
+fi
f338ef
+EXPECT "0" echo $?
f338ef
+EXPECT $SMALLER_FILE_SIZE stat -c %s file3
f338ef
+
f338ef
+################ Heal file4 using the source-brick option and it's gfid ##############
f338ef
+################ Use the brick having smaller file size as source #######
f338ef
+subvolume=$(get_replicate_subvol_number file4)
f338ef
+if [ $subvolume == 0 ]
f338ef
+then
f338ef
+        GFID=$(gf_get_gfid_xattr $B0/${V0}1/file4)
f338ef
+        GFIDSTR="gfid:$(gf_gfid_xattr_to_str $GFID)"
f338ef
+        $CLI volume heal $V0 split-brain source-brick $H0:$B0/${V0}2 $GFIDSTR
f338ef
+elif [ $subvolume == 1 ]
f338ef
+then
f338ef
+        GFID=$(gf_get_gfid_xattr $B0/${V0}3/file4)
f338ef
+        GFIDSTR="gfid:$(gf_gfid_xattr_to_str $GFID)"
f338ef
+        $CLI volume heal $V0 split-brain source-brick $H0:$B0/${V0}4 $GFIDSTR
f338ef
+fi
f338ef
+EXPECT "0" echo $?
f338ef
+EXPECT $SMALLER_FILE_SIZE stat -c %s file4
f338ef
+
f338ef
+# With ctime enabled, the ctime xattr ("trusted.glusterfs.mdata") gets healed
f338ef
+# as part of metadata heal. So mtime would be same, hence it can't be healed
f338ef
+# using 'latest-mtime' policy, use 'source-brick' option instead.
f338ef
+################ Heal file5 using the source-brick option  ##############
f338ef
+subvolume=$(get_replicate_subvol_number file5)
f338ef
+if [ $subvolume == 0 ]
f338ef
+then
f338ef
+        $CLI volume heal $V0 split-brain source-brick $H0:$B0/${V0}1 /file5
f338ef
+elif [ $subvolume == 1 ]
f338ef
+then
f338ef
+        $CLI volume heal $V0 split-brain source-brick $H0:$B0/${V0}3 /file5
f338ef
+fi
f338ef
+EXPECT "0" echo $?
f338ef
+
f338ef
+if [ $subvolume == 0 ]
f338ef
+then
f338ef
+        mtime1_after_heal=$(get_mtime $B0/${V0}1/file5)
f338ef
+        mtime2_after_heal=$(get_mtime $B0/${V0}2/file5)
f338ef
+elif [ $subvolume == 1 ]
f338ef
+then
f338ef
+        mtime1_after_heal=$(get_mtime $B0/${V0}3/file5)
f338ef
+        mtime2_after_heal=$(get_mtime $B0/${V0}4/file5)
f338ef
+fi
f338ef
+
f338ef
+#TODO: To below comparisons on full sub-second resolution
f338ef
+
f338ef
+TEST [ $mtime1_after_heal -eq $mtime2_after_heal ]
f338ef
+
f338ef
+mtime_mount_after_heal=$(stat -c %Y file5)
f338ef
+
f338ef
+TEST [ $mtime1_after_heal -eq $mtime_mount_after_heal ]
f338ef
+
f338ef
+################ Heal file6 using the source-brick option and its gfid  ##############
f338ef
+subvolume=$(get_replicate_subvol_number file6)
f338ef
+if [ $subvolume == 0 ]
f338ef
+then
f338ef
+        GFID=$(gf_get_gfid_xattr $B0/${V0}1/file6)
f338ef
+        GFIDSTR="gfid:$(gf_gfid_xattr_to_str $GFID)"
f338ef
+        $CLI volume heal $V0 split-brain source-brick $H0:$B0/${V0}1 $GFIDSTR
f338ef
+elif [ $subvolume == 1 ]
f338ef
+then
f338ef
+        GFID=$(gf_get_gfid_xattr $B0/${V0}3/file6)
f338ef
+        GFIDSTR="gfid:$(gf_gfid_xattr_to_str $GFID)"
f338ef
+        $CLI volume heal $V0 split-brain source-brick $H0:$B0/${V0}3 $GFIDSTR
f338ef
+fi
f338ef
+EXPECT "0" echo $?
f338ef
+
f338ef
+if [ $subvolume == 0 ]
f338ef
+then
f338ef
+        mtime1_after_heal=$(get_mtime $B0/${V0}1/file6)
f338ef
+        mtime2_after_heal=$(get_mtime $B0/${V0}2/file6)
f338ef
+elif [ $subvolume == 1 ]
f338ef
+then
f338ef
+        mtime1_after_heal=$(get_mtime $B0/${V0}3/file6)
f338ef
+        mtime2_after_heal=$(get_mtime $B0/${V0}4/file6)
f338ef
+fi
f338ef
+
f338ef
+#TODO: To below comparisons on full sub-second resolution
f338ef
+
f338ef
+TEST [ $mtime1_after_heal -eq $mtime2_after_heal ]
f338ef
+
f338ef
+mtime_mount_after_heal=$(stat -c %Y file6)
f338ef
+
f338ef
+TEST [ $mtime1_after_heal -eq $mtime_mount_after_heal ]
f338ef
+
f338ef
+################ Heal remaining SB'ed files of replica_0 using B1 as source ##############
f338ef
+$CLI volume heal $V0 split-brain source-brick $H0:$B0/${V0}1
f338ef
+EXPECT "0" echo $?
f338ef
+
f338ef
+################ Heal remaining SB'ed files of replica_1 using B3 as source ##############
f338ef
+$CLI volume heal $V0 split-brain source-brick $H0:$B0/${V0}3
f338ef
+EXPECT "0" echo $?
f338ef
+
f338ef
+############### Reading the files should now succeed. ###############################
f338ef
+TEST  cat file1
f338ef
+TEST  cat file2
f338ef
+TEST  cat file3
f338ef
+TEST  cat file4
f338ef
+TEST  cat file5
f338ef
+TEST  cat file6
f338ef
+TEST  cat file7
f338ef
+TEST  cat file8
f338ef
+TEST  cat file9
f338ef
+TEST  cat file10
f338ef
+
f338ef
+################ File contents on the bricks must be same. ################################
f338ef
+TEST diff <(arequal-checksum -p $B0/$V01 -i .glusterfs) <(arequal-checksum -p $B0/$V02 -i .glusterfs)
f338ef
+TEST diff <(arequal-checksum -p $B0/$V03 -i .glusterfs) <(arequal-checksum -p $B0/$V04 -i .glusterfs)
f338ef
+
f338ef
+############### Trying to heal files not in SB should fail. ###############################
f338ef
+$CLI volume heal $V0 split-brain bigger-file /file1
f338ef
+EXPECT "1" echo $?
f338ef
+$CLI volume heal $V0 split-brain source-brick $H0:$B0/${V0}4 /file3
f338ef
+EXPECT "1" echo $?
f338ef
+
f338ef
+cd -
f338ef
+TEST rm $AREQUAL_PATH/arequal-checksum
f338ef
+TEST rm $GET_MDATA_PATH/get-mdata-xattr
f338ef
+cleanup
f338ef
diff --git a/tests/basic/afr/split-brain-healing.t b/tests/basic/afr/split-brain-healing.t
f338ef
index 78553e6..315e815 100644
f338ef
--- a/tests/basic/afr/split-brain-healing.t
f338ef
+++ b/tests/basic/afr/split-brain-healing.t
f338ef
@@ -35,6 +35,7 @@ TEST $CLI volume set $V0 cluster.self-heal-daemon off
f338ef
 TEST $CLI volume set $V0 cluster.data-self-heal off
f338ef
 TEST $CLI volume set $V0 cluster.metadata-self-heal off
f338ef
 TEST $CLI volume set $V0 cluster.entry-self-heal off
f338ef
+TEST $CLI volume set $V0 ctime off
f338ef
 TEST $CLI volume start $V0
f338ef
 TEST $GFS --volfile-id=/$V0 --volfile-server=$H0 $M0
f338ef
 
f338ef
diff --git a/tests/basic/ctime/ctime-ec-heal.t b/tests/basic/ctime/ctime-ec-heal.t
f338ef
new file mode 100644
f338ef
index 0000000..1cb4516
f338ef
--- /dev/null
f338ef
+++ b/tests/basic/ctime/ctime-ec-heal.t
f338ef
@@ -0,0 +1,71 @@
f338ef
+#!/bin/bash
f338ef
+#
f338ef
+# This will test self healing of ctime xattr 'trusted.glusterfs.mdata'
f338ef
+#
f338ef
+###
f338ef
+
f338ef
+. $(dirname $0)/../../include.rc
f338ef
+. $(dirname $0)/../../volume.rc
f338ef
+. $(dirname $0)/../../afr.rc
f338ef
+
f338ef
+cleanup
f338ef
+
f338ef
+#cleate and start volume
f338ef
+TEST glusterd
f338ef
+TEST pidof glusterd
f338ef
+TEST $CLI volume create $V0 disperse 3 redundancy 1 $H0:$B0/${V0}{1..3}
f338ef
+TEST $CLI volume set $V0 ctime on
f338ef
+TEST $CLI volume start $V0
f338ef
+
f338ef
+#Mount the volume
f338ef
+TEST $GFS --volfile-id=/$V0 --volfile-server=$H0 $M0;
f338ef
+
f338ef
+# Create files
f338ef
+mkdir $M0/dir1
f338ef
+echo "Initial content" > $M0/file1
f338ef
+
f338ef
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT '3' get_mdata_count $B0/${V0}{1..3}/dir1
f338ef
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT '1' get_mdata_uniq_count $B0/${V0}{1..3}/dir1
f338ef
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT '3' get_mdata_count $B0/${V0}{1..3}/file1
f338ef
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT '1' get_mdata_uniq_count $B0/${V0}{1..3}/file1
f338ef
+
f338ef
+# Kill brick
f338ef
+TEST kill_brick $V0 $H0 $B0/${V0}3
f338ef
+
f338ef
+echo "B3 is down" >> $M0/file1
f338ef
+echo "Change dir1 time attributes" > $M0/dir1/dir1_file1
f338ef
+echo "Entry heal file" > $M0/entry_heal_file1
f338ef
+mkdir $M0/entry_heal_dir1
f338ef
+
f338ef
+# Check xattr
f338ef
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT '3' get_mdata_count $B0/${V0}{1..3}/dir1
f338ef
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT '2' get_mdata_uniq_count $B0/${V0}{1..3}/dir1
f338ef
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT '3' get_mdata_count $B0/${V0}{1..3}/file1
f338ef
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT '2' get_mdata_uniq_count $B0/${V0}{1..3}/file1
f338ef
+
f338ef
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT '2' get_mdata_count $B0/${V0}{1..3}/dir1/dir1_file1
f338ef
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT '1' get_mdata_uniq_count $B0/${V0}{1..3}/dir1/dir1_file1
f338ef
+
f338ef
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT '2' get_mdata_count $B0/${V0}{1..3}/entry_heal_file1
f338ef
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT '1' get_mdata_uniq_count $B0/${V0}{1..3}/entry_heal_file1
f338ef
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT '2' get_mdata_count $B0/${V0}{1..3}/entry_heal_dir1
f338ef
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT '1' get_mdata_uniq_count $B0/${V0}{1..3}/entry_heal_dir1
f338ef
+
f338ef
+TEST $CLI volume start $V0 force
f338ef
+$CLI volume heal $V0
f338ef
+
f338ef
+# Check xattr
f338ef
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT '3' get_mdata_count $B0/${V0}{1..3}/dir1
f338ef
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT '1' get_mdata_uniq_count $B0/${V0}{1..3}/dir1
f338ef
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT '3' get_mdata_count $B0/${V0}{1..3}/file1
f338ef
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT '1' get_mdata_uniq_count $B0/${V0}{1..3}/file1
f338ef
+
f338ef
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT '3' get_mdata_count $B0/${V0}{1..3}/dir1/dir1_file1
f338ef
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT '1' get_mdata_uniq_count $B0/${V0}{1..3}/dir1/dir1_file1
f338ef
+
f338ef
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT '3' get_mdata_count $B0/${V0}{1..3}/entry_heal_file1
f338ef
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT '1' get_mdata_uniq_count $B0/${V0}{1..3}/entry_heal_file1
f338ef
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT '3' get_mdata_count $B0/${V0}{1..3}/entry_heal_dir1
f338ef
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT '1' get_mdata_uniq_count $B0/${V0}{1..3}/entry_heal_dir1
f338ef
+
f338ef
+cleanup;
f338ef
diff --git a/tests/basic/ctime/ctime-ec-rebalance.t b/tests/basic/ctime/ctime-ec-rebalance.t
f338ef
new file mode 100644
f338ef
index 0000000..caccdc1
f338ef
--- /dev/null
f338ef
+++ b/tests/basic/ctime/ctime-ec-rebalance.t
f338ef
@@ -0,0 +1,44 @@
f338ef
+#!/bin/bash
f338ef
+#
f338ef
+# This will test healing of ctime xattr 'trusted.glusterfs.mdata' after add-brick and rebalance
f338ef
+#
f338ef
+###
f338ef
+
f338ef
+. $(dirname $0)/../../include.rc
f338ef
+. $(dirname $0)/../../volume.rc
f338ef
+. $(dirname $0)/../../fallocate.rc
f338ef
+
f338ef
+cleanup
f338ef
+
f338ef
+#cleate and start volume
f338ef
+TEST glusterd
f338ef
+TEST pidof glusterd
f338ef
+TEST $CLI volume create $V0 disperse 3 redundancy 1 $H0:$B0/${V0}{0..5}
f338ef
+TEST $CLI volume set $V0 ctime on
f338ef
+TEST $CLI volume start $V0
f338ef
+
f338ef
+#Mount the volume
f338ef
+TEST $GFS --volfile-id=/$V0 --volfile-server=$H0 $M0;
f338ef
+EXPECT_WITHIN $CHILD_UP_TIMEOUT "3" ec_child_up_count $V0 0
f338ef
+
f338ef
+# Create files
f338ef
+mkdir $M0/dir1
f338ef
+echo "test data" > $M0/dir1/file1
f338ef
+
f338ef
+# Add brick
f338ef
+TEST $CLI volume add-brick $V0 $H0:$B0/${V0}{6..8}
f338ef
+
f338ef
+#Trigger rebalance
f338ef
+TEST $CLI volume rebalance $V0 start force
f338ef
+EXPECT_WITHIN $REBALANCE_TIMEOUT "completed" rebalance_status_field $V0
f338ef
+
f338ef
+#Verify ctime xattr heal on directory
f338ef
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT 'trusted.glusterfs.mdata' check_for_xattr 'trusted.glusterfs.mdata' "$B0/${V0}6/dir1"
f338ef
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT 'trusted.glusterfs.mdata' check_for_xattr 'trusted.glusterfs.mdata' "$B0/${V0}7/dir1"
f338ef
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT 'trusted.glusterfs.mdata' check_for_xattr 'trusted.glusterfs.mdata' "$B0/${V0}8/dir1"
f338ef
+
f338ef
+b6_mdata=$(get_mdata "$B0/${V0}6/dir1")
f338ef
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT "${b6_mdata}" get_mdata $B0/${V0}7/dir1
f338ef
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT "${b6_mdata}" get_mdata $B0/${V0}8/dir1
f338ef
+
f338ef
+cleanup;
f338ef
diff --git a/tests/basic/ctime/ctime-rep-heal.t b/tests/basic/ctime/ctime-rep-heal.t
f338ef
new file mode 100644
f338ef
index 0000000..ba8b08a
f338ef
--- /dev/null
f338ef
+++ b/tests/basic/ctime/ctime-rep-heal.t
f338ef
@@ -0,0 +1,71 @@
f338ef
+#!/bin/bash
f338ef
+#
f338ef
+# This will test self healing of ctime xattr 'trusted.glusterfs.mdata'
f338ef
+#
f338ef
+###
f338ef
+
f338ef
+. $(dirname $0)/../../include.rc
f338ef
+. $(dirname $0)/../../volume.rc
f338ef
+. $(dirname $0)/../../afr.rc
f338ef
+
f338ef
+cleanup
f338ef
+
f338ef
+#cleate and start volume
f338ef
+TEST glusterd
f338ef
+TEST pidof glusterd
f338ef
+TEST $CLI volume create $V0 replica 3 $H0:$B0/${V0}{1..3}
f338ef
+TEST $CLI volume set $V0 ctime on
f338ef
+TEST $CLI volume start $V0
f338ef
+
f338ef
+#Mount the volume
f338ef
+TEST $GFS --volfile-id=/$V0 --volfile-server=$H0 $M0;
f338ef
+
f338ef
+# Create files
f338ef
+mkdir $M0/dir1
f338ef
+echo "Initial content" > $M0/file1
f338ef
+
f338ef
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT '3' get_mdata_count $B0/${V0}{1..3}/dir1
f338ef
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT '1' get_mdata_uniq_count $B0/${V0}{1..3}/dir1
f338ef
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT '3' get_mdata_count $B0/${V0}{1..3}/file1
f338ef
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT '1' get_mdata_uniq_count $B0/${V0}{1..3}/file1
f338ef
+
f338ef
+# Kill brick
f338ef
+TEST kill_brick $V0 $H0 $B0/${V0}3
f338ef
+
f338ef
+echo "B3 is down" >> $M0/file1
f338ef
+echo "Change dir1 time attributes" > $M0/dir1/dir1_file1
f338ef
+echo "Entry heal file" > $M0/entry_heal_file1
f338ef
+mkdir $M0/entry_heal_dir1
f338ef
+
f338ef
+# Check xattr
f338ef
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT '3' get_mdata_count $B0/${V0}{1..3}/dir1
f338ef
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT '2' get_mdata_uniq_count $B0/${V0}{1..3}/dir1
f338ef
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT '3' get_mdata_count $B0/${V0}{1..3}/file1
f338ef
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT '2' get_mdata_uniq_count $B0/${V0}{1..3}/file1
f338ef
+
f338ef
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT '2' get_mdata_count $B0/${V0}{1..3}/dir1/dir1_file1
f338ef
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT '1' get_mdata_uniq_count $B0/${V0}{1..3}/dir1/dir1_file1
f338ef
+
f338ef
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT '2' get_mdata_count $B0/${V0}{1..3}/entry_heal_file1
f338ef
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT '1' get_mdata_uniq_count $B0/${V0}{1..3}/entry_heal_file1
f338ef
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT '2' get_mdata_count $B0/${V0}{1..3}/entry_heal_dir1
f338ef
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT '1' get_mdata_uniq_count $B0/${V0}{1..3}/entry_heal_dir1
f338ef
+
f338ef
+TEST $CLI volume start $V0 force
f338ef
+$CLI volume heal $V0
f338ef
+
f338ef
+# Check xattr
f338ef
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT '3' get_mdata_count $B0/${V0}{1..3}/dir1
f338ef
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT '1' get_mdata_uniq_count $B0/${V0}{1..3}/dir1
f338ef
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT '3' get_mdata_count $B0/${V0}{1..3}/file1
f338ef
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT '1' get_mdata_uniq_count $B0/${V0}{1..3}/file1
f338ef
+
f338ef
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT '3' get_mdata_count $B0/${V0}{1..3}/dir1/dir1_file1
f338ef
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT '1' get_mdata_uniq_count $B0/${V0}{1..3}/dir1/dir1_file1
f338ef
+
f338ef
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT '3' get_mdata_count $B0/${V0}{1..3}/entry_heal_file1
f338ef
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT '1' get_mdata_uniq_count $B0/${V0}{1..3}/entry_heal_file1
f338ef
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT '3' get_mdata_count $B0/${V0}{1..3}/entry_heal_dir1
f338ef
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT '1' get_mdata_uniq_count $B0/${V0}{1..3}/entry_heal_dir1
f338ef
+
f338ef
+cleanup;
f338ef
diff --git a/tests/basic/ctime/ctime-rep-rebalance.t b/tests/basic/ctime/ctime-rep-rebalance.t
f338ef
new file mode 100644
f338ef
index 0000000..dd9743e
f338ef
--- /dev/null
f338ef
+++ b/tests/basic/ctime/ctime-rep-rebalance.t
f338ef
@@ -0,0 +1,42 @@
f338ef
+#!/bin/bash
f338ef
+#
f338ef
+# This will test healing of ctime xattr 'trusted.glusterfs.mdata' after add-brick and rebalance
f338ef
+#
f338ef
+###
f338ef
+
f338ef
+. $(dirname $0)/../../include.rc
f338ef
+. $(dirname $0)/../../volume.rc
f338ef
+. $(dirname $0)/../../afr.rc
f338ef
+
f338ef
+cleanup
f338ef
+
f338ef
+#cleate and start volume
f338ef
+TEST glusterd
f338ef
+TEST pidof glusterd
f338ef
+TEST $CLI volume create $V0 replica 3 $H0:$B0/${V0}{0..5}
f338ef
+TEST $CLI volume set $V0 ctime on
f338ef
+TEST $CLI volume start $V0
f338ef
+
f338ef
+#Mount the volume
f338ef
+TEST $GFS --volfile-id=/$V0 --volfile-server=$H0 $M0;
f338ef
+
f338ef
+# Create files
f338ef
+mkdir $M0/dir1
f338ef
+
f338ef
+# Add brick
f338ef
+TEST $CLI volume add-brick $V0 $H0:$B0/${V0}{6..8}
f338ef
+
f338ef
+#Trigger rebalance
f338ef
+TEST $CLI volume rebalance $V0 start force
f338ef
+EXPECT_WITHIN $REBALANCE_TIMEOUT "completed" rebalance_status_field $V0
f338ef
+
f338ef
+#Verify ctime xattr heal on directory
f338ef
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT 'trusted.glusterfs.mdata' check_for_xattr 'trusted.glusterfs.mdata' "$B0/${V0}6/dir1"
f338ef
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT 'trusted.glusterfs.mdata' check_for_xattr 'trusted.glusterfs.mdata' "$B0/${V0}7/dir1"
f338ef
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT 'trusted.glusterfs.mdata' check_for_xattr 'trusted.glusterfs.mdata' "$B0/${V0}8/dir1"
f338ef
+
f338ef
+b6_mdata=$(get_mdata "$B0/${V0}6/dir1")
f338ef
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT "${b6_mdata}" get_mdata $B0/${V0}7/dir1
f338ef
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT "${b6_mdata}" get_mdata $B0/${V0}8/dir1
f338ef
+
f338ef
+cleanup;
f338ef
diff --git a/tests/bugs/replicate/bug-1734370-entry-heal-restore-time.t b/tests/bugs/replicate/bug-1734370-entry-heal-restore-time.t
f338ef
new file mode 100644
f338ef
index 0000000..298d6ed
f338ef
--- /dev/null
f338ef
+++ b/tests/bugs/replicate/bug-1734370-entry-heal-restore-time.t
f338ef
@@ -0,0 +1,84 @@
f338ef
+#!/bin/bash
f338ef
+
f338ef
+. $(dirname $0)/../../include.rc
f338ef
+. $(dirname $0)/../../volume.rc
f338ef
+. $(dirname $0)/../../afr.rc
f338ef
+
f338ef
+cleanup;
f338ef
+
f338ef
+function time_stamps_match {
f338ef
+        path=$1
f338ef
+        mtime_source_b0=$(get_mtime $B0/${V0}0/$path)
f338ef
+        atime_source_b0=$(get_atime $B0/${V0}0/$path)
f338ef
+        mtime_source_b2=$(get_mtime $B0/${V0}2/$path)
f338ef
+        atime_source_b2=$(get_atime $B0/${V0}2/$path)
f338ef
+        mtime_sink_b1=$(get_mtime $B0/${V0}1/$path)
f338ef
+        atime_sink_b1=$(get_atime $B0/${V0}1/$path)
f338ef
+
f338ef
+        #The same brick must be the source of heal for both atime and mtime.
f338ef
+        if [[ ( $mtime_source_b0 -eq $mtime_sink_b1 && $atime_source_b0 -eq $atime_sink_b1 ) || \
f338ef
+              ( $mtime_source_b2 -eq $mtime_sink_b1 && $atime_source_b2 -eq $atime_sink_b1 ) ]]
f338ef
+        then
f338ef
+            echo "Y"
f338ef
+        else
f338ef
+            echo "N"
f338ef
+        fi
f338ef
+
f338ef
+}
f338ef
+
f338ef
+# Test that the parent dir's timestamps are restored during entry-heal.
f338ef
+GET_MDATA_PATH=$(dirname $0)/../../utils
f338ef
+build_tester $GET_MDATA_PATH/get-mdata-xattr.c
f338ef
+
f338ef
+TEST glusterd;
f338ef
+TEST pidof glusterd;
f338ef
+TEST $CLI volume create $V0 replica 3 $H0:$B0/${V0}{0,1,2};
f338ef
+TEST $CLI volume set $V0 ctime on
f338ef
+TEST $CLI volume start $V0;
f338ef
+
f338ef
+TEST $GFS --volfile-id=/$V0 --volfile-server=$H0 --attribute-timeout=0 --entry-timeout=0 $M0
f338ef
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 0
f338ef
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 1
f338ef
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 2
f338ef
+
f338ef
+###############################################################################
f338ef
+TEST mkdir $M0/DIR
f338ef
+TEST kill_brick $V0 $H0 $B0/${V0}1
f338ef
+TEST touch $M0/DIR/FILE
f338ef
+
f338ef
+TEST $CLI volume start $V0 force
f338ef
+EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status $V0 1
f338ef
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT "Y" glustershd_up_status
f338ef
+EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 0
f338ef
+EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 1
f338ef
+EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 2
f338ef
+TEST $CLI volume heal $V0
f338ef
+EXPECT_WITHIN $HEAL_TIMEOUT "0" get_pending_heal_count $V0
f338ef
+
f338ef
+EXPECT "Y" time_stamps_match DIR
f338ef
+ctime_source1=$(get_ctime $B0/${V0}0/$path)
f338ef
+ctime_source2=$(get_ctime $B0/${V0}2/$path)
f338ef
+ctime_sink=$(get_ctime $B0/${V0}1/$path)
f338ef
+TEST [ $ctime_source1 -eq $ctime_sink ]
f338ef
+TEST [ $ctime_source2 -eq $ctime_sink ]
f338ef
+
f338ef
+###############################################################################
f338ef
+# Repeat the test with ctime feature disabled.
f338ef
+TEST $CLI volume set $V0 features.ctime off
f338ef
+TEST mkdir $M0/DIR2
f338ef
+TEST kill_brick $V0 $H0 $B0/${V0}1
f338ef
+TEST touch $M0/DIR2/FILE
f338ef
+
f338ef
+TEST $CLI volume start $V0 force
f338ef
+EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status $V0 0
f338ef
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT "Y" glustershd_up_status
f338ef
+EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 0
f338ef
+EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 1
f338ef
+EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 2
f338ef
+TEST $CLI volume heal $V0
f338ef
+EXPECT_WITHIN $HEAL_TIMEOUT "0" get_pending_heal_count $V0
f338ef
+
f338ef
+EXPECT "Y" time_stamps_match DIR2
f338ef
+
f338ef
+TEST rm $GET_MDATA_PATH/get-mdata-xattr
f338ef
+cleanup;
f338ef
diff --git a/tests/volume.rc b/tests/volume.rc
f338ef
index 76a8fd4..9a002d9 100644
f338ef
--- a/tests/volume.rc
f338ef
+++ b/tests/volume.rc
f338ef
@@ -371,6 +371,19 @@ function get_gfid2path {
f338ef
         getfattr -h --only-values -n glusterfs.gfidtopath $path 2>/dev/null
f338ef
 }
f338ef
 
f338ef
+function get_mdata {
f338ef
+        local path=$1
f338ef
+        getfattr -h -e hex -n trusted.glusterfs.mdata $path 2>/dev/null | grep "trusted.glusterfs.mdata" | cut -f2 -d'='
f338ef
+}
f338ef
+
f338ef
+function get_mdata_count {
f338ef
+    getfattr -d -m . -e hex $@ 2>/dev/null | grep mdata | wc -l
f338ef
+}
f338ef
+
f338ef
+function get_mdata_uniq_count {
f338ef
+    getfattr -d -m . -e hex $@ 2>/dev/null | grep mdata | uniq | wc -l
f338ef
+}
f338ef
+
f338ef
 function get_xattr_key {
f338ef
         local key=$1
f338ef
         local path=$2
f338ef
@@ -925,7 +938,7 @@ function get_ctime {
f338ef
     local time=$(get-mdata-xattr -c $1)
f338ef
     if [ $time == "-1" ];
f338ef
     then
f338ef
-        echo $(stat -c %Z $2)
f338ef
+        echo $(stat -c %Z $1)
f338ef
     else
f338ef
         echo $time
f338ef
     fi
f338ef
diff --git a/xlators/cluster/afr/src/afr-self-heal-common.c b/xlators/cluster/afr/src/afr-self-heal-common.c
f338ef
index b38085a..81ef38a 100644
f338ef
--- a/xlators/cluster/afr/src/afr-self-heal-common.c
f338ef
+++ b/xlators/cluster/afr/src/afr-self-heal-common.c
f338ef
@@ -513,7 +513,8 @@ afr_selfheal_restore_time(call_frame_t *frame, xlator_t *this, inode_t *inode,
f338ef
 
f338ef
     AFR_ONLIST(healed_sinks, frame, afr_sh_generic_fop_cbk, setattr, &loc,
f338ef
                &replies[source].poststat,
f338ef
-               (GF_SET_ATTR_ATIME | GF_SET_ATTR_MTIME), NULL);
f338ef
+               (GF_SET_ATTR_ATIME | GF_SET_ATTR_MTIME | GF_SET_ATTR_CTIME),
f338ef
+               NULL);
f338ef
 
f338ef
     loc_wipe(&loc;;
f338ef
 
f338ef
diff --git a/xlators/cluster/afr/src/afr-self-heal-entry.c b/xlators/cluster/afr/src/afr-self-heal-entry.c
f338ef
index e07b521..35b600f 100644
f338ef
--- a/xlators/cluster/afr/src/afr-self-heal-entry.c
f338ef
+++ b/xlators/cluster/afr/src/afr-self-heal-entry.c
f338ef
@@ -1032,6 +1032,8 @@ unlock:
f338ef
             goto postop_unlock;
f338ef
         }
f338ef
 
f338ef
+        afr_selfheal_restore_time(frame, this, fd->inode, source, healed_sinks,
f338ef
+                                  locked_replies);
f338ef
         ret = afr_selfheal_undo_pending(
f338ef
             frame, this, fd->inode, sources, sinks, healed_sinks, undid_pending,
f338ef
             AFR_ENTRY_TRANSACTION, locked_replies, postop_lock);
f338ef
diff --git a/xlators/cluster/dht/src/dht-common.c b/xlators/cluster/dht/src/dht-common.c
f338ef
index 219b072..99cccd6 100644
f338ef
--- a/xlators/cluster/dht/src/dht-common.c
f338ef
+++ b/xlators/cluster/dht/src/dht-common.c
f338ef
@@ -115,6 +115,7 @@ char *xattrs_to_heal[] = {"user.",
f338ef
                           QUOTA_LIMIT_KEY,
f338ef
                           QUOTA_LIMIT_OBJECTS_KEY,
f338ef
                           GF_SELINUX_XATTR_KEY,
f338ef
+                          GF_XATTR_MDATA_KEY,
f338ef
                           NULL};
f338ef
 
f338ef
 char *dht_dbg_vxattrs[] = {DHT_DBG_HASHED_SUBVOL_PATTERN, NULL};
f338ef
diff --git a/xlators/cluster/ec/src/ec-heal.c b/xlators/cluster/ec/src/ec-heal.c
f338ef
index 0f0f398..06a7016 100644
f338ef
--- a/xlators/cluster/ec/src/ec-heal.c
f338ef
+++ b/xlators/cluster/ec/src/ec-heal.c
f338ef
@@ -2301,9 +2301,10 @@ ec_restore_time_and_adjust_versions(call_frame_t *frame, ec_t *ec, fd_t *fd,
f338ef
 
f338ef
         loc.inode = inode_ref(fd->inode);
f338ef
         gf_uuid_copy(loc.gfid, fd->inode->gfid);
f338ef
-        ret = cluster_setattr(ec->xl_list, healed_sinks, ec->nodes, replies,
f338ef
-                              output, frame, ec->xl, &loc, &source_buf,
f338ef
-                              GF_SET_ATTR_ATIME | GF_SET_ATTR_MTIME, NULL);
f338ef
+        ret = cluster_setattr(
f338ef
+            ec->xl_list, healed_sinks, ec->nodes, replies, output, frame,
f338ef
+            ec->xl, &loc, &source_buf,
f338ef
+            GF_SET_ATTR_ATIME | GF_SET_ATTR_MTIME | GF_SET_ATTR_CTIME, NULL);
f338ef
         EC_INTERSECT(healed_sinks, healed_sinks, output, ec->nodes);
f338ef
         if (EC_COUNT(healed_sinks, ec->nodes) == 0) {
f338ef
             ret = -ENOTCONN;
f338ef
diff --git a/xlators/storage/posix/src/posix-entry-ops.c b/xlators/storage/posix/src/posix-entry-ops.c
f338ef
index 34ee2b8..283b305 100644
f338ef
--- a/xlators/storage/posix/src/posix-entry-ops.c
f338ef
+++ b/xlators/storage/posix/src/posix-entry-ops.c
f338ef
@@ -500,7 +500,7 @@ post_op:
f338ef
         posix_set_gfid2path_xattr(this, real_path, loc->pargfid, loc->name);
f338ef
     }
f338ef
 
f338ef
-    op_ret = posix_entry_create_xattr_set(this, real_path, xdata);
f338ef
+    op_ret = posix_entry_create_xattr_set(this, loc, real_path, xdata);
f338ef
     if (op_ret) {
f338ef
         if (errno != EEXIST)
f338ef
             gf_msg(this->name, GF_LOG_ERROR, errno, P_MSG_XATTR_FAILED,
f338ef
@@ -828,7 +828,7 @@ posix_mkdir(call_frame_t *frame, xlator_t *this, loc_t *loc, mode_t mode,
f338ef
                "setting ACLs on %s failed ", real_path);
f338ef
     }
f338ef
 
f338ef
-    op_ret = posix_entry_create_xattr_set(this, real_path, xdata);
f338ef
+    op_ret = posix_entry_create_xattr_set(this, loc, real_path, xdata);
f338ef
     if (op_ret) {
f338ef
         gf_msg(this->name, GF_LOG_ERROR, errno, P_MSG_XATTR_FAILED,
f338ef
                "setting xattrs on %s failed", real_path);
f338ef
@@ -1529,7 +1529,7 @@ posix_symlink(call_frame_t *frame, xlator_t *this, const char *linkname,
f338ef
     }
f338ef
 
f338ef
 ignore:
f338ef
-    op_ret = posix_entry_create_xattr_set(this, real_path, xdata);
f338ef
+    op_ret = posix_entry_create_xattr_set(this, loc, real_path, xdata);
f338ef
     if (op_ret) {
f338ef
         gf_msg(this->name, GF_LOG_ERROR, errno, P_MSG_XATTR_FAILED,
f338ef
                "setting xattrs on %s failed ", real_path);
f338ef
@@ -2167,7 +2167,7 @@ posix_create(call_frame_t *frame, xlator_t *this, loc_t *loc, int32_t flags,
f338ef
         posix_set_gfid2path_xattr(this, real_path, loc->pargfid, loc->name);
f338ef
     }
f338ef
 ignore:
f338ef
-    op_ret = posix_entry_create_xattr_set(this, real_path, xdata);
f338ef
+    op_ret = posix_entry_create_xattr_set(this, loc, real_path, xdata);
f338ef
     if (op_ret) {
f338ef
         gf_msg(this->name, GF_LOG_ERROR, errno, P_MSG_XATTR_FAILED,
f338ef
                "setting xattrs on %s failed ", real_path);
f338ef
diff --git a/xlators/storage/posix/src/posix-helpers.c b/xlators/storage/posix/src/posix-helpers.c
f338ef
index d143d4c..6a1a35c 100644
f338ef
--- a/xlators/storage/posix/src/posix-helpers.c
f338ef
+++ b/xlators/storage/posix/src/posix-helpers.c
f338ef
@@ -1188,11 +1188,15 @@ posix_dump_buffer(xlator_t *this, const char *real_path, const char *key,
f338ef
 #endif
f338ef
 
f338ef
 int
f338ef
-posix_handle_pair(xlator_t *this, const char *real_path, char *key,
f338ef
+posix_handle_pair(xlator_t *this, loc_t *loc, const char *real_path, char *key,
f338ef
                   data_t *value, int flags, struct iatt *stbuf)
f338ef
 {
f338ef
     int sys_ret = -1;
f338ef
     int ret = 0;
f338ef
+    int op_errno = 0;
f338ef
+    struct mdata_iatt mdata_iatt = {
f338ef
+        0,
f338ef
+    };
f338ef
 #ifdef GF_DARWIN_HOST_OS
f338ef
     const int error_code = EINVAL;
f338ef
 #else
f338ef
@@ -1216,6 +1220,23 @@ posix_handle_pair(xlator_t *this, const char *real_path, char *key,
f338ef
         /* ignore this key value pair */
f338ef
         ret = 0;
f338ef
         goto out;
f338ef
+    } else if (!strncmp(key, GF_XATTR_MDATA_KEY, strlen(key))) {
f338ef
+        /* This is either by rebalance or self heal. Create the xattr if it's
f338ef
+         * not present. Compare and update the larger value if the xattr is
f338ef
+         * already present.
f338ef
+         */
f338ef
+        if (loc == NULL) {
f338ef
+            ret = -EINVAL;
f338ef
+            goto out;
f338ef
+        }
f338ef
+        posix_mdata_iatt_from_disk(&mdata_iatt,
f338ef
+                                   (posix_mdata_disk_t *)value->data);
f338ef
+        ret = posix_set_mdata_xattr_legacy_files(this, loc->inode, real_path,
f338ef
+                                                 &mdata_iatt, &op_errno);
f338ef
+        if (ret != 0) {
f338ef
+            ret = -op_errno;
f338ef
+        }
f338ef
+        goto out;
f338ef
     } else {
f338ef
         sys_ret = sys_lsetxattr(real_path, key, value->data, value->len, flags);
f338ef
 #ifdef GF_DARWIN_HOST_OS
f338ef
@@ -1810,8 +1831,8 @@ _handle_entry_create_keyvalue_pair(dict_t *d, char *k, data_t *v, void *tmp)
f338ef
         return 0;
f338ef
     }
f338ef
 
f338ef
-    ret = posix_handle_pair(filler->this, filler->real_path, k, v, XATTR_CREATE,
f338ef
-                            filler->stbuf);
f338ef
+    ret = posix_handle_pair(filler->this, filler->loc, filler->real_path, k, v,
f338ef
+                            XATTR_CREATE, filler->stbuf);
f338ef
     if (ret < 0) {
f338ef
         errno = -ret;
f338ef
         return -1;
f338ef
@@ -1820,7 +1841,8 @@ _handle_entry_create_keyvalue_pair(dict_t *d, char *k, data_t *v, void *tmp)
f338ef
 }
f338ef
 
f338ef
 int
f338ef
-posix_entry_create_xattr_set(xlator_t *this, const char *path, dict_t *dict)
f338ef
+posix_entry_create_xattr_set(xlator_t *this, loc_t *loc, const char *path,
f338ef
+                             dict_t *dict)
f338ef
 {
f338ef
     int ret = -1;
f338ef
 
f338ef
@@ -1834,6 +1856,7 @@ posix_entry_create_xattr_set(xlator_t *this, const char *path, dict_t *dict)
f338ef
     filler.this = this;
f338ef
     filler.real_path = path;
f338ef
     filler.stbuf = NULL;
f338ef
+    filler.loc = loc;
f338ef
 
f338ef
     ret = dict_foreach(dict, _handle_entry_create_keyvalue_pair, &filler);
f338ef
 
f338ef
diff --git a/xlators/storage/posix/src/posix-inode-fd-ops.c b/xlators/storage/posix/src/posix-inode-fd-ops.c
f338ef
index e0ea85b..a2a518f 100644
f338ef
--- a/xlators/storage/posix/src/posix-inode-fd-ops.c
f338ef
+++ b/xlators/storage/posix/src/posix-inode-fd-ops.c
f338ef
@@ -429,22 +429,9 @@ posix_setattr(call_frame_t *frame, xlator_t *this, loc_t *loc,
f338ef
                                     &frame->root->ctime, stbuf, valid);
f338ef
     }
f338ef
 
f338ef
-    if (valid & GF_SET_ATTR_CTIME && !priv->ctime) {
f338ef
-        /*
f338ef
-         * If ctime is not enabled, we have no means to associate an
f338ef
-         * arbitrary ctime with the file, so as a fallback, we ignore
f338ef
-         * the ctime payload and update the file ctime to current time
f338ef
-         * (which is possible directly with the POSIX API).
f338ef
-         */
f338ef
-        op_ret = PATH_SET_TIMESPEC_OR_TIMEVAL(real_path, NULL);
f338ef
-        if (op_ret == -1) {
f338ef
-            op_errno = errno;
f338ef
-            gf_msg(this->name, GF_LOG_ERROR, errno, P_MSG_UTIMES_FAILED,
f338ef
-                   "setattr (utimes) on %s "
f338ef
-                   "failed",
f338ef
-                   real_path);
f338ef
-            goto out;
f338ef
-        }
f338ef
+    if ((valid & GF_SET_ATTR_CTIME) && priv->ctime) {
f338ef
+        posix_update_ctime_in_mdata(this, real_path, -1, loc->inode,
f338ef
+                                    &frame->root->ctime, stbuf, valid);
f338ef
     }
f338ef
 
f338ef
     if (!valid) {
f338ef
@@ -469,14 +456,6 @@ posix_setattr(call_frame_t *frame, xlator_t *this, loc_t *loc,
f338ef
         goto out;
f338ef
     }
f338ef
 
f338ef
-    if (valid & GF_SET_ATTR_CTIME && priv->ctime) {
f338ef
-        /*
f338ef
-         * If we got ctime payload, we override
f338ef
-         * the ctime of statpost with that.
f338ef
-         */
f338ef
-        statpost.ia_ctime = stbuf->ia_ctime;
f338ef
-        statpost.ia_ctime_nsec = stbuf->ia_ctime_nsec;
f338ef
-    }
f338ef
     posix_set_ctime(frame, this, real_path, -1, loc->inode, &statpost);
f338ef
 
f338ef
     if (xdata)
f338ef
@@ -592,6 +571,7 @@ posix_fsetattr(call_frame_t *frame, xlator_t *this, fd_t *fd,
f338ef
     struct iatt statpost = {
f338ef
         0,
f338ef
     };
f338ef
+    struct posix_private *priv = NULL;
f338ef
     struct posix_fd *pfd = NULL;
f338ef
     dict_t *xattr_rsp = NULL;
f338ef
     int32_t ret = -1;
f338ef
@@ -604,6 +584,9 @@ posix_fsetattr(call_frame_t *frame, xlator_t *this, fd_t *fd,
f338ef
     VALIDATE_OR_GOTO(this, out);
f338ef
     VALIDATE_OR_GOTO(fd, out);
f338ef
 
f338ef
+    priv = this->private;
f338ef
+    VALIDATE_OR_GOTO(priv, out);
f338ef
+
f338ef
     ret = posix_fd_ctx_get(fd, this, &pfd, &op_errno);
f338ef
     if (ret < 0) {
f338ef
         gf_msg_debug(this->name, 0, "pfd is NULL from fd=%p", fd);
f338ef
@@ -656,6 +639,11 @@ posix_fsetattr(call_frame_t *frame, xlator_t *this, fd_t *fd,
f338ef
                                     &frame->root->ctime, stbuf, valid);
f338ef
     }
f338ef
 
f338ef
+    if ((valid & GF_SET_ATTR_CTIME) && priv->ctime) {
f338ef
+        posix_update_ctime_in_mdata(this, NULL, pfd->fd, fd->inode,
f338ef
+                                    &frame->root->ctime, stbuf, valid);
f338ef
+    }
f338ef
+
f338ef
     if (!valid) {
f338ef
         op_ret = sys_fchown(pfd->fd, -1, -1);
f338ef
         if (op_ret == -1) {
f338ef
@@ -2578,7 +2566,7 @@ _handle_setxattr_keyvalue_pair(dict_t *d, char *k, data_t *v, void *tmp)
f338ef
 
f338ef
     filler = tmp;
f338ef
 
f338ef
-    return posix_handle_pair(filler->this, filler->real_path, k, v,
f338ef
+    return posix_handle_pair(filler->this, filler->loc, filler->real_path, k, v,
f338ef
                              filler->flags, filler->stbuf);
f338ef
 }
f338ef
 
f338ef
@@ -2641,27 +2629,27 @@ posix_setxattr(call_frame_t *frame, xlator_t *this, loc_t *loc, dict_t *dict,
f338ef
     priv = this->private;
f338ef
     DISK_SPACE_CHECK_AND_GOTO(frame, priv, xdata, op_ret, op_errno, out);
f338ef
 
f338ef
+    MAKE_INODE_HANDLE(real_path, this, loc, NULL);
f338ef
+    if (!real_path) {
f338ef
+        op_ret = -1;
f338ef
+        op_errno = ESTALE;
f338ef
+        goto out;
f338ef
+    }
f338ef
+
f338ef
     ret = dict_get_mdata(dict, CTIME_MDATA_XDATA_KEY, &mdata_iatt);
f338ef
     if (ret == 0) {
f338ef
         /* This is initiated by lookup when ctime feature is enabled to create
f338ef
          * "trusted.glusterfs.mdata" xattr if not present. These are the files
f338ef
          * which were created when ctime feature is disabled.
f338ef
          */
f338ef
-        ret = posix_set_mdata_xattr_legacy_files(this, loc->inode, &mdata_iatt,
f338ef
-                                                 &op_errno);
f338ef
+        ret = posix_set_mdata_xattr_legacy_files(this, loc->inode, real_path,
f338ef
+                                                 &mdata_iatt, &op_errno);
f338ef
         if (ret != 0) {
f338ef
             op_ret = -1;
f338ef
         }
f338ef
         goto out;
f338ef
     }
f338ef
 
f338ef
-    MAKE_INODE_HANDLE(real_path, this, loc, NULL);
f338ef
-    if (!real_path) {
f338ef
-        op_ret = -1;
f338ef
-        op_errno = ESTALE;
f338ef
-        goto out;
f338ef
-    }
f338ef
-
f338ef
     posix_pstat(this, loc->inode, loc->gfid, real_path, &preop, _gf_false);
f338ef
 
f338ef
     op_ret = -1;
f338ef
@@ -2796,6 +2784,7 @@ posix_setxattr(call_frame_t *frame, xlator_t *this, loc_t *loc, dict_t *dict,
f338ef
     filler.real_path = real_path;
f338ef
     filler.this = this;
f338ef
     filler.stbuf = &preo;;
f338ef
+    filler.loc = loc;
f338ef
 
f338ef
 #ifdef GF_DARWIN_HOST_OS
f338ef
     filler.flags = map_xattr_flags(flags);
f338ef
diff --git a/xlators/storage/posix/src/posix-metadata.c b/xlators/storage/posix/src/posix-metadata.c
f338ef
index 532daa2..9efaf99 100644
f338ef
--- a/xlators/storage/posix/src/posix-metadata.c
f338ef
+++ b/xlators/storage/posix/src/posix-metadata.c
f338ef
@@ -56,6 +56,19 @@ posix_mdata_from_disk(posix_mdata_t *out, posix_mdata_disk_t *in)
f338ef
     out->atime.tv_nsec = be64toh(in->atime.tv_nsec);
f338ef
 }
f338ef
 
f338ef
+void
f338ef
+posix_mdata_iatt_from_disk(struct mdata_iatt *out, posix_mdata_disk_t *in)
f338ef
+{
f338ef
+    out->ia_ctime = be64toh(in->ctime.tv_sec);
f338ef
+    out->ia_ctime_nsec = be64toh(in->ctime.tv_nsec);
f338ef
+
f338ef
+    out->ia_mtime = be64toh(in->mtime.tv_sec);
f338ef
+    out->ia_mtime_nsec = be64toh(in->mtime.tv_nsec);
f338ef
+
f338ef
+    out->ia_atime = be64toh(in->atime.tv_sec);
f338ef
+    out->ia_atime_nsec = be64toh(in->atime.tv_nsec);
f338ef
+}
f338ef
+
f338ef
 /* posix_fetch_mdata_xattr fetches the posix_mdata_t from disk */
f338ef
 static int
f338ef
 posix_fetch_mdata_xattr(xlator_t *this, const char *real_path_arg, int _fd,
f338ef
@@ -341,6 +354,7 @@ posix_compare_timespec(struct timespec *first, struct timespec *second)
f338ef
 
f338ef
 int
f338ef
 posix_set_mdata_xattr_legacy_files(xlator_t *this, inode_t *inode,
f338ef
+                                   const char *realpath,
f338ef
                                    struct mdata_iatt *mdata_iatt, int *op_errno)
f338ef
 {
f338ef
     posix_mdata_t *mdata = NULL;
f338ef
@@ -369,8 +383,8 @@ posix_set_mdata_xattr_legacy_files(xlator_t *this, inode_t *inode,
f338ef
                 goto unlock;
f338ef
             }
f338ef
 
f338ef
-            ret = posix_fetch_mdata_xattr(this, NULL, -1, inode, (void *)mdata,
f338ef
-                                          op_errno);
f338ef
+            ret = posix_fetch_mdata_xattr(this, realpath, -1, inode,
f338ef
+                                          (void *)mdata, op_errno);
f338ef
             if (ret == 0) {
f338ef
                 /* Got mdata from disk. This is a race, another client
f338ef
                  * has healed the xattr during lookup. So set it in inode
f338ef
@@ -412,7 +426,7 @@ posix_set_mdata_xattr_legacy_files(xlator_t *this, inode_t *inode,
f338ef
             }
f338ef
         }
f338ef
 
f338ef
-        ret = posix_store_mdata_xattr(this, NULL, -1, inode, mdata);
f338ef
+        ret = posix_store_mdata_xattr(this, realpath, -1, inode, mdata);
f338ef
         if (ret) {
f338ef
             gf_msg(this->name, GF_LOG_ERROR, errno, P_MSG_STOREMDATA_FAILED,
f338ef
                    "gfid: %s key:%s ", uuid_utoa(inode->gfid),
f338ef
@@ -445,7 +459,8 @@ posix_set_mdata_xattr(xlator_t *this, const char *real_path, int fd,
f338ef
     GF_VALIDATE_OR_GOTO(this->name, inode, out);
f338ef
     GF_VALIDATE_OR_GOTO(this->name, time, out);
f338ef
 
f338ef
-    if (update_utime && (!u_atime || !u_mtime)) {
f338ef
+    if (update_utime && (flag->ctime && !time) && (flag->atime && !u_atime) &&
f338ef
+        (flag->mtime && !u_mtime)) {
f338ef
         goto out;
f338ef
     }
f338ef
 
f338ef
@@ -652,6 +667,48 @@ posix_update_utime_in_mdata(xlator_t *this, const char *real_path, int fd,
f338ef
     return;
f338ef
 }
f338ef
 
f338ef
+/* posix_update_ctime_in_mdata updates the posix_mdata_t when ctime needs
f338ef
+ * to be modified
f338ef
+ */
f338ef
+void
f338ef
+posix_update_ctime_in_mdata(xlator_t *this, const char *real_path, int fd,
f338ef
+                            inode_t *inode, struct timespec *ctime,
f338ef
+                            struct iatt *stbuf, int valid)
f338ef
+{
f338ef
+    int32_t ret = 0;
f338ef
+#if defined(HAVE_UTIMENSAT)
f338ef
+    struct timespec tv_ctime = {
f338ef
+        0,
f338ef
+    };
f338ef
+#else
f338ef
+    struct timeval tv_ctime = {
f338ef
+        0,
f338ef
+    };
f338ef
+#endif
f338ef
+    posix_mdata_flag_t flag = {
f338ef
+        0,
f338ef
+    };
f338ef
+
f338ef
+    struct posix_private *priv = NULL;
f338ef
+    priv = this->private;
f338ef
+
f338ef
+    if (inode && priv->ctime) {
f338ef
+        tv_ctime.tv_sec = stbuf->ia_ctime;
f338ef
+        SET_TIMESPEC_NSEC_OR_TIMEVAL_USEC(tv_ctime, stbuf->ia_ctime_nsec);
f338ef
+        flag.ctime = 1;
f338ef
+
f338ef
+        ret = posix_set_mdata_xattr(this, real_path, -1, inode, &tv_ctime, NULL,
f338ef
+                                    NULL, NULL, &flag, _gf_true);
f338ef
+        if (ret) {
f338ef
+            gf_msg(this->name, GF_LOG_WARNING, errno, P_MSG_SETMDATA_FAILED,
f338ef
+                   "posix set mdata atime failed on file:"
f338ef
+                   " %s gfid:%s",
f338ef
+                   real_path, uuid_utoa(inode->gfid));
f338ef
+        }
f338ef
+    }
f338ef
+    return;
f338ef
+}
f338ef
+
f338ef
 static void
f338ef
 posix_get_mdata_flag(uint64_t flags, posix_mdata_flag_t *flag)
f338ef
 {
f338ef
diff --git a/xlators/storage/posix/src/posix-metadata.h b/xlators/storage/posix/src/posix-metadata.h
f338ef
index c176699..63e8771 100644
f338ef
--- a/xlators/storage/posix/src/posix-metadata.h
f338ef
+++ b/xlators/storage/posix/src/posix-metadata.h
f338ef
@@ -43,6 +43,10 @@ posix_update_utime_in_mdata(xlator_t *this, const char *real_path, int fd,
f338ef
                             inode_t *inode, struct timespec *ctime,
f338ef
                             struct iatt *stbuf, int valid);
f338ef
 void
f338ef
+posix_update_ctime_in_mdata(xlator_t *this, const char *real_path, int fd,
f338ef
+                            inode_t *inode, struct timespec *ctime,
f338ef
+                            struct iatt *stbuf, int valid);
f338ef
+void
f338ef
 posix_set_ctime(call_frame_t *frame, xlator_t *this, const char *real_path,
f338ef
                 int fd, inode_t *inode, struct iatt *stbuf);
f338ef
 void
f338ef
@@ -56,7 +60,10 @@ posix_set_ctime_cfr(call_frame_t *frame, xlator_t *this,
f338ef
                     int fd_out, inode_t *inode_out, struct iatt *stbuf_out);
f338ef
 int
f338ef
 posix_set_mdata_xattr_legacy_files(xlator_t *this, inode_t *inode,
f338ef
+                                   const char *realpath,
f338ef
                                    struct mdata_iatt *mdata_iatt,
f338ef
                                    int *op_errno);
f338ef
+void
f338ef
+posix_mdata_iatt_from_disk(struct mdata_iatt *out, posix_mdata_disk_t *in);
f338ef
 
f338ef
 #endif /* _POSIX_METADATA_H */
f338ef
diff --git a/xlators/storage/posix/src/posix.h b/xlators/storage/posix/src/posix.h
f338ef
index 64288a7..dd51062 100644
f338ef
--- a/xlators/storage/posix/src/posix.h
f338ef
+++ b/xlators/storage/posix/src/posix.h
f338ef
@@ -339,7 +339,7 @@ dict_t *
f338ef
 posix_xattr_fill(xlator_t *this, const char *path, loc_t *loc, fd_t *fd,
f338ef
                  int fdnum, dict_t *xattr, struct iatt *buf);
f338ef
 int
f338ef
-posix_handle_pair(xlator_t *this, const char *real_path, char *key,
f338ef
+posix_handle_pair(xlator_t *this, loc_t *loc, const char *real_path, char *key,
f338ef
                   data_t *value, int flags, struct iatt *stbuf);
f338ef
 int
f338ef
 posix_fhandle_pair(call_frame_t *frame, xlator_t *this, int fd, char *key,
f338ef
@@ -352,7 +352,8 @@ int
f338ef
 posix_gfid_heal(xlator_t *this, const char *path, loc_t *loc,
f338ef
                 dict_t *xattr_req);
f338ef
 int
f338ef
-posix_entry_create_xattr_set(xlator_t *this, const char *path, dict_t *dict);
f338ef
+posix_entry_create_xattr_set(xlator_t *this, loc_t *loc, const char *path,
f338ef
+                             dict_t *dict);
f338ef
 
f338ef
 int
f338ef
 posix_fd_ctx_get(fd_t *fd, xlator_t *this, struct posix_fd **pfd,
f338ef
-- 
f338ef
1.8.3.1
f338ef