linux-um.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
From: "NeilBrown" <neil@brown.name>
To: "Al Viro" <viro@zeniv.linux.org.uk>
Cc: "Christian Brauner" <brauner@kernel.org>,
	"Jan Kara" <jack@suse.cz>, "David Howells" <dhowells@redhat.com>,
	"Marc Dionne" <marc.dionne@auristor.com>,
	"Xiubo Li" <xiubli@redhat.com>,
	"Ilya Dryomov" <idryomov@gmail.com>,
	"Tyler Hicks" <code@tyhicks.com>,
	"Miklos Szeredi" <miklos@szeredi.hu>,
	"Richard Weinberger" <richard@nod.at>,
	"Anton Ivanov" <anton.ivanov@cambridgegreys.com>,
	"Johannes Berg" <johannes@sipsolutions.net>,
	"Trond Myklebust" <trondmy@kernel.org>,
	"Anna Schumaker" <anna@kernel.org>,
	"Chuck Lever" <chuck.lever@oracle.com>,
	"Jeff Layton" <jlayton@kernel.org>,
	"Amir Goldstein" <amir73il@gmail.com>,
	"Steve French" <sfrench@samba.org>,
	"Namjae Jeon" <linkinjeon@kernel.org>,
	"Carlos Maiolino" <cem@kernel.org>,
	linux-fsdevel@vger.kernel.org, linux-afs@lists.infradead.org,
	netfs@lists.linux.dev, ceph-devel@vger.kernel.org,
	ecryptfs@vger.kernel.org, linux-um@lists.infradead.org,
	linux-nfs@vger.kernel.org, linux-unionfs@vger.kernel.org,
	linux-cifs@vger.kernel.org, linux-xfs@vger.kernel.org,
	linux-kernel@vger.kernel.org
Subject: Re: [PATCH 05/11] VFS: add rename_lookup()
Date: Wed, 13 Aug 2025 18:04:32 +1000	[thread overview]
Message-ID: <175507227245.2234665.4311084523419609794@noble.neil.brown.name> (raw)
In-Reply-To: <20250813043531.GB222315@ZenIV>

On Wed, 13 Aug 2025, Al Viro wrote:
> On Tue, Aug 12, 2025 at 12:25:08PM +1000, NeilBrown wrote:
> > rename_lookup() combines lookup and locking for a rename.
> > 
> > Two names - new_last and old_last - are added to struct renamedata so it
> > can be passed to rename_lookup() to have the old and new dentries filled
> > in.
> > 
> > __rename_lookup() in vfs-internal and assumes that the names are already
> > hashed and skips permission checking.  This is appropriate for use after
> > filename_parentat().
> > 
> > rename_lookup_noperm() does hash the name but avoids permission
> > checking.  This will be used by debugfs.
> 
> WTF would debugfs do anything of that sort?  Explain.  Unlike vfs_rename(),
> there we
> 	* are given the source dentry
> 	* are limited to pure name changes - same-directory only and
> target must not exist.
> 	* do not take ->s_vfs_rename_mutex
> 	...

Sure, debugfs_change_name() could have a simplified rename_lookup()
which doesn't just skip the perm checking but also skips other
s_vfs_rename_mutex etc.  But is there any value in creating a neutered
interface just because there is a case where all the functionality isn't
needed?

Or maybe I misunderstand your problem with rename_lookup_noperm().


> 
> > If either old_dentry or new_dentry are not NULL, the corresponding
> > "last" is ignored and the dentry is used as-is.  This provides similar
> > functionality to dentry_lookup_continue().  After locks are obtained we
> > check that the parent is still correct.  If old_parent was not given,
> > then it is set to the parent of old_dentry which was locked.  new_parent
> > must never be NULL.
> 
> That screams "bad API" to me...  Again, I want to see the users; you are
> asking to accept a semantics that smells really odd, and it's impossible
> to review without seeing the users.

There is a git tree you could pull.....

My API effectively supports both lock_rename() users and
lock_rename_child() users.  Maybe you want to preserve the two different
APIs.  I'd rather avoid the code duplication.

