From e63053803dca86b4283b71bc4ef4cb180ec72d89 Mon Sep 17 00:00:00 2001 From: Shehjar Tikoo Date: Wed, 31 Mar 2010 07:27:04 +0000 Subject: nfs: Add MOUNTv3 protocol support Signed-off-by: Shehjar Tikoo Signed-off-by: Anand V. Avati BUG: 399 (NFS translator with Mount v3 and NFS v3 support) URL: http://bugs.gluster.com/cgi-bin/bugzilla3/show_bug.cgi?id=399 --- xlators/nfs/server/src/Makefile.am | 4 +- xlators/nfs/server/src/mount3.c | 914 +++++++++++++++++++++++++++++++++++++ xlators/nfs/server/src/mount3.h | 78 ++++ xlators/nfs/server/src/nfs.c | 21 +- xlators/nfs/server/src/nfs3-fh.c | 271 +++++++++++ xlators/nfs/server/src/nfs3-fh.h | 105 +++++ 6 files changed, 1390 insertions(+), 3 deletions(-) create mode 100644 xlators/nfs/server/src/mount3.c create mode 100644 xlators/nfs/server/src/mount3.h create mode 100644 xlators/nfs/server/src/nfs3-fh.c create mode 100644 xlators/nfs/server/src/nfs3-fh.h (limited to 'xlators') diff --git a/xlators/nfs/server/src/Makefile.am b/xlators/nfs/server/src/Makefile.am index 453fd475..9661dd95 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 00000000..dc880508 --- /dev/null +++ b/xlators/nfs/server/src/mount3.c @@ -0,0 +1,914 @@ +/* + Copyright (c) 2010 Gluster, Inc. + 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 + . +*/ + +#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 +#include +#include + +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 00000000..7cfd2b0c --- /dev/null +++ b/xlators/nfs/server/src/mount3.h @@ -0,0 +1,78 @@ +/* + Copyright (c) 2010 Gluster, Inc. + 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 + . +*/ + +#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 ca6fda69..74937903 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 00000000..c7eb78fb --- /dev/null +++ b/xlators/nfs/server/src/nfs3-fh.c @@ -0,0 +1,271 @@ +/* + Copyright (c) 2010 Gluster, Inc. + 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 + . +*/ + +#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 00000000..f526edf4 --- /dev/null +++ b/xlators/nfs/server/src/nfs3-fh.h @@ -0,0 +1,105 @@ +/* + Copyright (c) 2010 Gluster, Inc. + 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 + . +*/ + +#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 + +/* 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 -- cgit