From: Al Viro <viro@zeniv.linux.org.uk>
To: NeilBrown <neilb@suse.de>
Cc: Christian Brauner <brauner@kernel.org>, Jan Kara <jack@suse.cz>,
Linus Torvalds <torvalds@linux-foundation.org>,
Jeff Layton <jlayton@kernel.org>,
Dave Chinner <david@fromorbit.com>,
linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: Re: [PATCH 08/19] VFS: introduce lookup_and_lock() and friends
Date: Sat, 8 Feb 2025 23:18:19 +0000 [thread overview]
Message-ID: <20250208231819.GR1977892@ZenIV> (raw)
In-Reply-To: <20250207202235.GH1977892@ZenIV>
On Fri, Feb 07, 2025 at 08:22:35PM +0000, Al Viro wrote:
> On Thu, Feb 06, 2025 at 04:42:45PM +1100, NeilBrown wrote:
> > lookup_and_lock() combines locking the directory and performing a lookup
> > prior to a change to the directory.
> > Abstracting this prepares for changing the locking requirements.
> >
> > done_lookup_and_lock() provides the inverse of putting the dentry and
> > unlocking.
> >
> > For "silly_rename" we will need to lookup_and_lock() in a directory that
> > is already locked. For this purpose we add LOOKUP_PARENT_LOCKED.
>
> Ewww... I do realize that such things might appear in intermediate
> stages of locking massage, but they'd better be _GONE_ by the end of it.
> Conditional locking of that sort is really asking for trouble.
>
> If nothing else, better split the function in two variants and document
> the differences; that kind of stuff really does not belong in arguments.
> If you need it to exist through the series, that is - if not, you should
> just leave lookup_one_qstr() for the "locked" case from the very beginning.
The same, BTW, applies to more than LOOKUP_PARENT_LOCKED part.
One general observation: if the locking behaviour of a function depends
upon the flags passed to it, it's going to cause massive headache afterwards.
If you need to bother with data flow analysis to tell what given call will
do, expect trouble.
If anything, I would rather have separate lookup_for_removal(), etc., each
with its locking effects explicitly spelled out. Incidentally, looking
through that I would say that your "VFS: filename_create(): fix incorrect
intent" is not the right solution. If we hit that condition (no LOOKUP_DIRECTORY
and last component ending with slash), we are going to fail anyway, the only
question is which error to return. Rules:
* if the last component lookup fails, return the error from lookup
* if it yields positive, return -EEXIST
* if it yields negative, return -ENOENT
Correct? So how about this:
diff --git a/fs/namei.c b/fs/namei.c
index 3ab9440c5b93..6189e54f767a 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -4054,13 +4054,13 @@ static struct dentry *filename_create(int dfd, struct filename *name,
struct dentry *dentry = ERR_PTR(-EEXIST);
struct qstr last;
bool want_dir = lookup_flags & LOOKUP_DIRECTORY;
- unsigned int reval_flag = lookup_flags & LOOKUP_REVAL;
- unsigned int create_flags = LOOKUP_CREATE | LOOKUP_EXCL;
int type;
int err2;
int error;
- error = filename_parentat(dfd, name, reval_flag, path, &last, &type);
+ lookup_flags &= LOOKUP_REVAL;
+
+ error = filename_parentat(dfd, name, lookup_flags, path, &last, &type);
if (error)
return ERR_PTR(error);
@@ -4070,18 +4070,28 @@ static struct dentry *filename_create(int dfd, struct filename *name,
*/
if (unlikely(type != LAST_NORM))
goto out;
+ /*
+ * mkdir foo/bar/ is OK, but for anything else a slash in the end
+ * is always an error; the only question is which one.
+ */
+ if (unlikely(last.name[last.len] && !want_dir)) {
+ dentry = lookup_dcache(&last, path->dentry, lookup_flags);
+ if (!dentry)
+ dentry = lookup_slow(&last, path->dentry, lookup_flags);
+ if (!IS_ERR(dentry)) {
+ error = d_is_positive(dentry) ? -EEXIST : -ENOENT;
+ dput(dentry);
+ dentry = ERR_PTR(error);
+ }
+ goto out;
+ }
/* don't fail immediately if it's r/o, at least try to report other errors */
err2 = mnt_want_write(path->mnt);
- /*
- * Do the final lookup. Suppress 'create' if there is a trailing
- * '/', and a directory wasn't requested.
- */
- if (last.name[last.len] && !want_dir)
- create_flags = 0;
+ /* do the final lookup */
inode_lock_nested(path->dentry->d_inode, I_MUTEX_PARENT);
dentry = lookup_one_qstr_excl(&last, path->dentry,
- reval_flag | create_flags);
+ lookup_flags | LOOKUP_CREATE | LOOKUP_EXCL);
if (IS_ERR(dentry))
goto unlock;
@@ -4089,16 +4099,6 @@ static struct dentry *filename_create(int dfd, struct filename *name,
if (d_is_positive(dentry))
goto fail;
- /*
- * Special case - lookup gave negative, but... we had foo/bar/
- * From the vfs_mknod() POV we just have a negative dentry -
- * all is fine. Let's be bastards - you had / on the end, you've
- * been asking for (non-existent) directory. -ENOENT for you.
- */
- if (unlikely(!create_flags)) {
- error = -ENOENT;
- goto fail;
- }
if (unlikely(err2)) {
error = err2;
goto fail;
next prev parent reply other threads:[~2025-02-08 23:18 UTC|newest]
Thread overview: 83+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-02-06 5:42 [PATCH 00/19 v7?] RFC: Allow concurrent and async changes in a directory NeilBrown
2025-02-06 5:42 ` [PATCH 01/19] VFS: introduce vfs_mkdir_return() NeilBrown
2025-02-06 12:24 ` Christian Brauner
2025-02-06 23:52 ` NeilBrown
2025-02-06 13:52 ` Jeff Layton
2025-02-06 23:57 ` NeilBrown
2025-02-07 19:45 ` Al Viro
2025-02-10 4:36 ` NeilBrown
2025-02-06 5:42 ` [PATCH 02/19] VFS: use global wait-queue table for d_alloc_parallel() NeilBrown
2025-02-07 19:32 ` Al Viro
2025-02-10 4:58 ` NeilBrown
2025-02-10 5:15 ` Al Viro
2025-02-11 23:35 ` NeilBrown
2025-02-12 0:25 ` Al Viro
2025-02-12 1:46 ` NeilBrown
2025-02-06 5:42 ` [PATCH 03/19] VFS: use d_alloc_parallel() in lookup_one_qstr_excl() and rename it NeilBrown
2025-02-06 14:30 ` Jeff Layton
2025-02-07 0:04 ` NeilBrown
2025-02-07 0:23 ` Jeff Layton
2025-02-07 20:01 ` Al Viro
2025-02-06 5:42 ` [PATCH 04/19] VFS: change kern_path_locked() and user_path_locked_at() to never return negative dentry NeilBrown
2025-02-06 12:31 ` Christian Brauner
2025-02-06 13:09 ` Christian Brauner
2025-02-07 0:08 ` NeilBrown
2025-02-06 5:42 ` [PATCH 05/19] VFS: add common error checks to lookup_one_qstr() NeilBrown
2025-02-06 12:33 ` Christian Brauner
2025-02-07 20:14 ` Al Viro
2025-02-09 20:23 ` Al Viro
2025-02-06 5:42 ` [PATCH 06/19] VFS: repack DENTRY_ flags NeilBrown
2025-02-06 12:34 ` (subset) " Christian Brauner
2025-02-06 5:42 ` [PATCH 07/19] VFS: repack LOOKUP_ bit flags NeilBrown
2025-02-06 12:44 ` Christian Brauner
2025-02-07 0:24 ` NeilBrown
2025-02-06 12:54 ` (subset) " Christian Brauner
2025-02-06 5:42 ` [PATCH 08/19] VFS: introduce lookup_and_lock() and friends NeilBrown
2025-02-06 13:49 ` Christian Brauner
2025-02-07 1:28 ` NeilBrown
2025-02-07 20:22 ` Al Viro
2025-02-08 23:18 ` Al Viro [this message]
2025-02-12 5:22 ` NeilBrown
2025-02-12 15:51 ` Al Viro
2025-02-12 20:11 ` Al Viro
2025-02-12 4:49 ` NeilBrown
2025-02-06 5:42 ` [PATCH 09/19] VFS: add _async versions of the various directory modifying inode_operations NeilBrown
2025-02-06 13:15 ` Christian Brauner
2025-02-07 1:46 ` NeilBrown
2025-02-07 22:41 ` Al Viro
2025-02-09 1:09 ` Al Viro
2025-02-09 4:57 ` Al Viro
2025-02-06 5:42 ` [PATCH 10/19] VFS: introduce inode flags to report locking needs for directory ops NeilBrown
2025-02-06 13:22 ` Christian Brauner
2025-02-07 2:01 ` NeilBrown
2025-02-06 5:42 ` [PATCH 11/19] VFS: Add ability to exclusively lock a dentry and use for create/remove operations NeilBrown
2025-02-08 1:38 ` Al Viro
2025-02-09 6:40 ` Al Viro
2025-02-06 5:42 ` [PATCH 12/19] VFS: enhance d_splice_alias to accommodate shared-lock updates NeilBrown
2025-02-06 5:42 ` [PATCH 13/19] VFS: lock dentry for ->revalidate to avoid races with rename etc NeilBrown
2025-02-07 20:28 ` Al Viro
2025-02-07 20:35 ` Al Viro
2025-02-08 1:30 ` Al Viro
2025-02-08 1:35 ` Al Viro
2025-02-12 21:22 ` Al Viro
2025-02-06 5:42 ` [PATCH 14/19] VFS: Ensure no async updates happening in directory being removed NeilBrown
2025-02-06 14:06 ` Christian Brauner
2025-02-07 2:17 ` NeilBrown
2025-02-07 21:06 ` Al Viro
2025-02-08 22:06 ` Al Viro
2025-02-08 22:30 ` Linus Torvalds
2025-02-08 22:34 ` Linus Torvalds
2025-02-08 23:25 ` Al Viro
2025-02-06 5:42 ` [PATCH 15/19] VFS: Change lookup_and_lock() to use shared lock when possible NeilBrown
2025-02-06 5:42 ` [PATCH 16/19] VFS: add lookup_and_lock_rename() NeilBrown
2025-02-07 21:21 ` Al Viro
2025-02-06 5:42 ` [PATCH 17/19] nfsd: use lookup_and_lock_one() and lookup_and_lock_rename_one() NeilBrown
2025-02-06 5:42 ` [PATCH 18/19] nfs: change mkdir inode_operation to mkdir_async NeilBrown
2025-02-06 5:42 ` [PATCH 19/19] nfs: switch to _async for all directory ops NeilBrown
2025-02-13 3:51 ` Al Viro
2025-02-13 4:09 ` Al Viro
2025-02-13 18:01 ` Al Viro
2025-02-06 14:36 ` [PATCH 00/19 v7?] RFC: Allow concurrent and async changes in a directory Christian Brauner
2025-02-06 15:36 ` John Stoffel
2025-02-07 2:18 ` NeilBrown
2025-02-09 23:33 ` Al Viro
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20250208231819.GR1977892@ZenIV \
--to=viro@zeniv.linux.org.uk \
--cc=brauner@kernel.org \
--cc=david@fromorbit.com \
--cc=jack@suse.cz \
--cc=jlayton@kernel.org \
--cc=linux-fsdevel@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=neilb@suse.de \
--cc=torvalds@linux-foundation.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).