mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH 0/9] Series short description
@ 2009-06-16 15:59 Alan Cox
  2009-06-16 16:00 ` [PATCH 1/9] tty: Fix leaks introduced by the shift to separate ldisc objects Alan Cox
                   ` (8 more replies)
  0 siblings, 9 replies; 10+ messages in thread
From: Alan Cox @ 2009-06-16 15:59 UTC (permalink / raw)
  To: torvalds, linux-kernel

Small fixes to the tty changes to sort out problems people hit, in particular
to fix a couple of SMP races Ingo found and properly fix the now rather more
visible (but long standing) pty race that James Bottomley encountered.
---

Alan Cox (5):
      tty: fix sanity check
      pty: Narrow the race on ldisc locking
      ldisc: debug aids
      ldisc: Make sure the ldisc isn't active when we close it
      tty: Fix leaks introduced by the shift to separate ldisc objects

Haavard Skinnemoen (1):
      atmel_serial: fix hang in set_termios when crtscts is enabled

Joe Perches (1):
      MAINTAINERS: update 8250 section, give Alan Cox a name

Mike Frysinger (1):
      tty: fix unused warning when TCGETX is not defined

Sascha Hauer (1):
      imx: Check for NULL pointer deref before calling  tty_encode_baud_rate


 MAINTAINERS                   |    3 ++
 drivers/char/pty.c            |   53 +++++++++++++++++++++++++++++++----------
 drivers/char/tty_io.c         |    2 ++
 drivers/char/tty_ioctl.c      |    5 ++--
 drivers/char/tty_ldisc.c      |    9 +++++--
 drivers/serial/atmel_serial.c |    8 ++++--
 drivers/serial/imx.c          |   12 +++++----
 7 files changed, 66 insertions(+), 26 deletions(-)

-- 
	"Standards committees don't like hashing.  It looks complicated and
         insufficiently deterministic on an overhead projector."
			-Vern Schryver


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH 1/9] tty: Fix leaks introduced by the shift to separate ldisc objects
  2009-06-16 15:59 [PATCH 0/9] Series short description Alan Cox
@ 2009-06-16 16:00 ` Alan Cox
  2009-06-16 16:00 ` [PATCH 2/9] ldisc: Make sure the ldisc isn't active when we close it Alan Cox
                   ` (7 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Alan Cox @ 2009-06-16 16:00 UTC (permalink / raw)
  To: torvalds, linux-kernel

From: Alan Cox <alan@linux.intel.com>

Gold star for the kmemleak detector.

Signed-off-by: Alan Cox <alan@linux.intel.com>
---

 drivers/char/tty_ldisc.c |    6 ++++--
 1 files changed, 4 insertions(+), 2 deletions(-)


diff --git a/drivers/char/tty_ldisc.c b/drivers/char/tty_ldisc.c
index 39c8f86..94b3e06 100644
--- a/drivers/char/tty_ldisc.c
+++ b/drivers/char/tty_ldisc.c
@@ -148,8 +148,10 @@ static struct tty_ldisc *tty_ldisc_try_get(int disc)
 		}
 	}
 	spin_unlock_irqrestore(&tty_ldisc_lock, flags);
-	if (err)
+	if (err) {
+		kfree(ld);
 		return ERR_PTR(err);
+	}
 	return ld;
 }
 
@@ -262,7 +264,7 @@ const struct file_operations tty_ldiscs_proc_fops = {
  *	@ld: line discipline
  *
  *	Install an instance of a line discipline into a tty structure. The
- *	ldisc must have a reference count above zero to ensure it remains/
+ *	ldisc must have a reference count above zero to ensure it remains.
  *	The tty instance refcount starts at zero.
  *
  *	Locking:


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH 2/9] ldisc: Make sure the ldisc isn't active when we close it
  2009-06-16 15:59 [PATCH 0/9] Series short description Alan Cox
  2009-06-16 16:00 ` [PATCH 1/9] tty: Fix leaks introduced by the shift to separate ldisc objects Alan Cox
