Unverified Commit 76c63ff1 authored by Christian Brauner's avatar Christian Brauner
Browse files

Merge patch series "vfs: recall-only directory delegations for knfsd"

Jeff Layton <jlayton@kernel.org> says:

At the fall NFS Bakeathon last week, the NFS client and server
maintainers had a discussion about how to merge support for directory
delegations. We decided to start with just merging support for simple,
recallable-only directory delegation support, for a number of reasons:

1/ RFC8881 has some gaps in coverage that we are hoping to have
addressed in RFC8881bis. In particular, it's written such that CB_NOTIFY
callbacks require directory position information. That will be hard to
do properly under Linux, so we're planning to extend the spec to allow
that information to be omitted.

2/ client-side support for CB_NOTIFY still lags a bit. The client side
is tricky, as it involves heuristics about when to request a delegation.

3/ we have some early indication that simple, recallable-only
delegations can help performance in some cases. Anna mentioned seeing a
multi-minute speedup in xfstests runs with them enabled. This needs more
investigation, but it's promising and seems like enough justification to
merge support.

This patchset is quite similar to the set I initially posted back in
early 2024. We've merged some GET_DIR_DELEGATION handling patches
since then, but the VFS layer support is basically the same.

One thing that I want to make clear is that with this patchset, userspace
can request a read lease on a directory that will be recalled on
conflicting accesses. I saw no reason to prevent this, and I think it may
be something useful for applications like Samba.

As always, users can disable leases altogether via the fs.leases-enable
sysctl if this is an issue, but I wanted to point this out in case
anyone sees footguns here.

* patches from https://patch.msgid.link/20251111-dir-deleg-ro-v6-0-52f3feebb2f2@kernel.org:
  vfs: expose delegation support to userland
  nfsd: wire up GET_DIR_DELEGATION handling
  nfsd: allow DELEGRETURN on directories
  nfsd: allow filecache to hold S_IFDIR files
  filelock: lift the ban on directory leases in generic_setlease
  vfs: make vfs_symlink break delegations on parent dir
  vfs: make vfs_mknod break delegations on parent directory
  vfs: make vfs_create break delegations on parent directory
  vfs: clean up argument list for vfs_create()
  vfs: break parent dir delegations in open(..., O_CREAT) codepath
  vfs: allow rmdir to wait for delegation break on parent
  vfs: allow mkdir to wait for delegation break on parent
  vfs: add try_break_deleg calls for parents to vfs_{link,rename,unlink}
  filelock: push the S_ISREG check down to ->setlease handlers
  filelock: add struct delegated_inode
  filelock: rework the __break_lease API to use flags
  filelock: make lease_alloc() take a flags argument

Link: https://patch.msgid.link/20251111-dir-deleg-ro-v6-0-52f3feebb2f2@kernel.org


Signed-off-by: default avatarChristian Brauner <brauner@kernel.org>
parents 3a866087 1602bad1
Loading
Loading
Loading
Loading
+3 −3
Original line number Diff line number Diff line
@@ -180,7 +180,7 @@ static int dev_mkdir(const char *name, umode_t mode)
	if (IS_ERR(dentry))
		return PTR_ERR(dentry);

	dentry = vfs_mkdir(&nop_mnt_idmap, d_inode(path.dentry), dentry, mode);
	dentry = vfs_mkdir(&nop_mnt_idmap, d_inode(path.dentry), dentry, mode, NULL);
	if (!IS_ERR(dentry))
		/* mark as kernel-created inode */
		d_inode(dentry)->i_private = &thread;
@@ -231,7 +231,7 @@ static int handle_create(const char *nodename, umode_t mode, kuid_t uid,
		return PTR_ERR(dentry);

	err = vfs_mknod(&nop_mnt_idmap, d_inode(path.dentry), dentry, mode,
			dev->devt);
			dev->devt, NULL);
	if (!err) {
		struct iattr newattrs;

@@ -261,7 +261,7 @@ static int dev_rmdir(const char *name)
		return PTR_ERR(dentry);
	if (d_inode(dentry)->i_private == &thread)
		err = vfs_rmdir(&nop_mnt_idmap, d_inode(parent.dentry),
				dentry);
				dentry, NULL);
	else
		err = -EPERM;