> 
> > On success new references are geld on old_dentry, new_dentry and old_parent.
> > 
> > done_rename_lookup() unlocks and drops those three references.
> > 
> > No __free() support is provided as done_rename_lookup() cannot be safely
> > called after rename_lookup() returns an error.
> > 
> > Signed-off-by: NeilBrown <neil@brown.name>
> > ---
> >  fs/namei.c            | 318 ++++++++++++++++++++++++++++++++++--------
> >  include/linux/fs.h    |   4 +
> >  include/linux/namei.h |   3 +
> >  3 files changed, 263 insertions(+), 62 deletions(-)
> > 
> > diff --git a/fs/namei.c b/fs/namei.c
> > index df21b6fa5a0e..cead810d53c6 100644
> > --- a/fs/namei.c
> > +++ b/fs/namei.c
> > @@ -3507,6 +3507,233 @@ void unlock_rename(struct dentry *p1, struct dentry *p2)
> >  }
> >  EXPORT_SYMBOL(unlock_rename);
> >  
> > +/**
> > + * __rename_lookup - lookup and lock names for rename
> > + * @rd:           rename data containing relevant details
> > + * @lookup_flags: extra flags to pass to ->lookup (e.g. LOOKUP_REVAL,
> > + *                LOOKUP_NO_SYMLINKS etc).
> > + *
> > + * Optionally look up two names and ensure locks are in place for
> > + * rename.
> > + * Normally @rd.old_dentry and @rd.new_dentry are %NULL and the
> > + * old and new directories and last names are given in @rd.  In this
> > + * case the names are looked up with appropriate locking and the
> > + * results stored in @rd.old_dentry and @rd.new_dentry.
> > + *
> > + * If either are not NULL, then the corresponding lookup is avoided but
> > + * the required locks are still taken.  In this case @rd.old_parent may
> > + * be %NULL, otherwise @rd.old_dentry must still have @rd.old_parent as
> > + * its d_parent after the locks are obtained.  @rd.new_parent must
> > + * always be non-NULL, and must always be the correct parent after
> > + * locking.
> > + *
> > + * On success a reference is held on @rd.old_dentry, @rd.new_dentry,
> > + * and @rd.old_parent whether they were originally %NULL or not.  These
> > + * references are dropped by done_rename_lookup().  @rd.new_parent
> > + * must always be non-NULL and no extra reference is taken.
> > + *
> > + * The passed in qstrs must have the hash calculated, and no permission
> > + * checking is performed.
> > + *
> > + * Returns: zero or an error.
> > + */
> > +static int
> > +__rename_lookup(struct renamedata *rd, int lookup_flags)
> > +{
> > +	struct dentry *p;
> > +	struct dentry *d1, *d2;
> > +	int target_flags = LOOKUP_RENAME_TARGET | LOOKUP_CREATE;
> > +	int err;
> > +
> > +	if (rd->flags & RENAME_EXCHANGE)
> > +		target_flags = 0;
> > +	if (rd->flags & RENAME_NOREPLACE)
> > +		target_flags |= LOOKUP_EXCL;
> > +
> > +	if (rd->old_dentry) {
> > +		/* Already have the dentry - need to be sure to lock the correct parent */
> > +		p = lock_rename_child(rd->old_dentry, rd->new_parent);
> > +		if (IS_ERR(p))
> > +			return PTR_ERR(p);
> > +		if (d_unhashed(rd->old_dentry) ||
> > +		    (rd->old_parent && rd->old_parent != rd->old_dentry->d_parent)) {
> > +			/* dentry was removed, or moved and explicit parent requested */
> > +			unlock_rename(rd->old_dentry->d_parent, rd->new_parent);
> > +			return -EINVAL;
> > +		}
> > +		rd->old_parent = dget(rd->old_dentry->d_parent);
> > +		d1 = dget(rd->old_dentry);
> > +	} else {
> > +		p = lock_rename(rd->old_parent, rd->new_parent);
> > +		if (IS_ERR(p))
> > +			return PTR_ERR(p);
> > +		dget(rd->old_parent);
> > +
> > +		d1 = lookup_one_qstr_excl(&rd->old_last, rd->old_parent,
> > +					  lookup_flags);
> > +		if (IS_ERR(d1))
> > +			goto out_unlock_1;
> > +	}
> > +	if (rd->new_dentry) {
> > +		if (d_unhashed(rd->new_dentry) ||
> > +		    rd->new_dentry->d_parent != rd->new_parent) {
> > +			/* new_dentry was moved or removed! */
> > +			goto out_unlock_2;
> > +		}
> > +		d2 = dget(rd->new_dentry);
> > +	} else {
> > +		d2 = lookup_one_qstr_excl(&rd->new_last, rd->new_parent,
> > +					  lookup_flags | target_flags);
> > +		if (IS_ERR(d2))
> > +			goto out_unlock_2;
> > +	}
> > +
> > +	if (d1 == p) {
> > +		/* source is an ancestor of target */
> > +		err = -EINVAL;
> > +		goto out_unlock_3;
> > +	}
> > +
> > +	if (d2 == p) {
> > +		/* target is an ancestor of source */
> > +		if (rd->flags & RENAME_EXCHANGE)
> > +			err = -EINVAL;
> > +		else
> > +			err = -ENOTEMPTY;
> > +		goto out_unlock_3;
> > +	}
> > +
> > +	rd->old_dentry = d1;
> > +	rd->new_dentry = d2;
> > +	return 0;
> > +
> > +out_unlock_3:
> > +	dput(d2);
> > +	d2 = ERR_PTR(err);
> > +out_unlock_2:
> > +	dput(d1);
> > +	d1 = d2;
> > +out_unlock_1:
> > +	unlock_rename(rd->old_parent, rd->new_parent);
> > +	dput(rd->old_parent);
> > +	return PTR_ERR(d1);
> > +}
> 
> This is too fucking ugly to live, IMO.  Too many things are mixed into it.
> I will NAK that until I get a chance to see the users of all that stuff.
> Sorry.
> 

