diff options
| author | N Balachandran <nbalacha@redhat.com> | 2019-02-12 13:58:54 +0530 | 
|---|---|---|
| committer | Raghavendra G <rgowdapp@redhat.com> | 2019-02-13 18:19:51 +0000 | 
| commit | b0f1d782fc45313fce4e1c0e74127401d5342d05 (patch) | |
| tree | f0e97b99b35c67621affe4d87d8131b05ac09a8f | |
| parent | 8a90d346b9d3f69ff11241feb0011c90a8e57e30 (diff) | |
cluster/dht: Fix lookup selfheal and rmdir race
A race between the lookup selfheal and rmdir can cause
directories to be healed only on non-hashed subvols.
This can prevent the directory from being listed from
the mount point and in turn causes rm -rf to fail with
ENOTEMPTY.
Fix: Update the layout information correctly and reduce
the call count only after processing the response.
Change-Id: I812779aaf3d7bcf24aab1cb158cb6ed50d212451
fixes: bz#1676400
Signed-off-by: N Balachandran <nbalacha@redhat.com>
| -rw-r--r-- | xlators/cluster/dht/src/dht-selfheal.c | 34 | 
1 files changed, 25 insertions, 9 deletions
diff --git a/xlators/cluster/dht/src/dht-selfheal.c b/xlators/cluster/dht/src/dht-selfheal.c index e306943edda..bd1b7eae256 100644 --- a/xlators/cluster/dht/src/dht-selfheal.c +++ b/xlators/cluster/dht/src/dht-selfheal.c @@ -1309,11 +1309,13 @@ dht_selfheal_dir_mkdir_lookup_cbk(call_frame_t *frame, void *cookie,      int missing_dirs = 0;      dht_layout_t *layout = NULL;      dht_conf_t *conf = 0; +    xlator_t *prev = 0;      loc_t *loc = NULL;      int check_mds = 0;      int errst = 0;      int32_t mds_xattr_val[1] = {0};      char gfid_local[GF_UUID_BUF_SIZE] = {0}; +    int index = -1;      VALIDATE_OR_GOTO(this->private, err); @@ -1321,32 +1323,46 @@ dht_selfheal_dir_mkdir_lookup_cbk(call_frame_t *frame, void *cookie,      layout = local->layout;      loc = &local->loc;      conf = this->private; +    prev = cookie; -    if (local->gfid) +    if (!gf_uuid_is_null(local->gfid))          gf_uuid_unparse(local->gfid, gfid_local); -    this_call_cnt = dht_frame_return(frame); -      LOCK(&frame->lock);      { +        index = dht_layout_index_for_subvol(layout, prev);          if ((op_ret < 0) && (op_errno == ENOENT || op_errno == ESTALE)) {              local->selfheal.hole_cnt = !local->selfheal.hole_cnt                                             ? 1                                             : local->selfheal.hole_cnt + 1; +            /* the status might have changed. Update the layout with the +             * new status +             */ +            if (index >= 0) { +                layout->list[index].err = op_errno; +            }          }          if (!op_ret) {              dht_iatt_merge(this, &local->stbuf, stbuf); -        } -        check_mds = dht_dict_get_array(xattr, conf->mds_xattr_key, -                                       mds_xattr_val, 1, &errst); -        if (dict_get(xattr, conf->mds_xattr_key) && check_mds && !errst) { -            dict_unref(local->xattr); -            local->xattr = dict_ref(xattr); +            check_mds = dht_dict_get_array(xattr, conf->mds_xattr_key, +                                           mds_xattr_val, 1, &errst); +            if (dict_get(xattr, conf->mds_xattr_key) && check_mds && !errst) { +                dict_unref(local->xattr); +                local->xattr = dict_ref(xattr); +            } +            /* the status might have changed. Update the layout with the +             * new status +             */ +            if (index >= 0) { +                layout->list[index].err = -1; +            }          }      }      UNLOCK(&frame->lock); +    this_call_cnt = dht_frame_return(frame); +      if (is_last_call(this_call_cnt)) {          if (local->selfheal.hole_cnt == layout->cnt) {              gf_msg_debug(this->name, op_errno,  | 
