diff options
Diffstat (limited to 'xlators')
-rw-r--r-- | xlators/cluster/dht/src/dht-common.h | 3 | ||||
-rw-r--r-- | xlators/cluster/dht/src/dht-rebalance.c | 94 |
2 files changed, 82 insertions, 15 deletions
diff --git a/xlators/cluster/dht/src/dht-common.h b/xlators/cluster/dht/src/dht-common.h index c2583e4f962..994b9e29d3e 100644 --- a/xlators/cluster/dht/src/dht-common.h +++ b/xlators/cluster/dht/src/dht-common.h @@ -1137,8 +1137,7 @@ void* gf_defrag_start (void *this); int32_t -gf_defrag_handle_hardlink (xlator_t *this, loc_t *loc, dict_t *xattrs, - struct iatt *stbuf, int *fop_errno); +gf_defrag_handle_hardlink (xlator_t *this, loc_t *loc, int *fop_errno); int dht_migrate_file (xlator_t *this, loc_t *loc, xlator_t *from, xlator_t *to, int flag, int *fop_errno); diff --git a/xlators/cluster/dht/src/dht-rebalance.c b/xlators/cluster/dht/src/dht-rebalance.c index 30d8d878be8..6269effe2ee 100644 --- a/xlators/cluster/dht/src/dht-rebalance.c +++ b/xlators/cluster/dht/src/dht-rebalance.c @@ -274,8 +274,7 @@ be converted to "0" in dht_migrate_file. */ int32_t -gf_defrag_handle_hardlink (xlator_t *this, loc_t *loc, dict_t *xattrs, - struct iatt *stbuf, int *fop_errno) +gf_defrag_handle_hardlink (xlator_t *this, loc_t *loc, int *fop_errno) { int32_t ret = -1; xlator_t *cached_subvol = NULL; @@ -287,15 +286,15 @@ gf_defrag_handle_hardlink (xlator_t *this, loc_t *loc, dict_t *xattrs, dht_conf_t *conf = NULL; gf_loglevel_t loglevel = 0; dict_t *link_xattr = NULL; - + dict_t *dict = NULL; + dict_t *xattr_rsp = NULL; + struct iatt stbuf = {0,}; *fop_errno = EINVAL; GF_VALIDATE_OR_GOTO ("defrag", loc, out); GF_VALIDATE_OR_GOTO ("defrag", loc->name, out); - GF_VALIDATE_OR_GOTO ("defrag", stbuf, out); GF_VALIDATE_OR_GOTO ("defrag", this, out); - GF_VALIDATE_OR_GOTO ("defrag", xattrs, out); GF_VALIDATE_OR_GOTO ("defrag", this->private, out); conf = this->private; @@ -351,8 +350,27 @@ gf_defrag_handle_hardlink (xlator_t *this, loc_t *loc, dict_t *xattrs, file or not. */ - ret = syncop_lookup (this, loc, NULL, NULL, - NULL, NULL); + dict = dict_new (); + if (!dict) { + ret = -1; + *fop_errno = ENOMEM; + gf_msg (this->name, GF_LOG_ERROR, ENOMEM, DHT_MSG_NO_MEMORY, + "could not allocate memory for dict"); + goto out; + } + + ret = dict_set_int32 (dict, conf->link_xattr_name, 256); + if (ret) { + *fop_errno = ENOMEM; + ret = -1; + gf_msg (this->name, GF_LOG_ERROR, 0, + DHT_MSG_MIGRATE_FILE_FAILED, + "Migrate file failed:" + "%s: failed to set 'linkto' key in dict", loc->path); + goto out; + } + + ret = syncop_lookup (this, loc, &stbuf, NULL, dict, &xattr_rsp); if (ret) { /*Ignore ENOENT and ESTALE as file might have been migrated already*/ @@ -393,6 +411,10 @@ gf_defrag_handle_hardlink (xlator_t *this, loc_t *loc, dict_t *xattrs, goto out; } + /* Hardlink migration happens only with remove-brick. So this condition will + * be true only when the migration has happened. In case hardlinks are migrated + * for rebalance case, remove this check. Having this check here avoid redundant + * calls below*/ if (hashed_subvol == cached_subvol) { ret = -2; goto out; @@ -401,7 +423,8 @@ gf_defrag_handle_hardlink (xlator_t *this, loc_t *loc, dict_t *xattrs, gf_log (this->name, GF_LOG_INFO, "Attempting to migrate hardlink %s " "with gfid %s from %s -> %s", loc->name, uuid_utoa (loc->gfid), cached_subvol->name, hashed_subvol->name); - data = dict_get (xattrs, conf->link_xattr_name); + + data = dict_get (xattr_rsp, conf->link_xattr_name); /* set linkto on cached -> hashed if not present, else link it */ if (!data) { ret = dict_set_str (link_xattr, conf->link_xattr_name, @@ -431,10 +454,15 @@ gf_defrag_handle_hardlink (xlator_t *this, loc_t *loc, dict_t *xattrs, ret = -1; goto out; } + + gf_msg_debug (this->name, 0, "hardlink target subvol created on %s " + ",cached %s, file %s", + hashed_subvol->name, cached_subvol->name, loc->path); + ret = -2; goto out; } else { - linkto_subvol = dht_linkfile_subvol (this, NULL, NULL, xattrs); + linkto_subvol = dht_linkfile_subvol (this, NULL, NULL, xattr_rsp); if (!linkto_subvol) { gf_msg (this->name, GF_LOG_ERROR, 0, DHT_MSG_SUBVOL_ERROR, @@ -461,8 +489,14 @@ gf_defrag_handle_hardlink (xlator_t *this, loc_t *loc, dict_t *xattrs, *fop_errno = op_errno; goto out; } + } else { + gf_msg_debug (this->name, 0, "syncop_link successful for" + " hardlink %s on subvol %s, cached %s", loc->path, + hashed_subvol->name, cached_subvol->name); + } } + ret = syncop_lookup (hashed_subvol, loc, &iatt, NULL, NULL, NULL); if (ret) { gf_msg (this->name, GF_LOG_ERROR, -ret, @@ -475,7 +509,22 @@ gf_defrag_handle_hardlink (xlator_t *this, loc_t *loc, dict_t *xattrs, goto out; } - if (iatt.ia_nlink == stbuf->ia_nlink) { + /* There is a race where on the target subvol for the hardlink + * (note: hash subvol for the hardlink might differ from this), some + * other client(non-rebalance) would have created a linkto file for that + * hardlink as part of lookup. So let say there are 10 hardlinks, on the + * 5th hardlink it self the hardlinks might have migrated. Now for + * (6..10th) hardlinks the cached and target would be same as the file + * has already migrated. Hence this check is needed */ + if (cached_subvol == hashed_subvol) { + gf_msg_debug (this->name, 0, "source %s and destination %s " + "for hardlink %s are same", cached_subvol->name, + hashed_subvol->name, loc->path); + ret = -2; + goto out; + } + + if (iatt.ia_nlink == stbuf.ia_nlink) { ret = dht_migrate_file (this, loc, cached_subvol, hashed_subvol, GF_DHT_MIGRATE_HARDLINK_IN_PROGRESS, fop_errno); @@ -487,6 +536,13 @@ gf_defrag_handle_hardlink (xlator_t *this, loc_t *loc, dict_t *xattrs, out: if (link_xattr) dict_unref (link_xattr); + + if (xattr_rsp) + dict_unref (xattr_rsp); + + if (dict) + dict_unref (dict); + return ret; } @@ -508,7 +564,7 @@ __check_file_has_hardlink (xlator_t *this, loc_t *loc, if (flags == GF_DHT_MIGRATE_HARDLINK) { synclock_lock (&conf->link_lock); ret = gf_defrag_handle_hardlink - (this, loc, xattrs, stbuf, fop_errno); + (this, loc, fop_errno); synclock_unlock (&conf->link_lock); /* Returning zero will force the file to be remigrated. @@ -1495,6 +1551,13 @@ dht_migrate_file (xlator_t *this, loc_t *loc, xlator_t *from, xlator_t *to, gf_boolean_t ignore_failure = _gf_false; + if (from == to) { + gf_msg_debug (this->name, 0, "destination and source are same. file %s" + " might have migrated already", loc->path); + ret = 0; + goto out; + } + /* If defrag is NULL, it should be assumed that migration is triggered * from client */ defrag = conf->defrag; @@ -1559,6 +1622,11 @@ dht_migrate_file (xlator_t *this, loc_t *loc, xlator_t *from, xlator_t *to, gf_uuid_copy (tmp_loc.gfid, loc->gfid); tmp_loc.path = gf_strdup(loc->path); + /* this inodelk happens with flock.owner being zero. But to synchronize + * hardlink migration we need to have different lkowner for each migration + * Filed a bug here: https://bugzilla.redhat.com/show_bug.cgi?id=1468202 to + * track the fix for this. Currently synclock takes care of synchronizing + * hardlink migration. Once this bug is fixed we can avoid taking synclock */ ret = syncop_inodelk (from, DHT_FILE_MIGRATE_DOMAIN, &tmp_loc, F_SETLKW, &flock, NULL, NULL); if (ret < 0) { @@ -2660,8 +2728,8 @@ gf_defrag_migrate_single_file (void *opaque) } UNLOCK (&defrag->lock); } else if (fop_errno != EEXIST) { - gf_msg (this->name, GF_LOG_ERROR, - DHT_MSG_MIGRATE_FILE_FAILED, fop_errno, + gf_msg (this->name, GF_LOG_ERROR, fop_errno, + DHT_MSG_MIGRATE_FILE_FAILED, "migrate-data failed for %s", entry_loc.path); LOCK (&defrag->lock); |