Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c94c0953 authored by Al Viro's avatar Al Viro
Browse files

nfs_atomic_open(): prevent parallel nfs_lookup() on a negative hashed



Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent 00699ad8
Loading
Loading
Loading
Loading
+25 −3
Original line number Diff line number Diff line
@@ -1485,11 +1485,13 @@ int nfs_atomic_open(struct inode *dir, struct dentry *dentry,
		    struct file *file, unsigned open_flags,
		    umode_t mode, int *opened)
{
	DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq);
	struct nfs_open_context *ctx;
	struct dentry *res;
	struct iattr attr = { .ia_valid = ATTR_OPEN };
	struct inode *inode;
	unsigned int lookup_flags = 0;
	bool switched = false;
	int err;

	/* Expect a negative dentry */
@@ -1528,6 +1530,17 @@ int nfs_atomic_open(struct inode *dir, struct dentry *dentry,
		attr.ia_size = 0;
	}

	if (!(open_flags & O_CREAT) && !d_in_lookup(dentry)) {
		d_drop(dentry);
		switched = true;
		dentry = d_alloc_parallel(dentry->d_parent,
					  &dentry->d_name, &wq);
		if (IS_ERR(dentry))
			return PTR_ERR(dentry);
		if (unlikely(!d_in_lookup(dentry)))
			return finish_no_open(file, dentry);
	}

	ctx = create_nfs_open_context(dentry, open_flags);
	err = PTR_ERR(ctx);
	if (IS_ERR(ctx))
@@ -1563,14 +1576,23 @@ int nfs_atomic_open(struct inode *dir, struct dentry *dentry,
	trace_nfs_atomic_open_exit(dir, ctx, open_flags, err);
	put_nfs_open_context(ctx);
out:
	if (unlikely(switched)) {
		d_lookup_done(dentry);
		dput(dentry);
	}
	return err;

no_open:
	res = nfs_lookup(dir, dentry, lookup_flags);
	err = PTR_ERR(res);
	if (switched) {
		d_lookup_done(dentry);
		if (!res)
			res = dentry;
		else
			dput(dentry);
	}
	if (IS_ERR(res))
		goto out;

		return PTR_ERR(res);
	return finish_no_open(file, res);
}
EXPORT_SYMBOL_GPL(nfs_atomic_open);