From: Dmitry Torokhov <dmitry.torokhov@gmail.com>
To: "James E.J. Bottomley" <James.Bottomley@HansenPartnership.com>,
Helge Deller <deller@gmx.de>
Cc: linux-kernel@vger.kernel.org, linux-input@vger.kernel.org,
linux-parisc@vger.kernel.org, sashiko-bot@kernel.org
Subject: [PATCH 2/7] Input: gscps2 - use RCU for ps2port_list and manage it in open/close
Date: Sun, 30 Aug 2026 13:52:47 -0700 [thread overview]
Message-ID: <20260830-gscps2-v1-2-c733d4cae7f9@gmail.com> (raw)
In-Reply-To: <20260830-gscps2-v1-0-c733d4cae7f9@gmail.com>
Managing ps2port_list in gscps2_probe() and gscps2_remove() had two
issues:
- in gscps2_remove(), serio_unregister_port() frees the serio port, but
because the port remained in ps2port_list until later in remove, a
shared interrupt firing on another CPU could traverse ps2port_list and
dereference the freed serio port
- ps2port_list additions and deletions in probe/remove raced locklessly
against list traversals in gscps2_interrupt().
Convert ps2port_list traversal in gscps2_interrupt() to use RCU, and
move list management to gscps2_open() and gscps2_close(). When
serio_unregister_port() runs during device removal, serio_close() is
invoked, cleanly taking the port out of ps2port_list before the serio
structure is destroyed, while maintaining active hardware communication
during child driver disconnect.
Reported-by: sashiko-bot@kernel.org
Assisted-by: LLM
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
---
drivers/input/serio/gscps2.c | 23 ++++++++++++++++-------
1 file changed, 16 insertions(+), 7 deletions(-)
diff --git a/drivers/input/serio/gscps2.c b/drivers/input/serio/gscps2.c
index b82c56ba8ff7..5b6e311f8a02 100644
--- a/drivers/input/serio/gscps2.c
+++ b/drivers/input/serio/gscps2.c
@@ -26,6 +26,7 @@
#include <linux/io.h>
#include <linux/ioport.h>
#include <linux/property.h>
+#include <linux/rcupdate.h>
#include <linux/serio.h>
#include <asm/irq.h>
@@ -195,6 +196,7 @@ struct gscps2port {
int id;
};
+static DEFINE_SPINLOCK(ps2port_list_lock);
static LIST_HEAD(ps2port_list);
/*
@@ -292,14 +294,16 @@ static irqreturn_t gscps2_interrupt(int irq, void *dev)
{
struct gscps2port *ps2port;
- list_for_each_entry(ps2port, &ps2port_list, node) {
+ guard(rcu)();
+
+ list_for_each_entry_rcu(ps2port, &ps2port_list, node) {
guard(spinlock_irqsave)(&ps2port->lock);
gscps2_read_data(ps2port);
- } /* list_for_each_entry */
+ }
/* all data was read from the ports - now report the data to upper layer */
- list_for_each_entry(ps2port, &ps2port_list, node) {
+ list_for_each_entry_rcu(ps2port, &ps2port_list, node) {
if (gscps2_report_data(ps2port)) {
/* More data ready - break early to restart interrupt */
break;
@@ -397,6 +401,9 @@ static int gscps2_open(struct serio *port)
gscps2_reset(ps2port);
+ scoped_guard(spinlock_irqsave, &ps2port_list_lock)
+ list_add_tail_rcu(&ps2port->node, &ps2port_list);
+
/* enable it */
gscps2_enable(ps2port, true);
@@ -413,6 +420,11 @@ static void gscps2_close(struct serio *port)
struct gscps2port *ps2port = port->port_data;
gscps2_enable(ps2port, false);
+
+ scoped_guard(spinlock_irqsave, &ps2port_list_lock)
+ list_del_rcu(&ps2port->node);
+
+ synchronize_rcu();
}
/**
@@ -446,6 +458,7 @@ static int __init gscps2_probe(struct parisc_device *dev)
ps2port->port = serio;
ps2port->padev = dev;
+ INIT_LIST_HEAD(&ps2port->node);
ps2port->addr = ioremap(hpa, GSC_STATUS + 4);
if (!ps2port->addr) {
ret = -ENOMEM;
@@ -501,8 +514,6 @@ static int __init gscps2_probe(struct parisc_device *dev)
serio_register_port(ps2port->port);
- list_add_tail(&ps2port->node, &ps2port_list);
-
return 0;
fail:
@@ -539,12 +550,10 @@ static void __exit gscps2_remove(struct parisc_device *dev)
serio_unregister_port(ps2port->port);
free_irq(dev->irq, ps2port);
gscps2_flush(ps2port);
- list_del(&ps2port->node);
iounmap(ps2port->addr);
#if 0
release_mem_region(dev->hpa, GSC_STATUS + 4);
#endif
- dev_set_drvdata(&dev->dev, NULL);
kfree(ps2port);
}
--
2.55.0.897.gb25b4bd76c-goog
next prev parent reply other threads:[~2026-08-30 20:52 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-30 20:52 [PATCH 0/7] Input: gscps2: cleanups and locking fixes Dmitry Torokhov
2026-08-30 20:52 ` [PATCH 1/7] Input: gscps2 - clean up driver code style and structure Dmitry Torokhov
2026-08-30 21:04 ` sashiko-bot
2026-08-30 20:52 ` Dmitry Torokhov [this message]
2026-08-30 20:52 ` [PATCH 3/7] Input: gscps2 - protect buffer access in read and report helpers Dmitry Torokhov
2026-08-30 21:05 ` sashiko-bot
2026-08-30 20:52 ` [PATCH 4/7] Input: gscps2 - serialize hardware and buffer access in gscps2_flush() Dmitry Torokhov
2026-08-30 21:02 ` sashiko-bot
2026-08-30 20:52 ` [PATCH 5/7] Input: gscps2 - return IRQ_NONE when interrupt is not handled Dmitry Torokhov
2026-08-30 21:05 ` sashiko-bot
2026-08-30 20:52 ` [PATCH 6/7] Input: gscps2 - serialize concurrent interrupt handlers Dmitry Torokhov
2026-08-30 21:07 ` sashiko-bot
2026-08-30 20:52 ` [PATCH 7/7] Input: gscps2 - drop busy-wait and manual interrupt pump on transmit Dmitry Torokhov
2026-08-30 21:05 ` sashiko-bot
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=20260830-gscps2-v1-2-c733d4cae7f9@gmail.com \
--to=dmitry.torokhov@gmail.com \
--cc=James.Bottomley@HansenPartnership.com \
--cc=deller@gmx.de \
--cc=linux-input@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-parisc@vger.kernel.org \
--cc=sashiko-bot@kernel.org \
/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.