diff options
Diffstat (limited to 'xlators/mount/fuse/src/fuse-resolve.c')
| -rw-r--r-- | xlators/mount/fuse/src/fuse-resolve.c | 282 |
1 files changed, 239 insertions, 43 deletions
diff --git a/xlators/mount/fuse/src/fuse-resolve.c b/xlators/mount/fuse/src/fuse-resolve.c index abb11dbb1..8565ce0e4 100644 --- a/xlators/mount/fuse/src/fuse-resolve.c +++ b/xlators/mount/fuse/src/fuse-resolve.c @@ -1,22 +1,12 @@ /* - Copyright (c) 2010-2011 Gluster, Inc. <http://www.gluster.com> - This file is part of GlusterFS. - - GlusterFS is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. -*/ + Copyright (c) 2010-2012 Red Hat, Inc. <http://www.redhat.com> + This file is part of GlusterFS. + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. +*/ #ifndef _CONFIG_H #define _CONFIG_H #include "config.h" @@ -30,10 +20,14 @@ fuse_resolve_all (fuse_state_t *state); int fuse_resolve_continue (fuse_state_t *state); int fuse_resolve_entry_simple (fuse_state_t *state); int fuse_resolve_inode_simple (fuse_state_t *state); +int fuse_migrate_fd (xlator_t *this, fd_t *fd, xlator_t *old_subvol, + xlator_t *new_subvol); fuse_fd_ctx_t * fuse_fd_ctx_get (xlator_t *this, fd_t *fd); +gf_boolean_t fuse_inode_needs_lookup (inode_t *inode, xlator_t *this); + static int fuse_resolve_loc_touchup (fuse_state_t *state) { @@ -96,6 +90,7 @@ fuse_resolve_entry_cbk (call_frame_t *frame, void *cookie, xlator_t *this, resolve_loc->name, buf); state->loc_now->inode = link_inode; + out: loc_wipe (resolve_loc); @@ -130,8 +125,8 @@ fuse_resolve_entry (fuse_state_t *state) 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, - dict_t *xattr, struct iatt *postparent) + 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; @@ -151,7 +146,19 @@ fuse_resolve_gfid_cbk (call_frame_t *frame, void *cookie, xlator_t *this, uuid_utoa (resolve->resolve_loc.gfid), strerror (op_errno)); loc_wipe (&resolve->resolve_loc); - resolve->op_ret = -1; + + /* resolve->op_ret can have 3 values: 0, -1, -2. + * 0 : resolution was successful. + * -1: parent inode could not be resolved. + * -2: entry (inode corresponding to path) could not be resolved + */ + + if (uuid_is_null (resolve->gfid)) { + resolve->op_ret = -1; + } else { + resolve->op_ret = -2; + } + resolve->op_errno = op_errno; goto out; } @@ -196,13 +203,16 @@ fuse_resolve_gfid (fuse_state_t *state) 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); + /* inode may already exist in case we are looking up an inode which was + linked through readdirplus */ + 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); if (ret <= 0) { gf_log (THIS->name, GF_LOG_WARNING, - "failed to get the path from inode %s", + "failed to get the path for inode %s", uuid_utoa (resolve->gfid)); } @@ -235,9 +245,26 @@ fuse_resolve_parent_simple (fuse_state_t *state) parent = resolve->parhint; if (parent->table == state->itable) { + if (fuse_inode_needs_lookup (parent, THIS)) + return 1; + /* no graph switches since */ loc->parent = inode_ref (parent); + uuid_copy (loc->pargfid, parent->gfid); loc->inode = inode_grep (state->itable, parent, loc->name); + + /* nodeid for root is 1 and we blindly take the latest graph's + * table->root as the parhint and because of this there is + * ambiguity whether the entry should have existed or not, and + * we took the conservative approach of assuming entry should + * have been there even though it need not have (bug #804592). + */ + if ((loc->inode == NULL) + && __is_root_gfid (parent->gfid)) { + /* non decisive result - entry missing */ + return -1; + } + /* decisive result - resolution success */ return 0; } @@ -247,6 +274,10 @@ fuse_resolve_parent_simple (fuse_state_t *state) /* non decisive result - parent missing */ return 1; } + if (fuse_inode_needs_lookup (parent, THIS)) { + inode_unref (parent); + return 1; + } loc->parent = parent; uuid_copy (loc->pargfid, resolve->pargfid); @@ -296,15 +327,18 @@ fuse_resolve_inode_simple (fuse_state_t *state) loc = state->loc_now; inode = resolve->hint; - if (inode->table == state->itable) { + if (inode->table == state->itable) inode_ref (inode); - goto found; + else + inode = inode_find (state->itable, resolve->gfid); + + if (inode) { + if (!fuse_inode_needs_lookup (inode, THIS)) + goto found; + /* inode was linked through readdirplus */ + inode_unref (inode); } - inode = inode_find (state->itable, resolve->gfid); - if (inode) - goto found; - return 1; found: loc->inode = inode; @@ -329,39 +363,201 @@ fuse_resolve_inode (fuse_state_t *state) return 0; } + +int +fuse_migrate_fd_task (void *data) +{ + int ret = -1; + fuse_state_t *state = NULL; + fd_t *basefd = NULL, *oldfd = NULL; + fuse_fd_ctx_t *basefd_ctx = NULL; + xlator_t *old_subvol = NULL; + + state = data; + if (state == NULL) { + goto out; + } + + basefd = state->fd; + + basefd_ctx = fuse_fd_ctx_get (state->this, basefd); + + LOCK (&basefd->lock); + { + oldfd = basefd_ctx->activefd ? basefd_ctx->activefd : basefd; + fd_ref (oldfd); + } + UNLOCK (&basefd->lock); + + old_subvol = oldfd->inode->table->xl; + + ret = fuse_migrate_fd (state->this, basefd, old_subvol, + state->active_subvol); + + LOCK (&basefd->lock); + { + if (ret < 0) { + basefd_ctx->migration_failed = 1; + } else { + basefd_ctx->migration_failed = 0; + } + } + UNLOCK (&basefd->lock); + + ret = 0; + +out: + if (oldfd) + fd_unref (oldfd); + + return ret; +} + + +static inline int +fuse_migrate_fd_error (xlator_t *this, fd_t *fd) +{ + fuse_fd_ctx_t *fdctx = NULL; + char error = 0; + + fdctx = fuse_fd_ctx_get (this, fd); + if (fdctx != NULL) { + if (fdctx->migration_failed) { + error = 1; + } + } + + return error; +} + +#define FUSE_FD_GET_ACTIVE_FD(activefd, basefd) \ + do { \ + LOCK (&basefd->lock); \ + { \ + activefd = basefd_ctx->activefd ? \ + basefd_ctx->activefd : basefd; \ + if (activefd != basefd) { \ + fd_ref (activefd); \ + } \ + } \ + UNLOCK (&basefd->lock); \ + \ + if (activefd == basefd) { \ + fd_ref (activefd); \ + } \ + } while (0); + + static int fuse_resolve_fd (fuse_state_t *state) { - fuse_resolve_t *resolve = NULL; - fd_t *fd = NULL; - xlator_t *active_subvol = NULL; - fuse_fd_ctx_t *fdctx = NULL; + fuse_resolve_t *resolve = NULL; + fd_t *basefd = NULL, *activefd = NULL; + xlator_t *active_subvol = NULL, *this = NULL; + int ret = 0; + char fd_migration_error = 0; + fuse_fd_ctx_t *basefd_ctx = NULL; resolve = state->resolve_now; - fd = resolve->fd; - active_subvol = fd->inode->table->xl; + this = state->this; - if (state->active_subvol != active_subvol) { + basefd = resolve->fd; + basefd_ctx = fuse_fd_ctx_get (this, basefd); + if (basefd_ctx == NULL) { + gf_log (state->this->name, GF_LOG_WARNING, + "fdctx is NULL for basefd (ptr:%p inode-gfid:%s), " + "resolver erroring out with errno EINVAL", + basefd, uuid_utoa (basefd->inode->gfid)); resolve->op_ret = -1; - resolve->op_errno = EBADF; + resolve->op_errno = EINVAL; + goto resolve_continue; } - fdctx = fuse_fd_ctx_get (state->this, fd); - if (fdctx != NULL) { - if (fdctx->migration_failed) { + FUSE_FD_GET_ACTIVE_FD (activefd, basefd); + + active_subvol = activefd->inode->table->xl; + + fd_migration_error = fuse_migrate_fd_error (state->this, basefd); + if (fd_migration_error) { + resolve->op_ret = -1; + resolve->op_errno = EBADF; + } else if (state->active_subvol != active_subvol) { + ret = synctask_new (state->this->ctx->env, fuse_migrate_fd_task, + NULL, NULL, state); + + fd_migration_error = fuse_migrate_fd_error (state->this, + basefd); + fd_unref (activefd); + + FUSE_FD_GET_ACTIVE_FD (activefd, basefd); + active_subvol = activefd->inode->table->xl; + + if ((ret == -1) || fd_migration_error + || (state->active_subvol != active_subvol)) { + if (ret == -1) { + gf_log (state->this->name, GF_LOG_WARNING, + "starting sync-task to migrate " + "basefd (ptr:%p inode-gfid:%s) failed " + "(old-subvolume:%s-%d " + "new-subvolume:%s-%d)", + basefd, + uuid_utoa (basefd->inode->gfid), + active_subvol->name, + active_subvol->graph->id, + state->active_subvol->name, + state->active_subvol->graph->id); + } else { + gf_log (state->this->name, GF_LOG_WARNING, + "fd migration of basefd " + "(ptr:%p inode-gfid:%s) failed " + "(old-subvolume:%s-%d " + "new-subvolume:%s-%d)", + basefd, + uuid_utoa (basefd->inode->gfid), + active_subvol->name, + active_subvol->graph->id, + state->active_subvol->name, + state->active_subvol->graph->id); + } + resolve->op_ret = -1; resolve->op_errno = EBADF; + } else { + gf_log (state->this->name, GF_LOG_DEBUG, + "basefd (ptr:%p inode-gfid:%s) migrated " + "successfully in resolver " + "(old-subvolume:%s-%d new-subvolume:%s-%d)", + basefd, uuid_utoa (basefd->inode->gfid), + active_subvol->name, active_subvol->graph->id, + state->active_subvol->name, + state->active_subvol->graph->id); } } if ((resolve->op_ret == -1) && (resolve->op_errno == EBADF)) { - gf_log ("fuse-resolve", GF_LOG_WARNING, "migration of fd (%p) " - "did not complete, failing fop with EBADF", fd); + gf_log ("fuse-resolve", GF_LOG_WARNING, + "migration of basefd (ptr:%p inode-gfid:%s) " + "did not complete, failing fop with EBADF " + "(old-subvolume:%s-%d new-subvolume:%s-%d)", basefd, + uuid_utoa (basefd->inode->gfid), + active_subvol->name, active_subvol->graph->id, + state->active_subvol->name, + state->active_subvol->graph->id); + } + + if (activefd != basefd) { + state->fd = fd_ref (activefd); + fd_unref (basefd); } /* state->active_subvol = active_subvol; */ +resolve_continue: + if (activefd != NULL) { + fd_unref (activefd); + } + fuse_resolve_continue (state); return 0; |
