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