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 | |
| 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')
| -rw-r--r-- | xlators/nfs/Makefile.am | 2 | ||||
| -rw-r--r-- | xlators/nfs/server/Makefile.am | 3 | ||||
| -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 | 
13 files changed, 4811 insertions, 1 deletions
diff --git a/xlators/nfs/Makefile.am b/xlators/nfs/Makefile.am index 8ead8848aa0..de3c08cbada 100644 --- a/xlators/nfs/Makefile.am +++ b/xlators/nfs/Makefile.am @@ -1,3 +1,3 @@ -SUBDIRS = lib +SUBDIRS = lib server  CLEANFILES = diff --git a/xlators/nfs/server/Makefile.am b/xlators/nfs/server/Makefile.am new file mode 100644 index 00000000000..a985f42a877 --- /dev/null +++ b/xlators/nfs/server/Makefile.am @@ -0,0 +1,3 @@ +SUBDIRS = src + +CLEANFILES = diff --git a/xlators/nfs/server/src/Makefile.am b/xlators/nfs/server/src/Makefile.am new file mode 100644 index 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  | 
