On 5/17/21 12:45 AM, NeilBrown wrote: > > Some filesystems cannot be exported without an fsid or uuid. > tmpfs is the main example. > > When mountd (or exportd) creates nfsv4 pseudo-root exports for the path > leading down to an export point it exports each directory without any > fsid or uuid. If one of these directories is on tmp, that will fail. > > The net result is that exporting a subdirectory of a tmpfs filesystem > will not work over NFSv4 as the parents within the filesystem cannot be > exported. It will either fail, or fall-back to NFSv3 (depending on the > version of the mount.nfs program). > > To fix this we need to provide an fsid or uuid for these pseudo-root > exports. This patch does that by creating an RFC-4122 V5 compatible > UUID based on an arbitrary seed and the path to the export. > > To check if an export needs a uuid, text_export() is moved from exportfs > to libexport.a, modified slightly and renamed to export_test(). > > Signed-off-by: NeilBrown <neilb@xxxxxxx> Committed... (tag: nfs-utils-2-5-4-rc4) Thanks! steved. > --- > > This version contains Chuck's suggestion for improving the uuid, and > general clean-up. > > support/export/cache.c | 3 ++- > support/export/export.c | 29 +++++++++++++++++++++++++++++ > support/export/v4root.c | 23 ++++++++++++++++++++++- > support/include/exportfs.h | 1 + > utils/exportd/Makefile.am | 2 +- > utils/exportfs/exportfs.c | 38 +++----------------------------------- > utils/mountd/Makefile.am | 2 +- > 7 files changed, 59 insertions(+), 39 deletions(-) > > diff --git a/support/export/cache.c b/support/export/cache.c > index 3e4f53c0a32e..a5823e92e9f2 100644 > --- a/support/export/cache.c > +++ b/support/export/cache.c > @@ -981,7 +981,8 @@ static int dump_to_cache(int f, char *buf, int blen, char *domain, > write_secinfo(&bp, &blen, exp, flag_mask); > if (exp->e_uuid == NULL || different_fs) { > char u[16]; > - if (uuid_by_path(path, 0, 16, u)) { > + if ((exp->e_flags & flag_mask & NFSEXP_FSID) == 0 && > + uuid_by_path(path, 0, 16, u)) { > qword_add(&bp, &blen, "uuid"); > qword_addhex(&bp, &blen, u, 16); > } > diff --git a/support/export/export.c b/support/export/export.c > index c753f68e4d63..03390dfc1de8 100644 > --- a/support/export/export.c > +++ b/support/export/export.c > @@ -10,9 +10,11 @@ > #include <config.h> > #endif > > +#include <unistd.h> > #include <string.h> > #include <sys/types.h> > #include <sys/param.h> > +#include <fcntl.h> > #include <netinet/in.h> > #include <limits.h> > #include <stdlib.h> > @@ -420,3 +422,30 @@ export_hash(char *str) > > return num % HASH_TABLE_SIZE; > } > + > +int export_test(struct exportent *eep, int with_fsid) > +{ > + char *path = eep->e_path; > + int flags = eep->e_flags | (with_fsid ? NFSEXP_FSID : 0); > + /* beside max path, buf size should take protocol str into account */ > + char buf[NFS_MAXPATHLEN+1+64] = { 0 }; > + char *bp = buf; > + int len = sizeof(buf); > + int fd, n; > + > + n = snprintf(buf, len, "-test-client- "); > + bp += n; > + len -= n; > + qword_add(&bp, &len, path); > + if (len < 1) > + return 0; > + snprintf(bp, len, " 3 %d 65534 65534 0\n", flags); > + fd = open("/proc/net/rpc/nfsd.export/channel", O_WRONLY); > + if (fd < 0) > + return 0; > + n = nfsd_path_write(fd, buf, strlen(buf)); > + close(fd); > + if (n < 0) > + return 0; > + return 1; > +} > diff --git a/support/export/v4root.c b/support/export/v4root.c > index 3654bd7c10c0..c12a7d8562b2 100644 > --- a/support/export/v4root.c > +++ b/support/export/v4root.c > @@ -20,6 +20,7 @@ > > #include <unistd.h> > #include <errno.h> > +#include <uuid/uuid.h> > > #include "xlog.h" > #include "exportfs.h" > @@ -89,11 +90,31 @@ v4root_create(char *path, nfs_export *export) > strncpy(eep.e_path, path, sizeof(eep.e_path)-1); > if (strcmp(path, "/") != 0) > eep.e_flags &= ~NFSEXP_FSID; > + > + if (strcmp(path, "/") != 0 && > + !export_test(&eep, 0)) { > + /* Need a uuid - base it on path using a fixed seed that > + * was generated randomly. > + */ > + const char seed_s[] = "39c6b5c1-3f24-4f4e-977c-7fe6546b8a25"; > + uuid_t seed, uuid; > + char uuid_s[UUID_STR_LEN]; > + unsigned int i, j; > + > + uuid_parse(seed_s, seed); > + uuid_generate_sha1(uuid, seed, path, strlen(path)); > + uuid_unparse_upper(uuid, uuid_s); > + /* strip hyhens */ > + for (i = j = 0; uuid_s[i]; i++) > + if (uuid_s[i] != '-') > + uuid_s[j++] = uuid_s[i]; > + eep.e_uuid = uuid_s; > + } > set_pseudofs_security(&eep); > exp = export_create(&eep, 0); > if (exp == NULL) > return NULL; > - xlog(D_CALL, "v4root_create: path '%s' flags 0x%x", > + xlog(D_CALL, "v4root_create: path '%s' flags 0x%x", > exp->m_export.e_path, exp->m_export.e_flags); > return &exp->m_export; > } > diff --git a/support/include/exportfs.h b/support/include/exportfs.h > index 81d137210862..7c1b74537186 100644 > --- a/support/include/exportfs.h > +++ b/support/include/exportfs.h > @@ -173,5 +173,6 @@ struct export_features { > struct export_features *get_export_features(void); > void fix_pseudoflavor_flags(struct exportent *ep); > char *exportent_realpath(struct exportent *eep); > +int export_test(struct exportent *eep, int with_fsid); > > #endif /* EXPORTFS_H */ > diff --git a/utils/exportd/Makefile.am b/utils/exportd/Makefile.am > index eb521f15032d..c95bdee76d3f 100644 > --- a/utils/exportd/Makefile.am > +++ b/utils/exportd/Makefile.am > @@ -16,7 +16,7 @@ exportd_SOURCES = exportd.c > exportd_LDADD = ../../support/export/libexport.a \ > ../../support/nfs/libnfs.la \ > ../../support/misc/libmisc.a \ > - $(OPTLIBS) $(LIBBLKID) $(LIBPTHREAD) > + $(OPTLIBS) $(LIBBLKID) $(LIBPTHREAD) -luuid > > exportd_CPPFLAGS = $(AM_CPPFLAGS) $(CPPFLAGS) \ > -I$(top_srcdir)/support/export > diff --git a/utils/exportfs/exportfs.c b/utils/exportfs/exportfs.c > index 25d757d8b4b4..bc76aaaf8714 100644 > --- a/utils/exportfs/exportfs.c > +++ b/utils/exportfs/exportfs.c > @@ -54,11 +54,6 @@ static int _lockfd = -1; > > struct state_paths etab; > > -static ssize_t exportfs_write(int fd, const char *buf, size_t len) > -{ > - return nfsd_path_write(fd, buf, len); > -} > - > /* > * If we aren't careful, changes made by exportfs can be lost > * when multiple exports process run at once: > @@ -510,33 +505,6 @@ static int can_test(void) > return 1; > } > > -static int test_export(nfs_export *exp, int with_fsid) > -{ > - char *path = exp->m_export.e_path; > - int flags = exp->m_export.e_flags | (with_fsid ? NFSEXP_FSID : 0); > - /* beside max path, buf size should take protocol str into account */ > - char buf[NFS_MAXPATHLEN+1+64] = { 0 }; > - char *bp = buf; > - int len = sizeof(buf); > - int fd, n; > - > - n = snprintf(buf, len, "-test-client- "); > - bp += n; > - len -= n; > - qword_add(&bp, &len, path); > - if (len < 1) > - return 0; > - snprintf(bp, len, " 3 %d 65534 65534 0\n", flags); > - fd = open("/proc/net/rpc/nfsd.export/channel", O_WRONLY); > - if (fd < 0) > - return 0; > - n = exportfs_write(fd, buf, strlen(buf)); > - close(fd); > - if (n < 0) > - return 0; > - return 1; > -} > - > static void > validate_export(nfs_export *exp) > { > @@ -568,12 +536,12 @@ validate_export(nfs_export *exp) > > if ((exp->m_export.e_flags & NFSEXP_FSID) || exp->m_export.e_uuid || > fs_has_fsid) { > - if ( !test_export(exp, 1)) { > + if ( !export_test(&exp->m_export, 1)) { > xlog(L_ERROR, "%s does not support NFS export", path); > return; > } > - } else if ( !test_export(exp, 0)) { > - if (test_export(exp, 1)) > + } else if ( !export_test(&exp->m_export, 0)) { > + if (export_test(&exp->m_export, 1)) > xlog(L_ERROR, "%s requires fsid= for NFS export", path); > else > xlog(L_ERROR, "%s does not support NFS export", path); > diff --git a/utils/mountd/Makefile.am b/utils/mountd/Makefile.am > index 859f28ecd6f3..13b25c90f06e 100644 > --- a/utils/mountd/Makefile.am > +++ b/utils/mountd/Makefile.am > @@ -18,7 +18,7 @@ mountd_LDADD = ../../support/export/libexport.a \ > ../../support/nfs/libnfs.la \ > ../../support/misc/libmisc.a \ > $(OPTLIBS) \ > - $(LIBBSD) $(LIBWRAP) $(LIBNSL) $(LIBBLKID) $(LIBTIRPC) \ > + $(LIBBSD) $(LIBWRAP) $(LIBNSL) $(LIBBLKID) -luuid $(LIBTIRPC) \ > $(LIBPTHREAD) > mountd_CPPFLAGS = $(AM_CPPFLAGS) $(CPPFLAGS) \ > -I$(top_builddir)/support/include \ >