From: Al Viro Date: Sat, 24 Jan 2026 22:58:48 +0000 (-0500) Subject: for_each_alias(): helper macro for iterating through dentries of given inode X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=408d8af01f3a4d666620029a85e741906ff96f47;p=thirdparty%2Flinux.git for_each_alias(): helper macro for iterating through dentries of given inode Most of the places using d_alias are loops iterating through all aliases for given inode; introduce a helper macro (for_each_alias(dentry, inode)) and convert open-coded instances of such loop to it. They are easier to read that way and it reduces the noise on the next steps. You _must_ hold inode->i_lock over that thing. Signed-off-by: Al Viro --- diff --git a/Documentation/filesystems/porting.rst b/Documentation/filesystems/porting.rst index 52ff1d19405be..9a9babd9ec486 100644 --- a/Documentation/filesystems/porting.rst +++ b/Documentation/filesystems/porting.rst @@ -1361,3 +1361,13 @@ to match what strlen() would return if it was ran on the string. However, if the string is freely accessible for the duration of inode's lifetime, consider using inode_set_cached_link() instead. + +--- + +**recommended** + +If you really need to iterate through dentries for given inode, use +for_each_alias(dentry, inode) instead of hlist_for_each_entry; better +yet, see if any of the exported primitives could be used instead of +the entire loop. You still need to hold ->i_lock of the inode over +either form of manual loop. diff --git a/fs/affs/amigaffs.c b/fs/affs/amigaffs.c index fd669daa4e7bc..91966b1f41f64 100644 --- a/fs/affs/amigaffs.c +++ b/fs/affs/amigaffs.c @@ -126,7 +126,7 @@ affs_fix_dcache(struct inode *inode, u32 entry_ino) { struct dentry *dentry; spin_lock(&inode->i_lock); - hlist_for_each_entry(dentry, &inode->i_dentry, d_u.d_alias) { + for_each_alias(dentry, inode) { if (entry_ino == (u32)(long)dentry->d_fsdata) { dentry->d_fsdata = (void *)inode->i_ino; break; diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c index b1746273f1863..f839109fb66f2 100644 --- a/fs/ceph/mds_client.c +++ b/fs/ceph/mds_client.c @@ -4614,7 +4614,7 @@ static struct dentry* d_find_primary(struct inode *inode) goto out_unlock; } - hlist_for_each_entry(alias, &inode->i_dentry, d_u.d_alias) { + for_each_alias(alias, inode) { spin_lock(&alias->d_lock); if (!d_unhashed(alias) && (ceph_dentry(alias)->flags & CEPH_DENTRY_PRIMARY_LINK)) { diff --git a/fs/dcache.c b/fs/dcache.c index 7ba1801d81329..e069b6ec4ec04 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -790,7 +790,7 @@ void d_mark_dontcache(struct inode *inode) struct dentry *de; spin_lock(&inode->i_lock); - hlist_for_each_entry(de, &inode->i_dentry, d_u.d_alias) { + for_each_alias(de, inode) { spin_lock(&de->d_lock); de->d_flags |= DCACHE_DONTCACHE; spin_unlock(&de->d_lock); @@ -1040,7 +1040,7 @@ static struct dentry *__d_find_alias(struct inode *inode) if (S_ISDIR(inode->i_mode)) return __d_find_any_alias(inode); - hlist_for_each_entry(alias, &inode->i_dentry, d_u.d_alias) { + for_each_alias(alias, inode) { spin_lock(&alias->d_lock); if (!d_unhashed(alias)) { dget_dlock(alias); @@ -1133,7 +1133,7 @@ void d_prune_aliases(struct inode *inode) struct dentry *dentry; spin_lock(&inode->i_lock); - hlist_for_each_entry(dentry, &inode->i_dentry, d_u.d_alias) + for_each_alias(dentry, inode) d_dispose_if_unused(dentry, &dispose); spin_unlock(&inode->i_lock); shrink_dentry_list(&dispose); diff --git a/fs/exportfs/expfs.c b/fs/exportfs/expfs.c index 6c9be60a3e48d..f67b3ce672fcc 100644 --- a/fs/exportfs/expfs.c +++ b/fs/exportfs/expfs.c @@ -52,7 +52,7 @@ find_acceptable_alias(struct dentry *result, inode = result->d_inode; spin_lock(&inode->i_lock); - hlist_for_each_entry(dentry, &inode->i_dentry, d_u.d_alias) { + for_each_alias(dentry, inode) { dget(dentry); spin_unlock(&inode->i_lock); if (toput) diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index 2402f57c8e7d9..5a0bd8113e3a3 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -1471,7 +1471,7 @@ static void nfs_clear_verifier_file(struct inode *inode) struct dentry *alias; struct inode *dir; - hlist_for_each_entry(alias, &inode->i_dentry, d_u.d_alias) { + for_each_alias(alias, inode) { spin_lock(&alias->d_lock); dir = d_inode_rcu(alias->d_parent); if (!dir || diff --git a/fs/notify/fsnotify.c b/fs/notify/fsnotify.c index 9995de1710e59..b7198c4744e3a 100644 --- a/fs/notify/fsnotify.c +++ b/fs/notify/fsnotify.c @@ -76,7 +76,7 @@ void fsnotify_set_children_dentry_flags(struct inode *inode) spin_lock(&inode->i_lock); /* run all of the dentries associated with this inode. Since this is a * directory, there damn well better only be one item on this list */ - hlist_for_each_entry(alias, &inode->i_dentry, d_u.d_alias) { + for_each_alias(alias, inode) { struct dentry *child; /* run all of the children of the original inode and fix their diff --git a/fs/ocfs2/dcache.c b/fs/ocfs2/dcache.c index c4ba968e778bf..e06774fd89d82 100644 --- a/fs/ocfs2/dcache.c +++ b/fs/ocfs2/dcache.c @@ -145,7 +145,7 @@ struct dentry *ocfs2_find_local_alias(struct inode *inode, struct dentry *dentry; spin_lock(&inode->i_lock); - hlist_for_each_entry(dentry, &inode->i_dentry, d_u.d_alias) { + for_each_alias(dentry, inode) { spin_lock(&dentry->d_lock); if (ocfs2_match_dentry(dentry, parent_blkno, skip_unhashed)) { trace_ocfs2_find_local_alias(dentry->d_name.len, diff --git a/fs/overlayfs/dir.c b/fs/overlayfs/dir.c index ff3dbd1ca61f2..f8dfa534b5666 100644 --- a/fs/overlayfs/dir.c +++ b/fs/overlayfs/dir.c @@ -904,7 +904,7 @@ static void ovl_drop_nlink(struct dentry *dentry) /* Try to find another, hashed alias */ spin_lock(&inode->i_lock); - hlist_for_each_entry(alias, &inode->i_dentry, d_u.d_alias) { + for_each_alias(alias, inode) { if (alias != dentry && !d_unhashed(alias)) break; } diff --git a/fs/smb/client/inode.c b/fs/smb/client/inode.c index 888f9e35f14b8..e2b4ad9bd0bdb 100644 --- a/fs/smb/client/inode.c +++ b/fs/smb/client/inode.c @@ -1595,7 +1595,7 @@ inode_has_hashed_dentries(struct inode *inode) struct dentry *dentry; spin_lock(&inode->i_lock); - hlist_for_each_entry(dentry, &inode->i_dentry, d_u.d_alias) { + for_each_alias(dentry, inode) { if (!d_unhashed(dentry) || IS_ROOT(dentry)) { spin_unlock(&inode->i_lock); return true; diff --git a/include/linux/dcache.h b/include/linux/dcache.h index 898c60d21c92b..7f1dbc7121d7c 100644 --- a/include/linux/dcache.h +++ b/include/linux/dcache.h @@ -615,4 +615,8 @@ void set_default_d_op(struct super_block *, const struct dentry_operations *); struct dentry *d_make_persistent(struct dentry *, struct inode *); void d_make_discardable(struct dentry *dentry); +/* inode->i_lock must be held over that */ +#define for_each_alias(dentry, inode) \ + hlist_for_each_entry(dentry, &(inode)->i_dentry, d_u.d_alias) + #endif /* __LINUX_DCACHE_H */