Re: [PATCH/RFC nfs-utils] Fix NFSv4 export of tmpfs filesystems.

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 




> On May 6, 2021, at 9:48 PM, NeilBrown <neilb@xxxxxxx> wrote:
> 
> 
> [[This is a proposed fix.  It seems to work.  I'd like
>  some review comments before it is committed.
>  Petr: it would be great if you could test it to confirm
>  it actually works in your case.
> ]]
> 
> Some filesystems cannot be exported without an fsid or uuid.
> tmpfs is the main example.
> 
> When mountd 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 a UUID with the first 4 bytes
> 0xFFFFFFFF and the remaining 12 bytes form from the path name, xoring
> bytes together if the path is longer than 12 characters.
> Hopefully no filesystem uses a UUID like this....

That's not really a UUID, as per RFC 4122. I'm guessing it's possible
for a collision to occur pretty quickly, for instance. It would be nicer
if a conformant UUID could be used here.

Is there a problem with specifying the export's fsid in /etc/exports?


> The patch borrows some code from exportfs.  Maybe that code should be
> move to a library..
> 
> Signed-off-by: NeilBrown <neilb@xxxxxxx>
> ---
> support/export/v4root.c | 57 +++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 57 insertions(+)
> 
> diff --git a/support/export/v4root.c b/support/export/v4root.c
> index 3654bd7c10c0..fd36eb704441 100644
> --- a/support/export/v4root.c
> +++ b/support/export/v4root.c
> @@ -11,6 +11,7 @@
> #include <config.h>
> #endif
> 
> +#include <fcntl.h>
> #include <sys/types.h>
> #include <sys/stat.h>
> #include <sys/queue.h>
> @@ -21,6 +22,7 @@
> #include <unistd.h>
> #include <errno.h>
> 
> +#include "nfsd_path.h"
> #include "xlog.h"
> #include "exportfs.h"
> #include "nfslib.h"
> @@ -73,6 +75,38 @@ set_pseudofs_security(struct exportent *pseudo)
> 	}
> }
> 
> +static ssize_t exportfs_write(int fd, const char *buf, size_t len)
> +{
> +	return nfsd_path_write(fd, buf, len);
> +}
> +
> +static int test_export(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 = exportfs_write(fd, buf, strlen(buf));
> +	close(fd);
> +	if (n < 0)
> +		return 0;
> +	return 1;
> +}
> +
> /*
>  * Create a pseudo export
>  */
> @@ -82,6 +116,7 @@ v4root_create(char *path, nfs_export *export)
> 	nfs_export *exp;
> 	struct exportent eep;
> 	struct exportent *curexp = &export->m_export;
> +	char uuid[33];
> 
> 	dupexportent(&eep, &pseudo_root.m_export);
> 	eep.e_ttl = default_ttl;
> @@ -89,6 +124,28 @@ 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 &&
> +	    !test_export(&eep, 0)) {
> +		/* Need a uuid - base it on path */
> +		char buf[12], *pp = path;
> +		unsigned int i = 0;
> +
> +		memset(buf, 0, sizeof(buf));
> +		while (*pp) {
> +			buf[i] ^= *pp++;
> +			i += 1;
> +			if (i >= sizeof(buf))
> +				i = 0;
> +		}
> +		memset(uuid, 'F', 32);
> +		uuid[32] = '\0';
> +		pp = uuid + 32 - sizeof(buf) * 2;
> +		for (i = 0; i < sizeof(buf); i++) {
> +			snprintf(pp, 3, "%02X", buf[i]);
> +			pp += 2;
> +		}
> +		eep.e_uuid = uuid;
> +	}
> 	set_pseudofs_security(&eep);
> 	exp = export_create(&eep, 0);
> 	if (exp == NULL)
> -- 
> 2.31.1
> 

--
Chuck Lever







[Index of Archives]     [Linux Filesystem Development]     [Linux USB Development]     [Linux Media Development]     [Video for Linux]     [Linux NILFS]     [Linux Audio Users]     [Yosemite Info]     [Linux SCSI]

  Powered by Linux