Can you say more about what you think it ugly?

Are you OK with combining the lookup and the locking in the one
function?
Are you OK with passing a 'struct rename_data' rather than a list of
assorted args?
Are you OK with deducing the target flags in this function, or do you
want them explicitly passed in?
Is it just that the function can use with lock_rename or
lock_rename_child depending on context?

???

Thanks,
NeilBrown


  reply	other threads:[~2025-08-13  8:18 UTC|newest]

Thread overview: 38+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-08-12  2:25 [PATCH 00/11] VFS: prepare for changes to directory locking NeilBrown
2025-08-12  2:25 ` [PATCH 01/11] VFS: discard err2 in filename_create() NeilBrown
2025-08-13  3:22   ` Al Viro
2025-08-12  2:25 ` [PATCH 02/11] VFS: introduce dentry_lookup() and friends NeilBrown
2025-08-13  4:12   ` Al Viro
2025-08-13  7:48     ` NeilBrown
2025-08-12  2:25 ` [PATCH 03/11] VFS: add dentry_lookup_killable() NeilBrown
2025-08-13  4:15   ` Al Viro
2025-08-13  7:50     ` NeilBrown
2025-08-12  2:25 ` [PATCH 04/11] VFS: introduce dentry_lookup_continue() NeilBrown
2025-08-13  4:22   ` Al Viro
2025-08-13  7:53     ` NeilBrown
2025-08-18 12:39   ` Amir Goldstein
2025-08-18 21:52     ` NeilBrown
2025-08-19  8:37       ` Amir Goldstein
2025-08-12  2:25 ` [PATCH 05/11] VFS: add rename_lookup() NeilBrown
2025-08-13  4:35   ` Al Viro
2025-08-13  8:04     ` NeilBrown [this message]
2025-08-14  1:40       ` Al Viro
2025-08-12  2:25 ` [PATCH 06/11] VFS: unify old_mnt_idmap and new_mnt_idmap in renamedata NeilBrown
2025-08-13  4:36   ` Al Viro
2025-08-12  2:25 ` [PATCH 07/11] VFS: Change vfs_mkdir() to unlock on failure NeilBrown
2025-08-13  7:22   ` Amir Goldstein
2025-08-14  1:13     ` NeilBrown
2025-08-14 13:29       ` Amir Goldstein
2025-08-12  2:25 ` [PATCH 08/11] VFS: allow d_splice_alias() and d_add() to work on hashed dentries NeilBrown
2025-08-13  5:07   ` Al Viro
2025-08-12  2:25 ` [PATCH 09/11] VFS: use global wait-queue table for d_alloc_parallel() NeilBrown
2025-08-13  6:44   ` Al Viro
2025-08-14  1:31     ` NeilBrown
2025-08-12  2:25 ` [PATCH 10/11] VFS: use d_alloc_parallel() in lookup_one_qstr_excl() NeilBrown
2025-08-13  5:19   ` Al Viro
2025-08-14  0:56     ` NeilBrown
2025-08-12  2:25 ` [PATCH 11/11] VFS: introduce d_alloc_noblock() and d_alloc_locked() NeilBrown
2025-08-13  6:53   ` Al Viro
2025-08-14  2:07     ` NeilBrown
2025-08-14 13:47       ` Amir Goldstein
2025-08-13  0:01 ` [PATCH 00/11] VFS: prepare for changes to directory locking 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=175507227245.2234665.4311084523419609794@noble.neil.brown.name \
    --to=neil@brown.name \
    --cc=amir73il@gmail.com \
    --cc=anna@kernel.org \
    --cc=anton.ivanov@cambridgegreys.com \
    --cc=brauner@kernel.org \
    --cc=cem@kernel.org \
    --cc=ceph-devel@vger.kernel.org \
    --cc=chuck.lever@oracle.com \
    --cc=code@tyhicks.com \
    --cc=dhowells@redhat.com \
    --cc=ecryptfs@vger.kernel.org \
    --cc=idryomov@gmail.com \
    --cc=jack@suse.cz \
    --cc=jlayton@kernel.org \
    --cc=johannes@sipsolutions.net \
    --cc=linkinjeon@kernel.org \
    --cc=linux-afs@lists.infradead.org \
    --cc=linux-cifs@vger.kernel.org \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-nfs@vger.kernel.org \
    --cc=linux-um@lists.infradead.org \
    --cc=linux-unionfs@vger.kernel.org \
    --cc=linux-xfs@vger.kernel.org \
    --cc=marc.dionne@auristor.com \
    --cc=miklos@szeredi.hu \
    --cc=netfs@lists.linux.dev \
    --cc=richard@nod.at \
    --cc=sfrench@samba.org \
    --cc=trondmy@kernel.org \
    --cc=viro@zeniv.linux.org.uk \
    --cc=xiubli@redhat.com \
    /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).