All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Darrick J. Wong" <djwong@kernel.org>
To: Bernd Schubert <bernd@bsbernd.com>
Cc: linux-fsdevel@vger.kernel.org, Miklos Szeredi <miklos@szeredi.hu>,
	Joanne Koong <joannelkoong@gmail.com>,
	Bernd Schubert <bschubert@ddn.com>
Subject: Re: [PATCH 15/19] Split the fusermount do_mount function
Date: Mon, 23 Mar 2026 17:14:14 -0700	[thread overview]
Message-ID: <20260324001414.GP6202@frogsfrogsfrogs> (raw)
In-Reply-To: <20260323-fuse-init-before-mount-v1-15-a52d3040af69@bsbernd.com>

On Mon, Mar 23, 2026 at 06:45:10PM +0100, Bernd Schubert wrote:
> From: Bernd Schubert <bschubert@ddn.com>
> 
> We will need new API and old API and need to pass the options to
> two different functions - factor out the option parsing.
> 
> Signed-off-by: Bernd Schubert <bschubert@ddn.com>
> ---
>  util/fusermount.c | 298 +++++++++++++++++++++++++++++++++++++-----------------
>  1 file changed, 205 insertions(+), 93 deletions(-)
> 
> diff --git a/util/fusermount.c b/util/fusermount.c
> index f17b44f51142c682b339d0ce2287f7c00d644454..ecf509bb80d5cd129f6e582f1ec666502c55603a 100644
> --- a/util/fusermount.c
> +++ b/util/fusermount.c
> @@ -917,30 +917,132 @@ static int mount_notrunc(const char *source, const char *target,
>  	return mount(source, target, filesystemtype, mountflags, data);
>  }
>  
> +struct mount_params {
> +	/* Input parameters */
> +	int fd;                  /* /dev/fuse file descriptor */
> +	mode_t rootmode;         /* Root mode from stat */
> +	const char *dev;         /* Device path (/dev/fuse) */
>  
> -static int do_mount(const char *mnt, const char **typep, mode_t rootmode,
> -		    int fd, const char *opts, const char *dev, char **sourcep,
> -		    char **mnt_optsp)
> +	/* Parsed mount options */
> +	unsigned long flags;     /* Mount flags (MS_NOSUID, etc.) */
> +	char *optbuf;           /* Kernel mount options buffer */
> +	char *fsname;           /* Filesystem name from options */
> +	char *subtype;          /* Subtype from options */
> +	int blkdev;             /* Block device flag */
> +
> +	/* Generated mount parameters */
> +	char *source;           /* Mount source string */
> +	char *type;             /* Filesystem type string */
> +	char *mnt_opts;         /* Mount table options */
> +
> +	/* Pointer for optbuf manipulation */
> +	char *optbuf_end;       /* Points to end of optbuf for sprintf */
> +};
> +
> +static void free_mount_params(struct mount_params *mp)
> +{
> +	free(mp->optbuf);
> +	free(mp->fsname);
> +	free(mp->subtype);
> +	free(mp->source);
> +	free(mp->type);
> +	free(mp->mnt_opts);
> +}
> +
> +/*
> + * Check if option is deprecated large_read.
> + *
> + * Returns true if the option should be skipped (large_read on kernel > 2.4),
> + * false otherwise (all other options or large_read on old kernels).
> + */
> +static bool check_large_read(const char *opt, unsigned int len)
> +{
> +	struct utsname utsname;
> +	unsigned int kmaj, kmin;
> +	int res;
> +
> +	if (!opt_eq(opt, len, "large_read"))
> +		return false;
> +
> +	res = uname(&utsname);
> +	if (res == 0 &&
> +	    sscanf(utsname.release, "%u.%u", &kmaj, &kmin) == 2 &&
> +	    (kmaj > 2 || (kmaj == 2 && kmin > 4))) {
> +		fprintf(stderr,
> +			"%s: note: 'large_read' mount option is deprecated for %i.%i kernels\n",
> +			progname, kmaj, kmin);
> +		return true;

Ugh, you can drop the uname and all that.  Nobody's running 2.4 kernels
anymore, right?

> +	}
> +	return false;
> +}
> +
> +/*
> + * Check if user has permission to use allow_other or allow_root options.
> + *
> + * Returns -1 if permission denied, 0 if allowed or option is not
> + * allow_other/allow_root.
> + */
> +static int check_allow_permission(const char *opt, unsigned int len)
> +{
> +	if (getuid() != 0 && !user_allow_other &&
> +	    (opt_eq(opt, len, "allow_other") || opt_eq(opt, len, "allow_root"))) {
> +		fprintf(stderr, "%s: option %.*s only allowed if 'user_allow_other' is set in %s\n",
> +			progname, len, opt, FUSE_CONF);
> +		return -1;
> +	}
> +	return 0;
> +}
> +
> +/*
> + * Process generic mount option.
> + *
> + * Handles mount flags (ro, rw, suid, etc.), kernel options
> + * (default_permissions, allow_other, max_read, blksize), or exits on
> + * unknown options.
> + */
> +static int process_generic_option(const char *opt, unsigned int len,
> +				   unsigned long *flags, char **dest)
> +{
> +	int on;
> +	int flag;
> +
> +	if (find_mount_flag(opt, len, &on, &flag)) {
> +		if (on)
> +			*flags |= flag;
> +		else
> +			*flags &= ~flag;
> +		return 0;
> +	}
> +
> +	if (opt_eq(opt, len, "default_permissions") ||
> +	    opt_eq(opt, len, "allow_other") ||
> +	    begins_with(opt, "max_read=") ||
> +	    begins_with(opt, "blksize=")) {
> +		memcpy(*dest, opt, len);
> +		*dest += len;
> +		**dest = ',';
> +		(*dest)++;
> +		return 0;
> +	}
> +
> +	fprintf(stderr, "%s: unknown option '%.*s'\n", progname, len, opt);
> +	exit(1);
> +}
> +
> +static int prepare_mount(const char *opts, struct mount_params *mp)
>  {
>  	int res;
> -	int flags = MS_NOSUID | MS_NODEV;
> -	char *optbuf;
> -	char *mnt_opts = NULL;
>  	const char *s;
>  	char *d;
> -	char *fsname = NULL;
> -	char *subtype = NULL;
> -	char *source = NULL;
> -	char *type = NULL;
> -	int blkdev = 0;
>  
> -	optbuf = (char *) malloc(strlen(opts) + 128);
> -	if (!optbuf) {
> +	mp->flags = MS_NOSUID | MS_NODEV;
> +	mp->optbuf = (char *) malloc(strlen(opts) + 128);
> +	if (!mp->optbuf) {
>  		fprintf(stderr, "%s: failed to allocate memory\n", progname);
>  		return -1;
>  	}
>  
> -	for (s = opts, d = optbuf; *s;) {
> +	for (s = opts, d = mp->optbuf; *s;) {
>  		unsigned len;
>  		const char *fsname_str = "fsname=";
>  		const char *subtype_str = "subtype=";
> @@ -953,10 +1055,10 @@ static int do_mount(const char *mnt, const char **typep, mode_t rootmode,
>  				break;
>  		}
>  		if (begins_with(s, fsname_str)) {
> -			if (!get_string_opt(s, len, fsname_str, &fsname))
> +			if (!get_string_opt(s, len, fsname_str, &mp->fsname))
>  				goto err;
>  		} else if (begins_with(s, subtype_str)) {
> -			if (!get_string_opt(s, len, subtype_str, &subtype))
> +			if (!get_string_opt(s, len, subtype_str, &mp->subtype))
>  				goto err;
>  		} else if (opt_eq(s, len, "blkdev")) {
>  			if (getuid() != 0) {
> @@ -965,7 +1067,7 @@ static int do_mount(const char *mnt, const char **typep, mode_t rootmode,
>  					progname);
>  				goto err;
>  			}
> -			blkdev = 1;
> +			mp->blkdev = 1;
>  		} else if (opt_eq(s, len, "auto_unmount")) {
>  			auto_unmount = 1;
>  		} else if (!opt_eq(s, len, "nonempty") &&
> @@ -973,122 +1075,132 @@ static int do_mount(const char *mnt, const char **typep, mode_t rootmode,
>  			   !begins_with(s, "rootmode=") &&
>  			   !begins_with(s, "user_id=") &&
>  			   !begins_with(s, "group_id=")) {
> -			int on;
> -			int flag;
> -			int skip_option = 0;
> -			if (opt_eq(s, len, "large_read")) {
> -				struct utsname utsname;
> -				unsigned kmaj, kmin;
> -				res = uname(&utsname);
> -				if (res == 0 &&
> -				    sscanf(utsname.release, "%u.%u",
> -					   &kmaj, &kmin) == 2 &&
> -				    (kmaj > 2 || (kmaj == 2 && kmin > 4))) {
> -					fprintf(stderr, "%s: note: 'large_read' mount option is deprecated for %i.%i kernels\n", progname, kmaj, kmin);
> -					skip_option = 1;
> -				}
> -			}
> -			if (getuid() != 0 && !user_allow_other &&
> -			    (opt_eq(s, len, "allow_other") ||
> -			     opt_eq(s, len, "allow_root"))) {
> -				fprintf(stderr, "%s: option %.*s only allowed if 'user_allow_other' is set in %s\n", progname, len, s, FUSE_CONF);
> +			bool skip;
> +
> +			if (check_allow_permission(s, len) == -1)
>  				goto err;
> -			}
> -			if (!skip_option) {
> -				if (find_mount_flag(s, len, &on, &flag)) {
> -					if (on)
> -						flags |= flag;
> -					else
> -						flags  &= ~flag;
> -				} else if (opt_eq(s, len, "default_permissions") ||
> -					   opt_eq(s, len, "allow_other") ||
> -					   begins_with(s, "max_read=") ||
> -					   begins_with(s, "blksize=")) {
> -					memcpy(d, s, len);
> -					d += len;
> -					*d++ = ',';
> -				} else {
> -					fprintf(stderr, "%s: unknown option '%.*s'\n", progname, len, s);
> -					exit(1);
> -				}
> -			}
> +
> +			skip = check_large_read(s, len);
> +
> +			/*
> +			 * Skip deprecated large_read to avoid passing it to
> +			 * kernel which would reject it as unknown option.
> +			 */
> +			if (!skip)
> +				process_generic_option(s, len, &mp->flags, &d);
>  		}
>  		s += len;
>  		if (*s)
>  			s++;
>  	}
>  	*d = '\0';
> -	res = get_mnt_opts(flags, optbuf, &mnt_opts);
> +	res = get_mnt_opts(mp->flags, mp->optbuf, &mp->mnt_opts);
>  	if (res == -1)
>  		goto err;
>  
> +	mp->optbuf_end = d;
> +
>  	sprintf(d, "fd=%i,rootmode=%o,user_id=%u,group_id=%u",
> -		fd, rootmode, getuid(), getgid());
> +		mp->fd, mp->rootmode, getuid(), getgid());
>  
> -	source = malloc((fsname ? strlen(fsname) : 0) +
> -			(subtype ? strlen(subtype) : 0) + strlen(dev) + 32);
> +	mp->source = malloc((mp->fsname ? strlen(mp->fsname) : 0) +
> +			(mp->subtype ? strlen(mp->subtype) : 0) + strlen(mp->dev) + 32);
>  
> -	type = malloc((subtype ? strlen(subtype) : 0) + 32);
> -	if (!type || !source) {
> +	mp->type = malloc((mp->subtype ? strlen(mp->subtype) : 0) + 32);
> +	if (!mp->type || !mp->source) {
>  		fprintf(stderr, "%s: failed to allocate memory\n", progname);
>  		goto err;
>  	}
>  
> -	if (subtype)
> -		sprintf(type, "%s.%s", blkdev ? "fuseblk" : "fuse", subtype);
> +	if (mp->subtype)
> +		sprintf(mp->type, "%s.%s", mp->blkdev ? "fuseblk" : "fuse", mp->subtype);
>  	else
> -		strcpy(type, blkdev ? "fuseblk" : "fuse");
> +		strcpy(mp->type, mp->blkdev ? "fuseblk" : "fuse");

Hrm, maybe the patch adding fuse_mnt_build_source / fuse_mnt_build_type
should have done something about this code too.

The straight-up conversion looks ok though.

--D

> -	if (fsname)
> -		strcpy(source, fsname);
> +	if (mp->fsname)
> +		strcpy(mp->source, mp->fsname);
>  	else
> -		strcpy(source, subtype ? subtype : dev);
> +		strcpy(mp->source, mp->subtype ? mp->subtype : mp->dev);
>  
> -	res = mount_notrunc(source, mnt, type, flags, optbuf);
> -	if (res == -1 && errno == ENODEV && subtype) {
> +	return 0;
> +
> +err:
> +	free_mount_params(mp);
> +	return -1;
> +}
> +
> +/*
> + * Perform the actual mount operation using prepared parameters.
> + *
> + * Returns 0 on success, -1 on failure.
> + */
> +static int perform_mount(const char *mnt, struct mount_params *mp)
> +{
> +	int res;
> +
> +	res = mount_notrunc(mp->source, mnt, mp->type, mp->flags, mp->optbuf);
> +	if (res == -1 && errno == ENODEV && mp->subtype) {
>  		/* Probably missing subtype support */
> -		strcpy(type, blkdev ? "fuseblk" : "fuse");
> -		if (fsname) {
> -			if (!blkdev)
> -				sprintf(source, "%s#%s", subtype, fsname);
> +		strcpy(mp->type, mp->blkdev ? "fuseblk" : "fuse");
> +		if (mp->fsname) {
> +			if (!mp->blkdev)
> +				sprintf(mp->source, "%s#%s", mp->subtype, mp->fsname);
>  		} else {
> -			strcpy(source, type);
> +			strcpy(mp->source, mp->type);
>  		}
>  
> -		res = mount_notrunc(source, mnt, type, flags, optbuf);
> +		res = mount_notrunc(mp->source, mnt, mp->type, mp->flags, mp->optbuf);
>  	}
>  	if (res == -1 && errno == EINVAL) {
>  		/* It could be an old version not supporting group_id */
> -		sprintf(d, "fd=%i,rootmode=%o,user_id=%u",
> -			fd, rootmode, getuid());
> -		res = mount_notrunc(source, mnt, type, flags, optbuf);
> +		sprintf(mp->optbuf_end, "fd=%i,rootmode=%o,user_id=%u",
> +			mp->fd, mp->rootmode, getuid());
> +		res = mount_notrunc(mp->source, mnt, mp->type, mp->flags, mp->optbuf);
>  	}
>  	if (res == -1) {
>  		int errno_save = errno;
> -		if (blkdev && errno == ENODEV && !fuse_mnt_check_fuseblk())
> +		if (mp->blkdev && errno == ENODEV && !fuse_mnt_check_fuseblk())
>  			fprintf(stderr, "%s: 'fuseblk' support missing\n",
>  				progname);
>  		else
>  			fprintf(stderr, "%s: mount failed: %s\n", progname,
>  				strerror(errno_save));
> -		goto err;
> +		return -1;
>  	}
> -	*sourcep = source;
> -	*typep = type;
> -	*mnt_optsp = mnt_opts;
> -	free(fsname);
> -	free(optbuf);
>  
>  	return 0;
> +}
>  
> -err:
> -	free(fsname);
> -	free(subtype);
> -	free(source);
> -	free(type);
> -	free(mnt_opts);
> -	free(optbuf);
> -	return -1;
> +static int do_mount(const char *mnt, const char **typep, mode_t rootmode,
> +		    int fd, const char *opts, const char *dev, char **sourcep,
> +		    char **mnt_optsp)
> +{
> +	struct mount_params mp = { .fd = fd }; /* implicit zero of other params */
> +	int res;
> +
> +	mp.rootmode = rootmode;
> +	mp.dev = dev;
> +
> +	res = prepare_mount(opts, &mp);
> +	if (res == -1)
> +		return -1;
> +
> +	res = perform_mount(mnt, &mp);
> +	if (res == -1) {
> +		free_mount_params(&mp);
> +		return -1;
> +	}
> +
> +	*sourcep = mp.source;
> +	*typep = mp.type;
> +	*mnt_optsp = mp.mnt_opts;
> +
> +	/* Free only the intermediate allocations, not the returned ones */
> +	free(mp.fsname);
> +	free(mp.subtype);
> +	free(mp.optbuf);
> +
> +	return 0;
>  }
>  
>  static int check_perm(const char **mntp, struct stat *stbuf, int *mountpoint_fd)
> 
> -- 
> 2.43.0
> 
> 

  reply	other threads:[~2026-03-24  0:14 UTC|newest]

Thread overview: 61+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-03-23 17:44 [PATCH 00/19] libfuse: Add support for synchronous init Bernd Schubert
2026-03-23 17:44 ` [PATCH 01/19] ci-build: Add environment logging Bernd Schubert
2026-03-23 17:44 ` [PATCH 02/19] Add 'STRCPY' to the checkpatch ignore option Bernd Schubert
2026-03-23 21:03   ` Darrick J. Wong
2026-03-23 17:44 ` [PATCH 03/19] checkpatch.pl: Add _Atomic to $Attribute patttern Bernd Schubert
2026-03-23 21:09   ` Darrick J. Wong
2026-03-23 17:44 ` [PATCH 04/19] Add a new daemonize API Bernd Schubert
2026-03-23 22:28   ` Darrick J. Wong
2026-03-24 17:36     ` Bernd Schubert
2026-03-24 22:20       ` Darrick J. Wong
2026-03-23 17:45 ` [PATCH 05/19] Sync fuse_kernel.h with linux-6.18 Bernd Schubert
2026-03-23 21:16   ` Darrick J. Wong
2026-03-23 17:45 ` [PATCH 06/19] mount.c: Split fuse_mount_sys to prepare privileged sync FUSE_INIT Bernd Schubert
2026-03-23 22:34   ` Darrick J. Wong
2026-03-23 17:45 ` [PATCH 07/19] Add FUSE_MOUNT_FALLBACK_NEEDED define for -2 mount errors Bernd Schubert
2026-03-23 22:36   ` Darrick J. Wong
2026-03-24 18:03     ` Bernd Schubert
2026-03-23 17:45 ` [PATCH 08/19] Refactor mount code / move common functions to mount_util.c Bernd Schubert
2026-03-23 22:40   ` Darrick J. Wong
2026-03-23 17:45 ` [PATCH 09/19] Move mount flags to mount_i.h Bernd Schubert
2026-03-23 22:45   ` Darrick J. Wong
2026-03-24 18:40     ` Bernd Schubert
2026-03-23 17:45 ` [PATCH 10/19] conftest.py: Add more valgrind filter patterns Bernd Schubert
2026-03-23 17:45 ` [PATCH 11/19] Add support for the new linux mount API Bernd Schubert
2026-03-23 23:42   ` Darrick J. Wong
2026-03-24 20:16     ` Bernd Schubert
2026-03-24 22:46       ` Darrick J. Wong
2026-03-23 17:45 ` [PATCH 12/19] fuse mount: Support synchronous FUSE_INIT (privileged daemon) Bernd Schubert
2026-03-24  0:03   ` Darrick J. Wong
2026-03-24 20:42     ` Bernd Schubert
2026-03-24 22:50       ` Darrick J. Wong
2026-03-25  7:52         ` Bernd Schubert
2026-03-25 16:42           ` Darrick J. Wong
2026-03-26 19:32         ` Bernd Schubert
2026-03-26 22:33           ` Darrick J. Wong
2026-03-23 17:45 ` [PATCH 13/19] Add fuse_session_set_debug() to enable debug output without foreground Bernd Schubert
2026-03-24  0:04   ` Darrick J. Wong
2026-03-23 17:45 ` [PATCH 14/19] Move more generic mount code to mount_util.{c,h} Bernd Schubert
2026-03-24  0:06   ` Darrick J. Wong
2026-03-24 20:57     ` Bernd Schubert
2026-03-23 17:45 ` [PATCH 15/19] Split the fusermount do_mount function Bernd Schubert
2026-03-24  0:14   ` Darrick J. Wong [this message]
2026-03-24 21:05     ` Bernd Schubert
2026-03-24 22:53       ` Darrick J. Wong
2026-03-23 17:45 ` [PATCH 16/19] fusermount: Refactor extract_x_options Bernd Schubert
2026-03-24  0:18   ` Darrick J. Wong
2026-03-23 17:45 ` [PATCH 17/19] Make fusermount work bidirectional for sync init Bernd Schubert
2026-03-24 19:35   ` Darrick J. Wong
2026-03-24 21:24     ` Bernd Schubert
2026-03-24 22:59       ` Darrick J. Wong
2026-03-25 19:48         ` Bernd Schubert
2026-03-25 22:03           ` Darrick J. Wong
2026-03-23 17:45 ` [PATCH 18/19] New mount API: Filter out "user=" Bernd Schubert
2026-03-24 19:51   ` Darrick J. Wong
2026-03-24 20:01     ` Bernd Schubert
2026-03-24 23:02       ` Darrick J. Wong
2026-03-23 17:45 ` [PATCH 19/19] Add support for sync-init of unprivileged daemons Bernd Schubert
2026-03-24 20:21   ` Darrick J. Wong
2026-03-24 21:53     ` Bernd Schubert
2026-03-24 23:13       ` Darrick J. Wong
2026-03-24  0:19 ` [PATCH 00/19] libfuse: Add support for synchronous init Darrick J. Wong

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260324001414.GP6202@frogsfrogsfrogs \
    --to=djwong@kernel.org \
    --cc=bernd@bsbernd.com \
    --cc=bschubert@ddn.com \
    --cc=joannelkoong@gmail.com \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=miklos@szeredi.hu \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.