summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIan Kent <raven@themaw.net>2021-10-04 09:03:53 +0800
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2021-10-04 10:27:18 +0200
commit410d591a19543f1347bc2b4b4ec3399cb548ba47 (patch)
tree86b13e3566df266dffd4c18610d68bde4e90b5e3
parent9e1ff307c779ce1f0f810c7ecce3d95bbae40896 (diff)
downloadlwn-410d591a19543f1347bc2b4b4ec3399cb548ba47.tar.gz
lwn-410d591a19543f1347bc2b4b4ec3399cb548ba47.zip
kernfs: don't create a negative dentry if inactive node exists
It's been reported that doing stress test for module insertion and removal can result in an ENOENT from libkmod for a valid module. In kernfs_iop_lookup() a negative dentry is created if there's no kernfs node associated with the dentry or the node is inactive. But inactive kernfs nodes are meant to be invisible to the VFS and creating a negative dentry for these can have unexpected side effects when the node transitions to an active state. The point of creating negative dentries is to avoid the expensive alloc/free cycle that occurs if there are frequent lookups for kernfs attributes that don't exist. So kernfs nodes that are not yet active should not result in a negative dentry being created so when they transition to an active state VFS lookups can create an associated dentry is a natural way. It's also been reported that https://github.com/osandov/blktests.git test block/001 hangs during the test. It was suggested that recent changes to blktests might have caused it but applying this patch resolved the problem without change to blktests. Fixes: c7e7c04274b1 ("kernfs: use VFS negative dentry caching") Tested-by: Yi Zhang <yi.zhang@redhat.com> ACKed-by: Al Viro <viro@zeniv.linux.org.uk> Signed-off-by: Ian Kent <raven@themaw.net> Link: https://lore.kernel.org/r/163330943316.19450.15056895533949392922.stgit@mickey.themaw.net Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--fs/kernfs/dir.c9
1 files changed, 8 insertions, 1 deletions
diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c
index cfc3ce8b815a..8e0a1378a4b1 100644
--- a/fs/kernfs/dir.c
+++ b/fs/kernfs/dir.c
@@ -1111,7 +1111,14 @@ static struct dentry *kernfs_iop_lookup(struct inode *dir,
kn = kernfs_find_ns(parent, dentry->d_name.name, ns);
/* attach dentry and inode */
- if (kn && kernfs_active(kn)) {
+ if (kn) {
+ /* Inactive nodes are invisible to the VFS so don't
+ * create a negative.
+ */
+ if (!kernfs_active(kn)) {
+ up_read(&kernfs_rwsem);
+ return NULL;
+ }
inode = kernfs_get_inode(dir->i_sb, kn);
if (!inode)
inode = ERR_PTR(-ENOMEM);