summaryrefslogtreecommitdiffstats
path: root/glusterfs-guts
diff options
context:
space:
mode:
Diffstat (limited to 'glusterfs-guts')
-rw-r--r--glusterfs-guts/Makefile.am1
-rw-r--r--glusterfs-guts/src/Makefile.am17
-rw-r--r--glusterfs-guts/src/fuse-bridge.c2724
-rw-r--r--glusterfs-guts/src/fuse-extra.c137
-rw-r--r--glusterfs-guts/src/fuse-extra.h38
-rw-r--r--glusterfs-guts/src/fuse_kernel.h380
-rw-r--r--glusterfs-guts/src/glusterfs-fuse.h58
-rw-r--r--glusterfs-guts/src/glusterfs-guts.c400
-rw-r--r--glusterfs-guts/src/glusterfs-guts.h62
-rw-r--r--glusterfs-guts/src/guts-extra.c18
-rw-r--r--glusterfs-guts/src/guts-lowlevel.h86
-rw-r--r--glusterfs-guts/src/guts-parse.c217
-rw-r--r--glusterfs-guts/src/guts-parse.h140
-rw-r--r--glusterfs-guts/src/guts-replay.c834
-rw-r--r--glusterfs-guts/src/guts-replay.h33
-rw-r--r--glusterfs-guts/src/guts-tables.c248
-rw-r--r--glusterfs-guts/src/guts-tables.h80
-rw-r--r--glusterfs-guts/src/guts-trace.c650
-rw-r--r--glusterfs-guts/src/guts-trace.h54
19 files changed, 6177 insertions, 0 deletions
diff --git a/glusterfs-guts/Makefile.am b/glusterfs-guts/Makefile.am
new file mode 100644
index 000000000..f963effea
--- /dev/null
+++ b/glusterfs-guts/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = src \ No newline at end of file
diff --git a/glusterfs-guts/src/Makefile.am b/glusterfs-guts/src/Makefile.am
new file mode 100644
index 000000000..bb8c7b176
--- /dev/null
+++ b/glusterfs-guts/src/Makefile.am
@@ -0,0 +1,17 @@
+sbin_PROGRAMS = glusterfs-guts
+
+glusterfs_guts_SOURCES = glusterfs-guts.c fuse-bridge.c guts-replay.c guts-trace.c \
+ fuse-extra.c guts-extra.c guts-parse.c guts-tables.c
+
+noinst_HEADERS = fuse_kernel.h fuse-extra.h glusterfs-guts.h glusterfs-fuse.h guts-lowlevel.h \
+ guts-parse.h guts-replay.h guts-tables.h guts-trace.h
+
+glusterfs_guts_LDADD = $(top_builddir)/libglusterfs/src/libglusterfs.la -lfuse
+
+AM_CFLAGS = -fPIC -Wall -pthread
+
+AM_CPPFLAGS = -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -DFUSE_USE_VERSION=26 \
+ -I$(top_srcdir)/libglusterfs/src -DDATADIR=\"$(localstatedir)\" \
+ -DCONFDIR=\"$(sysconfdir)/glusterfs\"
+
+CLEANFILES =
diff --git a/glusterfs-guts/src/fuse-bridge.c b/glusterfs-guts/src/fuse-bridge.c
new file mode 100644
index 000000000..0972563c6
--- /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);
+}
+
+
diff --git a/glusterfs-guts/src/fuse-extra.c b/glusterfs-guts/src/fuse-extra.c
new file mode 100644
index 000000000..93574d174
--- /dev/null
+++ b/glusterfs-guts/src/fuse-extra.c
@@ -0,0 +1,137 @@
+/*
+ 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/>.
+*/
+
+#ifndef _CONFIG_H
+#define _CONFIG_H
+#include "config.h"
+#endif /* _CONFIG_H */
+
+#include "fuse-extra.h"
+#include "common-utils.h"
+#include <stdio.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <string.h>
+#include "common-utils.h"
+
+struct fuse_req;
+struct fuse_ll;
+
+struct fuse_req {
+ struct fuse_ll *f;
+ uint64_t unique;
+ int ctr;
+ pthread_mutex_t lock;
+ struct fuse_ctx ctx;
+ struct fuse_chan *ch;
+ int interrupted;
+ union {
+ struct {
+ uint64_t unique;
+ } i;
+ struct {
+ fuse_interrupt_func_t func;
+ void *data;
+ } ni;
+ } u;
+ struct fuse_req *next;
+ struct fuse_req *prev;
+};
+
+struct fuse_ll {
+ int debug;
+ int allow_root;
+ struct fuse_lowlevel_ops op;
+ int got_init;
+ void *userdata;
+ uid_t owner;
+ struct fuse_conn_info conn;
+ struct fuse_req list;
+ struct fuse_req interrupts;
+ pthread_mutex_t lock;
+ int got_destroy;
+};
+
+struct fuse_out_header {
+ uint32_t len;
+ int32_t error;
+ uint64_t unique;
+};
+
+uint64_t req_callid (fuse_req_t req)
+{
+ return req->unique;
+}
+
+static void destroy_req(fuse_req_t req)
+{
+ pthread_mutex_destroy (&req->lock);
+ FREE (req);
+}
+
+static void list_del_req(struct fuse_req *req)
+{
+ struct fuse_req *prev = req->prev;
+ struct fuse_req *next = req->next;
+ prev->next = next;
+ next->prev = prev;
+}
+
+static void
+free_req (fuse_req_t req)
+{
+ int ctr;
+ struct fuse_ll *f = req->f;
+
+ pthread_mutex_lock(&req->lock);
+ req->u.ni.func = NULL;
+ req->u.ni.data = NULL;
+ pthread_mutex_unlock(&req->lock);
+
+ pthread_mutex_lock(&f->lock);
+ list_del_req(req);
+ ctr = --req->ctr;
+ pthread_mutex_unlock(&f->lock);
+ if (!ctr)
+ destroy_req(req);
+}
+
+int32_t
+fuse_reply_vec (fuse_req_t req,
+ struct iovec *vector,
+ int32_t count)
+{
+ int32_t error = 0;
+ struct fuse_out_header out;
+ struct iovec *iov;
+ int res;
+
+ iov = alloca ((count + 1) * sizeof (*vector));
+ out.unique = req->unique;
+ out.error = error;
+ iov[0].iov_base = &out;
+ iov[0].iov_len = sizeof(struct fuse_out_header);
+ memcpy (&iov[1], vector, count * sizeof (*vector));
+ count++;
+ out.len = iov_length(iov, count);
+ res = fuse_chan_send(req->ch, iov, count);
+ free_req(req);
+
+ return res;
+}
diff --git a/glusterfs-guts/src/fuse-extra.h b/glusterfs-guts/src/fuse-extra.h
new file mode 100644
index 000000000..c7d2877c0
--- /dev/null
+++ b/glusterfs-guts/src/fuse-extra.h
@@ -0,0 +1,38 @@
+/*
+ Copyright (c) 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/>.
+*/
+
+#ifndef _FUSE_EXTRA_H
+#define _FUSE_EXTRA_H
+
+#ifndef _CONFIG_H
+#define _CONFIG_H
+#include "config.h"
+#endif /* _CONFIG_H */
+
+#include <stdlib.h>
+#include <fuse/fuse_lowlevel.h>
+
+uint64_t req_callid (fuse_req_t req);
+
+int32_t
+fuse_reply_vec (fuse_req_t req,
+ struct iovec *vector,
+ int32_t count);
+
+#endif /* _FUSE_EXTRA_H */
diff --git a/glusterfs-guts/src/fuse_kernel.h b/glusterfs-guts/src/fuse_kernel.h
new file mode 100644
index 000000000..7ebff8b22
--- /dev/null
+++ b/glusterfs-guts/src/fuse_kernel.h
@@ -0,0 +1,380 @@
+/*
+ FUSE: Filesystem in Userspace
+ Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
+
+ This program can be distributed under the terms of the GNU GPL.
+ See the file COPYING.
+*/
+
+/* This file defines the kernel interface of FUSE */
+
+#ifdef __FreeBSD__
+/*
+ This -- and only this -- header file may also be distributed under
+ the terms of the BSD Licence as follows:
+
+ Copyright (C) 2001-2006 Miklos Szeredi. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ SUCH DAMAGE.
+*/
+
+#include <sys/types.h>
+#define __u64 uint64_t
+#define __u32 uint32_t
+#define __s32 int32_t
+#else
+#include <asm/types.h>
+#include <linux/major.h>
+#endif
+
+/** Version number of this interface */
+#define FUSE_KERNEL_VERSION 7
+
+/** Minor version number of this interface */
+#define FUSE_KERNEL_MINOR_VERSION 8
+
+/** The node ID of the root inode */
+#define FUSE_ROOT_ID 1
+
+/** The major number of the fuse character device */
+#define FUSE_MAJOR MISC_MAJOR
+
+/** The minor number of the fuse character device */
+#define FUSE_MINOR 229
+
+/* Make sure all structures are padded to 64bit boundary, so 32bit
+ userspace works under 64bit kernels */
+
+struct fuse_attr {
+ __u64 ino;
+ __u64 size;
+ __u64 blocks;
+ __u64 atime;
+ __u64 mtime;
+ __u64 ctime;
+ __u32 atimensec;
+ __u32 mtimensec;
+ __u32 ctimensec;
+ __u32 mode;
+ __u32 nlink;
+ __u32 uid;
+ __u32 gid;
+ __u32 rdev;
+};
+
+struct fuse_kstatfs {
+ __u64 blocks;
+ __u64 bfree;
+ __u64 bavail;
+ __u64 files;
+ __u64 ffree;
+ __u32 bsize;
+ __u32 namelen;
+ __u32 frsize;
+ __u32 padding;
+ __u32 spare[6];
+};
+
+struct fuse_file_lock {
+ __u64 start;
+ __u64 end;
+ __u32 type;
+ __u32 pid; /* tgid */
+};
+
+/**
+ * Bitmasks for fuse_setattr_in.valid
+ */
+#define FATTR_MODE (1 << 0)
+#define FATTR_UID (1 << 1)
+#define FATTR_GID (1 << 2)
+#define FATTR_SIZE (1 << 3)
+#define FATTR_ATIME (1 << 4)
+#define FATTR_MTIME (1 << 5)
+#define FATTR_FH (1 << 6)
+
+/**
+ * Flags returned by the OPEN request
+ *
+ * FOPEN_DIRECT_IO: bypass page cache for this open file
+ * FOPEN_KEEP_CACHE: don't invalidate the data cache on open
+ */
+#define FOPEN_DIRECT_IO (1 << 0)
+#define FOPEN_KEEP_CACHE (1 << 1)
+
+/**
+ * INIT request/reply flags
+ */
+#define FUSE_ASYNC_READ (1 << 0)
+#define FUSE_POSIX_LOCKS (1 << 1)
+
+/**
+ * Release flags
+ */
+#define FUSE_RELEASE_FLUSH (1 << 0)
+
+enum fuse_opcode {
+ FUSE_LOOKUP = 1,
+ FUSE_FORGET = 2, /* no reply */
+ FUSE_GETATTR = 3,
+ FUSE_SETATTR = 4,
+ FUSE_READLINK = 5,
+ FUSE_SYMLINK = 6,
+ FUSE_MKNOD = 8,
+ FUSE_MKDIR = 9,
+ FUSE_UNLINK = 10,
+ FUSE_RMDIR = 11,
+ FUSE_RENAME = 12,
+ FUSE_LINK = 13,
+ FUSE_OPEN = 14,
+ FUSE_READ = 15,
+ FUSE_WRITE = 16,
+ FUSE_STATFS = 17,
+ FUSE_RELEASE = 18,
+ FUSE_FSYNC = 20,
+ FUSE_SETXATTR = 21,
+ FUSE_GETXATTR = 22,
+ FUSE_LISTXATTR = 23,
+ FUSE_REMOVEXATTR = 24,
+ FUSE_FLUSH = 25,
+ FUSE_INIT = 26,
+ FUSE_OPENDIR = 27,
+ FUSE_READDIR = 28,
+ FUSE_RELEASEDIR = 29,
+ FUSE_FSYNCDIR = 30,
+ FUSE_GETLK = 31,
+ FUSE_SETLK = 32,
+ FUSE_SETLKW = 33,
+ FUSE_ACCESS = 34,
+ FUSE_CREATE = 35,
+ FUSE_INTERRUPT = 36,
+ FUSE_BMAP = 37,
+ FUSE_DESTROY = 38,
+};
+
+/* The read buffer is required to be at least 8k, but may be much larger */
+#define FUSE_MIN_READ_BUFFER 8192
+
+struct fuse_entry_out {
+ __u64 nodeid; /* Inode ID */
+ __u64 generation; /* Inode generation: nodeid:gen must
+ be unique for the fs's lifetime */
+ __u64 entry_valid; /* Cache timeout for the name */
+ __u64 attr_valid; /* Cache timeout for the attributes */
+ __u32 entry_valid_nsec;
+ __u32 attr_valid_nsec;
+ struct fuse_attr attr;
+};
+
+struct fuse_forget_in {
+ __u64 nlookup;
+};
+
+struct fuse_attr_out {
+ __u64 attr_valid; /* Cache timeout for the attributes */
+ __u32 attr_valid_nsec;
+ __u32 dummy;
+ struct fuse_attr attr;
+};
+
+struct fuse_mknod_in {
+ __u32 mode;
+ __u32 rdev;
+};
+
+struct fuse_mkdir_in {
+ __u32 mode;
+ __u32 padding;
+};
+
+struct fuse_rename_in {
+ __u64 newdir;
+};
+
+struct fuse_link_in {
+ __u64 oldnodeid;
+};
+
+struct fuse_setattr_in {
+ __u32 valid;
+ __u32 padding;
+ __u64 fh;
+ __u64 size;
+ __u64 unused1;
+ __u64 atime;
+ __u64 mtime;
+ __u64 unused2;
+ __u32 atimensec;
+ __u32 mtimensec;
+ __u32 unused3;
+ __u32 mode;
+ __u32 unused4;
+ __u32 uid;
+ __u32 gid;
+ __u32 unused5;
+};
+
+struct fuse_open_in {
+ __u32 flags;
+ __u32 mode;
+};
+
+struct fuse_open_out {
+ __u64 fh;
+ __u32 open_flags;
+ __u32 padding;
+};
+
+struct fuse_release_in {
+ __u64 fh;
+ __u32 flags;
+ __u32 release_flags;
+ __u64 lock_owner;
+};
+
+struct fuse_flush_in {
+ __u64 fh;
+ __u32 unused;
+ __u32 padding;
+ __u64 lock_owner;
+};
+
+struct fuse_read_in {
+ __u64 fh;
+ __u64 offset;
+ __u32 size;
+ __u32 padding;
+};
+
+struct fuse_write_in {
+ __u64 fh;
+ __u64 offset;
+ __u32 size;
+ __u32 write_flags;
+};
+
+struct fuse_write_out {
+ __u32 size;
+ __u32 padding;
+};
+
+#define FUSE_COMPAT_STATFS_SIZE 48
+
+struct fuse_statfs_out {
+ struct fuse_kstatfs st;
+};
+
+struct fuse_fsync_in {
+ __u64 fh;
+ __u32 fsync_flags;
+ __u32 padding;
+};
+
+struct fuse_setxattr_in {
+ __u32 size;
+ __u32 flags;
+};
+
+struct fuse_getxattr_in {
+ __u32 size;
+ __u32 padding;
+};
+
+struct fuse_getxattr_out {
+ __u32 size;
+ __u32 padding;
+};
+
+struct fuse_lk_in {
+ __u64 fh;
+ __u64 owner;
+ struct fuse_file_lock lk;
+};
+
+struct fuse_lk_out {
+ struct fuse_file_lock lk;
+};
+
+struct fuse_access_in {
+ __u32 mask;
+ __u32 padding;
+};
+
+struct fuse_init_in {
+ __u32 major;
+ __u32 minor;
+ __u32 max_readahead;
+ __u32 flags;
+};
+
+struct fuse_init_out {
+ __u32 major;
+ __u32 minor;
+ __u32 max_readahead;
+ __u32 flags;
+ __u32 unused;
+ __u32 max_write;
+};
+
+struct fuse_interrupt_in {
+ __u64 unique;
+};
+
+struct fuse_bmap_in {
+ __u64 block;
+ __u32 blocksize;
+ __u32 padding;
+};
+
+struct fuse_bmap_out {
+ __u64 block;
+};
+
+struct fuse_in_header {
+ __u32 len;
+ __u32 opcode;
+ __u64 unique;
+ __u64 nodeid;
+ __u32 uid;
+ __u32 gid;
+ __u32 pid;
+ __u32 padding;
+};
+
+struct fuse_out_header {
+ __u32 len;
+ __s32 error;
+ __u64 unique;
+};
+
+struct fuse_dirent {
+ __u64 ino;
+ __u64 off;
+ __u32 namelen;
+ __u32 type;
+ char name[0];
+};
+
+#define FUSE_NAME_OFFSET offsetof(struct fuse_dirent, name)
+#define FUSE_DIRENT_ALIGN(x) (((x) + sizeof(__u64) - 1) & ~(sizeof(__u64) - 1))
+#define FUSE_DIRENT_SIZE(d) \
+ FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET + (d)->namelen)
diff --git a/glusterfs-guts/src/glusterfs-fuse.h b/glusterfs-guts/src/glusterfs-fuse.h
new file mode 100644
index 000000000..f446202fb
--- /dev/null
+++ b/glusterfs-guts/src/glusterfs-fuse.h
@@ -0,0 +1,58 @@
+/*
+ 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/>.
+*/
+
+#ifndef __GLUSTERFS_FUSE_H__
+#define __GLUSTERFS_FUSE_H__
+
+#ifndef _CONFIG_H
+#define _CONFIG_H
+#include "config.h"
+#endif /* _CONFIG_H */
+
+#define DEFAULT_LOG_FILE DATADIR"/log/glusterfs/glusterfs.log"
+#define DEFAULT_GLUSTERFS_CLIENT_VOL CONFDIR "/glusterfs-client.vol"
+
+#define SPEC_LOCAL_FILE 1
+#define SPEC_REMOTE_FILE 2
+
+#if 0
+#define GF_YES 1
+#define GF_NO 0
+#endif
+
+#ifdef GF_LOG_FUSE_ARGS
+#undef GF_LOG_FUSE_ARGS
+#endif
+
+struct gf_spec_location {
+ int32_t where;
+ union {
+ char *file;
+ struct {
+ char *ip;
+ char *port;
+ char *transport;
+ }server;
+ }spec;
+};
+
+transport_t * glusterfs_mount (glusterfs_ctx_t *ctx,
+ const char *mount_point);
+
+#endif /* __GLUSTERFS_FUSE_H__ */
diff --git a/glusterfs-guts/src/glusterfs-guts.c b/glusterfs-guts/src/glusterfs-guts.c
new file mode 100644
index 000000000..3efac3a35
--- /dev/null
+++ b/glusterfs-guts/src/glusterfs-guts.c
@@ -0,0 +1,400 @@
+/*
+ Copyright (c) 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 <stdio.h>
+#include <stdlib.h>
+#include <argp.h>
+#include <string.h>
+
+#include "glusterfs.h"
+#include "xlator.h"
+#include "glusterfs-guts.h"
+
+/* argp initializations */
+static char doc[] = "glusterfs-guts is unit testing suite for glusterfs";
+static char argp_doc[] = "";
+const char *argp_program_version = PACKAGE_NAME " " PACKAGE_VERSION " built on " __DATE__;
+const char *argp_program_bug_address = PACKAGE_BUGREPORT;
+
+guts_ctx_t guts_ctx;
+error_t parse_opts (int32_t key, char *arg, struct argp_state *_state);
+
+static struct argp_option options[] = {
+ {"spec-file", 'f', "VOLUMESPEC-FILE", 0,\
+ "Load VOLUMESPEC-FILE."},
+ {"threads", 't', "NUMBER", 0,\
+ "Load NUMBER of threads."},
+ {"tio-file", 'i', "FILE", 0,\
+ "Replay fops from FILE."},
+ {"tio-directory", 'I', "DIRECTORY", 0,\
+ "Replay fops from files in DIRECTORY. Valid option only when using more than one thread."},
+ {"log-level", 'L', "LOGLEVEL", 0,
+ "LOGLEVEL should be one of DEBUG, WARNING, [ERROR], CRITICAL, NONE"},
+ {"log-file", 'l', "LOGFILE", 0, \
+ "Specify the file to redirect logs"},
+ {"trace", 'T', "MOUNTPOINT", 0, \
+ "Run guts in trace mode. Guts mounts glusterfs on MOUNTPOINT specified"},
+ {"output", 'o', "OUTPUT-TIOFILE", 0, \
+ "Write trace io output to OUTPUT-TIOFILE. Valid only when run in trace(-T) mode."},
+ {"version", 'V', 0, 0,\
+ "print version information"},
+ { 0, }
+};
+
+static struct argp argp = { options, parse_opts, argp_doc, doc };
+
+/* guts_print_version - used by argument parser routine to print version information for guts */
+static int32_t
+guts_print_version (void)
+{
+ printf ("%s\n", argp_program_version);
+ printf ("Copyright (c) 2006, 2007 Z RESEARCH Inc. <http://www.zresearch.com>\n");
+ printf ("GlusterFS comes with ABSOLUTELY NO WARRANTY.\nYou may redistribute copies of GlusterFS under the terms of the GNU General Public License.\n");
+ exit (0);
+}
+
+/* parse_opts - argument parsing helper routine for argp library */
+error_t
+parse_opts (int32_t key, char *arg, struct argp_state *_state)
+{
+ guts_ctx_t *state = _state->input;
+
+ switch (key) {
+ case 'f':
+ if (!state->specfile) {
+ state->specfile = strdup (arg);
+ }
+ break;
+
+ case 't':
+ if (!state->threads) {
+ state->threads = strtol (arg, NULL, 0);
+ }
+ break;
+
+ case 'i':
+ if (state->threads == 1) {
+ state->file = strdup (arg);
+ } else {
+ fprintf (stderr, "glusterfs-guts: -i option is valid only when guts is running single thread\n");
+ exit (1);
+ }
+ break;
+
+ case 'I':
+ if (state->threads > 1) {
+ state->directory = strdup (arg);
+ } else {
+ fprintf (stderr, "glusterfs-guts: -I option is valid only when guts is running multiple threads\n");
+ exit (1);
+ }
+ break;
+
+ case 'L':
+ /* set log level */
+ if (!strncasecmp (arg, "DEBUG", strlen ("DEBUG"))) {
+ state->loglevel = GF_LOG_DEBUG;
+ } else if (!strncasecmp (arg, "WARNING", strlen ("WARNING"))) {
+ state->loglevel = GF_LOG_WARNING;
+ } else if (!strncasecmp (arg, "CRITICAL", strlen ("CRITICAL"))) {
+ state->loglevel = GF_LOG_CRITICAL;
+ } else if (!strncasecmp (arg, "NONE", strlen ("NONE"))) {
+ state->loglevel = GF_LOG_NONE;
+ } else if (!strncasecmp (arg, "ERROR", strlen ("ERROR"))) {
+ state->loglevel = GF_LOG_ERROR;
+ } else {
+ fprintf (stderr, "glusterfs-guts: Unrecognized log-level \"%s\", possible values are \"DEBUG|WARNING|[ERROR]|CRITICAL|NONE\"\n", arg);
+ exit (EXIT_FAILURE);
+ }
+ break;
+ case 'l':
+ /* set log file */
+ state->logfile = strdup (arg);
+ break;
+
+ case 'T':
+ state->trace = 1;
+ state->mountpoint = strdup (arg);
+ break;
+
+ case 'o':
+ state->file = strdup (arg);
+ break;
+
+ case 'V':
+ guts_print_version ();
+ break;
+
+ }
+ return 0;
+}
+
+/* get_xlator_graph - creates a translator graph and returns the pointer to the root of the xlator tree
+ *
+ * @ctx: guts context structure
+ * @conf: file handle to volume specfile
+ *
+ * returns pointer to the root of the translator tree
+ */
+static xlator_t *
+get_xlator_graph (glusterfs_ctx_t *ctx,
+ FILE *conf)
+{
+ xlator_t *tree, *trav = NULL;
+
+ tree = file_to_xlator_tree (ctx, conf);
+ trav = tree;
+
+ if (tree == NULL) {
+ gf_log ("glusterfs-guts",
+ GF_LOG_ERROR,
+ "specification file parsing failed, exiting");
+ return NULL;
+ }
+
+ tree = trav;
+
+ return tree;
+}
+
+/* get_spec_fp - get file handle to volume spec file specified.
+ *
+ * @ctx: guts context structure
+ *
+ * returns FILE pointer to the volume spec file.
+ */
+static FILE *
+get_spec_fp (guts_ctx_t *ctx)
+{
+ char *specfile = ctx->specfile;
+ FILE *conf = NULL;
+
+ specfile = ctx->specfile;
+
+ conf = fopen (specfile, "r");
+
+ if (!conf) {
+ perror (specfile);
+ return NULL;
+ }
+ gf_log ("glusterfs-guts",
+ GF_LOG_DEBUG,
+ "loading spec from %s",
+ specfile);
+
+ return conf;
+}
+
+static void *
+guts_thread_main (void *ctx)
+{
+ guts_thread_ctx_t *tctx = (guts_thread_ctx_t *) ctx;
+
+ printf ("starting thread main with %s:\n", tctx->file);
+ guts_replay (tctx);
+ printf ("ending thread main.\n");
+
+ return NULL;
+}
+
+/* guts_create_threads - creates different threads based on thread number specified in ctx and assigns a
+ * tio file to each thread and attaches each thread to the graph created by main().
+ * @ctx: guts_ctx_t which contains the context corresponding to the current run of guts
+ *
+ * returns the guts_threads_t structure which contains handles to the different threads created.
+ *
+ */
+static guts_threads_t *
+guts_create_threads (guts_ctx_t *ctx)
+{
+ guts_threads_t *threads = NULL;
+ int32_t thread_count = ctx->threads;
+
+ threads = CALLOC (1, sizeof (*threads));
+ ERR_ABORT (threads);
+
+
+ INIT_LIST_HEAD (&(threads->threads));
+
+ if (thread_count == 1) {
+ /* special case: we have only one thread and we are given a tio-file as argument instead of a directory.
+ * handling differently */
+ guts_thread_ctx_t *thread = NULL;
+ thread = CALLOC (1, sizeof (*thread));
+ ERR_ABORT (thread);
+ list_add (&thread->threads, &threads->threads);
+ thread->file = strdup (ctx->file);
+ thread->ctx = ctx;
+ } else {
+ /* look for .tio files in the directory given and assign to each of the threads */
+ DIR *dir = opendir (ctx->directory);
+
+ if (!dir) {
+ gf_log ("guts",
+ GF_LOG_ERROR,
+ "failed to open directory %s", ctx->directory);
+ } else {
+ guts_thread_ctx_t *thread = NULL;
+ struct dirent *dirp = NULL;
+ /* to pass through "." and ".." */
+ readdir (dir);
+ readdir (dir);
+
+ while (thread_count > 0) {
+ char pathname[256] = {0,};
+
+ thread = CALLOC (1, sizeof (*thread));
+ ERR_ABORT (thread);
+ dirp = NULL;
+
+ list_add (&thread->threads, &threads->threads);
+ dirp = readdir (dir);
+ if (dirp) {
+ sprintf (pathname, "%s/%s", ctx->directory, dirp->d_name);
+ printf ("file name for thread(%d) is %s\n", thread_count, pathname);
+ thread->file = strdup (pathname);
+ thread->ctx = ctx;
+ } else if (thread_count > 0) {
+ gf_log ("guts",
+ GF_LOG_ERROR,
+ "number of tio files less than %d, number of threads specified", ctx->threads);
+ /* TODO: cleanup */
+ return NULL;
+ }
+ --thread_count;
+ }
+ }
+ }
+ return threads;
+}
+
+/* guts_start_threads - starts all the threads in @threads.
+ *
+ * @threads: guts_threads_t structure containing the handles to threads created by guts_create_threads.
+ *
+ * returns <0 on error.
+ *
+ */
+static void
+guts_start_threads (guts_threads_t *gthreads)
+{
+ guts_thread_ctx_t *thread = NULL;
+ list_for_each_entry (thread, &gthreads->threads, threads) {
+ if (pthread_create (&thread->pthread, NULL, guts_thread_main, (void *)thread) < 0) {
+ gf_log ("guts",
+ GF_LOG_ERROR,
+ "failed to start thread");
+ } else {
+ gf_log ("guts",
+ GF_LOG_DEBUG,
+ "started thread with file %s", thread->file);
+ }
+ }
+}
+
+static int32_t
+guts_join_threads (guts_threads_t *gthreads)
+{
+ guts_thread_ctx_t *thread = NULL;
+ list_for_each_entry (thread, &gthreads->threads, threads) {
+ if (pthread_join (thread->pthread, NULL) < 0) {
+ gf_log ("guts",
+ GF_LOG_ERROR,
+ "failed to join thread");
+ } else {
+ gf_log ("guts",
+ GF_LOG_DEBUG,
+ "joined thread with file %s", thread->file);
+ }
+ }
+ return 0;
+}
+
+
+int32_t
+main (int32_t argc, char *argv[])
+{
+ /* glusterfs_ctx_t is required to be passed to
+ * 1. get_xlator_graph
+ * 2. glusterfs_mount
+ */
+ glusterfs_ctx_t gfs_ctx = {
+ .logfile = DATADIR "/log/glusterfs/glusterfs-guts.log",
+ .loglevel = GF_LOG_DEBUG,
+ .poll_type = SYS_POLL_TYPE_EPOLL,
+ };
+
+ guts_ctx_t guts_ctx = {0,};
+ FILE *specfp = NULL;
+ xlator_t *graph = NULL;
+ guts_threads_t *threads = NULL;
+
+ argp_parse (&argp, argc, argv, 0, 0, &guts_ctx);
+
+ if (gf_log_init (gfs_ctx.logfile) == -1 ) {
+ fprintf (stderr,
+ "glusterfs-guts: failed to open logfile \"%s\"\n",
+ gfs_ctx.logfile);
+ return -1;
+ }
+ gf_log_set_loglevel (gfs_ctx.loglevel);
+
+ specfp = get_spec_fp (&guts_ctx);
+ if (!specfp) {
+ fprintf (stderr,
+ "glusterfs-guts: could not open specfile\n");
+ return -1;
+ }
+
+ graph = get_xlator_graph (&gfs_ctx, specfp);
+ if (!graph) {
+ gf_log ("guts", GF_LOG_ERROR,
+ "Unable to get xlator graph");
+ return -1;
+ }
+ fclose (specfp);
+
+ guts_ctx.graph = graph;
+
+ if (guts_ctx.trace) {
+ return guts_trace (&guts_ctx);
+ } else {
+ /* now that we have the xlator graph, we need to create as many threads as requested and assign a tio file
+ * to each of the threads and tell each thread to attach to the graph we just created. */
+
+ if (!guts_ctx.file && !guts_ctx.directory) {
+ fprintf (stderr,
+ "glusterfs-guts: no tio file specified");
+ return -1;
+ }
+
+ threads = guts_create_threads (&guts_ctx);
+
+ if (threads) {
+ guts_start_threads (threads);
+ guts_join_threads (threads);
+ } else {
+ gf_log ("guts", GF_LOG_ERROR,
+ "unable to create threads");
+ return 0;
+ }
+ }
+
+ return 0;
+}
+
diff --git a/glusterfs-guts/src/glusterfs-guts.h b/glusterfs-guts/src/glusterfs-guts.h
new file mode 100644
index 000000000..eda1788a9
--- /dev/null
+++ b/glusterfs-guts/src/glusterfs-guts.h
@@ -0,0 +1,62 @@
+/*
+ Copyright (c) 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/>.
+*/
+
+#ifndef __GLUSTERFS_GUTS_H
+#define __GLUSTERFS_GUTS_H
+
+#include "xlator.h"
+#include "transport.h"
+#include "glusterfs.h"
+#include "glusterfs-fuse.h"
+#include "timer.h"
+
+#ifdef DEFAULT_LOG_FILE
+#undef DEFAULT_LOG_FILE
+#endif
+
+#define DEFAULT_LOG_FILE DATADIR"/log/glusterfs/glusterfs-guts.log"
+
+
+typedef struct {
+ int32_t threads; /* number of threads to start in replay mode */
+ char *logfile; /* logfile path */
+ int32_t loglevel; /* logging level */
+ char *directory; /* path to directory containing tio files, when threads > 1 */
+ char *file; /* path to tio file, when threads == 1 during replay. in trace mode, path to tio output */
+ char *specfile; /* path to specfile to load translator tree */
+ xlator_t *graph; /* translator tree after the specfile is loaded */
+ int32_t trace; /* if trace == 1, glusterfs-guts runs in trace mode, otherwise in replay mode */
+ char *mountpoint; /* valid only when trace == 1, mounpoint to mount glusterfs */
+} guts_ctx_t;
+
+
+typedef struct {
+ struct list_head threads;
+ pthread_t pthread;
+ xlator_t *tree;
+ char *file;
+ guts_ctx_t *ctx;
+} guts_thread_ctx_t;
+
+typedef struct {
+ struct list_head threads;
+} guts_threads_t;
+
+int32_t guts_replay (guts_thread_ctx_t *);
+int32_t guts_trace (guts_ctx_t *);
+#endif
diff --git a/glusterfs-guts/src/guts-extra.c b/glusterfs-guts/src/guts-extra.c
new file mode 100644
index 000000000..dd4ad466f
--- /dev/null
+++ b/glusterfs-guts/src/guts-extra.c
@@ -0,0 +1,18 @@
+/*
+ Copyright (c) 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/>.
+*/
diff --git a/glusterfs-guts/src/guts-lowlevel.h b/glusterfs-guts/src/guts-lowlevel.h
new file mode 100644
index 000000000..498b5d01e
--- /dev/null
+++ b/glusterfs-guts/src/guts-lowlevel.h
@@ -0,0 +1,86 @@
+/*
+ Copyright (c) 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/>.
+*/
+
+#ifndef _GUTS_LOWLEVEL_H_
+#define _GUTS_LOWLEVEL_H_
+
+int
+guts_reply_err (fuse_req_t req,
+ int err);
+
+int
+guts_reply_none (fuse_req_t req);
+
+int
+guts_reply_entry (fuse_req_t req,
+ const struct fuse_entry_param *e);
+
+int
+guts_reply_create (fuse_req_t req,
+ const struct fuse_entry_param *e,
+ const struct fuse_file_info *f);
+
+int
+guts_reply_attr (fuse_req_t req,
+ const struct stat *attr,
+ double attr_timeout);
+
+int
+guts_reply_readlink (fuse_req_t req,
+ const char *linkname);
+
+int
+guts_reply_open (fuse_req_t req,
+ const struct fuse_file_info *f);
+
+int
+guts_reply_write (fuse_req_t req,
+ size_t count);
+
+int
+guts_reply_buf (fuse_req_t req,
+ const char *buf,
+ size_t size);
+
+int
+guts_reply_statfs (fuse_req_t req,
+ const struct statvfs *stbuf);
+
+int
+guts_reply_xattr (fuse_req_t req,
+ size_t count);
+
+int
+guts_reply_lock (fuse_req_t req,
+ struct flock *lock);
+
+/* exploiting the macros to reduce coding work ;) */
+#define fuse_reply_entry guts_reply_entry
+#define fuse_reply_err guts_reply_err
+#define fuse_reply_none guts_reply_none
+#define fuse_reply_attr guts_reply_attr
+#define fuse_reply_open guts_reply_open
+#define fuse_reply_readlink guts_reply_readlink
+#define fuse_reply_create guts_reply_create
+#define fuse_reply_write guts_reply_write
+#define fuse_reply_buf guts_reply_buf
+#define fuse_reply_statfs guts_reply_statfs
+#define fuse_reply_xattr guts_reply_xattr
+#define fuse_reply_lock guts_reply_lock
+
+#endif
diff --git a/glusterfs-guts/src/guts-parse.c b/glusterfs-guts/src/guts-parse.c
new file mode 100644
index 000000000..dd17a737e
--- /dev/null
+++ b/glusterfs-guts/src/guts-parse.c
@@ -0,0 +1,217 @@
+/*
+ Copyright (c) 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 "guts-parse.h"
+#include "guts-tables.h"
+
+/* unavoidable usage of global data.. :'( */
+static int32_t tio_fd = 0;
+
+int32_t
+guts_tio_init (const char *filename)
+{
+ tio_fd = open (filename, O_WRONLY | O_CREAT);
+
+ if (tio_fd < 0) {
+ gf_log ("guts",
+ GF_LOG_ERROR,
+ "failed to open tio file %s", filename);
+ }
+
+ return tio_fd;
+}
+
+void
+guts_reply_dump (fuse_req_t req,
+ const void *arg,
+ int32_t len)
+{
+ uint8_t *buf = NULL;
+ uint8_t *ibuf = NULL;
+ uint32_t buf_size = REP_HEADER_FULL_LEN + len;
+
+ ibuf = buf = CALLOC (1, buf_size);
+
+ /* being paranoid, checking for both ibuf and buf.. ;) */
+ if (ibuf && buf) {
+ memcpy (ibuf, REP_BEGIN, strlen (REP_BEGIN));
+ ibuf += strlen (REP_BEGIN);
+ memcpy (ibuf, req, sizeof (struct fuse_req));
+ ibuf += sizeof (struct fuse_req);
+ memcpy (ibuf, &len, sizeof (len));
+ ibuf += sizeof (len);
+ memcpy (ibuf, arg, len);
+
+ gf_full_write (tio_fd, buf, buf_size);
+
+ free (buf);
+ } else {
+ gf_log ("glusterfs-guts", GF_LOG_DEBUG,
+ "failed to allocate memory while dumping reply");
+ }
+}
+
+void
+guts_req_dump (struct fuse_in_header *in,
+ const void *arg,
+ int32_t len)
+{
+ /* GUTS_REQUEST_BEGIN:<fuse_in_header>:<arg-len>:<args>:GUTS_REQUEST_END */
+ uint8_t *buf = NULL;
+ uint8_t *ibuf = NULL;
+ uint32_t buf_size = REQ_HEADER_FULL_LEN + len;
+
+ ibuf = buf = CALLOC (1, buf_size);
+
+ if (ibuf && buf) {
+ memcpy (ibuf, REQ_BEGIN, strlen (REQ_BEGIN));
+ ibuf += strlen (REQ_BEGIN);
+ memcpy (ibuf, in, sizeof (*in));
+ ibuf += sizeof (*in);
+ memcpy (ibuf, &len, sizeof (len));
+ ibuf += sizeof (len);
+ memcpy (ibuf, arg, len);
+
+ gf_full_write (tio_fd, buf, buf_size);
+
+ free (buf);
+ } else {
+ gf_log ("glusterfs-guts", GF_LOG_DEBUG,
+ "failed to allocate memory while dumping reply");
+ }
+}
+
+
+
+guts_req_t *
+guts_read_entry (guts_replay_ctx_t *ctx)
+{
+ guts_req_t *req = NULL;
+ guts_reply_t *reply = NULL;
+ uint8_t begin[256] = {0,};
+ int32_t ret = 0;
+ int32_t fd = ctx->tio_fd;
+
+ while (!req) {
+ req = guts_get_request (ctx);
+
+ if (!req) {
+ ret = read (fd, begin, strlen (REQ_BEGIN));
+
+ if (ret == 0) {
+ gf_log ("glusterfs-guts", GF_LOG_DEBUG,
+ "guts replay finished");
+ req = NULL;
+ }
+
+ if (is_request (begin)) {
+ req = CALLOC (1, sizeof (*req));
+ ERR_ABORT (req);
+ gf_full_read (fd, (char *)req, REQ_HEADER_LEN);
+
+ req->arg = CALLOC (1, req->arg_len + 1);
+ ERR_ABORT (req->arg);
+ gf_full_read (fd, req->arg, req->arg_len);
+ gf_log ("guts",
+ GF_LOG_DEBUG,
+ "%s: fop %s (%d)\n",
+ begin, guts_log[req->header.opcode].name, req->header.opcode);
+ guts_add_request (ctx, req);
+ req = guts_get_request (ctx);
+ } else {
+ /* whenever a reply is read, we put it to a hash table and we would like to retrieve it whenever
+ * we get a reply for any call
+ */
+ reply = CALLOC (1, sizeof (*reply));
+ ERR_ABORT (reply);
+ gf_full_read (fd, (char *)reply, REP_HEADER_LEN);
+
+ reply->arg = CALLOC (1, reply->arg_len + 1);
+ ERR_ABORT (reply->arg);
+ gf_full_read (fd, reply->arg, reply->arg_len);
+
+ /* add a new reply to */
+ ret = guts_add_reply (ctx, reply);
+ gf_log ("guts",
+ GF_LOG_DEBUG,
+ "got a reply with unique: %ld", reply->req.unique);
+ }
+ }
+ }
+ return req;
+}
+
+guts_reply_t *
+guts_read_reply (guts_replay_ctx_t *ctx,
+ uint64_t unique)
+{
+ guts_req_t *req = NULL;
+ guts_reply_t *reply = NULL, *rep = NULL;
+ uint8_t begin[256] = {0,};
+ int32_t ret = 0;
+ int32_t fd = ctx->tio_fd;
+
+ while (!rep) {
+
+ ret = read (fd, begin, strlen (REQ_BEGIN));
+
+ if (ret == 0) {
+ printf ("\ndone\n");
+ return NULL;
+ }
+
+ if (is_request (begin)) {
+ req = CALLOC (1, sizeof (*req));
+ ERR_ABORT (req);
+ gf_full_read (fd, (char *)req, REQ_HEADER_LEN);
+
+ req->arg = CALLOC (1, req->arg_len + 1);
+ ERR_ABORT (req->arg);
+ gf_full_read (fd, req->arg, req->arg_len);
+ gf_log ("guts",
+ GF_LOG_DEBUG,
+ "%s: fop %s (%d)\n",
+ begin, guts_log[req->header.opcode].name, req->header.opcode);
+
+ ret = guts_add_request (ctx, req);
+
+ } else {
+ /* whenever a reply is read, we put it to a hash table and we would like to retrieve it whenever
+ * we get a reply for any call
+ */
+ reply = CALLOC (1, sizeof (*reply));
+ ERR_ABORT (reply);
+ gf_full_read (fd, (char *)reply, REP_HEADER_LEN);
+
+ reply->arg = CALLOC (1, reply->arg_len + 1);
+ ERR_ABORT (reply->arg);
+ gf_full_read (fd, reply->arg, reply->arg_len);
+
+ /* add a new reply to */
+ if (reply->req.unique == unique) {
+ return reply;
+ } else {
+ ret = guts_add_reply (ctx, reply);
+ gf_log ("guts",
+ GF_LOG_DEBUG,
+ "got a reply with unique: %ld", reply->req.unique);
+ }
+ }
+ }
+ return NULL;
+}
diff --git a/glusterfs-guts/src/guts-parse.h b/glusterfs-guts/src/guts-parse.h
new file mode 100644
index 000000000..7791b1215
--- /dev/null
+++ b/glusterfs-guts/src/guts-parse.h
@@ -0,0 +1,140 @@
+/*
+ Copyright (c) 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/>.
+*/
+
+#ifndef _GUTS_PARSE_H_
+#define _GUTS_PARSE_H_
+
+#include "glusterfs.h"
+#include "glusterfs-guts.h"
+#include "fuse_kernel.h"
+#include <fuse/fuse_lowlevel.h>
+#include "list.h"
+
+#ifndef _FUSE_OPAQUE_
+#define _FUSE_OPAQUE_
+
+struct fuse_private {
+ int fd;
+ struct fuse *fuse;
+ struct fuse_session *se;
+ struct fuse_chan *ch;
+ char *mountpoint;
+};
+
+struct fuse_req {
+ struct fuse_ll *f;
+ uint64_t unique;
+ int ctr;
+ pthread_mutex_t lock;
+ struct fuse_ctx ctx;
+ struct fuse_chan *ch;
+ int interrupted;
+ union {
+ struct {
+ uint64_t unique;
+ } i;
+ struct {
+ fuse_interrupt_func_t func;
+ void *data;
+ } ni;
+ } u;
+ struct fuse_req *next;
+ struct fuse_req *prev;
+};
+
+struct fuse_ll {
+ int debug;
+ int allow_root;
+ struct fuse_lowlevel_ops op;
+ int got_init;
+ void *userdata;
+ uid_t owner;
+ struct fuse_conn_info conn;
+ struct fuse_req list;
+ struct fuse_req interrupts;
+ pthread_mutex_t lock;
+ int got_destroy;
+};
+#endif
+
+#define REQ_BEGIN "GUTS_REQ_BEGIN:"
+#define REQ_HEADER_FULL_LEN (strlen(REQ_BEGIN) + sizeof (struct fuse_in_header) + sizeof (int32_t))
+
+#define REP_BEGIN "GUTS_REP_BEGIN:"
+#define REP_HEADER_FULL_LEN (strlen(REP_BEGIN) + sizeof (struct fuse_req) + sizeof (int32_t))
+
+#define REQ_HEADER_LEN (sizeof (struct fuse_in_header) + sizeof (int32_t))
+#define REP_HEADER_LEN (sizeof (struct fuse_req) + sizeof (int32_t))
+
+#define is_request(begin) (0==strcmp(begin, REQ_BEGIN)?1:0)
+
+typedef void (*func_t)(struct fuse_in_header *, const void *);
+
+typedef struct {
+ func_t func;
+ const char *name;
+} guts_log_t;
+
+typedef struct {
+ struct fuse_in_header header;
+ int32_t arg_len;
+ struct list_head list;
+ void *arg;
+} guts_req_t;
+
+typedef struct {
+ struct fuse_req req;
+ int32_t arg_len;
+ void *arg;
+} guts_reply_t;
+
+struct guts_replay_ctx {
+ int32_t tio_fd;
+ struct fuse_ll *guts_ll;
+ dict_t *replies;
+ dict_t *inodes;
+ dict_t *fds;
+ struct list_head requests;
+ dict_t *requests_dict;
+};
+
+typedef struct guts_replay_ctx guts_replay_ctx_t;
+
+extern guts_log_t guts_log[];
+
+int32_t
+guts_tio_init (const char *);
+
+void
+guts_req_dump (struct fuse_in_header *,
+ const void *,
+ int32_t);
+
+guts_req_t *
+guts_read_entry (guts_replay_ctx_t *ctx);
+
+void
+guts_reply_dump (fuse_req_t,
+ const void *,
+ int32_t);
+
+guts_reply_t *
+guts_read_reply (guts_replay_ctx_t *ctx,
+ uint64_t unique);
+
+#endif /* _GUTS_PARSE_H_ */
diff --git a/glusterfs-guts/src/guts-replay.c b/glusterfs-guts/src/guts-replay.c
new file mode 100644
index 000000000..a5447464d
--- /dev/null
+++ b/glusterfs-guts/src/guts-replay.c
@@ -0,0 +1,834 @@
+/*
+ Copyright (c) 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 "glusterfs-guts.h"
+#include "guts-parse.h"
+#include <signal.h>
+#include "guts-tables.h"
+#include "guts-replay.h"
+#include "guts-trace.h"
+
+static void
+convert_attr (const struct fuse_setattr_in *attr,
+ struct stat *stbuf)
+{
+ stbuf->st_mode = attr->mode;
+ stbuf->st_uid = attr->uid;
+ stbuf->st_gid = attr->gid;
+ stbuf->st_size = attr->size;
+ stbuf->st_atime = attr->atime;
+ /*
+ ST_ATIM_NSEC_SET (stbuf, attr->atimensec);
+ ST_MTIM_NSEC_SET (stbuf, attr->mtimensec);*/
+}
+
+static void
+guts_replay_lookup (fuse_req_t req,
+ fuse_ino_t ino,
+ const void *inargs)
+{
+ char *name = (char *) inargs;
+
+ if (req->f->op.lookup)
+ req->f->op.lookup(req, ino, name);
+ else
+ guts_reply_err (req, ENOSYS);
+
+}
+
+static void
+guts_replay_forget (fuse_req_t req,
+ fuse_ino_t ino,
+ const void *inargs)
+{
+ struct fuse_forget_in *arg = (struct fuse_forget_in *) inargs;
+
+ if (req->f->op.forget)
+ req->f->op.forget (req, ino, arg->nlookup);
+
+}
+
+static void
+guts_replay_getattr (fuse_req_t req,
+ fuse_ino_t ino,
+ const void *inargs)
+{
+ (void) inargs;
+
+ if (req->f->op.getattr)
+ req->f->op.getattr (req, ino, NULL);
+ else
+ guts_reply_err (req, ENOSYS);
+}
+
+static void
+guts_replay_setattr (fuse_req_t req,
+ fuse_ino_t ino,
+ const void *inargs)
+{
+ struct fuse_setattr_in *arg = (struct fuse_setattr_in *)inargs;
+
+ if (req->f->op.setattr) {
+ struct fuse_file_info *fi = NULL;
+ struct fuse_file_info fi_store;
+ struct stat stbuf;
+ memset (&stbuf, 0, sizeof (stbuf));
+ convert_attr (arg, &stbuf);
+ if (arg->valid & FATTR_FH) {
+ arg->valid &= ~FATTR_FH;
+ memset (&fi_store, 0, sizeof (fi_store));
+ fi = &fi_store;
+ fi->fh = arg->fh;
+ fi->fh_old = fi->fh;
+ }
+ req->f->op.setattr (req, ino, &stbuf, arg->valid, fi);
+ } else
+ guts_reply_err (req, ENOSYS);
+}
+
+static void
+guts_replay_access (fuse_req_t req,
+ fuse_ino_t ino,
+ const void *inargs)
+{
+ struct fuse_access_in *arg = (struct fuse_access_in *)inargs;
+
+ if (req->f->op.access)
+ req->f->op.access (req, ino, arg->mask);
+ else
+ guts_reply_err (req, ENOSYS);
+}
+
+static void
+guts_replay_readlink (fuse_req_t req,
+ fuse_ino_t ino,
+ const void *inargs)
+{
+ (void) inargs;
+
+ if (req->f->op.readlink)
+ req->f->op.readlink (req, ino);
+ else
+ guts_reply_err (req, ENOSYS);
+}
+
+
+static void
+guts_replay_mknod (fuse_req_t req,
+ fuse_ino_t ino,
+ const void *inargs)
+{
+ struct fuse_mknod_in *arg = (struct fuse_mknod_in *) inargs;
+
+ if (req->f->op.mknod)
+ req->f->op.mknod (req, ino, PARAM(arg), arg->mode, arg->rdev);
+ else
+ guts_reply_err (req, ENOSYS);
+}
+
+static void
+guts_replay_mkdir (fuse_req_t req,
+ fuse_ino_t ino,
+ const void *inargs)
+{
+ struct fuse_mkdir_in *arg = (struct fuse_mkdir_in *) inargs;
+
+ if (req->f->op.mkdir)
+ req->f->op.mkdir (req, ino, PARAM(arg), arg->mode);
+ else
+ guts_reply_err (req, ENOSYS);
+}
+
+static void
+guts_replay_unlink (fuse_req_t req,
+ fuse_ino_t ino,
+ const void *inargs)
+{
+ char *name = (char *)inargs;
+
+ if (req->f->op.unlink) {
+
+ req->f->op.unlink (req, ino, name);
+ } else
+ guts_reply_err (req, ENOSYS);
+}
+
+static void
+guts_replay_rmdir (fuse_req_t req,
+ fuse_ino_t ino,
+ const void *inargs)
+{
+ char *name = (char *)inargs;
+
+ if (req->f->op.rmdir) {
+ req->f->op.rmdir (req, ino, name);
+ } else
+ guts_reply_err (req, ENOSYS);
+}
+
+static void
+guts_replay_symlink (fuse_req_t req,
+ fuse_ino_t ino,
+ const void *inargs)
+{
+ char *name = (char *) inargs;
+ char *linkname = ((char *) inargs) + strlen ((char *) inargs) + 1;
+
+ if (req->f->op.symlink) {
+ req->f->op.symlink (req, linkname, ino, name);
+ } else
+ guts_reply_err (req, ENOSYS);
+}
+
+
+
+static void
+guts_replay_rename (fuse_req_t req,
+ fuse_ino_t ino,
+ const void *inargs)
+{
+ struct fuse_rename_in *arg = (struct fuse_rename_in *) inargs;
+ char *oldname = PARAM(arg);
+ char *newname = oldname + strlen (oldname) + 1;
+
+ if (req->f->op.rename) {
+ req->f->op.rename (req, ino, oldname, arg->newdir, newname);
+ } else
+ guts_reply_err (req, ENOSYS);
+
+}
+
+static void
+guts_replay_link (fuse_req_t req,
+ fuse_ino_t ino,
+ const void *inargs)
+{
+ struct fuse_link_in *arg = (struct fuse_link_in *) inargs;
+
+ if (req->f->op.link) {
+ guts_replay_ctx_t *ctx = (guts_replay_ctx_t *) req->u.ni.data;
+ fuse_ino_t old_ino = guts_inode_search (ctx, arg->oldnodeid);
+
+ req->f->op.link (req, old_ino, ino, PARAM(arg));
+ } else
+ guts_reply_err (req, ENOSYS);
+}
+
+
+static void
+guts_replay_create (fuse_req_t req,
+ fuse_ino_t ino,
+ const void *inargs)
+{
+ struct guts_create_in *arg = (struct guts_create_in *) inargs;
+
+ if (req->f->op.create) {
+ struct fuse_file_info fi;
+ memset (&fi, 0, sizeof (fi));
+ fi.flags = arg->open_in.flags;
+
+ req->f->op.create (req, ino, arg->name, arg->open_in.mode, &fi);
+ } else
+ guts_reply_err (req, ENOSYS);
+
+}
+
+static void
+guts_replay_open (fuse_req_t req,
+ fuse_ino_t ino,
+ const void *inargs)
+{
+ struct fuse_open_in *arg = (struct fuse_open_in *) inargs;
+ struct fuse_file_info fi;
+
+ memset (&fi, 0, sizeof (fi));
+ fi.flags = arg->flags;
+
+ if (req->f->op.open) {
+ /* TODO: how efficient is using dict_get here?? */
+ req->f->op.open (req, ino, &fi);
+ } else
+ guts_reply_open (req, &fi);
+}
+
+
+static void
+guts_replay_read(fuse_req_t req,
+ fuse_ino_t ino,
+ const void *inarg)
+{
+ struct fuse_read_in *arg = (struct fuse_read_in *) inarg;
+
+ if (req->f->op.read){
+ struct fuse_file_info fi;
+ guts_replay_ctx_t *ctx = req->u.ni.data;
+
+ memset (&fi, 0, sizeof (fi));
+ /* TODO: how efficient is using dict_get here?? */
+ fi.fh = (unsigned long) guts_fd_search (ctx, arg->fh);
+ if (!fi.fh) {
+ /* TODO: make it more meaningful and organized */
+ printf ("readv called without opening the file\n");
+ guts_reply_err (req, EBADFD);
+ } else {
+ fi.fh_old = fi.fh;
+ req->f->op.read (req, ino, arg->size, arg->offset, &fi);
+ }
+ } else
+ guts_reply_err (req, ENOSYS);
+}
+
+static void
+guts_replay_write(fuse_req_t req,
+ fuse_ino_t ino,
+ const void *inarg)
+{
+ struct fuse_write_in *arg = (struct fuse_write_in *) inarg;
+ struct fuse_file_info fi;
+ guts_replay_ctx_t *ctx = (guts_replay_ctx_t *) req->u.ni.data;
+
+ memset (&fi, 0, sizeof (fi));
+ fi.fh = (unsigned long) guts_fd_search (ctx, arg->fh);
+
+ if (!fi.fh) {
+ /* TODO: make it more meaningful and organized */
+ printf ("writev called without opening the file\n");
+ guts_reply_err (req, EBADFD);
+ } else {
+ fi.fh_old = fi.fh;
+ fi.writepage = arg->write_flags & 1;
+ if (req->f->op.write)
+ req->f->op.write (req, ino, PARAM(arg), arg->size, arg->offset, &fi);
+ else
+ guts_reply_err (req, ENOSYS);
+ }
+}
+
+static void
+guts_replay_flush(fuse_req_t req,
+ fuse_ino_t ino,
+ const void *inarg)
+{
+ struct fuse_flush_in *arg = (struct fuse_flush_in *) inarg;
+ struct fuse_file_info fi;
+ guts_replay_ctx_t *ctx = (guts_replay_ctx_t *) req->u.ni.data;
+
+ memset (&fi, 0, sizeof (fi));
+ fi.fh = (unsigned long) guts_fd_search (ctx, arg->fh);
+ if (!fi.fh) {
+ printf ("flush called without calling open\n");
+ guts_reply_err (req, EBADFD);
+ } else {
+ fi.fh_old = fi.fh;
+ fi.flush = 1;
+
+ if (req->f->conn.proto_minor >= 7)
+ fi.lock_owner = arg->lock_owner;
+
+ if (req->f->op.flush)
+ req->f->op.flush (req, ino, &fi);
+ else
+ guts_reply_err (req, ENOSYS);
+ }
+}
+
+static void
+guts_replay_release(fuse_req_t req,
+ fuse_ino_t ino,
+ const void *inarg)
+{
+ struct fuse_release_in *arg = (struct fuse_release_in *) inarg;
+ struct fuse_file_info fi;
+ guts_replay_ctx_t *ctx = (guts_replay_ctx_t *) req->u.ni.data;
+
+ memset (&fi, 0, sizeof (fi));
+ fi.flags = arg->flags;
+ fi.fh = (unsigned long) guts_fd_search (ctx, arg->fh);
+
+ if (!fi.fh) {
+ printf ("release called without calling open\n");
+ guts_reply_err (req, EBADFD);
+ } else {
+ fi.fh_old = fi.fh;
+ if (req->f->conn.proto_minor >= 8) {
+ fi.flush = (arg->release_flags & FUSE_RELEASE_FLUSH) ? 1 : 0;
+ fi.lock_owner = arg->lock_owner;
+ }
+ if (req->f->op.release)
+ req->f->op.release (req, ino, &fi);
+ else
+ guts_reply_err (req, ENOSYS);
+ }
+}
+
+static void
+guts_replay_fsync(fuse_req_t req,
+ fuse_ino_t ino,
+ const void *inarg)
+{
+ struct fuse_fsync_in *arg = (struct fuse_fsync_in *) inarg;
+ struct fuse_file_info fi;
+ guts_replay_ctx_t *ctx = (guts_replay_ctx_t *) req->u.ni.data;
+
+ memset (&fi, 0, sizeof (fi));
+ fi.fh = (unsigned long) guts_fd_search (ctx, arg->fh);
+ fi.fh_old = fi.fh;
+
+ if (req->f->op.fsync)
+ req->f->op.fsync (req, ino, arg->fsync_flags & 1, &fi);
+ else
+ guts_reply_err (req, ENOSYS);
+}
+
+static void
+guts_replay_opendir (fuse_req_t req,
+ fuse_ino_t ino,
+ const void *inarg)
+{
+ struct fuse_open_in *arg = (struct fuse_open_in *) inarg;
+ struct fuse_file_info fi;
+
+ memset (&fi, 0, sizeof (fi));
+ fi.flags = arg->flags;
+
+ if (req->f->op.opendir) {
+ req->f->op.opendir (req, ino, &fi);
+ } else
+ guts_reply_open (req, &fi);
+}
+
+static void
+guts_replay_readdir(fuse_req_t req,
+ fuse_ino_t ino,
+ const void *inarg)
+{
+ struct fuse_read_in *arg = (struct fuse_read_in *) inarg;
+ struct fuse_file_info fi;
+ guts_replay_ctx_t *ctx = (guts_replay_ctx_t *) req->u.ni.data;
+
+ memset (&fi, 0, sizeof (fi));
+ fi.fh = (unsigned long) guts_fd_search (ctx, arg->fh);
+
+ if (!fi.fh) {
+ /* TODO: make it more meaningful and organized */
+ printf ("readdir called without opening the file\n");
+ guts_reply_err (req, EBADFD);
+ } else {
+ fi.fh_old = fi.fh;
+
+ if (req->f->op.readdir)
+ req->f->op.readdir (req, ino, arg->size, arg->offset, &fi);
+ else
+ guts_reply_err (req, ENOSYS);
+ }
+
+}
+
+static void
+guts_replay_releasedir(fuse_req_t req,
+ fuse_ino_t ino,
+ const void *inarg)
+{
+ struct fuse_release_in *arg = (struct fuse_release_in *) inarg;
+ struct fuse_file_info fi;
+ guts_replay_ctx_t *ctx = (guts_replay_ctx_t *) req->u.ni.data;
+
+ memset (&fi, 0, sizeof (fi));
+ fi.flags = arg->flags;
+ fi.fh = (unsigned long) guts_fd_search (ctx, arg->fh);
+ if (!fi.fh) {
+ printf ("releasedir called without calling opendir\n");
+ guts_reply_err (req, EBADFD);
+ } else {
+
+ fi.fh_old = fi.fh;
+ if (req->f->op.releasedir)
+ req->f->op.releasedir (req, ino, &fi);
+ else
+ guts_reply_err (req, ENOSYS);
+ }
+}
+
+static void
+guts_replay_fsyncdir(fuse_req_t req,
+ fuse_ino_t ino,
+ const void *inarg)
+{
+ struct fuse_fsync_in *arg = (struct fuse_fsync_in *) inarg;
+ struct fuse_file_info fi;
+ guts_replay_ctx_t *ctx = (guts_replay_ctx_t *) req->u.ni.data;
+
+ memset (&fi, 0, sizeof (fi));
+ fi.fh = (unsigned long) guts_fd_search (ctx, arg->fh);
+ fi.fh_old = fi.fh;
+
+ if (req->f->op.fsyncdir)
+ req->f->op.fsyncdir (req, ino, arg->fsync_flags & 1, &fi);
+ else
+ guts_reply_err (req, ENOSYS);
+}
+
+static void
+guts_replay_statfs (fuse_req_t req,
+ fuse_ino_t ino,
+ const void *inargs)
+{
+ (void) ino;
+ (void) inargs;
+
+ if (req->f->op.statfs) {
+ req->f->op.statfs (req, ino);
+ } else {
+ struct statvfs buf = {
+ .f_namemax = 255,
+ .f_bsize = 512,
+ };
+ guts_reply_statfs (req, &buf);
+ }
+}
+
+static void
+guts_replay_setxattr(fuse_req_t req,
+ fuse_ino_t ino,
+ const void *inarg)
+{
+ struct fuse_setxattr_in *arg = (struct fuse_setxattr_in *) inarg;
+ char *name = PARAM(arg);
+ char *value = name + strlen(name) + 1;
+
+ if (req->f->op.setxattr)
+ req->f->op.setxattr (req, ino, name, value, arg->size, arg->flags);
+ else
+ guts_reply_err (req, ENOSYS);
+}
+
+static void
+guts_replay_getxattr(fuse_req_t req,
+ fuse_ino_t ino,
+ const void *inarg)
+{
+ struct fuse_getxattr_in *arg = (struct fuse_getxattr_in *) inarg;
+
+ if (req->f->op.getxattr)
+ req->f->op.getxattr (req, ino, PARAM(arg), arg->size);
+ else
+ guts_reply_err (req, ENOSYS);
+}
+
+static void
+guts_replay_listxattr (fuse_req_t req,
+ fuse_ino_t ino,
+ const void *inargs)
+{
+ struct fuse_getxattr_in *arg = (struct fuse_getxattr_in *) inargs;
+
+ if (req->f->op.listxattr)
+ req->f->op.listxattr (req, ino, arg->size);
+ else
+ guts_reply_err (req, ENOSYS);
+}
+
+static void
+guts_replay_removexattr(fuse_req_t req,
+ fuse_ino_t ino,
+ const void *inargs)
+{
+ char *name = (char *)inargs;
+
+ if (req->f->op.removexattr)
+ req->f->op.removexattr (req, ino, name);
+ else
+ guts_reply_err (req, ENOSYS);
+}
+
+guts_replay_t guts_replay_fop[] = {
+ [FUSE_LOOKUP] = { guts_replay_lookup, "lookup" },
+ [FUSE_FORGET] = { guts_replay_forget, "forget" },
+ [FUSE_GETATTR] = { guts_replay_getattr, "getattr" },
+ [FUSE_SETATTR] = { guts_replay_setattr, "setattr" },
+ [FUSE_ACCESS] = { guts_replay_access, "access" },
+ [FUSE_READLINK] = { guts_replay_readlink, "readlink" },
+ [FUSE_MKNOD] = { guts_replay_mknod, "mknod" },
+ [FUSE_MKDIR] = { guts_replay_mkdir, "mkdir" },
+ [FUSE_UNLINK] = { guts_replay_unlink, "unlink" },
+ [FUSE_RMDIR] = { guts_replay_rmdir, "rmdir" },
+ [FUSE_SYMLINK] = { guts_replay_symlink, "symlink" },
+ [FUSE_RENAME] = { guts_replay_rename, "rename" },
+ [FUSE_LINK] = { guts_replay_link, "link" },
+ [FUSE_CREATE] = { guts_replay_create, "create" },
+ [FUSE_OPEN] = { guts_replay_open, "open" },
+ [FUSE_READ] = { guts_replay_read, "read" },
+ [FUSE_WRITE] = { guts_replay_write, "write" },
+ [FUSE_FLUSH] = { guts_replay_flush, "flush" },
+ [FUSE_RELEASE] = { guts_replay_release, "release" },
+ [FUSE_FSYNC] = { guts_replay_fsync, "fsync" },
+ [FUSE_OPENDIR] = { guts_replay_opendir, "opendir" },
+ [FUSE_READDIR] = { guts_replay_readdir, "readdir" },
+ [FUSE_RELEASEDIR] = { guts_replay_releasedir, "releasedir" },
+ [FUSE_FSYNCDIR] = { guts_replay_fsyncdir, "fsyncdir" },
+ [FUSE_STATFS] = { guts_replay_statfs, "statfs" },
+ [FUSE_SETXATTR] = { guts_replay_setxattr, "setxattr" },
+ [FUSE_GETXATTR] = { guts_replay_getxattr, "getxattr" },
+ [FUSE_LISTXATTR] = { guts_replay_listxattr, "listxattr" },
+ [FUSE_REMOVEXATTR] = { guts_replay_removexattr, "removexattr" },
+};
+
+static inline void
+list_init_req (struct fuse_req *req)
+{
+ req->next = req;
+ req->prev = req;
+}
+
+
+static int32_t
+guts_transport_notify (xlator_t *xl,
+ int32_t event,
+ void *data,
+ ...)
+{
+ /* dummy, nobody has got anything to notify me.. ;) */
+ return 0;
+}
+
+static int32_t
+guts_transport_init (transport_t *this,
+ dict_t *options,
+ event_notify_fn_t notify)
+{
+ struct fuse_private *priv = CALLOC (1, sizeof (*priv));
+ ERR_ABORT (priv);
+
+ this->notify = NULL;
+ this->private = (void *)priv;
+
+ /* fuse channel */
+ priv->ch = NULL;
+
+ /* fuse session */
+ priv->se = NULL;
+
+ /* fuse channel fd */
+ priv->fd = -1;
+
+ this->buf = data_ref (data_from_dynptr (NULL, 0));
+ this->buf->is_locked = 1;
+
+ priv->mountpoint = NULL;
+
+ transport_ref (this);
+
+ return 0;
+}
+
+static void
+guts_transport_fini (transport_t *this)
+{
+
+}
+
+static int32_t
+guts_transport_disconnect (transport_t *this)
+{
+ struct fuse_private *priv = this->private;
+
+ gf_log ("glusterfs-guts",
+ GF_LOG_DEBUG,
+ "cleaning up fuse transport in disconnect handler");
+
+ 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
+ */
+ return -1;
+}
+
+static struct transport_ops guts_transport_ops = {
+ .disconnect = guts_transport_disconnect,
+};
+
+static transport_t guts_transport = {
+ .ops = &guts_transport_ops,
+ .private = NULL,
+ .xl = NULL,
+ .init = guts_transport_init,
+ .fini = guts_transport_fini,
+ .notify = guts_transport_notify
+};
+
+static inline xlator_t *
+fuse_graph (xlator_t *graph)
+{
+ xlator_t *top = NULL;
+ xlator_list_t *xlchild;
+
+ top = CALLOC (1, sizeof (*top));
+ ERR_ABORT (top);
+
+ xlchild = CALLOC (1, sizeof(*xlchild));
+ ERR_ABORT (xlchild);
+ xlchild->xlator = graph;
+ top->children = xlchild;
+ top->ctx = graph->ctx;
+ top->next = graph;
+ graph->parent = top;
+
+ return top;
+}
+
+static guts_replay_ctx_t *
+guts_replay_init (guts_thread_ctx_t *thread)
+{
+ guts_replay_ctx_t *ctx = NULL;
+ int32_t fd = open (thread->file, O_RDONLY);
+
+ if (fd < 0) {
+ gf_log ("glusterfs-guts", GF_LOG_DEBUG,
+ "failed to open tio_file %s", thread->file);
+ return ctx;
+ } else {
+ struct fuse_ll *guts_ll = CALLOC (1, sizeof (*guts_ll));
+ ERR_ABORT (guts_ll);
+
+ ctx = CALLOC (1, sizeof (*ctx));
+ ERR_ABORT (ctx);
+
+ if (ctx) {
+ /* equivalent to fuse_new_session () */
+ guts_ll->conn.async_read = 1;
+ guts_ll->conn.max_write = UINT_MAX;
+ guts_ll->conn.max_readahead = UINT_MAX;
+ memcpy (&guts_ll->op, &fuse_ops, sizeof (struct fuse_lowlevel_ops));
+ list_init_req (&guts_ll->list);
+ list_init_req (&guts_ll->interrupts);
+ guts_ll->owner = getuid ();
+ guts_ll->userdata = thread;
+
+ /* TODO: need to create transport_t object which whole of the glusterfs
+ * so desperately depends on */
+ transport_t *guts_trans = CALLOC (1, sizeof (*guts_trans));
+
+ if (guts_trans) {
+ memcpy (guts_trans, &guts_transport, sizeof (*guts_trans));
+ guts_trans->ops = &guts_transport_ops;
+ } else {
+ gf_log ("glusterfs-guts", GF_LOG_ERROR,
+ "failed to allocate memory for guts transport object");
+ return NULL;
+ }
+
+ glusterfs_ctx_t *glfs_ctx = CALLOC (1, sizeof (*glfs_ctx));;
+ if (glfs_ctx) {
+ guts_trans->xl_private = glfs_ctx;
+ guts_trans->xl = fuse_graph (thread->ctx->graph);
+ }else {
+ gf_log ("glusterfs-guts", GF_LOG_ERROR,
+ "failed to allocate memory for glusterfs_ctx_t object");
+ return NULL;
+ }
+
+ call_pool_t *pool = CALLOC (1, sizeof (call_pool_t));
+ if (pool) {
+ glfs_ctx->pool = pool;
+ LOCK_INIT (&pool->lock);
+ INIT_LIST_HEAD (&pool->all_frames);
+ } else {
+ gf_log ("glusterfs-guts", GF_LOG_ERROR,
+ "failed to allocate memory for guts call pool");
+ return NULL;
+ }
+
+ guts_trans->xl->ctx = glfs_ctx;
+ guts_trans->init (guts_trans, NULL, guts_transport_notify);
+ guts_ll->userdata = guts_trans;
+
+ /* call fuse_init */
+ guts_ll->op.init (guts_trans, NULL);
+
+ {
+ ctx->guts_ll = guts_ll;
+ ctx->tio_fd = fd;
+ ctx->inodes = get_new_dict ();
+ ctx->fds = get_new_dict ();
+ ctx->replies = get_new_dict ();
+ INIT_LIST_HEAD(&ctx->requests);
+ ctx->requests_dict = get_new_dict ();
+ }
+ } else {
+ gf_log ("glusterfs-guts", GF_LOG_ERROR,
+ "failed to allocate memory for guts_ctx_t object");
+ return NULL;
+ }
+ }
+
+ return ctx;
+}
+
+int32_t
+guts_replay (guts_thread_ctx_t *thread)
+{
+ guts_req_t *entry = NULL;
+ guts_replay_ctx_t *ctx = guts_replay_init (thread);
+
+ if (!ctx) {
+ gf_log ("glusterfs-guts", GF_LOG_ERROR,
+ "failed to initialize guts_replay");
+ return -1;
+ } else {
+ while ((entry = guts_read_entry (ctx))) {
+ /* here we go ... execute the request */
+ fuse_req_t req = CALLOC (1, sizeof (struct fuse_req));
+ ino_t ino = entry->header.nodeid;
+ void *arg = entry->arg;
+
+ if (req) {
+ req->f = ctx->guts_ll;
+ req->unique = entry->header.unique;
+ req->ctx.uid = entry->header.uid;
+ req->ctx.pid = entry->header.pid;
+
+ /* req->u.ni.data is unused void *, while running in replay mode. Making use of available real-estate
+ * to store useful information of thread specific guts_replay_ctx */
+ req->u.ni.data = (void *) ctx;
+ /* req->ch is of type 'struct fuse_chan', which fuse uses only at the
+ * time of the response it gets and is useful in sending the reply data to correct channel
+ * in /dev/fuse. This is not useful for us, so we ignore it by keeping it NULL */
+ list_init_req (req);
+
+ fuse_ino_t new_ino = guts_inode_search (ctx, ino);
+
+ if (guts_replay_fop[entry->header.opcode].func) {
+ printf ("operation: %s && inode: %ld\n", guts_replay_fop[entry->header.opcode].name, new_ino);
+ guts_replay_fop[entry->header.opcode].func (req, new_ino, arg);
+ }
+
+ if (entry->arg)
+ free (entry->arg);
+ free (entry);
+ } else {
+ gf_log ("glusterfs-guts", GF_LOG_ERROR,
+ "failed to allocate memory for fuse_req_t object");
+ return -1;
+ }
+ }
+ }
+ return 0;
+}
diff --git a/glusterfs-guts/src/guts-replay.h b/glusterfs-guts/src/guts-replay.h
new file mode 100644
index 000000000..532060d2b
--- /dev/null
+++ b/glusterfs-guts/src/guts-replay.h
@@ -0,0 +1,33 @@
+/*
+ Copyright (c) 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/>.
+*/
+
+#define PARAM(inarg) (((char *)(inarg)) + sizeof(*(inarg)))
+
+void guts_reply_err (fuse_req_t, error_t);
+void guts_reply_open (fuse_req_t, struct fuse_file_info *);
+void guts_reply_statfs (fuse_req_t, struct statvfs *);
+
+typedef void (*guts_replay_fop_t)(fuse_req_t, fuse_ino_t, const void *);
+
+typedef struct {
+ guts_replay_fop_t func;
+ const char *name;
+} guts_replay_t;
+
+extern struct fuse_lowlevel_ops fuse_ops;
+
diff --git a/glusterfs-guts/src/guts-tables.c b/glusterfs-guts/src/guts-tables.c
new file mode 100644
index 000000000..2992b3e2c
--- /dev/null
+++ b/glusterfs-guts/src/guts-tables.c
@@ -0,0 +1,248 @@
+/*
+ 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 "guts-parse.h"
+#include "dict.h"
+#include "guts-tables.h"
+
+
+int32_t
+guts_attr_cmp (const struct stat *attr,
+ const struct stat *old_attr)
+{
+ return 0;
+}
+
+int32_t
+guts_statvfs_cmp (const struct statvfs *stbuf,
+ const struct statvfs *old_stbuf)
+{
+ return 0;
+}
+
+int32_t
+guts_flock_cmp (struct flock *lock,
+ struct flock *old_lock)
+{
+ return 0;
+}
+
+
+guts_req_t *
+guts_lookup_request (guts_replay_ctx_t *ctx, uint64_t unique)
+{
+ guts_req_t *req = NULL;
+
+ if (unique == 0) {
+ if (list_empty (&ctx->requests))
+ req = NULL;
+ else {
+ /* pick an entry from list, move it out of the list and return it to the caller */
+ char *key = NULL;
+
+ req = list_entry (ctx->requests.next, guts_req_t, list);
+ list_del (&req->list);
+
+ asprintf (&key, "%llu", req->header.unique);
+
+ dict_set (ctx->requests_dict, key, data_from_static_ptr (req));
+
+ if (key)
+ free (key);
+ }
+ } else {
+ char *key = NULL;
+ data_t *req_data = NULL;
+
+ asprintf (&key, "%llu", unique);
+
+ req_data = dict_get (ctx->requests_dict, key);
+
+ if (req_data)
+ req = data_to_ptr (req_data);
+
+ if (key)
+ free (key);
+ }
+ return req;
+}
+
+guts_req_t *
+guts_get_request (guts_replay_ctx_t *ctx)
+{
+ return guts_lookup_request (ctx, 0);
+}
+
+int32_t
+guts_add_request (guts_replay_ctx_t *ctx,
+ guts_req_t *req)
+{
+ list_add_tail (&req->list, &ctx->requests);
+ return 0;
+}
+
+int32_t
+guts_add_reply (guts_replay_ctx_t *ctx,
+ guts_reply_t *reply)
+{
+ char *key = NULL;
+ asprintf (&key, "%llu", reply->req.unique);
+
+ dict_set (ctx->replies, key, data_from_static_ptr(reply));
+
+ if (key)
+ free(key);
+
+ return 0;
+}
+
+
+guts_reply_t *
+guts_lookup_reply (guts_replay_ctx_t *ctx,
+ uint64_t unique)
+{
+ char *key = NULL;
+ data_t *reply_data = NULL;
+ guts_reply_t *new_reply = NULL;
+
+ asprintf (&key, "%llu", unique);
+ reply_data = dict_get (ctx->replies, key);
+
+ if (reply_data) {
+ new_reply = data_to_ptr (reply_data);
+ dict_del (ctx->replies, key);
+ } else {
+ /* reply has not yet been read from tio file */
+ new_reply = guts_read_reply (ctx, unique);
+
+ if (!new_reply) {
+ /* failed to fetch reply for 'unique' from tio file */
+ new_reply;
+ }
+ }
+
+ if (key)
+ free(key);
+
+ return new_reply;
+
+}
+
+int32_t
+guts_inode_update (guts_replay_ctx_t *ctx,
+ fuse_ino_t old_ino,
+ fuse_ino_t new_ino)
+{
+ char *key = NULL;
+ asprintf (&key, "%ld", old_ino);
+ dict_set (ctx->inodes, key, data_from_uint64 (new_ino));
+
+ if (key)
+ free(key);
+
+ return 0;
+}
+
+fuse_ino_t
+guts_inode_search (guts_replay_ctx_t *ctx,
+ fuse_ino_t old_ino)
+{
+ char *key = NULL;
+ data_t *ino_data = NULL;
+ fuse_ino_t new_ino = 0;
+
+ asprintf (&key, "%ld", old_ino);
+ ino_data = dict_get (ctx->inodes, key);
+
+ if (ino_data)
+ new_ino = data_to_uint64 (ino_data);
+ else if (old_ino != /* TODO: FIXME */1 ) {
+ new_ino = 0;
+ } else
+ new_ino = old_ino;
+
+ if (key)
+ free(key);
+
+ return new_ino;
+}
+
+int32_t
+guts_fd_add (guts_replay_ctx_t *ctx,
+ unsigned long old_fd,
+ fd_t *new_fd)
+{
+ char *key = NULL;
+ asprintf (&key, "%ld", old_fd);
+ dict_set (ctx->fds, key, data_from_static_ptr (new_fd));
+
+ if (key)
+ free(key);
+
+ return 0;
+}
+
+fd_t *
+guts_fd_search (guts_replay_ctx_t *ctx,
+ unsigned long old_fd)
+{
+ char *key = NULL;
+ data_t *fd_data = NULL;
+ fd_t *new_fd = NULL;
+
+ asprintf (&key, "%ld", old_fd);
+ fd_data = dict_get (ctx->fds, key);
+
+ if (fd_data)
+ new_fd = data_to_ptr (fd_data);
+
+ if (key)
+ free(key);
+
+ return new_fd;
+}
+
+int32_t
+guts_delete_fd (guts_replay_ctx_t *ctx,
+ unsigned long old_fd)
+{
+ char *key = NULL;
+ data_t *fd_data = NULL;
+
+ asprintf (&key, "%ld", old_fd);
+ fd_data = dict_get (ctx->fds, key);
+
+ if (fd_data)
+ dict_del (ctx->fds, key);
+
+ if (key)
+ free(key);
+
+ return 0;
+}
+
+inline int32_t
+guts_get_opcode (guts_replay_ctx_t *ctx,
+ uint64_t unique)
+{
+ guts_req_t *req = guts_lookup_request (ctx, unique);
+
+ return ((req == NULL) ? -1 : req->header.opcode);
+
+}
diff --git a/glusterfs-guts/src/guts-tables.h b/glusterfs-guts/src/guts-tables.h
new file mode 100644
index 000000000..ff27300fa
--- /dev/null
+++ b/glusterfs-guts/src/guts-tables.h
@@ -0,0 +1,80 @@
+/*
+ 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/>.
+*/
+
+#ifndef _GUTS_TABLES_H_
+#define _GUTS_TABLES_H_
+
+
+int32_t
+guts_attr_cmp (const struct stat *attr,
+ const struct stat *old_attr);
+
+int32_t
+guts_statvfs_cmp (const struct statvfs *stbuf,
+ const struct statvfs *old_stbuf);
+
+int32_t
+guts_inode_update (guts_replay_ctx_t *ctx,
+ fuse_ino_t old_ino,
+ fuse_ino_t new_ino);
+
+fuse_ino_t
+guts_inode_search (guts_replay_ctx_t *ctx,
+ fuse_ino_t old_ino);
+
+int32_t
+guts_add_request (guts_replay_ctx_t *,
+ guts_req_t *);
+
+guts_req_t *
+guts_get_request (guts_replay_ctx_t *ctx);
+
+guts_req_t *
+guts_lookup_request (guts_replay_ctx_t *ctx,
+ uint64_t unique);
+
+guts_reply_t *
+guts_lookup_reply (guts_replay_ctx_t *ctx,
+ uint64_t unique);
+
+int32_t
+guts_add_reply (guts_replay_ctx_t *ctx,
+ guts_reply_t *reply);
+
+int32_t
+guts_flock_cmp (struct flock *lock,
+ struct flock *old_lock);
+
+fd_t *
+guts_fd_search (guts_replay_ctx_t *ctx,
+ unsigned long old_fd);
+
+int32_t
+guts_delete_fd (guts_replay_ctx_t *,
+ unsigned long);
+
+int32_t
+guts_get_opcode (guts_replay_ctx_t *ctx,
+ uint64_t unique);
+int32_t
+guts_fd_add (guts_replay_ctx_t *ctx,
+ unsigned long old_fd,
+ fd_t *new_fd);
+
+#endif
diff --git a/glusterfs-guts/src/guts-trace.c b/glusterfs-guts/src/guts-trace.c
new file mode 100644
index 000000000..51d8a68d6
--- /dev/null
+++ b/glusterfs-guts/src/guts-trace.c
@@ -0,0 +1,650 @@
+/*
+ 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 "glusterfs-guts.h"
+#include <signal.h>
+
+#include "guts-parse.h"
+#include "guts-tables.h"
+#include "guts-trace.h"
+
+static xlator_t *
+fuse_graph (xlator_t *graph)
+{
+ xlator_t *top = NULL;
+ xlator_list_t *xlchild;
+
+ top = CALLOC (1, sizeof (*top));
+ ERR_ABORT (top);
+ xlchild = CALLOC (1, sizeof(*xlchild));
+ ERR_ABORT (xlchild);
+ xlchild->xlator = graph;
+ top->children = xlchild;
+ top->ctx = graph->ctx;
+ top->next = graph;
+ graph->parent = top;
+
+ return top;
+}
+
+int32_t
+fuse_thread (pthread_t *thread, void *data);
+
+int32_t
+guts_trace (guts_ctx_t *guts_ctx)
+{
+ transport_t *mp = NULL;
+ glusterfs_ctx_t ctx = {
+ .poll_type = SYS_POLL_TYPE_EPOLL,
+ };
+ xlator_t *graph = NULL;
+ call_pool_t *pool = NULL;
+ int32_t ret = -1;
+ pthread_t thread;
+ /* Ignore SIGPIPE */
+ signal (SIGPIPE, SIG_IGN);
+
+#if HAVE_BACKTRACE
+ /* Handle SIGABORT and SIGSEGV */
+ signal (SIGSEGV, gf_print_trace);
+ signal (SIGABRT, gf_print_trace);
+#endif /* HAVE_BACKTRACE */
+
+ ret = guts_tio_init (guts_ctx->file);
+
+ if (ret < 0) {
+ gf_log ("glusterfs-guts", GF_LOG_ERROR,
+ "running in trace mode: failed to open tio file %s", guts_ctx->file);
+ return -1;
+ }
+
+ pool = ctx.pool = CALLOC (1, sizeof (call_pool_t));
+ ERR_ABORT (ctx.pool);
+ LOCK_INIT (&pool->lock);
+ INIT_LIST_HEAD (&pool->all_frames);
+
+ /* glusterfs_mount has to be ideally placed after all the initialisation stuff */
+ if (!(mp = glusterfs_mount (&ctx, guts_ctx->mountpoint))) {
+ gf_log ("glusterfs-guts", GF_LOG_ERROR, "Unable to mount glusterfs");
+ return -1;
+ }
+
+ gf_timer_registry_init (&ctx);
+ graph = guts_ctx->graph;
+
+ if (!graph) {
+ gf_log ("glusterfs-guts", GF_LOG_ERROR,
+ "Unable to get xlator graph for mount_point %s", guts_ctx->mountpoint);
+ transport_disconnect (mp);
+ return -1;
+ }
+
+ ctx.graph = graph;
+
+ mp->xl = fuse_graph (graph);
+ mp->xl->ctx = &ctx;
+
+ fuse_thread (&thread, mp);
+
+ while (!poll_iteration (&ctx));
+
+ return 0;
+}
+
+
+
+static void
+guts_name (struct fuse_in_header *in,
+ const void *inargs)
+{
+ char *name = (char *) inargs;
+
+ guts_req_dump (in, name, strlen (name));
+}
+
+static void
+guts_noarg (struct fuse_in_header *in,
+ const void *inargs)
+{
+ guts_req_dump (in, NULL, 0);
+}
+
+
+static void
+guts_setattr (struct fuse_in_header *in,
+ const void *inargs)
+{
+ struct fuse_setattr_in *arg = (struct fuse_setattr_in *)inargs;
+ guts_req_dump (in, arg, sizeof (*arg));
+}
+
+static void
+guts_access (struct fuse_in_header *in,
+ const void *inargs)
+{
+ struct fuse_access_in *arg = (struct fuse_access_in *)inargs;
+ guts_req_dump (in, arg, sizeof (*arg));
+}
+
+
+static void
+guts_mknod (struct fuse_in_header *in,
+ const void *inargs)
+{
+ struct fuse_mknod_in *arg = (struct fuse_mknod_in *) inargs;
+ guts_req_dump (in, arg, sizeof (*arg));
+}
+
+static void
+guts_mkdir (struct fuse_in_header *in,
+ const void *inargs)
+{
+ struct fuse_mkdir_in *arg = (struct fuse_mkdir_in *) inargs;
+ guts_req_dump (in, arg, sizeof (*arg));
+}
+
+
+static void
+guts_symlink (struct fuse_in_header *in,
+ const void *inargs)
+{
+ char *name = (char *) inargs;
+ char *linkname = ((char *) inargs) + strlen ((char *) inargs) + 1;
+ struct guts_symlink_in symlink_in;
+
+ strcpy (symlink_in.name, name);
+ strcpy (symlink_in.linkname, linkname);
+ guts_req_dump (in, &symlink_in, sizeof (symlink_in));
+}
+
+static void
+guts_rename (struct fuse_in_header *in,
+ const void *inargs)
+{
+ struct fuse_rename_in *arg = (struct fuse_rename_in *) inargs;
+ char *oldname = PARAM(arg);
+ char *newname = oldname + strlen (oldname) + 1;
+ struct guts_rename_in rename_in;
+
+ memset (&rename_in, 0, sizeof (rename_in));
+ memcpy (&rename_in, arg, sizeof (*arg));
+ strcpy (rename_in.oldname, oldname);
+ strcpy (rename_in.newname, newname);
+
+ guts_req_dump (in, &rename_in, sizeof (rename_in));
+
+}
+
+static void
+guts_link (struct fuse_in_header *in,
+ const void *inargs)
+{
+ struct fuse_link_in *arg = (struct fuse_link_in *) inargs;
+
+ guts_req_dump (in, arg, sizeof (*arg));
+}
+
+
+static void
+guts_open (struct fuse_in_header *in,
+ const void *inargs)
+{
+ struct fuse_open_in *arg = (struct fuse_open_in *) inargs;
+
+ guts_req_dump (in, arg, sizeof (*arg));
+}
+
+static void
+guts_create (struct fuse_in_header *in,
+ const void *inargs)
+{
+ struct guts_create_in create_in;
+ struct fuse_open_in *arg = (struct fuse_open_in *) inargs;
+ char *name = PARAM (arg);
+
+ memset (&create_in, 0, sizeof (create_in));
+ memcpy (&create_in.open_in, arg, sizeof (*arg));
+ memcpy (&create_in.name, name, strlen (name));
+
+ guts_req_dump (in, &create_in, sizeof (create_in));
+}
+
+
+static void
+guts_read(struct fuse_in_header *in,
+ const void *inarg)
+{
+ struct fuse_read_in *arg = (struct fuse_read_in *) inarg;
+ guts_req_dump (in, arg, sizeof (*arg));
+}
+
+static void
+guts_write(struct fuse_in_header *in,
+ const void *inarg)
+{
+ /* TODO: where the hell is the data to be written??? */
+ struct fuse_write_in *arg = (struct fuse_write_in *) inarg;
+ guts_req_dump (in, arg, sizeof (*arg));
+}
+
+static void
+guts_flush(struct fuse_in_header *in,
+ const void *inarg)
+{
+ struct fuse_flush_in *arg = (struct fuse_flush_in *) inarg;
+ guts_req_dump (in, arg, sizeof (*arg));
+}
+
+static void
+guts_release(struct fuse_in_header *in,
+ const void *inarg)
+{
+ struct fuse_release_in *arg = (struct fuse_release_in *) inarg;
+ guts_req_dump (in, arg, sizeof (*arg));
+}
+
+static void
+guts_fsync(struct fuse_in_header *in,
+ const void *inarg)
+{
+ struct fuse_fsync_in *arg = (struct fuse_fsync_in *) inarg;
+ guts_req_dump (in, arg, sizeof (*arg));
+}
+
+
+static void
+guts_readdir(struct fuse_in_header *in,
+ const void *inarg)
+{
+ struct fuse_read_in *arg = (struct fuse_read_in *) inarg;
+ guts_req_dump (in, arg, sizeof (*arg));
+}
+
+static void
+guts_releasedir(struct fuse_in_header *in,
+ const void *inarg)
+{
+ struct fuse_release_in *arg = (struct fuse_release_in *) inarg;
+ guts_req_dump (in, arg, sizeof (*arg));
+}
+
+static void
+guts_fsyncdir(struct fuse_in_header *in,
+ const void *inarg)
+{
+ struct fuse_fsync_in *arg = (struct fuse_fsync_in *) inarg;
+ guts_req_dump (in, arg, sizeof (*arg));
+}
+
+
+static void
+guts_setxattr(struct fuse_in_header *in,
+ const void *inarg)
+{
+ struct fuse_setxattr_in *arg = (struct fuse_setxattr_in *) inarg;
+ char *name = PARAM(arg);
+ char *value = name + strlen(name) + 1;
+ struct guts_xattr_in setxattr_in;
+
+ memset (&setxattr_in, 0, sizeof (setxattr_in));
+ memcpy (&setxattr_in, arg, sizeof (*arg));
+ strcpy (setxattr_in.name, name);
+ strcpy (setxattr_in.value, value);
+
+ guts_req_dump (in, &setxattr_in, sizeof (setxattr_in));
+
+}
+
+static void
+guts_getxattr(struct fuse_in_header *in,
+ const void *inarg)
+{
+ struct fuse_getxattr_in *arg = (struct fuse_getxattr_in *) inarg;
+ guts_req_dump (in, arg, sizeof (*arg));
+}
+
+guts_log_t guts_log[] = {
+ [FUSE_LOOKUP] = { guts_name, "lookup" },
+ [FUSE_GETATTR] = { guts_noarg, "getattr" },
+ [FUSE_SETATTR] = { guts_setattr, "setattr" },
+ [FUSE_ACCESS] = { guts_access, "access" },
+ [FUSE_READLINK] = { guts_noarg, "readlink" },
+ [FUSE_MKNOD] = { guts_mknod, "mknod" },
+ [FUSE_MKDIR] = { guts_mkdir, "mkdir" },
+ [FUSE_UNLINK] = { guts_name, "unlink" },
+ [FUSE_RMDIR] = { guts_name, "rmdir" },
+ [FUSE_SYMLINK] = { guts_symlink, "symlink" },
+ [FUSE_RENAME] = { guts_rename, "rename" },
+ [FUSE_LINK] = { guts_link, "link" },
+ [FUSE_CREATE] = { guts_create, "create" },
+ [FUSE_OPEN] = { guts_open, "open" },
+ [FUSE_READ] = { guts_read, "read" },
+ [FUSE_WRITE] = { guts_write, "write" },
+ [FUSE_FLUSH] = { guts_flush, "flush" },
+ [FUSE_RELEASE] = { guts_release, "release" },
+ [FUSE_FSYNC] = { guts_fsync, "fsync" },
+ [FUSE_OPENDIR] = { guts_open, "opendir" },
+ [FUSE_READDIR] = { guts_readdir, "readdir" },
+ [FUSE_RELEASEDIR] = { guts_releasedir, "releasedir" },
+ [FUSE_FSYNCDIR] = { guts_fsyncdir, "fsyncdir" },
+ [FUSE_STATFS] = { guts_noarg, "statfs" },
+ [FUSE_SETXATTR] = { guts_setxattr, "setxattr" },
+ [FUSE_GETXATTR] = { guts_getxattr, "getxattr" },
+ [FUSE_LISTXATTR] = { guts_getxattr, "listxattr" },
+ [FUSE_REMOVEXATTR] = { guts_name, "removexattr" },
+};
+
+/* used for actual tracing task */
+
+int32_t
+guts_log_req (void *buf,
+ int32_t len)
+{
+ struct fuse_in_header *in = buf;
+ const void *inargs = NULL;
+ int32_t header_len = sizeof (struct fuse_in_header);
+
+ if (header_len < len ) {
+ inargs = buf + header_len;
+ gf_log ("guts-gimmik", GF_LOG_ERROR,
+ "unique: %llu, opcode: %s (%i), nodeid: %lu, insize: %zu\n",
+ (unsigned long long) in->unique, "<null>",
+ /*opname((enum fuse_opcode) in->opcode),*/ in->opcode,
+ (unsigned long) in->nodeid, len);
+ if (guts_log[in->opcode].func)
+ guts_log[in->opcode].func (in, inargs);
+
+ } else {
+ gf_log ("guts", GF_LOG_ERROR,
+ "header is longer than the buffer passed");
+ }
+
+ return 0;
+}
+
+
+int
+guts_reply_err (fuse_req_t req, int err)
+{
+ if (IS_TRACE(req)) {
+ /* we are tracing calls, just dump the reply to file and continue with fuse_reply_err() */
+ guts_reply_dump (req, &err, sizeof (err));
+ return fuse_reply_err (req, err);
+ } else {
+ /* we are replaying. ;) */
+ guts_replay_ctx_t *ctx = (guts_replay_ctx_t *) req->u.ni.data;
+ int32_t opcode = guts_get_opcode (ctx, req->unique);
+
+ /* see if we are called by close/closedir, if yes remove do a guts_fd_delete () */
+ if (opcode == FUSE_RELEASEDIR || opcode == FUSE_RELEASE) {
+ guts_req_t *request = guts_lookup_request (ctx, req->unique);
+ struct fuse_release_in *arg = request->arg;
+
+ guts_delete_fd (ctx, arg->fh);
+ } else if (err == -1) {
+ /* error while replaying?? just quit as of now
+ * TODO: this is not the right way */
+ printf (":O - glusterfs-guts: replay failed\n");
+ exit (0);
+ }
+
+ return 0;
+ }
+}
+
+void
+guts_reply_none (fuse_req_t req)
+{
+ if (IS_TRACE(req)) {
+ guts_reply_dump (req, NULL, 0);
+ fuse_reply_none (req);
+ } else {
+ return;
+ }
+}
+
+int
+guts_reply_entry (fuse_req_t req,
+ const struct fuse_entry_param *e)
+{
+ if (IS_TRACE(req)) {
+ guts_reply_dump (req, e, sizeof (*e));
+ return fuse_reply_entry (req, e);
+ } else {
+ /* TODO: is dict_set() the best solution for this case?? */
+ guts_replay_ctx_t *ctx = (guts_replay_ctx_t *) req->u.ni.data;
+ guts_reply_t *reply = guts_lookup_reply (ctx, req->unique);
+ struct fuse_entry_param *old_entry = (struct fuse_entry_param *)reply->arg;
+ guts_inode_update (ctx, old_entry->ino, e->ino);
+ return 0;
+ }
+}
+
+int
+guts_reply_create (fuse_req_t req,
+ const struct fuse_entry_param *e,
+ const struct fuse_file_info *f)
+{
+ if (IS_TRACE(req)) {
+ struct guts_create_out create_out;
+
+ memset (&create_out, 0, sizeof (create_out));
+ memcpy (&create_out.e, e, sizeof (*e));
+ memcpy (&create_out.f, f, sizeof (*f));
+
+ guts_reply_dump (req, &create_out, sizeof (create_out));
+ return fuse_reply_create (req, e, f);
+ } else {
+ guts_replay_ctx_t *ctx = (guts_replay_ctx_t *) req->u.ni.data;
+ guts_reply_t *reply = guts_lookup_reply (ctx, req->unique);
+ struct guts_create_out *old_createout = (struct guts_create_out *) reply->arg;
+ struct fuse_file_info *old_f = &old_createout->f;
+
+ /* add a new fd and map it to the file handle, as stored in tio file */
+ guts_fd_add (ctx, old_f->fh, (fd_t *)(long)f->fh);
+
+ return 0;
+ }
+}
+
+
+int
+guts_reply_attr (fuse_req_t req,
+ const struct stat *attr,
+ double attr_timeout)
+{
+ if (IS_TRACE(req)) {
+ struct guts_attr_out attr_out;
+
+ memcpy (&attr_out.attr, attr, sizeof (*attr));
+ attr_out.attr_timeout = attr_timeout;
+
+ guts_reply_dump (req, &attr_out, sizeof (attr_out));
+ return fuse_reply_attr (req, attr, attr_timeout);
+ } else {
+ guts_replay_ctx_t *ctx = (guts_replay_ctx_t *) req->u.ni.data;
+ guts_reply_t *reply = guts_lookup_reply (ctx, req->unique);
+ struct guts_attr_out *old_attrout = (struct guts_attr_out *) reply->arg;
+
+ if (!guts_attr_cmp (attr, &old_attrout->attr))
+ return 0;
+ else {
+ gf_log ("glusterfs-guts", GF_LOG_ERROR,
+ "attr failed.");
+ return -1;
+ }
+ }
+}
+
+int
+guts_reply_readlink (fuse_req_t req,
+ const char *linkname)
+{
+ if (IS_TRACE(req)) {
+ guts_reply_dump (req, linkname, strlen (linkname));
+ return fuse_reply_readlink (req, linkname);
+ } else {
+ guts_replay_ctx_t *ctx = (guts_replay_ctx_t *) req->u.ni.data;
+ guts_reply_t *reply = guts_lookup_reply (ctx, req->unique);
+ char *old_linkname = (char *) reply->arg;
+ if (!strcmp (linkname, old_linkname))
+ return 0;
+ else {
+ gf_log ("glusterfs-guts", GF_LOG_ERROR,
+ "readlink failed. linkname in tio file: %s \n linkname recieved on replay: %s",
+ old_linkname, linkname);
+ return -1;
+ }
+ }
+}
+
+int
+guts_reply_open (fuse_req_t req,
+ const struct fuse_file_info *f)
+{
+ if (IS_TRACE(req)) {
+ guts_reply_dump (req, f, sizeof (*f));
+ return fuse_reply_open (req, f);
+ } else {
+ /* the fd we recieve here is the valid fd for our current session, map the indicative number we have
+ * in mapping */
+ guts_replay_ctx_t *ctx = (guts_replay_ctx_t *) req->u.ni.data;
+ guts_reply_t *reply = guts_lookup_reply (ctx, req->unique);
+
+ if (reply) {
+ struct fuse_file_info *old_f = reply->arg;
+
+ /* add a new fd and map it to the file handle, as stored in tio file */
+ guts_fd_add (ctx, old_f->fh, (fd_t *)(long)f->fh);
+ }
+
+ return 0;
+ }
+}
+
+int
+guts_reply_write (fuse_req_t req,
+ size_t count)
+{
+ if (IS_TRACE(req)) {
+ guts_reply_dump (req, &count, sizeof (count));
+ return fuse_reply_write (req, count);
+ } else {
+ guts_replay_ctx_t *ctx = (guts_replay_ctx_t *) req->u.ni.data;
+ guts_reply_t *reply = guts_lookup_reply (ctx, req->unique);
+ size_t *old_count = reply->arg;
+ if (count == *old_count)
+ return 0;
+ else {
+ gf_log ("glusterfs-guts", GF_LOG_ERROR,
+ "writev failed. old writev count: %d \n writev count on replay: %d",
+ old_count, count);
+ return -1;
+ }
+ }
+}
+
+int
+guts_reply_buf (fuse_req_t req,
+ const char *buf,
+ size_t size)
+{
+ if (IS_TRACE(req)) {
+ guts_reply_dump (req, buf, size);
+ return fuse_reply_buf (req, buf, size);
+ } else {
+ guts_replay_ctx_t *ctx = (guts_replay_ctx_t *) req->u.ni.data;
+ guts_reply_t *reply = guts_lookup_reply (ctx, req->unique);
+ char *old_buf = reply->arg;
+ size_t old_size = reply->arg_len;
+ if ((size == old_size) && (!memcmp (buf, old_buf, size)))
+ return 0;
+ else {
+ gf_log ("glusterfs-guts", GF_LOG_ERROR,
+ "readv failed. old readv size: %d \n readv size on replay: %d",
+ old_size, size);
+ return -1;
+ }
+ }
+}
+
+int
+guts_reply_statfs (fuse_req_t req,
+ const struct statvfs *stbuf)
+{
+ if (IS_TRACE(req)) {
+ guts_reply_dump (req, stbuf, sizeof (*stbuf));
+ return fuse_reply_statfs (req, stbuf);
+ } else {
+ guts_replay_ctx_t *ctx = (guts_replay_ctx_t *) req->u.ni.data;
+ guts_reply_t *reply = guts_lookup_reply (ctx, req->unique);
+ struct statvfs *old_stbuf = reply->arg;
+
+ if (!guts_statvfs_cmp (old_stbuf, stbuf))
+ return 0;
+ else {
+ gf_log ("glusterfs-guts", GF_LOG_ERROR,
+ "statfs failed.");
+ return -1;
+ }
+ }
+}
+
+int
+guts_reply_xattr (fuse_req_t req,
+ size_t count)
+{
+ if (IS_TRACE(req)) {
+ guts_reply_dump (req, &count, sizeof (count));
+ return fuse_reply_xattr (req, count);
+ } else {
+ guts_replay_ctx_t *ctx = (guts_replay_ctx_t *) req->u.ni.data;
+ guts_reply_t *reply = guts_lookup_reply (ctx, req->unique);
+ size_t *old_count = reply->arg;
+ if (count == *old_count)
+ return 0;
+ else {
+ gf_log ("glusterfs-guts", GF_LOG_ERROR,
+ "xattr failed. old xattr count: %d \n xattr count on replay: %d",
+ old_count, count);
+ return -1;
+ }
+ }
+}
+
+int
+guts_reply_lock (fuse_req_t req,
+ struct flock *lock)
+{
+ if (IS_TRACE(req)) {
+ guts_reply_dump (req, lock , sizeof (*lock));
+ return fuse_reply_lock (req, lock);
+ } else {
+ guts_replay_ctx_t *ctx = (guts_replay_ctx_t *) req->u.ni.data;
+ guts_reply_t *reply = guts_lookup_reply (ctx, req->unique);
+ struct flock *old_lock = (struct flock *)reply->arg;
+ if (!guts_flock_cmp (lock, old_lock))
+ return 0;
+ else {
+ gf_log ("glusterfs-guts", GF_LOG_ERROR,
+ "lock failed.");
+ return -1;
+ }
+ }
+}
diff --git a/glusterfs-guts/src/guts-trace.h b/glusterfs-guts/src/guts-trace.h
new file mode 100644
index 000000000..c877b2bcf
--- /dev/null
+++ b/glusterfs-guts/src/guts-trace.h
@@ -0,0 +1,54 @@
+/*
+ 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/>.
+*/
+
+#define IS_TRACE(req) (req->ch != NULL)
+
+#define PARAM(inarg) (((char *)(inarg)) + sizeof(*(inarg)))
+
+struct guts_symlink_in {
+ char name[NAME_MAX];
+ char linkname[NAME_MAX];
+};
+
+struct guts_create_in {
+ struct fuse_open_in open_in;
+ char name[NAME_MAX];
+};
+
+struct guts_xattr_in {
+ struct fuse_setxattr_in xattr;
+ char name[NAME_MAX];
+ char value[NAME_MAX];
+};
+
+struct guts_rename_in {
+ struct fuse_rename_in rename;
+ char oldname[NAME_MAX];
+ char newname[NAME_MAX];
+};
+
+struct guts_create_out {
+ struct fuse_entry_param e;
+ struct fuse_file_info f;
+};
+
+struct guts_attr_out {
+ struct stat attr;
+ double attr_timeout;
+};