[PATCH v8 07/10] kernfs: Change kernfs_rename_lock into a read-write lock.

From: Imran Khan
Date: Sat Apr 09 2022 - 22:38:21 EST


kernfs_rename_lock protects a node's ->parent and ->name and its current users
can be easily divided into readers or writers of ->parent and ->name.
kernfs_rename_lock also protects a static buffer (kernfs_pr_cont_buf) which
is used to hold read attributes (name, path etc.) of a kernfs_node and we
can maintain this functionality by accessing this buffer under write_lock.
So change kernfs_rename_lock into a read-write lock for better scalability.

Suggested by: Al Viro <viro@xxxxxxxxxxxxxxxxxx>
Signed-off-by: Imran Khan <imran.f.khan@xxxxxxxxxx>
---
fs/kernfs/dir.c | 32 ++++++++++++++++----------------
1 file changed, 16 insertions(+), 16 deletions(-)

diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c
index 17b438498c0b..8e8c8b2c350d 100644
--- a/fs/kernfs/dir.c
+++ b/fs/kernfs/dir.c
@@ -17,7 +17,7 @@

#include "kernfs-internal.h"

-static DEFINE_SPINLOCK(kernfs_rename_lock); /* kn->parent and ->name */
+static DEFINE_RWLOCK(kernfs_rename_lock); /* kn->parent and ->name */
static char kernfs_pr_cont_buf[PATH_MAX]; /* protected by rename_lock */
static DEFINE_SPINLOCK(kernfs_idr_lock); /* root->ino_idr */

@@ -184,9 +184,9 @@ int kernfs_name(struct kernfs_node *kn, char *buf, size_t buflen)
unsigned long flags;
int ret;

- spin_lock_irqsave(&kernfs_rename_lock, flags);
+ read_lock_irqsave(&kernfs_rename_lock, flags);
ret = kernfs_name_locked(kn, buf, buflen);
- spin_unlock_irqrestore(&kernfs_rename_lock, flags);
+ read_unlock_irqrestore(&kernfs_rename_lock, flags);
return ret;
}

@@ -212,9 +212,9 @@ int kernfs_path_from_node(struct kernfs_node *to, struct kernfs_node *from,
unsigned long flags;
int ret;

- spin_lock_irqsave(&kernfs_rename_lock, flags);
+ read_lock_irqsave(&kernfs_rename_lock, flags);
ret = kernfs_path_from_node_locked(to, from, buf, buflen);
- spin_unlock_irqrestore(&kernfs_rename_lock, flags);
+ read_unlock_irqrestore(&kernfs_rename_lock, flags);
return ret;
}
EXPORT_SYMBOL_GPL(kernfs_path_from_node);
@@ -229,12 +229,12 @@ void pr_cont_kernfs_name(struct kernfs_node *kn)
{
unsigned long flags;

- spin_lock_irqsave(&kernfs_rename_lock, flags);
+ write_lock_irqsave(&kernfs_rename_lock, flags);

kernfs_name_locked(kn, kernfs_pr_cont_buf, sizeof(kernfs_pr_cont_buf));
pr_cont("%s", kernfs_pr_cont_buf);

- spin_unlock_irqrestore(&kernfs_rename_lock, flags);
+ write_unlock_irqrestore(&kernfs_rename_lock, flags);
}

/**
@@ -248,7 +248,7 @@ void pr_cont_kernfs_path(struct kernfs_node *kn)
unsigned long flags;
int sz;

- spin_lock_irqsave(&kernfs_rename_lock, flags);
+ write_lock_irqsave(&kernfs_rename_lock, flags);

sz = kernfs_path_from_node_locked(kn, NULL, kernfs_pr_cont_buf,
sizeof(kernfs_pr_cont_buf));
@@ -265,7 +265,7 @@ void pr_cont_kernfs_path(struct kernfs_node *kn)
pr_cont("%s", kernfs_pr_cont_buf);

out:
- spin_unlock_irqrestore(&kernfs_rename_lock, flags);
+ write_unlock_irqrestore(&kernfs_rename_lock, flags);
}

/**
@@ -280,10 +280,10 @@ struct kernfs_node *kernfs_get_parent(struct kernfs_node *kn)
struct kernfs_node *parent;
unsigned long flags;

- spin_lock_irqsave(&kernfs_rename_lock, flags);
+ read_lock_irqsave(&kernfs_rename_lock, flags);
parent = kn->parent;
kernfs_get(parent);
- spin_unlock_irqrestore(&kernfs_rename_lock, flags);
+ read_unlock_irqrestore(&kernfs_rename_lock, flags);

return parent;
}
@@ -824,12 +824,12 @@ static struct kernfs_node *kernfs_walk_ns(struct kernfs_node *parent,
lockdep_assert_held_read(&kernfs_root(parent)->kernfs_rwsem);

/* grab kernfs_rename_lock to piggy back on kernfs_pr_cont_buf */
- spin_lock_irq(&kernfs_rename_lock);
+ write_lock_irq(&kernfs_rename_lock);

len = strlcpy(kernfs_pr_cont_buf, path, sizeof(kernfs_pr_cont_buf));

if (len >= sizeof(kernfs_pr_cont_buf)) {
- spin_unlock_irq(&kernfs_rename_lock);
+ write_unlock_irq(&kernfs_rename_lock);
return NULL;
}

@@ -841,7 +841,7 @@ static struct kernfs_node *kernfs_walk_ns(struct kernfs_node *parent,
parent = kernfs_find_ns(parent, name, ns);
}

- spin_unlock_irq(&kernfs_rename_lock);
+ write_unlock_irq(&kernfs_rename_lock);

return parent;
}
@@ -1635,7 +1635,7 @@ int kernfs_rename_ns(struct kernfs_node *kn, struct kernfs_node *new_parent,
kernfs_get(new_parent);

/* rename_lock protects ->parent and ->name accessors */
- spin_lock_irq(&kernfs_rename_lock);
+ write_lock_irq(&kernfs_rename_lock);

old_parent = kn->parent;
kn->parent = new_parent;
@@ -1646,7 +1646,7 @@ int kernfs_rename_ns(struct kernfs_node *kn, struct kernfs_node *new_parent,
kn->name = new_name;
}

- spin_unlock_irq(&kernfs_rename_lock);
+ write_unlock_irq(&kernfs_rename_lock);

kn->hash = kernfs_name_hash(kn->name, kn->ns);
kernfs_link_sibling(kn);
--
2.30.2