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: 14+ 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-05-08 9:38 ` Tzung-Bi Shih
2026-05-08 11:54 ` Jason Gunthorpe
2026-05-09 9:40 ` Tzung-Bi Shih
2026-05-09 16:32 ` 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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.