@@ -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);
@@ -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);
@@ -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 {
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(-)