[PATCH RESEND v4 3/4] kernfs: Introduce interface to access global kernfs_open_file_mutex.
From: Imran Khan
Date: Thu Jun 02 2022 - 02:40:06 EST
This allows to change underlying mutex locking, without needing to change
the users of the lock. For example next patch modifies this interface to
use hashed mutexes in place of a single global kernfs_open_file_mutex.
Signed-off-by: Imran Khan <imran.f.khan@xxxxxxxxxx>
Acked-by: Tejun Heo <tj@xxxxxxxxxx>
---
fs/kernfs/file.c | 72 +++++++++++++++++++++++++++++++-----------------
1 file changed, 46 insertions(+), 26 deletions(-)
diff --git a/fs/kernfs/file.c b/fs/kernfs/file.c
index b21c8e3b6a8d..d35d01d30fa0 100644
--- a/fs/kernfs/file.c
+++ b/fs/kernfs/file.c
@@ -49,6 +49,22 @@ struct kernfs_open_node {
static LLIST_HEAD(kernfs_notify_list);
+static inline struct mutex *kernfs_open_file_mutex_ptr(struct kernfs_node *kn)
+{
+ return &kernfs_open_file_mutex;
+}
+
+static inline struct mutex *kernfs_open_file_mutex_lock(struct kernfs_node *kn)
+{
+ struct mutex *lock;
+
+ lock = kernfs_open_file_mutex_ptr(kn);
+
+ mutex_lock(lock);
+
+ return lock;
+}
+
/**
* kernfs_deref_open_node - Get kernfs_open_node corresponding to @kn.
*
@@ -80,21 +96,21 @@ kernfs_deref_open_node(struct kernfs_open_file *of, struct kernfs_node *kn)
* @kn: target kernfs_node.
*
* Fetch and return ->attr.open of @kn when caller(writer) holds
- * kernfs_open_file_mutex.
+ * kernfs_open_file_mutex_ptr(kn).
*
- * Update of ->attr.open happens under kernfs_open_file_mutex. So as long as
- * the current updater (caller) is holding this mutex, other updaters will not
- * be able to change ->attr.open and this means that we can safely deref
- * ->attr.open outside RCU read-side critical section.
+ * Update of ->attr.open happens under kernfs_open_file_mutex_ptr(kn). So as
+ * long as the current updater (caller) is holding this mutex, other updaters
+ * will not be able to change ->attr.open and this means that we can safely
+ * deref ->attr.open outside RCU read-side critical section.
*
* This should ONLY be used by updaters of ->attr.open and caller needs to make
- * sure that kernfs_open_file_mutex is held.
+ * sure that kernfs_open_file_mutex_ptr(kn) is held.
*/
static struct kernfs_open_node *
kernfs_deref_open_node_protected(struct kernfs_node *kn)
{
return rcu_dereference_protected(kn->attr.open,
- lockdep_is_held(&kernfs_open_file_mutex));
+ lockdep_is_held(kernfs_open_file_mutex_ptr(kn)));
}
/**
@@ -103,21 +119,21 @@ kernfs_deref_open_node_protected(struct kernfs_node *kn)
* @kn: target kernfs_node.
*
* Fetch and return ->attr.open of @kn when caller(reader) holds
- * kernfs_open_file_mutex.
+ * kernfs_open_file_mutex_ptr(kn).
*
- * Update of ->attr.open happens under kernfs_open_file_mutex. So as long as
- * the current reader (caller) is holding this mutex, updaters will not be
- * able to change ->attr.open and this means that we can safely deref
+ * Update of ->attr.open happens under kernfs_open_file_mutex_ptr(kn). So as
+ * long as the current reader (caller) is holding this mutex, updaters will
+ * not be able to change ->attr.open and this means that we can safely deref
* ->attr.open outside RCU read-side critical section.
*
* This should ONLY be used by readers of ->attr.open and caller needs to make
- * sure that kernfs_open_file_mutex is held.
+ * sure that kernfs_open_file_mutex_ptr(kn) is held.
*/
static struct kernfs_open_node *
kernfs_check_open_node_protected(struct kernfs_node *kn)
{
return rcu_dereference_check(kn->attr.open,
- lockdep_is_held(&kernfs_open_file_mutex));
+ lockdep_is_held(kernfs_open_file_mutex_ptr(kn)));
}
static struct kernfs_open_file *kernfs_of(struct file *file)
@@ -600,19 +616,20 @@ static int kernfs_get_open_node(struct kernfs_node *kn,
struct kernfs_open_file *of)
{
struct kernfs_open_node *on, *new_on = NULL;
+ struct mutex *mutex = NULL;
- mutex_lock(&kernfs_open_file_mutex);
+ mutex = kernfs_open_file_mutex_lock(kn);
on = kernfs_deref_open_node_protected(kn);
if (on) {
list_add_tail(&of->list, &on->files);
- mutex_unlock(&kernfs_open_file_mutex);
+ mutex_unlock(mutex);
return 0;
} else {
/* not there, initialize a new one */
new_on = kmalloc(sizeof(*new_on), GFP_KERNEL);
if (!new_on) {
- mutex_unlock(&kernfs_open_file_mutex);
+ mutex_unlock(mutex);
return -ENOMEM;
}
atomic_set(&new_on->event, 1);
@@ -621,7 +638,7 @@ static int kernfs_get_open_node(struct kernfs_node *kn,
list_add_tail(&of->list, &new_on->files);
rcu_assign_pointer(kn->attr.open, new_on);
}
- mutex_unlock(&kernfs_open_file_mutex);
+ mutex_unlock(mutex);
return 0;
}
@@ -643,12 +660,13 @@ static void kernfs_unlink_open_file(struct kernfs_node *kn,
struct kernfs_open_file *of)
{
struct kernfs_open_node *on;
+ struct mutex *mutex = NULL;
- mutex_lock(&kernfs_open_file_mutex);
+ mutex = kernfs_open_file_mutex_lock(kn);
on = kernfs_deref_open_node_protected(kn);
if (!on) {
- mutex_unlock(&kernfs_open_file_mutex);
+ mutex_unlock(mutex);
return;
}
@@ -660,7 +678,7 @@ static void kernfs_unlink_open_file(struct kernfs_node *kn,
kfree_rcu(on, rcu_head);
}
- mutex_unlock(&kernfs_open_file_mutex);
+ mutex_unlock(mutex);
}
static int kernfs_fop_open(struct inode *inode, struct file *file)
@@ -802,7 +820,7 @@ static void kernfs_release_file(struct kernfs_node *kn,
* here because drain path may be called from places which can
* cause circular dependency.
*/
- lockdep_assert_held(&kernfs_open_file_mutex);
+ lockdep_assert_held(kernfs_open_file_mutex_ptr(kn));
if (!of->released) {
/*
@@ -819,11 +837,12 @@ static int kernfs_fop_release(struct inode *inode, struct file *filp)
{
struct kernfs_node *kn = inode->i_private;
struct kernfs_open_file *of = kernfs_of(filp);
+ struct mutex *mutex = NULL;
if (kn->flags & KERNFS_HAS_RELEASE) {
- mutex_lock(&kernfs_open_file_mutex);
+ mutex = kernfs_open_file_mutex_lock(kn);
kernfs_release_file(kn, of);
- mutex_unlock(&kernfs_open_file_mutex);
+ mutex_unlock(mutex);
}
kernfs_unlink_open_file(kn, of);
@@ -838,6 +857,7 @@ void kernfs_drain_open_files(struct kernfs_node *kn)
{
struct kernfs_open_node *on;
struct kernfs_open_file *of;
+ struct mutex *mutex = NULL;
if (!(kn->flags & (KERNFS_HAS_MMAP | KERNFS_HAS_RELEASE)))
return;
@@ -853,10 +873,10 @@ void kernfs_drain_open_files(struct kernfs_node *kn)
if (!rcu_access_pointer(kn->attr.open))
return;
- mutex_lock(&kernfs_open_file_mutex);
+ mutex = kernfs_open_file_mutex_lock(kn);
on = kernfs_check_open_node_protected(kn);
if (!on) {
- mutex_unlock(&kernfs_open_file_mutex);
+ mutex_unlock(mutex);
return;
}
@@ -870,7 +890,7 @@ void kernfs_drain_open_files(struct kernfs_node *kn)
kernfs_release_file(kn, of);
}
- mutex_unlock(&kernfs_open_file_mutex);
+ mutex_unlock(mutex);
}
/*
--
2.30.2