diff options
Diffstat (limited to 'xlators/mount')
-rw-r--r-- | xlators/mount/fuse/src/Makefile.am | 3 | ||||
-rw-r--r-- | xlators/mount/fuse/src/fuse-bridge.c | 1170 | ||||
-rw-r--r-- | xlators/mount/fuse/src/fuse-bridge.h | 26 | ||||
-rw-r--r-- | xlators/mount/fuse/src/fuse-helpers.c | 115 | ||||
-rw-r--r-- | xlators/mount/fuse/src/glfs-fuse-bridge.h | 53 | ||||
-rwxr-xr-x | xlators/mount/fuse/utils/mount.glusterfs.in | 16 |
6 files changed, 1265 insertions, 118 deletions
diff --git a/xlators/mount/fuse/src/Makefile.am b/xlators/mount/fuse/src/Makefile.am index 653121d18f6..04c656b93ee 100644 --- a/xlators/mount/fuse/src/Makefile.am +++ b/xlators/mount/fuse/src/Makefile.am @@ -6,6 +6,9 @@ noinst_HEADERS_common = $(CONTRIBDIR)/fuse-include/fuse-mount.h\ $(CONTRIBDIR)/fuse-include/fuse-misc.h fuse-mem-types.h \ fuse-bridge.h +fuse_HEADERS = glfs-fuse-bridge.h +fusedir = $(includedir)/glusterfs/ + if GF_DARWIN_HOST_OS noinst_HEADERS = $(noinst_HEADERS_common) $(noinst_HEADERS_darwin) else diff --git a/xlators/mount/fuse/src/fuse-bridge.c b/xlators/mount/fuse/src/fuse-bridge.c index 0291859c055..85ecce95802 100644 --- a/xlators/mount/fuse/src/fuse-bridge.c +++ b/xlators/mount/fuse/src/fuse-bridge.c @@ -9,9 +9,13 @@ */ #include <sys/wait.h> +#include <stdlib.h> +#include <sys/types.h> +#include <dirent.h> #include "fuse-bridge.h" #include "mount-gluster-compat.h" #include "glusterfs.h" +#include "byte-order.h" #ifdef __NetBSD__ #undef open /* in perfuse.h, pulled from mount-gluster-compat.h */ @@ -24,6 +28,14 @@ void fini (xlator_t *this_xl); static void fuse_invalidate_inode(xlator_t *this, uint64_t fuse_ino); +static inline void +fuse_lookup_gfid_dir (xlator_t *this, fuse_state_t *state, char *name, + gf_lookup_namespace_t ns); + +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, + dict_t *xdata); /* * Send an invalidate notification up to fuse to purge the file from local * page cache. @@ -43,10 +55,16 @@ fuse_invalidate(xlator_t *this, inode_t *inode) if (!priv->fopen_keep_cache) return 0; - nodeid = inode_to_fuse_nodeid(inode); + /* shouldn't matter what namespace we use here, since if it + * is auxiliary gfid mount, we are going to invalidate both inodes + * corresponding to gfid and path namespaces. + */ + nodeid = inode_to_fuse_nodeid(this, inode, GF_FUSE_PATH_NAMESPACE); + 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; @@ -214,10 +232,14 @@ fuse_invalidate_entry (xlator_t *this, uint64_t fuse_ino) list_for_each_entry (dentry, &inode->dentry_list, inode_list) { nlen = strlen (dentry->name); fouh->len = sizeof (*fouh) + sizeof (*fnieo) + nlen + 1; - fnieo->parent = inode_to_fuse_nodeid (dentry->parent); + + /* entries in GF_FUSE_GFID_NAMESPACE are never linked */ + fnieo->parent = inode_to_fuse_nodeid (this, dentry->parent, + GF_FUSE_PATH_NAMESPACE); fnieo->namelen = nlen; - strcpy (inval_buf + sizeof (*fouh) + sizeof (*fnieo), dentry->name); + strcpy (inval_buf + sizeof (*fouh) + sizeof (*fnieo), + dentry->name); rv = write (priv->revchan_out, inval_buf, fouh->len); if (rv != fouh->len) { @@ -245,6 +267,43 @@ fuse_invalidate_entry (xlator_t *this, uint64_t fuse_ino) inode_unref (inode); } +static int32_t +fuse_write_invalidate_request (xlator_t *this, struct fuse_out_header *fouh, + struct fuse_notify_inval_inode_out *fniio, + uint64_t fuse_ino, inode_t *inode) +{ + int32_t rv = -1; + fuse_private_t *priv = NULL; + + if (!this || !fouh || !fniio || !fuse_ino || !inode) + goto out; + + priv = this->private; + + /* inval the entire mapping until we learn how to be more granular */ + fniio->ino = fuse_ino; + + rv = write(priv->revchan_out, fouh, 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); + } + +out: + return rv; +} + /* * Send an inval inode notification to fuse. This causes an invalidation of the * entire page cache mapping on the inode. @@ -252,12 +311,14 @@ fuse_invalidate_entry (xlator_t *this, uint64_t fuse_ino) 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; + 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; + gf_fuse_nodeid_t *nodeid = NULL; + uint64_t value = 0; fouh = (struct fuse_out_header *) inval_buf; fniio = (struct fuse_notify_inval_inode_out *) (fouh + 1); @@ -272,31 +333,46 @@ fuse_invalidate_inode(xlator_t *this, uint64_t fuse_ino) 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); - } + if (priv->aux_gfid_mount) { + inode_ctx_get (inode, this, &value); + nodeid = (void *)value; + if (nodeid == NULL) { + gf_log (this->name, GF_LOG_WARNING, + "nodeid is NULL on an auxiliary mount"); + goto out; + } - gf_log("glusterfs-fuse", GF_LOG_TRACE, "INVALIDATE inode: %lu", fuse_ino); + rv = fuse_write_invalidate_request (this, fouh, fniio, + (uint64_t) &nodeid->inode_path_ns, + inode); + if (rv < 0) { + goto out; + } - if (inode) { - fuse_log_eh (this, "Invalidated inode %lu (gfid: %s)", - fuse_ino, uuid_utoa (inode->gfid)); + rv = fuse_write_invalidate_request (this, fouh, fniio, + (uint64_t) &nodeid->inode_gfid_ns, + inode); + if (rv < 0) { + goto out; + } } else { - fuse_log_eh (this, "Invalidated inode %lu ", fuse_ino); + rv = fuse_write_invalidate_request (this, fouh, fniio, + fuse_ino, inode); + if (rv < 0) { + goto out; + } } +out: if (inode) inode_unref (inode); + + return; } int @@ -340,10 +416,12 @@ fuse_entry_cbk (call_frame_t *frame, void *cookie, xlator_t *this, struct fuse_entry_out feo = {0, }; fuse_private_t *priv = NULL; inode_t *linked_inode = NULL; + gf_lookup_namespace_t ns = 0; priv = this->private; state = frame->root->state; finh = state->finh; + ns = (gf_lookup_namespace_t) cookie; if (op_ret == 0) { if (__is_root_gfid (state->loc.inode->gfid)) @@ -386,15 +464,20 @@ fuse_entry_cbk (call_frame_t *frame, void *cookie, xlator_t *this, gf_fop_list[frame->root->op], state->loc.path); } - linked_inode = inode_link (inode, state->loc.parent, - state->loc.name, buf); + if (ns == GF_FUSE_GFID_NAMESPACE) { + linked_inode = inode_link (inode, NULL, NULL, buf); + } else { + linked_inode = inode_link (inode, state->loc.parent, + state->loc.name, buf); - if (linked_inode != inode) { + if (linked_inode != inode) { + } } + inode_lookup (linked_inode); - feo.nodeid = inode_to_fuse_nodeid (linked_inode); + feo.nodeid = inode_to_fuse_nodeid (this, linked_inode, ns); inode_unref (linked_inode); @@ -456,11 +539,9 @@ fuse_lookup_cbk (call_frame_t *frame, void *cookie, xlator_t *this, struct iatt *postparent) { fuse_state_t *state = NULL; - call_frame_t *prev = NULL; inode_table_t *itable = NULL; state = frame->root->state; - prev = cookie; if (op_ret == -1 && state->is_revalidate == 1) { itable = state->itable; @@ -479,7 +560,8 @@ fuse_lookup_cbk (call_frame_t *frame, void *cookie, xlator_t *this, fuse_gfid_set (state); STACK_WIND (frame, fuse_lookup_cbk, - prev->this, prev->this->fops->lookup, + state->active_subvol, + state->active_subvol->fops->lookup, &state->loc, state->xdata); return 0; } @@ -527,27 +609,344 @@ fuse_lookup_resume (fuse_state_t *state) lookup, &state->loc, state->xdata); } +static inline int +fuse_handle_gfiddir_rename_op (fuse_state_t *state, void *msg) +{ + struct fuse_rename_in *fri = msg; + char *oldname = (char *)(fri + 1); + char *newname = oldname + strlen (oldname) + 1; + uuid_t aux_gfid = {0, }; + inode_t *src_parent = NULL, *dst_parent = NULL; + int ret = -1; + + aux_gfid[15] = 0xd; + + src_parent = fuse_ino_to_inode (state->finh->nodeid, state->this); + dst_parent = fuse_ino_to_inode (fri->newdir, state->this); + + if ((uuid_compare (aux_gfid, src_parent->gfid) == 0) + || (uuid_compare (aux_gfid, dst_parent->gfid) == 0)) { + gf_log ("glusterfs-fuse", GF_LOG_ERROR, + "RENAME %"PRIu64" rename into or from virtual " + "gfid-directory is not allowed.", + state->finh->unique); + + send_fuse_err (state->this, state->finh, ENOTSUP); + free_fuse_state (state); + ret = 0; + } + + if ((__is_root_gfid (src_parent->gfid) + && (strncmp (oldname, GF_GFID_DIR, strlen (GF_GFID_DIR) == 0))) + || (__is_root_gfid (dst_parent->gfid) + && (strncmp (newname, GF_GFID_DIR, + strlen (GF_GFID_DIR))) == 0)) { + gf_log ("glusterfs-fuse", GF_LOG_ERROR, + "RENAME %"PRIu64" renaming virtual " + "gfid-directory is not allowed.", + state->finh->unique); + + send_fuse_err (state->this, state->finh, ENOTSUP); + free_fuse_state (state); + ret = 0; + } + + inode_unref (src_parent); + inode_unref (dst_parent); + + return ret; +} + +static inline int +fuse_handle_gfiddir_inode_op (fuse_state_t *state, glusterfs_fop_t fop) +{ + uuid_t aux_gfid = {0, }; + int ret = -1; + inode_t *inode = NULL; + + aux_gfid[15] = 0xd; + + inode = fuse_ino_to_inode (state->finh->nodeid, state->this); + + if (uuid_compare (aux_gfid, inode->gfid) == 0) { + gf_log ("glusterfs-fuse", GF_LOG_ERROR, + "%s %"PRIu64" %s on virtual " + "gfid-directory is not allowed.", + gf_fop_list[fop], state->finh->unique, + gf_fop_list[fop]); + + send_fuse_err (state->this, state->finh, ENOTSUP); + free_fuse_state (state); + ret = 0; + } + + inode_unref (inode); + + return ret; +} + +static inline int +fuse_handle_gfiddir_rmdir_op (fuse_state_t *state, char *name) +{ + int ret = -1; + inode_t *parent = NULL; + + parent = fuse_ino_to_inode (state->finh->nodeid, state->this); + + if (__is_root_gfid (parent->gfid) && (strncmp (name, GF_GFID_DIR, + strlen (GF_GFID_DIR) + == 0))) { + gf_log ("glusterfs-fuse", GF_LOG_ERROR, + "RMDIR %"PRIu64" removing virtual " + "gfid-directory is not allowed.", + state->finh->unique); + + send_fuse_err (state->this, state->finh, ENOTSUP); + free_fuse_state (state); + ret = -1; + } + + return ret; +} + +static inline int +fuse_handle_gfiddir_entry_op (fuse_state_t *state, glusterfs_fop_t fop) +{ + uuid_t aux_gfid = {0, }; + int ret = -1; + inode_t *parent = NULL; + + aux_gfid[15] = 0xd; + + parent = fuse_ino_to_inode (state->finh->nodeid, state->this); + + if (uuid_compare (aux_gfid, parent->gfid) == 0) { + gf_log ("glusterfs-fuse", GF_LOG_ERROR, + "%s %"PRIu64" operation not allowed in virtual " + "gfid-directory.", gf_fop_list [fop], + state->finh->unique); + + send_fuse_err (state->this, state->finh, ENOTSUP); + free_fuse_state (state); + ret = 0; + } + + inode_unref (parent); + return ret; +} + +static inline int +fuse_handle_gfiddir_op (xlator_t *this, fuse_state_t *state, void *msg, + glusterfs_fop_t fop) +{ + int ret = -1; + + switch (fop) { + case GF_FOP_SETATTR: + case GF_FOP_ACCESS: + case GF_FOP_OPENDIR: + case GF_FOP_SETXATTR: + case GF_FOP_GETXATTR: + case GF_FOP_REMOVEXATTR: + ret = fuse_handle_gfiddir_inode_op (state, fop); + break; + + case GF_FOP_RMDIR: + ret = fuse_handle_gfiddir_rmdir_op (state, msg); + break; + + case GF_FOP_RENAME: + ret = fuse_handle_gfiddir_rename_op (state, msg); + break; + + case GF_FOP_LINK: + ret = fuse_handle_gfiddir_entry_op (state, fop); + + case GF_FOP_UNLINK: + ret = fuse_handle_gfiddir_entry_op (state, fop); + + default: + break; + } + + return ret; +} + +static inline int +fuse_lookup_aux_gfid (xlator_t *this, fuse_state_t *state, inode_t *parent, + char *name) +{ + int ret = -1, op_errno = EINVAL; + call_frame_t *frame = NULL; + uuid_t aux_gfid = {0, }; + + aux_gfid[15] = 0xd; + + ret = uuid_parse (name, state->gfid); + if (ret < 0) { + gf_log (this->name, GF_LOG_WARNING, + "parsing application provided gfid (%s) failed", name); + op_errno = EINVAL; + goto err; + } + + fuse_gfid_set (state); + + if (uuid_compare (aux_gfid, state->gfid) == 0) { + fuse_lookup_gfid_dir (this, state, NULL, + GF_FUSE_GFID_NAMESPACE); + goto out; + } + + state->loc.inode = inode_find (state->itable, state->gfid); + if (state->loc.inode == NULL) { + state->loc.inode = inode_new (state->itable); + if (state->loc.inode == NULL) { + op_errno = ENOMEM; + goto err; + } + } else { + state->is_revalidate = 1; + } + + uuid_copy (state->loc.gfid, state->gfid); + FUSE_FOP_COOKIE (state, this, fuse_lookup_cbk, + (void *)GF_FUSE_GFID_NAMESPACE, + GF_FOP_LOOKUP, lookup, &state->loc, state->xdata); + +out: + return 0; + +err: + frame = get_call_frame_for_req (state); + frame->root->state = state; + fuse_entry_cbk (frame, (void *)GF_FUSE_GFID_NAMESPACE, this, -1, + op_errno, NULL, NULL, NULL); + return 0; +} + + +static inline void +fuse_lookup_gfid_dir (xlator_t *this, fuse_state_t *state, char *name, + gf_lookup_namespace_t ns) +{ + call_frame_t *frame = NULL; + fuse_private_t *priv = NULL; + int32_t op_errno = EINVAL, op_ret = -1; + + priv = this->private; + + frame = get_call_frame_for_req (state); + if (frame == NULL) { + op_errno = ENOMEM; + goto out; + } + + frame->root->state = state; + + /* virtual stat entry */ + priv->gfiddir_stbuf.ia_gfid[15] = GF_AUX_GFID; + priv->gfiddir_stbuf.ia_ino = 13; + priv->gfiddir_stbuf.ia_type = IA_IFDIR; + priv->gfiddir_stbuf.ia_nlink = 2; + + state->loc.inode = inode_find (state->itable, + priv->gfiddir_stbuf.ia_gfid); + + if (state->loc.inode == NULL) { + /* need to build 'state->loc' ourselves */ + state->loc.inode = inode_new (state->itable); + if (state->loc.inode == NULL) { + op_errno = ENOMEM; + goto out; + } + } + + op_ret = op_errno = 0; +out: + switch (state->finh->opcode) { + case FUSE_LOOKUP: + fuse_entry_cbk (frame, (void *)ns, this, op_ret, op_errno, + state->loc.inode, &priv->gfiddir_stbuf, NULL); + break; + + case FUSE_GETATTR: + fuse_attr_cbk (frame, NULL, this, op_ret, op_errno, + &priv->gfiddir_stbuf, NULL); + break; + default: + break; + } + + return; +} + + 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; + fuse_private_t *priv = NULL; + inode_t *parent = NULL; + uuid_t aux_gfid = {0,}; + priv = this->private; GET_STATE (this, finh, state); + if (!priv->aux_gfid_mount) { + goto normal_mount; + } + + if ((finh->nodeid == 1) && (strcmp (GF_GFID_DIR, name) == 0)) { + fuse_lookup_gfid_dir (this, state, name, + GF_FUSE_PATH_NAMESPACE); + return; + } + + aux_gfid[15] = GF_AUX_GFID; + + parent = fuse_ino_to_inode (finh->nodeid, state->this); + + if (uuid_compare (aux_gfid, parent->gfid) == 0) { + fuse_lookup_aux_gfid (this, state, parent, name); + inode_unref (parent); + return; + } + + inode_unref (parent); + +normal_mount: (void) fuse_resolve_entry_init (state, &state->resolve, finh->nodeid, name); fuse_resolve_and_resume (state, fuse_lookup_resume); + + return; +} + +int32_t +fuse_xlator_forget (xlator_t *this, inode_t *inode) +{ + gf_fuse_nodeid_t *nodeid = NULL; + uint64_t value = 0; + + inode_ctx_del (inode, this, &value); + nodeid = (void *)value; + + if (nodeid != NULL) { + mem_put (nodeid); + } + + return 0; } 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; + inode_t *fuse_inode = NULL; if (finh->nodeid == 1) { GF_FREE (finh); @@ -648,6 +1047,10 @@ fuse_attr_cbk (call_frame_t *frame, void *cookie, xlator_t *this, state->loc.path ? state->loc.path : "ERR", buf->ia_ino); + if (__is_root_gfid (buf->ia_gfid)) { + priv->root_stbuf = *buf; + } + buf->ia_blksize = this->ctx->page_size; gf_fuse_stat2attr (buf, &fao.attr, priv->enable_ino32); @@ -732,9 +1135,13 @@ fuse_getattr_resume (fuse_state_t *state) static void fuse_getattr (xlator_t *this, fuse_in_header_t *finh, void *msg) { - fuse_state_t *state; - int32_t ret = -1; + fuse_state_t *state = NULL; + int32_t ret = -1; + fuse_private_t *priv = NULL; + uuid_t aux_gfid = {0, }; + inode_t *inode = NULL; + priv = this->private; GET_STATE (this, finh, state); if (finh->nodeid == 1) { @@ -757,6 +1164,21 @@ fuse_getattr (xlator_t *this, fuse_in_header_t *finh, void *msg) return; } + if (priv->aux_gfid_mount) { + aux_gfid[15] = GF_AUX_GFID; + + inode = fuse_ino_to_inode (finh->nodeid, state->this); + + if (uuid_compare (aux_gfid, inode->gfid) == 0) { + fuse_lookup_gfid_dir (this, state, NULL, + GF_FUSE_PATH_NAMESPACE); + inode_unref (inode); + return; + } + + inode_unref (inode); + } + fuse_resolve_inode_init (state, &state->resolve, state->finh->nodeid); fuse_resolve_and_resume (state, fuse_getattr_resume); @@ -1055,12 +1477,13 @@ fuse_setattr_resume (fuse_state_t *state) static void fuse_setattr (xlator_t *this, fuse_in_header_t *finh, void *msg) { - struct fuse_setattr_in *fsi = msg; - - fuse_private_t *priv = NULL; - fuse_state_t *state = NULL; + struct fuse_setattr_in *fsi = msg; + fuse_private_t *priv = NULL; + fuse_state_t *state = NULL; + int ret = 0; GET_STATE (this, finh, state); + priv = this->private; if (fsi->valid & FATTR_FH && !(fsi->valid & (FATTR_ATIME|FATTR_MTIME))) { @@ -1069,6 +1492,13 @@ fuse_setattr (xlator_t *this, fuse_in_header_t *finh, void *msg) state->fd = FH_TO_FD (fsi->fh); fuse_resolve_fd_init (state, &state->resolve, state->fd); } else { + if (priv->aux_gfid_mount) { + ret = fuse_handle_gfiddir_op (this, state, msg, + GF_FOP_SETATTR); + if (ret == 0) + return; + } + fuse_resolve_inode_init (state, &state->resolve, finh->nodeid); } @@ -1234,11 +1664,21 @@ fuse_access_resume (fuse_state_t *state) static void fuse_access (xlator_t *this, fuse_in_header_t *finh, void *msg) { - struct fuse_access_in *fai = msg; - fuse_state_t *state = NULL; + struct fuse_access_in *fai = msg; + fuse_state_t *state = NULL; + fuse_private_t *priv = NULL; + int ret = 0; GET_STATE (this, finh, state); + priv = this->private; + + if (priv->aux_gfid_mount) { + ret = fuse_handle_gfiddir_op (this, state, msg, GF_FOP_ACCESS); + if (ret == 0) + return; + } + fuse_resolve_inode_init (state, &state->resolve, finh->nodeid); state->mask = fai->mask; @@ -1324,6 +1764,11 @@ fuse_readlink (xlator_t *this, fuse_in_header_t *finh, void *msg) void fuse_mknod_resume (fuse_state_t *state) { + fuse_private_t *priv = NULL; + int ret = 0; + + priv = state->this->private; + if (!state->loc.parent) { gf_log ("glusterfs-fuse", GF_LOG_ERROR, "MKNOD %"PRId64"/%s (%s/%s) resolution failed", @@ -1340,11 +1785,31 @@ fuse_mknod_resume (fuse_state_t *state) } if (state->loc.inode) { - gf_log (state->this->name, GF_LOG_DEBUG, "inode already present"); + gf_log (state->this->name, GF_LOG_DEBUG, + "inode already present"); inode_unref (state->loc.inode); state->loc.inode = NULL; } + if (state->xdata == NULL) { + state->xdata = dict_new (); + } + + if (priv->aux_gfid_mount) { + ret = dict_set_str (state->xdata, GLUSTERFS_INTERNAL_FOP_KEY, + "gfid-mount"); + + if (ret < 0) { + gf_log ("glusterfs-fuse", GF_LOG_ERROR, + "MKNOD %"PRId64"/%s (%s/%s) setting a key to " + "overload mknod to act as link(2) when target " + "already exists failed", + state->finh->nodeid, state->resolve.bname, + uuid_utoa (state->resolve.gfid), + state->resolve.bname); + } + } + state->loc.inode = inode_new (state->loc.parent->table); gf_log ("glusterfs-fuse", GF_LOG_TRACE, @@ -1359,12 +1824,11 @@ fuse_mknod_resume (fuse_state_t *state) static void fuse_mknod (xlator_t *this, fuse_in_header_t *finh, void *msg) { - struct fuse_mknod_in *fmi = msg; - char *name = (char *)(fmi + 1); - - fuse_state_t *state = NULL; - fuse_private_t *priv = NULL; - int32_t ret = -1; + struct fuse_mknod_in *fmi = msg; + char *name = (char *)(fmi + 1); + fuse_state_t *state = NULL; + fuse_private_t *priv = NULL; + int32_t ret = -1; priv = this->private; #if FUSE_KERNEL_MINOR_VERSION >= 12 @@ -1477,10 +1941,19 @@ fuse_unlink_resume (fuse_state_t *state) static void fuse_unlink (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; + fuse_private_t *priv = NULL; + int ret = -1; GET_STATE (this, finh, state); + priv = this->private; + + if (priv->aux_gfid_mount) { + ret = fuse_handle_gfiddir_op (this, state, msg, GF_FOP_UNLINK); + if (ret == 0) + return; + } fuse_resolve_entry_init (state, &state->resolve, finh->nodeid, name); @@ -1513,11 +1986,21 @@ fuse_rmdir_resume (fuse_state_t *state) static void fuse_rmdir (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; + fuse_private_t *priv = NULL; + int ret = 0; GET_STATE (this, finh, state); + priv = this->private; + + if (priv->aux_gfid_mount) { + ret = fuse_handle_gfiddir_op (this, state, msg, GF_FOP_RMDIR); + if (ret == 0) + return; + } + fuse_resolve_entry_init (state, &state->resolve, finh->nodeid, name); fuse_resolve_and_resume (state, fuse_rmdir_resume); @@ -1544,7 +2027,8 @@ fuse_symlink_resume (fuse_state_t *state) } if (state->loc.inode) { - gf_log (state->this->name, GF_LOG_DEBUG, "inode already present"); + gf_log (state->this->name, GF_LOG_DEBUG, + "inode already present"); inode_unref (state->loc.inode); state->loc.inode = NULL; } @@ -1556,7 +2040,8 @@ 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->umask, state->xdata); + symlink, state->name, &state->loc, state->umask, + state->xdata); } static void @@ -1683,12 +2168,21 @@ fuse_rename_resume (fuse_state_t *state) static void fuse_rename (xlator_t *this, fuse_in_header_t *finh, void *msg) { - struct fuse_rename_in *fri = msg; - char *oldname = (char *)(fri + 1); - char *newname = oldname + strlen (oldname) + 1; - fuse_state_t *state = NULL; + struct fuse_rename_in *fri = msg; + char *oldname = (char *)(fri + 1); + char *newname = oldname + strlen (oldname) + 1; + fuse_state_t *state = NULL; + fuse_private_t *priv = NULL; + int ret = -1; GET_STATE (this, finh, state); + priv = this->private; + + if (priv->aux_gfid_mount) { + ret = fuse_handle_gfiddir_op (this, state, msg, GF_FOP_RENAME); + if (ret == 0) + return; + } fuse_resolve_entry_init (state, &state->resolve, finh->nodeid, oldname); @@ -1732,11 +2226,20 @@ fuse_link_resume (fuse_state_t *state) static void fuse_link (xlator_t *this, fuse_in_header_t *finh, void *msg) { - struct fuse_link_in *fli = msg; - char *name = (char *)(fli + 1); - fuse_state_t *state = NULL; + struct fuse_link_in *fli = msg; + char *name = (char *)(fli + 1); + fuse_state_t *state = NULL; + fuse_private_t *priv = NULL; + int ret = -1; GET_STATE (this, finh, state); + priv = this->private; + + if (priv->aux_gfid_mount) { + ret = fuse_handle_gfiddir_op (this, state, msg, GF_FOP_LINK); + if (ret == 0) + return; + } fuse_resolve_inode_init (state, &state->resolve2, fli->oldnodeid); @@ -1801,7 +2304,8 @@ fuse_create_cbk (call_frame_t *frame, void *cookie, xlator_t *this, inode_unref (linked_inode); - feo.nodeid = inode_to_fuse_nodeid (linked_inode); + feo.nodeid = inode_to_fuse_nodeid (this, linked_inode, + GF_FUSE_PATH_NAMESPACE); feo.entry_valid = calc_timeout_sec (priv->entry_timeout); feo.entry_valid_nsec = calc_timeout_nsec (priv->entry_timeout); @@ -1907,9 +2411,8 @@ fuse_create_resume (fuse_state_t *state) "%"PRIu64": CREATE %s", state->finh->unique, state->loc.path); - FUSE_FOP (state, fuse_create_cbk, GF_FOP_CREATE, - create, &state->loc, state->flags, state->mode, - state->umask, fd, state->xdata); + FUSE_FOP (state, fuse_create_cbk, GF_FOP_CREATE, create, &state->loc, + state->flags, state->mode, state->umask, fd, state->xdata); } @@ -2382,6 +2885,11 @@ fuse_opendir_resume (fuse_state_t *state) static void fuse_opendir (xlator_t *this, fuse_in_header_t *finh, void *msg) { + fuse_private_t *priv = NULL; + int ret = -1; + + priv = this->private; + /* struct fuse_open_in *foi = msg; */ @@ -2390,6 +2898,12 @@ fuse_opendir (xlator_t *this, fuse_in_header_t *finh, void *msg) GET_STATE (this, finh, state); + if (priv->aux_gfid_mount) { + ret = fuse_handle_gfiddir_op (this, state, msg, GF_FOP_OPENDIR); + if (ret == 0) + return; + } + fuse_resolve_inode_init (state, &state->resolve, finh->nodeid); fuse_resolve_and_resume (state, fuse_opendir_resume); @@ -2535,14 +3049,14 @@ 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; + 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; @@ -2597,16 +3111,23 @@ fuse_readdirp_cbk (call_frame_t *frame, void *cookie, xlator_t *this, continue; entry->d_stat.ia_blksize = this->ctx->page_size; - gf_fuse_stat2attr (&entry->d_stat, &feo->attr, priv->enable_ino32); + 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); + 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); + /* we fail opendir on /.gfid and hence there won't + * be readdir in that directory. + */ + feo->nodeid = inode_to_fuse_nodeid (this, linked_inode, + GF_FUSE_PATH_NAMESPACE); inode_unref (linked_inode); @@ -2859,7 +3380,6 @@ fuse_statfs_resume (fuse_state_t *state) statfs, &state->loc, state->xdata); } - static void fuse_statfs (xlator_t *this, fuse_in_header_t *finh, void *msg) { @@ -2872,10 +3392,363 @@ fuse_statfs (xlator_t *this, fuse_in_header_t *finh, void *msg) fuse_resolve_and_resume (state, fuse_statfs_resume); } +void +fuse_auxgfid_heal_args_free (fuse_auxgfid_heal_args_t *args) +{ + if (args == NULL) + goto out; + + GF_FREE (args->bname); + + mem_put (args); +out: + return; +} + +fuse_auxgfid_heal_args_t * +fuse_auxgfid_heal_parse_args (xlator_t *this, data_t *data) +{ + fuse_auxgfid_heal_args_t *args = NULL; + fuse_private_t *priv = NULL; + void *blob = NULL; + int len = 0, blob_len; + + blob = data->data; + blob_len = data->len; + + priv = this->private; + + /* bname should at least contain a character */ + if (blob_len < (sizeof (args->gfid) + 2)) + goto err; + + args = mem_get0 (priv->auxgfid_heal_args_pool); + if (args == NULL) + goto err; + + memcpy (args->gfid, blob, sizeof (args->gfid)); + blob += sizeof (args->gfid); + blob_len -= sizeof (args->gfid); + + len = strnlen (blob, blob_len); + if (len == blob_len) + goto err; + + args->bname = GF_CALLOC (1, len + 1, gf_common_mt_char); + if (args->bname == NULL) + goto err; + + memcpy (args->bname, blob, len); + blob_len -= (len + 1); + + if (blob_len) + goto err; + + return args; + +err: + if (args) + fuse_auxgfid_heal_args_free (args); + + return NULL; +} + +static int +fuse_auxgfid_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, + dict_t *xdata) +{ + /* don't worry about inode linking and other stuff. They'll happen on + * the next lookup. + */ + fuse_err_cbk (frame, cookie, this, op_ret, op_errno, xdata); + + return 0; +} + +static int +fuse_auxgfid_heal_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) +{ + /* don't worry about inode linking and other stuff. They'll happen on + * the next lookup. + */ + fuse_err_cbk (frame, cookie, this, op_ret, op_errno, NULL); + return 0; +} + +void +fuse_auxgfid_newfile_args_free (fuse_auxgfid_newfile_args_t *args) +{ + if (args == NULL) + goto out; + + if (args->bname) + GF_FREE (args->bname); + + if (S_ISLNK (args->st_mode) && args->args.symlink.linkpath) { + GF_FREE (args->args.symlink.linkpath); + args->args.symlink.linkpath = NULL; + } + + mem_put (args); +out: + return; +} + +fuse_auxgfid_newfile_args_t * +fuse_auxgfid_newfile_parse_args (xlator_t *this, data_t *data) +{ + fuse_auxgfid_newfile_args_t *args = NULL; + fuse_private_t *priv = NULL; + int len = 0, blob_len = 0; + int min_len = 0; + void *blob = NULL; + + priv = this->private; + + blob = data->data; + blob_len = data->len; + + min_len = sizeof (args->uid) + sizeof (args->gid) + sizeof (args->gfid) + + sizeof (args->st_mode) + 2 + 2; + if (blob_len < min_len) + goto err; + + + args = mem_get0 (priv->auxgfid_newfile_args_pool); + if (args == NULL) + goto err; + + args->uid = ntoh32 (*(uint32_t *)blob); + blob += sizeof (uint32_t); + blob_len -= sizeof (uint32_t); + + args->gid = ntoh32 (*(uint32_t *)blob); + blob += sizeof (uint32_t); + blob_len -= sizeof (uint32_t); + + memcpy (args->gfid, blob, sizeof (args->gfid)); + blob += sizeof (args->gfid); + blob_len -= sizeof (args->gfid); + + args->st_mode = ntoh32 (*(uint32_t *)blob); + blob += sizeof (uint32_t); + blob_len -= sizeof (uint32_t); + + len = strnlen (blob, blob_len); + if (len == blob_len) + goto err; + + args->bname = GF_CALLOC (1, (len + 1), gf_common_mt_char); + if (args->bname == NULL) + goto err; + + memcpy (args->bname, blob, (len + 1)); + blob += (len + 1); + blob_len -= (len + 1); + + if (S_ISDIR (args->st_mode)) { + if (blob_len < sizeof (uint32_t)) + goto err; + args->args.mkdir.mode = ntoh32 (*(uint32_t *)blob); + blob += sizeof (uint32_t); + blob_len -= sizeof (uint32_t); + + if (blob_len < sizeof (uint32_t)) + goto err; + args->args.mkdir.umask = ntoh32 (*(uint32_t *)blob); + blob += sizeof (uint32_t); + blob_len -= sizeof (uint32_t); + if (blob_len < 0) + goto err; + + } else if (S_ISLNK (args->st_mode)) { + len = strnlen (blob, blob_len); + if (len == blob_len) + goto err; + + args->args.symlink.linkpath = GF_CALLOC (1, len + 1, + gf_common_mt_char); + if (args->args.symlink.linkpath == NULL) + goto err; + + memcpy (args->args.symlink.linkpath, blob, (len + 1)); + blob += (len + 1); + blob_len -= (len + 1); + } else { + if (blob_len < sizeof (uint32_t)) + goto err; + args->args.mknod.mode = ntoh32 (*(uint32_t *)blob); + blob += sizeof (uint32_t); + blob_len -= sizeof (uint32_t); + + if (blob_len < sizeof (uint32_t)) + goto err; + args->args.mknod.rdev = ntoh32 (*(uint32_t *)blob); + blob += sizeof (uint32_t); + blob_len -= sizeof (uint32_t); + + if (blob_len < sizeof (uint32_t)) + goto err; + args->args.mknod.umask = ntoh32 (*(uint32_t *)blob); + blob += sizeof (uint32_t); + blob_len -= sizeof (uint32_t); + } + + if (blob_len) + goto err; + + return args; + +err: + if (args) + fuse_auxgfid_newfile_args_free (args); + + return NULL; +} + +int +fuse_auxgfid_loc_fill (fuse_state_t *state, char *gfid, char *bname) +{ + inode_t *parent = NULL; + int ret = -1; + + parent = inode_ref (state->loc.inode); + loc_wipe (&state->loc); + state->loc.parent = parent; + state->loc.inode = inode_grep (parent->table, parent, bname); + if (state->loc.inode == NULL) { + state->loc.inode = inode_new (parent->table); + if (state->loc.inode == NULL) + goto out; + } + + loc_path (&state->loc, bname); + state->loc.name = basename (state->loc.path); + + if (state->xdata == NULL) + state->xdata = dict_new (); + + uuid_parse (gfid, state->gfid); + uuid_copy (state->loc.gfid, state->gfid); + + ret = dict_set_static_bin (state->xdata, "gfid-req", state->gfid, 16); + if (ret < 0) { + gf_log (state->this->name, GF_LOG_WARNING, + "SETXATTR %"PRId64"/%s (%s/%s) setting gfid in xdata " + "failed. Hence, file created will not have the gfid " + "provided (%s)", state->finh->nodeid, + bname, uuid_utoa (state->loc.parent->gfid), + bname, uuid_utoa (state->gfid)); + ret = -1; + goto out; + } + + ret = 0; + +out: + return ret; +} + +int +fuse_auxgfid_heal (fuse_state_t *state, data_t *data) +{ + fuse_auxgfid_heal_args_t *args = NULL; + int ret = -1; + + args = fuse_auxgfid_heal_parse_args (state->this, data); + + gf_log ("glusterfs-fuse", GF_LOG_TRACE, + "%"PRIu64": LOOKUP %s", state->finh->unique, + state->loc.path); + + ret = fuse_auxgfid_loc_fill (state, args->gfid, args->bname); + if (ret < 0) { + goto err; + } + + FUSE_FOP (state, fuse_auxgfid_heal_cbk, GF_FOP_LOOKUP, + lookup, &state->loc, state->xdata); + + fuse_auxgfid_heal_args_free (args); + + return 0; + +err: + fuse_auxgfid_heal_args_free (args); + send_fuse_err (state->this, state->finh, ENOMEM); + free_fuse_state (state); + return 0; +} + +int +fuse_auxgfid_newentry (fuse_state_t *state, data_t *data) +{ + int ret = 0; + fuse_auxgfid_newfile_args_t *args = NULL; + + args = fuse_auxgfid_newfile_parse_args (state->this, data); + if (args == NULL) { + goto err; + } + + state->finh->uid = args->uid; + state->finh->gid = args->gid; + + ret = fuse_auxgfid_loc_fill (state, args->gfid, args->bname); + if (ret < 0) { + goto err; + } + + if (S_ISDIR (args->st_mode)) { + FUSE_FOP (state, fuse_auxgfid_newentry_cbk, + GF_FOP_MKDIR, mkdir, &state->loc, + args->args.mkdir.mode, args->args.mkdir.umask, + state->xdata); + } else if (S_ISLNK (args->st_mode)) { + FUSE_FOP (state, fuse_auxgfid_newentry_cbk, + GF_FOP_SYMLINK, symlink, args->args.symlink.linkpath, + &state->loc, 0, state->xdata); + } else { + if (S_ISREG (args->st_mode)) { + ret = dict_set_uint32 (state->xdata, + GLUSTERFS_CREATE_MODE_KEY, + args->args.mknod.mode); + if (ret < 0) { + // failure + } + args->args.mknod.mode = IA_IFREG; + } + + FUSE_FOP (state, fuse_auxgfid_newentry_cbk, GF_FOP_MKNOD, + mknod, &state->loc, args->args.mknod.mode, + args->args.mknod.rdev, args->args.mknod.umask, + state->xdata); + } + + fuse_auxgfid_newfile_args_free (args); + return 0; + +err: + fuse_auxgfid_newfile_args_free (args); + send_fuse_err (state->this, state->finh, ENOMEM); + free_fuse_state (state); + return 0; +} void fuse_setxattr_resume (fuse_state_t *state) { + fuse_private_t *priv = NULL; + data_t *data = NULL; + + priv = state->this->private; + if (!state->loc.inode) { gf_log ("glusterfs-fuse", GF_LOG_WARNING, "%"PRIu64": SETXATTR %s/%"PRIu64" (%s) " @@ -2887,6 +3760,20 @@ fuse_setxattr_resume (fuse_state_t *state) return; } + if (priv->aux_gfid_mount) { + data = dict_get (state->xattr, GF_FUSE_AUX_GFID_NEWFILE); + if (data != NULL) { + fuse_auxgfid_newentry (state, data); + return; + } + + data = dict_get (state->xattr, GF_FUSE_AUX_GFID_HEAL); + if (data != NULL) { + fuse_auxgfid_heal (state, data); + return; + } + } + #ifdef GF_TEST_FFOP state->fd = fd_lookup (state->loc.inode, state->finh->pid); #endif /* GF_TEST_FFOP */ @@ -2914,17 +3801,17 @@ fuse_setxattr_resume (fuse_state_t *state) static void fuse_setxattr (xlator_t *this, fuse_in_header_t *finh, void *msg) { - struct fuse_setxattr_in *fsi = msg; - char *name = (char *)(fsi + 1); - char *value = name + strlen (name) + 1; - struct fuse_private *priv = NULL; - - fuse_state_t *state = NULL; - char *dict_value = NULL; - int32_t ret = -1; - char *newkey = NULL; + struct fuse_setxattr_in *fsi = msg; + char *name = (char *)(fsi + 1); + char *value = name + strlen (name) + 1; + struct fuse_private *priv = NULL; + fuse_state_t *state = NULL; + char *dict_value = NULL; + int32_t ret = -1; + char *newkey = NULL; priv = this->private; + GET_STATE (this, finh, state); #ifdef GF_DARWIN_HOST_OS if (fsi->position) { @@ -2938,6 +3825,13 @@ fuse_setxattr (xlator_t *this, fuse_in_header_t *finh, void *msg) } #endif + if (priv->aux_gfid_mount) { + ret = fuse_handle_gfiddir_op (this, state, msg, + GF_FOP_SETXATTR); + if (ret == 0) + return; + } + if (fuse_ignore_xattr_set (priv, name)) { (void) send_fuse_err (this, finh, 0); return; @@ -2984,7 +3878,6 @@ fuse_setxattr (xlator_t *this, fuse_in_header_t *finh, void *msg) return; } - GET_STATE (this, finh, state); state->size = fsi->size; fuse_resolve_inode_init (state, &state->resolve, finh->nodeid); @@ -3249,15 +4142,15 @@ 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; + char *newkey = NULL; priv = this->private; + GET_STATE (this, finh, state); #ifdef GF_DARWIN_HOST_OS if (fgxi->position) { @@ -3279,6 +4172,12 @@ fuse_getxattr (xlator_t *this, fuse_in_header_t *finh, void *msg) } #endif + if (priv->aux_gfid_mount) { + rv = fuse_handle_gfiddir_op (this, state, msg, GF_FOP_GETXATTR); + if (rv == 0) + return; + } + if (!priv->acl) { if ((strcmp (name, "system.posix_acl_access") == 0) || (strcmp (name, "system.posix_acl_default") == 0)) { @@ -3296,8 +4195,6 @@ fuse_getxattr (xlator_t *this, fuse_in_header_t *finh, void *msg) } } - GET_STATE (this, finh, state); - fuse_resolve_inode_init (state, &state->resolve, finh->nodeid); rv = fuse_flip_xattr_ns (priv, name, &newkey); @@ -3355,11 +4252,22 @@ fuse_listxattr_resume (fuse_state_t *state) static void fuse_listxattr (xlator_t *this, fuse_in_header_t *finh, void *msg) { - struct fuse_getxattr_in *fgxi = msg; - fuse_state_t *state = NULL; + struct fuse_getxattr_in *fgxi = msg; + fuse_state_t *state = NULL; + fuse_private_t *priv = NULL; + int ret = -1; GET_STATE (this, finh, state); + priv = this->private; + + if (priv->aux_gfid_mount) { + ret = fuse_handle_gfiddir_op (this, state, msg, + GF_FOP_GETXATTR); + if (ret == 0) + return; + } + fuse_resolve_inode_init (state, &state->resolve, finh->nodeid); state->size = fgxi->size; @@ -3410,12 +4318,11 @@ fuse_removexattr_resume (fuse_state_t *state) static void fuse_removexattr (xlator_t *this, fuse_in_header_t *finh, void *msg) { - char *name = msg; - - fuse_state_t *state = NULL; - fuse_private_t *priv = NULL; - int32_t ret = -1; - char *newkey = NULL; + char *name = msg; + fuse_state_t *state = NULL; + fuse_private_t *priv = NULL; + int32_t ret = -1; + char *newkey = NULL; if (!strcmp (GFID_XATTR_KEY, name)) { send_fuse_err (this, finh, EPERM); @@ -3427,6 +4334,13 @@ fuse_removexattr (xlator_t *this, fuse_in_header_t *finh, void *msg) GET_STATE (this, finh, state); + if (priv->aux_gfid_mount) { + ret = fuse_handle_gfiddir_op (this, state, msg, + GF_FOP_REMOVEXATTR); + if (ret == 0) + return; + } + fuse_resolve_inode_init (state, &state->resolve, finh->nodeid); ret = fuse_flip_xattr_ns (priv, name, &newkey); @@ -5121,6 +6035,31 @@ init (xlator_t *this_xl) GF_OPTION_INIT ("selinux", priv->selinux, bool, cleanup_exit); + +#ifdef GF_LINUX_HOST_OS + GF_OPTION_INIT ("auxiliary-gfid-mount", priv->aux_gfid_mount, bool, + cleanup_exit); +#endif + + if (priv->aux_gfid_mount) { + priv->fuse_nodeid_pool = mem_pool_new (gf_fuse_nodeid_t, 2048); + if (priv->fuse_nodeid_pool == NULL) { + goto cleanup_exit; + } + + priv->auxgfid_newfile_args_pool + = mem_pool_new (fuse_auxgfid_newfile_args_t, 2048); + if (priv->auxgfid_newfile_args_pool == NULL) { + goto cleanup_exit; + } + + priv->auxgfid_heal_args_pool + = mem_pool_new (fuse_auxgfid_heal_args_t, 2048); + if (priv->auxgfid_heal_args_pool == NULL) { + goto cleanup_exit; + } + } + GF_OPTION_INIT ("read-only", priv->read_only, bool, cleanup_exit); GF_OPTION_INIT ("enable-ino32", priv->enable_ino32, bool, cleanup_exit); @@ -5284,6 +6223,16 @@ cleanup_exit: close (priv->fd); if (priv->fuse_dump_fd != -1) close (priv->fuse_dump_fd); + + if (priv->fuse_nodeid_pool != NULL) + mem_pool_destroy (priv->fuse_nodeid_pool); + + if (priv->auxgfid_newfile_args_pool != NULL) + mem_pool_destroy (priv->auxgfid_newfile_args_pool); + + if (priv->auxgfid_heal_args_pool != NULL) + mem_pool_destroy (priv->auxgfid_heal_args_pool); + GF_FREE (priv); } GF_FREE (mnt_args); @@ -5324,6 +6273,7 @@ struct xlator_fops fops; struct xlator_cbks cbks = { .invalidate = fuse_invalidate, + .forget = fuse_xlator_forget, }; @@ -5410,5 +6360,13 @@ struct volume_options options[] = { .type = GF_OPTION_TYPE_BOOL, .default_value = "no" }, +#ifdef GF_LINUX_HOST_OS + { .key = {"auxiliary-gfid-mount"}, + .type = GF_OPTION_TYPE_BOOL, + .default_value = "off", + .description = "an option which makes the mount point allow " + "access to gfid directly", + }, +#endif { .key = {NULL} }, }; diff --git a/xlators/mount/fuse/src/fuse-bridge.h b/xlators/mount/fuse/src/fuse-bridge.h index 2626638dc4f..d305d013a15 100644 --- a/xlators/mount/fuse/src/fuse-bridge.h +++ b/xlators/mount/fuse/src/fuse-bridge.h @@ -30,6 +30,7 @@ #include "defaults.h" #include "common-utils.h" #include "statedump.h" +#include "glfs-fuse-bridge.h" #ifdef GF_DARWIN_HOST_OS /* This is MacFUSE's marker for MacFUSE-specific code */ @@ -50,12 +51,26 @@ #if defined(GF_LINUX_HOST_OS) || defined(__NetBSD__) #define FUSE_OP_HIGH (FUSE_READDIRPLUS + 1) #endif + #ifdef GF_DARWIN_HOST_OS #define FUSE_OP_HIGH (FUSE_DESTROY + 1) #endif #define GLUSTERFS_XATTR_LEN_MAX 65536 #define MAX_FUSE_PROC_DELAY 1 +#define GF_GFID_KEY "GLUSTERFS_GFID" +#define GF_GFID_DIR ".gfid" +#define GF_AUX_GFID 0xd + +typedef enum { + GF_FUSE_PATH_NAMESPACE, + GF_FUSE_GFID_NAMESPACE +} gf_lookup_namespace_t; + +typedef struct { + inode_t *inode_path_ns; + inode_t *inode_gfid_ns; +} gf_fuse_nodeid_t; typedef struct fuse_in_header fuse_in_header_t; typedef void (fuse_handler_t) (xlator_t *this, fuse_in_header_t *finh, @@ -122,6 +137,14 @@ struct fuse_private { /* for using fuse-kernel readdirp*/ gf_boolean_t use_readdirp; + + gf_boolean_t aux_gfid_mount; + /* root inode's stbuf */ + struct iatt root_stbuf; + struct iatt gfiddir_stbuf; + struct mem_pool *fuse_nodeid_pool; + struct mem_pool *auxgfid_newfile_args_pool; + struct mem_pool *auxgfid_heal_args_pool; }; typedef struct fuse_private fuse_private_t; @@ -509,7 +532,8 @@ 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); +uint64_t +inode_to_fuse_nodeid (xlator_t *this, inode_t *inode, gf_lookup_namespace_t ns); 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); diff --git a/xlators/mount/fuse/src/fuse-helpers.c b/xlators/mount/fuse/src/fuse-helpers.c index d4dcc2e61bd..4ea3094d1b5 100644 --- a/xlators/mount/fuse/src/fuse-helpers.c +++ b/xlators/mount/fuse/src/fuse-helpers.c @@ -317,12 +317,31 @@ get_call_frame_for_req (fuse_state_t *state) return frame; } +inode_t * +fuse_ino_to_inode_gfid_mount (uint64_t ino, xlator_t *fuse) +{ + inode_t **ptr = NULL, *inode = NULL; + xlator_t *active_subvol = NULL; + + if (ino == 1) { + active_subvol = fuse_active_subvol (fuse); + if (active_subvol) + inode = active_subvol->itable->root; + } else { + ptr = (void *)ino; + + if (ptr != NULL) + inode = inode_ref (*ptr); + } + + return inode; +} inode_t * -fuse_ino_to_inode (uint64_t ino, xlator_t *fuse) +fuse_ino_to_inode_normal_mount (uint64_t ino, xlator_t *fuse) { - inode_t *inode = NULL; xlator_t *active_subvol = NULL; + inode_t *inode = NULL; if (ino == 1) { active_subvol = fuse_active_subvol (fuse); @@ -336,17 +355,98 @@ fuse_ino_to_inode (uint64_t ino, xlator_t *fuse) return inode; } -uint64_t -inode_to_fuse_nodeid (inode_t *inode) +inode_t * +fuse_ino_to_inode (uint64_t ino, xlator_t *fuse) +{ + inode_t *inode = NULL; + fuse_private_t *priv = NULL; + + priv = fuse->private; + + if (priv->aux_gfid_mount) { + inode = fuse_ino_to_inode_gfid_mount (ino, fuse); + } else { + inode = fuse_ino_to_inode_normal_mount (ino, fuse); + } + + return inode; +} + +inline uint64_t +inode_to_fuse_nodeid_gfid_mount (xlator_t *this, inode_t *inode, + gf_lookup_namespace_t ns) +{ + inode_t **ptr = NULL; + gf_fuse_nodeid_t *nodeid = NULL; + fuse_private_t *priv = NULL; + uint64_t value = 0; + int32_t ret = 0; + + priv = this->private; + + LOCK (&inode->lock); + { + __inode_ctx_get (inode, this, &value); + nodeid = (void *)value; + + if (nodeid == NULL) { + nodeid = mem_get0 (priv->fuse_nodeid_pool); + if (nodeid == NULL) + goto unlock; + + ret = __inode_ctx_set (inode, this, (uint64_t *)nodeid); + if (ret < 0) + goto unlock; + + nodeid->inode_path_ns = nodeid->inode_gfid_ns = inode; + } + } +unlock: + UNLOCK (&inode->lock); + + if (ret < 0) { + mem_put (nodeid); + nodeid = NULL; + } + + if (nodeid != NULL) { + if (ns == GF_FUSE_GFID_NAMESPACE) + ptr = &nodeid->inode_gfid_ns; + else + ptr = &nodeid->inode_path_ns; + } + + return (uint64_t) ptr; +} + +inline uint64_t +inode_to_fuse_nodeid_normal_mount (inode_t *inode) { - if (!inode) - return 0; if (__is_root_gfid (inode->gfid)) return 1; return (unsigned long) inode; } +uint64_t +inode_to_fuse_nodeid (xlator_t *this, inode_t *inode, gf_lookup_namespace_t ns) +{ + fuse_private_t *priv = NULL; + uint64_t ino = 0; + + priv = this->private; + + if (!inode) + return 0; + + if (priv->aux_gfid_mount) + ino = inode_to_fuse_nodeid_gfid_mount (this, inode, ns); + else + ino = inode_to_fuse_nodeid_normal_mount (inode); + + return ino; +} + GF_MUST_CHECK int32_t fuse_loc_fill (loc_t *loc, fuse_state_t *state, ino_t ino, @@ -580,7 +680,8 @@ fuse_ignore_xattr_set (fuse_private_t *priv, char *key) || (fnmatch ("*.glusterfs.volume-mark", key, FNM_PERIOD) == 0) || (fnmatch ("*.glusterfs.volume-mark.*", - key, FNM_PERIOD) == 0))) + key, FNM_PERIOD) == 0) + || (fnmatch ("glusterfs.gfid.newfile", key, FNM_PERIOD) == 0))) ret = -1; out: diff --git a/xlators/mount/fuse/src/glfs-fuse-bridge.h b/xlators/mount/fuse/src/glfs-fuse-bridge.h new file mode 100644 index 00000000000..98085b83df5 --- /dev/null +++ b/xlators/mount/fuse/src/glfs-fuse-bridge.h @@ -0,0 +1,53 @@ +/* + 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. +*/ + +#ifndef _GLFS_FUSE_BRIDGE_H +#define _GLFS_FUSE_BRIDGE_H + +#define UUID_CANONICAL_FORM_LEN 36 + +#define GF_FUSE_AUX_GFID_NEWFILE "glusterfs.gfid.newfile" +#define GF_FUSE_AUX_GFID_HEAL "glusterfs.gfid.heal" + +struct auxfuse_symlink_in { + char *linkpath; +} __attribute__ ((__packed__)); + +struct auxfuse_mknod_in { + unsigned int mode; + unsigned int rdev; + unsigned int umask; +} __attribute__ ((__packed__)); + +struct auxfuse_mkdir_in { + unsigned int mode; + unsigned int umask; +} __attribute__ ((__packed__)); + +typedef struct { + unsigned int uid; + unsigned int gid; + char gfid[UUID_CANONICAL_FORM_LEN + 1]; + unsigned int st_mode; + char *bname; + + union { + struct auxfuse_mkdir_in mkdir; + struct auxfuse_mknod_in mknod; + struct auxfuse_symlink_in symlink; + } __attribute__ ((__packed__)) args; +} __attribute__((__packed__)) fuse_auxgfid_newfile_args_t; + +typedef struct { + char gfid[UUID_CANONICAL_FORM_LEN + 1]; + char *bname; /* a null terminated basename */ +} __attribute__((__packed__)) fuse_auxgfid_heal_args_t; + +#endif diff --git a/xlators/mount/fuse/utils/mount.glusterfs.in b/xlators/mount/fuse/utils/mount.glusterfs.in index c0a2ed1a743..0f784835f02 100755 --- a/xlators/mount/fuse/utils/mount.glusterfs.in +++ b/xlators/mount/fuse/utils/mount.glusterfs.in @@ -122,6 +122,10 @@ start_glusterfs () 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"); @@ -268,13 +272,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 @@ -333,7 +337,6 @@ check_recursive_mount () main () { helper=$(echo "$@" | sed -n 's/.*\--[ ]*\([^ ]*\).*/\1/p'); - in_opt="no" pos_args=0 for opt in "$@"; do @@ -348,6 +351,11 @@ main () "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 @@ -437,7 +445,7 @@ main () exit 0; fi - check_recursive_mount "$@"; + 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 |