From: James Hilliard <james.hilliard1@gmail.com>
To: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
Jiri Slaby <jirislaby@kernel.org>,
linux-serial@vger.kernel.org, linux-input@vger.kernel.org,
linux-kernel@vger.kernel.org,
James Hilliard <james.hilliard1@gmail.com>
Subject: [PATCH v2] Input: serport - defer write wakeups to a worker
Date: Wed, 28 Oct 2026 01:14:19 -0600 [thread overview]
Message-ID: <20261028-submit-serport-write-wakeup-v1-v2-1-c05d96259985@gmail.com> (raw)
UART drivers can invoke the line discipline's write_wakeup() callback with
their port lock held. serport forwards the notification directly to the
serio driver. I-Force's callback can transmit a queued packet through
serio_write(), which calls back into uart_write() and tries to acquire the
same port lock. A notification after I-Force queues a packet but before it
sets IFORCE_XMIT_RUNNING can therefore deadlock.
Defer the serio notification to a work item, as required for transmitting
from a line discipline's write-wakeup path. Initialize the work disabled
and enable it, along with TTY_DO_WRITE_WAKEUP, only when a serio driver
with a write_wakeup() callback opens the port.
Clear TTY_DO_WRITE_WAKEUP and disable and drain the work when that driver
closes the port, before the serio driver and port can be torn down. This
allows the worker to call the driver without holding serport->lock,
breaking the lock ordering cycle with input event callbacks that write
to the UART.
Also clear TTY_DO_WRITE_WAKEUP and disable and drain the work on hangup,
before waking the reader to unregister the serio port. The additional
disable keeps the work disabled even if a driver opens the port while
hangup is in progress.
Signed-off-by: James Hilliard <james.hilliard1@gmail.com>
---
Changes in v2:
- Follow Dmitry's lifecycle suggestion: initialize the work disabled and
enable notifications only for a serio driver with a write_wakeup callback.
- Disable and drain the work in serio close before the driver is detached,
allowing the worker to call the driver without holding serport->lock.
- Disable and drain the work in hangup before waking the reader, keeping
it disabled even if a driver probe races with hangup.
- Link to v1: https://patch.msgid.link/20261023-submit-serport-write-wakeup-v1-v1-1-74e7311638a2@gmail.com
---
drivers/input/serio/serport.c | 36 +++++++++++++++++++++++++++++-------
1 file changed, 29 insertions(+), 7 deletions(-)
diff --git a/drivers/input/serio/serport.c b/drivers/input/serio/serport.c
index cabe3876c168..e522aa7f0fc2 100644
--- a/drivers/input/serio/serport.c
+++ b/drivers/input/serio/serport.c
@@ -18,6 +18,7 @@
#include <linux/serio.h>
#include <linux/tty.h>
#include <linux/compat.h>
+#include <linux/workqueue.h>
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
MODULE_DESCRIPTION("Input device TTY line discipline");
@@ -33,6 +34,7 @@ struct serport {
wait_queue_head_t wait;
struct serio *serio;
struct serio_device_id id;
+ struct work_struct write_wakeup;
spinlock_t lock;
unsigned long flags;
};
@@ -54,6 +56,11 @@ static int serport_serio_open(struct serio *serio)
guard(spinlock_irqsave)(&serport->lock);
set_bit(SERPORT_ACTIVE, &serport->flags);
+ if (serio->drv->write_wakeup) {
+ enable_work(&serport->write_wakeup);
+ set_bit(TTY_DO_WRITE_WAKEUP, &serport->tty->flags);
+ }
+
return 0;
}
@@ -62,8 +69,20 @@ static void serport_serio_close(struct serio *serio)
{
struct serport *serport = serio->port_data;
- guard(spinlock_irqsave)(&serport->lock);
- clear_bit(SERPORT_ACTIVE, &serport->flags);
+ scoped_guard(spinlock_irqsave, &serport->lock)
+ clear_bit(SERPORT_ACTIVE, &serport->flags);
+
+ if (serio->drv->write_wakeup) {
+ clear_bit(TTY_DO_WRITE_WAKEUP, &serport->tty->flags);
+ disable_work_sync(&serport->write_wakeup);
+ }
+}
+
+static void serport_write_wakeup(struct work_struct *work)
+{
+ struct serport *serport = container_of(work, struct serport, write_wakeup);
+
+ serio_drv_write_wakeup(serport->serio);
}
/*
@@ -85,10 +104,11 @@ static int serport_ldisc_open(struct tty_struct *tty)
serport->tty = tty;
spin_lock_init(&serport->lock);
init_waitqueue_head(&serport->wait);
+ INIT_WORK(&serport->write_wakeup, serport_write_wakeup);
+ disable_work(&serport->write_wakeup);
tty->disc_data = serport;
tty->receive_room = 256;
- set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
return 0;
}
@@ -239,6 +259,10 @@ static void serport_ldisc_hangup(struct tty_struct *tty)
{
struct serport *serport = tty->disc_data;
+ clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
+ /* Keep work disabled even if a driver opens the port during hangup. */
+ disable_work_sync(&serport->write_wakeup);
+
scoped_guard(spinlock_irqsave, &serport->lock)
set_bit(SERPORT_DEAD, &serport->flags);
@@ -249,10 +273,8 @@ static void serport_ldisc_write_wakeup(struct tty_struct * tty)
{
struct serport *serport = tty->disc_data;
- guard(spinlock_irqsave)(&serport->lock);
-
- if (test_bit(SERPORT_ACTIVE, &serport->flags))
- serio_drv_write_wakeup(serport->serio);
+ /* A serio driver may write to the TTY, so defer the callback. */
+ schedule_work(&serport->write_wakeup);
}
/*
---
base-commit: f57202d55333f750a18e21c3b3f35f48ef14a61e
change-id: 20261023-submit-serport-write-wakeup-v1-1bdd1006fafa
Best regards,
--
James Hilliard <james.hilliard1@gmail.com>
next reply other threads:[~2026-10-28 7:14 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-28 7:14 James Hilliard [this message]
2026-10-28 17:09 ` Dmitry Torokhov
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=20261028-submit-serport-write-wakeup-v1-v2-1-c05d96259985@gmail.com \
--to=james.hilliard1@gmail.com \
--cc=dmitry.torokhov@gmail.com \
--cc=gregkh@linuxfoundation.org \
--cc=jirislaby@kernel.org \
--cc=linux-input@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-serial@vger.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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®