+1 −1
Original line number Diff line number Diff line
@@ -415,7 +415,7 @@ EXPORT_SYMBOL(may_setattr);
 * performed on the raw inode simply pass @nop_mnt_idmap.
 */
int notify_change(struct mnt_idmap *idmap, struct dentry *dentry,
		  struct iattr *attr, struct inode **delegated_inode)
		  struct iattr *attr, struct delegated_inode *delegated_inode)
{
	struct inode *inode = dentry->d_inode;
	umode_t mode = inode->i_mode;
+1 −1
Original line number Diff line number Diff line
@@ -130,7 +130,7 @@ struct dentry *cachefiles_get_directory(struct cachefiles_cache *cache,
			goto mkdir_error;
		ret = cachefiles_inject_write_error();
		if (ret == 0)
			subdir = vfs_mkdir(&nop_mnt_idmap, d_inode(dir), subdir, 0700);
			subdir = vfs_mkdir(&nop_mnt_idmap, d_inode(dir), subdir, 0700, NULL);
		else
			subdir = ERR_PTR(ret);
		if (IS_ERR(subdir)) {
+5 −6
Original line number Diff line number Diff line
@@ -188,8 +188,7 @@ ecryptfs_do_create(struct inode *directory_inode,

	rc = lock_parent(ecryptfs_dentry, &lower_dentry, &lower_dir);
	if (!rc)
		rc = vfs_create(&nop_mnt_idmap, lower_dir,
				lower_dentry, mode, true);
		rc = vfs_create(&nop_mnt_idmap, lower_dentry, mode, NULL);
	if (rc) {
		printk(KERN_ERR "%s: Failure to create dentry in lower fs; "
		       "rc = [%d]\n", __func__, rc);
@@ -480,7 +479,7 @@ static int ecryptfs_symlink(struct mnt_idmap *idmap,
	if (rc)
		goto out_lock;
	rc = vfs_symlink(&nop_mnt_idmap, lower_dir, lower_dentry,
			 encoded_symname);
			 encoded_symname, NULL);
	kfree(encoded_symname);
	if (rc || d_really_is_negative(lower_dentry))
		goto out_lock;
@@ -508,7 +507,7 @@ static struct dentry *ecryptfs_mkdir(struct mnt_idmap *idmap, struct inode *dir,
		goto out;

	lower_dentry = vfs_mkdir(&nop_mnt_idmap, lower_dir,
				 lower_dentry, mode);
				 lower_dentry, mode, NULL);
	rc = PTR_ERR(lower_dentry);
	if (IS_ERR(lower_dentry))
		goto out;
@@ -540,7 +539,7 @@ static int ecryptfs_rmdir(struct inode *dir, struct dentry *dentry)
		if (d_unhashed(lower_dentry))
			rc = -EINVAL;
		else
			rc = vfs_rmdir(&nop_mnt_idmap, lower_dir, lower_dentry);
			rc = vfs_rmdir(&nop_mnt_idmap, lower_dir, lower_dentry, NULL);
	}
	if (!rc) {
		clear_nlink(d_inode(dentry));
@@ -565,7 +564,7 @@ ecryptfs_mknod(struct mnt_idmap *idmap, struct inode *dir,
	rc = lock_parent(dentry, &lower_dentry, &lower_dir);
	if (!rc)
		rc = vfs_mknod(&nop_mnt_idmap, lower_dir,
			       lower_dentry, mode, dev);
			       lower_dentry, mode, dev, NULL);
	if (rc || d_really_is_negative(lower_dentry))
		goto out;
	rc = ecryptfs_interpose(lower_dentry, dentry, dir->i_sb);
+13 −0
Original line number Diff line number Diff line
@@ -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;
	}
Loading