@ 2009-06-16 16:00 ` Alan Cox
  2009-06-16 16:00 ` [PATCH 3/9] ldisc: debug aids Alan Cox
                   ` (6 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Alan Cox @ 2009-06-16 16:00 UTC (permalink / raw)
  To: torvalds, linux-kernel

From: Alan Cox <alan@linux.intel.com>

Signed-off-by: Alan Cox <alan@linux.intel.com>
---

 drivers/char/tty_ldisc.c |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)


diff --git a/drivers/char/tty_ldisc.c b/drivers/char/tty_ldisc.c
index 94b3e06..874c248 100644
--- a/drivers/char/tty_ldisc.c
+++ b/drivers/char/tty_ldisc.c
@@ -793,6 +793,8 @@ void tty_ldisc_hangup(struct tty_struct *tty)
 		/* Avoid racing set_ldisc */
 		mutex_lock(&tty->ldisc_mutex);
 		/* Switch back to N_TTY */
+		tty_ldisc_halt(tty);
+		tty_ldisc_wait_idle(tty);
 		tty_ldisc_reinit(tty);
 		/* At this point we have a closed ldisc and we want to
 		   reopen it. We could defer this to the next open but


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH 3/9] ldisc: debug aids
  2009-06-16 15:59 [PATCH 0/9] Series short description Alan Cox
  2009-06-16 16:00 ` [PATCH 1/9] tty: Fix leaks introduced by the shift to separate ldisc objects Alan Cox
  2009-06-16 16:00 ` [PATCH 2/9] ldisc: Make sure the ldisc isn't active when we close it Alan Cox
@ 2009-06-16 16:00 ` Alan Cox
  2009-06-16 16:01 ` [PATCH 4/9] tty: fix unused warning when TCGETX is not defined Alan Cox
                   ` (5 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Alan Cox @ 2009-06-16 16:00 UTC (permalink / raw)
  To: torvalds, linux-kernel

From: Alan Cox <alan@linux.intel.com>


---

 drivers/char/tty_ldisc.c |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)


diff --git a/drivers/char/tty_ldisc.c b/drivers/char/tty_ldisc.c
index 874c248..a19e935 100644
--- a/drivers/char/tty_ldisc.c
+++ b/drivers/char/tty_ldisc.c
@@ -207,6 +207,7 @@ static void tty_ldisc_put(struct tty_ldisc *ld)
 	ldo->refcount--;
 	module_put(ldo->owner);
 	spin_unlock_irqrestore(&tty_ldisc_lock, flags);
+	WARN_ON(ld->refcount);
 	kfree(ld);
 }
 


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH 4/9] tty: fix unused warning when TCGETX is not defined
  2009-06-16 15:59 [PATCH 0/9] Series short description Alan Cox
                   ` (2 preceding siblings ...)
  2009-06-16 16:00 ` [PATCH 3/9] ldisc: debug aids Alan Cox
