summaryrefslogtreecommitdiffstats
path: root/xlators/nfs/server
diff options
context:
space:
mode:
Diffstat (limited to 'xlators/nfs/server')
-rw-r--r--xlators/nfs/server/Makefile.am3
-rw-r--r--xlators/nfs/server/src/Makefile.am14
-rw-r--r--xlators/nfs/server/src/nfs-common.c379
-rw-r--r--xlators/nfs/server/src/nfs-common.h76
-rw-r--r--xlators/nfs/server/src/nfs-fops.c1441
-rw-r--r--xlators/nfs/server/src/nfs-fops.h259
-rw-r--r--xlators/nfs/server/src/nfs-generics.c1067
-rw-r--r--xlators/nfs/server/src/nfs-generics.h174
-rw-r--r--xlators/nfs/server/src/nfs-inodes.c571
-rw-r--r--xlators/nfs/server/src/nfs-inodes.h83
-rw-r--r--xlators/nfs/server/src/nfs.c645
-rw-r--r--xlators/nfs/server/src/nfs.h98
12 files changed, 4810 insertions, 0 deletions
diff --git a/xlators/nfs/server/Makefile.am b/xlators/nfs/server/Makefile.am
new file mode 100644
index 000000000..a985f42a8
--- /dev/null
+++ b/xlators/nfs/server/Makefile.am
@@ -0,0 +1,3 @@
+SUBDIRS = src
+
+CLEANFILES =
diff --git a/xlators/nfs/server/src/Makefile.am b/xlators/nfs/server/src/Makefile.am
new file mode 100644
index 000000000..453fd4753
--- /dev/null
+++ b/xlators/nfs/server/src/Makefile.am
@@ -0,0 +1,14 @@
+xlator_LTLIBRARIES = server.la
+xlatordir = $(libdir)/glusterfs/$(PACKAGE_VERSION)/xlator/nfs
+rpclibdir = $(top_srcdir)/xlators/nfs/lib/src/
+server_la_LDFLAGS = -module -avoidversion
+server_la_SOURCES = nfs.c nfs-common.c nfs-fops.c nfs-inodes.c nfs-generics.c
+server_la_LIBADD = $(top_builddir)/xlators/nfs/lib/src/librpcsvc.la $(top_builddir)/libglusterfs/src/libglusterfs.la
+
+noinst_HEADERS = nfs.h nfs-common.h nfs-fops.h nfs-inodes.h nfs-generics.h
+
+AM_CFLAGS = -fPIC -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -Wall -D$(GF_HOST_OS)\
+ -I$(top_srcdir)/libglusterfs/src -shared -nostartfiles $(GF_CFLAGS)\
+ -I$(rpclibdir) -L$(xlatordir)/ -I$(CONTRIBDIR)/rbtree
+
+CLEANFILES =
diff --git a/xlators/nfs/server/src/nfs-common.c b/xlators/nfs/server/src/nfs-common.c
new file mode 100644
index 000000000..3623f041c
--- /dev/null
+++ b/xlators/nfs/server/src/nfs-common.c
@@ -0,0 +1,379 @@
+/*
+ Copyright (c) 2010 Gluster, Inc. <http://www.gluster.com>
+ This file is part of GlusterFS.
+
+ GlusterFS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3 of the License,
+ or (at your option) any later version.
+
+ GlusterFS is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see
+ <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _CONFIG_H
+#define _CONFIG_H
+#include "config.h"
+#endif
+
+#include "rpcsvc.h"
+#include "dict.h"
+#include "xlator.h"
+#include "xdr-nfs3.h"
+#include "msg-nfs3.h"
+#include "iobuf.h"
+#include "nfs-common.h"
+#include "nfs-fops.h"
+#include "rpcsvc.h"
+#include "iatt.h"
+
+#include <libgen.h>
+
+xlator_t *
+nfs_xlid_to_xlator (xlator_list_t *cl, uint8_t xlid)
+{
+ xlator_t *xl = NULL;
+ uint8_t id = 0;
+
+ while (id <= xlid) {
+ if (!cl) {
+ xl = NULL;
+ break;
+ }
+
+ xl = cl->xlator;
+ cl = cl->next;
+ id++;
+ }
+
+ return xl;
+}
+
+
+xlator_t *
+nfs_path_to_xlator (xlator_list_t *cl, char *path)
+{
+ return NULL;
+}
+
+
+uint16_t
+nfs_xlator_to_xlid (xlator_list_t *cl, xlator_t *xl)
+{
+ uint16_t xlid = 0;
+
+ if ((!cl) || (!xl))
+ return 0;
+
+ while (cl) {
+ if (xl == cl->xlator)
+ break;
+ cl = cl->next;
+ ++xlid;
+ }
+
+ return xlid;
+}
+
+
+xlator_t *
+nfs_mntpath_to_xlator (xlator_list_t *cl, char *path)
+{
+ char volname[MNTPATHLEN];
+ char *volptr = NULL;
+ int pathlen = 0;
+ xlator_t *targetxl = NULL;
+
+ if ((!cl) || (!path))
+ return NULL;
+
+ strcpy (volname, path);
+ pathlen = strlen (volname);
+ gf_log (GF_NFS, GF_LOG_TRACE, "Subvolume search: %s", path);
+ if (volname[0] == '/')
+ volptr = &volname[1];
+ else
+ volptr = &volname[0];
+
+ if (volname[pathlen - 1] == '/')
+ volname[pathlen - 1] = '\0';
+
+ while (cl) {
+ if (strcmp (volptr, cl->xlator->name) == 0) {
+ targetxl = cl->xlator;
+ break;
+ }
+
+ cl = cl->next;
+ }
+
+ return targetxl;
+
+}
+
+
+/* Returns 1 if the stat seems to be filled with zeroes. */
+int
+nfs_zero_filled_stat (struct iatt *buf)
+{
+ if (!buf)
+ return 1;
+
+ /* Do not use st_dev because it is transformed to store the xlator id
+ * in place of the device number. Do not use st_ino because by this time
+ * we've already mapped the root ino to 1 so it is not guaranteed to be
+ * 0.
+ */
+ if ((buf->ia_nlink == 0) && (buf->ia_type == 0))
+ return 1;
+
+ return 0;
+}
+
+
+void
+nfs_loc_wipe (loc_t *loc)
+{
+ if (!loc)
+ return;
+
+ if (loc->path) {
+ FREE (loc->path);
+ loc->path = NULL;
+ }
+
+ if (loc->parent) {
+ inode_unref (loc->parent);
+ loc->parent = NULL;
+ }
+
+ if (loc->inode) {
+ inode_unref (loc->inode);
+ loc->inode = NULL;
+ }
+
+ loc->ino = 0;
+}
+
+
+int
+nfs_loc_copy (loc_t *dst, loc_t *src)
+{
+ int ret = -1;
+
+ dst->ino = src->ino;
+
+ if (src->inode)
+ dst->inode = inode_ref (src->inode);
+
+ if (src->parent)
+ dst->parent = inode_ref (src->parent);
+
+ dst->path = strdup (src->path);
+
+ if (!dst->path)
+ goto out;
+
+ dst->name = strrchr (dst->path, '/');
+ if (dst->name)
+ dst->name++;
+
+ ret = 0;
+out:
+ return ret;
+}
+
+
+int
+nfs_loc_fill (loc_t *loc, inode_t *inode, inode_t *parent, char *path)
+{
+ int ret = -EFAULT;
+
+ if (!loc)
+ return ret;
+
+ if (inode) {
+ loc->inode = inode_ref (inode);
+ loc->ino = inode->ino;
+ }
+
+ if (parent)
+ loc->parent = inode_ref (parent);
+
+ loc->path = strdup (path);
+ if (!loc->path) {
+ gf_log (GF_NFS, GF_LOG_ERROR, "strdup failed");
+ goto loc_wipe;
+ }
+
+ loc->name = strrchr (loc->path, '/');
+ if (loc->name)
+ loc->name++;
+ else
+ goto loc_wipe;
+
+ ret = 0;
+loc_wipe:
+ if (ret < 0)
+ nfs_loc_wipe (loc);
+
+ return ret;
+}
+
+
+int
+nfs_inode_loc_fill (inode_t *inode, loc_t *loc)
+{
+ char *resolvedpath = NULL;
+ inode_t *parent = NULL;
+ int ret = -EFAULT;
+
+ if ((!inode) || (!loc))
+ return ret;
+
+ if ((inode) && (inode->ino == 1))
+ goto ignore_parent;
+
+ parent = inode_parent (inode, 0, NULL);
+ if (!parent)
+ goto err;
+
+ignore_parent:
+ ret = inode_path (inode, NULL, &resolvedpath);
+ if (ret < 0)
+ goto err;
+
+ ret = nfs_loc_fill (loc, inode, parent, resolvedpath);
+ if (ret < 0)
+ goto err;
+
+err:
+ if (parent)
+ inode_unref (parent);
+
+ if (resolvedpath)
+ FREE (resolvedpath);
+
+ return ret;
+}
+
+
+int
+nfs_ino_loc_fill (inode_table_t *itable, uint64_t ino, uint64_t gen, loc_t *loc)
+{
+ int ret = -EFAULT;
+ inode_t *inode = NULL;
+
+ if (!loc)
+ return ret;
+
+ inode = inode_get (itable, ino, gen);
+ if (!inode) {
+ ret = -ENOENT;
+ goto err;
+ }
+
+ ret = nfs_inode_loc_fill (inode, loc);
+
+err:
+ if (inode)
+ inode_unref (inode);
+ return ret;
+}
+
+
+int
+nfs_parent_inode_loc_fill (inode_t *parent, inode_t *entryinode, char *entry,
+ loc_t *loc)
+{
+ int ret = -EFAULT;
+ char *path = NULL;
+
+ if ((!parent) || (!entry) || (!loc) || (!entryinode))
+ return ret;
+
+ ret = inode_path (parent, entry, &path);
+ if (ret < 0)
+ goto err;
+
+ ret = nfs_loc_fill (loc, entryinode, parent, path);
+
+err:
+ return ret;
+}
+
+
+/* Returns -1 if parent is not available, return -2 if the entry is not
+ * available. In case the return is going to be -2, and how = NFS_RESOLVE_CREATE
+ * it does however fill in the loc so that it can be used to perform a lookup
+ * fop for the entry.
+ * On other errors, return -3. 0 on success.
+ */
+int
+nfs_entry_loc_fill (inode_table_t *itable, ino_t ino, uint64_t gen, char *entry,
+ loc_t *loc, int how)
+{
+ inode_t *parent = NULL;
+ inode_t *entryinode = NULL;
+ int ret = -3;
+ char *resolvedpath = NULL;
+
+ if ((!itable) || (!entry) || (!loc))
+ return ret;
+
+ parent = inode_get (itable, ino, gen);
+
+ ret = -1;
+ /* Will need hard resolution now */
+ if (!parent)
+ goto err;
+
+ ret = -2;
+ entryinode = inode_grep (itable, parent, entry);
+ if (!entryinode) {
+ if (how != NFS_RESOLVE_CREATE)
+ goto err;
+ else {
+ /* Even though we'll create the inode and the loc for
+ * a missing inode, we still need to return -2 so
+ * that the caller can use the filled loc to call
+ * lookup.
+ */
+ entryinode = inode_new (itable);
+ nfs_parent_inode_loc_fill (parent, entryinode, entry,
+ loc);
+ goto err;
+ }
+ }
+
+ ret = inode_path (parent, entry, &resolvedpath);
+ if (ret < 0) {
+ ret = -3;
+ goto err;
+ }
+
+ ret = nfs_loc_fill (loc, entryinode, parent, resolvedpath);
+ if (ret < 0)
+ ret = -3;
+
+err:
+ if (parent)
+ inode_unref (parent);
+
+ if (entryinode)
+ inode_unref (entryinode);
+
+ if (resolvedpath)
+ FREE (resolvedpath);
+
+ return ret;
+}
+
+
+
diff --git a/xlators/nfs/server/src/nfs-common.h b/xlators/nfs/server/src/nfs-common.h
new file mode 100644
index 000000000..20003aa71
--- /dev/null
+++ b/xlators/nfs/server/src/nfs-common.h
@@ -0,0 +1,76 @@
+/*
+ Copyright (c) 2010 Gluster, Inc. <http://www.gluster.com>
+ This file is part of GlusterFS.
+
+ GlusterFS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3 of the License,
+ or (at your option) any later version.
+
+ GlusterFS is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see
+ <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _NFS_COMMON_H_
+#define _NFS_COMMON_H_
+
+#ifndef _CONFIG_H
+#define _CONFIG_H
+#include "config.h"
+#endif
+
+#include <unistd.h>
+
+#include "xlator.h"
+#include "rpcsvc.h"
+#include "iatt.h"
+
+#define NFS_PATH_MAX PATH_MAX
+#define NFS_NAME_MAX NAME_MAX
+
+#define NFS_DEFAULT_CREATE_MODE 0644
+
+extern xlator_t *
+nfs_xlid_to_xlator (xlator_list_t *cl, uint8_t xlid);
+
+extern uint16_t
+nfs_xlator_to_xlid (xlator_list_t *cl, xlator_t *xl);
+
+extern xlator_t *
+nfs_path_to_xlator (xlator_list_t *cl, char *path);
+
+extern xlator_t *
+nfs_mntpath_to_xlator (xlator_list_t *cl, char *path);
+
+extern int
+nfs_zero_filled_stat (struct iatt *buf);
+
+extern void
+nfs_loc_wipe (loc_t *loc);
+
+extern int
+nfs_loc_copy (loc_t *dst, loc_t *src);
+
+extern int
+nfs_loc_fill (loc_t *loc, inode_t *inode, inode_t *parent, char *path);
+
+#define NFS_RESOLVE_EXIST 1
+#define NFS_RESOLVE_CREATE 2
+
+extern int
+nfs_inode_loc_fill (inode_t *inode, loc_t *loc);
+
+extern int
+nfs_ino_loc_fill (inode_table_t *itable, uint64_t ino, uint64_t gen, loc_t *l);
+
+extern int
+nfs_entry_loc_fill (inode_table_t *itable, ino_t ino, uint64_t gen, char *entry,
+ loc_t *loc, int how);
+
+#endif
diff --git a/xlators/nfs/server/src/nfs-fops.c b/xlators/nfs/server/src/nfs-fops.c
new file mode 100644
index 000000000..3d4968a8b
--- /dev/null
+++ b/xlators/nfs/server/src/nfs-fops.c
@@ -0,0 +1,1441 @@
+/*
+ Copyright (c) 2010 Gluster, Inc. <http://www.gluster.com>
+ This file is part of GlusterFS.
+
+ GlusterFS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3 of the License,
+ or (at your option) any later version.
+
+ GlusterFS is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see
+ <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _CONFIG_H
+#define _CONFIG_H
+#include "config.h"
+#endif
+
+#include "dict.h"
+#include "xlator.h"
+#include "iobuf.h"
+#include "call-stub.h"
+#include "stack.h"
+#include "nfs.h"
+#include "nfs-fops.h"
+#include "inode.h"
+#include "nfs-common.h"
+
+#include <libgen.h>
+#include <semaphore.h>
+
+#define nfs_stack_destroy(fram) \
+ do { \
+ (fram)->local = NULL; \
+ STACK_DESTROY ((fram)->root); \
+ } while (0) \
+
+
+struct nfs_fop_local *
+nfs_fop_local_init (xlator_t *xl)
+{
+ struct nfs_fop_local *l = NULL;
+ struct nfs_state *nfs = NULL;
+ if (!xl)
+ return NULL;
+
+ nfs = xlator_top_private (xl);
+ l = mem_get (nfs->foppool);
+
+ memset (l, 0, sizeof (*l));
+ return l;
+}
+
+void
+nfs_fop_local_wipe (xlator_t *xl, struct nfs_fop_local *l)
+{
+ struct nfs_state *nfs = NULL;
+
+ if ((!xl) || (!l))
+ return;
+
+ nfs = xlator_top_private (xl);
+
+ if (l->iobref)
+ iobref_unref (l->iobref);
+
+ if (l->parent)
+ inode_unref (l->parent);
+
+ if (l->inode)
+ inode_unref (l->inode);
+
+ if (l->newparent)
+ inode_unref (l->newparent);
+
+ mem_put (nfs->foppool, l);
+
+ return;
+}
+
+call_frame_t *
+nfs_create_frame (xlator_t *xl, nfs_user_t *nfu)
+{
+ call_frame_t *frame = NULL;
+ int x = 0;
+ int y = 0;
+
+ if ((!xl) || (!nfu) || (nfu->ngrps > NFS_NGROUPS))
+ return NULL;
+
+ frame = create_frame (xl, (call_pool_t *)xl->ctx->pool);
+ if (!frame)
+ goto err;
+ frame->root->uid = nfu->uid;
+ frame->root->gid = nfu->gids[NFS_PRIMGID_IDX];
+ if (nfu->ngrps == 1)
+ goto err; /* Done, we only got primary gid */
+
+ frame->root->ngrps = nfu->ngrps - 1;
+
+ gf_log (GF_NFS, GF_LOG_TRACE,"uid: %d, gid %d, gids: %d",
+ frame->root->uid, frame->root->gid, frame->root->ngrps);
+ for(y = 0, x = 1; y < frame->root->ngrps; x++,y++) {
+ gf_log (GF_NFS, GF_LOG_TRACE, "gid: %d", nfu->gids[x]);
+ frame->root->groups[y] = nfu->gids[x];
+ }
+
+err:
+ return frame;
+}
+
+#define nfs_fop_handle_frame_create(fram, xla, nfuser, retval, errlabel) \
+ do { \
+ fram = nfs_create_frame (xla, (nfuser)); \
+ if (!fram) { \
+ retval = (-ENOMEM); \
+ gf_log (GF_NFS, GF_LOG_ERROR,"Frame creation failed");\
+ goto errlabel; \
+ } \
+ } while (0) \
+
+/* Look into the inode and parent inode of a loc and save enough state
+ * for us to determine in the callback whether to funge the ino in the stat buf
+ * with 1 for the parent.
+ */
+#define nfs_fop_save_root_ino(locl, loc) \
+ do { \
+ if ((loc)->ino == 1) \
+ (locl)->rootinode = 1; \
+ else if (((loc)->parent) && ((loc)->parent->ino == 1)) \
+ (locl)->rootparentinode = 1; \
+ } while (0) \
+
+/* Do the same for an fd */
+#define nfs_fop_save_root_fd_ino(locl, fdesc) \
+ do { \
+ if ((fdesc)->inode->ino == 1) \
+ (locl)->rootinode = 1; \
+ } while (0) \
+
+
+
+/* Use the state saved by the previous macro to funge the ino in the appropriate
+ * structure.
+ */
+#define nfs_fop_restore_root_ino(locl, preattr, postattr, prepar, postpar) \
+ do { \
+ if ((locl)->rootinode) { \
+ if ((preattr)) { \
+ ((struct iatt *)(preattr))->ia_ino = 1; \
+ ((struct iatt *)(preattr))->ia_dev = 0; \
+ } \
+ if ((postattr)) { \
+ ((struct iatt *)(postattr))->ia_ino = 1; \
+ ((struct iatt *)(postattr))->ia_dev = 0; \
+ } \
+ } else if ((locl)->rootparentinode) { \
+ if ((prepar)) { \
+ ((struct iatt *)(prepar))->ia_ino = 1; \
+ ((struct iatt *)(prepar))->ia_dev = 0; \
+ } \
+ if ((postpar)) { \
+ ((struct iatt *)(postpar))->ia_ino = 1; \
+ ((struct iatt *)(postpar))->ia_dev = 0; \
+ } \
+ } \
+ } while (0) \
+
+/* If the newly created, inode's parent is root, we'll need to funge the ino
+ * in the parent attr when we receive them in the callback.
+ */
+#define nfs_fop_newloc_save_root_ino(locl, newloc) \
+ do { \
+ if ((newloc)->ino == 1) \
+ (locl)->newrootinode = 1; \
+ else if (((newloc)->parent) && ((newloc)->parent->ino == 1)) \
+ (locl)->newrootparentinode = 1; \
+ } while (0) \
+
+
+#define nfs_fop_newloc_restore_root_ino(locl, preattr, postattr, prepar, postpar) \
+ do { \
+ if ((locl)->newrootinode) { \
+ if ((preattr)) \
+ ((struct iatt *)(preattr))->ia_ino = 1; \
+ if ((postattr)) \
+ ((struct iatt *)(postattr))->ia_ino = 1; \
+ } else if ((locl)->newrootparentinode) { \
+ if ((prepar)) \
+ ((struct iatt *)(prepar))->ia_ino = 1; \
+ if ((postpar)) \
+ ((struct iatt *)(postpar))->ia_ino = 1; \
+ } \
+ } while (0) \
+
+/* Fops Layer Explained
+ * The fops layer has three types of functions. They can all be identified by
+ * their names. Here are the three patterns:
+ *
+ * nfs_fop_<fopname>
+ * This is the lowest level function that knows nothing about states and
+ * callbacks. At most this is required to create a frame and call the
+ * fop. The idea here is to provide a convenient way to call fops than
+ * directly use STACK_WINDs. If this type of interface is used, the caller's
+ * callback is responsible for doing the relevant GlusterFS state
+ * maintenance operations on the data returned in the callbacks.
+ *
+ * nfs_fop_<fopname>_sync
+ * These are synchronous versions of the above fops. The idea is that
+ * if the user wants to wait for the fop to complete, this is the interface to
+ * use. The caller is responsible for doing the relevant GlusterFS
+ * state maintenance operations on the call_stub_t that is returned, including
+ * calling call_stub_destroy.
+ *
+ * nfs_<fopname>_sync
+ * This is help callers avoid the need to pass a pathloc to the
+ * nfs_fop_<fopname>_sync versions of the same fops.
+ *
+ * nfs_<fopname>
+ * Unlike the nfs_fop_<fopname> variety, this is the stateful type of fop, in
+ * that it silently performs all the relevant GlusterFS state maintainence
+ * operations on the data returned to the callbacks, leaving the caller's
+ * callback to just use the data returned for whatever it needs to do with that
+ * data, for eg. the nfs_lookup, will take care of looking up the inodes,
+ * revalidating them if needed and linking new inodes into the table, while
+ * the caller's callback, for eg, the NFSv3 LOOKUP callback can just use
+ * the stat bufs returned to create file handle, map the file handle into the
+ * fh cache and finally encode the fh and the stat bufs into a NFS reply.
+ *
+ */
+
+int32_t
+nfs_fop_lookup_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
+ int32_t op_ret, int32_t op_errno, inode_t *inode,
+ struct iatt *buf, dict_t *xattr, struct iatt *postparent)
+{
+ struct nfs_fop_local *local = NULL;
+ fop_lookup_cbk_t progcbk;
+
+ nfl_to_prog_data (this, local, progcbk, frame);
+ nfs_fop_restore_root_ino (local, buf, NULL, NULL, postparent);
+ if (progcbk)
+ progcbk (frame, cookie, this, op_ret, op_errno, inode, buf,
+ xattr, postparent);
+
+ nfs_stack_destroy (frame);
+ return 0;
+}
+
+
+int
+nfs_fop_lookup (xlator_t *xl, nfs_user_t *nfu, loc_t *loc,
+ fop_lookup_cbk_t cbk, void *local)
+{
+ call_frame_t *frame = NULL;
+ int ret = -EFAULT;
+ struct nfs_fop_local *nfl = NULL;
+
+ if ((!xl) || (!loc) || (!nfu))
+ return ret;
+
+ gf_log (GF_NFS, GF_LOG_TRACE, "Lookup: %s", loc->path);
+ nfs_fop_handle_frame_create (frame, xl, nfu, ret, err);
+ nfs_fop_handle_local_init (frame, xl, nfl, cbk, local, ret, err);
+ nfs_fop_save_root_ino (nfl, loc);
+
+ STACK_WIND_COOKIE (frame, nfs_fop_lookup_cbk, xl, xl, xl->fops->lookup,
+ loc, NULL);
+
+ ret = 0;
+err:
+ if (ret < 0) {
+ if (frame)
+ nfs_stack_destroy (frame);
+ }
+
+ return ret;
+}
+
+
+int32_t
+nfs_fop_stat_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
+ int32_t op_ret, int32_t op_errno, struct iatt *buf)
+{
+ struct nfs_fop_local *nfl = NULL;
+ fop_stat_cbk_t progcbk = NULL;
+
+ nfl_to_prog_data (this, nfl, progcbk, frame);
+ nfs_fop_restore_root_ino (nfl, buf, NULL, NULL, NULL);
+ if (progcbk)
+ progcbk (frame, cookie, this, op_ret, op_errno, buf);
+
+ nfs_stack_destroy (frame);
+ return 0;
+}
+
+
+int
+nfs_fop_stat (xlator_t *xl, nfs_user_t *nfu, loc_t *loc,
+ fop_stat_cbk_t cbk, void *local)
+{
+ call_frame_t *frame = NULL;
+ int ret = -EFAULT;
+ struct nfs_fop_local *nfl = NULL;
+
+ if ((!xl) || (!loc) || (!nfu))
+ return ret;
+
+ gf_log (GF_NFS, GF_LOG_TRACE, "Stat: %s", loc->path);
+ nfs_fop_handle_frame_create (frame, xl, nfu, ret, err);
+ nfs_fop_handle_local_init (frame, xl, nfl, cbk, local, ret, err);
+ nfs_fop_save_root_ino (nfl, loc);
+
+ STACK_WIND_COOKIE (frame, nfs_fop_stat_cbk, xl, xl, xl->fops->stat,
+ loc);
+ ret = 0;
+err:
+ if (ret < 0) {
+ if (frame)
+ nfs_stack_destroy (frame);
+ }
+
+ return ret;
+}
+
+
+int32_t
+nfs_fop_fstat_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
+ int32_t op_ret, int32_t op_errno, struct iatt *buf)
+{
+ struct nfs_fop_local *nfl = NULL;
+ fop_fstat_cbk_t progcbk = NULL;
+
+ nfl_to_prog_data (this, nfl, progcbk, frame);
+ nfs_fop_restore_root_ino (nfl, buf, NULL, NULL, NULL);
+ if (progcbk)
+ progcbk (frame, cookie, this, op_ret, op_errno, buf);
+
+ nfs_stack_destroy (frame);
+ return 0;
+}
+
+
+int
+nfs_fop_fstat (xlator_t *xl, nfs_user_t *nfu, fd_t *fd,
+ fop_fstat_cbk_t cbk, void *local)
+{
+ call_frame_t *frame = NULL;
+ int ret = -EFAULT;
+ struct nfs_fop_local *nfl = NULL;
+
+ if ((!xl) || (!fd) || (!nfu))
+ return ret;
+
+ gf_log (GF_NFS, GF_LOG_TRACE, "FStat");
+ nfs_fop_handle_frame_create (frame, xl, nfu, ret, err);
+ nfs_fop_handle_local_init (frame, xl, nfl, cbk, local, ret, err);
+ nfs_fop_save_root_fd_ino (nfl, fd);
+
+ STACK_WIND_COOKIE (frame, nfs_fop_fstat_cbk, xl, xl, xl->fops->fstat,
+ fd);
+
+ ret = 0;
+err:
+ if (ret < 0) {
+ if (frame)
+ nfs_stack_destroy (frame);
+ }
+
+ return ret;
+}
+
+
+int32_t
+nfs_fop_opendir_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
+ int32_t op_ret, int32_t op_errno, fd_t *fd)
+{
+ struct nfs_fop_local *nfl = NULL;
+ fop_opendir_cbk_t progcbk = NULL;
+
+ nfl_to_prog_data (this, nfl, progcbk, frame);
+ if (progcbk)
+ progcbk (frame, cookie, this, op_ret, op_errno, fd);
+ nfs_stack_destroy (frame);
+ return 0;
+}
+
+
+int
+nfs_fop_opendir (xlator_t *xl, nfs_user_t *nfu, loc_t *pathloc,fd_t *dirfd,
+ fop_opendir_cbk_t cbk, void *local)
+{
+ call_frame_t *frame = NULL;
+ int ret = -EFAULT;
+ struct nfs_fop_local *nfl = NULL;
+
+ if ((!xl) || (!pathloc) || (!dirfd) || (!nfu))
+ return ret;
+
+ gf_log (GF_NFS, GF_LOG_TRACE, "Opendir: %s", pathloc->path);
+ nfs_fop_handle_frame_create (frame, xl, nfu, ret, err);
+ nfs_fop_handle_local_init (frame, xl, nfl, cbk, local, ret, err);
+
+ STACK_WIND_COOKIE (frame, nfs_fop_opendir_cbk, xl, xl,
+ xl->fops->opendir, pathloc, dirfd);
+ ret = 0;
+
+err:
+ if (ret < 0) {
+ if (frame)
+ nfs_stack_destroy (frame);
+ }
+
+ return ret;
+}
+
+int
+nfs_fop_flush_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
+ int32_t op_ret, int32_t op_errno)
+{
+ struct nfs_fop_local *nfl = NULL;
+ fop_flush_cbk_t progcbk = NULL;
+
+ nfl_to_prog_data (this, nfl, progcbk, frame);
+ if (progcbk)
+ progcbk (frame, cookie, this, op_ret, op_errno);
+
+ nfs_stack_destroy (frame);
+ return 0;
+}
+
+
+int
+nfs_fop_flush (xlator_t *xl, nfs_user_t *nfu, fd_t *fd,
+ fop_flush_cbk_t cbk, void *local)
+{
+ call_frame_t *frame = NULL;
+ int ret = -EFAULT;
+ struct nfs_fop_local *nfl = NULL;
+
+ if ((!xl) || (!fd) || (!nfu))
+ return ret;
+
+ nfs_fop_handle_frame_create (frame, xl, nfu, ret, err);
+ nfs_fop_handle_local_init (frame, xl, nfl, cbk, local, ret, err);
+
+ STACK_WIND_COOKIE (frame, nfs_fop_flush_cbk, xl, xl, xl->fops->flush,
+ fd);
+ ret = 0;
+err:
+ if (ret < 0) {
+ if (frame)
+ nfs_stack_destroy (frame);
+ }
+
+ return ret;
+}
+
+
+int32_t
+nfs_fop_readdirp_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
+ int32_t op_ret, int32_t op_errno, gf_dirent_t *entries)
+{
+ struct nfs_fop_local *nfl = NULL;
+ fop_readdirp_cbk_t progcbk = NULL;
+
+ nfl_to_prog_data (this, nfl, progcbk, frame);
+ if (progcbk)
+ progcbk (frame, cookie, this, op_ret, op_errno, entries);
+
+ nfs_stack_destroy (frame);
+
+ return 0;
+}
+
+
+int
+nfs_fop_readdirp (xlator_t *xl, nfs_user_t *nfu, fd_t *dirfd,
+ size_t bufsize, off_t offset, fop_readdirp_cbk_t cbk,
+ void *local)
+{
+ call_frame_t *frame = NULL;
+ int ret = -EFAULT;
+ struct nfs_fop_local *nfl = NULL;
+
+ if ((!xl) || (!dirfd) || (!nfu))
+ return ret;
+
+ gf_log (GF_NFS, GF_LOG_TRACE, "readdir");
+ nfs_fop_handle_frame_create (frame, xl, nfu, ret, err);
+ nfs_fop_handle_local_init (frame, xl, nfl, cbk, local, ret, err);
+
+ STACK_WIND_COOKIE (frame, nfs_fop_readdirp_cbk, xl, xl,
+ xl->fops->readdirp, dirfd, bufsize, offset);
+
+ ret = 0;
+err:
+ if (ret < 0) {
+ if (frame)
+ nfs_stack_destroy (frame);
+ }
+
+ return ret;
+}
+
+
+int32_t
+nfs_fop_statfs_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
+ int32_t op_ret, int32_t op_errno, struct statvfs *buf)
+{
+
+ struct nfs_fop_local *nfl = NULL;
+ fop_statfs_cbk_t progcbk = NULL;
+
+ nfl_to_prog_data (this, nfl, progcbk, frame);
+ if (progcbk)
+ progcbk (frame, cookie, this, op_ret, op_errno, buf);
+
+ nfs_stack_destroy (frame);
+ return 0;
+}
+
+
+int
+nfs_fop_statfs (xlator_t *xl, nfs_user_t *nfu, loc_t *pathloc,
+ fop_statfs_cbk_t cbk, void *local)
+{
+ call_frame_t *frame = NULL;
+ int ret = -EFAULT;
+ struct nfs_fop_local *nfl = NULL;
+
+ if ((!xl) || (!pathloc) || (!nfu))
+ return ret;
+
+ gf_log (GF_NFS, GF_LOG_TRACE, "Statfs: %s", pathloc->path);
+ nfs_fop_handle_frame_create (frame, xl, nfu, ret, err);
+ nfs_fop_handle_local_init (frame, xl, nfl, cbk, local, ret, err);
+
+ STACK_WIND_COOKIE (frame, nfs_fop_statfs_cbk, xl, xl, xl->fops->statfs
+ ,pathloc);
+ ret = 0;
+err:
+ if (ret < 0) {
+ if (frame)
+ nfs_stack_destroy (frame);
+ }
+
+ return ret;
+}
+
+
+int32_t
+nfs_fop_create_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
+ int32_t op_ret, int32_t op_errno, fd_t *fd, inode_t *inode,
+ struct iatt *buf, struct iatt *preparent,
+ struct iatt *postparent)
+{
+ struct nfs_fop_local *nfl = NULL;
+ fop_create_cbk_t progcbk = NULL;
+
+ nfl_to_prog_data (this, nfl, progcbk, frame);
+ nfs_fop_restore_root_ino (nfl, buf, NULL, preparent, postparent);
+ if (progcbk)
+ progcbk (frame, cookie, this, op_ret, op_errno, fd, inode, buf,
+ preparent, postparent);
+
+ nfs_stack_destroy (frame);
+ return 0;
+}
+
+
+int
+nfs_fop_create (xlator_t *xl, nfs_user_t *nfu, loc_t *pathloc, int flags,
+ mode_t mode, fd_t *fd, fop_create_cbk_t cbk, void *local)
+{
+ call_frame_t *frame = NULL;
+ int ret = -EFAULT;
+ struct nfs_fop_local *nfl = NULL;
+
+ if ((!xl) || (!pathloc) || (!nfu))
+ return ret;
+
+ gf_log (GF_NFS, GF_LOG_TRACE, "Create: %s", pathloc->path);
+ nfs_fop_handle_frame_create (frame, xl, nfu, ret, err);
+ nfs_fop_handle_local_init (frame, xl, nfl, cbk, local, ret, err);
+ nfs_fop_save_root_ino (nfl, pathloc);
+
+ STACK_WIND_COOKIE (frame, nfs_fop_create_cbk, xl, xl, xl->fops->create
+ , pathloc, flags, mode, fd);
+ ret = 0;
+err:
+ if (ret < 0) {
+ if (frame)
+ nfs_stack_destroy (frame);
+ }
+
+ return ret;
+}
+
+
+int32_t
+nfs_fop_setattr_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
+ int32_t op_ret, int32_t op_errno, struct iatt *pre,
+ struct iatt *post)
+{
+ struct nfs_fop_local *nfl = NULL;
+ fop_setattr_cbk_t progcbk = NULL;
+
+ nfl_to_prog_data (this, nfl, progcbk, frame);
+ nfs_fop_restore_root_ino (nfl, pre, post, NULL, NULL);
+ if (progcbk)
+ progcbk (frame, cookie, this, op_ret, op_errno, pre, post);
+ nfs_stack_destroy (frame);
+ return 0;
+}
+
+
+
+int
+nfs_fop_setattr (xlator_t *xl, nfs_user_t *nfu, loc_t *pathloc,
+ struct iatt *buf, int32_t valid, fop_setattr_cbk_t cbk,
+ void *local)
+{
+ call_frame_t *frame = NULL;
+ int ret = -EFAULT;
+ struct nfs_fop_local *nfl = NULL;
+
+ if ((!xl) || (!pathloc) || (!nfu))
+ return ret;
+
+ gf_log (GF_NFS, GF_LOG_TRACE, "Setattr: %s", pathloc->path);
+ nfs_fop_handle_frame_create (frame, xl, nfu, ret, err);
+ nfs_fop_handle_local_init (frame, xl, nfl, cbk, local, ret, err);
+ nfs_fop_save_root_ino (nfl, pathloc);
+
+ STACK_WIND_COOKIE (frame, nfs_fop_setattr_cbk, xl, xl,
+ xl->fops->setattr, pathloc, buf, valid);
+ ret = 0;
+err:
+ if (ret < 0) {
+ if (frame)
+ nfs_stack_destroy (frame);
+ }
+
+ return ret;
+}
+
+
+int32_t
+nfs_fop_mkdir_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
+ int32_t op_ret, int32_t op_errno, inode_t *inode,
+ struct iatt *buf, struct iatt *preparent,
+ struct iatt *postparent)
+{
+ struct nfs_fop_local *nfl = NULL;
+ fop_mkdir_cbk_t progcbk = NULL;
+
+ nfl_to_prog_data (this, nfl, progcbk, frame);
+ nfs_fop_restore_root_ino (nfl, buf, NULL, preparent, postparent);
+ if (progcbk)
+ progcbk (frame, cookie, this, op_ret, op_errno, inode, buf,
+ preparent, postparent);
+ nfs_stack_destroy (frame);
+ return 0;
+}
+
+
+int
+nfs_fop_mkdir (xlator_t *xl, nfs_user_t *nfu, loc_t *pathloc, mode_t mode,
+ fop_mkdir_cbk_t cbk, void *local)
+{
+ call_frame_t *frame = NULL;
+ int ret = -EFAULT;
+ struct nfs_fop_local *nfl = NULL;
+
+ if ((!xl) || (!pathloc) || (!nfu))
+ return ret;
+
+ gf_log (GF_NFS, GF_LOG_TRACE, "Mkdir: %s", pathloc->path);
+ nfs_fop_handle_frame_create (frame, xl, nfu, ret, err);
+ nfs_fop_handle_local_init (frame, xl, nfl, cbk, local, ret, err);
+ nfs_fop_save_root_ino (nfl, pathloc);
+
+ STACK_WIND_COOKIE (frame, nfs_fop_mkdir_cbk, xl, xl, xl->fops->mkdir,
+ pathloc, mode);
+ ret = 0;
+err:
+ if (ret < 0) {
+ if (frame)
+ nfs_stack_destroy (frame);
+ }
+
+ return ret;
+}
+
+
+int32_t
+nfs_fop_symlink_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
+ int32_t op_ret, int32_t op_errno, inode_t *inode,
+ struct iatt *buf, struct iatt *preparent,
+ struct iatt *postparent)
+{
+ struct nfs_fop_local *nfl = NULL;
+ fop_symlink_cbk_t progcbk = NULL;
+
+ nfl_to_prog_data (this, nfl, progcbk, frame);
+ nfs_fop_restore_root_ino (nfl, buf, NULL, preparent, postparent);
+ if (progcbk)
+ progcbk (frame, cookie, this, op_ret, op_errno, inode, buf,
+ preparent, postparent);
+ nfs_stack_destroy (frame);
+ return 0;
+}
+
+int
+nfs_fop_symlink (xlator_t *xl, nfs_user_t *nfu, char *target,
+ loc_t *pathloc, fop_symlink_cbk_t cbk, void *local)
+{
+ call_frame_t *frame = NULL;
+ int ret = -EFAULT;
+ struct nfs_fop_local *nfl = NULL;
+
+ if ((!xl) || (!pathloc) || (!target) || (!nfu))
+ return ret;
+
+ gf_log (GF_NFS, GF_LOG_TRACE, "Symlink: %s", pathloc->path);
+ nfs_fop_handle_frame_create (frame, xl, nfu, ret, err);
+ nfs_fop_handle_local_init (frame, xl, nfl, cbk, local, ret, err);
+ nfs_fop_save_root_ino (nfl, pathloc);
+
+ STACK_WIND_COOKIE (frame, nfs_fop_symlink_cbk, xl, xl,
+ xl->fops->symlink, target, pathloc);
+ ret = 0;
+err:
+ if (ret < 0) {
+ if (frame)
+ nfs_stack_destroy (frame);
+ }
+
+ return ret;
+}
+
+
+int32_t
+nfs_fop_readlink_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
+ int32_t op_ret, int32_t op_errno, const char *path,
+ struct iatt *buf)
+{
+ struct nfs_fop_local *nfl = NULL;
+ fop_readlink_cbk_t progcbk = NULL;
+
+ nfl_to_prog_data (this, nfl, progcbk, frame);
+ nfs_fop_restore_root_ino (nfl, buf, NULL, NULL, NULL);
+ if (progcbk)
+ progcbk (frame, cookie, this, op_ret, op_errno, path, buf);
+ nfs_stack_destroy (frame);
+ return 0;
+}
+
+
+int
+nfs_fop_readlink (xlator_t *xl, nfs_user_t *nfu, loc_t *pathloc,
+ size_t size, fop_readlink_cbk_t cbk, void *local)
+{
+ call_frame_t *frame = NULL;
+ int ret = -EFAULT;
+ struct nfs_fop_local *nfl = NULL;
+
+ if ((!xl) || (!pathloc) || (!nfu))
+ return ret;
+
+ gf_log (GF_NFS, GF_LOG_TRACE, "Readlink: %s", pathloc->path);
+ nfs_fop_handle_frame_create (frame, xl, nfu, ret, err);
+ nfs_fop_handle_local_init (frame, xl, nfl, cbk, local, ret, err);
+ nfs_fop_save_root_ino (nfl, pathloc);
+
+ STACK_WIND_COOKIE (frame, nfs_fop_readlink_cbk, xl, xl,
+ xl->fops->readlink, pathloc, size);
+ ret = 0;
+err:
+ if (ret < 0) {
+ if (frame)
+ nfs_stack_destroy (frame);
+ }
+
+ return ret;
+}
+
+
+int32_t
+nfs_fop_mknod_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
+ int32_t op_ret, int32_t op_errno, inode_t *inode,
+ struct iatt *buf, struct iatt *preparent,
+ struct iatt *postparent)
+{
+ struct nfs_fop_local *nfl = NULL;
+ fop_mknod_cbk_t progcbk = NULL;
+
+ nfl_to_prog_data (this, nfl, progcbk, frame);
+ nfs_fop_restore_root_ino (nfl, buf, NULL, preparent, postparent);
+ if (progcbk)
+ progcbk (frame, cookie, this, op_ret, op_errno, inode, buf,
+ preparent, postparent);
+ nfs_stack_destroy (frame);
+ return 0;
+}
+
+
+int
+nfs_fop_mknod (xlator_t *xl, nfs_user_t *nfu, loc_t *pathloc, mode_t mode,
+ dev_t dev, fop_mknod_cbk_t cbk, void *local)
+{
+ call_frame_t *frame = NULL;
+ int ret = -EFAULT;
+ struct nfs_fop_local *nfl = NULL;
+
+ if ((!xl) || (!pathloc) || (!nfu))
+ return ret;
+
+ gf_log (GF_NFS, GF_LOG_TRACE, "Mknod: %s", pathloc->path);
+ nfs_fop_handle_frame_create (frame, xl, nfu, ret, err);
+ nfs_fop_handle_local_init (frame, xl, nfl, cbk, local, ret, err);
+ nfs_fop_save_root_ino (nfl, pathloc);
+
+ STACK_WIND_COOKIE (frame, nfs_fop_mknod_cbk, xl, xl, xl->fops->mknod,
+ pathloc, mode, dev);
+ ret = 0;
+err:
+ if (ret < 0) {
+ if (frame)
+ nfs_stack_destroy (frame);
+ }
+
+ return ret;
+
+}
+
+int32_t
+nfs_fop_rmdir_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
+ int32_t op_ret, int32_t op_errno, struct iatt *preparent,
+ struct iatt *postparent)
+{
+ struct nfs_fop_local *nfl = frame->local;
+ fop_rmdir_cbk_t progcbk = NULL;
+
+ nfl_to_prog_data (this, nfl, progcbk, frame);
+ nfs_fop_restore_root_ino (nfl, NULL, NULL, preparent, postparent);
+ if (progcbk)
+ progcbk (frame, cookie, this, op_ret, op_errno, preparent,
+ postparent);
+ nfs_stack_destroy (frame);
+ return 0;
+}
+
+
+
+int
+nfs_fop_rmdir (xlator_t *xl, nfs_user_t *nfu, loc_t *pathloc,
+ fop_rmdir_cbk_t cbk, void *local)
+{
+ call_frame_t *frame = NULL;
+ int ret = -EFAULT;
+ struct nfs_fop_local *nfl = NULL;
+
+ if ((!xl) || (!pathloc) || (!nfu))
+ return ret;
+
+ gf_log (GF_NFS, GF_LOG_TRACE, "Rmdir: %s", pathloc->path);
+ nfs_fop_handle_frame_create (frame, xl, nfu, ret, err);
+ nfs_fop_handle_local_init (frame, xl, nfl, cbk, local, ret, err);
+ nfs_fop_save_root_ino (nfl, pathloc);
+
+ STACK_WIND_COOKIE (frame, nfs_fop_rmdir_cbk, xl, xl, xl->fops->rmdir,
+ pathloc);
+ ret = 0;
+err:
+ if (ret < 0) {
+ if (frame)
+ nfs_stack_destroy (frame);
+ }
+
+ return ret;
+
+}
+
+
+int32_t
+nfs_fop_unlink_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
+ int32_t op_ret, int32_t op_errno, struct iatt *preparent,
+ struct iatt *postparent)
+{
+ struct nfs_fop_local *nfl = frame->local;
+ fop_unlink_cbk_t progcbk = NULL;
+
+ nfl_to_prog_data (this, nfl, progcbk, frame);
+ nfs_fop_restore_root_ino (nfl, NULL, NULL, preparent, postparent);
+ if (progcbk)
+ progcbk (frame, cookie, this, op_ret, op_errno, preparent,
+ postparent);
+ nfs_stack_destroy (frame);
+ return 0;
+}
+
+
+int
+nfs_fop_unlink (xlator_t *xl, nfs_user_t *nfu, loc_t *pathloc,
+ fop_unlink_cbk_t cbk, void *local)
+{
+ call_frame_t *frame = NULL;
+ int ret = -EFAULT;
+ struct nfs_fop_local *nfl = NULL;
+
+ if ((!xl) || (!pathloc) || (!nfu))
+ return ret;
+
+ gf_log (GF_NFS, GF_LOG_TRACE, "Unlink: %s", pathloc->path);
+ nfs_fop_handle_frame_create (frame, xl, nfu, ret, err);
+ nfs_fop_handle_local_init (frame, xl, nfl, cbk, local, ret, err);
+ nfs_fop_save_root_ino (nfl, pathloc);
+
+ STACK_WIND_COOKIE (frame, nfs_fop_unlink_cbk, xl, xl, xl->fops->unlink,
+ pathloc);
+ ret = 0;
+err:
+ if (ret < 0) {
+ if (frame)
+ nfs_stack_destroy (frame);
+ }
+
+ return ret;
+
+}
+
+
+int32_t
+nfs_fop_link_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
+ int32_t op_ret, int32_t op_errno, inode_t *inode,
+ struct iatt *buf, struct iatt *preparent,
+ struct iatt *postparent)
+{
+ struct nfs_fop_local *nfl = NULL;
+ fop_link_cbk_t progcbk = NULL;
+
+ nfl_to_prog_data (this, nfl, progcbk, frame);
+ nfs_fop_restore_root_ino (nfl, buf, NULL, preparent, postparent);
+ if (progcbk)
+ progcbk (frame, cookie, this, op_ret, op_errno, inode, buf,
+ preparent, postparent);
+
+ nfs_stack_destroy (frame);
+ return 0;
+}
+
+
+int
+nfs_fop_link (xlator_t *xl, nfs_user_t *nfu, loc_t *oldloc, loc_t *newloc,
+ fop_link_cbk_t cbk, void *local)
+{
+ call_frame_t *frame = NULL;
+ int ret = -EFAULT;
+ struct nfs_fop_local *nfl = NULL;
+
+ if ((!xl) || (!oldloc) || (!newloc) || (!nfu))
+ return ret;
+
+ gf_log (GF_NFS, GF_LOG_TRACE, "Link: %s -> %s", newloc->path,
+ oldloc->path);
+ nfs_fop_handle_frame_create (frame, xl, nfu, ret, err);
+ nfs_fop_handle_local_init (frame, xl, nfl, cbk, local, ret, err);
+ nfs_fop_save_root_ino (nfl, newloc);
+
+ STACK_WIND_COOKIE (frame, nfs_fop_link_cbk, xl, xl, xl->fops->link,
+ oldloc, newloc);
+ ret = 0;
+err:
+ if (ret < 0) {
+ if (frame)
+ nfs_stack_destroy (frame);
+ }
+
+ return ret;
+}
+
+
+int32_t
+nfs_fop_rename_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
+ int32_t op_ret, int32_t op_errno, struct iatt *buf,
+ struct iatt *preoldparent, struct iatt *postoldparent,
+ struct iatt *prenewparent, struct iatt *postnewparent)
+{
+
+ struct nfs_fop_local *nfl = NULL;
+ fop_rename_cbk_t progcbk = NULL;
+
+ nfl_to_prog_data (this, nfl, progcbk, frame);
+ /* The preattr arg needs to be NULL instead of @buf because it is
+ * possible that the new parent is not root whereas the source dir
+ * could've been. That is handled in the next macro.
+ */
+ nfs_fop_restore_root_ino (nfl, NULL, NULL, preoldparent, postoldparent);
+ nfs_fop_newloc_restore_root_ino (nfl, buf, NULL, prenewparent,
+ postnewparent);
+ if (progcbk)
+ progcbk (frame, cookie, this, op_ret, op_errno, buf,
+ preoldparent, postoldparent, prenewparent,
+ postnewparent);
+ nfs_stack_destroy (frame);
+ return 0;
+}
+
+
+int
+nfs_fop_rename (xlator_t *xl, nfs_user_t *nfu, loc_t *oldloc,
+ loc_t *newloc, fop_rename_cbk_t cbk, void *local)
+{
+ call_frame_t *frame = NULL;
+ int ret = -EFAULT;
+ struct nfs_fop_local *nfl = NULL;
+
+ if ((!xl) || (!oldloc) || (!newloc) || (!nfu))
+ return ret;
+
+ gf_log (GF_NFS, GF_LOG_TRACE, "Rename: %s -> %s", oldloc->path,
+ newloc->path);
+ nfs_fop_handle_frame_create (frame, xl, nfu, ret, err);
+ nfs_fop_handle_local_init (frame, xl, nfl, cbk, local, ret, err);
+ nfs_fop_save_root_ino (nfl, oldloc);
+ nfs_fop_newloc_save_root_ino (nfl, newloc);
+
+ STACK_WIND_COOKIE (frame, nfs_fop_rename_cbk, xl, xl, xl->fops->rename,
+ oldloc, newloc);
+ ret = 0;
+err:
+ if (ret < 0) {
+ if (frame)
+ nfs_stack_destroy (frame);
+ }
+
+ return ret;
+}
+
+
+int32_t
+nfs_fop_open_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
+ int32_t op_ret, int32_t op_errno, fd_t *fd)
+{
+ struct nfs_fop_local *nfl = NULL;
+ fop_open_cbk_t progcbk = NULL;
+
+ nfl_to_prog_data (this, nfl, progcbk, frame);
+ if (progcbk)
+ progcbk (frame, cookie, this, op_ret, op_errno, fd);
+ nfs_stack_destroy (frame);
+
+ return 0;
+}
+
+int
+nfs_fop_open (xlator_t *xl, nfs_user_t *nfu, loc_t *loc, int32_t flags,
+ fd_t *fd, int32_t wbflags, fop_open_cbk_t cbk, void *local)
+{
+ call_frame_t *frame = NULL;
+ int ret = -EFAULT;
+ struct nfs_fop_local *nfl = NULL;
+
+ if ((!xl) || (!loc) || (!fd) || (!nfu))
+ return ret;
+
+ gf_log (GF_NFS, GF_LOG_TRACE, "Open: %s", loc->path);
+ nfs_fop_handle_frame_create (frame, xl, nfu, ret, err);
+ nfs_fop_handle_local_init (frame, xl, nfl, cbk, local, ret, err);
+
+ STACK_WIND_COOKIE (frame, nfs_fop_open_cbk, xl, xl, xl->fops->open,
+ loc, flags, fd, wbflags);
+ ret = 0;
+err:
+ if (ret < 0) {
+ if (frame)
+ nfs_stack_destroy (frame);
+ }
+
+ return ret;
+
+}
+
+
+int32_t
+nfs_fop_writev_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
+ int32_t op_ret, int32_t op_errno, struct iatt *prebuf,
+ struct iatt *postbuf)
+{
+ struct nfs_fop_local *nfl = NULL;
+ fop_writev_cbk_t progcbk = NULL;
+
+ nfl_to_prog_data (this, nfl, progcbk, frame);
+ nfs_fop_restore_root_ino (nfl, prebuf, postbuf, NULL, NULL);
+ if (progcbk)
+ progcbk (frame, cookie, this, op_ret, op_errno, prebuf,postbuf);
+
+ nfs_stack_destroy (frame);
+
+ return 0;
+}
+
+
+int
+nfs_fop_write (xlator_t *xl, nfs_user_t *nfu, fd_t *fd, struct iobuf *srciob,
+ struct iovec *vector, int32_t count, off_t offset,
+ fop_writev_cbk_t cbk, void *local)
+{
+ call_frame_t *frame = NULL;
+ int ret = -EFAULT;
+ struct nfs_fop_local *nfl = NULL;
+
+ if ((!xl) || (!fd) || (!vector) || (!nfu) || (!srciob))
+ return ret;
+
+ nfs_fop_handle_frame_create (frame, xl, nfu, ret, err);
+ nfs_fop_handle_local_init (frame, xl, nfl, cbk, local, ret, err);
+ nfs_fop_save_root_fd_ino (nfl, fd);
+
+ nfl->iobref = iobref_new ();
+ if (!nfl->iobref) {
+ gf_log (GF_NFS, GF_LOG_ERROR, "iobref creation failed");
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ iobref_add (nfl->iobref, srciob);
+ STACK_WIND_COOKIE (frame, nfs_fop_writev_cbk, xl, xl, xl->fops->writev
+ , fd, vector, count, offset, nfl->iobref);
+ ret = 0;
+err:
+ if (ret < 0) {
+ if (frame)
+ nfs_stack_destroy (frame);
+ nfs_fop_local_wipe (xl, nfl);
+ }
+
+ return ret;
+}
+
+
+int32_t
+nfs_fop_fsync_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
+ int32_t op_ret, int32_t op_errno, struct iatt *prebuf,
+ struct iatt *postbuf)
+{
+ struct nfs_fop_local *nfl = NULL;
+ fop_fsync_cbk_t progcbk = NULL;
+
+ nfl_to_prog_data (this, nfl, progcbk, frame);
+ nfs_fop_restore_root_ino (nfl, prebuf, postbuf, NULL, NULL);
+ if (progcbk)
+ progcbk (frame, cookie, this, op_ret, op_errno, prebuf,postbuf);
+ nfs_stack_destroy (frame);
+ return 0;
+}
+
+
+
+int
+nfs_fop_fsync (xlator_t *xl, nfs_user_t *nfu, fd_t *fd, int32_t datasync,
+ fop_fsync_cbk_t cbk, void *local)
+{
+ call_frame_t *frame = NULL;
+ int ret = -EFAULT;
+ struct nfs_fop_local *nfl = NULL;
+
+ if ((!xl) || (!fd))
+ return ret;
+
+ nfs_fop_handle_frame_create (frame, xl, nfu, ret, err);
+ nfs_fop_handle_local_init (frame, xl, nfl, cbk, local, ret, err);
+ nfs_fop_save_root_fd_ino (nfl, fd);
+
+ STACK_WIND_COOKIE (frame, nfs_fop_fsync_cbk, xl, xl,
+ xl->fops->fsync, fd, datasync);
+ ret = 0;
+err:
+ if (ret < 0) {
+ if (frame)
+ nfs_stack_destroy (frame);
+ }
+
+ return ret;
+}
+
+
+int32_t
+nfs_fop_readv_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
+ int32_t op_ret, int32_t op_errno, struct iovec *vector,
+ int32_t count, struct iatt *stbuf, struct iobref *iobref)
+{
+ struct nfs_fop_local *nfl = NULL;
+ fop_readv_cbk_t progcbk = NULL;
+
+ nfl_to_prog_data (this, nfl, progcbk, frame);
+ nfs_fop_restore_root_ino (nfl, stbuf, NULL, NULL, NULL);
+ if (progcbk)
+ progcbk (frame, cookie, this, op_ret, op_errno, vector, count,
+ stbuf, iobref);
+
+ nfs_stack_destroy (frame);
+ return 0;
+}
+
+
+int
+nfs_fop_read (xlator_t *xl, nfs_user_t *nfu, fd_t *fd, size_t size,
+ off_t offset, fop_readv_cbk_t cbk, void *local)
+{
+ call_frame_t *frame = NULL;
+ int ret = -EFAULT;
+ struct nfs_fop_local *nfl = NULL;
+
+ if ((!xl) || (!fd) || (!nfu))
+ return ret;
+
+ nfs_fop_handle_frame_create (frame, xl, nfu, ret, err);
+ nfs_fop_handle_local_init (frame, xl, nfl, cbk, local, ret, err);
+ nfs_fop_save_root_fd_ino (nfl, fd);
+
+ STACK_WIND_COOKIE (frame, nfs_fop_readv_cbk, xl, xl, xl->fops->readv, fd
+ , size, offset);
+ ret = 0;
+err:
+ if (ret < 0) {
+ if (frame)
+ nfs_stack_destroy (frame);
+ }
+
+ return ret;
+}
+
+
+int32_t
+nfs_fop_truncate_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
+ int32_t op_ret, int32_t op_errno, struct iatt *prebuf,
+ struct iatt *postbuf)
+{
+ struct nfs_fop_local *nfl = NULL;
+ fop_truncate_cbk_t progcbk = NULL;
+
+ nfl_to_prog_data (this, nfl, progcbk, frame);
+ nfs_fop_restore_root_ino (nfl, prebuf, postbuf, NULL, NULL);
+ if (progcbk)
+ progcbk (frame, cookie, this, op_ret, op_errno, prebuf,postbuf);
+
+ nfs_stack_destroy (frame);
+ return 0;
+}
+
+
+int
+nfs_fop_truncate (xlator_t *xl, nfs_user_t *nfu, loc_t *loc, off_t offset,
+ fop_truncate_cbk_t cbk, void *local)
+{
+ call_frame_t *frame = NULL;
+ int ret = -EFAULT;
+ struct nfs_fop_local *nfl = NULL;
+
+ if ((!xl) || (!loc) || (!nfu))
+ return ret;
+
+ nfs_fop_handle_frame_create (frame, xl, nfu, ret, err);
+ nfs_fop_handle_local_init (frame, xl, nfl, cbk, local, ret, err);
+ nfs_fop_save_root_ino (nfl, loc);
+
+ STACK_WIND_COOKIE (frame, nfs_fop_truncate_cbk, xl, xl,
+ xl->fops->truncate, loc, offset);
+
+ ret = 0;
+err:
+ if (ret < 0) {
+ if (frame)
+ nfs_stack_destroy (frame);
+ }
+
+ return ret;
+}
+
+
+int
+nfs_fop_lookup_sync_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
+ int32_t op_ret, int32_t op_errno, inode_t *inode,
+ struct iatt *buf, dict_t *xattr,
+ struct iatt *postparent)
+{
+ nfs_syncfop_t *sf = frame->local;
+
+ if (!sf)
+ return -1;
+
+ if (op_ret == -1)
+ gf_log (GF_NFS, GF_LOG_TRACE, "Sync lookup failed: %s",
+ strerror (op_errno));
+ else
+ gf_log (GF_NFS, GF_LOG_TRACE, "Sync lookup done");
+
+ sf->replystub = fop_lookup_cbk_stub (frame, NULL, op_ret, op_errno,
+ inode, buf, xattr, postparent);
+ nfs_syncfop_notify (sf);
+ return 0;
+}
+
+
+call_stub_t *
+nfs_fop_lookup_sync (xlator_t *xl, nfs_user_t *nfu, loc_t *loc)
+{
+ nfs_syncfop_t *sf = NULL;
+ call_stub_t *reply = NULL;
+ int ret = -1;
+
+ if ((!xl) || (!loc) || (!nfu))
+ return NULL;
+
+ sf = nfs_syncfop_init ();
+ if (!sf) {
+ gf_log (GF_NFS, GF_LOG_ERROR, "synclocal init failed");
+ goto err;
+ }
+
+ ret = nfs_fop_lookup (xl, nfu, loc, nfs_fop_lookup_sync_cbk, sf);
+ if (ret < 0) {
+ gf_log (GF_NFS, GF_LOG_ERROR, "Sync lookup failed");
+ goto err;
+ }
+
+ reply = nfs_syncfop_wait (sf);
+
+err:
+ return reply;
+}
+
+
+
+int32_t
+nfs_fop_readdirp_sync_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
+ int32_t op_ret, int32_t op_errno,
+ gf_dirent_t *entries)
+{
+ nfs_syncfop_t *sf = frame->local;
+
+ if (op_ret == -1)
+ gf_log (GF_NFS, GF_LOG_TRACE, "Sync readdir failed: %s",
+ strerror (op_errno));
+ else
+ gf_log (GF_NFS, GF_LOG_TRACE, "Sync readdir done");
+
+ sf->replystub = fop_readdirp_cbk_stub (frame, NULL, op_ret, op_errno,
+ entries);
+
+ nfs_syncfop_notify (sf);
+ return 0;
+}
+
+
+/* This function does not update or map the st_dev in the d_stat of all the
+ * entries that were read. That mapping for the sync version of readdiring
+ * happens in the dcache.
+ */
+call_stub_t *
+nfs_fop_readdirp_sync (xlator_t *fopxl, nfs_user_t *nfu, fd_t *dirfd,
+ off_t offset, size_t bufsize)
+{
+ nfs_syncfop_t *sf = NULL;
+ call_stub_t *reply = NULL;
+ int ret = -1;
+
+ if ((!fopxl) || (!nfu) || (!dirfd))
+ return NULL;
+
+ sf = nfs_syncfop_init ();
+ if (!sf) {
+ gf_log (GF_NFS, GF_LOG_ERROR, "sync fop local init failed");
+ goto ret;
+ }
+
+ ret = nfs_fop_readdirp (fopxl, nfu, dirfd, bufsize, offset,
+ nfs_fop_readdirp_sync_cbk, sf);
+ if (ret < 0) {
+ gf_log (GF_NFS, GF_LOG_ERROR, "Fop readdir failed: %s",
+ strerror (-ret));
+ goto ret;
+ }
+
+ reply = nfs_syncfop_wait (sf);
+
+ret:
+ return reply;
+}
+
+
+
+nfs_syncfop_t *
+nfs_syncfop_init ()
+{
+ nfs_syncfop_t *sfl = NULL;
+
+ sfl = CALLOC (1, sizeof (*sfl));
+ if (!sfl) {
+ gf_log (GF_NFS, GF_LOG_ERROR, "Memory allocation failed");
+ return NULL;
+ }
+
+ sem_init (&sfl->replysig, 0, 0);
+
+ return sfl;
+}
+
+
+call_stub_t *
+nfs_syncfop_wait (nfs_syncfop_t *s)
+{
+ call_stub_t *replystub = NULL;
+
+ gf_log (GF_NFS, GF_LOG_TRACE, "Waiting for sync fop");
+ sem_wait (&s->replysig);
+ gf_log (GF_NFS, GF_LOG_TRACE, "Sync fop notification received");
+ replystub = s->replystub;
+ FREE (s);
+ return replystub;
+}
+
+
+void
+nfs_syncfop_notify (nfs_syncfop_t *s)
+{
+ sem_post (&s->replysig);
+ gf_log (GF_NFS, GF_LOG_TRACE, "Sync fop notified");
+}
+
+
+
diff --git a/xlators/nfs/server/src/nfs-fops.h b/xlators/nfs/server/src/nfs-fops.h
new file mode 100644
index 000000000..8b12777d7
--- /dev/null
+++ b/xlators/nfs/server/src/nfs-fops.h
@@ -0,0 +1,259 @@
+/*
+ Copyright (c) 2010 Gluster, Inc. <http://www.gluster.com>
+ This file is part of GlusterFS.
+
+ GlusterFS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3 of the License,
+ or (at your option) any later version.
+
+ GlusterFS is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see
+ <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _NFS_FOPS_H_
+#define _NFS_FOPS_H_
+
+#ifndef _CONFIG_H
+#define _CONFIG_H
+#include "config.h"
+#endif
+
+#include "dict.h"
+#include "xlator.h"
+#include "iobuf.h"
+#include "call-stub.h"
+#include "stack.h"
+#include "nfs.h"
+#include "nfs-common.h"
+#include <semaphore.h>
+
+/* This structure used to communicate state between a fop and its callback.
+ * The problem is, when we're calling a fop in the nfs op handler, the callback
+ * is the NFS protocol's callback and we have to perform all GlusterFS
+ * inode, inode table, fd_ts and fd table operations in the NFS callback. That
+ * approach soon gets extremely complicated and confusing because, then we have
+ * to try and separate in our heads which source lines in those callbacks are
+ * required for serving the NFS op and which ones are needed for satisfying
+ * GlusterFS requirements. This structure allows us avoid performing GlusterFS
+ * state maintenance operations inside the fops layer itself. Now, before
+ * we call the callback registered by the NFS operation, a hidden fops-layer
+ * specific callback is called which performs the state maintenance and then
+ * calls the NFS callback.
+ *
+ * These are allocated from a mem-pool stored in the nfs xlator's state.
+ * i.e. struct nfs_state.
+ * That is initiated in nfs_init_subvolumes in nfs.c.
+ */
+struct nfs_fop_local {
+ /* The local sent along by the user of the fop. */
+ void *proglocal;
+
+ /* The address of the callback supplied by the user. After our
+ * callback is executed this one is called.
+ * The exact cast destination of this pointer will depend on the
+ * fop that is being called.
+ */
+ void *progcbk;
+
+ /* Used only for write requests. */
+ struct iobref *iobref;
+
+ inode_t *parent;
+ inode_t *newparent;
+ inode_t *inode;
+
+ /* Set to 1 by nfs-inodes layer, which uses this to decide whether to
+ * link the newly allocated inode into the itable, in case the fop was
+ * successful.
+ */
+ int newinode;
+
+ /* Used by nfs-fops layer in order to determine whether to funge the
+ * ino in a dir's stbuf. This funging of root ino is needed to ensure
+ * that the root ino remains 1 even when the NFS server has been
+ * restarted. Note that in distribute, a fresh lookup and a revalidate
+ * on the root inode returns two different inode numbers and this we
+ * need to handle by ourself.
+ */
+ int rootinode;
+
+ /* This member is used to determine whether the new parent of a file
+ * being renamed is the root directory. If yes, the ino is funged.
+ */
+ int newrootinode;
+ int newrootparentinode;
+
+ /* Determines whether to funge the ino in the post and pre parent
+ * stbufs for a file/dir where the parent directory could be the root
+ * dir. Needed here because of the same reason as above.
+ */
+ int rootparentinode;
+
+ char path[NFS_NAME_MAX];
+ char newpath[NFS_NAME_MAX];
+};
+
+extern struct nfs_fop_local *
+nfs_fop_local_init (xlator_t *xl);
+
+extern void
+nfs_fop_local_wipe (xlator_t *xl, struct nfs_fop_local *l);
+
+#define xlator_top_private(xl) ((struct nfs_state *)((xlator_t *)(xl)->ctx->top)->private)
+
+#define prog_data_to_nfl(xla, nflocal, fram, pcbk, plocal) \
+ do { \
+ nflocal = nfs_fop_local_init (xla); \
+ if (nflocal) { \
+ nflocal->proglocal = plocal; \
+ nflocal->progcbk = pcbk; \
+ if (fram) \
+ ((call_frame_t *)fram)->local = nflocal; \
+ } \
+ } while (0) \
+
+
+
+#define nfl_to_prog_data(xla, nflocal, pcbk, fram) \
+ do { \
+ nflocal = fram->local; \
+ fram->local = nflocal->proglocal; \
+ pcbk = nflocal->progcbk; \
+ nfs_fop_local_wipe (xla, nflocal); \
+ } while (0) \
+
+#define nfs_fop_handle_local_init(fram, xla, nfloc, cbck,prgloc,retval,lab) \
+ do { \
+ prog_data_to_nfl (xla, nfloc, fram, cbck, prgloc); \
+ if (!nfloc) { \
+ gf_log (GF_NFS,GF_LOG_ERROR,"Failed to init local");\
+ retval = -ENOMEM; \
+ goto lab; \
+ } \
+ } while (0) \
+
+extern int
+nfs_fop_fstat (xlator_t *xl, nfs_user_t *nfu, fd_t *fd,
+ fop_stat_cbk_t cbk, void *local);
+
+extern int
+nfs_fop_readdirp (xlator_t *xl, nfs_user_t *nfu, fd_t *dirfd,
+ size_t bufsize, off_t offset, fop_readdir_cbk_t cbk,
+ void *local);
+extern int
+nfs_fop_lookup (xlator_t *xl, nfs_user_t *nfu, loc_t *loc,
+ fop_lookup_cbk_t cbk, void *local);
+
+extern int
+nfs_fop_create (xlator_t *xl, nfs_user_t *nfu, loc_t *pathloc, int flags,
+ mode_t mode, fd_t *fd, fop_create_cbk_t cbk, void *local);
+extern int
+nfs_fop_flush (xlator_t *xl, nfs_user_t *nfu, fd_t *fd,
+ fop_flush_cbk_t cbk, void *local);
+
+extern int
+nfs_fop_mkdir (xlator_t *xl, nfs_user_t *nfu, loc_t *pathloc, mode_t mode,
+ fop_mkdir_cbk_t cbk, void *local);
+
+extern int
+nfs_fop_truncate (xlator_t *xl, nfs_user_t *nfu, loc_t *loc, off_t offset,
+ fop_truncate_cbk_t cbk, void *local);
+
+extern int
+nfs_fop_read (xlator_t *xl, nfs_user_t *nfu, fd_t *fd, size_t size,
+ off_t offset, fop_readv_cbk_t cbk, void *local);
+
+extern int
+nfs_fop_fsync (xlator_t *xl, nfs_user_t *nfu, fd_t *fd, int32_t datasync,
+ fop_fsync_cbk_t cbk, void *local);
+
+extern int
+nfs_fop_write (xlator_t *xl, nfs_user_t *nfu, fd_t *fd, struct iobuf *srciob,
+ struct iovec *vector, int32_t count, off_t offset,
+ fop_writev_cbk_t cbk, void *local);
+
+extern int
+nfs_fop_open (xlator_t *xl, nfs_user_t *nfu, loc_t *loc, int32_t flags,
+ fd_t *fd, int32_t wbflags, fop_open_cbk_t cbk, void *local);
+
+extern int
+nfs_fop_rename (xlator_t *xl, nfs_user_t *nfu, loc_t *oldloc,
+ loc_t *newloc, fop_rename_cbk_t cbk, void *local);
+
+extern int
+nfs_fop_link (xlator_t *xl, nfs_user_t *nfu, loc_t *oldloc, loc_t *newloc,
+ fop_link_cbk_t cbk, void *local);
+
+extern int
+nfs_fop_unlink (xlator_t *xl, nfs_user_t *nfu, loc_t *pathloc,
+ fop_unlink_cbk_t cbk, void *local);
+
+extern int
+nfs_fop_rmdir (xlator_t *xl, nfs_user_t *nfu, loc_t *pathloc,
+ fop_rmdir_cbk_t cbk, void *local);
+
+extern int
+nfs_fop_mknod (xlator_t *xl, nfs_user_t *nfu, loc_t *pathloc, mode_t mode,
+ dev_t dev, fop_mknod_cbk_t cbk, void *local);
+
+extern int
+nfs_fop_readlink (xlator_t *xl, nfs_user_t *nfu, loc_t *pathloc,
+ size_t size, fop_readlink_cbk_t cbk, void *local);
+
+extern int
+nfs_fop_symlink (xlator_t *xl, nfs_user_t *nfu, char *target,
+ loc_t *pathloc, fop_symlink_cbk_t cbk, void *local);
+
+extern int
+nfs_fop_setattr (xlator_t *xl, nfs_user_t *nfu, loc_t *pathloc,
+ struct iatt *buf, int32_t valid, fop_setattr_cbk_t cbk,
+ void *local);
+
+extern int
+nfs_fop_statfs (xlator_t *xl, nfs_user_t *nfu, loc_t *pathloc,
+ fop_statfs_cbk_t cbk, void *local);
+
+extern int
+nfs_fop_opendir (xlator_t *xl, nfs_user_t *nfu, loc_t *pathloc,fd_t *dirfd,
+ fop_opendir_cbk_t cbk, void *local);
+
+extern int
+nfs_fop_stat (xlator_t *xl, nfs_user_t *nfu, loc_t *loc,
+ fop_stat_cbk_t cbk, void *local);
+
+/* Synchronous equivalents of some of the fops above.
+ */
+
+/* sfl = sync fop local
+ * Structure used to turn async fops into sync calls for certain NFS ops
+ * that need blocking operations.
+ */
+typedef struct nfs_syncfop {
+ sem_t replysig;
+ call_stub_t *replystub;
+} nfs_syncfop_t;
+
+extern nfs_syncfop_t *
+nfs_syncfop_init ();
+
+extern call_stub_t *
+nfs_syncfop_wait (nfs_syncfop_t *s);
+
+extern void
+nfs_syncfop_notify (nfs_syncfop_t *s);
+
+extern call_stub_t *
+nfs_fop_lookup_sync (xlator_t *xl, nfs_user_t *nfu, loc_t *loc);
+
+extern call_stub_t *
+nfs_fop_readdirp_sync (xlator_t *fopxl, nfs_user_t *nfu, fd_t *dirfd,
+ off_t offset, size_t bufsize);
+
+#endif
diff --git a/xlators/nfs/server/src/nfs-generics.c b/xlators/nfs/server/src/nfs-generics.c
new file mode 100644
index 000000000..f83a7c868
--- /dev/null
+++ b/xlators/nfs/server/src/nfs-generics.c
@@ -0,0 +1,1067 @@
+/*
+ Copyright (c) 2010 Gluster, Inc. <http://www.gluster.com>
+ This file is part of GlusterFS.
+
+ GlusterFS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3 of the License,
+ or (at your option) any later version.
+
+ GlusterFS is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see
+ <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _CONFIG_H
+#define _CONFIG_H
+#include "config.h"
+#endif
+
+
+#include "string.h"
+
+#include "inode.h"
+#include "nfs.h"
+#include "nfs-fops.h"
+#include "nfs-inodes.h"
+#include "nfs-generics.h"
+#include "xlator.h"
+
+
+int
+nfs_fstat (xlator_t *xl, nfs_user_t *nfu, fd_t *fd, fop_stat_cbk_t cbk,
+ void *local)
+{
+ int ret = -EFAULT;
+
+ if ((!xl) || (!fd) || (!nfu))
+ return ret;
+
+ ret = nfs_fop_fstat (xl, nfu, fd, cbk, local);
+ return ret;
+}
+
+
+int
+nfs_stat (xlator_t *xl, nfs_user_t *nfu, loc_t *pathloc, fop_stat_cbk_t cbk,
+ void *local)
+{
+ int ret = -EFAULT;
+
+ if ((!xl) || (!pathloc) || (!nfu))
+ return ret;
+
+ ret = nfs_fop_stat (xl, nfu, pathloc, cbk, local);
+
+ return ret;
+}
+
+
+
+int
+nfs_readdirp (xlator_t *xl, nfs_user_t *nfu, fd_t *dirfd, size_t bufsize,
+ off_t offset, fop_readdir_cbk_t cbk, void *local)
+{
+ if ((!xl) || (!dirfd) || (!nfu))
+ return -EFAULT;
+
+ return nfs_fop_readdirp (xl, nfu, dirfd, bufsize, offset, cbk,
+ local);
+}
+
+
+
+int
+nfs_lookup (xlator_t *xl, nfs_user_t *nfu, loc_t *pathloc,
+ fop_lookup_cbk_t cbk, void *local)
+{
+ int ret = -EFAULT;
+
+ if ((!xl) || (!pathloc) || (!nfu))
+ return ret;
+
+ ret = nfs_fop_lookup (xl, nfu, pathloc, cbk, local);
+ return ret;
+}
+
+int
+nfs_create (xlator_t *xl, nfs_user_t *nfu, loc_t *pathloc, int flags,
+ mode_t mode, fop_create_cbk_t cbk, void *local)
+{
+ int ret = -EFAULT;
+
+ if ((!xl) || (!pathloc) || (!nfu))
+ return ret;
+
+ ret = nfs_inode_create (xl, nfu, pathloc, flags, mode, cbk,local);
+ return ret;
+}
+
+
+int
+nfs_flush (xlator_t *xl, nfs_user_t *nfu, fd_t *fd, fop_flush_cbk_t cbk,
+ void *local)
+{
+ return nfs_fop_flush (xl, nfu, fd, cbk, local);
+}
+
+
+
+int
+nfs_mkdir (xlator_t *xl, nfs_user_t *nfu, loc_t *pathloc, mode_t mode,
+ fop_mkdir_cbk_t cbk, void *local)
+{
+ int ret = -EFAULT;
+
+ if ((!xl) || (!pathloc) || (!nfu))
+ return ret;
+
+ ret = nfs_inode_mkdir (xl, nfu, pathloc, mode, cbk, local);
+ return ret;
+}
+
+
+
+int
+nfs_truncate (xlator_t *xl, nfs_user_t *nfu, loc_t *pathloc, off_t offset,
+ fop_truncate_cbk_t cbk, void *local)
+{
+ int ret = -EFAULT;
+
+ if ((!xl) || (!pathloc) || (!nfu))
+ return ret;
+
+ ret = nfs_fop_truncate (xl, nfu, pathloc, offset, cbk, local);
+ return ret;
+}
+
+
+int
+nfs_read (xlator_t *xl, nfs_user_t *nfu, fd_t *fd, size_t size,
+ off_t offset, fop_readv_cbk_t cbk, void *local)
+{
+ return nfs_fop_read (xl, nfu, fd, size, offset, cbk, local);
+}
+
+
+int
+nfs_fsync (xlator_t *xl, nfs_user_t *nfu, fd_t *fd, int32_t datasync,
+ fop_fsync_cbk_t cbk, void *local)
+{
+ return nfs_fop_fsync (xl, nfu, fd, datasync, cbk, local);
+}
+
+
+int
+nfs_write (xlator_t *xl, nfs_user_t *nfu, fd_t *fd, struct iobuf *srciob,
+ struct iovec *vector, int32_t count, off_t offset,
+ fop_writev_cbk_t cbk, void *local)
+{
+ return nfs_fop_write (xl, nfu, fd, srciob, vector, count, offset, cbk,
+ local);
+}
+
+
+int
+nfs_open (xlator_t *xl, nfs_user_t *nfu, loc_t *pathloc, int32_t flags,
+ fop_open_cbk_t cbk, void *local)
+{
+ int ret = -EFAULT;
+
+ if ((!xl) || (!pathloc) || (!nfu))
+ return ret;
+
+ ret = nfs_inode_open (xl, nfu, pathloc, flags, GF_OPEN_NOWB, cbk,
+ local);
+ return ret;
+}
+
+
+int
+nfs_rename (xlator_t *xl, nfs_user_t *nfu, loc_t *oldloc, loc_t *newloc,
+ fop_rename_cbk_t cbk, void *local)
+{
+ int ret = -EFAULT;
+
+ if ((!xl) || (!oldloc) || (!newloc) || (!nfu))
+ return ret;
+
+ ret = nfs_inode_rename (xl, nfu, oldloc, newloc, cbk, local);
+ return ret;
+}
+
+
+int
+nfs_link (xlator_t *xl, nfs_user_t *nfu, loc_t *oldloc, loc_t *newloc,
+ fop_link_cbk_t cbk, void *local)
+{
+ int ret = -EFAULT;
+
+ if ((!xl) || (!oldloc) || (!newloc) || (!nfu))
+ return ret;
+
+ ret = nfs_inode_link (xl, nfu, oldloc, newloc, cbk, local);
+ return ret;
+}
+
+
+int
+nfs_unlink (xlator_t *xl, nfs_user_t *nfu, loc_t *pathloc,
+ fop_unlink_cbk_t cbk, void *local)
+{
+ int ret = -EFAULT;
+
+ if ((!xl) || (!pathloc) || (!nfu))
+ return ret;
+
+ ret = nfs_inode_unlink (xl, nfu, pathloc, cbk, local);
+ return ret;
+}
+
+
+int
+nfs_rmdir (xlator_t *xl, nfs_user_t *nfu, loc_t *path, fop_rmdir_cbk_t cbk,
+ void *local)
+{
+ int ret = -EFAULT;
+
+ if ((!xl) || (!path) || (!nfu))
+ return ret;
+
+ ret = nfs_inode_rmdir (xl, nfu, path, cbk, local);
+ return ret;
+}
+
+
+int
+nfs_mknod (xlator_t *xl, nfs_user_t *nfu, loc_t *pathloc, mode_t mode,
+ dev_t dev, fop_mknod_cbk_t cbk, void *local)
+{
+ int ret = -EFAULT;
+
+ if ((!xl) || (!pathloc) || (!nfu))
+ return ret;
+
+ ret = nfs_inode_mknod (xl, nfu, pathloc, mode, dev, cbk, local);
+ return ret;
+}
+
+
+int
+nfs_readlink (xlator_t *xl, nfs_user_t *nfu, loc_t *linkloc,
+ fop_readlink_cbk_t cbk, void *local)
+{
+ int ret = -EFAULT;
+
+ if ((!xl) || (!linkloc) || (!nfu))
+ return ret;
+
+ ret = nfs_fop_readlink (xl, nfu, linkloc, NFS_PATH_MAX, cbk, local);
+ return ret;
+}
+
+
+
+int
+nfs_symlink (xlator_t *xl, nfs_user_t *nfu, char *target, loc_t *linkloc,
+ fop_symlink_cbk_t cbk, void *local)
+{
+ int ret = -EFAULT;
+
+ if ((!xl) || (!linkloc) || (!target) || (!nfu))
+ return ret;
+
+ ret = nfs_inode_symlink (xl, nfu, target, linkloc, cbk, local);
+ return ret;
+}
+
+
+
+int
+nfs_setattr (xlator_t *xl, nfs_user_t *nfu, loc_t *pathloc,
+ struct iatt *buf, int32_t valid, fop_setattr_cbk_t cbk,
+ void *local)
+{
+ int ret = -EFAULT;
+
+ if ((!xl) || (!pathloc) || (!nfu))
+ return ret;
+
+ ret = nfs_fop_setattr (xl, nfu, pathloc, buf, valid, cbk, local);
+ return ret;
+}
+
+
+int
+nfs_statfs (xlator_t *xl, nfs_user_t *nfu, loc_t *pathloc,
+ fop_statfs_cbk_t cbk, void *local)
+{
+ int ret = -EFAULT;
+
+ if ((!xl) || (!pathloc) || (!nfu))
+ return ret;
+
+ ret = nfs_fop_statfs (xl, nfu, pathloc, cbk, local);
+ return ret;
+}
+
+
+int
+nfs_open_sync_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
+ int32_t op_ret, int32_t op_errno, fd_t *fd)
+{
+ nfs_syncfop_t *sf = frame->local;
+
+ if (!sf)
+ return -1;
+
+ if (op_ret == -1)
+ gf_log (GF_NFS, GF_LOG_TRACE, "Sync open failed: %s",
+ strerror (op_errno));
+ else
+ gf_log (GF_NFS, GF_LOG_TRACE, "Sync open done");
+
+ sf->replystub = fop_open_cbk_stub (frame, NULL, op_ret, op_errno, fd);
+
+ nfs_syncfop_notify (sf);
+ return 0;
+}
+
+
+call_stub_t *
+nfs_open_sync (xlator_t *xl, nfs_user_t *nfu, loc_t *pathloc, int32_t flags)
+{
+ nfs_syncfop_t *sf = NULL;
+ call_stub_t *reply = NULL;
+ int ret = -1;
+
+ if ((!xl) || (!pathloc) || (!nfu))
+ return NULL;
+
+ sf = nfs_syncfop_init ();
+ if (!sf) {
+ gf_log (GF_NFS, GF_LOG_ERROR, "synclocal init failed");
+ goto err;
+ }
+
+ ret = nfs_open (xl, nfu, pathloc, flags, nfs_open_sync_cbk, sf);
+ if (ret < 0)
+ goto err;
+
+ reply = nfs_syncfop_wait (sf);
+
+err:
+ if (ret < 0)
+ FREE (sf);
+
+ return reply;
+}
+
+
+
+int
+nfs_fdctx_alloc (fd_t *fd, xlator_t *xl)
+{
+ nfs_fdctx_t *fdctx = NULL;
+ int ret = -EFAULT;
+
+ if ((!fd) || (!xl))
+ return ret;
+
+ fdctx = CALLOC (1, sizeof (*fdctx));
+ if (!fdctx) {
+ gf_log (GF_NFS, GF_LOG_ERROR, "Memory allocation failure");
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ pthread_mutex_init (&fdctx->lock, NULL);
+
+ ret = fd_ctx_set (fd, xl, (uint64_t)fdctx);
+ if (ret == -1) {
+ gf_log (GF_NFS, GF_LOG_ERROR, "Failed to set fd context");
+ ret = -EFAULT;
+ goto free_ctx;
+ }
+
+ ret = 0;
+
+free_ctx:
+ if (ret < 0)
+ FREE (fdctx);
+
+err:
+ return ret;
+}
+
+
+void
+nfs_fdctx_del (fd_t *fd, xlator_t *xl)
+{
+ nfs_fdctx_t *fdctx = NULL;
+ uint64_t ctxaddr = 0;
+ int ret = -1;
+
+ if ((!fd) || (!xl))
+ return;
+
+ ret = fd_ctx_del (fd, xl, &ctxaddr);
+ if (ret == -1)
+ goto err;
+
+ fdctx = (nfs_fdctx_t *)ctxaddr;
+ FREE (fdctx);
+
+err:
+ return;
+}
+
+
+nfs_fdctx_t *
+nfs_fdctx_get (fd_t *fd, xlator_t *xl)
+{
+ nfs_fdctx_t *fdctx = NULL;
+ int ret = -1;
+ uint64_t ctxptr = 0;
+
+ if ((!fd) || (!xl))
+ return NULL;
+
+ ret = fd_ctx_get (fd, xl, &ctxptr);
+ if (ret == -1) {
+ gf_log (GF_NFS, GF_LOG_ERROR, "Failed to get fd context");
+ goto err;
+ }
+
+ fdctx = (nfs_fdctx_t *)ctxptr;
+err:
+ return fdctx;
+}
+
+
+int
+nfs_dir_fdctx_init (fd_t *dirfd, xlator_t *xl, xlator_t *fopxl, size_t bufsize)
+{
+ int ret = -EFAULT;
+ nfs_fdctx_t *fdctx = NULL;
+
+ if ((!dirfd) || (!xl))
+ return ret;
+
+ ret = nfs_fdctx_alloc (dirfd, xl);
+ if (ret < 0) {
+ gf_log (GF_NFS, GF_LOG_ERROR, "Failed to alloc dir fd context");
+ goto err;
+ }
+
+ fdctx = nfs_fdctx_get (dirfd, xl);
+ if (!fdctx) {
+ ret = -EFAULT;
+ gf_log (GF_NFS, GF_LOG_ERROR, "Failed to get dir fd context");
+ goto err;
+ }
+
+ fdctx->dcache = CALLOC (1, sizeof (struct nfs_direntcache));
+ if (!fdctx->dcache) {
+ ret = -ENOMEM;
+ gf_log (GF_NFS, GF_LOG_ERROR, "Failed to allocate dirent"
+ " cache");
+ goto free_ctx;
+ }
+
+ INIT_LIST_HEAD (&fdctx->dcache->entries.list);
+ fdctx->dirent_bufsize = bufsize;
+ fdctx->dirvol = fopxl;
+
+ ret = 0;
+
+free_ctx:
+ if (ret < 0)
+ nfs_fdctx_del (dirfd, xl);
+err:
+ return ret;
+}
+
+
+
+
+/* Dirent caching code copied from libglusterfsclient.
+ * Please duplicate enhancements and bug fixes there too.
+ */
+void
+nfs_dcache_invalidate (xlator_t *nfsx, fd_t *fd)
+{
+ nfs_fdctx_t *fd_ctx = NULL;
+
+ if (!fd)
+ return;
+
+ fd_ctx = nfs_fdctx_get (fd, nfsx);
+ if (!fd_ctx) {
+ gf_log (GF_NFS, GF_LOG_ERROR, "No fd context present");
+ return;
+ }
+
+ if (!fd_ctx->dcache) {
+ gf_log (GF_NFS, GF_LOG_TRACE, "No dirent cache present");
+ return;
+ }
+
+ if (!list_empty (&fd_ctx->dcache->entries.list)) {
+ gf_log (GF_NFS, GF_LOG_TRACE, "Freeing dirents");
+ gf_dirent_free (&fd_ctx->dcache->entries);
+ }
+
+ INIT_LIST_HEAD (&fd_ctx->dcache->entries.list);
+
+ fd_ctx->dcache->next = NULL;
+ fd_ctx->dcache->prev_off = 0;
+ gf_log (GF_NFS, GF_LOG_TRACE, "Dirent cache invalidated");
+
+ return;
+}
+
+/* Dirent caching code copied from libglusterfsclient.
+ * Please duplicate enhancements and bug fixes there too.
+ */
+/* The first entry in the entries is always a placeholder
+ * or the list head. The real entries begin from entries->next.
+ */
+int
+nfs_dcache_update (xlator_t *nfsx, fd_t *fd, gf_dirent_t *entries)
+{
+ nfs_fdctx_t *fdctx = NULL;
+ int ret = -EFAULT;
+
+ if ((!fd) || (!entries))
+ return ret;
+
+ fdctx = nfs_fdctx_get (fd, nfsx);
+ if (!fdctx) {
+ gf_log (GF_NFS, GF_LOG_ERROR, "No fd context present");
+ return ret;
+ }
+
+ /* dcache is not enabled. */
+ if (!fdctx->dcache) {
+ gf_log (GF_NFS, GF_LOG_TRACE, "No dirent cache present");
+ return ret;
+ }
+
+ /* If we're updating, we must begin with invalidating any previous
+ * entries.
+ */
+ nfs_dcache_invalidate (nfsx, fd);
+
+ fdctx->dcache->next = entries->next;
+ /* We still need to store a pointer to the head
+ * so we start free'ing from the head when invalidation
+ * is required.
+ *
+ * Need to delink the entries from the list
+ * given to us by an underlying translators. Most translators will
+ * free this list after this call so we must preserve the dirents in
+ * order to cache them.
+ */
+ list_splice_init (&entries->list, &fdctx->dcache->entries.list);
+ ret = 0;
+ gf_log (GF_NFS, GF_LOG_TRACE, "Dirent cache updated");
+
+ return ret;
+}
+
+/* Dirent caching code copied from libglusterfsclient.
+ * Please duplicate enhancements and bug fixes there too.
+ */
+int
+nfs_dcache_readdir (xlator_t *nfsx, fd_t *fd, gf_dirent_t *dirp, off_t *offset)
+{
+ nfs_fdctx_t *fdctx = NULL;
+ int cachevalid = 0;
+
+ if ((!fd) || (!dirp) || (!offset))
+ return 0;
+
+ fdctx = nfs_fdctx_get (fd, nfsx);
+ if (!fdctx) {
+ gf_log (GF_NFS, GF_LOG_ERROR, "No fd context present");
+ goto out;
+ }
+
+ if (!fdctx->dcache) {
+ gf_log (GF_NFS, GF_LOG_TRACE, "No dirent cache present");
+ goto out;
+ }
+
+ /* We've either run out of entries in the cache
+ * or the cache is empty.
+ */
+ if (!fdctx->dcache->next) {
+ gf_log (GF_NFS, GF_LOG_TRACE, "Dirent cache is empty");
+ goto out;
+ }
+
+ /* The dirent list is created as a circular linked list
+ * so this check is needed to ensure, we dont start
+ * reading old entries again.
+ * If we're reached this situation, the cache is exhausted
+ * and we'll need to pre-fetch more entries to continue serving.
+ */
+ if (fdctx->dcache->next == &fdctx->dcache->entries) {
+ gf_log (GF_NFS, GF_LOG_TRACE, "Dirent cache was exhausted");
+ goto out;
+ }
+
+ /* During sequential reading we generally expect that the offset
+ * requested is the same as the offset we served in the previous call
+ * to readdir. But, seekdir, rewinddir and libgf_dcache_invalidate
+ * require special handling because seekdir/rewinddir change the offset
+ * in the fd_ctx and libgf_dcache_invalidate changes the prev_off.
+ */
+ if (*offset != fdctx->dcache->prev_off) {
+ /* For all cases of the if branch above, we know that the
+ * cache is now invalid except for the case below. It handles
+ * the case where the two offset values above are different
+ * but different because the previous readdir block was
+ * exhausted, resulting in a prev_off being set to 0 in
+ * libgf_dcache_invalidate, while the requested offset is non
+ * zero because that is what we returned for the last dirent
+ * of the previous readdir block.
+ */
+ if ((*offset != 0) && (fdctx->dcache->prev_off == 0)) {
+ gf_log (GF_NFS, GF_LOG_TRACE, "Dirent cache was"
+ " exhausted");
+ cachevalid = 1;
+ } else
+ gf_log (GF_NFS, GF_LOG_TRACE, "Dirent cache is"
+ " invalid");
+ } else {
+ gf_log (GF_NFS, GF_LOG_TRACE, "Dirent cache is valid");
+ cachevalid = 1;
+ }
+
+ if (!cachevalid)
+ goto out;
+
+ dirp->d_ino = fdctx->dcache->next->d_ino;
+ strncpy (dirp->d_name, fdctx->dcache->next->d_name,
+ fdctx->dcache->next->d_len + 1);
+ dirp->d_len = fdctx->dcache->next->d_len;
+ dirp->d_stat = fdctx->dcache->next->d_stat;
+// nfs_map_dev (fdctx->dirvol, &dirp->d_stat.st_dev);
+
+ *offset = fdctx->dcache->next->d_off;
+ dirp->d_off = *offset;
+ fdctx->dcache->prev_off = fdctx->dcache->next->d_off;
+ fdctx->dcache->next = fdctx->dcache->next->next;
+
+out:
+ return cachevalid;
+}
+
+int
+__nfs_readdir_sync (xlator_t *nfsx, xlator_t *fopxl, nfs_user_t *nfu,
+ fd_t *dirfd, off_t *offset, gf_dirent_t *entry,
+ size_t bufsize)
+{
+ int ret = -1;
+ call_stub_t *reply = NULL;
+
+ if ((!fopxl) || (!dirfd) || (!entry))
+ return ret;
+
+ ret = nfs_dcache_readdir (nfsx, dirfd, entry, offset);
+ if (ret) {
+ gf_log (GF_NFS, GF_LOG_TRACE, "Dirent served from cache");
+ ret = 0;
+ goto err;
+ }
+
+ reply = nfs_fop_readdirp_sync (fopxl, nfu, dirfd, *offset,bufsize);
+ if (!reply) {
+ ret = -1;
+ gf_log (GF_NFS, GF_LOG_ERROR, "Sync readdir failed");
+ goto err;
+ }
+
+ if (reply->args.readdir_cbk.op_ret <= 0) {
+ ret = -1;
+ goto err;
+ }
+
+ ret = nfs_dcache_update (nfsx, dirfd, &reply->args.readdir_cbk.entries);
+ if (ret < 0) {
+ gf_log (GF_NFS, GF_LOG_ERROR, "Failed to update dirent cache");
+ goto err;
+ }
+
+ ret = nfs_dcache_readdir (nfsx, dirfd, entry, offset);
+ if (ret) {
+ gf_log (GF_NFS, GF_LOG_TRACE, "Dirent served from cache,"
+ " after updating from server");
+ ret = 0;
+ } else {
+ gf_log (GF_NFS, GF_LOG_TRACE, "Dirent still not served from"
+ " cache, even after updating from server");
+ ret = -1;
+ }
+
+err:
+ if (reply)
+ call_stub_destroy (reply);
+ return ret;
+}
+
+
+
+int
+nfs_readdir_sync (xlator_t *nfsx, xlator_t *fopxl, nfs_user_t *nfu,
+ fd_t *dirfd, gf_dirent_t *entry)
+{
+ int ret = -EFAULT;
+ nfs_fdctx_t *fdctx = NULL;
+
+ if ((!nfsx) || (!fopxl) || (!dirfd) || (!entry) || (!nfu))
+ return ret;
+
+ fdctx = nfs_fdctx_get (dirfd, nfsx);
+ if (!fdctx) {
+ gf_log (GF_NFS, GF_LOG_ERROR, "No fd context present");
+ goto err;
+ }
+
+ pthread_mutex_lock (&fdctx->lock);
+ {
+ ret = __nfs_readdir_sync (nfsx, fopxl, nfu, dirfd,
+ &fdctx->offset, entry,
+ fdctx->dirent_bufsize);
+ }
+ pthread_mutex_unlock (&fdctx->lock);
+
+ if (ret < 0)
+ gf_log (GF_NFS, GF_LOG_ERROR, "Sync readdir failed: %s",
+ strerror (-ret));
+ else
+ gf_log (GF_NFS, GF_LOG_TRACE, "Entry read: %s: len %d, ino %"
+ PRIu64", igen: %"PRIu64, entry->d_name, entry->d_len,
+ entry->d_ino, entry->d_stat.ia_dev);
+
+err:
+ return ret;
+}
+
+
+int32_t
+nfs_flush_sync_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
+ int32_t op_ret, int32_t op_errno)
+{
+ nfs_syncfop_t *sf = frame->local;
+
+ if (!sf)
+ return -1;
+
+ if (op_ret == -1)
+ gf_log (GF_NFS, GF_LOG_TRACE, "Sync open failed: %s",
+ strerror (op_errno));
+ else
+ gf_log (GF_NFS, GF_LOG_TRACE, "Sync open done");
+
+ sf->replystub = fop_flush_cbk_stub (frame, NULL, op_ret, op_errno);
+
+ nfs_syncfop_notify (sf);
+ return 0;
+}
+
+
+call_stub_t *
+nfs_flush_sync (xlator_t *xl, nfs_user_t *nfu, fd_t *fd)
+{
+ nfs_syncfop_t *sf = NULL;
+ call_stub_t *reply = NULL;
+ int ret = -1;
+
+ if ((!xl) || (!fd) || (!nfu))
+ return NULL;
+
+ sf = nfs_syncfop_init ();
+ if (!sf) {
+ gf_log (GF_NFS, GF_LOG_ERROR, "synclocal init failed");
+ goto err;
+ }
+
+ ret = nfs_flush (xl, nfu, fd, nfs_flush_sync_cbk, sf);
+ if (ret < 0) {
+ gf_log (GF_NFS, GF_LOG_ERROR, "Sync flush failed: %s",
+ strerror (-ret));
+ goto err;
+ }
+
+ reply = nfs_syncfop_wait (sf);
+
+err:
+ if (ret < 0)
+ FREE (sf);
+
+ return reply;
+}
+
+
+int32_t
+nfs_writev_sync_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
+ int32_t op_ret, int32_t op_errno, struct iatt *prebuf,
+ struct iatt *postbuf)
+{
+ nfs_syncfop_t *sf = frame->local;
+
+ if (!sf)
+ return -1;
+
+ if (op_ret == -1)
+ gf_log (GF_NFS, GF_LOG_TRACE, "Sync write failed: %s",
+ strerror (op_errno));
+ else
+ gf_log (GF_NFS, GF_LOG_TRACE, "Sync write done");
+
+ sf->replystub = fop_writev_cbk_stub (frame, NULL, op_ret, op_errno,
+ prebuf, postbuf);
+
+ nfs_syncfop_notify (sf);
+ return 0;
+}
+
+
+
+call_stub_t *
+nfs_write_sync (xlator_t *xl, nfs_user_t *nfu, fd_t *fd, struct iobuf *srciob,
+ struct iovec *vec, int count, off_t offset)
+{
+ nfs_syncfop_t *sf = NULL;
+ call_stub_t *reply = NULL;
+ int ret = -1;
+
+ if ((!xl) || (!fd) || (!vec) || (!nfu) || (!srciob))
+ return NULL;
+
+ sf = nfs_syncfop_init ();
+ if (!sf) {
+ gf_log (GF_NFS, GF_LOG_ERROR, "synclocal init failed");
+ goto err;
+ }
+
+ ret = nfs_write (xl, nfu, fd, srciob, vec, count, offset,
+ nfs_writev_sync_cbk, sf);
+ if (ret < 0) {
+ gf_log (GF_NFS, GF_LOG_ERROR, "Sync flush failed: %s",
+ strerror (-ret));
+ goto err;
+ }
+
+ reply = nfs_syncfop_wait (sf);
+
+err:
+ if (ret < 0)
+ FREE (sf);
+
+ return reply;
+}
+
+
+
+int32_t
+nfs_fsync_sync_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
+ int32_t op_ret, int32_t op_errno, struct iatt *prebuf,
+ struct iatt *postbuf)
+{
+ nfs_syncfop_t *sf = frame->local;
+
+ if (!sf)
+ return -1;
+
+ if (op_ret == -1)
+ gf_log (GF_NFS, GF_LOG_TRACE, "Sync fsync failed: %s",
+ strerror (op_errno));
+ else
+ gf_log (GF_NFS, GF_LOG_TRACE, "Sync fsync done");
+
+ sf->replystub = fop_fsync_cbk_stub (frame, NULL, op_ret, op_errno,
+ prebuf, postbuf);
+
+ nfs_syncfop_notify (sf);
+ return 0;
+}
+
+
+
+call_stub_t *
+nfs_fsync_sync (xlator_t *xl, nfs_user_t *nfu, fd_t *fd, int32_t datasync)
+{
+ nfs_syncfop_t *sf = NULL;
+ call_stub_t *reply = NULL;
+ int ret = -1;
+
+ if ((!xl) || (!fd) || (!nfu))
+ return NULL;
+
+ sf = nfs_syncfop_init ();
+ if (!sf) {
+ gf_log (GF_NFS, GF_LOG_ERROR, "synclocal init failed");
+ goto err;
+ }
+
+ ret = nfs_fsync (xl, nfu, fd, datasync, nfs_fsync_sync_cbk, sf);
+ if (ret < 0) {
+ gf_log (GF_NFS, GF_LOG_ERROR, "Sync fsync failed: %s",
+ strerror (-ret));
+ goto err;
+ }
+
+ reply = nfs_syncfop_wait (sf);
+
+err:
+ if (ret < 0)
+ FREE (sf);
+
+ return reply;
+}
+
+int32_t
+nfs_read_sync_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
+ int32_t op_ret, int32_t op_errno, struct iovec *vector,
+ int32_t count, struct iatt *buf, struct iobref *iobref)
+{
+ nfs_syncfop_t *sf = frame->local;
+
+ if (!sf)
+ return -1;
+
+ if (op_ret == -1)
+ gf_log (GF_NFS, GF_LOG_TRACE, "Sync read failed: %s",
+ strerror (op_errno));
+ else
+ gf_log (GF_NFS, GF_LOG_TRACE, "Sync read done");
+
+ sf->replystub = fop_readv_cbk_stub (frame, NULL, op_ret, op_errno,
+ vector, count, buf, iobref);
+
+ nfs_syncfop_notify (sf);
+ return 0;
+}
+
+
+
+call_stub_t *
+nfs_read_sync (xlator_t *xl, nfs_user_t *nfu, fd_t *fd, size_t size,
+ off_t offset)
+{
+ nfs_syncfop_t *sf = NULL;
+ call_stub_t *reply = NULL;
+ int ret = -1;
+
+ if ((!xl) || (!fd) || (!nfu))
+ return NULL;
+
+ sf = nfs_syncfop_init ();
+ if (!sf) {
+ gf_log (GF_NFS, GF_LOG_ERROR, "synclocal init failed");
+ goto err;
+ }
+
+ ret = nfs_read (xl, nfu, fd, size, offset, nfs_read_sync_cbk, sf);
+ if (ret < 0) {
+ gf_log (GF_NFS, GF_LOG_ERROR, "Sync read failed: %s",
+ strerror (-ret));
+ goto err;
+ }
+
+ reply = nfs_syncfop_wait (sf);
+
+err:
+ if (ret < 0)
+ FREE (sf);
+
+ return reply;
+}
+
+
+int32_t
+nfs_opendir_sync_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
+ int32_t op_ret, int32_t op_errno, fd_t *fd)
+{
+ nfs_syncfop_t *sf = frame->local;
+
+ if (!sf)
+ return -1;
+
+ if (op_ret == -1)
+ gf_log (GF_NFS, GF_LOG_TRACE, "Sync opendir failed: %s",
+ strerror (op_errno));
+ else
+ gf_log (GF_NFS, GF_LOG_TRACE, "Sync opendir done");
+
+ sf->replystub = fop_opendir_cbk_stub (frame, NULL, op_ret, op_errno,fd);
+
+ nfs_syncfop_notify (sf);
+ return 0;
+}
+
+
+call_stub_t *
+nfs_opendir_sync (xlator_t *nfsx, xlator_t *fopxl, nfs_user_t *nfu,
+ loc_t *pathloc, size_t bufsize)
+{
+ int ret = -EFAULT;
+ call_stub_t *reply = NULL;
+ nfs_syncfop_t *sf = NULL;
+ fd_t *dirfd = NULL;
+
+ if ((!nfsx) || (!fopxl) || (!pathloc) || (!nfu))
+ return NULL;
+
+ sf = nfs_syncfop_init ();
+ if (!sf) {
+ gf_log (GF_NFS, GF_LOG_ERROR, "synclocal init failed");
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ ret = nfs_inode_opendir (fopxl, nfu, pathloc, nfs_opendir_sync_cbk, sf);
+ if (ret < 0)
+ goto err;
+
+ reply = nfs_syncfop_wait (sf);
+ if (!reply) {
+ ret = -EFAULT;
+ goto err;
+ }
+
+ dirfd = reply->args.opendir_cbk.fd;
+ ret = nfs_dir_fdctx_init (dirfd, nfsx, fopxl, bufsize);
+ if (ret < 0) {
+ gf_log (GF_NFS, GF_LOG_ERROR, "fd context allocation failed");
+ goto err;
+ }
+
+ ret = 0;
+
+err:
+ if (ret < 0)
+ FREE (sf);
+
+ return reply;
+}
+
+
+int
+nfs_opendir (xlator_t *fopxl, nfs_user_t *nfu, loc_t *pathloc,
+ fop_opendir_cbk_t cbk, void *local)
+{
+ if ((!fopxl) || (!pathloc) || (!nfu))
+ return -EFAULT;
+
+ return nfs_inode_opendir (fopxl, nfu, pathloc, cbk, local);
+}
diff --git a/xlators/nfs/server/src/nfs-generics.h b/xlators/nfs/server/src/nfs-generics.h
new file mode 100644
index 000000000..980e73020
--- /dev/null
+++ b/xlators/nfs/server/src/nfs-generics.h
@@ -0,0 +1,174 @@
+/*
+ Copyright (c) 2010 Gluster, Inc. <http://www.gluster.com>
+ This file is part of GlusterFS.
+
+ GlusterFS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3 of the License,
+ or (at your option) any later version.
+
+ GlusterFS is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see
+ <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _NFS_GENERICS_H_
+#define _NFS_GENERICS_H_
+
+#ifndef _CONFIG_H
+#define _CONFIG_H
+#include "config.h"
+#endif
+
+#include "nfs.h"
+#include "xlator.h"
+#include "nfs-fops.h"
+#include "nfs-inodes.h"
+
+struct nfs_direntcache {
+ gf_dirent_t entries; /* Head of list of cached dirents. */
+ gf_dirent_t *next; /* Pointer to the next entry that
+ * should be sent by readdir */
+ uint64_t prev_off; /* Offset where the next read will
+ * happen.
+ */
+};
+
+/* WE're trying to abstract the fops interface from the NFS xlator so that
+ * different NFS versions can simply call a standard interface and have fop
+ * interface dependent functions be handled internally.
+ * This structure is part of such an abstraction. The fops layer stores any
+ * state is requires in the fd. For eg, the dirent cache for a directory fd_t.
+ */
+typedef struct nfs_fop_fdcontext {
+ pthread_mutex_t lock;
+ size_t dirent_bufsize;
+ off_t offset;
+ struct nfs_direntcache *dcache;
+ xlator_t *dirvol;
+} nfs_fdctx_t;
+
+extern int
+nfs_fstat (xlator_t *xl, nfs_user_t *nfu, fd_t *fd, fop_stat_cbk_t cbk,
+ void *local);
+
+extern int
+nfs_readdirp (xlator_t *xl, nfs_user_t *nfu, fd_t *dirfd, size_t bufsize,
+ off_t offset, fop_readdir_cbk_t cbk, void *local);
+
+
+extern int
+nfs_lookup (xlator_t *xl, nfs_user_t *nfu, loc_t *pathloc,
+ fop_lookup_cbk_t cbk, void *local);
+
+extern int
+nfs_create (xlator_t *xl, nfs_user_t *nfu, loc_t *pathloc, int flags,
+ mode_t mode, fop_create_cbk_t cbk, void *local);
+
+extern int
+nfs_flush (xlator_t *xl, nfs_user_t *nfu, fd_t *fd, fop_flush_cbk_t cbk,
+ void *local);
+
+extern int
+nfs_mkdir (xlator_t *xl, nfs_user_t *nfu, loc_t *pathloc, mode_t mode,
+ fop_mkdir_cbk_t cbk, void *local);
+
+extern int
+nfs_truncate (xlator_t *xl, nfs_user_t *nfu, loc_t *pathloc, off_t offset,
+ fop_truncate_cbk_t cbk, void *local);
+
+extern int
+nfs_read (xlator_t *xl, nfs_user_t *nfu, fd_t *fd, size_t size,
+ off_t offset, fop_readv_cbk_t cbk, void *local);
+
+extern int
+nfs_fsync (xlator_t *xl, nfs_user_t *nfu, fd_t *fd, int32_t datasync,
+ fop_fsync_cbk_t cbk, void *local);
+
+extern int
+nfs_write (xlator_t *xl, nfs_user_t *nfu, fd_t *fd, struct iobuf *srciob,
+ struct iovec *vector, int32_t count, off_t offset,
+ fop_writev_cbk_t cbk, void *local);
+
+extern int
+nfs_open (xlator_t *xl, nfs_user_t *nfu, loc_t *pathloc, int32_t flags,
+ fop_open_cbk_t cbk, void *local);
+
+extern int
+nfs_rename (xlator_t *xl, nfs_user_t *nfu, loc_t *oldloc, loc_t *newloc,
+ fop_rename_cbk_t cbk, void *local);
+
+extern int
+nfs_link (xlator_t *xl, nfs_user_t *nfu, loc_t *oldloc, loc_t *newloc,
+ fop_link_cbk_t cbk, void *local);
+
+extern int
+nfs_unlink (xlator_t *xl, nfs_user_t *nfu, loc_t *pathloc,
+ fop_unlink_cbk_t cbk, void *local);
+
+extern int
+nfs_rmdir (xlator_t *xl, nfs_user_t *nfu, loc_t *pathloc,
+ fop_rmdir_cbk_t cbk, void *local);
+
+extern int
+nfs_mknod (xlator_t *xl, nfs_user_t *nfu, loc_t *pathloc, mode_t mode,
+ dev_t dev, fop_mknod_cbk_t cbk, void *local);
+
+extern int
+nfs_readlink (xlator_t *xl, nfs_user_t *nfu, loc_t *linkloc,
+ fop_readlink_cbk_t cbk, void *local);
+
+extern int
+nfs_setattr (xlator_t *xl, nfs_user_t *nfu, loc_t *pathloc,
+ struct iatt *buf, int32_t valid, fop_setattr_cbk_t cbk,
+ void *local);
+
+extern int
+nfs_statfs (xlator_t *xl, nfs_user_t *nfu, loc_t *pathloc,
+ fop_statfs_cbk_t cbk, void *local);
+
+extern int
+nfs_stat (xlator_t *xl, nfs_user_t *nfu, loc_t *pathloc, fop_stat_cbk_t cbk
+ , void *local);
+
+extern int
+nfs_symlink (xlator_t *xl, nfs_user_t *nfu, char *target, loc_t *linkloc,
+ fop_symlink_cbk_t cbk, void *local);
+
+/* Synchronous equivalents */
+
+extern call_stub_t *
+nfs_open_sync (xlator_t *xl, nfs_user_t *nfu, loc_t *pathloc,
+ int32_t flags);
+
+extern int
+nfs_readdir_sync (xlator_t *nfsx, xlator_t *fopxl, nfs_user_t *nfu,
+ fd_t *dirfd, gf_dirent_t *entry);
+
+extern call_stub_t *
+nfs_flush_sync (xlator_t *xl, nfs_user_t *nfu, fd_t *fd);
+
+extern call_stub_t *
+nfs_write_sync (xlator_t *xl, nfs_user_t *nfu, fd_t *fd, struct iobuf *srciob,
+ struct iovec *vec, int count, off_t offset);
+
+extern call_stub_t *
+nfs_fsync_sync (xlator_t *xl, nfs_user_t *nfu, fd_t *fd, int32_t datasync);
+
+extern call_stub_t *
+nfs_read_sync (xlator_t *xl, nfs_user_t *nfu, fd_t *fd, size_t size,
+ off_t offset);
+
+extern call_stub_t *
+nfs_opendir_sync (xlator_t *nfsx, xlator_t *fopxl, nfs_user_t *nfu,
+ loc_t *dirloc, size_t bufsize);
+
+extern int
+nfs_opendir (xlator_t *fopxl, nfs_user_t *nfu, loc_t *pathloc,
+ fop_opendir_cbk_t cbk, void *local);
+#endif
diff --git a/xlators/nfs/server/src/nfs-inodes.c b/xlators/nfs/server/src/nfs-inodes.c
new file mode 100644
index 000000000..69bad0724
--- /dev/null
+++ b/xlators/nfs/server/src/nfs-inodes.c
@@ -0,0 +1,571 @@
+/*
+ Copyright (c) 2010 Gluster, Inc. <http://www.gluster.com>
+ This file is part of GlusterFS.
+
+ GlusterFS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3 of the License,
+ or (at your option) any later version.
+
+ GlusterFS is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see
+ <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _CONFIG_H
+#define _CONFIG_H
+#include "config.h"
+#endif
+
+#include "string.h"
+
+#include "inode.h"
+#include "nfs.h"
+#include "nfs-inodes.h"
+#include "nfs-fops.h"
+#include "xlator.h"
+
+#include <libgen.h>
+
+void
+nfl_inodes_init (struct nfs_fop_local *nfl, inode_t *inode, inode_t *parent,
+ inode_t *newparent, const char *name, const char *newname)
+{
+ if (!nfl)
+ return;
+
+ if (inode)
+ nfl->inode = inode_ref (inode);
+
+ if (parent)
+ nfl->parent = inode_ref (parent);
+
+ if (newparent)
+ nfl->newparent = inode_ref (newparent);
+
+ if (name)
+ strcpy (nfl->path, name);
+
+ if (newname)
+ strcpy (nfl->newpath, newname);
+
+ return;
+}
+
+
+int32_t
+nfs_inode_create_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
+ int32_t op_ret, int32_t op_errno, fd_t *fd, inode_t *inode
+ , struct iatt *buf, struct iatt *preparent,
+ struct iatt *postparent)
+{
+ struct nfs_fop_local *nfl = frame->local;
+ fop_create_cbk_t progcbk = NULL;
+
+ if (op_ret == -1)
+ goto do_not_link;
+
+ inode_link (inode, nfl->parent, nfl->path, buf);
+
+do_not_link:
+ /* NFS does not need it, upper layers should not expect the pointer to
+ * be a valid fd.
+ */
+ fd_unref (fd);
+
+ nfl_to_prog_data (this, nfl, progcbk, frame);
+ if (progcbk)
+ progcbk (frame, cookie, this, op_ret, op_errno, fd, inode, buf,
+ preparent, postparent);
+ return 0;
+}
+
+
+int
+nfs_inode_create (xlator_t *xl, nfs_user_t *nfu, loc_t *pathloc, int flags,
+ int mode, fop_create_cbk_t cbk, void *local)
+{
+ struct nfs_fop_local *nfl = NULL;
+ int ret = -EFAULT;
+ fd_t *newfd = NULL;
+
+ if ((!xl) || (!pathloc) || (!nfu))
+ return ret;
+
+ nfs_fop_handle_local_init (NULL, xl, nfl, cbk, local, ret, err);
+
+ newfd = fd_create (pathloc->inode, 0);
+ if (!newfd) {
+ gf_log (GF_NFS, GF_LOG_ERROR, "Failed to create new fd");
+ ret = -ENOMEM;
+ goto wipe_nfl;
+ }
+
+ /* The parent and base name will be needed to link the new inode
+ * into the inode table.
+ */
+ nfl_inodes_init (nfl, pathloc->inode, pathloc->parent, NULL,
+ pathloc->name, NULL);
+ ret = nfs_fop_create (xl, nfu, pathloc, flags, mode, newfd,
+ nfs_inode_create_cbk, nfl);
+wipe_nfl:
+ if (ret < 0)
+ nfs_fop_local_wipe (xl, nfl);
+
+err:
+ return ret;
+}
+
+
+int32_t
+nfs_inode_mkdir_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
+ int32_t op_ret, int32_t op_errno, inode_t *inode,
+ struct iatt *buf, struct iatt *preparent,
+ struct iatt *postparent)
+{
+ struct nfs_fop_local *nfl = frame->local;
+ fop_mkdir_cbk_t progcbk = NULL;
+
+ if (op_ret == -1)
+ goto do_not_link;
+
+ inode_link (inode, nfl->parent, nfl->path, buf);
+
+do_not_link:
+ nfl_to_prog_data (this, nfl, progcbk, frame);
+ if (progcbk)
+ progcbk (frame, cookie, this, op_ret, op_errno, inode, buf,
+ preparent, postparent);
+
+ return 0;
+}
+
+int
+nfs_inode_mkdir (xlator_t *xl, nfs_user_t *nfu, loc_t *pathloc, int mode,
+ fop_mkdir_cbk_t cbk, void *local)
+{
+ struct nfs_fop_local *nfl = NULL;
+ int ret = -EFAULT;
+
+ if ((!xl) || (!pathloc) || (!nfu))
+ return ret;
+
+ nfs_fop_handle_local_init (NULL, xl, nfl, cbk, local, ret, err);
+ nfl_inodes_init (nfl, pathloc->inode, pathloc->parent, NULL,
+ pathloc->name, NULL);
+ ret = nfs_fop_mkdir (xl, nfu, pathloc, mode, nfs_inode_mkdir_cbk,
+ nfl);
+ if (ret < 0)
+ nfs_fop_local_wipe (xl, nfl);
+
+err:
+ return ret;
+}
+
+
+int32_t
+nfs_inode_open_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
+ int32_t op_ret, int32_t op_errno, fd_t *fd)
+{
+
+ struct nfs_fop_local *nfl = NULL;
+ fop_open_cbk_t progcbk = NULL;
+
+ if ((op_ret == -1) && (fd))
+ fd_unref (fd);
+ /* Not needed here since the fd is cached in higher layers and the bind
+ * must happen atomically when the fd gets added to the fd LRU.
+ */
+/* else
+ fd_bind (fd);
+*/
+ nfl_to_prog_data (this, nfl, progcbk, frame);
+ if (progcbk)
+ progcbk (frame, cookie, this, op_ret, op_errno, fd);
+ return 0;
+}
+
+
+int
+nfs_inode_open (xlator_t *xl, nfs_user_t *nfu, loc_t *loc, int32_t flags,
+ int32_t wbflags, fop_open_cbk_t cbk, void *local)
+{
+ struct nfs_fop_local *nfl = NULL;
+ fd_t *newfd = NULL;
+ int ret = -EFAULT;
+
+ if ((!xl) || (!loc) || (!nfu))
+ return ret;
+
+ newfd = fd_create (loc->inode, 0);
+ if (!newfd) {
+ gf_log (GF_NFS, GF_LOG_ERROR, "Failed to create fd");
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ nfs_fop_handle_local_init (NULL, xl, nfl, cbk, local, ret, fd_err);
+ ret = nfs_fop_open (xl, nfu, loc, flags, newfd, wbflags,
+ nfs_inode_open_cbk, nfl);
+
+ if (ret < 0)
+ nfs_fop_local_wipe (xl, nfl);
+
+fd_err:
+ if (ret < 0)
+ if (newfd)
+ fd_unref (newfd);
+
+err:
+
+ return ret;
+}
+
+
+
+int32_t
+nfs_inode_rename_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
+ int32_t op_ret, int32_t op_errno, struct iatt *buf,
+ struct iatt *preoldparent, struct iatt *postoldparent,
+ struct iatt *prenewparent, struct iatt *postnewparent)
+{
+ struct nfs_fop_local *nfl = NULL;
+ fop_rename_cbk_t progcbk = NULL;
+
+ nfl = frame->local;
+ if (op_ret == -1)
+ goto do_not_link;
+
+ inode_rename (this->itable, nfl->parent, nfl->path, nfl->newparent,
+ nfl->newpath, nfl->inode, buf);
+
+do_not_link:
+ nfl_to_prog_data (this, nfl, progcbk, frame);
+ if (progcbk)
+ progcbk (frame, cookie, this, op_ret, op_errno, buf,
+ preoldparent, postoldparent, prenewparent,
+ postnewparent);
+ return 0;
+}
+
+
+int
+nfs_inode_rename (xlator_t *xl, nfs_user_t *nfu, loc_t *oldloc,
+ loc_t *newloc, fop_rename_cbk_t cbk, void *local)
+{
+ struct nfs_fop_local *nfl = NULL;
+ int ret = -EFAULT;
+
+ if ((!xl) || (!oldloc) || (!newloc))
+ return ret;
+
+ nfs_fop_handle_local_init (NULL, xl, nfl, cbk, local, ret, err);
+ nfl_inodes_init (nfl, oldloc->inode, oldloc->parent, newloc->parent,
+ oldloc->name, newloc->name);
+ ret = nfs_fop_rename (xl, nfu, oldloc, newloc, nfs_inode_rename_cbk
+ , nfl);
+
+err:
+ if (ret < 0)
+ nfs_fop_local_wipe (xl, nfl);
+
+ return ret;
+}
+
+
+int32_t
+nfs_inode_link_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
+ int32_t op_ret, int32_t op_errno, inode_t *inode,
+ struct iatt *buf, struct iatt *preparent,
+ struct iatt *postparent)
+{
+ struct nfs_fop_local *nfl = NULL;
+ fop_link_cbk_t progcbk = NULL;
+
+ if (op_ret == -1)
+ goto do_not_link;
+
+ nfl = frame->local;
+ inode_link (inode, nfl->newparent, nfl->path, buf);
+
+do_not_link:
+ nfl_to_prog_data (this, nfl, progcbk, frame);
+ if (progcbk)
+ progcbk (frame, cookie, this, op_ret, op_errno, inode, buf,
+ preparent, postparent);
+ return 0;
+}
+
+
+int
+nfs_inode_link (xlator_t *xl, nfs_user_t *nfu, loc_t *oldloc,
+ loc_t *newloc, fop_link_cbk_t cbk, void *local)
+{
+ struct nfs_fop_local *nfl = NULL;
+ int ret = -EFAULT;
+
+ if ((!xl) || (!oldloc) || (!newloc) || (!nfu))
+ return -EFAULT;
+
+ nfs_fop_handle_local_init (NULL, xl, nfl, cbk, local, ret, err);
+ nfl_inodes_init (nfl, NULL, NULL, newloc->parent, newloc->name, NULL);
+ ret = nfs_fop_link (xl, nfu, oldloc, newloc, nfs_inode_link_cbk,
+ nfl);
+
+err:
+ if (ret < 0)
+ nfs_fop_local_wipe (xl, nfl);
+
+ return ret;
+}
+
+
+int32_t
+nfs_inode_unlink_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
+ int32_t op_ret, int32_t op_errno, struct iatt *preparent,
+ struct iatt *postparent)
+{
+ struct nfs_fop_local *nfl = NULL;
+ fop_unlink_cbk_t progcbk = NULL;
+
+ nfl = frame->local;
+
+ if (op_ret == -1)
+ goto do_not_unlink;
+
+ inode_unlink (nfl->inode, nfl->parent, nfl->path);
+
+do_not_unlink:
+ nfl_to_prog_data (this, nfl, progcbk, frame);
+ if (progcbk)
+ progcbk (frame, cookie, this, op_ret, op_errno, preparent,
+ postparent);
+ return 0;
+}
+
+
+int
+nfs_inode_unlink (xlator_t *xl, nfs_user_t *nfu, loc_t *pathloc,
+ fop_unlink_cbk_t cbk, void *local)
+{
+ struct nfs_fop_local *nfl = NULL;
+ int ret = -EFAULT;
+
+ if ((!xl) || (!pathloc) || (!nfu))
+ return -EFAULT;
+
+ nfs_fop_handle_local_init (NULL, xl, nfl, cbk, local, ret, err);
+ nfl_inodes_init (nfl, pathloc->inode, pathloc->parent, NULL,
+ pathloc->name, NULL);
+ ret = nfs_fop_unlink (xl, nfu, pathloc, nfs_inode_unlink_cbk, nfl);
+
+err:
+ if (ret < 0)
+ nfs_fop_local_wipe (xl, nfl);
+
+ return ret;
+}
+
+
+int32_t
+nfs_inode_rmdir_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
+ int32_t op_ret, int32_t op_errno, struct iatt *preparent,
+ struct iatt *postparent)
+{
+ struct nfs_fop_local *nfl = NULL;
+ fop_rmdir_cbk_t progcbk = NULL;
+
+ nfl = frame->local;
+
+ if (op_ret == -1)
+ goto do_not_unlink;
+
+ inode_unlink (nfl->inode, nfl->parent, nfl->path);
+
+do_not_unlink:
+ nfl_to_prog_data (this, nfl, progcbk, frame);
+ if (progcbk)
+ progcbk (frame, cookie, this, op_ret, op_errno, preparent,
+ postparent);
+
+ return 0;
+}
+
+
+int
+nfs_inode_rmdir (xlator_t *xl, nfs_user_t *nfu, loc_t *pathloc,
+ fop_rmdir_cbk_t cbk, void *local)
+{
+ struct nfs_fop_local *nfl = NULL;
+ int ret = -EFAULT;
+
+ if ((!xl) || (!pathloc) || (!nfu))
+ return ret;
+
+ nfs_fop_handle_local_init (NULL, xl, nfl, cbk, local, ret, err);
+ nfl_inodes_init (nfl, pathloc->inode, pathloc->parent, NULL,
+ pathloc->name, NULL);
+
+ ret = nfs_fop_rmdir (xl, nfu, pathloc, nfs_inode_rmdir_cbk, nfl);
+
+err:
+ if (ret < 0)
+ nfs_fop_local_wipe (xl, nfl);
+ return ret;
+}
+
+
+int32_t
+nfs_inode_mknod_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
+ int32_t op_ret, int32_t op_errno, inode_t *inode,
+ struct iatt *buf, struct iatt *preparent,
+ struct iatt *postparent)
+{
+ struct nfs_fop_local *nfl = NULL;
+ fop_mknod_cbk_t progcbk = NULL;
+
+ nfl = frame->local;
+
+ if (op_ret == -1)
+ goto do_not_link;
+
+ inode_link (inode, nfl->parent, nfl->path, buf);
+
+do_not_link:
+ nfl_to_prog_data (this, nfl, progcbk, frame);
+ if (progcbk)
+ progcbk (frame, cookie, this, op_ret, op_errno, inode, buf,
+ preparent, postparent);
+ return 0;
+}
+
+
+int
+nfs_inode_mknod (xlator_t *xl, nfs_user_t *nfu, loc_t *pathloc,
+ mode_t mode, dev_t dev, fop_mknod_cbk_t cbk, void *local)
+{
+ struct nfs_fop_local *nfl = NULL;
+ int ret = -EFAULT;
+
+ if ((!xl) || (!pathloc) || (!nfu))
+ return ret;
+
+ nfs_fop_handle_local_init (NULL, xl, nfl, cbk, local, ret, err);
+ nfl_inodes_init (nfl, pathloc->inode, pathloc->parent, NULL,
+ pathloc->name, NULL);
+
+ ret = nfs_fop_mknod (xl, nfu, pathloc, mode, dev, nfs_inode_mknod_cbk,
+ nfl);
+
+err:
+ if (ret < 0)
+ nfs_fop_local_wipe (xl, nfl);
+
+ return ret;
+}
+
+
+int32_t
+nfs_inode_symlink_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
+ int32_t op_ret, int32_t op_errno, inode_t *inode,
+ struct iatt *buf, struct iatt *preparent,
+ struct iatt *postparent)
+{
+ struct nfs_fop_local *nfl = NULL;
+ fop_symlink_cbk_t progcbk = NULL;
+
+ nfl = frame->local;
+ if (op_ret == -1)
+ goto do_not_link;
+
+ inode_link (inode, nfl->parent, nfl->path, buf);
+
+do_not_link:
+ nfl_to_prog_data (this, nfl, progcbk, frame);
+ if (progcbk)
+ progcbk (frame, cookie, this, op_ret, op_errno, inode, buf,
+ preparent, postparent);
+
+ return 0;
+}
+
+
+int
+nfs_inode_symlink (xlator_t *xl, nfs_user_t *nfu, char *target,
+ loc_t *pathloc, fop_symlink_cbk_t cbk, void *local)
+{
+ struct nfs_fop_local *nfl = NULL;
+ int ret = -EFAULT;
+
+ if ((!xl) || (!target) || (!pathloc) || (!nfu))
+ return ret;
+
+ nfs_fop_handle_local_init (NULL, xl, nfl, cbk, local, ret, err);
+ nfl_inodes_init (nfl, pathloc->inode, pathloc->parent, NULL,
+ pathloc->name, NULL);
+ ret = nfs_fop_symlink (xl, nfu, target, pathloc, nfs_inode_symlink_cbk,
+ nfl);
+
+err:
+ if (ret < 0)
+ nfs_fop_local_wipe (xl, nfl);
+
+ return ret;
+}
+
+int32_t
+nfs_inode_opendir_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
+ int32_t op_ret, int32_t op_errno, fd_t *fd)
+{
+
+ struct nfs_fop_local *nfl = NULL;
+ fop_open_cbk_t progcbk = NULL;
+
+ if ((op_ret == -1) && (fd))
+ fd_unref (fd);
+ else
+ fd_bind (fd);
+
+ nfl_to_prog_data (this, nfl, progcbk, frame);
+
+ if (progcbk)
+ progcbk (frame, cookie, this, op_ret, op_errno, fd);
+ return 0;
+}
+
+
+int
+nfs_inode_opendir (xlator_t *xl, nfs_user_t *nfu, loc_t *loc,
+ fop_opendir_cbk_t cbk, void *local)
+{
+ struct nfs_fop_local *nfl = NULL;
+ fd_t *newfd = NULL;
+ int ret = -EFAULT;
+
+ if ((!xl) || (!loc) || (!nfu))
+ return ret;
+
+ newfd = fd_create (loc->inode, 0);
+ if (!newfd) {
+ gf_log (GF_NFS, GF_LOG_ERROR, "Failed to create fd");
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ nfs_fop_handle_local_init (NULL, xl, nfl, cbk, local, ret, err);
+ ret = nfs_fop_opendir (xl, nfu, loc, newfd, nfs_inode_opendir_cbk, nfl);
+
+err:
+ if (ret < 0) {
+ if (newfd)
+ fd_unref (newfd);
+ nfs_fop_local_wipe (xl, nfl);
+ }
+
+ return ret;
+}
diff --git a/xlators/nfs/server/src/nfs-inodes.h b/xlators/nfs/server/src/nfs-inodes.h
new file mode 100644
index 000000000..04d3eba66
--- /dev/null
+++ b/xlators/nfs/server/src/nfs-inodes.h
@@ -0,0 +1,83 @@
+/*
+ Copyright (c) 2010 Gluster, Inc. <http://www.gluster.com>
+ This file is part of GlusterFS.
+
+ GlusterFS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3 of the License,
+ or (at your option) any later version.
+
+ GlusterFS is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see
+ <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _NFS_INODES_H_
+#define _NFS_INODES_H_
+
+#ifndef _CONFIG_H
+#define _CONFIG_H
+#include "config.h"
+#endif
+
+#include "dict.h"
+#include "xlator.h"
+#include "iobuf.h"
+#include "call-stub.h"
+#include "stack.h"
+#include "nfs-fops.h"
+
+
+extern int
+nfs_link_inode (inode_t *newi, inode_t *parent, char *name,
+ struct iatt *newstat);
+
+extern int
+nfs_inode_create (xlator_t *xl, nfs_user_t *nfu, loc_t *pathloc, int flags,
+ int mode, fop_create_cbk_t cbk, void *local);
+
+extern int
+nfs_inode_mkdir (xlator_t *xl, nfs_user_t *nfu, loc_t *pathloc, int mode,
+ fop_mkdir_cbk_t cbk, void *local);
+
+extern int
+nfs_inode_open (xlator_t *xl, nfs_user_t *nfu, loc_t *loc, int32_t flags,
+ int32_t wbflags, fop_open_cbk_t cbk, void *local);
+
+extern int
+nfs_inode_rename (xlator_t *xl, nfs_user_t *nfu, loc_t *oldloc,
+ loc_t *newloc, fop_rename_cbk_t cbk, void *local);
+
+extern int
+nfs_inode_link (xlator_t *xl, nfs_user_t *nfu, loc_t *oldloc,
+ loc_t *newloc, fop_link_cbk_t cbk, void *local);
+
+extern int
+nfs_inode_unlink (xlator_t *xl, nfs_user_t *nfu, loc_t *pathloc,
+ fop_unlink_cbk_t cbk, void *local);
+
+extern int
+nfs_inode_rmdir (xlator_t *xl, nfs_user_t *nfu, loc_t *pathloc,
+ fop_rmdir_cbk_t cbk, void *local);
+
+extern int
+nfs_inode_symlink (xlator_t *xl, nfs_user_t *nfu, char *target,
+ loc_t *pathloc, fop_symlink_cbk_t cbk, void *local);
+
+extern int
+nfs_inode_opendir (xlator_t *xl, nfs_user_t *nfu, loc_t *loc,
+ fop_opendir_cbk_t cbk, void *local);
+
+extern int
+nfs_inode_mknod (xlator_t *xl, nfs_user_t *nfu, loc_t *pathloc,
+ mode_t mode, dev_t dev, fop_mknod_cbk_t cbk, void *local);
+
+extern int
+nfs_inode_lookup (xlator_t *xl, nfs_user_t *nfu, loc_t *pathloc,
+ fop_lookup_cbk_t cbk, void *local);
+#endif
diff --git a/xlators/nfs/server/src/nfs.c b/xlators/nfs/server/src/nfs.c
new file mode 100644
index 000000000..ca6fda69c
--- /dev/null
+++ b/xlators/nfs/server/src/nfs.c
@@ -0,0 +1,645 @@
+/*
+ Copyright (c) 2010 Gluster, Inc. <http://www.gluster.com>
+ This file is part of GlusterFS.
+
+ GlusterFS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3 of the License,
+ or (at your option) any later version.
+
+ GlusterFS is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see
+ <http://www.gnu.org/licenses/>.
+*/
+
+/* This is the primary translator source for NFS.
+ * Every other protocol version gets initialized from here.
+ */
+
+
+#ifndef _CONFIG_H
+#define _CONFIG_H
+#include "config.h"
+#endif
+
+#include "defaults.h"
+#include "rpcsvc.h"
+#include "dict.h"
+#include "xlator.h"
+#include "nfs.h"
+#include "mem-pool.h"
+#include "logging.h"
+#include "nfs-fops.h"
+#include "inode.h"
+
+/* Every NFS version must call this function with the init function
+ * for its particular version.
+ */
+int
+nfs_add_initer (struct list_head *list, nfs_version_initer_t init)
+{
+ struct nfs_initer_list *new = NULL;
+ if ((!list) || (!init))
+ return -1;
+
+ new = CALLOC (1, sizeof (*new));
+ if (!new) {
+ gf_log (GF_NFS, GF_LOG_ERROR, "Memory allocation failed");
+ return -1;
+ }
+
+ new->init = init;
+ list_add_tail (&new->list, list);
+ return 0;
+}
+
+
+int
+nfs_deinit_versions (struct list_head *versions, xlator_t *this)
+{
+ struct nfs_initer_list *version = NULL;
+ struct nfs_initer_list *tmp = NULL;
+ struct nfs_state *nfs = NULL;
+
+ if ((!versions) || (!this))
+ return -1;
+
+ nfs = (struct nfs_state *)this->private;
+ list_for_each_entry_safe (version, tmp, versions, list) {
+ /* TODO: Add version specific destructor.
+ * if (!version->deinit)
+ goto err;
+
+ version->deinit (this);
+ */
+ if (version->program)
+ rpcsvc_program_unregister (nfs->rpcsvc,
+ *(version->program));
+
+ list_del (&version->list);
+ FREE (version);
+ }
+
+ return 0;
+}
+
+
+int
+nfs_init_versions (struct nfs_state *nfs, xlator_t *this)
+{
+ struct nfs_initer_list *version = NULL;
+ struct nfs_initer_list *tmp = NULL;
+ rpcsvc_program_t *prog = NULL;
+ int ret = -1;
+ struct list_head *versions = NULL;
+
+ if ((!nfs) || (!this))
+ return -1;
+
+ gf_log (GF_NFS, GF_LOG_DEBUG, "Initing protocol versions");
+ versions = &nfs->versions;
+ list_for_each_entry_safe (version, tmp, versions, list) {
+ if (!version->init) {
+ ret = -1;
+ goto err;
+ }
+
+ prog = version->init (this);
+ version->program = prog;
+ if (!prog) {
+ ret = -1;
+ goto err;
+ }
+
+ gf_log (GF_NFS, GF_LOG_DEBUG, "Starting program: %s",
+ prog->progname);
+ ret = rpcsvc_program_register (nfs->rpcsvc, *prog);
+ if (ret == -1) {
+ gf_log (GF_NFS, GF_LOG_ERROR, "Program init failed");
+ goto err;
+ }
+ }
+
+ ret = 0;
+err:
+ return ret;
+}
+
+
+int
+nfs_add_all_initiators (struct nfs_state *nfs)
+{
+ /* Add the initializers for all versions. */
+ return 0;
+}
+
+
+int
+nfs_subvolume_started (struct nfs_state *nfs, xlator_t *xl)
+{
+ int x = 0;
+ int started = 0;
+
+ if ((!nfs) || (!xl))
+ return 1;
+
+ LOCK (&nfs->svinitlock);
+ {
+ for (;x < nfs->allsubvols; ++x) {
+ if (nfs->initedxl[x] == xl) {
+ started = 1;
+ goto unlock;
+ }
+ }
+ }
+unlock:
+ UNLOCK (&nfs->svinitlock);
+
+ return started;
+}
+
+
+int
+nfs_subvolume_set_started (struct nfs_state *nfs, xlator_t *xl)
+{
+ int x = 0;
+
+ if ((!nfs) || (!xl))
+ return 1;
+
+ LOCK (&nfs->svinitlock);
+ {
+ for (;x < nfs->allsubvols; ++x) {
+ if (nfs->initedxl[x] == NULL) {
+ nfs->initedxl[x] = xl;
+ ++nfs->upsubvols;
+ gf_log (GF_NFS, GF_LOG_DEBUG, "Starting up: %s "
+ ", vols started till now: %d", xl->name,
+ nfs->upsubvols);
+ goto unlock;
+ }
+ }
+ }
+unlock:
+ UNLOCK (&nfs->svinitlock);
+
+ return 0;
+}
+
+
+int32_t
+nfs_start_subvol_lookup_cbk (call_frame_t *frame, void *cookie,
+ xlator_t *this, int32_t op_ret, int32_t op_errno,
+ inode_t *inode, struct iatt *buf, dict_t *xattr,
+ struct iatt *postparent)
+{
+ struct nfs_state *nfs = NULL;
+ xlator_t *startedxl = NULL;
+
+ if (op_ret == -1) {
+ gf_log (GF_NFS, GF_LOG_CRITICAL, "Failed to lookup root: %s",
+ strerror (op_errno));
+ goto err;
+ }
+
+ nfs = frame->local;
+ startedxl = cookie;
+ gf_log (GF_NFS, GF_LOG_TRACE, "Started %s", startedxl->name);
+err:
+ return 0;
+}
+
+
+int
+nfs_startup_subvolume (struct nfs_state *nfs, xlator_t *xl)
+{
+ int ret = -1;
+ loc_t rootloc = {0, };
+ nfs_user_t nfu = {0, };
+
+ if ((!nfs) || (!xl))
+ return -1;
+
+ if (nfs_subvolume_started (nfs, xl)) {
+ gf_log (GF_NFS,GF_LOG_TRACE, "Subvolume already started: %s",
+ xl->name);
+ ret = 0;
+ goto err;
+ }
+
+ nfs_subvolume_set_started (nfs, xl);
+ ret = nfs_inode_loc_fill (xl->itable->root, &rootloc);
+ if (ret == -1) {
+ gf_log (GF_NFS, GF_LOG_CRITICAL, "Failed to init root loc");
+ goto err;
+ }
+
+ nfs_user_root_create (&nfu);
+ ret = nfs_fop_lookup (xl, &nfu, &rootloc, nfs_start_subvol_lookup_cbk,
+ (void *)nfs);
+ if (ret < 0) {
+ gf_log (GF_NFS, GF_LOG_CRITICAL, "Failed to lookup root: %s",
+ strerror (-ret));
+ goto err;
+ }
+
+ nfs_loc_wipe (&rootloc);
+
+err:
+ return ret;
+}
+
+int
+nfs_startup_subvolumes (struct nfs_state *nfs)
+{
+ int ret = -1;
+ xlator_list_t *cl = NULL;
+ if (!nfs)
+ return -1;
+
+ cl = nfs->subvols;
+ while (cl) {
+ gf_log (GF_NFS, GF_LOG_DEBUG, "Starting subvolume: %s",
+ cl->xlator->name);
+ ret = nfs_startup_subvolume (nfs, cl->xlator);
+ if (ret == -1) {
+ gf_log (GF_NFS, GF_LOG_CRITICAL, "Failed to start-up "
+ "xlator: %s", cl->xlator->name);
+ goto err;
+ }
+ cl = cl->next;
+ }
+
+ ret = 0;
+err:
+ return ret;
+}
+
+
+int
+nfs_init_subvolume (struct nfs_state *nfs, xlator_t *xl)
+{
+ unsigned int lrusize = 0;
+ int ret = -1;
+
+ if ((!nfs) || (!xl))
+ return -1;
+
+ lrusize = nfs->memfactor * GF_NFS_INODE_LRU_MULT;
+ xl->itable = inode_table_new (lrusize, xl);
+ if (!xl->itable) {
+ gf_log (GF_NFS, GF_LOG_CRITICAL, "Failed to allocate "
+ "inode table");
+ goto err;
+ }
+ ret = 0;
+err:
+ return ret;
+}
+
+int
+nfs_init_subvolumes (struct nfs_state *nfs, xlator_list_t *cl)
+{
+ int ret = -1;
+ unsigned int lrusize = 0;
+ int svcount = 0;
+
+ if ((!nfs) || (!cl))
+ return -1;
+
+ lrusize = nfs->memfactor * GF_NFS_INODE_LRU_MULT;
+ nfs->subvols = cl;
+ gf_log (GF_NFS, GF_LOG_TRACE, "inode table lru: %d", lrusize);
+
+ while (cl) {
+ gf_log (GF_NFS, GF_LOG_DEBUG, "Initing subvolume: %s",
+ cl->xlator->name);
+ ret = nfs_init_subvolume (nfs, cl->xlator);
+ if (ret == -1) {
+ gf_log (GF_NFS, GF_LOG_CRITICAL, "Failed to init "
+ "xlator: %s", cl->xlator->name);
+ goto err;
+ }
+ ++svcount;
+ cl = cl->next;
+ }
+
+ LOCK_INIT (&nfs->svinitlock);
+ nfs->initedxl = CALLOC (svcount, sizeof (xlator_t *));
+ if (!nfs->initedxl) {
+ gf_log (GF_NFS, GF_LOG_ERROR, "Failed to allocated inited xls");
+ ret = -1;
+ goto err;
+ }
+
+ gf_log (GF_NFS, GF_LOG_TRACE, "Inited volumes: %d", svcount);
+ nfs->allsubvols = svcount;
+ ret = 0;
+err:
+ return ret;
+}
+
+
+int
+nfs_user_root_create (nfs_user_t *newnfu)
+{
+ if (!newnfu)
+ return -1;
+
+ newnfu->uid = 0;
+ newnfu->gids[0] = 0;
+ newnfu->ngrps = 1;
+
+ return 0;
+}
+
+
+int
+nfs_user_create (nfs_user_t *newnfu, uid_t uid, gid_t gid, gid_t *auxgids,
+ int auxcount)
+{
+ int x = 1;
+ int y = 0;
+
+ /* We test for GF_REQUEST_MAXGROUPS instead of NFS_FOP_NGROUPS because
+ * the latter accounts for the @gid being in @auxgids, which is not the
+ * case here.
+ */
+ if ((!newnfu) || (auxcount > GF_REQUEST_MAXGROUPS))
+ return -1;
+
+ newnfu->uid = uid;
+ newnfu->gids[0] = gid;
+ newnfu->ngrps = 1;
+
+ gf_log (GF_NFS, GF_LOG_TRACE, "uid: %d, gid %d, gids: %d", uid, gid,
+ auxcount);
+
+ if (!auxgids)
+ return 0;
+
+ for (; y < auxcount; ++x,++y) {
+ newnfu->gids[x] = auxgids[y];
+ ++newnfu->ngrps;
+ gf_log (GF_NFS, GF_LOG_TRACE, "gid: %d", auxgids[y]);
+ }
+
+ return 0;
+}
+
+
+void
+nfs_request_user_init (nfs_user_t *nfu, rpcsvc_request_t *req)
+{
+ gid_t *gidarr = NULL;
+ int gids = 0;
+
+ if ((!req) || (!nfu))
+ return;
+
+ gidarr = rpcsvc_auth_unix_auxgids (req, &gids);
+ nfs_user_create (nfu, rpcsvc_request_uid (req), rpcsvc_request_gid (req)
+ , gidarr, gids);
+
+ return;
+}
+
+
+int
+init (xlator_t *this) {
+
+ struct nfs_state *nfs = NULL;
+ int ret = -1;
+ unsigned int fopspoolsize = 0;
+
+ if (!this)
+ return -1;
+
+ if ((!this->children) || (!this->children->xlator)) {
+ gf_log (GF_NFS, GF_LOG_ERROR, "nfs must have at least one"
+ " child subvolume");
+ return -1;
+ }
+
+ nfs = CALLOC (1, sizeof (*nfs));
+ if (!nfs) {
+ gf_log (GF_NFS, GF_LOG_ERROR, "memory allocation failed");
+ return -1;
+ }
+
+ /* RPC service needs to be started before NFS versions can be inited. */
+ nfs->rpcsvc = rpcsvc_init (this->ctx, this->options);
+ if (!nfs->rpcsvc) {
+ gf_log (GF_NFS, GF_LOG_ERROR, "RPC service init failed");
+ goto free_nfs;
+ }
+
+ nfs->memfactor = GF_NFS_DEFAULT_MEMFACTOR;
+ fopspoolsize = nfs->memfactor * GF_NFS_CONCURRENT_OPS_MULT;
+ /* FIXME: Really saddens me to see this as xlator wide. */
+ nfs->foppool = mem_pool_new (struct nfs_fop_local, fopspoolsize);
+ if (!nfs->foppool) {
+ gf_log (GF_NFS, GF_LOG_CRITICAL, "Failed to allocate fops local"
+ " pool");
+ goto free_rpcsvc;
+ }
+
+ this->private = (void *)nfs;
+ INIT_LIST_HEAD (&nfs->versions);
+ ret = nfs_add_all_initiators (nfs);
+ if (ret == -1) {
+ gf_log (GF_NFS, GF_LOG_ERROR, "Failed to add initiators");
+ goto free_nfs;
+ }
+
+ this->ctx->top = this;
+ ret = nfs_init_subvolumes (nfs, this->children);
+ if (ret == -1) {
+ gf_log (GF_NFS, GF_LOG_CRITICAL, "Failed to init NFS exports");
+ goto free_rpcsvc;
+ }
+
+free_rpcsvc:
+ /*
+ * rpcsvc_deinit */
+free_nfs:
+ if (ret == -1)
+ FREE (nfs);
+
+ gf_log (GF_NFS, GF_LOG_DEBUG, "NFS service started");
+ return ret;
+}
+
+
+int
+notify (xlator_t *this, int32_t event, void *data, ...)
+{
+ struct nfs_state *nfs = NULL;
+ xlator_t *subvol = NULL;
+ int ret = -1;
+
+ nfs = (struct nfs_state *)this->private;
+ subvol = (xlator_t *)data;
+
+ gf_log (GF_NFS, GF_LOG_TRACE, "Notification received: %d",
+ event);
+ switch (event)
+ {
+ case GF_EVENT_CHILD_UP:
+ {
+ nfs_startup_subvolume (nfs, subvol);
+ if ((nfs->upsubvols == nfs->allsubvols) &&
+ (!nfs->subvols_started)) {
+ nfs->subvols_started = 1;
+ gf_log (GF_NFS, GF_LOG_TRACE, "All children up,"
+ " starting RPC");
+ ret = nfs_init_versions (nfs, this);
+ if (ret == -1)
+ gf_log (GF_NFS, GF_LOG_CRITICAL,
+ "Failed to initialize "
+ "protocols");
+ }
+ break;
+ }
+
+ case GF_EVENT_PARENT_UP:
+ {
+ default_notify (this, GF_EVENT_PARENT_UP, data);
+ break;
+ }
+ }
+ return 0;
+}
+
+
+int
+fini (xlator_t *this)
+{
+
+ struct nfs_state *nfs = NULL;
+
+ nfs = (struct nfs_state *)this->private;
+ gf_log (GF_NFS, GF_LOG_DEBUG, "NFS service going down");
+ nfs_deinit_versions (&nfs->versions, this);
+ return 0;
+}
+
+struct xlator_cbks cbks = { };
+struct xlator_mops mops = { };
+struct xlator_fops fops = { };
+
+struct volume_options options[] = {
+ { .key = {"nfs3.read-size"},
+ .type = GF_OPTION_TYPE_SIZET,
+ .description = "Size in which the client should issue read requests"
+ " to the Gluster NFSv3 server. Must be a multiple of"
+ " 4KiB."
+ },
+ { .key = {"nfs3.write-size"},
+ .type = GF_OPTION_TYPE_SIZET,
+ .description = "Size in which the client should issue write requests"
+ " to the Gluster NFSv3 server. Must be a multiple of"
+ " 4KiB."
+ },
+ { .key = {"nfs3.readdir-size"},
+ .type = GF_OPTION_TYPE_SIZET,
+ .description = "Size in which the client should issue directory "
+ " reading requests."
+ },
+ { .key = {"nfs3.*.volume-access"},
+ .type = GF_OPTION_TYPE_STR,
+ .description = "Type of access desired for this subvolume: "
+ " read-only, read-write(default)"
+ },
+ { .key = {"rpc-auth.auth-unix"},
+ .type = GF_OPTION_TYPE_BOOL,
+ .description = "Disable or enable the AUTH_UNIX authentication type."
+ "Must always be enabled for better interoperability."
+ "However, can be disabled if needed. Enabled by"
+ "default"
+ },
+ { .key = {"rpc-auth.auth-null"},
+ .type = GF_OPTION_TYPE_BOOL,
+ .description = "Disable or enable the AUTH_NULL authentication type."
+ "Must always be enabled. This option is here only to"
+ " avoid unrecognized option warnings"
+ },
+ { .key = {"rpc-auth.auth-unix.*"},
+ .type = GF_OPTION_TYPE_BOOL,
+ .description = "Disable or enable the AUTH_UNIX authentication type "
+ "for a particular exported volume over-riding defaults"
+ " and general setting for AUTH_UNIX scheme. Must "
+ "always be enabled for better interoperability."
+ "However, can be disabled if needed. Enabled by"
+ "default."
+ },
+ { .key = {"rpc-auth.auth-null.*"},
+ .type = GF_OPTION_TYPE_BOOL,
+ .description = "Disable or enable the AUTH_NULL authentication type "
+ "for a particular exported volume over-riding defaults"
+ " and general setting for AUTH_NULL. Must always be "
+ "enabled. This option is here only to avoid "
+ "unrecognized option warnings."
+ },
+ { .key = {"rpc-auth.addr.allow"},
+ .type = GF_OPTION_TYPE_STR,
+ .description = "Allow a comma separated list of addresses and/or"
+ " hostnames to connect to the server. By default, all"
+ " connections are disallowed. This allows users to "
+ "define a general rule for all exported volumes."
+ },
+ { .key = {"rpc-auth.addr.reject"},
+ .type = GF_OPTION_TYPE_STR,
+ .description = "Reject a comma separated list of addresses and/or"
+ " hostnames from connecting to the server. By default,"
+ " all connections are disallowed. This allows users to"
+ "define a general rule for all exported volumes."
+ },
+ { .key = {"rpc-auth.addr.*.allow"},
+ .type = GF_OPTION_TYPE_STR,
+ .description = "Allow a comma separated list of addresses and/or"
+ " hostnames to connect to the server. By default, all"
+ " connections are disallowed. This allows users to "
+ "define a rule for a specific exported volume."
+ },
+ { .key = {"rpc-auth.addr.*.reject"},
+ .type = GF_OPTION_TYPE_STR,
+ .description = "Reject a comma separated list of addresses and/or"
+ " hostnames from connecting to the server. By default,"
+ " all connections are disallowed. This allows users to"
+ "define a rule for a specific exported volume."
+ },
+ { .key = {"rpc-auth.ports.insecure"},
+ .type = GF_OPTION_TYPE_BOOL,
+ .description = "Allow client connections from unprivileged ports. By "
+ "default only privileged ports are allowed. This is a"
+ "global setting in case insecure ports are to be "
+ "enabled for all exports using a single option."
+ },
+ { .key = {"rpc-auth.ports.*.insecure"},
+ .type = GF_OPTION_TYPE_BOOL,
+ .description = "Allow client connections from unprivileged ports. By "
+ "default only privileged ports are allowed. Use this"
+ " option to set enable or disable insecure ports for "
+ "a specific subvolume and to over-ride global setting "
+ " set by the previous option."
+ },
+ { .key = {"rpc-auth.addr.namelookup"},
+ .type = GF_OPTION_TYPE_BOOL,
+ .description = "Users have the option of turning off name lookup for"
+ " incoming client connections using this option. In some "
+ "setups, the name server can take too long to reply to DNS "
+ "queries resulting in timeouts of mount requests. Use this "
+ "option to turn off name lookups during address "
+ "authentication. Note, turning this off will prevent you from"
+ " using hostnames in rpc-auth.addr.* filters. By default, "
+ " name lookup is on."
+ },
+ { .key = {NULL} },
+};
+
diff --git a/xlators/nfs/server/src/nfs.h b/xlators/nfs/server/src/nfs.h
new file mode 100644
index 000000000..b49738345
--- /dev/null
+++ b/xlators/nfs/server/src/nfs.h
@@ -0,0 +1,98 @@
+/*
+ Copyright (c) 2010 Gluster, Inc. <http://www.gluster.com>
+ This file is part of GlusterFS.
+
+ GlusterFS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3 of the License,
+ or (at your option) any later version.
+
+ GlusterFS is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see
+ <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __NFS_H__
+#define __NFS_H__
+
+#ifndef _CONFIG_H
+#define _CONFIG_H
+#include "config.h"
+#endif
+
+#include "rpcsvc.h"
+#include "dict.h"
+#include "xlator.h"
+
+#define GF_NFS "nfs"
+
+#define GF_NFS_CONCURRENT_OPS_MULT 15
+
+#define GF_NFS_INODE_LRU_MULT 6000
+
+#define GF_RPC_MIN_THREADS 1
+#define GF_RPC_MAX_THREADS 16
+
+#define GF_NFS_DEFAULT_MEMFACTOR 15
+#define GF_NFS_MIN_MEMFACTOR 1
+#define GF_NFS_MAX_MEMFACTOR 30
+
+/* Callback into a version-specific NFS protocol.
+ * The return type is used by the nfs.c code to register the protocol.
+ * with the RPC service.
+ */
+typedef rpcsvc_program_t *(*nfs_version_initer_t) (xlator_t *nfsx);
+
+/* List of version-specific protocol initiators */
+struct nfs_initer_list {
+ struct list_head list;
+ nfs_version_initer_t init;
+ rpcsvc_program_t *program;
+};
+
+
+struct nfs_state {
+ rpcsvc_t *rpcsvc;
+ struct list_head versions;
+ struct mem_pool *foppool;
+ unsigned int memfactor;
+ xlator_list_t *subvols;
+
+ gf_lock_t svinitlock;
+ int allsubvols;
+ int upsubvols;
+ xlator_t **initedxl;
+ int subvols_started;
+};
+
+
+/* We have one gid more than the glusterfs maximum since we pass the primary
+ * gid as the first element of the array.
+ */
+#define NFS_NGROUPS (GF_REQUEST_MAXGROUPS + 1)
+
+/* Index of the primary gid */
+#define NFS_PRIMGID_IDX 0
+
+typedef struct nfs_user_info {
+ uid_t uid;
+ gid_t gids[NFS_NGROUPS];
+ int ngrps;
+} nfs_user_t;
+
+extern int
+nfs_user_root_create (nfs_user_t *newnfu);
+
+extern int
+nfs_user_create (nfs_user_t *newnfu, uid_t uid, gid_t gid, gid_t *auxgids,
+ int auxcount);
+
+extern void
+nfs_request_user_init (nfs_user_t *nfu, rpcsvc_request_t *req);
+
+#endif