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