diff options
author | Shehjar Tikoo <shehjart@gluster.com> | 2010-03-31 07:27:03 +0000 |
---|---|---|
committer | Anand V. Avati <avati@dev.gluster.com> | 2010-03-31 07:44:02 -0700 |
commit | c4fd1cf7325972d8ff64ef3a2bea70edcf4f1085 (patch) | |
tree | b91c42227b2881eb8b77d39aca3d8348966bc052 /xlators/nfs/server/src | |
parent | 8b2949db0d56bdf5842abcb72437cc7dccd884df (diff) |
nfs: Add generic nfs translator
Signed-off-by: Shehjar Tikoo <shehjart@gluster.com>
Signed-off-by: Anand V. Avati <avati@dev.gluster.com>
BUG: 399 (NFS translator with Mount v3 and NFS v3 support)
URL: http://bugs.gluster.com/cgi-bin/bugzilla3/show_bug.cgi?id=399
Diffstat (limited to 'xlators/nfs/server/src')
-rw-r--r-- | xlators/nfs/server/src/Makefile.am | 14 | ||||
-rw-r--r-- | xlators/nfs/server/src/nfs-common.c | 379 | ||||
-rw-r--r-- | xlators/nfs/server/src/nfs-common.h | 76 | ||||
-rw-r--r-- | xlators/nfs/server/src/nfs-fops.c | 1441 | ||||
-rw-r--r-- | xlators/nfs/server/src/nfs-fops.h | 259 | ||||
-rw-r--r-- | xlators/nfs/server/src/nfs-generics.c | 1067 | ||||
-rw-r--r-- | xlators/nfs/server/src/nfs-generics.h | 174 | ||||
-rw-r--r-- | xlators/nfs/server/src/nfs-inodes.c | 571 | ||||
-rw-r--r-- | xlators/nfs/server/src/nfs-inodes.h | 83 | ||||
-rw-r--r-- | xlators/nfs/server/src/nfs.c | 645 | ||||
-rw-r--r-- | xlators/nfs/server/src/nfs.h | 98 |
11 files changed, 4807 insertions, 0 deletions
diff --git a/xlators/nfs/server/src/Makefile.am b/xlators/nfs/server/src/Makefile.am new file mode 100644 index 00000000000..453fd4753fc --- /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 00000000000..3623f041c14 --- /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 00000000000..20003aa7130 --- /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 00000000000..3d4968a8b17 --- /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 00000000000..8b12777d7b4 --- /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 00000000000..f83a7c86814 --- /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 00000000000..980e73020d4 --- /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 00000000000..69bad072484 --- /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 00000000000..04d3eba6662 --- /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 00000000000..ca6fda69c29 --- /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 00000000000..b4973834558 --- /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 |