diff options
author | NeilBrown <neilb@suse.de> | 2021-05-22 11:03:31 -0400 |
---|---|---|
committer | Steve Dickson <steved@redhat.com> | 2021-05-22 11:18:56 -0400 |
commit | c5528f40f9db5061e06dcf1f9b7fce5185b376c6 (patch) | |
tree | 129ac54f26a0b8a6b471c0e065ebc1139dfb08d4 /support/export | |
parent | ed83085ff310fdc95badb06a26289efb70f99ccd (diff) | |
download | nfs-utils-c5528f40f9db5061e06dcf1f9b7fce5185b376c6.tar.gz |
Fix NFSv4 export of tmpfs filesystems
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 tmpfs, 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().
Reported-by: Petr Vorel <pvorel@suse.cz>
Reviewed-by: Petr Vorel <pvorel@suse.cz>
Tested-by: Petr Vorel <pvorel@suse.cz>
Signed-off-by: NeilBrown <neilb@suse.de>
Signed-off-by: Steve Dickson <steved@redhat.com>
Diffstat (limited to 'support/export')
-rw-r--r-- | support/export/cache.c | 3 | ||||
-rw-r--r-- | support/export/export.c | 29 | ||||
-rw-r--r-- | support/export/v4root.c | 23 |
3 files changed, 53 insertions, 2 deletions
diff --git a/support/export/cache.c b/support/export/cache.c index 3e4f53c..a5823e9 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 c753f68..03390df 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 3654bd7..c12a7d8 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; } |