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