summaryrefslogtreecommitdiff
path: root/support/export
diff options
context:
space:
mode:
authorNeilBrown <neilb@suse.de>2021-05-22 11:03:31 -0400
committerSteve Dickson <steved@redhat.com>2021-05-22 11:18:56 -0400
commitc5528f40f9db5061e06dcf1f9b7fce5185b376c6 (patch)
tree129ac54f26a0b8a6b471c0e065ebc1139dfb08d4 /support/export
parented83085ff310fdc95badb06a26289efb70f99ccd (diff)
downloadnfs-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.c3
-rw-r--r--support/export/export.c29
-rw-r--r--support/export/v4root.c23
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;
}