mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH v2] serial: max3100: Fix a data race on s->rts in max3100_work()
       [not found] <20260922053151.11260-1-ginger.jzllee@gmail.com>
@ 2026-09-22 17:02 ` Ginger Li
  0 siblings, 0 replies; only message in thread
From: Ginger Li @ 2026-09-22 17:02 UTC (permalink / raw)
  To: jirislaby, gregkh; +Cc: linux-serial, linux-kernel, Maarten.Brock

max3100_set_mctrl() stores the new RTS state and raises s->rts_commit to tell
max3100_work() that it has to program it:

	spin_lock(&s->conf_lock);
	if (s->rts != rts) {
		s->rts = rts;
		s->rts_commit = 1;
	}
	if (s->loopback_commit || s->rts_commit)
		max3100_dowork(s);
	spin_unlock(&s->conf_lock);

max3100_work() consumes s->rts_commit under s->conf_lock, but reads s->rts
itself outside of the lock, both when it services that pending update and when
it later transmits a character, so the state it programs into the hardware can
be stale.

Read s->rts into a local variable in the s->conf_lock protected snapshot at
the top of the loop, before s->rts_commit is consumed, in the same way as
s->conf is read before s->conf_commit.

Fixes: 7831d56b0a35 ("tty: MAX3100")
Signed-off-by: Ginger Li <ginger.jzllee@gmail.com>
---
v2:
 - read s->rts into "rts" before s->rts_commit is consumed, as suggested by
   Maarten
 - mention s->rts_commit in the commit message
 - left the s->rts / s->rts_commit split alone; folding both into one byte
   would be a separate cleanup
---
 drivers/tty/serial/max3100.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/drivers/tty/serial/max3100.c b/drivers/tty/serial/max3100.c
--- a/drivers/tty/serial/max3100.c
+++ b/drivers/tty/serial/max3100.c
@@ -236,6 +236,7 @@ static void max3100_work(struct work_struct *w)
 	struct tty_port *tport = &s->port.state->port;
 	unsigned char ch;
 	int conf, cconf, cloopback, crts;
+	bool rts;
 	int rxchars;
 	u16 tx, rx;
 
@@ -249,6 +250,7 @@ static void max3100_work(struct work_struct *w)
 		s->conf_commit = 0;
 		cloopback = s->loopback_commit;
 		s->loopback_commit = 0;
+		rts = s->rts;
 		crts = s->rts_commit;
 		s->rts_commit = 0;
 		spin_unlock(&s->conf_lock);
@@ -258,7 +260,7 @@ static void max3100_work(struct work_struct *w)
 			max3100_sr(s, 0x4001, &rx);
 		if (crts) {
 			max3100_sr(s, MAX3100_WD | MAX3100_TE |
-				   (s->rts ? MAX3100_RTS : 0), &rx);
+				   (rts ? MAX3100_RTS : 0), &rx);
 			rxchars += max3100_handlerx(s, rx);
 		}
 
@@ -277,7 +279,7 @@ static void max3100_work(struct work_struct *w)
 			}
 			if (tx != 0xffff) {
 				max3100_calc_parity(s, &tx);
-				tx |= MAX3100_WD | (s->rts ? MAX3100_RTS : 0);
+				tx |= MAX3100_WD | (rts ? MAX3100_RTS : 0);
 				max3100_sr(s, tx, &rx);
 				rxchars += max3100_handlerx(s, rx);
 			}
-- 
2.43.0

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2026-09-22 17:02 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <20260922053151.11260-1-ginger.jzllee@gmail.com>
2026-09-22 17:02 ` [PATCH v2] serial: max3100: Fix a data race on s->rts in max3100_work() Ginger Li

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®