diff options
-rw-r--r-- | tests/bugs/shard/bug-1245547.t | 35 | ||||
-rw-r--r-- | xlators/features/shard/src/shard.c | 32 |
2 files changed, 65 insertions, 2 deletions
diff --git a/tests/bugs/shard/bug-1245547.t b/tests/bugs/shard/bug-1245547.t new file mode 100644 index 00000000000..c19b2a6a042 --- /dev/null +++ b/tests/bugs/shard/bug-1245547.t @@ -0,0 +1,35 @@ +#!/bin/bash + +. $(dirname $0)/../../include.rc + +cleanup; + +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 $H0:$B0/${V0}{0,1} +TEST $CLI volume set $V0 features.shard on +TEST $CLI volume start $V0 + +TEST $GFS --volfile-id=$V0 --volfile-server=$H0 $M0 +#Create a file. +TEST touch $M0/foo +#Write some data into it. +TEST `echo "abc" > $M0/foo` + +#This should ensure /.shard is created on the bricks. +TEST stat $B0/${V0}0/.shard +TEST stat $B0/${V0}1/.shard + +#Create a file 'bar' with holes. +TEST touch $M0/bar +TEST truncate -s 10G $M0/bar +#Unlink on such a file should succeed. +TEST unlink $M0/bar +# +#Create a file 'baz' with holes. +TEST touch $M0/baz +TEST truncate -s 10G $M0/baz +#Rename with a sharded existing dest that has holes must succeed. +TEST mv -f $M0/foo $M0/baz + +cleanup; diff --git a/xlators/features/shard/src/shard.c b/xlators/features/shard/src/shard.c index da95b92ecd9..5801651d8e3 100644 --- a/xlators/features/shard/src/shard.c +++ b/xlators/features/shard/src/shard.c @@ -649,7 +649,7 @@ shard_lookup (call_frame_t *frame, xlator_t *this, loc_t *loc, loc->path); goto err; } - if (dict_get (xattr_req, GF_CONTENT_KEY)) + if ((xattr_req) && (dict_get (xattr_req, GF_CONTENT_KEY))) dict_del (xattr_req, GF_CONTENT_KEY); STACK_WIND (frame, shard_lookup_cbk, FIRST_CHILD (this), @@ -1724,7 +1724,9 @@ done: int shard_unlink_shards_do (call_frame_t *frame, xlator_t *this, inode_t *inode) { + int i = 0; int ret = -1; + int count = 0; int call_count = 0; uint32_t last_block = 0; uint32_t cur_block = 0; @@ -1740,6 +1742,30 @@ shard_unlink_shards_do (call_frame_t *frame, xlator_t *this, inode_t *inode) local->call_count = call_count = local->num_blocks - 1; last_block = local->last_block; + for (i = 1; i < local->num_blocks; i++) { + if (!local->inode_list[i]) + continue; + count++; + } + + if (!count) { + /* callcount = 0 implies that all of the shards that need to be + * unlinked are non-existent (in other words the file is full of + * holes). So shard xlator would now proceed to do the final + * unlink on the base file. + */ + local->num_blocks = 1; + if (local->fop == GF_FOP_UNLINK) { + STACK_WIND (frame, shard_unlink_cbk, FIRST_CHILD(this), + FIRST_CHILD(this)->fops->unlink, + &local->loc, local->flags, + local->xattr_req); + } else if (local->fop == GF_FOP_RENAME) { + shard_rename_cbk (frame, this); + } + return 0; + } + while (cur_block <= last_block) { /* The base file is unlinked in the end to mark the * successful completion of the fop. @@ -1803,7 +1829,7 @@ shard_post_lookup_shards_unlink_handler (call_frame_t *frame, xlator_t *this) local = frame->local; - if (local->op_ret < 0) { + if ((local->op_ret < 0) && (local->op_errno != ENOENT)) { if (local->fop == GF_FOP_UNLINK) SHARD_STACK_UNWIND (unlink, frame, local->op_ret, local->op_errno, NULL, NULL, NULL); @@ -1813,6 +1839,8 @@ shard_post_lookup_shards_unlink_handler (call_frame_t *frame, xlator_t *this) NULL, NULL, NULL); return 0; } + local->op_ret = 0; + local->op_errno = 0; shard_unlink_shards_do (frame, this, (local->fop == GF_FOP_RENAME) |