diff options
-rw-r--r-- | libglusterfs/src/glusterfs.h | 2 | ||||
-rwxr-xr-x[-rw-r--r--] | tests/basic/rpc-coverage.t | 2 | ||||
-rw-r--r-- | tests/bugs/stripe/bug-1002207.t | 2 | ||||
-rw-r--r-- | tests/bugs/stripe/bug-1111454.t | 2 | ||||
-rw-r--r-- | xlators/cluster/dht/src/dht-common.c | 633 | ||||
-rw-r--r-- | xlators/cluster/dht/src/dht-common.h | 8 | ||||
-rw-r--r-- | xlators/cluster/dht/src/dht-helper.c | 5 | ||||
-rw-r--r-- | xlators/cluster/dht/src/dht-layout.c | 16 | ||||
-rw-r--r-- | xlators/cluster/dht/src/dht-messages.h | 11 | ||||
-rw-r--r-- | xlators/storage/posix/src/posix-messages.h | 10 | ||||
-rw-r--r-- | xlators/storage/posix/src/posix.c | 116 |
11 files changed, 766 insertions, 41 deletions
diff --git a/libglusterfs/src/glusterfs.h b/libglusterfs/src/glusterfs.h index 97331fdef17..9d077e5ad61 100644 --- a/libglusterfs/src/glusterfs.h +++ b/libglusterfs/src/glusterfs.h @@ -89,6 +89,8 @@ #define GF_READDIR_SKIP_DIRS "readdir-filter-directories" #define BD_XATTR_KEY "user.glusterfs" +#define GF_PREOP_PARENT_KEY "glusterfs.preop.parent.key" +#define GF_PREOP_CHECK_FAILED "glusterfs.preop.check.failed" #define XATTR_IS_PATHINFO(x) ((strncmp (x, GF_XATTR_PATHINFO_KEY, \ strlen (x)) == 0) || \ diff --git a/tests/basic/rpc-coverage.t b/tests/basic/rpc-coverage.t index f8ade599893..a76ba7084eb 100644..100755 --- a/tests/basic/rpc-coverage.t +++ b/tests/basic/rpc-coverage.t @@ -9,7 +9,7 @@ TEST glusterd TEST pidof glusterd TEST $CLI volume info; -TEST $CLI volume create $V0 replica 2 stripe 2 $H0:$B0/${V0}{1,2,3,4,5,6,7,8}; +TEST $CLI volume create $V0 replica 2 $H0:$B0/${V0}{1,2,3,4,5,6,7,8}; EXPECT "$V0" volinfo_field $V0 'Volume Name'; EXPECT 'Created' volinfo_field $V0 'Status'; diff --git a/tests/bugs/stripe/bug-1002207.t b/tests/bugs/stripe/bug-1002207.t index 1f8e46bae02..c58a6e20ab8 100644 --- a/tests/bugs/stripe/bug-1002207.t +++ b/tests/bugs/stripe/bug-1002207.t @@ -51,3 +51,5 @@ TEST $CLI volume delete $V0; TEST ! $CLI volume info $V0; cleanup; +#G_TESTDEF_TEST_STATUS_NETBSD7=BAD_TEST,BUG=000000 +#G_TESTDEF_TEST_STATUS_CENTOS6=BAD_TEST,BUG=000000 diff --git a/tests/bugs/stripe/bug-1111454.t b/tests/bugs/stripe/bug-1111454.t index 05f69345e4b..1509dd7b1a2 100644 --- a/tests/bugs/stripe/bug-1111454.t +++ b/tests/bugs/stripe/bug-1111454.t @@ -16,3 +16,5 @@ TEST touch $M0/dir/file TEST ln -s file $M0/dir/symlinkfile TEST ls -lR $M0 cleanup +#G_TESTDEF_TEST_STATUS_NETBSD7=BAD_TEST,BUG=000000 +#G_TESTDEF_TEST_STATUS_CENTOS6=BAD_TEST,BUG=000000 diff --git a/xlators/cluster/dht/src/dht-common.c b/xlators/cluster/dht/src/dht-common.c index 3afbc6258f3..be568063bd2 100644 --- a/xlators/cluster/dht/src/dht-common.c +++ b/xlators/cluster/dht/src/dht-common.c @@ -5377,7 +5377,6 @@ out: return 0; } - int32_t dht_mknod_do (call_frame_t *frame) { @@ -5562,6 +5561,357 @@ err: return -1; } +int +dht_refresh_parent_layout_resume (call_frame_t *frame, xlator_t *this, int ret, + int invoke_cbk) +{ + dht_local_t *local = NULL, *parent_local = NULL; + call_stub_t *stub = NULL; + call_frame_t *parent_frame = NULL; + + local = frame->local; + + stub = local->stub; + local->stub = NULL; + + parent_frame = stub->frame; + parent_local = parent_frame->local; + + if (ret < 0) { + parent_local->op_ret = -1; + parent_local->op_errno = local->op_errno + ? local->op_errno : EIO; + } else { + parent_local->op_ret = 0; + } + + call_resume (stub); + + DHT_STACK_DESTROY (frame); + + return 0; +} + + +int +dht_refresh_parent_layout_done (call_frame_t *frame) +{ + dht_local_t *local = NULL; + int ret = 0; + + local = frame->local; + + if (local->op_ret < 0) { + ret = -1; + goto resume; + } + + dht_layout_set (frame->this, local->loc.inode, + local->selfheal.refreshed_layout); + +resume: + dht_refresh_parent_layout_resume (frame, frame->this, ret, 1); + return 0; +} + + +int +dht_handle_parent_layout_change (xlator_t *this, call_stub_t *stub) +{ + call_frame_t *refresh_frame = NULL, *frame = NULL; + dht_local_t *refresh_local = NULL, *local = NULL; + + frame = stub->frame; + local = frame->local; + + refresh_frame = copy_frame (frame); + refresh_local = dht_local_init (refresh_frame, NULL, NULL, + stub->fop); + + refresh_local->loc.inode = inode_ref (local->loc.parent); + gf_uuid_copy (refresh_local->loc.gfid, local->loc.parent->gfid); + + refresh_local->stub = stub; + + refresh_local->refresh_layout_unlock = dht_refresh_parent_layout_resume; + refresh_local->refresh_layout_done = dht_refresh_parent_layout_done; + + dht_refresh_layout (refresh_frame); + return 0; +} + +int32_t +dht_unlock_parent_layout_during_entry_fop_done (call_frame_t *frame, + void *cookie, + xlator_t *this, + int32_t op_ret, + int32_t op_errno, + dict_t *xdata) +{ + dht_local_t *local = NULL; + char gfid[GF_UUID_BUF_SIZE] = {0}; + + local = frame->local; + gf_uuid_unparse (local->lock.locks[0]->loc.inode->gfid, gfid); + + if (op_ret < 0) { + gf_msg (this->name, GF_LOG_WARNING, op_errno, + DHT_MSG_PARENT_LAYOUT_CHANGED, + "unlock failed on gfid: %s, stale lock might be left " + "in DHT_LAYOUT_HEAL_DOMAIN", gfid); + } + + DHT_STACK_DESTROY (frame); + return 0; +} + +int32_t +dht_unlock_parent_layout_during_entry_fop (call_frame_t *frame) +{ + dht_local_t *local = NULL, *lock_local = NULL; + call_frame_t *lock_frame = NULL; + char pgfid[GF_UUID_BUF_SIZE] = {0}; + + local = frame->local; + + gf_uuid_unparse (local->loc.parent->gfid, pgfid); + + lock_frame = copy_frame (frame); + if (lock_frame == NULL) { + gf_msg (frame->this->name, GF_LOG_WARNING, ENOMEM, + DHT_MSG_PARENT_LAYOUT_CHANGED, + "mkdir (%s/%s) (path: %s): " + "copy frame failed", pgfid, local->loc.name, + local->loc.path); + goto done; + } + + lock_local = mem_get0 (THIS->local_pool); + if (lock_local == NULL) { + gf_msg (frame->this->name, GF_LOG_WARNING, ENOMEM, + DHT_MSG_PARENT_LAYOUT_CHANGED, + "mkdir (%s/%s) (path: %s): " + "local creation failed", pgfid, local->loc.name, + local->loc.path); + goto done; + } + + lock_frame->local = lock_local; + + lock_local->lock.locks = local->lock.locks; + lock_local->lock.lk_count = local->lock.lk_count; + + local->lock.locks = NULL; + local->lock.lk_count = 0; + + dht_unlock_inodelk (lock_frame, lock_local->lock.locks, + lock_local->lock.lk_count, + dht_unlock_parent_layout_during_entry_fop_done); + +done: + return 0; +} + +int32_t +dht_guard_parent_layout_during_entry_fop_cbk (call_frame_t *frame, void *cookie, + xlator_t *this, int32_t op_ret, + int32_t op_errno, dict_t *xdata) +{ + dht_local_t *local = NULL; + call_stub_t *stub = NULL; + + local = frame->local; + stub = local->stub; + local->stub = NULL; + + if (op_ret < 0) { + local->op_ret = -1; + local->op_errno = op_errno; + } else { + local->op_ret = 0; + } + + call_resume (stub); + + return 0; +} + +int32_t +dht_guard_parent_layout_during_entry_fop (xlator_t *subvol, call_stub_t *stub) +{ + dht_local_t *local = NULL; + int count = 1, ret = -1; + dht_lock_t **lk_array = NULL; + loc_t *loc = NULL; + xlator_t *hashed_subvol = NULL, *this = NULL;; + call_frame_t *frame = NULL; + char pgfid[GF_UUID_BUF_SIZE] = {0}; + loc_t parent = {0, }; + int32_t *parent_disk_layout = NULL; + dht_layout_t *parent_layout = NULL; + dht_conf_t *conf = NULL; + + GF_VALIDATE_OR_GOTO ("dht", stub, err); + + frame = stub->frame; + this = frame->this; + + conf = this->private; + + local = frame->local; + + local->stub = stub; + + /* TODO: recheck whether we should lock on src or dst if we do similar + * stale layout checks for rename. + */ + loc = &stub->args.loc; + + gf_uuid_unparse (loc->parent->gfid, pgfid); + + if (local->params == NULL) { + local->params = dict_new (); + if (local->params == NULL) { + local->op_errno = ENOMEM; + gf_msg (this->name, GF_LOG_WARNING, local->op_errno, + DHT_MSG_PARENT_LAYOUT_CHANGED, + "%s (%s/%s) (path: %s): " + "dict allocation failed", + gf_fop_list[stub->fop], + pgfid, loc->name, loc->path); + goto err; + } + } + + hashed_subvol = dht_subvol_get_hashed (this, loc); + if (hashed_subvol == NULL) { + local->op_errno = EINVAL; + + gf_msg (this->name, GF_LOG_WARNING, local->op_errno, + DHT_MSG_PARENT_LAYOUT_CHANGED, + "%s (%s/%s) (path: %s): " + "hashed subvolume not found", gf_fop_list[stub->fop], + pgfid, loc->name, loc->path); + goto err; + } + + parent_layout = dht_layout_get (this, loc->parent); + + ret = dht_disk_layout_extract_for_subvol (this, parent_layout, + hashed_subvol, + &parent_disk_layout); + if (ret == -1) { + local->op_errno = EINVAL; + gf_msg (this->name, GF_LOG_WARNING, local->op_errno, + DHT_MSG_PARENT_LAYOUT_CHANGED, + "%s (%s/%s) (path: %s): " + "extracting in-memory layout of parent failed. ", + gf_fop_list[stub->fop], pgfid, loc->name, loc->path); + goto err; + } + + memcpy ((void *)local->parent_disk_layout, (void *)parent_disk_layout, + sizeof (local->parent_disk_layout)); + + dht_layout_unref (this, parent_layout); + parent_layout = NULL; + + ret = dict_set_str (local->params, GF_PREOP_PARENT_KEY, + conf->xattr_name); + if (ret < 0) { + local->op_errno = -ret; + gf_msg (this->name, GF_LOG_WARNING, local->op_errno, + DHT_MSG_PARENT_LAYOUT_CHANGED, + "%s (%s/%s) (path: %s): " + "setting %s key in params dictionary failed. ", + gf_fop_list[stub->fop], pgfid, loc->name, loc->path, + GF_PREOP_PARENT_KEY); + goto err; + } + + ret = dict_set_bin (local->params, conf->xattr_name, parent_disk_layout, + 4 * 4); + if (ret < 0) { + local->op_errno = -ret; + gf_msg (this->name, GF_LOG_WARNING, local->op_errno, + DHT_MSG_PARENT_LAYOUT_CHANGED, + "%s (%s/%s) (path: %s): " + "setting parent-layout in params dictionary failed. ", + gf_fop_list[stub->fop], pgfid, loc->name, loc->path); + goto err; + } + + parent_disk_layout = NULL; + + parent.inode = inode_ref (loc->parent); + gf_uuid_copy (parent.gfid, loc->parent->gfid); + + lk_array = GF_CALLOC (count, sizeof (*lk_array), gf_common_mt_char); + + if (lk_array == NULL) { + local->op_errno = ENOMEM; + + gf_msg (this->name, GF_LOG_WARNING, local->op_errno, + DHT_MSG_PARENT_LAYOUT_CHANGED, + "%s (%s/%s) (path: %s): " + "calloc failure", + gf_fop_list[stub->fop], pgfid, loc->name, loc->path); + + goto err; + } + + lk_array[0] = dht_lock_new (frame->this, hashed_subvol, &parent, + F_RDLCK, DHT_LAYOUT_HEAL_DOMAIN); + + if (lk_array[0] == NULL) { + local->op_errno = ENOMEM; + gf_msg (this->name, GF_LOG_WARNING, local->op_errno, + DHT_MSG_PARENT_LAYOUT_CHANGED, + "%s (%s/%s) (path: %s): " + "lock allocation failed", + gf_fop_list[stub->fop], pgfid, loc->name, loc->path); + + goto err; + } + + local->lock.locks = lk_array; + local->lock.lk_count = count; + + ret = dht_blocking_inodelk (frame, lk_array, count, FAIL_ON_ANY_ERROR, + dht_guard_parent_layout_during_entry_fop_cbk); + + if (ret < 0) { + local->op_errno = EIO; + local->lock.locks = NULL; + local->lock.lk_count = 0; + gf_msg (this->name, GF_LOG_WARNING, local->op_errno, + DHT_MSG_PARENT_LAYOUT_CHANGED, + "%s (%s/%s) (path: %s): " + "dht_blocking_inodelk failed", + gf_fop_list[stub->fop], pgfid, loc->name, loc->path); + + goto err; + } + + loc_wipe (&parent); + + return 0; +err: + if (lk_array != NULL) { + dht_lock_array_free (lk_array, count); + GF_FREE (lk_array); + } + + loc_wipe (&parent); + + if (parent_disk_layout != NULL) + GF_FREE (parent_disk_layout); + + if (parent_layout != NULL) + dht_layout_unref (this, parent_layout); + + return -1; +} int dht_mknod (call_frame_t *frame, xlator_t *this, @@ -6690,15 +7040,154 @@ dht_mkdir_hashed_cbk (call_frame_t *frame, void *cookie, xlator_t *this, int op_ret, int op_errno, inode_t *inode, struct iatt *stbuf, struct iatt *preparent, struct iatt *postparent, + dict_t *xdata); + +int +dht_mkdir_helper (call_frame_t *frame, xlator_t *this, + loc_t *loc, mode_t mode, mode_t umask, dict_t *params) +{ + dht_local_t *local = NULL; + dht_conf_t *conf = NULL; + int op_errno = -1, ret = -1; + xlator_t *hashed_subvol = NULL; + int32_t *parent_disk_layout = NULL; + dht_layout_t *parent_layout = NULL; + char pgfid[GF_UUID_BUF_SIZE] = {0}; + + VALIDATE_OR_GOTO (frame, err); + VALIDATE_OR_GOTO (this, err); + VALIDATE_OR_GOTO (loc, err); + VALIDATE_OR_GOTO (loc->inode, err); + VALIDATE_OR_GOTO (loc->path, err); + VALIDATE_OR_GOTO (this->private, err); + + gf_uuid_unparse (loc->parent->gfid, pgfid); + + conf = this->private; + local = frame->local; + + if (local->op_ret == -1) { + gf_msg (this->name, GF_LOG_WARNING, local->op_errno, + DHT_MSG_PARENT_LAYOUT_CHANGED, + "mkdir (%s/%s) (path: %s): refreshing parent layout " + "failed.", pgfid, loc->name, + loc->path); + + op_errno = local->op_errno; + goto err; + } + + local->op_ret = -1; + + hashed_subvol = dht_subvol_get_hashed (this, loc); + if (hashed_subvol == NULL) { + gf_msg_debug (this->name, 0, + "mkdir (%s/%s) (path: %s): hashed subvol not " + "found", pgfid, loc->name, loc->path); + op_errno = ENOENT; + goto err; + } + + local->hashed_subvol = hashed_subvol; + + parent_layout = dht_layout_get (this, loc->parent); + + ret = dht_disk_layout_extract_for_subvol (this, parent_layout, + hashed_subvol, + &parent_disk_layout); + if (ret == -1) { + gf_msg (this->name, GF_LOG_WARNING, EIO, + DHT_MSG_PARENT_LAYOUT_CHANGED, + "mkdir (%s/%s) (path: %s): " + "extracting in-memory layout of parent failed. ", + pgfid, loc->name, loc->path); + goto err; + } + + if (memcmp (local->parent_disk_layout, parent_disk_layout, + sizeof (local->parent_disk_layout)) == 0) { + gf_msg (this->name, GF_LOG_WARNING, EIO, + DHT_MSG_PARENT_LAYOUT_CHANGED, + "mkdir (%s/%s) (path: %s): loop detected. " + "parent layout didn't change even though " + "previous attempt of mkdir failed because of " + "in-memory layout not matching with that on disk.", + pgfid, loc->name, loc->path); + op_errno = EIO; + goto err; + } + + memcpy ((void *)local->parent_disk_layout, (void *)parent_disk_layout, + sizeof (local->parent_disk_layout)); + + dht_layout_unref (this, parent_layout); + parent_layout = NULL; + + ret = dict_set_str (params, GF_PREOP_PARENT_KEY, conf->xattr_name); + if (ret < 0) { + local->op_errno = -ret; + gf_msg (this->name, GF_LOG_WARNING, local->op_errno, + DHT_MSG_PARENT_LAYOUT_CHANGED, + "mkdir (%s/%s) (path: %s): " + "setting %s key in params dictionary failed. ", + pgfid, loc->name, loc->path, GF_PREOP_PARENT_KEY); + goto err; + } + + ret = dict_set_bin (params, conf->xattr_name, parent_disk_layout, + 4 * 4); + if (ret < 0) { + local->op_errno = -ret; + gf_msg (this->name, GF_LOG_WARNING, local->op_errno, + DHT_MSG_PARENT_LAYOUT_CHANGED, + "setting parent-layout in params dictionary failed. " + "mkdir (%s/%s) (path: %s)", pgfid, loc->name, + loc->path); + goto err; + } + + parent_disk_layout = NULL; + + STACK_WIND (frame, dht_mkdir_hashed_cbk, + hashed_subvol, + hashed_subvol->fops->mkdir, + loc, mode, umask, params); + + return 0; + +err: + dht_unlock_parent_layout_during_entry_fop (frame); + + op_errno = local ? local->op_errno : op_errno; + DHT_STACK_UNWIND (mkdir, frame, -1, op_errno, NULL, NULL, NULL, + NULL, NULL); + + if (parent_disk_layout != NULL) + GF_FREE (parent_disk_layout); + + if (parent_layout != NULL) + dht_layout_unref (this, parent_layout); + + return 0; +} + +int +dht_mkdir_hashed_cbk (call_frame_t *frame, void *cookie, + xlator_t *this, int op_ret, int op_errno, + inode_t *inode, struct iatt *stbuf, + struct iatt *preparent, struct iatt *postparent, dict_t *xdata) { - dht_local_t *local = NULL; - int ret = -1; - call_frame_t *prev = NULL; - dht_layout_t *layout = NULL; - dht_conf_t *conf = NULL; - int i = 0; - xlator_t *hashed_subvol = NULL; + dht_local_t *local = NULL; + int ret = -1; + call_frame_t *prev = NULL; + dht_layout_t *layout = NULL; + dht_conf_t *conf = NULL; + int i = 0; + xlator_t *hashed_subvol = NULL; + char pgfid[GF_UUID_BUF_SIZE] = {0}; + gf_boolean_t parent_layout_changed = _gf_false; + call_stub_t *stub = NULL; VALIDATE_OR_GOTO (this->private, err); @@ -6708,9 +7197,44 @@ dht_mkdir_hashed_cbk (call_frame_t *frame, void *cookie, conf = this->private; hashed_subvol = local->hashed_subvol; + gf_uuid_unparse (local->loc.parent->gfid, pgfid); + if (gf_uuid_is_null (local->loc.gfid) && !op_ret) gf_uuid_copy (local->loc.gfid, stbuf->ia_gfid); + if (op_ret == -1) { + local->op_errno = op_errno; + + parent_layout_changed = dict_get (xdata, GF_PREOP_CHECK_FAILED) + ? 1 : 0; + if (parent_layout_changed) { + gf_msg (this->name, GF_LOG_INFO, 0, + DHT_MSG_PARENT_LAYOUT_CHANGED, + "mkdir (%s/%s) (path: %s): parent layout " + "changed. Attempting a refresh and then a " + "retry", pgfid, local->loc.name, + local->loc.path); + + stub = fop_mkdir_stub (frame, dht_mkdir_helper, + &local->loc, local->mode, + local->umask, local->params); + if (stub == NULL) { + goto err; + } + + dht_handle_parent_layout_change (this, stub); + stub = NULL; + + return 0; + } + + goto err; + } + + dht_unlock_parent_layout_during_entry_fop (frame); + dict_del (local->params, GF_PREOP_PARENT_KEY); + dict_del (local->params, conf->xattr_name); + if (dht_is_subvol_filled (this, hashed_subvol)) ret = dht_layout_merge (this, layout, prev->this, -1, ENOSPC, NULL); @@ -6726,10 +7250,6 @@ dht_mkdir_hashed_cbk (call_frame_t *frame, void *cookie, "%s: failed to merge layouts for subvol %s", local->loc.path, prev->this->name); - if (op_ret == -1) { - local->op_errno = op_errno; - goto err; - } local->op_ret = 0; dht_iatt_merge (this, &local->stbuf, stbuf, prev->this); @@ -6744,6 +7264,7 @@ dht_mkdir_hashed_cbk (call_frame_t *frame, void *cookie, dht_selfheal_directory (frame, dht_mkdir_selfheal_cbk, &local->loc, layout); } + for (i = 0; i < conf->subvolume_cnt; i++) { if (conf->subvolumes[i] == hashed_subvol) continue; @@ -6754,21 +7275,64 @@ dht_mkdir_hashed_cbk (call_frame_t *frame, void *cookie, } return 0; err: + if (local->op_ret != 0) + dht_unlock_parent_layout_during_entry_fop (frame); + DHT_STACK_UNWIND (mkdir, frame, -1, op_errno, NULL, NULL, NULL, NULL, NULL); + if (stub) { + call_stub_destroy (stub); + } + return 0; } +int +dht_mkdir_guard_parent_layout_cbk (call_frame_t *frame, xlator_t *this, + loc_t *loc, mode_t mode, mode_t umask, + dict_t *params) +{ + dht_local_t *local = NULL; + char pgfid[GF_UUID_BUF_SIZE] = {0}; + + local = frame->local; + + gf_uuid_unparse (loc->parent->gfid, pgfid); + + if (local->op_ret < 0) { + gf_msg (this->name, GF_LOG_WARNING, local->op_errno, + DHT_MSG_PARENT_LAYOUT_CHANGED, + "mkdir (%s/%s) (path: %s): " + "Acquiring lock on parent to guard against " + "layout-change failed.", pgfid, loc->name, loc->path); + goto err; + } + + local->op_ret = -1; + + STACK_WIND (frame, dht_mkdir_hashed_cbk, + local->hashed_subvol, + local->hashed_subvol->fops->mkdir, + loc, mode, umask, params); + + return 0; +err: + DHT_STACK_UNWIND (mkdir, frame, -1, local->op_errno, NULL, NULL, NULL, + NULL, NULL); + + return 0; +} int dht_mkdir (call_frame_t *frame, xlator_t *this, loc_t *loc, mode_t mode, mode_t umask, dict_t *params) { - dht_local_t *local = NULL; - dht_conf_t *conf = NULL; - int op_errno = -1; - xlator_t *hashed_subvol = NULL; - + dht_local_t *local = NULL; + dht_conf_t *conf = NULL; + int op_errno = -1, ret = -1; + xlator_t *hashed_subvol = NULL; + char pgfid[GF_UUID_BUF_SIZE] = {0}; + call_stub_t *stub = NULL; VALIDATE_OR_GOTO (frame, err); VALIDATE_OR_GOTO (this, err); @@ -6777,6 +7341,8 @@ dht_mkdir (call_frame_t *frame, xlator_t *this, VALIDATE_OR_GOTO (loc->path, err); VALIDATE_OR_GOTO (this->private, err); + gf_uuid_unparse (loc->parent->gfid, pgfid); + conf = this->private; dht_get_du_info (frame, this, loc); @@ -6792,14 +7358,17 @@ dht_mkdir (call_frame_t *frame, xlator_t *this, gf_msg_debug (this->name, 0, "hashed subvol not found for %s", loc->path); - op_errno = EIO; + local->op_errno = EIO; goto err; } + local->hashed_subvol = hashed_subvol; local->mode = mode; local->umask = umask; - local->params = dict_ref (params); + if (params) + local->params = dict_ref (params); + local->inode = inode_ref (loc->inode); local->layout = dht_layout_new (this, conf->subvolume_cnt); @@ -6818,15 +7387,31 @@ dht_mkdir (call_frame_t *frame, xlator_t *this, else local->layout->commit_hash = DHT_LAYOUT_HASH_INVALID; - STACK_WIND (frame, dht_mkdir_hashed_cbk, - hashed_subvol, - hashed_subvol->fops->mkdir, - loc, mode, umask, params); + + stub = fop_mkdir_stub (frame, dht_mkdir_guard_parent_layout_cbk, loc, + mode, umask, params); + if (stub == NULL) { + gf_msg (this->name, GF_LOG_WARNING, ENOMEM, + DHT_MSG_PARENT_LAYOUT_CHANGED, + "mkdir (%s/%s) (path: %s): " + "creating stub failed.", pgfid, loc->name, loc->path); + local->op_errno = ENOMEM; + goto err; + } + + ret = dht_guard_parent_layout_during_entry_fop (this, stub); + if (ret < 0) { + gf_msg (this->name, GF_LOG_WARNING, 0, + DHT_MSG_PARENT_LAYOUT_CHANGED, + "mkdir (%s/%s) (path: %s) cannot wind lock request to " + "guard parent layout", pgfid, loc->name, loc->path); + goto err; + } return 0; err: - op_errno = (op_errno == -1) ? errno : op_errno; + op_errno = local ? local->op_errno : op_errno; DHT_STACK_UNWIND (mkdir, frame, -1, op_errno, NULL, NULL, NULL, NULL, NULL); diff --git a/xlators/cluster/dht/src/dht-common.h b/xlators/cluster/dht/src/dht-common.h index b63ee65acfb..7cc549e133c 100644 --- a/xlators/cluster/dht/src/dht-common.h +++ b/xlators/cluster/dht/src/dht-common.h @@ -13,6 +13,7 @@ #include "dht-mem-types.h" #include "dht-messages.h" +#include "call-stub.h" #include "libxlator.h" #include "syncop.h" #include "refcount.h" @@ -281,6 +282,9 @@ struct dht_local { int op_ret; int op_errno; } lock; + + call_stub_t *stub; + int32_t parent_disk_layout[4]; }; typedef struct dht_local dht_local_t; @@ -705,7 +709,9 @@ int dht_disk_layout_extract (xlator_t *this, dht_layout_t *layout, int pos, int32_t **disk_layout_p); int dht_disk_layout_merge (xlator_t *this, dht_layout_t *layout, int pos, void *disk_layout_raw, int disk_layout_len); - +int +dht_disk_layout_extract_for_subvol (xlator_t *this, dht_layout_t *layout, + xlator_t *subvol, int32_t **disk_layout_p); int dht_frame_return (call_frame_t *frame); diff --git a/xlators/cluster/dht/src/dht-helper.c b/xlators/cluster/dht/src/dht-helper.c index 8673c1fd83a..0384c2a4cc4 100644 --- a/xlators/cluster/dht/src/dht-helper.c +++ b/xlators/cluster/dht/src/dht-helper.c @@ -621,6 +621,11 @@ dht_local_wipe (xlator_t *this, dht_local_t *local) if (local->rebalance.iobref) iobref_unref (local->rebalance.iobref); + if (local->stub) { + call_stub_destroy (local->stub); + local->stub = NULL; + } + mem_put (local); } diff --git a/xlators/cluster/dht/src/dht-layout.c b/xlators/cluster/dht/src/dht-layout.c index ca600e9618a..4352ffe5756 100644 --- a/xlators/cluster/dht/src/dht-layout.c +++ b/xlators/cluster/dht/src/dht-layout.c @@ -280,6 +280,22 @@ out: return ret; } +int +dht_disk_layout_extract_for_subvol (xlator_t *this, dht_layout_t *layout, + xlator_t *subvol, int32_t **disk_layout_p) +{ + int i = 0; + + for (i = 0; i < layout->cnt; i++) { + if (layout->list[i].xlator == subvol) + break; + } + + if (i == layout->cnt) + return -1; + + return dht_disk_layout_extract (this, layout, i, disk_layout_p); +} int dht_disk_layout_merge (xlator_t *this, dht_layout_t *layout, diff --git a/xlators/cluster/dht/src/dht-messages.h b/xlators/cluster/dht/src/dht-messages.h index 4403efc151c..ebad3d1ced9 100644 --- a/xlators/cluster/dht/src/dht-messages.h +++ b/xlators/cluster/dht/src/dht-messages.h @@ -40,7 +40,7 @@ */ #define GLFS_DHT_BASE GLFS_MSGID_COMP_DHT -#define GLFS_DHT_NUM_MESSAGES 113 +#define GLFS_DHT_NUM_MESSAGES 114 #define GLFS_MSGID_END (GLFS_DHT_BASE + GLFS_DHT_NUM_MESSAGES + 1) /* Messages with message IDs */ @@ -1043,12 +1043,19 @@ #define DHT_MSG_FD_CTX_SET_FAILED (GLFS_DHT_BASE + 112) /* - * @messageid 109112 + * @messageid 109113 * @diagnosis * @recommendedaction None */ #define DHT_MSG_STALE_LOOKUP (GLFS_DHT_BASE + 113) +/* + * @messageid 109114 + * @diagnosis + * @recommendedaction None + */ +#define DHT_MSG_PARENT_LAYOUT_CHANGED (GLFS_DHT_BASE + 114) + #define glfs_msg_end_x GLFS_MSGID_END, "Invalid: End of messages" #endif /* _DHT_MESSAGES_H_ */ diff --git a/xlators/storage/posix/src/posix-messages.h b/xlators/storage/posix/src/posix-messages.h index 0c0eb059270..b5472aded91 100644 --- a/xlators/storage/posix/src/posix-messages.h +++ b/xlators/storage/posix/src/posix-messages.h @@ -918,6 +918,16 @@ */ #define P_MSG_INODE_RESOLVE_FAILED (POSIX_COMP_BASE + 108) + +/*! + * @messageid + * @diagnosis + * @recommendedaction + * + */ + +#define P_MSG_PREOP_CHECK_FAILED (POSIX_COMP_BASE + 109) + /*! * @messageid * @diagnosis diff --git a/xlators/storage/posix/src/posix.c b/xlators/storage/posix/src/posix.c index 3a2fc13d2b1..4f286fda333 100644 --- a/xlators/storage/posix/src/posix.c +++ b/xlators/storage/posix/src/posix.c @@ -1393,18 +1393,22 @@ int posix_mkdir (call_frame_t *frame, xlator_t *this, loc_t *loc, mode_t mode, mode_t umask, dict_t *xdata) { - int32_t op_ret = -1; - int32_t op_errno = 0; - char *real_path = NULL, *gfid_path = NULL; - char *par_path = NULL; - struct iatt stbuf = {0, }; - struct posix_private *priv = NULL; - gid_t gid = 0; - struct iatt preparent = {0,}; - struct iatt postparent = {0,}; - gf_boolean_t entry_created = _gf_false, gfid_set = _gf_false; - void *uuid_req = NULL; - ssize_t size = 0; + int32_t op_ret = -1; + int32_t op_errno = 0; + char *real_path = NULL, *gfid_path = NULL; + char *par_path = NULL, *xattr_name = NULL; + struct iatt stbuf = {0, }; + struct posix_private *priv = NULL; + gid_t gid = 0; + struct iatt preparent = {0,}; + struct iatt postparent = {0,}; + gf_boolean_t entry_created = _gf_false, gfid_set = _gf_false; + void *uuid_req = NULL; + ssize_t size = 0; + dict_t *xdata_rsp = NULL; + void *disk_xattr = NULL, *arg_xattr = NULL; + data_t *arg_data = NULL; + char pgfid[GF_UUID_BUF_SIZE] = {0}; DECLARE_OLD_FS_ID_VAR; @@ -1434,6 +1438,11 @@ posix_mkdir (call_frame_t *frame, xlator_t *this, goto out; } + if (loc->parent) + gf_uuid_unparse (loc->parent->gfid, pgfid); + else + gf_uuid_unparse (loc->pargfid, pgfid); + gid = frame->root->gid; op_ret = posix_pstat (this, NULL, real_path, &stbuf); @@ -1477,6 +1486,84 @@ posix_mkdir (call_frame_t *frame, xlator_t *this, mode |= S_ISGID; } + op_ret = dict_get_str (xdata, GF_PREOP_PARENT_KEY, &xattr_name); + if (xattr_name != NULL) { + arg_data = dict_get (xdata, xattr_name); + if (arg_data) { + size = sys_lgetxattr (par_path, xattr_name, NULL, 0); + if (size < 0) { + op_ret = -1; + op_errno = errno; + gf_msg (this->name, GF_LOG_ERROR, errno, + P_MSG_PREOP_CHECK_FAILED, + "mkdir (%s/%s): getxattr on key (%s)" + " path (%s) failed ", pgfid, + loc->name, xattr_name, + par_path); + goto out; + } + + disk_xattr = alloca (size); + if (disk_xattr == NULL) { + op_ret = -1; + op_errno = errno; + gf_msg (this->name, GF_LOG_ERROR, errno, + P_MSG_PREOP_CHECK_FAILED, + "mkdir (%s/%s): alloca failed during" + " preop of mkdir (%s)", pgfid, + loc->name, real_path); + goto out; + } + + size = sys_lgetxattr (par_path, xattr_name, + disk_xattr, size); + if (size < 0) { + op_errno = errno; + gf_msg (this->name, GF_LOG_ERROR, errno, + P_MSG_PREOP_CHECK_FAILED, + "mkdir (%s/%s): getxattr on key (%s)" + " path (%s) failed (%s)", pgfid, + loc->name, xattr_name, + par_path, strerror (errno)); + goto out; + } + + if ((arg_data->len != size) + || (memcmp (arg_data->data, disk_xattr, size))) { + int ret = 0; + gf_msg (this->name, GF_LOG_INFO, EIO, + P_MSG_PREOP_CHECK_FAILED, + "mkdir (%s/%s): failing preop of " + "mkdir (%s) as on-disk" + " xattr value differs from argument " + "value for key %s", pgfid, loc->name, + real_path, xattr_name); + op_ret = -1; + op_errno = EIO; + + xdata_rsp = dict_new (); + if (xdata_rsp == NULL) { + gf_msg (this->name, GF_LOG_ERROR, + ENOMEM, + P_MSG_PREOP_CHECK_FAILED, + "mkdir (%s/%s): " + "dict allocation failed", pgfid, + loc->name); + op_errno = ENOMEM; + goto out; + } + + ret = dict_set_int8 (xdata_rsp, + GF_PREOP_CHECK_FAILED, 1); + goto out; + } + + dict_del (xdata, xattr_name); + } + + dict_del (xdata, GF_PREOP_PARENT_KEY); + } + op_ret = sys_mkdir (real_path, mode); if (op_ret == -1) { op_errno = errno; @@ -1540,7 +1627,7 @@ out: STACK_UNWIND_STRICT (mkdir, frame, op_ret, op_errno, (loc)?loc->inode:NULL, &stbuf, &preparent, - &postparent, NULL); + &postparent, xdata_rsp); if (op_ret < 0) { if (entry_created) @@ -1550,6 +1637,9 @@ out: posix_gfid_unset (this, xdata); } + if (xdata_rsp) + dict_unref (xdata_rsp); + return 0; } |