summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--tests/bugs/shard/bug-1245547.t35
-rw-r--r--xlators/features/shard/src/shard.c32
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)