summaryrefslogtreecommitdiffstats
path: root/xlators
diff options
context:
space:
mode:
authorShehjar Tikoo <shehjart@gluster.com>2010-03-31 07:27:04 +0000
committerAnand V. Avati <avati@dev.gluster.com>2010-03-31 07:44:06 -0700
commite63053803dca86b4283b71bc4ef4cb180ec72d89 (patch)
tree05702e5e62f1596250106e3668e3d1062a0472b5 /xlators
parentc4fd1cf7325972d8ff64ef3a2bea70edcf4f1085 (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')
-rw-r--r--xlators/nfs/server/src/Makefile.am4
-rw-r--r--xlators/nfs/server/src/mount3.c914
-rw-r--r--xlators/nfs/server/src/mount3.h78
-rw-r--r--xlators/nfs/server/src/nfs.c21
-rw-r--r--xlators/nfs/server/src/nfs3-fh.c271
-rw-r--r--xlators/nfs/server/src/nfs3-fh.h105
6 files changed, 1390 insertions, 3 deletions
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. <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 00000000..7cfd2b0c
--- /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 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. <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 00000000..f526edf4
--- /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