summaryrefslogtreecommitdiffstats
path: root/xlators/cluster
diff options
context:
space:
mode:
Diffstat (limited to 'xlators/cluster')
-rw-r--r--xlators/cluster/dht/src/dht-common.c76
-rw-r--r--xlators/cluster/dht/src/dht-common.h6
-rw-r--r--xlators/cluster/dht/src/dht-helper.c171
3 files changed, 246 insertions, 7 deletions
diff --git a/xlators/cluster/dht/src/dht-common.c b/xlators/cluster/dht/src/dht-common.c
index 79ba77bf16c..6af55d5d42e 100644
--- a/xlators/cluster/dht/src/dht-common.c
+++ b/xlators/cluster/dht/src/dht-common.c
@@ -212,17 +212,22 @@ out:
return ret;
}
-
int
dht_discover_complete (xlator_t *this, call_frame_t *discover_frame)
{
- dht_local_t *local = NULL;
- call_frame_t *main_frame = NULL;
- int op_errno = 0;
- int ret = -1;
- dht_layout_t *layout = NULL;
- dht_conf_t *conf = NULL;
+ dht_local_t *local = NULL;
+ dht_local_t *heal_local = NULL;
+ call_frame_t *main_frame = NULL;
+ call_frame_t *heal_frame = NULL;
+ int op_errno = 0;
+ int ret = -1;
+ dht_layout_t *layout = NULL;
+ dht_conf_t *conf = NULL;
uint32_t vol_commit_hash = 0;
+ xlator_t *source = NULL;
+ int heal_path = 0;
+ int i = 0;
+ loc_t loc = {0 };
local = discover_frame->local;
layout = local->layout;
@@ -301,6 +306,63 @@ dht_discover_complete (xlator_t *this, call_frame_t *discover_frame)
}
}
+ if (IA_ISDIR (local->stbuf.ia_type)) {
+ for (i = 0; i < layout->cnt; i++) {
+ if (!source && !layout->list[i].err)
+ source = layout->list[i].xlator;
+ if (layout->list[i].err == ENOENT ||
+ layout->list[i].err == ESTALE) {
+ heal_path = 1;
+ }
+ if (source && heal_path)
+ break;
+ }
+ }
+ if (source && heal_path) {
+ gf_uuid_copy (loc.gfid, local->gfid);
+ if (gf_uuid_is_null (loc.gfid)) {
+ goto done;
+ }
+
+ if (local->inode)
+ loc.inode = inode_ref (local->inode);
+ else
+ goto done;
+
+ heal_frame = create_frame (this, this->ctx->pool);
+ if (heal_frame) {
+ heal_local = dht_local_init (heal_frame, &loc,
+ NULL, 0);
+ if (!heal_local)
+ goto cleanup;
+
+ gf_uuid_copy (heal_local->gfid, local->gfid);
+ heal_frame->cookie = source;
+ heal_local->xattr = dict_ref (local->xattr);
+ heal_local->stbuf = local->stbuf;
+ heal_local->postparent = local->postparent;
+ heal_local->inode = inode_ref (loc.inode);
+ heal_local->main_frame = main_frame;
+ FRAME_SU_DO (heal_frame, dht_local_t);
+ ret = synctask_new (this->ctx->env,
+ dht_heal_full_path,
+ dht_heal_full_path_done,
+ heal_frame, heal_frame);
+ if (!ret) {
+ loc_wipe (&loc);
+ return 0;
+ }
+ /*
+ * Failed to spawn the synctask. Returning
+ * with out doing heal.
+ */
+cleanup:
+ loc_wipe (&loc);
+ DHT_STACK_DESTROY (heal_frame);
+ }
+
+ }
+done:
DHT_STACK_UNWIND (lookup, main_frame, local->op_ret, local->op_errno,
local->inode, &local->stbuf, local->xattr,
&local->postparent);
diff --git a/xlators/cluster/dht/src/dht-common.h b/xlators/cluster/dht/src/dht-common.h
index 6483b2e86d7..392d2cf163a 100644
--- a/xlators/cluster/dht/src/dht-common.h
+++ b/xlators/cluster/dht/src/dht-common.h
@@ -1106,6 +1106,12 @@ int
dht_layout_sort (dht_layout_t *layout);
int
+dht_heal_full_path (void *data);
+
+int
+dht_heal_full_path_done (int op_ret, call_frame_t *frame, void *data);
+
+int
dht_layout_missing_dirs (dht_layout_t *layout);
int
diff --git a/xlators/cluster/dht/src/dht-helper.c b/xlators/cluster/dht/src/dht-helper.c
index 6d00ce68909..49f087b3ec9 100644
--- a/xlators/cluster/dht/src/dht-helper.c
+++ b/xlators/cluster/dht/src/dht-helper.c
@@ -1917,3 +1917,174 @@ out:
return -1;
}
+inode_t*
+dht_heal_path (xlator_t *this, char *path, inode_table_t *itable)
+{
+ int ret = -1;
+ struct iatt iatt = {0, };
+ inode_t *linked_inode = NULL;
+ loc_t loc = {0, };
+ char *bname = NULL;
+ char *save_ptr = NULL;
+ uuid_t gfid = {0, };
+ char *tmp_path = NULL;
+
+
+ tmp_path = gf_strdup (path);
+ if (!tmp_path) {
+ goto out;
+ }
+
+ memset (gfid, 0, 16);
+ gfid[15] = 1;
+
+ gf_uuid_copy (loc.pargfid, gfid);
+ loc.parent = inode_ref (itable->root);
+
+ bname = strtok_r (tmp_path, "/", &save_ptr);
+
+ /* sending a lookup on parent directory,
+ * Eg: if path is like /a/b/c/d/e/f/g/
+ * then we will send a lookup on a first and then b,c,d,etc
+ */
+
+ while (bname) {
+ linked_inode = NULL;
+ loc.inode = inode_grep (itable, loc.parent, bname);
+ if (loc.inode == NULL) {
+ loc.inode = inode_new (itable);
+ if (loc.inode == NULL) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ } else {
+ /*
+ * Inode is already populated in the inode table.
+ * Which means we already looked up the inde and
+ * linked with a dentry. So that we will skip
+ * lookup on this entry, and proceed to next.
+ */
+ bname = strtok_r (NULL, "/", &save_ptr);
+ inode_unref (loc.parent);
+ loc.parent = loc.inode;
+ gf_uuid_copy (loc.pargfid, loc.inode->gfid);
+ loc.inode = NULL;
+ continue;
+ }
+
+ loc.name = bname;
+ ret = loc_path (&loc, bname);
+
+ ret = syncop_lookup (this, &loc, &iatt, NULL, NULL, NULL);
+ if (ret) {
+ gf_msg (this->name, GF_LOG_INFO, -ret,
+ DHT_MSG_DIR_SELFHEAL_FAILED,
+ "Healing of path %s failed on subvolume %s for "
+ "directory %s", path, this->name, bname);
+ goto out;
+ }
+
+ linked_inode = inode_link (loc.inode, loc.parent, bname, &iatt);
+ if (!linked_inode)
+ goto out;
+
+ loc_wipe (&loc);
+ gf_uuid_copy (loc.pargfid, linked_inode->gfid);
+ loc.inode = NULL;
+ loc.parent = linked_inode;
+
+ bname = strtok_r (NULL, "/", &save_ptr);
+ }
+out:
+ inode_ref (linked_inode);
+ loc_wipe (&loc);
+ GF_FREE (tmp_path);
+
+ return linked_inode;
+}
+
+
+int
+dht_heal_full_path (void *data)
+{
+ call_frame_t *heal_frame = data;
+ dht_local_t *local = NULL;
+ loc_t loc = {0, };
+ dict_t *dict = NULL;
+ char *path = NULL;
+ int ret = -1;
+ xlator_t *source = NULL;
+ xlator_t *this = NULL;
+ inode_table_t *itable = NULL;
+ inode_t *inode = NULL;
+ inode_t *tmp_inode = NULL;
+
+ GF_VALIDATE_OR_GOTO ("DHT", heal_frame, out);
+
+ local = heal_frame->local;
+ this = heal_frame->this;
+ source = heal_frame->cookie;
+ heal_frame->cookie = NULL;
+ gf_uuid_copy (loc.gfid, local->gfid);
+
+ if (local->loc.inode)
+ loc.inode = inode_ref (local->loc.inode);
+ else
+ goto out;
+
+ itable = loc.inode->table;
+ ret = syncop_getxattr (source, &loc, &dict,
+ GET_ANCESTRY_PATH_KEY, NULL, NULL);
+ if (ret) {
+ gf_msg (this->name, GF_LOG_INFO, -ret,
+ DHT_MSG_DIR_SELFHEAL_FAILED,
+ "Failed to get path from subvol %s. Aborting "
+ "directory healing.", source->name);
+ goto out;
+ }
+
+ ret = dict_get_str (dict, GET_ANCESTRY_PATH_KEY, &path);
+ if (path) {
+ inode = dht_heal_path (this, path, itable);
+ if (inode && inode != local->inode) {
+ /*
+ * if inode returned by heal function is different
+ * from what we passed, which means a racing thread
+ * already linked a different inode for dentry.
+ * So we will update our local->inode, so that we can
+ * retrurn proper inode.
+ */
+ tmp_inode = local->inode;
+ local->inode = inode;
+ inode_unref (tmp_inode);
+ tmp_inode = NULL;
+ } else {
+ inode_unref (inode);
+ }
+ }
+
+out:
+ loc_wipe (&loc);
+ if (dict)
+ dict_unref (dict);
+ return 0;
+}
+
+int
+dht_heal_full_path_done (int op_ret, call_frame_t *heal_frame, void *data)
+{
+
+ call_frame_t *main_frame = NULL;
+ dht_local_t *local = NULL;
+
+ local = heal_frame->local;
+ main_frame = local->main_frame;
+ local->main_frame = NULL;
+
+ DHT_STACK_UNWIND (lookup, main_frame, 0, 0,
+ local->inode, &local->stbuf, local->xattr,
+ &local->postparent);
+
+ DHT_STACK_DESTROY (heal_frame);
+ return 0;
+}