summaryrefslogtreecommitdiffstats
path: root/glusterfs-guts/src/fuse-bridge.c
diff options
context:
space:
mode:
Diffstat (limited to 'glusterfs-guts/src/fuse-bridge.c')
-rw-r--r--glusterfs-guts/src/fuse-bridge.c2724
1 files changed, 2724 insertions, 0 deletions
diff --git a/glusterfs-guts/src/fuse-bridge.c b/glusterfs-guts/src/fuse-bridge.c
new file mode 100644
index 00000000000..0972563c65e
--- /dev/null
+++ b/glusterfs-guts/src/fuse-bridge.c
@@ -0,0 +1,2724 @@
+/*
+ Copyright (c) 2006, 2007, 2008 Z RESEARCH, Inc. <http://www.zresearch.com>
+ This file is part of GlusterFS.
+
+ GlusterFS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3 of the License,
+ or (at your option) any later version.
+
+ GlusterFS is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see
+ <http://www.gnu.org/licenses/>.
+*/
+
+
+#include <stdint.h>
+#include <signal.h>
+#include <pthread.h>
+
+#ifndef _CONFIG_H
+#define _CONFIG_H
+#include "config.h"
+#endif /* _CONFIG_H */
+
+#include "glusterfs.h"
+#include "logging.h"
+#include "xlator.h"
+#include "glusterfs.h"
+#include "transport.h"
+#include "defaults.h"
+#include "common-utils.h"
+
+#include <fuse/fuse_lowlevel.h>
+
+#include "fuse-extra.h"
+#include "list.h"
+
+#include "guts-lowlevel.h"
+
+#define BIG_FUSE_CHANNEL_SIZE 1048576
+
+struct fuse_private {
+ int fd;
+ struct fuse *fuse;
+ struct fuse_session *se;
+ struct fuse_chan *ch;
+ char *mountpoint;
+};
+
+char glusterfs_fuse_direct_io_mode = 1;
+float glusterfs_fuse_entry_timeout = 1.0;
+float glusterfs_fuse_attr_timeout = 1.0;
+
+#define FI_TO_FD(fi) ((fd_t *)((long)fi->fh))
+
+#define FUSE_FOP(state, ret, op, args ...) \
+do { \
+ call_frame_t *frame = get_call_frame_for_req (state, 1); \
+ xlator_t *xl = frame->this->children ? \
+ frame->this->children->xlator : NULL; \
+ dict_t *refs = frame->root->req_refs; \
+ frame->root->state = state; \
+ STACK_WIND (frame, ret, xl, xl->fops->op, args); \
+ dict_unref (refs); \
+} while (0)
+
+#define FUSE_FOP_NOREPLY(state, op, args ...) \
+do { \
+ call_frame_t *_frame = get_call_frame_for_req (state, 0); \
+ xlator_t *xl = _frame->this->children->xlator; \
+ _frame->root->req_refs = NULL; \
+ STACK_WIND (_frame, fuse_nop_cbk, xl, xl->fops->op, args); \
+} while (0)
+
+typedef struct {
+ loc_t loc;
+ inode_t *parent;
+ inode_t *inode;
+ char *name;
+} fuse_loc_t;
+
+typedef struct {
+ void *pool;
+ xlator_t *this;
+ inode_table_t *itable;
+ fuse_loc_t fuse_loc;
+ fuse_loc_t fuse_loc2;
+ fuse_req_t req;
+
+ int32_t flags;
+ off_t off;
+ size_t size;
+ unsigned long nlookup;
+ fd_t *fd;
+ dict_t *dict;
+ char *name;
+ char is_revalidate;
+} fuse_state_t;
+
+
+static void
+loc_wipe (loc_t *loc)
+{
+ if (loc->inode) {
+ inode_unref (loc->inode);
+ loc->inode = NULL;
+ }
+ if (loc->path) {
+ FREE (loc->path);
+ loc->path = NULL;
+ }
+}
+
+
+static inode_t *
+dummy_inode (inode_table_t *table)
+{
+ inode_t *dummy;
+
+ dummy = CALLOC (1, sizeof (*dummy));
+ ERR_ABORT (dummy);
+
+ dummy->table = table;
+
+ INIT_LIST_HEAD (&dummy->list);
+ INIT_LIST_HEAD (&dummy->inode_hash);
+ INIT_LIST_HEAD (&dummy->fds);
+ INIT_LIST_HEAD (&dummy->dentry.name_hash);
+ INIT_LIST_HEAD (&dummy->dentry.inode_list);
+
+ dummy->ref = 1;
+ dummy->ctx = get_new_dict ();
+
+ LOCK_INIT (&dummy->lock);
+ return dummy;
+}
+
+static void
+fuse_loc_wipe (fuse_loc_t *fuse_loc)
+{
+ loc_wipe (&fuse_loc->loc);
+ if (fuse_loc->name) {
+ FREE (fuse_loc->name);
+ fuse_loc->name = NULL;
+ }
+ if (fuse_loc->inode) {
+ inode_unref (fuse_loc->inode);
+ fuse_loc->inode = NULL;
+ }
+ if (fuse_loc->parent) {
+ inode_unref (fuse_loc->parent);
+ fuse_loc->parent = NULL;
+ }
+}
+
+
+static void
+free_state (fuse_state_t *state)
+{
+ fuse_loc_wipe (&state->fuse_loc);
+
+ fuse_loc_wipe (&state->fuse_loc2);
+
+ if (state->dict) {
+ dict_unref (state->dict);
+ state->dict = (void *)0xaaaaeeee;
+ }
+ if (state->name) {
+ FREE (state->name);
+ state->name = NULL;
+ }
+#ifdef DEBUG
+ memset (state, 0x90, sizeof (*state));
+#endif
+ FREE (state);
+ state = NULL;
+}
+
+
+static int32_t
+fuse_nop_cbk (call_frame_t *frame,
+ void *cookie,
+ xlator_t *this,
+ int32_t op_ret,
+ int32_t op_errno)
+{
+ if (frame->root->state)
+ free_state (frame->root->state);
+
+ frame->root->state = EEEEKS;
+ STACK_DESTROY (frame->root);
+ return 0;
+}
+
+fuse_state_t *
+state_from_req (fuse_req_t req)
+{
+ fuse_state_t *state;
+ transport_t *trans = fuse_req_userdata (req);
+
+ state = (void *)calloc (1, sizeof (*state));
+ ERR_ABORT (state);
+ state->pool = trans->xl->ctx->pool;
+ state->itable = trans->xl->itable;
+ state->req = req;
+ state->this = trans->xl;
+
+ return state;
+}
+
+
+static call_frame_t *
+get_call_frame_for_req (fuse_state_t *state, char d)
+{
+ call_pool_t *pool = state->pool;
+ fuse_req_t req = state->req;
+ const struct fuse_ctx *ctx = NULL;
+ call_ctx_t *cctx = NULL;
+ transport_t *trans = NULL;
+
+ cctx = CALLOC (1, sizeof (*cctx));
+ ERR_ABORT (cctx);
+ cctx->frames.root = cctx;
+
+ if (req) {
+ ctx = fuse_req_ctx(req);
+
+ cctx->uid = ctx->uid;
+ cctx->gid = ctx->gid;
+ cctx->pid = ctx->pid;
+ cctx->unique = req_callid (req);
+ }
+
+ if (req) {
+ trans = fuse_req_userdata (req);
+ cctx->frames.this = trans->xl;
+ cctx->trans = trans;
+ } else {
+ cctx->frames.this = state->this;
+ }
+
+ if (d) {
+ cctx->req_refs = dict_ref (get_new_dict ());
+ dict_set (cctx->req_refs, NULL, trans->buf);
+ cctx->req_refs->is_locked = 1;
+ }
+
+ cctx->pool = pool;
+ LOCK (&pool->lock);
+ list_add (&cctx->all_frames, &pool->all_frames);
+ UNLOCK (&pool->lock);
+
+ return &cctx->frames;
+}
+
+
+static void
+fuse_loc_fill (fuse_loc_t *fuse_loc,
+ fuse_state_t *state,
+ ino_t ino,
+ const char *name)
+{
+ size_t n;
+ inode_t *inode, *parent = NULL;
+
+ /* resistance against multiple invocation of loc_fill not to get
+ reference leaks via inode_search() */
+ inode = fuse_loc->inode;
+ if (!inode) {
+ inode = inode_search (state->itable, ino, name);
+ }
+ fuse_loc->inode = inode;
+
+ if (name) {
+ if (!fuse_loc->name)
+ fuse_loc->name = strdup (name);
+
+ parent = fuse_loc->parent;
+ if (!parent) {
+ if (inode)
+ parent = inode_parent (inode, ino);
+ else
+ parent = inode_search (state->itable, ino, NULL);
+ }
+ }
+ fuse_loc->parent = parent;
+
+ if (inode) {
+ fuse_loc->loc.inode = inode_ref (inode);
+ fuse_loc->loc.ino = inode->ino;
+ }
+
+ if (parent) {
+ n = inode_path (parent, name, NULL, 0) + 1;
+ fuse_loc->loc.path = CALLOC (1, n);
+ ERR_ABORT (fuse_loc->loc.path);
+ inode_path (parent, name, (char *)fuse_loc->loc.path, n);
+ } else if (inode) {
+ n = inode_path (inode, NULL, NULL, 0) + 1;
+ fuse_loc->loc.path = CALLOC (1, n);
+ ERR_ABORT (fuse_loc->loc.path);
+ inode_path (inode, NULL, (char *)fuse_loc->loc.path, n);
+ }
+}
+
+static int32_t
+fuse_lookup_cbk (call_frame_t *frame,
+ void *cookie,
+ xlator_t *this,
+ int32_t op_ret,
+ int32_t op_errno,
+ inode_t *inode,
+ struct stat *stat,
+ dict_t *dict);
+
+static int32_t
+fuse_entry_cbk (call_frame_t *frame,
+ void *cookie,
+ xlator_t *this,
+ int32_t op_ret,
+ int32_t op_errno,
+ inode_t *inode,
+ struct stat *buf)
+{
+ fuse_state_t *state;
+ fuse_req_t req;
+ struct fuse_entry_param e = {0, };
+
+ state = frame->root->state;
+ req = state->req;
+
+ if (!op_ret) {
+ if (inode->ino == 1)
+ buf->st_ino = 1;
+ }
+
+ if (!op_ret && inode && inode->ino && buf && inode->ino != buf->st_ino) {
+ /* temporary workaround to handle AFR returning differnt inode number */
+ gf_log ("glusterfs-fuse", GF_LOG_WARNING,
+ "%"PRId64": %s => inode number changed %"PRId64" -> %"PRId64,
+ frame->root->unique, state->fuse_loc.loc.path,
+ inode->ino, buf->st_ino);
+ inode_unref (state->fuse_loc.loc.inode);
+ state->fuse_loc.loc.inode = dummy_inode (state->itable);
+ state->is_revalidate = 2;
+
+ STACK_WIND (frame, fuse_lookup_cbk,
+ FIRST_CHILD (this), FIRST_CHILD (this)->fops->lookup,
+ &state->fuse_loc.loc,
+ 0);
+
+ return 0;
+ }
+
+ if (op_ret == 0) {
+ ino_t ino = buf->st_ino;
+ inode_t *fuse_inode;
+
+ gf_log ("glusterfs-fuse", GF_LOG_DEBUG,
+ "%"PRId64": %s => %"PRId64, frame->root->unique,
+ state->fuse_loc.loc.path, ino);
+
+ try_again:
+ fuse_inode = inode_update (state->itable, state->fuse_loc.parent,
+ state->fuse_loc.name, buf);
+
+ if (fuse_inode->ctx) {
+ /* if the inode was already in the hash, checks to flush out
+ old name hashes */
+ if ((fuse_inode->st_mode ^ buf->st_mode) & S_IFMT) {
+ gf_log ("glusterfs-fuse", GF_LOG_WARNING,
+ "%"PRId64": %s => %"PRId64" Rehashing %x/%x",
+ frame->root->unique,
+ state->fuse_loc.loc.path, ino, (S_IFMT & buf->st_ino),
+ (S_IFMT & fuse_inode->st_mode));
+
+ fuse_inode->st_mode = buf->st_mode;
+ inode_unhash_name (state->itable, fuse_inode);
+ inode_unref (fuse_inode);
+ goto try_again;
+ }
+ if (buf->st_nlink == 1) {
+ /* no other name hashes should exist */
+ if (!list_empty (&fuse_inode->dentry.inode_list)) {
+ gf_log ("glusterfs-fuse", GF_LOG_WARNING,
+ "%"PRId64": %s => %"PRId64" Rehashing because st_nlink less than dentry maps",
+ frame->root->unique,
+ state->fuse_loc.loc.path, ino);
+ inode_unhash_name (state->itable, fuse_inode);
+ inode_unref (fuse_inode);
+ goto try_again;
+ }
+ if ((state->fuse_loc.parent != fuse_inode->dentry.parent) ||
+ strcmp (state->fuse_loc.name, fuse_inode->dentry.name)) {
+ gf_log ("glusterfs-fuse", GF_LOG_WARNING,
+ "%"PRId64": %s => %"PRId64" Rehashing because single st_nlink does not match dentry map",
+ frame->root->unique,
+ state->fuse_loc.loc.path, ino);
+ inode_unhash_name (state->itable, fuse_inode);
+ inode_unref (fuse_inode);
+ goto try_again;
+ }
+ }
+ }
+
+ if ((fuse_inode->ctx != inode->ctx) &&
+ list_empty (&fuse_inode->fds)) {
+ dict_t *swap = inode->ctx;
+ inode->ctx = fuse_inode->ctx;
+ fuse_inode->ctx = swap;
+ fuse_inode->generation = inode->generation;
+ fuse_inode->st_mode = buf->st_mode;
+ }
+
+ inode_lookup (fuse_inode);
+
+ inode_unref (fuse_inode);
+
+ /* TODO: make these timeouts configurable (via meta?) */
+ e.ino = fuse_inode->ino;
+ e.generation = buf->st_ctime;
+ e.entry_timeout = glusterfs_fuse_entry_timeout;
+ e.attr_timeout = glusterfs_fuse_attr_timeout;
+ e.attr = *buf;
+ e.attr.st_blksize = BIG_FUSE_CHANNEL_SIZE;
+ if (state->fuse_loc.parent)
+ fuse_reply_entry (req, &e);
+ else
+ fuse_reply_attr (req, buf, glusterfs_fuse_attr_timeout);
+ } else {
+ if (state->is_revalidate == -1 && op_errno == ENOENT) {
+ gf_log ("glusterfs-fuse", GF_LOG_DEBUG,
+ "%"PRId64": %s => -1 (%d)", frame->root->unique,
+ state->fuse_loc.loc.path, op_errno);
+ } else {
+ gf_log ("glusterfs-fuse", GF_LOG_ERROR,
+ "%"PRId64": %s => -1 (%d)", frame->root->unique,
+ state->fuse_loc.loc.path, op_errno);
+ }
+
+ if (state->is_revalidate == 1) {
+ gf_log ("glusterfs-fuse", GF_LOG_DEBUG,
+ "unlinking stale dentry for `%s'",
+ state->fuse_loc.loc.path);
+
+ if (state->fuse_loc.parent)
+ inode_unlink (state->itable, state->fuse_loc.parent,
+ state->fuse_loc.name);
+
+ inode_unref (state->fuse_loc.loc.inode);
+ state->fuse_loc.loc.inode = dummy_inode (state->itable);
+ state->is_revalidate = 2;
+
+ STACK_WIND (frame, fuse_lookup_cbk,
+ FIRST_CHILD (this), FIRST_CHILD (this)->fops->lookup,
+ &state->fuse_loc.loc, 0);
+
+ return 0;
+ }
+
+ fuse_reply_err (req, op_errno);
+ }
+
+ free_state (state);
+ STACK_DESTROY (frame->root);
+ return 0;
+}
+
+
+static int32_t
+fuse_lookup_cbk (call_frame_t *frame,
+ void *cookie,
+ xlator_t *this,
+ int32_t op_ret,
+ int32_t op_errno,
+ inode_t *inode,
+ struct stat *stat,
+ dict_t *dict)
+{
+ fuse_entry_cbk (frame, cookie, this, op_ret, op_errno, inode, stat);
+ return 0;
+}
+
+
+static void
+fuse_lookup (fuse_req_t req,
+ fuse_ino_t par,
+ const char *name)
+{
+ fuse_state_t *state;
+
+ state = state_from_req (req);
+
+ fuse_loc_fill (&state->fuse_loc, state, par, name);
+
+ if (!state->fuse_loc.loc.inode) {
+ gf_log ("glusterfs-fuse", GF_LOG_DEBUG,
+ "%"PRId64": LOOKUP %s", req_callid (req),
+ state->fuse_loc.loc.path);
+
+ state->fuse_loc.loc.inode = dummy_inode (state->itable);
+ /* to differntiate in entry_cbk what kind of call it is */
+ state->is_revalidate = -1;
+ } else {
+ gf_log ("glusterfs-fuse", GF_LOG_DEBUG,
+ "%"PRId64": LOOKUP %s(%"PRId64")", req_callid (req),
+ state->fuse_loc.loc.path, state->fuse_loc.loc.inode->ino);
+ state->is_revalidate = 1;
+ }
+
+ FUSE_FOP (state, fuse_lookup_cbk, lookup,
+ &state->fuse_loc.loc, 0);
+}
+
+
+static void
+fuse_forget (fuse_req_t req,
+ fuse_ino_t ino,
+ unsigned long nlookup)
+{
+ inode_t *fuse_inode;
+ fuse_state_t *state;
+
+ if (ino == 1) {
+ fuse_reply_none (req);
+ return;
+ }
+
+ state = state_from_req (req);
+ fuse_inode = inode_search (state->itable, ino, NULL);
+ inode_forget (fuse_inode, nlookup);
+ inode_unref (fuse_inode);
+
+ free_state (state);
+ fuse_reply_none (req);
+}
+
+
+static int32_t
+fuse_attr_cbk (call_frame_t *frame,
+ void *cookie,
+ xlator_t *this,
+ int32_t op_ret,
+ int32_t op_errno,
+ struct stat *buf)
+{
+ fuse_state_t *state;
+ fuse_req_t req;
+
+ state = frame->root->state;
+ req = state->req;
+
+ if (op_ret == 0) {
+ gf_log ("glusterfs-fuse", GF_LOG_DEBUG,
+ "%"PRId64": %s => %"PRId64, frame->root->unique,
+ state->fuse_loc.loc.path ? state->fuse_loc.loc.path : "ERR",
+ buf->st_ino);
+ /* TODO: make these timeouts configurable via meta */
+ /* TODO: what if the inode number has changed by now */
+ buf->st_blksize = BIG_FUSE_CHANNEL_SIZE;
+ fuse_reply_attr (req, buf, glusterfs_fuse_attr_timeout);
+ } else {
+ gf_log ("glusterfs-fuse", GF_LOG_ERROR,
+ "%"PRId64"; %s => -1 (%d)", frame->root->unique,
+ state->fuse_loc.loc.path ? state->fuse_loc.loc.path : "ERR",
+ op_errno);
+ fuse_reply_err (req, op_errno);
+ }
+
+ free_state (state);
+ STACK_DESTROY (frame->root);
+ return 0;
+}
+
+
+static void
+fuse_getattr (fuse_req_t req,
+ fuse_ino_t ino,
+ struct fuse_file_info *fi)
+{
+ fuse_state_t *state;
+
+ state = state_from_req (req);
+
+ if (ino == 1) {
+ fuse_loc_fill (&state->fuse_loc, state, ino, NULL);
+ if (state->fuse_loc.loc.inode)
+ state->is_revalidate = 1;
+ else
+ state->is_revalidate = -1;
+ FUSE_FOP (state,
+ fuse_lookup_cbk, lookup, &state->fuse_loc.loc, 0);
+ return;
+ }
+
+ fuse_loc_fill (&state->fuse_loc, state, ino, NULL);
+ if (!state->fuse_loc.loc.inode) {
+ gf_log ("glusterfs-fuse", GF_LOG_ERROR,
+ "%"PRId64": GETATTR %"PRId64" (%s) (fuse_loc_fill() returned NULL inode)",
+ req_callid (req), (int64_t)ino, state->fuse_loc.loc.path);
+ fuse_reply_err (req, EINVAL);
+ return;
+ }
+
+ if (list_empty (&state->fuse_loc.loc.inode->fds) ||
+ S_ISDIR (state->fuse_loc.loc.inode->st_mode)) {
+
+ gf_log ("glusterfs-fuse", GF_LOG_DEBUG,
+ "%"PRId64": GETATTR %"PRId64" (%s)",
+ req_callid (req), (int64_t)ino, state->fuse_loc.loc.path);
+
+ FUSE_FOP (state,
+ fuse_attr_cbk,
+ stat,
+ &state->fuse_loc.loc);
+ } else {
+ fd_t *fd = list_entry (state->fuse_loc.loc.inode->fds.next,
+ fd_t, inode_list);
+
+ gf_log ("glusterfs-fuse", GF_LOG_DEBUG,
+ "%"PRId64": FGETATTR %"PRId64" (%s/%p)",
+ req_callid (req), (int64_t)ino, state->fuse_loc.loc.path, fd);
+
+ FUSE_FOP (state,
+ fuse_attr_cbk,
+ fstat, fd);
+ }
+}
+
+
+static int32_t
+fuse_fd_cbk (call_frame_t *frame,
+ void *cookie,
+ xlator_t *this,
+ int32_t op_ret,
+ int32_t op_errno,
+ fd_t *fd)
+{
+ fuse_state_t *state;
+ fuse_req_t req;
+
+ state = frame->root->state;
+ req = state->req;
+ fd = state->fd;
+
+ if (op_ret >= 0) {
+ struct fuse_file_info fi = {0, };
+
+ LOCK (&fd->inode->lock);
+ list_add (&fd->inode_list, &fd->inode->fds);
+ UNLOCK (&fd->inode->lock);
+
+ fi.fh = (unsigned long) fd;
+ fi.flags = state->flags;
+
+ if (!S_ISDIR (fd->inode->st_mode)) {
+ if ((fi.flags & 3) && glusterfs_fuse_direct_io_mode)
+ fi.direct_io = 1;
+ }
+
+ gf_log ("glusterfs-fuse", GF_LOG_DEBUG,
+ "%"PRId64": %s => %p", frame->root->unique,
+ state->fuse_loc.loc.path, fd);
+
+ if (fuse_reply_open (req, &fi) == -ENOENT) {
+ gf_log ("glusterfs-fuse", GF_LOG_WARNING, "open() got EINTR");
+ state->req = 0;
+
+ if (S_ISDIR (fd->inode->st_mode))
+ FUSE_FOP_NOREPLY (state, closedir, fd);
+ else
+ FUSE_FOP_NOREPLY (state, close, fd);
+ }
+ } else {
+ gf_log ("glusterfs-fuse", GF_LOG_ERROR,
+ "%"PRId64": %s => -1 (%d)", frame->root->unique,
+ state->fuse_loc.loc.path, op_errno);
+ fuse_reply_err (req, op_errno);
+ fd_destroy (fd);
+ }
+
+ free_state (state);
+ STACK_DESTROY (frame->root);
+ return 0;
+}
+
+
+
+static void
+do_chmod (fuse_req_t req,
+ fuse_ino_t ino,
+ struct stat *attr,
+ struct fuse_file_info *fi)
+{
+ fuse_state_t *state = state_from_req (req);
+
+ if (fi) {
+ gf_log ("glusterfs-fuse", GF_LOG_DEBUG,
+ "%"PRId64": FCHMOD %p", req_callid (req), FI_TO_FD (fi));
+
+ FUSE_FOP (state,
+ fuse_attr_cbk,
+ fchmod,
+ FI_TO_FD (fi),
+ attr->st_mode);
+ } else {
+ fuse_loc_fill (&state->fuse_loc, state, ino, NULL);
+ if (!state->fuse_loc.loc.inode) {
+ gf_log ("glusterfs-fuse", GF_LOG_ERROR,
+ "%"PRId64": CHMOD %"PRId64" (%s) (fuse_loc_fill() returned NULL inode)",
+ req_callid (req), (int64_t)ino, state->fuse_loc.loc.path);
+ fuse_reply_err (req, EINVAL);
+ return;
+ }
+
+
+ gf_log ("glusterfs-fuse", GF_LOG_DEBUG,
+ "%"PRId64": CHMOD %s", req_callid (req),
+ state->fuse_loc.loc.path);
+
+ FUSE_FOP (state,
+ fuse_attr_cbk,
+ chmod,
+ &state->fuse_loc.loc,
+ attr->st_mode);
+ }
+}
+
+static void
+do_chown (fuse_req_t req,
+ fuse_ino_t ino,
+ struct stat *attr,
+ int valid,
+ struct fuse_file_info *fi)
+{
+ fuse_state_t *state;
+
+ uid_t uid = (valid & FUSE_SET_ATTR_UID) ? attr->st_uid : (uid_t) -1;
+ gid_t gid = (valid & FUSE_SET_ATTR_GID) ? attr->st_gid : (gid_t) -1;
+
+ state = state_from_req (req);
+
+ if (fi) {
+ gf_log ("glusterfs-fuse", GF_LOG_DEBUG,
+ "%"PRId64": FCHOWN %p", req_callid (req), FI_TO_FD (fi));
+
+ FUSE_FOP (state,
+ fuse_attr_cbk,
+ fchown,
+ FI_TO_FD (fi),
+ uid,
+ gid);
+ } else {
+ fuse_loc_fill (&state->fuse_loc, state, ino, NULL);
+ if (!state->fuse_loc.loc.inode) {
+ gf_log ("glusterfs-fuse", GF_LOG_ERROR,
+ "%"PRId64": CHOWN %"PRId64" (%s) (fuse_loc_fill() returned NULL inode)",
+ req_callid (req), (int64_t)ino, state->fuse_loc.loc.path);
+ fuse_reply_err (req, EINVAL);
+ return;
+ }
+
+ gf_log ("glusterfs-fuse", GF_LOG_DEBUG,
+ "%"PRId64": CHOWN %s", req_callid (req),
+ state->fuse_loc.loc.path);
+
+ FUSE_FOP (state,
+ fuse_attr_cbk,
+ chown,
+ &state->fuse_loc.loc,
+ uid,
+ gid);
+ }
+}
+
+static void
+do_truncate (fuse_req_t req,
+ fuse_ino_t ino,
+ struct stat *attr,
+ struct fuse_file_info *fi)
+{
+ fuse_state_t *state;
+
+ state = state_from_req (req);
+
+ if (fi) {
+ gf_log ("glusterfs-fuse", GF_LOG_DEBUG,
+ "%"PRId64": FTRUNCATE %p/%"PRId64, req_callid (req),
+ FI_TO_FD (fi), attr->st_size);
+
+ FUSE_FOP (state,
+ fuse_attr_cbk,
+ ftruncate,
+ FI_TO_FD (fi),
+ attr->st_size);
+ } else {
+ fuse_loc_fill (&state->fuse_loc, state, ino, NULL);
+ if (!state->fuse_loc.loc.inode) {
+ gf_log ("glusterfs-fuse", GF_LOG_ERROR,
+ "%"PRId64": TRUNCATE %s/%"PRId64" (fuse_loc_fill() returned NULL inode)",
+ req_callid (req), state->fuse_loc.loc.path, attr->st_size);
+ fuse_reply_err (req, EINVAL);
+ return;
+ }
+
+ gf_log ("glusterfs-fuse", GF_LOG_DEBUG,
+ "%"PRId64": TRUNCATE %s/%"PRId64, req_callid (req),
+ state->fuse_loc.loc.path, attr->st_size);
+
+ FUSE_FOP (state,
+ fuse_attr_cbk,
+ truncate,
+ &state->fuse_loc.loc,
+ attr->st_size);
+ }
+
+ return;
+}
+
+static void
+do_utimes (fuse_req_t req,
+ fuse_ino_t ino,
+ struct stat *attr)
+{
+ fuse_state_t *state;
+
+ struct timespec tv[2];
+#ifdef FUSE_STAT_HAS_NANOSEC
+ tv[0] = ST_ATIM(attr);
+ tv[1] = ST_MTIM(attr);
+#else
+ tv[0].tv_sec = attr->st_atime;
+ tv[0].tv_nsec = 0;
+ tv[1].tv_sec = attr->st_mtime;
+ tv[1].tv_nsec = 0;
+#endif
+
+ state = state_from_req (req);
+ fuse_loc_fill (&state->fuse_loc, state, ino, NULL);
+ if (!state->fuse_loc.loc.inode) {
+ gf_log ("glusterfs-fuse", GF_LOG_ERROR,
+ "%"PRId64": UTIMENS %s (fuse_loc_fill() returned NULL inode)",
+ req_callid (req), state->fuse_loc.loc.path);
+ fuse_reply_err (req, EINVAL);
+ return;
+ }
+
+ gf_log ("glusterfs-fuse", GF_LOG_DEBUG,
+ "%"PRId64": UTIMENS %s", req_callid (req),
+ state->fuse_loc.loc.path);
+
+ FUSE_FOP (state,
+ fuse_attr_cbk,
+ utimens,
+ &state->fuse_loc.loc,
+ tv);
+}
+
+static void
+fuse_setattr (fuse_req_t req,
+ fuse_ino_t ino,
+ struct stat *attr,
+ int valid,
+ struct fuse_file_info *fi)
+{
+
+ if (valid & FUSE_SET_ATTR_MODE)
+ do_chmod (req, ino, attr, fi);
+ else if (valid & (FUSE_SET_ATTR_UID | FUSE_SET_ATTR_GID))
+ do_chown (req, ino, attr, valid, fi);
+ else if (valid & FUSE_SET_ATTR_SIZE)
+ do_truncate (req, ino, attr, fi);
+ else if ((valid & (FUSE_SET_ATTR_ATIME | FUSE_SET_ATTR_MTIME)) == (FUSE_SET_ATTR_ATIME | FUSE_SET_ATTR_MTIME))
+ do_utimes (req, ino, attr);
+
+ if (!valid)
+ fuse_getattr (req, ino, fi);
+}
+
+
+static int32_t
+fuse_err_cbk (call_frame_t *frame,
+ void *cookie,
+ xlator_t *this,
+ int32_t op_ret,
+ int32_t op_errno)
+{
+ fuse_state_t *state = frame->root->state;
+ fuse_req_t req = state->req;
+
+ if (op_ret == 0) {
+ gf_log ("glusterfs-fuse", GF_LOG_DEBUG,
+ "%"PRId64": %s => 0", frame->root->unique,
+ state->fuse_loc.loc.path ? state->fuse_loc.loc.path : "ERR");
+ fuse_reply_err (req, 0);
+ } else {
+ gf_log ("glusterfs-fuse", GF_LOG_ERROR,
+ "%"PRId64": %s => -1 (%d)", frame->root->unique,
+ state->fuse_loc.loc.path ? state->fuse_loc.loc.path : "ERR",
+ op_errno);
+ fuse_reply_err (req, op_errno);
+ }
+
+ if (state->fd)
+ fd_destroy (state->fd);
+
+ free_state (state);
+ STACK_DESTROY (frame->root);
+
+ return 0;
+}
+
+
+
+static int32_t
+fuse_unlink_cbk (call_frame_t *frame,
+ void *cookie,
+ xlator_t *this,
+ int32_t op_ret,
+ int32_t op_errno)
+{
+ fuse_state_t *state = frame->root->state;
+ fuse_req_t req = state->req;
+
+ if (op_ret == 0)
+ inode_unlink (state->itable, state->fuse_loc.parent, state->fuse_loc.name);
+
+ if (op_ret == 0) {
+ gf_log ("glusterfs-fuse", GF_LOG_DEBUG,
+ "%"PRId64": %s => 0", frame->root->unique,
+ state->fuse_loc.loc.path);
+
+ fuse_reply_err (req, 0);
+ } else {
+ gf_log ("glusterfs-fuse", (op_errno == ENOTEMPTY) ? GF_LOG_DEBUG : GF_LOG_ERROR,
+ "%"PRId64": %s => -1 (%d)", frame->root->unique,
+ state->fuse_loc.loc.path, op_errno);
+
+ fuse_reply_err (req, op_errno);
+ }
+
+ free_state (state);
+ STACK_DESTROY (frame->root);
+
+ return 0;
+}
+
+
+static void
+fuse_access (fuse_req_t req,
+ fuse_ino_t ino,
+ int mask)
+{
+ fuse_state_t *state;
+
+ state = state_from_req (req);
+
+ fuse_loc_fill (&state->fuse_loc, state, ino, NULL);
+ if (!state->fuse_loc.loc.inode) {
+ gf_log ("glusterfs-fuse", GF_LOG_ERROR,
+ "%"PRId64": ACCESS %"PRId64" (%s) (fuse_loc_fill() returned NULL inode)",
+ req_callid (req), (int64_t)ino, state->fuse_loc.loc.path);
+ fuse_reply_err (req, EINVAL);
+ return;
+ }
+
+ FUSE_FOP (state,
+ fuse_err_cbk,
+ access,
+ &state->fuse_loc.loc,
+ mask);
+
+ return;
+}
+
+
+
+static int32_t
+fuse_readlink_cbk (call_frame_t *frame,
+ void *cookie,
+ xlator_t *this,
+ int32_t op_ret,
+ int32_t op_errno,
+ const char *linkname)
+{
+ fuse_state_t *state = frame->root->state;
+ fuse_req_t req = state->req;
+
+ if (op_ret > 0) {
+ ((char *)linkname)[op_ret] = '\0';
+
+ gf_log ("glusterfs-fuse", GF_LOG_DEBUG,
+ "%"PRId64": %s => %s", frame->root->unique,
+ state->fuse_loc.loc.path, linkname);
+
+ fuse_reply_readlink(req, linkname);
+ } else {
+ gf_log ("glusterfs-fuse", GF_LOG_ERROR,
+ "%"PRId64": %s => -1 (%d)", frame->root->unique,
+ state->fuse_loc.loc.path, op_errno);
+ fuse_reply_err(req, op_errno);
+ }
+
+ free_state (state);
+ STACK_DESTROY (frame->root);
+
+ return 0;
+}
+
+static void
+fuse_readlink (fuse_req_t req,
+ fuse_ino_t ino)
+{
+ fuse_state_t *state;
+
+ state = state_from_req (req);
+ fuse_loc_fill (&state->fuse_loc, state, ino, NULL);
+ if (!state->fuse_loc.loc.inode) {
+ gf_log ("glusterfs-fuse", GF_LOG_ERROR,
+ "%"PRId64" READLINK %s/%"PRId64" (fuse_loc_fill() returned NULL inode)",
+ req_callid (req), state->fuse_loc.loc.path, state->fuse_loc.loc.inode->ino);
+ fuse_reply_err (req, EINVAL);
+ return;
+ }
+
+ gf_log ("glusterfs-fuse", GF_LOG_DEBUG,
+ "%"PRId64" READLINK %s/%"PRId64, req_callid (req),
+ state->fuse_loc.loc.path, state->fuse_loc.loc.inode->ino);
+
+ FUSE_FOP (state,
+ fuse_readlink_cbk,
+ readlink,
+ &state->fuse_loc.loc,
+ 4096);
+
+ return;
+}
+
+
+static void
+fuse_mknod (fuse_req_t req,
+ fuse_ino_t par,
+ const char *name,
+ mode_t mode,
+ dev_t rdev)
+{
+ fuse_state_t *state;
+
+ state = state_from_req (req);
+ fuse_loc_fill (&state->fuse_loc, state, par, name);
+
+ state->fuse_loc.loc.inode = dummy_inode (state->itable);
+
+ gf_log ("glusterfs-fuse", GF_LOG_DEBUG,
+ "%"PRId64": MKNOD %s", req_callid (req),
+ state->fuse_loc.loc.path);
+
+ FUSE_FOP (state,
+ fuse_entry_cbk,
+ mknod,
+ &state->fuse_loc.loc,
+ mode,
+ rdev);
+
+ return;
+}
+
+
+static void
+fuse_mkdir (fuse_req_t req,
+ fuse_ino_t par,
+ const char *name,
+ mode_t mode)
+{
+ fuse_state_t *state;
+
+ state = state_from_req (req);
+ fuse_loc_fill (&state->fuse_loc, state, par, name);
+
+ state->fuse_loc.loc.inode = dummy_inode (state->itable);
+
+ gf_log ("glusterfs-fuse", GF_LOG_DEBUG,
+ "%"PRId64": MKDIR %s", req_callid (req),
+ state->fuse_loc.loc.path);
+
+ FUSE_FOP (state,
+ fuse_entry_cbk,
+ mkdir,
+ &state->fuse_loc.loc,
+ mode);
+
+ return;
+}
+
+
+static void
+fuse_unlink (fuse_req_t req,
+ fuse_ino_t par,
+ const char *name)
+{
+ fuse_state_t *state;
+
+ state = state_from_req (req);
+
+ gf_log ("glusterfs-fuse", GF_LOG_DEBUG,
+ "%"PRId64": UNLINK %s", req_callid (req),
+ state->fuse_loc.loc.path);
+
+ fuse_loc_fill (&state->fuse_loc, state, par, name);
+ if (!state->fuse_loc.loc.inode) {
+ gf_log ("glusterfs-fuse", GF_LOG_ERROR,
+ "%"PRId64": UNLINK %s (fuse_loc_fill() returned NULL inode)", req_callid (req),
+ state->fuse_loc.loc.path);
+ fuse_reply_err (req, EINVAL);
+ return;
+ }
+
+ FUSE_FOP (state,
+ fuse_unlink_cbk,
+ unlink,
+ &state->fuse_loc.loc);
+
+ return;
+}
+
+
+static void
+fuse_rmdir (fuse_req_t req,
+ fuse_ino_t par,
+ const char *name)
+{
+ fuse_state_t *state;
+
+ state = state_from_req (req);
+ fuse_loc_fill (&state->fuse_loc, state, par, name);
+ if (!state->fuse_loc.loc.inode) {
+ gf_log ("glusterfs-fuse", GF_LOG_DEBUG,
+ "%"PRId64": RMDIR %s (fuse_loc_fill() returned NULL inode)", req_callid (req),
+ state->fuse_loc.loc.path);
+ fuse_reply_err (req, EINVAL);
+ return;
+ }
+
+ gf_log ("glusterfs-fuse", GF_LOG_DEBUG,
+ "%"PRId64": RMDIR %s", req_callid (req),
+ state->fuse_loc.loc.path);
+
+ FUSE_FOP (state,
+ fuse_unlink_cbk,
+ rmdir,
+ &state->fuse_loc.loc);
+
+ return;
+}
+
+
+static void
+fuse_symlink (fuse_req_t req,
+ const char *linkname,
+ fuse_ino_t par,
+ const char *name)
+{
+ fuse_state_t *state;
+
+ state = state_from_req (req);
+ fuse_loc_fill (&state->fuse_loc, state, par, name);
+
+ state->fuse_loc.loc.inode = dummy_inode (state->itable);
+
+ gf_log ("glusterfs-fuse", GF_LOG_DEBUG,
+ "%"PRId64": SYMLINK %s -> %s", req_callid (req),
+ state->fuse_loc.loc.path, linkname);
+
+ FUSE_FOP (state,
+ fuse_entry_cbk,
+ symlink,
+ linkname,
+ &state->fuse_loc.loc);
+ return;
+}
+
+
+int32_t
+fuse_rename_cbk (call_frame_t *frame,
+ void *cookie,
+ xlator_t *this,
+ int32_t op_ret,
+ int32_t op_errno,
+ struct stat *buf)
+{
+ fuse_state_t *state = frame->root->state;
+ fuse_req_t req = state->req;
+
+ if (op_ret == 0) {
+ gf_log ("glusterfs-fuse", GF_LOG_DEBUG,
+ "%"PRId64": %s -> %s => 0", frame->root->unique,
+ state->fuse_loc.loc.path,
+ state->fuse_loc2.loc.path);
+
+ inode_t *inode;
+ {
+ /* ugly ugly - to stay blind to situation where
+ rename happens on a new inode
+ */
+ buf->st_ino = state->fuse_loc.loc.ino;
+ }
+ inode = inode_rename (state->itable,
+ state->fuse_loc.parent,
+ state->fuse_loc.name,
+ state->fuse_loc2.parent,
+ state->fuse_loc2.name,
+ buf);
+
+ inode_unref (inode);
+ fuse_reply_err (req, 0);
+ } else {
+ gf_log ("glusterfs-fuse", GF_LOG_ERROR,
+ "%"PRId64": %s -> %s => -1 (%d)", frame->root->unique,
+ state->fuse_loc.loc.path,
+ state->fuse_loc2.loc.path, op_errno);
+ fuse_reply_err (req, op_errno);
+ }
+
+ free_state (state);
+ STACK_DESTROY (frame->root);
+ return 0;
+}
+
+
+static void
+fuse_rename (fuse_req_t req,
+ fuse_ino_t oldpar,
+ const char *oldname,
+ fuse_ino_t newpar,
+ const char *newname)
+{
+ fuse_state_t *state;
+
+ state = state_from_req (req);
+
+ fuse_loc_fill (&state->fuse_loc, state, oldpar, oldname);
+ if (!state->fuse_loc.loc.inode) {
+ gf_log ("glusterfs-fuse", GF_LOG_ERROR,
+ "for %s %"PRId64": RENAME `%s' -> `%s' (fuse_loc_fill() returned NULL inode)",
+ state->fuse_loc.loc.path, req_callid (req), state->fuse_loc.loc.path,
+ state->fuse_loc2.loc.path);
+
+ fuse_reply_err (req, EINVAL);
+ return;
+ }
+
+ fuse_loc_fill (&state->fuse_loc2, state, newpar, newname);
+
+ gf_log ("glusterfs-fuse", GF_LOG_DEBUG,
+ "%"PRId64": RENAME `%s' -> `%s'",
+ req_callid (req), state->fuse_loc.loc.path,
+ state->fuse_loc2.loc.path);
+
+ FUSE_FOP (state,
+ fuse_rename_cbk,
+ rename,
+ &state->fuse_loc.loc,
+ &state->fuse_loc2.loc);
+
+ return;
+}
+
+
+static void
+fuse_link (fuse_req_t req,
+ fuse_ino_t ino,
+ fuse_ino_t par,
+ const char *name)
+{
+ fuse_state_t *state;
+
+ state = state_from_req (req);
+
+ fuse_loc_fill (&state->fuse_loc, state, par, name);
+ fuse_loc_fill (&state->fuse_loc2, state, ino, NULL);
+ if (!state->fuse_loc2.loc.inode) {
+ gf_log ("glusterfs-fuse", GF_LOG_ERROR,
+ "fuse_loc_fill() returned NULL inode for %s %"PRId64": LINK %s %s",
+ state->fuse_loc2.loc.path, req_callid (req),
+ state->fuse_loc2.loc.path, state->fuse_loc.loc.path);
+ fuse_reply_err (req, EINVAL);
+ return;
+ }
+
+ state->fuse_loc.loc.inode = inode_ref (state->fuse_loc2.loc.inode);
+ gf_log ("glusterfs-fuse", GF_LOG_DEBUG,
+ "%"PRId64": LINK %s %s", req_callid (req),
+ state->fuse_loc2.loc.path, state->fuse_loc.loc.path);
+
+ FUSE_FOP (state,
+ fuse_entry_cbk,
+ link,
+ &state->fuse_loc2.loc,
+ state->fuse_loc.loc.path);
+
+ return;
+}
+
+
+static int32_t
+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 stat *buf)
+{
+ fuse_state_t *state = frame->root->state;
+ fuse_req_t req = state->req;
+
+ struct fuse_file_info fi = {0, };
+ struct fuse_entry_param e = {0, };
+
+ fd = state->fd;
+
+ fi.flags = state->flags;
+ if (op_ret >= 0) {
+ inode_t *fuse_inode;
+ fi.fh = (unsigned long) fd;
+
+ if ((fi.flags & 3) && glusterfs_fuse_direct_io_mode)
+ fi.direct_io = 1;
+
+ gf_log ("glusterfs-fuse", GF_LOG_DEBUG,
+ "%"PRId64": %s => %p", frame->root->unique,
+ state->fuse_loc.loc.path, fd);
+
+ fuse_inode = inode_update (state->itable,
+ state->fuse_loc.parent,
+ state->fuse_loc.name,
+ buf);
+ if (fuse_inode->ctx) {
+ inode_unhash_name (state->itable, fuse_inode);
+ inode_unref (fuse_inode);
+
+ fuse_inode = inode_update (state->itable,
+ state->fuse_loc.parent,
+ state->fuse_loc.name,
+ buf);
+ }
+
+
+ {
+ if (fuse_inode->ctx != inode->ctx) {
+ dict_t *swap = inode->ctx;
+ inode->ctx = fuse_inode->ctx;
+ fuse_inode->ctx = swap;
+ fuse_inode->generation = inode->generation;
+ fuse_inode->st_mode = buf->st_mode;
+ }
+
+ inode_lookup (fuse_inode);
+
+ /* list_del (&fd->inode_list); */
+
+ LOCK (&fuse_inode->lock);
+ list_add (&fd->inode_list, &fuse_inode->fds);
+ inode_unref (fd->inode);
+ fd->inode = inode_ref (fuse_inode);
+ UNLOCK (&fuse_inode->lock);
+
+ // inode_destroy (inode);
+ }
+
+ inode_unref (fuse_inode);
+
+ e.ino = fuse_inode->ino;
+ e.generation = buf->st_ctime;
+ e.entry_timeout = glusterfs_fuse_entry_timeout;
+ e.attr_timeout = glusterfs_fuse_attr_timeout;
+ e.attr = *buf;
+ e.attr.st_blksize = BIG_FUSE_CHANNEL_SIZE;
+
+ fi.keep_cache = 0;
+
+ // if (fi.flags & 1)
+ // fi.direct_io = 1;
+
+ if (fuse_reply_create (req, &e, &fi) == -ENOENT) {
+ gf_log ("glusterfs-fuse", GF_LOG_WARNING, "create() got EINTR");
+ /* TODO: forget this node too */
+ state->req = 0;
+ FUSE_FOP_NOREPLY (state, close, fd);
+ }
+ } else {
+ gf_log ("glusterfs-fuse", GF_LOG_ERROR,
+ "%"PRId64": %s => -1 (%d)", req_callid (req),
+ state->fuse_loc.loc.path, op_errno);
+ fuse_reply_err (req, op_errno);
+ fd_destroy (fd);
+ }
+
+ free_state (state);
+ STACK_DESTROY (frame->root);
+
+ return 0;
+}
+
+
+static void
+fuse_create (fuse_req_t req,
+ fuse_ino_t par,
+ const char *name,
+ mode_t mode,
+ struct fuse_file_info *fi)
+{
+ fuse_state_t *state;
+ fd_t *fd;
+
+ state = state_from_req (req);
+ state->flags = fi->flags;
+
+ fuse_loc_fill (&state->fuse_loc, state, par, name);
+ state->fuse_loc.loc.inode = dummy_inode (state->itable);
+
+ fd = fd_create (state->fuse_loc.loc.inode);
+ state->fd = fd;
+
+
+ LOCK (&fd->inode->lock);
+ list_del_init (&fd->inode_list);
+ UNLOCK (&fd->inode->lock);
+
+ gf_log ("glusterfs-fuse", GF_LOG_DEBUG,
+ "%"PRId64": CREATE %s", req_callid (req),
+ state->fuse_loc.loc.path);
+
+ FUSE_FOP (state,
+ fuse_create_cbk,
+ create,
+ &state->fuse_loc.loc,
+ state->flags,
+ mode, fd);
+
+ return;
+}
+
+
+static void
+fuse_open (fuse_req_t req,
+ fuse_ino_t ino,
+ struct fuse_file_info *fi)
+{
+ fuse_state_t *state;
+ fd_t *fd;
+
+ state = state_from_req (req);
+ state->flags = fi->flags;
+
+ fuse_loc_fill (&state->fuse_loc, state, ino, NULL);
+ if (!state->fuse_loc.loc.inode) {
+ gf_log ("glusterfs-fuse", GF_LOG_ERROR,
+ "%"PRId64": OPEN %s (fuse_loc_fill() returned NULL inode)", req_callid (req),
+ state->fuse_loc.loc.path);
+
+ fuse_reply_err (req, EINVAL);
+ return;
+ }
+
+
+ fd = fd_create (state->fuse_loc.loc.inode);
+ state->fd = fd;
+
+ LOCK (&fd->inode->lock);
+ list_del_init (&fd->inode_list);
+ UNLOCK (&fd->inode->lock);
+
+ gf_log ("glusterfs-fuse", GF_LOG_DEBUG,
+ "%"PRId64": OPEN %s", req_callid (req),
+ state->fuse_loc.loc.path);
+
+ FUSE_FOP (state,
+ fuse_fd_cbk,
+ open,
+ &state->fuse_loc.loc,
+ fi->flags, fd);
+
+ return;
+}
+
+
+static int32_t
+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 stat *stbuf)
+{
+ fuse_state_t *state = frame->root->state;
+ fuse_req_t req = state->req;
+
+ if (op_ret >= 0) {
+ gf_log ("glusterfs-fuse", GF_LOG_DEBUG,
+ "%"PRId64": READ => %d/%d,%"PRId64"/%"PRId64, frame->root->unique,
+ op_ret, state->size, state->off, stbuf->st_size);
+
+ fuse_reply_vec (req, vector, count);
+ } else {
+ gf_log ("glusterfs-fuse", GF_LOG_ERROR,
+ "%"PRId64": READ => -1 (%d)", frame->root->unique, op_errno);
+
+ fuse_reply_err (req, op_errno);
+ }
+
+ free_state (state);
+ STACK_DESTROY (frame->root);
+
+ return 0;
+}
+
+static void
+fuse_readv (fuse_req_t req,
+ fuse_ino_t ino,
+ size_t size,
+ off_t off,
+ struct fuse_file_info *fi)
+{
+ fuse_state_t *state;
+
+ state = state_from_req (req);
+ state->size = size;
+ state->off = off;
+
+ gf_log ("glusterfs-fuse", GF_LOG_DEBUG,
+ "%"PRId64": READ (%p, size=%d, offset=%"PRId64")",
+ req_callid (req), FI_TO_FD (fi), size, off);
+
+ FUSE_FOP (state,
+ fuse_readv_cbk,
+ readv,
+ FI_TO_FD (fi),
+ size,
+ off);
+
+}
+
+
+static int32_t
+fuse_writev_cbk (call_frame_t *frame,
+ void *cookie,
+ xlator_t *this,
+ int32_t op_ret,
+ int32_t op_errno,
+ struct stat *stbuf)
+{
+ fuse_state_t *state = frame->root->state;
+ fuse_req_t req = state->req;
+
+ if (op_ret >= 0) {
+ gf_log ("glusterfs-fuse", GF_LOG_DEBUG,
+ "%"PRId64": WRITE => %d/%d,%"PRId64"/%"PRId64, frame->root->unique,
+ op_ret, state->size, state->off, stbuf->st_size);
+
+ fuse_reply_write (req, op_ret);
+ } else {
+ gf_log ("glusterfs-fuse", GF_LOG_ERROR,
+ "%"PRId64": WRITE => -1 (%d)", frame->root->unique, op_errno);
+
+ fuse_reply_err (req, op_errno);
+ }
+
+ free_state (state);
+ STACK_DESTROY (frame->root);
+
+ return 0;
+}
+
+
+static void
+fuse_write (fuse_req_t req,
+ fuse_ino_t ino,
+ const char *buf,
+ size_t size,
+ off_t off,
+ struct fuse_file_info *fi)
+{
+ fuse_state_t *state;
+ struct iovec vector;
+
+ state = state_from_req (req);
+ state->size = size;
+ state->off = off;
+
+ vector.iov_base = (void *)buf;
+ vector.iov_len = size;
+
+ gf_log ("glusterfs-fuse", GF_LOG_DEBUG,
+ "%"PRId64": WRITE (%p, size=%d, offset=%"PRId64")",
+ req_callid (req), FI_TO_FD (fi), size, off);
+
+ FUSE_FOP (state,
+ fuse_writev_cbk,
+ writev,
+ FI_TO_FD (fi),
+ &vector,
+ 1,
+ off);
+ return;
+}
+
+
+static void
+fuse_flush (fuse_req_t req,
+ fuse_ino_t ino,
+ struct fuse_file_info *fi)
+{
+ fuse_state_t *state;
+
+ state = state_from_req (req);
+
+ gf_log ("glusterfs-fuse", GF_LOG_DEBUG,
+ "%"PRId64": FLUSH %p", req_callid (req), FI_TO_FD (fi));
+
+ FUSE_FOP (state,
+ fuse_err_cbk,
+ flush,
+ FI_TO_FD (fi));
+
+ return;
+}
+
+
+static void
+fuse_release (fuse_req_t req,
+ fuse_ino_t ino,
+ struct fuse_file_info *fi)
+{
+ fuse_state_t *state;
+
+ state = state_from_req (req);
+ state->fd = FI_TO_FD (fi);
+
+ LOCK (&state->fd->inode->lock);
+ list_del_init (&state->fd->inode_list);
+ UNLOCK (&state->fd->inode->lock);
+
+ gf_log ("glusterfs-fuse", GF_LOG_DEBUG,
+ "%"PRId64": CLOSE %p", req_callid (req), FI_TO_FD (fi));
+
+ FUSE_FOP (state, fuse_err_cbk, close, state->fd);
+ return;
+}
+
+
+static void
+fuse_fsync (fuse_req_t req,
+ fuse_ino_t ino,
+ int datasync,
+ struct fuse_file_info *fi)
+{
+ fuse_state_t *state;
+
+ state = state_from_req (req);
+
+ gf_log ("glusterfs-fuse", GF_LOG_DEBUG,
+ "%"PRId64": FSYNC %p", req_callid (req), FI_TO_FD (fi));
+
+ FUSE_FOP (state,
+ fuse_err_cbk,
+ fsync,
+ FI_TO_FD (fi),
+ datasync);
+
+ return;
+}
+
+static void
+fuse_opendir (fuse_req_t req,
+ fuse_ino_t ino,
+ struct fuse_file_info *fi)
+{
+ fuse_state_t *state;
+ fd_t *fd;
+
+ state = state_from_req (req);
+ fuse_loc_fill (&state->fuse_loc, state, ino, NULL);
+ if (!state->fuse_loc.loc.inode) {
+ gf_log ("glusterfs-fuse", GF_LOG_ERROR,
+ "%"PRId64": OPEN %s (fuse_loc_fill() returned NULL inode)", req_callid (req),
+ state->fuse_loc.loc.path);
+
+ fuse_reply_err (req, EINVAL);
+ return;
+ }
+
+
+ fd = fd_create (state->fuse_loc.loc.inode);
+ state->fd = fd;
+
+ LOCK (&fd->inode->lock);
+ list_del_init (&fd->inode_list);
+ UNLOCK (&fd->inode->lock);
+
+ gf_log ("glusterfs-fuse", GF_LOG_DEBUG,
+ "%"PRId64": OPEN %s", req_callid (req),
+ state->fuse_loc.loc.path);
+
+ FUSE_FOP (state,
+ fuse_fd_cbk,
+ opendir,
+ &state->fuse_loc.loc, fd);
+}
+
+#if 0
+
+void
+fuse_dir_reply (fuse_req_t req,
+ size_t size,
+ off_t off,
+ fd_t *fd)
+{
+ char *buf;
+ size_t size_limited;
+ data_t *buf_data;
+
+ buf_data = dict_get (fd->ctx, "__fuse__getdents__internal__@@!!");
+ buf = buf_data->data;
+ size_limited = size;
+
+ if (size_limited > (buf_data->len - off))
+ size_limited = (buf_data->len - off);
+
+ if (off > buf_data->len) {
+ size_limited = 0;
+ off = 0;
+ }
+
+ fuse_reply_buf (req, buf + off, size_limited);
+}
+
+
+static int32_t
+fuse_getdents_cbk (call_frame_t *frame,
+ void *cookie,
+ xlator_t *this,
+ int32_t op_ret,
+ int32_t op_errno,
+ dir_entry_t *entries,
+ int32_t count)
+{
+ fuse_state_t *state = frame->root->state;
+ fuse_req_t req = state->req;
+
+ if (op_ret < 0) {
+ gf_log ("glusterfs-fuse", GF_LOG_ERROR,
+ "%"PRId64": READDIR => -1 (%d)",
+ frame->root->unique, op_errno);
+
+ fuse_reply_err (state->req, op_errno);
+ } else {
+ dir_entry_t *trav;
+ size_t size = 0;
+ char *buf;
+ data_t *buf_data;
+
+ gf_log ("glusterfs-fuse", GF_LOG_DEBUG,
+ "%"PRId64": READDIR => %d entries",
+ frame->root->unique, count);
+
+ for (trav = entries->next; trav; trav = trav->next) {
+ size += fuse_add_direntry (req, NULL, 0, trav->name, NULL, 0);
+ }
+
+ buf = CALLOC (1, size);
+ ERR_ABORT (buf);
+ buf_data = data_from_dynptr (buf, size);
+ size = 0;
+
+ for (trav = entries->next; trav; trav = trav->next) {
+ size_t entry_size;
+ entry_size = fuse_add_direntry (req, NULL, 0, trav->name, NULL, 0);
+ fuse_add_direntry (req, buf + size, entry_size, trav->name,
+ &trav->buf, entry_size + size);
+ size += entry_size;
+ }
+
+ dict_set (state->fd->ctx,
+ "__fuse__getdents__internal__@@!!",
+ buf_data);
+
+ fuse_dir_reply (state->req, state->size, state->off, state->fd);
+ }
+
+ free_state (state);
+ STACK_DESTROY (frame->root);
+
+ return 0;
+}
+
+static void
+fuse_getdents (fuse_req_t req,
+ fuse_ino_t ino,
+ struct fuse_file_info *fi,
+ size_t size,
+ off_t off,
+ int32_t flag)
+{
+ fuse_state_t *state;
+ fd_t *fd = FI_TO_FD (fi);
+
+ gf_log ("glusterfs-fuse", GF_LOG_DEBUG,
+ "%"PRId64": GETDENTS %p", req_callid (req), FI_TO_FD (fi));
+
+ if (!off)
+ dict_del (fd->ctx, "__fuse__getdents__internal__@@!!");
+
+ if (dict_get (fd->ctx, "__fuse__getdents__internal__@@!!")) {
+ fuse_dir_reply (req, size, off, fd);
+ return;
+ }
+
+ state = state_from_req (req);
+
+ state->size = size;
+ state->off = off;
+ state->fd = fd;
+
+ FUSE_FOP (state,
+ fuse_getdents_cbk,
+ getdents,
+ fd,
+ size,
+ off,
+ 0);
+}
+
+#endif
+
+static int32_t
+fuse_readdir_cbk (call_frame_t *frame,
+ void *cookie,
+ xlator_t *this,
+ int32_t op_ret,
+ int32_t op_errno,
+ gf_dirent_t *buf)
+{
+ fuse_state_t *state = frame->root->state;
+ fuse_req_t req = state->req;
+
+ if (op_ret >= 0) {
+ gf_log ("glusterfs-fuse", GF_LOG_DEBUG,
+ "%"PRId64": READDIR => %d/%d,%"PRId64, frame->root->unique,
+ op_ret, state->size, state->off);
+
+ fuse_reply_buf (req, (void *)buf, op_ret);
+ } else {
+ gf_log ("glusterfs-fuse", GF_LOG_ERROR,
+ "%"PRId64": READDIR => -1 (%d)", frame->root->unique, op_errno);
+
+ fuse_reply_err (req, op_errno);
+ }
+
+ free_state (state);
+ STACK_DESTROY (frame->root);
+
+ return 0;
+
+}
+
+static void
+fuse_readdir (fuse_req_t req,
+ fuse_ino_t ino,
+ size_t size,
+ off_t off,
+ struct fuse_file_info *fi)
+{
+ fuse_state_t *state;
+
+ state = state_from_req (req);
+ state->size = size;
+ state->off = off;
+
+ gf_log ("glusterfs-fuse", GF_LOG_DEBUG,
+ "%"PRId64": READDIR (%p, size=%d, offset=%"PRId64")",
+ req_callid (req), FI_TO_FD (fi), size, off);
+
+ FUSE_FOP (state,
+ fuse_readdir_cbk,
+ readdir,
+ FI_TO_FD (fi),
+ size,
+ off);
+}
+
+
+static void
+fuse_releasedir (fuse_req_t req,
+ fuse_ino_t ino,
+ struct fuse_file_info *fi)
+{
+ fuse_state_t *state;
+
+ state = state_from_req (req);
+ state->fd = FI_TO_FD (fi);
+
+ LOCK (&state->fd->inode->lock);
+ list_del_init (&state->fd->inode_list);
+ UNLOCK (&state->fd->inode->lock);
+
+ gf_log ("glusterfs-fuse", GF_LOG_DEBUG,
+ "%"PRId64": CLOSEDIR %p", req_callid (req), FI_TO_FD (fi));
+
+ FUSE_FOP (state, fuse_err_cbk, closedir, state->fd);
+}
+
+
+static void
+fuse_fsyncdir (fuse_req_t req,
+ fuse_ino_t ino,
+ int datasync,
+ struct fuse_file_info *fi)
+{
+ fuse_state_t *state;
+
+ state = state_from_req (req);
+
+ FUSE_FOP (state,
+ fuse_err_cbk,
+ fsyncdir,
+ FI_TO_FD (fi),
+ datasync);
+
+ return;
+}
+
+
+static int32_t
+fuse_statfs_cbk (call_frame_t *frame,
+ void *cookie,
+ xlator_t *this,
+ int32_t op_ret,
+ int32_t op_errno,
+ struct statvfs *buf)
+{
+ fuse_state_t *state = frame->root->state;
+ fuse_req_t req = state->req;
+
+ /*
+ Filesystems (like ZFS on solaris) reports
+ different ->f_frsize and ->f_bsize. Old coreutils
+ df tools use statfs() and do not see ->f_frsize.
+ the ->f_blocks, ->f_bavail and ->f_bfree are
+ w.r.t ->f_frsize and not ->f_bsize which makes the
+ df tools report wrong values.
+
+ Scale the block counts to match ->f_bsize.
+ */
+ /* TODO: with old coreutils, f_bsize is taken from stat()'s st_blksize
+ * so the df with old coreutils this wont work :(
+ */
+
+ if (op_ret == 0) {
+
+ buf->f_blocks *= buf->f_frsize;
+ buf->f_blocks /= BIG_FUSE_CHANNEL_SIZE;
+
+ buf->f_bavail *= buf->f_frsize;
+ buf->f_bavail /= BIG_FUSE_CHANNEL_SIZE;
+
+ buf->f_bfree *= buf->f_frsize;
+ buf->f_bfree /= BIG_FUSE_CHANNEL_SIZE;
+
+ buf->f_frsize = buf->f_bsize = BIG_FUSE_CHANNEL_SIZE;
+
+ fuse_reply_statfs (req, buf);
+
+ } else {
+ gf_log ("glusterfs-fuse", GF_LOG_ERROR,
+ "%"PRId64": ERR => -1 (%d)", frame->root->unique, op_errno);
+ fuse_reply_err (req, op_errno);
+ }
+
+ free_state (state);
+ STACK_DESTROY (frame->root);
+
+ return 0;
+}
+
+
+static void
+fuse_statfs (fuse_req_t req,
+ fuse_ino_t ino)
+{
+ fuse_state_t *state;
+
+ state = state_from_req (req);
+ fuse_loc_fill (&state->fuse_loc, state, 1, NULL);
+ if (!state->fuse_loc.loc.inode) {
+ gf_log ("glusterfs-fuse", GF_LOG_ERROR,
+ "%"PRId64": STATFS (fuse_loc_fill() returned NULL inode)", req_callid (req));
+
+ fuse_reply_err (req, EINVAL);
+ return;
+ }
+
+ gf_log ("glusterfs-fuse", GF_LOG_DEBUG,
+ "%"PRId64": STATFS", req_callid (req));
+
+ FUSE_FOP (state,
+ fuse_statfs_cbk,
+ statfs,
+ &state->fuse_loc.loc);
+}
+
+static void
+fuse_setxattr (fuse_req_t req,
+ fuse_ino_t ino,
+ const char *name,
+ const char *value,
+ size_t size,
+ int flags)
+{
+ fuse_state_t *state;
+
+ state = state_from_req (req);
+ state->size = size;
+ fuse_loc_fill (&state->fuse_loc, state, ino, NULL);
+ if (!state->fuse_loc.loc.inode) {
+ gf_log ("glusterfs-fuse", GF_LOG_ERROR,
+ "%"PRId64": SETXATTR %s/%"PRId64" (%s) (fuse_loc_fill() returned NULL inode)",
+ req_callid (req),
+ state->fuse_loc.loc.path, (int64_t)ino, name);
+
+ fuse_reply_err (req, EINVAL);
+ return;
+ }
+
+ state->dict = get_new_dict ();
+
+ dict_set (state->dict, (char *)name,
+ bin_to_data ((void *)value, size));
+ dict_ref (state->dict);
+
+ gf_log ("glusterfs-fuse", GF_LOG_DEBUG,
+ "%"PRId64": SETXATTR %s/%"PRId64" (%s)", req_callid (req),
+ state->fuse_loc.loc.path, (int64_t)ino, name);
+
+ FUSE_FOP (state,
+ fuse_err_cbk,
+ setxattr,
+ &state->fuse_loc.loc,
+ state->dict,
+ flags);
+
+ return;
+}
+
+
+static int32_t
+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 ret = op_ret;
+ char *value = "";
+ fuse_state_t *state = frame->root->state;
+ fuse_req_t req = state->req;
+
+ if (ret >= 0) {
+ gf_log ("glusterfs-fuse", GF_LOG_DEBUG,
+ "%"PRId64": %s => %d", frame->root->unique,
+ state->fuse_loc.loc.path, op_ret);
+
+ /* if successful */
+ if (state->name) {
+ /* if callback for getxattr */
+ data_t *value_data = dict_get (dict, state->name);
+ if (value_data) {
+ ret = value_data->len; /* Don't return the value for '\0' */
+ value = value_data->data;
+
+ if (state->size) {
+ /* if callback for getxattr and asks for value */
+ fuse_reply_buf (req, value, ret);
+ } else {
+ /* if callback for getxattr and asks for value length only */
+ fuse_reply_xattr (req, ret);
+ }
+ } else {
+ fuse_reply_err (req, ENODATA);
+ }
+ } else {
+ /* if callback for listxattr */
+ int32_t len = 0;
+ data_pair_t *trav = dict->members_list;
+ while (trav) {
+ len += strlen (trav->key) + 1;
+ trav = trav->next;
+ }
+ value = alloca (len + 1);
+ ERR_ABORT (value);
+ 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;
+ }
+ if (state->size) {
+ /* if callback for listxattr and asks for list of keys */
+ fuse_reply_buf (req, value, len);
+ } else {
+ /* if callback for listxattr and asks for length of keys only */
+ fuse_reply_xattr (req, len);
+ }
+ }
+ } else {
+ /* if failure - no need to check if listxattr or getxattr */
+ if (op_errno != ENODATA) {
+ gf_log ("glusterfs-fuse", GF_LOG_ERROR,
+ "%"PRId64": %s => -1 (%d)", frame->root->unique,
+ state->fuse_loc.loc.path, op_errno);
+ } else {
+ gf_log ("glusterfs-fuse", GF_LOG_DEBUG,
+ "%"PRId64": %s => -1 (%d)", frame->root->unique,
+ state->fuse_loc.loc.path, op_errno);
+ }
+
+ fuse_reply_err (req, op_errno);
+ }
+
+ free_state (state);
+ STACK_DESTROY (frame->root);
+
+ return 0;
+}
+
+
+static void
+fuse_getxattr (fuse_req_t req,
+ fuse_ino_t ino,
+ const char *name,
+ size_t size)
+{
+ fuse_state_t *state;
+
+ state = state_from_req (req);
+ state->size = size;
+ state->name = strdup (name);
+ fuse_loc_fill (&state->fuse_loc, state, ino, NULL);
+ if (!state->fuse_loc.loc.inode) {
+ gf_log ("glusterfs-fuse", GF_LOG_ERROR,
+ "%"PRId64": GETXATTR %s/%"PRId64" (%s) (fuse_loc_fill() returned NULL inode)",
+ req_callid (req), state->fuse_loc.loc.path, (int64_t)ino, name);
+
+ fuse_reply_err (req, EINVAL);
+ return;
+ }
+
+ gf_log ("glusterfs-fuse", GF_LOG_DEBUG,
+ "%"PRId64": GETXATTR %s/%"PRId64" (%s)", req_callid (req),
+ state->fuse_loc.loc.path, (int64_t)ino, name);
+
+ FUSE_FOP (state,
+ fuse_xattr_cbk,
+ getxattr,
+ &state->fuse_loc.loc);
+
+ return;
+}
+
+
+static void
+fuse_listxattr (fuse_req_t req,
+ fuse_ino_t ino,
+ size_t size)
+{
+ fuse_state_t *state;
+
+ state = state_from_req (req);
+ state->size = size;
+ fuse_loc_fill (&state->fuse_loc, state, ino, NULL);
+ if (!state->fuse_loc.loc.inode) {
+ gf_log ("glusterfs-fuse", GF_LOG_ERROR,
+ "%"PRId64": LISTXATTR %s/%"PRId64" (fuse_loc_fill() returned NULL inode)",
+ req_callid (req), state->fuse_loc.loc.path, (int64_t)ino);
+
+ fuse_reply_err (req, EINVAL);
+ return;
+ }
+
+ gf_log ("glusterfs-fuse", GF_LOG_DEBUG,
+ "%"PRId64": LISTXATTR %s/%"PRId64, req_callid (req),
+ state->fuse_loc.loc.path, (int64_t)ino);
+
+ FUSE_FOP (state,
+ fuse_xattr_cbk,
+ getxattr,
+ &state->fuse_loc.loc);
+
+ return;
+}
+
+
+static void
+fuse_removexattr (fuse_req_t req,
+ fuse_ino_t ino,
+ const char *name)
+
+{
+ fuse_state_t *state;
+
+ state = state_from_req (req);
+ fuse_loc_fill (&state->fuse_loc, state, ino, NULL);
+ if (!state->fuse_loc.loc.inode) {
+ gf_log ("glusterfs-fuse", GF_LOG_ERROR,
+ "%"PRId64": REMOVEXATTR %s/%"PRId64" (%s) (fuse_loc_fill() returned NULL inode)",
+ req_callid (req), state->fuse_loc.loc.path, (int64_t)ino, name);
+
+ fuse_reply_err (req, EINVAL);
+ return;
+ }
+
+ gf_log ("glusterfs-fuse", GF_LOG_DEBUG,
+ "%"PRId64": REMOVEXATTR %s/%"PRId64" (%s)", req_callid (req),
+ state->fuse_loc.loc.path, (int64_t)ino, name);
+
+ FUSE_FOP (state,
+ fuse_err_cbk,
+ removexattr,
+ &state->fuse_loc.loc,
+ name);
+
+ return;
+}
+
+static int32_t
+fuse_getlk_cbk (call_frame_t *frame,
+ void *cookie,
+ xlator_t *this,
+ int32_t op_ret,
+ int32_t op_errno,
+ struct flock *lock)
+{
+ fuse_state_t *state = frame->root->state;
+
+ if (op_ret == 0) {
+ gf_log ("glusterfs-fuse", GF_LOG_DEBUG,
+ "%"PRId64": ERR => 0", frame->root->unique);
+ fuse_reply_lock (state->req, lock);
+ } else {
+ gf_log ("glusterfs-fuse", GF_LOG_ERROR,
+ "%"PRId64": ERR => -1 (%d)", frame->root->unique, op_errno);
+ fuse_reply_err (state->req, op_errno);
+ }
+
+ free_state (state);
+ STACK_DESTROY (frame->root);
+
+ return 0;
+}
+
+static void
+fuse_getlk (fuse_req_t req,
+ fuse_ino_t ino,
+ struct fuse_file_info *fi,
+ struct flock *lock)
+{
+ fuse_state_t *state;
+
+ state = state_from_req (req);
+ state->req = req;
+
+ gf_log ("glusterfs-fuse", GF_LOG_DEBUG,
+ "%"PRId64": GETLK %p", req_callid (req), FI_TO_FD (fi));
+
+ FUSE_FOP (state,
+ fuse_getlk_cbk,
+ lk,
+ FI_TO_FD (fi),
+ F_GETLK,
+ lock);
+
+ return;
+}
+
+static int32_t
+fuse_setlk_cbk (call_frame_t *frame,
+ void *cookie,
+ xlator_t *this,
+ int32_t op_ret,
+ int32_t op_errno,
+ struct flock *lock)
+{
+ fuse_state_t *state = frame->root->state;
+
+ if (op_ret == 0) {
+ gf_log ("glusterfs-fuse", GF_LOG_DEBUG,
+ "%"PRId64": ERR => 0", frame->root->unique);
+ fuse_reply_err (state->req, 0);
+ } else {
+ gf_log ("glusterfs-fuse", GF_LOG_ERROR,
+ "%"PRId64": ERR => -1 (%d)", frame->root->unique, op_errno);
+ fuse_reply_err (state->req, op_errno);
+ }
+
+ free_state (state);
+ STACK_DESTROY (frame->root);
+
+ return 0;
+}
+
+static void
+fuse_setlk (fuse_req_t req,
+ fuse_ino_t ino,
+ struct fuse_file_info *fi,
+ struct flock *lock,
+ int sleep)
+{
+ fuse_state_t *state;
+
+ state = state_from_req (req);
+ state->req = req;
+
+ gf_log ("glusterfs-fuse", GF_LOG_DEBUG,
+ "%"PRId64": SETLK %p (sleep=%d)", req_callid (req), FI_TO_FD (fi),
+ sleep);
+
+ FUSE_FOP (state,
+ fuse_setlk_cbk,
+ lk,
+ FI_TO_FD(fi),
+ (sleep ? F_SETLKW : F_SETLK),
+ lock);
+
+ return;
+}
+
+
+int32_t
+fuse_forget_notify (call_frame_t *frame, xlator_t *this,
+ inode_t *inode)
+{
+ return 0;
+}
+
+struct xlator_fops fuse_xl_fops = {
+ .forget = fuse_forget_notify
+};
+
+static void
+fuse_init (void *data, struct fuse_conn_info *conn)
+{
+ transport_t *trans = data;
+ struct fuse_private *priv = trans->private;
+ xlator_t *xl = trans->xl;
+ int32_t ret;
+
+ xl->name = "fuse";
+ xl->fops = &fuse_xl_fops;
+ xl->itable = inode_table_new (0, xl);
+ xl->notify = default_notify;
+ ret = xlator_tree_init (xl);
+ if (ret == 0) {
+
+ } else {
+ fuse_unmount (priv->mountpoint, priv->ch);
+ exit (1);
+ }
+}
+
+
+static void
+fuse_destroy (void *data)
+{
+
+}
+
+struct fuse_lowlevel_ops fuse_ops = {
+ .init = fuse_init,
+ .destroy = fuse_destroy,
+ .lookup = fuse_lookup,
+ .forget = fuse_forget,
+ .getattr = fuse_getattr,
+ .setattr = fuse_setattr,
+ .opendir = fuse_opendir,
+ .readdir = fuse_readdir,
+ .releasedir = fuse_releasedir,
+ .access = fuse_access,
+ .readlink = fuse_readlink,
+ .mknod = fuse_mknod,
+ .mkdir = fuse_mkdir,
+ .unlink = fuse_unlink,
+ .rmdir = fuse_rmdir,
+ .symlink = fuse_symlink,
+ .rename = fuse_rename,
+ .link = fuse_link,
+ .create = fuse_create,
+ .open = fuse_open,
+ .read = fuse_readv,
+ .write = fuse_write,
+ .flush = fuse_flush,
+ .release = fuse_release,
+ .fsync = fuse_fsync,
+ .fsyncdir = fuse_fsyncdir,
+ .statfs = fuse_statfs,
+ .setxattr = fuse_setxattr,
+ .getxattr = fuse_getxattr,
+ .listxattr = fuse_listxattr,
+ .removexattr = fuse_removexattr,
+ .getlk = fuse_getlk,
+ .setlk = fuse_setlk
+};
+
+
+static int32_t
+fuse_transport_disconnect (transport_t *this)
+{
+ struct fuse_private *priv = this->private;
+
+ gf_log ("glusterfs-fuse",
+ GF_LOG_DEBUG,
+ "cleaning up fuse transport in disconnect handler");
+
+ fuse_session_remove_chan (priv->ch);
+ fuse_session_destroy (priv->se);
+ fuse_unmount (priv->mountpoint, priv->ch);
+
+ FREE (priv);
+ priv = NULL;
+ this->private = NULL;
+
+ /* TODO: need graceful exit. every xlator should be ->fini()'ed
+ and come out of main poll loop cleanly
+ */
+ exit (0);
+
+ return -1;
+}
+
+
+static int32_t
+fuse_transport_init (transport_t *this,
+ dict_t *options,
+ event_notify_fn_t notify)
+{
+ char *mountpoint = strdup (data_to_str (dict_get (options,
+ "mountpoint")));
+ char *source;
+ asprintf (&source, "fsname=glusterfs");
+ char *argv[] = { "glusterfs",
+
+#ifndef GF_DARWIN_HOST_OS
+ "-o", "nonempty",
+#endif
+ "-o", "allow_other",
+ "-o", "default_permissions",
+ "-o", source,
+ "-o", "max_readahead=1048576",
+ "-o", "max_read=1048576",
+ "-o", "max_write=1048576",
+ NULL };
+#ifdef GF_DARWIN_HOST_OS
+ int argc = 13;
+#else
+ int argc = 15;
+#endif
+
+ struct fuse_args args = FUSE_ARGS_INIT(argc,
+ argv);
+ struct fuse_private *priv = NULL;
+ int32_t res;
+
+ priv = CALLOC (1, sizeof (*priv));
+ ERR_ABORT (priv);
+
+
+ this->notify = notify;
+ this->private = (void *)priv;
+
+ priv->ch = fuse_mount (mountpoint, &args);
+ if (!priv->ch) {
+ gf_log ("glusterfs-fuse",
+ GF_LOG_ERROR, "fuse_mount failed (%s)\n", strerror (errno));
+ fuse_opt_free_args(&args);
+ goto err_free;
+ }
+
+ priv->se = fuse_lowlevel_new (&args, &fuse_ops, sizeof (fuse_ops), this);
+ fuse_opt_free_args(&args);
+
+ res = fuse_set_signal_handlers (priv->se);
+ if (res == -1) {
+ gf_log ("glusterfs-fuse", GF_LOG_ERROR, "fuse_set_signal_handlers failed");
+ goto err;
+ }
+
+ fuse_session_add_chan (priv->se, priv->ch);
+
+ priv->fd = fuse_chan_fd (priv->ch);
+ this->buf = data_ref (data_from_dynptr (NULL, 0));
+ this->buf->is_locked = 1;
+
+ priv->mountpoint = mountpoint;
+
+ transport_ref (this);
+ //poll_register (this->xl_private, priv->fd, this);
+
+ return 0;
+
+ err:
+ fuse_unmount (mountpoint, priv->ch);
+ err_free:
+ FREE (mountpoint);
+ mountpoint = NULL;
+ return -1;
+}
+
+void
+guts_log_req (void *, int32_t);
+
+static void *
+fuse_thread_proc (void *data)
+{
+ transport_t *trans = data;
+ struct fuse_private *priv = trans->private;
+ int32_t res = 0;
+ data_t *buf = trans->buf;
+ int32_t ref = 0;
+ size_t chan_size = fuse_chan_bufsize (priv->ch);
+ char *recvbuf = CALLOC (1, chan_size);
+ ERR_ABORT (recvbuf);
+
+ while (!fuse_session_exited (priv->se)) {
+ int32_t fuse_chan_receive (struct fuse_chan * ch,
+ char *buf,
+ int32_t size);
+
+
+ res = fuse_chan_receive (priv->ch,
+ recvbuf,
+ chan_size);
+
+ if (res == -1) {
+ transport_disconnect (trans);
+ }
+
+ buf = trans->buf;
+
+ if (res && res != -1) {
+ if (buf->len < (res)) {
+ if (buf->data) {
+ FREE (buf->data);
+ buf->data = NULL;
+ }
+ buf->data = CALLOC (1, res);
+ ERR_ABORT (buf->data);
+ buf->len = res;
+ }
+ memcpy (buf->data, recvbuf, res); // evil evil
+ guts_log_req (buf->data, res);
+ fuse_session_process (priv->se,
+ buf->data,
+ res,
+ priv->ch);
+ }
+
+ LOCK (&buf->lock);
+ ref = buf->refcount;
+ UNLOCK (&buf->lock);
+ if (1) {
+ data_unref (buf);
+
+ trans->buf = data_ref (data_from_dynptr (NULL, 0));
+ trans->buf->is_locked = 1;
+ }
+ }
+
+ exit (0);
+
+ return NULL;
+}
+
+
+static int32_t
+fuse_transport_notify (xlator_t *xl,
+ int32_t event,
+ void *data,
+ ...)
+{
+ transport_t *trans = data;
+ struct fuse_private *priv = trans->private;
+ int32_t res = 0;
+ data_t *buf;
+ int32_t ref = 0;
+
+ if (event == GF_EVENT_POLLERR) {
+ gf_log ("glusterfs-fuse", GF_LOG_ERROR, "got GF_EVENT_POLLERR");
+ transport_disconnect (trans);
+ return -1;
+ }
+
+ if (event != GF_EVENT_POLLIN) {
+ gf_log ("glusterfs-fuse", GF_LOG_WARNING, "Ignoring notify event %d",
+ event);
+ return 0;
+ }
+
+ if (!fuse_session_exited(priv->se)) {
+ static size_t chan_size = 0;
+
+ int32_t fuse_chan_receive (struct fuse_chan * ch,
+ char *buf,
+ int32_t size);
+ if (!chan_size)
+ chan_size = fuse_chan_bufsize (priv->ch) ;
+
+ buf = trans->buf;
+
+ if (!buf->data) {
+ buf->data = MALLOC (chan_size);
+ ERR_ABORT (buf->data);
+ buf->len = chan_size;
+ }
+
+ res = fuse_chan_receive (priv->ch,
+ buf->data,
+ chan_size);
+ /* if (res == -1) {
+ transport_destroy (trans);
+ */
+ if (res && res != -1) {
+ /* trace the request and log it to tio file */
+ guts_log_req (buf->data, res);
+ fuse_session_process (priv->se,
+ buf->data,
+ res,
+ priv->ch);
+ }
+
+ LOCK (&buf->lock);
+ ref = buf->refcount;
+ UNLOCK (&buf->lock);
+ /* TODO do the check with a lock */
+ if (ref > 1) {
+ data_unref (buf);
+
+ // trans->buf = data_ref (data_from_dynptr (malloc (fuse_chan_bufsize (priv->ch)),
+ trans->buf = data_ref (data_from_dynptr (NULL, 0));
+ trans->buf->data = MALLOC (chan_size);
+ ERR_ABORT (trans->buf->data);
+ trans->buf->len = chan_size;
+ trans->buf->is_locked = 1;
+ }
+ } else {
+ transport_disconnect (trans);
+ }
+
+ /*
+ if (fuse_session_exited (priv->se)) {
+ transport_destroy (trans);
+ res = -1;
+ }*/
+
+ return res >= 0 ? 0 : res;
+}
+
+static void
+fuse_transport_fini (transport_t *this)
+{
+
+}
+
+static struct transport_ops fuse_transport_ops = {
+ .disconnect = fuse_transport_disconnect,
+};
+
+static transport_t fuse_transport = {
+ .ops = &fuse_transport_ops,
+ .private = NULL,
+ .xl = NULL,
+ .init = fuse_transport_init,
+ .fini = fuse_transport_fini,
+ .notify = fuse_transport_notify
+};
+
+
+transport_t *
+glusterfs_mount (glusterfs_ctx_t *ctx,
+ const char *mount_point)
+{
+ dict_t *options = get_new_dict ();
+ transport_t *new_fuse = CALLOC (1, sizeof (*new_fuse));
+ ERR_ABORT (new_fuse);
+
+ memcpy (new_fuse, &fuse_transport, sizeof (*new_fuse));
+ new_fuse->ops = &fuse_transport_ops;
+ new_fuse->xl_private = ctx;
+
+ dict_set (options,
+ "mountpoint",
+ str_to_data ((char *)mount_point));
+
+ return (new_fuse->init (new_fuse,
+ options,
+ fuse_transport_notify) == 0 ? new_fuse : NULL);
+}
+
+int32_t
+fuse_thread (pthread_t *thread, void *data)
+{
+ return pthread_create (thread, NULL, fuse_thread_proc, data);
+}
+
+