diff options
| author | Shehjar Tikoo <shehjart@gluster.com> | 2010-03-31 07:27:04 +0000 | 
|---|---|---|
| committer | Anand V. Avati <avati@dev.gluster.com> | 2010-03-31 07:44:06 -0700 | 
| commit | e63053803dca86b4283b71bc4ef4cb180ec72d89 (patch) | |
| tree | 05702e5e62f1596250106e3668e3d1062a0472b5 /xlators/nfs/server/src | |
| parent | c4fd1cf7325972d8ff64ef3a2bea70edcf4f1085 (diff) | |
nfs: Add MOUNTv3 protocol support
Signed-off-by: Shehjar Tikoo <shehjart@gluster.com>
Signed-off-by: Anand V. Avati <avati@dev.gluster.com>
BUG: 399 (NFS translator with Mount v3 and NFS v3 support)
URL: http://bugs.gluster.com/cgi-bin/bugzilla3/show_bug.cgi?id=399
Diffstat (limited to 'xlators/nfs/server/src')
| -rw-r--r-- | xlators/nfs/server/src/Makefile.am | 4 | ||||
| -rw-r--r-- | xlators/nfs/server/src/mount3.c | 914 | ||||
| -rw-r--r-- | xlators/nfs/server/src/mount3.h | 78 | ||||
| -rw-r--r-- | xlators/nfs/server/src/nfs.c | 21 | ||||
| -rw-r--r-- | xlators/nfs/server/src/nfs3-fh.c | 271 | ||||
| -rw-r--r-- | xlators/nfs/server/src/nfs3-fh.h | 105 | 
6 files changed, 1390 insertions, 3 deletions
diff --git a/xlators/nfs/server/src/Makefile.am b/xlators/nfs/server/src/Makefile.am index 453fd4753..9661dd95d 100644 --- a/xlators/nfs/server/src/Makefile.am +++ b/xlators/nfs/server/src/Makefile.am @@ -2,10 +2,10 @@ 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_SOURCES = nfs.c nfs-common.c nfs-fops.c nfs-inodes.c nfs-generics.c mount3.c nfs3-fh.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 +noinst_HEADERS = nfs.h nfs-common.h nfs-fops.h nfs-inodes.h nfs-generics.h mount3.h nfs3-fh.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)\ diff --git a/xlators/nfs/server/src/mount3.c b/xlators/nfs/server/src/mount3.c new file mode 100644 index 000000000..dc8805085 --- /dev/null +++ b/xlators/nfs/server/src/mount3.c @@ -0,0 +1,914 @@ +/* +  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 "mount3.h" +#include "xdr-nfs3.h" +#include "msg-nfs3.h" +#include "iobuf.h" +#include "nfs-common.h" +#include "nfs3-fh.h" +#include "nfs-fops.h" +#include "nfs-inodes.h" +#include "nfs-generics.h" +#include "locking.h" +#include "iatt.h" + + +#include <errno.h> +#include <sys/socket.h> +#include <sys/uio.h> + +typedef ssize_t (*mnt3_serializer) (struct iovec outmsg, void *args); + + +/* Generic reply function for MOUNTv3 specific replies. */ +int +mnt3svc_submit_reply (rpcsvc_request_t *req, void *arg, mnt3_serializer sfunc) +{ +        struct iovec            outmsg = {0, }; +        struct iobuf            *iob = NULL; +        struct mount3_state     *ms = NULL; +        int                     ret = -1; + +        if (!req) +                return -1; + +        ms = (struct mount3_state *)rpcsvc_request_program_private (req); +        if (!ms) { +                gf_log (GF_MNT, GF_LOG_ERROR, "mount state not found"); +                goto ret; +        } + +        /* First, get the io buffer into which the reply in arg will +         * be serialized. +         */ +        iob = iobuf_get (ms->iobpool); +        if (!iob) { +                gf_log (GF_MNT, GF_LOG_ERROR, "Failed to get iobuf"); +                goto ret; +        } + +        iobuf_to_iovec (iob, &outmsg); +        /* Use the given serializer to translate the give C structure in arg +         * to XDR format which will be written into the buffer in outmsg. +         */ +        outmsg.iov_len = sfunc (outmsg, arg); + +        /* Then, submit the message for transmission. */ +        ret = rpcsvc_submit_message (req, outmsg, iob); +        iobuf_unref (iob); +        if (ret == -1) { +                gf_log (GF_MNT, GF_LOG_ERROR, "Reply submission failed"); +                goto ret; +        } + +        ret = 0; +ret: +        return ret; +} + + +/* Generic error reply function, just pass the err status + * and it will do the rest, including transmission. + */ +int +mnt3svc_mnt_error_reply (rpcsvc_request_t *req, int mntstat) +{ +        mountres3       res; + +        if (!req) +                return -1; + +        res.fhs_status = mntstat; +        mnt3svc_submit_reply (req, (void *)&res, +                              (mnt3_serializer)xdr_serialize_mountres3); + +        return 0; +} + + +mountstat3 +mnt3svc_errno_to_mnterr (int32_t errnum) +{ +        mountstat3      stat; + +        switch (errnum) { + +                case 0: +                        stat = MNT3_OK; +                        break; +                case ENOENT: +                        stat = MNT3ERR_NOENT; +                        break; +                case EPERM: +                        stat = MNT3ERR_PERM; +                        break; +                case EIO: +                        stat = MNT3ERR_IO; +                        break; +                case EACCES: +                        stat = MNT3ERR_ACCES; +                        break; +                case ENOTDIR: +                        stat = MNT3ERR_NOTDIR; +                        break; +                case EINVAL: +                        stat = MNT3ERR_INVAL; +                        break; +                case ENOSYS: +                        stat = MNT3ERR_NOTSUPP; +                        break; +                case ENOMEM: +                        stat = MNT3ERR_SERVERFAULT; +                        break; +                default: +                        stat = MNT3ERR_SERVERFAULT; +                        break; +        } + +        return stat; +} + + +mountres3 +mnt3svc_set_mountres3 (mountstat3 stat, struct nfs3_fh *fh, int *authflavor, +                       u_int aflen) +{ +        mountres3       res = {0, }; +        uint32_t        fhlen = 0; + +        res.fhs_status = stat; +        fhlen = nfs3_fh_compute_size (fh); +        res.mountres3_u.mountinfo.fhandle.fhandle3_len = fhlen; +        res.mountres3_u.mountinfo.fhandle.fhandle3_val = (char *)fh; +        res.mountres3_u.mountinfo.auth_flavors.auth_flavors_val = authflavor; +        res.mountres3_u.mountinfo.auth_flavors.auth_flavors_len = aflen; + +        return res; +} + + +int +mnt3svc_update_mountlist (struct mount3_state *ms, rpcsvc_request_t *req, +                          xlator_t *exportxl) +{ +        struct mountentry       *me = NULL; +        int                     ret = -1; + +        if ((!ms) || (!req) || (!exportxl)) +                return -1; + +        me = (struct mountentry *)CALLOC (1, sizeof (*me)); +        if (!me) +                return -1; + +        strcpy (me->exname, exportxl->name); +        INIT_LIST_HEAD (&me->mlist); +        /* Must get the IP or hostname of the client so we +         * can map it into the mount entry. +         */ +        ret = rpcsvc_conn_peername (req->conn, me->hostname, MNTPATHLEN); +        if (ret == -1) +                goto free_err; + +        LOCK (&ms->mountlock); +        { +                list_add_tail (&me->mlist, &ms->mountlist); +        } +        UNLOCK (&ms->mountlock); + +free_err: +        if (ret == -1) +                FREE (me); + +        return ret; +} + + +int32_t +mnt3svc_lookup_mount_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) +{ +        mountres3               res = {0, }; +        rpcsvc_request_t        *req = NULL; +        struct nfs3_fh          fh = {{0}, }; +        struct mount3_state     *ms = NULL; +        xlator_t                *exportxl = NULL; +        mountstat3              status = 0; +        int                     autharr[10]; +        int                     autharrlen = 0; +        rpcsvc_t                *svc = NULL; + +        req = (rpcsvc_request_t *)frame->local; + +        if (!req) +                return -1; + +        ms = (struct mount3_state *)rpcsvc_request_program_private (req); +        if (!ms) { +                gf_log (GF_MNT, GF_LOG_ERROR, "mount state not found"); +                op_ret = -1; +                op_errno = EINVAL; +        } + +        if (op_ret == -1) +                status = mnt3svc_errno_to_mnterr (op_errno); + +        if (status != MNT3_OK) +                goto xmit_res; + +        exportxl = (xlator_t *)cookie; +        fh = nfs3_fh_build_root_fh (ms->nfsx->children, exportxl, *buf); +        mnt3svc_update_mountlist (ms, req, exportxl); +xmit_res: +        gf_log (GF_MNT, GF_LOG_DEBUG, "Mount reply status: %d", status); +        if (op_ret == 0) { +                svc = rpcsvc_request_service (req); +                autharrlen = rpcsvc_auth_array (svc, exportxl->name, autharr, +                                                10); +        } + +        res = mnt3svc_set_mountres3 (status, &fh, autharr, autharrlen); +        mnt3svc_submit_reply (req, (void *)&res, +                              (mnt3_serializer)xdr_serialize_mountres3); + +        return 0; +} + + +int +mnt3svc_mount (rpcsvc_request_t *req, xlator_t * xl) +{ +        loc_t           oploc = {0, }; +        int             ret = -1; +        nfs_user_t      nfu = {0, }; + +        if ((!req) || (!xl)) +                return ret; + +        ret = nfs_ino_loc_fill (xl->itable, 1, 0, &oploc); +        /* To service the mount request, all we need to do +         * is to send a lookup fop that returns the stat +         * for the root of the child volume. This is +         * used to build the root fh sent to the client. +         */ +        nfs_request_user_init (&nfu, req); +        ret = nfs_lookup (xl, &nfu, &oploc, mnt3svc_lookup_mount_cbk, +                          (void *)req); +        nfs_loc_wipe (&oploc); + +        return ret; +} + + +int +mnt3svc_mnt (rpcsvc_request_t *req) +{ +        struct iovec            pvec = {0, }; +        char                    path[MNTPATHLEN]; +        int                     ret = -1; +        xlator_t                *targetxl = NULL; +        struct mount3_state     *ms = NULL; +        rpcsvc_t                *svc = NULL; +        mountstat3              mntstat = MNT3ERR_SERVERFAULT; + +        if (!req) +                return -1; + +        pvec.iov_base = path; +        pvec.iov_len = MNTPATHLEN; +        ret = xdr_to_mountpath (pvec, req->msg); +        if (ret == -1) { +                gf_log (GF_MNT, GF_LOG_ERROR, "Failed to decode args"); +                rpcsvc_request_seterr (req, GARBAGE_ARGS); +                goto rpcerr; +        } + +        ms = (struct mount3_state *)rpcsvc_request_program_private (req); +        if (!ms) { +                gf_log (GF_MNT, GF_LOG_ERROR, "Mount state not present"); +                rpcsvc_request_seterr (req, SYSTEM_ERR); +                ret = -1; +                goto rpcerr; +        } + +        ret = 0; +        gf_log (GF_MNT, GF_LOG_DEBUG, "dirpath: %s", path); +        targetxl = nfs_mntpath_to_xlator (ms->nfsx->children, path); +        if (!targetxl) { +                ret = -1; +                mntstat = MNT3ERR_NOENT; +                goto mnterr; +        } + +        svc = rpcsvc_request_service (req); +        ret = rpcsvc_conn_peer_check (svc->options, targetxl->name, +                                      rpcsvc_request_conn (req)); +        if (ret == RPCSVC_AUTH_REJECT) { +                mntstat = MNT3ERR_ACCES; +                ret = -1; +                gf_log (GF_MNT, GF_LOG_TRACE, "Peer not allowed"); +                goto mnterr; +        } + +        ret = rpcsvc_conn_privport_check (svc, targetxl->name, +                                          rpcsvc_request_conn (req)); +        if (ret == RPCSVC_AUTH_REJECT) { +                mntstat = MNT3ERR_ACCES; +                ret = -1; +                gf_log (GF_MNT, GF_LOG_TRACE, "Unprivileged port not allowed"); +                goto rpcerr; +        } + +        mnt3svc_mount (req, targetxl); +mnterr: +        if (ret == -1) { +                mnt3svc_mnt_error_reply (req, mntstat); +                ret = 0; +        } + +rpcerr: +        return ret; +} + + +int +mnt3svc_null (rpcsvc_request_t *req) +{ +        struct iovec    dummyvec = {0, }; + +        if (!req) { +                gf_log (GF_MNT, GF_LOG_ERROR, "Got NULL request!"); +                return 0; +        } + +        rpcsvc_submit_generic (req, dummyvec, NULL); +        return 0; +} + + +mountlist +__build_mountlist (struct mount3_state *ms, int *count) +{ +        struct mountbody        *mlist = NULL; +        struct mountbody        *prev = NULL; +        struct mountbody        *first = NULL; +        size_t                  namelen = 0; +        int                     ret = -1; +        struct mountentry       *me = NULL; + +        if ((!ms) || (!count)) +                return NULL; + +        *count = 0; +        gf_log (GF_MNT, GF_LOG_DEBUG, "Building mount list:"); +        list_for_each_entry (me, &ms->mountlist, mlist) { +                namelen = strlen (me->exname); +                mlist = CALLOC (1, sizeof (*mlist)); +                if (!mlist) { +                        gf_log (GF_MNT, GF_LOG_ERROR, "Memory allocation" +                                " failed"); +                        goto free_list; +                } + +                mlist->ml_directory = CALLOC (namelen + 2, sizeof (char)); +                if (!mlist->ml_directory) { +                        gf_log (GF_MNT, GF_LOG_ERROR, "Memory allocation" +                                " failed"); +                        goto free_list; +                } + +                strcpy (mlist->ml_directory, "/"); +                strcat (mlist->ml_directory, me->exname); + +                namelen = strlen (me->hostname); +                mlist->ml_hostname = CALLOC (namelen + 2, sizeof (char)); +                if (!mlist->ml_hostname) { +                        gf_log (GF_MNT, GF_LOG_ERROR, "Memory allocation" +                                " failed"); +                        goto free_list; +                } + +                strcat (mlist->ml_hostname, me->hostname); + +                gf_log (GF_MNT, GF_LOG_DEBUG, "mount entry: dir: %s, host: %s", +                        mlist->ml_directory, mlist->ml_hostname); +                if (prev) { +                        prev->ml_next = mlist; +                        prev = mlist; +                } else +                        prev = mlist; + +                if (!first) +                        first = mlist; + +                (*count)++; +        } + +        ret = 0; + +free_list: +        if (ret == -1) { +                xdr_free_mountlist (first); +                first = NULL; +        } + +        return first; +} + + +mountlist +mnt3svc_build_mountlist (struct mount3_state *ms, int *count) +{ +        struct mountbody        *first = NULL; + +        LOCK (&ms->mountlock); +        { +                first = __build_mountlist (ms, count); +        } +        UNLOCK (&ms->mountlock); + +        return first; +} + + +int +mnt3svc_dump (rpcsvc_request_t *req) +{ +        int                     ret = -1; +        struct mount3_state     *ms = NULL; +        mountlist               mlist; +        mountstat3              mstat = 0; +        mnt3_serializer         sfunc = NULL; +        void                    *arg = NULL; + + +        if (!req) +                return -1; + +        ms = (struct mount3_state *)rpcsvc_request_program_private (req); +        if (!ms) { +                rpcsvc_request_seterr (req, SYSTEM_ERR); +                goto rpcerr; +        } + +        sfunc = (mnt3_serializer)xdr_serialize_mountlist; +        mlist = mnt3svc_build_mountlist (ms, &ret); +        arg = mlist; +        sfunc = (mnt3_serializer)xdr_serialize_mountlist; +        if (!mlist) { +                if (ret != 0) { +                        rpcsvc_request_seterr (req, SYSTEM_ERR); +                        ret = -1; +                        goto rpcerr; +                } else { +                        arg = &mstat; +                        sfunc = (mnt3_serializer)xdr_serialize_mountstat3; +                } +        } + +        mnt3svc_submit_reply (req, arg, sfunc); + +        xdr_free_mountlist (mlist); +        ret = 0; + +rpcerr: +        return ret; +} + + +int +__mnt3svc_umount (struct mount3_state *ms, char *dirpath, char *hostname) +{ +        struct mountentry       *me = NULL; +        char                    *exname = NULL; +        int                     ret = -1; + +        if ((!ms) || (!dirpath) || (!hostname)) +                return -1; + +        if (list_empty (&ms->mountlist)) +                return 0; + +        list_for_each_entry (me, &ms->mountlist, mlist) { +                exname = dirpath+1; +                if ((strcmp (me->exname, exname) == 0) && +                    (strcmp (me->hostname, hostname) == 0)) +                        break; +        } + +        if (!me) +                goto ret; + +        gf_log (GF_MNT, GF_LOG_DEBUG, "Unmounting: dir %s, host: %s", +                me->exname, me->hostname); +        list_del (&me->mlist); +        FREE (me); +        ret = 0; +ret: +        return ret; +} + + + +int +mnt3svc_umount (struct mount3_state *ms, char *dirpath, char *hostname) +{ +        int ret = -1; +        if ((!ms) || (!dirpath) || (!hostname)) +                return -1; + +        LOCK (&ms->mountlock); +        { +               ret = __mnt3svc_umount (ms, dirpath, hostname); +        } +        UNLOCK (&ms->mountlock); + +        return ret; +} + + +int +mnt3svc_umnt (rpcsvc_request_t *req) +{ +        char                    hostname[MNTPATHLEN]; +        char                    dirpath[MNTPATHLEN]; +        struct iovec            pvec = {0, }; +        int                     ret = -1; +        struct mount3_state     *ms = NULL; +        mountstat3              mstat = MNT3_OK; + +        if (!req) +                return -1; + +        /* Remove the mount point from the exports list. */ +        pvec.iov_base = dirpath; +        pvec.iov_len = MNTPATHLEN; +        ret = xdr_to_mountpath (pvec, req->msg);; +        if (ret == -1) { +                gf_log (GF_MNT, GF_LOG_ERROR, "Failed decode args"); +                rpcsvc_request_seterr (req, GARBAGE_ARGS); +                goto rpcerr; +        } + +        ms = (struct mount3_state *)rpcsvc_request_program_private (req); +        if (!ms) { +                gf_log (GF_MNT, GF_LOG_ERROR, "Mount state not present"); +                rpcsvc_request_seterr (req, SYSTEM_ERR); +                ret = -1; +                goto rpcerr; +        } + +        ret = rpcsvc_conn_peername (req->conn, hostname, MNTPATHLEN); +        if (ret != 0) { +                gf_log (GF_MNT, GF_LOG_ERROR, "Failed to get remote name: %s", +                        gai_strerror (ret)); +                goto try_umount_with_addr; +        } + +        gf_log (GF_MNT, GF_LOG_DEBUG, "dirpath: %s, hostname: %s", dirpath, +                hostname); +        ret = mnt3svc_umount (ms, dirpath, hostname); + +        /* Unmount succeeded with the given hostname. */ +        if (ret == 0) +                goto snd_reply; + +try_umount_with_addr: +        if (ret != 0) +                ret = rpcsvc_conn_peeraddr (req->conn, hostname, MNTPATHLEN, +                                            NULL, 0); + +        if (ret != 0) { +                gf_log (GF_MNT, GF_LOG_ERROR, "Failed to get remote addr: %s", +                        gai_strerror (ret)); +                rpcsvc_request_seterr (req, SYSTEM_ERR); +                goto rpcerr; +        } + +        gf_log (GF_MNT, GF_LOG_DEBUG, "dirpath: %s, hostname: %s", dirpath, +                hostname); +        ret = mnt3svc_umount (ms, dirpath, hostname); +        if (ret == -1) +                mstat = MNT3ERR_INVAL; + +        ret = 0; +snd_reply: +        mnt3svc_submit_reply (req, &mstat, +                              (mnt3_serializer)xdr_serialize_mountstat3); + +rpcerr: +        return ret; +} + + +int +__mnt3svc_umountall (struct mount3_state *ms) +{ +        struct mountentry       *me = NULL; + +        if (!ms) +                return -1; + +        list_for_each_entry (me, &ms->mountlist, mlist) { +                list_del (&me->mlist); +                FREE (me); +        } + +        return 0; +} + + +int +mnt3svc_umountall (struct mount3_state *ms) +{ +        int     ret = -1; +        if (!ms) +                return -1; + +        LOCK (&ms->mountlock); +        { +               ret = __mnt3svc_umountall (ms); +        } +        UNLOCK (&ms->mountlock); + +        return ret; +} + + +int +mnt3svc_umntall (rpcsvc_request_t *req) +{ +        int                     ret = -1; +        struct mount3_state     *ms = NULL; +        mountstat3              mstat = MNT3_OK; + +        if (!req) +                return -1; + +        ms = (struct mount3_state *)rpcsvc_request_program_private (req); +        if (!ms) { +                gf_log (GF_MNT, GF_LOG_ERROR, "Mount state not present"); +                rpcsvc_request_seterr (req, SYSTEM_ERR); +                ret = -1; +                goto rpcerr; +        } + +        mnt3svc_umountall (ms); +        mnt3svc_submit_reply (req, &mstat, +                              (mnt3_serializer)xdr_serialize_mountstat3); + +rpcerr: +        return ret; +} + + +exports +mnt3_xlchildren_to_exports (rpcsvc_t *svc, xlator_list_t *cl) +{ +        struct exportnode       *elist = NULL; +        struct exportnode       *prev = NULL; +        struct exportnode       *first = NULL; +        size_t                  namelen = 0; +        int                     ret = -1; +        char                    *addrstr = NULL; + +        if ((!cl) || (!svc)) +                return NULL; + +        while (cl) { +                namelen = strlen (cl->xlator->name); +                elist = CALLOC (1, sizeof (*elist)); +                if (!elist) { +                        gf_log (GF_MNT, GF_LOG_ERROR, "Memory allocation" +                                " failed"); +                        goto free_list; +                } + +                elist->ex_dir = CALLOC (namelen + 2, sizeof (char)); +                if (!elist->ex_dir) { +                        gf_log (GF_MNT, GF_LOG_ERROR, "Memory allocation" +                                " failed"); +                        goto free_list; +                } + +                strcpy (elist->ex_dir, "/"); +                strcat (elist->ex_dir, cl->xlator->name); + +                addrstr = rpcsvc_volume_allowed (svc->options,cl->xlator->name); +                if (addrstr) +                        addrstr = strdup (addrstr); +                else +                        addrstr = strdup ("No Access"); + +                elist->ex_groups = CALLOC (1, sizeof (struct groupnode)); +                if (!elist->ex_groups) { +                        gf_log (GF_MNT, GF_LOG_ERROR, "Memory allocation" +                                " failed"); +                        goto free_list; +                } + +                elist->ex_groups->gr_name = addrstr; +                if (prev) { +                        prev->ex_next = elist; +                        prev = elist; +                } else +                        prev = elist; + +                if (!first) +                        first = elist; + +                cl = cl->next; +        } + +        ret = 0; + +free_list: +        if (ret == -1) { +                xdr_free_exports_list (first); +                first = NULL; +        } + +        return first; +} + + +int +mnt3svc_export (rpcsvc_request_t *req) +{ +        struct mount3_state     *ms = NULL; +        exports                 elist = NULL; +        int                     ret = -1; + +        if (!req) +                return -1; + +        ms = (struct mount3_state *)rpcsvc_request_program_private (req); +        if (!ms) { +                gf_log (GF_MNT, GF_LOG_ERROR, "mount state not found"); +                rpcsvc_request_seterr (req, SYSTEM_ERR); +                goto err; +        } + +        /* Using the children translator names, build the export list */ +        elist = mnt3_xlchildren_to_exports (rpcsvc_request_service (req), +                                            ms->nfsx->children); +        if (!elist) { +                gf_log (GF_MNT, GF_LOG_ERROR, "Failed to build exports list"); +                rpcsvc_request_seterr (req, SYSTEM_ERR); +                goto err; +        } + +        /* Note how the serializer is passed to the generic reply function. */ +        mnt3svc_submit_reply (req, &elist, +                              (mnt3_serializer)xdr_serialize_exports); + +        xdr_free_exports_list (elist); +        ret = 0; +err: +        return ret; +} + + +struct mount3_state * +mnt3_init_state (xlator_t *nfsx) +{ +        struct mount3_state     *ms = NULL; + +        if (!nfsx) +                return NULL; + +        ms = CALLOC (1, sizeof (*ms)); +        if (!ms) { +                gf_log (GF_MNT, GF_LOG_ERROR, "Memory allocation failed"); +                return NULL; +        } + +        ms->iobpool = nfsx->ctx->iobuf_pool; +        ms->nfsx = nfsx; +        ms->exports = nfsx->children; +        INIT_LIST_HEAD (&ms->mountlist); +        LOCK_INIT (&ms->mountlock); + +        return ms; +} + +rpcsvc_actor_t  mnt3svc_actors[MOUNT3_PROC_COUNT] = { +        {"NULL", MOUNT3_NULL, mnt3svc_null, NULL, NULL}, +        {"MNT", MOUNT3_MNT, mnt3svc_mnt, NULL, NULL}, +        {"DUMP", MOUNT3_DUMP, mnt3svc_dump, NULL, NULL}, +        {"UMNT", MOUNT3_UMNT, mnt3svc_umnt, NULL, NULL}, +        {"UMNTALL", MOUNT3_UMNTALL, mnt3svc_umntall, NULL, NULL}, +        {"EXPORT", MOUNT3_EXPORT, mnt3svc_export, NULL, NULL} +}; + + + +/* Static init parts are assigned here, dynamic ones are done in + * mnt3svc_init and mnt3_init_state. + */ +rpcsvc_program_t        mnt3prog = { +                        .progname       = "MOUNT3", +                        .prognum        = MOUNT_PROGRAM, +                        .progver        = MOUNT_V3, +                        .progport       = GF_MOUNTV3_PORT, +                        .progaddrfamily = AF_INET, +                        .proghost       = NULL, +                        .actors         = mnt3svc_actors, +                        .numactors      = MOUNT3_PROC_COUNT, +}; + + +rpcsvc_program_t * +mnt3svc_init (xlator_t *nfsx) +{ +        struct mount3_state     *mstate = NULL; + +        if (!nfsx) +                return NULL; + +        gf_log (GF_MNT, GF_LOG_DEBUG, "Initing Mount v3 state"); +        mstate = mnt3_init_state (nfsx); +        if (!mstate) { +                gf_log (GF_MNT, GF_LOG_ERROR, "Mount v3 state init failed"); +                goto err; +        } + +        mnt3prog.private = mstate; + +        return &mnt3prog; +err: +        return NULL; +} + + +rpcsvc_actor_t  mnt1svc_actors[MOUNT1_PROC_COUNT] = { +        {"NULL", MOUNT1_NULL, mnt3svc_null, NULL, NULL}, +        {{0}, }, +        {"DUMP", MOUNT1_DUMP, mnt3svc_dump, NULL, NULL}, +        {"UMNT", MOUNT1_UMNT, mnt3svc_umnt, NULL, NULL}, +        {{0}, }, +        {"EXPORT", MOUNT1_EXPORT, mnt3svc_export, NULL, NULL} +}; + +rpcsvc_program_t        mnt1prog = { +                        .progname       = "MOUNT1", +                        .prognum        = MOUNT_PROGRAM, +                        .progver        = MOUNT_V1, +                        .progport       = GF_MOUNTV1_PORT, +                        .progaddrfamily = AF_INET, +                        .proghost       = NULL, +                        .actors         = mnt1svc_actors, +                        .numactors      = MOUNT1_PROC_COUNT, +}; + + +rpcsvc_program_t * +mnt1svc_init (xlator_t *nfsx) +{ +        struct mount3_state     *mstate = NULL; + +        if (!nfsx) +                return NULL; + +        gf_log (GF_MNT, GF_LOG_DEBUG, "Initing Mount v1 state"); +        mstate = mnt3_init_state (nfsx); +        if (!mstate) { +                gf_log (GF_MNT, GF_LOG_ERROR, "Mount v3 state init failed"); +                goto err; +        } + +        mnt1prog.private = mstate; + +        return &mnt1prog; +err: +        return NULL; +} + + diff --git a/xlators/nfs/server/src/mount3.h b/xlators/nfs/server/src/mount3.h new file mode 100644 index 000000000..7cfd2b0cb --- /dev/null +++ b/xlators/nfs/server/src/mount3.h @@ -0,0 +1,78 @@ +/* +  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 _MOUNT3_H_ +#define _MOUNT3_H_ + +#ifndef _CONFIG_H +#define _CONFIG_H +#include "config.h" +#endif + +#include "rpcsvc.h" +#include "dict.h" +#include "xlator.h" +#include "iobuf.h" +#include "nfs.h" +#include "list.h" +#include "xdr-nfs3.h" +#include "locking.h" + +/* Registered with portmap */ +#define GF_MOUNTV3_PORT         38465 +#define GF_MOUNTV3_IOB          (2 * GF_UNIT_KB) +#define GF_MOUNTV3_IOBPOOL      (GF_MOUNTV3_IOB * 50) + +#define GF_MOUNTV1_PORT         38466 +#define GF_MNT                  GF_NFS"-mount" + +extern rpcsvc_program_t * +mnt3svc_init (xlator_t *nfsx); + +extern rpcsvc_program_t * +mnt1svc_init (xlator_t *nfsx); + +/* Data structureused to store the list of mounts points currently + * in use by NFS clients. + */ +struct mountentry { +        /* Links to mount3_state->mountlist.  */ +        struct list_head        mlist; + +        /* The export name */ +        char                    exname[MNTPATHLEN]; +        char                    hostname[MNTPATHLEN]; +}; + +struct mount3_state { +        xlator_t                *nfsx; + +        /* The buffers for all network IO are got from this pool. */ +        struct iobuf_pool       *iobpool; +        xlator_list_t           *exports; + +        /* List of current mount points over all the exports from this +         * server. +         */ +        struct list_head        mountlist; + +        /* Used to protect the mountlist. */ +        gf_lock_t               mountlock; +}; +#endif diff --git a/xlators/nfs/server/src/nfs.c b/xlators/nfs/server/src/nfs.c index ca6fda69c..749379036 100644 --- a/xlators/nfs/server/src/nfs.c +++ b/xlators/nfs/server/src/nfs.c @@ -36,6 +36,7 @@  #include "logging.h"  #include "nfs-fops.h"  #include "inode.h" +#include "mount3.h"  /* Every NFS version must call this function with the init function   * for its particular version. @@ -134,8 +135,26 @@ err:  int  nfs_add_all_initiators (struct nfs_state *nfs)  { +        int     ret = 0; +          /* Add the initializers for all versions. */ -        return 0; +        ret = nfs_add_initer (&nfs->versions, mnt3svc_init); +        if (ret == -1) { +                gf_log (GF_NFS, GF_LOG_ERROR, "Failed to add protocol" +                        " initializer"); +                goto ret; +        } + +        ret = nfs_add_initer (&nfs->versions, mnt1svc_init); +        if (ret == -1) { +                gf_log (GF_NFS, GF_LOG_ERROR, "Failed to add protocol" +                        " initializer"); +                goto ret; +        } + +        ret = 0; +ret: +        return ret;  } diff --git a/xlators/nfs/server/src/nfs3-fh.c b/xlators/nfs/server/src/nfs3-fh.c new file mode 100644 index 000000000..c7eb78fb3 --- /dev/null +++ b/xlators/nfs/server/src/nfs3-fh.c @@ -0,0 +1,271 @@ +/* +  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 "nfs3-fh.h" +#include "nfs-common.h" +#include "iatt.h" + + +int +nfs3_fh_validate (struct nfs3_fh *fh) +{ +	if (!fh) +		return 0; + +	if (fh->ident[0] != GF_NFSFH_IDENT0) +		return 0; + +	if (fh->ident[1] != GF_NFSFH_IDENT1) +		return 0; + +        return 1; +} + + +xlator_t * +nfs3_fh_to_xlator (xlator_list_t *cl, struct nfs3_fh *fh) +{ +	if ((!cl) || (!fh)) +		return NULL; + +	return nfs_xlid_to_xlator (cl, fh->xlatorid); +} + +void +nfs3_fh_init (struct nfs3_fh *fh, struct iatt *buf) +{ +        if ((!fh) || (!buf)) +                return; + +        fh->ident[0] = GF_NFSFH_IDENT0; +        fh->ident[1] = GF_NFSFH_IDENT1; + +        fh->hashcount = 0; +        fh->gen = buf->ia_gen; +        fh->ino = buf->ia_ino; + +} + + +struct nfs3_fh +nfs3_fh_build_root_fh (xlator_list_t *cl, xlator_t *xl, struct iatt buf) +{ +        struct nfs3_fh  fh = {{0}, }; +        if ((!cl) || (!xl)) +                return fh; + +        nfs3_fh_init (&fh, &buf); +        fh.xlatorid = nfs_xlator_to_xlid (cl, xl); +        fh.ino = 1; +        fh.gen = 0; +        return fh; +} + + +int +nfs3_fh_is_root_fh (struct nfs3_fh *fh) +{ +        if (!fh) +                return 0; + +        if (fh->hashcount == 0) +                return 1; + +        return 0; +} + + +nfs3_hash_entry_t +nfs3_fh_hash_entry (ino_t ino, uint64_t gen) +{ +        nfs3_hash_entry_t       hash = 0; +        int                     shiftsize = 48; +        nfs3_hash_entry_t       inomsb = 0; +        nfs3_hash_entry_t       inolsb = 0; +        nfs3_hash_entry_t       inols23b = 0; + +        nfs3_hash_entry_t       genmsb = 0; +        nfs3_hash_entry_t       genlsb = 0; +        nfs3_hash_entry_t       genls23b = 0; + +        hash = ino; +        while (shiftsize != 0) { +                hash ^= (ino >> shiftsize); +                shiftsize -= 16; +        } +/* +        gf_log ("FILEHANDLE", GF_LOG_TRACE, "INO %"PRIu64, ino); +        gf_log ("FILEHANDLE",GF_LOG_TRACE, "PRI HASH %d", hash); +*/ +        inomsb = (ino >> 56); +//        gf_log ("FILEHANDLE", GF_LOG_TRACE, "inomsb %d", inomsb); + +        inolsb = ((ino << 56) >> 56); +//        gf_log ("FILEHANDLE", GF_LOG_TRACE, "inolsb %d", inolsb); + +        inolsb = (inolsb << 8); +//        gf_log ("FILEHANDLE", GF_LOG_TRACE, "inolsb to inomsb %d", inolsb); +        inols23b = ((ino << 40) >> 48); +//        gf_log ("FILEHANDLE", GF_LOG_TRACE, "inols23b %d", inols23b); + +        inols23b = (inols23b << 8); +//        gf_log ("FILEHDNALE", GF_LOG_TRACE, "inols23b  %d", inols23b); + +        genmsb = (gen >> 56); +//        gf_log ("FILEHANDLE", GF_LOG_TRACE, "inomsb %d", inomsb); + +        genlsb = ((gen << 56) >> 56); +//        gf_log ("FILEHANDLE", GF_LOG_TRACE, "inolsb %d", inolsb); + +        genlsb = (genlsb << 8); +//        gf_log ("FILEHANDLE", GF_LOG_TRACE, "inolsb to inomsb %d", inolsb); + +        genls23b = ((gen << 40) >> 48); +//        gf_log ("FILEHANDLE", GF_LOG_TRACE, "inols23b %d", inols23b); + +        genls23b = (genls23b << 8); +//        gf_log ("FILEHDNALE", GF_LOG_TRACE, "inols23b  %d", inols23b); + +        hash ^= inolsb ^ inomsb ^ inols23b ^ genmsb ^ genlsb ^ genls23b; +        return hash; + +} + + +void +nfs3_fh_to_str (struct nfs3_fh *fh, char *str) +{ +        if ((!fh) || (!str)) +                return; + +        sprintf (str, "FH: hashcount %d, xlid %d, gen %"PRIu64", ino %"PRIu64, +                 fh->hashcount, fh->xlatorid, fh->gen, fh->ino); +} + + +void +nfs3_log_fh (struct nfs3_fh *fh) +{ +//        int     x = 0; +        if (!fh) +                return; + +        gf_log ("nfs3-fh", GF_LOG_TRACE, "filehandle: hashcount %d, xlid %d, " +                "gen %"PRIu64", ino %"PRIu64, fh->hashcount, fh->xlatorid, +                fh->gen, fh->ino); +/* +        for (; x < fh->hashcount; ++x) +                gf_log ("FILEHANDLE", GF_LOG_TRACE, "Hash %d: %d", x, +                        fh->entryhash[x]); +*/ +} + + +int +nfs3_fh_build_parent_fh (struct nfs3_fh *child, struct iatt *newstat, +                         struct nfs3_fh *newfh) +{ +        if ((!child) || (!newstat) || (!newfh)) +                return -1; + +        nfs3_fh_init (newfh, newstat); +        newfh->xlatorid = child->xlatorid; +        if ((newstat->ia_ino == 1) && (newstat->ia_gen == 0)) { +                newfh->ino = 1; +                newfh->gen = 0; +                goto done; +        } + +        newfh->hashcount = child->hashcount - 1; +        memcpy (newfh->entryhash, child->entryhash, +                newfh->hashcount * GF_NFSFH_ENTRYHASH_SIZE); + +done: +//        nfs3_log_fh (newfh); + +        return 0; +} + + + +int +nfs3_fh_build_child_fh (struct nfs3_fh *parent, struct iatt *newstat, +                        struct nfs3_fh *newfh) +{ +        int             entry = 0; + +        if ((!parent) || (!newstat) || (!newfh)) +                return -1; + +        nfs3_fh_init (newfh, newstat); +        newfh->xlatorid = parent->xlatorid; +        if ((newstat->ia_ino == 1) && (newstat->ia_gen == 0)) { +                newfh->ino = 1; +                newfh->gen = 0; +                goto done; +        } + +        newfh->hashcount = parent->hashcount + 1; +        memcpy (newfh->entryhash, parent->entryhash, +                parent->hashcount * GF_NFSFH_ENTRYHASH_SIZE); +        entry = newfh->hashcount - 1; +        newfh->entryhash[entry] = nfs3_fh_hash_entry (parent->ino, parent->gen); + +done: +//        nfs3_log_fh (newfh); + +        return 0; +} + + +uint32_t +nfs3_fh_compute_size (struct nfs3_fh *fh) +{ +        if (!fh) +                return 0; + +        return (GF_NFSFH_STATIC_SIZE + +                        (fh->hashcount * GF_NFSFH_ENTRYHASH_SIZE)); +} + +int +nfs3_fh_hash_index_is_beyond (struct nfs3_fh *fh, int hashidx) +{ +        if (!fh) +                return 1; + +        if (fh->hashcount >= hashidx) +                return 0; +        else +                return 1; + +        return 1; +} + diff --git a/xlators/nfs/server/src/nfs3-fh.h b/xlators/nfs/server/src/nfs3-fh.h new file mode 100644 index 000000000..f526edf43 --- /dev/null +++ b/xlators/nfs/server/src/nfs3-fh.h @@ -0,0 +1,105 @@ +/* +  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_FH_H_ +#define _NFS_FH_H_ + +#ifndef _CONFIG_H +#define _CONFIG_H +#include "config.h" +#endif + +#include "xlator.h" +#include "xdr-nfs3.h" +#include "iatt.h" +#include <sys/types.h> + +/* BIG FAT WARNING: The file handle code is tightly coupled to NFSv3 file + * handles for now. This will change if and when we need v4. */ +#define GF_NFSFH_IDENT0         ':' +#define GF_NFSFH_IDENT1         'O' +#define GF_NFSFH_IDENT_SIZE     (sizeof(char) * 2) +#define GF_NFSFH_STATIC_SIZE    (GF_NFSFH_IDENT_SIZE + sizeof (uint16_t) + sizeof (uint16_t) + sizeof (uint64_t) + sizeof(uint64_t)) +#define GF_NFSFH_MAX_HASH_BYTES (NFS3_FHSIZE - GF_NFSFH_STATIC_SIZE) + +/* Each hash element in the file handle is of 2 bytes thus giving + * us theoretically 65536 unique entries in a directory. + */ +typedef uint16_t                nfs3_hash_entry_t; +#define GF_NFSFH_ENTRYHASH_SIZE (sizeof (nfs3_hash_entry_t)) +#define GF_NFSFH_MAXHASHES      ((int)(GF_NFSFH_MAX_HASH_BYTES / GF_NFSFH_ENTRYHASH_SIZE)) + +/* ATTENTION: Change in size of the structure below should be reflected in the + * GF_NFSFH_STATIC_SIZE. + */ +struct nfs3_fh { + +        /* Used to ensure that a bunch of bytes are actually a GlusterFS NFS +         * file handle. Should contain ":O" +         */ +        char                    ident[2]; + +        /* Number of file/ino hash elements that follow the ino. */ +        uint16_t                hashcount; + +        /* Basically, the position/index of an xlator among the children of +         * the NFS xlator. +         */ +        uint16_t                xlatorid; +        uint64_t                gen; +        uint64_t                ino; +        nfs3_hash_entry_t       entryhash[GF_NFSFH_MAXHASHES]; +} __attribute__((__packed__)); + + +extern uint32_t +nfs3_fh_compute_size (struct nfs3_fh *fh); + +extern int +nfs3_fh_hash_index_is_beyond (struct nfs3_fh *fh, int hashidx); + +extern uint16_t +nfs3_fh_hash_entry (ino_t ino, uint64_t gen); + +extern int +nfs3_fh_validate (struct nfs3_fh *fh); + +extern xlator_t * +nfs3_fh_to_xlator (xlator_list_t *cl, struct nfs3_fh *fh); + +extern struct nfs3_fh +nfs3_fh_build_root_fh (xlator_list_t *cl, xlator_t *xl, struct iatt buf); + +extern int +nfs3_fh_is_root_fh (struct nfs3_fh *fh); + +extern int +nfs3_fh_build_child_fh (struct nfs3_fh *parent, struct iatt *newstat, +                        struct nfs3_fh *newfh); + +extern void +nfs3_log_fh (struct nfs3_fh *fh); + +extern void +nfs3_fh_to_str (struct nfs3_fh *fh, char *str); + +extern int +nfs3_fh_build_parent_fh (struct nfs3_fh *child, struct iatt *newstat, +                         struct nfs3_fh *newfh); +#endif  | 
