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 _at__at_ -61,7 +61,9 _at__at_ #include <rpcsvc/mount.h> #include <nfs/rpcv2.h> #include <nfs/nfsproto.h> +#include <nfs/nfssvc.h> #include <nfsserver/nfs.h> +#include <fs/nfs/nfsport.h> #include <arpa/inet.h> _at__at_ -200,6 +202,7 _at__at_ 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); _at__at_ -233,6 +236,10 _at__at_ 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 _at__at_ -288,17 +295,15 _at__at_ 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; _at__at_ -343,6 +348,26 _at__at_ 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; _at__at_ -707,7 +732,7 _at__at_ usage() { fprintf(stderr, - "usage: mountd [-2] [-d] [-l] [-n] [-p <port>] [-r] " + "usage: mountd [-2] [-4] [-d] [-l] [-n] [-p <port>] [-r] " "[-h <bindip>] [export_file ...]\n"); exit(1); } _at__at_ -1166,6 +1191,26 _at__at_ 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; _at__at_ -1382,7 +1427,9 _at__at_ 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; _at__at_ -1411,6 +1458,21 _at__at_ 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. _at__at_ -1491,6 +1553,12 _at__at_ 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); } /* _at__at_ -1936,6 +2004,12 _at__at_ 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; _at__at_ -2233,6 +2307,29 _at__at_ 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; _at__at_ -2688,7 +2785,7 _at__at_ 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"); _at__at_ -2710,6 +2807,12 _at__at_ 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); } _at__at_ -2871,3 +2974,86 _at__at_ 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; +} +Received on Thu May 21 2009 - 14:04:22 UTC
This archive was generated by hypermail 2.4.0 : Wed May 19 2021 - 11:39:48 UTC