Skip to content

Commit 11fe69f

Browse files
committed
Merge tag 'pull-dcache' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
Pull dentry d_flags updates from Al Viro: "The current exclusion rules for dentry->d_flags stores are rather unpleasant. The basic rules are simple: - stores to dentry->d_flags are OK under dentry->d_lock - stores to dentry->d_flags are OK in the dentry constructor, before becomes potentially visible to other threads Unfortunately, there's a couple of exceptions to that, and that's where the headache comes from. The main PITA comes from d_set_d_op(); that primitive sets ->d_op of dentry and adjusts the flags that correspond to presence of individual methods. It's very easy to misuse; existing uses _are_ safe, but proof of correctness is brittle. Use in __d_alloc() is safe (we are within a constructor), but we might as well precalculate the initial value of 'd_flags' when we set the default ->d_op for given superblock and set 'd_flags' directly instead of messing with that helper. The reasons why other uses are safe are bloody convoluted; I'm not going to reproduce it here. See [1] for gory details, if you care. The critical part is using d_set_d_op() only just prior to d_splice_alias(), which makes a combination of d_splice_alias() with setting ->d_op, etc a natural replacement primitive. Better yet, if we go that way, it's easy to take setting ->d_op and modifying 'd_flags' under ->d_lock, which eliminates the headache as far as 'd_flags' exclusion rules are concerned. Other exceptions are minor and easy to deal with. What this series does: - d_set_d_op() is no longer available; instead a new primitive (d_splice_alias_ops()) is provided, equivalent to combination of d_set_d_op() and d_splice_alias(). - new field of struct super_block - 's_d_flags'. This sets the default value of 'd_flags' to be used when allocating dentries on this filesystem. - new primitive for setting 's_d_op': set_default_d_op(). This replaces stores to 's_d_op' at mount time. All in-tree filesystems converted; out-of-tree ones will get caught by the compiler ('s_d_op' is renamed, so stores to it will be caught). 's_d_flags' is set by the same primitive to match the 's_d_op'. - a lot of filesystems had sb->s_d_op->d_delete equal to always_delete_dentry; that is equivalent to setting DCACHE_DONTCACHE in 'd_flags', so such filesystems can bloody well set that bit in 's_d_flags' and drop 'd_delete()' from dentry_operations. In quite a few cases that results in empty dentry_operations, which means that we can get rid of those. - kill simple_dentry_operations - not needed anymore - massage d_alloc_parallel() to get rid of the other exception wrt 'd_flags' stores - we can set DCACHE_PAR_LOOKUP as soon as we allocate the new dentry; no need to delay that until we commit to using the sucker. As the result, 'd_flags' stores are all either under ->d_lock or done before the dentry becomes visible in any shared data structures" Link: https://lore.kernel.org/all/20250224010624.GT1977892@ZenIV/ [1] * tag 'pull-dcache' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: (21 commits) configfs: use DCACHE_DONTCACHE debugfs: use DCACHE_DONTCACHE efivarfs: use DCACHE_DONTCACHE instead of always_delete_dentry() 9p: don't bother with always_delete_dentry ramfs, hugetlbfs, mqueue: set DCACHE_DONTCACHE kill simple_dentry_operations devpts, sunrpc, hostfs: don't bother with ->d_op shmem: no dentry retention past the refcount reaching zero d_alloc_parallel(): set DCACHE_PAR_LOOKUP earlier make d_set_d_op() static simple_lookup(): just set DCACHE_DONTCACHE tracefs: Add d_delete to remove negative dentries set_default_d_op(): calculate the matching value for ->d_flags correct the set of flags forbidden at d_set_d_op() time split d_flags calculation out of d_set_d_op() new helper: set_default_d_op() fuse: no need for special dentry_operations for root dentry switch procfs from d_set_d_op() to d_splice_alias_ops() new helper: d_splice_alias_ops() procfs: kill ->proc_dops ...
2 parents 126e575 + a509e7c commit 11fe69f

53 files changed

Lines changed: 210 additions & 159 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

Documentation/filesystems/porting.rst

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1258,3 +1258,21 @@ iterator needed. Instead of a cloned mount tree, the new interface returns
12581258
an array of struct path, one for each mount collect_mounts() would've
12591259
created. These struct path point to locations in the caller's namespace
12601260
that would be roots of the cloned mounts.
1261+
1262+
---
1263+
1264+
**mandatory**
1265+
1266+
If your filesystem sets the default dentry_operations, use set_default_d_op()
1267+
rather than manually setting sb->s_d_op.
1268+
1269+
---
1270+
1271+
**mandatory**
1272+
1273+
d_set_d_op() is no longer exported (or public, for that matter); _if_
1274+
your filesystem really needed that, make use of d_splice_alias_ops()
1275+
to have them set. Better yet, think hard whether you need different
1276+
->d_op for different dentries - if not, just use set_default_d_op()
1277+
at mount time and be done with that. Currently procfs is the only
1278+
thing that really needs ->d_op varying between dentries.

fs/9p/vfs_dentry.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,6 @@ const struct dentry_operations v9fs_cached_dentry_operations = {
127127
};
128128

