diff options
-rw-r--r-- | tests/bugs/bug-1101143.t | 83 | ||||
-rw-r--r-- | tests/include.rc | 1 | ||||
-rw-r--r-- | tests/volume.rc | 5 | ||||
-rw-r--r-- | xlators/storage/posix/src/posix-helpers.c | 63 |
4 files changed, 151 insertions, 1 deletions
diff --git a/tests/bugs/bug-1101143.t b/tests/bugs/bug-1101143.t new file mode 100644 index 00000000000..a6eda0c1acd --- /dev/null +++ b/tests/bugs/bug-1101143.t @@ -0,0 +1,83 @@ +#!/bin/bash + +. $(dirname $0)/../include.rc +. $(dirname $0)/../volume.rc + +#This file checks if softlinks are removed or not when rename is done while +#a brick is down in a replica pair. +cleanup; + +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 replica 2 $H0:$B0/${V0}{0,1} +TEST $CLI volume set $V0 brick-log-level DEBUG +TEST $CLI volume start $V0 +TEST glusterfs --volfile-id=/$V0 --volfile-server=$H0 $M0 --attribute-timeout=0 --entry-timeout=0 +cd $M0 +TEST mkdir -p d1/d2/d3 +TEST mkdir -p dir1/dir1 +d1_gfid_path=$(gf_get_gfid_backend_file_path $B0/${V0}0 d1) +d1_gfid=$(gf_get_gfid_xattr $B0/${V0}0/d1) +dir1_gfid_path=$(gf_get_gfid_backend_file_path $B0/${V0}0 dir1) +dir1_dir1_gfid_path=$(gf_get_gfid_backend_file_path $B0/${V0}0 dir1/dir1) +d1_d2_d3_old_gfid_path=$(gf_get_gfid_backend_file_path $B0/${V0}0 d1/d2/d3) +d1_d2_d3_gfid=$(gf_get_gfid_xattr $B0/${V0}0/d1/d2/d3) +TEST kill_brick $V0 $H0 $B0/${V0}0 + +#Rename should not delete gfid-link by janitor +TEST mv d1 d2 + +#Rmdir should delete gfid-link by janitor +TEST rm -rf dir1 + +#Stale-link will be created if we do this after self-heal where old-gfid dir will be pointing to dir with different gfid on brick-0 +TEST rmdir d2/d2/d3 +TEST mkdir d2/d2/d3 + +TEST $CLI volume set $V0 self-heal-daemon off +TEST $CLI volume start $V0 force +#Wait for the brick to come up +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status $V0 0 + +#Now enable self-heal-daemon so that heal will populate landfill +TEST $CLI volume set $V0 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 +TEST $CLI volume heal $V0 full +EXPECT_WITHIN $HEAL_TIMEOUT "0" afr_get_pending_heal_count $V0 +EXPECT_NOT "0" landfill_entry_count $B0/${V0}0 + +#Janitor thread walks once every 10 minutes, or at the time of brick start +#So lets stop the volume and make some checks. +TEST $CLI volume stop $V0 + +#Test that it is pointing to gfid which is not the old one +TEST stat $d1_d2_d3_old_gfid_path #Check there is stale link file +new_gfid=$(getfattr -d -m. -e hex $d1_d2_d3_old_gfid_path | grep gfid| cut -f2 -d'=') +#Check the gfids are valid +EXPECT 34 expr length $new_gfid +EXPECT 34 expr length $d1_d2_d3_gfid +EXPECT_NOT $new_gfid echo $d1_d2_d3_gfid + +#restart it to make sure janitor wakes up. +TEST $CLI volume start $V0 force +EXPECT_WITHIN $JANITOR_TIMEOUT "0" landfill_entry_count $B0/${V0}0 + +#After janitor cleans up, check that the directories have their softlinks +d2_gfid_path=$(gf_get_gfid_backend_file_path $B0/${V0}0 d2) +d2_gfid=$(gf_get_gfid_xattr $B0/${V0}0/d2) +EXPECT "$d1_gfid_path" echo $d2_gfid_path +EXPECT "$d1_gfid" echo $d2_gfid +TEST stat $d1_gfid_path + +#TODO afr-v2 is not healing sub-directories because heal is not marking +#new-entry changelog?. Will need to fix that. After the fix, the following line +#needs to be un-commented. +#TEST stat $(gf_get_gfid_backend_file_path $B0/${V0}0 d2/d2) + +#Check that janitor removed stale links +TEST ! stat $dir1_gfid_path +TEST ! stat $dir1_dir1_gfid_path +TEST ! stat $d1_d2_d3_old_gfid_path #Check stale link file is deleted +cleanup diff --git a/tests/include.rc b/tests/include.rc index 882785bd1b3..5dbbc7c7336 100644 --- a/tests/include.rc +++ b/tests/include.rc @@ -16,6 +16,7 @@ REBALANCE_TIMEOUT=120 REOPEN_TIMEOUT=20 HEAL_TIMEOUT=60 MARKER_UPDATE_TIMEOUT=20 +JANITOR_TIMEOUT=60 statedumpdir=`gluster --print-statedumpdir`; # Default directory for statedump diff --git a/tests/volume.rc b/tests/volume.rc index 301b57b8d42..acd9f94b124 100644 --- a/tests/volume.rc +++ b/tests/volume.rc @@ -364,3 +364,8 @@ function afr_get_index_count { local brick=$1 ls $1/.glusterfs/indices/xattrop | grep -v xattrop | wc -l } + +function landfill_entry_count { + local brick=$1 + ls $brick/.glusterfs/landfill | wc -l +} diff --git a/xlators/storage/posix/src/posix-helpers.c b/xlators/storage/posix/src/posix-helpers.c index 2ddb41a7be2..143267637b5 100644 --- a/xlators/storage/posix/src/posix-helpers.c +++ b/xlators/storage/posix/src/posix-helpers.c @@ -972,6 +972,67 @@ out: return ret; } +static void +del_stale_dir_handle (xlator_t *this, uuid_t gfid) +{ + char newpath[PATH_MAX] = {0, }; + uuid_t gfid_curr = {0, }; + ssize_t size = -1; + gf_boolean_t stale = _gf_false; + char *hpath = NULL; + struct stat stbuf = {0, }; + struct iatt iabuf = {0, }; + + MAKE_HANDLE_GFID_PATH (hpath, this, gfid, NULL); + + /* check that it is valid directory handle */ + size = sys_lstat (hpath, &stbuf); + if (size < 0) { + gf_log (this->name, GF_LOG_DEBUG, "%s: Handle stat failed: " + "%s", hpath, strerror (errno)); + goto out; + } + + iatt_from_stat (&iabuf, &stbuf); + if (iabuf.ia_nlink != 1 || !IA_ISLNK (iabuf.ia_type)) { + gf_log (this->name, GF_LOG_DEBUG, "%s: Handle nlink %d %d", + hpath, iabuf.ia_nlink, IA_ISLNK (iabuf.ia_type)); + goto out; + } + + size = posix_handle_path (this, gfid, NULL, newpath, sizeof (newpath)); + if (size <= 0 && errno == ENOENT) { + gf_log (this->name, GF_LOG_DEBUG, "%s: %s", newpath, + strerror (ENOENT)); + stale = _gf_true; + goto out; + } + + size = sys_lgetxattr (newpath, GFID_XATTR_KEY, gfid_curr, 16); + if (size < 0 && errno == ENOENT) { + gf_log (this->name, GF_LOG_DEBUG, "%s: %s", newpath, + strerror (ENOENT)); + stale = _gf_true; + } else if (size == 16 && uuid_compare (gfid, gfid_curr)) { + gf_log (this->name, GF_LOG_DEBUG, "%s: mismatching gfid: %s, " + "at %s", hpath, uuid_utoa (gfid_curr), newpath); + stale = _gf_true; + } + +out: + if (stale) { + size = sys_unlink (hpath); + if (size < 0 && errno != ENOENT) + gf_log (this->name, GF_LOG_ERROR, "%s: Failed to " + "remove handle to %s (%s)", hpath, newpath, + strerror (errno)); + } else if (size == 16) { + gf_log (this->name, GF_LOG_DEBUG, "%s: Fresh handle for " + "%s with gfid %s", hpath, newpath, + uuid_utoa (gfid_curr)); + } + return; +} static int janitor_walker (const char *fpath, const struct stat *sb, @@ -1002,7 +1063,7 @@ janitor_walker (const char *fpath, const struct stat *sb, "removing directory %s", fpath); rmdir (fpath); - posix_handle_unset (this, stbuf.ia_gfid, NULL); + del_stale_dir_handle (this, stbuf.ia_gfid); } break; } |