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