diff options
author | Anand Avati <avati@gluster.com> | 2011-07-12 02:11:59 +0000 |
---|---|---|
committer | Anand Avati <avati@gluster.com> | 2011-07-12 02:12:52 -0700 |
commit | 1f5119627b278b98518afb68a7eb88752932976c (patch) | |
tree | 995c4b9092b909e56bece30ef5d0ee0b047a6ddf | |
parent | b894a5c79f93707149181a51bfab67fdbffcc43b (diff) |
cluster/dht: fix race between two directory renames
let the race get arbitrated at the dst_hashed subvolume.
Signed-off-by: Anand Avati <avati@gluster.com>
BUG: 2522 ([glusterfs-3.1.3qa8]: rm -rf shows invalid argument)
URL: http://bugs.gluster.com/cgi-bin/bugzilla3/show_bug.cgi?id=2522
-rw-r--r-- | xlators/cluster/dht/src/dht-rename.c | 86 |
1 files changed, 79 insertions, 7 deletions
diff --git a/xlators/cluster/dht/src/dht-rename.c b/xlators/cluster/dht/src/dht-rename.c index 2db707cb57b..dd1354269bb 100644 --- a/xlators/cluster/dht/src/dht-rename.c +++ b/xlators/cluster/dht/src/dht-rename.c @@ -90,30 +90,102 @@ unwind: } - int -dht_rename_dir_do (call_frame_t *frame, xlator_t *this) +dht_rename_hashed_dir_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, struct iatt *stbuf, + struct iatt *preoldparent, + struct iatt *postoldparent, + struct iatt *prenewparent, + struct iatt *postnewparent) { - dht_local_t *local = NULL; dht_conf_t *conf = NULL; + dht_local_t *local = NULL; + int call_cnt = 0; + call_frame_t *prev = NULL; int i = 0; conf = this->private; local = frame->local; + prev = cookie; - if (local->op_ret == -1) - goto err; + if (op_ret == -1) { + /* TODO: undo the damage */ - local->call_cnt = conf->subvolume_cnt; - local->op_ret = 0; + gf_log (this->name, GF_LOG_INFO, + "rename %s -> %s on %s failed (%s)", + local->loc.path, local->loc2.path, + prev->this->name, strerror (op_errno)); + + local->op_ret = op_ret; + local->op_errno = op_errno; + goto unwind; + } + /* TODO: construct proper stbuf for dir */ + /* + * FIXME: is this the correct way to build stbuf and + * parent bufs? + */ + dht_iatt_merge (this, &local->stbuf, stbuf, prev->this); + dht_iatt_merge (this, &local->preoldparent, preoldparent, + prev->this); + dht_iatt_merge (this, &local->postoldparent, postoldparent, + prev->this); + dht_iatt_merge (this, &local->preparent, prenewparent, + prev->this); + dht_iatt_merge (this, &local->postparent, postnewparent, + prev->this); + + call_cnt = local->call_cnt = conf->subvolume_cnt - 1; + + if (!local->call_cnt) + goto unwind; for (i = 0; i < conf->subvolume_cnt; i++) { + if (conf->subvolumes[i] == local->dst_hashed) + continue; STACK_WIND (frame, dht_rename_dir_cbk, conf->subvolumes[i], conf->subvolumes[i]->fops->rename, &local->loc, &local->loc2); + if (!--call_cnt) + break; } + + return 0; +unwind: + WIPE (&local->preoldparent); + WIPE (&local->postoldparent); + WIPE (&local->preparent); + WIPE (&local->postparent); + + DHT_STACK_UNWIND (rename, frame, local->op_ret, local->op_errno, + &local->stbuf, &local->preoldparent, + &local->postoldparent, + &local->preparent, &local->postparent); + + return 0; +} + + +int +dht_rename_dir_do (call_frame_t *frame, xlator_t *this) +{ + dht_local_t *local = NULL; + dht_conf_t *conf = NULL; + + conf = this->private; + local = frame->local; + + if (local->op_ret == -1) + goto err; + + local->op_ret = 0; + + STACK_WIND (frame, dht_rename_hashed_dir_cbk, + local->dst_hashed, + local->dst_hashed->fops->rename, + &local->loc, &local->loc2); return 0; err: |