Forráskód Böngészése

Merge branch 'serial'

* serial:
  imx: Check for NULL pointer deref before calling tty_encode_baud_rate
  atmel_serial: fix hang in set_termios when crtscts is enabled
  MAINTAINERS: update 8250 section, give Alan Cox a name
  tty: fix sanity check
  pty: Narrow the race on ldisc locking
  tty: fix unused warning when TCGETX is not defined
  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

Fix conflicts in drivers/char/pty.c due to earlier version of the ldisc
race narrowing.
Linus Torvalds 16 éve
szülő
commit
15bdb56526

+ 2 - 1
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

+ 42 - 15
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 || !to->ldisc || tty->stopped)
+	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 || !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);
 
-	if (!to || !to->ldisc)
+	/* 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);

+ 2 - 0
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;
 }

+ 3 - 2
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:

+ 3 - 0
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);
 }
 
@@ -793,6 +794,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

+ 5 - 3
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);

+ 7 - 5
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;