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
This commit is contained in:
Shehjar Tikoo 2010-03-31 07:27:04 +00:00 committed by Anand V. Avati
parent c4fd1cf732
commit e63053803d
6 changed files with 1390 additions and 3 deletions

View File

@ -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)\

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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