Re: [PATCH v2] autofs: add per dentry expire timeout

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

 



On Wed, Aug 14, 2024 at 05:02:31PM GMT, Ian Kent wrote:
> Add ability to set per-dentry mount expire timeout to autofs.
> 
> There are two fairly well known automounter map formats, the autofs
> format and the amd format (more or less System V and Berkley).
> 
> Some time ago Linux autofs added an amd map format parser that
> implemented a fair amount of the amd functionality. This was done
> within the autofs infrastructure and some functionality wasn't
> implemented because it either didn't make sense or required extra
> kernel changes. The idea was to restrict changes to be within the
> existing autofs functionality as much as possible and leave changes
> with a wider scope to be considered later.
> 
> One of these changes is implementing the amd options:
> 1) "unmount", expire this mount according to a timeout (same as the
>    current autofs default).
> 2) "nounmount", don't expire this mount (same as setting the autofs
>    timeout to 0 except only for this specific mount) .
> 3) "utimeout=<seconds>", expire this mount using the specified
>    timeout (again same as setting the autofs timeout but only for
>    this mount).
> 
> To implement these options per-dentry expire timeouts need to be
> implemented for autofs indirect mounts. This is because all map keys
> (mounts) for autofs indirect mounts use an expire timeout stored in
> the autofs mount super block info. structure and all indirect mounts
> use the same expire timeout.
> 
> Now I have a request to add the "nounmount" option so I need to add
> the per-dentry expire handling to the kernel implementation to do this.
> 
> The implementation uses the trailing path component to identify the
> mount (and is also used as the autofs map key) which is passed in the
> autofs_dev_ioctl structure path field. The expire timeout is passed
> in autofs_dev_ioctl timeout field (well, of the timeout union).
> 
> If the passed in timeout is equal to -1 the per-dentry timeout and
> flag are cleared providing for the "unmount" option. If the timeout
> is greater than or equal to 0 the timeout is set to the value and the
> flag is also set. If the dentry timeout is 0 the dentry will not expire
> by timeout which enables the implementation of the "nounmount" option
> for the specific mount. When the dentry timeout is greater than zero it
> allows for the implementation of the "utimeout=<seconds>" option.
> 
> Signed-off-by: Ian Kent <raven@xxxxxxxxxx>
> ---
>  fs/autofs/autofs_i.h         |  4 ++
>  fs/autofs/dev-ioctl.c        | 97 ++++++++++++++++++++++++++++++++++--
>  fs/autofs/expire.c           |  7 ++-
>  fs/autofs/inode.c            |  2 +
>  include/uapi/linux/auto_fs.h |  2 +-
>  5 files changed, 104 insertions(+), 8 deletions(-)
> 
> diff --git a/fs/autofs/autofs_i.h b/fs/autofs/autofs_i.h
> index 8c1d587b3eef..77c7991d89aa 100644
> --- a/fs/autofs/autofs_i.h
> +++ b/fs/autofs/autofs_i.h
> @@ -62,6 +62,7 @@ struct autofs_info {
>  	struct list_head expiring;
>  
>  	struct autofs_sb_info *sbi;
> +	unsigned long exp_timeout;
>  	unsigned long last_used;
>  	int count;
>  
> @@ -81,6 +82,9 @@ struct autofs_info {
>  					*/
>  #define AUTOFS_INF_PENDING	(1<<2) /* dentry pending mount */
>  
> +#define AUTOFS_INF_EXPIRE_SET	(1<<3) /* per-dentry expire timeout set for
> +					  this mount point.
> +					*/
>  struct autofs_wait_queue {
>  	wait_queue_head_t queue;
>  	struct autofs_wait_queue *next;
> diff --git a/fs/autofs/dev-ioctl.c b/fs/autofs/dev-ioctl.c
> index 5bf781ea6d67..f011e026358e 100644
> --- a/fs/autofs/dev-ioctl.c
> +++ b/fs/autofs/dev-ioctl.c
> @@ -128,7 +128,13 @@ static int validate_dev_ioctl(int cmd, struct autofs_dev_ioctl *param)
>  			goto out;
>  		}
>  
> +		/* Setting the per-dentry expire timeout requires a trailing
> +		 * path component, ie. no '/', so invert the logic of the
> +		 * check_name() return for AUTOFS_DEV_IOCTL_TIMEOUT_CMD.
> +		 */
>  		err = check_name(param->path);
> +		if (cmd == AUTOFS_DEV_IOCTL_TIMEOUT_CMD)
> +			err = err ? 0 : -EINVAL;
>  		if (err) {
>  			pr_warn("invalid path supplied for cmd(0x%08x)\n",
>  				cmd);
> @@ -396,16 +402,97 @@ static int autofs_dev_ioctl_catatonic(struct file *fp,
>  	return 0;
>  }
>  
> -/* Set the autofs mount timeout */
> +/*
> + * Set the autofs mount expire timeout.
> + *
> + * There are two places an expire timeout can be set, in the autofs
> + * super block info. (this is all that's needed for direct and offset
> + * mounts because there's a distinct mount corresponding to each of
> + * these) and per-dentry within within the dentry info. If a per-dentry
> + * timeout is set it will override the expire timeout set in the parent
> + * autofs super block info.
> + *
> + * If setting the autofs super block expire timeout the autofs_dev_ioctl
> + * size field will be equal to the autofs_dev_ioctl structure size. If
> + * setting the per-dentry expire timeout the mount point name is passed
> + * in the autofs_dev_ioctl path field and the size field updated to
> + * reflect this.
> + *
> + * Setting the autofs mount expire timeout sets the timeout in the super
> + * block info. struct. Setting the per-dentry timeout does a little more.
> + * If the timeout is equal to -1 the per-dentry timeout (and flag) is
> + * cleared which reverts to using the super block timeout, otherwise if
> + * timeout is 0 the timeout is set to this value and the flag is left
> + * set which disables expiration for the mount point, lastly the flag
> + * and the timeout are set enabling the dentry to use this timeout.
> + */
>  static int autofs_dev_ioctl_timeout(struct file *fp,
>  				    struct autofs_sb_info *sbi,
>  				    struct autofs_dev_ioctl *param)
>  {
> -	unsigned long timeout;
> +	unsigned long timeout = param->timeout.timeout;
> +
> +	/* If setting the expire timeout for an individual indirect
> +	 * mount point dentry the mount trailing component path is
> +	 * placed in param->path and param->size adjusted to account
> +	 * for it otherwise param->size it is set to the structure
> +	 * size.
> +	 */
> +	if (param->size == AUTOFS_DEV_IOCTL_SIZE) {
> +		param->timeout.timeout = sbi->exp_timeout / HZ;
> +		sbi->exp_timeout = timeout * HZ;
> +	} else {
> +		struct dentry *base = fp->f_path.dentry;
> +		struct inode *inode = base->d_inode;
> +		int path_len = param->size - AUTOFS_DEV_IOCTL_SIZE - 1;
> +		struct dentry *dentry;
> +		struct autofs_info *ino;
> +
> +		if (!autofs_type_indirect(sbi->type))
> +			return -EINVAL;
> +
> +		/* An expire timeout greater than the superblock timeout
> +		 * could be a problem at shutdown but the super block
> +		 * timeout itself can change so all we can really do is
> +		 * warn the user.
> +		 */
> +		if (timeout >= sbi->exp_timeout)
> +			pr_warn("per-mount expire timeout is greater than "
> +				"the parent autofs mount timeout which could "
> +				"prevent shutdown\n");

Wouldn't it be possible to just record the lowest known per-dentry
timeout in idk sbi->exp_lower_bound and reject sbi->exp_timeout changes
that go below that?




[Index of Archives]     [Linux Filesystem Development]     [Linux Ext4]     [Linux ARM Kernel]     [Linux ARM]     [Linux Omap]     [Fedora ARM]     [IETF Annouce]     [Security]     [Bugtraq]     [Linux]     [Linux OMAP]     [Linux MIPS]     [ECOS]     [Asterisk Internet PBX]     [Linux API]

  Powered by Linux