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