summaryrefslogtreecommitdiffstats
path: root/xlators
diff options
context:
space:
mode:
Diffstat (limited to 'xlators')
-rw-r--r--xlators/cluster/dht/src/dht-common.h3
-rw-r--r--xlators/cluster/dht/src/dht-rebalance.c94
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);