From: Tzung-Bi Shih <tzungbi@kernel.org>
To: Arnd Bergmann <arnd@arndb.de>,
Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Benson Leung <bleung@chromium.org>,
tzungbi@kernel.org, linux-kernel@vger.kernel.org,
chrome-platform@lists.linux.dev,
"Rafael J. Wysocki" <rafael@kernel.org>,
Danilo Krummrich <dakr@kernel.org>,
Jonathan Corbet <corbet@lwn.net>, Shuah Khan <shuah@kernel.org>,
Laurent Pinchart <laurent.pinchart@ideasonboard.com>,
Wolfram Sang <wsa+renesas@sang-engineering.com>,
Jason Gunthorpe <jgg@nvidia.com>, Johan Hovold <johan@kernel.org>,
"Paul E . McKenney" <paulmck@kernel.org>,
Dan Williams <dan.j.williams@intel.com>
Subject: [PATCH 4/8] char: misc: Use SRCU to protect list traversal
Date: Mon, 27 Apr 2026 21:46:55 +0800 [thread overview]
Message-ID: <20260427134659.95181-5-tzungbi@kernel.org> (raw)
In-Reply-To: <20260427134659.95181-1-tzungbi@kernel.org>
Replace the global mutex with SRCU to protect list traversal in the
file operations. This allows concurrent file operations on misc devices
without contending for a global lock.
Writers (registration and deregistration) continue to be serialized
by a mutex when modifying the lists.
Signed-off-by: Tzung-Bi Shih <tzungbi@kernel.org>
---
drivers/char/misc.c | 84 ++++++++++++++++++++++++++-------------------
1 file changed, 48 insertions(+), 36 deletions(-)
diff --git a/drivers/char/misc.c b/drivers/char/misc.c
index 87f47bdc7afb..8514287b8ff9 100644
--- a/drivers/char/misc.c
+++ b/drivers/char/misc.c
@@ -45,6 +45,7 @@
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
+#include <linux/srcu.h>
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/device.h>
@@ -58,6 +59,7 @@
static LIST_HEAD(misc_list);
static LIST_HEAD(misc_sync_ctx_list);
static DEFINE_MUTEX(misc_mtx);
+DEFINE_STATIC_SRCU(misc_srcu);
/*
* Assigned numbers.
@@ -86,23 +88,23 @@ static void misc_minor_free(int minor)
#ifdef CONFIG_PROC_FS
static void *misc_seq_start(struct seq_file *seq, loff_t *pos)
{
- mutex_lock(&misc_mtx);
- return seq_list_start(&misc_list, *pos);
+ seq->private = (void *)(long)srcu_read_lock(&misc_srcu);
+ return seq_list_start_rcu(&misc_list, *pos);
}
static void *misc_seq_next(struct seq_file *seq, void *v, loff_t *pos)
{
- return seq_list_next(v, &misc_list, pos);
+ return seq_list_next_rcu(v, &misc_list, pos);
}
static void misc_seq_stop(struct seq_file *seq, void *v)
{
- mutex_unlock(&misc_mtx);
+ srcu_read_unlock(&misc_srcu, (int)(long)seq->private);
}
static int misc_seq_show(struct seq_file *seq, void *v)
{
- const struct miscdevice *p = list_entry(v, struct miscdevice, list);
+ const struct miscdevice *p = list_entry_rcu(v, struct miscdevice, list);
seq_printf(seq, "%3i %s\n", p->minor, p->name ? p->name : "");
return 0;
@@ -121,9 +123,8 @@ static struct miscdevice *misc_find(int minor)
{
struct miscdevice *iter;
- lockdep_assert_held(&misc_mtx);
-
- list_for_each_entry(iter, &misc_list, list) {
+ list_for_each_entry_srcu(iter, &misc_list, list,
+ srcu_read_lock_held(&misc_srcu)) {
if (iter->minor == minor)
return iter;
}
@@ -136,7 +137,7 @@ static struct miscdevice *misc_find(int minor)
{ \
struct miscdevice *c; \
\
- guard(mutex)(&misc_mtx); \
+ guard(srcu)(&misc_srcu); \
\
c = misc_find(iminor(filp->f_inode)); \
if (!c) \
@@ -160,7 +161,9 @@ static void misc_sync_ctx_release(struct kref *kref)
struct miscdevice_sync_ctx *ctx = container_of(kref, typeof(*ctx), kref);
misc_minor_free(ctx->minor);
- list_del(&ctx->list);
+ scoped_guard(mutex, &misc_mtx)
+ list_del_rcu(&ctx->list);
+ synchronize_srcu(&misc_srcu);
kfree(ctx);
}
@@ -170,23 +173,24 @@ static int misc_sync_release(struct inode *inode, struct file *filp)
struct miscdevice *c;
struct miscdevice_sync_ctx *iter, *ctx = NULL;
- guard(mutex)(&misc_mtx);
-
- c = misc_find(minor);
- if (c) {
- /* The miscdevice is still registered. */
- ctx = c->sync_ctx;
- } else {
- /* The miscdeivce is unregistered. Search in the list. */
- list_for_each_entry(iter, &misc_sync_ctx_list, list) {
- if (iter->minor == minor) {
- ctx = iter;
- break;
+ scoped_guard(srcu, &misc_srcu) {
+ c = misc_find(minor);
+ if (c) {
+ /* The miscdevice is still registered. */
+ ctx = c->sync_ctx;
+ } else {
+ /* The miscdeivce is unregistered. Search in the list. */
+ list_for_each_entry_srcu(iter, &misc_sync_ctx_list,
+ list, srcu_read_lock_held(&misc_srcu)) {
+ if (iter->minor == minor) {
+ ctx = iter;
+ break;
+ }
+ }
+ if (!ctx) {
+ pr_err("Cannot find miscdevice_sync_ctx\n");
+ return -ENOENT;
}
- }
- if (!ctx) {
- pr_err("Cannot find miscdevice_sync_ctx\n");
- return -ENOENT;
}
}
@@ -206,8 +210,9 @@ static int misc_open(struct inode *inode, struct file *file)
struct miscdevice *c = NULL;
int err = -ENODEV;
const struct file_operations *new_fops = NULL;
+ int idx;
- mutex_lock(&misc_mtx);
+ idx = srcu_read_lock(&misc_srcu);
c = misc_find(minor);
if (c)
@@ -215,9 +220,9 @@ static int misc_open(struct inode *inode, struct file *file)
/* Only request module for fixed minor code */
if (!new_fops && minor < MISC_DYNAMIC_MINOR) {
- mutex_unlock(&misc_mtx);
+ srcu_read_unlock(&misc_srcu, idx);
request_module("char-major-%d-%d", MISC_MAJOR, minor);
- mutex_lock(&misc_mtx);
+ idx = srcu_read_lock(&misc_srcu);
c = misc_find(minor);
if (c)
@@ -243,7 +248,7 @@ static int misc_open(struct inode *inode, struct file *file)
if (file->f_op->open)
err = file->f_op->open(inode, file);
fail:
- mutex_unlock(&misc_mtx);
+ srcu_read_unlock(&misc_srcu, idx);
return err;
}
@@ -311,8 +316,10 @@ int misc_register(struct miscdevice *misc)
} else {
int i;
- if (misc_find(misc->minor))
- return -EBUSY;
+ scoped_guard(srcu, &misc_srcu) {
+ if (misc_find(misc->minor))
+ return -EBUSY;
+ }
i = misc_minor_alloc(misc->minor);
if (i < 0)
@@ -336,7 +343,7 @@ int misc_register(struct miscdevice *misc)
* Add it to the front, so that later devices can "override"
* earlier defaults
*/
- list_add(&misc->list, &misc_list);
+ list_add_rcu(&misc->list, &misc_list);
return 0;
}
EXPORT_SYMBOL(misc_register);
@@ -351,15 +358,20 @@ EXPORT_SYMBOL(misc_register);
void misc_deregister(struct miscdevice *misc)
{
- guard(mutex)(&misc_mtx);
- list_del_init(&misc->list);
+ scoped_guard(mutex, &misc_mtx)
+ list_del_rcu(&misc->list);
+ synchronize_srcu(&misc_srcu);
+ INIT_LIST_HEAD(&misc->list);
+
device_destroy(&misc_class, MKDEV(MISC_MAJOR, misc->minor));
/* Defer to free the minor number for sync fops */
if (!misc->sync_ctx) {
misc_minor_free(misc->minor);
} else {
- list_add(&misc->sync_ctx->list, &misc_sync_ctx_list);
+ scoped_guard(mutex, &misc_mtx)
+ list_add_rcu(&misc->sync_ctx->list,
+ &misc_sync_ctx_list);
kref_put(&misc->sync_ctx->kref, misc_sync_ctx_release);
}
--
2.51.0
next prev parent reply other threads:[~2026-04-27 13:47 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-04-27 13:46 [PATCH 0/8] char: misc: Introduce misc_sync to fix UAF Tzung-Bi Shih
2026-04-27 13:46 ` [PATCH 1/8] char: misc: Simplify locking with guard() Tzung-Bi Shih
2026-04-27 13:46 ` [PATCH 2/8] char: misc: Introduce misc_find() helper Tzung-Bi Shih
2026-04-27 13:46 ` [PATCH 3/8] char: misc: Introduce misc_sync_register() Tzung-Bi Shih
2026-04-28 16:09 ` Jason Gunthorpe
2026-04-27 13:46 ` Tzung-Bi Shih [this message]
2026-04-27 13:46 ` [PATCH 5/8] platform/chrome: cros_ec_chardev: Introduce chardev_data Tzung-Bi Shih
2026-04-27 13:46 ` [PATCH 6/8] platform/chrome: cros_ec_chardev: Move data to chardev_pdata Tzung-Bi Shih
2026-04-27 13:46 ` [PATCH 7/8] platform/chrome: cros_ec_chardev: Add event relayer Tzung-Bi Shih
2026-04-27 13:46 ` [PATCH 8/8] platform/chrome: cros_ec_chardev: Use misc_sync_register() Tzung-Bi Shih
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260427134659.95181-5-tzungbi@kernel.org \
--to=tzungbi@kernel.org \
--cc=arnd@arndb.de \
--cc=bleung@chromium.org \
--cc=chrome-platform@lists.linux.dev \
--cc=corbet@lwn.net \
--cc=dakr@kernel.org \
--cc=dan.j.williams@intel.com \
--cc=gregkh@linuxfoundation.org \
--cc=jgg@nvidia.com \
--cc=johan@kernel.org \
--cc=laurent.pinchart@ideasonboard.com \
--cc=linux-kernel@vger.kernel.org \
--cc=paulmck@kernel.org \
--cc=rafael@kernel.org \
--cc=shuah@kernel.org \
--cc=wsa+renesas@sang-engineering.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox