lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <159237949356.89469.1012120560805135591.stgit@mickey.themaw.net>
Date:   Wed, 17 Jun 2020 15:38:13 +0800
From:   Ian Kent <raven@...maw.net>
To:     Greg Kroah-Hartman <gregkh@...uxfoundation.org>
Cc:     Tejun Heo <tj@...nel.org>, Stephen Rothwell <sfr@...b.auug.org.au>,
        Andrew Morton <akpm@...ux-foundation.org>,
        Al Viro <viro@...IV.linux.org.uk>,
        Rick Lindsley <ricklind@...ux.vnet.ibm.com>,
        David Howells <dhowells@...hat.com>,
        Miklos Szeredi <miklos@...redi.hu>,
        linux-fsdevel <linux-fsdevel@...r.kernel.org>,
        Kernel Mailing List <linux-kernel@...r.kernel.org>
Subject: [PATCH v2 6/6] kernfs: make attr_mutex a local kernfs node lock

The global mutex attr_mutex is used to protect the update of inode
attributes in kernfs_refresh_inode() (as well as kernfs node attribute
structure creation) and this function is called by the inode operation
.permission().

Since .permission() is called quite frequently during path walks it
can lead to contention when the number of concurrent path walks is
high.

This mutex is used for kernfs node objects only so make it local to
the kernfs node to reduce the impact of this type of contention.

Signed-off-by: Ian Kent <raven@...maw.net>
---
 fs/kernfs/dir.c        |    1 +
 fs/kernfs/inode.c      |   12 ++++++------
 include/linux/kernfs.h |    2 ++
 3 files changed, 9 insertions(+), 6 deletions(-)

diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c
index 03f4f179bbc4..3233e01651e4 100644
--- a/fs/kernfs/dir.c
+++ b/fs/kernfs/dir.c
@@ -597,6 +597,7 @@ static struct kernfs_node *__kernfs_new_node(struct kernfs_root *root,
 	kn = kmem_cache_zalloc(kernfs_node_cache, GFP_KERNEL);
 	if (!kn)
 		goto err_out1;
+	mutex_init(&kn->attr_mutex);
 
 	idr_preload(GFP_KERNEL);
 	spin_lock(&kernfs_idr_lock);
diff --git a/fs/kernfs/inode.c b/fs/kernfs/inode.c
index 5c3fac356ce0..5eb11094bb2e 100644
--- a/fs/kernfs/inode.c
+++ b/fs/kernfs/inode.c
@@ -36,7 +36,7 @@ static struct kernfs_iattrs *__kernfs_iattrs(struct kernfs_node *kn, int alloc)
 {
 	struct kernfs_iattrs *iattr = NULL;
 
-	mutex_lock(&attr_mutex);
+	mutex_lock(&kn->attr_mutex);
 	if (kn->iattr || !alloc) {
 		iattr = kn->iattr;
 		goto out_unlock;
@@ -59,7 +59,7 @@ static struct kernfs_iattrs *__kernfs_iattrs(struct kernfs_node *kn, int alloc)
 	atomic_set(&iattr->user_xattr_size, 0);
 	kn->iattr = iattr;
 out_unlock:
-	mutex_unlock(&attr_mutex);
+	mutex_unlock(&kn->attr_mutex);
 	return iattr;
 }
 
@@ -192,9 +192,9 @@ int kernfs_iop_getattr(const struct path *path, struct kstat *stat,
 	struct kernfs_node *kn = inode->i_private;
 
 	down_read(&kernfs_rwsem);
-	mutex_lock(&attr_mutex);
+	mutex_lock(&kn->attr_mutex);
 	kernfs_refresh_inode(kn, inode);
-	mutex_unlock(&attr_mutex);
+	mutex_unlock(&kn->attr_mutex);
 	up_read(&kernfs_rwsem);
 
 	generic_fillattr(inode, stat);
@@ -286,9 +286,9 @@ int kernfs_iop_permission(struct inode *inode, int mask)
 	kn = inode->i_private;
 
 	down_read(&kernfs_rwsem);
-	mutex_lock(&attr_mutex);
+	mutex_lock(&kn->attr_mutex);
 	kernfs_refresh_inode(kn, inode);
-	mutex_unlock(&attr_mutex);
+	mutex_unlock(&kn->attr_mutex);
 	up_read(&kernfs_rwsem);
 
 	return generic_permission(inode, mask);
diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h
index 74727d98e380..8669f65d5a39 100644
--- a/include/linux/kernfs.h
+++ b/include/linux/kernfs.h
@@ -142,6 +142,8 @@ struct kernfs_node {
 
 	struct rb_node		rb;
 
+	struct mutex		attr_mutex; /* protect attr updates */
+
 	const void		*ns;	/* namespace tag */
 	unsigned int		hash;	/* ns + name hash */
 	union {


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