@ 2009-06-16 16:01 ` Alan Cox
  2009-06-16 16:01 ` [PATCH 5/9] pty: Narrow the race on ldisc locking Alan Cox
                   ` (4 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Alan Cox @ 2009-06-16 16:01 UTC (permalink / raw)
  To: torvalds, linux-kernel

From: Mike Frysinger <vapier@gentoo.org>

If TCGETX is not defined, we end up with this warning:
drivers/char/tty_ioctl.c: In function ‘tty_mode_ioctl’:
drivers/char/tty_ioctl.c:950: warning: unused variable ‘ktermx’

Since the variable is only used in one case statement, push it down to
the local case scope.

Signed-off-by: Mike Frysinger <vapier@gentoo.org>
Signed-off-by: Alan Cox <alan@linux.intel.com>
---

 drivers/char/tty_ioctl.c |    5 +++--
 1 files changed, 3 insertions(+), 2 deletions(-)


diff --git a/drivers/char/tty_ioctl.c b/drivers/char/tty_ioctl.c
index 8116bb1..b24f6c6 100644
--- a/drivers/char/tty_ioctl.c
+++ b/drivers/char/tty_ioctl.c
@@ -947,7 +947,6 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file,
 	void __user *p = (void __user *)arg;
 	int ret = 0;
 	struct ktermios kterm;
-	struct termiox ktermx;
 
 	if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
 	    tty->driver->subtype == PTY_TYPE_MASTER)
@@ -1049,7 +1048,8 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file,
 		return ret;
 #endif
 #ifdef TCGETX
-	case TCGETX:
+	case TCGETX: {
+		struct termiox ktermx;
 		if (real_tty->termiox == NULL)
 			return -EINVAL;
 		mutex_lock(&real_tty->termios_mutex);
@@ -1058,6 +1058,7 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file,
 		if (copy_to_user(p, &ktermx, sizeof(struct termiox)))
 			ret = -EFAULT;
 		return ret;
+	}
 	case TCSETX:
 		return set_termiox(real_tty, p, 0);
 	case TCSETXW:


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH 5/9] pty: Narrow the race on ldisc locking
  2009-06-16 15:59 [PATCH 0/9] Series short description Alan Cox
                   ` (3 preceding siblings ...)
  2009-06-16 16:01 ` [PATCH 4/9] tty: fix unused warning when TCGETX is not defined Alan Cox
@ 2009-06-16 16:01 ` Alan Cox
  2009-06-16 16:01 ` [PATCH 6/9] tty: fix sanity check Alan Cox
                   ` (3 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Alan Cox @ 2009-06-16 16:01 UTC (permalink / raw)
  To: torvalds, linux-kernel

From: Alan Cox <alan@linux.intel.com>

The pty code has always been buggy on its ldisc handling. The recent
changes made the window for the race much bigger. Pending fixing it
properly which is not at all trivial, at least make the race small again so
we don't disrupt other dev work.

Signed-off-by: Alan Cox <alan@linux.intel.com>
---

 drivers/char/pty.c |   53 +++++++++++++++++++++++++++++++++++++++-------------
 1 files changed, 40 insertions(+), 13 deletions(-)


diff --git a/drivers/char/pty.c b/drivers/char/pty.c
index 5acd29e..daebe1b 100644
--- a/drivers/char/pty.c
+++ b/drivers/char/pty.c
@@ -95,23 +95,34 @@ static void pty_unthrottle(struct tty_struct *tty)
  * a count.
  *
  * FIXME: Our pty_write method is called with our ldisc lock held but
- * not our partners. We can't just take the other one blindly without
- * risking deadlocks.
+ * not our partners. We can't just wait on the other one blindly without
+ * risking deadlocks. At some point when everything has settled down we need
+ * to look into making pty_write at least able to sleep over an ldisc change.
+ *
+ * The return on no ldisc is a bit counter intuitive but the logic works
+ * like this. During an ldisc change the other end will flush its buffers. We
+ * thus return the full length which is identical to the case where we had
+ * proper locking and happened to queue the bytes just before the flush during
+ * the ldisc change.
  */
 static int pty_write(struct tty_struct *tty, const unsigned char *buf,
 								int count)
 {
 	struct tty_struct *to = tty->link;
-	int	c;
+	struct tty_ldisc *ld;
+	int c = count;
 
 	if (!to || tty->stopped)
 		return 0;
-
-	c = to->receive_room;
-	if (c > count)
-		c = count;
-	to->ldisc->ops->receive_buf(to, buf, NULL, c);
-
+	ld = tty_ldisc_ref(to);
+
+	if (ld) {
+		c = to->receive_room;
+		if (c > count)
+			c = count;
+		ld->ops->receive_buf(to, buf, NULL, c);
+		tty_ldisc_deref(ld);
+	}
 	return c;
 }
 
@@ -145,14 +156,23 @@ static int pty_write_room(struct tty_struct *tty)
 static int pty_chars_in_buffer(struct tty_struct *tty)
 {
 	struct tty_struct *to = tty->link;
-	int count;
+	struct tty_ldisc *ld;
+	int count = 0;
 
 	/* We should get the line discipline lock for "tty->link" */
-	if (!to || !to->ldisc->ops->chars_in_buffer)
+	if (!to)
+		return 0;
+	/* We cannot take a sleeping reference here without deadlocking with
+	   an ldisc change - but it doesn't really matter */
+	ld = tty_ldisc_ref(to);
+	if (ld == NULL)
 		return 0;
 
 	/* The ldisc must report 0 if no characters available to be read */
-	count = to->ldisc->ops->chars_in_buffer(to);
+	if (ld->ops->chars_in_buffer)
+		count = ld->ops->chars_in_buffer(to);
+
+	tty_ldisc_deref(ld);
 
 	if (tty->driver->subtype == PTY_TYPE_SLAVE)
 		return count;
@@ -182,12 +202,19 @@ static void pty_flush_buffer(struct tty_struct *tty)
 {
 	struct tty_struct *to = tty->link;
 	unsigned long flags;
+	struct tty_ldisc *ld;
 
 	if (!to)
 		return;
+	ld = tty_ldisc_ref(to);
+
+	/* The other end is changing discipline */
+	if (!ld)
+		return;
 
-	if (to->ldisc->ops->flush_buffer)
+	if (ld->ops->flush_buffer)
 		to->ldisc->ops->flush_buffer(to);
+	tty_ldisc_deref(ld);
 
 	if (to->packet) {
 		spin_lock_irqsave(&tty->ctrl_lock, flags);


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH 6/9] tty: fix sanity check
  2009-06-16 15:59 [PATCH 0/9] Series short description Alan Cox
                   ` (4 preceding siblings ...)
  2009-06-16 16:01 ` [PATCH 5/9] pty: Narrow the race on ldisc locking Alan Cox
@ 2009-06-16 16:01 ` Alan Cox
  2009-06-16 16:01 ` [PATCH 7/9] MAINTAINERS: update 8250 section, give Alan Cox a name Alan Cox
                   ` (2 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Alan Cox @ 2009-06-16 16:01 UTC (permalink / raw)
  To: torvalds, linux-kernel

From: Alan Cox <alan@linux.intel.com>

The WARN_ON() that was added to tty_reopen can be triggered in the specific
case of a hangup occurring during a re-open of a tty which is not in the
middle of being otherwise closed.

In that case however the WARN() is bogus as we don't hold the neccessary
locks to make a correct decision.

The case we should be checking is "if the ldisc is not changing and reopen
is occuring". We could drop the WARN_ON but for the moment the debug is more
valuable even if it means taking a mutex as it will find any other cases.

Signed-off-by: Alan Cox <alan@linux.intel.com>
---

 drivers/char/tty_io.c |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)


diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index 939e198..a3afa0c 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -1263,7 +1263,9 @@ static int tty_reopen(struct tty_struct *tty)
 	tty->count++;
 	tty->driver = driver; /* N.B. why do this every time?? */
 
+	mutex_lock(&tty->ldisc_mutex);
 	WARN_ON(!test_bit(TTY_LDISC, &tty->flags));
+	mutex_unlock(&tty->ldisc_mutex);
 
 	return 0;
 }


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH 7/9] MAINTAINERS: update 8250 section, give Alan Cox a name
  2009-06-16 15:59 [PATCH 0/9] Series short description Alan Cox
                   ` (5 preceding siblings ...)
  2009-06-16 16:01 ` [PATCH 6/9] tty: fix sanity check Alan Cox
@ 2009-06-16 16:01 ` Alan Cox
  2009-06-16 16:02 ` [PATCH 8/9] atmel_serial: fix hang in set_termios when crtscts is enabled Alan Cox
  2009-06-16 16:02 ` [PATCH 9/9] imx: Check for NULL pointer deref before calling tty_encode_baud_rate Alan Cox
  8 siblings, 0 replies; 10+ messages in thread
From: Alan Cox @ 2009-06-16 16:01 UTC (permalink / raw)
  To: torvalds, linux-kernel

From: Joe Perches <joe@perches.com>

Signed-off-by: Joe Perches <joe@perches.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Alan Cox <alan@linux.intel.com>
---

 MAINTAINERS |    3 ++-
 1 files changed, 2 insertions(+), 1 deletions(-)


diff --git a/MAINTAINERS b/MAINTAINERS
index 2cb7566..09f6b3e 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -157,9 +157,10 @@ S:	Maintained
 F:	drivers/net/r8169.c
 
 8250/16?50 (AND CLONE UARTS) SERIAL DRIVER
+P:	Alan Cox
+M:	alan@lxorguk.ukuu.org.uk
 L:	linux-serial@vger.kernel.org
 W:	http://serial.sourceforge.net
-M:	alan@lxorguk.ukuu.org.uk
 S:	Odd Fixes
 F:	drivers/serial/8250*
 F:	include/linux/serial_8250.h


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH 8/9] atmel_serial: fix hang in set_termios when crtscts is enabled
  2009-06-16 15:59 [PATCH 0/9] Series short description Alan Cox
                   ` (6 preceding siblings ...)
  2009-06-16 16:01 ` [PATCH 7/9] MAINTAINERS: update 8250 section, give Alan Cox a name Alan Cox
@ 2009-06-16 16:02 ` Alan Cox
  2009-06-16 16:02 ` [PATCH 9/9] imx: Check for NULL pointer deref before calling tty_encode_baud_rate Alan Cox
  8 siblings, 0 replies; 10+ messages in thread
From: Alan Cox @ 2009-06-16 16:02 UTC (permalink / raw)
  To: torvalds, linux-kernel

From: Haavard Skinnemoen <haavard.skinnemoen@atmel.com>

After enabling hardware flow control, any subsequent termios call may hang
waiting for the transmitter to drain.  This appears to be caused by a
busy-loop in set_termios() waiting for the transmitter to become empty,
which may take a very long time (or hang indefinitely) if the device at
the other end is blocking us.

A quick look through the tty and serial_core code indicates that any
necessary flushing (which is optional) has already been done at this
point, so there's no need for the driver to flush the transmitter on its
own.

Fix it by removing the busy-loop altogether.

Tested-by: Eirik Aanonsen <eaa@wprmedical.com>
Signed-off-by: Haavard Skinnemoen <haavard.skinnemoen@atmel.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Alan Cox <alan@linux.intel.com>
---

 drivers/serial/atmel_serial.c |    8 +++++---
 1 files changed, 5 insertions(+), 3 deletions(-)


diff --git a/drivers/serial/atmel_serial.c b/drivers/serial/atmel_serial.c
index b3497d7..338b15c 100644
--- a/drivers/serial/atmel_serial.c
+++ b/drivers/serial/atmel_serial.c
@@ -1104,11 +1104,13 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios,
 	/* update the per-port timeout */
 	uart_update_timeout(port, termios->c_cflag, baud);
 
-	/* save/disable interrupts and drain transmitter */
+	/*
+	 * save/disable interrupts. The tty layer will ensure that the
+	 * transmitter is empty if requested by the caller, so there's
+	 * no need to wait for it here.
+	 */
 	imr = UART_GET_IMR(port);
 	UART_PUT_IDR(port, -1);
-	while (!(UART_GET_CSR(port) & ATMEL_US_TXEMPTY))
-		cpu_relax();
 
 	/* disable receiver and transmitter */
 	UART_PUT_CR(port, ATMEL_US_TXDIS | ATMEL_US_RXDIS);


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH 9/9] imx: Check for NULL pointer deref before calling tty_encode_baud_rate
  2009-06-16 15:59 [PATCH 0/9] Series short description Alan Cox
                   ` (7 preceding siblings ...)
  2009-06-16 16:02 ` [PATCH 8/9] atmel_serial: fix hang in set_termios when crtscts is enabled Alan Cox
@ 2009-06-16 16:02 ` Alan Cox
  8 siblings, 0 replies; 10+ messages in thread
From: Alan Cox @ 2009-06-16 16:02 UTC (permalink / raw)
  To: torvalds, linux-kernel

From: Sascha Hauer <s.hauer@pengutronix.de>

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Signed-off-by: Alan Cox <alan@linux.intel.com>
---

 drivers/serial/imx.c |   12 +++++++-----
 1 files changed, 7 insertions(+), 5 deletions(-)


diff --git a/drivers/serial/imx.c b/drivers/serial/imx.c
index 285b414..5d7b58f 100644
--- a/drivers/serial/imx.c
+++ b/drivers/serial/imx.c
@@ -924,11 +924,13 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios,
 	rational_best_approximation(16 * div * baud, sport->port.uartclk,
 		1 << 16, 1 << 16, &num, &denom);
 
-	tdiv64 = sport->port.uartclk;
-	tdiv64 *= num;
-	do_div(tdiv64, denom * 16 * div);
-	tty_encode_baud_rate(sport->port.info->port.tty,
-		(speed_t)tdiv64, (speed_t)tdiv64);
+	if (port->info && port->info->port.tty) {
+		tdiv64 = sport->port.uartclk;
+		tdiv64 *= num;
+		do_div(tdiv64, denom * 16 * div);
+		tty_encode_baud_rate(sport->port.info->port.tty,
+				(speed_t)tdiv64, (speed_t)tdiv64);
+	}
 
 	num -= 1;
 	denom -= 1;


^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2009-06-16 15:04 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-06-16 15:59 [PATCH 0/9] Series short description Alan Cox
2009-06-16 16:00 ` [PATCH 1/9] tty: Fix leaks introduced by the shift to separate ldisc objects Alan Cox
2009-06-16 16:00 ` [PATCH 2/9] ldisc: Make sure the ldisc isn't active when we close it Alan Cox
2009-06-16 16:00 ` [PATCH 3/9] ldisc: debug aids Alan Cox
2009-06-16 16:01 ` [PATCH 4/9] tty: fix unused warning when TCGETX is not defined Alan Cox
2009-06-16 16:01 ` [PATCH 5/9] pty: Narrow the race on ldisc locking Alan Cox
2009-06-16 16:01 ` [PATCH 6/9] tty: fix sanity check Alan Cox
2009-06-16 16:01 ` [PATCH 7/9] MAINTAINERS: update 8250 section, give Alan Cox a name Alan Cox
2009-06-16 16:02 ` [PATCH 8/9] atmel_serial: fix hang in set_termios when crtscts is enabled Alan Cox
2009-06-16 16:02 ` [PATCH 9/9] imx: Check for NULL pointer deref before calling tty_encode_baud_rate Alan Cox

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®