Re: [PATCH v6 17/17] vfs: expose delegation support to userland

Jan Kara <[email protected]>
Newsgroups org.kernel.vger.ecryptfs,dev.linux.lists.netfs,org.kernel.vger.linux-api,org.kernel.vger.linux-cifs,org.kernel.vger.linux-fsdevel,org.kernel.vger.linux-kernel,org.kernel.vger.linux-nfs,org.kernel.vger.linux-unionfs,org.kernel.vger.linux-xfs,org.kernel.vger.netdev
Message-ID <htsrrghapbhriwdtt6pbrgsptwf5nri6ehzgmgjqrc2bmsmku4@hl4q3fvz4kyc>
On Tue 11-11-25 09:12:58, Jeff Layton wrote:
> Now that support for recallable directory delegations is available,
> expose this functionality to userland with new F_SETDELEG and F_GETDELEG
> commands for fcntl().
> 
> Note that this also allows userland to request a FL_DELEG type lease on
> files too. Userland applications that do will get signalled when there
> are metadata changes in addition to just data changes (which is a
> limitation of FL_LEASE leases).
> 
> These commands accept a new "struct delegation" argument that contains a
> flags field for future expansion.
> 
> Signed-off-by: Jeff Layton <[email protected]>

Looks good. Feel free to add:

Reviewed-by: Jan Kara <[email protected]>

								Honza

