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;  }  | 
