diff options
Diffstat (limited to 'xlators/mount')
-rw-r--r-- | xlators/mount/fuse/src/Makefile.am | 11 | ||||
-rw-r--r-- | xlators/mount/fuse/src/fuse-bridge.c | 1292 | ||||
-rw-r--r-- | xlators/mount/fuse/src/fuse-bridge.h | 277 | ||||
-rw-r--r-- | xlators/mount/fuse/src/fuse-helpers.c | 300 | ||||
-rw-r--r-- | xlators/mount/fuse/src/fuse-resolve.c | 747 |
5 files changed, 1889 insertions, 738 deletions
diff --git a/xlators/mount/fuse/src/Makefile.am b/xlators/mount/fuse/src/Makefile.am index 58e33a4e116..66d044e32f9 100644 --- a/xlators/mount/fuse/src/Makefile.am +++ b/xlators/mount/fuse/src/Makefile.am @@ -1,6 +1,7 @@ noinst_HEADERS = $(CONTRIBDIR)/fuse-include/fuse_kernel.h\ $(CONTRIBDIR)/fuse-include/fuse-mount.h\ - $(CONTRIBDIR)/fuse-include/fuse-misc.h fuse-mem-types.h + $(CONTRIBDIR)/fuse-include/fuse-misc.h fuse-mem-types.h \ + fuse-bridge.h xlator_LTLIBRARIES = fuse.la xlatordir = $(libdir)/glusterfs/$(PACKAGE_VERSION)/xlator/mount @@ -11,8 +12,9 @@ else mount_source=$(CONTRIBDIR)/fuse-lib/mount.c endif -fuse_la_SOURCES = fuse-bridge.c $(CONTRIBDIR)/fuse-lib/misc.c \ - $(mount_source) +fuse_la_SOURCES = fuse-helpers.c fuse-resolve.c fuse-bridge.c \ + $(CONTRIBDIR)/fuse-lib/misc.c $(mount_source) + fuse_la_LDFLAGS = -module -avoidversion -shared -nostartfiles AM_CFLAGS = -fPIC -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -D$(GF_HOST_OS) -Wall \ @@ -20,5 +22,4 @@ AM_CFLAGS = -fPIC -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -D$(GF_HOST_OS) -Wall \ -I$(top_srcdir)/glusterfsd/src $(GF_CFLAGS) $(GF_FUSE_CFLAGS) -CLEANFILES = - +CLEANFILES = diff --git a/xlators/mount/fuse/src/fuse-bridge.c b/xlators/mount/fuse/src/fuse-bridge.c index b1de4692a10..ea5b5ae38ad 100644 --- a/xlators/mount/fuse/src/fuse-bridge.c +++ b/xlators/mount/fuse/src/fuse-bridge.c @@ -25,283 +25,11 @@ * fuse_loc_fill() and inode_path() return success/failure. */ - -#include <stdint.h> -#include <signal.h> -#include <pthread.h> -#include <stddef.h> -#include <dirent.h> -#include <sys/mount.h> -#include <sys/time.h> - -#ifndef _CONFIG_H -#define _CONFIG_H -#include "config.h" -#endif /* _CONFIG_H */ - -#include "glusterfs.h" -#include "logging.h" -#include "xlator.h" -#include "defaults.h" -#include "common-utils.h" -#include "glusterfsd-common.h" -#include "statedump.h" - -#ifdef GF_DARWIN_HOST_OS -/* This is MacFUSE's marker for MacFUSE-specific code */ -#define __FreeBSD__ 10 -#include "fuse_kernel_macfuse.h" -#else -#include "fuse_kernel.h" -#endif -#include "fuse-misc.h" -#include "fuse-mount.h" -#include "fuse-mem-types.h" - -#include "list.h" -#include "dict.h" - -/* TODO: when supporting posix acl, remove this definition */ -#define DISABLE_POSIX_ACL - -#ifdef GF_LINUX_HOST_OS -#define FUSE_OP_HIGH (FUSE_POLL + 1) -#endif -#ifdef GF_DARWIN_HOST_OS -#define FUSE_OP_HIGH (FUSE_DESTROY + 1) -#endif -#define GLUSTERFS_XATTR_LEN_MAX 65536 - -#define MAX_FUSE_PROC_DELAY 1 +#include "fuse-bridge.h" static int gf_fuse_conn_err_log; static int gf_fuse_xattr_enotsup_log; -typedef struct fuse_in_header fuse_in_header_t; -typedef void (fuse_handler_t) (xlator_t *this, fuse_in_header_t *finh, - void *msg); - -struct fuse_private { - int fd; - uint32_t proto_minor; - char *volfile; - size_t volfile_size; - char *mount_point; - struct iobuf *iobuf; - - pthread_t fuse_thread; - char fuse_thread_started; - - uint32_t direct_io_mode; - size_t *msg0_len_p; - - double entry_timeout; - double attribute_timeout; - - pthread_cond_t sync_cond; - pthread_mutex_t sync_mutex; - char child_up; - - char init_recvd; - - gf_boolean_t strict_volfile_check; - - fuse_handler_t **fuse_ops; - fuse_handler_t **fuse_ops0; - pthread_mutex_t fuse_dump_mutex; - int fuse_dump_fd; - - glusterfs_graph_t *next_graph; - xlator_t *active_subvol; -}; -typedef struct fuse_private fuse_private_t; - -#define _FH_TO_FD(fh) ((fd_t *)(uintptr_t)(fh)) - -#define FH_TO_FD(fh) ((_FH_TO_FD (fh))?(fd_ref (_FH_TO_FD (fh))):((fd_t *) 0)) - -#define FUSE_FOP(state, ret, op_num, fop, args ...) \ - do { \ - call_frame_t *frame = NULL; \ - xlator_t *xl = NULL; \ - \ - frame = get_call_frame_for_req (state); \ - if (!frame) { \ - /* This is not completely clean, as some \ - * earlier allocations might remain unfreed \ - * if we return at this point, but still \ - * better than trying to go on with a NULL \ - * frame ... \ - */ \ - gf_log ("glusterfs-fuse", \ - GF_LOG_ERROR, \ - "FUSE message" \ - " unique %"PRIu64" opcode %d:" \ - " frame allocation failed", \ - state->finh->unique, \ - state->finh->opcode); \ - free_state (state); \ - return; \ - } \ - xl = fuse_state_subvol (state); \ - \ - frame->root->state = state; \ - frame->root->op = op_num; \ - frame->op = op_num; \ - STACK_WIND (frame, ret, xl, xl->fops->fop, args); \ - } while (0) - -#define GF_SELECT_LOG_LEVEL(_errno) \ - (((_errno == ENOENT) || (_errno == ESTALE))? \ - GF_LOG_DEBUG) - -#define GET_STATE(this, finh, state) \ - do { \ - state = get_state (this, finh); \ - if (!state) { \ - gf_log ("glusterfs-fuse", \ - GF_LOG_ERROR, \ - "FUSE message unique %"PRIu64" opcode %d:" \ - " state allocation failed", \ - finh->unique, finh->opcode); \ - \ - send_fuse_err (this, finh, ENOMEM); \ - GF_FREE (finh); \ - \ - return; \ - } \ - } while (0) - - -typedef struct { - void *pool; - xlator_t *this; - inode_table_t *itable; - loc_t loc; - loc_t loc2; - fuse_in_header_t *finh; - int32_t flags; - off_t off; - size_t size; - unsigned long nlookup; - fd_t *fd; - dict_t *dict; - char *name; - char is_revalidate; - gf_boolean_t truncate_needed; - gf_lock_t lock; - uint64_t lk_owner; -} fuse_state_t; - - -xlator_t * -fuse_state_subvol (fuse_state_t *state) -{ - xlator_t *subvol = NULL; - - if (!state) - return NULL; - - if (state->loc.inode) - subvol = state->loc.inode->table->xl; - - if (state->fd) - subvol = state->fd->inode->table->xl; - - return subvol; -} - - -xlator_t * -fuse_active_subvol (xlator_t *fuse) -{ - fuse_private_t *priv = NULL; - - priv = fuse->private; - - return priv->active_subvol; -} - - -static void -free_state (fuse_state_t *state) -{ - loc_wipe (&state->loc); - - loc_wipe (&state->loc2); - - if (state->dict) { - dict_unref (state->dict); - state->dict = (void *)0xaaaaeeee; - } - if (state->name) { - GF_FREE (state->name); - state->name = NULL; - } - if (state->fd) { - fd_unref (state->fd); - state->fd = (void *)0xfdfdfdfd; - } - if (state->finh) { - GF_FREE (state->finh); - state->finh = NULL; - } -#ifdef DEBUG - memset (state, 0x90, sizeof (*state)); -#endif - GF_FREE (state); - state = NULL; -} - - -fuse_state_t * -get_state (xlator_t *this, fuse_in_header_t *finh) -{ - fuse_state_t *state = NULL; - - state = (void *)GF_CALLOC (1, sizeof (*state), - gf_fuse_mt_fuse_state_t); - if (!state) - return NULL; - state->pool = this->ctx->pool; - state->finh = finh; - state->this = this; - - LOCK_INIT (&state->lock); - - return state; -} - - -static call_frame_t * -get_call_frame_for_req (fuse_state_t *state) -{ - call_pool_t *pool = NULL; - fuse_in_header_t *finh = NULL; - call_frame_t *frame = NULL; - xlator_t *this = NULL; - - pool = state->pool; - finh = state->finh; - this = state->this; - - frame = create_frame (this, pool); - if (!frame) - return NULL; - - if (finh) { - frame->root->uid = finh->uid; - frame->root->gid = finh->gid; - frame->root->pid = finh->pid; - frame->root->lk_owner = state->lk_owner; - frame->root->unique = finh->unique; - } - - frame->root->type = GF_OP_TYPE_FOP; - - return frame; -} - /* * iov_out should contain a fuse_out_header at zeroth position. @@ -378,142 +106,6 @@ send_fuse_err (xlator_t *this, fuse_in_header_t *finh, int error) return send_fuse_iov (this, finh, &iov_out, 1); } -static inode_t * -fuse_ino_to_inode (uint64_t ino, xlator_t *fuse) -{ - inode_t *inode = NULL; - xlator_t *active_subvol = NULL; - - if (ino == 1) { - active_subvol = fuse_active_subvol (fuse); - inode = active_subvol->itable->root; - } else { - inode = (inode_t *) (unsigned long) ino; - inode_ref (inode); - } - - return inode; -} - -static uint64_t -inode_to_nodeid (inode_t *inode) -{ - if (!inode || inode->ino == 1) - return 1; - - return (unsigned long) inode; -} - - -GF_MUST_CHECK static int32_t -fuse_loc_fill (loc_t *loc, fuse_state_t *state, ino_t ino, - ino_t par, const char *name) -{ - inode_t *inode = NULL; - inode_t *parent = NULL; - int32_t ret = -1; - char *path = NULL; - - /* resistance against multiple invocation of loc_fill not to get - reference leaks via inode_search() */ - - if (name) { - parent = loc->parent; - if (!parent) { - parent = fuse_ino_to_inode (par, state->this); - loc->parent = parent; - } - - inode = loc->inode; - if (!inode) { - inode = inode_grep (parent->table, parent, name); - loc->inode = inode; - } - - ret = inode_path (parent, name, &path); - if (ret <= 0) { - gf_log ("glusterfs-fuse", GF_LOG_DEBUG, - "inode_path failed for %"PRId64"/%s", - parent->ino, name); - goto fail; - } - loc->path = path; - } else { - inode = loc->inode; - if (!inode) { - inode = fuse_ino_to_inode (ino, state->this); - loc->inode = inode; - } - - parent = loc->parent; - if (!parent) { - parent = inode_parent (inode, par, name); - loc->parent = parent; - } - - ret = inode_path (inode, NULL, &path); - if (ret <= 0) { - gf_log ("glusterfs-fuse", GF_LOG_DEBUG, - "inode_path failed for %"PRId64, - inode->ino); - goto fail; - } - loc->path = path; - } - - if (inode) - loc->ino = inode->ino; - - if (loc->path) { - loc->name = strrchr (loc->path, '/'); - if (loc->name) - loc->name++; - else - loc->name = ""; - } - - if ((ino != 1) && (parent == NULL)) { - gf_log ("fuse-bridge", GF_LOG_DEBUG, - "failed to search parent for %"PRId64"/%s (%"PRId64")", - (ino_t)par, name, (ino_t)ino); - ret = -1; - goto fail; - } - ret = 0; -fail: - return ret; -} - - -/* courtesy of folly */ -static void -stat2attr (struct iatt *st, struct fuse_attr *fa) -{ - fa->ino = st->ia_ino; - fa->size = st->ia_size; - fa->blocks = st->ia_blocks; - fa->atime = st->ia_atime; - fa->mtime = st->ia_mtime; - fa->ctime = st->ia_ctime; - fa->atimensec = st->ia_atime_nsec; - fa->mtimensec = st->ia_mtime_nsec; - fa->ctimensec = st->ia_ctime_nsec; - fa->mode = st_mode_from_ia (st->ia_prot, st->ia_type); - fa->nlink = st->ia_nlink; - fa->uid = st->ia_uid; - fa->gid = st->ia_gid; - fa->rdev = st->ia_rdev; -#if FUSE_KERNEL_MINOR_VERSION >= 9 - fa->blksize = st->ia_blksize; -#endif -#ifdef GF_DARWIN_HOST_OS - fa->crtime = (uint64_t)-1; - fa->crtimensec = (uint32_t)-1; - fa->flags = 0; -#endif -} - - static int fuse_entry_cbk (call_frame_t *frame, void *cookie, xlator_t *this, int32_t op_ret, int32_t op_errno, @@ -540,7 +132,7 @@ fuse_entry_cbk (call_frame_t *frame, void *cookie, xlator_t *this, state->loc.path, buf->ia_ino, state->loc.ino); buf->ia_blksize = this->ctx->page_size; - stat2attr (buf, &feo.attr); + gf_fuse_stat2attr (buf, &feo.attr); if (!buf->ia_ino) { gf_log ("glusterfs-fuse", GF_LOG_WARNING, @@ -566,7 +158,8 @@ fuse_entry_cbk (call_frame_t *frame, void *cookie, xlator_t *this, inode_lookup (linked_inode); /* TODO: make these timeouts configurable (via meta?) */ - feo.nodeid = inode_to_nodeid (linked_inode); + /* should we do linked_node or inode */ + feo.nodeid = inode_to_fuse_nodeid (linked_inode); feo.generation = linked_inode->generation; @@ -598,7 +191,7 @@ fuse_entry_cbk (call_frame_t *frame, void *cookie, xlator_t *this, send_fuse_err (this, state->finh, op_errno); } - free_state (state); + free_fuse_state (state); STACK_DESTROY (frame->root); return 0; } @@ -644,14 +237,24 @@ fuse_lookup_cbk (call_frame_t *frame, void *cookie, xlator_t *this, return 0; } +void +fuse_lookup_resume (fuse_state_t *state) +{ + if (!state->loc.inode) + state->loc.inode = inode_new (state->loc.parent->table); + + state->dict = dict_new (); + + FUSE_FOP (state, fuse_lookup_cbk, GF_FOP_LOOKUP, + lookup, &state->loc, state->dict); +} static void fuse_lookup (xlator_t *this, fuse_in_header_t *finh, void *msg) { - char *name = msg; - - fuse_state_t *state = NULL; - int32_t ret = -1; + char *name = msg; + fuse_state_t *state = NULL; + int32_t ret = -1; GET_STATE (this, finh, state); @@ -662,27 +265,23 @@ fuse_lookup (xlator_t *this, fuse_in_header_t *finh, void *msg) "%"PRIu64": LOOKUP %"PRIu64"/%s (fuse_loc_fill() failed)", finh->unique, finh->nodeid, name); send_fuse_err (this, finh, ENOENT); - free_state (state); + free_fuse_state (state); return; } - if (!state->loc.inode) { - gf_log ("glusterfs-fuse", GF_LOG_TRACE, - "%"PRIu64": LOOKUP %s", finh->unique, - state->loc.path); - - state->loc.inode = inode_new (state->loc.parent->table); - } else { + if (state->loc.inode) { gf_log ("glusterfs-fuse", GF_LOG_TRACE, "%"PRIu64": LOOKUP %s(%"PRId64")", finh->unique, state->loc.path, state->loc.inode->ino); state->is_revalidate = 1; + } else { + gf_log ("glusterfs-fuse", GF_LOG_TRACE, + "%"PRIu64": LOOKUP %s", finh->unique, + state->loc.path); } - state->dict = dict_new (); + fuse_resolve_and_resume (state, fuse_lookup_resume); - FUSE_FOP (state, fuse_lookup_cbk, GF_FOP_LOOKUP, - lookup, &state->loc, state->dict); } @@ -732,7 +331,7 @@ fuse_truncate_cbk (call_frame_t *frame, void *cookie, xlator_t *this, /* TODO: make these timeouts configurable via meta */ /* TODO: what if the inode number has changed by now */ postbuf->ia_blksize = this->ctx->page_size; - stat2attr (postbuf, &fao.attr); + gf_fuse_stat2attr (postbuf, &fao.attr); fao.attr_valid = calc_timeout_sec (priv->attribute_timeout); fao.attr_valid_nsec = @@ -756,7 +355,7 @@ fuse_truncate_cbk (call_frame_t *frame, void *cookie, xlator_t *this, send_fuse_err (this, finh, op_errno); } - free_state (state); + free_fuse_state (state); STACK_DESTROY (frame->root); return 0; @@ -786,7 +385,7 @@ fuse_attr_cbk (call_frame_t *frame, void *cookie, xlator_t *this, /* TODO: make these timeouts configurable via meta */ /* TODO: what if the inode number has changed by now */ buf->ia_blksize = this->ctx->page_size; - stat2attr (buf, &fao.attr); + gf_fuse_stat2attr (buf, &fao.attr); fao.attr_valid = calc_timeout_sec (priv->attribute_timeout); fao.attr_valid_nsec = @@ -812,7 +411,7 @@ fuse_attr_cbk (call_frame_t *frame, void *cookie, xlator_t *this, send_fuse_err (this, finh, op_errno); } - free_state (state); + free_fuse_state (state); STACK_DESTROY (frame->root); return 0; @@ -830,6 +429,28 @@ fuse_root_lookup_cbk (call_frame_t *frame, void *cookie, xlator_t *this, return 0; } +void +fuse_getattr_resume (fuse_state_t *state) +{ + if (!state->fd || IA_ISDIR (state->loc.inode->ia_type)) { + gf_log ("glusterfs-fuse", GF_LOG_TRACE, + "%"PRIu64": GETATTR %"PRIu64" (%s)", + state->finh->unique, state->finh->nodeid, + state->loc.path); + + FUSE_FOP (state, fuse_attr_cbk, GF_FOP_STAT, + stat, &state->loc); + } else { + + gf_log ("glusterfs-fuse", GF_LOG_TRACE, + "%"PRIu64": FGETATTR %"PRIu64" (%s/%p)", + state->finh->unique, state->finh->nodeid, + state->loc.path, state->fd); + + FUSE_FOP (state, fuse_attr_cbk, GF_FOP_FSTAT, + fstat, state->fd); + } +} static void fuse_getattr (xlator_t *this, fuse_in_header_t *finh, void *msg) @@ -844,10 +465,10 @@ fuse_getattr (xlator_t *this, fuse_in_header_t *finh, void *msg) ret = fuse_loc_fill (&state->loc, state, finh->nodeid, 0, NULL); if (ret < 0) { gf_log ("glusterfs-fuse", GF_LOG_WARNING, - "%"PRIu64": GETATTR %"PRIu64" (fuse_loc_fill() failed)", - finh->unique, finh->nodeid); + "%"PRIu64": GETATTR on / (fuse_loc_fill() failed)", + finh->unique); send_fuse_err (this, finh, ENOENT); - free_state (state); + free_fuse_state (state); return; } @@ -858,18 +479,18 @@ fuse_getattr (xlator_t *this, fuse_in_header_t *finh, void *msg) return; } - ret = fuse_loc_fill (&state->loc, state, finh->nodeid, 0, NULL); + ret = fuse_loc_fill (&state->loc, state, state->finh->nodeid, 0, NULL); if (!state->loc.inode) { gf_log ("glusterfs-fuse", GF_LOG_WARNING, "%"PRIu64": GETATTR %"PRIu64" (%s) (fuse_loc_fill() returned NULL inode)", - finh->unique, finh->nodeid, state->loc.path); - send_fuse_err (this, finh, ENOENT); - free_state (state); + state->finh->unique, state->finh->nodeid, state->loc.path); + send_fuse_err (state->this, state->finh, ENOENT); + free_fuse_state (state); return; } - fd = fd_lookup (state->loc.inode, finh->pid); + fd = fd_lookup (state->loc.inode, state->finh->pid); state->fd = fd; if (!fd || IA_ISDIR (state->loc.inode->ia_type)) { /* this is the @ret of fuse_loc_fill, checked here @@ -878,28 +499,15 @@ fuse_getattr (xlator_t *this, fuse_in_header_t *finh, void *msg) if (ret < 0) { gf_log ("glusterfs-fuse", GF_LOG_WARNING, "%"PRIu64": GETATTR %"PRIu64" (fuse_loc_fill() failed)", - finh->unique, finh->nodeid); - send_fuse_err (this, finh, ENOENT); - free_state (state); + state->finh->unique, state->finh->nodeid); + send_fuse_err (state->this, state->finh, ENOENT); + free_fuse_state (state); return; } - - gf_log ("glusterfs-fuse", GF_LOG_TRACE, - "%"PRIu64": GETATTR %"PRIu64" (%s)", - finh->unique, finh->nodeid, state->loc.path); - - - FUSE_FOP (state, fuse_attr_cbk, GF_FOP_STAT, - stat, &state->loc); - } else { - - gf_log ("glusterfs-fuse", GF_LOG_TRACE, - "%"PRIu64": FGETATTR %"PRIu64" (%s/%p)", - finh->unique, finh->nodeid, state->loc.path, fd); - - FUSE_FOP (state,fuse_attr_cbk, GF_FOP_FSTAT, - fstat, fd); + state->fd = NULL; } + + fuse_resolve_and_resume (state, fuse_getattr_resume); } @@ -960,7 +568,7 @@ fuse_fd_cbk (call_frame_t *frame, void *cookie, xlator_t *this, send_fuse_err (this, finh, op_errno); } out: - free_state (state); + free_fuse_state (state); STACK_DESTROY (frame->root); return 0; } @@ -1009,7 +617,7 @@ fuse_setattr_cbk (call_frame_t *frame, void *cookie, xlator_t *this, statpost->ia_blksize = this->ctx->page_size; - stat2attr (statpost, &fao.attr); + gf_fuse_stat2attr (statpost, &fao.attr); fao.attr_valid = calc_timeout_sec (priv->attribute_timeout); fao.attr_valid_nsec = @@ -1040,7 +648,7 @@ fuse_setattr_cbk (call_frame_t *frame, void *cookie, xlator_t *this, } if (op_done) { - free_state (state); + free_fuse_state (state); } STACK_DESTROY (frame->root); @@ -1081,18 +689,40 @@ fattr_to_gf_set_attr (int32_t valid) | FATTR_ATIME | FATTR_MTIME \ | FATTR_MODE) +void +fuse_setattr_resume (fuse_state_t *state) +{ + if ((state->valid & (FATTR_MASK)) != FATTR_SIZE) { + if (state->fd && + !((state->valid & FATTR_ATIME) || + (state->valid & FATTR_MTIME))) { + /* + there is no "futimes" call, so don't send + fsetattr if ATIME or MTIME is set + */ + + FUSE_FOP (state, fuse_setattr_cbk, GF_FOP_FSETATTR, + fsetattr, state->fd, &state->attr, + fattr_to_gf_set_attr (state->valid)); + } else { + FUSE_FOP (state, fuse_setattr_cbk, GF_FOP_SETATTR, + setattr, &state->loc, &state->attr, + fattr_to_gf_set_attr (state->valid)); + } + } else { + fuse_do_truncate (state, state->size); + } + +} static void fuse_setattr (xlator_t *this, fuse_in_header_t *finh, void *msg) { struct fuse_setattr_in *fsi = msg; - struct iatt attr = {0, }; - fuse_private_t *priv = NULL; fuse_state_t *state = NULL; int32_t ret = -1; - int32_t valid = 0; GET_STATE (this, finh, state); @@ -1132,7 +762,7 @@ fuse_setattr (xlator_t *this, fuse_in_header_t *finh, void *msg) finh->unique, state->loc.path); send_fuse_err (this, finh, ENOENT); - free_state (state); + free_fuse_state (state); return; } @@ -1141,48 +771,32 @@ fuse_setattr (xlator_t *this, fuse_in_header_t *finh, void *msg) "%"PRIu64": SETATTR (%"PRIu64")%s", finh->unique, finh->nodeid, state->loc.path); - valid = fsi->valid; + state->valid = fsi->valid; if (fsi->valid & FATTR_FH) { state->fd = FH_TO_FD (fsi->fh); } - if ((valid & (FATTR_MASK)) != FATTR_SIZE) { - if (valid & FATTR_SIZE) { + if ((fsi->valid & (FATTR_MASK)) != FATTR_SIZE) { + if (fsi->valid & FATTR_SIZE) { state->size = fsi->size; state->truncate_needed = _gf_true; } - attr.ia_size = fsi->size; - attr.ia_atime = fsi->atime; - attr.ia_mtime = fsi->mtime; - attr.ia_atime_nsec = fsi->atimensec; - attr.ia_mtime_nsec = fsi->mtimensec; + state->attr.ia_size = fsi->size; + state->attr.ia_atime = fsi->atime; + state->attr.ia_mtime = fsi->mtime; + state->attr.ia_atime_nsec = fsi->atimensec; + state->attr.ia_mtime_nsec = fsi->mtimensec; - attr.ia_prot = ia_prot_from_st_mode (fsi->mode); - attr.ia_uid = fsi->uid; - attr.ia_gid = fsi->gid; - - if (state->fd && - !((fsi->valid & FATTR_ATIME) || (fsi->valid & FATTR_MTIME))) { - - /* - there is no "futimes" call, so don't send - fsetattr if ATIME or MTIME is set - */ - - FUSE_FOP (state, fuse_setattr_cbk, GF_FOP_FSETATTR, - fsetattr, state->fd, &attr, - fattr_to_gf_set_attr (fsi->valid)); - } else { - FUSE_FOP (state, fuse_setattr_cbk, GF_FOP_SETATTR, - setattr, &state->loc, &attr, - fattr_to_gf_set_attr (fsi->valid)); - } + state->attr.ia_prot = ia_prot_from_st_mode (fsi->mode); + state->attr.ia_uid = fsi->uid; + state->attr.ia_gid = fsi->gid; } else { - fuse_do_truncate (state, fsi->size); + state->size = fsi->size; } + fuse_resolve_and_resume (state, fuse_setattr_resume); } @@ -1211,7 +825,7 @@ fuse_err_cbk (call_frame_t *frame, void *cookie, xlator_t *this, send_fuse_err (this, finh, op_errno); } - free_state (state); + free_fuse_state (state); STACK_DESTROY (frame->root); return 0; @@ -1272,12 +886,24 @@ fuse_unlink_cbk (call_frame_t *frame, void *cookie, xlator_t *this, send_fuse_err (this, finh, op_errno); } - free_state (state); + free_fuse_state (state); STACK_DESTROY (frame->root); return 0; } +void +fuse_access_resume (fuse_state_t *state) +{ + gf_log ("glusterfs-fuse", GF_LOG_TRACE, + "%"PRIu64" ACCESS %s/%"PRIu64" mask=%d", + state->finh->unique, state->loc.path, + state->finh->nodeid, state->mask); + + FUSE_FOP (state, fuse_err_cbk, GF_FOP_ACCESS, access, + &state->loc, state->mask); + +} static void fuse_access (xlator_t *this, fuse_in_header_t *finh, void *msg) @@ -1296,18 +922,13 @@ fuse_access (xlator_t *this, fuse_in_header_t *finh, void *msg) "%"PRIu64": ACCESS %"PRIu64" (%s) (fuse_loc_fill() failed)", finh->unique, finh->nodeid, state->loc.path); send_fuse_err (this, finh, ENOENT); - free_state (state); + free_fuse_state (state); return; } - gf_log ("glusterfs-fuse", GF_LOG_TRACE, - "%"PRIu64" ACCESS %s/%"PRIu64" mask=%d", finh->unique, - state->loc.path, finh->nodeid, fai->mask); - - FUSE_FOP (state, fuse_err_cbk, - GF_FOP_ACCESS, access, - &state->loc, fai->mask); + state->mask = fai->mask; + fuse_resolve_and_resume (state, fuse_access_resume); return; } @@ -1339,12 +960,23 @@ fuse_readlink_cbk (call_frame_t *frame, void *cookie, xlator_t *this, send_fuse_err (this, finh, op_errno); } - free_state (state); + free_fuse_state (state); STACK_DESTROY (frame->root); return 0; } +void +fuse_readlink_resume (fuse_state_t *state) +{ + gf_log ("glusterfs-fuse", GF_LOG_TRACE, + "%"PRIu64" READLINK %s/%"PRId64, state->finh->unique, + state->loc.path, state->loc.inode->ino); + + FUSE_FOP (state, fuse_readlink_cbk, GF_FOP_READLINK, + readlink, &state->loc, 4096); + +} static void fuse_readlink (xlator_t *this, fuse_in_header_t *finh, void *msg) @@ -1360,20 +992,31 @@ fuse_readlink (xlator_t *this, fuse_in_header_t *finh, void *msg) "%"PRIu64" READLINK %s (fuse_loc_fill() returned NULL inode)", finh->unique, state->loc.path); send_fuse_err (this, finh, ENOENT); - free_state (state); + free_fuse_state (state); return; } - gf_log ("glusterfs-fuse", GF_LOG_TRACE, - "%"PRIu64" READLINK %s/%"PRId64, finh->unique, - state->loc.path, state->loc.inode->ino); - - FUSE_FOP (state, fuse_readlink_cbk, GF_FOP_READLINK, - readlink, &state->loc, 4096); + fuse_resolve_and_resume (state, fuse_readlink_resume); return; } +void +fuse_mknod_resume (fuse_state_t *state) +{ + if (!state->loc.inode) + state->loc.inode = inode_new (state->loc.parent->table); + else + gf_log (state->this->name, GF_LOG_ERROR, "inode already present"); + + gf_log ("glusterfs-fuse", GF_LOG_TRACE, + "%"PRIu64": MKNOD %s", state->finh->unique, + state->loc.path); + + FUSE_FOP (state, fuse_newentry_cbk, GF_FOP_MKNOD, + mknod, &state->loc, state->mode, state->rdev); + +} static void fuse_mknod (xlator_t *this, fuse_in_header_t *finh, void *msg) @@ -1398,22 +1041,33 @@ fuse_mknod (xlator_t *this, fuse_in_header_t *finh, void *msg) "%"PRIu64" MKNOD %s (fuse_loc_fill() failed)", finh->unique, state->loc.path); send_fuse_err (this, finh, ENOENT); - free_state (state); + free_fuse_state (state); return; } - state->loc.inode = inode_new (state->loc.parent->table); - - gf_log ("glusterfs-fuse", GF_LOG_TRACE, - "%"PRIu64": MKNOD %s", finh->unique, - state->loc.path); + state->mode = fmi->mode; + state->rdev = fmi->rdev; - FUSE_FOP (state, fuse_newentry_cbk, GF_FOP_MKNOD, - mknod, &state->loc, fmi->mode, fmi->rdev); + fuse_resolve_and_resume (state, fuse_mknod_resume); return; } +void +fuse_mkdir_resume (fuse_state_t *state) +{ + if (!state->loc.inode) + state->loc.inode = inode_new (state->loc.parent->table); + else + gf_log (state->this->name, GF_LOG_ERROR, "inode already present"); + + gf_log ("glusterfs-fuse", GF_LOG_TRACE, + "%"PRIu64": MKDIR %s", state->finh->unique, + state->loc.path); + + FUSE_FOP (state, fuse_newentry_cbk, GF_FOP_MKDIR, + mkdir, &state->loc, state->mode); +} static void fuse_mkdir (xlator_t *this, fuse_in_header_t *finh, void *msg) @@ -1431,23 +1085,35 @@ fuse_mkdir (xlator_t *this, fuse_in_header_t *finh, void *msg) "%"PRIu64" MKDIR %s (fuse_loc_fill() failed)", finh->unique, state->loc.path); send_fuse_err (this, finh, ENOENT); - free_state (state); + free_fuse_state (state); return; } - state->loc.inode = inode_new (state->loc.parent->table); + state->mode = fmi->mode; + + fuse_resolve_and_resume (state, fuse_mkdir_resume); + return; +} + +void +fuse_unlink_resume (fuse_state_t *state) +{ + if (!state->loc.inode) { + gf_log ("fuse", GF_LOG_WARNING, "path resolving failed"); + send_fuse_err (state->this, state->finh, ENOENT); + free_fuse_state (state); + return; + } gf_log ("glusterfs-fuse", GF_LOG_TRACE, - "%"PRIu64": MKDIR %s", finh->unique, + "%"PRIu64": UNLINK %s", state->finh->unique, state->loc.path); - FUSE_FOP (state, fuse_newentry_cbk, GF_FOP_MKDIR, - mkdir, &state->loc, fmi->mode); + FUSE_FOP (state, fuse_unlink_cbk, GF_FOP_UNLINK, + unlink, &state->loc); - return; } - static void fuse_unlink (xlator_t *this, fuse_in_header_t *finh, void *msg) { @@ -1457,29 +1123,38 @@ fuse_unlink (xlator_t *this, fuse_in_header_t *finh, void *msg) int32_t ret = -1; GET_STATE (this, finh, state); - ret = fuse_loc_fill (&state->loc, state, 0, finh->nodeid, name); - - if ((state->loc.inode == NULL) || - (ret < 0)) { + if (ret < 0) { gf_log ("glusterfs-fuse", GF_LOG_WARNING, "%"PRIu64": UNLINK %s (fuse_loc_fill() returned NULL inode)", finh->unique, state->loc.path); send_fuse_err (this, finh, ENOENT); - free_state (state); + free_fuse_state (state); return; } - gf_log ("glusterfs-fuse", GF_LOG_TRACE, - "%"PRIu64": UNLINK %s", finh->unique, - state->loc.path); - - FUSE_FOP (state, fuse_unlink_cbk, GF_FOP_UNLINK, - unlink, &state->loc); + fuse_resolve_and_resume (state, fuse_unlink_resume); return; } +void +fuse_rmdir_resume (fuse_state_t *state) +{ + if (!state->loc.inode) { + gf_log ("fuse", GF_LOG_WARNING, "path resolving failed"); + send_fuse_err (state->this, state->finh, ENOENT); + free_fuse_state (state); + return; + } + + gf_log ("glusterfs-fuse", GF_LOG_TRACE, + "%"PRIu64": RMDIR %s", state->finh->unique, + state->loc.path); + + FUSE_FOP (state, fuse_unlink_cbk, GF_FOP_RMDIR, + rmdir, &state->loc); +} static void fuse_rmdir (xlator_t *this, fuse_in_header_t *finh, void *msg) @@ -1491,26 +1166,34 @@ fuse_rmdir (xlator_t *this, fuse_in_header_t *finh, void *msg) GET_STATE (this, finh, state); ret = fuse_loc_fill (&state->loc, state, 0, finh->nodeid, name); - if ((state->loc.inode == NULL) || - (ret < 0)) { + if (ret < 0) { gf_log ("glusterfs-fuse", GF_LOG_WARNING, "%"PRIu64": RMDIR %s (fuse_loc_fill() failed)", finh->unique, state->loc.path); send_fuse_err (this, finh, ENOENT); - free_state (state); + free_fuse_state (state); return; } - gf_log ("glusterfs-fuse", GF_LOG_TRACE, - "%"PRIu64": RMDIR %s", finh->unique, - state->loc.path); - - FUSE_FOP (state, fuse_unlink_cbk, GF_FOP_RMDIR, - rmdir, &state->loc); - + fuse_resolve_and_resume (state, fuse_rmdir_resume); return; } +void +fuse_symlink_resume (fuse_state_t *state) +{ + if (!state->loc.inode) + state->loc.inode = inode_new (state->loc.parent->table); + else + gf_log (state->this->name, GF_LOG_ERROR, "inode already present"); + + gf_log ("glusterfs-fuse", GF_LOG_TRACE, + "%"PRIu64": SYMLINK %s -> %s", state->finh->unique, + state->loc.path, state->name); + + FUSE_FOP (state, fuse_newentry_cbk, GF_FOP_SYMLINK, + symlink, state->name, &state->loc); +} static void fuse_symlink (xlator_t *this, fuse_in_header_t *finh, void *msg) @@ -1528,19 +1211,12 @@ fuse_symlink (xlator_t *this, fuse_in_header_t *finh, void *msg) "%"PRIu64" SYMLINK %s -> %s (fuse_loc_fill() failed)", finh->unique, state->loc.path, linkname); send_fuse_err (this, finh, ENOENT); - free_state (state); + free_fuse_state (state); return; } - state->loc.inode = inode_new (state->loc.parent->table); - - gf_log ("glusterfs-fuse", GF_LOG_TRACE, - "%"PRIu64": SYMLINK %s -> %s", finh->unique, - state->loc.path, linkname); - - FUSE_FOP (state, fuse_newentry_cbk, GF_FOP_SYMLINK, - symlink, linkname, &state->loc); - + state->name = gf_strdup (linkname); + fuse_resolve_and_resume (state, fuse_symlink_resume); return; } @@ -1586,11 +1262,28 @@ fuse_rename_cbk (call_frame_t *frame, void *cookie, xlator_t *this, send_fuse_err (this, finh, op_errno); } - free_state (state); + free_fuse_state (state); STACK_DESTROY (frame->root); return 0; } +void +fuse_rename_resume (fuse_state_t *state) +{ + if (!state->loc.inode) { + send_fuse_err (state->this, state->finh, ENOENT); + free_fuse_state (state); + return; + } + + gf_log ("glusterfs-fuse", GF_LOG_TRACE, + "%"PRIu64": RENAME `%s (%"PRId64")' -> `%s (%"PRId64")'", + state->finh->unique, state->loc.path, state->loc.ino, + state->loc2.path, state->loc2.ino); + + FUSE_FOP (state, fuse_rename_cbk, GF_FOP_RENAME, + rename, &state->loc, &state->loc2); +} static void fuse_rename (xlator_t *this, fuse_in_header_t *finh, void *msg) @@ -1605,15 +1298,14 @@ fuse_rename (xlator_t *this, fuse_in_header_t *finh, void *msg) GET_STATE (this, finh, state); ret = fuse_loc_fill (&state->loc, state, 0, finh->nodeid, oldname); - if ((state->loc.inode == NULL) || - (ret < 0)) { + if (ret < 0) { gf_log ("glusterfs-fuse", GF_LOG_WARNING, "for %s %"PRIu64": RENAME `%s' -> `%s' (fuse_loc_fill() failed)", state->loc.path, finh->unique, state->loc.path, state->loc2.path); send_fuse_err (this, finh, ENOENT); - free_state (state); + free_fuse_state (state); return; } @@ -1625,21 +1317,31 @@ fuse_rename (xlator_t *this, fuse_in_header_t *finh, void *msg) state->loc2.path); send_fuse_err (this, finh, ENOENT); - free_state (state); + free_fuse_state (state); return; - } - - gf_log ("glusterfs-fuse", GF_LOG_TRACE, - "%"PRIu64": RENAME `%s (%"PRId64")' -> `%s (%"PRId64")'", - finh->unique, state->loc.path, state->loc.ino, - state->loc2.path, state->loc2.ino); + } - FUSE_FOP (state, fuse_rename_cbk, GF_FOP_RENAME, - rename, &state->loc, &state->loc2); + fuse_resolve_and_resume (state, fuse_rename_resume); return; } +void +fuse_link_resume (fuse_state_t *state) +{ + if (!state->loc.inode) + state->loc.inode = inode_ref (state->loc2.inode); + else + gf_log (state->this->name, GF_LOG_ERROR, "inode already present"); + + gf_log ("glusterfs-fuse", GF_LOG_TRACE, + "%"PRIu64": LINK() %s (%"PRId64") -> %s (%"PRId64")", + state->finh->unique, state->loc2.path, state->loc2.ino, + state->loc.path, state->loc.ino); + + FUSE_FOP (state, fuse_newentry_cbk, GF_FOP_LINK, + link, &state->loc2, &state->loc); +} static void fuse_link (xlator_t *this, fuse_in_header_t *finh, void *msg) @@ -1664,18 +1366,11 @@ fuse_link (xlator_t *this, fuse_in_header_t *finh, void *msg) state->loc2.path, finh->unique, state->loc2.path, state->loc.path); send_fuse_err (this, finh, ENOENT); - free_state (state); + free_fuse_state (state); return; } - state->loc.inode = inode_ref (state->loc2.inode); - gf_log ("glusterfs-fuse", GF_LOG_TRACE, - "%"PRIu64": LINK() %s (%"PRId64") -> %s (%"PRId64")", - finh->unique, state->loc2.path, state->loc2.ino, - state->loc.path, state->loc.ino); - - FUSE_FOP (state, fuse_newentry_cbk, GF_FOP_LINK, - link, &state->loc2, &state->loc); + fuse_resolve_and_resume (state, fuse_link_resume); return; } @@ -1696,7 +1391,6 @@ fuse_create_cbk (call_frame_t *frame, void *cookie, xlator_t *this, struct iovec iov_out[3]; inode_t *linked_inode = NULL; - state = frame->root->state; priv = this->private; finh = state->finh; @@ -1714,7 +1408,7 @@ fuse_create_cbk (call_frame_t *frame, void *cookie, xlator_t *this, state->loc.path, fd, buf->ia_ino); buf->ia_blksize = this->ctx->page_size; - stat2attr (buf, &feo.attr); + gf_fuse_stat2attr (buf, &feo.attr); linked_inode = inode_link (inode, state->loc.parent, state->loc.name, buf); @@ -1738,11 +1432,12 @@ fuse_create_cbk (call_frame_t *frame, void *cookie, xlator_t *this, inode_lookup (linked_inode); + inode_ref (state->loc.parent); inode_unref (linked_inode); fd_ref (fd); - feo.nodeid = inode_to_nodeid (linked_inode); + feo.nodeid = inode_to_fuse_nodeid (linked_inode); feo.generation = linked_inode->generation; @@ -1780,12 +1475,34 @@ fuse_create_cbk (call_frame_t *frame, void *cookie, xlator_t *this, send_fuse_err (this, finh, op_errno); } out: - free_state (state); + free_fuse_state (state); STACK_DESTROY (frame->root); return 0; } +void +fuse_create_resume (fuse_state_t *state) +{ + fd_t *fd = NULL; + + if (!state->loc.inode) + state->loc.inode = inode_new (state->loc.parent->table); + else + gf_log (state->this->name, GF_LOG_ERROR, "inode already present"); + + fd = fd_create (state->loc.inode, state->finh->pid); + state->fd = fd; + fd->flags = state->flags; + + gf_log ("glusterfs-fuse", GF_LOG_TRACE, + "%"PRIu64": CREATE %s", state->finh->unique, + state->loc.path); + + FUSE_FOP (state, fuse_create_cbk, GF_FOP_CREATE, + create, &state->loc, state->flags, state->mode, fd); + +} static void fuse_create (xlator_t *this, fuse_in_header_t *finh, void *msg) @@ -1799,7 +1516,6 @@ fuse_create (xlator_t *this, fuse_in_header_t *finh, void *msg) fuse_private_t *priv = NULL; fuse_state_t *state = NULL; - fd_t *fd = NULL; int32_t ret = -1; priv = this->private; @@ -1809,7 +1525,6 @@ fuse_create (xlator_t *this, fuse_in_header_t *finh, void *msg) #endif GET_STATE (this, finh, state); - state->flags = fci->flags; ret = fuse_loc_fill (&state->loc, state, 0, finh->nodeid, name); if (ret < 0) { @@ -1817,38 +1532,44 @@ fuse_create (xlator_t *this, fuse_in_header_t *finh, void *msg) "%"PRIu64" CREATE %s (fuse_loc_fill() failed)", finh->unique, state->loc.path); send_fuse_err (this, finh, ENOENT); - free_state (state); + free_fuse_state (state); return; } - state->loc.inode = inode_new (state->loc.parent->table); + state->mode = fci->mode; + state->flags = fci->flags; + + fuse_resolve_and_resume (state, fuse_create_resume); + + return; +} + +void +fuse_open_resume (fuse_state_t *state) +{ + fd_t *fd = NULL; - fd = fd_create (state->loc.inode, finh->pid); + fd = fd_create (state->loc.inode, state->finh->pid); state->fd = fd; fd->flags = state->flags; gf_log ("glusterfs-fuse", GF_LOG_TRACE, - "%"PRIu64": CREATE %s", finh->unique, + "%"PRIu64": OPEN %s", state->finh->unique, state->loc.path); - FUSE_FOP (state, fuse_create_cbk, GF_FOP_CREATE, - create, &state->loc, state->flags, fci->mode, fd); - - return; + FUSE_FOP (state, fuse_fd_cbk, GF_FOP_OPEN, + open, &state->loc, state->flags, fd, 0); } - static void fuse_open (xlator_t *this, fuse_in_header_t *finh, void *msg) { struct fuse_open_in *foi = msg; fuse_state_t *state = NULL; - fd_t *fd = NULL; int32_t ret = -1; GET_STATE (this, finh, state); - state->flags = foi->flags; ret = fuse_loc_fill (&state->loc, state, finh->nodeid, 0, NULL); if ((state->loc.inode == NULL) || @@ -1858,20 +1579,12 @@ fuse_open (xlator_t *this, fuse_in_header_t *finh, void *msg) finh->unique, state->loc.path); send_fuse_err (this, finh, ENOENT); - free_state (state); + free_fuse_state (state); return; } - fd = fd_create (state->loc.inode, finh->pid); - state->fd = fd; - fd->flags = foi->flags; - - gf_log ("glusterfs-fuse", GF_LOG_TRACE, - "%"PRIu64": OPEN %s", finh->unique, - state->loc.path); - - FUSE_FOP (state, fuse_fd_cbk, GF_FOP_OPEN, - open, &state->loc, foi->flags, fd, 0); + state->flags = foi->flags; + fuse_resolve_and_resume (state, fuse_open_resume); return; } @@ -1915,12 +1628,22 @@ fuse_readv_cbk (call_frame_t *frame, void *cookie, xlator_t *this, send_fuse_err (this, finh, op_errno); } - free_state (state); + free_fuse_state (state); STACK_DESTROY (frame->root); return 0; } +void +fuse_readv_resume (fuse_state_t *state) +{ + gf_log ("glusterfs-fuse", GF_LOG_TRACE, + "%"PRIu64": READ (%p, size=%zu, offset=%"PRIu64")", + state->finh->unique, state->fd, state->size, state->off); + + FUSE_FOP (state, fuse_readv_cbk, GF_FOP_READ, + readv, state->fd, state->size, state->off); +} static void fuse_readv (xlator_t *this, fuse_in_header_t *finh, void *msg) @@ -1933,8 +1656,6 @@ fuse_readv (xlator_t *this, fuse_in_header_t *finh, void *msg) GET_STATE (this, finh, state); - state->size = fri->size; - state->off = fri->offset; fd = FH_TO_FD (fri->fh); state->fd = fd; @@ -1946,13 +1667,10 @@ fuse_readv (xlator_t *this, fuse_in_header_t *finh, void *msg) state->lk_owner = fri->lock_owner; #endif - gf_log ("glusterfs-fuse", GF_LOG_TRACE, - "%"PRIu64": READ (%p, size=%"PRIu32", offset=%"PRIu64")", - finh->unique, fd, fri->size, fri->offset); - - FUSE_FOP (state, fuse_readv_cbk, GF_FOP_READ, - readv, fd, fri->size, fri->offset); + state->size = fri->size; + state->off = fri->offset; + fuse_resolve_and_resume (state, fuse_readv_resume); } @@ -1984,12 +1702,43 @@ fuse_writev_cbk (call_frame_t *frame, void *cookie, xlator_t *this, send_fuse_err (this, finh, op_errno); } - free_state (state); + free_fuse_state (state); STACK_DESTROY (frame->root); return 0; } +void +fuse_write_resume (fuse_state_t *state) +{ + struct iobref *iobref = NULL; + struct iobuf *iobuf = NULL; + + if (!state->fd || !state->fd->inode) { + send_fuse_err (state->this, state->finh, EBADFD); + free_fuse_state (state); + return; + } + + iobref = iobref_new (); + if (!iobref) { + gf_log ("glusterfs-fuse", GF_LOG_ERROR, + "%"PRIu64": WRITE iobref allocation failed", + state->finh->unique); + send_fuse_err (state->this, state->finh, ENOMEM); + + free_fuse_state (state); + return; + } + + iobuf = ((fuse_private_t *) (state->this->private))->iobuf; + iobref_add (iobref, iobuf); + + FUSE_FOP (state, fuse_writev_cbk, GF_FOP_WRITE, writev, state->fd, + &state->vector, 1, state->off, iobref); + + iobref_unref (iobref); +} static void fuse_write (xlator_t *this, fuse_in_header_t *finh, void *msg) @@ -2002,20 +1751,15 @@ fuse_write (xlator_t *this, fuse_in_header_t *finh, void *msg) fuse_private_t *priv = NULL; fuse_state_t *state = NULL; - struct iovec vector; fd_t *fd = NULL; - struct iobref *iobref = NULL; - struct iobuf *iobuf = NULL; priv = this->private; GET_STATE (this, finh, state); - state->size = fwi->size; - state->off = fwi->offset; fd = FH_TO_FD (fwi->fh); state->fd = fd; - vector.iov_base = msg; - vector.iov_len = fwi->size; + state->size = fwi->size; + state->off = fwi->offset; /* See comment by similar code in fuse_settatr */ priv = this->private; @@ -2028,25 +1772,20 @@ fuse_write (xlator_t *this, fuse_in_header_t *finh, void *msg) "%"PRIu64": WRITE (%p, size=%"PRIu32", offset=%"PRId64")", finh->unique, fd, fwi->size, fwi->offset); - iobref = iobref_new (); - if (!iobref) { - gf_log ("glusterfs-fuse", GF_LOG_ERROR, - "%"PRIu64": WRITE iobref allocation failed", - finh->unique); - - free_state (state); - return; - } - iobuf = ((fuse_private_t *) (state->this->private))->iobuf; - iobref_add (iobref, iobuf); + state->vector.iov_base = msg; + state->vector.iov_len = fwi->size; - FUSE_FOP (state, fuse_writev_cbk, GF_FOP_WRITE, - writev, fd, &vector, 1, fwi->offset, iobref); + fuse_resolve_and_resume (state, fuse_write_resume); - iobref_unref (iobref); return; } +void +fuse_flush_resume (fuse_state_t *state) +{ + FUSE_FOP (state, fuse_err_cbk, GF_FOP_FLUSH, + flush, state->fd); +} static void fuse_flush (xlator_t *this, fuse_in_header_t *finh, void *msg) @@ -2067,22 +1806,30 @@ fuse_flush (xlator_t *this, fuse_in_header_t *finh, void *msg) gf_log ("glusterfs-fuse", GF_LOG_TRACE, "%"PRIu64": FLUSH %p", finh->unique, fd); - FUSE_FOP (state, fuse_err_cbk, GF_FOP_FLUSH, - flush, fd); + fuse_resolve_and_resume (state, fuse_flush_resume); return; } +static int +fuse_release_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno) +{ + STACK_DESTROY (frame->root); + + return 0; +} static void fuse_release (xlator_t *this, fuse_in_header_t *finh, void *msg) { - struct fuse_release_in *fri = msg; - - fd_t *fd = NULL; - int do_flush = 0; - - fuse_state_t *state = NULL; + struct fuse_release_in *fri = msg; + fd_t *new_fd = NULL; + fd_t *fd = NULL; + int do_flush = 0; + uint64_t tmp_fd_ctx = 0; + int ret = 0; + fuse_state_t *state = NULL; GET_STATE (this, finh, state); fd = FH_TO_FD (fri->fh); @@ -2122,25 +1869,47 @@ fuse_release (xlator_t *this, fuse_in_header_t *finh, void *msg) do_flush = 1; #endif + /* TODO */ gf_log ("glusterfs-fuse", GF_LOG_TRACE, "%"PRIu64": RELEASE %p%s", finh->unique, fd, do_flush ? " (FLUSH implied)" : ""); if (do_flush) { state->lk_owner = (uint64_t)-1; + ret = fd_ctx_get (fd, this, &tmp_fd_ctx); + if (!ret) { + new_fd = (fd_t *)(long)tmp_fd_ctx; + FUSE_FOP (state, fuse_release_cbk, GF_FOP_FLUSH, flush, + new_fd); + fd_unref (new_fd); + } + FUSE_FOP (state, fuse_err_cbk, GF_FOP_FLUSH, flush, fd); + fd_unref (fd); } else { + ret = fd_ctx_get (fd, this, &tmp_fd_ctx); + if (!ret) { + new_fd = (fd_t *)(long)tmp_fd_ctx; + fd_unref (new_fd); + } fd_unref (fd); send_fuse_err (this, finh, 0); - free_state (state); + free_fuse_state (state); } return; } +void +fuse_fsync_resume (fuse_state_t *state) +{ + /* fsync_flags: 1 means "datasync" (no defines for this) */ + FUSE_FOP (state, fuse_fsync_cbk, GF_FOP_FSYNC, + fsync, state->fd, state->flags & 1); +} static void fuse_fsync (xlator_t *this, fuse_in_header_t *finh, void *msg) @@ -2157,13 +1926,26 @@ fuse_fsync (xlator_t *this, fuse_in_header_t *finh, void *msg) gf_log ("glusterfs-fuse", GF_LOG_TRACE, "%"PRIu64": FSYNC %p", finh->unique, fd); - /* fsync_flags: 1 means "datasync" (no defines for this) */ - FUSE_FOP (state, fuse_fsync_cbk, GF_FOP_FSYNC, - fsync, fd, fsi->fsync_flags & 1); - + state->flags = fsi->fsync_flags; + fuse_resolve_and_resume (state, fuse_fsync_resume); return; } +void +fuse_opendir_resume (fuse_state_t *state) +{ + fd_t *fd = NULL; + + fd = fd_create (state->loc.inode, state->finh->pid); + state->fd = fd; + + gf_log ("glusterfs-fuse", GF_LOG_TRACE, + "%"PRIu64": OPENDIR %s", state->finh->unique, + state->loc.path); + + FUSE_FOP (state, fuse_fd_cbk, GF_FOP_OPENDIR, + opendir, &state->loc, fd); +} static void fuse_opendir (xlator_t *this, fuse_in_header_t *finh, void *msg) @@ -2173,31 +1955,21 @@ fuse_opendir (xlator_t *this, fuse_in_header_t *finh, void *msg) */ fuse_state_t *state = NULL; - fd_t *fd = NULL; int32_t ret = -1; GET_STATE (this, finh, state); ret = fuse_loc_fill (&state->loc, state, finh->nodeid, 0, NULL); - if ((state->loc.inode == NULL) || - (ret < 0)) { + if ((state->loc.inode == NULL) || (ret < 0)) { gf_log ("glusterfs-fuse", GF_LOG_WARNING, "%"PRIu64": OPENDIR %s (fuse_loc_fill() failed)", finh->unique, state->loc.path); send_fuse_err (this, finh, ENOENT); - free_state (state); + free_fuse_state (state); return; } - fd = fd_create (state->loc.inode, finh->pid); - state->fd = fd; - - gf_log ("glusterfs-fuse", GF_LOG_TRACE, - "%"PRIu64": OPENDIR %s", finh->unique, - state->loc.path); - - FUSE_FOP (state, fuse_fd_cbk, GF_FOP_OPENDIR, - opendir, &state->loc, fd); + fuse_resolve_and_resume (state, fuse_opendir_resume); } @@ -2289,7 +2061,7 @@ fuse_readdir_cbk (call_frame_t *frame, void *cookie, xlator_t *this, send_fuse_data (this, finh, buf, size); out: - free_state (state); + free_fuse_state (state); STACK_DESTROY (frame->root); if (buf) GF_FREE (buf); @@ -2297,6 +2069,16 @@ out: } +void +fuse_readdir_resume (fuse_state_t *state) +{ + gf_log ("glusterfs-fuse", GF_LOG_TRACE, + "%"PRIu64": READDIR (%p, size=%zu, offset=%"PRId64")", + state->finh->unique, state->fd, state->size, state->off); + + FUSE_FOP (state, fuse_readdir_cbk, GF_FOP_READDIR, + readdir, state->fd, state->size, state->off); +} static void fuse_readdir (xlator_t *this, fuse_in_header_t *finh, void *msg) @@ -2312,37 +2094,48 @@ fuse_readdir (xlator_t *this, fuse_in_header_t *finh, void *msg) fd = FH_TO_FD (fri->fh); state->fd = fd; - gf_log ("glusterfs-fuse", GF_LOG_TRACE, - "%"PRIu64": READDIR (%p, size=%"PRIu32", offset=%"PRId64")", - finh->unique, fd, fri->size, fri->offset); - - FUSE_FOP (state, fuse_readdir_cbk, GF_FOP_READDIR, - readdir, fd, fri->size, fri->offset); + fuse_resolve_and_resume (state, fuse_readdir_resume); } static void fuse_releasedir (xlator_t *this, fuse_in_header_t *finh, void *msg) { - struct fuse_release_in *fri = msg; - - fuse_state_t *state = NULL; + struct fuse_release_in *fri = msg; + fd_t *new_fd = NULL; + uint64_t tmp_fd_ctx = 0; + int ret = 0; + fuse_state_t *state = NULL; GET_STATE (this, finh, state); state->fd = FH_TO_FD (fri->fh); + /* TODO: free 'new-fd' in the ctx */ gf_log ("glusterfs-fuse", GF_LOG_TRACE, "%"PRIu64": RELEASEDIR %p", finh->unique, state->fd); + ret = fd_ctx_get (state->fd, this, &tmp_fd_ctx); + if (!ret) { + new_fd = (fd_t *)(long)tmp_fd_ctx; + fd_unref (new_fd); + } + fd_unref (state->fd); send_fuse_err (this, finh, 0); - free_state (state); + free_fuse_state (state); return; } +void +fuse_fsyncdir_resume (fuse_state_t *state) +{ + FUSE_FOP (state, fuse_err_cbk, GF_FOP_FSYNCDIR, + fsyncdir, state->fd, state->flags & 1); + +} static void fuse_fsyncdir (xlator_t *this, fuse_in_header_t *finh, void *msg) @@ -2357,8 +2150,8 @@ fuse_fsyncdir (xlator_t *this, fuse_in_header_t *finh, void *msg) GET_STATE (this, finh, state); state->fd = fd; - FUSE_FOP (state, fuse_err_cbk, GF_FOP_FSYNCDIR, - fsyncdir, fd, fsi->fsync_flags & 1); + state->flags = fsi->fsync_flags; + fuse_resolve_and_resume (state, fuse_fsyncdir_resume); return; } @@ -2423,13 +2216,12 @@ fuse_statfs_cbk (call_frame_t *frame, void *cookie, xlator_t *this, send_fuse_err (this, finh, op_errno); } - free_state (state); + free_fuse_state (state); STACK_DESTROY (frame->root); return 0; } - static void fuse_statfs (xlator_t *this, fuse_in_header_t *finh, void *msg) { @@ -2445,7 +2237,7 @@ fuse_statfs (xlator_t *this, fuse_in_header_t *finh, void *msg) finh->unique); send_fuse_err (this, finh, ENOENT); - free_state (state); + free_fuse_state (state); return; } @@ -2456,6 +2248,16 @@ fuse_statfs (xlator_t *this, fuse_in_header_t *finh, void *msg) statfs, &state->loc); } +void +fuse_setxattr_resume (fuse_state_t *state) +{ + gf_log ("glusterfs-fuse", GF_LOG_TRACE, + "%"PRIu64": SETXATTR %s/%"PRIu64" (%s)", state->finh->unique, + state->loc.path, state->finh->nodeid, state->name); + + FUSE_FOP (state, fuse_setxattr_cbk, GF_FOP_SETXATTR, + setxattr, &state->loc, state->dict, state->flags); +} static void fuse_setxattr (xlator_t *this, fuse_in_header_t *finh, void *msg) @@ -2499,7 +2301,7 @@ fuse_setxattr (xlator_t *this, fuse_in_header_t *finh, void *msg) state->loc.path, finh->nodeid, name); send_fuse_err (this, finh, ENOENT); - free_state (state); + free_fuse_state (state); return; } @@ -2509,7 +2311,7 @@ fuse_setxattr (xlator_t *this, fuse_in_header_t *finh, void *msg) "%"PRIu64": SETXATTR dict allocation failed", finh->unique); - free_state (state); + free_fuse_state (state); return; } @@ -2518,12 +2320,10 @@ fuse_setxattr (xlator_t *this, fuse_in_header_t *finh, void *msg) data_from_dynptr ((void *)dict_value, fsi->size)); dict_ref (state->dict); - gf_log ("glusterfs-fuse", GF_LOG_TRACE, - "%"PRIu64": SETXATTR %s/%"PRIu64" (%s)", finh->unique, - state->loc.path, finh->nodeid, name); + state->flags = fsi->flags; + state->name = gf_strdup (name); - FUSE_FOP (state, fuse_setxattr_cbk, GF_FOP_SETXATTR, - setxattr, &state->loc, state->dict, fsi->flags); + fuse_resolve_and_resume (state, fuse_setxattr_resume); return; } @@ -2638,12 +2438,22 @@ out: if (need_to_free_dict) dict_unref (dict); - free_state (state); + free_fuse_state (state); STACK_DESTROY (frame->root); return 0; } +void +fuse_getxattr_resume (fuse_state_t *state) +{ + gf_log ("glusterfs-fuse", GF_LOG_TRACE, + "%"PRIu64": GETXATTR %s/%"PRIu64" (%s)", state->finh->unique, + state->loc.path, state->finh->nodeid, state->name); + + FUSE_FOP (state, fuse_xattr_cbk, GF_FOP_GETXATTR, + getxattr, &state->loc, state->name); +} static void fuse_getxattr (xlator_t *this, fuse_in_header_t *finh, void *msg) @@ -2683,8 +2493,6 @@ fuse_getxattr (xlator_t *this, fuse_in_header_t *finh, void *msg) #endif GET_STATE (this, finh, state); - state->size = fgxi->size; - state->name = gf_strdup (name); ret = fuse_loc_fill (&state->loc, state, finh->nodeid, 0, NULL); if ((state->loc.inode == NULL) || @@ -2694,20 +2502,27 @@ fuse_getxattr (xlator_t *this, fuse_in_header_t *finh, void *msg) finh->unique, state->loc.path, finh->nodeid, name); send_fuse_err (this, finh, ENOENT); - free_state (state); + free_fuse_state (state); return; } - gf_log ("glusterfs-fuse", GF_LOG_TRACE, - "%"PRIu64": GETXATTR %s/%"PRIu64" (%s)", finh->unique, - state->loc.path, finh->nodeid, name); - - FUSE_FOP (state, fuse_xattr_cbk, GF_FOP_GETXATTR, - getxattr, &state->loc, name); + state->size = fgxi->size; + state->name = gf_strdup (name); + fuse_resolve_and_resume (state, fuse_getxattr_resume); return; } +void +fuse_listxattr_resume (fuse_state_t *state) +{ + gf_log ("glusterfs-fuse", GF_LOG_TRACE, + "%"PRIu64": LISTXATTR %s/%"PRIu64, state->finh->unique, + state->loc.path, state->finh->nodeid); + + FUSE_FOP (state, fuse_xattr_cbk, GF_FOP_GETXATTR, + getxattr, &state->loc, NULL); +} static void fuse_listxattr (xlator_t *this, fuse_in_header_t *finh, void *msg) @@ -2718,7 +2533,7 @@ fuse_listxattr (xlator_t *this, fuse_in_header_t *finh, void *msg) int32_t ret = -1; GET_STATE (this, finh, state); - state->size = fgxi->size; + ret = fuse_loc_fill (&state->loc, state, finh->nodeid, 0, NULL); if ((state->loc.inode == NULL) || (ret < 0)) { @@ -2727,20 +2542,26 @@ fuse_listxattr (xlator_t *this, fuse_in_header_t *finh, void *msg) finh->unique, state->loc.path, finh->nodeid); send_fuse_err (this, finh, ENOENT); - free_state (state); + free_fuse_state (state); return; } - gf_log ("glusterfs-fuse", GF_LOG_TRACE, - "%"PRIu64": LISTXATTR %s/%"PRIu64, finh->unique, - state->loc.path, finh->nodeid); - - FUSE_FOP (state, fuse_xattr_cbk, GF_FOP_GETXATTR, - getxattr, &state->loc, NULL); + state->size = fgxi->size; + fuse_resolve_and_resume (state, fuse_listxattr_resume); return; } +void +fuse_removexattr_resume (fuse_state_t *state) +{ + gf_log ("glusterfs-fuse", GF_LOG_TRACE, + "%"PRIu64": REMOVEXATTR %s/%"PRIu64" (%s)", state->finh->unique, + state->loc.path, state->finh->nodeid, state->name); + + FUSE_FOP (state, fuse_err_cbk, GF_FOP_REMOVEXATTR, + removexattr, &state->loc, state->name); +} static void fuse_removexattr (xlator_t *this, fuse_in_header_t *finh, void *msg) @@ -2760,17 +2581,12 @@ fuse_removexattr (xlator_t *this, fuse_in_header_t *finh, void *msg) finh->unique, state->loc.path, finh->nodeid, name); send_fuse_err (this, finh, ENOENT); - free_state (state); + free_fuse_state (state); return; } - gf_log ("glusterfs-fuse", GF_LOG_TRACE, - "%"PRIu64": REMOVEXATTR %s/%"PRIu64" (%s)", finh->unique, - state->loc.path, finh->nodeid, name); - - FUSE_FOP (state, fuse_err_cbk, GF_FOP_REMOVEXATTR, - removexattr, &state->loc, name); - + state->name = gf_strdup (name); + fuse_resolve_and_resume (state, fuse_removexattr_resume); return; } @@ -2817,12 +2633,21 @@ fuse_getlk_cbk (call_frame_t *frame, void *cookie, xlator_t *this, send_fuse_err (this, state->finh, op_errno); } - free_state (state); + free_fuse_state (state); STACK_DESTROY (frame->root); return 0; } +void +fuse_getlk_resume (fuse_state_t *state) +{ + gf_log ("glusterfs-fuse", GF_LOG_TRACE, + "%"PRIu64": GETLK %p", state->finh->unique, state->fd); + + FUSE_FOP (state, fuse_getlk_cbk, GF_FOP_LK, + lk, state->fd, F_GETLK, &state->lk_lock); +} static void fuse_getlk (xlator_t *this, fuse_in_header_t *finh, void *msg) @@ -2831,20 +2656,15 @@ fuse_getlk (xlator_t *this, fuse_in_header_t *finh, void *msg) fuse_state_t *state = NULL; fd_t *fd = NULL; - struct flock lock = {0, }; fd = FH_TO_FD (fli->fh); GET_STATE (this, finh, state); state->fd = fd; - convert_fuse_file_lock (&fli->lk, &lock); + convert_fuse_file_lock (&fli->lk, &state->lk_lock); state->lk_owner = fli->owner; - gf_log ("glusterfs-fuse", GF_LOG_TRACE, - "%"PRIu64": GETLK %p", finh->unique, fd); - - FUSE_FOP (state, fuse_getlk_cbk, GF_FOP_LK, - lk, fd, F_GETLK, &lock); + fuse_resolve_and_resume (state, fuse_getlk_resume); return; } @@ -2889,13 +2709,25 @@ fuse_setlk_cbk (call_frame_t *frame, void *cookie, xlator_t *this, send_fuse_err (this, state->finh, op_errno); } - free_state (state); + free_fuse_state (state); STACK_DESTROY (frame->root); return 0; } +void +fuse_setlk_resume (fuse_state_t *state) +{ + gf_log ("glusterfs-fuse", GF_LOG_TRACE, + "%"PRIu64": SETLK%s %p", state->finh->unique, + state->finh->opcode == FUSE_SETLK ? "" : "W", state->fd); + + FUSE_FOP (state, fuse_setlk_cbk, GF_FOP_LK, lk, state->fd, + state->finh->opcode == FUSE_SETLK ? F_SETLK : F_SETLKW, + &state->lk_lock); +} + static void fuse_setlk (xlator_t *this, fuse_in_header_t *finh, void *msg) { @@ -2903,23 +2735,16 @@ fuse_setlk (xlator_t *this, fuse_in_header_t *finh, void *msg) fuse_state_t *state = NULL; fd_t *fd = NULL; - struct flock lock = {0, }; fd = FH_TO_FD (fli->fh); GET_STATE (this, finh, state); state->finh = finh; state->fd = fd; - convert_fuse_file_lock (&fli->lk, &lock); + convert_fuse_file_lock (&fli->lk, &state->lk_lock); state->lk_owner = fli->owner; - gf_log ("glusterfs-fuse", GF_LOG_TRACE, - "%"PRIu64": SETLK%s %p", finh->unique, - finh->opcode == FUSE_SETLK ? "" : "W", fd); - - FUSE_FOP (state, fuse_setlk_cbk, GF_FOP_LK, - lk, fd, finh->opcode == FUSE_SETLK ? F_SETLK : F_SETLKW, - &lock); + fuse_resolve_and_resume (state, fuse_setlk_resume); return; } @@ -3142,8 +2967,9 @@ fuse_graph_sync (xlator_t *this) unlock: pthread_mutex_unlock (&priv->sync_mutex); - if (need_first_lookup) + if (need_first_lookup) { fuse_first_lookup (this); + } return 0; } diff --git a/xlators/mount/fuse/src/fuse-bridge.h b/xlators/mount/fuse/src/fuse-bridge.h new file mode 100644 index 00000000000..8165053e06f --- /dev/null +++ b/xlators/mount/fuse/src/fuse-bridge.h @@ -0,0 +1,277 @@ +/* + Copyright (c) 2006-2009 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/>. +*/ + +#ifndef _GF_FUSE_BRIDGE_H_ +#define _GF_FUSE_BRIDGE_H_ + +#include <stdint.h> +#include <signal.h> +#include <pthread.h> +#include <stddef.h> +#include <dirent.h> +#include <sys/mount.h> +#include <sys/time.h> + +#ifndef _CONFIG_H +#define _CONFIG_H +#include "config.h" +#endif /* _CONFIG_H */ + +#include "glusterfs.h" +#include "logging.h" +#include "xlator.h" +#include "defaults.h" +#include "common-utils.h" +#include "glusterfsd-common.h" +#include "statedump.h" + +#ifdef GF_DARWIN_HOST_OS +/* This is MacFUSE's marker for MacFUSE-specific code */ +#define __FreeBSD__ 10 +#include "fuse_kernel_macfuse.h" +#else +#include "fuse_kernel.h" +#endif +#include "fuse-misc.h" +#include "fuse-mount.h" +#include "fuse-mem-types.h" + +#include "list.h" +#include "dict.h" + +/* TODO: when supporting posix acl, remove this definition */ +#define DISABLE_POSIX_ACL + +#ifdef GF_LINUX_HOST_OS +#define FUSE_OP_HIGH (FUSE_POLL + 1) +#endif +#ifdef GF_DARWIN_HOST_OS +#define FUSE_OP_HIGH (FUSE_DESTROY + 1) +#endif +#define GLUSTERFS_XATTR_LEN_MAX 65536 + +#define MAX_FUSE_PROC_DELAY 1 + +typedef struct fuse_in_header fuse_in_header_t; +typedef void (fuse_handler_t) (xlator_t *this, fuse_in_header_t *finh, + void *msg); + +struct fuse_private { + int fd; + uint32_t proto_minor; + char *volfile; + size_t volfile_size; + char *mount_point; + struct iobuf *iobuf; + + pthread_t fuse_thread; + char fuse_thread_started; + + uint32_t direct_io_mode; + size_t *msg0_len_p; + + double entry_timeout; + double attribute_timeout; + + pthread_cond_t sync_cond; + pthread_mutex_t sync_mutex; + char child_up; + + char init_recvd; + + gf_boolean_t strict_volfile_check; + + fuse_handler_t **fuse_ops; + fuse_handler_t **fuse_ops0; + pthread_mutex_t fuse_dump_mutex; + int fuse_dump_fd; + + glusterfs_graph_t *next_graph; + xlator_t *active_subvol; +}; +typedef struct fuse_private fuse_private_t; + +#define _FH_TO_FD(fh) ((fd_t *)(uintptr_t)(fh)) + +#define FH_TO_FD(fh) ((_FH_TO_FD (fh))?(fd_ref (_FH_TO_FD (fh))):((fd_t *) 0)) + +#define FUSE_FOP(state, ret, op_num, fop, args ...) \ + do { \ + call_frame_t *frame = NULL; \ + xlator_t *xl = NULL; \ + \ + frame = get_call_frame_for_req (state); \ + if (!frame) { \ + /* This is not completely clean, as some \ + * earlier allocations might remain unfreed \ + * if we return at this point, but still \ + * better than trying to go on with a NULL \ + * frame ... \ + */ \ + gf_log ("glusterfs-fuse", \ + GF_LOG_ERROR, \ + "FUSE message" \ + " unique %"PRIu64" opcode %d:" \ + " frame allocation failed", \ + state->finh->unique, \ + state->finh->opcode); \ + free_fuse_state (state); \ + return; \ + } \ + xl = fuse_state_subvol (state); \ + \ + frame->root->state = state; \ + frame->root->op = op_num; \ + frame->op = op_num; \ + STACK_WIND (frame, ret, xl, xl->fops->fop, args); \ + } while (0) + + +#define FUSE_FOP_COOKIE(state, xl, ret, cky, op_num, fop, args ...) \ + do { \ + call_frame_t *frame = NULL; \ + \ + frame = get_call_frame_for_req (state); \ + if (!frame) { \ + gf_log ("glusterfs-fuse", \ + GF_LOG_ERROR, \ + "FUSE message" \ + " unique %"PRIu64" opcode %d:" \ + " frame allocation failed", \ + state->finh->unique, \ + state->finh->opcode); \ + free_fuse_state (state); \ + return 0; \ + } \ + \ + frame->root->state = state; \ + frame->root->op = op_num; \ + frame->op = op_num; \ + STACK_WIND_COOKIE (frame, ret, cky, xl, xl->fops->fop, args); \ + } while (0) + +#define GF_SELECT_LOG_LEVEL(_errno) \ + (((_errno == ENOENT) || (_errno == ESTALE))? \ + GF_LOG_DEBUG) + +#define GET_STATE(this, finh, state) \ + do { \ + state = get_fuse_state (this, finh); \ + if (!state) { \ + gf_log ("glusterfs-fuse", \ + GF_LOG_ERROR, \ + "FUSE message unique %"PRIu64" opcode %d:" \ + " state allocation failed", \ + finh->unique, finh->opcode); \ + \ + send_fuse_err (this, finh, ENOMEM); \ + GF_FREE (finh); \ + \ + return; \ + } \ + } while (0) + + + +typedef enum { + RESOLVE_MUST = 1, + RESOLVE_NOT, + RESOLVE_MAY, + RESOLVE_DONTCARE, + RESOLVE_EXACT +} gf_resolve_type_t; + +struct gf_resolve_comp { + char *basename; + ino_t ino; + uint64_t gen; + inode_t *inode; +}; + +typedef struct { + gf_resolve_type_t type; + ino_t ino; + uint64_t gen; + ino_t par; + fd_t *fd; + char *path; + char *bname; + char *resolved; + int op_ret; + int op_errno; + loc_t deep_loc; + struct gf_resolve_comp *components; + int comp_count; +} gf_resolve_t; + + +typedef struct { + void *pool; + xlator_t *this; + inode_table_t *itable; + loc_t loc; + loc_t loc2; + fuse_in_header_t *finh; + int32_t flags; + off_t off; + size_t size; + unsigned long nlookup; + fd_t *fd; + dict_t *dict; + char *name; + char is_revalidate; + gf_boolean_t truncate_needed; + gf_lock_t lock; + uint64_t lk_owner; + + /* used within resolve_and_resume */ + /* */ + gf_resolve_t resolve; + gf_resolve_t resolve2; + + loc_t *loc_now; + gf_resolve_t *resolve_now; + + void *resume_fn; + + int valid; + int mask; + dev_t rdev; + mode_t mode; + struct iatt attr; + struct flock lk_lock; + struct iovec vector; +} fuse_state_t; + +typedef void (*fuse_resume_fn_t) (fuse_state_t *state); + +GF_MUST_CHECK int32_t +fuse_loc_fill (loc_t *loc, fuse_state_t *state, ino_t ino, + ino_t par, const char *name); +call_frame_t *get_call_frame_for_req (fuse_state_t *state); +fuse_state_t *get_fuse_state (xlator_t *this, fuse_in_header_t *finh); +void free_fuse_state (fuse_state_t *state); +void gf_fuse_stat2attr (struct iatt *st, struct fuse_attr *fa); +uint64_t inode_to_fuse_nodeid (inode_t *inode); +xlator_t *fuse_state_subvol (fuse_state_t *state); +xlator_t *fuse_active_subvol (xlator_t *fuse); +inode_t *fuse_ino_to_inode (uint64_t ino, xlator_t *fuse); +int fuse_resolve_and_resume (fuse_state_t *state, fuse_resume_fn_t fn); + +#endif /* _GF_FUSE_BRIDGE_H_ */ diff --git a/xlators/mount/fuse/src/fuse-helpers.c b/xlators/mount/fuse/src/fuse-helpers.c new file mode 100644 index 00000000000..d478d014db0 --- /dev/null +++ b/xlators/mount/fuse/src/fuse-helpers.c @@ -0,0 +1,300 @@ +/* + Copyright (c) 2010 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/>. +*/ + +#include "fuse-bridge.h" + +xlator_t * +fuse_state_subvol (fuse_state_t *state) +{ + xlator_t *subvol = NULL; + + if (!state) + return NULL; + + if (state->loc.inode) + subvol = state->loc.inode->table->xl; + + if (state->fd) + subvol = state->fd->inode->table->xl; + + return subvol; +} + + +xlator_t * +fuse_active_subvol (xlator_t *fuse) +{ + fuse_private_t *priv = NULL; + + priv = fuse->private; + + return priv->active_subvol; +} + + + +static void +fuse_resolve_wipe (gf_resolve_t *resolve) +{ + struct gf_resolve_comp *comp = NULL; + + if (resolve->path) + GF_FREE ((void *)resolve->path); + + if (resolve->bname) + GF_FREE ((void *)resolve->bname); + + if (resolve->resolved) + GF_FREE ((void *)resolve->resolved); + + loc_wipe (&resolve->deep_loc); + + comp = resolve->components; + + if (comp) { +/* + int i = 0; + + for (i = 0; comp[i].basename; i++) { + if (comp[i].inode) + inode_unref (comp[i].inode); + } +*/ + GF_FREE ((void *)resolve->components); + } +} + +void +free_fuse_state (fuse_state_t *state) +{ + loc_wipe (&state->loc); + + loc_wipe (&state->loc2); + + if (state->dict) { + dict_unref (state->dict); + state->dict = (void *)0xaaaaeeee; + } + if (state->name) { + GF_FREE (state->name); + state->name = NULL; + } + if (state->fd) { + fd_unref (state->fd); + state->fd = (void *)0xfdfdfdfd; + } + if (state->finh) { + GF_FREE (state->finh); + state->finh = NULL; + } + + fuse_resolve_wipe (&state->resolve); + fuse_resolve_wipe (&state->resolve2); + +#ifdef DEBUG + memset (state, 0x90, sizeof (*state)); +#endif + GF_FREE (state); + state = NULL; +} + + +fuse_state_t * +get_fuse_state (xlator_t *this, fuse_in_header_t *finh) +{ + fuse_state_t *state = NULL; + + state = (void *)GF_CALLOC (1, sizeof (*state), + gf_fuse_mt_fuse_state_t); + if (!state) + return NULL; + state->pool = this->ctx->pool; + state->finh = finh; + state->this = this; + + LOCK_INIT (&state->lock); + + return state; +} + + +call_frame_t * +get_call_frame_for_req (fuse_state_t *state) +{ + call_pool_t *pool = NULL; + fuse_in_header_t *finh = NULL; + call_frame_t *frame = NULL; + xlator_t *this = NULL; + + pool = state->pool; + finh = state->finh; + this = state->this; + + frame = create_frame (this, pool); + if (!frame) + return NULL; + + if (finh) { + frame->root->uid = finh->uid; + frame->root->gid = finh->gid; + frame->root->pid = finh->pid; + frame->root->lk_owner = state->lk_owner; + frame->root->unique = finh->unique; + } + + frame->root->type = GF_OP_TYPE_FOP; + + return frame; +} + + +inode_t * +fuse_ino_to_inode (uint64_t ino, xlator_t *fuse) +{ + inode_t *inode = NULL; + xlator_t *active_subvol = NULL; + + if (ino == 1) { + active_subvol = fuse_active_subvol (fuse); + inode = active_subvol->itable->root; + } else { + inode = (inode_t *) (unsigned long) ino; + inode_ref (inode); + } + + return inode; +} + +uint64_t +inode_to_fuse_nodeid (inode_t *inode) +{ + if (!inode || inode->ino == 1) + return 1; + + return (unsigned long) inode; +} + + +GF_MUST_CHECK int32_t +fuse_loc_fill (loc_t *loc, fuse_state_t *state, ino_t ino, + ino_t par, const char *name) +{ + inode_t *inode = NULL; + inode_t *parent = NULL; + int32_t ret = -1; + char *path = NULL; + + /* resistance against multiple invocation of loc_fill not to get + reference leaks via inode_search() */ + + if (name) { + parent = loc->parent; + if (!parent) { + parent = fuse_ino_to_inode (par, state->this); + loc->parent = parent; + } + + inode = loc->inode; + if (!inode) { + inode = inode_grep (parent->table, parent, name); + loc->inode = inode; + } + + ret = inode_path (parent, name, &path); + if (ret <= 0) { + gf_log ("glusterfs-fuse", GF_LOG_DEBUG, + "inode_path failed for %"PRId64"/%s", + parent->ino, name); + goto fail; + } + loc->path = path; + } else { + inode = loc->inode; + if (!inode) { + inode = fuse_ino_to_inode (ino, state->this); + loc->inode = inode; + } + + parent = loc->parent; + if (!parent) { + parent = inode_parent (inode, par, name); + loc->parent = parent; + } + + ret = inode_path (inode, NULL, &path); + if (ret <= 0) { + gf_log ("glusterfs-fuse", GF_LOG_DEBUG, + "inode_path failed for %"PRId64, + inode->ino); + goto fail; + } + loc->path = path; + } + + if (inode) + loc->ino = inode->ino; + + if (loc->path) { + loc->name = strrchr (loc->path, '/'); + if (loc->name) + loc->name++; + else + loc->name = ""; + } + + if ((ino != 1) && (parent == NULL)) { + gf_log ("fuse-bridge", GF_LOG_DEBUG, + "failed to search parent for %"PRId64"/%s (%"PRId64")", + (ino_t)par, name, (ino_t)ino); + ret = -1; + goto fail; + } + ret = 0; +fail: + return ret; +} + + +/* courtesy of folly */ +void +gf_fuse_stat2attr (struct iatt *st, struct fuse_attr *fa) +{ + fa->ino = st->ia_ino; + fa->size = st->ia_size; + fa->blocks = st->ia_blocks; + fa->atime = st->ia_atime; + fa->mtime = st->ia_mtime; + fa->ctime = st->ia_ctime; + fa->atimensec = st->ia_atime_nsec; + fa->mtimensec = st->ia_mtime_nsec; + fa->ctimensec = st->ia_ctime_nsec; + fa->mode = st_mode_from_ia (st->ia_prot, st->ia_type); + fa->nlink = st->ia_nlink; + fa->uid = st->ia_uid; + fa->gid = st->ia_gid; + fa->rdev = st->ia_rdev; +#if FUSE_KERNEL_MINOR_VERSION >= 9 + fa->blksize = st->ia_blksize; +#endif +#ifdef GF_DARWIN_HOST_OS + fa->crtime = (uint64_t)-1; + fa->crtimensec = (uint32_t)-1; + fa->flags = 0; +#endif +} diff --git a/xlators/mount/fuse/src/fuse-resolve.c b/xlators/mount/fuse/src/fuse-resolve.c new file mode 100644 index 00000000000..b90ef3d5f8d --- /dev/null +++ b/xlators/mount/fuse/src/fuse-resolve.c @@ -0,0 +1,747 @@ +/* + Copyright (c) 2010 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/>. +*/ + +#ifndef _CONFIG_H +#define _CONFIG_H +#include "config.h" +#endif + +#include "fuse-bridge.h" + +static int +gf_resolve_all (fuse_state_t *state); +static int +resolve_entry_simple (fuse_state_t *state); +static int +resolve_inode_simple (fuse_state_t *state); +static int +resolve_path_simple (fuse_state_t *state); + +static int +component_count (const char *path) +{ + int count = 0; + const char *trav = NULL; + + for (trav = path; *trav; trav++) { + if (*trav == '/') + count++; + } + + return count + 2; +} + + +static int +prepare_components (fuse_state_t *state) +{ + xlator_t *active_xl = NULL; + gf_resolve_t *resolve = NULL; + char *resolved = NULL; + struct gf_resolve_comp *components = NULL; + char *trav = NULL; + int count = 0; + int i = 0; + + resolve = state->resolve_now; + + resolved = gf_strdup (resolve->path); + resolve->resolved = resolved; + + count = component_count (resolve->path); + components = GF_CALLOC (sizeof (*components), count, 0); //TODO + if (!components) + goto out; + resolve->components = components; + + active_xl = fuse_active_subvol (state->this); + + components[0].basename = ""; + components[0].ino = 1; + components[0].gen = 0; + components[0].inode = inode_ref (active_xl->itable->root); + + i = 1; + for (trav = resolved; *trav; trav++) { + if (*trav == '/') { + components[i].basename = trav + 1; + *trav = 0; + i++; + } + } +out: + return 0; +} + + +static int +resolve_loc_touchup (fuse_state_t *state) +{ + gf_resolve_t *resolve = NULL; + loc_t *loc = NULL; + char *path = NULL; + int ret = 0; + + resolve = state->resolve_now; + loc = state->loc_now; + + if (!loc->path) { + if (loc->parent) { + ret = inode_path (loc->parent, resolve->bname, &path); + } else if (loc->inode) { + ret = inode_path (loc->inode, NULL, &path); + } + if (ret) + gf_log ("", GF_LOG_TRACE, + "return value inode_path %d", ret); + + if (!path) + path = gf_strdup (resolve->path); + + loc->path = path; + } + + loc->name = strrchr (loc->path, '/'); + if (loc->name) + loc->name++; + + if (!loc->parent && loc->inode) { + loc->parent = inode_parent (loc->inode, 0, NULL); + } + + return 0; +} + +static int +fuse_resolve_newfd_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, fd_t *fd) +{ + fuse_state_t *state = NULL; + gf_resolve_t *resolve = NULL; + fd_t *old_fd = NULL; + fd_t *tmp_fd = NULL; + uint64_t tmp_fd_ctx = 0; + int ret = 0; + + state = frame->root->state; + resolve = state->resolve_now; + + STACK_DESTROY (frame->root); + + if (op_ret == -1) { + goto out; + } + + old_fd = resolve->fd; + + state->fd = fd_ref (fd); + + fd_bind (fd); + + resolve->fd = NULL; + ret = fd_ctx_del (old_fd, state->this, &tmp_fd_ctx); + if (!ret) { + tmp_fd = (fd_t *)(long)tmp_fd_ctx; + fd_unref (tmp_fd); + } + ret = fd_ctx_set (old_fd, state->this, (uint64_t)(long)fd); + if (ret) + gf_log ("resolve", GF_LOG_WARNING, + "failed to set the fd ctx with resolved fd"); +out: + gf_resolve_all (state); + return 0; +} + +static void +gf_resolve_new_fd (fuse_state_t *state) +{ + gf_resolve_t *resolve = NULL; + fd_t *new_fd = NULL; + fd_t *fd = NULL; + + resolve = state->resolve_now; + fd = resolve->fd; + + new_fd = fd_create (state->loc.inode, state->finh->pid); + new_fd->flags = (fd->flags & ~O_TRUNC); + + gf_log ("resolve", GF_LOG_DEBUG, + "%"PRIu64": OPEN %s", state->finh->unique, + state->loc.path); + + FUSE_FOP (state, fuse_resolve_newfd_cbk, GF_FOP_OPEN, + open, &state->loc, new_fd->flags, new_fd, 0); +} + +static int +resolve_deep_continue (fuse_state_t *state) +{ + gf_resolve_t *resolve = NULL; + int ret = 0; + + resolve = state->resolve_now; + + resolve->op_ret = 0; + resolve->op_errno = 0; + + if (resolve->par) + ret = resolve_entry_simple (state); + else if (resolve->ino) + ret = resolve_inode_simple (state); + else if (resolve->path) + ret = resolve_path_simple (state); + if (ret) + gf_log ("resolve", GF_LOG_TRACE, + "return value of resolve_*_simple %d", ret); + + resolve_loc_touchup (state); + + /* This function is called by either fd resolve or inode resolve */ + if (!resolve->fd) + gf_resolve_all (state); + else + gf_resolve_new_fd (state); + + return 0; +} + + +static int +resolve_deep_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) +{ + xlator_t *active_xl = NULL; + fuse_state_t *state = NULL; + gf_resolve_t *resolve = NULL; + struct gf_resolve_comp *components = NULL; + inode_t *link_inode = NULL; + int i = 0; + + state = frame->root->state; + resolve = state->resolve_now; + components = resolve->components; + + i = (long) cookie; + + STACK_DESTROY (frame->root); + + if (op_ret == -1) { + goto get_out_of_here; + } + + if (i != 0) { + inode_ref (inode); + /* no linking for root inode */ + link_inode = inode_link (inode, resolve->deep_loc.parent, + resolve->deep_loc.name, buf); + components[i].inode = inode_ref (link_inode); + link_inode = NULL; + } + inode_ref (resolve->deep_loc.parent); + inode_ref (inode); + loc_wipe (&resolve->deep_loc); + i++; /* next component */ + + if (!components[i].basename) { + /* all components of the path are resolved */ + goto get_out_of_here; + } + + /* join the current component with the path resolved until now */ + *(components[i].basename - 1) = '/'; + + active_xl = fuse_active_subvol (state->this); + + resolve->deep_loc.path = gf_strdup (resolve->resolved); + resolve->deep_loc.parent = inode_ref (components[i-1].inode); + resolve->deep_loc.inode = inode_new (active_xl->itable); + resolve->deep_loc.name = components[i].basename; + + FUSE_FOP_COOKIE (state, active_xl, resolve_deep_cbk, (void *)(long)i, + GF_FOP_LOOKUP, lookup, &resolve->deep_loc, NULL); + return 0; + +get_out_of_here: + resolve_deep_continue (state); + return 0; +} + + +static int +resolve_path_deep (fuse_state_t *state) +{ + xlator_t *active_xl = NULL; + gf_resolve_t *resolve = NULL; + struct gf_resolve_comp *components = NULL; + inode_t *inode = NULL; + long i = 0; + + resolve = state->resolve_now; + + prepare_components (state); + + components = resolve->components; + + /* start from the root */ + active_xl = fuse_active_subvol (state->this); + resolve->deep_loc.inode = inode_ref (active_xl->itable->root); + resolve->deep_loc.path = gf_strdup ("/"); + resolve->deep_loc.name = ""; + + for (i = 1; components[i].basename; i++) { + *(components[i].basename - 1) = '/'; + inode = inode_grep (active_xl->itable, components[i-1].inode, + components[i].basename); + if (!inode) + break; + components[i].inode = inode_ref (inode); + } + + if (!components[i].basename) + goto resolved; + + resolve->deep_loc.path = gf_strdup (resolve->resolved); + resolve->deep_loc.parent = inode_ref (components[i-1].inode); + resolve->deep_loc.inode = inode_new (active_xl->itable); + resolve->deep_loc.name = components[i].basename; + + FUSE_FOP_COOKIE (state, active_xl, resolve_deep_cbk, (void *)(long)i, + GF_FOP_LOOKUP, lookup, &resolve->deep_loc, NULL); + + return 0; +resolved: + resolve_deep_continue (state); + return 0; +} + + +static int +resolve_path_simple (fuse_state_t *state) +{ + gf_resolve_t *resolve = NULL; + struct gf_resolve_comp *components = NULL; + int ret = -1; + int par_idx = 0; + int ino_idx = 0; + int i = 0; + + resolve = state->resolve_now; + components = resolve->components; + + if (!components) { + resolve->op_ret = -1; + resolve->op_errno = ENOENT; + goto out; + } + + for (i = 0; components[i].basename; i++) { + par_idx = ino_idx; + ino_idx = i; + } + + if (!components[par_idx].inode) { + resolve->op_ret = -1; + resolve->op_errno = ENOENT; + goto out; + } + + if (!components[ino_idx].inode && + (resolve->type == RESOLVE_MUST || resolve->type == RESOLVE_EXACT)) { + resolve->op_ret = -1; + resolve->op_errno = ENOENT; + goto out; + } + + if (components[ino_idx].inode && resolve->type == RESOLVE_NOT) { + resolve->op_ret = -1; + resolve->op_errno = EEXIST; + goto out; + } + + if (components[ino_idx].inode) + state->loc_now->inode = inode_ref (components[ino_idx].inode); + state->loc_now->parent = inode_ref (components[par_idx].inode); + + ret = 0; + +out: + return ret; +} + +/* + 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 +*/ + +static int +resolve_entry_simple (fuse_state_t *state) +{ + xlator_t *this = NULL; + xlator_t *active_xl = NULL; + gf_resolve_t *resolve = NULL; + inode_t *parent = NULL; + inode_t *inode = NULL; + int ret = 0; + + this = state->this; + resolve = state->resolve_now; + + active_xl = fuse_active_subvol (this); + + parent = inode_get (active_xl->itable, resolve->par, 0); + if (!parent) { + /* simple resolution is indecisive. need to perform + deep resolution */ + resolve->op_ret = -1; + resolve->op_errno = ENOENT; + ret = 1; + + inode = inode_grep (active_xl->itable, parent, resolve->bname); + if (inode != NULL) { + gf_log (this->name, GF_LOG_DEBUG, "%"PRId64": inode " + "(pointer:%p ino: %"PRIu64") present but parent" + " is NULL for path (%s)", 0L, + inode, inode->ino, resolve->path); + inode_unref (inode); + } + goto out; + } + + /* expected @parent was found from the inode cache */ + state->loc_now->parent = inode_ref (parent); + + inode = inode_grep (active_xl->itable, parent, resolve->bname); + if (!inode) { + switch (resolve->type) { + case RESOLVE_DONTCARE: + case RESOLVE_NOT: + ret = 0; + break; + case RESOLVE_MAY: + ret = 1; + break; + default: + resolve->op_ret = -1; + resolve->op_errno = ENOENT; + ret = 1; + break; + } + + goto out; + } + + if (resolve->type == RESOLVE_NOT) { + gf_log (this->name, GF_LOG_DEBUG, "inode (pointer: %p ino:%" + PRIu64") found for path (%s) while type is RESOLVE_NOT", + inode, inode->ino, resolve->path); + resolve->op_ret = -1; + resolve->op_errno = EEXIST; + ret = -1; + goto out; + } + + ret = 0; + + state->loc_now->inode = inode_ref (inode); + +out: + if (parent) + inode_unref (parent); + + if (inode) + inode_unref (inode); + + return ret; +} + + +static int +gf_resolve_entry (fuse_state_t *state) +{ + int ret = 0; + loc_t *loc = NULL; + + loc = state->loc_now; + + ret = resolve_entry_simple (state); + + if (ret > 0) { + loc_wipe (loc); + resolve_path_deep (state); + return 0; + } + + if (ret == 0) + resolve_loc_touchup (state); + + gf_resolve_all (state); + + return 0; +} + + +static int +resolve_inode_simple (fuse_state_t *state) +{ + xlator_t *active_xl = NULL; + gf_resolve_t *resolve = NULL; + inode_t *inode = NULL; + int ret = 0; + + resolve = state->resolve_now; + + active_xl = fuse_active_subvol (state->this); + + if (resolve->type == RESOLVE_EXACT) { + inode = inode_get (active_xl->itable, resolve->ino, + resolve->gen); + } else { + inode = inode_get (active_xl->itable, resolve->ino, 0); + } + + if (!inode) { + resolve->op_ret = -1; + resolve->op_errno = ENOENT; + ret = 1; + goto out; + } + + ret = 0; + + state->loc_now->inode = inode_ref (inode); + +out: + if (inode) + inode_unref (inode); + + return ret; +} + + +static int +gf_resolve_inode (fuse_state_t *state) +{ + int ret = 0; + loc_t *loc = NULL; + + loc = state->loc_now; + + ret = resolve_inode_simple (state); + + if (ret > 0) { + loc_wipe (loc); + resolve_path_deep (state); + return 0; + } + + if (ret == 0) + resolve_loc_touchup (state); + + gf_resolve_all (state); + + return 0; +} + + +static int +gf_resolve_fd (fuse_state_t *state) +{ + gf_resolve_t *resolve = NULL; + fd_t *fd = NULL; + int ret = 0; + uint64_t tmp_fd_ctx = 0; + char *path = NULL; + char *name = NULL; + + resolve = state->resolve_now; + + fd = resolve->fd; + + ret = fd_ctx_get (fd, state->this, &tmp_fd_ctx); + if (!ret) { + state->fd = (fd_t *)(long)tmp_fd_ctx; + fd_ref (state->fd); + gf_resolve_all (state); + goto out; + } + + ret = inode_path (fd->inode, 0, &path); + if (!ret || !path) + gf_log ("", GF_LOG_WARNING, + "failed to do inode-path on fd %d %s", ret, path); + + name = strrchr (path, '/'); + if (name) + name++; + + resolve->path = path; + resolve->bname = gf_strdup (name); + + state->loc_now = &state->loc; + + resolve_path_deep (state); + +out: + return 0; +} + + +static int +gf_resolve (fuse_state_t *state) + { + gf_resolve_t *resolve = NULL; + + resolve = state->resolve_now; + + if (resolve->fd) { + + gf_resolve_fd (state); + + } else if (resolve->par) { + + gf_resolve_entry (state); + + } else if (resolve->ino) { + + gf_resolve_inode (state); + + } else if (resolve->path) { + + resolve_path_deep (state); + + } else { + + resolve->op_ret = -1; + resolve->op_errno = EINVAL; + + gf_resolve_all (state); + } + + return 0; +} + + +static int +gf_resolve_done (fuse_state_t *state) +{ + fuse_resume_fn_t fn = NULL; + + fn = state->resume_fn; + if (fn) + fn (state); + + return 0; +} + + +/* + * This function is called multiple times, once per resolving one location/fd. + * state->resolve_now is used to decide which location/fd is to be resolved now + */ +static int +gf_resolve_all (fuse_state_t *state) +{ + xlator_t *this = NULL; + + if (state->resolve_now == NULL) { + + state->resolve_now = &state->resolve; + state->loc_now = &state->loc; + + gf_resolve (state); + + } else if (state->resolve_now == &state->resolve) { + + state->resolve_now = &state->resolve2; + state->loc_now = &state->loc2; + + gf_resolve (state); + + } else if (state->resolve_now == &state->resolve2) { + + gf_resolve_done (state); + + } else { + gf_log (this->name, GF_LOG_ERROR, + "Invalid pointer for state->resolve_now"); + } + + 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; + + 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) + goto resume; + + /* If the resolve is for 'fd' and its open with 'write' flag + set, don't switch to new graph yet */ + if (state->fd && ((state->fd->flags & O_RDWR) || + (state->fd->flags & O_WRONLY))) + goto resume; + + if (state->loc.path) { + state->resolve.path = gf_strdup (state->loc.path); + state->resolve.bname = gf_strdup (state->loc.name); + /* TODO: make sure there is no leaks in inode refs */ + //loc_wipe (&state->loc); + state->loc.inode = NULL; + state->loc.parent = NULL; + } + + /* Needed for rename and link */ + if (state->loc2.path) { + state->resolve2.path = gf_strdup (state->loc2.path); + state->resolve2.bname = gf_strdup (state->loc2.name); + //loc_wipe (&state->loc2); + state->loc2.inode = NULL; + state->loc2.parent = NULL; + } + + if (state->fd) { + state->resolve.fd = state->fd; + /* TODO: check if its a leak, if yes, then do 'unref' */ + state->fd = NULL; + } + + gf_resolve_all (state); + + return 0; +resume: + fn (state); + + return 0; +} |