diff options
| author | Shehjar Tikoo <shehjart@gluster.com> | 2010-03-31 07:27:03 +0000 | 
|---|---|---|
| committer | Anand V. Avati <avati@dev.gluster.com> | 2010-03-31 07:44:02 -0700 | 
| commit | c4fd1cf7325972d8ff64ef3a2bea70edcf4f1085 (patch) | |
| tree | b91c42227b2881eb8b77d39aca3d8348966bc052 /xlators/nfs/server/src/nfs.c | |
| parent | 8b2949db0d56bdf5842abcb72437cc7dccd884df (diff) | |
nfs: Add generic nfs translator
Signed-off-by: Shehjar Tikoo <shehjart@gluster.com>
Signed-off-by: Anand V. Avati <avati@dev.gluster.com>
BUG: 399 (NFS translator with Mount v3 and NFS v3 support)
URL: http://bugs.gluster.com/cgi-bin/bugzilla3/show_bug.cgi?id=399
Diffstat (limited to 'xlators/nfs/server/src/nfs.c')
| -rw-r--r-- | xlators/nfs/server/src/nfs.c | 645 | 
1 files changed, 645 insertions, 0 deletions
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} }, +}; +  | 
