From d0edb6d555d687f76837515207b9408be0bdd55e Mon Sep 17 00:00:00 2001 From: Mohammed Rafi KC Date: Mon, 5 Oct 2015 21:36:14 +0530 Subject: fuse: resolve complete path after a graph switch If a graph switch has happended as part of a attach-tier, then there is a chance to hash fops to newly added brick before fix-layout. This causes on going i/o to fail. This patch will resolve a path, for graph switch by sending recursive lookup to the parent directories. Those lookups will help to heal the directory. Change-Id: Ia2bb4b43a21e5cc6875ba1205628744c3f0ce4e5 BUG: 1263549 Signed-off-by: Mohammed Rafi KC Reviewed-on: http://review.gluster.org/12184 Tested-by: NetBSD Build System Tested-by: Dan Lambright Reviewed-by: Dan Lambright --- xlators/mount/fuse/src/fuse-bridge.c | 49 ++++++++++++--- xlators/mount/fuse/src/fuse-bridge.h | 7 +++ xlators/mount/fuse/src/fuse-resolve.c | 113 +++++++++++++++++++++++++++++++--- xlators/storage/posix/src/posix.c | 6 +- 4 files changed, 156 insertions(+), 19 deletions(-) diff --git a/xlators/mount/fuse/src/fuse-bridge.c b/xlators/mount/fuse/src/fuse-bridge.c index fd07f5f0def..bf63697233b 100644 --- a/xlators/mount/fuse/src/fuse-bridge.c +++ b/xlators/mount/fuse/src/fuse-bridge.c @@ -4150,18 +4150,21 @@ fuse_first_lookup (xlator_t *this) int -fuse_nameless_lookup (xlator_t *xl, uuid_t gfid, loc_t *loc) +fuse_nameless_lookup (xlator_t *xl, uuid_t gfid, loc_t *loc, + gf_boolean_t resolve_path) { int ret = -1; dict_t *xattr_req = NULL; struct iatt iatt = {0, }; inode_t *linked_inode = NULL; + inode_t *inode = NULL; + char *path = NULL; + dict_t *xattr_ret = NULL; if ((loc == NULL) || (xl == NULL)) { ret = -EINVAL; goto out; } - if (loc->inode == NULL) { loc->inode = inode_new (xl->itable); if (loc->inode == NULL) { @@ -4171,6 +4174,9 @@ fuse_nameless_lookup (xlator_t *xl, uuid_t gfid, loc_t *loc) } gf_uuid_copy (loc->gfid, gfid); + if (gf_uuid_is_null (loc->gfid)) { + goto out; + } xattr_req = dict_new (); if (xattr_req == NULL) { @@ -4178,20 +4184,42 @@ fuse_nameless_lookup (xlator_t *xl, uuid_t gfid, loc_t *loc) goto out; } - ret = syncop_lookup (xl, loc, &iatt, NULL, xattr_req, NULL); + if (resolve_path) { + /* + * setting virtual xattr glusterfs.ancestry.path to get + * the path of the parent directory. + */ + ret = dict_set_int32 (xattr_req, GET_ANCESTRY_PATH_KEY, 42); + if (ret) + goto out; + } + + ret = syncop_lookup (xl, loc, &iatt, NULL, xattr_req, &xattr_ret); if (ret < 0) goto out; - linked_inode = inode_link (loc->inode, NULL, NULL, &iatt); - inode_unref (loc->inode); - loc->inode = linked_inode; - + if (resolve_path) { + ret = dict_get_str (xattr_ret, GET_ANCESTRY_PATH_KEY, &path); + } + if (path) { + inode = loc->inode; + loc->inode = fuse_resolve_path (xl, path); + inode_unref (inode); + } else { + linked_inode = inode_link (loc->inode, NULL, NULL, &iatt); + inode_unref (loc->inode); + loc->inode = linked_inode; + } ret = 0; out: if (xattr_req != NULL) { dict_unref (xattr_req); } + if (xattr_ret) { + dict_unref (xattr_ret); + } + return ret; } @@ -4222,8 +4250,13 @@ fuse_migrate_fd_open (xlator_t *this, fd_t *basefd, fd_t *oldfd, loc.inode = inode_find (new_subvol->itable, basefd->inode->gfid); if (loc.inode == NULL) { + + /* setting the get_resolve_path to send lookup + * on parent directories + * */ + ret = fuse_nameless_lookup (new_subvol, basefd->inode->gfid, - &loc); + &loc, _gf_true); if (ret < 0) { gf_log ("glusterfs-fuse", GF_LOG_WARNING, "name-less lookup of gfid (%s) failed (%s)" diff --git a/xlators/mount/fuse/src/fuse-bridge.h b/xlators/mount/fuse/src/fuse-bridge.h index 850eeb60ea8..ea346c05f9e 100644 --- a/xlators/mount/fuse/src/fuse-bridge.h +++ b/xlators/mount/fuse/src/fuse-bridge.h @@ -401,6 +401,9 @@ int fuse_flip_xattr_ns (struct fuse_private *priv, char *okey, char **nkey); fuse_fd_ctx_t * __fuse_fd_ctx_check_n_create (xlator_t *this, fd_t *fd); fuse_fd_ctx_t * fuse_fd_ctx_check_n_create (xlator_t *this, fd_t *fd); +inode_t* +fuse_resolve_path (xlator_t *this, char *path); + int fuse_resolve_and_resume (fuse_state_t *state, fuse_resume_fn_t fn); int fuse_resolve_inode_init (fuse_state_t *state, fuse_resolve_t *resolve, ino_t ino); @@ -408,6 +411,10 @@ int fuse_resolve_entry_init (fuse_state_t *state, fuse_resolve_t *resolve, ino_t par, char *name); int fuse_resolve_fd_init (fuse_state_t *state, fuse_resolve_t *resolve, fd_t *fd); +int +fuse_nameless_lookup (xlator_t *xl, uuid_t gfid, loc_t *loc, + gf_boolean_t resolve_path); + int fuse_ignore_xattr_set (fuse_private_t *priv, char *key); void fuse_fop_resume (fuse_state_t *state); int dump_history_fuse (circular_buffer_t *cb, void *data); diff --git a/xlators/mount/fuse/src/fuse-resolve.c b/xlators/mount/fuse/src/fuse-resolve.c index 7e9014cf2bf..a46e1f0b5dc 100644 --- a/xlators/mount/fuse/src/fuse-resolve.c +++ b/xlators/mount/fuse/src/fuse-resolve.c @@ -77,16 +77,36 @@ out: int -fuse_resolve_entry (fuse_state_t *state) +fuse_resolve_entry (fuse_state_t *state, gf_boolean_t resolve_path) { - fuse_resolve_t *resolve = NULL; - loc_t *resolve_loc = NULL; + fuse_resolve_t *resolve = NULL; + loc_t *resolve_loc = NULL; + loc_t tmp_loc = {0, }; + uuid_t gfid = {0, }; + inode_t *parent = NULL; resolve = state->resolve_now; resolve_loc = &resolve->resolve_loc; - resolve_loc->parent = inode_ref (state->loc_now->parent); + parent = resolve->parhint ? resolve->parhint : resolve->hint; + gf_uuid_copy (resolve_loc->pargfid, state->loc_now->pargfid); + + if (parent && parent->table != state->itable && resolve_path) { + /* graph switch happened */ + if (!gf_uuid_is_null (resolve->pargfid)) { + gf_uuid_copy (gfid, resolve->pargfid); + } else if (!gf_uuid_is_null (resolve->gfid)) { + gf_uuid_copy (gfid, resolve->gfid); + } + + /* sending lookup on parent directories */ + fuse_nameless_lookup (state->active_subvol, + gfid, + &tmp_loc, _gf_true); + } + + resolve_loc->parent = inode_ref (state->loc_now->parent); resolve_loc->name = resolve->bname; resolve_loc->inode = inode_new (state->itable); @@ -108,7 +128,7 @@ fuse_resolve_gfid_cbk (call_frame_t *frame, void *cookie, xlator_t *this, fuse_state_t *state = NULL; fuse_resolve_t *resolve = NULL; inode_t *link_inode = NULL; - loc_t *loc_now = NULL; + loc_t *loc_now = NULL; state = frame->root->state; resolve = state->resolve_now; @@ -155,7 +175,7 @@ fuse_resolve_gfid_cbk (call_frame_t *frame, void *cookie, xlator_t *this, loc_now->parent = link_inode; gf_uuid_copy (loc_now->pargfid, link_inode->gfid); - fuse_resolve_entry (state); + fuse_resolve_entry (state, _gf_false); return 0; out: @@ -163,6 +183,73 @@ out: return 0; } +inode_t* +fuse_resolve_path (xlator_t *this, char *path) +{ + int ret = -1; + dict_t *xattr_req = NULL; + 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); + + memset (gfid, 0, 16); + gfid[15] = 1; + + gf_uuid_copy (loc.pargfid, gfid); + loc.parent = inode_ref (this->itable->root); + + xattr_req = dict_new (); + if (xattr_req == NULL) { + ret = -ENOMEM; + goto out; + } + + 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) { + loc.inode = inode_grep (this->itable, loc.parent, bname); + if (loc.inode == NULL) { + loc.inode = inode_new (this->itable); + if (loc.inode == NULL) { + ret = -ENOMEM; + goto out; + } + } + + loc.name = bname; + ret = loc_path (&loc, bname); + + ret = syncop_lookup (this, &loc, &iatt, NULL, xattr_req, NULL); + if (ret) + 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); + } + return linked_inode; +out: + return NULL; +} int fuse_resolve_gfid (fuse_state_t *state) @@ -170,10 +257,13 @@ fuse_resolve_gfid (fuse_state_t *state) fuse_resolve_t *resolve = NULL; loc_t *resolve_loc = NULL; int ret = 0; + loc_t tmp_loc = {0, }; + inode_t *inode = NULL; resolve = state->resolve_now; resolve_loc = &resolve->resolve_loc; + if (!gf_uuid_is_null (resolve->pargfid)) { gf_uuid_copy (resolve_loc->gfid, resolve->pargfid); } else if (!gf_uuid_is_null (resolve->gfid)) { @@ -185,14 +275,21 @@ fuse_resolve_gfid (fuse_state_t *state) resolve_loc->inode = inode_find (state->itable, resolve_loc->gfid); if (!resolve_loc->inode) resolve_loc->inode = inode_new (state->itable); - ret = loc_path (resolve_loc, NULL); + ret = loc_path (resolve_loc, NULL); if (ret <= 0) { gf_log (THIS->name, GF_LOG_WARNING, "failed to get the path for inode %s", uuid_utoa (resolve->gfid)); } + inode = resolve->parhint ? resolve->parhint : resolve->hint; + if (inode && inode->table != state->itable) { + /* sending lookup on parent directories */ + fuse_nameless_lookup (state->active_subvol, resolve_loc->gfid, + &tmp_loc, _gf_true); + } + FUSE_FOP (state, fuse_resolve_gfid_cbk, GF_FOP_LOOKUP, lookup, resolve_loc, NULL); @@ -283,7 +380,7 @@ fuse_resolve_parent (fuse_state_t *state) } if (ret < 0) { - fuse_resolve_entry (state); + fuse_resolve_entry (state, _gf_true); return 0; } diff --git a/xlators/storage/posix/src/posix.c b/xlators/storage/posix/src/posix.c index ad3ecf719fb..bc4e4904b74 100644 --- a/xlators/storage/posix/src/posix.c +++ b/xlators/storage/posix/src/posix.c @@ -3802,14 +3802,14 @@ posix_get_ancestry (xlator_t *this, inode_t *leaf_inode, priv = this->private; - if (!priv->update_pgfid_nlinks) - goto out; - if (IA_ISDIR (leaf_inode->ia_type)) { ret = posix_get_ancestry_directory (this, leaf_inode, head, path, type, op_errno, xdata); } else { + + if (!priv->update_pgfid_nlinks) + goto out; ret = posix_get_ancestry_non_directory (this, leaf_inode, head, path, type, op_errno, xdata); -- cgit