diff options
Diffstat (limited to 'xlators/mount')
| -rw-r--r-- | xlators/mount/fuse/src/Makefile.am | 22 | ||||
| -rw-r--r-- | xlators/mount/fuse/src/fuse-bridge.c | 2255 | ||||
| -rw-r--r-- | xlators/mount/fuse/src/fuse-bridge.h | 279 | ||||
| -rw-r--r-- | xlators/mount/fuse/src/fuse-helpers.c | 257 | ||||
| -rw-r--r-- | xlators/mount/fuse/src/fuse-mem-types.h | 21 | ||||
| -rw-r--r-- | xlators/mount/fuse/src/fuse-resolve.c | 294 | ||||
| -rwxr-xr-x | xlators/mount/fuse/utils/mount.glusterfs.in | 392 | ||||
| -rwxr-xr-x | xlators/mount/fuse/utils/mount_glusterfs.in | 3 |
8 files changed, 2529 insertions, 994 deletions
diff --git a/xlators/mount/fuse/src/Makefile.am b/xlators/mount/fuse/src/Makefile.am index 7bb3931ec..653121d18 100644 --- a/xlators/mount/fuse/src/Makefile.am +++ b/xlators/mount/fuse/src/Makefile.am @@ -1,26 +1,36 @@ -noinst_HEADERS = $(CONTRIBDIR)/fuse-include/fuse_kernel.h\ - $(CONTRIBDIR)/fuse-include/fuse-mount.h\ +noinst_HEADERS_linux = $(CONTRIBDIR)/fuse-include/fuse_kernel.h\ + $(CONTRIBDIR)/fuse-include/mount_util.h\ + $(CONTRIBDIR)/fuse-lib/mount-gluster-compat.h +noinst_HEADERS_darwin = $(CONTRIBDIR)/fuse-include/fuse_kernel_macfuse.h +noinst_HEADERS_common = $(CONTRIBDIR)/fuse-include/fuse-mount.h\ $(CONTRIBDIR)/fuse-include/fuse-misc.h fuse-mem-types.h \ fuse-bridge.h +if GF_DARWIN_HOST_OS + noinst_HEADERS = $(noinst_HEADERS_common) $(noinst_HEADERS_darwin) +else + noinst_HEADERS = $(noinst_HEADERS_common) $(noinst_HEADERS_linux) +endif + xlator_LTLIBRARIES = fuse.la xlatordir = $(libdir)/glusterfs/$(PACKAGE_VERSION)/xlator/mount if GF_DARWIN_HOST_OS mount_source=$(CONTRIBDIR)/macfuse/mount_darwin.c else - mount_source=$(CONTRIBDIR)/fuse-lib/mount.c + mount_source=$(CONTRIBDIR)/fuse-lib/mount.c $(CONTRIBDIR)/fuse-lib/mount-common.c endif 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 +fuse_la_LDFLAGS = -module -avoid-version fuse_la_LIBADD = @GF_FUSE_LDADD@ -AM_CFLAGS = -fPIC -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -D$(GF_HOST_OS) -Wall \ +AM_CPPFLAGS = $(GF_CPPFLAGS) \ -I$(top_srcdir)/libglusterfs/src -I$(CONTRIBDIR)/fuse-include \ - $(GF_CFLAGS) $(GF_FUSE_CFLAGS) + -I$(CONTRIBDIR)/fuse-lib $(GF_FUSE_CFLAGS) +AM_CFLAGS = -Wall $(GF_CFLAGS) CLEANFILES = diff --git a/xlators/mount/fuse/src/fuse-bridge.c b/xlators/mount/fuse/src/fuse-bridge.c index b50598788..6a5587c2d 100644 --- a/xlators/mount/fuse/src/fuse-bridge.c +++ b/xlators/mount/fuse/src/fuse-bridge.c @@ -1,31 +1,100 @@ /* - Copyright (c) 2006-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) 2006-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. */ +#include <sys/wait.h> #include "fuse-bridge.h" +#include "mount-gluster-compat.h" +#include "glusterfs.h" +#include "glusterfs-acl.h" + +#ifdef __NetBSD__ +#undef open /* in perfuse.h, pulled from mount-gluster-compat.h */ +#endif static int gf_fuse_conn_err_log; static int gf_fuse_xattr_enotsup_log; void fini (xlator_t *this_xl); +static void fuse_invalidate_inode(xlator_t *this, uint64_t fuse_ino); + +/* + * Send an invalidate notification up to fuse to purge the file from local + * page cache. + */ +static int32_t +fuse_invalidate(xlator_t *this, inode_t *inode) +{ + fuse_private_t *priv = this->private; + uint64_t nodeid; + + /* + * NOTE: We only invalidate at the moment if fopen_keep_cache is + * enabled because otherwise this is a departure from default + * behavior. Specifically, the performance/write-behind xlator + * causes unconditional invalidations on write requests. + */ + if (!priv->fopen_keep_cache) + return 0; + + nodeid = inode_to_fuse_nodeid(inode); + gf_log(this->name, GF_LOG_DEBUG, "Invalidate inode id %lu.", nodeid); + fuse_log_eh (this, "Sending invalidate inode id: %lu gfid: %s", nodeid, + uuid_utoa (inode->gfid)); + fuse_invalidate_inode(this, nodeid); + + return 0; +} + +static int32_t +fuse_forget_cbk (xlator_t *this, inode_t *inode) +{ + //Nothing to free in inode ctx, hence return. + return 0; +} + +void +fuse_inode_set_need_lookup (inode_t *inode, xlator_t *this) +{ + uint64_t need_lookup = 1; + + if (!inode || !this) + return; + + inode_ctx_set (inode, this, &need_lookup); + + return; +} + + +gf_boolean_t +fuse_inode_needs_lookup (inode_t *inode, xlator_t *this) +{ + uint64_t need_lookup = 0; + gf_boolean_t ret = _gf_false; + + if (!inode || !this) + return ret; + + inode_ctx_get (inode, this, &need_lookup); + if (need_lookup) + ret = _gf_true; + need_lookup = 0; + inode_ctx_set (inode, this, &need_lookup); + + return ret; +} + + fuse_fd_ctx_t * -__fuse_fd_ctx_check_n_create (fd_t *fd, xlator_t *this) +__fuse_fd_ctx_check_n_create (xlator_t *this, fd_t *fd) { uint64_t val = 0; int32_t ret = 0; @@ -38,7 +107,9 @@ __fuse_fd_ctx_check_n_create (fd_t *fd, xlator_t *this) if (fd_ctx == NULL) { fd_ctx = GF_CALLOC (1, sizeof (*fd_ctx), gf_fuse_mt_fd_ctx_t); - + if (!fd_ctx) { + goto out; + } ret = __fd_ctx_set (fd, this, (uint64_t)(unsigned long)fd_ctx); if (ret < 0) { @@ -48,12 +119,12 @@ __fuse_fd_ctx_check_n_create (fd_t *fd, xlator_t *this) fd_ctx = NULL; } } - +out: return fd_ctx; } fuse_fd_ctx_t * -fuse_fd_ctx_check_n_create (fd_t *fd, xlator_t *this) +fuse_fd_ctx_check_n_create (xlator_t *this, fd_t *fd) { fuse_fd_ctx_t *fd_ctx = NULL; @@ -63,7 +134,7 @@ fuse_fd_ctx_check_n_create (fd_t *fd, xlator_t *this) LOCK (&fd->lock); { - fd_ctx = __fuse_fd_ctx_check_n_create (fd, this); + fd_ctx = __fuse_fd_ctx_check_n_create (this, fd); } UNLOCK (&fd->lock); @@ -71,6 +142,23 @@ out: return fd_ctx; } +fuse_fd_ctx_t * +fuse_fd_ctx_get (xlator_t *this, fd_t *fd) +{ + fuse_fd_ctx_t *fdctx = NULL; + uint64_t value = 0; + int ret = 0; + + ret = fd_ctx_get (fd, this, &value); + if (ret < 0) { + goto out; + } + + fdctx = (fuse_fd_ctx_t *) (unsigned long)value; + +out: + return fdctx; +} /* * iov_out should contain a fuse_out_header at zeroth position. @@ -86,7 +174,7 @@ send_fuse_iov (xlator_t *this, fuse_in_header_t *finh, struct iovec *iov_out, if (!this || !finh || !iov_out) { gf_log ("send_fuse_iov", GF_LOG_ERROR,"Invalid arguments"); - return -1; + return EINVAL; } priv = this->private; @@ -141,7 +229,7 @@ send_fuse_data (xlator_t *this, fuse_in_header_t *finh, void *data, size_t size) static void -fuse_invalidate (xlator_t *this, uint64_t fuse_ino) +fuse_invalidate_entry (xlator_t *this, uint64_t fuse_ino) { struct fuse_out_header *fouh = NULL; struct fuse_notify_inval_entry_out *fnieo = NULL; @@ -150,8 +238,7 @@ fuse_invalidate (xlator_t *this, uint64_t fuse_ino) inode_t *inode = NULL; size_t nlen = 0; int rv = 0; - - char inval_buf[INVAL_BUF_SIZE] = {0,}; + char inval_buf[INVAL_BUF_SIZE] = {0,}; fouh = (struct fuse_out_header *)inval_buf; fnieo = (struct fuse_notify_inval_entry_out *)(fouh + 1); @@ -184,7 +271,73 @@ fuse_invalidate (xlator_t *this, uint64_t fuse_ino) gf_log ("glusterfs-fuse", GF_LOG_TRACE, "INVALIDATE entry: " "%"PRIu64"/%s", fnieo->parent, dentry->name); + + if (dentry->parent) { + fuse_log_eh (this, "Invalidated entry %s (parent: %s)", + dentry->name, + uuid_utoa (dentry->parent->gfid)); + } else { + fuse_log_eh (this, "Invalidated entry %s(nodeid: %ld)", + dentry->name, fnieo->parent); + } + } + + if (inode) + inode_unref (inode); +} + +/* + * Send an inval inode notification to fuse. This causes an invalidation of the + * entire page cache mapping on the inode. + */ +static void +fuse_invalidate_inode(xlator_t *this, uint64_t fuse_ino) +{ + struct fuse_out_header *fouh = NULL; + struct fuse_notify_inval_inode_out *fniio = NULL; + fuse_private_t *priv = NULL; + int rv = 0; + char inval_buf[INVAL_BUF_SIZE] = {0}; + inode_t *inode = NULL; + + fouh = (struct fuse_out_header *) inval_buf; + fniio = (struct fuse_notify_inval_inode_out *) (fouh + 1); + + priv = this->private; + + if (priv->revchan_out < 0) + return; + + fouh->unique = 0; + fouh->error = FUSE_NOTIFY_INVAL_INODE; + fouh->len = sizeof(struct fuse_out_header) + + sizeof(struct fuse_notify_inval_inode_out); + + /* inval the entire mapping until we learn how to be more granular */ + fniio->ino = fuse_ino; + fniio->off = 0; + fniio->len = -1; + + inode = fuse_ino_to_inode (fuse_ino, this); + + rv = write(priv->revchan_out, inval_buf, fouh->len); + if (rv != fouh->len) { + gf_log("glusterfs-fuse", GF_LOG_ERROR, "kernel notification " + "daemon defunct"); + close(priv->fd); + } + + gf_log("glusterfs-fuse", GF_LOG_TRACE, "INVALIDATE inode: %lu", fuse_ino); + + if (inode) { + fuse_log_eh (this, "Invalidated inode %lu (gfid: %s)", + fuse_ino, uuid_utoa (inode->gfid)); + } else { + fuse_log_eh (this, "Invalidated inode %lu ", fuse_ino); } + + if (inode) + inode_unref (inode); } int @@ -192,18 +345,36 @@ send_fuse_err (xlator_t *this, fuse_in_header_t *finh, int error) { struct fuse_out_header fouh = {0, }; struct iovec iov_out; + inode_t *inode = NULL; fouh.error = -error; iov_out.iov_base = &fouh; + inode = fuse_ino_to_inode (finh->nodeid, this); + + // filter out ENOENT + if (error != ENOENT) { + if (inode) { + fuse_log_eh (this,"Sending %s for operation %d on " + "inode %s", strerror (error), finh->opcode, + uuid_utoa (inode->gfid)); + } else { + fuse_log_eh (this, "Sending %s for operation %d on " + "inode %ld", strerror (error), + finh->opcode, finh->nodeid); + } + } + + if (inode) + inode_unref (inode); + return send_fuse_iov (this, finh, &iov_out, 1); } - static int fuse_entry_cbk (call_frame_t *frame, void *cookie, xlator_t *this, int32_t op_ret, int32_t op_errno, - inode_t *inode, struct iatt *buf) + inode_t *inode, struct iatt *buf, dict_t *xdata) { fuse_state_t *state = NULL; fuse_in_header_t *finh = NULL; @@ -215,18 +386,39 @@ fuse_entry_cbk (call_frame_t *frame, void *cookie, xlator_t *this, state = frame->root->state; finh = state->finh; - if (!op_ret && __is_root_gfid (state->loc.inode->gfid)) { - buf->ia_ino = 1; + if (op_ret == 0) { + if (__is_root_gfid (state->loc.inode->gfid)) + buf->ia_ino = 1; + if (uuid_is_null (buf->ia_gfid)) { + /* With a NULL gfid inode linking is + not possible. Let's not pretend this + call was a "success". + */ + gf_log ("glusterfs-fuse", GF_LOG_WARNING, + "Received NULL gfid for %s. Forcing EIO", + state->loc.path); + op_ret = -1; + op_errno = EIO; + } } + /* log into the event-history after the null uuid check is done, since + * the op_ret and op_errno are being changed if the gfid is NULL. + */ + fuse_log_eh (this, "op_ret: %d op_errno: %d " + "%"PRIu64": %s() %s => %s", op_ret, op_errno, + frame->root->unique, gf_fop_list[frame->root->op], + state->loc.path, (op_ret == 0)? + uuid_utoa(buf->ia_gfid):uuid_utoa(state->loc.gfid)); + if (op_ret == 0) { gf_log ("glusterfs-fuse", GF_LOG_TRACE, - "%"PRIu64": %s() %s => %"PRId64, + "%"PRIu64": %s() %s => %"PRIu64, frame->root->unique, gf_fop_list[frame->root->op], state->loc.path, buf->ia_ino); buf->ia_blksize = this->ctx->page_size; - gf_fuse_stat2attr (buf, &feo.attr); + gf_fuse_stat2attr (buf, &feo.attr, priv->enable_ino32); if (!buf->ia_ino) { gf_log ("glusterfs-fuse", GF_LOG_WARNING, @@ -270,7 +462,16 @@ fuse_entry_cbk (call_frame_t *frame, void *cookie, xlator_t *this, "%"PRIu64": %s() %s => -1 (%s)", frame->root->unique, gf_fop_list[frame->root->op], state->loc.path, strerror (op_errno)); - send_fuse_err (this, state->finh, op_errno); + + if ((op_errno == ENOENT) && (priv->negative_timeout != 0)) { + feo.entry_valid = + calc_timeout_sec (priv->negative_timeout); + feo.entry_valid_nsec = + calc_timeout_nsec (priv->negative_timeout); + send_fuse_obj (this, finh, &feo); + } else { + send_fuse_err (this, state->finh, op_errno); + } } free_fuse_state (state); @@ -278,18 +479,17 @@ fuse_entry_cbk (call_frame_t *frame, void *cookie, xlator_t *this, return 0; } - static int fuse_newentry_cbk (call_frame_t *frame, void *cookie, xlator_t *this, int32_t op_ret, int32_t op_errno, inode_t *inode, struct iatt *buf, struct iatt *preparent, - struct iatt *postparent) + struct iatt *postparent, dict_t *xdata) { - fuse_entry_cbk (frame, cookie, this, op_ret, op_errno, inode, buf); + fuse_entry_cbk (frame, cookie, this, op_ret, op_errno, inode, buf, + xdata); return 0; } - static int fuse_lookup_cbk (call_frame_t *frame, void *cookie, xlator_t *this, int32_t op_ret, int32_t op_errno, @@ -305,6 +505,13 @@ fuse_lookup_cbk (call_frame_t *frame, void *cookie, xlator_t *this, if (op_ret == -1 && state->is_revalidate == 1) { itable = state->itable; + /* + * A stale mapping might exist for a dentry/inode that has been + * removed from another client. + */ + if (op_errno == ENOENT) + inode_unlink(state->loc.inode, state->loc.parent, + state->loc.name); inode_unref (state->loc.inode); state->loc.inode = inode_new (itable); state->is_revalidate = 2; @@ -314,11 +521,12 @@ fuse_lookup_cbk (call_frame_t *frame, void *cookie, xlator_t *this, STACK_WIND (frame, fuse_lookup_cbk, prev->this, prev->this->fops->lookup, - &state->loc, state->dict); + &state->loc, state->xdata); return 0; } - fuse_entry_cbk (frame, cookie, this, op_ret, op_errno, inode, stat); + fuse_entry_cbk (frame, cookie, this, op_ret, op_errno, inode, stat, + dict); return 0; } @@ -333,6 +541,14 @@ fuse_lookup_resume (fuse_state_t *state) return; } + /* parent was resolved, entry could not, may be a missing gfid? + * Hence try to do a regular lookup + */ + if ((state->resolve.op_ret == -1) + && (state->resolve.op_errno == ENODATA)) { + state->resolve.op_ret = 0; + } + if (state->loc.inode) { gf_log ("glusterfs-fuse", GF_LOG_TRACE, "%"PRIu64": LOOKUP %s(%s)", state->finh->unique, @@ -343,17 +559,20 @@ fuse_lookup_resume (fuse_state_t *state) "%"PRIu64": LOOKUP %s", state->finh->unique, state->loc.path); state->loc.inode = inode_new (state->loc.parent->table); + if (uuid_is_null (state->gfid)) + uuid_generate (state->gfid); + fuse_gfid_set (state); } FUSE_FOP (state, fuse_lookup_cbk, GF_FOP_LOOKUP, - lookup, &state->loc, state->dict); + lookup, &state->loc, state->xdata); } static void fuse_lookup (xlator_t *this, fuse_in_header_t *finh, void *msg) { - char *name = msg; - fuse_state_t *state = NULL; + char *name = msg; + fuse_state_t *state = NULL; GET_STATE (this, finh, state); @@ -361,16 +580,27 @@ fuse_lookup (xlator_t *this, fuse_in_header_t *finh, void *msg) finh->nodeid, name); fuse_resolve_and_resume (state, fuse_lookup_resume); + + return; } +static inline void +do_forget(xlator_t *this, uint64_t unique, uint64_t nodeid, uint64_t nlookup) +{ + inode_t *fuse_inode = fuse_ino_to_inode(nodeid, this); + + fuse_log_eh(this, "%"PRIu64": FORGET %"PRIu64"/%"PRIu64" gfid: (%s)", + unique, nodeid, nlookup, uuid_utoa(fuse_inode->gfid)); + + inode_forget(fuse_inode, nlookup); + inode_unref(fuse_inode); +} static void fuse_forget (xlator_t *this, fuse_in_header_t *finh, void *msg) { - struct fuse_forget_in *ffi = msg; - - inode_t *fuse_inode; + struct fuse_forget_in *ffi = msg; if (finh->nodeid == 1) { GF_FREE (finh); @@ -381,19 +611,35 @@ fuse_forget (xlator_t *this, fuse_in_header_t *finh, void *msg) "%"PRIu64": FORGET %"PRIu64"/%"PRIu64, finh->unique, finh->nodeid, ffi->nlookup); - fuse_inode = fuse_ino_to_inode (finh->nodeid, this); - - inode_forget (fuse_inode, ffi->nlookup); - inode_unref (fuse_inode); + do_forget(this, finh->unique, finh->nodeid, ffi->nlookup); GF_FREE (finh); } +static void +fuse_batch_forget(xlator_t *this, fuse_in_header_t *finh, void *msg) +{ + struct fuse_batch_forget_in *fbfi = msg; + struct fuse_forget_one *ffo = (struct fuse_forget_one *) (fbfi + 1); + int i; + + gf_log("glusterfs-fuse", GF_LOG_TRACE, + "%"PRIu64": BATCH_FORGET %"PRIu64"/%"PRIu32, + finh->unique, finh->nodeid, fbfi->count); + + for (i = 0; i < fbfi->count; i++) { + if (ffo[i].nodeid == 1) + continue; + do_forget(this, finh->unique, ffo[i].nodeid, ffo[i].nlookup); + } + + GF_FREE(finh); +} static int fuse_truncate_cbk (call_frame_t *frame, void *cookie, xlator_t *this, int32_t op_ret, int32_t op_errno, struct iatt *prebuf, - struct iatt *postbuf) + struct iatt *postbuf, dict_t *xdata) { fuse_state_t *state; fuse_in_header_t *finh; @@ -404,15 +650,17 @@ fuse_truncate_cbk (call_frame_t *frame, void *cookie, xlator_t *this, state = frame->root->state; finh = state->finh; + fuse_log_eh_fop(this, state, frame, op_ret, op_errno); + if (op_ret == 0) { gf_log ("glusterfs-fuse", GF_LOG_TRACE, - "%"PRIu64": %s() %s => %"PRId64, frame->root->unique, + "%"PRIu64": %s() %s => %"PRIu64, frame->root->unique, gf_fop_list[frame->root->op], state->loc.path ? state->loc.path : "ERR", prebuf->ia_ino); postbuf->ia_blksize = this->ctx->page_size; - gf_fuse_stat2attr (postbuf, &fao.attr); + gf_fuse_stat2attr (postbuf, &fao.attr, priv->enable_ino32); fao.attr_valid = calc_timeout_sec (priv->attribute_timeout); fao.attr_valid_nsec = @@ -442,10 +690,9 @@ fuse_truncate_cbk (call_frame_t *frame, void *cookie, xlator_t *this, return 0; } - static int fuse_attr_cbk (call_frame_t *frame, void *cookie, xlator_t *this, - int32_t op_ret, int32_t op_errno, struct iatt *buf) + int32_t op_ret, int32_t op_errno, struct iatt *buf, dict_t *xdata) { fuse_state_t *state; fuse_in_header_t *finh; @@ -456,15 +703,19 @@ fuse_attr_cbk (call_frame_t *frame, void *cookie, xlator_t *this, state = frame->root->state; finh = state->finh; + fuse_log_eh (this, "op_ret: %d, op_errno: %d, %"PRIu64": %s() %s => " + "gfid: %s", op_ret, op_errno, frame->root->unique, + gf_fop_list[frame->root->op], state->loc.path, + state->loc.inode ? uuid_utoa (state->loc.inode->gfid) : ""); if (op_ret == 0) { gf_log ("glusterfs-fuse", GF_LOG_TRACE, - "%"PRIu64": %s() %s => %"PRId64, frame->root->unique, + "%"PRIu64": %s() %s => %"PRIu64, frame->root->unique, gf_fop_list[frame->root->op], state->loc.path ? state->loc.path : "ERR", buf->ia_ino); buf->ia_blksize = this->ctx->page_size; - gf_fuse_stat2attr (buf, &fao.attr); + gf_fuse_stat2attr (buf, &fao.attr, priv->enable_ino32); fao.attr_valid = calc_timeout_sec (priv->attribute_timeout); fao.attr_valid_nsec = @@ -479,9 +730,9 @@ fuse_attr_cbk (call_frame_t *frame, void *cookie, xlator_t *this, send_fuse_obj (this, finh, &fao); #endif } else { - GF_LOG_OCCASIONALLY ( gf_fuse_conn_err_log, "glusterfs-fuse", - GF_LOG_WARNING, - "%"PRIu64": %s() %s => -1 (%s)", + GF_LOG_OCCASIONALLY ( gf_fuse_conn_err_log, "glusterfs-fuse", + GF_LOG_WARNING, + "%"PRIu64": %s() %s => -1 (%s)", frame->root->unique, gf_fop_list[frame->root->op], state->loc.path ? state->loc.path : "ERR", @@ -496,14 +747,13 @@ fuse_attr_cbk (call_frame_t *frame, void *cookie, xlator_t *this, return 0; } - static int fuse_root_lookup_cbk (call_frame_t *frame, void *cookie, xlator_t *this, int32_t op_ret, int32_t op_errno, inode_t *inode, struct iatt *stat, dict_t *dict, struct iatt *postparent) { - fuse_attr_cbk (frame, cookie, this, op_ret, op_errno, stat); + fuse_attr_cbk (frame, cookie, this, op_ret, op_errno, stat, dict); return 0; } @@ -515,15 +765,15 @@ fuse_getattr_resume (fuse_state_t *state) gf_log ("glusterfs-fuse", GF_LOG_ERROR, "%"PRIu64": GETATTR %"PRIu64" (%s) resolution failed", state->finh->unique, state->finh->nodeid, - uuid_utoa (state->resolve.gfid)); + uuid_utoa (state->resolve.gfid)); send_fuse_err (state->this, state->finh, ENOENT); free_fuse_state (state); return; } - if (!IA_ISDIR (state->loc.inode->ia_type)) { - state->fd = fd_lookup (state->loc.inode, state->finh->pid); - } + if (!IA_ISDIR (state->loc.inode->ia_type)) { + state->fd = fd_lookup (state->loc.inode, state->finh->pid); + } if (!state->fd) { gf_log ("glusterfs-fuse", GF_LOG_TRACE, @@ -532,7 +782,7 @@ fuse_getattr_resume (fuse_state_t *state) state->loc.path); FUSE_FOP (state, fuse_attr_cbk, GF_FOP_STAT, - stat, &state->loc); + stat, &state->loc, state->xdata); } else { gf_log ("glusterfs-fuse", GF_LOG_TRACE, @@ -541,7 +791,7 @@ fuse_getattr_resume (fuse_state_t *state) state->loc.path, state->fd); FUSE_FOP (state, fuse_attr_cbk, GF_FOP_FSTAT, - fstat, state->fd); + fstat, state->fd, state->xdata); } } @@ -569,7 +819,7 @@ fuse_getattr (xlator_t *this, fuse_in_header_t *finh, void *msg) fuse_gfid_set (state); FUSE_FOP (state, fuse_root_lookup_cbk, GF_FOP_LOOKUP, - lookup, &state->loc, state->dict); + lookup, &state->loc, state->xdata); return; } @@ -578,14 +828,12 @@ fuse_getattr (xlator_t *this, fuse_in_header_t *finh, void *msg) fuse_resolve_and_resume (state, fuse_getattr_resume); } - static int32_t fuse_fd_inherit_directio (xlator_t *this, fd_t *fd, struct fuse_open_out *foo) { int32_t ret = 0; fuse_fd_ctx_t *fdctx = NULL, *tmp_fdctx = NULL; fd_t *tmp_fd = NULL; - uint64_t val = 0; GF_VALIDATE_OR_GOTO_WITH_ERROR ("glusterfs-fuse", this, out, ret, -EINVAL); @@ -594,7 +842,7 @@ fuse_fd_inherit_directio (xlator_t *this, fd_t *fd, struct fuse_open_out *foo) GF_VALIDATE_OR_GOTO_WITH_ERROR ("glusterfs-fuse", foo, out, ret, -EINVAL); - fdctx = fuse_fd_ctx_check_n_create (fd, this); + fdctx = fuse_fd_ctx_get (this, fd); if (!fdctx) { ret = -ENOMEM; goto out; @@ -602,14 +850,11 @@ fuse_fd_inherit_directio (xlator_t *this, fd_t *fd, struct fuse_open_out *foo) tmp_fd = fd_lookup (fd->inode, 0); if (tmp_fd) { - ret = fd_ctx_get (tmp_fd, this, &val); - if (!ret) { - tmp_fdctx = (fuse_fd_ctx_t *)(unsigned long)val; - if (tmp_fdctx) { - foo->open_flags &= ~FOPEN_DIRECT_IO; - foo->open_flags |= (tmp_fdctx->open_flags - & FOPEN_DIRECT_IO); - } + tmp_fdctx = fuse_fd_ctx_get (this, tmp_fd); + if (tmp_fdctx) { + foo->open_flags &= ~FOPEN_DIRECT_IO; + foo->open_flags |= (tmp_fdctx->open_flags + & FOPEN_DIRECT_IO); } } @@ -624,10 +869,9 @@ out: return ret; } - static int fuse_fd_cbk (call_frame_t *frame, void *cookie, xlator_t *this, - int32_t op_ret, int32_t op_errno, fd_t *fd) + int32_t op_ret, int32_t op_errno, fd_t *fd, dict_t *xdata) { fuse_state_t *state = NULL; fuse_in_header_t *finh = NULL; @@ -639,6 +883,8 @@ fuse_fd_cbk (call_frame_t *frame, void *cookie, xlator_t *this, state = frame->root->state; finh = state->finh; + fuse_log_eh_fop(this, state, frame, op_ret, op_errno); + if (op_ret >= 0) { foo.fh = (uintptr_t) fd; foo.open_flags = 0; @@ -649,17 +895,27 @@ fuse_fd_cbk (call_frame_t *frame, void *cookie, xlator_t *this, || (priv->direct_io_mode == 1)) foo.open_flags |= FOPEN_DIRECT_IO; #ifdef GF_DARWIN_HOST_OS - /* In Linux: by default, buffer cache - * is purged upon open, setting - * FOPEN_KEEP_CACHE implies no-purge - * - * In MacFUSE: by default, buffer cache - * is left intact upon open, setting - * FOPEN_PURGE_UBC implies purge - * - * [[Interesting...]] - */ + /* In Linux: by default, buffer cache + * is purged upon open, setting + * FOPEN_KEEP_CACHE implies no-purge + * + * In MacFUSE: by default, buffer cache + * is left intact upon open, setting + * FOPEN_PURGE_UBC implies purge + * + * [[Interesting...]] + */ + if (!priv->fopen_keep_cache) foo.open_flags |= FOPEN_PURGE_UBC; +#else + /* + * If fopen-keep-cache is enabled, we set the associated + * flag here such that files are not invalidated on open. + * File invalidations occur either in fuse or explicitly + * when the cache is set invalid on the inode. + */ + if (priv->fopen_keep_cache) + foo.open_flags |= FOPEN_KEEP_CACHE; #endif } @@ -671,8 +927,9 @@ fuse_fd_cbk (call_frame_t *frame, void *cookie, xlator_t *this, if (ret < 0) { op_errno = -ret; gf_log ("glusterfs-fuse", GF_LOG_WARNING, - "cannot inherit direct-io values from fds " - "already opened"); + "cannot inherit direct-io values for fd " + "(ptr:%p inode-gfid:%s) from fds already " + "opened", fd, uuid_utoa (fd->inode->gfid)); goto err; } @@ -700,26 +957,24 @@ out: return 0; } - static void fuse_do_truncate (fuse_state_t *state, size_t size) { if (state->fd) { FUSE_FOP (state, fuse_truncate_cbk, GF_FOP_FTRUNCATE, - ftruncate, state->fd, size); + ftruncate, state->fd, size, state->xdata); } else { FUSE_FOP (state, fuse_truncate_cbk, GF_FOP_TRUNCATE, - truncate, &state->loc, size); + truncate, &state->loc, size, state->xdata); } return; } - static int fuse_setattr_cbk (call_frame_t *frame, void *cookie, xlator_t *this, int32_t op_ret, int32_t op_errno, - struct iatt *statpre, struct iatt *statpost) + struct iatt *statpre, struct iatt *statpost, dict_t *xdata) { fuse_state_t *state; fuse_in_header_t *finh; @@ -732,15 +987,20 @@ fuse_setattr_cbk (call_frame_t *frame, void *cookie, xlator_t *this, state = frame->root->state; finh = state->finh; + fuse_log_eh(this, "op_ret: %d, op_errno: %d, %"PRIu64", %s() %s => " + "gfid: %s", op_ret, op_errno, frame->root->unique, + gf_fop_list[frame->root->op], state->loc.path, + state->loc.inode ? uuid_utoa (state->loc.inode->gfid) : ""); + if (op_ret == 0) { gf_log ("glusterfs-fuse", GF_LOG_TRACE, - "%"PRIu64": %s() %s => %"PRId64, frame->root->unique, + "%"PRIu64": %s() %s => %"PRIu64, frame->root->unique, gf_fop_list[frame->root->op], state->loc.path ? state->loc.path : "ERR", statpost->ia_ino); statpost->ia_blksize = this->ctx->page_size; - gf_fuse_stat2attr (statpost, &fao.attr); + gf_fuse_stat2attr (statpost, &fao.attr, priv->enable_ino32); fao.attr_valid = calc_timeout_sec (priv->attribute_timeout); fao.attr_valid_nsec = @@ -779,7 +1039,6 @@ fuse_setattr_cbk (call_frame_t *frame, void *cookie, xlator_t *this, return 0; } - static int32_t fattr_to_gf_set_attr (int32_t valid) { @@ -806,7 +1065,6 @@ fattr_to_gf_set_attr (int32_t valid) return gf_valid; } - #define FATTR_MASK (FATTR_SIZE \ | FATTR_UID | FATTR_GID \ | FATTR_ATIME | FATTR_MTIME \ @@ -819,7 +1077,7 @@ fuse_setattr_resume (fuse_state_t *state) gf_log ("glusterfs-fuse", GF_LOG_ERROR, "%"PRIu64": SETATTR %"PRIu64" (%s) resolution failed", state->finh->unique, state->finh->nodeid, - uuid_utoa (state->resolve.gfid)); + uuid_utoa (state->resolve.gfid)); send_fuse_err (state->this, state->finh, ENOENT); free_fuse_state (state); return; @@ -846,11 +1104,13 @@ fuse_setattr_resume (fuse_state_t *state) FUSE_FOP (state, fuse_setattr_cbk, GF_FOP_FSETATTR, fsetattr, state->fd, &state->attr, - fattr_to_gf_set_attr (state->valid)); + fattr_to_gf_set_attr (state->valid), + state->xdata); } else { FUSE_FOP (state, fuse_setattr_cbk, GF_FOP_SETATTR, setattr, &state->loc, &state->attr, - fattr_to_gf_set_attr (state->valid)); + fattr_to_gf_set_attr (state->valid), + state->xdata); } } else { fuse_do_truncate (state, state->size); @@ -873,10 +1133,10 @@ fuse_setattr (xlator_t *this, fuse_in_header_t *finh, void *msg) /* We need no loc if kernel sent us an fd and * we are not fiddling with times */ state->fd = FH_TO_FD (fsi->fh); - fuse_resolve_fd_init (state, &state->resolve, state->fd); - } else { - fuse_resolve_inode_init (state, &state->resolve, finh->nodeid); - } + fuse_resolve_fd_init (state, &state->resolve, state->fd); + } else { + fuse_resolve_inode_init (state, &state->resolve, finh->nodeid); + } /* * This is just stub code demonstrating how to retrieve @@ -921,14 +1181,15 @@ fuse_setattr (xlator_t *this, fuse_in_header_t *finh, void *msg) fuse_resolve_and_resume (state, fuse_setattr_resume); } - static int fuse_err_cbk (call_frame_t *frame, void *cookie, xlator_t *this, - int32_t op_ret, int32_t op_errno) + int32_t op_ret, int32_t op_errno, dict_t *xdata) { fuse_state_t *state = frame->root->state; fuse_in_header_t *finh = state->finh; + fuse_log_eh_fop(this, state, frame, op_ret, op_errno); + if (op_ret == 0) { gf_log ("glusterfs-fuse", GF_LOG_TRACE, "%"PRIu64": %s() %s => 0", frame->root->unique, @@ -953,19 +1214,17 @@ fuse_err_cbk (call_frame_t *frame, void *cookie, xlator_t *this, return 0; } - static int fuse_fsync_cbk (call_frame_t *frame, void *cookie, xlator_t *this, int32_t op_ret, int32_t op_errno, struct iatt *prebuf, - struct iatt *postbuf) + struct iatt *postbuf, dict_t *xdata) { - return fuse_err_cbk (frame, cookie, this, op_ret, op_errno); + return fuse_err_cbk (frame, cookie, this, op_ret, op_errno, xdata); } - static int fuse_setxattr_cbk (call_frame_t *frame, void *cookie, xlator_t *this, - int32_t op_ret, int32_t op_errno) + int32_t op_ret, int32_t op_errno, dict_t *xdata) { if (op_ret == -1 && op_errno == ENOTSUP) GF_LOG_OCCASIONALLY (gf_fuse_xattr_enotsup_log, @@ -973,14 +1232,13 @@ fuse_setxattr_cbk (call_frame_t *frame, void *cookie, xlator_t *this, "extended attribute not supported " "by the backend storage"); - return fuse_err_cbk (frame, cookie, this, op_ret, op_errno); + return fuse_err_cbk (frame, cookie, this, op_ret, op_errno, xdata); } - static int fuse_unlink_cbk (call_frame_t *frame, void *cookie, xlator_t *this, int32_t op_ret, int32_t op_errno, struct iatt *preparent, - struct iatt *postparent) + struct iatt *postparent, dict_t *xdata) { fuse_state_t *state = NULL; fuse_in_header_t *finh = NULL; @@ -988,11 +1246,14 @@ fuse_unlink_cbk (call_frame_t *frame, void *cookie, xlator_t *this, state = frame->root->state; finh = state->finh; - if (op_ret == 0) - inode_unlink (state->loc.inode, state->loc.parent, - state->loc.name); + fuse_log_eh (this, "op_ret: %d, op_errno: %d, %"PRIu64": %s() %s => " + "gfid: %s", op_ret, op_errno, frame->root->unique, + gf_fop_list[frame->root->op], state->loc.path, + state->loc.inode ? uuid_utoa (state->loc.inode->gfid) : ""); if (op_ret == 0) { + inode_unlink (state->loc.inode, state->loc.parent, + state->loc.name); gf_log ("glusterfs-fuse", GF_LOG_TRACE, "%"PRIu64": %s() %s => 0", frame->root->unique, gf_fop_list[frame->root->op], state->loc.path); @@ -1014,7 +1275,6 @@ fuse_unlink_cbk (call_frame_t *frame, void *cookie, xlator_t *this, return 0; } - void fuse_access_resume (fuse_state_t *state) { @@ -1022,7 +1282,7 @@ fuse_access_resume (fuse_state_t *state) gf_log ("glusterfs-fuse", GF_LOG_ERROR, "%"PRIu64": ACCESS %"PRIu64" (%s) resolution failed", state->finh->unique, state->finh->nodeid, - uuid_utoa (state->resolve.gfid)); + uuid_utoa (state->resolve.gfid)); send_fuse_err (state->this, state->finh, ENOENT); free_fuse_state (state); return; @@ -1034,10 +1294,9 @@ fuse_access_resume (fuse_state_t *state) state->finh->nodeid, state->mask); FUSE_FOP (state, fuse_err_cbk, GF_FOP_ACCESS, access, - &state->loc, state->mask); + &state->loc, state->mask, state->xdata); } - static void fuse_access (xlator_t *this, fuse_in_header_t *finh, void *msg) { @@ -1055,11 +1314,10 @@ fuse_access (xlator_t *this, fuse_in_header_t *finh, void *msg) return; } - static int fuse_readlink_cbk (call_frame_t *frame, void *cookie, xlator_t *this, int32_t op_ret, int32_t op_errno, const char *linkname, - struct iatt *buf) + struct iatt *buf, dict_t *xdata) { fuse_state_t *state = NULL; fuse_in_header_t *finh = NULL; @@ -1067,6 +1325,12 @@ fuse_readlink_cbk (call_frame_t *frame, void *cookie, xlator_t *this, state = frame->root->state; finh = state->finh; + fuse_log_eh (this, "op_ret: %d, op_errno: %d %"PRIu64": %s() => %s" + " linkname: %s, gfid: %s", op_ret, op_errno, + frame->root->unique, gf_fop_list[frame->root->op], + state->loc.gfid, linkname, + uuid_utoa (state->loc.gfid)); + if (op_ret > 0) { ((char *)linkname)[op_ret] = '\0'; @@ -1089,7 +1353,6 @@ fuse_readlink_cbk (call_frame_t *frame, void *cookie, xlator_t *this, return 0; } - void fuse_readlink_resume (fuse_state_t *state) { @@ -1107,10 +1370,9 @@ fuse_readlink_resume (fuse_state_t *state) state->loc.path, uuid_utoa (state->loc.inode->gfid)); FUSE_FOP (state, fuse_readlink_cbk, GF_FOP_READLINK, - readlink, &state->loc, 4096); + readlink, &state->loc, 4096, state->xdata); } - static void fuse_readlink (xlator_t *this, fuse_in_header_t *finh, void *msg) { @@ -1118,22 +1380,21 @@ fuse_readlink (xlator_t *this, fuse_in_header_t *finh, void *msg) GET_STATE (this, finh, state); - fuse_resolve_inode_init (state, &state->resolve, finh->nodeid); + fuse_resolve_inode_init (state, &state->resolve, finh->nodeid); fuse_resolve_and_resume (state, fuse_readlink_resume); return; } - void fuse_mknod_resume (fuse_state_t *state) { if (!state->loc.parent) { gf_log ("glusterfs-fuse", GF_LOG_ERROR, - "MKNOD %"PRId64"/%s (%s/%s) resolution failed", + "MKNOD %"PRIu64"/%s (%s/%s) resolution failed", state->finh->nodeid, state->resolve.bname, - uuid_utoa (state->resolve.gfid), state->resolve.bname); + uuid_utoa (state->resolve.gfid), state->resolve.bname); send_fuse_err (state->this, state->finh, ENOENT); free_fuse_state (state); return; @@ -1147,7 +1408,7 @@ fuse_mknod_resume (fuse_state_t *state) if (state->loc.inode) { gf_log (state->this->name, GF_LOG_DEBUG, "inode already present"); inode_unref (state->loc.inode); - state->loc.inode = NULL; + state->loc.inode = NULL; } state->loc.inode = inode_new (state->loc.parent->table); @@ -1157,10 +1418,10 @@ fuse_mknod_resume (fuse_state_t *state) state->loc.path); FUSE_FOP (state, fuse_newentry_cbk, GF_FOP_MKNOD, - mknod, &state->loc, state->mode, state->rdev, state->dict); + mknod, &state->loc, state->mode, state->rdev, state->umask, + state->xdata); } - static void fuse_mknod (xlator_t *this, fuse_in_header_t *finh, void *msg) { @@ -1181,43 +1442,14 @@ fuse_mknod (xlator_t *this, fuse_in_header_t *finh, void *msg) uuid_generate (state->gfid); - fuse_resolve_entry_init (state, &state->resolve, finh->nodeid, name); + fuse_resolve_entry_init (state, &state->resolve, finh->nodeid, name); state->mode = fmi->mode; state->rdev = fmi->rdev; priv = this->private; #if FUSE_KERNEL_MINOR_VERSION >=12 - if (priv->proto_minor >= 12) - state->mode &= ~fmi->umask; - if (priv->proto_minor >= 12 && priv->acl) { - state->dict = dict_new (); - if (!state->dict) { - gf_log ("glusterfs-fuse", GF_LOG_WARNING, - "MKNOD Failed to allocate a param dictionary"); - send_fuse_err (this, finh, ENOMEM); - free_fuse_state (state); - return; - } - ret = dict_set_int16 (state->dict, "umask", fmi->umask); - if (ret < 0) { - gf_log ("glusterfs-fuse", GF_LOG_WARNING, - "MKNOD Failed adding umask to request"); - dict_destroy (state->dict); - send_fuse_err (this, finh, ENOMEM); - free_fuse_state (state); - return; - } - ret = dict_set_int16 (state->dict, "mode", fmi->mode); - if (ret < 0) { - gf_log ("glusterfs-fuse", GF_LOG_WARNING, - "MKNOD Failed adding mode to request"); - dict_destroy (state->dict); - send_fuse_err (this, finh, ENOMEM); - free_fuse_state (state); - return; - } - } + FUSE_ENTRY_CREATE(this, priv, finh, state, fmi, "MKNOD"); #endif fuse_resolve_and_resume (state, fuse_mknod_resume); @@ -1225,15 +1457,14 @@ fuse_mknod (xlator_t *this, fuse_in_header_t *finh, void *msg) return; } - void fuse_mkdir_resume (fuse_state_t *state) { if (!state->loc.parent) { gf_log ("glusterfs-fuse", GF_LOG_ERROR, - "MKDIR %"PRId64" (%s/%s) resolution failed", + "MKDIR %"PRIu64" (%s/%s) resolution failed", state->finh->nodeid, uuid_utoa (state->resolve.gfid), - state->resolve.bname); + state->resolve.bname); send_fuse_err (state->this, state->finh, ENOENT); free_fuse_state (state); return; @@ -1247,7 +1478,7 @@ fuse_mkdir_resume (fuse_state_t *state) if (state->loc.inode) { gf_log (state->this->name, GF_LOG_DEBUG, "inode already present"); inode_unref (state->loc.inode); - state->loc.inode = NULL; + state->loc.inode = NULL; } state->loc.inode = inode_new (state->loc.parent->table); @@ -1257,10 +1488,9 @@ fuse_mkdir_resume (fuse_state_t *state) state->loc.path); FUSE_FOP (state, fuse_newentry_cbk, GF_FOP_MKDIR, - mkdir, &state->loc, state->mode, state->dict); + mkdir, &state->loc, state->mode, state->umask, state->xdata); } - static void fuse_mkdir (xlator_t *this, fuse_in_header_t *finh, void *msg) { @@ -1275,42 +1505,13 @@ fuse_mkdir (xlator_t *this, fuse_in_header_t *finh, void *msg) uuid_generate (state->gfid); - fuse_resolve_entry_init (state, &state->resolve, finh->nodeid, name); + fuse_resolve_entry_init (state, &state->resolve, finh->nodeid, name); state->mode = fmi->mode; priv = this->private; #if FUSE_KERNEL_MINOR_VERSION >=12 - if (priv->proto_minor >= 12) - state->mode &= ~fmi->umask; - if (priv->proto_minor >= 12 && priv->acl) { - state->dict = dict_new (); - if (!state->dict) { - gf_log ("glusterfs-fuse", GF_LOG_WARNING, - "MKDIR Failed to allocate a param dictionary"); - send_fuse_err (this, finh, ENOMEM); - free_fuse_state (state); - return; - } - ret = dict_set_int16 (state->dict, "umask", fmi->umask); - if (ret < 0) { - gf_log ("glusterfs-fuse", GF_LOG_WARNING, - "MKDIR Failed adding umask to request"); - dict_destroy (state->dict); - send_fuse_err (this, finh, ENOMEM); - free_fuse_state (state); - return; - } - ret = dict_set_int16 (state->dict, "mode", fmi->mode); - if (ret < 0) { - gf_log ("glusterfs-fuse", GF_LOG_WARNING, - "MKDIR Failed adding mode to request"); - dict_destroy (state->dict); - send_fuse_err (this, finh, ENOMEM); - free_fuse_state (state); - return; - } - } + FUSE_ENTRY_CREATE(this, priv, finh, state, fmi, "MKDIR"); #endif fuse_resolve_and_resume (state, fuse_mkdir_resume); @@ -1318,15 +1519,14 @@ fuse_mkdir (xlator_t *this, fuse_in_header_t *finh, void *msg) return; } - void fuse_unlink_resume (fuse_state_t *state) { if (!state->loc.parent || !state->loc.inode) { gf_log ("glusterfs-fuse", GF_LOG_ERROR, - "UNLINK %"PRId64" (%s/%s) resolution failed", - state->finh->nodeid, uuid_utoa (state->resolve.gfid), - state->resolve.bname); + "UNLINK %"PRIu64" (%s/%s) resolution failed", + state->finh->nodeid, uuid_utoa (state->resolve.gfid), + state->resolve.bname); send_fuse_err (state->this, state->finh, ENOENT); free_fuse_state (state); return; @@ -1337,10 +1537,9 @@ fuse_unlink_resume (fuse_state_t *state) state->loc.path); FUSE_FOP (state, fuse_unlink_cbk, GF_FOP_UNLINK, - unlink, &state->loc); + unlink, &state->loc, 0, state->xdata); } - static void fuse_unlink (xlator_t *this, fuse_in_header_t *finh, void *msg) { @@ -1349,7 +1548,7 @@ fuse_unlink (xlator_t *this, fuse_in_header_t *finh, void *msg) GET_STATE (this, finh, state); - fuse_resolve_entry_init (state, &state->resolve, finh->nodeid, name); + fuse_resolve_entry_init (state, &state->resolve, finh->nodeid, name); fuse_resolve_and_resume (state, fuse_unlink_resume); @@ -1361,9 +1560,9 @@ fuse_rmdir_resume (fuse_state_t *state) { if (!state->loc.parent || !state->loc.inode) { gf_log ("glusterfs-fuse", GF_LOG_ERROR, - "RMDIR %"PRId64" (%s/%s) resolution failed", - state->finh->nodeid, uuid_utoa (state->resolve.gfid), - state->resolve.bname); + "RMDIR %"PRIu64" (%s/%s) resolution failed", + state->finh->nodeid, uuid_utoa (state->resolve.gfid), + state->resolve.bname); send_fuse_err (state->this, state->finh, ENOENT); free_fuse_state (state); return; @@ -1374,10 +1573,9 @@ fuse_rmdir_resume (fuse_state_t *state) state->loc.path); FUSE_FOP (state, fuse_unlink_cbk, GF_FOP_RMDIR, - rmdir, &state->loc, 0); + rmdir, &state->loc, 0, state->xdata); } - static void fuse_rmdir (xlator_t *this, fuse_in_header_t *finh, void *msg) { @@ -1386,22 +1584,21 @@ fuse_rmdir (xlator_t *this, fuse_in_header_t *finh, void *msg) GET_STATE (this, finh, state); - fuse_resolve_entry_init (state, &state->resolve, finh->nodeid, name); + fuse_resolve_entry_init (state, &state->resolve, finh->nodeid, name); fuse_resolve_and_resume (state, fuse_rmdir_resume); return; } - void fuse_symlink_resume (fuse_state_t *state) { if (!state->loc.parent) { gf_log ("glusterfs-fuse", GF_LOG_ERROR, - "SYMLINK %"PRId64" (%s/%s) -> %s resolution failed", + "SYMLINK %"PRIu64" (%s/%s) -> %s resolution failed", state->finh->nodeid, uuid_utoa (state->resolve.gfid), - state->resolve.bname, state->name); + state->resolve.bname, state->name); send_fuse_err (state->this, state->finh, ENOENT); free_fuse_state (state); return; @@ -1415,7 +1612,7 @@ fuse_symlink_resume (fuse_state_t *state) if (state->loc.inode) { gf_log (state->this->name, GF_LOG_DEBUG, "inode already present"); inode_unref (state->loc.inode); - state->loc.inode = NULL; + state->loc.inode = NULL; } state->loc.inode = inode_new (state->loc.parent->table); @@ -1425,10 +1622,9 @@ fuse_symlink_resume (fuse_state_t *state) state->loc.path, state->name); FUSE_FOP (state, fuse_newentry_cbk, GF_FOP_SYMLINK, - symlink, state->name, &state->loc, state->dict); + symlink, state->name, &state->loc, state->umask, state->xdata); } - static void fuse_symlink (xlator_t *this, fuse_in_header_t *finh, void *msg) { @@ -1440,7 +1636,7 @@ fuse_symlink (xlator_t *this, fuse_in_header_t *finh, void *msg) uuid_generate (state->gfid); - fuse_resolve_entry_init (state, &state->resolve, finh->nodeid, name); + fuse_resolve_entry_init (state, &state->resolve, finh->nodeid, name); state->name = gf_strdup (linkname); @@ -1449,12 +1645,12 @@ fuse_symlink (xlator_t *this, fuse_in_header_t *finh, void *msg) return; } - int fuse_rename_cbk (call_frame_t *frame, void *cookie, xlator_t *this, int32_t op_ret, int32_t op_errno, struct iatt *buf, struct iatt *preoldparent, struct iatt *postoldparent, - struct iatt *prenewparent, struct iatt *postnewparent) + struct iatt *prenewparent, struct iatt *postnewparent, + dict_t *xdata) { fuse_state_t *state = NULL; fuse_in_header_t *finh = NULL; @@ -1462,9 +1658,18 @@ fuse_rename_cbk (call_frame_t *frame, void *cookie, xlator_t *this, state = frame->root->state; finh = state->finh; + fuse_log_eh (this, "op_ret: %d, op_errno: %d, %"PRIu64": %s() " + "path: %s parent: %s ==> path: %s parent: %s" + "gfid: %s", op_ret, op_errno, frame->root->unique, + gf_fop_list[frame->root->op], state->loc.path, + state->loc.parent?uuid_utoa (state->loc.parent->gfid):"", + state->loc2.path, + state->loc2.parent?uuid_utoa (state->loc2.parent->gfid):"", + state->loc.inode?uuid_utoa (state->loc.inode->gfid):""); + if (op_ret == 0) { gf_log ("glusterfs-fuse", GF_LOG_TRACE, - "%"PRIu64": %s -> %s => 0 (buf->ia_ino=%"PRId64")", + "%"PRIu64": %s -> %s => 0 (buf->ia_ino=%"PRIu64")", frame->root->unique, state->loc.path, state->loc2.path, buf->ia_ino); @@ -1504,11 +1709,11 @@ fuse_rename_resume (fuse_state_t *state) if (!state->loc.parent || !state->loc.inode) { gf_log ("glusterfs-fuse", GF_LOG_ERROR, "RENAME %"PRIu64" %s/%s -> %s/%s src resolution failed", - state->finh->unique, - uuid_utoa_r (state->resolve.gfid, loc_uuid), - state->resolve.bname, - uuid_utoa_r (state->resolve2.gfid, loc2_uuid), - state->resolve2.bname); + state->finh->unique, + uuid_utoa_r (state->resolve.gfid, loc_uuid), + state->resolve.bname, + uuid_utoa_r (state->resolve2.gfid, loc2_uuid), + state->resolve2.bname); send_fuse_err (state->this, state->finh, ENOENT); free_fuse_state (state); @@ -1518,11 +1723,11 @@ fuse_rename_resume (fuse_state_t *state) if (!state->loc2.parent) { gf_log ("glusterfs-fuse", GF_LOG_ERROR, "RENAME %"PRIu64" %s/%s -> %s/%s dst resolution failed", - state->finh->unique, - uuid_utoa_r (state->resolve.gfid, loc_uuid), - state->resolve.bname, - uuid_utoa_r (state->resolve2.gfid, loc2_uuid), - state->resolve2.bname); + state->finh->unique, + uuid_utoa_r (state->resolve.gfid, loc_uuid), + state->resolve.bname, + uuid_utoa_r (state->resolve2.gfid, loc2_uuid), + state->resolve2.bname); send_fuse_err (state->this, state->finh, ENOENT); free_fuse_state (state); @@ -1538,10 +1743,9 @@ fuse_rename_resume (fuse_state_t *state) state->loc2.path, loc2_uuid); FUSE_FOP (state, fuse_rename_cbk, GF_FOP_RENAME, - rename, &state->loc, &state->loc2); + rename, &state->loc, &state->loc2, state->xdata); } - static void fuse_rename (xlator_t *this, fuse_in_header_t *finh, void *msg) { @@ -1552,16 +1756,15 @@ fuse_rename (xlator_t *this, fuse_in_header_t *finh, void *msg) GET_STATE (this, finh, state); - fuse_resolve_entry_init (state, &state->resolve, finh->nodeid, oldname); + fuse_resolve_entry_init (state, &state->resolve, finh->nodeid, oldname); - fuse_resolve_entry_init (state, &state->resolve2, fri->newdir, newname); + fuse_resolve_entry_init (state, &state->resolve2, fri->newdir, newname); fuse_resolve_and_resume (state, fuse_rename_resume); return; } - void fuse_link_resume (fuse_state_t *state) { @@ -1577,11 +1780,11 @@ fuse_link_resume (fuse_state_t *state) state->resolve.op_ret = 0; state->resolve2.op_ret = 0; - if (state->loc.inode) { - inode_unref (state->loc.inode); - state->loc.inode = NULL; - } - state->loc.inode = inode_ref (state->loc2.inode); + if (state->loc.inode) { + inode_unref (state->loc.inode); + state->loc.inode = NULL; + } + state->loc.inode = inode_ref (state->loc2.inode); gf_log ("glusterfs-fuse", GF_LOG_TRACE, "%"PRIu64": LINK() %s -> %s", @@ -1589,10 +1792,9 @@ fuse_link_resume (fuse_state_t *state) state->loc.path); FUSE_FOP (state, fuse_newentry_cbk, GF_FOP_LINK, - link, &state->loc2, &state->loc); + link, &state->loc2, &state->loc, state->xdata); } - static void fuse_link (xlator_t *this, fuse_in_header_t *finh, void *msg) { @@ -1602,21 +1804,20 @@ fuse_link (xlator_t *this, fuse_in_header_t *finh, void *msg) GET_STATE (this, finh, state); - fuse_resolve_inode_init (state, &state->resolve2, fli->oldnodeid); + fuse_resolve_inode_init (state, &state->resolve2, fli->oldnodeid); - fuse_resolve_entry_init (state, &state->resolve, finh->nodeid, name); + fuse_resolve_entry_init (state, &state->resolve, finh->nodeid, name); fuse_resolve_and_resume (state, fuse_link_resume); return; } - static int fuse_create_cbk (call_frame_t *frame, void *cookie, xlator_t *this, int32_t op_ret, int32_t op_errno, fd_t *fd, inode_t *inode, struct iatt *buf, - struct iatt *preparent, struct iatt *postparent) + struct iatt *preparent, struct iatt *postparent, dict_t *xdata) { fuse_state_t *state = NULL; fuse_in_header_t *finh = NULL; @@ -1632,6 +1833,8 @@ fuse_create_cbk (call_frame_t *frame, void *cookie, xlator_t *this, finh = state->finh; foo.open_flags = 0; + fuse_log_eh_fop(this, state, frame, op_ret, op_errno); + if (op_ret >= 0) { foo.fh = (uintptr_t) fd; @@ -1641,12 +1844,12 @@ fuse_create_cbk (call_frame_t *frame, void *cookie, xlator_t *this, foo.open_flags |= FOPEN_DIRECT_IO; gf_log ("glusterfs-fuse", GF_LOG_TRACE, - "%"PRIu64": %s() %s => %p (ino=%"PRId64")", + "%"PRIu64": %s() %s => %p (ino=%"PRIu64")", frame->root->unique, gf_fop_list[frame->root->op], state->loc.path, fd, buf->ia_ino); buf->ia_blksize = this->ctx->page_size; - gf_fuse_stat2attr (buf, &feo.attr); + gf_fuse_stat2attr (buf, &feo.attr, priv->enable_ino32); linked_inode = inode_link (inode, state->loc.parent, state->loc.name, buf); @@ -1684,6 +1887,7 @@ fuse_create_cbk (call_frame_t *frame, void *cookie, xlator_t *this, #endif iov_out[2].iov_base = &foo; iov_out[2].iov_len = sizeof (foo); + if (send_fuse_iov (this, finh, iov_out, 3) == ENOENT) { gf_log ("glusterfs-fuse", GF_LOG_DEBUG, "create(%s) got EINTR", state->loc.path); @@ -1707,18 +1911,18 @@ out: return 0; } - void fuse_create_resume (fuse_state_t *state) { - fd_t *fd = NULL; - fuse_private_t *priv = NULL; + fd_t *fd = NULL; + fuse_private_t *priv = NULL; + fuse_fd_ctx_t *fdctx = NULL; if (!state->loc.parent) { gf_log ("glusterfs-fuse", GF_LOG_WARNING, "%"PRIu64" CREATE %s/%s resolution failed", state->finh->unique, uuid_utoa (state->resolve.gfid), - state->resolve.bname); + state->resolve.bname); send_fuse_err (state->this, state->finh, ENOENT); free_fuse_state (state); return; @@ -1738,6 +1942,25 @@ fuse_create_resume (fuse_state_t *state) state->loc.inode = inode_new (state->loc.parent->table); fd = fd_create (state->loc.inode, state->finh->pid); + if (fd == NULL) { + gf_log ("glusterfs-fuse", GF_LOG_WARNING, + "%"PRIu64" CREATE cannot create a new fd", + state->finh->unique); + send_fuse_err (state->this, state->finh, ENOMEM); + free_fuse_state (state); + return; + } + + fdctx = fuse_fd_ctx_check_n_create (state->this, fd); + if (fdctx == NULL) { + gf_log ("glusterfs-fuse", GF_LOG_WARNING, + "%"PRIu64" CREATE creation of fdctx failed", + state->finh->unique); + fd_unref (fd); + send_fuse_err (state->this, state->finh, ENOMEM); + free_fuse_state (state); + return; + } priv = state->this->private; @@ -1752,11 +1975,10 @@ fuse_create_resume (fuse_state_t *state) FUSE_FOP (state, fuse_create_cbk, GF_FOP_CREATE, create, &state->loc, state->flags, state->mode, - fd, state->dict); + state->umask, fd, state->xdata); } - static void fuse_create (xlator_t *this, fuse_in_header_t *finh, void *msg) { @@ -1781,56 +2003,26 @@ fuse_create (xlator_t *this, fuse_in_header_t *finh, void *msg) uuid_generate (state->gfid); - fuse_resolve_entry_init (state, &state->resolve, finh->nodeid, name); + fuse_resolve_entry_init (state, &state->resolve, finh->nodeid, name); state->mode = fci->mode; state->flags = fci->flags; priv = this->private; #if FUSE_KERNEL_MINOR_VERSION >=12 - if (priv->proto_minor >= 12) - state->mode &= ~fci->umask; - if (priv->proto_minor >= 12 && priv->acl) { - state->dict = dict_new (); - if (!state->dict) { - gf_log ("glusterfs-fuse", GF_LOG_WARNING, - "CREATE Failed to allocate a param dictionary"); - send_fuse_err (this, finh, ENOMEM); - free_fuse_state (state); - return; - } - ret = dict_set_int16 (state->dict, "umask", fci->umask); - if (ret < 0) { - gf_log ("glusterfs-fuse", GF_LOG_WARNING, - "CREATE Failed adding umask to request"); - dict_destroy (state->dict); - send_fuse_err (this, finh, ENOMEM); - free_fuse_state (state); - return; - } - ret = dict_set_int16 (state->dict, "mode", fci->mode); - if (ret < 0) { - gf_log ("glusterfs-fuse", GF_LOG_WARNING, - "CREATE Failed adding mode to request"); - dict_destroy (state->dict); - send_fuse_err (this, finh, ENOMEM); - free_fuse_state (state); - return; - } - } + FUSE_ENTRY_CREATE(this, priv, finh, state, fci, "CREATE"); #endif - fuse_resolve_and_resume (state, fuse_create_resume); return; } - void fuse_open_resume (fuse_state_t *state) { - fd_t *fd = NULL; - fuse_private_t *priv = NULL; + fd_t *fd = NULL; + fuse_private_t *priv = NULL; + fuse_fd_ctx_t *fdctx = NULL; if (!state->loc.inode) { gf_log ("glusterfs-fuse", GF_LOG_ERROR, @@ -1851,6 +2043,17 @@ fuse_open_resume (fuse_state_t *state) return; } + fdctx = fuse_fd_ctx_check_n_create (state->this, fd); + if (fdctx == NULL) { + gf_log ("glusterfs-fuse", GF_LOG_WARNING, + "%"PRIu64": OPEN creation of fdctx failed", + state->finh->unique); + fd_unref (fd); + send_fuse_err (state->this, state->finh, ENOMEM); + free_fuse_state (state); + return; + } + priv = state->this->private; state->fd_no = gf_fd_unused_get (priv->fdtable, fd); @@ -1862,10 +2065,9 @@ fuse_open_resume (fuse_state_t *state) state->loc.path); FUSE_FOP (state, fuse_fd_cbk, GF_FOP_OPEN, - open, &state->loc, state->flags, fd, 0); + open, &state->loc, state->flags, fd, state->xdata); } - static void fuse_open (xlator_t *this, fuse_in_header_t *finh, void *msg) { @@ -1874,7 +2076,7 @@ fuse_open (xlator_t *this, fuse_in_header_t *finh, void *msg) GET_STATE (this, finh, state); - fuse_resolve_inode_init (state, &state->resolve, finh->nodeid); + fuse_resolve_inode_init (state, &state->resolve, finh->nodeid); state->flags = foi->flags; @@ -1883,12 +2085,11 @@ fuse_open (xlator_t *this, fuse_in_header_t *finh, void *msg) return; } - static int fuse_readv_cbk (call_frame_t *frame, void *cookie, xlator_t *this, int32_t op_ret, int32_t op_errno, struct iovec *vector, int32_t count, - struct iatt *stbuf, struct iobref *iobref) + struct iatt *stbuf, struct iobref *iobref, dict_t *xdata) { fuse_state_t *state = NULL; fuse_in_header_t *finh = NULL; @@ -1898,9 +2099,11 @@ fuse_readv_cbk (call_frame_t *frame, void *cookie, xlator_t *this, state = frame->root->state; finh = state->finh; + fuse_log_eh_fop(this, state, frame, op_ret, op_errno); + if (op_ret >= 0) { gf_log ("glusterfs-fuse", GF_LOG_TRACE, - "%"PRIu64": READ => %d/%"GF_PRI_SIZET",%"PRId64"/%"PRId64, + "%"PRIu64": READ => %d/%"GF_PRI_SIZET",%"PRId64"/%"PRIu64, frame->root->unique, op_ret, state->size, state->off, stbuf->ia_size); @@ -1935,8 +2138,8 @@ fuse_readv_resume (fuse_state_t *state) "%"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, state->io_flags); + FUSE_FOP (state, fuse_readv_cbk, GF_FOP_READ, readv, state->fd, + state->size, state->off, state->io_flags, state->xdata); } static void @@ -1953,7 +2156,7 @@ fuse_readv (xlator_t *this, fuse_in_header_t *finh, void *msg) fd = FH_TO_FD (fri->fh); state->fd = fd; - fuse_resolve_fd_init (state, &state->resolve, fd); + fuse_resolve_fd_init (state, &state->resolve, fd); /* See comment by similar code in fuse_settatr */ priv = this->private; @@ -1970,11 +2173,10 @@ fuse_readv (xlator_t *this, fuse_in_header_t *finh, void *msg) fuse_resolve_and_resume (state, fuse_readv_resume); } - static int fuse_writev_cbk (call_frame_t *frame, void *cookie, xlator_t *this, int32_t op_ret, int32_t op_errno, - struct iatt *stbuf, struct iatt *postbuf) + struct iatt *stbuf, struct iatt *postbuf, dict_t *xdata) { fuse_state_t *state = NULL; fuse_in_header_t *finh = NULL; @@ -1983,9 +2185,11 @@ fuse_writev_cbk (call_frame_t *frame, void *cookie, xlator_t *this, state = frame->root->state; finh = state->finh; + fuse_log_eh_fop(this, state, frame, op_ret, op_errno); + if (op_ret >= 0) { gf_log ("glusterfs-fuse", GF_LOG_TRACE, - "%"PRIu64": WRITE => %d/%"GF_PRI_SIZET",%"PRId64"/%"PRId64, + "%"PRIu64": WRITE => %d/%"GF_PRI_SIZET",%"PRId64"/%"PRIu64, frame->root->unique, op_ret, state->size, state->off, stbuf->ia_size); @@ -2027,11 +2231,12 @@ fuse_write_resume (fuse_state_t *state) iobref_add (iobref, iobuf); gf_log ("glusterfs-fuse", GF_LOG_TRACE, - "%"PRIu64": WRITE (%p, size=%"PRId64", offset=%"PRId64")", + "%"PRIu64": WRITE (%p, size=%"GF_PRI_SIZET", offset=%"PRId64")", state->finh->unique, state->fd, state->size, state->off); FUSE_FOP (state, fuse_writev_cbk, GF_FOP_WRITE, writev, state->fd, - &state->vector, 1, state->off, state->io_flags, iobref); + &state->vector, 1, state->off, state->io_flags, iobref, + state->xdata); iobref_unref (iobref); } @@ -2064,7 +2269,7 @@ fuse_write (xlator_t *this, fuse_in_header_t *finh, void *msg) */ - fuse_resolve_fd_init (state, &state->resolve, fd); + fuse_resolve_fd_init (state, &state->resolve, fd); /* See comment by similar code in fuse_settatr */ priv = this->private; @@ -2081,15 +2286,13 @@ fuse_write (xlator_t *this, fuse_in_header_t *finh, void *msg) return; } - void fuse_flush_resume (fuse_state_t *state) { FUSE_FOP (state, fuse_err_cbk, GF_FOP_FLUSH, - flush, state->fd); + flush, state->fd, state->xdata); } - static void fuse_flush (xlator_t *this, fuse_in_header_t *finh, void *msg) { @@ -2102,7 +2305,7 @@ fuse_flush (xlator_t *this, fuse_in_header_t *finh, void *msg) fd = FH_TO_FD (ffi->fh); state->fd = fd; - fuse_resolve_fd_init (state, &state->resolve, fd); + fuse_resolve_fd_init (state, &state->resolve, fd); state->lk_owner = ffi->lock_owner; @@ -2114,18 +2317,17 @@ fuse_flush (xlator_t *this, fuse_in_header_t *finh, void *msg) return; } - static void fuse_release (xlator_t *this, fuse_in_header_t *finh, void *msg) { - struct fuse_release_in *fri = msg; - fd_t *new_fd = NULL; - fd_t *fd = NULL; - uint64_t val = 0; - int ret = 0; - fuse_state_t *state = NULL; - fuse_fd_ctx_t *fdctx = NULL; - fuse_private_t *priv = NULL; + struct fuse_release_in *fri = msg; + fd_t *activefd = NULL; + fd_t *fd = NULL; + uint64_t val = 0; + int ret = 0; + fuse_state_t *state = NULL; + fuse_fd_ctx_t *fdctx = NULL; + fuse_private_t *priv = NULL; GET_STATE (this, finh, state); fd = FH_TO_FD (fri->fh); @@ -2133,6 +2335,9 @@ fuse_release (xlator_t *this, fuse_in_header_t *finh, void *msg) priv = this->private; + fuse_log_eh (this, "RELEASE(): %"PRIu64":, fd: %p, gfid: %s", + finh->unique, fd, uuid_utoa (fd->inode->gfid)); + gf_log ("glusterfs-fuse", GF_LOG_TRACE, "%"PRIu64": RELEASE %p", finh->unique, state->fd); @@ -2140,9 +2345,9 @@ fuse_release (xlator_t *this, fuse_in_header_t *finh, void *msg) if (!ret) { fdctx = (fuse_fd_ctx_t *)(unsigned long)val; if (fdctx) { - new_fd = fdctx->fd; - if (new_fd) { - fd_unref (new_fd); + activefd = fdctx->activefd; + if (activefd) { + fd_unref (activefd); } GF_FREE (fdctx); @@ -2160,20 +2365,18 @@ fuse_release (xlator_t *this, fuse_in_header_t *finh, void *msg) return; } - void fuse_fsync_resume (fuse_state_t *state) { gf_log ("glusterfs-fuse", GF_LOG_TRACE, "%"PRIu64": FSYNC %p", state->finh->unique, - state->fd); + state->fd); /* fsync_flags: 1 means "datasync" (no defines for this) */ FUSE_FOP (state, fuse_fsync_cbk, GF_FOP_FSYNC, - fsync, state->fd, state->flags & 1); + fsync, state->fd, (state->flags & 1), state->xdata); } - static void fuse_fsync (xlator_t *this, fuse_in_header_t *finh, void *msg) { @@ -2186,19 +2389,19 @@ fuse_fsync (xlator_t *this, fuse_in_header_t *finh, void *msg) fd = FH_TO_FD (fsi->fh); state->fd = fd; - fuse_resolve_fd_init (state, &state->resolve, fd); + fuse_resolve_fd_init (state, &state->resolve, fd); 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; - fuse_private_t *priv = NULL; + fd_t *fd = NULL; + fuse_private_t *priv = NULL; + fuse_fd_ctx_t *fdctx = NULL; priv = state->this->private; @@ -2212,6 +2415,25 @@ fuse_opendir_resume (fuse_state_t *state) } fd = fd_create (state->loc.inode, state->finh->pid); + if (fd == NULL) { + gf_log ("glusterfs-fuse", GF_LOG_WARNING, + "%"PRIu64": OPENDIR fd creation failed", + state->finh->unique); + send_fuse_err (state->this, state->finh, ENOMEM); + free_fuse_state (state); + } + + fdctx = fuse_fd_ctx_check_n_create (state->this, fd); + if (fdctx == NULL) { + gf_log ("glusterfs-fuse", GF_LOG_WARNING, + "%"PRIu64": OPENDIR creation of fdctx failed", + state->finh->unique); + fd_unref (fd); + send_fuse_err (state->this, state->finh, ENOMEM); + free_fuse_state (state); + return; + } + state->fd = fd_ref (fd); state->fd_no = gf_fd_unused_get (priv->fdtable, fd); @@ -2220,10 +2442,9 @@ fuse_opendir_resume (fuse_state_t *state) state->loc.path); FUSE_FOP (state, fuse_fd_cbk, GF_FOP_OPENDIR, - opendir, &state->loc, fd); + opendir, &state->loc, fd, state->xdata); } - static void fuse_opendir (xlator_t *this, fuse_in_header_t *finh, void *msg) { @@ -2240,7 +2461,6 @@ fuse_opendir (xlator_t *this, fuse_in_header_t *finh, void *msg) fuse_resolve_and_resume (state, fuse_opendir_resume); } - unsigned char d_type_from_stat (struct iatt *buf) { @@ -2274,10 +2494,10 @@ d_type_from_stat (struct iatt *buf) return d_type; } - static int fuse_readdir_cbk (call_frame_t *frame, void *cookie, xlator_t *this, - int32_t op_ret, int32_t op_errno, gf_dirent_t *entries) + int32_t op_ret, int32_t op_errno, gf_dirent_t *entries, + dict_t *xdata) { fuse_state_t *state = NULL; fuse_in_header_t *finh = NULL; @@ -2285,9 +2505,13 @@ fuse_readdir_cbk (call_frame_t *frame, void *cookie, xlator_t *this, char *buf = NULL; gf_dirent_t *entry = NULL; struct fuse_dirent *fde = NULL; + fuse_private_t *priv = NULL; state = frame->root->state; finh = state->finh; + priv = state->this->private; + + fuse_log_eh_fop(this, state, frame, op_ret, op_errno); if (op_ret < 0) { gf_log ("glusterfs-fuse", GF_LOG_WARNING, @@ -2307,6 +2531,11 @@ fuse_readdir_cbk (call_frame_t *frame, void *cookie, xlator_t *this, strlen (entry->d_name)); } + if (size <= 0) { + send_fuse_data (this, finh, 0, 0); + goto out; + } + buf = GF_CALLOC (1, size, gf_fuse_mt_char); if (!buf) { gf_log ("glusterfs-fuse", GF_LOG_DEBUG, @@ -2319,10 +2548,7 @@ fuse_readdir_cbk (call_frame_t *frame, void *cookie, xlator_t *this, size = 0; list_for_each_entry (entry, &entries->list, list) { fde = (struct fuse_dirent *)(buf + size); - fde->ino = entry->d_ino; - fde->off = entry->d_off; - fde->namelen = strlen (entry->d_name); - strncpy (fde->name, entry->d_name, fde->namelen); + gf_fuse_fill_dirent (entry, fde, priv->enable_ino32); size += FUSE_DIRENT_SIZE (fde); } @@ -2334,25 +2560,22 @@ fuse_readdir_cbk (call_frame_t *frame, void *cookie, xlator_t *this, out: free_fuse_state (state); STACK_DESTROY (frame->root); - if (buf) - GF_FREE (buf); + GF_FREE (buf); return 0; } - void fuse_readdir_resume (fuse_state_t *state) { gf_log ("glusterfs-fuse", GF_LOG_TRACE, - "%"PRIu64": READDIR (%p, size=%zu, offset=%"PRId64")", + "%"PRIu64": READDIR (%p, size=%"GF_PRI_SIZET", 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); + readdir, state->fd, state->size, state->off, state->xdata); } - static void fuse_readdir (xlator_t *this, fuse_in_header_t *finh, void *msg) { @@ -2367,28 +2590,207 @@ fuse_readdir (xlator_t *this, fuse_in_header_t *finh, void *msg) fd = FH_TO_FD (fri->fh); state->fd = fd; - fuse_resolve_fd_init (state, &state->resolve, fd); + fuse_resolve_fd_init (state, &state->resolve, fd); fuse_resolve_and_resume (state, fuse_readdir_resume); } +static int +fuse_readdirp_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, gf_dirent_t *entries, + dict_t *xdata) +{ + fuse_state_t *state = NULL; + fuse_in_header_t *finh = NULL; + int size = 0; + char *buf = NULL; + gf_dirent_t *entry = NULL; + struct fuse_direntplus *fde = NULL; + struct fuse_entry_out *feo = NULL; + fuse_private_t *priv = NULL; + + state = frame->root->state; + finh = state->finh; + priv = this->private; + + if (op_ret < 0) { + gf_log ("glusterfs-fuse", GF_LOG_WARNING, + "%"PRIu64": READDIRP => -1 (%s)", frame->root->unique, + strerror (op_errno)); + + send_fuse_err (this, finh, op_errno); + goto out; + } + + gf_log ("glusterfs-fuse", GF_LOG_TRACE, + "%"PRIu64": READDIRP => %d/%"GF_PRI_SIZET",%"PRId64, + frame->root->unique, op_ret, state->size, state->off); + + list_for_each_entry (entry, &entries->list, list) { + size += FUSE_DIRENT_ALIGN (FUSE_NAME_OFFSET_DIRENTPLUS + + strlen (entry->d_name)); + } + + if (size <= 0) { + send_fuse_data (this, finh, 0, 0); + goto out; + } + + buf = GF_CALLOC (1, size, gf_fuse_mt_char); + if (!buf) { + gf_log ("glusterfs-fuse", GF_LOG_DEBUG, + "%"PRIu64": READDIRP => -1 (%s)", frame->root->unique, + strerror (ENOMEM)); + send_fuse_err (this, finh, ENOMEM); + goto out; + } + + size = 0; + list_for_each_entry (entry, &entries->list, list) { + inode_t *linked_inode; + + fde = (struct fuse_direntplus *)(buf + size); + feo = &fde->entry_out; + fde->dirent.ino = entry->d_ino; + fde->dirent.off = entry->d_off; + fde->dirent.type = entry->d_type; + fde->dirent.namelen = strlen (entry->d_name); + strncpy (fde->dirent.name, entry->d_name, fde->dirent.namelen); + size += FUSE_DIRENTPLUS_SIZE (fde); + + if (!entry->inode) + continue; + + entry->d_stat.ia_blksize = this->ctx->page_size; + gf_fuse_stat2attr (&entry->d_stat, &feo->attr, priv->enable_ino32); + + linked_inode = inode_link (entry->inode, state->fd->inode, + entry->d_name, &entry->d_stat); + if (!linked_inode) + continue; + + inode_lookup (linked_inode); + + feo->nodeid = inode_to_fuse_nodeid (linked_inode); + + fuse_inode_set_need_lookup (linked_inode, this); + + inode_unref (linked_inode); + + feo->entry_valid = + calc_timeout_sec (priv->entry_timeout); + feo->entry_valid_nsec = + calc_timeout_nsec (priv->entry_timeout); + feo->attr_valid = + calc_timeout_sec (priv->attribute_timeout); + feo->attr_valid_nsec = + calc_timeout_nsec (priv->attribute_timeout); + } + + send_fuse_data (this, finh, buf, size); +out: + free_fuse_state (state); + STACK_DESTROY (frame->root); + GF_FREE (buf); + return 0; + +} + + +void +fuse_readdirp_resume (fuse_state_t *state) +{ + gf_log ("glusterfs-fuse", GF_LOG_TRACE, + "%"PRIu64": READDIRP (%p, size=%"GF_PRI_SIZET", offset=%"PRId64")", + state->finh->unique, state->fd, state->size, state->off); + + FUSE_FOP (state, fuse_readdirp_cbk, GF_FOP_READDIRP, + readdirp, state->fd, state->size, state->off, state->xdata); +} + + +static void +fuse_readdirp (xlator_t *this, fuse_in_header_t *finh, void *msg) +{ + struct fuse_read_in *fri = msg; + + fuse_state_t *state = NULL; + fd_t *fd = NULL; + + GET_STATE (this, finh, state); + state->size = fri->size; + state->off = fri->offset; + fd = FH_TO_FD (fri->fh); + state->fd = fd; + + fuse_resolve_fd_init (state, &state->resolve, fd); + + fuse_resolve_and_resume (state, fuse_readdirp_resume); +} + +static int +fuse_fallocate_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, struct iatt *prebuf, + struct iatt *postbuf, dict_t *xdata) +{ + return fuse_err_cbk(frame, cookie, this, op_ret, op_errno, xdata); +} + +static void +fuse_fallocate_resume(fuse_state_t *state) +{ + gf_log("glusterfs-fuse", GF_LOG_TRACE, + "%"PRIu64": FALLOCATE (%p, flags=%d, size=%zu, offset=%"PRId64")", + state->finh->unique, state->fd, state->flags, state->size, + state->off); + + if (state->flags & FALLOC_FL_PUNCH_HOLE) + FUSE_FOP(state, fuse_fallocate_cbk, GF_FOP_DISCARD, discard, + state->fd, state->off, state->size, state->xdata); + else + FUSE_FOP(state, fuse_fallocate_cbk, GF_FOP_FALLOCATE, fallocate, + state->fd, (state->flags & FALLOC_FL_KEEP_SIZE), + state->off, state->size, state->xdata); +} + +static void +fuse_fallocate(xlator_t *this, fuse_in_header_t *finh, void *msg) +{ + struct fuse_fallocate_in *ffi = msg; + fuse_state_t *state = NULL; + + GET_STATE(this, finh, state); + state->off = ffi->offset; + state->size = ffi->length; + state->flags = ffi->mode; + state->fd = FH_TO_FD(ffi->fh); + + fuse_resolve_fd_init(state, &state->resolve, state->fd); + fuse_resolve_and_resume(state, fuse_fallocate_resume); +} + + static void fuse_releasedir (xlator_t *this, fuse_in_header_t *finh, void *msg) { - struct fuse_release_in *fri = msg; - fd_t *new_fd = NULL; - uint64_t val = 0; - int ret = 0; - fuse_state_t *state = NULL; - fuse_fd_ctx_t *fdctx = NULL; - fuse_private_t *priv = NULL; + struct fuse_release_in *fri = msg; + fd_t *activefd = NULL; + uint64_t val = 0; + int ret = 0; + fuse_state_t *state = NULL; + fuse_fd_ctx_t *fdctx = NULL; + fuse_private_t *priv = NULL; GET_STATE (this, finh, state); state->fd = FH_TO_FD (fri->fh); priv = this->private; + fuse_log_eh (this, "RELEASEDIR (): %"PRIu64": fd: %p, gfid: %s", + finh->unique, state->fd, + uuid_utoa (state->fd->inode->gfid)); + gf_log ("glusterfs-fuse", GF_LOG_TRACE, "%"PRIu64": RELEASEDIR %p", finh->unique, state->fd); @@ -2397,9 +2799,9 @@ fuse_releasedir (xlator_t *this, fuse_in_header_t *finh, void *msg) if (!ret) { fdctx = (fuse_fd_ctx_t *)(unsigned long)val; if (fdctx) { - new_fd = fdctx->fd; - if (new_fd) { - fd_unref (new_fd); + activefd = fdctx->activefd; + if (activefd) { + fd_unref (activefd); } GF_FREE (fdctx); @@ -2423,7 +2825,7 @@ void fuse_fsyncdir_resume (fuse_state_t *state) { FUSE_FOP (state, fuse_err_cbk, GF_FOP_FSYNCDIR, - fsyncdir, state->fd, state->flags & 1); + fsyncdir, state->fd, (state->flags & 1), state->xdata); } @@ -2440,7 +2842,7 @@ fuse_fsyncdir (xlator_t *this, fuse_in_header_t *finh, void *msg) GET_STATE (this, finh, state); state->fd = fd; - fuse_resolve_fd_init (state, &state->resolve, fd); + fuse_resolve_fd_init (state, &state->resolve, fd); state->flags = fsi->fsync_flags; fuse_resolve_and_resume (state, fuse_fsyncdir_resume); @@ -2448,10 +2850,10 @@ fuse_fsyncdir (xlator_t *this, fuse_in_header_t *finh, void *msg) return; } - static int fuse_statfs_cbk (call_frame_t *frame, void *cookie, xlator_t *this, - int32_t op_ret, int32_t op_errno, struct statvfs *buf) + int32_t op_ret, int32_t op_errno, struct statvfs *buf, + dict_t *xdata) { fuse_state_t *state = NULL; fuse_in_header_t *finh = NULL; @@ -2462,6 +2864,10 @@ fuse_statfs_cbk (call_frame_t *frame, void *cookie, xlator_t *this, priv = this->private; finh = state->finh; + fuse_log_eh (this, "op_ret: %d, op_errno: %d, %"PRIu64": %s()", + op_ret, op_errno, frame->root->unique, + gf_fop_list[frame->root->op]); + if (op_ret == 0) { #ifndef GF_DARWIN_HOST_OS /* MacFUSE doesn't respect anyof these tweaks */ @@ -2501,7 +2907,6 @@ fuse_statfs_cbk (call_frame_t *frame, void *cookie, xlator_t *this, return 0; } - void fuse_statfs_resume (fuse_state_t *state) { @@ -2519,7 +2924,7 @@ fuse_statfs_resume (fuse_state_t *state) "%"PRIu64": STATFS", state->finh->unique); FUSE_FOP (state, fuse_statfs_cbk, GF_FOP_STATFS, - statfs, &state->loc); + statfs, &state->loc, state->xdata); } @@ -2530,9 +2935,9 @@ fuse_statfs (xlator_t *this, fuse_in_header_t *finh, void *msg) GET_STATE (this, finh, state); - fuse_resolve_inode_init (state, &state->resolve, finh->nodeid); + fuse_resolve_inode_init (state, &state->resolve, finh->nodeid); - fuse_resolve_and_resume (state, fuse_statfs_resume); + fuse_resolve_and_resume (state, fuse_statfs_resume); } @@ -2544,7 +2949,7 @@ fuse_setxattr_resume (fuse_state_t *state) "%"PRIu64": SETXATTR %s/%"PRIu64" (%s) " "resolution failed", state->finh->unique, uuid_utoa (state->resolve.gfid), - state->finh->nodeid, state->name); + state->finh->nodeid, state->name); send_fuse_err (state->this, state->finh, ENOENT); free_fuse_state (state); return; @@ -2560,14 +2965,16 @@ fuse_setxattr_resume (fuse_state_t *state) state->fd, state->finh->nodeid, state->name); FUSE_FOP (state, fuse_setxattr_cbk, GF_FOP_FSETXATTR, - fsetxattr, state->fd, state->dict, state->flags); + fsetxattr, state->fd, state->xattr, state->flags, + state->xdata); } else { 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); + setxattr, &state->loc, state->xattr, state->flags, + state->xdata); } } @@ -2599,22 +3006,27 @@ fuse_setxattr (xlator_t *this, fuse_in_header_t *finh, void *msg) } #endif + if (fuse_ignore_xattr_set (priv, name)) { + (void) send_fuse_err (this, finh, 0); + return; + } + if (!priv->acl) { - if ((strcmp (name, "system.posix_acl_access") == 0) || - (strcmp (name, "system.posix_acl_default") == 0)) { + if ((strcmp (name, POSIX_ACL_ACCESS_XATTR) == 0) || + (strcmp (name, POSIX_ACL_DEFAULT_XATTR) == 0)) { send_fuse_err (this, finh, EOPNOTSUPP); GF_FREE (finh); return; } } -#ifdef DISABLE_SELINUX - if (!strncmp (name, "security.", 9)) { - send_fuse_err (this, finh, EOPNOTSUPP); - GF_FREE (finh); - return; + if (!priv->selinux) { + if (strncmp (name, "security.", 9) == 0) { + send_fuse_err (this, finh, EOPNOTSUPP); + GF_FREE (finh); + return; + } } -#endif /* Check if the command is for changing the log level of process or specific xlator */ @@ -2629,7 +3041,7 @@ fuse_setxattr (xlator_t *this, fuse_in_header_t *finh, void *msg) gf_log ("fuse", GF_LOG_TRACE, "got request to invalidate %"PRIu64, finh->nodeid); send_fuse_err (this, finh, 0); - fuse_invalidate (this, finh->nodeid); + fuse_invalidate_entry (this, finh->nodeid); GF_FREE (finh); return; } @@ -2643,10 +3055,10 @@ fuse_setxattr (xlator_t *this, fuse_in_header_t *finh, void *msg) GET_STATE (this, finh, state); state->size = fsi->size; - fuse_resolve_inode_init (state, &state->resolve, finh->nodeid); + fuse_resolve_inode_init (state, &state->resolve, finh->nodeid); - state->dict = get_new_dict (); - if (!state->dict) { + state->xattr = get_new_dict (); + if (!state->xattr) { gf_log ("glusterfs-fuse", GF_LOG_ERROR, "%"PRIu64": SETXATTR dict allocation failed", finh->unique); @@ -2669,9 +3081,9 @@ fuse_setxattr (xlator_t *this, fuse_in_header_t *finh, void *msg) gf_log (THIS->name, GF_LOG_ERROR, "value size zero"); dict_value = NULL; } - dict_set (state->dict, newkey, + dict_set (state->xattr, newkey, data_from_dynptr ((void *)dict_value, fsi->size)); - dict_ref (state->dict); + dict_ref (state->xattr); state->flags = fsi->flags; state->name = newkey; @@ -2705,10 +3117,28 @@ send_fuse_xattr (xlator_t *this, fuse_in_header_t *finh, const char *value, } } +/* filter out xattrs that need not be visible on the + * mount point. this is _specifically_ for geo-rep + * as of now, to prevent Rsync from crying out loud + * when it tries to setxattr() for selinux xattrs + */ +static int +fuse_filter_xattr(char *key) +{ + int need_filter = 0; + struct fuse_private *priv = THIS->private; + + if ((priv->client_pid == GF_CLIENT_PID_GSYNCD) + && fnmatch ("*.selinux*", key, FNM_PERIOD) == 0) + need_filter = 1; + + return need_filter; +} + static int fuse_xattr_cbk (call_frame_t *frame, void *cookie, xlator_t *this, - int32_t op_ret, int32_t op_errno, dict_t *dict) + int32_t op_ret, int32_t op_errno, dict_t *dict, dict_t *xdata) { int need_to_free_dict = 0; char *value = ""; @@ -2717,11 +3147,13 @@ fuse_xattr_cbk (call_frame_t *frame, void *cookie, xlator_t *this, data_t *value_data = NULL; int ret = -1; int32_t len = 0; - data_pair_t *trav = NULL; + int32_t len_next = 0; state = frame->root->state; finh = state->finh; + fuse_log_eh_fop(this, state, frame, op_ret, op_errno); + if (op_ret >= 0) { gf_log ("glusterfs-fuse", GF_LOG_TRACE, "%"PRIu64": %s() %s => %d", frame->root->unique, @@ -2743,22 +3175,24 @@ fuse_xattr_cbk (call_frame_t *frame, void *cookie, xlator_t *this, } /* if(value_data)...else */ } else { /* if callback for listxattr */ - trav = dict->members_list; - while (trav) { - len += strlen (trav->key) + 1; - trav = trav->next; - } /* while(trav) */ + /* we need to invoke fuse_filter_xattr() twice. Once + * while counting size and then while filling buffer + */ + len = dict_keys_join (NULL, 0, dict, fuse_filter_xattr); + if (len < 0) + goto out; + value = alloca (len + 1); if (!value) goto out; - len = 0; - trav = dict->members_list; - while (trav) { - strcpy (value + len, trav->key); - value[len + strlen (trav->key)] = '\0'; - len += strlen (trav->key) + 1; - trav = trav->next; - } /* while(trav) */ + + len_next = dict_keys_join (value, len, dict, + fuse_filter_xattr); + if (len_next != len) + gf_log (THIS->name, GF_LOG_ERROR, + "sizes not equal %d != %d", + len, len_next); + send_fuse_xattr (this, finh, value, len, state->size); } /* if(state->name)...else */ } else { @@ -2803,13 +3237,15 @@ out: void fuse_getxattr_resume (fuse_state_t *state) { + char *value = NULL; + if (!state->loc.inode) { gf_log ("glusterfs-fuse", GF_LOG_WARNING, "%"PRIu64": GETXATTR %s/%"PRIu64" (%s) " - "resolution failed", + "resolution failed", state->finh->unique, - uuid_utoa (state->resolve.gfid), - state->finh->nodeid, state->name); + uuid_utoa (state->resolve.gfid), + state->finh->nodeid, state->name); send_fuse_err (state->this, state->finh, ENOENT); free_fuse_state (state); @@ -2820,20 +3256,60 @@ fuse_getxattr_resume (fuse_state_t *state) state->fd = fd_lookup (state->loc.inode, state->finh->pid); #endif /* GF_TEST_FFOP */ + if (state->name && + (strcmp (state->name, VIRTUAL_GFID_XATTR_KEY) == 0)) { + /* send glusterfs gfid in binary form */ + + value = GF_CALLOC (16 + 1, sizeof(char), + gf_common_mt_char); + if (!value) { + send_fuse_err (state->this, state->finh, ENOMEM); + goto internal_out; + } + memcpy (value, state->loc.inode->gfid, 16); + + send_fuse_xattr (THIS, state->finh, value, 16, state->size); + GF_FREE (value); + internal_out: + free_fuse_state (state); + return; + } + + if (state->name && + (strcmp (state->name, VIRTUAL_GFID_XATTR_KEY_STR) == 0)) { + /* transform binary gfid to canonical form */ + + value = GF_CALLOC (UUID_CANONICAL_FORM_LEN + 1, sizeof(char), + gf_common_mt_char); + if (!value) { + send_fuse_err (state->this, state->finh, ENOMEM); + goto internal_out1; + } + uuid_utoa_r (state->loc.inode->gfid, value); + + send_fuse_xattr (THIS, state->finh, value, + UUID_CANONICAL_FORM_LEN, state->size); + GF_FREE (value); + internal_out1: + free_fuse_state (state); + return; + } + + if (state->fd) { gf_log ("glusterfs-fuse", GF_LOG_TRACE, "%"PRIu64": GETXATTR %p/%"PRIu64" (%s)", state->finh->unique, state->fd, state->finh->nodeid, state->name); FUSE_FOP (state, fuse_xattr_cbk, GF_FOP_FGETXATTR, - fgetxattr, state->fd, state->name); + fgetxattr, state->fd, state->name, state->xdata); } else { 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); + getxattr, &state->loc, state->name, state->xdata); } } @@ -2841,15 +3317,16 @@ fuse_getxattr_resume (fuse_state_t *state) static void fuse_getxattr (xlator_t *this, fuse_in_header_t *finh, void *msg) { - struct fuse_getxattr_in *fgxi = msg; - char *name = (char *)(fgxi + 1); - - fuse_state_t *state = NULL; - struct fuse_private *priv = NULL; - int rv = 0; - char *newkey = NULL; + struct fuse_getxattr_in *fgxi = msg; + char *name = (char *)(fgxi + 1); + fuse_state_t *state = NULL; + struct fuse_private *priv = NULL; + int rv = 0; + int op_errno = EINVAL; + char *newkey = NULL; priv = this->private; + GET_STATE (this, finh, state); #ifdef GF_DARWIN_HOST_OS if (fgxi->position) { @@ -2865,45 +3342,45 @@ fuse_getxattr (xlator_t *this, fuse_in_header_t *finh, void *msg) "%"PRIu64": GETXATTR %s/%"PRIu64" (%s):" "refusing positioned getxattr", finh->unique, state->loc.path, finh->nodeid, name); - send_fuse_err (this, finh, EINVAL); - FREE (finh); - return; + op_errno = EINVAL; + goto err; } #endif if (!priv->acl) { - if ((strcmp (name, "system.posix_acl_access") == 0) || - (strcmp (name, "system.posix_acl_default") == 0)) { - send_fuse_err (this, finh, ENOTSUP); - GF_FREE (finh); - return; + if ((strcmp (name, POSIX_ACL_ACCESS_XATTR) == 0) || + (strcmp (name, POSIX_ACL_DEFAULT_XATTR) == 0)) { + op_errno = ENOTSUP; + goto err; } } -#ifdef DISABLE_SELINUX - if (!strncmp (name, "security.", 9)) { - send_fuse_err (this, finh, ENODATA); - GF_FREE (finh); - return; + if (!priv->selinux) { + if (strncmp (name, "security.", 9) == 0) { + op_errno = ENODATA; + goto err; + } } -#endif GET_STATE (this, finh, state); - fuse_resolve_inode_init (state, &state->resolve, finh->nodeid); + fuse_resolve_inode_init (state, &state->resolve, finh->nodeid); rv = fuse_flip_xattr_ns (priv, name, &newkey); if (rv) { - send_fuse_err (this, finh, ENOMEM); - free_fuse_state (state); - goto out; + op_errno = ENOMEM; + goto err; } state->size = fgxi->size; state->name = newkey; fuse_resolve_and_resume (state, fuse_getxattr_resume); - out: + + return; + err: + send_fuse_err (this, finh, op_errno); + free_fuse_state (state); return; } @@ -2915,7 +3392,7 @@ fuse_listxattr_resume (fuse_state_t *state) gf_log ("glusterfs-fuse", GF_LOG_WARNING, "%"PRIu64": LISTXATTR %s/%"PRIu64 "resolution failed", state->finh->unique, - uuid_utoa (state->resolve.gfid), state->finh->nodeid); + uuid_utoa (state->resolve.gfid), state->finh->nodeid); send_fuse_err (state->this, state->finh, ENOENT); free_fuse_state (state); @@ -2932,14 +3409,14 @@ fuse_listxattr_resume (fuse_state_t *state) state->fd, state->finh->nodeid); FUSE_FOP (state, fuse_xattr_cbk, GF_FOP_FGETXATTR, - fgetxattr, state->fd, NULL); + fgetxattr, state->fd, NULL, state->xdata); } else { 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); + getxattr, &state->loc, NULL, state->xdata); } } @@ -2952,7 +3429,7 @@ fuse_listxattr (xlator_t *this, fuse_in_header_t *finh, void *msg) GET_STATE (this, finh, state); - fuse_resolve_inode_init (state, &state->resolve, finh->nodeid); + fuse_resolve_inode_init (state, &state->resolve, finh->nodeid); state->size = fgxi->size; @@ -2968,9 +3445,9 @@ fuse_removexattr_resume (fuse_state_t *state) if (!state->loc.inode) { gf_log ("glusterfs-fuse", GF_LOG_DEBUG, "%"PRIu64": REMOVEXATTR %s/%"PRIu64" (%s) " - "resolution failed", + "resolution failed", state->finh->unique, uuid_utoa (state->resolve.gfid), - state->finh->nodeid, state->name); + state->finh->nodeid, state->name); send_fuse_err (state->this, state->finh, ENOENT); free_fuse_state (state); @@ -2987,14 +3464,14 @@ fuse_removexattr_resume (fuse_state_t *state) state->fd, state->finh->nodeid, state->name); FUSE_FOP (state, fuse_err_cbk, GF_FOP_FREMOVEXATTR, - fremovexattr, state->fd, state->name); + fremovexattr, state->fd, state->name, state->xdata); } else { 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); + removexattr, &state->loc, state->name, state->xdata); } } @@ -3009,11 +3486,17 @@ fuse_removexattr (xlator_t *this, fuse_in_header_t *finh, void *msg) int32_t ret = -1; char *newkey = NULL; + if (!strcmp (GFID_XATTR_KEY, name)) { + send_fuse_err (this, finh, EPERM); + GF_FREE (finh); + return; + } + priv = this->private; GET_STATE (this, finh, state); - fuse_resolve_inode_init (state, &state->resolve, finh->nodeid); + fuse_resolve_inode_init (state, &state->resolve, finh->nodeid); ret = fuse_flip_xattr_ns (priv, name, &newkey); if (ret) { @@ -3033,13 +3516,16 @@ static int gf_fuse_lk_enosys_log; static int fuse_getlk_cbk (call_frame_t *frame, void *cookie, xlator_t *this, - int32_t op_ret, int32_t op_errno, struct gf_flock *lock) + int32_t op_ret, int32_t op_errno, struct gf_flock *lock, + dict_t *xdata) { fuse_state_t *state = NULL; state = frame->root->state; struct fuse_lk_out flo = {{0, }, }; + fuse_log_eh_fop(this, state, frame, op_ret, op_errno); + if (op_ret == 0) { gf_log ("glusterfs-fuse", GF_LOG_TRACE, "%"PRIu64": ERR => 0", frame->root->unique); @@ -3085,7 +3571,7 @@ fuse_getlk_resume (fuse_state_t *state) "%"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); + lk, state->fd, F_GETLK, &state->lk_lock, state->xdata); } @@ -3101,7 +3587,7 @@ fuse_getlk (xlator_t *this, fuse_in_header_t *finh, void *msg) GET_STATE (this, finh, state); state->fd = fd; - fuse_resolve_fd_init (state, &state->resolve, fd); + fuse_resolve_fd_init (state, &state->resolve, fd); convert_fuse_file_lock (&fli->lk, &state->lk_lock, fli->owner); @@ -3116,7 +3602,8 @@ fuse_getlk (xlator_t *this, fuse_in_header_t *finh, void *msg) static int fuse_setlk_cbk (call_frame_t *frame, void *cookie, xlator_t *this, - int32_t op_ret, int32_t op_errno, struct gf_flock *lock) + int32_t op_ret, int32_t op_errno, struct gf_flock *lock, + dict_t *xdata) { uint32_t op = 0; fuse_state_t *state = NULL; @@ -3124,6 +3611,8 @@ fuse_setlk_cbk (call_frame_t *frame, void *cookie, xlator_t *this, state = frame->root->state; op = state->finh->opcode; + fuse_log_eh_fop(this, state, frame, op_ret, op_errno); + if (op_ret == 0) { gf_log ("glusterfs-fuse", GF_LOG_TRACE, "%"PRIu64": ERR => 0", frame->root->unique); @@ -3145,11 +3634,10 @@ fuse_setlk_cbk (call_frame_t *frame, void *cookie, xlator_t *this, gf_log ("glusterfs-fuse", GF_LOG_DEBUG, "Returning EAGAIN Flock: " "start=%llu, len=%llu, pid=%llu, lk-owner=%s", - (unsigned long long) lock->l_start, - (unsigned long long) lock->l_len, - (unsigned long long) lock->l_pid, + (unsigned long long) state->lk_lock.l_start, + (unsigned long long) state->lk_lock.l_len, + (unsigned long long) state->lk_lock.l_pid, lkowner_utoa (&frame->root->lk_owner)); - } else { gf_log ("glusterfs-fuse", GF_LOG_WARNING, "%"PRIu64": ERR => -1 (%s)", @@ -3175,7 +3663,7 @@ fuse_setlk_resume (fuse_state_t *state) FUSE_FOP (state, fuse_setlk_cbk, GF_FOP_LK, lk, state->fd, state->finh->opcode == FUSE_SETLK ? F_SETLK : F_SETLKW, - &state->lk_lock); + &state->lk_lock, state->xdata); } @@ -3192,7 +3680,7 @@ fuse_setlk (xlator_t *this, fuse_in_header_t *finh, void *msg) state->finh = finh; state->fd = fd; - fuse_resolve_fd_init (state, &state->resolve, fd); + fuse_resolve_fd_init (state, &state->resolve, fd); convert_fuse_file_lock (&fli->lk, &state->lk_lock, fli->owner); @@ -3279,6 +3767,10 @@ fuse_init (xlator_t *this, fuse_in_header_t *finh, void *msg) fino.max_readahead = 1 << 17; fino.max_write = 1 << 17; fino.flags = FUSE_ASYNC_READ | FUSE_POSIX_LOCKS; +#if FUSE_KERNEL_MINOR_VERSION >= 17 + if (fini->minor >= 17) + fino.flags |= FUSE_FLOCK_LOCKS; +#endif #if FUSE_KERNEL_MINOR_VERSION >= 12 if (fini->minor >= 12) { /* let fuse leave the umask processing to us, so that it does not @@ -3307,8 +3799,8 @@ fuse_init (xlator_t *this, fuse_in_header_t *finh, void *msg) } priv->revchan_in = pfd[0]; priv->revchan_out = pfd[1]; - ret = pthread_create (&messenger, NULL, notify_kernel_loop, - this); + ret = gf_thread_create (&messenger, NULL, notify_kernel_loop, + this); if (ret != 0) { gf_log ("glusterfs-fuse", GF_LOG_ERROR, "failed to start messenger daemon (%s)", @@ -3318,15 +3810,70 @@ fuse_init (xlator_t *this, fuse_in_header_t *finh, void *msg) goto out; } priv->reverse_fuse_thread_started = _gf_true; + } else { + /* + * FUSE minor < 12 does not implement invalidate notifications. + * This mechanism is required for fopen-keep-cache to operate + * correctly. Disable and warn the user. + */ + if (priv->fopen_keep_cache) { + gf_log("glusterfs-fuse", GF_LOG_WARNING, "FUSE version " + "%d.%d does not support inval notifications. " + "fopen-keep-cache disabled.", fini->major, + fini->minor); + priv->fopen_keep_cache = 0; + } } + if (fini->minor >= 13) { - /* these values seemed to work fine during testing */ - fino.max_background = 64; - fino.congestion_threshold = 48; + fino.max_background = priv->background_qlen; + fino.congestion_threshold = priv->congestion_threshold; } if (fini->minor < 9) *priv->msg0_len_p = sizeof(*finh) + FUSE_COMPAT_WRITE_IN_SIZE; #endif + if (priv->use_readdirp) { + if (fini->flags & FUSE_DO_READDIRPLUS) + fino.flags |= FUSE_DO_READDIRPLUS; + } + + if (priv->fopen_keep_cache == 2) { + /* If user did not explicitly set --fopen-keep-cache[=off], + then check if kernel support FUSE_AUTO_INVAL_DATA and ... + */ + if (fini->flags & FUSE_AUTO_INVAL_DATA) { + /* ... enable fopen_keep_cache mode if supported. + */ + gf_log ("glusterfs-fuse", GF_LOG_DEBUG, "Detected " + "support for FUSE_AUTO_INVAL_DATA. Enabling " + "fopen_keep_cache automatically."); + fino.flags |= FUSE_AUTO_INVAL_DATA; + priv->fopen_keep_cache = 1; + } else { + gf_log ("glusterfs-fuse", GF_LOG_DEBUG, "No support " + "for FUSE_AUTO_INVAL_DATA. Disabling " + "fopen_keep_cache."); + /* ... else disable. */ + priv->fopen_keep_cache = 0; + } + } else if (priv->fopen_keep_cache == 1) { + /* If user explicitly set --fopen-keep-cache[=on], + then enable FUSE_AUTO_INVAL_DATA if possible. + */ + if (fini->flags & FUSE_AUTO_INVAL_DATA) { + gf_log ("glusterfs-fuse", GF_LOG_DEBUG, "fopen_keep_cache " + "is explicitly set. Enabling FUSE_AUTO_INVAL_DATA"); + fino.flags |= FUSE_AUTO_INVAL_DATA; + } else { + gf_log ("glusterfs-fuse", GF_LOG_WARNING, "fopen_keep_cache " + "is explicitly set. Support for " + "FUSE_AUTO_INVAL_DATA is missing"); + } + } + + if (fini->flags & FUSE_ASYNC_DIO) + fino.flags |= FUSE_ASYNC_DIO; + ret = send_fuse_obj (this, finh, &fino); if (ret == 0) gf_log ("glusterfs-fuse", GF_LOG_INFO, @@ -3466,6 +4013,7 @@ fuse_nameless_lookup (xlator_t *xl, uuid_t gfid, loc_t *loc) int ret = -1; dict_t *xattr_req = NULL; struct iatt iatt = {0, }; + inode_t *linked_inode = NULL; if ((loc == NULL) || (xl == NULL)) { goto out; @@ -3490,7 +4038,9 @@ fuse_nameless_lookup (xlator_t *xl, uuid_t gfid, loc_t *loc) goto out; } - inode_link (loc->inode, NULL, NULL, &iatt); + linked_inode = inode_link (loc->inode, NULL, NULL, &iatt); + inode_unref (loc->inode); + loc->inode = linked_inode; ret = 0; out: @@ -3503,99 +4053,292 @@ out: int -fuse_migrate_fd (xlator_t *this, fd_t *fd, xlator_t *old_subvol, - xlator_t *new_subvol) +fuse_migrate_fd_open (xlator_t *this, fd_t *basefd, fd_t *oldfd, + xlator_t *old_subvol, xlator_t *new_subvol) { - int ret = -1; - loc_t loc = {0, }; - char create_in_progress = 0; - inode_t *old_inode = NULL; + loc_t loc = {0, }; + fd_t *newfd = NULL, *old_activefd = NULL; + fuse_fd_ctx_t *basefd_ctx = NULL; + fuse_fd_ctx_t *newfd_ctx = NULL; + int ret = 0, flags = 0; - /* could've used pthread_cond_wait, but that requires a cond variable to - * be mainted for each fd and that is a bit too much overhead. - */ - do { - LOCK (&fd->inode->lock); - { - if (uuid_is_null (fd->inode->gfid)) { - create_in_progress = 1; - } else { - create_in_progress = 0; - } - } - UNLOCK (&fd->inode->lock); + ret = inode_path (basefd->inode, NULL, (char **)&loc.path); + if (ret < 0) { + gf_log ("glusterfs-fuse", GF_LOG_WARNING, + "cannot construct path of gfid (%s) failed" + "(old-subvolume:%s-%d new-subvolume:%s-%d)", + uuid_utoa (basefd->inode->gfid), + old_subvol->name, old_subvol->graph->id, + new_subvol->name, new_subvol->graph->id); + goto out; + } - if (create_in_progress) { - gf_log ("glusterfs-fuse", GF_LOG_INFO, - "create call on fd (%p) is in progress, " - "hence waiting", fd); - sleep (1); - } + uuid_copy (loc.gfid, basefd->inode->gfid); - } while (create_in_progress); + loc.inode = inode_find (new_subvol->itable, basefd->inode->gfid); - if (fd->inode->table->xl == old_subvol) { - ret = syncop_fsync (old_subvol, fd); + if (loc.inode == NULL) { + ret = fuse_nameless_lookup (new_subvol, basefd->inode->gfid, + &loc); if (ret < 0) { gf_log ("glusterfs-fuse", GF_LOG_WARNING, - "syncop_fsync failed (%s)", strerror (errno)); + "name-less lookup of gfid (%s) failed (%s)" + "(old-subvolume:%s-%d new-subvolume:%s-%d)", + uuid_utoa (basefd->inode->gfid), + strerror (errno), + old_subvol->name, old_subvol->graph->id, + new_subvol->name, new_subvol->graph->id); + goto out; } - } else { - gf_log ("glusterfs-fuse", GF_LOG_DEBUG, "fd (%p) was not " - "migrated during previous graph switch", fd); + } - loc.path = ""; - loc.name = NULL; + basefd_ctx = fuse_fd_ctx_get (this, basefd); + GF_VALIDATE_OR_GOTO ("glusterfs-fuse", basefd_ctx, out); + + newfd = fd_create (loc.inode, basefd->pid); + if (newfd == NULL) { + gf_log ("glusterfs-fuse", GF_LOG_WARNING, + "cannot create new fd, hence not migrating basefd " + "(ptr:%p inode-gfid:%s) " + "(old-subvolume:%s-%d new-subvolume:%s-%d)", basefd, + uuid_utoa (loc.inode->gfid), + old_subvol->name, old_subvol->graph->id, + new_subvol->name, new_subvol->graph->id); + goto out; + } + + newfd->flags = basefd->flags; + if (newfd->lk_ctx) + fd_lk_ctx_unref (newfd->lk_ctx); + + newfd->lk_ctx = fd_lk_ctx_ref (oldfd->lk_ctx); + + newfd_ctx = fuse_fd_ctx_check_n_create (this, newfd); + GF_VALIDATE_OR_GOTO ("glusterfs-fuse", newfd_ctx, out); + + if (IA_ISDIR (basefd->inode->ia_type)) { + ret = syncop_opendir (new_subvol, &loc, newfd); + } else { + flags = basefd->flags & ~(O_CREAT | O_EXCL | O_TRUNC); + ret = syncop_open (new_subvol, &loc, flags, newfd); + } - ret = fuse_nameless_lookup (new_subvol, fd->inode->gfid, &loc); if (ret < 0) { gf_log ("glusterfs-fuse", GF_LOG_WARNING, - "name-less lookup of gfid (%s) failed (%s)", - uuid_utoa (fd->inode->gfid), strerror (errno)); + "open on basefd (ptr:%p inode-gfid:%s) failed (%s)" + "(old-subvolume:%s-%d new-subvolume:%s-%d)", basefd, + uuid_utoa (basefd->inode->gfid), strerror (errno), + old_subvol->name, old_subvol->graph->id, + new_subvol->name, new_subvol->graph->id); goto out; } - old_inode = fd->inode; + fd_bind (newfd); + + LOCK (&basefd->lock); + { + if (basefd_ctx->activefd != NULL) { + old_activefd = basefd_ctx->activefd; + } + + basefd_ctx->activefd = newfd; + } + UNLOCK (&basefd->lock); + + if (old_activefd != NULL) { + fd_unref (old_activefd); + } + + gf_log ("glusterfs-fuse", GF_LOG_INFO, + "migrated basefd (%p) to newfd (%p) (inode-gfid:%s)" + "(old-subvolume:%s-%d new-subvolume:%s-%d)", basefd, newfd, + uuid_utoa (basefd->inode->gfid), + old_subvol->name, old_subvol->graph->id, + new_subvol->name, new_subvol->graph->id); + + ret = 0; + +out: + loc_wipe (&loc); + + return ret; +} + +int +fuse_migrate_locks (xlator_t *this, fd_t *basefd, fd_t *oldfd, + xlator_t *old_subvol, xlator_t *new_subvol) +{ + int ret = -1; + dict_t *lockinfo = NULL; + void *ptr = NULL; + fd_t *newfd = NULL; + fuse_fd_ctx_t *basefd_ctx = NULL; + + + if (!oldfd->lk_ctx || fd_lk_ctx_empty (oldfd->lk_ctx)) + return 0; - inode_ref (loc.inode); + basefd_ctx = fuse_fd_ctx_get (this, basefd); + GF_VALIDATE_OR_GOTO ("glusterfs-fuse", basefd_ctx, out); - LOCK (&fd->inode->lock); + LOCK (&basefd->lock); { - list_del_init (&fd->inode_list); + newfd = fd_ref (basefd_ctx->activefd); } - UNLOCK (&fd->inode->lock); + UNLOCK (&basefd->lock); - LOCK (&fd->lock); + ret = syncop_fgetxattr (old_subvol, oldfd, &lockinfo, + GF_XATTR_LOCKINFO_KEY); + if (ret < 0) { + gf_log (this->name, GF_LOG_WARNING, + "getting lockinfo failed while migrating locks" + "(oldfd:%p newfd:%p inode-gfid:%s)" + "(old-subvol:%s-%d new-subvol:%s-%d)", + oldfd, newfd, uuid_utoa (newfd->inode->gfid), + old_subvol->name, old_subvol->graph->id, + new_subvol->name, new_subvol->graph->id); + goto out; + } + + ret = dict_get_ptr (lockinfo, GF_XATTR_LOCKINFO_KEY, &ptr); + if (ptr == NULL) { + ret = 0; + gf_log (this->name, GF_LOG_INFO, + "No lockinfo present on any of the bricks " + "(oldfd: %p newfd:%p inode-gfid:%s) " + "(old-subvol:%s-%d new-subvol:%s-%d)", + oldfd, newfd, uuid_utoa (newfd->inode->gfid), + old_subvol->name, old_subvol->graph->id, + new_subvol->name, new_subvol->graph->id); + + goto out; + } + + ret = syncop_fsetxattr (new_subvol, newfd, lockinfo, 0); + if (ret < 0) { + gf_log (this->name, GF_LOG_WARNING, + "migrating locks failed (oldfd:%p newfd:%p " + "inode-gfid:%s) (old-subvol:%s-%d new-subvol:%s-%d)", + oldfd, newfd, uuid_utoa (newfd->inode->gfid), + old_subvol->name, old_subvol->graph->id, + new_subvol->name, new_subvol->graph->id); + goto out; + } + +out: + if (newfd) + fd_unref (newfd); + + if (lockinfo != NULL) { + dict_unref (lockinfo); + } + + return ret; +} + + +int +fuse_migrate_fd (xlator_t *this, fd_t *basefd, xlator_t *old_subvol, + xlator_t *new_subvol) +{ + int ret = -1; + char create_in_progress = 0; + fuse_fd_ctx_t *basefd_ctx = NULL; + fd_t *oldfd = NULL; + + basefd_ctx = fuse_fd_ctx_get (this, basefd); + GF_VALIDATE_OR_GOTO ("glusterfs-fuse", basefd_ctx, out); + + LOCK (&basefd->lock); { - fd->inode = loc.inode; + oldfd = basefd_ctx->activefd ? basefd_ctx->activefd + : basefd; + fd_ref (oldfd); + } + UNLOCK (&basefd->lock); + + LOCK (&oldfd->inode->lock); + { + if (uuid_is_null (oldfd->inode->gfid)) { + create_in_progress = 1; + } else { + create_in_progress = 0; + } + } + UNLOCK (&oldfd->inode->lock); + + if (create_in_progress) { + gf_log ("glusterfs-fuse", GF_LOG_INFO, + "create call on fd (%p) is in progress " + "(basefd-ptr:%p basefd-inode.gfid:%s), " + "hence deferring migration till application does an " + "fd based operation on this fd" + "(old-subvolume:%s-%d, new-subvolume:%s-%d)", + oldfd, basefd, uuid_utoa (basefd->inode->gfid), + old_subvol->name, old_subvol->graph->id, + new_subvol->name, new_subvol->graph->id); + + ret = 0; + goto out; } - UNLOCK (&fd->lock); - if (IA_ISDIR (fd->inode->ia_type)) { - ret = syncop_opendir (new_subvol, &loc, fd); + if (oldfd->inode->table->xl == old_subvol) { + ret = syncop_fsync (old_subvol, oldfd, 0); + if (ret < 0) { + gf_log ("glusterfs-fuse", GF_LOG_WARNING, + "syncop_fsync failed (%s) on fd (%p)" + "(basefd:%p basefd-inode.gfid:%s) " + "(old-subvolume:%s-%d new-subvolume:%s-%d)", + strerror (errno), oldfd, basefd, + uuid_utoa (basefd->inode->gfid), + old_subvol->name, old_subvol->graph->id, + new_subvol->name, new_subvol->graph->id); + } } else { - ret = syncop_open (new_subvol, &loc, fd->flags, fd); + gf_log ("glusterfs-fuse", GF_LOG_WARNING, + "basefd (ptr:%p inode-gfid:%s) was not " + "migrated during previous graph switch" + "(old-subvolume:%s-%d new-subvolume: %s-%d)", basefd, + basefd->inode->gfid, + old_subvol->name, old_subvol->graph->id, + new_subvol->name, new_subvol->graph->id); } + ret = fuse_migrate_fd_open (this, basefd, oldfd, old_subvol, + new_subvol); if (ret < 0) { - gf_log ("glusterfs-fuse", GF_LOG_WARNING, - "open on gfid (%s) failed (%s)", - uuid_utoa (fd->inode->gfid), strerror (errno)); + gf_log (this->name, GF_LOG_WARNING, "open corresponding to " + "basefd (ptr:%p inode-gfid:%s) in new graph failed " + "(old-subvolume:%s-%d new-subvolume:%s-%d)", basefd, + uuid_utoa (basefd->inode->gfid), old_subvol->name, + old_subvol->graph->id, new_subvol->name, + new_subvol->graph->id); goto out; } - fd_bind (fd); + ret = fuse_migrate_locks (this, basefd, oldfd, old_subvol, + new_subvol); + if (ret < 0) { + gf_log (this->name, GF_LOG_WARNING, + "migrating locks from old-subvolume (%s-%d) to " + "new-subvolume (%s-%d) failed (inode-gfid:%s oldfd:%p " + "basefd:%p)", old_subvol->name, old_subvol->graph->id, + new_subvol->name, new_subvol->graph->id, + uuid_utoa (basefd->inode->gfid), oldfd, basefd); - ret = 0; + } out: - if (loc.inode != NULL) { - inode_unref (loc.inode); + if (ret < 0) { + gf_log (this->name, GF_LOG_WARNING, "migration of basefd " + "(ptr:%p inode-gfid:%s) failed" + "(old-subvolume:%s-%d new-subvolume:%s-%d)", basefd, + oldfd ? uuid_utoa (oldfd->inode->gfid) : NULL, + old_subvol->name, old_subvol->graph->id, + new_subvol->name, new_subvol->graph->id); } - if (old_inode != NULL) { - inode_unref (old_inode); - } + fd_unref (oldfd); return ret; } @@ -3611,6 +4354,8 @@ fuse_handle_opened_fds (xlator_t *this, xlator_t *old_subvol, fdtable_t *fdtable = NULL; int i = 0; fd_t *fd = NULL; + int32_t ret = 0; + fuse_fd_ctx_t *fdctx = NULL; priv = this->private; @@ -3620,12 +4365,32 @@ fuse_handle_opened_fds (xlator_t *this, xlator_t *old_subvol, if (fdentries != NULL) { for (i = 0; i < count; i++) { fd = fdentries[i].fd; - if (fd != NULL) { - fuse_migrate_fd (this, fd, old_subvol, - new_subvol); + if (fd == NULL) + continue; + + ret = fuse_migrate_fd (this, fd, old_subvol, + new_subvol); + + fdctx = fuse_fd_ctx_get (this, fd); + if (fdctx) { + LOCK (&fd->lock); + { + if (ret < 0) { + fdctx->migration_failed = 1; + } else { + fdctx->migration_failed = 0; + } + } + UNLOCK (&fd->lock); } } + for (i = 0; i < count ; i++) { + fd = fdentries[i].fd; + if (fd) + fd_unref (fd); + } + GF_FREE (fdentries); } @@ -3659,12 +4424,6 @@ fuse_graph_switch_task (void *data) fuse_handle_blocked_locks (args->this, args->old_subvol, args->new_subvol); - pthread_mutex_lock (&args->lock); - { - args->complete = 1; - pthread_cond_broadcast (&args->cond); - } - pthread_mutex_unlock (&args->lock); out: return 0; } @@ -3680,9 +4439,6 @@ fuse_graph_switch_args_alloc (void) goto out; } - pthread_cond_init (&args->cond, NULL); - pthread_mutex_init (&args->lock, NULL); - out: return args; } @@ -3695,22 +4451,12 @@ fuse_graph_switch_args_destroy (fuse_graph_switch_args_t *args) goto out; } - pthread_cond_destroy (&args->cond); - pthread_mutex_destroy (&args->lock); - GF_FREE (args); out: return; } -static int -fuse_graph_switch_complete (int ret, call_frame_t *frame, void *data) -{ - return 0; -} - - int fuse_handle_graph_switch (xlator_t *this, xlator_t *old_subvol, xlator_t *new_subvol) @@ -3733,27 +4479,14 @@ fuse_handle_graph_switch (xlator_t *this, xlator_t *old_subvol, args->old_subvol = old_subvol; args->new_subvol = new_subvol; - ret = synctask_new (this->ctx->env, fuse_graph_switch_task, - fuse_graph_switch_complete, frame, args); + ret = synctask_new (this->ctx->env, fuse_graph_switch_task, NULL, frame, + args); if (ret == -1) { gf_log (this->name, GF_LOG_WARNING, "starting sync-task to " "handle graph switch failed"); goto out; } - pthread_mutex_lock (&args->lock); - { - while (!args->complete) { - ret = pthread_cond_wait (&args->cond, &args->lock); - if (ret != 0) { - gf_log (this->name, GF_LOG_WARNING, - "cond_wait failed ret:%d errno:%d", ret, - errno); - } - } - } - pthread_mutex_unlock (&args->lock); - ret = 0; out: if (args != NULL) { @@ -3793,11 +4526,11 @@ fuse_graph_sync (xlator_t *this) ret = pthread_cond_wait (&priv->sync_cond, &priv->sync_mutex); if (ret != 0) { - gf_log (this->name, GF_LOG_DEBUG, - "timedwait returned non zero value " - "ret: %d errno: %d", ret, errno); - break; - } + gf_log (this->name, GF_LOG_DEBUG, + "timedwait returned non zero value " + "ret: %d errno: %d", ret, errno); + break; + } } } unlock: @@ -3826,20 +4559,38 @@ unlock: return 0; } +int +fuse_get_mount_status (xlator_t *this) +{ + int kid_status = -1; + fuse_private_t *priv = this->private; + + if (read(priv->status_pipe[0],&kid_status, sizeof(kid_status)) < 0) { + gf_log (this->name, GF_LOG_ERROR, "could not get mount status"); + kid_status = -1; + } + gf_log (this->name, GF_LOG_DEBUG, "mount status is %d", kid_status); + + close(priv->status_pipe[0]); + close(priv->status_pipe[1]); + return kid_status; +} static void * fuse_thread_proc (void *data) { - char *mount_point = NULL; - xlator_t *this = NULL; - fuse_private_t *priv = NULL; - ssize_t res = 0; - struct iobuf *iobuf = NULL; - fuse_in_header_t *finh; - struct iovec iov_in[2]; - void *msg = NULL; - const size_t msg0_size = sizeof (*finh) + 128; - fuse_handler_t **fuse_ops = NULL; + char *mount_point = NULL; + xlator_t *this = NULL; + fuse_private_t *priv = NULL; + ssize_t res = 0; + struct iobuf *iobuf = NULL; + fuse_in_header_t *finh; + struct iovec iov_in[2]; + void *msg = NULL; + const size_t msg0_size = sizeof (*finh) + 128; + fuse_handler_t **fuse_ops = NULL; + struct pollfd pfd[2] = {{0,}}; + gf_boolean_t mount_finished = _gf_false; this = data; priv = this->private; @@ -3856,6 +4607,41 @@ fuse_thread_proc (void *data) /* THIS has to be reset here */ THIS = this; + if (!mount_finished) { + memset(pfd,0,sizeof(pfd)); + pfd[0].fd = priv->status_pipe[0]; + pfd[0].events = POLLIN | POLLHUP | POLLERR; + pfd[1].fd = priv->fd; + pfd[1].events = POLLIN | POLLHUP | POLLERR; + if (poll(pfd,2,-1) < 0) { + gf_log (this->name, GF_LOG_ERROR, + "poll error %s", strerror(errno)); + break; + } + if (pfd[0].revents & POLLIN) { + if (fuse_get_mount_status(this) != 0) { + break; + } + mount_finished = _gf_true; + } + else if (pfd[0].revents) { + gf_log (this->name, GF_LOG_ERROR, + "mount pipe closed without status"); + break; + } + if (!pfd[1].revents) { + continue; + } + } + + /* + * We don't want to block on readv while we're still waiting + * for mount status. That means we only want to get here if + * mount_status is true (meaning that our wait completed + * already) or if we already called poll(2) on priv->fd to + * make sure it's ready. + */ + if (priv->init_recvd) fuse_graph_sync (this); @@ -3895,13 +4681,20 @@ fuse_thread_proc (void *data) "terminating upon getting %s when " "reading /dev/fuse", errno == ENODEV ? "ENODEV" : "EBADF"); - + fuse_log_eh (this, "glusterfs-fuse: terminating" + " upon getting %s when " + "reading /dev/fuse", + errno == ENODEV ? "ENODEV": + "EBADF"); break; } if (errno != EINTR) { gf_log ("glusterfs-fuse", GF_LOG_WARNING, "read from /dev/fuse returned -1 (%s)", strerror (errno)); + fuse_log_eh (this, "glusterfs-fuse: read from " + "/dev/fuse returned -1 (%s)", + strerror (errno)); } goto cont_err; @@ -3909,6 +4702,8 @@ fuse_thread_proc (void *data) if (res < sizeof (finh)) { gf_log ("glusterfs-fuse", GF_LOG_WARNING, "short read on /dev/fuse"); + fuse_log_eh (this, "glusterfs-fuse: short read on " + "/dev/fuse"); break; } @@ -3927,6 +4722,8 @@ fuse_thread_proc (void *data) ) { gf_log ("glusterfs-fuse", GF_LOG_WARNING, "inconsistent read on /dev/fuse"); + fuse_log_eh (this, "glusterfs-fuse: inconsistent read " + "on /dev/fuse"); break; } @@ -3936,11 +4733,12 @@ fuse_thread_proc (void *data) msg = iov_in[1].iov_base; else { if (res > msg0_size) { - iov_in[0].iov_base = - GF_REALLOC (iov_in[0].iov_base, res); - if (iov_in[0].iov_base) + void *b = GF_REALLOC (iov_in[0].iov_base, res); + if (b) { + iov_in[0].iov_base = b; finh = (fuse_in_header_t *) iov_in[0].iov_base; + } else { gf_log ("glusterfs-fuse", GF_LOG_ERROR, "Out of memory"); @@ -3961,13 +4759,11 @@ fuse_thread_proc (void *data) finh->uid == priv->uid_map_root) finh->uid = 0; -#ifdef GF_DARWIN_HOST_OS if (finh->opcode >= FUSE_OP_HIGH) /* turn down MacFUSE specific messages */ fuse_enosys (this, finh, msg); else -#endif - fuse_ops[finh->opcode] (this, finh, msg); + fuse_ops[finh->opcode] (this, finh, msg); iobuf_unref (iobuf); continue; @@ -3977,8 +4773,11 @@ fuse_thread_proc (void *data) GF_FREE (iov_in[0].iov_base); } - iobuf_unref (iobuf); - GF_FREE (iov_in[0].iov_base); + /* + * We could be in all sorts of states with respect to iobuf and iov_in + * by the time we get here, and it's just not worth untangling them if + * we're about to kill ourselves anyway. + */ if (dict_get (this->options, ZR_MOUNTPOINT_OPT)) mount_point = data_to_str (dict_get (this->options, @@ -3986,11 +4785,10 @@ fuse_thread_proc (void *data) if (mount_point) { gf_log (this->name, GF_LOG_INFO, "unmounting %s", mount_point); - dict_del (this->options, ZR_MOUNTPOINT_OPT); } + /* Kill the whole process, not just this thread. */ kill (getpid(), SIGTERM); - return NULL; } @@ -4004,7 +4802,7 @@ fuse_itable_dump (xlator_t *this) gf_proc_dump_add_section("xlator.mount.fuse.itable"); inode_table_dump(this->itable, "xlator.mount.fuse.itable"); - return 0; + return 0; } int32_t @@ -4047,10 +4845,51 @@ fuse_priv_dump (xlator_t *this) (int)private->strict_volfile_check); gf_proc_dump_write("reverse_thread_started", "%d", (int)private->reverse_fuse_thread_started); + gf_proc_dump_write("use_readdirp", "%d", private->use_readdirp); return 0; } +int +fuse_history_dump (xlator_t *this) +{ + int ret = -1; + char key_prefix[GF_DUMP_MAX_BUF_LEN] = {0,}; + + GF_VALIDATE_OR_GOTO ("fuse", this, out); + GF_VALIDATE_OR_GOTO (this->name, this->history, out); + + gf_proc_dump_build_key (key_prefix, "xlator.mount.fuse", + "history"); + gf_proc_dump_add_section (key_prefix); + eh_dump (this->history, NULL, dump_history_fuse); + + ret = 0; +out: + return ret; +} + +int +dump_history_fuse (circular_buffer_t *cb, void *data) +{ + char *string = NULL; + struct tm *tm = NULL; + char timestr[256] = {0,}; + + string = (char *)cb->data; + tm = localtime (&cb->tv.tv_sec); + + if (tm) { + strftime (timestr, 256, "%Y-%m-%d %H:%M:%S", tm); + snprintf (timestr + strlen (timestr), 256 - strlen (timestr), + ".%"GF_PRI_SUSECONDS, cb->tv.tv_usec); + gf_proc_dump_write ("TIME", "%s", timestr); + } + + gf_proc_dump_write ("message", "%s\n", string); + + return 0; +} int fuse_graph_setup (xlator_t *this, glusterfs_graph_t *graph) @@ -4135,8 +4974,8 @@ notify (xlator_t *this, int32_t event, void *data, ...) if (!private->fuse_thread_started) { private->fuse_thread_started = 1; - ret = pthread_create (&private->fuse_thread, NULL, - fuse_thread_proc, this); + ret = gf_thread_create (&private->fuse_thread, NULL, + fuse_thread_proc, this); if (ret != 0) { gf_log (this->name, GF_LOG_DEBUG, "pthread_create() failed (%s)", @@ -4184,45 +5023,52 @@ mem_acct_init (xlator_t *this) static fuse_handler_t *fuse_std_ops[FUSE_OP_HIGH] = { - [FUSE_INIT] = fuse_init, - [FUSE_DESTROY] = fuse_destroy, [FUSE_LOOKUP] = fuse_lookup, [FUSE_FORGET] = fuse_forget, [FUSE_GETATTR] = fuse_getattr, [FUSE_SETATTR] = fuse_setattr, - [FUSE_OPENDIR] = fuse_opendir, - [FUSE_READDIR] = fuse_readdir, - [FUSE_RELEASEDIR] = fuse_releasedir, - [FUSE_ACCESS] = fuse_access, [FUSE_READLINK] = fuse_readlink, + [FUSE_SYMLINK] = fuse_symlink, [FUSE_MKNOD] = fuse_mknod, [FUSE_MKDIR] = fuse_mkdir, [FUSE_UNLINK] = fuse_unlink, [FUSE_RMDIR] = fuse_rmdir, - [FUSE_SYMLINK] = fuse_symlink, [FUSE_RENAME] = fuse_rename, [FUSE_LINK] = fuse_link, - [FUSE_CREATE] = fuse_create, [FUSE_OPEN] = fuse_open, [FUSE_READ] = fuse_readv, [FUSE_WRITE] = fuse_write, - [FUSE_FLUSH] = fuse_flush, + [FUSE_STATFS] = fuse_statfs, [FUSE_RELEASE] = fuse_release, [FUSE_FSYNC] = fuse_fsync, - [FUSE_FSYNCDIR] = fuse_fsyncdir, - [FUSE_STATFS] = fuse_statfs, [FUSE_SETXATTR] = fuse_setxattr, [FUSE_GETXATTR] = fuse_getxattr, [FUSE_LISTXATTR] = fuse_listxattr, [FUSE_REMOVEXATTR] = fuse_removexattr, + [FUSE_FLUSH] = fuse_flush, + [FUSE_INIT] = fuse_init, + [FUSE_OPENDIR] = fuse_opendir, + [FUSE_READDIR] = fuse_readdir, + [FUSE_RELEASEDIR] = fuse_releasedir, + [FUSE_FSYNCDIR] = fuse_fsyncdir, [FUSE_GETLK] = fuse_getlk, [FUSE_SETLK] = fuse_setlk, [FUSE_SETLKW] = fuse_setlk, + [FUSE_ACCESS] = fuse_access, + [FUSE_CREATE] = fuse_create, + /* [FUSE_INTERRUPT] */ + /* [FUSE_BMAP] */ + [FUSE_DESTROY] = fuse_destroy, + /* [FUSE_IOCTL] */ + /* [FUSE_POLL] */ + /* [FUSE_NOTIFY_REPLY] */ + [FUSE_BATCH_FORGET]= fuse_batch_forget, + [FUSE_FALLOCATE] = fuse_fallocate, + [FUSE_READDIRPLUS] = fuse_readdirp, }; -static fuse_handler_t *fuse_dump_ops[FUSE_OP_HIGH] = { -}; +static fuse_handler_t *fuse_dump_ops[FUSE_OP_HIGH]; static void @@ -4250,7 +5096,7 @@ fuse_dumper (xlator_t *this, fuse_in_header_t *finh, void *msg) "failed to dump fuse message (R): %s", strerror (errno)); - return priv->fuse_ops0[finh->opcode] (this, finh, msg); + priv->fuse_ops0[finh->opcode] (this, finh, msg); } @@ -4268,8 +5114,11 @@ init (xlator_t *this_xl) int xl_name_allocated = 0; int fsname_allocated = 0; glusterfs_ctx_t *ctx = NULL; - gf_boolean_t sync_mtab = _gf_false; + gf_boolean_t sync_to_mount = _gf_false; + gf_boolean_t fopen_keep_cache = _gf_false; + unsigned long mntflags = 0; char *mnt_args = NULL; + eh_t *event = NULL; if (this_xl == NULL) return -1; @@ -4277,7 +5126,7 @@ init (xlator_t *this_xl) if (this_xl->options == NULL) return -1; - ctx = glusterfs_ctx_get (); + ctx = this_xl->ctx; if (!ctx) return -1; @@ -4348,25 +5197,21 @@ init (xlator_t *this_xl) goto cleanup_exit; } - ret = dict_get_double (options, "attribute-timeout", - &priv->attribute_timeout); - if (ret != 0) - priv->attribute_timeout = 1.0; /* default */ + GF_OPTION_INIT ("attribute-timeout", priv->attribute_timeout, double, + cleanup_exit); - ret = dict_get_double (options, "entry-timeout", - &priv->entry_timeout); - if (ret != 0) - priv->entry_timeout = 1.0; /* default */ + GF_OPTION_INIT ("entry-timeout", priv->entry_timeout, double, + cleanup_exit); - ret = dict_get_int32 (options, "client-pid", - &priv->client_pid); - if (ret == 0) - priv->client_pid_set = _gf_true; + GF_OPTION_INIT ("negative-timeout", priv->negative_timeout, double, + cleanup_exit); + + GF_OPTION_INIT ("client-pid", priv->client_pid, int32, cleanup_exit); + /* have to check & register the presence of client-pid manually */ + priv->client_pid_set = !!dict_get (this_xl->options, "client-pid"); - ret = dict_get_uint32 (options, "uid-map-root", - &priv->uid_map_root); - if (ret != 0) - priv->uid_map_root = 0; + GF_OPTION_INIT ("uid-map-root", priv->uid_map_root, uint32, + cleanup_exit); priv->direct_io_mode = 2; ret = dict_get_str (options, ZR_DIRECT_IO_OPT, &value_string); @@ -4375,29 +5220,21 @@ init (xlator_t *this_xl) GF_ASSERT (ret == 0); } - priv->strict_volfile_check = 0; - ret = dict_get_str (options, ZR_STRICT_VOLFILE_CHECK, &value_string); - if (ret == 0) { - ret = gf_string2boolean (value_string, - &priv->strict_volfile_check); - GF_ASSERT (ret == 0); - } + GF_OPTION_INIT (ZR_STRICT_VOLFILE_CHECK, priv->strict_volfile_check, + bool, cleanup_exit); + + GF_OPTION_INIT ("acl", priv->acl, bool, cleanup_exit); - priv->acl = 0; - ret = dict_get_str (options, "acl", &value_string); - if (ret == 0) { - ret = gf_string2boolean (value_string, &priv->acl); - GF_ASSERT (ret == 0); - } if (priv->uid_map_root) priv->acl = 1; - priv->read_only = 0; - ret = dict_get_str (options, "read-only", &value_string); - if (ret == 0) { - ret = gf_string2boolean (value_string, &priv->read_only); - GF_ASSERT (ret == 0); - } + GF_OPTION_INIT ("selinux", priv->selinux, bool, cleanup_exit); + + GF_OPTION_INIT ("read-only", priv->read_only, bool, cleanup_exit); + + GF_OPTION_INIT ("enable-ino32", priv->enable_ino32, bool, cleanup_exit); + + GF_OPTION_INIT ("use-readdirp", priv->use_readdirp, bool, cleanup_exit); priv->fuse_dump_fd = -1; ret = dict_get_str (options, "dump-fuse", &value_string); @@ -4416,14 +5253,58 @@ init (xlator_t *this_xl) priv->fuse_dump_fd = ret; } - sync_mtab = _gf_false; - ret = dict_get_str (options, "sync-mtab", &value_string); + sync_to_mount = _gf_false; + ret = dict_get_str (options, "sync-to-mount", &value_string); if (ret == 0) { ret = gf_string2boolean (value_string, - &sync_mtab); + &sync_to_mount); GF_ASSERT (ret == 0); } + priv->fopen_keep_cache = 2; + if (dict_get (options, "fopen-keep-cache")) { + GF_OPTION_INIT("fopen-keep-cache", fopen_keep_cache, bool, + cleanup_exit); + priv->fopen_keep_cache = fopen_keep_cache; + } + + GF_OPTION_INIT("gid-timeout", priv->gid_cache_timeout, int32, + cleanup_exit); + + GF_OPTION_INIT ("fuse-mountopts", priv->fuse_mountopts, str, cleanup_exit); + + if (gid_cache_init(&priv->gid_cache, priv->gid_cache_timeout) < 0) { + gf_log("glusterfs-fuse", GF_LOG_ERROR, "Failed to initialize " + "group cache."); + goto cleanup_exit; + } + + /* default values seemed to work fine during testing */ + GF_OPTION_INIT ("background-qlen", priv->background_qlen, int32, + cleanup_exit); + GF_OPTION_INIT ("congestion-threshold", priv->congestion_threshold, + int32, cleanup_exit); + + /* user has set only background-qlen, not congestion-threshold, + use the fuse kernel driver formula to set congestion. ie, 75% */ + if (dict_get (this_xl->options, "background-qlen") && + !dict_get (this_xl->options, "congestion-threshold")) { + priv->congestion_threshold = (priv->background_qlen * 3) / 4; + gf_log (this_xl->name, GF_LOG_INFO, + "setting congestion control as 75%% of " + "background-queue length (ie, (.75 * %d) = %d", + priv->background_qlen, priv->congestion_threshold); + } + + /* congestion should not be higher than background queue length */ + if (priv->congestion_threshold > priv->background_qlen) { + gf_log (this_xl->name, GF_LOG_INFO, + "setting congestion control same as " + "background-queue length (%d)", + priv->background_qlen); + priv->congestion_threshold = priv->background_qlen; + } + cmd_args = &this_xl->ctx->cmd_args; fsname = cmd_args->volfile; if (!fsname && cmd_args->volfile_server) { @@ -4453,17 +5334,36 @@ init (xlator_t *this_xl) goto cleanup_exit; } - gf_asprintf (&mnt_args, "%s%sallow_other,max_read=131072", - priv->read_only ? "ro," : "", - priv->acl ? "" : "default_permissions,"); + if (priv->read_only) + mntflags |= MS_RDONLY; + gf_asprintf (&mnt_args, "%s%s%sallow_other,max_read=131072", + priv->acl ? "" : "default_permissions,", + priv->fuse_mountopts ? priv->fuse_mountopts : "", + priv->fuse_mountopts ? "," : ""); if (!mnt_args) goto cleanup_exit; - priv->fd = gf_fuse_mount (priv->mount_point, fsname, mnt_args, - sync_mtab ? &ctx->mtab_pid : NULL); + if (pipe(priv->status_pipe) < 0) { + gf_log (this_xl->name, GF_LOG_ERROR, + "could not create pipe to separate mount process"); + goto cleanup_exit; + } + + priv->fd = gf_fuse_mount (priv->mount_point, fsname, mntflags, mnt_args, + sync_to_mount ? &ctx->mnt_pid : NULL, + priv->status_pipe[1]); if (priv->fd == -1) goto cleanup_exit; + event = eh_new (FUSE_EVENT_HISTORY_SIZE, _gf_false, NULL); + if (!event) { + gf_log (this_xl->name, GF_LOG_ERROR, + "could not create a new event history"); + goto cleanup_exit; + } + + this_xl->history = event; + pthread_mutex_init (&priv->fuse_dump_mutex, NULL); pthread_cond_init (&priv->sync_cond, NULL); pthread_mutex_init (&priv->sync_mutex, NULL); @@ -4493,12 +5393,13 @@ cleanup_exit: GF_FREE (fsname); if (priv) { GF_FREE (priv->mount_point); - close (priv->fd); - close (priv->fuse_dump_fd); + if (priv->fd != -1) + close (priv->fd); + if (priv->fuse_dump_fd != -1) + close (priv->fuse_dump_fd); GF_FREE (priv); } - if (mnt_args) - GF_FREE (mnt_args); + GF_FREE (mnt_args); return -1; } @@ -4522,26 +5423,28 @@ fini (xlator_t *this_xl) gf_log (this_xl->name, GF_LOG_INFO, "Unmounting '%s'.", mount_point); - dict_del (this_xl->options, ZR_MOUNTPOINT_OPT); gf_fuse_unmount (mount_point, priv->fd); close (priv->fuse_dump_fd); + dict_del (this_xl->options, ZR_MOUNTPOINT_OPT); } /* Process should terminate once fuse xlator is finished. * Required for AUTH_FAILED event. */ - raise (SIGTERM); + kill (getpid (), SIGTERM); } -struct xlator_fops fops = { -}; +struct xlator_fops fops; struct xlator_cbks cbks = { + .invalidate = fuse_invalidate, + .forget = fuse_forget_cbk, }; struct xlator_dumpops dumpops = { .priv = fuse_priv_dump, .inode = fuse_itable_dump, + .history = fuse_history_dump, }; struct volume_options options[] = { @@ -4555,13 +5458,20 @@ struct volume_options options[] = { .type = GF_OPTION_TYPE_PATH }, { .key = {ZR_ATTR_TIMEOUT_OPT}, - .type = GF_OPTION_TYPE_DOUBLE + .type = GF_OPTION_TYPE_DOUBLE, + .default_value = "1.0" }, { .key = {ZR_ENTRY_TIMEOUT_OPT}, - .type = GF_OPTION_TYPE_DOUBLE + .type = GF_OPTION_TYPE_DOUBLE, + .default_value = "1.0" + }, + { .key = {ZR_NEGATIVE_TIMEOUT_OPT}, + .type = GF_OPTION_TYPE_DOUBLE, + .default_value = "0.0" }, { .key = {ZR_STRICT_VOLFILE_CHECK}, - .type = GF_OPTION_TYPE_BOOL + .type = GF_OPTION_TYPE_BOOL, + .default_value = "false" }, { .key = {"client-pid"}, .type = GF_OPTION_TYPE_INT @@ -4569,11 +5479,50 @@ struct volume_options options[] = { { .key = {"uid-map-root"}, .type = GF_OPTION_TYPE_INT }, - { .key = {"sync-mtab"}, + { .key = {"sync-to-mount"}, .type = GF_OPTION_TYPE_BOOL }, { .key = {"read-only"}, .type = GF_OPTION_TYPE_BOOL }, + { .key = {"fopen-keep-cache"}, + .type = GF_OPTION_TYPE_BOOL, + .default_value = "false" + }, + { .key = {"gid-timeout"}, + .type = GF_OPTION_TYPE_INT, + .default_value = "2" + }, + { .key = {"acl"}, + .type = GF_OPTION_TYPE_BOOL, + .default_value = "false" + }, + { .key = {"selinux"}, + .type = GF_OPTION_TYPE_BOOL, + .default_value = "false" + }, + { .key = {"enable-ino32"}, + .type = GF_OPTION_TYPE_BOOL, + .default_value = "false" + }, + { .key = {"background-qlen"}, + .type = GF_OPTION_TYPE_INT, + .default_value = "64", + .min = 16, + .max = (64 * GF_UNIT_KB), + }, + { .key = {"congestion-threshold"}, + .type = GF_OPTION_TYPE_INT, + .default_value = "48", + .min = 12, + .max = (64 * GF_UNIT_KB), + }, + { .key = {"fuse-mountopts"}, + .type = GF_OPTION_TYPE_STR + }, + { .key = {"use-readdirp"}, + .type = GF_OPTION_TYPE_BOOL, + .default_value = "yes" + }, { .key = {NULL} }, }; diff --git a/xlators/mount/fuse/src/fuse-bridge.h b/xlators/mount/fuse/src/fuse-bridge.h index 13c026bcf..34794b6ea 100644 --- a/xlators/mount/fuse/src/fuse-bridge.h +++ b/xlators/mount/fuse/src/fuse-bridge.h @@ -1,22 +1,12 @@ /* - Copyright (c) 2006-2011 Gluster, Inc. <http://www.gluster.com> + Copyright (c) 2006-2012 Red Hat, Inc. <http://www.redhat.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/>. + 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 _GF_FUSE_BRIDGE_H_ #define _GF_FUSE_BRIDGE_H_ @@ -55,9 +45,10 @@ #include "list.h" #include "dict.h" #include "syncop.h" +#include "gidcache.h" #if defined(GF_LINUX_HOST_OS) || defined(__NetBSD__) -#define FUSE_OP_HIGH (FUSE_POLL + 1) +#define FUSE_OP_HIGH (FUSE_READDIRPLUS + 1) #endif #ifdef GF_DARWIN_HOST_OS #define FUSE_OP_HIGH (FUSE_DESTROY + 1) @@ -66,8 +57,6 @@ #define MAX_FUSE_PROC_DELAY 1 -#define DISABLE_SELINUX 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); @@ -87,6 +76,7 @@ struct fuse_private { size_t *msg0_len_p; double entry_timeout; + double negative_timeout; double attribute_timeout; pthread_cond_t sync_cond; @@ -109,13 +99,29 @@ struct fuse_private { gf_boolean_t client_pid_set; unsigned uid_map_root; gf_boolean_t acl; + gf_boolean_t selinux; gf_boolean_t read_only; + int32_t fopen_keep_cache; + int32_t gid_cache_timeout; + gf_boolean_t enable_ino32; fdtable_t *fdtable; + gid_cache_t gid_cache; + char *fuse_mountopts; /* For fuse-reverse-validation */ int revchan_in; int revchan_out; gf_boolean_t reverse_fuse_thread_started; + + /* For communicating with separate mount thread. */ + int status_pipe[2]; + + /* for fuse queue length and congestion threshold */ + int background_qlen; + int congestion_threshold; + + /* for using fuse-kernel readdirp*/ + gf_boolean_t use_readdirp; }; typedef struct fuse_private fuse_private_t; @@ -123,9 +129,6 @@ struct fuse_graph_switch_args { xlator_t *this; xlator_t *old_subvol; xlator_t *new_subvol; - pthread_cond_t cond; - pthread_mutex_t lock; - char complete; }; typedef struct fuse_graph_switch_args fuse_graph_switch_args_t; @@ -134,6 +137,7 @@ typedef struct fuse_graph_switch_args fuse_graph_switch_args_t; sizeof (struct fuse_notify_inval_entry_out) + \ NAME_MAX + 1)) +#define FUSE_EVENT_HISTORY_SIZE 1024 #define _FH_TO_FD(fh) ((fd_t *)(uintptr_t)(fh)) @@ -141,9 +145,10 @@ typedef struct fuse_graph_switch_args fuse_graph_switch_args_t; #define FUSE_FOP(state, ret, op_num, fop, args ...) \ do { \ - call_frame_t *frame = NULL; \ - xlator_t *xl = NULL; \ - int32_t op_ret = 0, op_errno = 0; \ + call_frame_t *frame = NULL; \ + xlator_t *xl = NULL; \ + int32_t op_ret = 0, op_errno = 0; \ + fuse_resolve_t *resolve = NULL; \ \ frame = get_call_frame_for_req (state); \ if (!frame) { \ @@ -170,32 +175,66 @@ typedef struct fuse_graph_switch_args fuse_graph_switch_args_t; frame->root->op = op_num; \ frame->op = op_num; \ \ + if ( state->resolve_now ) { \ + resolve = state->resolve_now; \ + } else { \ + resolve = &(state->resolve); \ + } \ + \ xl = state->active_subvol; \ if (!xl) { \ gf_log_callingfn ("glusterfs-fuse", GF_LOG_ERROR, \ - "xl is NULL"); \ + "xl is NULL"); \ op_errno = ENOENT; \ op_ret = -1; \ - } else if (state->resolve.op_ret < 0) { \ - op_errno = state->resolve.op_errno; \ - op_ret = -1; \ -/* gf_log_callingfn ("glusterfs-fuse", GF_LOG_WARNING, \ - "resolve failed (%s)", \ - strerror (op_errno)); */ \ - } else if (state->resolve2.op_ret < 0) { \ - op_errno = state->resolve2.op_errno; \ - op_ret = -1; \ - /* gf_log_callingfn ("glusterfs-fuse", GF_LOG_WARNING, \ - "resolve of second entity " \ - "failed (%s)", \ - strerror (op_errno)); */ \ - } \ - \ - if (op_ret < 0) { \ - send_fuse_err (state->this, state->finh, op_errno); \ + } else if (resolve->op_ret < 0) { \ + op_errno = resolve->op_errno; \ + op_ret = -1; \ + if (op_num == GF_FOP_LOOKUP) { \ + gf_log ("glusterfs-fuse", \ + (op_errno == ENOENT ? GF_LOG_TRACE \ + : GF_LOG_WARNING), \ + "%"PRIu64": %s() %s => -1 (%s)", \ + frame->root->unique, \ + gf_fop_list[frame->root->op], \ + resolve->resolve_loc.path, \ + strerror (op_errno)); \ + } else { \ + gf_log ("glusterfs-fuse", \ + GF_LOG_WARNING, \ + "%"PRIu64": %s() inode " \ + "migration of %s failed (%s)", \ + frame->root->unique, \ + gf_fop_list[frame->root->op], \ + resolve->resolve_loc.path, \ + strerror (op_errno)); \ + } \ + } else if (state->resolve2.op_ret < 0) { \ + op_errno = state->resolve2.op_errno; \ + op_ret = -1; \ + gf_log ("glusterfs-fuse", \ + GF_LOG_WARNING, \ + "%"PRIu64": %s() inode " \ + "migration of %s failed (%s)", \ + frame->root->unique, \ + gf_fop_list[frame->root->op], \ + state->resolve2.resolve_loc.path, \ + strerror (op_errno)); \ + } \ + \ + if (op_ret < 0) { \ + send_fuse_err (state->this, state->finh, op_errno); \ free_fuse_state (state); \ STACK_DESTROY (frame->root); \ } else { \ + if (state->this->history) \ + gf_log_eh ("%"PRIu64", %s, path: (%s), gfid: " \ + "(%s)", frame->root->unique, \ + gf_fop_list[frame->root->op], \ + state->loc.path, \ + (state->fd == NULL)? \ + uuid_utoa (state->loc.gfid): \ + uuid_utoa (state->fd->inode->gfid));\ STACK_WIND (frame, ret, xl, xl->fops->fop, args); \ } \ \ @@ -204,7 +243,9 @@ typedef struct fuse_graph_switch_args fuse_graph_switch_args_t; #define FUSE_FOP_COOKIE(state, xl, ret, cky, op_num, fop, args ...) \ do { \ - call_frame_t *frame = NULL; \ + call_frame_t *frame = NULL; \ + xlator_t *xl = NULL; \ + int32_t op_ret = 0, op_errno = 0; \ \ frame = get_call_frame_for_req (state); \ if (!frame) { \ @@ -222,7 +263,62 @@ typedef struct fuse_graph_switch_args fuse_graph_switch_args_t; frame->root->state = state; \ frame->root->op = op_num; \ frame->op = op_num; \ - STACK_WIND_COOKIE (frame, ret, cky, xl, xl->fops->fop, args); \ + \ + xl = state->active_subvol; \ + if (!xl) { \ + gf_log_callingfn ("glusterfs-fuse", GF_LOG_ERROR, \ + "xl is NULL"); \ + op_errno = ENOENT; \ + op_ret = -1; \ + } else if (state->resolve.op_ret < 0) { \ + op_errno = state->resolve.op_errno; \ + op_ret = -1; \ + if (op_num == GF_FOP_LOOKUP) { \ + gf_log ("glusterfs-fuse", \ + (op_errno == ENOENT ? GF_LOG_TRACE \ + : GF_LOG_WARNING), \ + "%"PRIu64": %s() %s => -1 (%s)", \ + frame->root->unique, \ + gf_fop_list[frame->root->op], \ + state->resolve.resolve_loc.path, \ + strerror (op_errno)); \ + } else { \ + gf_log ("glusterfs-fuse", \ + GF_LOG_WARNING, \ + "%"PRIu64": %s() inode " \ + "migration of %s failed (%s)", \ + frame->root->unique, \ + gf_fop_list[frame->root->op], \ + state->resolve.resolve_loc.path, \ + strerror (op_errno)); \ + } \ + } else if (state->resolve2.op_ret < 0) { \ + op_errno = state->resolve2.op_errno; \ + op_ret = -1; \ + gf_log ("glusterfs-fuse", \ + GF_LOG_WARNING, \ + "%"PRIu64": %s() inode " \ + "migration of %s failed (%s)", \ + frame->root->unique, \ + gf_fop_list[frame->root->op], \ + state->resolve2.resolve_loc.path, \ + strerror (op_errno)); \ + } \ + \ + if (op_ret < 0) { \ + send_fuse_err (state->this, state->finh, op_errno); \ + free_fuse_state (state); \ + STACK_DESTROY (frame->root); \ + } else { \ + if (xl->history) \ + gf_log_eh ("%"PRIu64", %s, path: (%s), gfid: " \ + "(%s)", frame->root->unique, \ + gf_fop_list[frame->root->op], \ + state->loc.path, \ + uuid_utoa (state->loc.gfid)); \ + STACK_WIND_COOKIE (frame, ret, cky, xl, xl->fops->fop, \ + args); \ + } \ } while (0) #define GF_SELECT_LOG_LEVEL(_errno) \ @@ -246,7 +342,80 @@ typedef struct fuse_graph_switch_args fuse_graph_switch_args_t; } \ } while (0) +#define FUSE_ENTRY_CREATE(this, priv, finh, state, fci, op) \ + do { \ + if (priv->proto_minor >= 12) \ + state->mode &= ~fci->umask; \ + if (priv->proto_minor >= 12 && priv->acl) { \ + state->xdata = dict_new (); \ + if (!state->xdata) { \ + gf_log ("glusterfs-fuse", \ + GF_LOG_WARNING, \ + "%s failed to allocate " \ + "a param dictionary", op); \ + send_fuse_err (this, finh, ENOMEM); \ + free_fuse_state (state); \ + return; \ + } \ + state->umask = fci->umask; \ + \ +/* TODO: remove this after 3.4.0 release. keeping it for the \ + sake of backward compatibility with old (3.3.[01]) \ + releases till then. */ \ + ret = dict_set_int16 (state->xdata, "umask", \ + fci->umask); \ + if (ret < 0) { \ + gf_log ("glusterfs-fuse", \ + GF_LOG_WARNING, \ + "%s Failed adding umask"\ + " to request", op); \ + dict_destroy (state->xdata); \ + send_fuse_err (this, finh, ENOMEM); \ + free_fuse_state (state); \ + return; \ + } \ + ret = dict_set_int16 (state->xdata, "mode", \ + fci->mode); \ + if (ret < 0) { \ + gf_log ("glusterfs-fuse", \ + GF_LOG_WARNING, \ + "%s Failed adding mode " \ + "to request", op); \ + dict_destroy (state->xdata); \ + send_fuse_err (this, finh, ENOMEM); \ + free_fuse_state (state); \ + return; \ + } \ + } \ + } while (0) + +#define fuse_log_eh_fop(this, state, frame, op_ret, op_errno) \ + do { \ + if (this->history) { \ + if (state->fd) \ + gf_log_eh ("op_ret: %d, op_errno: %d, " \ + "%"PRIu64", %s () => %p, gfid: %s", \ + op_ret, op_errno, \ + frame->root->unique, \ + gf_fop_list[frame->root->op], \ + state->fd, \ + uuid_utoa (state->fd->inode->gfid)); \ + else \ + gf_log_eh ("op_ret: %d, op_errno: %d, " \ + "%"PRIu64", %s () => %s, gfid: %s", \ + op_ret, op_errno, \ + frame->root->unique, \ + gf_fop_list[frame->root->op], \ + state->loc.path, \ + uuid_utoa (state->loc.gfid)); \ + } \ + } while(0) +#define fuse_log_eh(this, args...) \ + do { \ + if (this->history) \ + gf_log_eh(args); \ + } while (0) static inline xlator_t * fuse_active_subvol (xlator_t *fuse) @@ -297,7 +466,8 @@ typedef struct { size_t size; unsigned long nlookup; fd_t *fd; - dict_t *dict; + dict_t *xattr; + dict_t *xdata; char *name; char is_revalidate; gf_boolean_t truncate_needed; @@ -318,6 +488,7 @@ typedef struct { int mask; dev_t rdev; mode_t mode; + mode_t umask; struct iatt attr; struct gf_flock lk_lock; struct iovec vector; @@ -327,9 +498,10 @@ typedef struct { int32_t fd_no; } fuse_state_t; -typedef struct fuse_fd_ctx { +typedef struct { uint32_t open_flags; - fd_t *fd; + char migration_failed; + fd_t *activefd; } fuse_fd_ctx_t; typedef void (*fuse_resume_fn_t) (fuse_state_t *state); @@ -340,17 +512,18 @@ fuse_loc_fill (loc_t *loc, fuse_state_t *state, ino_t ino, 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); +void gf_fuse_stat2attr (struct iatt *st, struct fuse_attr *fa, + gf_boolean_t enable_ino32); +void gf_fuse_fill_dirent (gf_dirent_t *entry, struct fuse_dirent *fde, + gf_boolean_t enable_ino32); uint64_t inode_to_fuse_nodeid (inode_t *inode); xlator_t *fuse_active_subvol (xlator_t *fuse); inode_t *fuse_ino_to_inode (uint64_t ino, xlator_t *fuse); int send_fuse_err (xlator_t *this, fuse_in_header_t *finh, int error); int fuse_gfid_set (fuse_state_t *state); int fuse_flip_xattr_ns (struct fuse_private *priv, char *okey, char **nkey); -int fuse_flip_user_to_trusted (char *okey, char **nkey); -int fuse_xattr_alloc_default (char *okey, char **nkey); -fuse_fd_ctx_t * __fuse_fd_ctx_check_n_create (fd_t *fd, xlator_t *this); -fuse_fd_ctx_t * fuse_fd_ctx_check_n_create (fd_t *fd, xlator_t *this); +fuse_fd_ctx_t * __fuse_fd_ctx_check_n_create (xlator_t *this, fd_t *fd); +fuse_fd_ctx_t * fuse_fd_ctx_check_n_create (xlator_t *this, fd_t *fd); int fuse_resolve_and_resume (fuse_state_t *state, fuse_resume_fn_t fn); int fuse_resolve_inode_init (fuse_state_t *state, fuse_resolve_t *resolve, @@ -359,4 +532,6 @@ int fuse_resolve_entry_init (fuse_state_t *state, fuse_resolve_t *resolve, ino_t par, char *name); int fuse_resolve_fd_init (fuse_state_t *state, fuse_resolve_t *resolve, fd_t *fd); +int fuse_ignore_xattr_set (fuse_private_t *priv, char *key); +int dump_history_fuse (circular_buffer_t *cb, void *data); #endif /* _GF_FUSE_BRIDGE_H_ */ diff --git a/xlators/mount/fuse/src/fuse-helpers.c b/xlators/mount/fuse/src/fuse-helpers.c index 6aee69715..4d478b919 100644 --- a/xlators/mount/fuse/src/fuse-helpers.c +++ b/xlators/mount/fuse/src/fuse-helpers.c @@ -1,21 +1,15 @@ /* - Copyright (c) 2010-2011 Gluster, Inc. <http://www.gluster.com> + Copyright (c) 2010-2012 Red Hat, Inc. <http://www.redhat.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/>. + 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. */ +#ifdef __NetBSD__ +#define _KMEMUSER +#endif #include "fuse-bridge.h" #if defined(GF_SOLARIS_HOST_OS) @@ -28,14 +22,11 @@ static void fuse_resolve_wipe (fuse_resolve_t *resolve) { - if (resolve->path) - GF_FREE ((void *)resolve->path); + GF_FREE ((void *)resolve->path); - if (resolve->bname) - GF_FREE ((void *)resolve->bname); + GF_FREE ((void *)resolve->bname); - if (resolve->resolved) - GF_FREE ((void *)resolve->resolved); + GF_FREE ((void *)resolve->resolved); if (resolve->fd) fd_unref (resolve->fd); @@ -70,10 +61,13 @@ free_fuse_state (fuse_state_t *state) loc_wipe (&state->loc2); - if (state->dict) { - dict_unref (state->dict); - state->dict = (void *)0xaaaaeeee; + if (state->xdata) { + dict_unref (state->xdata); + state->xdata = (void *)0xaaaaeeee; } + if (state->xattr) + dict_unref (state->xattr); + if (state->name) { GF_FREE (state->name); state->name = NULL; @@ -145,6 +139,7 @@ get_fuse_state (xlator_t *this, fuse_in_header_t *finh) } +#define FUSE_MAX_AUX_GROUPS 32 /* We can get only up to 32 aux groups from /proc */ void frame_fill_groups (call_frame_t *frame) { @@ -167,6 +162,9 @@ frame_fill_groups (call_frame_t *frame) if (!fp) goto out; + if (call_stack_alloc_groups (frame->root, FUSE_MAX_AUX_GROUPS) != 0) + goto out; + while ((ptr = fgets (line, sizeof line, fp))) { if (strncmp (ptr, "Groups:", 7) != 0) continue; @@ -183,7 +181,7 @@ frame_fill_groups (call_frame_t *frame) if (!endptr || *endptr) break; frame->root->groups[idx++] = id; - if (idx == GF_MAX_AUX_GROUPS) + if (idx == FUSE_MAX_AUX_GROUPS) break; } @@ -199,6 +197,7 @@ out: prcred_t *prcred = (prcred_t *) scratch; FILE *fp = NULL; int ret = 0; + int ngrps; ret = snprintf (filename, sizeof filename, "/proc/%d/cred", frame->root->pid); @@ -207,8 +206,11 @@ out: fp = fopen (filename, "r"); if (fp != NULL) { if (fgets (scratch, sizeof scratch, fp) != NULL) { - frame->root->ngrps = MIN(prcred->pr_ngroups, - GF_REQUEST_MAXGROUPS); + ngrps = MIN(prcred->pr_ngroups, + GF_MAX_AUX_GROUPS); + if (call_stack_alloc_groups (frame->root, + ngrps) != 0) + return; } fclose (fp); } @@ -233,7 +235,9 @@ out: if (sysctl(name, namelen, &kp, &kplen, NULL, 0) != 0) return; - ngroups = MIN(kp.kp_eproc.e_ucred.cr_ngroups, GF_REQUEST_MAXGROUPS); + ngroups = MIN(kp.kp_eproc.e_ucred.cr_ngroups, GF_MAX_AUX_GROUPS); + if (call_stack_alloc_groups (frame->root, ngroups) != 0) + return; for (i = 0; i < ngroups; i++) frame->root->groups[i] = kp.kp_eproc.e_ucred.cr_groups[i]; frame->root->ngrps = ngroups; @@ -242,6 +246,53 @@ out: #endif /* GF_LINUX_HOST_OS */ } +/* + * Get the groups for the PID associated with this frame. If enabled, + * use the gid cache to reduce group list collection. + */ +static void get_groups(fuse_private_t *priv, call_frame_t *frame) +{ + int i; + const gid_list_t *gl; + gid_list_t agl; + + if (-1 == priv->gid_cache_timeout) { + frame->root->ngrps = 0; + return; + } + + if (!priv->gid_cache_timeout) { + frame_fill_groups(frame); + return; + } + + gl = gid_cache_lookup(&priv->gid_cache, frame->root->pid); + if (gl) { + if (call_stack_alloc_groups (frame->root, gl->gl_count) != 0) + return; + frame->root->ngrps = gl->gl_count; + for (i = 0; i < gl->gl_count; i++) + frame->root->groups[i] = gl->gl_list[i]; + gid_cache_release(&priv->gid_cache, gl); + return; + } + + frame_fill_groups (frame); + + agl.gl_id = frame->root->pid; + agl.gl_count = frame->root->ngrps; + agl.gl_list = GF_CALLOC(frame->root->ngrps, sizeof(gid_t), + gf_fuse_mt_gids_t); + if (!agl.gl_list) + return; + + for (i = 0; i < frame->root->ngrps; i++) + agl.gl_list[i] = frame->root->groups[i]; + + if (gid_cache_add(&priv->gid_cache, &agl) != 1) + GF_FREE(agl.gl_list); +} + call_frame_t * get_call_frame_for_req (fuse_state_t *state) { @@ -269,7 +320,7 @@ get_call_frame_for_req (fuse_state_t *state) state->lk_owner); } - frame_fill_groups (frame); + get_groups(priv, frame); if (priv && priv->client_pid_set) frame->root->pid = priv->client_pid; @@ -301,7 +352,9 @@ fuse_ino_to_inode (uint64_t ino, xlator_t *fuse) uint64_t inode_to_fuse_nodeid (inode_t *inode) { - if (!inode || __is_root_gfid (inode->gfid)) + if (!inode) + return 0; + if (__is_root_gfid (inode->gfid)) return 1; return (unsigned long) inode; @@ -389,54 +442,81 @@ fuse_loc_fill (loc_t *loc, fuse_state_t *state, ino_t ino, } ret = 0; fail: + /* this should not happen as inode_path returns -1 when buf is NULL + for sure */ + if (path && !loc->path) + GF_FREE (path); return ret; } +/* Use the same logic as the Linux NFS-client */ +#define GF_FUSE_SQUASH_INO(ino) ((uint32_t) ino) ^ (ino >> 32) /* courtesy of folly */ void -gf_fuse_stat2attr (struct iatt *st, struct fuse_attr *fa) +gf_fuse_stat2attr (struct iatt *st, struct fuse_attr *fa, gf_boolean_t enable_ino32) { - 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 = makedev (ia_major (st->ia_rdev), - ia_minor (st->ia_rdev)); + if (enable_ino32) + fa->ino = GF_FUSE_SQUASH_INO(st->ia_ino); + else + 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 = makedev (ia_major (st->ia_rdev), + ia_minor (st->ia_rdev)); #if FUSE_KERNEL_MINOR_VERSION >= 9 - fa->blksize = st->ia_blksize; + fa->blksize = st->ia_blksize; #endif #ifdef GF_DARWIN_HOST_OS - fa->crtime = (uint64_t)-1; - fa->crtimensec = (uint32_t)-1; - fa->flags = 0; + fa->crtime = (uint64_t)-1; + fa->crtimensec = (uint32_t)-1; + fa->flags = 0; #endif } -int -fuse_flip_user_to_trusted (char *okey, char **nkey) +void +gf_fuse_fill_dirent (gf_dirent_t *entry, struct fuse_dirent *fde, gf_boolean_t enable_ino32) +{ + if (enable_ino32) + fde->ino = GF_FUSE_SQUASH_INO(entry->d_ino); + else + fde->ino = entry->d_ino; + + fde->off = entry->d_off; + fde->type = entry->d_type; + fde->namelen = strlen (entry->d_name); + strncpy (fde->name, entry->d_name, fde->namelen); +} + +static int +fuse_do_flip_xattr_ns (char *okey, const char *nns, char **nkey) { int ret = 0; char *key = NULL; - key = GF_CALLOC (1, strlen(okey) + 10, gf_common_mt_char); + okey = strchr (okey, '.'); + GF_ASSERT (okey); + + key = GF_CALLOC (1, strlen (nns) + strlen(okey) + 1, + gf_common_mt_char); if (!key) { ret = -1; goto out; } - okey += 5; - strncpy(key, "trusted.", 8); - strncat(key+8, okey, strlen(okey)); + strcpy (key, nns); + strcat (key, okey); *nkey = key; @@ -444,7 +524,7 @@ fuse_flip_user_to_trusted (char *okey, char **nkey) return ret; } -int +static int fuse_xattr_alloc_default (char *okey, char **nkey) { int ret = 0; @@ -455,56 +535,71 @@ fuse_xattr_alloc_default (char *okey, char **nkey) return ret; } +#define PRIV_XA_NS "trusted" +#define UNPRIV_XA_NS "system" + int fuse_flip_xattr_ns (fuse_private_t *priv, char *okey, char **nkey) { int ret = 0; gf_boolean_t need_flip = _gf_false; - gf_client_pid_t npid = 0; - - npid = priv->client_pid; - if (gf_client_pid_check (npid)) { - ret = fuse_xattr_alloc_default (okey, nkey); - goto out; - } - - switch (npid) { - /* - * These two cases will never execute as we check the - * pid range above, but are kept to keep the compiler - * happy. - */ - case GF_CLIENT_PID_MAX: - case GF_CLIENT_PID_MIN: - goto out; + switch (priv->client_pid) { case GF_CLIENT_PID_GSYNCD: /* valid xattr(s): *xtime, volume-mark* */ gf_log("glusterfs-fuse", GF_LOG_DEBUG, "PID: %d, checking xattr(s): " - "volume-mark*, *xtime", npid); - if ( (strcmp (okey, "user.glusterfs.volume-mark") == 0) - || (fnmatch (okey, "user.glusterfs.volume-mark.*", FNM_PERIOD) == 0) - || (fnmatch ("user.glusterfs.*.xtime", okey, FNM_PERIOD) == 0) ) + "volume-mark*, *xtime", priv->client_pid); + if ( (strcmp (okey, UNPRIV_XA_NS".glusterfs.volume-mark") == 0) + || (fnmatch (UNPRIV_XA_NS".glusterfs.volume-mark.*", okey, FNM_PERIOD) == 0) + || (fnmatch (UNPRIV_XA_NS".glusterfs.*.xtime", okey, FNM_PERIOD) == 0) ) need_flip = _gf_true; break; case GF_CLIENT_PID_HADOOP: /* valid xattr(s): pathinfo */ gf_log("glusterfs-fuse", GF_LOG_DEBUG, "PID: %d, checking xattr(s): " - "pathinfo", npid); - if (strcmp (okey, "user.glusterfs.pathinfo") == 0) + "pathinfo", priv->client_pid); + if (strcmp (okey, UNPRIV_XA_NS".glusterfs.pathinfo") == 0) need_flip = _gf_true; break; } if (need_flip) { - gf_log ("glusterfs-fuse", GF_LOG_DEBUG, "flipping %s to trusted equivalent", + gf_log ("glusterfs-fuse", GF_LOG_DEBUG, "flipping %s to "PRIV_XA_NS" equivalent", okey); - ret = fuse_flip_user_to_trusted (okey, nkey); + ret = fuse_do_flip_xattr_ns (okey, PRIV_XA_NS, nkey); } else { /* if we cannot match, continue with what we got */ ret = fuse_xattr_alloc_default (okey, nkey); } + + return ret; +} + +int +fuse_ignore_xattr_set (fuse_private_t *priv, char *key) +{ + int ret = 0; + + /* don't mess with user namespace */ + if (fnmatch ("user.*", key, FNM_PERIOD) == 0) + goto out; + + if (priv->client_pid != GF_CLIENT_PID_GSYNCD) + goto out; + + /* trusted NS check */ + if (!((fnmatch ("*.glusterfs.*.xtime", key, FNM_PERIOD) == 0) + || (fnmatch ("*.glusterfs.volume-mark", + key, FNM_PERIOD) == 0) + || (fnmatch ("*.glusterfs.volume-mark.*", + key, FNM_PERIOD) == 0))) + ret = -1; + out: + gf_log ("glusterfs-fuse", GF_LOG_DEBUG, "%s setxattr: key [%s], " + " client pid [%d]", (ret ? "disallowing" : "allowing"), key, + priv->client_pid); + return ret; } diff --git a/xlators/mount/fuse/src/fuse-mem-types.h b/xlators/mount/fuse/src/fuse-mem-types.h index 9c6a1c67a..28b4dfbdd 100644 --- a/xlators/mount/fuse/src/fuse-mem-types.h +++ b/xlators/mount/fuse/src/fuse-mem-types.h @@ -1,23 +1,13 @@ /* - Copyright (c) 2008-2011 Gluster, Inc. <http://www.gluster.com> + Copyright (c) 2008-2012 Red Hat, Inc. <http://www.redhat.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/>. + 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 __FUSE_MEM_TYPES_H__ #define __FUSE_MEM_TYPES_H__ @@ -31,6 +21,7 @@ enum gf_fuse_mem_types_ { gf_fuse_mt_fuse_state_t, gf_fuse_mt_fd_ctx_t, gf_fuse_mt_graph_switch_args_t, + gf_fuse_mt_gids_t, gf_fuse_mt_end }; #endif diff --git a/xlators/mount/fuse/src/fuse-resolve.c b/xlators/mount/fuse/src/fuse-resolve.c index 5a09ea0d3..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,7 +20,13 @@ 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) @@ -94,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); @@ -128,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; @@ -149,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; } @@ -194,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)); } @@ -233,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; } @@ -245,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); @@ -294,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; @@ -327,27 +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_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; + + 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 = EINVAL; + goto resolve_continue; + } + + FUSE_FD_GET_ACTIVE_FD (activefd, basefd); + + active_subvol = activefd->inode->table->xl; - if (state->active_subvol != active_subvol) { + fd_migration_error = fuse_migrate_fd_error (state->this, basefd); + if (fd_migration_error) { 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); + } 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 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; @@ -362,15 +572,15 @@ fuse_gfid_set (fuse_state_t *state) if (uuid_is_null (state->gfid)) goto out; - if (!state->dict) - state->dict = dict_new (); + if (!state->xdata) + state->xdata = dict_new (); - if (!state->dict) { + if (!state->xdata) { ret = -1; goto out; } - ret = dict_set_static_bin (state->dict, "gfid-req", + ret = dict_set_static_bin (state->xdata, "gfid-req", state->gfid, sizeof (state->gfid)); out: return ret; diff --git a/xlators/mount/fuse/utils/mount.glusterfs.in b/xlators/mount/fuse/utils/mount.glusterfs.in index 9cdc69c1a..a192d6059 100755 --- a/xlators/mount/fuse/utils/mount.glusterfs.in +++ b/xlators/mount/fuse/utils/mount.glusterfs.in @@ -1,4 +1,4 @@ -#!/bin/bash +#!/bin/sh # (C) 2006, 2007, 2008 Gluster Inc. <http://www.gluster.com> # # This program is free software; you can redistribute it and/or @@ -27,138 +27,233 @@ _init () LOG_DEBUG=DEBUG; LOG_TRACE=TRACE; + HOST_NAME_MAX=64; + prefix="@prefix@"; exec_prefix=@exec_prefix@; cmd_line=$(echo "@sbindir@/glusterfs"); + case `uname -s` in + NetBSD) + getinode="stat -f %i" + getdev="stat -f %d" + lgetinode="${getinode} -L" + lgetdev="${getdev} -L" + + mounttab=/proc/mounts + ;; + Linux) + getinode="stat -c %i $i" + getdev="stat -c %d $d" + lgetinode="${getinode} -L" + lgetdev="${getdev} -L" + + mounttab=/etc/mtab + ;; + esac + UPDATEDBCONF=/etc/updatedb.conf } +parse_backup_volfile_servers () +{ + local server_list=$1 + local servers="" + local new_servers="" + + servers=$(echo ${server_list} | sed 's/\:/ /g') + for server in ${servers}; do + length=$(echo $server | wc -c) + if [ ${length} -gt ${HOST_NAME_MAX} ]; then + echo "Hostname:${server} provided is too long.. skipping" + continue + fi + new_servers=$(echo "$new_servers $server") + done + echo ${new_servers} +} + start_glusterfs () { + # lets the comparsion be case insensitive for all strings + if [ -n "$log_level_str" ]; then - case "$log_level_str" in - "ERROR") - log_level=$LOG_ERROR; - ;; + case "$( echo $log_level_str | tr '[a-z]' '[A-Z]')" in + "ERROR") + log_level=$LOG_ERROR; + ;; "INFO") log_level=$LOG_INFO ;; - "DEBUG") - log_level=$LOG_DEBUG; - ;; - "CRITICAL") - log_level=$LOG_CRITICAL; - ;; - "WARNING") - log_level=$LOG_WARNING; - ;; - "TRACE") - log_level=$LOG_TRACE; - ;; - "NONE") - log_level=$LOG_NONE; - ;; - *) - echo "invalid log level $log_level_str, using INFO"; - log_level=$LOG_INFO; - ;; - esac - fi - if [ -n "$log_level" ]; then - cmd_line=$(echo "$cmd_line --log-level=$log_level"); + "DEBUG") + log_level=$LOG_DEBUG; + ;; + "CRITICAL") + log_level=$LOG_CRITICAL; + ;; + "WARNING") + log_level=$LOG_WARNING; + ;; + "TRACE") + log_level=$LOG_TRACE; + ;; + "NONE") + log_level=$LOG_NONE; + ;; + *) + echo "invalid log level $log_level_str, using INFO"; + log_level=$LOG_INFO; + ;; + esac fi +#options without values start here if [ -n "$read_only" ]; then - cmd_line=$(echo "$cmd_line --read-only"); + cmd_line=$(echo "$cmd_line --read-only"); fi if [ -n "$acl" ]; then - cmd_line=$(echo "$cmd_line --acl"); + cmd_line=$(echo "$cmd_line --acl"); + fi + + if [ -n "$selinux" ]; then + cmd_line=$(echo "$cmd_line --selinux"); + fi + + if [ -n "$enable_ino32" ]; then + cmd_line=$(echo "$cmd_line --enable-ino32"); fi if [ -n "$worm" ]; then cmd_line=$(echo "$cmd_line --worm"); fi - if [ -n "$log_file" ]; then - cmd_line=$(echo "$cmd_line --log-file=$log_file"); + if [ -n "$fopen_keep_cache" ]; then + cmd_line=$(echo "$cmd_line --fopen-keep-cache"); fi if [ -n "$volfile_check" ]; then - cmd_line=$(echo "$cmd_line --volfile-check"); + cmd_line=$(echo "$cmd_line --volfile-check"); + fi + + if [ -n "$mem_accounting" ]; then + cmd_line=$(echo "$cmd_line --mem-accounting"); + fi + + if [ -n "$aux_gfid_mount" ]; then + cmd_line=$(echo "$cmd_line --aux-gfid-mount"); + fi + +#options with values start here + if [ -n "$log_level" ]; then + cmd_line=$(echo "$cmd_line --log-level=$log_level"); + fi + + if [ -n "$log_file" ]; then + cmd_line=$(echo "$cmd_line --log-file=$log_file"); fi if [ -n "$direct_io_mode" ]; then - cmd_line=$(echo "$cmd_line --direct-io-mode=$direct_io_mode"); + cmd_line=$(echo "$cmd_line --direct-io-mode=$direct_io_mode"); + fi + + if [ -n "$use_readdirp" ]; then + cmd_line=$(echo "$cmd_line --use-readdirp=$use_readdirp"); fi if [ -n "$volume_name" ]; then cmd_line=$(echo "$cmd_line --volume-name=$volume_name"); fi - if [ -n "$log_server" ]; then - if [ -n "$log_server_port" ]; then - cmd_line=$(echo "$cmd_line \ ---log-server=$log_server \ ---log-server-port=$log_server_port"); - fi + if [ -n "$attribute_timeout" ]; then + cmd_line=$(echo "$cmd_line --attribute-timeout=$attribute_timeout"); + fi + + if [ -n "$entry_timeout" ]; then + cmd_line=$(echo "$cmd_line --entry-timeout=$entry_timeout"); + fi + + if [ -n "$negative_timeout" ]; then + cmd_line=$(echo "$cmd_line --negative-timeout=$negative_timeout"); + fi + + if [ -n "$gid_timeout" ]; then + cmd_line=$(echo "$cmd_line --gid-timeout=$gid_timeout"); + fi + + if [ -n "$bg_qlen" ]; then + cmd_line=$(echo "$cmd_line --background-qlen=$bg_qlen"); + fi + + if [ -n "$cong_threshold" ]; then + cmd_line=$(echo "$cmd_line --congestion-threshold=$cong_threshold"); + fi + + if [ -n "$fuse_mountopts" ]; then + cmd_line=$(echo "$cmd_line --fuse-mountopts=$fuse_mountopts"); fi + if [ -n "$xlator_option" ]; then + xlator_option=$(echo $xlator_option | sed s/"xlator-option="/"--xlator-option "/g) + cmd_line=$(echo "$cmd_line $xlator_option"); + fi + + # for rdma volume, we have to fetch volfile with '.rdma' added + # to volume name, so that it fetches the right client vol file + volume_id_rdma=""; + if [ -z "$volfile_loc" ]; then if [ -n "$server_ip" ]; then + + cmd_line=$(echo "$cmd_line --volfile-server=$server_ip"); + + if [ -n "$backup_volfile_servers" ]; then + servers=$(parse_backup_volfile_servers ${backup_volfile_servers}) + for i in $(echo ${servers}); do + cmd_line=$(echo "$cmd_line --volfile-server=$i"); + done + fi + if [ -n "$server_port" ]; then cmd_line=$(echo "$cmd_line --volfile-server-port=$server_port"); fi - if [ -n "$transport" ]; then + + if [ -n "$transport" ]; then cmd_line=$(echo "$cmd_line --volfile-server-transport=$transport"); + if [ "$transport" = "rdma" ]; then + volume_id_rdma=".rdma"; + fi fi + if [ -n "$volume_id" ]; then + if [ -n "$volume_id_rdma" ]; then + volume_id="$volume_id$volume_id_rdma"; + fi cmd_line=$(echo "$cmd_line --volfile-id=$volume_id"); fi - - if [ -n "$backupvolfile_server" ]; then - cmd_line1=$(echo "$cmd_line --volfile-server=$backupvolfile_server"); - fi - if [ -n "$volfile_max_fetch_attempts" ]; then - cmd_line=$(echo "$cmd_line --volfile-max-fetch-attempts=$volfile_max_fetch_attempts"); - fi - cmd_line=$(echo "$cmd_line --volfile-server=$server_ip"); fi else cmd_line=$(echo "$cmd_line --volfile=$volfile_loc"); fi + if [ -n "$fuse_mountopts" ]; then + cmd_line=$(echo "$cmd_line --fuse-mountopts=$fuse_mountopts"); + fi + cmd_line=$(echo "$cmd_line $mount_point"); err=0; $cmd_line; - inode=$(stat -c %i $mount_point 2>/dev/null); + inode=$( ${getinode} $mount_point 2>/dev/null); # this is required if the stat returns error if [ -z "$inode" ]; then inode="0"; fi - # retry the failover - # if [ $? != "0" ]; then # <--- TODO: Once glusterfs returns proper error code, change it. if [ $inode -ne 1 ]; then err=1; - if [ -n "$cmd_line1" ]; then - cmd_line1=$(echo "$cmd_line1 $mount_point"); - $cmd_line1; - err=0; - - inode=$(stat -c %i $mount_point 2>/dev/null); - # this is required if the stat returns error - if [ -z "$inode" ]; then - inode="0"; - fi - if [ $inode -ne 1 ]; then - err=1; - fi - fi fi if [ $err -eq "1" ]; then @@ -183,13 +278,13 @@ mount.glusterfs --version" # check for recursive mounts. i.e, mounting over an existing brick check_recursive_mount () { - if [ $2 = "/" ]; then + if [ $1 = "/" ]; then echo Cannot mount over root; exit 2; fi # GFID check first # remove trailing / from mount point - mnt_dir=${2%/}; + mnt_dir=${1%/}; export PATH; # check whether getfattr exists @@ -205,18 +300,18 @@ check_recursive_mount () fi # check if the mount point is a brick's parent directory - GLUSTERD_WORKDIR="/etc/glusterd"; + GLUSTERD_WORKDIR="/var/lib/glusterd"; ls -L "$GLUSTERD_WORKDIR"/vols/*/bricks/* > /dev/null 2>&1; if [ $? -ne 0 ]; then return; fi - brick_path=(`grep ^path "$GLUSTERD_WORKDIR"/vols/*/bricks/* | cut -d "=" -f 2`); - root_inode=`stat -Lc %i /`; - root_dev=`stat -Lc %d /`; - mnt_inode=`stat -Lc %i $mnt_dir`; - mnt_dev=`stat -Lc %d $mnt_dir`; + brick_path=`grep ^path "$GLUSTERD_WORKDIR"/vols/*/bricks/* | cut -d "=" -f 2`; + root_inode=`${lgetinode} /`; + root_dev=`${lgetdev} /`; + mnt_inode=`${lgetinode} $mnt_dir`; + mnt_dev=`${lgetdev} $mnt_dir`; for brick in "$brick_path"; do # evaluate brick path to see if this is local, if non-local, skip iteration @@ -233,8 +328,8 @@ check_recursive_mount () do tmp_brick="$brick"; brick="$brick"/..; - brick_dev=`stat -Lc %d $brick`; - brick_inode=`stat -Lc %i $brick`; + brick_dev=`${lgetdev} $brick`; + brick_inode=`${lgetinode} $brick`; if [ "$mnt_inode" -eq "$brick_inode" -a "$mnt_dev" -eq "$brick_dev" ]; then echo ERROR: $mnt_dir is a parent of the brick $tmp_brick; exit 2; @@ -248,44 +343,79 @@ check_recursive_mount () main () { helper=$(echo "$@" | sed -n 's/.*\--[ ]*\([^ ]*\).*/\1/p'); - - options=$(echo "$@" | sed -n 's/.*\-o[ ]*\([^ ]*\).*/\1/p'); - - new_log_level=$(echo "$options" | sed -n 's/.*log-level=\([^,]*\).*/\1/p'); - - [ -n "$new_log_level" ] && { - log_level_str="$new_log_level"; - } - - log_file=$(echo "$options" | sed -n 's/.*log-file=\([^,]*\).*/\1/p'); - - read_only=$(echo "$options" | sed -n 's/.*\(ro\)[^,]*.*/\1/p'); - - acl=$(echo "$options" | sed -n 's/.*\(acl\)[^,]*.*/\1/p'); - - worm=$(echo "$options" | sed -n 's/.*\(worm\)[^,]*.*/\1/p'); - - transport=$(echo "$options" | sed -n 's/.*transport=\([^,]*\).*/\1/p'); - - direct_io_mode=$(echo "$options" | sed -n 's/.*direct-io-mode=\([^,]*\).*/\1/p'); - - volume_name=$(echo "$options" | sed -n 's/.*volume-name=\([^,]*\).*/\1/p'); - - volume_id=$(echo "$options" | sed -n 's/.*volume_id=\([^,]*\).*/\1/p'); - - volfile_check=$(echo "$options" | sed -n 's/.*volfile-check=\([^,]*\).*/\1/p'); - - volfile_max_fetch_attempts=$(echo "$options" | sed -n 's/.*fetch-attempts=\([^,]*\).*/\1/p'); - - server_port=$(echo "$options" | sed -n 's/.*server-port=\([^,]*\).*/\1/p'); - - backupvolfile_server=$(echo "$options" | sed -n 's/.*backupvolfile-server=\([^,]*\).*/\1/p'); - - log_server=$(echo "$options" | sed -n 's/.*log-server=\([^,]*\).*/\1/p'); - - log_server_port=$(echo "$options" | sed -n 's/.*log-server-port=\([^,]*\).*/\1/p'); - - volfile_loc="$1"; + in_opt="no" + pos_args=0 + for opt in "$@"; do + if [ "$in_opt" = "yes" ]; then + for pair in $(echo "$opt" | tr "," " "); do + # Handle options without values. + case "$pair" in + "ro") read_only=1 ;; + "acl") acl=1 ;; + "selinux") selinux=1 ;; + "worm") worm=1 ;; + "fopen-keep-cache") fopen_keep_cache=1 ;; + "enable-ino32") enable_ino32=1 ;; + "mem-accounting") mem_accounting=1;; + "aux-gfid-mount") + if [ `uname -s` = "Linux" ]; then + aux_gfid_mount=1 + fi + ;; + # "mount -t glusterfs" sends this, but it's useless. + "rw") ;; + # these ones are interpreted during system initialization + "noauto") ;; + "_netdev") ;; + *) + key=$(echo "$pair" | cut -f1 -d'='); + value=$(echo "$pair" | cut -f2- -d'='); + + # Handle options with values. + case "$key" in + "log-level") log_level_str=$value ;; + "log-file") log_file=$value ;; + "transport") transport=$value ;; + "direct-io-mode") direct_io_mode=$value ;; + "volume-name") volume_name=$value ;; + "volume-id") volume_id=$value ;; + "volfile-check") volfile_check=$value ;; + "server-port") server_port=$value ;; + "attribute-timeout") + attribute_timeout=$value ;; + "entry-timeout") entry_timeout=$value ;; + "negative-timeout") negative_timeout=$value ;; + "gid-timeout") gid_timeout=$value ;; + "background-qlen") bg_qlen=$value ;; + "backup-volfile-servers") backup_volfile_servers=$value ;; + "congestion-threshold") cong_threshold=$value ;; + "xlator-option") xlator_option=$xlator_option" "$pair ;; + "fuse-mountopts") fuse_mountopts=$value ;; + "use-readdirp") use_readdirp=$value ;; + *) + # Passthru + [ -z "$fuse_mountopts" ] || fuse_mountopts="$fuse_mountopts," + fuse_mountopts="$fuse_mountopts$pair" + ;; + esac + esac + done + in_opt="no" + elif [ "$opt" = "-o" ]; then + in_opt="yes" + else + case $pos_args in + 0) volfile_loc=$opt ;; + 1) mount_point=$opt ;; + *) echo "extra arguments at end (ignored)" ;; + esac + pos_args=$((pos_args+1)) + fi + done + if [ $in_opt = "yes" -o $pos_args -lt 2 ]; then + usage + exit 1 + fi [ -r "$volfile_loc" ] || { server_ip=$(echo "$volfile_loc" | sed -n 's/\([a-zA-Z0-9:.\-]*\):.*/\1/p'); @@ -293,25 +423,9 @@ main () [ -n "$test_str" ] && { volume_id="$test_str"; } - volfile_loc=""; + volfile_loc=""; } - new_fs_options=$(echo "$options" | sed -e 's/[,]*log-file=[^,]*//' \ - -e 's/[,]*log-level=[^,]*//' \ - -e 's/[,]*volume-name=[^,]*//' \ - -e 's/[,]*direct-io-mode=[^,]*//' \ - -e 's/[,]*volfile-check=[^,]*//' \ - -e 's/[,]*transport=[^,]*//' \ - -e 's/[,]*backupvolfile-server=[^,]*//' \ - -e 's/[,]*server-port=[^,]*//' \ - -e 's/[,]*volume-id=[^,]*//' \ - -e 's/[,]*fetch-attempts=[^,]*//' \ - -e 's/[,]*log-server=[^,]*//' \ - -e 's/[,]*ro[^,]*//' \ - -e 's/[,]*acl[^,]*//' \ - -e 's/[,]*worm[^,]*//' \ - -e 's/[,]*log-server-port=[^,]*//'); - # [ -n "$helper" ] && { cmd_line=$(echo "$cmd_line --$helper"); @@ -319,31 +433,22 @@ main () exit 0; } - mount_point="" - for arg in "$@"; do - [ -d "$arg" ] && { - mount_point=$arg - } - done - # No need to do a ! -d test, it is taken care while initializing the # variable mount_point - [ -z "$mount_point" ] && { + [ -z "$mount_point" -o ! -d "$mount_point" ] && { echo "ERROR: Mount point does not exist." usage; exit 0; } # Simple check to avoid multiple identical mounts - if grep -q " $mount_point fuse" /etc/mtab; then + if grep -q "[[:space:]+]${mount_point}[[:space:]+]fuse" $mounttab; then echo -n "$0: according to mtab, GlusterFS is already mounted on " echo "$mount_point" exit 0; fi - check_recursive_mount "$@"; - - fs_options=$(echo "$fs_options,$new_fs_options"); + check_recursive_mount "$mount_point"; # Append fuse.glusterfs to PRUNEFS variable in updatedb.conf(5). updatedb(8) # should not index files under GlusterFS, indexing will slow down GlusteFS @@ -360,4 +465,3 @@ main () } _init "$@" && main "$@"; - diff --git a/xlators/mount/fuse/utils/mount_glusterfs.in b/xlators/mount/fuse/utils/mount_glusterfs.in index 3d4d28620..b12b4e04e 100755 --- a/xlators/mount/fuse/utils/mount_glusterfs.in +++ b/xlators/mount/fuse/utils/mount_glusterfs.in @@ -85,7 +85,7 @@ start_glusterfs () --volfile-server-transport=$transport"); else cmd_line=$(echo "$cmd_line \ ---volfile-server=$server_ip \ +--volfile-server=$server_ip"); fi else cmd_line=$(echo "$cmd_line --volfile=$volfile_loc"); @@ -173,6 +173,7 @@ main () [ -r "$volfile_loc" ] || { server_ip=$(echo "$volfile_loc" | sed -n 's/\([a-zA-Z0-9:.\-]*\):.*/\1/p'); + volume_id=$(echo "$volfile_loc" | sed -n 's/[a-zA-Z0-9:.\-]*:\(.*\)/\1/p'); volfile_loc=""; } # following line is product of love towards sed |
