diff mbox series

[v2,6/6] kernfs: make attr_mutex a local kernfs node lock

Message ID 159237949356.89469.1012120560805135591.stgit@mickey.themaw.net (mailing list archive)
State New, archived
Headers show
Series kernfs: proposed locking and concurrency improvement | expand

Commit Message

Ian Kent June 17, 2020, 7:38 a.m. UTC
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@themaw.net>
---
 fs/kernfs/dir.c        |    1 +
 fs/kernfs/inode.c      |   12 ++++++------
 include/linux/kernfs.h |    2 ++
 3 files changed, 9 insertions(+), 6 deletions(-)
diff mbox series

Patch

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 {