129129
const struct dentry_operations v9fs_dentry_operations = {
130-
.d_delete = always_delete_dentry,
131130
.d_release = v9fs_dentry_release,
132131
.d_unalias_trylock = v9fs_dentry_unalias_trylock,
133132
.d_unalias_unlock = v9fs_dentry_unalias_unlock,

fs/9p/vfs_super.c

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -134,10 +134,12 @@ static struct dentry *v9fs_mount(struct file_system_type *fs_type, int flags,
134134
if (retval)
135135
goto release_sb;
136136

137-
if (v9ses->cache & (CACHE_META|CACHE_LOOSE))
138-
sb->s_d_op = &v9fs_cached_dentry_operations;
139-
else
140-
sb->s_d_op = &v9fs_dentry_operations;
137+
if (v9ses->cache & (CACHE_META|CACHE_LOOSE)) {
138+
set_default_d_op(sb, &v9fs_cached_dentry_operations);
139+
} else {
140+
set_default_d_op(sb, &v9fs_dentry_operations);
141+
sb->s_d_flags |= DCACHE_DONTCACHE;
142+
}
141143

142144
inode = v9fs_get_new_inode_from_fid(v9ses, fid, sb);
143145
if (IS_ERR(inode)) {

fs/adfs/super.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -397,7 +397,7 @@ static int adfs_fill_super(struct super_block *sb, struct fs_context *fc)
397397
if (asb->s_ftsuffix)
398398
asb->s_namelen += 4;
399399

400-
sb->s_d_op = &adfs_dentry_operations;
400+
set_default_d_op(sb, &adfs_dentry_operations);
401401
root = adfs_iget(sb, &root_obj);
402402
sb->s_root = d_make_root(root);
403403
if (!sb->s_root) {

fs/affs/super.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -500,9 +500,9 @@ static int affs_fill_super(struct super_block *sb, struct fs_context *fc)
500500
return PTR_ERR(root_inode);
501501

502502
if (affs_test_opt(AFFS_SB(sb)->s_flags, SF_INTL))
503-
sb->s_d_op = &affs_intl_dentry_operations;
503+
set_default_d_op(sb, &affs_intl_dentry_operations);
504504
else
505-
sb->s_d_op = &affs_dentry_operations;
505+
set_default_d_op(sb, &affs_dentry_operations);
506506

507507
sb->s_root = d_make_root(root_inode);
508508
if (!sb->s_root) {

fs/afs/super.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -483,9 +483,9 @@ static int afs_fill_super(struct super_block *sb, struct afs_fs_context *ctx)
483483
goto error;
484484

485485
if (as->dyn_root) {
486-
sb->s_d_op = &afs_dynroot_dentry_operations;
486+
set_default_d_op(sb, &afs_dynroot_dentry_operations);
487487
} else {
488-
sb->s_d_op = &afs_fs_dentry_operations;
488+
set_default_d_op(sb, &afs_fs_dentry_operations);
489489
rcu_assign_pointer(as->volume->sb, sb);
490490
}
491491

fs/autofs/inode.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -311,7 +311,7 @@ static int autofs_fill_super(struct super_block *s, struct fs_context *fc)
311311
s->s_blocksize_bits = 10;
312312
s->s_magic = AUTOFS_SUPER_MAGIC;
313313
s->s_op = &autofs_sops;
314-
s->s_d_op = &autofs_dentry_operations;
314+
set_default_d_op(s, &autofs_dentry_operations);
315315
s->s_time_gran = 1;
316316

317317
/*

fs/btrfs/super.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -959,7 +959,7 @@ static int btrfs_fill_super(struct super_block *sb,
959959
sb->s_maxbytes = MAX_LFS_FILESIZE;
960960
sb->s_magic = BTRFS_SUPER_MAGIC;
961961
sb->s_op = &btrfs_super_ops;
962-
sb->s_d_op = &btrfs_dentry_operations;
962+
set_default_d_op(sb, &btrfs_dentry_operations);
963963
sb->s_export_op = &btrfs_export_ops;
964964
#ifdef CONFIG_FS_VERITY
965965
sb->s_vop = &btrfs_verityops;

fs/ceph/super.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1219,7 +1219,7 @@ static int ceph_set_super(struct super_block *s, struct fs_context *fc)
12191219
fsc->max_file_size = 1ULL << 40; /* temp value until we get mdsmap */
12201220

12211221
s->s_op = &ceph_super_ops;
1222-
s->s_d_op = &ceph_dentry_ops;
1222+
set_default_d_op(s, &ceph_dentry_ops);
12231223
s->s_export_op = &ceph_export_ops;
12241224

12251225
s->s_time_gran = 1;

fs/coda/inode.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,7 @@ static int coda_fill_super(struct super_block *sb, struct fs_context *fc)
230230
sb->s_blocksize_bits = 12;
231231
sb->s_magic = CODA_SUPER_MAGIC;
232232
sb->s_op = &coda_super_operations;
233-
sb->s_d_op = &coda_dentry_operations;
233+
set_default_d_op(sb, &coda_dentry_operations);
234234
sb->s_time_gran = 1;
235235
sb->s_time_min = S64_MIN;
236236
sb->s_time_max = S64_MAX;

0 commit comments

Comments
 (0)