summaryrefslogtreecommitdiffstats
path: root/fs/dcache.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2021-02-22 22:05:30 +0100
committerLinus Torvalds <torvalds@linux-foundation.org>2021-02-22 22:05:30 +0100
commit250a25e7a1d71da06213aa354ece44fb8faa73f7 (patch)
tree53bce39e79d1501eb275b5ad3ff780f009894db1 /fs/dcache.c
parentMerge branch 'work.d_name' of git://git.kernel.org/pub/scm/linux/kernel/git/v... (diff)
parentmake dump_common_audit_data() safe to be called from RCU pathwalk (diff)
downloadlinux-250a25e7a1d71da06213aa354ece44fb8faa73f7.tar.xz
linux-250a25e7a1d71da06213aa354ece44fb8faa73f7.zip
Merge branch 'work.audit' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
Pull RCU-safe common_lsm_audit() from Al Viro: "Make common_lsm_audit() non-blocking and usable from RCU pathwalk context. We don't really need to grab/drop dentry in there - rcu_read_lock() is enough. There's a couple of followups using that to simplify the logics in selinux, but those hadn't soaked in -next yet, so they'll have to go in next window" * 'work.audit' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: make dump_common_audit_data() safe to be called from RCU pathwalk new helper: d_find_alias_rcu()
Diffstat (limited to 'fs/dcache.c')
-rw-r--r--fs/dcache.c25
1 files changed, 25 insertions, 0 deletions
diff --git a/fs/dcache.c b/fs/dcache.c
index c17fd15b01d4..799d9e4f0bcd 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -1044,6 +1044,31 @@ struct dentry *d_find_alias(struct inode *inode)
EXPORT_SYMBOL(d_find_alias);
/*
+ * Caller MUST be holding rcu_read_lock() and be guaranteed
+ * that inode won't get freed until rcu_read_unlock().
+ */
+struct dentry *d_find_alias_rcu(struct inode *inode)
+{
+ struct hlist_head *l = &inode->i_dentry;
+ struct dentry *de = NULL;
+
+ spin_lock(&inode->i_lock);
+ // ->i_dentry and ->i_rcu are colocated, but the latter won't be
+ // used without having I_FREEING set, which means no aliases left
+ if (likely(!(inode->i_state & I_FREEING) && !hlist_empty(l))) {
+ if (S_ISDIR(inode->i_mode)) {
+ de = hlist_entry(l->first, struct dentry, d_u.d_alias);
+ } else {
+ hlist_for_each_entry(de, l, d_u.d_alias)
+ if (!d_unhashed(de))
+ break;
+ }
+ }
+ spin_unlock(&inode->i_lock);
+ return de;
+}
+
+/*
* Try to kill dentries associated with this inode.
* WARNING: you must own a reference to inode.
*/