From 8e81cbacc53adc77bc4eabb5a26d6d13012f5f86 Mon Sep 17 00:00:00 2001 From: Anand Avati Date: Mon, 30 Jan 2012 15:03:56 +0530 Subject: fuse: fix resolver to handle graph switches properly perform resolution on the latest graph by caching it in state->itable and use fuse_nodeid as just a hint to the possible final resolved inode (in case it was resolved off the latest graph). GFID is the primary key for resolving inodes on the latest graph. Change-Id: I3921c6f59c9ff80e4ff076bec3bd334423fc36cc BUG: 785675 Reviewed-on: http://review.gluster.com/2703 Tested-by: Gluster Build System Reviewed-by: Amar Tumballi Reviewed-by: Anand Avati --- xlators/mount/fuse/src/fuse-resolve.c | 431 +++++++++++++++------------------- 1 file changed, 183 insertions(+), 248 deletions(-) (limited to 'xlators/mount/fuse/src/fuse-resolve.c') diff --git a/xlators/mount/fuse/src/fuse-resolve.c b/xlators/mount/fuse/src/fuse-resolve.c index 755e2f429..1af80b93c 100644 --- a/xlators/mount/fuse/src/fuse-resolve.c +++ b/xlators/mount/fuse/src/fuse-resolve.c @@ -46,8 +46,11 @@ fuse_resolve_loc_touchup (fuse_state_t *state) if (!loc->path) { if (loc->parent && resolve->bname) { ret = inode_path (loc->parent, resolve->bname, &path); + uuid_copy (loc->pargfid, loc->parent->gfid); + loc->name = resolve->bname; } else if (loc->inode) { ret = inode_path (loc->inode, NULL, &path); + uuid_copy (loc->gfid, loc->inode->gfid); } if (ret) gf_log (THIS->name, GF_LOG_TRACE, @@ -60,10 +63,10 @@ fuse_resolve_loc_touchup (fuse_state_t *state) int -fuse_resolve_gfid_entry_cbk (call_frame_t *frame, void *cookie, xlator_t *this, - int op_ret, int op_errno, inode_t *inode, - struct iatt *buf, dict_t *xattr, - struct iatt *postparent) +fuse_resolve_entry_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int op_ret, int op_errno, inode_t *inode, + struct iatt *buf, dict_t *xattr, + struct iatt *postparent) { fuse_state_t *state = NULL; fuse_resolve_t *resolve = NULL; @@ -88,13 +91,7 @@ fuse_resolve_gfid_entry_cbk (call_frame_t *frame, void *cookie, xlator_t *this, link_inode = inode_link (inode, resolve_loc->parent, resolve_loc->name, buf); - if (!link_inode) - goto out; - - inode_lookup (link_inode); - - inode_unref (link_inode); - + state->loc_now->inode = link_inode; out: loc_wipe (resolve_loc); @@ -103,6 +100,30 @@ out: } +int +fuse_resolve_entry (fuse_state_t *state) +{ + fuse_resolve_t *resolve = NULL; + loc_t *resolve_loc = NULL; + + resolve = state->resolve_now; + resolve_loc = &resolve->resolve_loc; + + resolve_loc->parent = inode_ref (state->loc_now->parent); + uuid_copy (resolve_loc->pargfid, state->loc_now->pargfid); + resolve_loc->name = resolve->bname; + resolve_loc->inode = inode_new (state->itable); + + inode_path (resolve_loc->parent, resolve_loc->name, + (char **) &resolve_loc->path); + + FUSE_FOP (state, fuse_resolve_entry_cbk, GF_FOP_LOOKUP, + lookup, resolve_loc, NULL); + + return 0; +} + + int fuse_resolve_gfid_cbk (call_frame_t *frame, void *cookie, xlator_t *this, int op_ret, int op_errno, inode_t *inode, struct iatt *buf, @@ -111,11 +132,11 @@ 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 *resolve_loc = NULL; + loc_t *loc_now = NULL; state = frame->root->state; resolve = state->resolve_now; - resolve_loc = &resolve->resolve_loc; + loc_now = state->loc_now; STACK_DESTROY (frame->root); @@ -123,36 +144,27 @@ fuse_resolve_gfid_cbk (call_frame_t *frame, void *cookie, xlator_t *this, gf_log (this->name, ((op_errno == ENOENT) ? GF_LOG_DEBUG : GF_LOG_WARNING), "%s: failed to resolve (%s)", - uuid_utoa (resolve_loc->gfid), strerror (op_errno)); + uuid_utoa (resolve->resolve_loc.gfid), + strerror (op_errno)); loc_wipe (&resolve->resolve_loc); goto out; } - loc_wipe (resolve_loc); + loc_wipe (&resolve->resolve_loc); link_inode = inode_link (inode, NULL, NULL, buf); if (!link_inode) goto out; - inode_lookup (link_inode); - - if (uuid_is_null (resolve->pargfid)) { - inode_unref (link_inode); - goto out; - } - - resolve_loc->parent = link_inode; - uuid_copy (resolve_loc->pargfid, resolve_loc->parent->gfid); + if (!uuid_is_null (resolve->gfid)) { + loc_now->inode = link_inode; + goto out; + } - resolve_loc->name = resolve->bname; - - resolve_loc->inode = inode_new (state->itable); - inode_path (resolve_loc->parent, resolve_loc->name, - (char **) &resolve_loc->path); + loc_now->parent = link_inode; - FUSE_FOP (state, fuse_resolve_gfid_entry_cbk, GF_FOP_LOOKUP, - lookup, &resolve->resolve_loc, NULL); + fuse_resolve_entry (state); return 0; out: @@ -173,15 +185,14 @@ fuse_resolve_gfid (fuse_state_t *state) if (!uuid_is_null (resolve->pargfid)) { uuid_copy (resolve_loc->gfid, resolve->pargfid); - resolve_loc->inode = inode_new (state->itable); - ret = inode_path (resolve_loc->inode, NULL, - (char **)&resolve_loc->path); } else if (!uuid_is_null (resolve->gfid)) { uuid_copy (resolve_loc->gfid, resolve->gfid); - resolve_loc->inode = inode_new (state->itable); - ret = inode_path (resolve_loc->inode, NULL, - (char **)&resolve_loc->path); } + + resolve_loc->inode = inode_new (state->itable); + ret = inode_path (resolve_loc->inode, NULL, + (char **)&resolve_loc->path); + if (ret <= 0) { gf_log (THIS->name, GF_LOG_WARNING, "failed to get the path from inode %s", @@ -189,122 +200,83 @@ fuse_resolve_gfid (fuse_state_t *state) } FUSE_FOP (state, fuse_resolve_gfid_cbk, GF_FOP_LOOKUP, - lookup, &resolve->resolve_loc, NULL); - - return 0; -} - - -int -fuse_resolve_continue (fuse_state_t *state) -{ - fuse_resolve_t *resolve = NULL; - int ret = 0; - - resolve = state->resolve_now; - - resolve->op_ret = 0; - resolve->op_errno = 0; - - /* TODO: should we handle 'fd' here ? */ - if (!uuid_is_null (resolve->pargfid)) - ret = fuse_resolve_entry_simple (state); - else if (!uuid_is_null (resolve->gfid)) - ret = fuse_resolve_inode_simple (state); - if (ret) - gf_log (THIS->name, GF_LOG_DEBUG, - "return value of resolve_*_simple %d", ret); - - fuse_resolve_loc_touchup (state); - - fuse_resolve_all (state); + lookup, resolve_loc, NULL); return 0; } /* - Check if the requirements are fulfilled by entries in the inode cache itself - Return value: - <= 0 - simple resolution was decisive and complete (either success or failure) - > 0 - indecisive, need to perform deep resolution -*/ + * Return value: + * 0 - resolved parent and entry (as necessary) + * -1 - resolved parent but not entry (though necessary) + * 1 - resolved neither parent nor entry + */ int -fuse_resolve_entry_simple (fuse_state_t *state) +fuse_resolve_parent_simple (fuse_state_t *state) { fuse_resolve_t *resolve = NULL; - inode_t *parent = NULL; - inode_t *inode = NULL; - int ret = 0; + loc_t *loc = NULL; + inode_t *parent = NULL; + inode_t *inode = NULL; resolve = state->resolve_now; + loc = state->loc_now; - parent = inode_find (state->itable, resolve->pargfid); - if (!parent) { - /* simple resolution is indecisive. need to perform - deep resolution */ - resolve->op_ret = -1; - resolve->op_errno = ENOENT; - ret = 1; - goto out; - } - - /* expected @parent was found from the inode cache */ - if (state->loc_now->parent) { - inode_unref (state->loc_now->parent); - } - - state->loc_now->parent = inode_ref (parent); + loc->name = resolve->bname; - inode = inode_grep (state->itable, parent, resolve->bname); - if (!inode) { - resolve->op_ret = -1; - resolve->op_errno = ENOENT; - ret = 1; - goto out; - } - - ret = 0; - - if (state->loc_now->inode) { - inode_unref (state->loc_now->inode); - state->loc_now->inode = NULL; - } + parent = resolve->parhint; + if (parent->table == state->itable) { + /* no graph switches since */ + loc->parent = inode_ref (parent); + loc->inode = inode_grep (state->itable, parent, loc->name); + /* decisive result - resolution success */ + return 0; + } - state->loc_now->inode = inode_ref (inode); - uuid_copy (state->loc_now->gfid, resolve->gfid); - -out: - if (parent) - inode_unref (parent); - - if (inode) - inode_unref (inode); - - return ret; + parent = inode_find (state->itable, resolve->pargfid); + if (!parent) { + resolve->op_ret = -1; + resolve->op_errno = ENOENT; + /* non decisive result - parent missing */ + return 1; + } + + loc->parent = parent; + + inode = inode_grep (state->itable, parent, loc->name); + if (inode) { + loc->inode = inode; + /* decisive result - resolution success */ + return 0; + } + + /* non decisive result - entry missing */ + return -1; } int -fuse_resolve_entry (fuse_state_t *state) +fuse_resolve_parent (fuse_state_t *state) { int ret = 0; loc_t *loc = NULL; loc = state->loc_now; - ret = fuse_resolve_entry_simple (state); + ret = fuse_resolve_parent_simple (state); if (ret > 0) { - loc_wipe (loc); fuse_resolve_gfid (state); return 0; } - if (ret == 0) - fuse_resolve_loc_touchup (state); + if (ret < 0) { + fuse_resolve_entry (state); + return 0; + } - fuse_resolve_all (state); + fuse_resolve_continue (state); return 0; } @@ -314,33 +286,29 @@ int fuse_resolve_inode_simple (fuse_state_t *state) { fuse_resolve_t *resolve = NULL; - inode_t *inode = NULL; - int ret = 0; + loc_t *loc = NULL; + inode_t *inode = NULL; resolve = state->resolve_now; + loc = state->loc_now; - inode = inode_find (state->itable, resolve->gfid); - if (!inode) { - resolve->op_ret = -1; - resolve->op_errno = ENOENT; - ret = 1; - goto out; - } - - ret = 0; - - if (state->loc_now->inode) { - inode_unref (state->loc_now->inode); - } - - state->loc_now->inode = inode_ref (inode); - uuid_copy (state->loc_now->gfid, resolve->gfid); + inode = resolve->hint; + if (inode->table == state->itable) { + inode_ref (inode); + goto found; + } -out: + inode = inode_find (state->itable, resolve->gfid); if (inode) - inode_unref (inode); + goto found; - return ret; + resolve->op_ret = -1; + resolve->op_errno = ENOENT; + + return 1; +found: + loc->inode = inode; + return 0; } @@ -355,15 +323,11 @@ fuse_resolve_inode (fuse_state_t *state) ret = fuse_resolve_inode_simple (state); if (ret > 0) { - loc_wipe (loc); fuse_resolve_gfid (state); return 0; } - if (ret == 0) - fuse_resolve_loc_touchup (state); - - fuse_resolve_all (state); + fuse_resolve_continue (state); return 0; } @@ -372,46 +336,87 @@ static int fuse_resolve_fd (fuse_state_t *state) { fuse_resolve_t *resolve = NULL; - fd_t *fd = NULL; - int ret = 0; - uint64_t tmp_fd_ctx = 0; - char *path = NULL; - char *name = NULL; + fd_t *fd = NULL; + xlator_t *active_subvol = NULL; resolve = state->resolve_now; fd = resolve->fd; + active_subvol = fd->inode->table->xl; - ret = fd_ctx_get (fd, state->this, &tmp_fd_ctx); - if (!ret) { - state->fd = (fd_t *)(long)tmp_fd_ctx; - fd_ref (state->fd); - fuse_resolve_all (state); + state->active_subvol = active_subvol; + + fuse_resolve_continue (state); + + return 0; +} + + +int +fuse_gfid_set (fuse_state_t *state) +{ + int ret = 0; + + if (uuid_is_null (state->gfid)) + goto out; + + if (!state->dict) + state->dict = dict_new (); + + if (!state->dict) { + ret = -1; goto out; } - ret = inode_path (fd->inode, 0, &path); - if (ret <= 0) - gf_log ("", GF_LOG_WARNING, - "failed to do inode-path on fd %d %s", ret, path); + ret = dict_set_static_bin (state->dict, "gfid-req", + state->gfid, sizeof (state->gfid)); +out: + return ret; +} - name = strrchr (path, '/'); - if (name) - name++; - resolve->path = path; - resolve->bname = gf_strdup (name); +int +fuse_resolve_entry_init (fuse_state_t *state, fuse_resolve_t *resolve, + ino_t par, char *name) +{ + inode_t *parent = NULL; - state->loc_now = &state->loc; + parent = fuse_ino_to_inode (par, state->this); + uuid_copy (resolve->pargfid, parent->gfid); + resolve->parhint = parent; + resolve->bname = gf_strdup (name); -out: - return 0; + return 0; +} + + +int +fuse_resolve_inode_init (fuse_state_t *state, fuse_resolve_t *resolve, + ino_t ino) +{ + inode_t *inode = NULL; + + inode = fuse_ino_to_inode (ino, state->this); + uuid_copy (resolve->gfid, inode->gfid); + resolve->hint = inode; + + return 0; +} + + +int +fuse_resolve_fd_init (fuse_state_t *state, fuse_resolve_t *resolve, + fd_t *fd) +{ + resolve->fd = fd_ref (fd); + + return 0; } static int fuse_resolve (fuse_state_t *state) - { +{ fuse_resolve_t *resolve = NULL; resolve = state->resolve_now; @@ -422,7 +427,7 @@ fuse_resolve (fuse_state_t *state) } else if (!uuid_is_null (resolve->pargfid)) { - fuse_resolve_entry (state); + fuse_resolve_parent (state); } else if (!uuid_is_null (resolve->gfid)) { @@ -445,17 +450,10 @@ fuse_resolve_done (fuse_state_t *state) { fuse_resume_fn_t fn = NULL; - if (state->resolve.op_ret || state->resolve2.op_ret) { - send_fuse_err (state->this, state->finh, - state->resolve.op_errno); - free_fuse_state (state); - goto out; - } fn = state->resume_fn; - if (fn) - fn (state); -out: + fn (state); + return 0; } @@ -495,87 +493,24 @@ fuse_resolve_all (fuse_state_t *state) int -fuse_gfid_set (fuse_state_t *state) +fuse_resolve_continue (fuse_state_t *state) { - int ret = 0; - - if (uuid_is_null (state->gfid)) - goto out; - - if (!state->dict) - state->dict = dict_new (); + fuse_resolve_loc_touchup (state); - if (!state->dict) { - ret = -1; - goto out; - } + fuse_resolve_all (state); - ret = dict_set_static_bin (state->dict, "gfid-req", - state->gfid, sizeof (state->gfid)); -out: - return ret; + return 0; } int fuse_resolve_and_resume (fuse_state_t *state, fuse_resume_fn_t fn) { - xlator_t *inode_xl = NULL; - xlator_t *active_xl = NULL; - fuse_gfid_set (state); state->resume_fn = fn; - active_xl = fuse_active_subvol (state->this); - inode_xl = fuse_state_subvol (state); - if (!inode_xl && state->loc.parent) - inode_xl = state->loc.parent->table->xl; - - /* If inode or fd is already in new graph, goto resume */ - if (inode_xl == active_xl) { - /* Lets move to resume if there is no other inode to check */ - if (!(state->loc2.parent || state->loc2.inode)) - goto resume; - - inode_xl = NULL; - /* We have to make sure both inodes we are - working on are in same inode table */ - if (state->loc2.inode) - inode_xl = state->loc2.inode->table->xl; - if (!inode_xl && state->loc2.parent) - inode_xl = state->loc2.parent->table->xl; - - if (inode_xl == active_xl) - goto resume; - } - - - /* If the resolve is for 'fd' and its open with 'write' flag - set, don't switch to new graph yet */ - - /* TODO: fix it later */ - /* if (state->fd && ((state->fd->flags & O_RDWR) || - (state->fd->flags & O_WRONLY))) - */ - if (state->fd) - goto resume; - - /* - if (state->fd) { - state->resolve.fd = state->fd; - state->fd = NULL; // TODO: we may need a 'fd_unref()' here, not very sure' - } - */ - - /* now we have to resolve the inode to 'itable' */ - state->itable = active_xl->itable; - fuse_resolve_all (state); - return 0; -resume: - fn (state); - return 0; } -- cgit