> ---
>  fs/fcntl.c                 | 13 +++++++++++++
>  fs/locks.c                 | 45 ++++++++++++++++++++++++++++++++++++++++-----
>  include/linux/filelock.h   | 12 ++++++++++++
>  include/uapi/linux/fcntl.h | 11 +++++++++++
>  4 files changed, 76 insertions(+), 5 deletions(-)
> 
> diff --git a/fs/fcntl.c b/fs/fcntl.c
> index 72f8433d9109889eecef56b32d20a85b4e12ea44..f93dbca0843557d197bd1e023519cfa0f00ad78f 100644
> --- a/fs/fcntl.c
> +++ b/fs/fcntl.c
> @@ -445,6 +445,7 @@ static long do_fcntl(int fd, unsigned int cmd, unsigned long arg,
>  		struct file *filp)
>  {
>  	void __user *argp = (void __user *)arg;
> +	struct delegation deleg;
>  	int argi = (int)arg;
>  	struct flock flock;
>  	long err = -EINVAL;
> @@ -550,6 +551,18 @@ static long do_fcntl(int fd, unsigned int cmd, unsigned long arg,
>  	case F_SET_RW_HINT:
>  		err = fcntl_set_rw_hint(filp, arg);
>  		break;
> +	case F_GETDELEG:
> +		if (copy_from_user(&deleg, argp, sizeof(deleg)))
> +			return -EFAULT;
> +		err = fcntl_getdeleg(filp, &deleg);
> +		if (!err && copy_to_user(argp, &deleg, sizeof(deleg)))
> +			return -EFAULT;
> +		break;
> +	case F_SETDELEG:
> +		if (copy_from_user(&deleg, argp, sizeof(deleg)))
> +			return -EFAULT;
> +		err = fcntl_setdeleg(fd, filp, &deleg);
> +		break;
>  	default:
>  		break;
>  	}
> diff --git a/fs/locks.c b/fs/locks.c
> index dd290a87f58eb5d522f03fa99d612fbad84dacf3..7f4ccc7974bc8d3e82500ee692c6520b53f2280f 100644
> --- a/fs/locks.c
> +++ b/fs/locks.c
> @@ -1703,7 +1703,7 @@ EXPORT_SYMBOL(lease_get_mtime);
>   *	XXX: sfr & willy disagree over whether F_INPROGRESS
>   *	should be returned to userspace.
>   */
> -int fcntl_getlease(struct file *filp)
> +static int __fcntl_getlease(struct file *filp, unsigned int flavor)
>  {
>  	struct file_lease *fl;
>  	struct inode *inode = file_inode(filp);
> @@ -1719,7 +1719,8 @@ int fcntl_getlease(struct file *filp)
>  		list_for_each_entry(fl, &ctx->flc_lease, c.flc_list) {
>  			if (fl->c.flc_file != filp)
>  				continue;
> -			type = target_leasetype(fl);
> +			if (fl->c.flc_flags & flavor)
> +				type = target_leasetype(fl);
>  			break;
>  		}
>  		spin_unlock(&ctx->flc_lock);
> @@ -1730,6 +1731,19 @@ int fcntl_getlease(struct file *filp)
>  	return type;
>  }
>  
> +int fcntl_getlease(struct file *filp)
> +{
> +	return __fcntl_getlease(filp, FL_LEASE);
> +}
> +
> +int fcntl_getdeleg(struct file *filp, struct delegation *deleg)
> +{
> +	if (deleg->d_flags != 0 || deleg->__pad != 0)
> +		return -EINVAL;
> +	deleg->d_type = __fcntl_getlease(filp, FL_DELEG);
> +	return 0;
> +}
> +
>  /**
>   * check_conflicting_open - see if the given file points to an inode that has
>   *			    an existing open that would conflict with the
> @@ -2039,13 +2053,13 @@ vfs_setlease(struct file *filp, int arg, struct file_lease **lease, void **priv)
>  }
>  EXPORT_SYMBOL_GPL(vfs_setlease);
>  
> -static int do_fcntl_add_lease(unsigned int fd, struct file *filp, int arg)
> +static int do_fcntl_add_lease(unsigned int fd, struct file *filp, unsigned int flavor, int arg)
>  {
>  	struct file_lease *fl;
>  	struct fasync_struct *new;
>  	int error;
>  
> -	fl = lease_alloc(filp, FL_LEASE, arg);
> +	fl = lease_alloc(filp, flavor, arg);
>  	if (IS_ERR(fl))
>  		return PTR_ERR(fl);
>  
> @@ -2081,7 +2095,28 @@ int fcntl_setlease(unsigned int fd, struct file *filp, int arg)
>  
>  	if (arg == F_UNLCK)
>  		return vfs_setlease(filp, F_UNLCK, NULL, (void **)&filp);
> -	return do_fcntl_add_lease(fd, filp, arg);
> +	return do_fcntl_add_lease(fd, filp, FL_LEASE, arg);
> +}
> +
> +/**
> + *	fcntl_setdeleg	-	sets a delegation on an open file
> + *	@fd: open file descriptor
> + *	@filp: file pointer
> + *	@deleg: delegation request from userland
> + *
> + *	Call this fcntl to establish a delegation on the file.
> + *	Note that you also need to call %F_SETSIG to
> + *	receive a signal when the lease is broken.
> + */
> +int fcntl_setdeleg(unsigned int fd, struct file *filp, struct delegation *deleg)
> +{
> +	/* For now, no flags are supported */
> +	if (deleg->d_flags != 0 || deleg->__pad != 0)
> +		return -EINVAL;
> +
> +	if (deleg->d_type == F_UNLCK)
> +		return vfs_setlease(filp, F_UNLCK, NULL, (void **)&filp);
> +	return do_fcntl_add_lease(fd, filp, FL_DELEG, deleg->d_type);
>  }
>  
>  /**
> diff --git a/include/linux/filelock.h b/include/linux/filelock.h
> index 208d108df2d73a9df65e5dc9968d074af385f881..54b824c05299261e6bd6acc4175cb277ea35b35d 100644
> --- a/include/linux/filelock.h
> +++ b/include/linux/filelock.h
> @@ -159,6 +159,8 @@ int fcntl_setlk64(unsigned int, struct file *, unsigned int,
>  
>  int fcntl_setlease(unsigned int fd, struct file *filp, int arg);
>  int fcntl_getlease(struct file *filp);
> +int fcntl_setdeleg(unsigned int fd, struct file *filp, struct delegation *deleg);
> +int fcntl_getdeleg(struct file *filp, struct delegation *deleg);
>  
>  static inline bool lock_is_unlock(struct file_lock *fl)
>  {
> @@ -278,6 +280,16 @@ static inline int fcntl_getlease(struct file *filp)
>  	return F_UNLCK;
>  }
>  
> +static inline int fcntl_setdeleg(unsigned int fd, struct file *filp, struct delegation *deleg)
> +{
> +	return -EINVAL;
> +}
> +
> +static inline int fcntl_getdeleg(struct file *filp, struct delegation *deleg)
> +{
> +	return -EINVAL;
> +}
> +
>  static inline bool lock_is_unlock(struct file_lock *fl)
>  {
>  	return false;
> diff --git a/include/uapi/linux/fcntl.h b/include/uapi/linux/fcntl.h
> index 3741ea1b73d8500061567b6590ccf5fb4c6770f0..008fac15e573084a9b48e4e991528b4363c54047 100644
> --- a/include/uapi/linux/fcntl.h
> +++ b/include/uapi/linux/fcntl.h
> @@ -79,6 +79,17 @@
>   */
>  #define RWF_WRITE_LIFE_NOT_SET	RWH_WRITE_LIFE_NOT_SET
>  
> +/* Set/Get delegations */
> +#define F_GETDELEG		(F_LINUX_SPECIFIC_BASE + 15)
> +#define F_SETDELEG		(F_LINUX_SPECIFIC_BASE + 16)
> +
> +/* Argument structure for F_GETDELEG and F_SETDELEG */
> +struct delegation {
> +	uint32_t	d_flags;	/* Must be 0 */
> +	uint16_t	d_type;		/* F_RDLCK, F_WRLCK, F_UNLCK */
> +	uint16_t	__pad;		/* Must be 0 */
> +};
> +
>  /*
>   * Types of directory notifications that may be requested.
>   */
> 
> -- 
> 2.51.1
> 
-- 
Jan Kara <[email protected]>
SUSE Labs, CR
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.