* [RFC] dentry->d_flags locking
@ 2025-02-24 1:06 Al Viro
2025-02-24 1:38 ` Al Viro
` (2 more replies)
0 siblings, 3 replies; 87+ messages in thread
From: Al Viro @ 2025-02-24 1:06 UTC (permalink / raw)
To: linux-fsdevel
Cc: Linus Torvalds, Neil Brown, Miklos Szeredi, Christian Brauner,
Jan Kara
Recently I went looking through the ->d_flags locking (long
story, that was a side branch in digging through the issues with
Neil's locking scheme); results are interesting.
All stores to dentry->d_flags are done by somebody who
* holds a counting reference to dentry or
* has found a counting reference in shared data structures, in
conditions that guarantee that this reference won't go away or
* has found dentry in alias list of some inode (under ->i_lock)
* [fs/dcache.c only] is an LRU walker callback running into that dentry
in LRU list or
* [fs/dcache.c only] is owner of a shrink list running into dentry in that
list or
* [fs/dcache.c only] is a d_walk() callback running into that dentry with zero
refcount (and moving it to shrink list) or
* [fs/dcache.c only] is a d_walk() called by kill_litter_super() running into
that dentry when unpinning theretofore persistent dentries; that can happen
only during filesystem shutdown, when nobody else could be accessing it.
The above guarantees that dentry won't disappear under us;
another interesting thing is exclusion, and that's where the things
get nasty. Most of the stores to dentry->d_flags are under
dentry->d_lock. There are obvious exceptions on the allocation side
(stores done to dentry that is not visible to anybody else), but aside
of those there are two exceptions.
One is d_set_d_op(), another - setting DCACHE_PAR_LOOKUP in
d_alloc_parallel().
The former sets ->d_op and marks the presense of several methods
(->d_hash(), ->d_compare(), ->d_revalidate(), ->d_weak_revalidate(),
->d_delete(), ->d_prune() and ->d_real()) in ->d_flags.
It can't be done more than once and, if the filesystem
has ->s_d_op set in its superblock, it is done by the constructor
(__d_alloc()). That, obviously, falls under the "on allocation side";
so does another common case - d_alloc_pseudo() setting ->d_op to &anon_ops
if __d_alloc() hadn't set it to ->s_d_op.
Note that there's no barriers between the stores to ->d_op and
->d_flags in d_set_d_op(); for allocation time uses that's not a problem -
fetches on another CPU would have to be preceded by finding the dentry
in the first place, and barriers on the insertion into wherever it
had been found would suffice.
There are other callers of d_set_d_op(), though - one in
simple_lookup() (again, if ->s_d_op is NULL) and the rest are all in
procfs. Those are done with no locking whatsoever and dentry is *not*
entirely invisible.
It's mostly invisible, though - in all those cases dentry is
* negative, and thus unreachable via the alias list of any inode
* unhashed, and thus can't be found via dcache lookup
* has the only direct reference held by the caller who has been holding
it since it got allocated (i.e. it couldn't have been put into LRU or
shrink lists either).
That is enough to guarantee that nobody else will be doing stores
to ->d_flags, so our store is safe even without ->d_lock. It is also
fucking ugly and brittle...
Moreover, the question about ->d_op vs ->d_flags ordering also
needs to be dealt with - unlike the calls at allocation time, insertion
into wherever it had been found does *not* order fetches past both
stores - not if it had been inserted into that wherever before the
call of d_set_d_op().
Thankfully, the set of methods present in dentry_operations
ever fed to those late calls of d_set_d_op() is limited: ->d_revalidate,
->d_delete and, in one case, ->d_compare.
->d_delete() is easy - it's called only from one place (retain_dentry())
and there we have just dropped the last reference to dentry in question.
Since the caller of d_set_d_op() is holding a reference, the usual barriers
on ->d_reflock use are enough.
->d_compare() is a bit confusing - dentry it's getting as argument
is not the one whose method it is. We have the parent (already observed
to be positive) and we are checking if this child (with ->d_parent pointing
to parent) matches the name we want to look up. We take parent's
->d_compare() and give it child dentry, snapshot of child's name and the
name we want to match it against.
We *CAN* get a dentry in the middle of d_set_d_op() passed to
someone's ->d_compare() - d_alloc_parent() does that to check if there's
an in-lookup dentry matching the name we want. But ->d_compare() comes
from parent, and that had been already observed to be positive. Which means
that barriers in __d_set_inode_and_type() (from d_splice_alias()) suffice.
->d_revalidate() is only called for dentries that had been found
in dcache hash chains at some point, so there the barrier on insertion into
hash (in __d_add() from d_splice_alias()) is enough.
That covers d_set_d_op() callers; another exception is
d_alloc_parallel() when it decides to insert a new dentry into in-lookup
hash and marks it with DCACHE_PAR_LOOKUP. Also safe, since dentry is
only visible in the parent's list of children, has positive refcount and
had it all along, so nobody else would try to do a store to ->d_flags
at the same time.
In case it's not obvious from the above, I'm less than happy with
the entire thing - it may be provably correct, but it's much too brittle.
If nothing else, d_set_d_op() should be unexported. Do it to
a hashed or, worse, a positive dentry and you are asking for serious
trouble. Leaving it as a public API is a really bad idea.
Something along the lines of d_splice_alias_ops(inode, dentry, ops)
(not exported, until we get a convincing modular user) is worth doing;
all procfs callers of d_set_d_op() follow it with d_splice_alias() pretty
much immediately. And yes, that could be done under ->d_lock, eliminating
that special case from the proof.
As for the allocation-time uses... We could bloody well calculate
the ->d_flags bits to go along with ->s_d_op and just use that; it's not
just about getting rid of recalculating them for each dentry ever allocated
on the filesystem in question, we could get rid of quite a few always_delete_dentry
users while we are at it.
Look: ->d_delete == always_delete_dentry (and DCACHE_OP_DELETE to
go with it) is equivalent to DCACHE_DONTCACHE; the only place where we
look at either is retain_dentry(), where we have this:
// ->d_delete() might tell us not to bother, but that requires
// ->d_lock; can't decide without it
if (unlikely(d_flags & DCACHE_OP_DELETE)) {
if (!locked || dentry->d_op->d_delete(dentry))
return false;
}
// Explicitly told not to bother
if (unlikely(d_flags & DCACHE_DONTCACHE))
return false;
The inner if turns into
if (!locked || 1)
return false;
so for those DCACHE_DONTCACHE would be equivalent. And it could be
put into the same "set those bits in all ->d_flags on that fs";
what's more, simple_lookup() doesn't need to set ->d_op at all -
it can just set DCACHE_DONTCACHE in the unlikely case when it's
not been already set.
How about something along the lines of
0) add d_splice_alias_ops(inode, dentry, dops), have procfs switch
to that.
1) provide set_default_d_op(superblock, dops), use it in place of
assignments to ->s_d_op. Rename ->s_d_op to catch unconverted
filesystems. Tree-wide, entirely mechanical.
2) split the calculation of d_flags bits into a separate helper,
add ->s_d_flags, have set_default_d_op() calculate and set
that, have __d_alloc() pick ->s_d_op and ->s_d_flags directly.
3) convert those who wish to move from use of always_delete_dentry
to adding DCACHE_DONTCACHE into ->s_d_flags. For devpts, for
example, that avoids the need of non-NULL ->d_op.
4) replace d_set_d_op() in simple_lookup() with
if (unlikely(!(dentry->d_flags & DCACHE_DONTCACHE))) {
spin_lock(&dentry->d_lock);
dentry->d_flags |= DCACHE_DONTCACHE;
spin_unlock(&dentry->d_lock);
}
5) Kill simple_dentry_operations - no users would be left
6) make d_set_d_op() static in fs/dcache.c
I'll put together something along those lines and post it
later today.
With that done, the last remaining store to ->d_flags without
->d_lock would be in d_alloc_parallel(); it can be killed off
(we could set it in new->d_flags before anyone sees that
dentry), the only reason I'd left that to actual insertion
into in-lookup hash chain is that DCACHE_PAR_LOOKUP currently
corresponds to "it's in in-lookup hash, what would've been
->d_alias is occupied by that hash chain" and at some point
I think we had final dput() scream bloody murder if it saw
such a dentry.
Hell knows... d_alloc_parallel() is going to be heavily affected
by any locking reworks; what should be done with that wart
depends upon the direction we take for that work.
PS: turns out that set_default_d_op() is slightly more interesting
than I expected - fuse has separate dentry_operations for its
root dentry. I don't see the point, TBH - the only difference is
that root one lacks
* ->d_delete() (never even called for root dentry; it's
only called if d_unhashed() is false)
* ->d_revalidate() (never called for root)
* ->d_automount() (not even looked at unless you have
S_AUTOMOUNT set on the inode).
What's wrong with using fuse_dentry_operations for root dentry?
Am I missing something subtle here? Miklos?
^ permalink raw reply [flat|nested] 87+ messages in thread
* Re: [RFC] dentry->d_flags locking
2025-02-24 1:06 [RFC] dentry->d_flags locking Al Viro
@ 2025-02-24 1:38 ` Al Viro
2025-02-24 10:35 ` Christian Brauner
2025-02-24 11:45 ` Christian Brauner
2025-02-24 14:07 ` [RFC] " Miklos Szeredi
2 siblings, 1 reply; 87+ messages in thread
From: Al Viro @ 2025-02-24 1:38 UTC (permalink / raw)
To: linux-fsdevel
Cc: Linus Torvalds, Neil Brown, Miklos Szeredi, Christian Brauner,
Jan Kara
On Mon, Feb 24, 2025 at 01:06:24AM +0000, Al Viro wrote:
> PS: turns out that set_default_d_op() is slightly more interesting
> than I expected - fuse has separate dentry_operations for its
> root dentry. I don't see the point, TBH - the only difference is
> that root one lacks
> * ->d_delete() (never even called for root dentry; it's
> only called if d_unhashed() is false)
> * ->d_revalidate() (never called for root)
> * ->d_automount() (not even looked at unless you have
> S_AUTOMOUNT set on the inode).
> What's wrong with using fuse_dentry_operations for root dentry?
> Am I missing something subtle here? Miklos?
Speaking of fun questions - does pidfs_dentry_operations need
->d_delete()? I mean, it's not even called for unhashed
dentries and AFAICS there's no way for those to be hashed...
The same goes for all filesystems created by init_pseudo().
Is there any reason to have that in pidfs_dentry_operations and
ns_dentry_operations?
I think nsfs is my sloppiness back then - original commit message
explicitly says that neither dentries nor inodes in that thing
are ever hashed, so ->d_delete() had been clearly pointless
from the very beginning.
Christian, pidfs looks like it just had copied that from nsfs.
Is there something subtle about pidfs that makes ->d_delete()
needed there?
^ permalink raw reply [flat|nested] 87+ messages in thread
* Re: [RFC] dentry->d_flags locking
2025-02-24 1:38 ` Al Viro
@ 2025-02-24 10:35 ` Christian Brauner
2025-02-24 14:14 ` Al Viro
0 siblings, 1 reply; 87+ messages in thread
From: Christian Brauner @ 2025-02-24 10:35 UTC (permalink / raw)
To: Al Viro; +Cc: linux-fsdevel, Linus Torvalds, Neil Brown, Miklos Szeredi,
Jan Kara
On Mon, Feb 24, 2025 at 01:38:44AM +0000, Al Viro wrote:
> On Mon, Feb 24, 2025 at 01:06:24AM +0000, Al Viro wrote:
>
> > PS: turns out that set_default_d_op() is slightly more interesting
> > than I expected - fuse has separate dentry_operations for its
> > root dentry. I don't see the point, TBH - the only difference is
> > that root one lacks
> > * ->d_delete() (never even called for root dentry; it's
> > only called if d_unhashed() is false)
> > * ->d_revalidate() (never called for root)
> > * ->d_automount() (not even looked at unless you have
> > S_AUTOMOUNT set on the inode).
> > What's wrong with using fuse_dentry_operations for root dentry?
> > Am I missing something subtle here? Miklos?
>
> Speaking of fun questions - does pidfs_dentry_operations need
> ->d_delete()? I mean, it's not even called for unhashed
> dentries and AFAICS there's no way for those to be hashed...
> The same goes for all filesystems created by init_pseudo().
>
> Is there any reason to have that in pidfs_dentry_operations and
> ns_dentry_operations?
>
> I think nsfs is my sloppiness back then - original commit message
> explicitly says that neither dentries nor inodes in that thing
> are ever hashed, so ->d_delete() had been clearly pointless
> from the very beginning.
>
> Christian, pidfs looks like it just had copied that from nsfs.
> Is there something subtle about pidfs that makes ->d_delete()
> needed there?
No, I don't think so. I put patches on top of vfs.fixes that remove it
for both pidfs and nsfs. Thanks!
The fact that hashing a dentry happens during lookup and that I didn't
even have to think about lookup for pidfs and nsfs because they don't
matter probably just led to carrying this over for pidfs.
I think it would be worthwhile to mark dentries of such filesystems as
always unhashed and then add an assert into fs/dcache.c whenever such a
dentry should suddenly become hashed.
That would not just make it very easy to see for the reviewer that the
dentries of this filesystem are always unhashed it would also make it
possible to spot bugs.
^ permalink raw reply [flat|nested] 87+ messages in thread
* Re: [RFC] dentry->d_flags locking
2025-02-24 1:06 [RFC] dentry->d_flags locking Al Viro
2025-02-24 1:38 ` Al Viro
@ 2025-02-24 11:45 ` Christian Brauner
2025-06-11 7:50 ` [RFC][PATCHES v2] " Al Viro
2025-02-24 14:07 ` [RFC] " Miklos Szeredi
2 siblings, 1 reply; 87+ messages in thread
From: Christian Brauner @ 2025-02-24 11:45 UTC (permalink / raw)
To: Al Viro; +Cc: linux-fsdevel, Linus Torvalds, Neil Brown, Miklos Szeredi,
Jan Kara
On Mon, Feb 24, 2025 at 01:06:24AM +0000, Al Viro wrote:
> Recently I went looking through the ->d_flags locking (long
> story, that was a side branch in digging through the issues with
> Neil's locking scheme); results are interesting.
>
> All stores to dentry->d_flags are done by somebody who
> * holds a counting reference to dentry or
> * has found a counting reference in shared data structures, in
> conditions that guarantee that this reference won't go away or
> * has found dentry in alias list of some inode (under ->i_lock)
> * [fs/dcache.c only] is an LRU walker callback running into that dentry
> in LRU list or
> * [fs/dcache.c only] is owner of a shrink list running into dentry in that
> list or
> * [fs/dcache.c only] is a d_walk() callback running into that dentry with zero
> refcount (and moving it to shrink list) or
> * [fs/dcache.c only] is a d_walk() called by kill_litter_super() running into
> that dentry when unpinning theretofore persistent dentries; that can happen
> only during filesystem shutdown, when nobody else could be accessing it.
>
> The above guarantees that dentry won't disappear under us;
> another interesting thing is exclusion, and that's where the things
> get nasty. Most of the stores to dentry->d_flags are under
> dentry->d_lock. There are obvious exceptions on the allocation side
> (stores done to dentry that is not visible to anybody else), but aside
> of those there are two exceptions.
>
> One is d_set_d_op(), another - setting DCACHE_PAR_LOOKUP in
> d_alloc_parallel().
>
> The former sets ->d_op and marks the presense of several methods
> (->d_hash(), ->d_compare(), ->d_revalidate(), ->d_weak_revalidate(),
> ->d_delete(), ->d_prune() and ->d_real()) in ->d_flags.
>
> It can't be done more than once and, if the filesystem
> has ->s_d_op set in its superblock, it is done by the constructor
> (__d_alloc()). That, obviously, falls under the "on allocation side";
> so does another common case - d_alloc_pseudo() setting ->d_op to &anon_ops
> if __d_alloc() hadn't set it to ->s_d_op.
>
> Note that there's no barriers between the stores to ->d_op and
> ->d_flags in d_set_d_op(); for allocation time uses that's not a problem -
> fetches on another CPU would have to be preceded by finding the dentry
> in the first place, and barriers on the insertion into wherever it
> had been found would suffice.
>
> There are other callers of d_set_d_op(), though - one in
> simple_lookup() (again, if ->s_d_op is NULL) and the rest are all in
> procfs. Those are done with no locking whatsoever and dentry is *not*
> entirely invisible.
>
> It's mostly invisible, though - in all those cases dentry is
> * negative, and thus unreachable via the alias list of any inode
> * unhashed, and thus can't be found via dcache lookup
> * has the only direct reference held by the caller who has been holding
> it since it got allocated (i.e. it couldn't have been put into LRU or
> shrink lists either).
>
> That is enough to guarantee that nobody else will be doing stores
> to ->d_flags, so our store is safe even without ->d_lock. It is also
> fucking ugly and brittle...
>
> Moreover, the question about ->d_op vs ->d_flags ordering also
> needs to be dealt with - unlike the calls at allocation time, insertion
> into wherever it had been found does *not* order fetches past both
> stores - not if it had been inserted into that wherever before the
> call of d_set_d_op().
>
> Thankfully, the set of methods present in dentry_operations
> ever fed to those late calls of d_set_d_op() is limited: ->d_revalidate,
> ->d_delete and, in one case, ->d_compare.
>
> ->d_delete() is easy - it's called only from one place (retain_dentry())
> and there we have just dropped the last reference to dentry in question.
> Since the caller of d_set_d_op() is holding a reference, the usual barriers
> on ->d_reflock use are enough.
>
> ->d_compare() is a bit confusing - dentry it's getting as argument
> is not the one whose method it is. We have the parent (already observed
> to be positive) and we are checking if this child (with ->d_parent pointing
> to parent) matches the name we want to look up. We take parent's
> ->d_compare() and give it child dentry, snapshot of child's name and the
> name we want to match it against.
> We *CAN* get a dentry in the middle of d_set_d_op() passed to
> someone's ->d_compare() - d_alloc_parent() does that to check if there's
> an in-lookup dentry matching the name we want. But ->d_compare() comes
> from parent, and that had been already observed to be positive. Which means
> that barriers in __d_set_inode_and_type() (from d_splice_alias()) suffice.
>
> ->d_revalidate() is only called for dentries that had been found
> in dcache hash chains at some point, so there the barrier on insertion into
> hash (in __d_add() from d_splice_alias()) is enough.
>
> That covers d_set_d_op() callers; another exception is
> d_alloc_parallel() when it decides to insert a new dentry into in-lookup
> hash and marks it with DCACHE_PAR_LOOKUP. Also safe, since dentry is
> only visible in the parent's list of children, has positive refcount and
> had it all along, so nobody else would try to do a store to ->d_flags
> at the same time.
>
> In case it's not obvious from the above, I'm less than happy with
> the entire thing - it may be provably correct, but it's much too brittle.
>
> If nothing else, d_set_d_op() should be unexported. Do it to
Agreed.
> a hashed or, worse, a positive dentry and you are asking for serious
> trouble. Leaving it as a public API is a really bad idea.
>
> Something along the lines of d_splice_alias_ops(inode, dentry, ops)
> (not exported, until we get a convincing modular user) is worth doing;
> all procfs callers of d_set_d_op() follow it with d_splice_alias() pretty
> much immediately. And yes, that could be done under ->d_lock, eliminating
> that special case from the proof.
That sounds great.
>
> As for the allocation-time uses... We could bloody well calculate
> the ->d_flags bits to go along with ->s_d_op and just use that; it's not
> just about getting rid of recalculating them for each dentry ever allocated
> on the filesystem in question, we could get rid of quite a few always_delete_dentry
> users while we are at it.
See my reply to your other mail: I'll kill it for pidfs and nsfs.
>
> Look: ->d_delete == always_delete_dentry (and DCACHE_OP_DELETE to
> go with it) is equivalent to DCACHE_DONTCACHE; the only place where we
Also mentioned in my other reply: Can you please make the unhashed case
really explicit ideally at dentry allocation time. IOW, that there's a
flag or some other way of simply identifying a dentry as belonging to an
fs that will never hash them?
> look at either is retain_dentry(), where we have this:
> // ->d_delete() might tell us not to bother, but that requires
> // ->d_lock; can't decide without it
> if (unlikely(d_flags & DCACHE_OP_DELETE)) {
> if (!locked || dentry->d_op->d_delete(dentry))
> return false;
> }
>
> // Explicitly told not to bother
> if (unlikely(d_flags & DCACHE_DONTCACHE))
> return false;
> The inner if turns into
> if (!locked || 1)
> return false;
> so for those DCACHE_DONTCACHE would be equivalent. And it could be
> put into the same "set those bits in all ->d_flags on that fs";
> what's more, simple_lookup() doesn't need to set ->d_op at all -
> it can just set DCACHE_DONTCACHE in the unlikely case when it's
> not been already set.
>
> How about something along the lines of
> 0) add d_splice_alias_ops(inode, dentry, dops), have procfs switch
> to that.
> 1) provide set_default_d_op(superblock, dops), use it in place of
> assignments to ->s_d_op. Rename ->s_d_op to catch unconverted
> filesystems. Tree-wide, entirely mechanical.
> 2) split the calculation of d_flags bits into a separate helper,
> add ->s_d_flags, have set_default_d_op() calculate and set
> that, have __d_alloc() pick ->s_d_op and ->s_d_flags directly.
> 3) convert those who wish to move from use of always_delete_dentry
> to adding DCACHE_DONTCACHE into ->s_d_flags. For devpts, for
> example, that avoids the need of non-NULL ->d_op.
> 4) replace d_set_d_op() in simple_lookup() with
> if (unlikely(!(dentry->d_flags & DCACHE_DONTCACHE))) {
> spin_lock(&dentry->d_lock);
> dentry->d_flags |= DCACHE_DONTCACHE;
> spin_unlock(&dentry->d_lock);
> }
> 5) Kill simple_dentry_operations - no users would be left
> 6) make d_set_d_op() static in fs/dcache.c
Sounds good.
^ permalink raw reply [flat|nested] 87+ messages in thread
* Re: [RFC] dentry->d_flags locking
2025-02-24 1:06 [RFC] dentry->d_flags locking Al Viro
2025-02-24 1:38 ` Al Viro
2025-02-24 11:45 ` Christian Brauner
@ 2025-02-24 14:07 ` Miklos Szeredi
2025-02-25 17:56 ` Al Viro
2 siblings, 1 reply; 87+ messages in thread
From: Miklos Szeredi @ 2025-02-24 14:07 UTC (permalink / raw)
To: Al Viro
Cc: linux-fsdevel, Linus Torvalds, Neil Brown, Christian Brauner,
Jan Kara
On Mon, 24 Feb 2025 at 02:06, Al Viro <viro@zeniv.linux.org.uk> wrote:
> PS: turns out that set_default_d_op() is slightly more interesting
> than I expected - fuse has separate dentry_operations for its
> root dentry. I don't see the point, TBH - the only difference is
> that root one lacks
> * ->d_delete() (never even called for root dentry; it's
> only called if d_unhashed() is false)
> * ->d_revalidate() (never called for root)
> * ->d_automount() (not even looked at unless you have
> S_AUTOMOUNT set on the inode).
> What's wrong with using fuse_dentry_operations for root dentry?
> Am I missing something subtle here? Miklos?
Looks like a historical accident:
- initial version only had .d_revalidate and only set d_op in .loookup.
- then it grew .d_init/.d_release
- then, as a bugfix, the separate fuse_root_dentry_operations was added
Will fix.
Thanks,
Miklos
^ permalink raw reply [flat|nested] 87+ messages in thread
* Re: [RFC] dentry->d_flags locking
2025-02-24 10:35 ` Christian Brauner
@ 2025-02-24 14:14 ` Al Viro
2025-02-24 21:20 ` [PATCH 01/21] procfs: kill ->proc_dops Al Viro
2025-02-26 8:41 ` [RFC] dentry->d_flags locking Christian Brauner
0 siblings, 2 replies; 87+ messages in thread
From: Al Viro @ 2025-02-24 14:14 UTC (permalink / raw)
To: Christian Brauner
Cc: linux-fsdevel, Linus Torvalds, Neil Brown, Miklos Szeredi,
Jan Kara
On Mon, Feb 24, 2025 at 11:35:47AM +0100, Christian Brauner wrote:
> I think it would be worthwhile to mark dentries of such filesystems as
> always unhashed and then add an assert into fs/dcache.c whenever such a
> dentry should suddenly become hashed.
>
> That would not just make it very easy to see for the reviewer that the
> dentries of this filesystem are always unhashed it would also make it
> possible to spot bugs.
Not sure that's useful, really... Details are tied into the tree-in-dcache
rework, and I'll need to finish resurrecting that; should post in a week
or so.
For this series, see viro/vfs.git#work.dcache - it's a WIP at the moment,
and it's going to get reordered (if nothing else, d_alloc_parallel()
side needs an audit of tree-walkers to prove that it won't get confused
by seeing DCACHE_PAR_LOOKUP on the stuff that hasn't yet reached in-lookup
hash chains, and that might add prereqs that would need to go early in
queue), but that at least fleshes out what I described upthread.
I'll post individual patches for review in a few hours.
^ permalink raw reply [flat|nested] 87+ messages in thread
* [PATCH 01/21] procfs: kill ->proc_dops
2025-02-24 14:14 ` Al Viro
@ 2025-02-24 21:20 ` Al Viro
2025-02-24 21:20 ` [PATCH 02/21] new helper: d_splice_alias_ops() Al Viro
` (22 more replies)
2025-02-26 8:41 ` [RFC] dentry->d_flags locking Christian Brauner
1 sibling, 23 replies; 87+ messages in thread
From: Al Viro @ 2025-02-24 21:20 UTC (permalink / raw)
To: linux-fsdevel
Cc: Linus Torvalds, Christian Brauner, Neil Brown, Miklos Szeredi,
Jan Kara
It has two possible values - one for "forced lookup" entries, another
for the normal ones. We'd be better off with that as an explicit
flag anyway and in addition to that it opens some fun possibilities
with ->d_op and ->d_flags handling.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/proc/generic.c | 8 +++++---
fs/proc/internal.h | 5 +++--
2 files changed, 8 insertions(+), 5 deletions(-)
diff --git a/fs/proc/generic.c b/fs/proc/generic.c
index 8ec90826a49e..499c2bf67488 100644
--- a/fs/proc/generic.c
+++ b/fs/proc/generic.c
@@ -254,7 +254,10 @@ struct dentry *proc_lookup_de(struct inode *dir, struct dentry *dentry,
inode = proc_get_inode(dir->i_sb, de);
if (!inode)
return ERR_PTR(-ENOMEM);
- d_set_d_op(dentry, de->proc_dops);
+ if (de->flags & PROC_ENTRY_FORCE_LOOKUP)
+ d_set_d_op(dentry, &proc_net_dentry_ops);
+ else
+ d_set_d_op(dentry, &proc_misc_dentry_ops);
return d_splice_alias(inode, dentry);
}
read_unlock(&proc_subdir_lock);
@@ -448,9 +451,8 @@ static struct proc_dir_entry *__proc_create(struct proc_dir_entry **parent,
INIT_LIST_HEAD(&ent->pde_openers);
proc_set_user(ent, (*parent)->uid, (*parent)->gid);
- ent->proc_dops = &proc_misc_dentry_ops;
/* Revalidate everything under /proc/${pid}/net */
- if ((*parent)->proc_dops == &proc_net_dentry_ops)
+ if ((*parent)->flags & PROC_ENTRY_FORCE_LOOKUP)
pde_force_lookup(ent);
out:
diff --git a/fs/proc/internal.h b/fs/proc/internal.h
index 1695509370b8..07f75c959173 100644
--- a/fs/proc/internal.h
+++ b/fs/proc/internal.h
@@ -44,7 +44,6 @@ struct proc_dir_entry {
const struct proc_ops *proc_ops;
const struct file_operations *proc_dir_ops;
};
- const struct dentry_operations *proc_dops;
union {
const struct seq_operations *seq_ops;
int (*single_show)(struct seq_file *, void *);
@@ -67,6 +66,8 @@ struct proc_dir_entry {
char inline_name[];
} __randomize_layout;
+#define PROC_ENTRY_FORCE_LOOKUP 2 /* same space as PROC_ENTRY_PERMANENT */
+
#define SIZEOF_PDE ( \
sizeof(struct proc_dir_entry) < 128 ? 128 : \
sizeof(struct proc_dir_entry) < 192 ? 192 : \
@@ -346,7 +347,7 @@ extern const struct dentry_operations proc_net_dentry_ops;
static inline void pde_force_lookup(struct proc_dir_entry *pde)
{
/* /proc/net/ entries can be changed under us by setns(CLONE_NEWNET) */
- pde->proc_dops = &proc_net_dentry_ops;
+ pde->flags |= PROC_ENTRY_FORCE_LOOKUP;
}
/*
--
2.39.5
^ permalink raw reply related [flat|nested] 87+ messages in thread
* [PATCH 02/21] new helper: d_splice_alias_ops()
2025-02-24 21:20 ` [PATCH 01/21] procfs: kill ->proc_dops Al Viro
@ 2025-02-24 21:20 ` Al Viro
2025-02-26 8:28 ` Christian Brauner
2025-02-24 21:20 ` [PATCH 03/21] switch procfs from d_set_d_op() to d_splice_alias_ops() Al Viro
` (21 subsequent siblings)
22 siblings, 1 reply; 87+ messages in thread
From: Al Viro @ 2025-02-24 21:20 UTC (permalink / raw)
To: linux-fsdevel
Cc: Linus Torvalds, Christian Brauner, Neil Brown, Miklos Szeredi,
Jan Kara
Uses of d_set_d_op() on live dentry can be very dangerous; it is going
to be withdrawn and replaced with saner things.
The best way for a filesystem is to have the default dentry_operations
set at mount time and be done with that - __d_alloc() will use that.
Currently there are two cases when d_set_d_op() is used on a live dentry -
one is procfs, which has several genuinely different dentry_operations
instances (different ->d_revalidate(), etc.) and another is
simple_lookup(), where we would be better off without overriding ->d_op.
For procfs we have d_set_d_op() calls followed by d_splice_alias();
provide a new helper (d_splice_alias_ops(inode, dentry, d_ops)) that would
combine those two, and do the d_set_d_op() part while under ->d_lock.
That eliminates one of the places where ->d_flags had been modified
without holding ->d_lock; current behaviour is not racy, but the reasons
for that are far too brittle. Better move to uniform locking rules and
simpler proof of correctness...
The next commit will convert procfs to use of that helper; it is not
exported and won't be until somebody comes up with convincing modular
user for it.
Again, the best approach is to have default ->d_op and let __d_alloc()
do the right thing; filesystem _may_ need non-uniform ->d_op (procfs
does), but there'd better be good reasons for that.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/dcache.c | 63 ++++++++++++++++++++++++------------------
include/linux/dcache.h | 3 ++
2 files changed, 39 insertions(+), 27 deletions(-)
diff --git a/fs/dcache.c b/fs/dcache.c
index e3634916ffb9..c85efbda133a 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -2641,7 +2641,8 @@ EXPORT_SYMBOL(__d_lookup_unhash_wake);
/* inode->i_lock held if inode is non-NULL */
-static inline void __d_add(struct dentry *dentry, struct inode *inode)
+static inline void __d_add(struct dentry *dentry, struct inode *inode,
+ const struct dentry_operations *ops)
{
wait_queue_head_t *d_wait;
struct inode *dir = NULL;
@@ -2652,6 +2653,8 @@ static inline void __d_add(struct dentry *dentry, struct inode *inode)
n = start_dir_add(dir);
d_wait = __d_lookup_unhash(dentry);
}
+ if (unlikely(ops))
+ d_set_d_op(dentry, ops);
if (inode) {
unsigned add_flags = d_flags_for_inode(inode);
hlist_add_head(&dentry->d_u.d_alias, &inode->i_dentry);
@@ -2683,7 +2686,7 @@ void d_add(struct dentry *entry, struct inode *inode)
security_d_instantiate(entry, inode);
spin_lock(&inode->i_lock);
}
- __d_add(entry, inode);
+ __d_add(entry, inode, NULL);
}
EXPORT_SYMBOL(d_add);
@@ -2981,30 +2984,8 @@ static int __d_unalias(struct dentry *dentry, struct dentry *alias)
return ret;
}
-/**
- * d_splice_alias - splice a disconnected dentry into the tree if one exists
- * @inode: the inode which may have a disconnected dentry
- * @dentry: a negative dentry which we want to point to the inode.
- *
- * If inode is a directory and has an IS_ROOT alias, then d_move that in
- * place of the given dentry and return it, else simply d_add the inode
- * to the dentry and return NULL.
- *
- * If a non-IS_ROOT directory is found, the filesystem is corrupt, and
- * we should error out: directories can't have multiple aliases.
- *
- * This is needed in the lookup routine of any filesystem that is exportable
- * (via knfsd) so that we can build dcache paths to directories effectively.
- *
- * If a dentry was found and moved, then it is returned. Otherwise NULL
- * is returned. This matches the expected return value of ->lookup.
- *
- * Cluster filesystems may call this function with a negative, hashed dentry.
- * In that case, we know that the inode will be a regular file, and also this
- * will only occur during atomic_open. So we need to check for the dentry
- * being already hashed only in the final case.
- */
-struct dentry *d_splice_alias(struct inode *inode, struct dentry *dentry)
+struct dentry *d_splice_alias_ops(struct inode *inode, struct dentry *dentry,
+ const struct dentry_operations *ops)
{
if (IS_ERR(inode))
return ERR_CAST(inode);
@@ -3050,9 +3031,37 @@ struct dentry *d_splice_alias(struct inode *inode, struct dentry *dentry)
}
}
out:
- __d_add(dentry, inode);
+ __d_add(dentry, inode, ops);
return NULL;
}
+
+/**
+ * d_splice_alias - splice a disconnected dentry into the tree if one exists
+ * @inode: the inode which may have a disconnected dentry
+ * @dentry: a negative dentry which we want to point to the inode.
+ *
+ * If inode is a directory and has an IS_ROOT alias, then d_move that in
+ * place of the given dentry and return it, else simply d_add the inode
+ * to the dentry and return NULL.
+ *
+ * If a non-IS_ROOT directory is found, the filesystem is corrupt, and
+ * we should error out: directories can't have multiple aliases.
+ *
+ * This is needed in the lookup routine of any filesystem that is exportable
+ * (via knfsd) so that we can build dcache paths to directories effectively.
+ *
+ * If a dentry was found and moved, then it is returned. Otherwise NULL
+ * is returned. This matches the expected return value of ->lookup.
+ *
+ * Cluster filesystems may call this function with a negative, hashed dentry.
+ * In that case, we know that the inode will be a regular file, and also this
+ * will only occur during atomic_open. So we need to check for the dentry
+ * being already hashed only in the final case.
+ */
+struct dentry *d_splice_alias(struct inode *inode, struct dentry *dentry)
+{
+ return d_splice_alias_ops(inode, dentry, NULL);
+}
EXPORT_SYMBOL(d_splice_alias);
/*
diff --git a/include/linux/dcache.h b/include/linux/dcache.h
index 4afb60365675..f47f3a47d97b 100644
--- a/include/linux/dcache.h
+++ b/include/linux/dcache.h
@@ -250,6 +250,9 @@ extern struct dentry * d_alloc_anon(struct super_block *);
extern struct dentry * d_alloc_parallel(struct dentry *, const struct qstr *,
wait_queue_head_t *);
extern struct dentry * d_splice_alias(struct inode *, struct dentry *);
+/* weird procfs mess; *NOT* exported */
+extern struct dentry * d_splice_alias_ops(struct inode *, struct dentry *,
+ const struct dentry_operations *);
extern struct dentry * d_add_ci(struct dentry *, struct inode *, struct qstr *);
extern bool d_same_name(const struct dentry *dentry, const struct dentry *parent,
const struct qstr *name);
--
2.39.5
^ permalink raw reply related [flat|nested] 87+ messages in thread
* [PATCH 03/21] switch procfs from d_set_d_op() to d_splice_alias_ops()
2025-02-24 21:20 ` [PATCH 01/21] procfs: kill ->proc_dops Al Viro
2025-02-24 21:20 ` [PATCH 02/21] new helper: d_splice_alias_ops() Al Viro
@ 2025-02-24 21:20 ` Al Viro
2025-02-26 8:29 ` Christian Brauner
2025-02-24 21:20 ` [PATCH 04/21] fuse: no need for special dentry_operations for root dentry Al Viro
` (20 subsequent siblings)
22 siblings, 1 reply; 87+ messages in thread
From: Al Viro @ 2025-02-24 21:20 UTC (permalink / raw)
To: linux-fsdevel
Cc: Linus Torvalds, Christian Brauner, Neil Brown, Miklos Szeredi,
Jan Kara
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/proc/base.c | 9 +++------
fs/proc/generic.c | 8 ++++----
fs/proc/internal.h | 3 +--
fs/proc/namespaces.c | 3 +--
fs/proc/proc_sysctl.c | 7 +++----
5 files changed, 12 insertions(+), 18 deletions(-)
diff --git a/fs/proc/base.c b/fs/proc/base.c
index cd89e956c322..397a9f6f463e 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -2709,8 +2709,7 @@ static struct dentry *proc_pident_instantiate(struct dentry *dentry,
inode->i_fop = p->fop;
ei->op = p->op;
pid_update_inode(task, inode);
- d_set_d_op(dentry, &pid_dentry_operations);
- return d_splice_alias(inode, dentry);
+ return d_splice_alias_ops(inode, dentry, &pid_dentry_operations);
}
static struct dentry *proc_pident_lookup(struct inode *dir,
@@ -3508,8 +3507,7 @@ static struct dentry *proc_pid_instantiate(struct dentry * dentry,
set_nlink(inode, nlink_tgid);
pid_update_inode(task, inode);
- d_set_d_op(dentry, &pid_dentry_operations);
- return d_splice_alias(inode, dentry);
+ return d_splice_alias_ops(inode, dentry, &pid_dentry_operations);
}
struct dentry *proc_pid_lookup(struct dentry *dentry, unsigned int flags)
@@ -3813,8 +3811,7 @@ static struct dentry *proc_task_instantiate(struct dentry *dentry,
set_nlink(inode, nlink_tid);
pid_update_inode(task, inode);
- d_set_d_op(dentry, &pid_dentry_operations);
- return d_splice_alias(inode, dentry);
+ return d_splice_alias_ops(inode, dentry, &pid_dentry_operations);
}
static struct dentry *proc_task_lookup(struct inode *dir, struct dentry * dentry, unsigned int flags)
diff --git a/fs/proc/generic.c b/fs/proc/generic.c
index 499c2bf67488..774e18372914 100644
--- a/fs/proc/generic.c
+++ b/fs/proc/generic.c
@@ -255,10 +255,10 @@ struct dentry *proc_lookup_de(struct inode *dir, struct dentry *dentry,
if (!inode)
return ERR_PTR(-ENOMEM);
if (de->flags & PROC_ENTRY_FORCE_LOOKUP)
- d_set_d_op(dentry, &proc_net_dentry_ops);
- else
- d_set_d_op(dentry, &proc_misc_dentry_ops);
- return d_splice_alias(inode, dentry);
+ return d_splice_alias_ops(inode, dentry,
+ &proc_net_dentry_ops);
+ return d_splice_alias_ops(inode, dentry,
+ &proc_misc_dentry_ops);
}
read_unlock(&proc_subdir_lock);
return ERR_PTR(-ENOENT);
diff --git a/fs/proc/internal.h b/fs/proc/internal.h
index 07f75c959173..48410381036b 100644
--- a/fs/proc/internal.h
+++ b/fs/proc/internal.h
@@ -358,7 +358,6 @@ static inline void pde_force_lookup(struct proc_dir_entry *pde)
static inline struct dentry *proc_splice_unmountable(struct inode *inode,
struct dentry *dentry, const struct dentry_operations *d_ops)
{
- d_set_d_op(dentry, d_ops);
dont_mount(dentry);
- return d_splice_alias(inode, dentry);
+ return d_splice_alias_ops(inode, dentry, d_ops);
}
diff --git a/fs/proc/namespaces.c b/fs/proc/namespaces.c
index c610224faf10..4403a2e20c16 100644
--- a/fs/proc/namespaces.c
+++ b/fs/proc/namespaces.c
@@ -111,8 +111,7 @@ static struct dentry *proc_ns_instantiate(struct dentry *dentry,
ei->ns_ops = ns_ops;
pid_update_inode(task, inode);
- d_set_d_op(dentry, &pid_dentry_operations);
- return d_splice_alias(inode, dentry);
+ return d_splice_alias_ops(inode, dentry, &pid_dentry_operations);
}
static int proc_ns_dir_readdir(struct file *file, struct dir_context *ctx)
diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c
index cc9d74a06ff0..7a8bffc03dc8 100644
--- a/fs/proc/proc_sysctl.c
+++ b/fs/proc/proc_sysctl.c
@@ -540,9 +540,8 @@ static struct dentry *proc_sys_lookup(struct inode *dir, struct dentry *dentry,
goto out;
}
- d_set_d_op(dentry, &proc_sys_dentry_operations);
inode = proc_sys_make_inode(dir->i_sb, h ? h : head, p);
- err = d_splice_alias(inode, dentry);
+ err = d_splice_alias_ops(inode, dentry, &proc_sys_dentry_operations);
out:
if (h)
@@ -699,9 +698,9 @@ static bool proc_sys_fill_cache(struct file *file,
return false;
if (d_in_lookup(child)) {
struct dentry *res;
- d_set_d_op(child, &proc_sys_dentry_operations);
inode = proc_sys_make_inode(dir->d_sb, head, table);
- res = d_splice_alias(inode, child);
+ res = d_splice_alias_ops(inode, child,
+ &proc_sys_dentry_operations);
d_lookup_done(child);
if (unlikely(res)) {
dput(child);
--
2.39.5
^ permalink raw reply related [flat|nested] 87+ messages in thread
* [PATCH 04/21] fuse: no need for special dentry_operations for root dentry
2025-02-24 21:20 ` [PATCH 01/21] procfs: kill ->proc_dops Al Viro
2025-02-24 21:20 ` [PATCH 02/21] new helper: d_splice_alias_ops() Al Viro
2025-02-24 21:20 ` [PATCH 03/21] switch procfs from d_set_d_op() to d_splice_alias_ops() Al Viro
@ 2025-02-24 21:20 ` Al Viro
2025-02-26 8:29 ` Christian Brauner
2025-02-27 14:33 ` Miklos Szeredi
2025-02-24 21:20 ` [PATCH 05/21] new helper: set_default_d_op() Al Viro
` (19 subsequent siblings)
22 siblings, 2 replies; 87+ messages in thread
From: Al Viro @ 2025-02-24 21:20 UTC (permalink / raw)
To: linux-fsdevel
Cc: Linus Torvalds, Christian Brauner, Neil Brown, Miklos Szeredi,
Jan Kara
->d_revalidate() is never called for root anyway...
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/fuse/dir.c | 7 -------
fs/fuse/fuse_i.h | 1 -
fs/fuse/inode.c | 4 +---
3 files changed, 1 insertion(+), 11 deletions(-)
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
index 198862b086ff..24979d5413fa 100644
--- a/fs/fuse/dir.c
+++ b/fs/fuse/dir.c
@@ -336,13 +336,6 @@ const struct dentry_operations fuse_dentry_operations = {
.d_automount = fuse_dentry_automount,
};
-const struct dentry_operations fuse_root_dentry_operations = {
-#if BITS_PER_LONG < 64
- .d_init = fuse_dentry_init,
- .d_release = fuse_dentry_release,
-#endif
-};
-
int fuse_valid_type(int m)
{
return S_ISREG(m) || S_ISDIR(m) || S_ISLNK(m) || S_ISCHR(m) ||
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
index fee96fe7887b..71a2b3900854 100644
--- a/fs/fuse/fuse_i.h
+++ b/fs/fuse/fuse_i.h
@@ -1069,7 +1069,6 @@ static inline void fuse_sync_bucket_dec(struct fuse_sync_bucket *bucket)
extern const struct file_operations fuse_dev_operations;
extern const struct dentry_operations fuse_dentry_operations;
-extern const struct dentry_operations fuse_root_dentry_operations;
/**
* Get a filled in inode
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
index e9db2cb8c150..57a1ee016b73 100644
--- a/fs/fuse/inode.c
+++ b/fs/fuse/inode.c
@@ -1800,12 +1800,10 @@ int fuse_fill_super_common(struct super_block *sb, struct fuse_fs_context *ctx)
err = -ENOMEM;
root = fuse_get_root_inode(sb, ctx->rootmode);
- sb->s_d_op = &fuse_root_dentry_operations;
+ sb->s_d_op = &fuse_dentry_operations;
root_dentry = d_make_root(root);
if (!root_dentry)
goto err_dev_free;
- /* Root dentry doesn't have .d_revalidate */
- sb->s_d_op = &fuse_dentry_operations;
mutex_lock(&fuse_mutex);
err = -EINVAL;
--
2.39.5
^ permalink raw reply related [flat|nested] 87+ messages in thread
* [PATCH 05/21] new helper: set_default_d_op()
2025-02-24 21:20 ` [PATCH 01/21] procfs: kill ->proc_dops Al Viro
` (2 preceding siblings ...)
2025-02-24 21:20 ` [PATCH 04/21] fuse: no need for special dentry_operations for root dentry Al Viro
@ 2025-02-24 21:20 ` Al Viro
2025-02-26 8:30 ` Christian Brauner
2025-02-24 21:20 ` [PATCH 06/21] split d_flags calculation out of d_set_d_op() Al Viro
` (18 subsequent siblings)
22 siblings, 1 reply; 87+ messages in thread
From: Al Viro @ 2025-02-24 21:20 UTC (permalink / raw)
To: linux-fsdevel
Cc: Linus Torvalds, Christian Brauner, Neil Brown, Miklos Szeredi,
Jan Kara
... to be used instead of manually assigning to ->s_d_op.
All in-tree filesystem converted (and field itself is renamed,
so any out-of-tree ones in need of conversion will be caught
by compiler).
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
Documentation/filesystems/porting.rst | 7 +++++++
fs/9p/vfs_super.c | 4 ++--
fs/adfs/super.c | 2 +-
fs/affs/super.c | 4 ++--
fs/afs/super.c | 4 ++--
fs/autofs/inode.c | 2 +-
fs/btrfs/super.c | 2 +-
fs/ceph/super.c | 2 +-
fs/coda/inode.c | 2 +-
fs/configfs/mount.c | 2 +-
fs/dcache.c | 10 ++++++++--
fs/debugfs/inode.c | 2 +-
fs/devpts/inode.c | 2 +-
fs/ecryptfs/main.c | 2 +-
fs/efivarfs/super.c | 2 +-
fs/exfat/super.c | 4 ++--
fs/fat/namei_msdos.c | 2 +-
fs/fat/namei_vfat.c | 4 ++--
fs/fuse/inode.c | 4 ++--
fs/gfs2/ops_fstype.c | 2 +-
fs/hfs/super.c | 2 +-
fs/hfsplus/super.c | 2 +-
fs/hostfs/hostfs_kern.c | 2 +-
fs/hpfs/super.c | 2 +-
fs/isofs/inode.c | 2 +-
fs/jfs/super.c | 2 +-
fs/kernfs/mount.c | 2 +-
fs/libfs.c | 16 ++++++++--------
fs/nfs/super.c | 2 +-
fs/ntfs3/super.c | 3 ++-
fs/ocfs2/super.c | 2 +-
fs/orangefs/super.c | 2 +-
fs/overlayfs/super.c | 2 +-
fs/smb/client/cifsfs.c | 4 ++--
fs/tracefs/inode.c | 2 +-
fs/vboxsf/super.c | 2 +-
include/linux/dcache.h | 2 ++
include/linux/fs.h | 2 +-
mm/shmem.c | 2 +-
net/sunrpc/rpc_pipe.c | 2 +-
40 files changed, 69 insertions(+), 53 deletions(-)
diff --git a/Documentation/filesystems/porting.rst b/Documentation/filesystems/porting.rst
index 1639e78e3146..004cd69617a2 100644
--- a/Documentation/filesystems/porting.rst
+++ b/Documentation/filesystems/porting.rst
@@ -1157,3 +1157,10 @@ in normal case it points into the pathname being looked up.
NOTE: if you need something like full path from the root of filesystem,
you are still on your own - this assists with simple cases, but it's not
magic.
+
+---
+
+**mandatory**
+
+If your filesystem sets the default dentry_operations, use set_default_d_op()
+rather than manually setting sb->s_d_op.
diff --git a/fs/9p/vfs_super.c b/fs/9p/vfs_super.c
index 489db161abc9..5c3dc3efb909 100644
--- a/fs/9p/vfs_super.c
+++ b/fs/9p/vfs_super.c
@@ -135,9 +135,9 @@ static struct dentry *v9fs_mount(struct file_system_type *fs_type, int flags,
goto release_sb;
if (v9ses->cache & (CACHE_META|CACHE_LOOSE))
- sb->s_d_op = &v9fs_cached_dentry_operations;
+ set_default_d_op(sb, &v9fs_cached_dentry_operations);
else
- sb->s_d_op = &v9fs_dentry_operations;
+ set_default_d_op(sb, &v9fs_dentry_operations);
inode = v9fs_get_new_inode_from_fid(v9ses, fid, sb);
if (IS_ERR(inode)) {
diff --git a/fs/adfs/super.c b/fs/adfs/super.c
index 017c48a80203..fdccdbbfc213 100644
--- a/fs/adfs/super.c
+++ b/fs/adfs/super.c
@@ -397,7 +397,7 @@ static int adfs_fill_super(struct super_block *sb, struct fs_context *fc)
if (asb->s_ftsuffix)
asb->s_namelen += 4;
- sb->s_d_op = &adfs_dentry_operations;
+ set_default_d_op(sb, &adfs_dentry_operations);
root = adfs_iget(sb, &root_obj);
sb->s_root = d_make_root(root);
if (!sb->s_root) {
diff --git a/fs/affs/super.c b/fs/affs/super.c
index 2fa40337776d..44f8aa883100 100644
--- a/fs/affs/super.c
+++ b/fs/affs/super.c
@@ -500,9 +500,9 @@ static int affs_fill_super(struct super_block *sb, struct fs_context *fc)
return PTR_ERR(root_inode);
if (affs_test_opt(AFFS_SB(sb)->s_flags, SF_INTL))
- sb->s_d_op = &affs_intl_dentry_operations;
+ set_default_d_op(sb, &affs_intl_dentry_operations);
else
- sb->s_d_op = &affs_dentry_operations;
+ set_default_d_op(sb, &affs_dentry_operations);
sb->s_root = d_make_root(root_inode);
if (!sb->s_root) {
diff --git a/fs/afs/super.c b/fs/afs/super.c
index a9bee610674e..13d0414a1ddb 100644
--- a/fs/afs/super.c
+++ b/fs/afs/super.c
@@ -487,12 +487,12 @@ static int afs_fill_super(struct super_block *sb, struct afs_fs_context *ctx)
goto error;
if (as->dyn_root) {
- sb->s_d_op = &afs_dynroot_dentry_operations;
+ set_default_d_op(sb, &afs_dynroot_dentry_operations);
ret = afs_dynroot_populate(sb);
if (ret < 0)
goto error;
} else {
- sb->s_d_op = &afs_fs_dentry_operations;
+ set_default_d_op(sb, &afs_fs_dentry_operations);
rcu_assign_pointer(as->volume->sb, sb);
}
diff --git a/fs/autofs/inode.c b/fs/autofs/inode.c
index ee2edccaef70..f5c16ffba013 100644
--- a/fs/autofs/inode.c
+++ b/fs/autofs/inode.c
@@ -311,7 +311,7 @@ static int autofs_fill_super(struct super_block *s, struct fs_context *fc)
s->s_blocksize_bits = 10;
s->s_magic = AUTOFS_SUPER_MAGIC;
s->s_op = &autofs_sops;
- s->s_d_op = &autofs_dentry_operations;
+ set_default_d_op(s, &autofs_dentry_operations);
s->s_time_gran = 1;
/*
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
index dc4fee519ca6..5f39857ea3ae 100644
--- a/fs/btrfs/super.c
+++ b/fs/btrfs/super.c
@@ -954,7 +954,7 @@ static int btrfs_fill_super(struct super_block *sb,
sb->s_maxbytes = MAX_LFS_FILESIZE;
sb->s_magic = BTRFS_SUPER_MAGIC;
sb->s_op = &btrfs_super_ops;
- sb->s_d_op = &btrfs_dentry_operations;
+ set_default_d_op(sb, &btrfs_dentry_operations);
sb->s_export_op = &btrfs_export_ops;
#ifdef CONFIG_FS_VERITY
sb->s_vop = &btrfs_verityops;
diff --git a/fs/ceph/super.c b/fs/ceph/super.c
index 4344e1f11806..adec6e2f01c4 100644
--- a/fs/ceph/super.c
+++ b/fs/ceph/super.c
@@ -1220,7 +1220,7 @@ static int ceph_set_super(struct super_block *s, struct fs_context *fc)
fsc->max_file_size = 1ULL << 40; /* temp value until we get mdsmap */
s->s_op = &ceph_super_ops;
- s->s_d_op = &ceph_dentry_ops;
+ set_default_d_op(s, &ceph_dentry_ops);
s->s_export_op = &ceph_export_ops;
s->s_time_gran = 1;
diff --git a/fs/coda/inode.c b/fs/coda/inode.c
index 6896fce122e1..08450d006016 100644
--- a/fs/coda/inode.c
+++ b/fs/coda/inode.c
@@ -230,7 +230,7 @@ static int coda_fill_super(struct super_block *sb, struct fs_context *fc)
sb->s_blocksize_bits = 12;
sb->s_magic = CODA_SUPER_MAGIC;
sb->s_op = &coda_super_operations;
- sb->s_d_op = &coda_dentry_operations;
+ set_default_d_op(sb, &coda_dentry_operations);
sb->s_time_gran = 1;
sb->s_time_min = S64_MIN;
sb->s_time_max = S64_MAX;
diff --git a/fs/configfs/mount.c b/fs/configfs/mount.c
index c2d820063ec4..20412eaca972 100644
--- a/fs/configfs/mount.c
+++ b/fs/configfs/mount.c
@@ -92,7 +92,7 @@ static int configfs_fill_super(struct super_block *sb, struct fs_context *fc)
configfs_root_group.cg_item.ci_dentry = root;
root->d_fsdata = &configfs_root;
sb->s_root = root;
- sb->s_d_op = &configfs_dentry_ops; /* the rest get that */
+ set_default_d_op(sb, &configfs_dentry_ops); /* the rest get that */
return 0;
}
diff --git a/fs/dcache.c b/fs/dcache.c
index c85efbda133a..cd5e5139ca4c 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -1712,7 +1712,7 @@ static struct dentry *__d_alloc(struct super_block *sb, const struct qstr *name)
INIT_HLIST_HEAD(&dentry->d_children);
INIT_HLIST_NODE(&dentry->d_u.d_alias);
INIT_HLIST_NODE(&dentry->d_sib);
- d_set_d_op(dentry, dentry->d_sb->s_d_op);
+ d_set_d_op(dentry, dentry->d_sb->__s_d_op);
if (dentry->d_op && dentry->d_op->d_init) {
err = dentry->d_op->d_init(dentry);
@@ -1795,7 +1795,7 @@ struct dentry *d_alloc_pseudo(struct super_block *sb, const struct qstr *name)
struct dentry *dentry = __d_alloc(sb, name);
if (likely(dentry)) {
dentry->d_flags |= DCACHE_NORCU;
- if (!sb->s_d_op)
+ if (!dentry->d_op)
d_set_d_op(dentry, &anon_ops);
}
return dentry;
@@ -1841,6 +1841,12 @@ void d_set_d_op(struct dentry *dentry, const struct dentry_operations *op)
}
EXPORT_SYMBOL(d_set_d_op);
+void set_default_d_op(struct super_block *s, const struct dentry_operations *ops)
+{
+ s->__s_d_op = ops;
+}
+EXPORT_SYMBOL(set_default_d_op);
+
static unsigned d_flags_for_inode(struct inode *inode)
{
unsigned add_flags = DCACHE_REGULAR_TYPE;
diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c
index 75715d8877ee..f54a8fd960e4 100644
--- a/fs/debugfs/inode.c
+++ b/fs/debugfs/inode.c
@@ -273,7 +273,7 @@ static int debugfs_fill_super(struct super_block *sb, struct fs_context *fc)
return err;
sb->s_op = &debugfs_super_operations;
- sb->s_d_op = &debugfs_dops;
+ set_default_d_op(sb, &debugfs_dops);
debugfs_apply_options(sb);
diff --git a/fs/devpts/inode.c b/fs/devpts/inode.c
index 1096ff8562fa..f092973236ef 100644
--- a/fs/devpts/inode.c
+++ b/fs/devpts/inode.c
@@ -433,7 +433,7 @@ devpts_fill_super(struct super_block *s, void *data, int silent)
s->s_blocksize_bits = 10;
s->s_magic = DEVPTS_SUPER_MAGIC;
s->s_op = &devpts_sops;
- s->s_d_op = &simple_dentry_operations;
+ set_default_d_op(s, &simple_dentry_operations);
s->s_time_gran = 1;
error = -ENOMEM;
diff --git a/fs/ecryptfs/main.c b/fs/ecryptfs/main.c
index 8dd1d7189c3b..45f9ca4465da 100644
--- a/fs/ecryptfs/main.c
+++ b/fs/ecryptfs/main.c
@@ -471,7 +471,7 @@ static int ecryptfs_get_tree(struct fs_context *fc)
sbi = NULL;
s->s_op = &ecryptfs_sops;
s->s_xattr = ecryptfs_xattr_handlers;
- s->s_d_op = &ecryptfs_dops;
+ set_default_d_op(s, &ecryptfs_dops);
err = "Reading sb failed";
rc = kern_path(fc->source, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &path);
diff --git a/fs/efivarfs/super.c b/fs/efivarfs/super.c
index 09fcf731e65d..3f3188e0cfa7 100644
--- a/fs/efivarfs/super.c
+++ b/fs/efivarfs/super.c
@@ -345,7 +345,7 @@ static int efivarfs_fill_super(struct super_block *sb, struct fs_context *fc)
sb->s_blocksize_bits = PAGE_SHIFT;
sb->s_magic = EFIVARFS_MAGIC;
sb->s_op = &efivarfs_ops;
- sb->s_d_op = &efivarfs_d_ops;
+ set_default_d_op(sb, &efivarfs_d_ops);
sb->s_time_gran = 1;
if (!efivar_supports_writes())
diff --git a/fs/exfat/super.c b/fs/exfat/super.c
index bd57844414aa..c821582fa1ef 100644
--- a/fs/exfat/super.c
+++ b/fs/exfat/super.c
@@ -697,9 +697,9 @@ static int exfat_fill_super(struct super_block *sb, struct fs_context *fc)
}
if (sbi->options.utf8)
- sb->s_d_op = &exfat_utf8_dentry_ops;
+ set_default_d_op(sb, &exfat_utf8_dentry_ops);
else
- sb->s_d_op = &exfat_dentry_ops;
+ set_default_d_op(sb, &exfat_dentry_ops);
root_inode = new_inode(sb);
if (!root_inode) {
diff --git a/fs/fat/namei_msdos.c b/fs/fat/namei_msdos.c
index f06f6ba643cc..71302291d33c 100644
--- a/fs/fat/namei_msdos.c
+++ b/fs/fat/namei_msdos.c
@@ -646,7 +646,7 @@ static const struct inode_operations msdos_dir_inode_operations = {
static void setup(struct super_block *sb)
{
MSDOS_SB(sb)->dir_ops = &msdos_dir_inode_operations;
- sb->s_d_op = &msdos_dentry_operations;
+ set_default_d_op(sb, &msdos_dentry_operations);
sb->s_flags |= SB_NOATIME;
}
diff --git a/fs/fat/namei_vfat.c b/fs/fat/namei_vfat.c
index 926c26e90ef8..2476afd1304d 100644
--- a/fs/fat/namei_vfat.c
+++ b/fs/fat/namei_vfat.c
@@ -1187,9 +1187,9 @@ static void setup(struct super_block *sb)
{
MSDOS_SB(sb)->dir_ops = &vfat_dir_inode_operations;
if (MSDOS_SB(sb)->options.name_check != 's')
- sb->s_d_op = &vfat_ci_dentry_ops;
+ set_default_d_op(sb, &vfat_ci_dentry_ops);
else
- sb->s_d_op = &vfat_dentry_ops;
+ set_default_d_op(sb, &vfat_dentry_ops);
}
static int vfat_fill_super(struct super_block *sb, struct fs_context *fc)
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
index 57a1ee016b73..9994f3b33a9f 100644
--- a/fs/fuse/inode.c
+++ b/fs/fuse/inode.c
@@ -1665,7 +1665,7 @@ static int fuse_fill_super_submount(struct super_block *sb,
fi = get_fuse_inode(root);
fi->nlookup--;
- sb->s_d_op = &fuse_dentry_operations;
+ set_default_d_op(sb, &fuse_dentry_operations);
sb->s_root = d_make_root(root);
if (!sb->s_root)
return -ENOMEM;
@@ -1800,7 +1800,7 @@ int fuse_fill_super_common(struct super_block *sb, struct fuse_fs_context *ctx)
err = -ENOMEM;
root = fuse_get_root_inode(sb, ctx->rootmode);
- sb->s_d_op = &fuse_dentry_operations;
+ set_default_d_op(sb, &fuse_dentry_operations);
root_dentry = d_make_root(root);
if (!root_dentry)
goto err_dev_free;
diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c
index e83d293c3614..949bbdb5b564 100644
--- a/fs/gfs2/ops_fstype.c
+++ b/fs/gfs2/ops_fstype.c
@@ -1156,7 +1156,7 @@ static int gfs2_fill_super(struct super_block *sb, struct fs_context *fc)
sb->s_flags |= SB_NOSEC;
sb->s_magic = GFS2_MAGIC;
sb->s_op = &gfs2_super_ops;
- sb->s_d_op = &gfs2_dops;
+ set_default_d_op(sb, &gfs2_dops);
sb->s_export_op = &gfs2_export_ops;
sb->s_qcop = &gfs2_quotactl_ops;
sb->s_quota_types = QTYPE_MASK_USR | QTYPE_MASK_GRP;
diff --git a/fs/hfs/super.c b/fs/hfs/super.c
index fe09c2093a93..388a318297ec 100644
--- a/fs/hfs/super.c
+++ b/fs/hfs/super.c
@@ -365,7 +365,7 @@ static int hfs_fill_super(struct super_block *sb, struct fs_context *fc)
if (!root_inode)
goto bail_no_root;
- sb->s_d_op = &hfs_dentry_operations;
+ set_default_d_op(sb, &hfs_dentry_operations);
res = -ENOMEM;
sb->s_root = d_make_root(root_inode);
if (!sb->s_root)
diff --git a/fs/hfsplus/super.c b/fs/hfsplus/super.c
index 948b8aaee33e..0caf7aa1c249 100644
--- a/fs/hfsplus/super.c
+++ b/fs/hfsplus/super.c
@@ -508,7 +508,7 @@ static int hfsplus_fill_super(struct super_block *sb, struct fs_context *fc)
goto out_put_alloc_file;
}
- sb->s_d_op = &hfsplus_dentry_operations;
+ set_default_d_op(sb, &hfsplus_dentry_operations);
sb->s_root = d_make_root(root);
if (!sb->s_root) {
err = -ENOMEM;
diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c
index e0741e468956..a0e0563a29d7 100644
--- a/fs/hostfs/hostfs_kern.c
+++ b/fs/hostfs/hostfs_kern.c
@@ -920,7 +920,7 @@ static int hostfs_fill_super(struct super_block *sb, struct fs_context *fc)
sb->s_blocksize_bits = 10;
sb->s_magic = HOSTFS_SUPER_MAGIC;
sb->s_op = &hostfs_sbops;
- sb->s_d_op = &simple_dentry_operations;
+ set_default_d_op(sb, &simple_dentry_operations);
sb->s_maxbytes = MAX_LFS_FILESIZE;
err = super_setup_bdi(sb);
if (err)
diff --git a/fs/hpfs/super.c b/fs/hpfs/super.c
index 27567920abe4..42b779b4d87f 100644
--- a/fs/hpfs/super.c
+++ b/fs/hpfs/super.c
@@ -554,7 +554,7 @@ static int hpfs_fill_super(struct super_block *s, struct fs_context *fc)
/* Fill superblock stuff */
s->s_magic = HPFS_SUPER_MAGIC;
s->s_op = &hpfs_sops;
- s->s_d_op = &hpfs_dentry_operations;
+ set_default_d_op(s, &hpfs_dentry_operations);
s->s_time_min = local_to_gmt(s, 0);
s->s_time_max = local_to_gmt(s, U32_MAX);
diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c
index 47038e660812..05ddc2544ade 100644
--- a/fs/isofs/inode.c
+++ b/fs/isofs/inode.c
@@ -939,7 +939,7 @@ static int isofs_fill_super(struct super_block *s, struct fs_context *fc)
sbi->s_check = opt->check;
if (table)
- s->s_d_op = &isofs_dentry_ops[table - 1];
+ set_default_d_op(s, &isofs_dentry_ops[table - 1]);
/* get the root dentry */
s->s_root = d_make_root(inode);
diff --git a/fs/jfs/super.c b/fs/jfs/super.c
index 223d9ac59839..10c3cb714423 100644
--- a/fs/jfs/super.c
+++ b/fs/jfs/super.c
@@ -542,7 +542,7 @@ static int jfs_fill_super(struct super_block *sb, struct fs_context *fc)
sb->s_magic = JFS_SUPER_MAGIC;
if (sbi->mntflag & JFS_OS2)
- sb->s_d_op = &jfs_ci_dentry_operations;
+ set_default_d_op(sb, &jfs_ci_dentry_operations);
inode = jfs_iget(sb, ROOT_I);
if (IS_ERR(inode)) {
diff --git a/fs/kernfs/mount.c b/fs/kernfs/mount.c
index 1358c21837f1..91e788d15073 100644
--- a/fs/kernfs/mount.c
+++ b/fs/kernfs/mount.c
@@ -281,7 +281,7 @@ static int kernfs_fill_super(struct super_block *sb, struct kernfs_fs_context *k
return -ENOMEM;
}
sb->s_root = root;
- sb->s_d_op = &kernfs_dops;
+ set_default_d_op(sb, &kernfs_dops);
return 0;
}
diff --git a/fs/libfs.c b/fs/libfs.c
index 8444f5cc4064..929bef0fecbd 100644
--- a/fs/libfs.c
+++ b/fs/libfs.c
@@ -75,7 +75,7 @@ struct dentry *simple_lookup(struct inode *dir, struct dentry *dentry, unsigned
{
if (dentry->d_name.len > NAME_MAX)
return ERR_PTR(-ENAMETOOLONG);
- if (!dentry->d_sb->s_d_op)
+ if (!dentry->d_op)
d_set_d_op(dentry, &simple_dentry_operations);
if (IS_ENABLED(CONFIG_UNICODE) && IS_CASEFOLDED(dir))
@@ -683,7 +683,7 @@ static int pseudo_fs_fill_super(struct super_block *s, struct fs_context *fc)
s->s_root = d_make_root(root);
if (!s->s_root)
return -ENOMEM;
- s->s_d_op = ctx->dops;
+ set_default_d_op(s, ctx->dops);
return 0;
}
@@ -1943,22 +1943,22 @@ static const struct dentry_operations generic_encrypted_dentry_ops = {
* @sb: superblock to be configured
*
* Filesystems supporting casefolding and/or fscrypt can call this
- * helper at mount-time to configure sb->s_d_op to best set of dentry
- * operations required for the enabled features. The helper must be
- * called after these have been configured, but before the root dentry
- * is created.
+ * helper at mount-time to configure default dentry_operations to the
+ * best set of dentry operations required for the enabled features.
+ * The helper must be called after these have been configured, but
+ * before the root dentry is created.
*/
void generic_set_sb_d_ops(struct super_block *sb)
{
#if IS_ENABLED(CONFIG_UNICODE)
if (sb->s_encoding) {
- sb->s_d_op = &generic_ci_dentry_ops;
+ set_default_d_op(sb, &generic_ci_dentry_ops);
return;
}
#endif
#ifdef CONFIG_FS_ENCRYPTION
if (sb->s_cop) {
- sb->s_d_op = &generic_encrypted_dentry_ops;
+ set_default_d_op(sb, &generic_encrypted_dentry_ops);
return;
}
#endif
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index aeb715b4a690..38b0ecf02ad6 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -1169,7 +1169,7 @@ static int nfs_set_super(struct super_block *s, struct fs_context *fc)
struct nfs_server *server = fc->s_fs_info;
int ret;
- s->s_d_op = server->nfs_client->rpc_ops->dentry_ops;
+ set_default_d_op(s, server->nfs_client->rpc_ops->dentry_ops);
ret = set_anon_super(s, server);
if (ret == 0)
server->s_dev = s->s_dev;
diff --git a/fs/ntfs3/super.c b/fs/ntfs3/super.c
index 6a0f6b0a3ab2..90f5361ae13f 100644
--- a/fs/ntfs3/super.c
+++ b/fs/ntfs3/super.c
@@ -1182,7 +1182,8 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc)
sb->s_export_op = &ntfs_export_ops;
sb->s_time_gran = NTFS_TIME_GRAN; // 100 nsec
sb->s_xattr = ntfs_xattr_handlers;
- sb->s_d_op = options->nocase ? &ntfs_dentry_ops : NULL;
+ if (options->nocase)
+ set_default_d_op(sb, &ntfs_dentry_ops);
options->nls = ntfs_load_nls(options->nls_name);
if (IS_ERR(options->nls)) {
diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c
index 8bb5022f3082..411f72be4a9b 100644
--- a/fs/ocfs2/super.c
+++ b/fs/ocfs2/super.c
@@ -1959,7 +1959,7 @@ static int ocfs2_initialize_super(struct super_block *sb,
sb->s_fs_info = osb;
sb->s_op = &ocfs2_sops;
- sb->s_d_op = &ocfs2_dentry_ops;
+ set_default_d_op(sb, &ocfs2_dentry_ops);
sb->s_export_op = &ocfs2_export_ops;
sb->s_qcop = &dquot_quotactl_sysfile_ops;
sb->dq_op = &ocfs2_quota_operations;
diff --git a/fs/orangefs/super.c b/fs/orangefs/super.c
index eba3e357192e..d4c8d8b32f14 100644
--- a/fs/orangefs/super.c
+++ b/fs/orangefs/super.c
@@ -434,7 +434,7 @@ static int orangefs_fill_sb(struct super_block *sb,
sb->s_xattr = orangefs_xattr_handlers;
sb->s_magic = ORANGEFS_SUPER_MAGIC;
sb->s_op = &orangefs_s_ops;
- sb->s_d_op = &orangefs_dentry_operations;
+ set_default_d_op(sb, &orangefs_dentry_operations);
sb->s_blocksize = PAGE_SIZE;
sb->s_blocksize_bits = PAGE_SHIFT;
diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c
index 86ae6f6da36b..5f7a5a8c0778 100644
--- a/fs/overlayfs/super.c
+++ b/fs/overlayfs/super.c
@@ -1315,7 +1315,7 @@ int ovl_fill_super(struct super_block *sb, struct fs_context *fc)
if (WARN_ON(fc->user_ns != current_user_ns()))
goto out_err;
- sb->s_d_op = &ovl_dentry_operations;
+ set_default_d_op(sb, &ovl_dentry_operations);
err = -ENOMEM;
ofs->creator_cred = cred = prepare_creds();
diff --git a/fs/smb/client/cifsfs.c b/fs/smb/client/cifsfs.c
index 6a3bd652d251..5ba1046d1e5a 100644
--- a/fs/smb/client/cifsfs.c
+++ b/fs/smb/client/cifsfs.c
@@ -261,9 +261,9 @@ cifs_read_super(struct super_block *sb)
}
if (tcon->nocase)
- sb->s_d_op = &cifs_ci_dentry_ops;
+ set_default_d_op(sb, &cifs_ci_dentry_ops);
else
- sb->s_d_op = &cifs_dentry_ops;
+ set_default_d_op(sb, &cifs_dentry_ops);
sb->s_root = d_make_root(inode);
if (!sb->s_root) {
diff --git a/fs/tracefs/inode.c b/fs/tracefs/inode.c
index 53214499e384..30a951133831 100644
--- a/fs/tracefs/inode.c
+++ b/fs/tracefs/inode.c
@@ -480,7 +480,7 @@ static int tracefs_fill_super(struct super_block *sb, struct fs_context *fc)
return err;
sb->s_op = &tracefs_super_operations;
- sb->s_d_op = &tracefs_dentry_operations;
+ set_default_d_op(sb, &tracefs_dentry_operations);
return 0;
}
diff --git a/fs/vboxsf/super.c b/fs/vboxsf/super.c
index 1d94bb784108..46eea52beb23 100644
--- a/fs/vboxsf/super.c
+++ b/fs/vboxsf/super.c
@@ -190,7 +190,7 @@ static int vboxsf_fill_super(struct super_block *sb, struct fs_context *fc)
sb->s_blocksize = 1024;
sb->s_maxbytes = MAX_LFS_FILESIZE;
sb->s_op = &vboxsf_super_ops;
- sb->s_d_op = &vboxsf_dentry_ops;
+ set_default_d_op(sb, &vboxsf_dentry_ops);
iroot = iget_locked(sb, 0);
if (!iroot) {
diff --git a/include/linux/dcache.h b/include/linux/dcache.h
index f47f3a47d97b..e8cf1d0fdd08 100644
--- a/include/linux/dcache.h
+++ b/include/linux/dcache.h
@@ -619,4 +619,6 @@ static inline struct dentry *d_next_sibling(const struct dentry *dentry)
return hlist_entry_safe(dentry->d_sib.next, struct dentry, d_sib);
}
+void set_default_d_op(struct super_block *, const struct dentry_operations *);
+
#endif /* __LINUX_DCACHE_H */
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 2c3b2f8a621f..23fd8b0d4e81 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -1405,7 +1405,7 @@ struct super_block {
*/
const char *s_subtype;
- const struct dentry_operations *s_d_op; /* default d_op for dentries */
+ const struct dentry_operations *__s_d_op; /* default d_op for dentries */
struct shrinker *s_shrink; /* per-sb shrinker handle */
diff --git a/mm/shmem.c b/mm/shmem.c
index 4ea6109a8043..0ecb49113bb2 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -5019,7 +5019,7 @@ static int shmem_fill_super(struct super_block *sb, struct fs_context *fc)
if (ctx->encoding) {
sb->s_encoding = ctx->encoding;
- sb->s_d_op = &shmem_ci_dentry_ops;
+ set_default_d_op(sb, &shmem_ci_dentry_ops);
if (ctx->strict_encoding)
sb->s_encoding_flags = SB_ENC_STRICT_MODE_FL;
}
diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c
index eadc00410ebc..e093e4cf20fa 100644
--- a/net/sunrpc/rpc_pipe.c
+++ b/net/sunrpc/rpc_pipe.c
@@ -1363,7 +1363,7 @@ rpc_fill_super(struct super_block *sb, struct fs_context *fc)
sb->s_blocksize_bits = PAGE_SHIFT;
sb->s_magic = RPCAUTH_GSSMAGIC;
sb->s_op = &s_ops;
- sb->s_d_op = &simple_dentry_operations;
+ set_default_d_op(sb, &simple_dentry_operations);
sb->s_time_gran = 1;
inode = rpc_get_inode(sb, S_IFDIR | 0555);
--
2.39.5
^ permalink raw reply related [flat|nested] 87+ messages in thread
* [PATCH 06/21] split d_flags calculation out of d_set_d_op()
2025-02-24 21:20 ` [PATCH 01/21] procfs: kill ->proc_dops Al Viro
` (3 preceding siblings ...)
2025-02-24 21:20 ` [PATCH 05/21] new helper: set_default_d_op() Al Viro
@ 2025-02-24 21:20 ` Al Viro
2025-02-26 8:31 ` Christian Brauner
2025-02-24 21:20 ` [PATCH 07/21] set_default_d_op(): calculate the matching value for ->d_flags Al Viro
` (17 subsequent siblings)
22 siblings, 1 reply; 87+ messages in thread
From: Al Viro @ 2025-02-24 21:20 UTC (permalink / raw)
To: linux-fsdevel
Cc: Linus Torvalds, Christian Brauner, Neil Brown, Miklos Szeredi,
Jan Kara
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/dcache.c | 53 ++++++++++++++++++++++++++++++-----------------------
1 file changed, 30 insertions(+), 23 deletions(-)
diff --git a/fs/dcache.c b/fs/dcache.c
index cd5e5139ca4c..1201149e1e2c 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -1811,33 +1811,40 @@ struct dentry *d_alloc_name(struct dentry *parent, const char *name)
}
EXPORT_SYMBOL(d_alloc_name);
+#define DCACHE_OP_FLAGS \
+ (DCACHE_OP_HASH | DCACHE_OP_COMPARE | DCACHE_OP_REVALIDATE | \
+ DCACHE_OP_WEAK_REVALIDATE | DCACHE_OP_DELETE | DCACHE_OP_REAL)
+
+static unsigned int d_op_flags(const struct dentry_operations *op)
+{
+ unsigned int flags = 0;
+ if (op) {
+ if (op->d_hash)
+ flags |= DCACHE_OP_HASH;
+ if (op->d_compare)
+ flags |= DCACHE_OP_COMPARE;
+ if (op->d_revalidate)
+ flags |= DCACHE_OP_REVALIDATE;
+ if (op->d_weak_revalidate)
+ flags |= DCACHE_OP_WEAK_REVALIDATE;
+ if (op->d_delete)
+ flags |= DCACHE_OP_DELETE;
+ if (op->d_prune)
+ flags |= DCACHE_OP_PRUNE;
+ if (op->d_real)
+ flags |= DCACHE_OP_REAL;
+ }
+ return flags;
+}
+
void d_set_d_op(struct dentry *dentry, const struct dentry_operations *op)
{
+ unsigned int flags = d_op_flags(op);
WARN_ON_ONCE(dentry->d_op);
- WARN_ON_ONCE(dentry->d_flags & (DCACHE_OP_HASH |
- DCACHE_OP_COMPARE |
- DCACHE_OP_REVALIDATE |
- DCACHE_OP_WEAK_REVALIDATE |
- DCACHE_OP_DELETE |
- DCACHE_OP_REAL));
+ WARN_ON_ONCE(dentry->d_flags & DCACHE_OP_FLAGS);
dentry->d_op = op;
- if (!op)
- return;
- if (op->d_hash)
- dentry->d_flags |= DCACHE_OP_HASH;
- if (op->d_compare)
- dentry->d_flags |= DCACHE_OP_COMPARE;
- if (op->d_revalidate)
- dentry->d_flags |= DCACHE_OP_REVALIDATE;
- if (op->d_weak_revalidate)
- dentry->d_flags |= DCACHE_OP_WEAK_REVALIDATE;
- if (op->d_delete)
- dentry->d_flags |= DCACHE_OP_DELETE;
- if (op->d_prune)
- dentry->d_flags |= DCACHE_OP_PRUNE;
- if (op->d_real)
- dentry->d_flags |= DCACHE_OP_REAL;
-
+ if (flags)
+ dentry->d_flags |= flags;
}
EXPORT_SYMBOL(d_set_d_op);
--
2.39.5
^ permalink raw reply related [flat|nested] 87+ messages in thread
* [PATCH 07/21] set_default_d_op(): calculate the matching value for ->d_flags
2025-02-24 21:20 ` [PATCH 01/21] procfs: kill ->proc_dops Al Viro
` (4 preceding siblings ...)
2025-02-24 21:20 ` [PATCH 06/21] split d_flags calculation out of d_set_d_op() Al Viro
@ 2025-02-24 21:20 ` Al Viro
2025-02-26 8:33 ` Christian Brauner
2025-02-24 21:20 ` [PATCH 08/21] simple_lookup(): just set DCACHE_DONTCACHE Al Viro
` (16 subsequent siblings)
22 siblings, 1 reply; 87+ messages in thread
From: Al Viro @ 2025-02-24 21:20 UTC (permalink / raw)
To: linux-fsdevel
Cc: Linus Torvalds, Christian Brauner, Neil Brown, Miklos Szeredi,
Jan Kara
... and store it in ->s_d_flags, to be used in __d_alloc()
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/dcache.c | 6 ++++--
include/linux/fs.h | 1 +
2 files changed, 5 insertions(+), 2 deletions(-)
diff --git a/fs/dcache.c b/fs/dcache.c
index 1201149e1e2c..a4795617c3db 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -1705,14 +1705,14 @@ static struct dentry *__d_alloc(struct super_block *sb, const struct qstr *name)
dentry->d_inode = NULL;
dentry->d_parent = dentry;
dentry->d_sb = sb;
- dentry->d_op = NULL;
+ dentry->d_op = sb->__s_d_op;
+ dentry->d_flags = sb->s_d_flags;
dentry->d_fsdata = NULL;
INIT_HLIST_BL_NODE(&dentry->d_hash);
INIT_LIST_HEAD(&dentry->d_lru);
INIT_HLIST_HEAD(&dentry->d_children);
INIT_HLIST_NODE(&dentry->d_u.d_alias);
INIT_HLIST_NODE(&dentry->d_sib);
- d_set_d_op(dentry, dentry->d_sb->__s_d_op);
if (dentry->d_op && dentry->d_op->d_init) {
err = dentry->d_op->d_init(dentry);
@@ -1850,7 +1850,9 @@ EXPORT_SYMBOL(d_set_d_op);
void set_default_d_op(struct super_block *s, const struct dentry_operations *ops)
{
+ unsigned int flags = d_op_flags(ops);
s->__s_d_op = ops;
+ s->s_d_flags = (s->s_d_flags & ~DCACHE_OP_FLAGS) | flags;
}
EXPORT_SYMBOL(set_default_d_op);
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 23fd8b0d4e81..473a9de5fc8f 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -1392,6 +1392,7 @@ struct super_block {
char s_sysfs_name[UUID_STRING_LEN + 1];
unsigned int s_max_links;
+ unsigned int s_d_flags;
/*
* The next field is for VFS *only*. No filesystems have any business
--
2.39.5
^ permalink raw reply related [flat|nested] 87+ messages in thread
* [PATCH 08/21] simple_lookup(): just set DCACHE_DONTCACHE
2025-02-24 21:20 ` [PATCH 01/21] procfs: kill ->proc_dops Al Viro
` (5 preceding siblings ...)
2025-02-24 21:20 ` [PATCH 07/21] set_default_d_op(): calculate the matching value for ->d_flags Al Viro
@ 2025-02-24 21:20 ` Al Viro
2025-02-26 8:34 ` Christian Brauner
2025-02-24 21:20 ` [PATCH 09/21] make d_set_d_op() static Al Viro
` (15 subsequent siblings)
22 siblings, 1 reply; 87+ messages in thread
From: Al Viro @ 2025-02-24 21:20 UTC (permalink / raw)
To: linux-fsdevel
Cc: Linus Torvalds, Christian Brauner, Neil Brown, Miklos Szeredi,
Jan Kara
No need to mess with ->d_op at all. Note that ->d_delete that always
returns 1 is equivalent to having DCACHE_DONTCACHE in ->d_flags.
Later the same thing will be placed into ->s_d_flags of the filesystems
where we want that behaviour for all dentries; then the check in
simple_lookup() will at least get unlikely() slapped on it.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/libfs.c | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/fs/libfs.c b/fs/libfs.c
index 929bef0fecbd..b15a2148714e 100644
--- a/fs/libfs.c
+++ b/fs/libfs.c
@@ -75,9 +75,11 @@ struct dentry *simple_lookup(struct inode *dir, struct dentry *dentry, unsigned
{
if (dentry->d_name.len > NAME_MAX)
return ERR_PTR(-ENAMETOOLONG);
- if (!dentry->d_op)
- d_set_d_op(dentry, &simple_dentry_operations);
-
+ if (!(dentry->d_flags & DCACHE_DONTCACHE)) {
+ spin_lock(&dentry->d_lock);
+ dentry->d_flags |= DCACHE_DONTCACHE;
+ spin_unlock(&dentry->d_lock);
+ }
if (IS_ENABLED(CONFIG_UNICODE) && IS_CASEFOLDED(dir))
return NULL;
--
2.39.5
^ permalink raw reply related [flat|nested] 87+ messages in thread
* [PATCH 09/21] make d_set_d_op() static
2025-02-24 21:20 ` [PATCH 01/21] procfs: kill ->proc_dops Al Viro
` (6 preceding siblings ...)
2025-02-24 21:20 ` [PATCH 08/21] simple_lookup(): just set DCACHE_DONTCACHE Al Viro
@ 2025-02-24 21:20 ` Al Viro
2025-02-25 23:09 ` NeilBrown
2025-02-26 8:35 ` Christian Brauner
2025-02-24 21:20 ` [PATCH 10/21] d_alloc_parallel(): set DCACHE_PAR_LOOKUP earlier Al Viro
` (14 subsequent siblings)
22 siblings, 2 replies; 87+ messages in thread
From: Al Viro @ 2025-02-24 21:20 UTC (permalink / raw)
To: linux-fsdevel
Cc: Linus Torvalds, Christian Brauner, Neil Brown, Miklos Szeredi,
Jan Kara
Convert the last user (d_alloc_pseudo()) and be done with that.
Any out-of-tree filesystem using it should switch to d_splice_alias_ops()
or, better yet, check whether it really needs to have ->d_op vary among
its dentries.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
Documentation/filesystems/porting.rst | 11 +++++++++++
fs/dcache.c | 5 ++---
include/linux/dcache.h | 1 -
3 files changed, 13 insertions(+), 4 deletions(-)
diff --git a/Documentation/filesystems/porting.rst b/Documentation/filesystems/porting.rst
index 004cd69617a2..61b5771dde53 100644
--- a/Documentation/filesystems/porting.rst
+++ b/Documentation/filesystems/porting.rst
@@ -1164,3 +1164,14 @@ magic.
If your filesystem sets the default dentry_operations, use set_default_d_op()
rather than manually setting sb->s_d_op.
+
+---
+
+**mandatory**
+
+d_set_d_op() is no longer exported (or public, for that matter); _if_
+your filesystem really needed that, make use of d_splice_alias_ops()
+to have them set. Better yet, think hard whether you need different
+->d_op for different dentries - if not, just use set_default_d_op()
+at mount time and be done with that. Currently procfs is the only
+thing that really needs ->d_op varying between dentries.
diff --git a/fs/dcache.c b/fs/dcache.c
index a4795617c3db..29db27228d97 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -1796,7 +1796,7 @@ struct dentry *d_alloc_pseudo(struct super_block *sb, const struct qstr *name)
if (likely(dentry)) {
dentry->d_flags |= DCACHE_NORCU;
if (!dentry->d_op)
- d_set_d_op(dentry, &anon_ops);
+ dentry->d_op = &anon_ops;
}
return dentry;
}
@@ -1837,7 +1837,7 @@ static unsigned int d_op_flags(const struct dentry_operations *op)
return flags;
}
-void d_set_d_op(struct dentry *dentry, const struct dentry_operations *op)
+static void d_set_d_op(struct dentry *dentry, const struct dentry_operations *op)
{
unsigned int flags = d_op_flags(op);
WARN_ON_ONCE(dentry->d_op);
@@ -1846,7 +1846,6 @@ void d_set_d_op(struct dentry *dentry, const struct dentry_operations *op)
if (flags)
dentry->d_flags |= flags;
}
-EXPORT_SYMBOL(d_set_d_op);
void set_default_d_op(struct super_block *s, const struct dentry_operations *ops)
{
diff --git a/include/linux/dcache.h b/include/linux/dcache.h
index e8cf1d0fdd08..5a03e85f92a4 100644
--- a/include/linux/dcache.h
+++ b/include/linux/dcache.h
@@ -242,7 +242,6 @@ extern void d_instantiate_new(struct dentry *, struct inode *);
extern void __d_drop(struct dentry *dentry);
extern void d_drop(struct dentry *dentry);
extern void d_delete(struct dentry *);
-extern void d_set_d_op(struct dentry *dentry, const struct dentry_operations *op);
/* allocate/de-allocate */
extern struct dentry * d_alloc(struct dentry *, const struct qstr *);
--
2.39.5
^ permalink raw reply related [flat|nested] 87+ messages in thread
* [PATCH 10/21] d_alloc_parallel(): set DCACHE_PAR_LOOKUP earlier
2025-02-24 21:20 ` [PATCH 01/21] procfs: kill ->proc_dops Al Viro
` (7 preceding siblings ...)
2025-02-24 21:20 ` [PATCH 09/21] make d_set_d_op() static Al Viro
@ 2025-02-24 21:20 ` Al Viro
2025-02-26 8:36 ` Christian Brauner
2025-02-24 21:20 ` [PATCH 11/21] nsfs, pidfs: drop the pointless ->d_delete() Al Viro
` (13 subsequent siblings)
22 siblings, 1 reply; 87+ messages in thread
From: Al Viro @ 2025-02-24 21:20 UTC (permalink / raw)
To: linux-fsdevel
Cc: Linus Torvalds, Christian Brauner, Neil Brown, Miklos Szeredi,
Jan Kara
Do that before new dentry is visible anywhere. It does create
a new possible state for dentries present in ->d_children/->d_sib -
DCACHE_PAR_LOOKUP present, negative, unhashed, not in in-lookup
hash chains, refcount positive. Those are going to be skipped
by all tree-walkers (both d_walk() callbacks in fs/dcache.c and
explicit loops over children/sibling lists elsewhere) and
dput() is fine with those.
NOTE: dropping the final reference to a "normal" in-lookup dentry
(in in-lookup hash) is a bug - somebody must've forgotten to
call d_lookup_done() on it and bad things will happen. With those
it's OK; if/when we get around to making __dentry_kill() complain
about such breakage, remember that predicate to check should
*not* be just d_in_lookup(victim) but rather a combination of that
with hlist_bl_unhashed(&victim->d_u.d_in_lookup_hash). Might
be worth to consider later...
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/dcache.c | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)
diff --git a/fs/dcache.c b/fs/dcache.c
index 29db27228d97..9ad7cbb5a6b0 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -2518,13 +2518,19 @@ struct dentry *d_alloc_parallel(struct dentry *parent,
unsigned int hash = name->hash;
struct hlist_bl_head *b = in_lookup_hash(parent, hash);
struct hlist_bl_node *node;
- struct dentry *new = d_alloc(parent, name);
+ struct dentry *new = __d_alloc(parent->d_sb, name);
struct dentry *dentry;
unsigned seq, r_seq, d_seq;
if (unlikely(!new))
return ERR_PTR(-ENOMEM);
+ new->d_flags |= DCACHE_PAR_LOOKUP;
+ spin_lock(&parent->d_lock);
+ new->d_parent = dget_dlock(parent);
+ hlist_add_head(&new->d_sib, &parent->d_children);
+ spin_unlock(&parent->d_lock);
+
retry:
rcu_read_lock();
seq = smp_load_acquire(&parent->d_inode->i_dir_seq);
@@ -2608,8 +2614,6 @@ struct dentry *d_alloc_parallel(struct dentry *parent,
return dentry;
}
rcu_read_unlock();
- /* we can't take ->d_lock here; it's OK, though. */
- new->d_flags |= DCACHE_PAR_LOOKUP;
new->d_wait = wq;
hlist_bl_add_head(&new->d_u.d_in_lookup_hash, b);
hlist_bl_unlock(b);
--
2.39.5
^ permalink raw reply related [flat|nested] 87+ messages in thread
* [PATCH 11/21] nsfs, pidfs: drop the pointless ->d_delete()
2025-02-24 21:20 ` [PATCH 01/21] procfs: kill ->proc_dops Al Viro
` (8 preceding siblings ...)
2025-02-24 21:20 ` [PATCH 10/21] d_alloc_parallel(): set DCACHE_PAR_LOOKUP earlier Al Viro
@ 2025-02-24 21:20 ` Al Viro
2025-02-26 8:37 ` Christian Brauner
2025-02-24 21:20 ` [PATCH 12/21] shmem: no dentry retention past the refcount reaching zero Al Viro
` (12 subsequent siblings)
22 siblings, 1 reply; 87+ messages in thread
From: Al Viro @ 2025-02-24 21:20 UTC (permalink / raw)
To: linux-fsdevel
Cc: Linus Torvalds, Christian Brauner, Neil Brown, Miklos Szeredi,
Jan Kara
No dentries are ever hashed on those, so ->d_delete() wouldn't be
even looked at. If it's unhashed, we are not retaining it in dcache
once the refcount hits zero, no matter what.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/nsfs.c | 1 -
fs/pidfs.c | 1 -
2 files changed, 2 deletions(-)
diff --git a/fs/nsfs.c b/fs/nsfs.c
index 663f8656158d..f7fddf8ecf73 100644
--- a/fs/nsfs.c
+++ b/fs/nsfs.c
@@ -37,7 +37,6 @@ static char *ns_dname(struct dentry *dentry, char *buffer, int buflen)
}
const struct dentry_operations ns_dentry_operations = {
- .d_delete = always_delete_dentry,
.d_dname = ns_dname,
.d_prune = stashed_dentry_prune,
};
diff --git a/fs/pidfs.c b/fs/pidfs.c
index 63f9699ebac3..c0478b3c55d9 100644
--- a/fs/pidfs.c
+++ b/fs/pidfs.c
@@ -521,7 +521,6 @@ static char *pidfs_dname(struct dentry *dentry, char *buffer, int buflen)
}
const struct dentry_operations pidfs_dentry_operations = {
- .d_delete = always_delete_dentry,
.d_dname = pidfs_dname,
.d_prune = stashed_dentry_prune,
};
--
2.39.5
^ permalink raw reply related [flat|nested] 87+ messages in thread
* [PATCH 12/21] shmem: no dentry retention past the refcount reaching zero
2025-02-24 21:20 ` [PATCH 01/21] procfs: kill ->proc_dops Al Viro
` (9 preceding siblings ...)
2025-02-24 21:20 ` [PATCH 11/21] nsfs, pidfs: drop the pointless ->d_delete() Al Viro
@ 2025-02-24 21:20 ` Al Viro
2025-02-26 8:38 ` Christian Brauner
2025-02-24 21:20 ` [PATCH 13/21] devpts, sunrpc: don't bother with ->d_delete or ->d_op, for that matter Al Viro
` (11 subsequent siblings)
22 siblings, 1 reply; 87+ messages in thread
From: Al Viro @ 2025-02-24 21:20 UTC (permalink / raw)
To: linux-fsdevel
Cc: Linus Torvalds, Christian Brauner, Neil Brown, Miklos Szeredi,
Jan Kara
Just set DCACHE_DONTCACHE in ->s_d_flags and be done with that.
Dentries there live for as long as they are pinned; once the
refcount hits zero, that's it. The same, of course, goes for
other tree-in-dcache filesystems - more in the next commits...
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
mm/shmem.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/mm/shmem.c b/mm/shmem.c
index 0ecb49113bb2..dd84b1c554a8 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -4971,7 +4971,6 @@ static void shmem_put_super(struct super_block *sb)
static const struct dentry_operations shmem_ci_dentry_ops = {
.d_hash = generic_ci_d_hash,
.d_compare = generic_ci_d_compare,
- .d_delete = always_delete_dentry,
};
#endif
@@ -5028,6 +5027,7 @@ static int shmem_fill_super(struct super_block *sb, struct fs_context *fc)
#else
sb->s_flags |= SB_NOUSER;
#endif /* CONFIG_TMPFS */
+ sb->s_d_flags |= DCACHE_DONTCACHE;
sbinfo->max_blocks = ctx->blocks;
sbinfo->max_inodes = ctx->inodes;
sbinfo->free_ispace = sbinfo->max_inodes * BOGO_INODE_SIZE;
--
2.39.5
^ permalink raw reply related [flat|nested] 87+ messages in thread
* [PATCH 13/21] devpts, sunrpc: don't bother with ->d_delete or ->d_op, for that matter
2025-02-24 21:20 ` [PATCH 01/21] procfs: kill ->proc_dops Al Viro
` (10 preceding siblings ...)
2025-02-24 21:20 ` [PATCH 12/21] shmem: no dentry retention past the refcount reaching zero Al Viro
@ 2025-02-24 21:20 ` Al Viro
2025-02-26 8:38 ` Christian Brauner
2025-02-24 21:20 ` [PATCH 14/21] hostfs: don't bother with ->d_op Al Viro
` (10 subsequent siblings)
22 siblings, 1 reply; 87+ messages in thread
From: Al Viro @ 2025-02-24 21:20 UTC (permalink / raw)
To: linux-fsdevel
Cc: Linus Torvalds, Christian Brauner, Neil Brown, Miklos Szeredi,
Jan Kara
Just put DCACHE_DONTCACHE into ->s_d_flags.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/devpts/inode.c | 2 +-
net/sunrpc/rpc_pipe.c | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/fs/devpts/inode.c b/fs/devpts/inode.c
index f092973236ef..39344af02d1f 100644
--- a/fs/devpts/inode.c
+++ b/fs/devpts/inode.c
@@ -433,7 +433,7 @@ devpts_fill_super(struct super_block *s, void *data, int silent)
s->s_blocksize_bits = 10;
s->s_magic = DEVPTS_SUPER_MAGIC;
s->s_op = &devpts_sops;
- set_default_d_op(s, &simple_dentry_operations);
+ s->s_d_flags = DCACHE_DONTCACHE;
s->s_time_gran = 1;
error = -ENOMEM;
diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c
index e093e4cf20fa..acb28a502580 100644
--- a/net/sunrpc/rpc_pipe.c
+++ b/net/sunrpc/rpc_pipe.c
@@ -1363,7 +1363,7 @@ rpc_fill_super(struct super_block *sb, struct fs_context *fc)
sb->s_blocksize_bits = PAGE_SHIFT;
sb->s_magic = RPCAUTH_GSSMAGIC;
sb->s_op = &s_ops;
- set_default_d_op(sb, &simple_dentry_operations);
+ sb->s_d_flags = DCACHE_DONTCACHE;
sb->s_time_gran = 1;
inode = rpc_get_inode(sb, S_IFDIR | 0555);
--
2.39.5
^ permalink raw reply related [flat|nested] 87+ messages in thread
* [PATCH 14/21] hostfs: don't bother with ->d_op
2025-02-24 21:20 ` [PATCH 01/21] procfs: kill ->proc_dops Al Viro
` (11 preceding siblings ...)
2025-02-24 21:20 ` [PATCH 13/21] devpts, sunrpc: don't bother with ->d_delete or ->d_op, for that matter Al Viro
@ 2025-02-24 21:20 ` Al Viro
2025-02-26 8:38 ` Christian Brauner
2025-02-24 21:20 ` [PATCH 15/21] kill simple_dentry_operations Al Viro
` (9 subsequent siblings)
22 siblings, 1 reply; 87+ messages in thread
From: Al Viro @ 2025-02-24 21:20 UTC (permalink / raw)
To: linux-fsdevel
Cc: Linus Torvalds, Christian Brauner, Neil Brown, Miklos Szeredi,
Jan Kara
All we have there is ->d_delete equal to always_delete_dentry() and we
want that for all dentries on that things. Setting DCACHE_DONTCACHE in
->s_d_flags will do just that.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/hostfs/hostfs_kern.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c
index a0e0563a29d7..52479205cefe 100644
--- a/fs/hostfs/hostfs_kern.c
+++ b/fs/hostfs/hostfs_kern.c
@@ -920,7 +920,7 @@ static int hostfs_fill_super(struct super_block *sb, struct fs_context *fc)
sb->s_blocksize_bits = 10;
sb->s_magic = HOSTFS_SUPER_MAGIC;
sb->s_op = &hostfs_sbops;
- set_default_d_op(sb, &simple_dentry_operations);
+ sb->s_d_flags = DCACHE_DONTCACHE;
sb->s_maxbytes = MAX_LFS_FILESIZE;
err = super_setup_bdi(sb);
if (err)
--
2.39.5
^ permalink raw reply related [flat|nested] 87+ messages in thread
* [PATCH 15/21] kill simple_dentry_operations
2025-02-24 21:20 ` [PATCH 01/21] procfs: kill ->proc_dops Al Viro
` (12 preceding siblings ...)
2025-02-24 21:20 ` [PATCH 14/21] hostfs: don't bother with ->d_op Al Viro
@ 2025-02-24 21:20 ` Al Viro
2025-02-26 8:39 ` Christian Brauner
2025-02-24 21:20 ` [PATCH 16/21] ramfs, hugetlbfs, mqueue: set DCACHE_DONTCACHE Al Viro
` (8 subsequent siblings)
22 siblings, 1 reply; 87+ messages in thread
From: Al Viro @ 2025-02-24 21:20 UTC (permalink / raw)
To: linux-fsdevel
Cc: Linus Torvalds, Christian Brauner, Neil Brown, Miklos Szeredi,
Jan Kara
No users left and anything that wants it would be better off just
setting DCACHE_DONTCACHE in their ->s_d_flags.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/libfs.c | 5 -----
include/linux/fs.h | 1 -
2 files changed, 6 deletions(-)
diff --git a/fs/libfs.c b/fs/libfs.c
index b15a2148714e..7eebaee9d082 100644
--- a/fs/libfs.c
+++ b/fs/libfs.c
@@ -62,11 +62,6 @@ int always_delete_dentry(const struct dentry *dentry)
}
EXPORT_SYMBOL(always_delete_dentry);
-const struct dentry_operations simple_dentry_operations = {
- .d_delete = always_delete_dentry,
-};
-EXPORT_SYMBOL(simple_dentry_operations);
-
/*
* Lookup the data. This is trivial - if the dentry didn't already
* exist, we know it is negative. Set d_op to delete negative dentries.
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 473a9de5fc8f..bdaf2f85e1ad 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -3540,7 +3540,6 @@ extern const struct address_space_operations ram_aops;
extern int always_delete_dentry(const struct dentry *);
extern struct inode *alloc_anon_inode(struct super_block *);
extern int simple_nosetlease(struct file *, int, struct file_lease **, void **);
-extern const struct dentry_operations simple_dentry_operations;
extern struct dentry *simple_lookup(struct inode *, struct dentry *, unsigned int flags);
extern ssize_t generic_read_dir(struct file *, char __user *, size_t, loff_t *);
--
2.39.5
^ permalink raw reply related [flat|nested] 87+ messages in thread
* [PATCH 16/21] ramfs, hugetlbfs, mqueue: set DCACHE_DONTCACHE
2025-02-24 21:20 ` [PATCH 01/21] procfs: kill ->proc_dops Al Viro
` (13 preceding siblings ...)
2025-02-24 21:20 ` [PATCH 15/21] kill simple_dentry_operations Al Viro
@ 2025-02-24 21:20 ` Al Viro
2025-02-25 23:25 ` NeilBrown
2025-02-26 8:39 ` Christian Brauner
2025-02-24 21:20 ` [PATCH 17/21] 9p: don't bother with always_delete_dentry Al Viro
` (7 subsequent siblings)
22 siblings, 2 replies; 87+ messages in thread
From: Al Viro @ 2025-02-24 21:20 UTC (permalink / raw)
To: linux-fsdevel
Cc: Linus Torvalds, Christian Brauner, Neil Brown, Miklos Szeredi,
Jan Kara
makes simple_lookup() slightly cheaper there.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/hugetlbfs/inode.c | 1 +
fs/ramfs/inode.c | 1 +
ipc/mqueue.c | 1 +
3 files changed, 3 insertions(+)
diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c
index 0fc179a59830..205dd7562be1 100644
--- a/fs/hugetlbfs/inode.c
+++ b/fs/hugetlbfs/inode.c
@@ -1431,6 +1431,7 @@ hugetlbfs_fill_super(struct super_block *sb, struct fs_context *fc)
sb->s_blocksize_bits = huge_page_shift(ctx->hstate);
sb->s_magic = HUGETLBFS_MAGIC;
sb->s_op = &hugetlbfs_ops;
+ sb->s_d_flags = DCACHE_DONTCACHE;
sb->s_time_gran = 1;
/*
diff --git a/fs/ramfs/inode.c b/fs/ramfs/inode.c
index 8006faaaf0ec..c4ee67870c4b 100644
--- a/fs/ramfs/inode.c
+++ b/fs/ramfs/inode.c
@@ -269,6 +269,7 @@ static int ramfs_fill_super(struct super_block *sb, struct fs_context *fc)
sb->s_blocksize_bits = PAGE_SHIFT;
sb->s_magic = RAMFS_MAGIC;
sb->s_op = &ramfs_ops;
+ sb->s_d_flags = DCACHE_DONTCACHE;
sb->s_time_gran = 1;
inode = ramfs_get_inode(sb, NULL, S_IFDIR | fsi->mount_opts.mode, 0);
diff --git a/ipc/mqueue.c b/ipc/mqueue.c
index 35b4f8659904..dbd5c74eecb2 100644
--- a/ipc/mqueue.c
+++ b/ipc/mqueue.c
@@ -411,6 +411,7 @@ static int mqueue_fill_super(struct super_block *sb, struct fs_context *fc)
sb->s_blocksize_bits = PAGE_SHIFT;
sb->s_magic = MQUEUE_MAGIC;
sb->s_op = &mqueue_super_ops;
+ sb->s_d_flags = DCACHE_DONTCACHE;
inode = mqueue_get_inode(sb, ns, S_IFDIR | S_ISVTX | S_IRWXUGO, NULL);
if (IS_ERR(inode))
--
2.39.5
^ permalink raw reply related [flat|nested] 87+ messages in thread
* [PATCH 17/21] 9p: don't bother with always_delete_dentry
2025-02-24 21:20 ` [PATCH 01/21] procfs: kill ->proc_dops Al Viro
` (14 preceding siblings ...)
2025-02-24 21:20 ` [PATCH 16/21] ramfs, hugetlbfs, mqueue: set DCACHE_DONTCACHE Al Viro
@ 2025-02-24 21:20 ` Al Viro
2025-02-26 8:40 ` Christian Brauner
2025-02-24 21:20 ` [PATCH 18/21] efivarfs: use DCACHE_DONTCACHE instead of always_delete_dentry() Al Viro
` (6 subsequent siblings)
22 siblings, 1 reply; 87+ messages in thread
From: Al Viro @ 2025-02-24 21:20 UTC (permalink / raw)
To: linux-fsdevel
Cc: Linus Torvalds, Christian Brauner, Neil Brown, Miklos Szeredi,
Jan Kara
just set DCACHE_DONTCACHE for "don't cache" mounts...
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/9p/vfs_dentry.c | 1 -
fs/9p/vfs_super.c | 6 ++++--
2 files changed, 4 insertions(+), 3 deletions(-)
diff --git a/fs/9p/vfs_dentry.c b/fs/9p/vfs_dentry.c
index 5061f192eafd..04795508a795 100644
--- a/fs/9p/vfs_dentry.c
+++ b/fs/9p/vfs_dentry.c
@@ -127,7 +127,6 @@ const struct dentry_operations v9fs_cached_dentry_operations = {
};
const struct dentry_operations v9fs_dentry_operations = {
- .d_delete = always_delete_dentry,
.d_release = v9fs_dentry_release,
.d_unalias_trylock = v9fs_dentry_unalias_trylock,
.d_unalias_unlock = v9fs_dentry_unalias_unlock,
diff --git a/fs/9p/vfs_super.c b/fs/9p/vfs_super.c
index 5c3dc3efb909..795c6388744c 100644
--- a/fs/9p/vfs_super.c
+++ b/fs/9p/vfs_super.c
@@ -134,10 +134,12 @@ static struct dentry *v9fs_mount(struct file_system_type *fs_type, int flags,
if (retval)
goto release_sb;
- if (v9ses->cache & (CACHE_META|CACHE_LOOSE))
+ if (v9ses->cache & (CACHE_META|CACHE_LOOSE)) {
set_default_d_op(sb, &v9fs_cached_dentry_operations);
- else
+ } else {
set_default_d_op(sb, &v9fs_dentry_operations);
+ sb->s_d_flags |= DCACHE_DONTCACHE;
+ }
inode = v9fs_get_new_inode_from_fid(v9ses, fid, sb);
if (IS_ERR(inode)) {
--
2.39.5
^ permalink raw reply related [flat|nested] 87+ messages in thread
* [PATCH 18/21] efivarfs: use DCACHE_DONTCACHE instead of always_delete_dentry()
2025-02-24 21:20 ` [PATCH 01/21] procfs: kill ->proc_dops Al Viro
` (15 preceding siblings ...)
2025-02-24 21:20 ` [PATCH 17/21] 9p: don't bother with always_delete_dentry Al Viro
@ 2025-02-24 21:20 ` Al Viro
2025-02-26 8:40 ` Christian Brauner
2025-02-24 21:20 ` [PATCH 19/21] debugfs: use DCACHE_DONTCACHE Al Viro
` (5 subsequent siblings)
22 siblings, 1 reply; 87+ messages in thread
From: Al Viro @ 2025-02-24 21:20 UTC (permalink / raw)
To: linux-fsdevel
Cc: Linus Torvalds, Christian Brauner, Neil Brown, Miklos Szeredi,
Jan Kara
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/efivarfs/super.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/fs/efivarfs/super.c b/fs/efivarfs/super.c
index 3f3188e0cfa7..e5d3147cfcea 100644
--- a/fs/efivarfs/super.c
+++ b/fs/efivarfs/super.c
@@ -175,7 +175,6 @@ static int efivarfs_d_hash(const struct dentry *dentry, struct qstr *qstr)
static const struct dentry_operations efivarfs_d_ops = {
.d_compare = efivarfs_d_compare,
.d_hash = efivarfs_d_hash,
- .d_delete = always_delete_dentry,
};
static struct dentry *efivarfs_alloc_dentry(struct dentry *parent, char *name)
@@ -346,6 +345,7 @@ static int efivarfs_fill_super(struct super_block *sb, struct fs_context *fc)
sb->s_magic = EFIVARFS_MAGIC;
sb->s_op = &efivarfs_ops;
set_default_d_op(sb, &efivarfs_d_ops);
+ sb->s_d_flags |= DCACHE_DONTCACHE;
sb->s_time_gran = 1;
if (!efivar_supports_writes())
--
2.39.5
^ permalink raw reply related [flat|nested] 87+ messages in thread
* [PATCH 19/21] debugfs: use DCACHE_DONTCACHE
2025-02-24 21:20 ` [PATCH 01/21] procfs: kill ->proc_dops Al Viro
` (16 preceding siblings ...)
2025-02-24 21:20 ` [PATCH 18/21] efivarfs: use DCACHE_DONTCACHE instead of always_delete_dentry() Al Viro
@ 2025-02-24 21:20 ` Al Viro
2025-02-26 8:40 ` Christian Brauner
2025-02-24 21:20 ` [PATCH 20/21] configfs: " Al Viro
` (4 subsequent siblings)
22 siblings, 1 reply; 87+ messages in thread
From: Al Viro @ 2025-02-24 21:20 UTC (permalink / raw)
To: linux-fsdevel
Cc: Linus Torvalds, Christian Brauner, Neil Brown, Miklos Szeredi,
Jan Kara
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/debugfs/inode.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c
index f54a8fd960e4..1c71d9932a67 100644
--- a/fs/debugfs/inode.c
+++ b/fs/debugfs/inode.c
@@ -258,7 +258,6 @@ static struct vfsmount *debugfs_automount(struct path *path)
}
static const struct dentry_operations debugfs_dops = {
- .d_delete = always_delete_dentry,
.d_release = debugfs_release_dentry,
.d_automount = debugfs_automount,
};
@@ -274,6 +273,7 @@ static int debugfs_fill_super(struct super_block *sb, struct fs_context *fc)
sb->s_op = &debugfs_super_operations;
set_default_d_op(sb, &debugfs_dops);
+ sb->s_d_flags |= DCACHE_DONTCACHE;
debugfs_apply_options(sb);
--
2.39.5
^ permalink raw reply related [flat|nested] 87+ messages in thread
* [PATCH 20/21] configfs: use DCACHE_DONTCACHE
2025-02-24 21:20 ` [PATCH 01/21] procfs: kill ->proc_dops Al Viro
` (17 preceding siblings ...)
2025-02-24 21:20 ` [PATCH 19/21] debugfs: use DCACHE_DONTCACHE Al Viro
@ 2025-02-24 21:20 ` Al Viro
2025-02-26 8:40 ` Christian Brauner
2025-02-24 21:20 ` [PATCH 21/21] afs dynroot: " Al Viro
` (3 subsequent siblings)
22 siblings, 1 reply; 87+ messages in thread
From: Al Viro @ 2025-02-24 21:20 UTC (permalink / raw)
To: linux-fsdevel
Cc: Linus Torvalds, Christian Brauner, Neil Brown, Miklos Szeredi,
Jan Kara
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/configfs/dir.c | 1 -
fs/configfs/mount.c | 1 +
2 files changed, 1 insertion(+), 1 deletion(-)
diff --git a/fs/configfs/dir.c b/fs/configfs/dir.c
index 7d10278db30d..637267a76ad8 100644
--- a/fs/configfs/dir.c
+++ b/fs/configfs/dir.c
@@ -67,7 +67,6 @@ static void configfs_d_iput(struct dentry * dentry,
const struct dentry_operations configfs_dentry_ops = {
.d_iput = configfs_d_iput,
- .d_delete = always_delete_dentry,
};
#ifdef CONFIG_LOCKDEP
diff --git a/fs/configfs/mount.c b/fs/configfs/mount.c
index 20412eaca972..740f18b60c9d 100644
--- a/fs/configfs/mount.c
+++ b/fs/configfs/mount.c
@@ -93,6 +93,7 @@ static int configfs_fill_super(struct super_block *sb, struct fs_context *fc)
root->d_fsdata = &configfs_root;
sb->s_root = root;
set_default_d_op(sb, &configfs_dentry_ops); /* the rest get that */
+ sb->s_d_flags |= DCACHE_DONTCACHE;
return 0;
}
--
2.39.5
^ permalink raw reply related [flat|nested] 87+ messages in thread
* [PATCH 21/21] afs dynroot: use DCACHE_DONTCACHE
2025-02-24 21:20 ` [PATCH 01/21] procfs: kill ->proc_dops Al Viro
` (18 preceding siblings ...)
2025-02-24 21:20 ` [PATCH 20/21] configfs: " Al Viro
@ 2025-02-24 21:20 ` Al Viro
2025-02-26 8:41 ` Christian Brauner
2025-02-25 15:55 ` [PATCH 01/21] procfs: kill ->proc_dops Jan Kara
` (2 subsequent siblings)
22 siblings, 1 reply; 87+ messages in thread
From: Al Viro @ 2025-02-24 21:20 UTC (permalink / raw)
To: linux-fsdevel
Cc: Linus Torvalds, Christian Brauner, Neil Brown, Miklos Szeredi,
Jan Kara
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/afs/dynroot.c | 1 -
fs/afs/super.c | 1 +
2 files changed, 1 insertion(+), 1 deletion(-)
diff --git a/fs/afs/dynroot.c b/fs/afs/dynroot.c
index d8bf52f77d93..2fad2987a6dc 100644
--- a/fs/afs/dynroot.c
+++ b/fs/afs/dynroot.c
@@ -211,7 +211,6 @@ const struct inode_operations afs_dynroot_inode_operations = {
};
const struct dentry_operations afs_dynroot_dentry_operations = {
- .d_delete = always_delete_dentry,
.d_release = afs_d_release,
.d_automount = afs_d_automount,
};
diff --git a/fs/afs/super.c b/fs/afs/super.c
index 13d0414a1ddb..b48f524c1cb6 100644
--- a/fs/afs/super.c
+++ b/fs/afs/super.c
@@ -488,6 +488,7 @@ static int afs_fill_super(struct super_block *sb, struct afs_fs_context *ctx)
if (as->dyn_root) {
set_default_d_op(sb, &afs_dynroot_dentry_operations);
+ sb->s_d_flags |= DCACHE_DONTCACHE;
ret = afs_dynroot_populate(sb);
if (ret < 0)
goto error;
--
2.39.5
^ permalink raw reply related [flat|nested] 87+ messages in thread
* Re: [PATCH 01/21] procfs: kill ->proc_dops
2025-02-24 21:20 ` [PATCH 01/21] procfs: kill ->proc_dops Al Viro
` (19 preceding siblings ...)
2025-02-24 21:20 ` [PATCH 21/21] afs dynroot: " Al Viro
@ 2025-02-25 15:55 ` Jan Kara
2025-02-25 23:30 ` NeilBrown
2025-02-25 22:51 ` NeilBrown
2025-02-26 8:25 ` Christian Brauner
22 siblings, 1 reply; 87+ messages in thread
From: Jan Kara @ 2025-02-25 15:55 UTC (permalink / raw)
To: Al Viro
Cc: linux-fsdevel, Linus Torvalds, Christian Brauner, Neil Brown,
Miklos Szeredi, Jan Kara
On Mon 24-02-25 21:20:31, Al Viro wrote:
> It has two possible values - one for "forced lookup" entries, another
> for the normal ones. We'd be better off with that as an explicit
> flag anyway and in addition to that it opens some fun possibilities
> with ->d_op and ->d_flags handling.
>
> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
FWIW I went through the patches and I like them. They look mostly
straightforward enough to me and as good simplifications.
Honza
> ---
> fs/proc/generic.c | 8 +++++---
> fs/proc/internal.h | 5 +++--
> 2 files changed, 8 insertions(+), 5 deletions(-)
>
> diff --git a/fs/proc/generic.c b/fs/proc/generic.c
> index 8ec90826a49e..499c2bf67488 100644
> --- a/fs/proc/generic.c
> +++ b/fs/proc/generic.c
> @@ -254,7 +254,10 @@ struct dentry *proc_lookup_de(struct inode *dir, struct dentry *dentry,
> inode = proc_get_inode(dir->i_sb, de);
> if (!inode)
> return ERR_PTR(-ENOMEM);
> - d_set_d_op(dentry, de->proc_dops);
> + if (de->flags & PROC_ENTRY_FORCE_LOOKUP)
> + d_set_d_op(dentry, &proc_net_dentry_ops);
> + else
> + d_set_d_op(dentry, &proc_misc_dentry_ops);
> return d_splice_alias(inode, dentry);
> }
> read_unlock(&proc_subdir_lock);
> @@ -448,9 +451,8 @@ static struct proc_dir_entry *__proc_create(struct proc_dir_entry **parent,
> INIT_LIST_HEAD(&ent->pde_openers);
> proc_set_user(ent, (*parent)->uid, (*parent)->gid);
>
> - ent->proc_dops = &proc_misc_dentry_ops;
> /* Revalidate everything under /proc/${pid}/net */
> - if ((*parent)->proc_dops == &proc_net_dentry_ops)
> + if ((*parent)->flags & PROC_ENTRY_FORCE_LOOKUP)
> pde_force_lookup(ent);
>
> out:
> diff --git a/fs/proc/internal.h b/fs/proc/internal.h
> index 1695509370b8..07f75c959173 100644
> --- a/fs/proc/internal.h
> +++ b/fs/proc/internal.h
> @@ -44,7 +44,6 @@ struct proc_dir_entry {
> const struct proc_ops *proc_ops;
> const struct file_operations *proc_dir_ops;
> };
> - const struct dentry_operations *proc_dops;
> union {
> const struct seq_operations *seq_ops;
> int (*single_show)(struct seq_file *, void *);
> @@ -67,6 +66,8 @@ struct proc_dir_entry {
> char inline_name[];
> } __randomize_layout;
>
> +#define PROC_ENTRY_FORCE_LOOKUP 2 /* same space as PROC_ENTRY_PERMANENT */
> +
> #define SIZEOF_PDE ( \
> sizeof(struct proc_dir_entry) < 128 ? 128 : \
> sizeof(struct proc_dir_entry) < 192 ? 192 : \
> @@ -346,7 +347,7 @@ extern const struct dentry_operations proc_net_dentry_ops;
> static inline void pde_force_lookup(struct proc_dir_entry *pde)
> {
> /* /proc/net/ entries can be changed under us by setns(CLONE_NEWNET) */
> - pde->proc_dops = &proc_net_dentry_ops;
> + pde->flags |= PROC_ENTRY_FORCE_LOOKUP;
> }
>
> /*
> --
> 2.39.5
>
--
Jan Kara <jack@suse.com>
SUSE Labs, CR
^ permalink raw reply [flat|nested] 87+ messages in thread
* Re: [RFC] dentry->d_flags locking
2025-02-24 14:07 ` [RFC] " Miklos Szeredi
@ 2025-02-25 17:56 ` Al Viro
0 siblings, 0 replies; 87+ messages in thread
From: Al Viro @ 2025-02-25 17:56 UTC (permalink / raw)
To: Miklos Szeredi
Cc: linux-fsdevel, Linus Torvalds, Neil Brown, Christian Brauner,
Jan Kara
On Mon, Feb 24, 2025 at 03:07:03PM +0100, Miklos Szeredi wrote:
> On Mon, 24 Feb 2025 at 02:06, Al Viro <viro@zeniv.linux.org.uk> wrote:
>
> > PS: turns out that set_default_d_op() is slightly more interesting
> > than I expected - fuse has separate dentry_operations for its
> > root dentry. I don't see the point, TBH - the only difference is
> > that root one lacks
> > * ->d_delete() (never even called for root dentry; it's
> > only called if d_unhashed() is false)
> > * ->d_revalidate() (never called for root)
> > * ->d_automount() (not even looked at unless you have
> > S_AUTOMOUNT set on the inode).
> > What's wrong with using fuse_dentry_operations for root dentry?
> > Am I missing something subtle here? Miklos?
>
> Looks like a historical accident:
>
> - initial version only had .d_revalidate and only set d_op in .loookup.
> - then it grew .d_init/.d_release
> - then, as a bugfix, the separate fuse_root_dentry_operations was added
Speaking of historical accidents - "seqlock: Add a new locking reader type"
(introduction of read_seqlock_excl()) happened a week after your
"vfs: check unlinked ancestors before mount" (Sep 12 and Sep 5 2013, resp.)
I'm switching d_set_mounted() from write_seqlock(&rename_lock); to
read_seqlock_excl(&rename_lock) - we need exclusion with movers,
but there's no need for anyone to retry ancestry chains or hash lookups
just because we have marked something as a mountpoint.
IOW, it's a reader, not writer; we can't replace it with need_seqretry
loop without more audit of d_mountpoint() callers I want to mess with
at the moment[*], but exclusive reader is fine.
[*] the ones under ->d_lock are not a problem and so are all that
are followed by "check if something's mounted in our namespace,
ignore if there isn't" as well as the ones that have an exclusion with
the caller of d_set_mounted(), but for now let's not go there.
^ permalink raw reply [flat|nested] 87+ messages in thread
* Re: [PATCH 01/21] procfs: kill ->proc_dops
2025-02-24 21:20 ` [PATCH 01/21] procfs: kill ->proc_dops Al Viro
` (20 preceding siblings ...)
2025-02-25 15:55 ` [PATCH 01/21] procfs: kill ->proc_dops Jan Kara
@ 2025-02-25 22:51 ` NeilBrown
2025-02-26 0:03 ` Al Viro
2025-02-26 8:25 ` Christian Brauner
22 siblings, 1 reply; 87+ messages in thread
From: NeilBrown @ 2025-02-25 22:51 UTC (permalink / raw)
To: Al Viro
Cc: linux-fsdevel, Linus Torvalds, Christian Brauner, Miklos Szeredi,
Jan Kara
On Tue, 25 Feb 2025, Al Viro wrote:
> It has two possible values - one for "forced lookup" entries, another
> for the normal ones. We'd be better off with that as an explicit
> flag anyway and in addition to that it opens some fun possibilities
> with ->d_op and ->d_flags handling.
>
> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
> ---
> fs/proc/generic.c | 8 +++++---
> fs/proc/internal.h | 5 +++--
> 2 files changed, 8 insertions(+), 5 deletions(-)
>
> diff --git a/fs/proc/generic.c b/fs/proc/generic.c
> index 8ec90826a49e..499c2bf67488 100644
> --- a/fs/proc/generic.c
> +++ b/fs/proc/generic.c
> @@ -254,7 +254,10 @@ struct dentry *proc_lookup_de(struct inode *dir, struct dentry *dentry,
> inode = proc_get_inode(dir->i_sb, de);
> if (!inode)
> return ERR_PTR(-ENOMEM);
> - d_set_d_op(dentry, de->proc_dops);
> + if (de->flags & PROC_ENTRY_FORCE_LOOKUP)
> + d_set_d_op(dentry, &proc_net_dentry_ops);
> + else
> + d_set_d_op(dentry, &proc_misc_dentry_ops);
> return d_splice_alias(inode, dentry);
> }
> read_unlock(&proc_subdir_lock);
> @@ -448,9 +451,8 @@ static struct proc_dir_entry *__proc_create(struct proc_dir_entry **parent,
> INIT_LIST_HEAD(&ent->pde_openers);
> proc_set_user(ent, (*parent)->uid, (*parent)->gid);
>
> - ent->proc_dops = &proc_misc_dentry_ops;
> /* Revalidate everything under /proc/${pid}/net */
> - if ((*parent)->proc_dops == &proc_net_dentry_ops)
> + if ((*parent)->flags & PROC_ENTRY_FORCE_LOOKUP)
> pde_force_lookup(ent);
>
> out:
> diff --git a/fs/proc/internal.h b/fs/proc/internal.h
> index 1695509370b8..07f75c959173 100644
> --- a/fs/proc/internal.h
> +++ b/fs/proc/internal.h
> @@ -44,7 +44,6 @@ struct proc_dir_entry {
> const struct proc_ops *proc_ops;
> const struct file_operations *proc_dir_ops;
> };
> - const struct dentry_operations *proc_dops;
> union {
> const struct seq_operations *seq_ops;
> int (*single_show)(struct seq_file *, void *);
> @@ -67,6 +66,8 @@ struct proc_dir_entry {
> char inline_name[];
> } __randomize_layout;
>
> +#define PROC_ENTRY_FORCE_LOOKUP 2 /* same space as PROC_ENTRY_PERMANENT */
Should there be a note in include/linux/proc_fs.h say that '2' is in
use?
Otherwise it seems sensible.
Thanks,
NeilBrown
> +
> #define SIZEOF_PDE ( \
> sizeof(struct proc_dir_entry) < 128 ? 128 : \
> sizeof(struct proc_dir_entry) < 192 ? 192 : \
> @@ -346,7 +347,7 @@ extern const struct dentry_operations proc_net_dentry_ops;
> static inline void pde_force_lookup(struct proc_dir_entry *pde)
> {
> /* /proc/net/ entries can be changed under us by setns(CLONE_NEWNET) */
> - pde->proc_dops = &proc_net_dentry_ops;
> + pde->flags |= PROC_ENTRY_FORCE_LOOKUP;
> }
>
> /*
> --
> 2.39.5
>
>
^ permalink raw reply [flat|nested] 87+ messages in thread
* Re: [PATCH 09/21] make d_set_d_op() static
2025-02-24 21:20 ` [PATCH 09/21] make d_set_d_op() static Al Viro
@ 2025-02-25 23:09 ` NeilBrown
2025-02-26 8:35 ` Christian Brauner
1 sibling, 0 replies; 87+ messages in thread
From: NeilBrown @ 2025-02-25 23:09 UTC (permalink / raw)
To: Al Viro
Cc: linux-fsdevel, Linus Torvalds, Christian Brauner, Miklos Szeredi,
Jan Kara
On Tue, 25 Feb 2025, Al Viro wrote:
> Convert the last user (d_alloc_pseudo()) and be done with that.
> Any out-of-tree filesystem using it should switch to d_splice_alias_ops()
> or, better yet, check whether it really needs to have ->d_op vary among
> its dentries.
>
> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
> ---
> Documentation/filesystems/porting.rst | 11 +++++++++++
> fs/dcache.c | 5 ++---
> include/linux/dcache.h | 1 -
> 3 files changed, 13 insertions(+), 4 deletions(-)
>
> diff --git a/Documentation/filesystems/porting.rst b/Documentation/filesystems/porting.rst
> index 004cd69617a2..61b5771dde53 100644
> --- a/Documentation/filesystems/porting.rst
> +++ b/Documentation/filesystems/porting.rst
> @@ -1164,3 +1164,14 @@ magic.
>
> If your filesystem sets the default dentry_operations, use set_default_d_op()
> rather than manually setting sb->s_d_op.
> +
> +---
> +
> +**mandatory**
> +
> +d_set_d_op() is no longer exported (or public, for that matter); _if_
> +your filesystem really needed that, make use of d_splice_alias_ops()
> +to have them set. Better yet, think hard whether you need different
> +->d_op for different dentries - if not, just use set_default_d_op()
> +at mount time and be done with that. Currently procfs is the only
> +thing that really needs ->d_op varying between dentries.
> diff --git a/fs/dcache.c b/fs/dcache.c
> index a4795617c3db..29db27228d97 100644
> --- a/fs/dcache.c
> +++ b/fs/dcache.c
> @@ -1796,7 +1796,7 @@ struct dentry *d_alloc_pseudo(struct super_block *sb, const struct qstr *name)
> if (likely(dentry)) {
> dentry->d_flags |= DCACHE_NORCU;
> if (!dentry->d_op)
> - d_set_d_op(dentry, &anon_ops);
> + dentry->d_op = &anon_ops;
This is safe because d_op_flags(anon_ops) is zero so there is no need to
update dentry->d_flags. I wonder if that deserves a comment.
Thanks,
NeilBrown
> }
> return dentry;
> }
> @@ -1837,7 +1837,7 @@ static unsigned int d_op_flags(const struct dentry_operations *op)
> return flags;
> }
>
> -void d_set_d_op(struct dentry *dentry, const struct dentry_operations *op)
> +static void d_set_d_op(struct dentry *dentry, const struct dentry_operations *op)
> {
> unsigned int flags = d_op_flags(op);
> WARN_ON_ONCE(dentry->d_op);
> @@ -1846,7 +1846,6 @@ void d_set_d_op(struct dentry *dentry, const struct dentry_operations *op)
> if (flags)
> dentry->d_flags |= flags;
> }
> -EXPORT_SYMBOL(d_set_d_op);
>
> void set_default_d_op(struct super_block *s, const struct dentry_operations *ops)
> {
> diff --git a/include/linux/dcache.h b/include/linux/dcache.h
> index e8cf1d0fdd08..5a03e85f92a4 100644
> --- a/include/linux/dcache.h
> +++ b/include/linux/dcache.h
> @@ -242,7 +242,6 @@ extern void d_instantiate_new(struct dentry *, struct inode *);
> extern void __d_drop(struct dentry *dentry);
> extern void d_drop(struct dentry *dentry);
> extern void d_delete(struct dentry *);
> -extern void d_set_d_op(struct dentry *dentry, const struct dentry_operations *op);
>
> /* allocate/de-allocate */
> extern struct dentry * d_alloc(struct dentry *, const struct qstr *);
> --
> 2.39.5
>
>
^ permalink raw reply [flat|nested] 87+ messages in thread
* Re: [PATCH 16/21] ramfs, hugetlbfs, mqueue: set DCACHE_DONTCACHE
2025-02-24 21:20 ` [PATCH 16/21] ramfs, hugetlbfs, mqueue: set DCACHE_DONTCACHE Al Viro
@ 2025-02-25 23:25 ` NeilBrown
2025-02-25 23:36 ` Al Viro
2025-02-26 8:39 ` Christian Brauner
1 sibling, 1 reply; 87+ messages in thread
From: NeilBrown @ 2025-02-25 23:25 UTC (permalink / raw)
To: Al Viro
Cc: linux-fsdevel, Linus Torvalds, Christian Brauner, Miklos Szeredi,
Jan Kara
On Tue, 25 Feb 2025, Al Viro wrote:
> makes simple_lookup() slightly cheaper there.
I think the patch make sense because there is no point keeping negative
dentries for these filesystems - and positive dentries get an extra
refcount so DCACHE_DONTCACHE doesn't apply.
But I don't see how this makes simple_lookup() cheaper. It means that
if someone repeatedly looks up the same non-existent name then
simple_lookup() will be called more often (because we didn't cache the
result of the previous time) but otherwise I don't see the relevance to
simple_lookup(). Am I missing something?
Thanks,
NeilBrown
>
> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
> ---
> fs/hugetlbfs/inode.c | 1 +
> fs/ramfs/inode.c | 1 +
> ipc/mqueue.c | 1 +
> 3 files changed, 3 insertions(+)
>
> diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c
> index 0fc179a59830..205dd7562be1 100644
> --- a/fs/hugetlbfs/inode.c
> +++ b/fs/hugetlbfs/inode.c
> @@ -1431,6 +1431,7 @@ hugetlbfs_fill_super(struct super_block *sb, struct fs_context *fc)
> sb->s_blocksize_bits = huge_page_shift(ctx->hstate);
> sb->s_magic = HUGETLBFS_MAGIC;
> sb->s_op = &hugetlbfs_ops;
> + sb->s_d_flags = DCACHE_DONTCACHE;
> sb->s_time_gran = 1;
>
> /*
> diff --git a/fs/ramfs/inode.c b/fs/ramfs/inode.c
> index 8006faaaf0ec..c4ee67870c4b 100644
> --- a/fs/ramfs/inode.c
> +++ b/fs/ramfs/inode.c
> @@ -269,6 +269,7 @@ static int ramfs_fill_super(struct super_block *sb, struct fs_context *fc)
> sb->s_blocksize_bits = PAGE_SHIFT;
> sb->s_magic = RAMFS_MAGIC;
> sb->s_op = &ramfs_ops;
> + sb->s_d_flags = DCACHE_DONTCACHE;
> sb->s_time_gran = 1;
>
> inode = ramfs_get_inode(sb, NULL, S_IFDIR | fsi->mount_opts.mode, 0);
> diff --git a/ipc/mqueue.c b/ipc/mqueue.c
> index 35b4f8659904..dbd5c74eecb2 100644
> --- a/ipc/mqueue.c
> +++ b/ipc/mqueue.c
> @@ -411,6 +411,7 @@ static int mqueue_fill_super(struct super_block *sb, struct fs_context *fc)
> sb->s_blocksize_bits = PAGE_SHIFT;
> sb->s_magic = MQUEUE_MAGIC;
> sb->s_op = &mqueue_super_ops;
> + sb->s_d_flags = DCACHE_DONTCACHE;
>
> inode = mqueue_get_inode(sb, ns, S_IFDIR | S_ISVTX | S_IRWXUGO, NULL);
> if (IS_ERR(inode))
> --
> 2.39.5
>
>
^ permalink raw reply [flat|nested] 87+ messages in thread
* Re: [PATCH 01/21] procfs: kill ->proc_dops
2025-02-25 15:55 ` [PATCH 01/21] procfs: kill ->proc_dops Jan Kara
@ 2025-02-25 23:30 ` NeilBrown
2025-02-25 23:56 ` Al Viro
0 siblings, 1 reply; 87+ messages in thread
From: NeilBrown @ 2025-02-25 23:30 UTC (permalink / raw)
To: Jan Kara
Cc: Al Viro, linux-fsdevel, Linus Torvalds, Christian Brauner,
Miklos Szeredi, Jan Kara
On Wed, 26 Feb 2025, Jan Kara wrote:
> On Mon 24-02-25 21:20:31, Al Viro wrote:
> > It has two possible values - one for "forced lookup" entries, another
> > for the normal ones. We'd be better off with that as an explicit
> > flag anyway and in addition to that it opens some fun possibilities
> > with ->d_op and ->d_flags handling.
> >
> > Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
>
> FWIW I went through the patches and I like them. They look mostly
> straightforward enough to me and as good simplifications.
>
Ditto. Nice clean-up
It might be good to document s_d_flags and particularly the value of
setting DCACHE_DONTCACHE. That flag is documented in the list of
DCACHE_ flags, but making the connection that it can usefully be put in
s_d_flags might be a step to far for many.
Thanks,
NeilBrown
^ permalink raw reply [flat|nested] 87+ messages in thread
* Re: [PATCH 16/21] ramfs, hugetlbfs, mqueue: set DCACHE_DONTCACHE
2025-02-25 23:25 ` NeilBrown
@ 2025-02-25 23:36 ` Al Viro
2025-02-25 23:40 ` NeilBrown
0 siblings, 1 reply; 87+ messages in thread
From: Al Viro @ 2025-02-25 23:36 UTC (permalink / raw)
To: NeilBrown
Cc: linux-fsdevel, Linus Torvalds, Christian Brauner, Miklos Szeredi,
Jan Kara
On Wed, Feb 26, 2025 at 10:25:12AM +1100, NeilBrown wrote:
> On Tue, 25 Feb 2025, Al Viro wrote:
> > makes simple_lookup() slightly cheaper there.
>
> I think the patch make sense because there is no point keeping negative
> dentries for these filesystems - and positive dentries get an extra
> refcount so DCACHE_DONTCACHE doesn't apply.
>
> But I don't see how this makes simple_lookup() cheaper. It means that
> if someone repeatedly looks up the same non-existent name then
> simple_lookup() will be called more often (because we didn't cache the
> result of the previous time) but otherwise I don't see the relevance to
> simple_lookup(). Am I missing something?
This:
if (!(dentry->d_flags & DCACHE_DONTCACHE)) {
spin_lock(&dentry->d_lock);
dentry->d_flags |= DCACHE_DONTCACHE;
spin_unlock(&dentry->d_lock);
}
IOW, no need to mark that sucker as "don't retain past the moment when
its refcount drops to zero" - they'll all be marked that way since
they'd been created.
Note that we used to switch then to ->d_op that had ->d_delete always
returning true. That had been replaced with setting DCACHE_DONTCACHE;
that was an equivalent transformation. So retention rules have not changed;
the only change here is that this flag doesn't need to be set.
^ permalink raw reply [flat|nested] 87+ messages in thread
* Re: [PATCH 16/21] ramfs, hugetlbfs, mqueue: set DCACHE_DONTCACHE
2025-02-25 23:36 ` Al Viro
@ 2025-02-25 23:40 ` NeilBrown
0 siblings, 0 replies; 87+ messages in thread
From: NeilBrown @ 2025-02-25 23:40 UTC (permalink / raw)
To: Al Viro
Cc: linux-fsdevel, Linus Torvalds, Christian Brauner, Miklos Szeredi,
Jan Kara
On Wed, 26 Feb 2025, Al Viro wrote:
> On Wed, Feb 26, 2025 at 10:25:12AM +1100, NeilBrown wrote:
> > On Tue, 25 Feb 2025, Al Viro wrote:
> > > makes simple_lookup() slightly cheaper there.
> >
> > I think the patch make sense because there is no point keeping negative
> > dentries for these filesystems - and positive dentries get an extra
> > refcount so DCACHE_DONTCACHE doesn't apply.
> >
> > But I don't see how this makes simple_lookup() cheaper. It means that
> > if someone repeatedly looks up the same non-existent name then
> > simple_lookup() will be called more often (because we didn't cache the
> > result of the previous time) but otherwise I don't see the relevance to
> > simple_lookup(). Am I missing something?
>
> This:
> if (!(dentry->d_flags & DCACHE_DONTCACHE)) {
> spin_lock(&dentry->d_lock);
> dentry->d_flags |= DCACHE_DONTCACHE;
> spin_unlock(&dentry->d_lock);
> }
Ah - right. Thanks.
NeilBrown
>
> IOW, no need to mark that sucker as "don't retain past the moment when
> its refcount drops to zero" - they'll all be marked that way since
> they'd been created.
>
> Note that we used to switch then to ->d_op that had ->d_delete always
> returning true. That had been replaced with setting DCACHE_DONTCACHE;
> that was an equivalent transformation. So retention rules have not changed;
> the only change here is that this flag doesn't need to be set.
>
^ permalink raw reply [flat|nested] 87+ messages in thread
* Re: [PATCH 01/21] procfs: kill ->proc_dops
2025-02-25 23:30 ` NeilBrown
@ 2025-02-25 23:56 ` Al Viro
0 siblings, 0 replies; 87+ messages in thread
From: Al Viro @ 2025-02-25 23:56 UTC (permalink / raw)
To: NeilBrown
Cc: Jan Kara, linux-fsdevel, Linus Torvalds, Christian Brauner,
Miklos Szeredi
On Wed, Feb 26, 2025 at 10:30:21AM +1100, NeilBrown wrote:
> On Wed, 26 Feb 2025, Jan Kara wrote:
> > On Mon 24-02-25 21:20:31, Al Viro wrote:
> > > It has two possible values - one for "forced lookup" entries, another
> > > for the normal ones. We'd be better off with that as an explicit
> > > flag anyway and in addition to that it opens some fun possibilities
> > > with ->d_op and ->d_flags handling.
> > >
> > > Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
> >
> > FWIW I went through the patches and I like them. They look mostly
> > straightforward enough to me and as good simplifications.
> >
>
> Ditto. Nice clean-up
> It might be good to document s_d_flags and particularly the value of
> setting DCACHE_DONTCACHE. That flag is documented in the list of
> DCACHE_ flags, but making the connection that it can usefully be put in
> s_d_flags might be a step to far for many.
Probably... The thing is, I'm resurrecting the DCACHE_PERSISTENT
patchset (aka tree-in-dcache stuff) and that will have non-trivial
interplay there. But you are right - it's probably worth documenting
that thing in this series.
Re documentation - I'll be posting bits and pieces of dcache
docs/audit/proofs of correctness over the next few weeks; at some
point we'll need to collect that into a single text, but at the
moment what I've got is too disjoint for that. OTOH, we could
start a WIP variant in D/f/<something> and have it augmented as
we go... Not sure.
^ permalink raw reply [flat|nested] 87+ messages in thread
* Re: [PATCH 01/21] procfs: kill ->proc_dops
2025-02-25 22:51 ` NeilBrown
@ 2025-02-26 0:03 ` Al Viro
0 siblings, 0 replies; 87+ messages in thread
From: Al Viro @ 2025-02-26 0:03 UTC (permalink / raw)
To: NeilBrown
Cc: linux-fsdevel, Linus Torvalds, Christian Brauner, Miklos Szeredi,
Jan Kara
On Wed, Feb 26, 2025 at 09:51:32AM +1100, NeilBrown wrote:
> > char inline_name[];
> > } __randomize_layout;
> >
> > +#define PROC_ENTRY_FORCE_LOOKUP 2 /* same space as PROC_ENTRY_PERMANENT */
>
> Should there be a note in include/linux/proc_fs.h say that '2' is in
> use?
Umm... Point, I guess - or we could just put "all other bits are belong to us"
there ;-)
^ permalink raw reply [flat|nested] 87+ messages in thread
* Re: [PATCH 01/21] procfs: kill ->proc_dops
2025-02-24 21:20 ` [PATCH 01/21] procfs: kill ->proc_dops Al Viro
` (21 preceding siblings ...)
2025-02-25 22:51 ` NeilBrown
@ 2025-02-26 8:25 ` Christian Brauner
22 siblings, 0 replies; 87+ messages in thread
From: Christian Brauner @ 2025-02-26 8:25 UTC (permalink / raw)
To: Al Viro; +Cc: linux-fsdevel, Linus Torvalds, Neil Brown, Miklos Szeredi,
Jan Kara
On Mon, Feb 24, 2025 at 09:20:31PM +0000, Al Viro wrote:
> It has two possible values - one for "forced lookup" entries, another
> for the normal ones. We'd be better off with that as an explicit
> flag anyway and in addition to that it opens some fun possibilities
> with ->d_op and ->d_flags handling.
>
> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
> ---
Reviewed-by: Christian Brauner <brauner@kernel.org>
^ permalink raw reply [flat|nested] 87+ messages in thread
* Re: [PATCH 02/21] new helper: d_splice_alias_ops()
2025-02-24 21:20 ` [PATCH 02/21] new helper: d_splice_alias_ops() Al Viro
@ 2025-02-26 8:28 ` Christian Brauner
0 siblings, 0 replies; 87+ messages in thread
From: Christian Brauner @ 2025-02-26 8:28 UTC (permalink / raw)
To: Al Viro; +Cc: linux-fsdevel, Linus Torvalds, Neil Brown, Miklos Szeredi,
Jan Kara
On Mon, Feb 24, 2025 at 09:20:32PM +0000, Al Viro wrote:
> Uses of d_set_d_op() on live dentry can be very dangerous; it is going
> to be withdrawn and replaced with saner things.
>
> The best way for a filesystem is to have the default dentry_operations
> set at mount time and be done with that - __d_alloc() will use that.
>
> Currently there are two cases when d_set_d_op() is used on a live dentry -
> one is procfs, which has several genuinely different dentry_operations
> instances (different ->d_revalidate(), etc.) and another is
> simple_lookup(), where we would be better off without overriding ->d_op.
>
> For procfs we have d_set_d_op() calls followed by d_splice_alias();
> provide a new helper (d_splice_alias_ops(inode, dentry, d_ops)) that would
> combine those two, and do the d_set_d_op() part while under ->d_lock.
> That eliminates one of the places where ->d_flags had been modified
> without holding ->d_lock; current behaviour is not racy, but the reasons
> for that are far too brittle. Better move to uniform locking rules and
> simpler proof of correctness...
>
> The next commit will convert procfs to use of that helper; it is not
> exported and won't be until somebody comes up with convincing modular
> user for it.
>
> Again, the best approach is to have default ->d_op and let __d_alloc()
> do the right thing; filesystem _may_ need non-uniform ->d_op (procfs
> does), but there'd better be good reasons for that.
>
> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
> ---
Reviewed-by: Christian Brauner <brauner@kernel.org>
> fs/dcache.c | 63 ++++++++++++++++++++++++------------------
> include/linux/dcache.h | 3 ++
> 2 files changed, 39 insertions(+), 27 deletions(-)
>
> diff --git a/fs/dcache.c b/fs/dcache.c
> index e3634916ffb9..c85efbda133a 100644
> --- a/fs/dcache.c
> +++ b/fs/dcache.c
> @@ -2641,7 +2641,8 @@ EXPORT_SYMBOL(__d_lookup_unhash_wake);
>
> /* inode->i_lock held if inode is non-NULL */
>
> -static inline void __d_add(struct dentry *dentry, struct inode *inode)
> +static inline void __d_add(struct dentry *dentry, struct inode *inode,
> + const struct dentry_operations *ops)
> {
> wait_queue_head_t *d_wait;
> struct inode *dir = NULL;
> @@ -2652,6 +2653,8 @@ static inline void __d_add(struct dentry *dentry, struct inode *inode)
> n = start_dir_add(dir);
> d_wait = __d_lookup_unhash(dentry);
> }
> + if (unlikely(ops))
> + d_set_d_op(dentry, ops);
> if (inode) {
> unsigned add_flags = d_flags_for_inode(inode);
> hlist_add_head(&dentry->d_u.d_alias, &inode->i_dentry);
> @@ -2683,7 +2686,7 @@ void d_add(struct dentry *entry, struct inode *inode)
> security_d_instantiate(entry, inode);
> spin_lock(&inode->i_lock);
> }
> - __d_add(entry, inode);
> + __d_add(entry, inode, NULL);
> }
> EXPORT_SYMBOL(d_add);
>
> @@ -2981,30 +2984,8 @@ static int __d_unalias(struct dentry *dentry, struct dentry *alias)
> return ret;
> }
>
> -/**
> - * d_splice_alias - splice a disconnected dentry into the tree if one exists
> - * @inode: the inode which may have a disconnected dentry
> - * @dentry: a negative dentry which we want to point to the inode.
> - *
> - * If inode is a directory and has an IS_ROOT alias, then d_move that in
> - * place of the given dentry and return it, else simply d_add the inode
> - * to the dentry and return NULL.
> - *
> - * If a non-IS_ROOT directory is found, the filesystem is corrupt, and
> - * we should error out: directories can't have multiple aliases.
> - *
> - * This is needed in the lookup routine of any filesystem that is exportable
> - * (via knfsd) so that we can build dcache paths to directories effectively.
> - *
> - * If a dentry was found and moved, then it is returned. Otherwise NULL
> - * is returned. This matches the expected return value of ->lookup.
> - *
> - * Cluster filesystems may call this function with a negative, hashed dentry.
> - * In that case, we know that the inode will be a regular file, and also this
> - * will only occur during atomic_open. So we need to check for the dentry
> - * being already hashed only in the final case.
> - */
> -struct dentry *d_splice_alias(struct inode *inode, struct dentry *dentry)
> +struct dentry *d_splice_alias_ops(struct inode *inode, struct dentry *dentry,
> + const struct dentry_operations *ops)
> {
> if (IS_ERR(inode))
> return ERR_CAST(inode);
> @@ -3050,9 +3031,37 @@ struct dentry *d_splice_alias(struct inode *inode, struct dentry *dentry)
> }
> }
> out:
> - __d_add(dentry, inode);
> + __d_add(dentry, inode, ops);
> return NULL;
> }
> +
> +/**
> + * d_splice_alias - splice a disconnected dentry into the tree if one exists
> + * @inode: the inode which may have a disconnected dentry
> + * @dentry: a negative dentry which we want to point to the inode.
> + *
> + * If inode is a directory and has an IS_ROOT alias, then d_move that in
> + * place of the given dentry and return it, else simply d_add the inode
> + * to the dentry and return NULL.
> + *
> + * If a non-IS_ROOT directory is found, the filesystem is corrupt, and
> + * we should error out: directories can't have multiple aliases.
> + *
> + * This is needed in the lookup routine of any filesystem that is exportable
> + * (via knfsd) so that we can build dcache paths to directories effectively.
> + *
> + * If a dentry was found and moved, then it is returned. Otherwise NULL
> + * is returned. This matches the expected return value of ->lookup.
> + *
> + * Cluster filesystems may call this function with a negative, hashed dentry.
> + * In that case, we know that the inode will be a regular file, and also this
> + * will only occur during atomic_open. So we need to check for the dentry
> + * being already hashed only in the final case.
> + */
> +struct dentry *d_splice_alias(struct inode *inode, struct dentry *dentry)
> +{
> + return d_splice_alias_ops(inode, dentry, NULL);
> +}
> EXPORT_SYMBOL(d_splice_alias);
>
> /*
> diff --git a/include/linux/dcache.h b/include/linux/dcache.h
> index 4afb60365675..f47f3a47d97b 100644
> --- a/include/linux/dcache.h
> +++ b/include/linux/dcache.h
> @@ -250,6 +250,9 @@ extern struct dentry * d_alloc_anon(struct super_block *);
> extern struct dentry * d_alloc_parallel(struct dentry *, const struct qstr *,
> wait_queue_head_t *);
> extern struct dentry * d_splice_alias(struct inode *, struct dentry *);
> +/* weird procfs mess; *NOT* exported */
> +extern struct dentry * d_splice_alias_ops(struct inode *, struct dentry *,
> + const struct dentry_operations *);
> extern struct dentry * d_add_ci(struct dentry *, struct inode *, struct qstr *);
> extern bool d_same_name(const struct dentry *dentry, const struct dentry *parent,
> const struct qstr *name);
> --
> 2.39.5
>
^ permalink raw reply [flat|nested] 87+ messages in thread
* Re: [PATCH 03/21] switch procfs from d_set_d_op() to d_splice_alias_ops()
2025-02-24 21:20 ` [PATCH 03/21] switch procfs from d_set_d_op() to d_splice_alias_ops() Al Viro
@ 2025-02-26 8:29 ` Christian Brauner
0 siblings, 0 replies; 87+ messages in thread
From: Christian Brauner @ 2025-02-26 8:29 UTC (permalink / raw)
To: Al Viro; +Cc: linux-fsdevel, Linus Torvalds, Neil Brown, Miklos Szeredi,
Jan Kara
On Mon, Feb 24, 2025 at 09:20:33PM +0000, Al Viro wrote:
> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
> ---
Reviewed-by: Christian Brauner <brauner@kernel.org>
> fs/proc/base.c | 9 +++------
> fs/proc/generic.c | 8 ++++----
> fs/proc/internal.h | 3 +--
> fs/proc/namespaces.c | 3 +--
> fs/proc/proc_sysctl.c | 7 +++----
> 5 files changed, 12 insertions(+), 18 deletions(-)
>
> diff --git a/fs/proc/base.c b/fs/proc/base.c
> index cd89e956c322..397a9f6f463e 100644
> --- a/fs/proc/base.c
> +++ b/fs/proc/base.c
> @@ -2709,8 +2709,7 @@ static struct dentry *proc_pident_instantiate(struct dentry *dentry,
> inode->i_fop = p->fop;
> ei->op = p->op;
> pid_update_inode(task, inode);
> - d_set_d_op(dentry, &pid_dentry_operations);
> - return d_splice_alias(inode, dentry);
> + return d_splice_alias_ops(inode, dentry, &pid_dentry_operations);
> }
>
> static struct dentry *proc_pident_lookup(struct inode *dir,
> @@ -3508,8 +3507,7 @@ static struct dentry *proc_pid_instantiate(struct dentry * dentry,
> set_nlink(inode, nlink_tgid);
> pid_update_inode(task, inode);
>
> - d_set_d_op(dentry, &pid_dentry_operations);
> - return d_splice_alias(inode, dentry);
> + return d_splice_alias_ops(inode, dentry, &pid_dentry_operations);
> }
>
> struct dentry *proc_pid_lookup(struct dentry *dentry, unsigned int flags)
> @@ -3813,8 +3811,7 @@ static struct dentry *proc_task_instantiate(struct dentry *dentry,
> set_nlink(inode, nlink_tid);
> pid_update_inode(task, inode);
>
> - d_set_d_op(dentry, &pid_dentry_operations);
> - return d_splice_alias(inode, dentry);
> + return d_splice_alias_ops(inode, dentry, &pid_dentry_operations);
> }
>
> static struct dentry *proc_task_lookup(struct inode *dir, struct dentry * dentry, unsigned int flags)
> diff --git a/fs/proc/generic.c b/fs/proc/generic.c
> index 499c2bf67488..774e18372914 100644
> --- a/fs/proc/generic.c
> +++ b/fs/proc/generic.c
> @@ -255,10 +255,10 @@ struct dentry *proc_lookup_de(struct inode *dir, struct dentry *dentry,
> if (!inode)
> return ERR_PTR(-ENOMEM);
> if (de->flags & PROC_ENTRY_FORCE_LOOKUP)
> - d_set_d_op(dentry, &proc_net_dentry_ops);
> - else
> - d_set_d_op(dentry, &proc_misc_dentry_ops);
> - return d_splice_alias(inode, dentry);
> + return d_splice_alias_ops(inode, dentry,
> + &proc_net_dentry_ops);
> + return d_splice_alias_ops(inode, dentry,
> + &proc_misc_dentry_ops);
> }
> read_unlock(&proc_subdir_lock);
> return ERR_PTR(-ENOENT);
> diff --git a/fs/proc/internal.h b/fs/proc/internal.h
> index 07f75c959173..48410381036b 100644
> --- a/fs/proc/internal.h
> +++ b/fs/proc/internal.h
> @@ -358,7 +358,6 @@ static inline void pde_force_lookup(struct proc_dir_entry *pde)
> static inline struct dentry *proc_splice_unmountable(struct inode *inode,
> struct dentry *dentry, const struct dentry_operations *d_ops)
> {
> - d_set_d_op(dentry, d_ops);
> dont_mount(dentry);
> - return d_splice_alias(inode, dentry);
> + return d_splice_alias_ops(inode, dentry, d_ops);
> }
> diff --git a/fs/proc/namespaces.c b/fs/proc/namespaces.c
> index c610224faf10..4403a2e20c16 100644
> --- a/fs/proc/namespaces.c
> +++ b/fs/proc/namespaces.c
> @@ -111,8 +111,7 @@ static struct dentry *proc_ns_instantiate(struct dentry *dentry,
> ei->ns_ops = ns_ops;
> pid_update_inode(task, inode);
>
> - d_set_d_op(dentry, &pid_dentry_operations);
> - return d_splice_alias(inode, dentry);
> + return d_splice_alias_ops(inode, dentry, &pid_dentry_operations);
> }
>
> static int proc_ns_dir_readdir(struct file *file, struct dir_context *ctx)
> diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c
> index cc9d74a06ff0..7a8bffc03dc8 100644
> --- a/fs/proc/proc_sysctl.c
> +++ b/fs/proc/proc_sysctl.c
> @@ -540,9 +540,8 @@ static struct dentry *proc_sys_lookup(struct inode *dir, struct dentry *dentry,
> goto out;
> }
>
> - d_set_d_op(dentry, &proc_sys_dentry_operations);
> inode = proc_sys_make_inode(dir->i_sb, h ? h : head, p);
> - err = d_splice_alias(inode, dentry);
> + err = d_splice_alias_ops(inode, dentry, &proc_sys_dentry_operations);
>
> out:
> if (h)
> @@ -699,9 +698,9 @@ static bool proc_sys_fill_cache(struct file *file,
> return false;
> if (d_in_lookup(child)) {
> struct dentry *res;
> - d_set_d_op(child, &proc_sys_dentry_operations);
> inode = proc_sys_make_inode(dir->d_sb, head, table);
> - res = d_splice_alias(inode, child);
> + res = d_splice_alias_ops(inode, child,
> + &proc_sys_dentry_operations);
> d_lookup_done(child);
> if (unlikely(res)) {
> dput(child);
> --
> 2.39.5
>
^ permalink raw reply [flat|nested] 87+ messages in thread
* Re: [PATCH 04/21] fuse: no need for special dentry_operations for root dentry
2025-02-24 21:20 ` [PATCH 04/21] fuse: no need for special dentry_operations for root dentry Al Viro
@ 2025-02-26 8:29 ` Christian Brauner
2025-02-27 14:33 ` Miklos Szeredi
1 sibling, 0 replies; 87+ messages in thread
From: Christian Brauner @ 2025-02-26 8:29 UTC (permalink / raw)
To: Al Viro; +Cc: linux-fsdevel, Linus Torvalds, Neil Brown, Miklos Szeredi,
Jan Kara
On Mon, Feb 24, 2025 at 09:20:34PM +0000, Al Viro wrote:
> ->d_revalidate() is never called for root anyway...
>
> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
> ---
Reviewed-by: Christian Brauner <brauner@kernel.org>
> fs/fuse/dir.c | 7 -------
> fs/fuse/fuse_i.h | 1 -
> fs/fuse/inode.c | 4 +---
> 3 files changed, 1 insertion(+), 11 deletions(-)
>
> diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
> index 198862b086ff..24979d5413fa 100644
> --- a/fs/fuse/dir.c
> +++ b/fs/fuse/dir.c
> @@ -336,13 +336,6 @@ const struct dentry_operations fuse_dentry_operations = {
> .d_automount = fuse_dentry_automount,
> };
>
> -const struct dentry_operations fuse_root_dentry_operations = {
> -#if BITS_PER_LONG < 64
> - .d_init = fuse_dentry_init,
> - .d_release = fuse_dentry_release,
> -#endif
> -};
> -
> int fuse_valid_type(int m)
> {
> return S_ISREG(m) || S_ISDIR(m) || S_ISLNK(m) || S_ISCHR(m) ||
> diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
> index fee96fe7887b..71a2b3900854 100644
> --- a/fs/fuse/fuse_i.h
> +++ b/fs/fuse/fuse_i.h
> @@ -1069,7 +1069,6 @@ static inline void fuse_sync_bucket_dec(struct fuse_sync_bucket *bucket)
> extern const struct file_operations fuse_dev_operations;
>
> extern const struct dentry_operations fuse_dentry_operations;
> -extern const struct dentry_operations fuse_root_dentry_operations;
>
> /**
> * Get a filled in inode
> diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
> index e9db2cb8c150..57a1ee016b73 100644
> --- a/fs/fuse/inode.c
> +++ b/fs/fuse/inode.c
> @@ -1800,12 +1800,10 @@ int fuse_fill_super_common(struct super_block *sb, struct fuse_fs_context *ctx)
>
> err = -ENOMEM;
> root = fuse_get_root_inode(sb, ctx->rootmode);
> - sb->s_d_op = &fuse_root_dentry_operations;
> + sb->s_d_op = &fuse_dentry_operations;
> root_dentry = d_make_root(root);
> if (!root_dentry)
> goto err_dev_free;
> - /* Root dentry doesn't have .d_revalidate */
> - sb->s_d_op = &fuse_dentry_operations;
>
> mutex_lock(&fuse_mutex);
> err = -EINVAL;
> --
> 2.39.5
>
^ permalink raw reply [flat|nested] 87+ messages in thread
* Re: [PATCH 05/21] new helper: set_default_d_op()
2025-02-24 21:20 ` [PATCH 05/21] new helper: set_default_d_op() Al Viro
@ 2025-02-26 8:30 ` Christian Brauner
0 siblings, 0 replies; 87+ messages in thread
From: Christian Brauner @ 2025-02-26 8:30 UTC (permalink / raw)
To: Al Viro; +Cc: linux-fsdevel, Linus Torvalds, Neil Brown, Miklos Szeredi,
Jan Kara
On Mon, Feb 24, 2025 at 09:20:35PM +0000, Al Viro wrote:
> ... to be used instead of manually assigning to ->s_d_op.
> All in-tree filesystem converted (and field itself is renamed,
> so any out-of-tree ones in need of conversion will be caught
> by compiler).
>
> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
> ---
Reviewed-by: Christian Brauner <brauner@kernel.org>
> Documentation/filesystems/porting.rst | 7 +++++++
> fs/9p/vfs_super.c | 4 ++--
> fs/adfs/super.c | 2 +-
> fs/affs/super.c | 4 ++--
> fs/afs/super.c | 4 ++--
> fs/autofs/inode.c | 2 +-
> fs/btrfs/super.c | 2 +-
> fs/ceph/super.c | 2 +-
> fs/coda/inode.c | 2 +-
> fs/configfs/mount.c | 2 +-
> fs/dcache.c | 10 ++++++++--
> fs/debugfs/inode.c | 2 +-
> fs/devpts/inode.c | 2 +-
> fs/ecryptfs/main.c | 2 +-
> fs/efivarfs/super.c | 2 +-
> fs/exfat/super.c | 4 ++--
> fs/fat/namei_msdos.c | 2 +-
> fs/fat/namei_vfat.c | 4 ++--
> fs/fuse/inode.c | 4 ++--
> fs/gfs2/ops_fstype.c | 2 +-
> fs/hfs/super.c | 2 +-
> fs/hfsplus/super.c | 2 +-
> fs/hostfs/hostfs_kern.c | 2 +-
> fs/hpfs/super.c | 2 +-
> fs/isofs/inode.c | 2 +-
> fs/jfs/super.c | 2 +-
> fs/kernfs/mount.c | 2 +-
> fs/libfs.c | 16 ++++++++--------
> fs/nfs/super.c | 2 +-
> fs/ntfs3/super.c | 3 ++-
> fs/ocfs2/super.c | 2 +-
> fs/orangefs/super.c | 2 +-
> fs/overlayfs/super.c | 2 +-
> fs/smb/client/cifsfs.c | 4 ++--
> fs/tracefs/inode.c | 2 +-
> fs/vboxsf/super.c | 2 +-
> include/linux/dcache.h | 2 ++
> include/linux/fs.h | 2 +-
> mm/shmem.c | 2 +-
> net/sunrpc/rpc_pipe.c | 2 +-
> 40 files changed, 69 insertions(+), 53 deletions(-)
>
> diff --git a/Documentation/filesystems/porting.rst b/Documentation/filesystems/porting.rst
> index 1639e78e3146..004cd69617a2 100644
> --- a/Documentation/filesystems/porting.rst
> +++ b/Documentation/filesystems/porting.rst
> @@ -1157,3 +1157,10 @@ in normal case it points into the pathname being looked up.
> NOTE: if you need something like full path from the root of filesystem,
> you are still on your own - this assists with simple cases, but it's not
> magic.
> +
> +---
> +
> +**mandatory**
> +
> +If your filesystem sets the default dentry_operations, use set_default_d_op()
> +rather than manually setting sb->s_d_op.
> diff --git a/fs/9p/vfs_super.c b/fs/9p/vfs_super.c
> index 489db161abc9..5c3dc3efb909 100644
> --- a/fs/9p/vfs_super.c
> +++ b/fs/9p/vfs_super.c
> @@ -135,9 +135,9 @@ static struct dentry *v9fs_mount(struct file_system_type *fs_type, int flags,
> goto release_sb;
>
> if (v9ses->cache & (CACHE_META|CACHE_LOOSE))
> - sb->s_d_op = &v9fs_cached_dentry_operations;
> + set_default_d_op(sb, &v9fs_cached_dentry_operations);
> else
> - sb->s_d_op = &v9fs_dentry_operations;
> + set_default_d_op(sb, &v9fs_dentry_operations);
>
> inode = v9fs_get_new_inode_from_fid(v9ses, fid, sb);
> if (IS_ERR(inode)) {
> diff --git a/fs/adfs/super.c b/fs/adfs/super.c
> index 017c48a80203..fdccdbbfc213 100644
> --- a/fs/adfs/super.c
> +++ b/fs/adfs/super.c
> @@ -397,7 +397,7 @@ static int adfs_fill_super(struct super_block *sb, struct fs_context *fc)
> if (asb->s_ftsuffix)
> asb->s_namelen += 4;
>
> - sb->s_d_op = &adfs_dentry_operations;
> + set_default_d_op(sb, &adfs_dentry_operations);
> root = adfs_iget(sb, &root_obj);
> sb->s_root = d_make_root(root);
> if (!sb->s_root) {
> diff --git a/fs/affs/super.c b/fs/affs/super.c
> index 2fa40337776d..44f8aa883100 100644
> --- a/fs/affs/super.c
> +++ b/fs/affs/super.c
> @@ -500,9 +500,9 @@ static int affs_fill_super(struct super_block *sb, struct fs_context *fc)
> return PTR_ERR(root_inode);
>
> if (affs_test_opt(AFFS_SB(sb)->s_flags, SF_INTL))
> - sb->s_d_op = &affs_intl_dentry_operations;
> + set_default_d_op(sb, &affs_intl_dentry_operations);
> else
> - sb->s_d_op = &affs_dentry_operations;
> + set_default_d_op(sb, &affs_dentry_operations);
>
> sb->s_root = d_make_root(root_inode);
> if (!sb->s_root) {
> diff --git a/fs/afs/super.c b/fs/afs/super.c
> index a9bee610674e..13d0414a1ddb 100644
> --- a/fs/afs/super.c
> +++ b/fs/afs/super.c
> @@ -487,12 +487,12 @@ static int afs_fill_super(struct super_block *sb, struct afs_fs_context *ctx)
> goto error;
>
> if (as->dyn_root) {
> - sb->s_d_op = &afs_dynroot_dentry_operations;
> + set_default_d_op(sb, &afs_dynroot_dentry_operations);
> ret = afs_dynroot_populate(sb);
> if (ret < 0)
> goto error;
> } else {
> - sb->s_d_op = &afs_fs_dentry_operations;
> + set_default_d_op(sb, &afs_fs_dentry_operations);
> rcu_assign_pointer(as->volume->sb, sb);
> }
>
> diff --git a/fs/autofs/inode.c b/fs/autofs/inode.c
> index ee2edccaef70..f5c16ffba013 100644
> --- a/fs/autofs/inode.c
> +++ b/fs/autofs/inode.c
> @@ -311,7 +311,7 @@ static int autofs_fill_super(struct super_block *s, struct fs_context *fc)
> s->s_blocksize_bits = 10;
> s->s_magic = AUTOFS_SUPER_MAGIC;
> s->s_op = &autofs_sops;
> - s->s_d_op = &autofs_dentry_operations;
> + set_default_d_op(s, &autofs_dentry_operations);
> s->s_time_gran = 1;
>
> /*
> diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
> index dc4fee519ca6..5f39857ea3ae 100644
> --- a/fs/btrfs/super.c
> +++ b/fs/btrfs/super.c
> @@ -954,7 +954,7 @@ static int btrfs_fill_super(struct super_block *sb,
> sb->s_maxbytes = MAX_LFS_FILESIZE;
> sb->s_magic = BTRFS_SUPER_MAGIC;
> sb->s_op = &btrfs_super_ops;
> - sb->s_d_op = &btrfs_dentry_operations;
> + set_default_d_op(sb, &btrfs_dentry_operations);
> sb->s_export_op = &btrfs_export_ops;
> #ifdef CONFIG_FS_VERITY
> sb->s_vop = &btrfs_verityops;
> diff --git a/fs/ceph/super.c b/fs/ceph/super.c
> index 4344e1f11806..adec6e2f01c4 100644
> --- a/fs/ceph/super.c
> +++ b/fs/ceph/super.c
> @@ -1220,7 +1220,7 @@ static int ceph_set_super(struct super_block *s, struct fs_context *fc)
> fsc->max_file_size = 1ULL << 40; /* temp value until we get mdsmap */
>
> s->s_op = &ceph_super_ops;
> - s->s_d_op = &ceph_dentry_ops;
> + set_default_d_op(s, &ceph_dentry_ops);
> s->s_export_op = &ceph_export_ops;
>
> s->s_time_gran = 1;
> diff --git a/fs/coda/inode.c b/fs/coda/inode.c
> index 6896fce122e1..08450d006016 100644
> --- a/fs/coda/inode.c
> +++ b/fs/coda/inode.c
> @@ -230,7 +230,7 @@ static int coda_fill_super(struct super_block *sb, struct fs_context *fc)
> sb->s_blocksize_bits = 12;
> sb->s_magic = CODA_SUPER_MAGIC;
> sb->s_op = &coda_super_operations;
> - sb->s_d_op = &coda_dentry_operations;
> + set_default_d_op(sb, &coda_dentry_operations);
> sb->s_time_gran = 1;
> sb->s_time_min = S64_MIN;
> sb->s_time_max = S64_MAX;
> diff --git a/fs/configfs/mount.c b/fs/configfs/mount.c
> index c2d820063ec4..20412eaca972 100644
> --- a/fs/configfs/mount.c
> +++ b/fs/configfs/mount.c
> @@ -92,7 +92,7 @@ static int configfs_fill_super(struct super_block *sb, struct fs_context *fc)
> configfs_root_group.cg_item.ci_dentry = root;
> root->d_fsdata = &configfs_root;
> sb->s_root = root;
> - sb->s_d_op = &configfs_dentry_ops; /* the rest get that */
> + set_default_d_op(sb, &configfs_dentry_ops); /* the rest get that */
> return 0;
> }
>
> diff --git a/fs/dcache.c b/fs/dcache.c
> index c85efbda133a..cd5e5139ca4c 100644
> --- a/fs/dcache.c
> +++ b/fs/dcache.c
> @@ -1712,7 +1712,7 @@ static struct dentry *__d_alloc(struct super_block *sb, const struct qstr *name)
> INIT_HLIST_HEAD(&dentry->d_children);
> INIT_HLIST_NODE(&dentry->d_u.d_alias);
> INIT_HLIST_NODE(&dentry->d_sib);
> - d_set_d_op(dentry, dentry->d_sb->s_d_op);
> + d_set_d_op(dentry, dentry->d_sb->__s_d_op);
>
> if (dentry->d_op && dentry->d_op->d_init) {
> err = dentry->d_op->d_init(dentry);
> @@ -1795,7 +1795,7 @@ struct dentry *d_alloc_pseudo(struct super_block *sb, const struct qstr *name)
> struct dentry *dentry = __d_alloc(sb, name);
> if (likely(dentry)) {
> dentry->d_flags |= DCACHE_NORCU;
> - if (!sb->s_d_op)
> + if (!dentry->d_op)
> d_set_d_op(dentry, &anon_ops);
> }
> return dentry;
> @@ -1841,6 +1841,12 @@ void d_set_d_op(struct dentry *dentry, const struct dentry_operations *op)
> }
> EXPORT_SYMBOL(d_set_d_op);
>
> +void set_default_d_op(struct super_block *s, const struct dentry_operations *ops)
> +{
> + s->__s_d_op = ops;
> +}
> +EXPORT_SYMBOL(set_default_d_op);
> +
> static unsigned d_flags_for_inode(struct inode *inode)
> {
> unsigned add_flags = DCACHE_REGULAR_TYPE;
> diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c
> index 75715d8877ee..f54a8fd960e4 100644
> --- a/fs/debugfs/inode.c
> +++ b/fs/debugfs/inode.c
> @@ -273,7 +273,7 @@ static int debugfs_fill_super(struct super_block *sb, struct fs_context *fc)
> return err;
>
> sb->s_op = &debugfs_super_operations;
> - sb->s_d_op = &debugfs_dops;
> + set_default_d_op(sb, &debugfs_dops);
>
> debugfs_apply_options(sb);
>
> diff --git a/fs/devpts/inode.c b/fs/devpts/inode.c
> index 1096ff8562fa..f092973236ef 100644
> --- a/fs/devpts/inode.c
> +++ b/fs/devpts/inode.c
> @@ -433,7 +433,7 @@ devpts_fill_super(struct super_block *s, void *data, int silent)
> s->s_blocksize_bits = 10;
> s->s_magic = DEVPTS_SUPER_MAGIC;
> s->s_op = &devpts_sops;
> - s->s_d_op = &simple_dentry_operations;
> + set_default_d_op(s, &simple_dentry_operations);
> s->s_time_gran = 1;
>
> error = -ENOMEM;
> diff --git a/fs/ecryptfs/main.c b/fs/ecryptfs/main.c
> index 8dd1d7189c3b..45f9ca4465da 100644
> --- a/fs/ecryptfs/main.c
> +++ b/fs/ecryptfs/main.c
> @@ -471,7 +471,7 @@ static int ecryptfs_get_tree(struct fs_context *fc)
> sbi = NULL;
> s->s_op = &ecryptfs_sops;
> s->s_xattr = ecryptfs_xattr_handlers;
> - s->s_d_op = &ecryptfs_dops;
> + set_default_d_op(s, &ecryptfs_dops);
>
> err = "Reading sb failed";
> rc = kern_path(fc->source, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &path);
> diff --git a/fs/efivarfs/super.c b/fs/efivarfs/super.c
> index 09fcf731e65d..3f3188e0cfa7 100644
> --- a/fs/efivarfs/super.c
> +++ b/fs/efivarfs/super.c
> @@ -345,7 +345,7 @@ static int efivarfs_fill_super(struct super_block *sb, struct fs_context *fc)
> sb->s_blocksize_bits = PAGE_SHIFT;
> sb->s_magic = EFIVARFS_MAGIC;
> sb->s_op = &efivarfs_ops;
> - sb->s_d_op = &efivarfs_d_ops;
> + set_default_d_op(sb, &efivarfs_d_ops);
> sb->s_time_gran = 1;
>
> if (!efivar_supports_writes())
> diff --git a/fs/exfat/super.c b/fs/exfat/super.c
> index bd57844414aa..c821582fa1ef 100644
> --- a/fs/exfat/super.c
> +++ b/fs/exfat/super.c
> @@ -697,9 +697,9 @@ static int exfat_fill_super(struct super_block *sb, struct fs_context *fc)
> }
>
> if (sbi->options.utf8)
> - sb->s_d_op = &exfat_utf8_dentry_ops;
> + set_default_d_op(sb, &exfat_utf8_dentry_ops);
> else
> - sb->s_d_op = &exfat_dentry_ops;
> + set_default_d_op(sb, &exfat_dentry_ops);
>
> root_inode = new_inode(sb);
> if (!root_inode) {
> diff --git a/fs/fat/namei_msdos.c b/fs/fat/namei_msdos.c
> index f06f6ba643cc..71302291d33c 100644
> --- a/fs/fat/namei_msdos.c
> +++ b/fs/fat/namei_msdos.c
> @@ -646,7 +646,7 @@ static const struct inode_operations msdos_dir_inode_operations = {
> static void setup(struct super_block *sb)
> {
> MSDOS_SB(sb)->dir_ops = &msdos_dir_inode_operations;
> - sb->s_d_op = &msdos_dentry_operations;
> + set_default_d_op(sb, &msdos_dentry_operations);
> sb->s_flags |= SB_NOATIME;
> }
>
> diff --git a/fs/fat/namei_vfat.c b/fs/fat/namei_vfat.c
> index 926c26e90ef8..2476afd1304d 100644
> --- a/fs/fat/namei_vfat.c
> +++ b/fs/fat/namei_vfat.c
> @@ -1187,9 +1187,9 @@ static void setup(struct super_block *sb)
> {
> MSDOS_SB(sb)->dir_ops = &vfat_dir_inode_operations;
> if (MSDOS_SB(sb)->options.name_check != 's')
> - sb->s_d_op = &vfat_ci_dentry_ops;
> + set_default_d_op(sb, &vfat_ci_dentry_ops);
> else
> - sb->s_d_op = &vfat_dentry_ops;
> + set_default_d_op(sb, &vfat_dentry_ops);
> }
>
> static int vfat_fill_super(struct super_block *sb, struct fs_context *fc)
> diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
> index 57a1ee016b73..9994f3b33a9f 100644
> --- a/fs/fuse/inode.c
> +++ b/fs/fuse/inode.c
> @@ -1665,7 +1665,7 @@ static int fuse_fill_super_submount(struct super_block *sb,
> fi = get_fuse_inode(root);
> fi->nlookup--;
>
> - sb->s_d_op = &fuse_dentry_operations;
> + set_default_d_op(sb, &fuse_dentry_operations);
> sb->s_root = d_make_root(root);
> if (!sb->s_root)
> return -ENOMEM;
> @@ -1800,7 +1800,7 @@ int fuse_fill_super_common(struct super_block *sb, struct fuse_fs_context *ctx)
>
> err = -ENOMEM;
> root = fuse_get_root_inode(sb, ctx->rootmode);
> - sb->s_d_op = &fuse_dentry_operations;
> + set_default_d_op(sb, &fuse_dentry_operations);
> root_dentry = d_make_root(root);
> if (!root_dentry)
> goto err_dev_free;
> diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c
> index e83d293c3614..949bbdb5b564 100644
> --- a/fs/gfs2/ops_fstype.c
> +++ b/fs/gfs2/ops_fstype.c
> @@ -1156,7 +1156,7 @@ static int gfs2_fill_super(struct super_block *sb, struct fs_context *fc)
> sb->s_flags |= SB_NOSEC;
> sb->s_magic = GFS2_MAGIC;
> sb->s_op = &gfs2_super_ops;
> - sb->s_d_op = &gfs2_dops;
> + set_default_d_op(sb, &gfs2_dops);
> sb->s_export_op = &gfs2_export_ops;
> sb->s_qcop = &gfs2_quotactl_ops;
> sb->s_quota_types = QTYPE_MASK_USR | QTYPE_MASK_GRP;
> diff --git a/fs/hfs/super.c b/fs/hfs/super.c
> index fe09c2093a93..388a318297ec 100644
> --- a/fs/hfs/super.c
> +++ b/fs/hfs/super.c
> @@ -365,7 +365,7 @@ static int hfs_fill_super(struct super_block *sb, struct fs_context *fc)
> if (!root_inode)
> goto bail_no_root;
>
> - sb->s_d_op = &hfs_dentry_operations;
> + set_default_d_op(sb, &hfs_dentry_operations);
> res = -ENOMEM;
> sb->s_root = d_make_root(root_inode);
> if (!sb->s_root)
> diff --git a/fs/hfsplus/super.c b/fs/hfsplus/super.c
> index 948b8aaee33e..0caf7aa1c249 100644
> --- a/fs/hfsplus/super.c
> +++ b/fs/hfsplus/super.c
> @@ -508,7 +508,7 @@ static int hfsplus_fill_super(struct super_block *sb, struct fs_context *fc)
> goto out_put_alloc_file;
> }
>
> - sb->s_d_op = &hfsplus_dentry_operations;
> + set_default_d_op(sb, &hfsplus_dentry_operations);
> sb->s_root = d_make_root(root);
> if (!sb->s_root) {
> err = -ENOMEM;
> diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c
> index e0741e468956..a0e0563a29d7 100644
> --- a/fs/hostfs/hostfs_kern.c
> +++ b/fs/hostfs/hostfs_kern.c
> @@ -920,7 +920,7 @@ static int hostfs_fill_super(struct super_block *sb, struct fs_context *fc)
> sb->s_blocksize_bits = 10;
> sb->s_magic = HOSTFS_SUPER_MAGIC;
> sb->s_op = &hostfs_sbops;
> - sb->s_d_op = &simple_dentry_operations;
> + set_default_d_op(sb, &simple_dentry_operations);
> sb->s_maxbytes = MAX_LFS_FILESIZE;
> err = super_setup_bdi(sb);
> if (err)
> diff --git a/fs/hpfs/super.c b/fs/hpfs/super.c
> index 27567920abe4..42b779b4d87f 100644
> --- a/fs/hpfs/super.c
> +++ b/fs/hpfs/super.c
> @@ -554,7 +554,7 @@ static int hpfs_fill_super(struct super_block *s, struct fs_context *fc)
> /* Fill superblock stuff */
> s->s_magic = HPFS_SUPER_MAGIC;
> s->s_op = &hpfs_sops;
> - s->s_d_op = &hpfs_dentry_operations;
> + set_default_d_op(s, &hpfs_dentry_operations);
> s->s_time_min = local_to_gmt(s, 0);
> s->s_time_max = local_to_gmt(s, U32_MAX);
>
> diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c
> index 47038e660812..05ddc2544ade 100644
> --- a/fs/isofs/inode.c
> +++ b/fs/isofs/inode.c
> @@ -939,7 +939,7 @@ static int isofs_fill_super(struct super_block *s, struct fs_context *fc)
> sbi->s_check = opt->check;
>
> if (table)
> - s->s_d_op = &isofs_dentry_ops[table - 1];
> + set_default_d_op(s, &isofs_dentry_ops[table - 1]);
>
> /* get the root dentry */
> s->s_root = d_make_root(inode);
> diff --git a/fs/jfs/super.c b/fs/jfs/super.c
> index 223d9ac59839..10c3cb714423 100644
> --- a/fs/jfs/super.c
> +++ b/fs/jfs/super.c
> @@ -542,7 +542,7 @@ static int jfs_fill_super(struct super_block *sb, struct fs_context *fc)
> sb->s_magic = JFS_SUPER_MAGIC;
>
> if (sbi->mntflag & JFS_OS2)
> - sb->s_d_op = &jfs_ci_dentry_operations;
> + set_default_d_op(sb, &jfs_ci_dentry_operations);
>
> inode = jfs_iget(sb, ROOT_I);
> if (IS_ERR(inode)) {
> diff --git a/fs/kernfs/mount.c b/fs/kernfs/mount.c
> index 1358c21837f1..91e788d15073 100644
> --- a/fs/kernfs/mount.c
> +++ b/fs/kernfs/mount.c
> @@ -281,7 +281,7 @@ static int kernfs_fill_super(struct super_block *sb, struct kernfs_fs_context *k
> return -ENOMEM;
> }
> sb->s_root = root;
> - sb->s_d_op = &kernfs_dops;
> + set_default_d_op(sb, &kernfs_dops);
> return 0;
> }
>
> diff --git a/fs/libfs.c b/fs/libfs.c
> index 8444f5cc4064..929bef0fecbd 100644
> --- a/fs/libfs.c
> +++ b/fs/libfs.c
> @@ -75,7 +75,7 @@ struct dentry *simple_lookup(struct inode *dir, struct dentry *dentry, unsigned
> {
> if (dentry->d_name.len > NAME_MAX)
> return ERR_PTR(-ENAMETOOLONG);
> - if (!dentry->d_sb->s_d_op)
> + if (!dentry->d_op)
> d_set_d_op(dentry, &simple_dentry_operations);
>
> if (IS_ENABLED(CONFIG_UNICODE) && IS_CASEFOLDED(dir))
> @@ -683,7 +683,7 @@ static int pseudo_fs_fill_super(struct super_block *s, struct fs_context *fc)
> s->s_root = d_make_root(root);
> if (!s->s_root)
> return -ENOMEM;
> - s->s_d_op = ctx->dops;
> + set_default_d_op(s, ctx->dops);
> return 0;
> }
>
> @@ -1943,22 +1943,22 @@ static const struct dentry_operations generic_encrypted_dentry_ops = {
> * @sb: superblock to be configured
> *
> * Filesystems supporting casefolding and/or fscrypt can call this
> - * helper at mount-time to configure sb->s_d_op to best set of dentry
> - * operations required for the enabled features. The helper must be
> - * called after these have been configured, but before the root dentry
> - * is created.
> + * helper at mount-time to configure default dentry_operations to the
> + * best set of dentry operations required for the enabled features.
> + * The helper must be called after these have been configured, but
> + * before the root dentry is created.
> */
> void generic_set_sb_d_ops(struct super_block *sb)
> {
> #if IS_ENABLED(CONFIG_UNICODE)
> if (sb->s_encoding) {
> - sb->s_d_op = &generic_ci_dentry_ops;
> + set_default_d_op(sb, &generic_ci_dentry_ops);
> return;
> }
> #endif
> #ifdef CONFIG_FS_ENCRYPTION
> if (sb->s_cop) {
> - sb->s_d_op = &generic_encrypted_dentry_ops;
> + set_default_d_op(sb, &generic_encrypted_dentry_ops);
> return;
> }
> #endif
> diff --git a/fs/nfs/super.c b/fs/nfs/super.c
> index aeb715b4a690..38b0ecf02ad6 100644
> --- a/fs/nfs/super.c
> +++ b/fs/nfs/super.c
> @@ -1169,7 +1169,7 @@ static int nfs_set_super(struct super_block *s, struct fs_context *fc)
> struct nfs_server *server = fc->s_fs_info;
> int ret;
>
> - s->s_d_op = server->nfs_client->rpc_ops->dentry_ops;
> + set_default_d_op(s, server->nfs_client->rpc_ops->dentry_ops);
> ret = set_anon_super(s, server);
> if (ret == 0)
> server->s_dev = s->s_dev;
> diff --git a/fs/ntfs3/super.c b/fs/ntfs3/super.c
> index 6a0f6b0a3ab2..90f5361ae13f 100644
> --- a/fs/ntfs3/super.c
> +++ b/fs/ntfs3/super.c
> @@ -1182,7 +1182,8 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc)
> sb->s_export_op = &ntfs_export_ops;
> sb->s_time_gran = NTFS_TIME_GRAN; // 100 nsec
> sb->s_xattr = ntfs_xattr_handlers;
> - sb->s_d_op = options->nocase ? &ntfs_dentry_ops : NULL;
> + if (options->nocase)
> + set_default_d_op(sb, &ntfs_dentry_ops);
>
> options->nls = ntfs_load_nls(options->nls_name);
> if (IS_ERR(options->nls)) {
> diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c
> index 8bb5022f3082..411f72be4a9b 100644
> --- a/fs/ocfs2/super.c
> +++ b/fs/ocfs2/super.c
> @@ -1959,7 +1959,7 @@ static int ocfs2_initialize_super(struct super_block *sb,
>
> sb->s_fs_info = osb;
> sb->s_op = &ocfs2_sops;
> - sb->s_d_op = &ocfs2_dentry_ops;
> + set_default_d_op(sb, &ocfs2_dentry_ops);
> sb->s_export_op = &ocfs2_export_ops;
> sb->s_qcop = &dquot_quotactl_sysfile_ops;
> sb->dq_op = &ocfs2_quota_operations;
> diff --git a/fs/orangefs/super.c b/fs/orangefs/super.c
> index eba3e357192e..d4c8d8b32f14 100644
> --- a/fs/orangefs/super.c
> +++ b/fs/orangefs/super.c
> @@ -434,7 +434,7 @@ static int orangefs_fill_sb(struct super_block *sb,
> sb->s_xattr = orangefs_xattr_handlers;
> sb->s_magic = ORANGEFS_SUPER_MAGIC;
> sb->s_op = &orangefs_s_ops;
> - sb->s_d_op = &orangefs_dentry_operations;
> + set_default_d_op(sb, &orangefs_dentry_operations);
>
> sb->s_blocksize = PAGE_SIZE;
> sb->s_blocksize_bits = PAGE_SHIFT;
> diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c
> index 86ae6f6da36b..5f7a5a8c0778 100644
> --- a/fs/overlayfs/super.c
> +++ b/fs/overlayfs/super.c
> @@ -1315,7 +1315,7 @@ int ovl_fill_super(struct super_block *sb, struct fs_context *fc)
> if (WARN_ON(fc->user_ns != current_user_ns()))
> goto out_err;
>
> - sb->s_d_op = &ovl_dentry_operations;
> + set_default_d_op(sb, &ovl_dentry_operations);
>
> err = -ENOMEM;
> ofs->creator_cred = cred = prepare_creds();
> diff --git a/fs/smb/client/cifsfs.c b/fs/smb/client/cifsfs.c
> index 6a3bd652d251..5ba1046d1e5a 100644
> --- a/fs/smb/client/cifsfs.c
> +++ b/fs/smb/client/cifsfs.c
> @@ -261,9 +261,9 @@ cifs_read_super(struct super_block *sb)
> }
>
> if (tcon->nocase)
> - sb->s_d_op = &cifs_ci_dentry_ops;
> + set_default_d_op(sb, &cifs_ci_dentry_ops);
> else
> - sb->s_d_op = &cifs_dentry_ops;
> + set_default_d_op(sb, &cifs_dentry_ops);
>
> sb->s_root = d_make_root(inode);
> if (!sb->s_root) {
> diff --git a/fs/tracefs/inode.c b/fs/tracefs/inode.c
> index 53214499e384..30a951133831 100644
> --- a/fs/tracefs/inode.c
> +++ b/fs/tracefs/inode.c
> @@ -480,7 +480,7 @@ static int tracefs_fill_super(struct super_block *sb, struct fs_context *fc)
> return err;
>
> sb->s_op = &tracefs_super_operations;
> - sb->s_d_op = &tracefs_dentry_operations;
> + set_default_d_op(sb, &tracefs_dentry_operations);
>
> return 0;
> }
> diff --git a/fs/vboxsf/super.c b/fs/vboxsf/super.c
> index 1d94bb784108..46eea52beb23 100644
> --- a/fs/vboxsf/super.c
> +++ b/fs/vboxsf/super.c
> @@ -190,7 +190,7 @@ static int vboxsf_fill_super(struct super_block *sb, struct fs_context *fc)
> sb->s_blocksize = 1024;
> sb->s_maxbytes = MAX_LFS_FILESIZE;
> sb->s_op = &vboxsf_super_ops;
> - sb->s_d_op = &vboxsf_dentry_ops;
> + set_default_d_op(sb, &vboxsf_dentry_ops);
>
> iroot = iget_locked(sb, 0);
> if (!iroot) {
> diff --git a/include/linux/dcache.h b/include/linux/dcache.h
> index f47f3a47d97b..e8cf1d0fdd08 100644
> --- a/include/linux/dcache.h
> +++ b/include/linux/dcache.h
> @@ -619,4 +619,6 @@ static inline struct dentry *d_next_sibling(const struct dentry *dentry)
> return hlist_entry_safe(dentry->d_sib.next, struct dentry, d_sib);
> }
>
> +void set_default_d_op(struct super_block *, const struct dentry_operations *);
> +
> #endif /* __LINUX_DCACHE_H */
> diff --git a/include/linux/fs.h b/include/linux/fs.h
> index 2c3b2f8a621f..23fd8b0d4e81 100644
> --- a/include/linux/fs.h
> +++ b/include/linux/fs.h
> @@ -1405,7 +1405,7 @@ struct super_block {
> */
> const char *s_subtype;
>
> - const struct dentry_operations *s_d_op; /* default d_op for dentries */
> + const struct dentry_operations *__s_d_op; /* default d_op for dentries */
>
> struct shrinker *s_shrink; /* per-sb shrinker handle */
>
> diff --git a/mm/shmem.c b/mm/shmem.c
> index 4ea6109a8043..0ecb49113bb2 100644
> --- a/mm/shmem.c
> +++ b/mm/shmem.c
> @@ -5019,7 +5019,7 @@ static int shmem_fill_super(struct super_block *sb, struct fs_context *fc)
>
> if (ctx->encoding) {
> sb->s_encoding = ctx->encoding;
> - sb->s_d_op = &shmem_ci_dentry_ops;
> + set_default_d_op(sb, &shmem_ci_dentry_ops);
> if (ctx->strict_encoding)
> sb->s_encoding_flags = SB_ENC_STRICT_MODE_FL;
> }
> diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c
> index eadc00410ebc..e093e4cf20fa 100644
> --- a/net/sunrpc/rpc_pipe.c
> +++ b/net/sunrpc/rpc_pipe.c
> @@ -1363,7 +1363,7 @@ rpc_fill_super(struct super_block *sb, struct fs_context *fc)
> sb->s_blocksize_bits = PAGE_SHIFT;
> sb->s_magic = RPCAUTH_GSSMAGIC;
> sb->s_op = &s_ops;
> - sb->s_d_op = &simple_dentry_operations;
> + set_default_d_op(sb, &simple_dentry_operations);
> sb->s_time_gran = 1;
>
> inode = rpc_get_inode(sb, S_IFDIR | 0555);
> --
> 2.39.5
>
^ permalink raw reply [flat|nested] 87+ messages in thread
* Re: [PATCH 06/21] split d_flags calculation out of d_set_d_op()
2025-02-24 21:20 ` [PATCH 06/21] split d_flags calculation out of d_set_d_op() Al Viro
@ 2025-02-26 8:31 ` Christian Brauner
0 siblings, 0 replies; 87+ messages in thread
From: Christian Brauner @ 2025-02-26 8:31 UTC (permalink / raw)
To: Al Viro; +Cc: linux-fsdevel, Linus Torvalds, Neil Brown, Miklos Szeredi,
Jan Kara
On Mon, Feb 24, 2025 at 09:20:36PM +0000, Al Viro wrote:
> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
> ---
Reviewed-by: Christian Brauner <brauner@kernel.org>
> fs/dcache.c | 53 ++++++++++++++++++++++++++++++-----------------------
> 1 file changed, 30 insertions(+), 23 deletions(-)
>
> diff --git a/fs/dcache.c b/fs/dcache.c
> index cd5e5139ca4c..1201149e1e2c 100644
> --- a/fs/dcache.c
> +++ b/fs/dcache.c
> @@ -1811,33 +1811,40 @@ struct dentry *d_alloc_name(struct dentry *parent, const char *name)
> }
> EXPORT_SYMBOL(d_alloc_name);
>
> +#define DCACHE_OP_FLAGS \
> + (DCACHE_OP_HASH | DCACHE_OP_COMPARE | DCACHE_OP_REVALIDATE | \
> + DCACHE_OP_WEAK_REVALIDATE | DCACHE_OP_DELETE | DCACHE_OP_REAL)
> +
> +static unsigned int d_op_flags(const struct dentry_operations *op)
> +{
> + unsigned int flags = 0;
> + if (op) {
> + if (op->d_hash)
> + flags |= DCACHE_OP_HASH;
> + if (op->d_compare)
> + flags |= DCACHE_OP_COMPARE;
> + if (op->d_revalidate)
> + flags |= DCACHE_OP_REVALIDATE;
> + if (op->d_weak_revalidate)
> + flags |= DCACHE_OP_WEAK_REVALIDATE;
> + if (op->d_delete)
> + flags |= DCACHE_OP_DELETE;
> + if (op->d_prune)
> + flags |= DCACHE_OP_PRUNE;
> + if (op->d_real)
> + flags |= DCACHE_OP_REAL;
> + }
> + return flags;
> +}
> +
> void d_set_d_op(struct dentry *dentry, const struct dentry_operations *op)
> {
> + unsigned int flags = d_op_flags(op);
> WARN_ON_ONCE(dentry->d_op);
> - WARN_ON_ONCE(dentry->d_flags & (DCACHE_OP_HASH |
> - DCACHE_OP_COMPARE |
> - DCACHE_OP_REVALIDATE |
> - DCACHE_OP_WEAK_REVALIDATE |
> - DCACHE_OP_DELETE |
> - DCACHE_OP_REAL));
> + WARN_ON_ONCE(dentry->d_flags & DCACHE_OP_FLAGS);
> dentry->d_op = op;
> - if (!op)
> - return;
> - if (op->d_hash)
> - dentry->d_flags |= DCACHE_OP_HASH;
> - if (op->d_compare)
> - dentry->d_flags |= DCACHE_OP_COMPARE;
> - if (op->d_revalidate)
> - dentry->d_flags |= DCACHE_OP_REVALIDATE;
> - if (op->d_weak_revalidate)
> - dentry->d_flags |= DCACHE_OP_WEAK_REVALIDATE;
> - if (op->d_delete)
> - dentry->d_flags |= DCACHE_OP_DELETE;
> - if (op->d_prune)
> - dentry->d_flags |= DCACHE_OP_PRUNE;
> - if (op->d_real)
> - dentry->d_flags |= DCACHE_OP_REAL;
> -
> + if (flags)
> + dentry->d_flags |= flags;
> }
> EXPORT_SYMBOL(d_set_d_op);
>
> --
> 2.39.5
>
^ permalink raw reply [flat|nested] 87+ messages in thread
* Re: [PATCH 07/21] set_default_d_op(): calculate the matching value for ->d_flags
2025-02-24 21:20 ` [PATCH 07/21] set_default_d_op(): calculate the matching value for ->d_flags Al Viro
@ 2025-02-26 8:33 ` Christian Brauner
0 siblings, 0 replies; 87+ messages in thread
From: Christian Brauner @ 2025-02-26 8:33 UTC (permalink / raw)
To: Al Viro; +Cc: linux-fsdevel, Linus Torvalds, Neil Brown, Miklos Szeredi,
Jan Kara
On Mon, Feb 24, 2025 at 09:20:37PM +0000, Al Viro wrote:
> ... and store it in ->s_d_flags, to be used in __d_alloc()
>
> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
> ---
Reviewed-by: Christian Brauner <brauner@kernel.org>
> fs/dcache.c | 6 ++++--
> include/linux/fs.h | 1 +
> 2 files changed, 5 insertions(+), 2 deletions(-)
>
> diff --git a/fs/dcache.c b/fs/dcache.c
> index 1201149e1e2c..a4795617c3db 100644
> --- a/fs/dcache.c
> +++ b/fs/dcache.c
> @@ -1705,14 +1705,14 @@ static struct dentry *__d_alloc(struct super_block *sb, const struct qstr *name)
> dentry->d_inode = NULL;
> dentry->d_parent = dentry;
> dentry->d_sb = sb;
> - dentry->d_op = NULL;
> + dentry->d_op = sb->__s_d_op;
> + dentry->d_flags = sb->s_d_flags;
> dentry->d_fsdata = NULL;
> INIT_HLIST_BL_NODE(&dentry->d_hash);
> INIT_LIST_HEAD(&dentry->d_lru);
> INIT_HLIST_HEAD(&dentry->d_children);
> INIT_HLIST_NODE(&dentry->d_u.d_alias);
> INIT_HLIST_NODE(&dentry->d_sib);
> - d_set_d_op(dentry, dentry->d_sb->__s_d_op);
>
> if (dentry->d_op && dentry->d_op->d_init) {
> err = dentry->d_op->d_init(dentry);
> @@ -1850,7 +1850,9 @@ EXPORT_SYMBOL(d_set_d_op);
>
> void set_default_d_op(struct super_block *s, const struct dentry_operations *ops)
> {
> + unsigned int flags = d_op_flags(ops);
> s->__s_d_op = ops;
> + s->s_d_flags = (s->s_d_flags & ~DCACHE_OP_FLAGS) | flags;
> }
> EXPORT_SYMBOL(set_default_d_op);
>
> diff --git a/include/linux/fs.h b/include/linux/fs.h
> index 23fd8b0d4e81..473a9de5fc8f 100644
> --- a/include/linux/fs.h
> +++ b/include/linux/fs.h
> @@ -1392,6 +1392,7 @@ struct super_block {
> char s_sysfs_name[UUID_STRING_LEN + 1];
>
> unsigned int s_max_links;
> + unsigned int s_d_flags;
>
> /*
> * The next field is for VFS *only*. No filesystems have any business
> --
> 2.39.5
>
^ permalink raw reply [flat|nested] 87+ messages in thread
* Re: [PATCH 08/21] simple_lookup(): just set DCACHE_DONTCACHE
2025-02-24 21:20 ` [PATCH 08/21] simple_lookup(): just set DCACHE_DONTCACHE Al Viro
@ 2025-02-26 8:34 ` Christian Brauner
0 siblings, 0 replies; 87+ messages in thread
From: Christian Brauner @ 2025-02-26 8:34 UTC (permalink / raw)
To: Al Viro; +Cc: linux-fsdevel, Linus Torvalds, Neil Brown, Miklos Szeredi,
Jan Kara
On Mon, Feb 24, 2025 at 09:20:38PM +0000, Al Viro wrote:
> No need to mess with ->d_op at all. Note that ->d_delete that always
> returns 1 is equivalent to having DCACHE_DONTCACHE in ->d_flags.
> Later the same thing will be placed into ->s_d_flags of the filesystems
> where we want that behaviour for all dentries; then the check in
> simple_lookup() will at least get unlikely() slapped on it.
>
> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
> ---
Reviewed-by: Christian Brauner <brauner@kernel.org>
> fs/libfs.c | 8 +++++---
> 1 file changed, 5 insertions(+), 3 deletions(-)
>
> diff --git a/fs/libfs.c b/fs/libfs.c
> index 929bef0fecbd..b15a2148714e 100644
> --- a/fs/libfs.c
> +++ b/fs/libfs.c
> @@ -75,9 +75,11 @@ struct dentry *simple_lookup(struct inode *dir, struct dentry *dentry, unsigned
> {
> if (dentry->d_name.len > NAME_MAX)
> return ERR_PTR(-ENAMETOOLONG);
> - if (!dentry->d_op)
> - d_set_d_op(dentry, &simple_dentry_operations);
> -
> + if (!(dentry->d_flags & DCACHE_DONTCACHE)) {
> + spin_lock(&dentry->d_lock);
> + dentry->d_flags |= DCACHE_DONTCACHE;
> + spin_unlock(&dentry->d_lock);
> + }
> if (IS_ENABLED(CONFIG_UNICODE) && IS_CASEFOLDED(dir))
> return NULL;
>
> --
> 2.39.5
>
^ permalink raw reply [flat|nested] 87+ messages in thread
* Re: [PATCH 09/21] make d_set_d_op() static
2025-02-24 21:20 ` [PATCH 09/21] make d_set_d_op() static Al Viro
2025-02-25 23:09 ` NeilBrown
@ 2025-02-26 8:35 ` Christian Brauner
1 sibling, 0 replies; 87+ messages in thread
From: Christian Brauner @ 2025-02-26 8:35 UTC (permalink / raw)
To: Al Viro; +Cc: linux-fsdevel, Linus Torvalds, Neil Brown, Miklos Szeredi,
Jan Kara
On Mon, Feb 24, 2025 at 09:20:39PM +0000, Al Viro wrote:
> Convert the last user (d_alloc_pseudo()) and be done with that.
> Any out-of-tree filesystem using it should switch to d_splice_alias_ops()
> or, better yet, check whether it really needs to have ->d_op vary among
> its dentries.
>
> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
> ---
Reviewed-by: Christian Brauner <brauner@kernel.org>
> Documentation/filesystems/porting.rst | 11 +++++++++++
> fs/dcache.c | 5 ++---
> include/linux/dcache.h | 1 -
> 3 files changed, 13 insertions(+), 4 deletions(-)
>
> diff --git a/Documentation/filesystems/porting.rst b/Documentation/filesystems/porting.rst
> index 004cd69617a2..61b5771dde53 100644
> --- a/Documentation/filesystems/porting.rst
> +++ b/Documentation/filesystems/porting.rst
> @@ -1164,3 +1164,14 @@ magic.
>
> If your filesystem sets the default dentry_operations, use set_default_d_op()
> rather than manually setting sb->s_d_op.
> +
> +---
> +
> +**mandatory**
> +
> +d_set_d_op() is no longer exported (or public, for that matter); _if_
> +your filesystem really needed that, make use of d_splice_alias_ops()
> +to have them set. Better yet, think hard whether you need different
> +->d_op for different dentries - if not, just use set_default_d_op()
> +at mount time and be done with that. Currently procfs is the only
> +thing that really needs ->d_op varying between dentries.
> diff --git a/fs/dcache.c b/fs/dcache.c
> index a4795617c3db..29db27228d97 100644
> --- a/fs/dcache.c
> +++ b/fs/dcache.c
> @@ -1796,7 +1796,7 @@ struct dentry *d_alloc_pseudo(struct super_block *sb, const struct qstr *name)
> if (likely(dentry)) {
> dentry->d_flags |= DCACHE_NORCU;
> if (!dentry->d_op)
> - d_set_d_op(dentry, &anon_ops);
> + dentry->d_op = &anon_ops;
> }
> return dentry;
> }
> @@ -1837,7 +1837,7 @@ static unsigned int d_op_flags(const struct dentry_operations *op)
> return flags;
> }
>
> -void d_set_d_op(struct dentry *dentry, const struct dentry_operations *op)
> +static void d_set_d_op(struct dentry *dentry, const struct dentry_operations *op)
> {
> unsigned int flags = d_op_flags(op);
> WARN_ON_ONCE(dentry->d_op);
> @@ -1846,7 +1846,6 @@ void d_set_d_op(struct dentry *dentry, const struct dentry_operations *op)
> if (flags)
> dentry->d_flags |= flags;
> }
> -EXPORT_SYMBOL(d_set_d_op);
>
> void set_default_d_op(struct super_block *s, const struct dentry_operations *ops)
> {
> diff --git a/include/linux/dcache.h b/include/linux/dcache.h
> index e8cf1d0fdd08..5a03e85f92a4 100644
> --- a/include/linux/dcache.h
> +++ b/include/linux/dcache.h
> @@ -242,7 +242,6 @@ extern void d_instantiate_new(struct dentry *, struct inode *);
> extern void __d_drop(struct dentry *dentry);
> extern void d_drop(struct dentry *dentry);
> extern void d_delete(struct dentry *);
> -extern void d_set_d_op(struct dentry *dentry, const struct dentry_operations *op);
>
> /* allocate/de-allocate */
> extern struct dentry * d_alloc(struct dentry *, const struct qstr *);
> --
> 2.39.5
>
^ permalink raw reply [flat|nested] 87+ messages in thread
* Re: [PATCH 10/21] d_alloc_parallel(): set DCACHE_PAR_LOOKUP earlier
2025-02-24 21:20 ` [PATCH 10/21] d_alloc_parallel(): set DCACHE_PAR_LOOKUP earlier Al Viro
@ 2025-02-26 8:36 ` Christian Brauner
0 siblings, 0 replies; 87+ messages in thread
From: Christian Brauner @ 2025-02-26 8:36 UTC (permalink / raw)
To: Al Viro; +Cc: linux-fsdevel, Linus Torvalds, Neil Brown, Miklos Szeredi,
Jan Kara
On Mon, Feb 24, 2025 at 09:20:40PM +0000, Al Viro wrote:
> Do that before new dentry is visible anywhere. It does create
> a new possible state for dentries present in ->d_children/->d_sib -
> DCACHE_PAR_LOOKUP present, negative, unhashed, not in in-lookup
> hash chains, refcount positive. Those are going to be skipped
> by all tree-walkers (both d_walk() callbacks in fs/dcache.c and
> explicit loops over children/sibling lists elsewhere) and
> dput() is fine with those.
>
> NOTE: dropping the final reference to a "normal" in-lookup dentry
> (in in-lookup hash) is a bug - somebody must've forgotten to
> call d_lookup_done() on it and bad things will happen. With those
> it's OK; if/when we get around to making __dentry_kill() complain
> about such breakage, remember that predicate to check should
> *not* be just d_in_lookup(victim) but rather a combination of that
> with hlist_bl_unhashed(&victim->d_u.d_in_lookup_hash). Might
> be worth to consider later...
>
> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
> ---
Reviewed-by: Christian Brauner <brauner@kernel.org>
> fs/dcache.c | 10 +++++++---
> 1 file changed, 7 insertions(+), 3 deletions(-)
>
> diff --git a/fs/dcache.c b/fs/dcache.c
> index 29db27228d97..9ad7cbb5a6b0 100644
> --- a/fs/dcache.c
> +++ b/fs/dcache.c
> @@ -2518,13 +2518,19 @@ struct dentry *d_alloc_parallel(struct dentry *parent,
> unsigned int hash = name->hash;
> struct hlist_bl_head *b = in_lookup_hash(parent, hash);
> struct hlist_bl_node *node;
> - struct dentry *new = d_alloc(parent, name);
> + struct dentry *new = __d_alloc(parent->d_sb, name);
> struct dentry *dentry;
> unsigned seq, r_seq, d_seq;
>
> if (unlikely(!new))
> return ERR_PTR(-ENOMEM);
This is minor but it would be clearer if the __d_alloc() call was placed
directly above the error handling.
>
> + new->d_flags |= DCACHE_PAR_LOOKUP;
> + spin_lock(&parent->d_lock);
> + new->d_parent = dget_dlock(parent);
> + hlist_add_head(&new->d_sib, &parent->d_children);
> + spin_unlock(&parent->d_lock);
> +
> retry:
> rcu_read_lock();
> seq = smp_load_acquire(&parent->d_inode->i_dir_seq);
> @@ -2608,8 +2614,6 @@ struct dentry *d_alloc_parallel(struct dentry *parent,
> return dentry;
> }
> rcu_read_unlock();
> - /* we can't take ->d_lock here; it's OK, though. */
> - new->d_flags |= DCACHE_PAR_LOOKUP;
> new->d_wait = wq;
> hlist_bl_add_head(&new->d_u.d_in_lookup_hash, b);
> hlist_bl_unlock(b);
> --
> 2.39.5
>
^ permalink raw reply [flat|nested] 87+ messages in thread
* Re: [PATCH 11/21] nsfs, pidfs: drop the pointless ->d_delete()
2025-02-24 21:20 ` [PATCH 11/21] nsfs, pidfs: drop the pointless ->d_delete() Al Viro
@ 2025-02-26 8:37 ` Christian Brauner
0 siblings, 0 replies; 87+ messages in thread
From: Christian Brauner @ 2025-02-26 8:37 UTC (permalink / raw)
To: Al Viro; +Cc: linux-fsdevel, Linus Torvalds, Neil Brown, Miklos Szeredi,
Jan Kara
On Mon, Feb 24, 2025 at 09:20:41PM +0000, Al Viro wrote:
> No dentries are ever hashed on those, so ->d_delete() wouldn't be
> even looked at. If it's unhashed, we are not retaining it in dcache
> once the refcount hits zero, no matter what.
>
> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
> ---
Patches to remove this have already been merged into mainline.
> fs/nsfs.c | 1 -
> fs/pidfs.c | 1 -
> 2 files changed, 2 deletions(-)
>
> diff --git a/fs/nsfs.c b/fs/nsfs.c
> index 663f8656158d..f7fddf8ecf73 100644
> --- a/fs/nsfs.c
> +++ b/fs/nsfs.c
> @@ -37,7 +37,6 @@ static char *ns_dname(struct dentry *dentry, char *buffer, int buflen)
> }
>
> const struct dentry_operations ns_dentry_operations = {
> - .d_delete = always_delete_dentry,
> .d_dname = ns_dname,
> .d_prune = stashed_dentry_prune,
> };
> diff --git a/fs/pidfs.c b/fs/pidfs.c
> index 63f9699ebac3..c0478b3c55d9 100644
> --- a/fs/pidfs.c
> +++ b/fs/pidfs.c
> @@ -521,7 +521,6 @@ static char *pidfs_dname(struct dentry *dentry, char *buffer, int buflen)
> }
>
> const struct dentry_operations pidfs_dentry_operations = {
> - .d_delete = always_delete_dentry,
> .d_dname = pidfs_dname,
> .d_prune = stashed_dentry_prune,
> };
> --
> 2.39.5
>
^ permalink raw reply [flat|nested] 87+ messages in thread
* Re: [PATCH 12/21] shmem: no dentry retention past the refcount reaching zero
2025-02-24 21:20 ` [PATCH 12/21] shmem: no dentry retention past the refcount reaching zero Al Viro
@ 2025-02-26 8:38 ` Christian Brauner
0 siblings, 0 replies; 87+ messages in thread
From: Christian Brauner @ 2025-02-26 8:38 UTC (permalink / raw)
To: Al Viro; +Cc: linux-fsdevel, Linus Torvalds, Neil Brown, Miklos Szeredi,
Jan Kara
On Mon, Feb 24, 2025 at 09:20:42PM +0000, Al Viro wrote:
> Just set DCACHE_DONTCACHE in ->s_d_flags and be done with that.
> Dentries there live for as long as they are pinned; once the
> refcount hits zero, that's it. The same, of course, goes for
> other tree-in-dcache filesystems - more in the next commits...
>
> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
> ---
Reviewed-by: Christian Brauner <brauner@kernel.org>
> mm/shmem.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/mm/shmem.c b/mm/shmem.c
> index 0ecb49113bb2..dd84b1c554a8 100644
> --- a/mm/shmem.c
> +++ b/mm/shmem.c
> @@ -4971,7 +4971,6 @@ static void shmem_put_super(struct super_block *sb)
> static const struct dentry_operations shmem_ci_dentry_ops = {
> .d_hash = generic_ci_d_hash,
> .d_compare = generic_ci_d_compare,
> - .d_delete = always_delete_dentry,
> };
> #endif
>
> @@ -5028,6 +5027,7 @@ static int shmem_fill_super(struct super_block *sb, struct fs_context *fc)
> #else
> sb->s_flags |= SB_NOUSER;
> #endif /* CONFIG_TMPFS */
> + sb->s_d_flags |= DCACHE_DONTCACHE;
> sbinfo->max_blocks = ctx->blocks;
> sbinfo->max_inodes = ctx->inodes;
> sbinfo->free_ispace = sbinfo->max_inodes * BOGO_INODE_SIZE;
> --
> 2.39.5
>
^ permalink raw reply [flat|nested] 87+ messages in thread
* Re: [PATCH 13/21] devpts, sunrpc: don't bother with ->d_delete or ->d_op, for that matter
2025-02-24 21:20 ` [PATCH 13/21] devpts, sunrpc: don't bother with ->d_delete or ->d_op, for that matter Al Viro
@ 2025-02-26 8:38 ` Christian Brauner
0 siblings, 0 replies; 87+ messages in thread
From: Christian Brauner @ 2025-02-26 8:38 UTC (permalink / raw)
To: Al Viro; +Cc: linux-fsdevel, Linus Torvalds, Neil Brown, Miklos Szeredi,
Jan Kara
On Mon, Feb 24, 2025 at 09:20:43PM +0000, Al Viro wrote:
> Just put DCACHE_DONTCACHE into ->s_d_flags.
>
> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
> ---
Reviewed-by: Christian Brauner <brauner@kernel.org>
> fs/devpts/inode.c | 2 +-
> net/sunrpc/rpc_pipe.c | 2 +-
> 2 files changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/fs/devpts/inode.c b/fs/devpts/inode.c
> index f092973236ef..39344af02d1f 100644
> --- a/fs/devpts/inode.c
> +++ b/fs/devpts/inode.c
> @@ -433,7 +433,7 @@ devpts_fill_super(struct super_block *s, void *data, int silent)
> s->s_blocksize_bits = 10;
> s->s_magic = DEVPTS_SUPER_MAGIC;
> s->s_op = &devpts_sops;
> - set_default_d_op(s, &simple_dentry_operations);
> + s->s_d_flags = DCACHE_DONTCACHE;
> s->s_time_gran = 1;
>
> error = -ENOMEM;
> diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c
> index e093e4cf20fa..acb28a502580 100644
> --- a/net/sunrpc/rpc_pipe.c
> +++ b/net/sunrpc/rpc_pipe.c
> @@ -1363,7 +1363,7 @@ rpc_fill_super(struct super_block *sb, struct fs_context *fc)
> sb->s_blocksize_bits = PAGE_SHIFT;
> sb->s_magic = RPCAUTH_GSSMAGIC;
> sb->s_op = &s_ops;
> - set_default_d_op(sb, &simple_dentry_operations);
> + sb->s_d_flags = DCACHE_DONTCACHE;
> sb->s_time_gran = 1;
>
> inode = rpc_get_inode(sb, S_IFDIR | 0555);
> --
> 2.39.5
>
^ permalink raw reply [flat|nested] 87+ messages in thread
* Re: [PATCH 14/21] hostfs: don't bother with ->d_op
2025-02-24 21:20 ` [PATCH 14/21] hostfs: don't bother with ->d_op Al Viro
@ 2025-02-26 8:38 ` Christian Brauner
0 siblings, 0 replies; 87+ messages in thread
From: Christian Brauner @ 2025-02-26 8:38 UTC (permalink / raw)
To: Al Viro; +Cc: linux-fsdevel, Linus Torvalds, Neil Brown, Miklos Szeredi,
Jan Kara
On Mon, Feb 24, 2025 at 09:20:44PM +0000, Al Viro wrote:
> All we have there is ->d_delete equal to always_delete_dentry() and we
> want that for all dentries on that things. Setting DCACHE_DONTCACHE in
> ->s_d_flags will do just that.
>
> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
> ---
Reviewed-by: Christian Brauner <brauner@kernel.org>
> fs/hostfs/hostfs_kern.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c
> index a0e0563a29d7..52479205cefe 100644
> --- a/fs/hostfs/hostfs_kern.c
> +++ b/fs/hostfs/hostfs_kern.c
> @@ -920,7 +920,7 @@ static int hostfs_fill_super(struct super_block *sb, struct fs_context *fc)
> sb->s_blocksize_bits = 10;
> sb->s_magic = HOSTFS_SUPER_MAGIC;
> sb->s_op = &hostfs_sbops;
> - set_default_d_op(sb, &simple_dentry_operations);
> + sb->s_d_flags = DCACHE_DONTCACHE;
> sb->s_maxbytes = MAX_LFS_FILESIZE;
> err = super_setup_bdi(sb);
> if (err)
> --
> 2.39.5
>
^ permalink raw reply [flat|nested] 87+ messages in thread
* Re: [PATCH 15/21] kill simple_dentry_operations
2025-02-24 21:20 ` [PATCH 15/21] kill simple_dentry_operations Al Viro
@ 2025-02-26 8:39 ` Christian Brauner
0 siblings, 0 replies; 87+ messages in thread
From: Christian Brauner @ 2025-02-26 8:39 UTC (permalink / raw)
To: Al Viro; +Cc: linux-fsdevel, Linus Torvalds, Neil Brown, Miklos Szeredi,
Jan Kara
On Mon, Feb 24, 2025 at 09:20:45PM +0000, Al Viro wrote:
> No users left and anything that wants it would be better off just
> setting DCACHE_DONTCACHE in their ->s_d_flags.
>
> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
> ---
Reviewed-by: Christian Brauner <brauner@kernel.org>
> fs/libfs.c | 5 -----
> include/linux/fs.h | 1 -
> 2 files changed, 6 deletions(-)
>
> diff --git a/fs/libfs.c b/fs/libfs.c
> index b15a2148714e..7eebaee9d082 100644
> --- a/fs/libfs.c
> +++ b/fs/libfs.c
> @@ -62,11 +62,6 @@ int always_delete_dentry(const struct dentry *dentry)
> }
> EXPORT_SYMBOL(always_delete_dentry);
>
> -const struct dentry_operations simple_dentry_operations = {
> - .d_delete = always_delete_dentry,
> -};
> -EXPORT_SYMBOL(simple_dentry_operations);
> -
> /*
> * Lookup the data. This is trivial - if the dentry didn't already
> * exist, we know it is negative. Set d_op to delete negative dentries.
> diff --git a/include/linux/fs.h b/include/linux/fs.h
> index 473a9de5fc8f..bdaf2f85e1ad 100644
> --- a/include/linux/fs.h
> +++ b/include/linux/fs.h
> @@ -3540,7 +3540,6 @@ extern const struct address_space_operations ram_aops;
> extern int always_delete_dentry(const struct dentry *);
> extern struct inode *alloc_anon_inode(struct super_block *);
> extern int simple_nosetlease(struct file *, int, struct file_lease **, void **);
> -extern const struct dentry_operations simple_dentry_operations;
>
> extern struct dentry *simple_lookup(struct inode *, struct dentry *, unsigned int flags);
> extern ssize_t generic_read_dir(struct file *, char __user *, size_t, loff_t *);
> --
> 2.39.5
>
^ permalink raw reply [flat|nested] 87+ messages in thread
* Re: [PATCH 16/21] ramfs, hugetlbfs, mqueue: set DCACHE_DONTCACHE
2025-02-24 21:20 ` [PATCH 16/21] ramfs, hugetlbfs, mqueue: set DCACHE_DONTCACHE Al Viro
2025-02-25 23:25 ` NeilBrown
@ 2025-02-26 8:39 ` Christian Brauner
1 sibling, 0 replies; 87+ messages in thread
From: Christian Brauner @ 2025-02-26 8:39 UTC (permalink / raw)
To: Al Viro; +Cc: linux-fsdevel, Linus Torvalds, Neil Brown, Miklos Szeredi,
Jan Kara
On Mon, Feb 24, 2025 at 09:20:46PM +0000, Al Viro wrote:
> makes simple_lookup() slightly cheaper there.
>
> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
> ---
Reviewed-by: Christian Brauner <brauner@kernel.org>
> fs/hugetlbfs/inode.c | 1 +
> fs/ramfs/inode.c | 1 +
> ipc/mqueue.c | 1 +
> 3 files changed, 3 insertions(+)
>
> diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c
> index 0fc179a59830..205dd7562be1 100644
> --- a/fs/hugetlbfs/inode.c
> +++ b/fs/hugetlbfs/inode.c
> @@ -1431,6 +1431,7 @@ hugetlbfs_fill_super(struct super_block *sb, struct fs_context *fc)
> sb->s_blocksize_bits = huge_page_shift(ctx->hstate);
> sb->s_magic = HUGETLBFS_MAGIC;
> sb->s_op = &hugetlbfs_ops;
> + sb->s_d_flags = DCACHE_DONTCACHE;
> sb->s_time_gran = 1;
>
> /*
> diff --git a/fs/ramfs/inode.c b/fs/ramfs/inode.c
> index 8006faaaf0ec..c4ee67870c4b 100644
> --- a/fs/ramfs/inode.c
> +++ b/fs/ramfs/inode.c
> @@ -269,6 +269,7 @@ static int ramfs_fill_super(struct super_block *sb, struct fs_context *fc)
> sb->s_blocksize_bits = PAGE_SHIFT;
> sb->s_magic = RAMFS_MAGIC;
> sb->s_op = &ramfs_ops;
> + sb->s_d_flags = DCACHE_DONTCACHE;
> sb->s_time_gran = 1;
>
> inode = ramfs_get_inode(sb, NULL, S_IFDIR | fsi->mount_opts.mode, 0);
> diff --git a/ipc/mqueue.c b/ipc/mqueue.c
> index 35b4f8659904..dbd5c74eecb2 100644
> --- a/ipc/mqueue.c
> +++ b/ipc/mqueue.c
> @@ -411,6 +411,7 @@ static int mqueue_fill_super(struct super_block *sb, struct fs_context *fc)
> sb->s_blocksize_bits = PAGE_SHIFT;
> sb->s_magic = MQUEUE_MAGIC;
> sb->s_op = &mqueue_super_ops;
> + sb->s_d_flags = DCACHE_DONTCACHE;
>
> inode = mqueue_get_inode(sb, ns, S_IFDIR | S_ISVTX | S_IRWXUGO, NULL);
> if (IS_ERR(inode))
> --
> 2.39.5
>
^ permalink raw reply [flat|nested] 87+ messages in thread
* Re: [PATCH 17/21] 9p: don't bother with always_delete_dentry
2025-02-24 21:20 ` [PATCH 17/21] 9p: don't bother with always_delete_dentry Al Viro
@ 2025-02-26 8:40 ` Christian Brauner
0 siblings, 0 replies; 87+ messages in thread
From: Christian Brauner @ 2025-02-26 8:40 UTC (permalink / raw)
To: Al Viro; +Cc: linux-fsdevel, Linus Torvalds, Neil Brown, Miklos Szeredi,
Jan Kara
On Mon, Feb 24, 2025 at 09:20:47PM +0000, Al Viro wrote:
> just set DCACHE_DONTCACHE for "don't cache" mounts...
>
> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
> ---
Reviewed-by: Christian Brauner <brauner@kernel.org>
> fs/9p/vfs_dentry.c | 1 -
> fs/9p/vfs_super.c | 6 ++++--
> 2 files changed, 4 insertions(+), 3 deletions(-)
>
> diff --git a/fs/9p/vfs_dentry.c b/fs/9p/vfs_dentry.c
> index 5061f192eafd..04795508a795 100644
> --- a/fs/9p/vfs_dentry.c
> +++ b/fs/9p/vfs_dentry.c
> @@ -127,7 +127,6 @@ const struct dentry_operations v9fs_cached_dentry_operations = {
> };
>
> const struct dentry_operations v9fs_dentry_operations = {
> - .d_delete = always_delete_dentry,
> .d_release = v9fs_dentry_release,
> .d_unalias_trylock = v9fs_dentry_unalias_trylock,
> .d_unalias_unlock = v9fs_dentry_unalias_unlock,
> diff --git a/fs/9p/vfs_super.c b/fs/9p/vfs_super.c
> index 5c3dc3efb909..795c6388744c 100644
> --- a/fs/9p/vfs_super.c
> +++ b/fs/9p/vfs_super.c
> @@ -134,10 +134,12 @@ static struct dentry *v9fs_mount(struct file_system_type *fs_type, int flags,
> if (retval)
> goto release_sb;
>
> - if (v9ses->cache & (CACHE_META|CACHE_LOOSE))
> + if (v9ses->cache & (CACHE_META|CACHE_LOOSE)) {
> set_default_d_op(sb, &v9fs_cached_dentry_operations);
> - else
> + } else {
> set_default_d_op(sb, &v9fs_dentry_operations);
> + sb->s_d_flags |= DCACHE_DONTCACHE;
> + }
>
> inode = v9fs_get_new_inode_from_fid(v9ses, fid, sb);
> if (IS_ERR(inode)) {
> --
> 2.39.5
>
^ permalink raw reply [flat|nested] 87+ messages in thread
* Re: [PATCH 18/21] efivarfs: use DCACHE_DONTCACHE instead of always_delete_dentry()
2025-02-24 21:20 ` [PATCH 18/21] efivarfs: use DCACHE_DONTCACHE instead of always_delete_dentry() Al Viro
@ 2025-02-26 8:40 ` Christian Brauner
0 siblings, 0 replies; 87+ messages in thread
From: Christian Brauner @ 2025-02-26 8:40 UTC (permalink / raw)
To: Al Viro; +Cc: linux-fsdevel, Linus Torvalds, Neil Brown, Miklos Szeredi,
Jan Kara
On Mon, Feb 24, 2025 at 09:20:48PM +0000, Al Viro wrote:
> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
> ---
Reviewed-by: Christian Brauner <brauner@kernel.org>
> fs/efivarfs/super.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/fs/efivarfs/super.c b/fs/efivarfs/super.c
> index 3f3188e0cfa7..e5d3147cfcea 100644
> --- a/fs/efivarfs/super.c
> +++ b/fs/efivarfs/super.c
> @@ -175,7 +175,6 @@ static int efivarfs_d_hash(const struct dentry *dentry, struct qstr *qstr)
> static const struct dentry_operations efivarfs_d_ops = {
> .d_compare = efivarfs_d_compare,
> .d_hash = efivarfs_d_hash,
> - .d_delete = always_delete_dentry,
> };
>
> static struct dentry *efivarfs_alloc_dentry(struct dentry *parent, char *name)
> @@ -346,6 +345,7 @@ static int efivarfs_fill_super(struct super_block *sb, struct fs_context *fc)
> sb->s_magic = EFIVARFS_MAGIC;
> sb->s_op = &efivarfs_ops;
> set_default_d_op(sb, &efivarfs_d_ops);
> + sb->s_d_flags |= DCACHE_DONTCACHE;
> sb->s_time_gran = 1;
>
> if (!efivar_supports_writes())
> --
> 2.39.5
>
^ permalink raw reply [flat|nested] 87+ messages in thread
* Re: [PATCH 20/21] configfs: use DCACHE_DONTCACHE
2025-02-24 21:20 ` [PATCH 20/21] configfs: " Al Viro
@ 2025-02-26 8:40 ` Christian Brauner
0 siblings, 0 replies; 87+ messages in thread
From: Christian Brauner @ 2025-02-26 8:40 UTC (permalink / raw)
To: Al Viro; +Cc: linux-fsdevel, Linus Torvalds, Neil Brown, Miklos Szeredi,
Jan Kara
On Mon, Feb 24, 2025 at 09:20:50PM +0000, Al Viro wrote:
> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
> ---
Reviewed-by: Christian Brauner <brauner@kernel.org>
> fs/configfs/dir.c | 1 -
> fs/configfs/mount.c | 1 +
> 2 files changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/fs/configfs/dir.c b/fs/configfs/dir.c
> index 7d10278db30d..637267a76ad8 100644
> --- a/fs/configfs/dir.c
> +++ b/fs/configfs/dir.c
> @@ -67,7 +67,6 @@ static void configfs_d_iput(struct dentry * dentry,
>
> const struct dentry_operations configfs_dentry_ops = {
> .d_iput = configfs_d_iput,
> - .d_delete = always_delete_dentry,
> };
>
> #ifdef CONFIG_LOCKDEP
> diff --git a/fs/configfs/mount.c b/fs/configfs/mount.c
> index 20412eaca972..740f18b60c9d 100644
> --- a/fs/configfs/mount.c
> +++ b/fs/configfs/mount.c
> @@ -93,6 +93,7 @@ static int configfs_fill_super(struct super_block *sb, struct fs_context *fc)
> root->d_fsdata = &configfs_root;
> sb->s_root = root;
> set_default_d_op(sb, &configfs_dentry_ops); /* the rest get that */
> + sb->s_d_flags |= DCACHE_DONTCACHE;
> return 0;
> }
>
> --
> 2.39.5
>
^ permalink raw reply [flat|nested] 87+ messages in thread
* Re: [PATCH 19/21] debugfs: use DCACHE_DONTCACHE
2025-02-24 21:20 ` [PATCH 19/21] debugfs: use DCACHE_DONTCACHE Al Viro
@ 2025-02-26 8:40 ` Christian Brauner
0 siblings, 0 replies; 87+ messages in thread
From: Christian Brauner @ 2025-02-26 8:40 UTC (permalink / raw)
To: Al Viro; +Cc: linux-fsdevel, Linus Torvalds, Neil Brown, Miklos Szeredi,
Jan Kara
On Mon, Feb 24, 2025 at 09:20:49PM +0000, Al Viro wrote:
> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
> ---
Reviewed-by: Christian Brauner <brauner@kernel.org>
> fs/debugfs/inode.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c
> index f54a8fd960e4..1c71d9932a67 100644
> --- a/fs/debugfs/inode.c
> +++ b/fs/debugfs/inode.c
> @@ -258,7 +258,6 @@ static struct vfsmount *debugfs_automount(struct path *path)
> }
>
> static const struct dentry_operations debugfs_dops = {
> - .d_delete = always_delete_dentry,
> .d_release = debugfs_release_dentry,
> .d_automount = debugfs_automount,
> };
> @@ -274,6 +273,7 @@ static int debugfs_fill_super(struct super_block *sb, struct fs_context *fc)
>
> sb->s_op = &debugfs_super_operations;
> set_default_d_op(sb, &debugfs_dops);
> + sb->s_d_flags |= DCACHE_DONTCACHE;
>
> debugfs_apply_options(sb);
>
> --
> 2.39.5
>
^ permalink raw reply [flat|nested] 87+ messages in thread
* Re: [PATCH 21/21] afs dynroot: use DCACHE_DONTCACHE
2025-02-24 21:20 ` [PATCH 21/21] afs dynroot: " Al Viro
@ 2025-02-26 8:41 ` Christian Brauner
0 siblings, 0 replies; 87+ messages in thread
From: Christian Brauner @ 2025-02-26 8:41 UTC (permalink / raw)
To: Al Viro; +Cc: linux-fsdevel, Linus Torvalds, Neil Brown, Miklos Szeredi,
Jan Kara
On Mon, Feb 24, 2025 at 09:20:51PM +0000, Al Viro wrote:
> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
> ---
Reviewed-by: Christian Brauner <brauner@kernel.org>
> fs/afs/dynroot.c | 1 -
> fs/afs/super.c | 1 +
> 2 files changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/fs/afs/dynroot.c b/fs/afs/dynroot.c
> index d8bf52f77d93..2fad2987a6dc 100644
> --- a/fs/afs/dynroot.c
> +++ b/fs/afs/dynroot.c
> @@ -211,7 +211,6 @@ const struct inode_operations afs_dynroot_inode_operations = {
> };
>
> const struct dentry_operations afs_dynroot_dentry_operations = {
> - .d_delete = always_delete_dentry,
> .d_release = afs_d_release,
> .d_automount = afs_d_automount,
> };
> diff --git a/fs/afs/super.c b/fs/afs/super.c
> index 13d0414a1ddb..b48f524c1cb6 100644
> --- a/fs/afs/super.c
> +++ b/fs/afs/super.c
> @@ -488,6 +488,7 @@ static int afs_fill_super(struct super_block *sb, struct afs_fs_context *ctx)
>
> if (as->dyn_root) {
> set_default_d_op(sb, &afs_dynroot_dentry_operations);
> + sb->s_d_flags |= DCACHE_DONTCACHE;
> ret = afs_dynroot_populate(sb);
> if (ret < 0)
> goto error;
> --
> 2.39.5
>
^ permalink raw reply [flat|nested] 87+ messages in thread
* Re: [RFC] dentry->d_flags locking
2025-02-24 14:14 ` Al Viro
2025-02-24 21:20 ` [PATCH 01/21] procfs: kill ->proc_dops Al Viro
@ 2025-02-26 8:41 ` Christian Brauner
1 sibling, 0 replies; 87+ messages in thread
From: Christian Brauner @ 2025-02-26 8:41 UTC (permalink / raw)
To: Al Viro; +Cc: linux-fsdevel, Linus Torvalds, Neil Brown, Miklos Szeredi,
Jan Kara
On Mon, Feb 24, 2025 at 02:14:44PM +0000, Al Viro wrote:
> On Mon, Feb 24, 2025 at 11:35:47AM +0100, Christian Brauner wrote:
>
> > I think it would be worthwhile to mark dentries of such filesystems as
> > always unhashed and then add an assert into fs/dcache.c whenever such a
> > dentry should suddenly become hashed.
> >
> > That would not just make it very easy to see for the reviewer that the
> > dentries of this filesystem are always unhashed it would also make it
> > possible to spot bugs.
>
> Not sure that's useful, really... Details are tied into the tree-in-dcache
> rework, and I'll need to finish resurrecting that; should post in a week
> or so.
>
> For this series, see viro/vfs.git#work.dcache - it's a WIP at the moment,
> and it's going to get reordered (if nothing else, d_alloc_parallel()
> side needs an audit of tree-walkers to prove that it won't get confused
> by seeing DCACHE_PAR_LOOKUP on the stuff that hasn't yet reached in-lookup
> hash chains, and that might add prereqs that would need to go early in
> queue), but that at least fleshes out what I described upthread.
>
> I'll post individual patches for review in a few hours.
Went through them all. Everything looks good! Thanks!
Christian
^ permalink raw reply [flat|nested] 87+ messages in thread
* Re: [PATCH 04/21] fuse: no need for special dentry_operations for root dentry
2025-02-24 21:20 ` [PATCH 04/21] fuse: no need for special dentry_operations for root dentry Al Viro
2025-02-26 8:29 ` Christian Brauner
@ 2025-02-27 14:33 ` Miklos Szeredi
1 sibling, 0 replies; 87+ messages in thread
From: Miklos Szeredi @ 2025-02-27 14:33 UTC (permalink / raw)
To: Al Viro
Cc: linux-fsdevel, Linus Torvalds, Christian Brauner, Neil Brown,
Jan Kara
On Mon, 24 Feb 2025 at 22:20, Al Viro <viro@zeniv.linux.org.uk> wrote:
>
> ->d_revalidate() is never called for root anyway...
>
> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Acked-by: Miklos Szeredi <mszeredi@redhat.com>
^ permalink raw reply [flat|nested] 87+ messages in thread
* [RFC][PATCHES v2] dentry->d_flags locking
2025-02-24 11:45 ` Christian Brauner
@ 2025-06-11 7:50 ` Al Viro
2025-06-11 7:54 ` [PATCH v2 01/21] d_set_mounted(): we don't need to bump seqcount component of rename_lock Al Viro
2025-06-11 9:47 ` [RFC][PATCHES v2] dentry->d_flags locking Christian Brauner
0 siblings, 2 replies; 87+ messages in thread
From: Al Viro @ 2025-06-11 7:50 UTC (permalink / raw)
To: Christian Brauner
Cc: linux-fsdevel, Linus Torvalds, Neil Brown, Miklos Szeredi,
Jan Kara
On Mon, Feb 24, 2025 at 12:45:49PM +0100, Christian Brauner wrote:
> Also mentioned in my other reply: Can you please make the unhashed case
> really explicit ideally at dentry allocation time. IOW, that there's a
> flag or some other way of simply identifying a dentry as belonging to an
> fs that will never hash them?
This really doesn't make sense; on all those filesystems we *do* want
everything positive to be hashed. So I don't see anything useful that
fs/dcache.c could check, not to mention how much I dislike behaviour
that depends upon "feature flags" in file_system_type in general.
All dentries are allocated unhashed negative; a plenty of such fs
go through the normal lookup helpers when they populate their
trees. Sure, we could have their ->lookup() just return NULL
and be done with that, but then we'd have to modify the code
that handles attaching the damn things to inodes accordingly...
I don't see any point, especially since it would just create churn
for tree-in-dcache series porting^Wresurrection, which I'm going
to do this weekend.
Or are you talking about DCACHE_DONTCACHE (i.e. "unhash as soon as
refcount hits 0", rather than "never hash it at all")?
Anyway, I have ported the "safe ->d_flags" series (this thread) to
6.16-rc1. Changes:
* several commits got dropped (merged or, as in afs dynroot case, invalidated)
* procfs flag moved to include/linux/procfs.h, deconflicted.
* tracefs told to set DCACHE_DONTCACHE on everything; it is a behaviour
change, and IMO the correct one.
* in "simple_lookup(): just set DCACHE_DONTCACHE", don't set the flag if
->d_op had been set and DCACHE_DONTCACHE wasn't already present. That
matches the mainline logics. See comments in that commit...
Force-pushed into
git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs.git #work.dcache
Individual patches in followups; if nobody comes up with objections,
into #for-next it goes. Folks, please review.
^ permalink raw reply [flat|nested] 87+ messages in thread
* [PATCH v2 01/21] d_set_mounted(): we don't need to bump seqcount component of rename_lock
2025-06-11 7:50 ` [RFC][PATCHES v2] " Al Viro
@ 2025-06-11 7:54 ` Al Viro
2025-06-11 7:54 ` [PATCH v2 02/21] procfs: kill ->proc_dops Al Viro
` (19 more replies)
2025-06-11 9:47 ` [RFC][PATCHES v2] dentry->d_flags locking Christian Brauner
1 sibling, 20 replies; 87+ messages in thread
From: Al Viro @ 2025-06-11 7:54 UTC (permalink / raw)
To: linux-fsdevel; +Cc: brauner, jack, miklos, neilb, torvalds
IOW, read_seqlock_excl() is sufficient there; no need to bother
with write_seqlock() (forcing all rename_lock readers into retry).
That leaves rename_lock taken for write only when we want to change
someone's parent or name.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/dcache.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/fs/dcache.c b/fs/dcache.c
index 03d58b2d4fa3..3c3cfb345233 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -1436,7 +1436,7 @@ int d_set_mounted(struct dentry *dentry)
{
struct dentry *p;
int ret = -ENOENT;
- write_seqlock(&rename_lock);
+ read_seqlock_excl(&rename_lock);
for (p = dentry->d_parent; !IS_ROOT(p); p = p->d_parent) {
/* Need exclusion wrt. d_invalidate() */
spin_lock(&p->d_lock);
@@ -1456,7 +1456,7 @@ int d_set_mounted(struct dentry *dentry)
}
spin_unlock(&dentry->d_lock);
out:
- write_sequnlock(&rename_lock);
+ read_sequnlock_excl(&rename_lock);
return ret;
}
--
2.39.5
^ permalink raw reply related [flat|nested] 87+ messages in thread
* [PATCH v2 02/21] procfs: kill ->proc_dops
2025-06-11 7:54 ` [PATCH v2 01/21] d_set_mounted(): we don't need to bump seqcount component of rename_lock Al Viro
@ 2025-06-11 7:54 ` Al Viro
2025-06-11 7:54 ` [PATCH v2 03/21] new helper: d_splice_alias_ops() Al Viro
` (18 subsequent siblings)
19 siblings, 0 replies; 87+ messages in thread
From: Al Viro @ 2025-06-11 7:54 UTC (permalink / raw)
To: linux-fsdevel; +Cc: brauner, jack, miklos, neilb, torvalds
It has two possible values - one for "forced lookup" entries, another
for the normal ones. We'd be better off with that as an explicit
flag anyway and in addition to that it opens some fun possibilities
with ->d_op and ->d_flags handling.
[moved PROC_ENTRY_FORCE_LOOKUP to include/linux/proc_fs.h, switched it
to an unused bit - there was a conflict]
Reviewed-by: Christian Brauner <brauner@kernel.org>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/proc/generic.c | 8 +++++---
fs/proc/internal.h | 3 +--
include/linux/proc_fs.h | 2 ++
3 files changed, 8 insertions(+), 5 deletions(-)
diff --git a/fs/proc/generic.c b/fs/proc/generic.c
index a3e22803cddf..38ce45ce0eb6 100644
--- a/fs/proc/generic.c
+++ b/fs/proc/generic.c
@@ -254,7 +254,10 @@ struct dentry *proc_lookup_de(struct inode *dir, struct dentry *dentry,
inode = proc_get_inode(dir->i_sb, de);
if (!inode)
return ERR_PTR(-ENOMEM);
- d_set_d_op(dentry, de->proc_dops);
+ if (de->flags & PROC_ENTRY_FORCE_LOOKUP)
+ d_set_d_op(dentry, &proc_net_dentry_ops);
+ else
+ d_set_d_op(dentry, &proc_misc_dentry_ops);
return d_splice_alias(inode, dentry);
}
read_unlock(&proc_subdir_lock);
@@ -448,9 +451,8 @@ static struct proc_dir_entry *__proc_create(struct proc_dir_entry **parent,
INIT_LIST_HEAD(&ent->pde_openers);
proc_set_user(ent, (*parent)->uid, (*parent)->gid);
- ent->proc_dops = &proc_misc_dentry_ops;
/* Revalidate everything under /proc/${pid}/net */
- if ((*parent)->proc_dops == &proc_net_dentry_ops)
+ if ((*parent)->flags & PROC_ENTRY_FORCE_LOOKUP)
pde_force_lookup(ent);
out:
diff --git a/fs/proc/internal.h b/fs/proc/internal.h
index 96122e91c645..a4054916f6da 100644
--- a/fs/proc/internal.h
+++ b/fs/proc/internal.h
@@ -44,7 +44,6 @@ struct proc_dir_entry {
const struct proc_ops *proc_ops;
const struct file_operations *proc_dir_ops;
};
- const struct dentry_operations *proc_dops;
union {
const struct seq_operations *seq_ops;
int (*single_show)(struct seq_file *, void *);
@@ -403,7 +402,7 @@ extern const struct dentry_operations proc_net_dentry_ops;
static inline void pde_force_lookup(struct proc_dir_entry *pde)
{
/* /proc/net/ entries can be changed under us by setns(CLONE_NEWNET) */
- pde->proc_dops = &proc_net_dentry_ops;
+ pde->flags |= PROC_ENTRY_FORCE_LOOKUP;
}
/*
diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h
index ea62201c74c4..de1d24f19f76 100644
--- a/include/linux/proc_fs.h
+++ b/include/linux/proc_fs.h
@@ -27,6 +27,8 @@ enum {
PROC_ENTRY_proc_read_iter = 1U << 1,
PROC_ENTRY_proc_compat_ioctl = 1U << 2,
+
+ PROC_ENTRY_FORCE_LOOKUP = 1U << 7,
};
struct proc_ops {
--
2.39.5
^ permalink raw reply related [flat|nested] 87+ messages in thread
* [PATCH v2 03/21] new helper: d_splice_alias_ops()
2025-06-11 7:54 ` [PATCH v2 01/21] d_set_mounted(): we don't need to bump seqcount component of rename_lock Al Viro
2025-06-11 7:54 ` [PATCH v2 02/21] procfs: kill ->proc_dops Al Viro
@ 2025-06-11 7:54 ` Al Viro
2025-06-11 7:54 ` [PATCH v2 04/21] switch procfs from d_set_d_op() to d_splice_alias_ops() Al Viro
` (17 subsequent siblings)
19 siblings, 0 replies; 87+ messages in thread
From: Al Viro @ 2025-06-11 7:54 UTC (permalink / raw)
To: linux-fsdevel; +Cc: brauner, jack, miklos, neilb, torvalds
Uses of d_set_d_op() on live dentry can be very dangerous; it is going
to be withdrawn and replaced with saner things.
The best way for a filesystem is to have the default dentry_operations
set at mount time and be done with that - __d_alloc() will use that.
Currently there are two cases when d_set_d_op() is used on a live dentry -
one is procfs, which has several genuinely different dentry_operations
instances (different ->d_revalidate(), etc.) and another is
simple_lookup(), where we would be better off without overriding ->d_op.
For procfs we have d_set_d_op() calls followed by d_splice_alias();
provide a new helper (d_splice_alias_ops(inode, dentry, d_ops)) that would
combine those two, and do the d_set_d_op() part while under ->d_lock.
That eliminates one of the places where ->d_flags had been modified
without holding ->d_lock; current behaviour is not racy, but the reasons
for that are far too brittle. Better move to uniform locking rules and
simpler proof of correctness...
The next commit will convert procfs to use of that helper; it is not
exported and won't be until somebody comes up with convincing modular
user for it.
Again, the best approach is to have default ->d_op and let __d_alloc()
do the right thing; filesystem _may_ need non-uniform ->d_op (procfs
does), but there'd better be good reasons for that.
Reviewed-by: Christian Brauner <brauner@kernel.org>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/dcache.c | 63 ++++++++++++++++++++++++------------------
include/linux/dcache.h | 3 ++
2 files changed, 39 insertions(+), 27 deletions(-)
diff --git a/fs/dcache.c b/fs/dcache.c
index 3c3cfb345233..bf550d438e40 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -2667,7 +2667,8 @@ EXPORT_SYMBOL(__d_lookup_unhash_wake);
/* inode->i_lock held if inode is non-NULL */
-static inline void __d_add(struct dentry *dentry, struct inode *inode)
+static inline void __d_add(struct dentry *dentry, struct inode *inode,
+ const struct dentry_operations *ops)
{
wait_queue_head_t *d_wait;
struct inode *dir = NULL;
@@ -2678,6 +2679,8 @@ static inline void __d_add(struct dentry *dentry, struct inode *inode)
n = start_dir_add(dir);
d_wait = __d_lookup_unhash(dentry);
}
+ if (unlikely(ops))
+ d_set_d_op(dentry, ops);
if (inode) {
unsigned add_flags = d_flags_for_inode(inode);
hlist_add_head(&dentry->d_u.d_alias, &inode->i_dentry);
@@ -2709,7 +2712,7 @@ void d_add(struct dentry *entry, struct inode *inode)
security_d_instantiate(entry, inode);
spin_lock(&inode->i_lock);
}
- __d_add(entry, inode);
+ __d_add(entry, inode, NULL);
}
EXPORT_SYMBOL(d_add);
@@ -2961,30 +2964,8 @@ static int __d_unalias(struct dentry *dentry, struct dentry *alias)
return ret;
}
-/**
- * d_splice_alias - splice a disconnected dentry into the tree if one exists
- * @inode: the inode which may have a disconnected dentry
- * @dentry: a negative dentry which we want to point to the inode.
- *
- * If inode is a directory and has an IS_ROOT alias, then d_move that in
- * place of the given dentry and return it, else simply d_add the inode
- * to the dentry and return NULL.
- *
- * If a non-IS_ROOT directory is found, the filesystem is corrupt, and
- * we should error out: directories can't have multiple aliases.
- *
- * This is needed in the lookup routine of any filesystem that is exportable
- * (via knfsd) so that we can build dcache paths to directories effectively.
- *
- * If a dentry was found and moved, then it is returned. Otherwise NULL
- * is returned. This matches the expected return value of ->lookup.
- *
- * Cluster filesystems may call this function with a negative, hashed dentry.
- * In that case, we know that the inode will be a regular file, and also this
- * will only occur during atomic_open. So we need to check for the dentry
- * being already hashed only in the final case.
- */
-struct dentry *d_splice_alias(struct inode *inode, struct dentry *dentry)
+struct dentry *d_splice_alias_ops(struct inode *inode, struct dentry *dentry,
+ const struct dentry_operations *ops)
{
if (IS_ERR(inode))
return ERR_CAST(inode);
@@ -3030,9 +3011,37 @@ struct dentry *d_splice_alias(struct inode *inode, struct dentry *dentry)
}
}
out:
- __d_add(dentry, inode);
+ __d_add(dentry, inode, ops);
return NULL;
}
+
+/**
+ * d_splice_alias - splice a disconnected dentry into the tree if one exists
+ * @inode: the inode which may have a disconnected dentry
+ * @dentry: a negative dentry which we want to point to the inode.
+ *
+ * If inode is a directory and has an IS_ROOT alias, then d_move that in
+ * place of the given dentry and return it, else simply d_add the inode
+ * to the dentry and return NULL.
+ *
+ * If a non-IS_ROOT directory is found, the filesystem is corrupt, and
+ * we should error out: directories can't have multiple aliases.
+ *
+ * This is needed in the lookup routine of any filesystem that is exportable
+ * (via knfsd) so that we can build dcache paths to directories effectively.
+ *
+ * If a dentry was found and moved, then it is returned. Otherwise NULL
+ * is returned. This matches the expected return value of ->lookup.
+ *
+ * Cluster filesystems may call this function with a negative, hashed dentry.
+ * In that case, we know that the inode will be a regular file, and also this
+ * will only occur during atomic_open. So we need to check for the dentry
+ * being already hashed only in the final case.
+ */
+struct dentry *d_splice_alias(struct inode *inode, struct dentry *dentry)
+{
+ return d_splice_alias_ops(inode, dentry, NULL);
+}
EXPORT_SYMBOL(d_splice_alias);
/*
diff --git a/include/linux/dcache.h b/include/linux/dcache.h
index e29823c701ac..1993e6704552 100644
--- a/include/linux/dcache.h
+++ b/include/linux/dcache.h
@@ -245,6 +245,9 @@ extern struct dentry * d_alloc_anon(struct super_block *);
extern struct dentry * d_alloc_parallel(struct dentry *, const struct qstr *,
wait_queue_head_t *);
extern struct dentry * d_splice_alias(struct inode *, struct dentry *);
+/* weird procfs mess; *NOT* exported */
+extern struct dentry * d_splice_alias_ops(struct inode *, struct dentry *,
+ const struct dentry_operations *);
extern struct dentry * d_add_ci(struct dentry *, struct inode *, struct qstr *);
extern bool d_same_name(const struct dentry *dentry, const struct dentry *parent,
const struct qstr *name);
--
2.39.5
^ permalink raw reply related [flat|nested] 87+ messages in thread
* [PATCH v2 04/21] switch procfs from d_set_d_op() to d_splice_alias_ops()
2025-06-11 7:54 ` [PATCH v2 01/21] d_set_mounted(): we don't need to bump seqcount component of rename_lock Al Viro
2025-06-11 7:54 ` [PATCH v2 02/21] procfs: kill ->proc_dops Al Viro
2025-06-11 7:54 ` [PATCH v2 03/21] new helper: d_splice_alias_ops() Al Viro
@ 2025-06-11 7:54 ` Al Viro
2025-06-11 7:54 ` [PATCH v2 05/21] fuse: no need for special dentry_operations for root dentry Al Viro
` (16 subsequent siblings)
19 siblings, 0 replies; 87+ messages in thread
From: Al Viro @ 2025-06-11 7:54 UTC (permalink / raw)
To: linux-fsdevel; +Cc: brauner, jack, miklos, neilb, torvalds
Reviewed-by: Christian Brauner <brauner@kernel.org>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/proc/base.c | 9 +++------
fs/proc/generic.c | 8 ++++----
fs/proc/internal.h | 3 +--
fs/proc/namespaces.c | 3 +--
fs/proc/proc_sysctl.c | 7 +++----
5 files changed, 12 insertions(+), 18 deletions(-)
diff --git a/fs/proc/base.c b/fs/proc/base.c
index c667702dc69b..e93149a01341 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -2704,8 +2704,7 @@ static struct dentry *proc_pident_instantiate(struct dentry *dentry,
inode->i_fop = p->fop;
ei->op = p->op;
pid_update_inode(task, inode);
- d_set_d_op(dentry, &pid_dentry_operations);
- return d_splice_alias(inode, dentry);
+ return d_splice_alias_ops(inode, dentry, &pid_dentry_operations);
}
static struct dentry *proc_pident_lookup(struct inode *dir,
@@ -3501,8 +3500,7 @@ static struct dentry *proc_pid_instantiate(struct dentry * dentry,
set_nlink(inode, nlink_tgid);
pid_update_inode(task, inode);
- d_set_d_op(dentry, &pid_dentry_operations);
- return d_splice_alias(inode, dentry);
+ return d_splice_alias_ops(inode, dentry, &pid_dentry_operations);
}
struct dentry *proc_pid_lookup(struct dentry *dentry, unsigned int flags)
@@ -3804,8 +3802,7 @@ static struct dentry *proc_task_instantiate(struct dentry *dentry,
set_nlink(inode, nlink_tid);
pid_update_inode(task, inode);
- d_set_d_op(dentry, &pid_dentry_operations);
- return d_splice_alias(inode, dentry);
+ return d_splice_alias_ops(inode, dentry, &pid_dentry_operations);
}
static struct dentry *proc_task_lookup(struct inode *dir, struct dentry * dentry, unsigned int flags)
diff --git a/fs/proc/generic.c b/fs/proc/generic.c
index 38ce45ce0eb6..5635453cd476 100644
--- a/fs/proc/generic.c
+++ b/fs/proc/generic.c
@@ -255,10 +255,10 @@ struct dentry *proc_lookup_de(struct inode *dir, struct dentry *dentry,
if (!inode)
return ERR_PTR(-ENOMEM);
if (de->flags & PROC_ENTRY_FORCE_LOOKUP)
- d_set_d_op(dentry, &proc_net_dentry_ops);
- else
- d_set_d_op(dentry, &proc_misc_dentry_ops);
- return d_splice_alias(inode, dentry);
+ return d_splice_alias_ops(inode, dentry,
+ &proc_net_dentry_ops);
+ return d_splice_alias_ops(inode, dentry,
+ &proc_misc_dentry_ops);
}
read_unlock(&proc_subdir_lock);
return ERR_PTR(-ENOENT);
diff --git a/fs/proc/internal.h b/fs/proc/internal.h
index a4054916f6da..520c4742101d 100644
--- a/fs/proc/internal.h
+++ b/fs/proc/internal.h
@@ -413,7 +413,6 @@ static inline void pde_force_lookup(struct proc_dir_entry *pde)
static inline struct dentry *proc_splice_unmountable(struct inode *inode,
struct dentry *dentry, const struct dentry_operations *d_ops)
{
- d_set_d_op(dentry, d_ops);
dont_mount(dentry);
- return d_splice_alias(inode, dentry);
+ return d_splice_alias_ops(inode, dentry, d_ops);
}
diff --git a/fs/proc/namespaces.c b/fs/proc/namespaces.c
index c610224faf10..4403a2e20c16 100644
--- a/fs/proc/namespaces.c
+++ b/fs/proc/namespaces.c
@@ -111,8 +111,7 @@ static struct dentry *proc_ns_instantiate(struct dentry *dentry,
ei->ns_ops = ns_ops;
pid_update_inode(task, inode);
- d_set_d_op(dentry, &pid_dentry_operations);
- return d_splice_alias(inode, dentry);
+ return d_splice_alias_ops(inode, dentry, &pid_dentry_operations);
}
static int proc_ns_dir_readdir(struct file *file, struct dir_context *ctx)
diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c
index cc9d74a06ff0..7a8bffc03dc8 100644
--- a/fs/proc/proc_sysctl.c
+++ b/fs/proc/proc_sysctl.c
@@ -540,9 +540,8 @@ static struct dentry *proc_sys_lookup(struct inode *dir, struct dentry *dentry,
goto out;
}
- d_set_d_op(dentry, &proc_sys_dentry_operations);
inode = proc_sys_make_inode(dir->i_sb, h ? h : head, p);
- err = d_splice_alias(inode, dentry);
+ err = d_splice_alias_ops(inode, dentry, &proc_sys_dentry_operations);
out:
if (h)
@@ -699,9 +698,9 @@ static bool proc_sys_fill_cache(struct file *file,
return false;
if (d_in_lookup(child)) {
struct dentry *res;
- d_set_d_op(child, &proc_sys_dentry_operations);
inode = proc_sys_make_inode(dir->d_sb, head, table);
- res = d_splice_alias(inode, child);
+ res = d_splice_alias_ops(inode, child,
+ &proc_sys_dentry_operations);
d_lookup_done(child);
if (unlikely(res)) {
dput(child);
--
2.39.5
^ permalink raw reply related [flat|nested] 87+ messages in thread
* [PATCH v2 05/21] fuse: no need for special dentry_operations for root dentry
2025-06-11 7:54 ` [PATCH v2 01/21] d_set_mounted(): we don't need to bump seqcount component of rename_lock Al Viro
` (2 preceding siblings ...)
2025-06-11 7:54 ` [PATCH v2 04/21] switch procfs from d_set_d_op() to d_splice_alias_ops() Al Viro
@ 2025-06-11 7:54 ` Al Viro
2025-06-11 7:54 ` [PATCH v2 06/21] new helper: set_default_d_op() Al Viro
` (15 subsequent siblings)
19 siblings, 0 replies; 87+ messages in thread
From: Al Viro @ 2025-06-11 7:54 UTC (permalink / raw)
To: linux-fsdevel; +Cc: brauner, jack, miklos, neilb, torvalds
->d_revalidate() is never called for root anyway...
Reviewed-by: Christian Brauner <brauner@kernel.org>
Acked-by: Miklos Szeredi <mszeredi@redhat.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/fuse/dir.c | 7 -------
fs/fuse/fuse_i.h | 1 -
fs/fuse/inode.c | 4 +---
3 files changed, 1 insertion(+), 11 deletions(-)
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
index 45b4c3cc1396..2d817d7cab26 100644
--- a/fs/fuse/dir.c
+++ b/fs/fuse/dir.c
@@ -338,13 +338,6 @@ const struct dentry_operations fuse_dentry_operations = {
.d_automount = fuse_dentry_automount,
};
-const struct dentry_operations fuse_root_dentry_operations = {
-#if BITS_PER_LONG < 64
- .d_init = fuse_dentry_init,
- .d_release = fuse_dentry_release,
-#endif
-};
-
int fuse_valid_type(int m)
{
return S_ISREG(m) || S_ISDIR(m) || S_ISLNK(m) || S_ISCHR(m) ||
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
index b54f4f57789f..fb885376db6a 100644
--- a/fs/fuse/fuse_i.h
+++ b/fs/fuse/fuse_i.h
@@ -1109,7 +1109,6 @@ static inline void fuse_sync_bucket_dec(struct fuse_sync_bucket *bucket)
extern const struct file_operations fuse_dev_operations;
extern const struct dentry_operations fuse_dentry_operations;
-extern const struct dentry_operations fuse_root_dentry_operations;
/**
* Get a filled in inode
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
index bfe8d8af46f3..eb6177508598 100644
--- a/fs/fuse/inode.c
+++ b/fs/fuse/inode.c
@@ -1850,12 +1850,10 @@ int fuse_fill_super_common(struct super_block *sb, struct fuse_fs_context *ctx)
err = -ENOMEM;
root = fuse_get_root_inode(sb, ctx->rootmode);
- sb->s_d_op = &fuse_root_dentry_operations;
+ sb->s_d_op = &fuse_dentry_operations;
root_dentry = d_make_root(root);
if (!root_dentry)
goto err_dev_free;
- /* Root dentry doesn't have .d_revalidate */
- sb->s_d_op = &fuse_dentry_operations;
mutex_lock(&fuse_mutex);
err = -EINVAL;
--
2.39.5
^ permalink raw reply related [flat|nested] 87+ messages in thread
* [PATCH v2 06/21] new helper: set_default_d_op()
2025-06-11 7:54 ` [PATCH v2 01/21] d_set_mounted(): we don't need to bump seqcount component of rename_lock Al Viro
` (3 preceding siblings ...)
2025-06-11 7:54 ` [PATCH v2 05/21] fuse: no need for special dentry_operations for root dentry Al Viro
@ 2025-06-11 7:54 ` Al Viro
2025-06-11 7:54 ` [PATCH v2 07/21] split d_flags calculation out of d_set_d_op() Al Viro
` (14 subsequent siblings)
19 siblings, 0 replies; 87+ messages in thread
From: Al Viro @ 2025-06-11 7:54 UTC (permalink / raw)
To: linux-fsdevel; +Cc: brauner, jack, miklos, neilb, torvalds
... to be used instead of manually assigning to ->s_d_op.
All in-tree filesystem converted (and field itself is renamed,
so any out-of-tree ones in need of conversion will be caught
by compiler).
Reviewed-by: Christian Brauner <brauner@kernel.org>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
Documentation/filesystems/porting.rst | 7 +++++++
fs/9p/vfs_super.c | 4 ++--
fs/adfs/super.c | 2 +-
fs/affs/super.c | 4 ++--
fs/afs/super.c | 4 ++--
fs/autofs/inode.c | 2 +-
fs/btrfs/super.c | 2 +-
fs/ceph/super.c | 2 +-
fs/coda/inode.c | 2 +-
fs/configfs/mount.c | 2 +-
fs/dcache.c | 10 ++++++++--
fs/debugfs/inode.c | 2 +-
fs/devpts/inode.c | 2 +-
fs/ecryptfs/main.c | 2 +-
fs/efivarfs/super.c | 2 +-
fs/exfat/super.c | 4 ++--
fs/fat/namei_msdos.c | 2 +-
fs/fat/namei_vfat.c | 4 ++--
fs/fuse/inode.c | 4 ++--
fs/gfs2/ops_fstype.c | 2 +-
fs/hfs/super.c | 2 +-
fs/hfsplus/super.c | 2 +-
fs/hostfs/hostfs_kern.c | 2 +-
fs/hpfs/super.c | 2 +-
fs/isofs/inode.c | 2 +-
fs/jfs/super.c | 2 +-
fs/kernfs/mount.c | 2 +-
fs/libfs.c | 16 ++++++++--------
fs/nfs/super.c | 2 +-
fs/ntfs3/super.c | 3 ++-
fs/ocfs2/super.c | 2 +-
fs/orangefs/super.c | 2 +-
fs/overlayfs/super.c | 2 +-
fs/smb/client/cifsfs.c | 4 ++--
fs/tracefs/inode.c | 2 +-
fs/vboxsf/super.c | 2 +-
include/linux/dcache.h | 2 ++
include/linux/fs.h | 2 +-
mm/shmem.c | 2 +-
net/sunrpc/rpc_pipe.c | 2 +-
40 files changed, 69 insertions(+), 53 deletions(-)
diff --git a/Documentation/filesystems/porting.rst b/Documentation/filesystems/porting.rst
index 3616d7161dab..b16139e91942 100644
--- a/Documentation/filesystems/porting.rst
+++ b/Documentation/filesystems/porting.rst
@@ -1249,3 +1249,10 @@ Using try_lookup_noperm() will require linux/namei.h to be included.
Calling conventions for ->d_automount() have changed; we should *not* grab
an extra reference to new mount - it should be returned with refcount 1.
+
+---
+
+**mandatory**
+
+If your filesystem sets the default dentry_operations, use set_default_d_op()
+rather than manually setting sb->s_d_op.
diff --git a/fs/9p/vfs_super.c b/fs/9p/vfs_super.c
index 489db161abc9..5c3dc3efb909 100644
--- a/fs/9p/vfs_super.c
+++ b/fs/9p/vfs_super.c
@@ -135,9 +135,9 @@ static struct dentry *v9fs_mount(struct file_system_type *fs_type, int flags,
goto release_sb;
if (v9ses->cache & (CACHE_META|CACHE_LOOSE))
- sb->s_d_op = &v9fs_cached_dentry_operations;
+ set_default_d_op(sb, &v9fs_cached_dentry_operations);
else
- sb->s_d_op = &v9fs_dentry_operations;
+ set_default_d_op(sb, &v9fs_dentry_operations);
inode = v9fs_get_new_inode_from_fid(v9ses, fid, sb);
if (IS_ERR(inode)) {
diff --git a/fs/adfs/super.c b/fs/adfs/super.c
index 017c48a80203..fdccdbbfc213 100644
--- a/fs/adfs/super.c
+++ b/fs/adfs/super.c
@@ -397,7 +397,7 @@ static int adfs_fill_super(struct super_block *sb, struct fs_context *fc)
if (asb->s_ftsuffix)
asb->s_namelen += 4;
- sb->s_d_op = &adfs_dentry_operations;
+ set_default_d_op(sb, &adfs_dentry_operations);
root = adfs_iget(sb, &root_obj);
sb->s_root = d_make_root(root);
if (!sb->s_root) {
diff --git a/fs/affs/super.c b/fs/affs/super.c
index 2fa40337776d..44f8aa883100 100644
--- a/fs/affs/super.c
+++ b/fs/affs/super.c
@@ -500,9 +500,9 @@ static int affs_fill_super(struct super_block *sb, struct fs_context *fc)
return PTR_ERR(root_inode);
if (affs_test_opt(AFFS_SB(sb)->s_flags, SF_INTL))
- sb->s_d_op = &affs_intl_dentry_operations;
+ set_default_d_op(sb, &affs_intl_dentry_operations);
else
- sb->s_d_op = &affs_dentry_operations;
+ set_default_d_op(sb, &affs_dentry_operations);
sb->s_root = d_make_root(root_inode);
if (!sb->s_root) {
diff --git a/fs/afs/super.c b/fs/afs/super.c
index 25b306db6992..da407f2d6f0d 100644
--- a/fs/afs/super.c
+++ b/fs/afs/super.c
@@ -483,9 +483,9 @@ static int afs_fill_super(struct super_block *sb, struct afs_fs_context *ctx)
goto error;
if (as->dyn_root) {
- sb->s_d_op = &afs_dynroot_dentry_operations;
+ set_default_d_op(sb, &afs_dynroot_dentry_operations);
} else {
- sb->s_d_op = &afs_fs_dentry_operations;
+ set_default_d_op(sb, &afs_fs_dentry_operations);
rcu_assign_pointer(as->volume->sb, sb);
}
diff --git a/fs/autofs/inode.c b/fs/autofs/inode.c
index ee2edccaef70..f5c16ffba013 100644
--- a/fs/autofs/inode.c
+++ b/fs/autofs/inode.c
@@ -311,7 +311,7 @@ static int autofs_fill_super(struct super_block *s, struct fs_context *fc)
s->s_blocksize_bits = 10;
s->s_magic = AUTOFS_SUPER_MAGIC;
s->s_op = &autofs_sops;
- s->s_d_op = &autofs_dentry_operations;
+ set_default_d_op(s, &autofs_dentry_operations);
s->s_time_gran = 1;
/*
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
index a0c65adce1ab..ad75d9f8f404 100644
--- a/fs/btrfs/super.c
+++ b/fs/btrfs/super.c
@@ -950,7 +950,7 @@ static int btrfs_fill_super(struct super_block *sb,
sb->s_maxbytes = MAX_LFS_FILESIZE;
sb->s_magic = BTRFS_SUPER_MAGIC;
sb->s_op = &btrfs_super_ops;
- sb->s_d_op = &btrfs_dentry_operations;
+ set_default_d_op(sb, &btrfs_dentry_operations);
sb->s_export_op = &btrfs_export_ops;
#ifdef CONFIG_FS_VERITY
sb->s_vop = &btrfs_verityops;
diff --git a/fs/ceph/super.c b/fs/ceph/super.c
index 2b8438d8a324..c3eb651862c5 100644
--- a/fs/ceph/super.c
+++ b/fs/ceph/super.c
@@ -1219,7 +1219,7 @@ static int ceph_set_super(struct super_block *s, struct fs_context *fc)
fsc->max_file_size = 1ULL << 40; /* temp value until we get mdsmap */
s->s_op = &ceph_super_ops;
- s->s_d_op = &ceph_dentry_ops;
+ set_default_d_op(s, &ceph_dentry_ops);
s->s_export_op = &ceph_export_ops;
s->s_time_gran = 1;
diff --git a/fs/coda/inode.c b/fs/coda/inode.c
index 6896fce122e1..08450d006016 100644
--- a/fs/coda/inode.c
+++ b/fs/coda/inode.c
@@ -230,7 +230,7 @@ static int coda_fill_super(struct super_block *sb, struct fs_context *fc)
sb->s_blocksize_bits = 12;
sb->s_magic = CODA_SUPER_MAGIC;
sb->s_op = &coda_super_operations;
- sb->s_d_op = &coda_dentry_operations;
+ set_default_d_op(sb, &coda_dentry_operations);
sb->s_time_gran = 1;
sb->s_time_min = S64_MIN;
sb->s_time_max = S64_MAX;
diff --git a/fs/configfs/mount.c b/fs/configfs/mount.c
index c2d820063ec4..20412eaca972 100644
--- a/fs/configfs/mount.c
+++ b/fs/configfs/mount.c
@@ -92,7 +92,7 @@ static int configfs_fill_super(struct super_block *sb, struct fs_context *fc)
configfs_root_group.cg_item.ci_dentry = root;
root->d_fsdata = &configfs_root;
sb->s_root = root;
- sb->s_d_op = &configfs_dentry_ops; /* the rest get that */
+ set_default_d_op(sb, &configfs_dentry_ops); /* the rest get that */
return 0;
}
diff --git a/fs/dcache.c b/fs/dcache.c
index bf550d438e40..2ed875558ccc 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -1738,7 +1738,7 @@ static struct dentry *__d_alloc(struct super_block *sb, const struct qstr *name)
INIT_HLIST_HEAD(&dentry->d_children);
INIT_HLIST_NODE(&dentry->d_u.d_alias);
INIT_HLIST_NODE(&dentry->d_sib);
- d_set_d_op(dentry, dentry->d_sb->s_d_op);
+ d_set_d_op(dentry, dentry->d_sb->__s_d_op);
if (dentry->d_op && dentry->d_op->d_init) {
err = dentry->d_op->d_init(dentry);
@@ -1821,7 +1821,7 @@ struct dentry *d_alloc_pseudo(struct super_block *sb, const struct qstr *name)
struct dentry *dentry = __d_alloc(sb, name);
if (likely(dentry)) {
dentry->d_flags |= DCACHE_NORCU;
- if (!sb->s_d_op)
+ if (!dentry->d_op)
d_set_d_op(dentry, &anon_ops);
}
return dentry;
@@ -1867,6 +1867,12 @@ void d_set_d_op(struct dentry *dentry, const struct dentry_operations *op)
}
EXPORT_SYMBOL(d_set_d_op);
+void set_default_d_op(struct super_block *s, const struct dentry_operations *ops)
+{
+ s->__s_d_op = ops;
+}
+EXPORT_SYMBOL(set_default_d_op);
+
static unsigned d_flags_for_inode(struct inode *inode)
{
unsigned add_flags = DCACHE_REGULAR_TYPE;
diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c
index 30c4944e1862..29c5ec382342 100644
--- a/fs/debugfs/inode.c
+++ b/fs/debugfs/inode.c
@@ -273,7 +273,7 @@ static int debugfs_fill_super(struct super_block *sb, struct fs_context *fc)
return err;
sb->s_op = &debugfs_super_operations;
- sb->s_d_op = &debugfs_dops;
+ set_default_d_op(sb, &debugfs_dops);
debugfs_apply_options(sb);
diff --git a/fs/devpts/inode.c b/fs/devpts/inode.c
index 9c20d78e41f6..fd17992ee298 100644
--- a/fs/devpts/inode.c
+++ b/fs/devpts/inode.c
@@ -381,7 +381,7 @@ static int devpts_fill_super(struct super_block *s, struct fs_context *fc)
s->s_blocksize_bits = 10;
s->s_magic = DEVPTS_SUPER_MAGIC;
s->s_op = &devpts_sops;
- s->s_d_op = &simple_dentry_operations;
+ set_default_d_op(s, &simple_dentry_operations);
s->s_time_gran = 1;
fsi->sb = s;
diff --git a/fs/ecryptfs/main.c b/fs/ecryptfs/main.c
index 8dd1d7189c3b..45f9ca4465da 100644
--- a/fs/ecryptfs/main.c
+++ b/fs/ecryptfs/main.c
@@ -471,7 +471,7 @@ static int ecryptfs_get_tree(struct fs_context *fc)
sbi = NULL;
s->s_op = &ecryptfs_sops;
s->s_xattr = ecryptfs_xattr_handlers;
- s->s_d_op = &ecryptfs_dops;
+ set_default_d_op(s, &ecryptfs_dops);
err = "Reading sb failed";
rc = kern_path(fc->source, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &path);
diff --git a/fs/efivarfs/super.c b/fs/efivarfs/super.c
index c900d98bf494..f76d8dfa646b 100644
--- a/fs/efivarfs/super.c
+++ b/fs/efivarfs/super.c
@@ -350,7 +350,7 @@ static int efivarfs_fill_super(struct super_block *sb, struct fs_context *fc)
sb->s_blocksize_bits = PAGE_SHIFT;
sb->s_magic = EFIVARFS_MAGIC;
sb->s_op = &efivarfs_ops;
- sb->s_d_op = &efivarfs_d_ops;
+ set_default_d_op(sb, &efivarfs_d_ops);
sb->s_time_gran = 1;
if (!efivar_supports_writes())
diff --git a/fs/exfat/super.c b/fs/exfat/super.c
index 7ed858937d45..ea5c1334a214 100644
--- a/fs/exfat/super.c
+++ b/fs/exfat/super.c
@@ -667,9 +667,9 @@ static int exfat_fill_super(struct super_block *sb, struct fs_context *fc)
}
if (sbi->options.utf8)
- sb->s_d_op = &exfat_utf8_dentry_ops;
+ set_default_d_op(sb, &exfat_utf8_dentry_ops);
else
- sb->s_d_op = &exfat_dentry_ops;
+ set_default_d_op(sb, &exfat_dentry_ops);
root_inode = new_inode(sb);
if (!root_inode) {
diff --git a/fs/fat/namei_msdos.c b/fs/fat/namei_msdos.c
index 23e9b9371ec3..0b920ee40a7f 100644
--- a/fs/fat/namei_msdos.c
+++ b/fs/fat/namei_msdos.c
@@ -646,7 +646,7 @@ static const struct inode_operations msdos_dir_inode_operations = {
static void setup(struct super_block *sb)
{
MSDOS_SB(sb)->dir_ops = &msdos_dir_inode_operations;
- sb->s_d_op = &msdos_dentry_operations;
+ set_default_d_op(sb, &msdos_dentry_operations);
sb->s_flags |= SB_NOATIME;
}
diff --git a/fs/fat/namei_vfat.c b/fs/fat/namei_vfat.c
index dd910edd2404..5dbc4cbb8fce 100644
--- a/fs/fat/namei_vfat.c
+++ b/fs/fat/namei_vfat.c
@@ -1187,9 +1187,9 @@ static void setup(struct super_block *sb)
{
MSDOS_SB(sb)->dir_ops = &vfat_dir_inode_operations;
if (MSDOS_SB(sb)->options.name_check != 's')
- sb->s_d_op = &vfat_ci_dentry_ops;
+ set_default_d_op(sb, &vfat_ci_dentry_ops);
else
- sb->s_d_op = &vfat_dentry_ops;
+ set_default_d_op(sb, &vfat_dentry_ops);
}
static int vfat_fill_super(struct super_block *sb, struct fs_context *fc)
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
index eb6177508598..0dd65c0e9e29 100644
--- a/fs/fuse/inode.c
+++ b/fs/fuse/inode.c
@@ -1715,7 +1715,7 @@ static int fuse_fill_super_submount(struct super_block *sb,
fi = get_fuse_inode(root);
fi->nlookup--;
- sb->s_d_op = &fuse_dentry_operations;
+ set_default_d_op(sb, &fuse_dentry_operations);
sb->s_root = d_make_root(root);
if (!sb->s_root)
return -ENOMEM;
@@ -1850,7 +1850,7 @@ int fuse_fill_super_common(struct super_block *sb, struct fuse_fs_context *ctx)
err = -ENOMEM;
root = fuse_get_root_inode(sb, ctx->rootmode);
- sb->s_d_op = &fuse_dentry_operations;
+ set_default_d_op(sb, &fuse_dentry_operations);
root_dentry = d_make_root(root);
if (!root_dentry)
goto err_dev_free;
diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c
index 85c491fcf1a3..b568767dba46 100644
--- a/fs/gfs2/ops_fstype.c
+++ b/fs/gfs2/ops_fstype.c
@@ -1145,7 +1145,7 @@ static int gfs2_fill_super(struct super_block *sb, struct fs_context *fc)
sb->s_magic = GFS2_MAGIC;
sb->s_op = &gfs2_super_ops;
- sb->s_d_op = &gfs2_dops;
+ set_default_d_op(sb, &gfs2_dops);
sb->s_export_op = &gfs2_export_ops;
sb->s_qcop = &gfs2_quotactl_ops;
sb->s_quota_types = QTYPE_MASK_USR | QTYPE_MASK_GRP;
diff --git a/fs/hfs/super.c b/fs/hfs/super.c
index fe09c2093a93..388a318297ec 100644
--- a/fs/hfs/super.c
+++ b/fs/hfs/super.c
@@ -365,7 +365,7 @@ static int hfs_fill_super(struct super_block *sb, struct fs_context *fc)
if (!root_inode)
goto bail_no_root;
- sb->s_d_op = &hfs_dentry_operations;
+ set_default_d_op(sb, &hfs_dentry_operations);
res = -ENOMEM;
sb->s_root = d_make_root(root_inode);
if (!sb->s_root)
diff --git a/fs/hfsplus/super.c b/fs/hfsplus/super.c
index 948b8aaee33e..0caf7aa1c249 100644
--- a/fs/hfsplus/super.c
+++ b/fs/hfsplus/super.c
@@ -508,7 +508,7 @@ static int hfsplus_fill_super(struct super_block *sb, struct fs_context *fc)
goto out_put_alloc_file;
}
- sb->s_d_op = &hfsplus_dentry_operations;
+ set_default_d_op(sb, &hfsplus_dentry_operations);
sb->s_root = d_make_root(root);
if (!sb->s_root) {
err = -ENOMEM;
diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c
index 702c41317589..1c0f5038e19c 100644
--- a/fs/hostfs/hostfs_kern.c
+++ b/fs/hostfs/hostfs_kern.c
@@ -933,7 +933,7 @@ static int hostfs_fill_super(struct super_block *sb, struct fs_context *fc)
sb->s_blocksize_bits = 10;
sb->s_magic = HOSTFS_SUPER_MAGIC;
sb->s_op = &hostfs_sbops;
- sb->s_d_op = &simple_dentry_operations;
+ set_default_d_op(sb, &simple_dentry_operations);
sb->s_maxbytes = MAX_LFS_FILESIZE;
err = super_setup_bdi(sb);
if (err)
diff --git a/fs/hpfs/super.c b/fs/hpfs/super.c
index 27567920abe4..42b779b4d87f 100644
--- a/fs/hpfs/super.c
+++ b/fs/hpfs/super.c
@@ -554,7 +554,7 @@ static int hpfs_fill_super(struct super_block *s, struct fs_context *fc)
/* Fill superblock stuff */
s->s_magic = HPFS_SUPER_MAGIC;
s->s_op = &hpfs_sops;
- s->s_d_op = &hpfs_dentry_operations;
+ set_default_d_op(s, &hpfs_dentry_operations);
s->s_time_min = local_to_gmt(s, 0);
s->s_time_max = local_to_gmt(s, U32_MAX);
diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c
index d5da9817df9b..8624393c0d8c 100644
--- a/fs/isofs/inode.c
+++ b/fs/isofs/inode.c
@@ -939,7 +939,7 @@ static int isofs_fill_super(struct super_block *s, struct fs_context *fc)
sbi->s_check = opt->check;
if (table)
- s->s_d_op = &isofs_dentry_ops[table - 1];
+ set_default_d_op(s, &isofs_dentry_ops[table - 1]);
/* get the root dentry */
s->s_root = d_make_root(inode);
diff --git a/fs/jfs/super.c b/fs/jfs/super.c
index 10368c188c5e..3cfb86c5a36e 100644
--- a/fs/jfs/super.c
+++ b/fs/jfs/super.c
@@ -542,7 +542,7 @@ static int jfs_fill_super(struct super_block *sb, struct fs_context *fc)
sb->s_magic = JFS_SUPER_MAGIC;
if (sbi->mntflag & JFS_OS2)
- sb->s_d_op = &jfs_ci_dentry_operations;
+ set_default_d_op(sb, &jfs_ci_dentry_operations);
inode = jfs_iget(sb, ROOT_I);
if (IS_ERR(inode)) {
diff --git a/fs/kernfs/mount.c b/fs/kernfs/mount.c
index c1719b5778a1..e384a69fbece 100644
--- a/fs/kernfs/mount.c
+++ b/fs/kernfs/mount.c
@@ -318,7 +318,7 @@ static int kernfs_fill_super(struct super_block *sb, struct kernfs_fs_context *k
return -ENOMEM;
}
sb->s_root = root;
- sb->s_d_op = &kernfs_dops;
+ set_default_d_op(sb, &kernfs_dops);
return 0;
}
diff --git a/fs/libfs.c b/fs/libfs.c
index 9ea0ecc325a8..ab82de070310 100644
--- a/fs/libfs.c
+++ b/fs/libfs.c
@@ -75,7 +75,7 @@ struct dentry *simple_lookup(struct inode *dir, struct dentry *dentry, unsigned
{
if (dentry->d_name.len > NAME_MAX)
return ERR_PTR(-ENAMETOOLONG);
- if (!dentry->d_sb->s_d_op)
+ if (!dentry->d_op)
d_set_d_op(dentry, &simple_dentry_operations);
if (IS_ENABLED(CONFIG_UNICODE) && IS_CASEFOLDED(dir))
@@ -684,7 +684,7 @@ static int pseudo_fs_fill_super(struct super_block *s, struct fs_context *fc)
s->s_root = d_make_root(root);
if (!s->s_root)
return -ENOMEM;
- s->s_d_op = ctx->dops;
+ set_default_d_op(s, ctx->dops);
return 0;
}
@@ -1950,22 +1950,22 @@ static const struct dentry_operations generic_encrypted_dentry_ops = {
* @sb: superblock to be configured
*
* Filesystems supporting casefolding and/or fscrypt can call this
- * helper at mount-time to configure sb->s_d_op to best set of dentry
- * operations required for the enabled features. The helper must be
- * called after these have been configured, but before the root dentry
- * is created.
+ * helper at mount-time to configure default dentry_operations to the
+ * best set of dentry operations required for the enabled features.
+ * The helper must be called after these have been configured, but
+ * before the root dentry is created.
*/
void generic_set_sb_d_ops(struct super_block *sb)
{
#if IS_ENABLED(CONFIG_UNICODE)
if (sb->s_encoding) {
- sb->s_d_op = &generic_ci_dentry_ops;
+ set_default_d_op(sb, &generic_ci_dentry_ops);
return;
}
#endif
#ifdef CONFIG_FS_ENCRYPTION
if (sb->s_cop) {
- sb->s_d_op = &generic_encrypted_dentry_ops;
+ set_default_d_op(sb, &generic_encrypted_dentry_ops);
return;
}
#endif
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index 91b5503b6f74..72dee6f3050e 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -1183,7 +1183,7 @@ static int nfs_set_super(struct super_block *s, struct fs_context *fc)
struct nfs_server *server = fc->s_fs_info;
int ret;
- s->s_d_op = server->nfs_client->rpc_ops->dentry_ops;
+ set_default_d_op(s, server->nfs_client->rpc_ops->dentry_ops);
ret = set_anon_super(s, server);
if (ret == 0)
server->s_dev = s->s_dev;
diff --git a/fs/ntfs3/super.c b/fs/ntfs3/super.c
index 920a1ab47b63..ddff94c091b8 100644
--- a/fs/ntfs3/super.c
+++ b/fs/ntfs3/super.c
@@ -1223,7 +1223,8 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc)
sb->s_export_op = &ntfs_export_ops;
sb->s_time_gran = NTFS_TIME_GRAN; // 100 nsec
sb->s_xattr = ntfs_xattr_handlers;
- sb->s_d_op = options->nocase ? &ntfs_dentry_ops : NULL;
+ if (options->nocase)
+ set_default_d_op(sb, &ntfs_dentry_ops);
options->nls = ntfs_load_nls(options->nls_name);
if (IS_ERR(options->nls)) {
diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c
index 3d2533950bae..53daa4482406 100644
--- a/fs/ocfs2/super.c
+++ b/fs/ocfs2/super.c
@@ -1962,7 +1962,7 @@ static int ocfs2_initialize_super(struct super_block *sb,
sb->s_fs_info = osb;
sb->s_op = &ocfs2_sops;
- sb->s_d_op = &ocfs2_dentry_ops;
+ set_default_d_op(sb, &ocfs2_dentry_ops);
sb->s_export_op = &ocfs2_export_ops;
sb->s_qcop = &dquot_quotactl_sysfile_ops;
sb->dq_op = &ocfs2_quota_operations;
diff --git a/fs/orangefs/super.c b/fs/orangefs/super.c
index 64ca9498f550..f3da840758e7 100644
--- a/fs/orangefs/super.c
+++ b/fs/orangefs/super.c
@@ -416,7 +416,7 @@ static int orangefs_fill_sb(struct super_block *sb,
sb->s_xattr = orangefs_xattr_handlers;
sb->s_magic = ORANGEFS_SUPER_MAGIC;
sb->s_op = &orangefs_s_ops;
- sb->s_d_op = &orangefs_dentry_operations;
+ set_default_d_op(sb, &orangefs_dentry_operations);
sb->s_blocksize = PAGE_SIZE;
sb->s_blocksize_bits = PAGE_SHIFT;
diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c
index e19940d649ca..efbf0b291551 100644
--- a/fs/overlayfs/super.c
+++ b/fs/overlayfs/super.c
@@ -1322,7 +1322,7 @@ int ovl_fill_super(struct super_block *sb, struct fs_context *fc)
if (WARN_ON(fc->user_ns != current_user_ns()))
goto out_err;
- sb->s_d_op = &ovl_dentry_operations;
+ set_default_d_op(sb, &ovl_dentry_operations);
err = -ENOMEM;
if (!ofs->creator_cred)
diff --git a/fs/smb/client/cifsfs.c b/fs/smb/client/cifsfs.c
index 0a5266ecfd15..d4ec73359922 100644
--- a/fs/smb/client/cifsfs.c
+++ b/fs/smb/client/cifsfs.c
@@ -260,9 +260,9 @@ cifs_read_super(struct super_block *sb)
}
if (tcon->nocase)
- sb->s_d_op = &cifs_ci_dentry_ops;
+ set_default_d_op(sb, &cifs_ci_dentry_ops);
else
- sb->s_d_op = &cifs_dentry_ops;
+ set_default_d_op(sb, &cifs_dentry_ops);
sb->s_root = d_make_root(inode);
if (!sb->s_root) {
diff --git a/fs/tracefs/inode.c b/fs/tracefs/inode.c
index a3fd3cc591bd..c8ca61777323 100644
--- a/fs/tracefs/inode.c
+++ b/fs/tracefs/inode.c
@@ -480,7 +480,7 @@ static int tracefs_fill_super(struct super_block *sb, struct fs_context *fc)
return err;
sb->s_op = &tracefs_super_operations;
- sb->s_d_op = &tracefs_dentry_operations;
+ set_default_d_op(sb, &tracefs_dentry_operations);
return 0;
}
diff --git a/fs/vboxsf/super.c b/fs/vboxsf/super.c
index 0bc96ab6580b..241647b060ee 100644
--- a/fs/vboxsf/super.c
+++ b/fs/vboxsf/super.c
@@ -189,7 +189,7 @@ static int vboxsf_fill_super(struct super_block *sb, struct fs_context *fc)
sb->s_blocksize = 1024;
sb->s_maxbytes = MAX_LFS_FILESIZE;
sb->s_op = &vboxsf_super_ops;
- sb->s_d_op = &vboxsf_dentry_ops;
+ set_default_d_op(sb, &vboxsf_dentry_ops);
iroot = iget_locked(sb, 0);
if (!iroot) {
diff --git a/include/linux/dcache.h b/include/linux/dcache.h
index 1993e6704552..be7ae058fa90 100644
--- a/include/linux/dcache.h
+++ b/include/linux/dcache.h
@@ -607,4 +607,6 @@ static inline struct dentry *d_next_sibling(const struct dentry *dentry)
return hlist_entry_safe(dentry->d_sib.next, struct dentry, d_sib);
}
+void set_default_d_op(struct super_block *, const struct dentry_operations *);
+
#endif /* __LINUX_DCACHE_H */
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 96c7925a6551..7cd8eaab4d4e 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -1413,7 +1413,7 @@ struct super_block {
*/
const char *s_subtype;
- const struct dentry_operations *s_d_op; /* default d_op for dentries */
+ const struct dentry_operations *__s_d_op; /* default d_op for dentries */
struct shrinker *s_shrink; /* per-sb shrinker handle */
diff --git a/mm/shmem.c b/mm/shmem.c
index 0c5fb4ffa03a..3583508800fc 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -5028,7 +5028,7 @@ static int shmem_fill_super(struct super_block *sb, struct fs_context *fc)
if (ctx->encoding) {
sb->s_encoding = ctx->encoding;
- sb->s_d_op = &shmem_ci_dentry_ops;
+ set_default_d_op(sb, &shmem_ci_dentry_ops);
if (ctx->strict_encoding)
sb->s_encoding_flags = SB_ENC_STRICT_MODE_FL;
}
diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c
index 98f78cd55905..f4e880383f67 100644
--- a/net/sunrpc/rpc_pipe.c
+++ b/net/sunrpc/rpc_pipe.c
@@ -1363,7 +1363,7 @@ rpc_fill_super(struct super_block *sb, struct fs_context *fc)
sb->s_blocksize_bits = PAGE_SHIFT;
sb->s_magic = RPCAUTH_GSSMAGIC;
sb->s_op = &s_ops;
- sb->s_d_op = &simple_dentry_operations;
+ set_default_d_op(sb, &simple_dentry_operations);
sb->s_time_gran = 1;
inode = rpc_get_inode(sb, S_IFDIR | 0555);
--
2.39.5
^ permalink raw reply related [flat|nested] 87+ messages in thread
* [PATCH v2 07/21] split d_flags calculation out of d_set_d_op()
2025-06-11 7:54 ` [PATCH v2 01/21] d_set_mounted(): we don't need to bump seqcount component of rename_lock Al Viro
` (4 preceding siblings ...)
2025-06-11 7:54 ` [PATCH v2 06/21] new helper: set_default_d_op() Al Viro
@ 2025-06-11 7:54 ` Al Viro
2025-06-11 7:54 ` [PATCH v2 08/21] correct the set of flags forbidden at d_set_d_op() time Al Viro
` (13 subsequent siblings)
19 siblings, 0 replies; 87+ messages in thread
From: Al Viro @ 2025-06-11 7:54 UTC (permalink / raw)
To: linux-fsdevel; +Cc: brauner, jack, miklos, neilb, torvalds
Reviewed-by: Christian Brauner <brauner@kernel.org>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/dcache.c | 53 ++++++++++++++++++++++++++++++-----------------------
1 file changed, 30 insertions(+), 23 deletions(-)
diff --git a/fs/dcache.c b/fs/dcache.c
index 2ed875558ccc..f998e26c9cd4 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -1837,33 +1837,40 @@ struct dentry *d_alloc_name(struct dentry *parent, const char *name)
}
EXPORT_SYMBOL(d_alloc_name);
+#define DCACHE_OP_FLAGS \
+ (DCACHE_OP_HASH | DCACHE_OP_COMPARE | DCACHE_OP_REVALIDATE | \
+ DCACHE_OP_WEAK_REVALIDATE | DCACHE_OP_DELETE | DCACHE_OP_REAL)
+
+static unsigned int d_op_flags(const struct dentry_operations *op)
+{
+ unsigned int flags = 0;
+ if (op) {
+ if (op->d_hash)
+ flags |= DCACHE_OP_HASH;
+ if (op->d_compare)
+ flags |= DCACHE_OP_COMPARE;
+ if (op->d_revalidate)
+ flags |= DCACHE_OP_REVALIDATE;
+ if (op->d_weak_revalidate)
+ flags |= DCACHE_OP_WEAK_REVALIDATE;
+ if (op->d_delete)
+ flags |= DCACHE_OP_DELETE;
+ if (op->d_prune)
+ flags |= DCACHE_OP_PRUNE;
+ if (op->d_real)
+ flags |= DCACHE_OP_REAL;
+ }
+ return flags;
+}
+
void d_set_d_op(struct dentry *dentry, const struct dentry_operations *op)
{
+ unsigned int flags = d_op_flags(op);
WARN_ON_ONCE(dentry->d_op);
- WARN_ON_ONCE(dentry->d_flags & (DCACHE_OP_HASH |
- DCACHE_OP_COMPARE |
- DCACHE_OP_REVALIDATE |
- DCACHE_OP_WEAK_REVALIDATE |
- DCACHE_OP_DELETE |
- DCACHE_OP_REAL));
+ WARN_ON_ONCE(dentry->d_flags & DCACHE_OP_FLAGS);
dentry->d_op = op;
- if (!op)
- return;
- if (op->d_hash)
- dentry->d_flags |= DCACHE_OP_HASH;
- if (op->d_compare)
- dentry->d_flags |= DCACHE_OP_COMPARE;
- if (op->d_revalidate)
- dentry->d_flags |= DCACHE_OP_REVALIDATE;
- if (op->d_weak_revalidate)
- dentry->d_flags |= DCACHE_OP_WEAK_REVALIDATE;
- if (op->d_delete)
- dentry->d_flags |= DCACHE_OP_DELETE;
- if (op->d_prune)
- dentry->d_flags |= DCACHE_OP_PRUNE;
- if (op->d_real)
- dentry->d_flags |= DCACHE_OP_REAL;
-
+ if (flags)
+ dentry->d_flags |= flags;
}
EXPORT_SYMBOL(d_set_d_op);
--
2.39.5
^ permalink raw reply related [flat|nested] 87+ messages in thread
* [PATCH v2 08/21] correct the set of flags forbidden at d_set_d_op() time
2025-06-11 7:54 ` [PATCH v2 01/21] d_set_mounted(): we don't need to bump seqcount component of rename_lock Al Viro
` (5 preceding siblings ...)
2025-06-11 7:54 ` [PATCH v2 07/21] split d_flags calculation out of d_set_d_op() Al Viro
@ 2025-06-11 7:54 ` Al Viro
2025-06-11 9:49 ` Christian Brauner
2025-06-11 7:54 ` [PATCH v2 09/21] set_default_d_op(): calculate the matching value for ->d_flags Al Viro
` (12 subsequent siblings)
19 siblings, 1 reply; 87+ messages in thread
From: Al Viro @ 2025-06-11 7:54 UTC (permalink / raw)
To: linux-fsdevel; +Cc: brauner, jack, miklos, neilb, torvalds
DCACHE_OP_PRUNE in ->d_flags at the time of d_set_d_op() should've
been treated the same as any other DCACHE_OP_... - we forgot to adjust
that WARN_ON() when DCACHE_OP_PRUNE had been introduced...
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/dcache.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/fs/dcache.c b/fs/dcache.c
index f998e26c9cd4..27e6d2f36973 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -1839,7 +1839,8 @@ EXPORT_SYMBOL(d_alloc_name);
#define DCACHE_OP_FLAGS \
(DCACHE_OP_HASH | DCACHE_OP_COMPARE | DCACHE_OP_REVALIDATE | \
- DCACHE_OP_WEAK_REVALIDATE | DCACHE_OP_DELETE | DCACHE_OP_REAL)
+ DCACHE_OP_WEAK_REVALIDATE | DCACHE_OP_DELETE | DCACHE_OP_PRUNE | \
+ DCACHE_OP_REAL)
static unsigned int d_op_flags(const struct dentry_operations *op)
{
--
2.39.5
^ permalink raw reply related [flat|nested] 87+ messages in thread
* [PATCH v2 09/21] set_default_d_op(): calculate the matching value for ->d_flags
2025-06-11 7:54 ` [PATCH v2 01/21] d_set_mounted(): we don't need to bump seqcount component of rename_lock Al Viro
` (6 preceding siblings ...)
2025-06-11 7:54 ` [PATCH v2 08/21] correct the set of flags forbidden at d_set_d_op() time Al Viro
@ 2025-06-11 7:54 ` Al Viro
2025-06-11 7:54 ` [PATCH v2 10/21] simple_lookup(): just set DCACHE_DONTCACHE Al Viro
` (11 subsequent siblings)
19 siblings, 0 replies; 87+ messages in thread
From: Al Viro @ 2025-06-11 7:54 UTC (permalink / raw)
To: linux-fsdevel; +Cc: brauner, jack, miklos, neilb, torvalds
... and store it in ->s_d_flags, to be used by __d_alloc()
Reviewed-by: Christian Brauner <brauner@kernel.org>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/dcache.c | 6 ++++--
include/linux/fs.h | 1 +
2 files changed, 5 insertions(+), 2 deletions(-)
diff --git a/fs/dcache.c b/fs/dcache.c
index 27e6d2f36973..7519c5f66f79 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -1731,14 +1731,14 @@ static struct dentry *__d_alloc(struct super_block *sb, const struct qstr *name)
dentry->d_inode = NULL;
dentry->d_parent = dentry;
dentry->d_sb = sb;
- dentry->d_op = NULL;
+ dentry->d_op = sb->__s_d_op;
+ dentry->d_flags = sb->s_d_flags;
dentry->d_fsdata = NULL;
INIT_HLIST_BL_NODE(&dentry->d_hash);
INIT_LIST_HEAD(&dentry->d_lru);
INIT_HLIST_HEAD(&dentry->d_children);
INIT_HLIST_NODE(&dentry->d_u.d_alias);
INIT_HLIST_NODE(&dentry->d_sib);
- d_set_d_op(dentry, dentry->d_sb->__s_d_op);
if (dentry->d_op && dentry->d_op->d_init) {
err = dentry->d_op->d_init(dentry);
@@ -1877,7 +1877,9 @@ EXPORT_SYMBOL(d_set_d_op);
void set_default_d_op(struct super_block *s, const struct dentry_operations *ops)
{
+ unsigned int flags = d_op_flags(ops);
s->__s_d_op = ops;
+ s->s_d_flags = (s->s_d_flags & ~DCACHE_OP_FLAGS) | flags;
}
EXPORT_SYMBOL(set_default_d_op);
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 7cd8eaab4d4e..65548e70e596 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -1400,6 +1400,7 @@ struct super_block {
char s_sysfs_name[UUID_STRING_LEN + 1];
unsigned int s_max_links;
+ unsigned int s_d_flags; /* default d_flags for dentries */
/*
* The next field is for VFS *only*. No filesystems have any business
--
2.39.5
^ permalink raw reply related [flat|nested] 87+ messages in thread
* [PATCH v2 10/21] simple_lookup(): just set DCACHE_DONTCACHE
2025-06-11 7:54 ` [PATCH v2 01/21] d_set_mounted(): we don't need to bump seqcount component of rename_lock Al Viro
` (7 preceding siblings ...)
2025-06-11 7:54 ` [PATCH v2 09/21] set_default_d_op(): calculate the matching value for ->d_flags Al Viro
@ 2025-06-11 7:54 ` Al Viro
2025-06-11 9:50 ` Christian Brauner
2025-06-11 7:54 ` [PATCH v2 11/21] make d_set_d_op() static Al Viro
` (10 subsequent siblings)
19 siblings, 1 reply; 87+ messages in thread
From: Al Viro @ 2025-06-11 7:54 UTC (permalink / raw)
To: linux-fsdevel; +Cc: brauner, jack, miklos, neilb, torvalds
No need to mess with ->d_op at all. Note that ->d_delete that always
returns 1 is equivalent to having DCACHE_DONTCACHE in ->d_flags.
Later the same thing will be placed into ->s_d_flags of the filesystems
where we want that behaviour for all dentries; then the check in
simple_lookup() will at least get unlikely() slapped on it.
NOTE: there are only two filesystems where
* simple_lookup() might be called
* default ->d_op is non-NULL
* its ->d_delete() doesn't always return 1
If not for those, we could have simple_lookup() just set DCACHE_DONTCACHE
without even looking at ->d_op. Filesystems in question are btrfs
(where ->d_delete() takes care to recognize the dentries that might
come from simple_lookup() and returns 1 for those) and tracefs.
The former would be fine with simple_lookup() setting DCACHE_DONTCACHE;
the latter... probably wants DCACHE_DONTCACHE in default d_flags.
IOW, we might want to drop the check for ->d_op in simple_lookup();
it's definitely a separate story, though.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/libfs.c | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/fs/libfs.c b/fs/libfs.c
index ab82de070310..19cc12651708 100644
--- a/fs/libfs.c
+++ b/fs/libfs.c
@@ -75,9 +75,11 @@ struct dentry *simple_lookup(struct inode *dir, struct dentry *dentry, unsigned
{
if (dentry->d_name.len > NAME_MAX)
return ERR_PTR(-ENAMETOOLONG);
- if (!dentry->d_op)
- d_set_d_op(dentry, &simple_dentry_operations);
-
+ if (!dentry->d_op && !(dentry->d_flags & DCACHE_DONTCACHE)) {
+ spin_lock(&dentry->d_lock);
+ dentry->d_flags |= DCACHE_DONTCACHE;
+ spin_unlock(&dentry->d_lock);
+ }
if (IS_ENABLED(CONFIG_UNICODE) && IS_CASEFOLDED(dir))
return NULL;
--
2.39.5
^ permalink raw reply related [flat|nested] 87+ messages in thread
* [PATCH v2 11/21] make d_set_d_op() static
2025-06-11 7:54 ` [PATCH v2 01/21] d_set_mounted(): we don't need to bump seqcount component of rename_lock Al Viro
` (8 preceding siblings ...)
2025-06-11 7:54 ` [PATCH v2 10/21] simple_lookup(): just set DCACHE_DONTCACHE Al Viro
@ 2025-06-11 7:54 ` Al Viro
2025-06-11 7:54 ` [PATCH v2 12/21] d_alloc_parallel(): set DCACHE_PAR_LOOKUP earlier Al Viro
` (9 subsequent siblings)
19 siblings, 0 replies; 87+ messages in thread
From: Al Viro @ 2025-06-11 7:54 UTC (permalink / raw)
To: linux-fsdevel; +Cc: brauner, jack, miklos, neilb, torvalds
Convert the last user (d_alloc_pseudo()) and be done with that.
Any out-of-tree filesystem using it should switch to d_splice_alias_ops()
or, better yet, check whether it really needs to have ->d_op vary among
its dentries.
Reviewed-by: Christian Brauner <brauner@kernel.org>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
Documentation/filesystems/porting.rst | 11 +++++++++++
fs/dcache.c | 6 +++---
include/linux/dcache.h | 1 -
3 files changed, 14 insertions(+), 4 deletions(-)
diff --git a/Documentation/filesystems/porting.rst b/Documentation/filesystems/porting.rst
index b16139e91942..579f17df46cf 100644
--- a/Documentation/filesystems/porting.rst
+++ b/Documentation/filesystems/porting.rst
@@ -1256,3 +1256,14 @@ an extra reference to new mount - it should be returned with refcount 1.
If your filesystem sets the default dentry_operations, use set_default_d_op()
rather than manually setting sb->s_d_op.
+
+---
+
+**mandatory**
+
+d_set_d_op() is no longer exported (or public, for that matter); _if_
+your filesystem really needed that, make use of d_splice_alias_ops()
+to have them set. Better yet, think hard whether you need different
+->d_op for different dentries - if not, just use set_default_d_op()
+at mount time and be done with that. Currently procfs is the only
+thing that really needs ->d_op varying between dentries.
diff --git a/fs/dcache.c b/fs/dcache.c
index 7519c5f66f79..4e6ab27471a4 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -1821,8 +1821,9 @@ struct dentry *d_alloc_pseudo(struct super_block *sb, const struct qstr *name)
struct dentry *dentry = __d_alloc(sb, name);
if (likely(dentry)) {
dentry->d_flags |= DCACHE_NORCU;
+ /* d_op_flags(&anon_ops) is 0 */
if (!dentry->d_op)
- d_set_d_op(dentry, &anon_ops);
+ dentry->d_op = &anon_ops;
}
return dentry;
}
@@ -1864,7 +1865,7 @@ static unsigned int d_op_flags(const struct dentry_operations *op)
return flags;
}
-void d_set_d_op(struct dentry *dentry, const struct dentry_operations *op)
+static void d_set_d_op(struct dentry *dentry, const struct dentry_operations *op)
{
unsigned int flags = d_op_flags(op);
WARN_ON_ONCE(dentry->d_op);
@@ -1873,7 +1874,6 @@ void d_set_d_op(struct dentry *dentry, const struct dentry_operations *op)
if (flags)
dentry->d_flags |= flags;
}
-EXPORT_SYMBOL(d_set_d_op);
void set_default_d_op(struct super_block *s, const struct dentry_operations *ops)
{
diff --git a/include/linux/dcache.h b/include/linux/dcache.h
index be7ae058fa90..cc3e1c1a3454 100644
--- a/include/linux/dcache.h
+++ b/include/linux/dcache.h
@@ -237,7 +237,6 @@ extern void d_instantiate_new(struct dentry *, struct inode *);
extern void __d_drop(struct dentry *dentry);
extern void d_drop(struct dentry *dentry);
extern void d_delete(struct dentry *);
-extern void d_set_d_op(struct dentry *dentry, const struct dentry_operations *op);
/* allocate/de-allocate */
extern struct dentry * d_alloc(struct dentry *, const struct qstr *);
--
2.39.5
^ permalink raw reply related [flat|nested] 87+ messages in thread
* [PATCH v2 12/21] d_alloc_parallel(): set DCACHE_PAR_LOOKUP earlier
2025-06-11 7:54 ` [PATCH v2 01/21] d_set_mounted(): we don't need to bump seqcount component of rename_lock Al Viro
` (9 preceding siblings ...)
2025-06-11 7:54 ` [PATCH v2 11/21] make d_set_d_op() static Al Viro
@ 2025-06-11 7:54 ` Al Viro
2025-06-11 7:54 ` [PATCH v2 13/21] shmem: no dentry retention past the refcount reaching zero Al Viro
` (8 subsequent siblings)
19 siblings, 0 replies; 87+ messages in thread
From: Al Viro @ 2025-06-11 7:54 UTC (permalink / raw)
To: linux-fsdevel; +Cc: brauner, jack, miklos, neilb, torvalds
Do that before new dentry is visible anywhere. It does create
a new possible state for dentries present in ->d_children/->d_sib -
DCACHE_PAR_LOOKUP present, negative, unhashed, not in in-lookup
hash chains, refcount positive. Those are going to be skipped
by all tree-walkers (both d_walk() callbacks in fs/dcache.c and
explicit loops over children/sibling lists elsewhere) and
dput() is fine with those.
NOTE: dropping the final reference to a "normal" in-lookup dentry
(in in-lookup hash) is a bug - somebody must've forgotten to
call d_lookup_done() on it and bad things will happen. With those
it's OK; if/when we get around to making __dentry_kill() complain
about such breakage, remember that predicate to check should
*not* be just d_in_lookup(victim) but rather a combination of that
with !hlist_bl_unhashed(&victim->d_u.d_in_lookup_hash). Might
be worth considering later...
Reviewed-by: Christian Brauner <brauner@kernel.org>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/dcache.c | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)
diff --git a/fs/dcache.c b/fs/dcache.c
index 4e6ab27471a4..2adac023ba23 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -2546,13 +2546,19 @@ struct dentry *d_alloc_parallel(struct dentry *parent,
unsigned int hash = name->hash;
struct hlist_bl_head *b = in_lookup_hash(parent, hash);
struct hlist_bl_node *node;
- struct dentry *new = d_alloc(parent, name);
+ struct dentry *new = __d_alloc(parent->d_sb, name);
struct dentry *dentry;
unsigned seq, r_seq, d_seq;
if (unlikely(!new))
return ERR_PTR(-ENOMEM);
+ new->d_flags |= DCACHE_PAR_LOOKUP;
+ spin_lock(&parent->d_lock);
+ new->d_parent = dget_dlock(parent);
+ hlist_add_head(&new->d_sib, &parent->d_children);
+ spin_unlock(&parent->d_lock);
+
retry:
rcu_read_lock();
seq = smp_load_acquire(&parent->d_inode->i_dir_seq);
@@ -2636,8 +2642,6 @@ struct dentry *d_alloc_parallel(struct dentry *parent,
return dentry;
}
rcu_read_unlock();
- /* we can't take ->d_lock here; it's OK, though. */
- new->d_flags |= DCACHE_PAR_LOOKUP;
new->d_wait = wq;
hlist_bl_add_head(&new->d_u.d_in_lookup_hash, b);
hlist_bl_unlock(b);
--
2.39.5
^ permalink raw reply related [flat|nested] 87+ messages in thread
* [PATCH v2 13/21] shmem: no dentry retention past the refcount reaching zero
2025-06-11 7:54 ` [PATCH v2 01/21] d_set_mounted(): we don't need to bump seqcount component of rename_lock Al Viro
` (10 preceding siblings ...)
2025-06-11 7:54 ` [PATCH v2 12/21] d_alloc_parallel(): set DCACHE_PAR_LOOKUP earlier Al Viro
@ 2025-06-11 7:54 ` Al Viro
2025-06-11 7:54 ` [PATCH v2 14/21] devpts, sunrpc, hostfs: don't bother with ->d_op Al Viro
` (7 subsequent siblings)
19 siblings, 0 replies; 87+ messages in thread
From: Al Viro @ 2025-06-11 7:54 UTC (permalink / raw)
To: linux-fsdevel; +Cc: brauner, jack, miklos, neilb, torvalds
Just set DCACHE_DONTCACHE in ->s_d_flags and be done with that.
Dentries there live for as long as they are pinned; once the
refcount hits zero, that's it. The same, of course, goes for
other tree-in-dcache filesystems - more in the next commits...
Reviewed-by: Christian Brauner <brauner@kernel.org>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
mm/shmem.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/mm/shmem.c b/mm/shmem.c
index 3583508800fc..94b2b4264607 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -4980,7 +4980,6 @@ static void shmem_put_super(struct super_block *sb)
static const struct dentry_operations shmem_ci_dentry_ops = {
.d_hash = generic_ci_d_hash,
.d_compare = generic_ci_d_compare,
- .d_delete = always_delete_dentry,
};
#endif
@@ -5037,6 +5036,7 @@ static int shmem_fill_super(struct super_block *sb, struct fs_context *fc)
#else
sb->s_flags |= SB_NOUSER;
#endif /* CONFIG_TMPFS */
+ sb->s_d_flags |= DCACHE_DONTCACHE;
sbinfo->max_blocks = ctx->blocks;
sbinfo->max_inodes = ctx->inodes;
sbinfo->free_ispace = sbinfo->max_inodes * BOGO_INODE_SIZE;
--
2.39.5
^ permalink raw reply related [flat|nested] 87+ messages in thread
* [PATCH v2 14/21] devpts, sunrpc, hostfs: don't bother with ->d_op
2025-06-11 7:54 ` [PATCH v2 01/21] d_set_mounted(): we don't need to bump seqcount component of rename_lock Al Viro
` (11 preceding siblings ...)
2025-06-11 7:54 ` [PATCH v2 13/21] shmem: no dentry retention past the refcount reaching zero Al Viro
@ 2025-06-11 7:54 ` Al Viro
2025-06-11 9:50 ` Christian Brauner
2025-06-11 7:54 ` [PATCH v2 15/21] kill simple_dentry_operations Al Viro
` (6 subsequent siblings)
19 siblings, 1 reply; 87+ messages in thread
From: Al Viro @ 2025-06-11 7:54 UTC (permalink / raw)
To: linux-fsdevel; +Cc: brauner, jack, miklos, neilb, torvalds
Default ->d_op being simple_dentry_operations is equivalent to leaving
it NULL and putting DCACHE_DONTCACHE into ->s_d_flags.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/devpts/inode.c | 2 +-
fs/hostfs/hostfs_kern.c | 2 +-
net/sunrpc/rpc_pipe.c | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/fs/devpts/inode.c b/fs/devpts/inode.c
index fd17992ee298..fdf22264a8e9 100644
--- a/fs/devpts/inode.c
+++ b/fs/devpts/inode.c
@@ -381,7 +381,7 @@ static int devpts_fill_super(struct super_block *s, struct fs_context *fc)
s->s_blocksize_bits = 10;
s->s_magic = DEVPTS_SUPER_MAGIC;
s->s_op = &devpts_sops;
- set_default_d_op(s, &simple_dentry_operations);
+ s->s_d_flags = DCACHE_DONTCACHE;
s->s_time_gran = 1;
fsi->sb = s;
diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c
index 1c0f5038e19c..1f512f8ea757 100644
--- a/fs/hostfs/hostfs_kern.c
+++ b/fs/hostfs/hostfs_kern.c
@@ -933,7 +933,7 @@ static int hostfs_fill_super(struct super_block *sb, struct fs_context *fc)
sb->s_blocksize_bits = 10;
sb->s_magic = HOSTFS_SUPER_MAGIC;
sb->s_op = &hostfs_sbops;
- set_default_d_op(sb, &simple_dentry_operations);
+ sb->s_d_flags = DCACHE_DONTCACHE;
sb->s_maxbytes = MAX_LFS_FILESIZE;
err = super_setup_bdi(sb);
if (err)
diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c
index f4e880383f67..b85537191f8f 100644
--- a/net/sunrpc/rpc_pipe.c
+++ b/net/sunrpc/rpc_pipe.c
@@ -1363,7 +1363,7 @@ rpc_fill_super(struct super_block *sb, struct fs_context *fc)
sb->s_blocksize_bits = PAGE_SHIFT;
sb->s_magic = RPCAUTH_GSSMAGIC;
sb->s_op = &s_ops;
- set_default_d_op(sb, &simple_dentry_operations);
+ sb->s_d_flags = DCACHE_DONTCACHE;
sb->s_time_gran = 1;
inode = rpc_get_inode(sb, S_IFDIR | 0555);
--
2.39.5
^ permalink raw reply related [flat|nested] 87+ messages in thread
* [PATCH v2 15/21] kill simple_dentry_operations
2025-06-11 7:54 ` [PATCH v2 01/21] d_set_mounted(): we don't need to bump seqcount component of rename_lock Al Viro
` (12 preceding siblings ...)
2025-06-11 7:54 ` [PATCH v2 14/21] devpts, sunrpc, hostfs: don't bother with ->d_op Al Viro
@ 2025-06-11 7:54 ` Al Viro
2025-06-11 7:54 ` [PATCH v2 16/21] ramfs, hugetlbfs, mqueue: set DCACHE_DONTCACHE Al Viro
` (5 subsequent siblings)
19 siblings, 0 replies; 87+ messages in thread
From: Al Viro @ 2025-06-11 7:54 UTC (permalink / raw)
To: linux-fsdevel; +Cc: brauner, jack, miklos, neilb, torvalds
No users left and anything that wants it would be better off just
setting DCACHE_DONTCACHE in their ->s_d_flags.
Reviewed-by: Christian Brauner <brauner@kernel.org>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/libfs.c | 5 -----
include/linux/fs.h | 1 -
2 files changed, 6 deletions(-)
diff --git a/fs/libfs.c b/fs/libfs.c
index 19cc12651708..3051211998b6 100644
--- a/fs/libfs.c
+++ b/fs/libfs.c
@@ -62,11 +62,6 @@ int always_delete_dentry(const struct dentry *dentry)
}
EXPORT_SYMBOL(always_delete_dentry);
-const struct dentry_operations simple_dentry_operations = {
- .d_delete = always_delete_dentry,
-};
-EXPORT_SYMBOL(simple_dentry_operations);
-
/*
* Lookup the data. This is trivial - if the dentry didn't already
* exist, we know it is negative. Set d_op to delete negative dentries.
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 65548e70e596..d58bbb8262e8 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -3606,7 +3606,6 @@ extern const struct address_space_operations ram_aops;
extern int always_delete_dentry(const struct dentry *);
extern struct inode *alloc_anon_inode(struct super_block *);
extern int simple_nosetlease(struct file *, int, struct file_lease **, void **);
-extern const struct dentry_operations simple_dentry_operations;
extern struct dentry *simple_lookup(struct inode *, struct dentry *, unsigned int flags);
extern ssize_t generic_read_dir(struct file *, char __user *, size_t, loff_t *);
--
2.39.5
^ permalink raw reply related [flat|nested] 87+ messages in thread
* [PATCH v2 16/21] ramfs, hugetlbfs, mqueue: set DCACHE_DONTCACHE
2025-06-11 7:54 ` [PATCH v2 01/21] d_set_mounted(): we don't need to bump seqcount component of rename_lock Al Viro
` (13 preceding siblings ...)
2025-06-11 7:54 ` [PATCH v2 15/21] kill simple_dentry_operations Al Viro
@ 2025-06-11 7:54 ` Al Viro
2025-06-11 7:54 ` [PATCH v2 17/21] 9p: don't bother with always_delete_dentry Al Viro
` (4 subsequent siblings)
19 siblings, 0 replies; 87+ messages in thread
From: Al Viro @ 2025-06-11 7:54 UTC (permalink / raw)
To: linux-fsdevel; +Cc: brauner, jack, miklos, neilb, torvalds
makes simple_lookup() slightly cheaper there - no need for
simple_lookup() to set the flag and we want it on everything
on those anyway.
Reviewed-by: Christian Brauner <brauner@kernel.org>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/hugetlbfs/inode.c | 1 +
fs/ramfs/inode.c | 1 +
ipc/mqueue.c | 1 +
3 files changed, 3 insertions(+)
diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c
index e4de5425838d..6e0ade365a33 100644
--- a/fs/hugetlbfs/inode.c
+++ b/fs/hugetlbfs/inode.c
@@ -1433,6 +1433,7 @@ hugetlbfs_fill_super(struct super_block *sb, struct fs_context *fc)
sb->s_blocksize_bits = huge_page_shift(ctx->hstate);
sb->s_magic = HUGETLBFS_MAGIC;
sb->s_op = &hugetlbfs_ops;
+ sb->s_d_flags = DCACHE_DONTCACHE;
sb->s_time_gran = 1;
/*
diff --git a/fs/ramfs/inode.c b/fs/ramfs/inode.c
index 775fa905fda0..f8874c3b8c1e 100644
--- a/fs/ramfs/inode.c
+++ b/fs/ramfs/inode.c
@@ -269,6 +269,7 @@ static int ramfs_fill_super(struct super_block *sb, struct fs_context *fc)
sb->s_blocksize_bits = PAGE_SHIFT;
sb->s_magic = RAMFS_MAGIC;
sb->s_op = &ramfs_ops;
+ sb->s_d_flags = DCACHE_DONTCACHE;
sb->s_time_gran = 1;
inode = ramfs_get_inode(sb, NULL, S_IFDIR | fsi->mount_opts.mode, 0);
diff --git a/ipc/mqueue.c b/ipc/mqueue.c
index 82ed2d3c9846..482af449e00d 100644
--- a/ipc/mqueue.c
+++ b/ipc/mqueue.c
@@ -411,6 +411,7 @@ static int mqueue_fill_super(struct super_block *sb, struct fs_context *fc)
sb->s_blocksize_bits = PAGE_SHIFT;
sb->s_magic = MQUEUE_MAGIC;
sb->s_op = &mqueue_super_ops;
+ sb->s_d_flags = DCACHE_DONTCACHE;
inode = mqueue_get_inode(sb, ns, S_IFDIR | S_ISVTX | S_IRWXUGO, NULL);
if (IS_ERR(inode))
--
2.39.5
^ permalink raw reply related [flat|nested] 87+ messages in thread
* [PATCH v2 17/21] 9p: don't bother with always_delete_dentry
2025-06-11 7:54 ` [PATCH v2 01/21] d_set_mounted(): we don't need to bump seqcount component of rename_lock Al Viro
` (14 preceding siblings ...)
2025-06-11 7:54 ` [PATCH v2 16/21] ramfs, hugetlbfs, mqueue: set DCACHE_DONTCACHE Al Viro
@ 2025-06-11 7:54 ` Al Viro
2025-06-11 7:54 ` [PATCH v2 18/21] efivarfs: use DCACHE_DONTCACHE instead of always_delete_dentry() Al Viro
` (3 subsequent siblings)
19 siblings, 0 replies; 87+ messages in thread
From: Al Viro @ 2025-06-11 7:54 UTC (permalink / raw)
To: linux-fsdevel; +Cc: brauner, jack, miklos, neilb, torvalds
just set DCACHE_DONTCACHE for "don't cache" mounts...
Reviewed-by: Christian Brauner <brauner@kernel.org>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/9p/vfs_dentry.c | 1 -
fs/9p/vfs_super.c | 6 ++++--
2 files changed, 4 insertions(+), 3 deletions(-)
diff --git a/fs/9p/vfs_dentry.c b/fs/9p/vfs_dentry.c
index 5061f192eafd..04795508a795 100644
--- a/fs/9p/vfs_dentry.c
+++ b/fs/9p/vfs_dentry.c
@@ -127,7 +127,6 @@ const struct dentry_operations v9fs_cached_dentry_operations = {
};
const struct dentry_operations v9fs_dentry_operations = {
- .d_delete = always_delete_dentry,
.d_release = v9fs_dentry_release,
.d_unalias_trylock = v9fs_dentry_unalias_trylock,
.d_unalias_unlock = v9fs_dentry_unalias_unlock,
diff --git a/fs/9p/vfs_super.c b/fs/9p/vfs_super.c
index 5c3dc3efb909..795c6388744c 100644
--- a/fs/9p/vfs_super.c
+++ b/fs/9p/vfs_super.c
@@ -134,10 +134,12 @@ static struct dentry *v9fs_mount(struct file_system_type *fs_type, int flags,
if (retval)
goto release_sb;
- if (v9ses->cache & (CACHE_META|CACHE_LOOSE))
+ if (v9ses->cache & (CACHE_META|CACHE_LOOSE)) {
set_default_d_op(sb, &v9fs_cached_dentry_operations);
- else
+ } else {
set_default_d_op(sb, &v9fs_dentry_operations);
+ sb->s_d_flags |= DCACHE_DONTCACHE;
+ }
inode = v9fs_get_new_inode_from_fid(v9ses, fid, sb);
if (IS_ERR(inode)) {
--
2.39.5
^ permalink raw reply related [flat|nested] 87+ messages in thread
* [PATCH v2 18/21] efivarfs: use DCACHE_DONTCACHE instead of always_delete_dentry()
2025-06-11 7:54 ` [PATCH v2 01/21] d_set_mounted(): we don't need to bump seqcount component of rename_lock Al Viro
` (15 preceding siblings ...)
2025-06-11 7:54 ` [PATCH v2 17/21] 9p: don't bother with always_delete_dentry Al Viro
@ 2025-06-11 7:54 ` Al Viro
2025-06-11 7:54 ` [PATCH v2 19/21] debugfs: use DCACHE_DONTCACHE Al Viro
` (2 subsequent siblings)
19 siblings, 0 replies; 87+ messages in thread
From: Al Viro @ 2025-06-11 7:54 UTC (permalink / raw)
To: linux-fsdevel; +Cc: brauner, jack, miklos, neilb, torvalds
Reviewed-by: Christian Brauner <brauner@kernel.org>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/efivarfs/super.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/fs/efivarfs/super.c b/fs/efivarfs/super.c
index f76d8dfa646b..23ff4e873651 100644
--- a/fs/efivarfs/super.c
+++ b/fs/efivarfs/super.c
@@ -183,7 +183,6 @@ static int efivarfs_d_hash(const struct dentry *dentry, struct qstr *qstr)
static const struct dentry_operations efivarfs_d_ops = {
.d_compare = efivarfs_d_compare,
.d_hash = efivarfs_d_hash,
- .d_delete = always_delete_dentry,
};
static struct dentry *efivarfs_alloc_dentry(struct dentry *parent, char *name)
@@ -351,6 +350,7 @@ static int efivarfs_fill_super(struct super_block *sb, struct fs_context *fc)
sb->s_magic = EFIVARFS_MAGIC;
sb->s_op = &efivarfs_ops;
set_default_d_op(sb, &efivarfs_d_ops);
+ sb->s_d_flags |= DCACHE_DONTCACHE;
sb->s_time_gran = 1;
if (!efivar_supports_writes())
--
2.39.5
^ permalink raw reply related [flat|nested] 87+ messages in thread
* [PATCH v2 19/21] debugfs: use DCACHE_DONTCACHE
2025-06-11 7:54 ` [PATCH v2 01/21] d_set_mounted(): we don't need to bump seqcount component of rename_lock Al Viro
` (16 preceding siblings ...)
2025-06-11 7:54 ` [PATCH v2 18/21] efivarfs: use DCACHE_DONTCACHE instead of always_delete_dentry() Al Viro
@ 2025-06-11 7:54 ` Al Viro
2025-06-11 7:54 ` [PATCH v2 20/21] configfs: " Al Viro
2025-06-11 7:54 ` [PATCH v2 21/21] tracefs: set DCACHE_DONTCACHE Al Viro
19 siblings, 0 replies; 87+ messages in thread
From: Al Viro @ 2025-06-11 7:54 UTC (permalink / raw)
To: linux-fsdevel; +Cc: brauner, jack, miklos, neilb, torvalds
Reviewed-by: Christian Brauner <brauner@kernel.org>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/debugfs/inode.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c
index 29c5ec382342..441e3547a4f3 100644
--- a/fs/debugfs/inode.c
+++ b/fs/debugfs/inode.c
@@ -258,7 +258,6 @@ static struct vfsmount *debugfs_automount(struct path *path)
}
static const struct dentry_operations debugfs_dops = {
- .d_delete = always_delete_dentry,
.d_release = debugfs_release_dentry,
.d_automount = debugfs_automount,
};
@@ -274,6 +273,7 @@ static int debugfs_fill_super(struct super_block *sb, struct fs_context *fc)
sb->s_op = &debugfs_super_operations;
set_default_d_op(sb, &debugfs_dops);
+ sb->s_d_flags |= DCACHE_DONTCACHE;
debugfs_apply_options(sb);
--
2.39.5
^ permalink raw reply related [flat|nested] 87+ messages in thread
* [PATCH v2 20/21] configfs: use DCACHE_DONTCACHE
2025-06-11 7:54 ` [PATCH v2 01/21] d_set_mounted(): we don't need to bump seqcount component of rename_lock Al Viro
` (17 preceding siblings ...)
2025-06-11 7:54 ` [PATCH v2 19/21] debugfs: use DCACHE_DONTCACHE Al Viro
@ 2025-06-11 7:54 ` Al Viro
2025-06-11 7:54 ` [PATCH v2 21/21] tracefs: set DCACHE_DONTCACHE Al Viro
19 siblings, 0 replies; 87+ messages in thread
From: Al Viro @ 2025-06-11 7:54 UTC (permalink / raw)
To: linux-fsdevel; +Cc: brauner, jack, miklos, neilb, torvalds
Reviewed-by: Christian Brauner <brauner@kernel.org>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/configfs/dir.c | 1 -
fs/configfs/mount.c | 1 +
2 files changed, 1 insertion(+), 1 deletion(-)
diff --git a/fs/configfs/dir.c b/fs/configfs/dir.c
index ebf32822e29b..f327fbb9a0ca 100644
--- a/fs/configfs/dir.c
+++ b/fs/configfs/dir.c
@@ -67,7 +67,6 @@ static void configfs_d_iput(struct dentry * dentry,
const struct dentry_operations configfs_dentry_ops = {
.d_iput = configfs_d_iput,
- .d_delete = always_delete_dentry,
};
#ifdef CONFIG_LOCKDEP
diff --git a/fs/configfs/mount.c b/fs/configfs/mount.c
index 20412eaca972..740f18b60c9d 100644
--- a/fs/configfs/mount.c
+++ b/fs/configfs/mount.c
@@ -93,6 +93,7 @@ static int configfs_fill_super(struct super_block *sb, struct fs_context *fc)
root->d_fsdata = &configfs_root;
sb->s_root = root;
set_default_d_op(sb, &configfs_dentry_ops); /* the rest get that */
+ sb->s_d_flags |= DCACHE_DONTCACHE;
return 0;
}
--
2.39.5
^ permalink raw reply related [flat|nested] 87+ messages in thread
* [PATCH v2 21/21] tracefs: set DCACHE_DONTCACHE
2025-06-11 7:54 ` [PATCH v2 01/21] d_set_mounted(): we don't need to bump seqcount component of rename_lock Al Viro
` (18 preceding siblings ...)
2025-06-11 7:54 ` [PATCH v2 20/21] configfs: " Al Viro
@ 2025-06-11 7:54 ` Al Viro
2025-06-11 9:51 ` Christian Brauner
19 siblings, 1 reply; 87+ messages in thread
From: Al Viro @ 2025-06-11 7:54 UTC (permalink / raw)
To: linux-fsdevel; +Cc: brauner, jack, miklos, neilb, torvalds
*NOTE* - this does change behaviour; as it is, cache misses are hashed
and retained there.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/tracefs/inode.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/fs/tracefs/inode.c b/fs/tracefs/inode.c
index c8ca61777323..40fa6220189d 100644
--- a/fs/tracefs/inode.c
+++ b/fs/tracefs/inode.c
@@ -481,6 +481,7 @@ static int tracefs_fill_super(struct super_block *sb, struct fs_context *fc)
sb->s_op = &tracefs_super_operations;
set_default_d_op(sb, &tracefs_dentry_operations);
+ sb->s_d_flags |= DCACHE_DONTCACHE;
return 0;
}
--
2.39.5
^ permalink raw reply related [flat|nested] 87+ messages in thread
* Re: [RFC][PATCHES v2] dentry->d_flags locking
2025-06-11 7:50 ` [RFC][PATCHES v2] " Al Viro
2025-06-11 7:54 ` [PATCH v2 01/21] d_set_mounted(): we don't need to bump seqcount component of rename_lock Al Viro
@ 2025-06-11 9:47 ` Christian Brauner
1 sibling, 0 replies; 87+ messages in thread
From: Christian Brauner @ 2025-06-11 9:47 UTC (permalink / raw)
To: Al Viro; +Cc: linux-fsdevel, Linus Torvalds, Neil Brown, Miklos Szeredi,
Jan Kara
> Or are you talking about DCACHE_DONTCACHE (i.e. "unhash as soon as
> refcount hits 0", rather than "never hash it at all")?
Yes. The series is doing exactly that.
^ permalink raw reply [flat|nested] 87+ messages in thread
* Re: [PATCH v2 08/21] correct the set of flags forbidden at d_set_d_op() time
2025-06-11 7:54 ` [PATCH v2 08/21] correct the set of flags forbidden at d_set_d_op() time Al Viro
@ 2025-06-11 9:49 ` Christian Brauner
0 siblings, 0 replies; 87+ messages in thread
From: Christian Brauner @ 2025-06-11 9:49 UTC (permalink / raw)
To: Al Viro; +Cc: linux-fsdevel, jack, miklos, neilb, torvalds
On Wed, Jun 11, 2025 at 08:54:24AM +0100, Al Viro wrote:
> DCACHE_OP_PRUNE in ->d_flags at the time of d_set_d_op() should've
> been treated the same as any other DCACHE_OP_... - we forgot to adjust
> that WARN_ON() when DCACHE_OP_PRUNE had been introduced...
>
> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
> ---
Reviewed-by: Christian Brauner <brauner@kernel.org>
^ permalink raw reply [flat|nested] 87+ messages in thread
* Re: [PATCH v2 10/21] simple_lookup(): just set DCACHE_DONTCACHE
2025-06-11 7:54 ` [PATCH v2 10/21] simple_lookup(): just set DCACHE_DONTCACHE Al Viro
@ 2025-06-11 9:50 ` Christian Brauner
0 siblings, 0 replies; 87+ messages in thread
From: Christian Brauner @ 2025-06-11 9:50 UTC (permalink / raw)
To: Al Viro; +Cc: linux-fsdevel, jack, miklos, neilb, torvalds
On Wed, Jun 11, 2025 at 08:54:26AM +0100, Al Viro wrote:
> No need to mess with ->d_op at all. Note that ->d_delete that always
> returns 1 is equivalent to having DCACHE_DONTCACHE in ->d_flags.
> Later the same thing will be placed into ->s_d_flags of the filesystems
> where we want that behaviour for all dentries; then the check in
> simple_lookup() will at least get unlikely() slapped on it.
>
> NOTE: there are only two filesystems where
> * simple_lookup() might be called
> * default ->d_op is non-NULL
> * its ->d_delete() doesn't always return 1
> If not for those, we could have simple_lookup() just set DCACHE_DONTCACHE
> without even looking at ->d_op. Filesystems in question are btrfs
> (where ->d_delete() takes care to recognize the dentries that might
> come from simple_lookup() and returns 1 for those) and tracefs.
>
> The former would be fine with simple_lookup() setting DCACHE_DONTCACHE;
> the latter... probably wants DCACHE_DONTCACHE in default d_flags.
>
> IOW, we might want to drop the check for ->d_op in simple_lookup();
> it's definitely a separate story, though.
>
> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
> ---
Reviewed-by: Christian Brauner <brauner@kernel.org>
^ permalink raw reply [flat|nested] 87+ messages in thread
* Re: [PATCH v2 14/21] devpts, sunrpc, hostfs: don't bother with ->d_op
2025-06-11 7:54 ` [PATCH v2 14/21] devpts, sunrpc, hostfs: don't bother with ->d_op Al Viro
@ 2025-06-11 9:50 ` Christian Brauner
0 siblings, 0 replies; 87+ messages in thread
From: Christian Brauner @ 2025-06-11 9:50 UTC (permalink / raw)
To: Al Viro; +Cc: linux-fsdevel, jack, miklos, neilb, torvalds
On Wed, Jun 11, 2025 at 08:54:30AM +0100, Al Viro wrote:
> Default ->d_op being simple_dentry_operations is equivalent to leaving
> it NULL and putting DCACHE_DONTCACHE into ->s_d_flags.
>
> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
> ---
Reviewed-by: Christian Brauner <brauner@kernel.org>
^ permalink raw reply [flat|nested] 87+ messages in thread
* Re: [PATCH v2 21/21] tracefs: set DCACHE_DONTCACHE
2025-06-11 7:54 ` [PATCH v2 21/21] tracefs: set DCACHE_DONTCACHE Al Viro
@ 2025-06-11 9:51 ` Christian Brauner
0 siblings, 0 replies; 87+ messages in thread
From: Christian Brauner @ 2025-06-11 9:51 UTC (permalink / raw)
To: Al Viro; +Cc: linux-fsdevel, jack, miklos, neilb, torvalds
On Wed, Jun 11, 2025 at 08:54:37AM +0100, Al Viro wrote:
> *NOTE* - this does change behaviour; as it is, cache misses are hashed
> and retained there.
>
> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
> ---
Reviewed-by: Christian Brauner <brauner@kernel.org>
^ permalink raw reply [flat|nested] 87+ messages in thread
end of thread, other threads:[~2025-06-11 9:51 UTC | newest]
Thread overview: 87+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-02-24 1:06 [RFC] dentry->d_flags locking Al Viro
2025-02-24 1:38 ` Al Viro
2025-02-24 10:35 ` Christian Brauner
2025-02-24 14:14 ` Al Viro
2025-02-24 21:20 ` [PATCH 01/21] procfs: kill ->proc_dops Al Viro
2025-02-24 21:20 ` [PATCH 02/21] new helper: d_splice_alias_ops() Al Viro
2025-02-26 8:28 ` Christian Brauner
2025-02-24 21:20 ` [PATCH 03/21] switch procfs from d_set_d_op() to d_splice_alias_ops() Al Viro
2025-02-26 8:29 ` Christian Brauner
2025-02-24 21:20 ` [PATCH 04/21] fuse: no need for special dentry_operations for root dentry Al Viro
2025-02-26 8:29 ` Christian Brauner
2025-02-27 14:33 ` Miklos Szeredi
2025-02-24 21:20 ` [PATCH 05/21] new helper: set_default_d_op() Al Viro
2025-02-26 8:30 ` Christian Brauner
2025-02-24 21:20 ` [PATCH 06/21] split d_flags calculation out of d_set_d_op() Al Viro
2025-02-26 8:31 ` Christian Brauner
2025-02-24 21:20 ` [PATCH 07/21] set_default_d_op(): calculate the matching value for ->d_flags Al Viro
2025-02-26 8:33 ` Christian Brauner
2025-02-24 21:20 ` [PATCH 08/21] simple_lookup(): just set DCACHE_DONTCACHE Al Viro
2025-02-26 8:34 ` Christian Brauner
2025-02-24 21:20 ` [PATCH 09/21] make d_set_d_op() static Al Viro
2025-02-25 23:09 ` NeilBrown
2025-02-26 8:35 ` Christian Brauner
2025-02-24 21:20 ` [PATCH 10/21] d_alloc_parallel(): set DCACHE_PAR_LOOKUP earlier Al Viro
2025-02-26 8:36 ` Christian Brauner
2025-02-24 21:20 ` [PATCH 11/21] nsfs, pidfs: drop the pointless ->d_delete() Al Viro
2025-02-26 8:37 ` Christian Brauner
2025-02-24 21:20 ` [PATCH 12/21] shmem: no dentry retention past the refcount reaching zero Al Viro
2025-02-26 8:38 ` Christian Brauner
2025-02-24 21:20 ` [PATCH 13/21] devpts, sunrpc: don't bother with ->d_delete or ->d_op, for that matter Al Viro
2025-02-26 8:38 ` Christian Brauner
2025-02-24 21:20 ` [PATCH 14/21] hostfs: don't bother with ->d_op Al Viro
2025-02-26 8:38 ` Christian Brauner
2025-02-24 21:20 ` [PATCH 15/21] kill simple_dentry_operations Al Viro
2025-02-26 8:39 ` Christian Brauner
2025-02-24 21:20 ` [PATCH 16/21] ramfs, hugetlbfs, mqueue: set DCACHE_DONTCACHE Al Viro
2025-02-25 23:25 ` NeilBrown
2025-02-25 23:36 ` Al Viro
2025-02-25 23:40 ` NeilBrown
2025-02-26 8:39 ` Christian Brauner
2025-02-24 21:20 ` [PATCH 17/21] 9p: don't bother with always_delete_dentry Al Viro
2025-02-26 8:40 ` Christian Brauner
2025-02-24 21:20 ` [PATCH 18/21] efivarfs: use DCACHE_DONTCACHE instead of always_delete_dentry() Al Viro
2025-02-26 8:40 ` Christian Brauner
2025-02-24 21:20 ` [PATCH 19/21] debugfs: use DCACHE_DONTCACHE Al Viro
2025-02-26 8:40 ` Christian Brauner
2025-02-24 21:20 ` [PATCH 20/21] configfs: " Al Viro
2025-02-26 8:40 ` Christian Brauner
2025-02-24 21:20 ` [PATCH 21/21] afs dynroot: " Al Viro
2025-02-26 8:41 ` Christian Brauner
2025-02-25 15:55 ` [PATCH 01/21] procfs: kill ->proc_dops Jan Kara
2025-02-25 23:30 ` NeilBrown
2025-02-25 23:56 ` Al Viro
2025-02-25 22:51 ` NeilBrown
2025-02-26 0:03 ` Al Viro
2025-02-26 8:25 ` Christian Brauner
2025-02-26 8:41 ` [RFC] dentry->d_flags locking Christian Brauner
2025-02-24 11:45 ` Christian Brauner
2025-06-11 7:50 ` [RFC][PATCHES v2] " Al Viro
2025-06-11 7:54 ` [PATCH v2 01/21] d_set_mounted(): we don't need to bump seqcount component of rename_lock Al Viro
2025-06-11 7:54 ` [PATCH v2 02/21] procfs: kill ->proc_dops Al Viro
2025-06-11 7:54 ` [PATCH v2 03/21] new helper: d_splice_alias_ops() Al Viro
2025-06-11 7:54 ` [PATCH v2 04/21] switch procfs from d_set_d_op() to d_splice_alias_ops() Al Viro
2025-06-11 7:54 ` [PATCH v2 05/21] fuse: no need for special dentry_operations for root dentry Al Viro
2025-06-11 7:54 ` [PATCH v2 06/21] new helper: set_default_d_op() Al Viro
2025-06-11 7:54 ` [PATCH v2 07/21] split d_flags calculation out of d_set_d_op() Al Viro
2025-06-11 7:54 ` [PATCH v2 08/21] correct the set of flags forbidden at d_set_d_op() time Al Viro
2025-06-11 9:49 ` Christian Brauner
2025-06-11 7:54 ` [PATCH v2 09/21] set_default_d_op(): calculate the matching value for ->d_flags Al Viro
2025-06-11 7:54 ` [PATCH v2 10/21] simple_lookup(): just set DCACHE_DONTCACHE Al Viro
2025-06-11 9:50 ` Christian Brauner
2025-06-11 7:54 ` [PATCH v2 11/21] make d_set_d_op() static Al Viro
2025-06-11 7:54 ` [PATCH v2 12/21] d_alloc_parallel(): set DCACHE_PAR_LOOKUP earlier Al Viro
2025-06-11 7:54 ` [PATCH v2 13/21] shmem: no dentry retention past the refcount reaching zero Al Viro
2025-06-11 7:54 ` [PATCH v2 14/21] devpts, sunrpc, hostfs: don't bother with ->d_op Al Viro
2025-06-11 9:50 ` Christian Brauner
2025-06-11 7:54 ` [PATCH v2 15/21] kill simple_dentry_operations Al Viro
2025-06-11 7:54 ` [PATCH v2 16/21] ramfs, hugetlbfs, mqueue: set DCACHE_DONTCACHE Al Viro
2025-06-11 7:54 ` [PATCH v2 17/21] 9p: don't bother with always_delete_dentry Al Viro
2025-06-11 7:54 ` [PATCH v2 18/21] efivarfs: use DCACHE_DONTCACHE instead of always_delete_dentry() Al Viro
2025-06-11 7:54 ` [PATCH v2 19/21] debugfs: use DCACHE_DONTCACHE Al Viro
2025-06-11 7:54 ` [PATCH v2 20/21] configfs: " Al Viro
2025-06-11 7:54 ` [PATCH v2 21/21] tracefs: set DCACHE_DONTCACHE Al Viro
2025-06-11 9:51 ` Christian Brauner
2025-06-11 9:47 ` [RFC][PATCHES v2] dentry->d_flags locking Christian Brauner
2025-02-24 14:07 ` [RFC] " Miklos Szeredi
2025-02-25 17:56 ` Al Viro
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).