Module Name: src Committed By: hannken Date: Fri Jun 4 10:46:57 UTC 2021
Modified Files: src/usr.sbin/mountd: mountd.c Log Message: Change get_exportlist() to collect all exports and emit all exports for a single mount in one call to nfssvc(2). Should finally fix PR kern/5844 (NFS server sends "permission denied" while mound re-read exports). To generate a diff of this commit: cvs rdiff -u -r1.135 -r1.136 src/usr.sbin/mountd/mountd.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/usr.sbin/mountd/mountd.c diff -u src/usr.sbin/mountd/mountd.c:1.135 src/usr.sbin/mountd/mountd.c:1.136 --- src/usr.sbin/mountd/mountd.c:1.135 Fri Jun 4 10:46:01 2021 +++ src/usr.sbin/mountd/mountd.c Fri Jun 4 10:46:57 2021 @@ -1,4 +1,4 @@ -/* $NetBSD: mountd.c,v 1.135 2021/06/04 10:46:01 hannken Exp $ */ +/* $NetBSD: mountd.c,v 1.136 2021/06/04 10:46:57 hannken Exp $ */ /* * Copyright (c) 1989, 1993 @@ -42,7 +42,7 @@ __COPYRIGHT("@(#) Copyright (c) 1989, 19 #if 0 static char sccsid[] = "@(#)mountd.c 8.15 (Berkeley) 5/1/95"; #else -__RCSID("$NetBSD: mountd.c,v 1.135 2021/06/04 10:46:01 hannken Exp $"); +__RCSID("$NetBSD: mountd.c,v 1.136 2021/06/04 10:46:57 hannken Exp $"); #endif #endif /* not lint */ @@ -235,6 +235,8 @@ static struct uucred def_anon = { 0, { 0 } }; +static struct mountd_exports_list *mel_tab; +static int mel_tab_len; int opt_flags; static int have_v6 = 1; @@ -1207,6 +1209,18 @@ nextline: } /* + * Compare two export lists by path. + */ +static int +mel_compare(const void *a, const void *b) +{ + const struct mountd_exports_list *mela = a; + const struct mountd_exports_list *melb = b; + + return strcmp(mela->mel_path, melb->mel_path); +} + +/* * Get the export list */ /* ARGSUSED */ @@ -1216,7 +1230,7 @@ get_exportlist(int n) struct exportlist *ep, *ep2; struct grouplist *grp, *tgrp; struct statvfs *fsp; - int num, i; + int i, j; FILE *exp_file; @@ -1243,20 +1257,14 @@ get_exportlist(int n) * And delete exports that are in the kernel for all local * file systems. */ - num = getmntinfo(&fsp, MNT_NOWAIT); - for (i = 0; i < num; i++) { - struct mountd_exports_list mel; - - /* Delete all entries from the export list. */ - mel.mel_path = fsp->f_mntonname; - mel.mel_nexports = 0; - if (nfssvc(NFSSVC_SETEXPORTSLIST, &mel) == -1 && - errno != EOPNOTSUPP) - syslog(LOG_ERR, "Can't delete exports for %s (%m)", - fsp->f_mntonname); - - fsp++; + mel_tab_len = getmntinfo(&fsp, MNT_NOWAIT); + mel_tab = ecalloc(mel_tab_len, sizeof(*mel_tab)); + for (i = 0; i < mel_tab_len; i++) { + mel_tab[i].mel_path = estrdup(fsp[i].f_mntonname); + mel_tab[i].mel_nexports = 0; + mel_tab[i].mel_exports = NULL; } + qsort(mel_tab, mel_tab_len, sizeof(mel_tab[0]), mel_compare); /* * Read in the exports file and build the list, calling @@ -1278,6 +1286,30 @@ get_exportlist(int n) (void)fclose(exp_file); } + + for (i = 0; i < mel_tab_len; i++) { + struct mountd_exports_list *mel = &mel_tab[i]; + + if (nfssvc(NFSSVC_REPLACEEXPORTSLIST, mel) == -1 && + (mel->mel_nexports > 0 || errno != EOPNOTSUPP)) + syslog(LOG_ERR, "Can't update exports for %s (%m)", + mel_tab[i].mel_path); + for (j = 0; j < (int)mel_tab->mel_nexports; j++) { + struct export_args *export = &mel->mel_exports[j]; + + if (export->ex_indexfile) + free(export->ex_indexfile); + if (export->ex_addr) + free(export->ex_addr); + if (export->ex_mask) + free(export->ex_mask); + } + if (mel->mel_nexports > 0) + free(mel->mel_exports); + free(__UNCONST(mel->mel_path)); + } + free(mel_tab); + mel_tab_len = 0; } /* @@ -1923,31 +1955,39 @@ add_export_arg(const char *path, int exf struct sockaddr *addrp, int addrlen, struct sockaddr *maskp, int masklen, char *indexfile) { - struct mountd_exports_list mel; - struct export_args export; - int error; + const struct mountd_exports_list mel_key = { .mel_path = path }; + struct mountd_exports_list *mel; + struct export_args *export; if (addrp != NULL && addrp->sa_family == AF_INET6 && have_v6 == 0) return 0; - mel.mel_path = path; - mel.mel_nexports = 1; - mel.mel_exports = &export; - - export.ex_flags = exflags; - export.ex_anon = *anoncrp; - export.ex_indexfile = indexfile; - export.ex_addr = addrp; - export.ex_addrlen = addrlen; - export.ex_mask = maskp; - export.ex_masklen = masklen; - - error = nfssvc(NFSSVC_SETEXPORTSLIST, &mel); - - if (error) { - syslog(LOG_ERR, "Can't change attributes for %s: %m", path); + mel = bsearch(&mel_key, mel_tab, mel_tab_len, sizeof(mel_tab[0]), + mel_compare); + if (mel == NULL) { + syslog(LOG_ERR, "Can't change attributes for %s: not found", + path); return 1; } + ereallocarr(&mel->mel_exports, mel->mel_nexports + 1, + sizeof(*mel->mel_exports)); + export = &mel->mel_exports[mel->mel_nexports++]; + memset(export, 0, sizeof(*export)); + + export->ex_flags = exflags; + export->ex_anon = *anoncrp; + if (indexfile) + export->ex_indexfile = estrdup(indexfile); + if (addrlen > 0) { + export->ex_addr = emalloc(addrlen); + export->ex_addrlen = addrlen; + memcpy(export->ex_addr, addrp, addrlen); + } + if (masklen > 0) { + export->ex_mask = emalloc(masklen); + export->ex_masklen = masklen; + memcpy(export->ex_mask, maskp, masklen); + } return 0; }