From owner-freebsd-current@FreeBSD.ORG Thu May 21 16:04:22 2009 Return-Path: Delivered-To: freebsd-current@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 4B82D106566B for ; Thu, 21 May 2009 16:04:22 +0000 (UTC) (envelope-from rmacklem@uoguelph.ca) Received: from esa-annu.mail.uoguelph.ca (esa-annu.mail.uoguelph.ca [131.104.91.36]) by mx1.freebsd.org (Postfix) with ESMTP id E25AA8FC12 for ; Thu, 21 May 2009 16:04:21 +0000 (UTC) (envelope-from rmacklem@uoguelph.ca) X-IronPort-Anti-Spam-Filtered: true X-IronPort-Anti-Spam-Result: Ag8GAG8WFUqDaFvK/2dsb2JhbACOBQHERoQJBQ X-IronPort-AV: E=Sophos;i="4.41,228,1241409600"; d="scan'208";a="34060986" Received: from fraser.cs.uoguelph.ca ([131.104.91.202]) by esa-annu-pri.mail.uoguelph.ca with ESMTP; 21 May 2009 11:54:50 -0400 Received: from localhost (localhost.localdomain [127.0.0.1]) by fraser.cs.uoguelph.ca (Postfix) with ESMTP id 1B76C109C257 for ; Thu, 21 May 2009 11:54:50 -0400 (EDT) X-Virus-Scanned: amavisd-new at fraser.cs.uoguelph.ca Received: from fraser.cs.uoguelph.ca ([127.0.0.1]) by localhost (fraser.cs.uoguelph.ca [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id S31tRoruXnlZ for ; Thu, 21 May 2009 11:54:49 -0400 (EDT) Received: from muncher.cs.uoguelph.ca (muncher.cs.uoguelph.ca [131.104.91.102]) by fraser.cs.uoguelph.ca (Postfix) with ESMTP id 693A5109C24A for ; Thu, 21 May 2009 11:54:49 -0400 (EDT) Received: from localhost (rmacklem@localhost) by muncher.cs.uoguelph.ca (8.11.7p3+Sun/8.11.6) with ESMTP id n4LFtX407682 for ; Thu, 21 May 2009 11:55:33 -0400 (EDT) X-Authentication-Warning: muncher.cs.uoguelph.ca: rmacklem owned process doing -bs Date: Thu, 21 May 2009 11:55:33 -0400 (EDT) From: Rick Macklem X-X-Sender: rmacklem@muncher.cs.uoguelph.ca To: freebsd-current@freebsd.org Message-ID: MIME-Version: 1.0 Content-Type: TEXT/PLAIN; charset=US-ASCII; format=flowed Subject: review of changes to mountd.c to add experimental server support X-BeenThere: freebsd-current@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Discussions about the use of FreeBSD-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 21 May 2009 16:04:22 -0000 In case anyone would like to review them, here are my proposed changes to src/usr.sbin/mountd.c so that it supports the experimental server as well as the regular one. It will run the experimental server if that is the only one loaded into the kernel or the "-4" option is specified on the command line. It parses one additional line in the exports file, which defines where the root of the nfsv4 file system is. This line is parsed but ignored for the regular server. Thanks in advance for any comments, rick --- diff -u mountd.c --- --- freebsd-svn/usr-src/usr.sbin/mountd/mountd.c 2009-05-17 15:59:31.000000000 -0400 +++ usr-src/usr.sbin/mountd/mountd.c 2009-05-19 09:47:58.000000000 -0400 @@ -61,7 +61,9 @@ #include #include #include +#include #include +#include #include @@ -200,6 +202,7 @@ struct sockaddr *samask); int scan_tree(struct dirlist *, struct sockaddr *); static void usage(void); +void parse_v4root(char *, char *, int, struct xucred *); int xdr_dir(XDR *, char *); int xdr_explist(XDR *, caddr_t); int xdr_explist_brief(XDR *, caddr_t); @@ -233,6 +236,10 @@ int opt_flags; static int have_v6 = 1; +int v4root_phase = 0; +int run_v4server = 0; +int has_publicfh = 0; + struct pidfh *pfh = NULL; /* Bits for opt_flags above */ #define OP_MAPROOT 0x01 @@ -288,17 +295,15 @@ have_v6 = 0; else close(s); - if (modfind("nfsserver") < 0) { - /* Not present in kernel, try loading it */ - if (kldload("nfsserver") < 0 || modfind("nfsserver") < 0) - errx(1, "NFS server is not available or loadable"); - } - while ((c = getopt(argc, argv, "2dh:lnp:r")) != -1) + while ((c = getopt(argc, argv, "24dh:lnp:r")) != -1) switch (c) { case '2': force_v2 = 1; break; + case '4': + run_v4server = 1; + break; case 'n': resvport_only = 0; break; @@ -343,6 +348,26 @@ default: usage(); }; + + /* + * If the "-4" option was specified OR only the nfsd module is + * found in the server, run "nfsd". + * Otherwise, try and run "nfsserver". + */ + if (run_v4server > 0) { + if (modfind("nfsd") < 0) { + /* Not present in kernel, try loading it */ + if (kldload("nfsd") < 0 || modfind("nfsd") < 0) + errx(1, "NFS server is not available"); + } + } else if (modfind("nfsserver") < 0 && modfind("nfsd") >= 0) { + run_v4server = 1; + } else if (modfind("nfsserver") < 0) { + /* Not present in kernel, try loading it */ + if (kldload("nfsserver") < 0 || modfind("nfsserver") < 0) + errx(1, "NFS server is not available"); + } + argc -= optind; argv += optind; grphead = (struct grouplist *)NULL; @@ -707,7 +732,7 @@ usage() { fprintf(stderr, - "usage: mountd [-2] [-d] [-l] [-n] [-p ] [-r] " + "usage: mountd [-2] [-4] [-d] [-l] [-n] [-p ] [-r] " "[-h ] [export_file ...]\n"); exit(1); } @@ -1166,6 +1191,26 @@ ep = (struct exportlist *)NULL; /* + * Handle the V4 root dir. + */ + if (*cp == 'V' && *(cp + 1) == '4' && *(cp + 2) == ':') { + /* + * V4: just indicates that it is the v4 root point, + * so skip over that and set v4root_phase. + */ + if (v4root_phase > 0) { + syslog(LOG_ERR, "V4:duplicate line, ignored"); + goto nextline; + } + v4root_phase = 1; + cp += 3; + nextfield(&cp, &endcp); + if (run_v4server > 0) + parse_v4root(cp, endcp, exflags, &anon); + goto nextline; + } + + /* * Create new exports list entry */ len = endcp-cp; @@ -1382,7 +1427,9 @@ int dirplen, num, i; int iovlen; int done; + struct nfsex_args eargs; + v4root_phase = 0; bzero(&export, sizeof(export)); export.ex_flags = MNT_DELEXPORT; dirp = NULL; @@ -1411,6 +1458,21 @@ grphead = (struct grouplist *)NULL; /* + * and the old V4 root dir. + */ + bzero(&eargs, sizeof (eargs)); + eargs.export.ex_flags = MNT_DELEXPORT; + if (run_v4server > 0 && + nfssvc(NFSSVC_V4ROOTEXPORT, (caddr_t)&eargs) < 0 && + errno != ENOENT) + syslog(LOG_ERR, "Can't delete exports for V4:"); + + /* + * and clear flag that notes if a public fh has been exported. + */ + has_publicfh = 0; + + /* * And delete exports that are in the kernel for all local * filesystems. * XXX: Should know how to handle all local exportable filesystems. @@ -1491,6 +1553,12 @@ syslog(LOG_ERR, "can't open any exports file"); exit(2); } + + /* + * If there was no public fh, clear any previous one set. + */ + if (run_v4server > 0 && has_publicfh == 0) + (void) nfssvc(NFSSVC_NOPUBLICFH, NULL); } /* @@ -1936,6 +2004,12 @@ syslog(LOG_ERR, "bad opt %s", cpopt); return (1); } + if (v4root_phase == 1 && + ((*exflagsp & ~MNT_EXPORTED) || + (opt_flags & ~OP_SEC))) { + syslog(LOG_ERR, "Bad opt %s on V4:", cpopt); + return (1); + } if (usedarg >= 0) { *endcp = savedc2; **endcpp = savedc; @@ -2233,6 +2307,29 @@ goto error_exit; } } + + /* + * For the experimental server: + * If this is the public directory, get the file handle + * and load it into the kernel via the nfssvc() syscall. + */ + if (run_v4server > 0 && (exflags & MNT_EXPUBLIC) != 0) { + fhandle_t fh; + char *public_name; + + if (eap.ex_indexfile != NULL) + public_name = eap.ex_indexfile; + else + public_name = dirp; + if (getfh(public_name, &fh) < 0) + syslog(LOG_ERR, + "Can't get public fh for %s", public_name); + else if (nfssvc(NFSSVC_PUBLICFH, (caddr_t)&fh) < 0) + syslog(LOG_ERR, + "Can't set public fh for %s", public_name); + else + has_publicfh = 1; + } skip: if (ai != NULL) ai = ai->ai_next; @@ -2688,7 +2785,7 @@ struct dirlist *dp; { - if (dp == (struct dirlist *)NULL) + if (v4root_phase != 1 && dp == NULL) return (1); if ((opt_flags & (OP_MAPROOT | OP_MAPALL)) == (OP_MAPROOT | OP_MAPALL)) { syslog(LOG_ERR, "-mapall and -maproot mutually exclusive"); @@ -2710,6 +2807,12 @@ syslog(LOG_ERR, "-alldirs has multiple directories"); return (1); } + if (v4root_phase == 1) { + if ((opt_flags & ~OP_SEC) != 0) { + syslog(LOG_ERR, "only -sec option allowed on V4:"); + return (1); + } + } return (0); } @@ -2871,3 +2974,86 @@ rpcb_unset(RPCPROG_MNT, RPCMNT_VER3, NULL); exit (0); } + +/* + * Parse the V4: line. + */ +void +parse_v4root(char *cp, char *endcp, int exflags, struct xucred *anonp) +{ + char *dirp, savedc; + struct grouplist gr; + struct exportlist ea; + struct nfsex_args nfsea; + int len, has_host, i; + + exflags = MNT_EXPORTED; + bzero(&nfsea, sizeof (nfsea)); + bzero(&ea, sizeof (ea)); + bzero(&gr, sizeof (gr)); + dirp = NULL; + len = endcp - cp; + while (len > 0) { + if (len > RPCMNT_NAMELEN) { + syslog(LOG_ERR, "V4: line too long, ignored"); + v4root_phase = 2; + return; + } + if (*cp == '-') { + if (debug) + warnx("doing opt %s", cp); + if (do_opt(&cp, &endcp, &ea, &gr, &has_host, + &exflags, anonp)) { + v4root_phase = 2; + return; + } + } else if (*cp == '/') { + savedc = *endcp; + *endcp = '\0'; + if (check_dirpath(cp)) { + if (dirp != NULL) { + syslog(LOG_ERR, "Multiple V4 dirs"); + v4root_phase = 2; + return; + } + dirp = cp; + } else { + syslog(LOG_ERR, "V4: dir %s invalid", cp); + v4root_phase = 2; + return; + } + *endcp = savedc; + } + cp = endcp; + nextfield(&cp, &endcp); + len = endcp - cp; + } + + /* Check the options */ + if (check_options(NULL)) { + v4root_phase = 2; + return; + } + + /* + * Now, do the nfssvc() syscall. + */ + nfsea.export.ex_flags = exflags; + nfsea.export.ex_anon = *anonp; + if (ea.ex_numsecflavors == 0) { + nfsea.export.ex_numsecflavors = 4; + nfsea.export.ex_secflavors[0] = AUTH_SYS; + nfsea.export.ex_secflavors[1] = RPCSEC_GSS_KRB5; + nfsea.export.ex_secflavors[2] = RPCSEC_GSS_KRB5I; + nfsea.export.ex_secflavors[3] = RPCSEC_GSS_KRB5P; + } else { + nfsea.export.ex_numsecflavors = ea.ex_numsecflavors; + for (i = 0; i < ea.ex_numsecflavors; i++) + nfsea.export.ex_secflavors[i] = ea.ex_secflavors[i]; + } + nfsea.fspec = dirp; + if (nfssvc(NFSSVC_V4ROOTEXPORT, (caddr_t)&nfsea) < 0) + syslog(LOG_ERR, "Exporting V4: failed"); + v4root_phase = 2; +} +