svn commit: r297899 - projects/pnfs-server/usr.sbin/nfsd
Rick Macklem
rmacklem at FreeBSD.org
Wed Apr 13 01:00:30 UTC 2016
Author: rmacklem
Date: Wed Apr 13 01:00:29 2016
New Revision: 297899
URL: https://svnweb.freebsd.org/changeset/base/297899
Log:
Update nfsd.c so that it has the "-p" option for the pNFS server.
Modified:
projects/pnfs-server/usr.sbin/nfsd/nfsd.c
Modified: projects/pnfs-server/usr.sbin/nfsd/nfsd.c
==============================================================================
--- projects/pnfs-server/usr.sbin/nfsd/nfsd.c Wed Apr 13 00:53:04 2016 (r297898)
+++ projects/pnfs-server/usr.sbin/nfsd/nfsd.c Wed Apr 13 01:00:29 2016 (r297899)
@@ -59,12 +59,16 @@ static const char rcsid[] =
#include <rpc/rpc.h>
#include <rpc/pmap_clnt.h>
#include <rpcsvc/nfs_prot.h>
+#include <rpcsvc/mount.h>
#include <netdb.h>
#include <arpa/inet.h>
-#include <nfsserver/nfs.h>
#include <nfs/nfssvc.h>
+#include <fs/nfs/nfsproto.h>
+#include <fs/nfs/nfskpiport.h>
+#include <fs/nfs/nfs.h>
+
#include <err.h>
#include <errno.h>
#include <signal.h>
@@ -92,6 +96,8 @@ static int stablefd = -1; /* Fd for the
static int backupfd; /* Fd for the backup stable restart file */
static const char *getopt_shortopts;
static const char *getopt_usage;
+static char *dshost = NULL;
+static int dshostc = 0;
static int minthreads_set;
static int maxthreads_set;
@@ -100,9 +106,18 @@ static struct option longopts[] = {
{ "debug", no_argument, &debug, 1 },
{ "minthreads", required_argument, &minthreads_set, 1 },
{ "maxthreads", required_argument, &maxthreads_set, 1 },
+ { "pnfs", required_argument, NULL, 'p' },
{ NULL, 0, NULL, 0}
};
+struct nfhret {
+ u_long stat;
+ long vers;
+ long auth;
+ long fhsize;
+ u_char nfh[NFS3_FHSIZE];
+};
+
static void cleanup(int);
static void child_cleanup(int);
static void killchildren(void);
@@ -111,13 +126,18 @@ static void nonfs(int);
static void reapchild(int);
static int setbindhost(struct addrinfo **ia, const char *bindhost,
struct addrinfo hints);
-static void start_server(int);
+static void start_server(int, struct nfsd_nfsd_args *);
static void unregistration(void);
static void usage(void);
static void open_stable(int *, int *);
static void copy_stable(int, int);
static void backup_stable(int);
static void set_nfsdcnt(int);
+static void parse_dsserver(const char *, struct nfsd_nfsd_args *);
+static int xdr_dir(XDR *, char *);
+static int xdr_fh(XDR *, struct nfhret *);
+static u_long getdsrootfh(struct sockaddr *, socklen_t,
+ struct nfsd_nfsd_args *, char *);
/*
* Nfs server daemon mostly just a user context for nfssvc()
@@ -161,15 +181,18 @@ main(int argc, char **argv)
const char *lopt;
char **bindhost = NULL;
pid_t pid;
+ struct nfsd_nfsd_args nfsdargs;
nfsdcnt = DEFNFSDCNT;
unregister = reregister = tcpflag = maxsock = 0;
bindanyflag = udpflag = connect_type_cnt = bindhostc = 0;
- getopt_shortopts = "ah:n:rdtue";
+ getopt_shortopts = "ah:n:rdtuep:";
getopt_usage =
"usage:\n"
" nfsd [-ardtue] [-h bindip]\n"
- " [-n numservers] [--minthreads #] [--maxthreads #]\n";
+ " [-n numservers] [--minthreads #] [--maxthreads #]\n"
+ " [-p/--pnfs dsserver0,...,dsserverN:/gluster-volume-name:"
+ "mntport#:nfsport#]\n";
while ((ch = getopt_long(argc, argv, getopt_shortopts, longopts,
&longindex)) != -1)
switch (ch) {
@@ -203,6 +226,10 @@ main(int argc, char **argv)
case 'e':
/* now a no-op, since this is the default */
break;
+ case 'p':
+ /* Parse out the DS server host names and the port#s. */
+ parse_dsserver(optarg, &nfsdargs);
+ break;
case 0:
lopt = longopts[longindex].name;
if (!strcmp(lopt, "minthreads")) {
@@ -393,7 +420,7 @@ main(int argc, char **argv)
exit(1);
}
nfssvc_addsock = NFSSVC_NFSDADDSOCK;
- nfssvc_nfsd = NFSSVC_NFSDNFSD;
+ nfssvc_nfsd = NFSSVC_NFSDNFSD | NFSSVC_NEWSTRUCT;
if (tcpflag) {
/*
@@ -411,7 +438,7 @@ main(int argc, char **argv)
} else {
(void)signal(SIGUSR1, child_cleanup);
setproctitle("server");
- start_server(0);
+ start_server(0, &nfsdargs);
}
}
@@ -711,7 +738,7 @@ main(int argc, char **argv)
* a "server" too. start_server will not return.
*/
if (!tcpflag)
- start_server(1);
+ start_server(1, &nfsdargs);
/*
* Loop forever accepting connections and passing the sockets
@@ -935,10 +962,9 @@ get_tuned_nfsdcount(void)
}
static void
-start_server(int master)
+start_server(int master, struct nfsd_nfsd_args *nfsdargp)
{
char principal[MAXHOSTNAMELEN + 5];
- struct nfsd_nfsd_args nfsdargs;
int status, error;
char hostname[MAXHOSTNAMELEN + 1], *cp;
struct addrinfo *aip, hints;
@@ -961,17 +987,17 @@ start_server(int master)
freeaddrinfo(aip);
}
}
- nfsdargs.principal = principal;
+ nfsdargp->principal = principal;
if (nfsdcnt_set)
- nfsdargs.minthreads = nfsdargs.maxthreads = nfsdcnt;
+ nfsdargp->minthreads = nfsdargp->maxthreads = nfsdcnt;
else {
- nfsdargs.minthreads = minthreads_set ? minthreads : get_tuned_nfsdcount();
- nfsdargs.maxthreads = maxthreads_set ? maxthreads : nfsdargs.minthreads;
- if (nfsdargs.maxthreads < nfsdargs.minthreads)
- nfsdargs.maxthreads = nfsdargs.minthreads;
+ nfsdargp->minthreads = minthreads_set ? minthreads : get_tuned_nfsdcount();
+ nfsdargp->maxthreads = maxthreads_set ? maxthreads : nfsdargp->minthreads;
+ if (nfsdargp->maxthreads < nfsdargp->minthreads)
+ nfsdargp->maxthreads = nfsdargp->minthreads;
}
- error = nfssvc(nfssvc_nfsd, &nfsdargs);
+ error = nfssvc(nfssvc_nfsd, nfsdargp);
if (error < 0 && errno == EAUTH) {
/*
* This indicates that it could not register the
@@ -981,7 +1007,7 @@ start_server(int master)
*/
syslog(LOG_ERR, "No gssd, using AUTH_SYS only");
principal[0] = '\0';
- error = nfssvc(nfssvc_nfsd, &nfsdargs);
+ error = nfssvc(nfssvc_nfsd, nfsdargp);
}
if (error < 0) {
syslog(LOG_ERR, "nfssvc: %m");
@@ -1084,3 +1110,239 @@ backup_stable(__unused int signo)
copy_stable(stablefd, backupfd);
}
+/*
+ * Parse the pNFS string and extract the DS servers and ports numbers.
+ */
+static void
+parse_dsserver(const char *optarg, struct nfsd_nfsd_args *nfsdargp)
+{
+ char *ad, *cp, *cp2, *dsaddr, *dshost, *gvol, nfsprt[9], *portcp;
+ int adsiz, dsaddrcnt, dshostcnt, ecode, hostsiz;
+ size_t cpsiz, dsaddrsiz, dshostsiz, nfsprtsiz;
+ struct addrinfo hints, *ai_tcp;
+ struct sockaddr_in *sin;
+ u_short dsmntport, dsnfsport;
+ u_long getrootret;
+
+ cp = strdup(optarg);
+ if (cp == NULL)
+ errx(1, "Out of memory");
+ cpsiz = strlen(cp);
+ /*
+ * The first field separated from the dshost lby ':' ist is the
+ * GlusterFS volume path. (ie. '/' followed by the GlusterFS volume
+ * name).
+ */
+ gvol = strchr(cp, ':');
+ if (gvol == NULL || gvol == cp)
+ usage();
+
+ /*
+ * The last two fields separated by ':' are the Mount and NFS protocol
+ * port #s for the DS servers.
+ * The minimal field starting with ':' is 4 characters long.
+ * consisting of 2 ':' characters each followed by a digit.
+ */
+ portcp = strchr(gvol + 1, ':');
+ if (portcp == NULL || portcp == gvol + 1 || portcp > cp + cpsiz - 4)
+ usage();
+ cp2 = strchr(portcp + 1, ':');
+ if (cp2 == NULL || cp2 == portcp + 1 || cp2 > cp + cpsiz - 1)
+ usage();
+ *gvol++ = '\0';
+ *portcp++ = '\0';
+ *cp2++ = '\0';
+
+ /* Do the port numbers. */
+ dsmntport = atoi(portcp);
+ dsnfsport = atoi(cp2);
+ if (dsmntport <= 0 || dsmntport > 65535 ||
+ dsnfsport <= 0 || dsnfsport > 65535)
+ usage();
+ snprintf(nfsprt, 9, ".%d.%d", dsnfsport >> 8, dsnfsport & 0xff);
+ nfsprtsiz = strlen(nfsprt);
+
+ /* Now, do the host names. */
+ dshostsiz = 1024;
+ dshostcnt = 0;
+ dshost = malloc(dshostsiz);
+ if (dshost == NULL)
+ errx(1, "Out of memory");
+ dsaddrsiz = 1024;
+ dsaddrcnt = 0;
+ dsaddr = malloc(dsaddrsiz);
+ if (dsaddr == NULL)
+ errx(1, "Out of memory");
+ ai_tcp = NULL;
+ /* Loop around for each DS server name. */
+ do {
+ if (ai_tcp != NULL)
+ freeaddrinfo(ai_tcp);
+ cp2 = strchr(cp, ',');
+ if (cp2 != NULL)
+ *cp2++ = '\0';
+
+ /* Get the fully qualified domain name and IP address. */
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_flags = AI_CANONNAME;
+ hints.ai_family = AF_INET;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_protocol = IPPROTO_TCP;
+ ecode = getaddrinfo(cp, NULL, &hints, &ai_tcp);
+ if (ecode != 0)
+ err(1, "getaddrinfo pnfs: %s %s", cp,
+ gai_strerror(ecode));
+ sin = (struct sockaddr_in *)ai_tcp->ai_addr;
+ if (sin->sin_family != AF_INET)
+ err(1, "getaddrinfo() returned non-INET address");
+
+ /* Append this address to dsaddr. */
+ ad = inet_ntoa(sin->sin_addr);
+ adsiz = strlen(ad);
+ if (dsaddrcnt + adsiz + nfsprtsiz + 1 > dsaddrsiz) {
+ dsaddrsiz *= 2;
+ dsaddr = realloc(dsaddr, dsaddrsiz);
+ if (dsaddr == NULL)
+ errx(1, "Out of memory");
+ }
+ strcpy(&dsaddr[dsaddrcnt], ad);
+ strcat(&dsaddr[dsaddrcnt], nfsprt);
+ dsaddrcnt += adsiz + nfsprtsiz + 1;
+
+ /* Append this hostname to dshost. */
+ hostsiz = strlen(ai_tcp->ai_canonname);
+ if (dshostcnt + hostsiz + 1 > dshostsiz) {
+ dshostsiz *= 2;
+ dshost = realloc(dshost, dshostsiz);
+ if (dshost == NULL)
+ errx(1, "Out of memory");
+ }
+ strcpy(&dshost[dshostcnt], ai_tcp->ai_canonname);
+ dshostcnt += hostsiz + 1;
+
+ cp = cp2;
+ } while (cp != NULL && *cp != '\0' && cp < portcp);
+
+ /*
+ * At the point, ai_tcp refers to the last DS server host and
+ * sin is set to point to the sockaddr structure in it.
+ * Set the port# for the DS Mount protocol and get the DS root FH.
+ */
+ sin->sin_port = htons(dsmntport);
+ getrootret = getdsrootfh(ai_tcp->ai_addr, ai_tcp->ai_addrlen, nfsdargp,
+ gvol);
+ if (getrootret != 0)
+ errx(1, "Can't do Mount RPC against DS:%s stat=%lu",
+ ai_tcp->ai_canonname, getrootret);
+ nfsdargp->addr = dsaddr;
+ nfsdargp->addrlen = dsaddrcnt;
+ nfsdargp->dnshost = dshost;
+ nfsdargp->dnshostlen = dshostcnt;
+ freeaddrinfo(ai_tcp);
+}
+
+/*
+ * Do a Mount RPC agains a DS server to get the root fh for the DS volume.
+ */
+static u_long
+getdsrootfh(struct sockaddr *saddr, socklen_t len,
+ struct nfsd_nfsd_args *nfsdargp, char *gvol)
+{
+ struct netbuf srvaddr;
+ struct netconfig *nconf;
+ CLIENT *clp;
+ struct timeval try;
+ struct nfhret nfhret;
+ enum clnt_stat clntstat;
+ int so;
+
+ nconf = getnetconfigent("tcp");
+ if (nconf == NULL)
+ errx(1, "getdsrootfh: getnetconfigent for tcp failed");
+ so = socket(AF_INET, SOCK_STREAM, 0);
+ if (so < 0)
+ err(1, "getdsrootfh: can't create socket");
+ srvaddr.buf = saddr;
+ srvaddr.len = srvaddr.maxlen = len;
+ clp = clnt_tli_create(so, nconf, &srvaddr, MOUNTPROG, 3, 0, 0);
+ if (clp == NULL)
+ errx(1, "getdsrootfh: clnt_tli_create failed");
+ /* Send the MOUNTPROC_MNT RPC to get the root filehandle. */
+ try.tv_sec = 10;
+ try.tv_usec = 0;
+ clp->cl_auth = authsys_create_default();
+ nfhret.auth = AUTH_SYS;
+ nfhret.vers = 3;
+ clntstat = clnt_call(clp, MOUNTPROC_MNT, (xdrproc_t)xdr_dir, gvol,
+ (xdrproc_t)xdr_fh, &nfhret, try);
+ auth_destroy(clp->cl_auth);
+ clnt_destroy(clp);
+ freenetconfigent(nconf);
+
+ if (clntstat != RPC_SUCCESS)
+ return (clntstat);
+ if (nfhret.stat != 0)
+ return (nfhret.stat);
+ /*
+ * Store the filehandle and server address in nfsargsp, making
+ * sure to copy any locally allocated structures.
+ */
+ if (nfhret.fhsize != sizeof(struct pnfsfh))
+ errx(1, "getdsrootfh: DS FH size wrong");
+ memcpy(&nfsdargp->nfsfh, nfhret.nfh, nfhret.fhsize);
+ return (0);
+}
+
+/*
+ * xdr routines for mount rpc's
+ */
+static int
+xdr_dir(XDR *xdrsp, char *dirp)
+{
+
+ return (xdr_string(xdrsp, &dirp, MNTPATHLEN));
+}
+
+static int
+xdr_fh(XDR *xdrsp, struct nfhret *np)
+{
+ int i;
+ long auth, authcnt, authfnd = 0;
+
+ if (!xdr_u_long(xdrsp, &np->stat))
+ return (0);
+ if (np->stat != 0)
+ return (1);
+ switch (np->vers) {
+ case 3:
+ if (!xdr_long(xdrsp, &np->fhsize))
+ return (0);
+ if (np->fhsize <= 0 || np->fhsize > NFS3_FHSIZE)
+ return (0);
+ if (!xdr_opaque(xdrsp, (caddr_t)np->nfh, np->fhsize))
+ return (0);
+ if (!xdr_long(xdrsp, &authcnt))
+ return (0);
+ for (i = 0; i < authcnt; i++) {
+ if (!xdr_long(xdrsp, &auth))
+ return (0);
+ if (np->auth == -1) {
+ np->auth = auth;
+ authfnd++;
+ } else if (auth == np->auth) {
+ authfnd++;
+ }
+ }
+ /*
+ * Some servers, such as DEC's OSF/1 return a nil authenticator
+ * list to indicate RPCAUTH_UNIX.
+ */
+ if (authcnt == 0 && np->auth == -1)
+ np->auth = AUTH_SYS;
+ if (!authfnd && (authcnt > 0 || np->auth != AUTH_SYS))
+ np->stat = EAUTH;
+ return (1);
+ };
+ return (0);
+}
+
More information about the svn-src-projects
mailing list