summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorShyam <srangana@redhat.com>2014-09-10 09:55:11 +0530
committerKaleb KEITHLEY <kkeithle@redhat.com>2014-10-20 07:56:00 -0700
commit3ade63522322d3c09b603a802eb1058cf4d0b50d (patch)
tree9a4633988841706da5d9afa7ccd1e3b28680b24e
parent49c4106fc338ebfeef15d4800cb8c17e575d8d3e (diff)
cluster/dht: Rename should not fail post hardlink creation
In the rename path, we wind the creation of newname hardlink and linkto file in dst hashed a the same time. If the linkto creation fails, but the link creation succeeds, we enter the failure code and cleanup the created newname hardlink. In the interim if another client looks up newname and finds it as a hardlink from FUSE, it could send an unlink for oldname instead of a rename. This combined with the above cleanup code could end up losing all the files copies, and thereby losing data. This fix separates these steps into 2 parts, creating the linkto first and then the link file, so that post link file creation no failures would cleanup the newname file. If linkto fails then link is not attempted, thereby not polluting the name space with newname. Change-Id: I61da8e906060da16a31ea1076eec2f01fd617f44 BUG: 1139998 Signed-off-by: Shyam <srangana@redhat.com> Reviewed-on: http://review.gluster.org/8570 Tested-by: Gluster Build System <jenkins@build.gluster.com> Reviewed-by: Jeff Darcy <jdarcy@redhat.com> Reviewed-by: Vijay Bellur <vbellur@redhat.com> Reviewed-on: http://review.gluster.org/8683 Reviewed-by: Kaleb KEITHLEY <kkeithle@redhat.com>
-rw-r--r--xlators/cluster/dht/src/dht-common.h10
-rw-r--r--xlators/cluster/dht/src/dht-rename.c130
2 files changed, 95 insertions, 45 deletions
diff --git a/xlators/cluster/dht/src/dht-common.h b/xlators/cluster/dht/src/dht-common.h
index 3049d366403..c42fb96b965 100644
--- a/xlators/cluster/dht/src/dht-common.h
+++ b/xlators/cluster/dht/src/dht-common.h
@@ -496,11 +496,11 @@ int dht_filter_loc_subvol_key (xlator_t *this, loc_t *loc, loc_t *new_loc,
xlator_t **subvol);
int dht_rename_cleanup (call_frame_t *frame);
-int dht_rename_links_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
- int32_t op_ret, int32_t op_errno,
- inode_t *inode, struct iatt *stbuf,
- struct iatt *preparent, struct iatt *postparent,
- dict_t *xdata);
+int dht_rename_link_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
+ int32_t op_ret, int32_t op_errno,
+ inode_t *inode, struct iatt *stbuf,
+ struct iatt *preparent, struct iatt *postparent,
+ dict_t *xdata);
int dht_fix_directory_layout (call_frame_t *frame,
dht_selfheal_dir_cbk_t dir_cbk,
diff --git a/xlators/cluster/dht/src/dht-rename.c b/xlators/cluster/dht/src/dht-rename.c
index 8bcea4d8e18..8ea16253898 100644
--- a/xlators/cluster/dht/src/dht-rename.c
+++ b/xlators/cluster/dht/src/dht-rename.c
@@ -707,9 +707,8 @@ dht_do_rename (call_frame_t *frame)
return 0;
}
-
int
-dht_rename_links_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
+dht_rename_link_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
int32_t op_ret, int32_t op_errno,
inode_t *inode, struct iatt *stbuf,
struct iatt *preparent, struct iatt *postparent,
@@ -717,8 +716,6 @@ dht_rename_links_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
{
dht_local_t *local = NULL;
call_frame_t *prev = NULL;
- int this_call_cnt = 0;
-
local = frame->local;
prev = cookie;
@@ -728,26 +725,65 @@ dht_rename_links_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
"link/file on %s failed (%s)",
prev->this->name, strerror (op_errno));
local->op_ret = -1;
- if (op_errno != ENOENT) {
- local->op_errno = op_errno;
-
- if (prev->this == local->src_cached) {
- local->added_link = _gf_false;
- }
- }
- } else if (local->src_cached == prev->this) {
- /* merge of attr returned only from linkfile creation */
+ local->op_errno = op_errno;
+ local->added_link = _gf_false;
+ } else {
dht_iatt_merge (this, &local->stbuf, stbuf, prev->this);
}
- this_call_cnt = dht_frame_return (frame);
- if (is_last_call (this_call_cnt)) {
- if (local->op_ret == -1)
- goto cleanup;
+ if (local->op_ret == -1)
+ goto cleanup;
- dht_do_rename (frame);
+ dht_do_rename (frame);
+
+ return 0;
+
+cleanup:
+ dht_rename_cleanup (frame);
+
+ return 0;
+}
+
+int
+dht_rename_linkto_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
+ int32_t op_ret, int32_t op_errno,
+ inode_t *inode, struct iatt *stbuf,
+ struct iatt *preparent, struct iatt *postparent,
+ dict_t *xdata)
+{
+ dht_local_t *local = NULL;
+ call_frame_t *prev = NULL;
+ xlator_t *src_cached = NULL;
+
+ local = frame->local;
+ prev = cookie;
+
+ src_cached = local->src_cached;
+
+ if (op_ret == -1) {
+ gf_log (this->name, GF_LOG_DEBUG,
+ "link/file on %s failed (%s)",
+ prev->this->name, strerror (op_errno));
+ local->op_ret = -1;
+ local->op_errno = op_errno;
+ }
+
+ /* If linkto creation failed move to failure cleanup code,
+ * instead of continuing with creating the link file */
+ if (local->op_ret != 0) {
+ goto cleanup;
}
+ gf_log (this->name, GF_LOG_TRACE,
+ "link %s => %s (%s)", local->loc.path,
+ local->loc2.path, src_cached->name);
+
+ local->added_link = _gf_true;
+
+ STACK_WIND (frame, dht_rename_link_cbk,
+ src_cached, src_cached->fops->link,
+ &local->loc, &local->loc2, NULL);
+
return 0;
cleanup:
@@ -796,14 +832,13 @@ cleanup:
int
dht_rename_create_links (call_frame_t *frame)
{
- dht_local_t *local = NULL;
- xlator_t *this = NULL;
+ dht_local_t *local = NULL;
+ xlator_t *this = NULL;
xlator_t *src_hashed = NULL;
xlator_t *src_cached = NULL;
xlator_t *dst_hashed = NULL;
xlator_t *dst_cached = NULL;
- int call_cnt = 0;
-
+ int call_cnt = 0;
local = frame->local;
this = frame->this;
@@ -813,45 +848,59 @@ dht_rename_create_links (call_frame_t *frame)
dst_hashed = local->dst_hashed;
dst_cached = local->dst_cached;
-
if (src_cached == dst_cached) {
if (dst_hashed == dst_cached)
goto nolinks;
+
gf_log (this->name, GF_LOG_TRACE,
- "unlinking dst linkfile %s @ %s",
- local->loc2.path, dst_hashed->name);
+ "unlinking dst linkfile %s @ %s",
+ local->loc2.path, dst_hashed->name);
STACK_WIND (frame, dht_rename_unlink_links_cbk,
dst_hashed, dst_hashed->fops->unlink,
&local->loc2, 0, NULL);
+
return 0;
}
- if (dst_hashed != src_hashed && dst_hashed != src_cached)
+ if (src_cached != dst_hashed) {
+ /* needed to create the link file */
call_cnt++;
+ if (dst_hashed != src_hashed)
+ /* needed to create the linkto file */
+ call_cnt ++;
+ }
- if (src_cached != dst_hashed)
- call_cnt++;
-
- local->call_cnt = call_cnt;
-
- if (dst_hashed != src_hashed && dst_hashed != src_cached) {
+ /* We should not have any failures post the link creation, as this
+ * introduces the newname into the namespace. Clients could have cached
+ * the existence of the newname and may start taking actions based on
+ * the same. Hence create the linkto first, and then attempt the link.
+ *
+ * NOTE: If another client is attempting the same oldname -> newname
+ * rename, and finds both file names as existing, and are hard links
+ * to each other, then FUSE would send in an unlink for oldname. In
+ * this time duration if we treat the linkto as a critical error and
+ * unlink the newname we created, we would have effectively lost the
+ * file to rename operations. */
+ if (dst_hashed != src_hashed && src_cached != dst_hashed) {
gf_log (this->name, GF_LOG_TRACE,
"linkfile %s @ %s => %s",
- local->loc.path, dst_hashed->name, src_cached->name);
+ local->loc.path, dst_hashed->name,
+ src_cached->name);
+
memcpy (local->gfid, local->loc.inode->gfid, 16);
- dht_linkfile_create (frame, dht_rename_links_cbk,
- src_cached, dst_hashed, &local->loc);
- }
- if (src_cached != dst_hashed) {
+ dht_linkfile_create (frame, dht_rename_linkto_cbk,
+ src_cached, dst_hashed, &local->loc);
+ } else if (src_cached != dst_hashed) {
gf_log (this->name, GF_LOG_TRACE,
- "link %s => %s (%s)", local->loc.path,
- local->loc2.path, src_cached->name);
+ "link %s => %s (%s)", local->loc.path,
+ local->loc2.path, src_cached->name);
local->added_link = _gf_true;
- STACK_WIND (frame, dht_rename_links_cbk,
+
+ STACK_WIND (frame, dht_rename_link_cbk,
src_cached, src_cached->fops->link,
&local->loc, &local->loc2, NULL);
}
@@ -865,6 +914,7 @@ nolinks:
return 0;
}
+
int
dht_rename_lookup_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
int op_ret, int op_errno,