diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2026-10-19 18:59:41 -1000 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2026-10-19 18:59:41 -1000 |
| commit | 96a377ba007a6a1ee9fa9f0ba48812fe9284f0ce (patch) | |
| tree | e6238b82c77f03b5f237646a3916feba30427bd1 /include/linux | |
| parent | 0ddc887102d8a13ce85041a41c45f2053b483119 (diff) | |
| parent | 31fbbc8bb1ca256f3d27d1172ad3493d46d29c73 (diff) | |
Merge tag 'vfs-7.4-rc1.lookup' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs
Pull path lookup updates from Christian Brauner:
"This prepares for Neil's changes to directory locking. The goal is for
the VFS to lock the dentry and not the parent directory and to push
the i_rwsem parent locking down into the filesystems where it can be
kept, removed or adjusted as each filesystem sees fit.
The next step in that is to swap the lock order of d_alloc_parallel()
and i_rwsem so code can wait on i_rwsem while holding an in-lookup
dentry. Two things have to change before that can happen. Nobody may
call d_alloc_parallel() while holding i_rwsem, and nobody may d_drop()
a dentry while it is being worked on since that effectively unlocks an
in-lookup dentry and lets another one be allocated too early.
So d_splice_alias() learns to handle hashed dentries in addition to
unhashed and in-lookup ones, which is what ->atomic_open() needs and
removes the reason filesystems d_drop() first. d_alloc_trylock() is a
non-blocking d_alloc_parallel() for the filesystems that prime the
dcache from readdir, smb, nfs, fuse and ceph, where waiting for a
concurrent lookup is pointless. d_duplicate() creates an in-lookup
dentry with the name of an existing one for silly-rename and
whiteouts. LOOKUP_SHARED tells ->lookup() how the parent is locked so
it can drop and retake it. DCACHE_PAR_LOOKUP is tracked by lockdep now
with a per filesystem type key, and overlayfs gets its own class since
it stacks over itself. And a d_flags bit is reserved for filesystem
private use.
Also included is Mateusz's fix for the spurious dentry reference cycle
on open. __legitimize_path() grabs a reference, do_dentry_open() grabs
another and terminate_walk() drops the first. do_dentry_open()
consumes the held reference now. Opening the same file read-only on a
20-core VM goes from 4,043,375 to 5,629,378 ops/s in will-it-scale"
* tag 'vfs-7.4-rc1.lookup' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs:
VFS: d_duplicate: repair comments to avoid kernel-doc warnings
ovl: provide private lockdep class for dentry->dep_map
VFS: rename lookup_map to dep_map
VFS: per-fs-type lockdep key for dentry in-lookup locking
VFS: reserve a d_flags bit for fs-specific usage
VFS: add lockdep monitoring of DCACHE_PAR_LOOKUP lock.
VFS: Add LOOKUP_SHARED flag.
VFS: add d_duplicate()
VFS: introduce d_alloc_trylock()
VFS: enhance d_splice_alias() to handle hashed dentries
VFS: fix various typos in documentation for start_creating start_removing etc
fs: avoid spurious dentry ref/unref cycle on open
Diffstat (limited to 'include/linux')
| -rw-r--r-- | include/linux/dcache.h | 38 | ||||
| -rw-r--r-- | include/linux/fs.h | 2 | ||||
| -rw-r--r-- | include/linux/namei.h | 3 |
3 files changed, 41 insertions, 2 deletions
diff --git a/include/linux/dcache.h b/include/linux/dcache.h index 4b1ff99608e0..796282817181 100644 --- a/include/linux/dcache.h +++ b/include/linux/dcache.h @@ -116,6 +116,8 @@ struct dentry { * possible! */ + /* lockdep tracking of DCACHE_PAR_LOOKUP locks */ + struct lockdep_map dep_map; struct list_head d_lru; /* LRU list */ struct hlist_node d_sib; /* child of parent list */ struct hlist_head d_children; /* our children */ @@ -236,7 +238,9 @@ enum dentry_flags { DCACHE_PAR_LOOKUP = BIT(24), /* being looked up (with parent locked shared) */ DCACHE_DENTRY_CURSOR = BIT(25), DCACHE_NORCU = BIT(26), /* No RCU delay for freeing */ - DCACHE_PERSISTENT = BIT(27) + DCACHE_PERSISTENT = BIT(27), +/* 28, 29, 30 free */ + DCACHE_PRIVATE = BIT(31) /* fs-specific flag */ }; #define DCACHE_MANAGED_DENTRY \ @@ -257,7 +261,9 @@ extern void d_delete(struct dentry *); extern struct dentry * d_alloc(struct dentry *, const struct qstr *); extern struct dentry * d_alloc_anon(struct super_block *); extern struct dentry * d_alloc_parallel(struct dentry *, const struct qstr *); +extern struct dentry * d_alloc_trylock(struct dentry *, struct qstr *); extern struct dentry * d_splice_alias(struct inode *, struct dentry *); +struct dentry *d_duplicate(struct dentry *dentry); /* weird procfs mess; *NOT* exported */ extern struct dentry * d_splice_alias_ops(struct inode *, struct dentry *, const struct dentry_operations *); @@ -553,6 +559,36 @@ static inline int simple_positive(const struct dentry *dentry) unsigned long vfs_pressure_ratio(unsigned long val); /** + * d_lookup_release - release ownership of DCACHE_PAR_LOOKUP lock + * @dentry: dentry that is locked + * + * If an in-lookup dentry is to be passed to another thread which + * will drop the in-lookup lock, then d_lookup_release() must be called + * to tell lockdep that this thread no lock holds the lock. The + * thread that receives the lock must call d_lookup_acquire() to + * acquire the lock. + */ +static inline void d_lookup_release(struct dentry *dentry) +{ + if (d_in_lookup(dentry)) + lock_map_release(&dentry->dep_map); +} + +/** + * d_lookup_acquire - acquire ownership of DCACHE_PAR_LOOKUP lock + * @dentry: dentry that is locked + * + * If an in-lookup dentry was passed to this thread, the + * d_lookup_acquire() must be called to tell lockdep that this + * thread now owns the DCACHE_PAR_LOOKUP lock. + */ +static inline void d_lookup_acquire(struct dentry *dentry) +{ + if (d_in_lookup(dentry)) + lock_map_acquire_try(&dentry->dep_map); +} + +/** * d_inode - Get the actual inode of this dentry * @dentry: The dentry to query * diff --git a/include/linux/fs.h b/include/linux/fs.h index d17e9d42d67b..1b8ee5d11ee0 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -2316,6 +2316,8 @@ struct file_system_type { struct lock_class_key i_mutex_key; struct lock_class_key invalidate_lock_key; struct lock_class_key i_mutex_dir_key; + + struct lock_class_key d_lookup_key; }; #define MODULE_ALIAS_FS(NAME) MODULE_ALIAS("fs-" NAME) diff --git a/include/linux/namei.h b/include/linux/namei.h index da5b4ccca1b5..c4436e5c2ba6 100644 --- a/include/linux/namei.h +++ b/include/linux/namei.h @@ -32,8 +32,9 @@ enum { MAX_NESTED_LINKS = 8 }; #define LOOKUP_CREATE BIT(17) /* ... in object creation */ #define LOOKUP_EXCL BIT(18) /* ... in target must not exist */ #define LOOKUP_RENAME_TARGET BIT(19) /* ... in destination of rename() */ +#define LOOKUP_SHARED BIT(20) /* Parent lock is held shared */ -/* 4 spare bits for intent */ +/* 3 spare bits for intent */ /* Scoping flags for lookup. */ #define LOOKUP_NO_SYMLINKS BIT(24) /* No symlink crossing. */ |
