diff options
| author | Shreyas Siravara <sshreyas@fb.com> | 2017-09-02 21:12:42 -0700 |
|---|---|---|
| committer | Shreyas Siravara <sshreyas@fb.com> | 2017-09-03 04:30:49 +0000 |
| commit | a87e690e2b883b06240e01828dd83c86cbcd950f (patch) | |
| tree | fe56c5a3fb0d19c0b3978752557adaaf1506f093 | |
| parent | c547fc214dfe280374f23f8063a1bf0b794f4977 (diff) | |
cluster/afr: Fix gfid unsplit code when renamed filename exceeds NAME_MAX
Summary:
- We noticed some folks name their files all the way up to NAME_MAX (usually 255) and when split-brain is encountered, we fail to heal the file.
- This diff puts an upper bound on the number of bytes we will snprintf into the buffer so that we do not fail the rename.
- This is a port of D3646254 to 3.8
Test Plan: Prove test -- can show it fails without patch as well.
Reviewers: #posix_storage, rwareing
Reviewed By: rwareing
Change-Id: I51c6b28374d4a3f21e29044cb727b4b1da7b69e1
Reviewed-on: https://review.gluster.org/18194
Reviewed-by: Shreyas Siravara <sshreyas@fb.com>
CentOS-regression: Gluster Build System <jenkins@build.gluster.org>
Smoke: Gluster Build System <jenkins@build.gluster.org>
| -rw-r--r-- | tests/basic/afr/gfid-unsplit-shd.t | 77 | ||||
| -rw-r--r-- | xlators/cluster/afr/src/afr-self-heal-name.c | 15 |
2 files changed, 88 insertions, 4 deletions
diff --git a/tests/basic/afr/gfid-unsplit-shd.t b/tests/basic/afr/gfid-unsplit-shd.t index 77da5243724..760ea3e0868 100644 --- a/tests/basic/afr/gfid-unsplit-shd.t +++ b/tests/basic/afr/gfid-unsplit-shd.t @@ -17,9 +17,6 @@ TEST $CLI volume set $V0 nfs.disable off TEST $CLI volume set $V0 cluster.quorum-type none TEST $CLI volume set $V0 cluster.heal-timeout 5 TEST $CLI volume set $V0 cluster.favorite-child-policy majority -#EST $CLI volume set $V0 cluster.favorite-child-by-majority off -#EST $CLI volume set $V0 cluster.favorite-child-by-mtime on -#EST $CLI volume set $V0 cluster.favorite-child-by-size off TEST $CLI volume set $V0 cluster.metadata-self-heal off TEST $CLI volume set $V0 cluster.data-self-heal off TEST $CLI volume set $V0 cluster.entry-self-heal off @@ -95,4 +92,78 @@ TEST [ "$MD5" == "$HEALED_MD5" ] TEST rm -f foo/splitfile cd ~ +umount $M0 + +# Part II: Absurdly longfile test +LONG_FILE_NAME="aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +TEST glusterfs --volfile-id=/$V0 --volfile-server=$H0 $M0 \ + --attribute-timeout=0 --entry-timeout=0 + +cd $M0 +mkdir foo +dd if=/dev/urandom of=foo/${LONG_FILE_NAME} bs=128k count=5 2>/dev/null + +MD5=$(md5sum foo/${LONG_FILE_NAME} | cut -d\ -f1) + +sleep 1 +cd ~ + +GFID_PARENT_RAW=$(getfattr -n trusted.gfid -e hex $B0/${V0}1/foo 2>/dev/null | grep trusted.gfid | cut -d= -f2) +GFID_PARENT_FORMATTED=$(echo "$GFID_PARENT_RAW" | awk '{print substr($1,3,8)"-"substr($1,11,4)"-"substr($1,15,4)"-"substr($1,19,4)"-"substr($1,23,12)}') +GFID_RAW=$(getfattr -n trusted.gfid -e hex $B0/${V0}1/foo/${LONG_FILE_NAME} 2>/dev/null | grep trusted.gfid | cut -d= -f2) +GFID_FORMATTED=$(echo "$GFID_RAW" | awk '{print substr($1,3,8)"-"substr($1,11,4)"-"substr($1,15,4)"-"substr($1,19,4)"-"substr($1,23,12)}') +GFID_LINK_B1="$B0/${V0}1/.glusterfs/$(echo $GFID_RAW | awk '{print substr($0,3,2)"/"substr($0,5,2)"/"substr($1,3,8)"-"substr($1,11,4)"-"substr($1,15,4)"-"substr($1,19,4)"-"substr($1,23,12)}')" + +# Create a split-brain by downing a brick, and flipping the +# gfid on the down brick, then bring the brick back up. + +# For good measure kill the first brick so the inode cache is wiped, we don't +# want any funny business +TEST kill_brick $V0 $H0 $B0/${V0}1 +TEST $CLI volume start $V0 force +pkill -f gluster/glustershd + +rm -f $GFID_LINK_B1 +TEST setfattr -n "trusted.gfid" -v "0xfd551a5cfddd4c1aa4d096ef09ef5c08" $B0/${V0}1/foo/${LONG_FILE_NAME} +sleep 1 +TEST touch $B0/${V0}1/foo/${LONG_FILE_NAME} + +mkdir -p $B0/${V0}1/.glusterfs/fd/55 +ln $B0/${V0}1/foo/${LONG_FILE_NAME} $B0/${V0}1/.glusterfs/fd/55/fd551a5c-fddd-4c1a-a4d0-96ef09ef5c08 +cd ~ + +touch $B0/${V0}3/.glusterfs/indices/xattrop/$GFID_FORMATTED +touch $B0/${V0}3/.glusterfs/indices/xattrop/$GFID_PARENT_FORMATTED + +TEST $CLI volume start $V0 force +EXPECT_WITHIN 20 "1" afr_child_up_status $V0 0 +sleep 5 + +EXPECT_WITHIN 60 "0" get_pending_heal_count $V0 + +TEST stat $B0/${V0}1/foo/${LONG_FILE_NAME} + +cd $M0 + +# Tickle the file to trigger the gfid unsplit +TEST stat foo/${LONG_FILE_NAME} +sleep 1 + +# Verify the file is readable +TEST dd if=foo/${LONG_FILE_NAME} of=/dev/null 2>/dev/null + +# Verify entry healing happened on the back-end regardless of the +# gfid-splitbrain state of the directory. +TEST stat $B0/${V0}1/foo/${LONG_FILE_NAME} + +# Verify the MD5 signature of the file +HEALED_MD5=$(md5sum foo/${LONG_FILE_NAME} | cut -d\ -f1) +TEST [ "$MD5" == "$HEALED_MD5" ] + +# Verify the file can be removed +TEST rm -f foo/${LONG_FILE_NAME} +cd ~ + + + cleanup diff --git a/xlators/cluster/afr/src/afr-self-heal-name.c b/xlators/cluster/afr/src/afr-self-heal-name.c index 9ca56f8bd9d..8e5546a702f 100644 --- a/xlators/cluster/afr/src/afr-self-heal-name.c +++ b/xlators/cluster/afr/src/afr-self-heal-name.c @@ -84,6 +84,19 @@ _afr_sh_create_unsplit_loc (struct afr_reply *replies, const int child_idx, ret = ENOMEM; goto err; } + + /* + * Attempting to do a rename on a file that is too long + * will return ENAMETOOLONG and heals will fail. Therefore + * we should just limit the name to NAME_MAX + * knowing that the filename will be truncated. + */ + if (new_name_len > NAME_MAX) { + gf_log ("afr", GF_LOG_WARNING, + "Filename too long, truncating to %d bytes.", NAME_MAX); + new_name_len = NAME_MAX; + } + snprintf (new_name, new_name_len, ".unsplit_%s_%s", tmp_gfid_str, loc->name); unsplit_loc->name = new_name; @@ -376,7 +389,7 @@ __afr_selfheal_assign_gfid (xlator_t *this, inode_t *parent, uuid_t pargfid, continue; } gf_log (this->name, GF_LOG_WARNING, - "type[%d] = %d (not %d)", i, + "type[%d] = %d (not %d)", i, replies[i].poststat.ia_type, ia_type); if (ia_type != IA_INVAL) { ret = -EIO; |
