FreeBSD Bugzilla – Attachment 204343 Details for
Bug 237860
mountd is slow at reloading exports for an NFS server with a lot of exported file systems
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
make exportlist linked list hashed and add "-I" for incremental exports updates
mountd-export.patch (text/plain), 27.14 KB, created by
Rick Macklem
on 2019-05-12 23:41:49 UTC
(
hide
)
Description:
make exportlist linked list hashed and add "-I" for incremental exports updates
Filename:
MIME Type:
Creator:
Rick Macklem
Created:
2019-05-12 23:41:49 UTC
Size:
27.14 KB
patch
obsolete
>--- usr.sbin/mountd/mountd.c.xxx 2019-05-12 18:51:58.718916000 -0400 >+++ usr.sbin/mountd/mountd.c 2019-05-12 18:47:55.423166000 -0400 >@@ -49,6 +49,7 @@ __FBSDID("$FreeBSD: head/usr.sbin/mountd > > #include <sys/param.h> > #include <sys/fcntl.h> >+#include <sys/fnv_hash.h> > #include <sys/linker.h> > #include <sys/module.h> > #include <sys/mount.h> >@@ -114,10 +115,13 @@ struct dirlist { > struct exportlist { > struct dirlist *ex_dirl; > struct dirlist *ex_defdir; >+ struct grouplist *ex_grphead; > int ex_flag; > fsid_t ex_fs; > char *ex_fsdir; > char *ex_indexfile; >+ struct xucred ex_defanon; >+ int ex_defexflags; > int ex_numsecflavors; > int ex_secflavors[MAXSECFLAVORS]; > int ex_defnumsecflavors; >@@ -127,6 +131,9 @@ struct exportlist { > }; > /* ex_flag bits */ > #define EX_LINKED 0x1 >+#define EX_DONE 0x2 >+ >+SLIST_HEAD(exportlisthead, exportlist); > > struct netmsk { > struct sockaddr_storage nt_net; >@@ -143,6 +150,9 @@ struct grouplist { > int gr_type; > union grouptypes gr_ptr; > struct grouplist *gr_next; >+ struct xucred gr_anon; >+ int gr_exflags; >+ int gr_flag; > int gr_numsecflavors; > int gr_secflavors[MAXSECFLAVORS]; > }; >@@ -153,6 +163,9 @@ struct grouplist { > #define GT_DEFAULT 0x3 > #define GT_IGNORE 0x5 > >+/* Group flags */ >+#define GR_FND 0x1 >+ > struct hostlist { > int ht_flag; /* Uses DP_xx bits */ > struct grouplist *ht_grp; >@@ -185,17 +198,28 @@ static void complete_service(struct netc > static void clearout_service(void); > static void del_mlist(char *hostp, char *dirp); > static struct dirlist *dirp_search(struct dirlist *, char *); >+static int do_export_mount(struct exportlist *, struct statfs *); > static int do_mount(struct exportlist *, struct grouplist *, int, > struct xucred *, char *, int, struct statfs *); > static int do_opt(char **, char **, struct exportlist *, > struct grouplist *, int *, int *, struct xucred *); >-static struct exportlist *ex_search(fsid_t *); >+static struct exportlist *ex_search(fsid_t *, struct exportlisthead *); > static struct exportlist *get_exp(void); > static void free_dir(struct dirlist *); > static void free_exp(struct exportlist *); > static void free_grp(struct grouplist *); > static void free_host(struct hostlist *); >-static void get_exportlist(void); >+static void free_v4rootexp(void); >+static void get_exportlist_one(int); >+static void get_exportlist(int); >+static void insert_exports(struct exportlist *, struct exportlisthead *); >+static void free_exports(struct exportlisthead *); >+static void read_exportfile(int); >+static int compare_nmount_exportlist(struct iovec *, int, char *); >+static int compare_export(struct exportlist *, struct exportlist *); >+static int compare_cred(struct xucred *, struct xucred *); >+static int compare_secflavor(int *, int *, int); >+static void delete_export(struct iovec *, int, struct statfs *, char *); > static int get_host(char *, struct grouplist *, struct grouplist *); > static struct hostlist *get_ht(void); > static int get_line(void); >@@ -204,7 +228,7 @@ static int get_net(char *, struct netmsk > static void getexp_err(struct exportlist *, struct grouplist *, const char *); > static struct grouplist *get_grp(void); > static void hang_dirp(struct dirlist *, struct grouplist *, >- struct exportlist *, int); >+ struct exportlist *, int, struct xucred *, int); > static void huphandler(int sig); > static int makemask(struct sockaddr_storage *ssp, int bitlen); > static void mntsrv(struct svc_req *, SVCXPRT *); >@@ -227,9 +251,11 @@ static int xdr_fhs(XDR *, caddr_t); > static int xdr_mlist(XDR *, caddr_t); > static void terminate(int); > >-static SLIST_HEAD(, exportlist) exphead = SLIST_HEAD_INITIALIZER(exphead); >-static SLIST_HEAD(, mountlist) mlhead = SLIST_HEAD_INITIALIZER(mlhead); >-static struct grouplist *grphead; >+#define EXPHASH(f) (fnv_32_buf((f), sizeof(fsid_t), 0) % exphashsize) >+static struct exportlisthead *exphead = NULL; >+static struct exportlisthead *oldexphead = NULL; >+static int exphashsize = 0; >+static SLIST_HEAD(, mountlist) mlhead = SLIST_HEAD_INITIALIZER(&mlhead); > static char *exnames_default[2] = { _PATH_EXPORTS, NULL }; > static char **exnames; > static char **hosts = NULL; >@@ -260,6 +286,8 @@ static int have_v6 = 1; > > static int v4root_phase = 0; > static char v4root_dirpath[PATH_MAX + 1]; >+static struct exportlist *v4root_ep = NULL; >+static struct grouplist *v4root_grp = NULL; > static int has_publicfh = 0; > > static struct pidfh *pfh = NULL; >@@ -368,9 +396,10 @@ main(int argc, char **argv) > in_port_t svcport; > int c, k, s; > int maxrec = RPC_MAXDATASIZE; >- int attempt_cnt, port_len, port_pos, ret; >+ int attempt_cnt, passno, port_len, port_pos, ret; > char **port_list; > >+ passno = 0; > /* Check that another mountd isn't already running. */ > pfh = pidfile_open(_PATH_MOUNTDPID, 0600, &otherpid); > if (pfh == NULL) { >@@ -385,7 +414,7 @@ main(int argc, char **argv) > else > close(s); > >- while ((c = getopt(argc, argv, "2deh:lnp:rS")) != -1) >+ while ((c = getopt(argc, argv, "2deh:Ilnp:rS")) != -1) > switch (c) { > case '2': > force_v2 = 1; >@@ -437,6 +466,9 @@ main(int argc, char **argv) > case 'S': > suspend_nfsd = 1; > break; >+ case 'I': >+ passno = 1; >+ break; > default: > usage(); > } >@@ -449,7 +481,6 @@ main(int argc, char **argv) > > argc -= optind; > argv += optind; >- grphead = (struct grouplist *)NULL; > if (argc > 0) > exnames = argv; > else >@@ -457,7 +488,7 @@ main(int argc, char **argv) > openlog("mountd", LOG_PID, LOG_DAEMON); > if (debug) > warnx("getting export list"); >- get_exportlist(); >+ get_exportlist(0); > if (debug) > warnx("getting mount list"); > get_mountlist(); >@@ -628,7 +659,7 @@ main(int argc, char **argv) > /* Expand svc_run() here so that we can call get_exportlist(). */ > for (;;) { > if (got_sighup) { >- get_exportlist(); >+ get_exportlist(passno); > got_sighup = 0; > } > readfds = svc_fdset; >@@ -1087,7 +1118,7 @@ mntsrv(struct svc_req *rqstp, SVCXPRT *t > if (bad) > ep = NULL; > else >- ep = ex_search(&fsb.f_fsid); >+ ep = ex_search(&fsb.f_fsid, exphead); > hostset = defset = 0; > if (ep && (chk_host(ep->ex_defdir, saddr, &defset, &hostset, > &numsecflavors, &secflavorsp) || >@@ -1302,21 +1333,23 @@ xdr_explist_common(XDR *xdrsp, caddr_t c > int false = 0; > int putdef; > sigset_t sighup_mask; >+ int i; > > sigemptyset(&sighup_mask); > sigaddset(&sighup_mask, SIGHUP); > sigprocmask(SIG_BLOCK, &sighup_mask, NULL); > >- SLIST_FOREACH(ep, &exphead, entries) { >- putdef = 0; >- if (put_exlist(ep->ex_dirl, xdrsp, ep->ex_defdir, >- &putdef, brief)) >- goto errout; >- if (ep->ex_defdir && putdef == 0 && >- put_exlist(ep->ex_defdir, xdrsp, (struct dirlist *)NULL, >- &putdef, brief)) >- goto errout; >- } >+ for (i = 0; i < exphashsize; i++) >+ SLIST_FOREACH(ep, &exphead[i], entries) { >+ putdef = 0; >+ if (put_exlist(ep->ex_dirl, xdrsp, ep->ex_defdir, >+ &putdef, brief)) >+ goto errout; >+ if (ep->ex_defdir && putdef == 0 && >+ put_exlist(ep->ex_defdir, xdrsp, >+ (struct dirlist *)NULL, &putdef, brief)) >+ goto errout; >+ } > sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); > if (!xdr_bool(xdrsp, &false)) > return (0); >@@ -1416,7 +1449,7 @@ static FILE *exp_file; > * Get the export list from one, currently open file > */ > static void >-get_exportlist_one(void) >+get_exportlist_one(int passno) > { > struct exportlist *ep; > struct grouplist *grp, *tgrp; >@@ -1540,7 +1573,7 @@ get_exportlist_one(void) > * See if this directory is already > * in the list. > */ >- ep = ex_search(&fsb.f_fsid); >+ ep = ex_search(&fsb.f_fsid, exphead); > if (ep == (struct exportlist *)NULL) { > ep = get_exp(); > ep->ex_fs = fsb.f_fsid; >@@ -1653,11 +1686,15 @@ get_exportlist_one(void) > * Loop through hosts, pushing the exports into the kernel. > * After loop, tgrp points to the start of the list and > * grp points to the last entry in the list. >+ * Do not do the do_mount() for passno == 1, since the >+ * second pass will do it, as required. > */ > grp = tgrp; > do { >- if (do_mount(ep, grp, exflags, &anon, dirp, dirplen, >- &fsb)) { >+ grp->gr_exflags = exflags; >+ grp->gr_anon = anon; >+ if (passno != 1 && do_mount(ep, grp, exflags, &anon, >+ dirp, dirplen, &fsb)) { > getexp_err(ep, tgrp, NULL); > goto nextline; > } >@@ -1668,15 +1705,26 @@ get_exportlist_one(void) > */ > if (v4root_phase > 0 && v4root_phase <= 2) { > /* >- * Since these structures aren't used by mountd, >+ * These structures are used for the "-I" reload, >+ * so save them for that case. Otherwise, just > * free them up now. > */ >- if (ep != NULL) >- free_exp(ep); >- while (tgrp != NULL) { >- grp = tgrp; >- tgrp = tgrp->gr_next; >- free_grp(grp); >+ if (passno == 1) { >+ if (v4root_ep != NULL) { >+ getexp_err(ep, tgrp, >+ "multiple V4 lines"); >+ goto nextline; >+ } >+ v4root_ep = ep; >+ v4root_grp = tgrp; >+ } else { >+ if (ep != NULL) >+ free_exp(ep); >+ while (tgrp != NULL) { >+ grp = tgrp; >+ tgrp = tgrp->gr_next; >+ free_grp(grp); >+ } > } > goto nextline; > } >@@ -1685,17 +1733,17 @@ get_exportlist_one(void) > * Success. Update the data structures. > */ > if (has_host) { >- hang_dirp(dirhead, tgrp, ep, opt_flags); >- grp->gr_next = grphead; >- grphead = tgrp; >+ hang_dirp(dirhead, tgrp, ep, opt_flags, &anon, exflags); >+ grp->gr_next = ep->ex_grphead; >+ ep->ex_grphead = tgrp; > } else { > hang_dirp(dirhead, (struct grouplist *)NULL, ep, >- opt_flags); >+ opt_flags, &anon, exflags); > free_grp(grp); > } > dirhead = (struct dirlist *)NULL; > if ((ep->ex_flag & EX_LINKED) == 0) { >- SLIST_INSERT_HEAD(&exphead, ep, entries); >+ insert_exports(ep, exphead); > > ep->ex_flag |= EX_LINKED; > } >@@ -1712,45 +1760,50 @@ nextline: > * Get the export list from all specified files > */ > static void >-get_exportlist(void) >+get_exportlist(int passno) > { >- struct exportlist *ep, *ep2; >- struct grouplist *grp, *tgrp; > struct export_args export; > struct iovec *iov; >- struct statfs *fsp, *mntbufp; >- struct xvfsconf vfc; >+ struct statfs *mntbufp; > char errmsg[255]; > int num, i; > int iovlen; >- int done; > struct nfsex_args eargs; > >- if (suspend_nfsd != 0) >- (void)nfssvc(NFSSVC_SUSPENDNFSD, NULL); >+syslog(LOG_ERR, "passno=%d", passno); > v4root_dirpath[0] = '\0'; >+ free_v4rootexp(); >+ if (passno == 1) { >+ /* >+ * Save the current lists as old ones, so that the new lists >+ * can be compared with the old ones in the 2nd pass. >+ */ >+ for (i = 0; i < exphashsize; i++) { >+ SLIST_FIRST(&oldexphead[i]) = SLIST_FIRST(&exphead[i]); >+ SLIST_INIT(&exphead[i]); >+ } >+ >+ /* Read the export file(s) and process them */ >+ read_exportfile(passno); >+syslog(LOG_ERR, "readexp1"); >+ } else { >+ /* >+ * Just make the old lists empty. >+ * exphashsize == 0 for the first call, before oldexphead >+ * has been initialized-->loop won't be executed. >+ */ >+ for (i = 0; i < exphashsize; i++) >+ SLIST_INIT(&oldexphead[i]); >+ } >+ > bzero(&export, sizeof(export)); > export.ex_flags = MNT_DELEXPORT; > iov = NULL; > iovlen = 0; > bzero(errmsg, sizeof(errmsg)); > >- /* >- * First, get rid of the old list >- */ >- SLIST_FOREACH_SAFE(ep, &exphead, entries, ep2) { >- SLIST_REMOVE(&exphead, ep, exportlist, entries); >- free_exp(ep); >- } >- >- grp = grphead; >- while (grp) { >- tgrp = grp; >- grp = grp->gr_next; >- free_grp(tgrp); >- } >- grphead = (struct grouplist *)NULL; >- >+ if (suspend_nfsd != 0) >+ (void)nfssvc(NFSSVC_SUSPENDNFSD, NULL); > /* > * and the old V4 root dir. > */ >@@ -1765,62 +1818,72 @@ get_exportlist(void) > */ > has_publicfh = 0; > >+ build_iovec(&iov, &iovlen, "fstype", NULL, 0); >+ build_iovec(&iov, &iovlen, "fspath", NULL, 0); >+ build_iovec(&iov, &iovlen, "from", NULL, 0); >+ build_iovec(&iov, &iovlen, "update", NULL, 0); >+ build_iovec(&iov, &iovlen, "export", &export, >+ sizeof(export)); >+ build_iovec(&iov, &iovlen, "errmsg", errmsg, >+ sizeof(errmsg)); >+ > /* >- * And delete exports that are in the kernel for all local >- * filesystems. >- * XXX: Should know how to handle all local exportable filesystems. >+ * For passno == 1, compare the old and new lists updating the kernel >+ * exports for any cases that have changed. >+ * This call is doing the second pass through the lists. >+ * If it fails, fall back on the bulk reload. > */ >- num = getmntinfo(&mntbufp, MNT_NOWAIT); >- >- if (num > 0) { >- build_iovec(&iov, &iovlen, "fstype", NULL, 0); >- build_iovec(&iov, &iovlen, "fspath", NULL, 0); >- build_iovec(&iov, &iovlen, "from", NULL, 0); >- build_iovec(&iov, &iovlen, "update", NULL, 0); >- build_iovec(&iov, &iovlen, "export", &export, sizeof(export)); >- build_iovec(&iov, &iovlen, "errmsg", errmsg, sizeof(errmsg)); >- } >- >- for (i = 0; i < num; i++) { >- fsp = &mntbufp[i]; >- if (getvfsbyname(fsp->f_fstypename, &vfc) != 0) { >- syslog(LOG_ERR, "getvfsbyname() failed for %s", >- fsp->f_fstypename); >- continue; >+ if (passno == 1 && compare_nmount_exportlist(iov, iovlen, errmsg) == >+ 0) { >+syslog(LOG_ERR, "compareok"); >+ /* Free up the old lists. */ >+ free_exports(oldexphead); >+ } else { >+syslog(LOG_ERR, "doin passno=0"); >+ /* exphead == NULL if not yet allocated (first call). */ >+ if (exphead != NULL) { >+ /* >+ * First, get rid of the old lists. >+ */ >+ free_exports(exphead); >+ free_exports(oldexphead); > } >+ free_v4rootexp(); > > /* >- * We do not need to delete "export" flag from >- * filesystems that do not have it set. >- */ >- if (!(fsp->f_flags & MNT_EXPORTED)) >- continue; >- /* >- * Do not delete export for network filesystem by >- * passing "export" arg to nmount(). >- * It only makes sense to do this for local filesystems. >- */ >- if (vfc.vfc_flags & VFCF_NETWORK) >- continue; >- >- iov[1].iov_base = fsp->f_fstypename; >- iov[1].iov_len = strlen(fsp->f_fstypename) + 1; >- iov[3].iov_base = fsp->f_mntonname; >- iov[3].iov_len = strlen(fsp->f_mntonname) + 1; >- iov[5].iov_base = fsp->f_mntfromname; >- iov[5].iov_len = strlen(fsp->f_mntfromname) + 1; >- errmsg[0] = '\0'; >- >- /* >- * EXDEV is returned when path exists but is not a >- * mount point. May happens if raced with unmount. >- */ >- if (nmount(iov, iovlen, fsp->f_flags) < 0 && >- errno != ENOENT && errno != ENOTSUP && errno != EXDEV) { >- syslog(LOG_ERR, >- "can't delete exports for %s: %m %s", >- fsp->f_mntonname, errmsg); >+ * And delete exports that are in the kernel for all local >+ * filesystems. >+ * XXX: Should know how to handle all local exportable >+ * filesystems. >+ */ >+ num = getmntinfo(&mntbufp, MNT_NOWAIT); >+ >+ /* Allocate hash tables, for first call. */ >+ if (exphead == NULL) { >+ /* Target an average linked list length of 20. */ >+ exphashsize = num / 10; >+ if (exphashsize < 1) >+ exphashsize = 1; >+ else if (exphashsize > 100000) >+ exphashsize = 100000; >+ exphead = malloc(exphashsize * sizeof(*exphead)); >+ oldexphead = malloc(exphashsize * sizeof(*oldexphead)); >+ if (exphead == NULL || oldexphead == NULL) >+ errx(1, "Can't malloc hash tables"); >+ >+ for (i = 0; i < exphashsize; i++) { >+ SLIST_INIT(&exphead[i]); >+ SLIST_INIT(&oldexphead[i]); >+ } > } >+ >+ for (i = 0; i < num; i++) >+ delete_export(iov, iovlen, &mntbufp[i], errmsg); >+ >+ >+ /* Read the export file(s) and process them */ >+ read_exportfile(0); >+syslog(LOG_ERR, "readexp0"); > } > > if (iov != NULL) { >@@ -1838,6 +1901,56 @@ get_exportlist(void) > } > > /* >+ * If there was no public fh, clear any previous one set. >+ */ >+ if (has_publicfh == 0) >+ (void) nfssvc(NFSSVC_NOPUBLICFH, NULL); >+ >+ /* Resume the nfsd. If they weren't suspended, this is harmless. */ >+ (void)nfssvc(NFSSVC_RESUMENFSD, NULL); >+syslog(LOG_ERR, "eo get_exportlist"); >+} >+ >+/* >+ * Insert an export entry in the appropriate list. >+ */ >+static void >+insert_exports(struct exportlist *ep, struct exportlisthead *exhp) >+{ >+ uint32_t i; >+ >+ i = EXPHASH(&ep->ex_fs); >+syslog(LOG_ERR, "fs=%s hash=%i", ep->ex_fsdir, i); >+ SLIST_INSERT_HEAD(&exhp[i], ep, entries); >+} >+ >+/* >+ * Free up the exports lists passed in as arguments. >+ */ >+static void >+free_exports(struct exportlisthead *exhp) >+{ >+ struct exportlist *ep, *ep2; >+ int i; >+ >+ for (i = 0; i < exphashsize; i++) { >+ SLIST_FOREACH_SAFE(ep, &exhp[i], entries, ep2) { >+ SLIST_REMOVE(&exhp[i], ep, exportlist, entries); >+ free_exp(ep); >+ } >+ SLIST_INIT(&exhp[i]); >+ } >+} >+ >+/* >+ * Read the exports file(s) and call get_exportlist_one() for each line. >+ */ >+static void >+read_exportfile(int passno) >+{ >+ int done, i; >+ >+ /* > * Read in the exports file and build the list, calling > * nmount() as we go along to push the export rules into the kernel. > */ >@@ -1849,7 +1962,7 @@ get_exportlist(void) > syslog(LOG_WARNING, "can't open %s", exnames[i]); > continue; > } >- get_exportlist_one(); >+ get_exportlist_one(passno); > fclose(exp_file); > done++; > } >@@ -1857,15 +1970,250 @@ get_exportlist(void) > syslog(LOG_ERR, "can't open any exports file"); > exit(2); > } >+} >+ >+/* >+ * Compare the export lists against the old ones and do nmount() operations >+ * for any cases that have changed. This avoids doing nmount() for entries >+ * that have not changed. >+ * Return 0 upon success, 1 otherwise. >+ */ >+static int >+compare_nmount_exportlist(struct iovec *iov, int iovlen, char *errmsg) >+{ >+ struct exportlist *ep, *oep; >+ struct grouplist *grp; >+ struct statfs fs, ofs; >+ int i, ret; > > /* >- * If there was no public fh, clear any previous one set. >+ * Loop through the current list and look for an entry in the old >+ * list. >+ * If found, check to see if it the same. >+ * If it is not the same, delete and re-export. >+ * Then mark it done on the old list. >+ * else (not found) >+ * export it. >+ * Any entries left in the old list after processing must have their >+ * exports deleted. > */ >- if (has_publicfh == 0) >- (void) nfssvc(NFSSVC_NOPUBLICFH, NULL); >+ for (i = 0; i < exphashsize; i++) >+ SLIST_FOREACH(ep, &exphead[i], entries) { >+syslog(LOG_ERR, "foreach ep"); >+ if (statfs(ep->ex_fsdir, &fs) < 0) >+ return (1); >+syslog(LOG_ERR, "fsv0=%d fsv1=%d", fs.f_fsid.val[0], fs.f_fsid.val[1]); >+ oep = ex_search(&ep->ex_fs, oldexphead); >+ if (oep != NULL) { >+ /* >+ * Statfs both file systems and sanity check >+ * that they still refer to the same file >+ * system. >+ * If not, return 1 so that the reload of the >+ * exports will be done in bulk, the >+ * passno == 0 way. >+ */ >+syslog(LOG_ERR, "fnd ex"); >+ if (statfs(oep->ex_fsdir, &ofs) < 0 || >+ ep->ex_fs.val[0] != fs.f_fsid.val[0] || >+ ep->ex_fs.val[1] != fs.f_fsid.val[1] || >+ fs.f_fsid.val[0] != ofs.f_fsid.val[0] || >+ fs.f_fsid.val[1] != ofs.f_fsid.val[1]) >+ return (1); >+ /* >+ * Test to see if the entry is the same. >+ * If not the same delete exports and >+ * re-export. >+ */ >+syslog(LOG_ERR, "at compare"); >+ if (compare_export(ep, oep) != 0) { >+ delete_export(iov, iovlen, &fs, errmsg); >+ ret = do_export_mount(ep, &fs); >+ if (ret != 0) >+ return (ret); >+ } >+ oep->ex_flag |= EX_DONE; >+syslog(LOG_ERR, "exdone"); >+ } else { >+syslog(LOG_ERR, "not fnd so ex"); >+ /* Not found, so do export. */ >+ ret = do_export_mount(ep, &fs); >+ if (ret != 0) >+ return (ret); >+ } >+ } > >- /* Resume the nfsd. If they weren't suspended, this is harmless. */ >- (void)nfssvc(NFSSVC_RESUMENFSD, NULL); >+ /* Delete exports not done. */ >+ for (i = 0; i < exphashsize; i++) >+ SLIST_FOREACH(oep, &oldexphead[i], entries) { >+ if ((oep->ex_flag & EX_DONE) == 0) { >+syslog(LOG_ERR, "not done delete"); >+ if (statfs(oep->ex_fsdir, &ofs) >= 0 && >+ oep->ex_fs.val[0] == ofs.f_fsid.val[0] && >+ oep->ex_fs.val[1] == ofs.f_fsid.val[1]) >+syslog(LOG_ERR, "do delete"); >+ delete_export(iov, iovlen, &ofs, errmsg); >+ } >+ } >+ >+ /* Do the V4 root exports, as required. */ >+ grp = v4root_grp; >+ v4root_phase = 2; >+ while (v4root_ep != NULL && grp != NULL) { >+syslog(LOG_ERR, "v4ex path=%s gr_type=0x%x gr_exflags=0x%x", v4root_dirpath, grp->gr_type, grp->gr_exflags); >+syslog(LOG_ERR, "v4rootd=%s", v4root_dirpath); >+ ret = do_mount(v4root_ep, grp, grp->gr_exflags, &grp->gr_anon, >+ v4root_dirpath, strlen(v4root_dirpath), &fs); >+ if (ret != 0) { >+ v4root_phase = 0; >+ return (ret); >+ } >+ grp = grp->gr_next; >+ } >+ v4root_phase = 0; >+ free_v4rootexp(); >+ return (0); >+} >+ >+/* >+ * Compare old and current exportlist entries for the fsid and return 0 >+ * if they are the same, 1 otherwise. >+ */ >+static int >+compare_export(struct exportlist *ep, struct exportlist *oep) >+{ >+ struct grouplist *grp, *ogrp; >+ >+ if (strcmp(ep->ex_fsdir, oep->ex_fsdir) != 0) >+ return (1); >+ if ((ep->ex_defdir != NULL && oep->ex_defdir == NULL) || >+ (ep->ex_defdir == NULL && oep->ex_defdir != NULL)) >+ return (1); >+ if (ep->ex_defdir != NULL) { >+ if ((ep->ex_defdir->dp_flag & DP_DEFSET) != 0) { >+ if ((oep->ex_defdir->dp_flag & DP_DEFSET) == 0) >+ return (1); >+ if (ep->ex_defnumsecflavors != >+ oep->ex_defnumsecflavors || >+ ep->ex_defexflags != oep->ex_defexflags || >+ compare_cred(&ep->ex_defanon, &oep->ex_defanon) != >+ 0 || compare_secflavor(ep->ex_defsecflavors, >+ oep->ex_defsecflavors, ep->ex_defnumsecflavors) != >+ 0) >+ return (1); >+ } >+ } >+ >+ /* Now, check all the groups. */ >+ for (ogrp = oep->ex_grphead; ogrp != NULL; ogrp = ogrp->gr_next) >+ ogrp->gr_flag = 0; >+ for (grp = ep->ex_grphead; grp != NULL; grp = grp->gr_next) { >+ for (ogrp = oep->ex_grphead; ogrp != NULL; ogrp = >+ ogrp->gr_next) >+ if ((ogrp->gr_flag & GR_FND) == 0 && >+ grp->gr_numsecflavors == ogrp->gr_numsecflavors && >+ grp->gr_exflags == ogrp->gr_exflags && >+ compare_cred(&grp->gr_anon, &ogrp->gr_anon) == 0 && >+ compare_secflavor(grp->gr_secflavors, >+ ogrp->gr_secflavors, grp->gr_numsecflavors) == 0) >+ break; >+ if (ogrp != NULL) >+ ogrp->gr_flag |= GR_FND; >+ else >+ return (1); >+ } >+ for (ogrp = oep->ex_grphead; ogrp != NULL; ogrp = ogrp->gr_next) >+ if ((ogrp->gr_flag & GR_FND) == 0) >+ return (1); >+ return (0); >+} >+ >+/* >+ * Compare to struct xucred's. Return 0 if the same and 1 otherwise. >+ * This algorithm is O(N**2) but fortunately N is always small. >+ */ >+static int >+compare_cred(struct xucred *cr0, struct xucred *cr1) >+{ >+ int i, j; >+ >+ if (cr0->cr_uid != cr1->cr_uid || cr0->cr_ngroups != cr1->cr_ngroups) >+ return (1); >+ for (i = 0; i < cr0->cr_ngroups; i++) { >+ for (j = 0; j < cr0->cr_ngroups; j++) >+ if (cr0->cr_groups[i] == cr1->cr_groups[j]) >+ break; >+ if (j == cr0->cr_ngroups) >+ return (1); >+ } >+ return (0); >+} >+ >+/* >+ * Compare two lists of security flavors. Return 0 if the same and 1 otherwise. >+ * This algorithm is O(N**2) but fortunately N is always small. >+ */ >+static int >+compare_secflavor(int *sec1, int *sec2, int nsec) >+{ >+ int i, j; >+ >+ for (i = 0; i < nsec; i++) { >+ for (j = 0; j < nsec; j++) >+ if (sec1[i] == sec2[j]) >+ break; >+ if (j == nsec) >+ return (1); >+ } >+ return (0); >+} >+ >+/* >+ * Delete an exports entry. >+ */ >+static void >+delete_export(struct iovec *iov, int iovlen, struct statfs *fsp, char *errmsg) >+{ >+ struct xvfsconf vfc; >+ >+ if (getvfsbyname(fsp->f_fstypename, &vfc) != 0) { >+ syslog(LOG_ERR, "getvfsbyname() failed for %s", >+ fsp->f_fstypename); >+ return; >+ } >+ >+ /* >+ * We do not need to delete "export" flag from >+ * filesystems that do not have it set. >+ */ >+ if (!(fsp->f_flags & MNT_EXPORTED)) >+ return; >+ /* >+ * Do not delete export for network filesystem by >+ * passing "export" arg to nmount(). >+ * It only makes sense to do this for local filesystems. >+ */ >+ if (vfc.vfc_flags & VFCF_NETWORK) >+ return; >+ >+ iov[1].iov_base = fsp->f_fstypename; >+ iov[1].iov_len = strlen(fsp->f_fstypename) + 1; >+ iov[3].iov_base = fsp->f_mntonname; >+ iov[3].iov_len = strlen(fsp->f_mntonname) + 1; >+ iov[5].iov_base = fsp->f_mntfromname; >+ iov[5].iov_len = strlen(fsp->f_mntfromname) + 1; >+ errmsg[0] = '\0'; >+ >+ /* >+ * EXDEV is returned when path exists but is not a >+ * mount point. May happens if raced with unmount. >+ */ >+ if (nmount(iov, iovlen, fsp->f_flags) < 0 && errno != ENOENT && >+ errno != ENOTSUP && errno != EXDEV) { >+ syslog(LOG_ERR, >+ "can't delete exports for %s: %m %s", >+ fsp->f_mntonname, errmsg); >+ } > } > > /* >@@ -1924,11 +2272,13 @@ getexp_err(struct exportlist *ep, struct > * Search the export list for a matching fs. > */ > static struct exportlist * >-ex_search(fsid_t *fsid) >+ex_search(fsid_t *fsid, struct exportlisthead *exhp) > { > struct exportlist *ep; >+ uint32_t i; > >- SLIST_FOREACH(ep, &exphead, entries) { >+ i = EXPHASH(fsid); >+ SLIST_FOREACH(ep, &exhp[i], entries) { > if (ep->ex_fs.val[0] == fsid->val[0] && > ep->ex_fs.val[1] == fsid->val[1]) > return (ep); >@@ -1965,7 +2315,7 @@ add_expdir(struct dirlist **dpp, char *c > */ > static void > hang_dirp(struct dirlist *dp, struct grouplist *grp, struct exportlist *ep, >- int flags) >+ int flags, struct xucred *anoncrp, int exflags) > { > struct hostlist *hp; > struct dirlist *dp2; >@@ -1982,6 +2332,8 @@ hang_dirp(struct dirlist *dp, struct gro > if (ep->ex_numsecflavors > 0) > memcpy(ep->ex_defsecflavors, ep->ex_secflavors, > sizeof(ep->ex_secflavors)); >+ ep->ex_defanon = *anoncrp; >+ ep->ex_defexflags = exflags; > } else while (grp) { > hp = get_ht(); > hp->ht_grp = grp; >@@ -2403,6 +2755,7 @@ get_host(char *cp, struct grouplist *grp > static void > free_exp(struct exportlist *ep) > { >+ struct grouplist *grp, *tgrp; > > if (ep->ex_defdir) { > free_host(ep->ex_defdir->dp_hosts); >@@ -2413,10 +2766,37 @@ free_exp(struct exportlist *ep) > if (ep->ex_indexfile) > free(ep->ex_indexfile); > free_dir(ep->ex_dirl); >+ grp = ep->ex_grphead; >+ while (grp) { >+ tgrp = grp; >+ grp = grp->gr_next; >+ free_grp(tgrp); >+ } > free((caddr_t)ep); > } > > /* >+ * Free up the v4root exports. >+ */ >+static void >+free_v4rootexp(void) >+{ >+ struct grouplist *grp, *tgrp; >+ >+ if (v4root_ep != NULL) { >+ free_exp(v4root_ep); >+ v4root_ep = NULL; >+ } >+ tgrp = v4root_grp; >+ v4root_grp = NULL; >+ while (tgrp != NULL) { >+ grp = tgrp; >+ tgrp = tgrp->gr_next; >+ free_grp(grp); >+ } >+} >+ >+/* > * Free hosts. > */ > static void >@@ -2456,6 +2836,44 @@ out_of_mem(void) > } > > /* >+ * Call do_mount() from the struct exportlist, for each case needed. >+ */ >+static int >+do_export_mount(struct exportlist *ep, struct statfs *fsp) >+{ >+ struct dirlist *dp; >+ struct grouplist *grp, defgrp; >+ int ret; >+ size_t dirlen; >+ >+syslog(LOG_ERR, "do_mount_export=%s", ep->ex_fsdir); >+ dirlen = strlen(ep->ex_fsdir); >+ dp = ep->ex_defdir; >+ if (dp != NULL && (dp->dp_flag & DP_DEFSET) != 0) { >+ defgrp.gr_type = GT_DEFAULT; >+ defgrp.gr_next = NULL; >+ /* We have an entry for all other hosts/nets. */ >+syslog(LOG_ERR, "ex_defexflags=0x%x", ep->ex_defexflags); >+ ret = do_mount(ep, &defgrp, ep->ex_defexflags, &ep->ex_defanon, >+ ep->ex_fsdir, dirlen, fsp); >+ if (ret != 0) >+ return (ret); >+ } >+ >+ /* Do a mount for each group. */ >+ grp = ep->ex_grphead; >+ while (grp != NULL) { >+syslog(LOG_ERR, "do mount gr_type=0x%x gr_exflags=0x%x", grp->gr_type, grp->gr_exflags); >+ ret = do_mount(ep, grp, grp->gr_exflags, &grp->gr_anon, >+ ep->ex_fsdir, dirlen, fsp); >+ if (ret != 0) >+ return (ret); >+ grp = grp->gr_next; >+ } >+ return (0); >+} >+ >+/* > * Do the nmount() syscall with the update flag to push the export info into > * the kernel. > */ >@@ -2487,6 +2905,7 @@ do_mount(struct exportlist *ep, struct g > bzero(errmsg, sizeof(errmsg)); > eap->ex_flags = exflags; > eap->ex_anon = *anoncrp; >+syslog(LOG_ERR, "do_exflags=0x%x", exflags); > eap->ex_indexfile = ep->ex_indexfile; > if (grp->gr_type == GT_HOST) > ai = grp->gr_ptr.gt_addrinfo;
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Raw
Actions:
View
Attachments on
bug 237860
:
204343
|
204409
|
204435
|
204458
|
204460
|
204472
|
204552
|
204560
|
204580