Skip to contentSkip to conversation

Queued TTY Patches

PATCH In review Alan Cox 7 participants 88 messages Oct 5, 2008 – Oct 9, 2008

Subsystems (19)
Network drivers Documentation VFS USB +15 more subsystems
lore
Share & tools
lore

Alan Cox

author
#0 lore raw

cover Queued TTY Patches

This is the patch stack waiting for 2.6.28 to open. The patches start with various queued bug fixes then move on to tackle the first stage of making the tty layer sane. These patches have been in linux-next.

The main thrust is to begin using krefs and refcounts to kill races and make the locking saner. At this point we still have BKL users but will hopefully change bit by bit.

Alan

---

Adrian Bunk (1):
coldfire: scheduled SERIAL_COLDFIRE removal

Akinobu Mita (1):
ip2: avoid add_timer with pending timer

Alan Cox (43):
ftdi: A few errors are err() that should be debug which causes much spewage
applicom: Fix an unchecked user ioctl range and an error return
hso: net driver using tty without locking
tty: Minor tidyups and document fixes for n_tty
tty: Remove lots of NULL checks
tty: fix up gigaset a bit
tty: some ICANON magic is in the wrong places
tty: simplify ktermios allocation
pty: simplify unix98 allocation
pty: Fix allocation failure double free
pty: Coding style and polish
tty: extract the pty init time special cases
tty: Finish fixing up the init_dev interface to use ERR_PTR
tty: More driver operations
tty: kref the tty driver object
tty: Clean up the tty_init_dev changes further
tty: Remove more special casing and out of place code
tty: shutdown method
vt: remove bogus lock dropping
pty: If the administrator creates a device for a ptmx slave we should not error
tty: Fix abusers of current->sighand->tty
tty: Redo current tty locking
tty: the vhangup syscall is racy
mxser: Switch to kref tty
stallion: Use krefs
tty: kref usage for isicom and moxa
tty: usb-serial krefs
tty: Move tty_write_message out of kernel/printk
tty: Make get_current_tty use a kref
tty: compare the tty winsize
tty: Termios locking - sort out real_tty confusions and lock reads
tty: Add termiox
tty: ipw need reworking
tty: Cris has a nice RS485 ioctl so we should steal it
tty: use krefs to protect driver module counts
tty: Add a kref count
pps: Reserve a line discipline number for PPS
tty: Split tty_port into its own file
tty: split the buffering from tty_io
uml: small cleanups and note bugs to be dealt with by uml authors...
tty: move tioclinux from a special case
8250: Remove NR_IRQ usage
epca: call tty_port_init

Andrew Morton (1):
serial-make-uart_ports-ioport-unsigned-long-fix

David Miller (2):
serial: allow 8250 to be used on sparc
serial: Make uart_port's ioport "unsigned long".

David S. Miller (1):
serial: fix device name reporting when minor space is shared between drivers

Graf Yang (1):
Blackfin Serial Driver: Fix bug - ircp fails on sir over Blackfin UART

Jason Wessel (2):
usb: fix pl2303 initialization
tty: tty_io.c shadows sparse fix

Jiri Slaby (6):
Char: sx, fix io unmapping
Char: cyclades. remove bogus iomap
ip2, init/deinit cleanup
ip2, fix sparse warnings
ip2, cleanup globals
Char: merge ip2main and ip2base

Julia Lawall (2):
drivers/char/hvc_console.c: adjust call to put_tty_driver drivers/serial/crisv10.c: add missing put_tty_driver

Mike Frysinger (3):
Blackfin Serial Driver: move common variables out of serial headers and into the serial driver Blackfin Serial Driver: trim trailing whitespace -- no functional changes Blackfin Serial Driver: use __initdata for data, not __init

Miloslav Trmac (1):
audit: Handle embedded NUL in TTY input auditing

Sonic Zhang (4):
Blackfin Serial Driver: Fix bug - request UART2/3 peripheral mapped interrupts in PIO mode Blackfin Serial Driver: Fix bug - Don't call tx_stop in tx_transfer. Blackfin Serial Driver: Remove useless stop
Blackfin Serial Driver: Fix bug - should suspend/resume/remove all uart ports.

Stephen Rothwell (1):
tty: Fallout from tty-move-canon-specials

Sukadev Bhattiprolu (6):
Simplify devpts_pty_kill
Simplify devpts_pty_new()
Simplify devpts_get_tty()
Add an instance parameter devpts interfaces Move tty lookup/reopen to caller
tty: Move parts of tty_init_dev into new functions

\\\"Will Newton\\\ (1):
8250: remove a few inlines of dubious value

 Documentation/feature-removal-schedule.txt         |    8 
 arch/blackfin/kernel/bfin_dma_5xx.c                |   13 
 .../mach-bf527/include/mach/bfin_serial_5xx.h      |    6 
 .../mach-bf533/include/mach/bfin_serial_5xx.h      |    4 
 .../mach-bf537/include/mach/bfin_serial_5xx.h      |    6 
 .../mach-bf548/include/mach/bfin_serial_5xx.h      |    6 
 .../mach-bf561/include/mach/bfin_serial_5xx.h      |    4 
 arch/sparc/include/asm/serial.h                    |    6 
 arch/um/drivers/line.c                             |    2 
 drivers/bluetooth/hci_ldisc.c                      |    2 
 drivers/char/Kconfig                               |    4 
 drivers/char/Makefile                              |    2 
 drivers/char/amiserial.c                           |    6 
 drivers/char/applicom.c                            |    6 
 drivers/char/cyclades.c                            |   21 
 drivers/char/epca.c                                |    5 
 drivers/char/generic_serial.c                      |   21 
 drivers/char/hvc_console.c                         |    4 
 drivers/char/ip2/Makefile                          |    2 
 drivers/char/ip2/i2ellis.c                         |   32 
 drivers/char/ip2/i2ellis.h                         |    2 
 drivers/char/ip2/ip2base.c                         |  108 -
 drivers/char/ip2/ip2main.c                         |  550 +++---
 drivers/char/isicom.c                              |   61 -
 drivers/char/istallion.c                           |  113 +
 drivers/char/moxa.c                                |   61 -
 drivers/char/mxser.c                               |  193 +-
 drivers/char/n_hdlc.c                              |    2 
 drivers/char/n_r3964.c                             |    9 
 drivers/char/n_tty.c                               |   99 +
 drivers/char/pcmcia/ipwireless/tty.c               |   19 
 drivers/char/pty.c                                 |  335 +++
 drivers/char/stallion.c                            |  139 +
 drivers/char/sx.c                                  |    4 
 drivers/char/tty_audit.c                           |    2 
 drivers/char/tty_buffer.c                          |  511 +++++
 drivers/char/tty_io.c                              | 1380 ++++----------
 drivers/char/tty_ioctl.c                           |  212 ++
 drivers/char/tty_port.c                            |   96 +
 drivers/char/vt.c                                  |   84 -
 drivers/char/vt_ioctl.c                            |    2 
 drivers/isdn/capi/capi.c                           |    2 
 drivers/isdn/gigaset/ser-gigaset.c                 |   27 
 drivers/net/usb/hso.c                              |   46 
 drivers/net/wan/Kconfig                            |    2 
 drivers/s390/char/fs3270.c                         |    3 
 drivers/serial/68328serial.c                       |   11 
 drivers/serial/8250.c                              |  123 +
 drivers/serial/Kconfig                             |   17 
 drivers/serial/Makefile                            |   16 
 drivers/serial/bfin_5xx.c                          |  123 +
 drivers/serial/crisv10.c                           |    5 
 drivers/serial/mcfserial.c                         | 1965 --------------------
 drivers/serial/mcfserial.h                         |   74 -
 drivers/serial/serial_core.c                       |   12 
 drivers/usb/serial/aircable.c                      |   15 
 drivers/usb/serial/belkin_sa.c                     |    3 
 drivers/usb/serial/console.c                       |    8 
 drivers/usb/serial/cyberjack.c                     |    3 
 drivers/usb/serial/cypress_m8.c                    |    5 
 drivers/usb/serial/digi_acceleport.c               |   19 
 drivers/usb/serial/empeg.c                         |    8 
 drivers/usb/serial/ftdi_sio.c                      |   25 
 drivers/usb/serial/garmin_gps.c                    |    3 
 drivers/usb/serial/generic.c                       |    3 
 drivers/usb/serial/io_edgeport.c                   |   43 
 drivers/usb/serial/io_ti.c                         |   26 
 drivers/usb/serial/ipaq.c                          |    3 
 drivers/usb/serial/ipw.c                           |    3 
 drivers/usb/serial/ir-usb.c                        |    3 
 drivers/usb/serial/iuu_phoenix.c                   |    3 
 drivers/usb/serial/keyspan.c                       |   77 -
 drivers/usb/serial/keyspan_pda.c                   |   16 
 drivers/usb/serial/kl5kusb105.c                    |    3 
 drivers/usb/serial/kobil_sct.c                     |    3 
 drivers/usb/serial/mct_u232.c                      |    6 
 drivers/usb/serial/mos7720.c                       |   36 
 drivers/usb/serial/mos7840.c                       |    7 
 drivers/usb/serial/navman.c                        |    3 
 drivers/usb/serial/omninet.c                       |   10 
 drivers/usb/serial/option.c                        |   18 
 drivers/usb/serial/oti6858.c                       |    3 
 drivers/usb/serial/pl2303.c                        |   15 
 drivers/usb/serial/safe_serial.c                   |   11 
 drivers/usb/serial/sierra.c                        |   16 
 drivers/usb/serial/spcp8x5.c                       |    3 
 drivers/usb/serial/ti_usb_3410_5052.c              |   44 
 drivers/usb/serial/usb-serial.c                    |   24 
 drivers/usb/serial/visor.c                         |   18 
 drivers/usb/serial/whiteheat.c                     |    8 
 fs/devpts/inode.c                                  |   66 -
 fs/dquot.c                                         |    6 
 fs/open.c                                          |    3 
 include/asm-x86/ioctls.h                           |    6 
 include/linux/devpts_fs.h                          |   31 
 include/linux/serial.h                             |   16 
 include/linux/serial_core.h                        |    2 
 include/linux/termios.h                            |   15 
 include/linux/tty.h                                |   45 
 include/linux/tty_driver.h                         |   56 +
 include/linux/vt_kern.h                            |    2 
 kernel/acct.c                                      |    2 
 kernel/auditsc.c                                   |    9 
 kernel/fork.c                                      |    5 
 kernel/printk.c                                    |   16 
 kernel/sys.c                                       |    4 
 security/selinux/hooks.c                           |    3 
 107 files changed, 2948 insertions(+), 4401 deletions(-)
 create mode 100644 arch/sparc/include/asm/serial.h
 delete mode 100644 drivers/char/ip2/ip2base.c
 create mode 100644 drivers/char/tty_buffer.c
 create mode 100644 drivers/char/tty_port.c
 delete mode 100644 drivers/serial/mcfserial.c
 delete mode 100644 drivers/serial/mcfserial.h
Signature · 1 line
Signature
author
#1 lore raw

PATCH 1/76 drivers/serial/crisv10.c: add missing put_tty_driver

From: Julia Lawall <[email protected]>

alloc_tty_driver is called at the beginning of the function containing the lines of code shown in the patch. Thus, put_tty_driver is needed before returning in the error handling code.

The semantic match that finds this problem is as follows:
(http://www.emn.fr/x-info/coccinelle/)

// <smpl>
@nr exists@
local idexpression x;
expression E,f;
position p1,p2,p3;
identifier l;
statement S;
@@

x = alloc_tty_driver@p1(...)
...
if (x == NULL) S
... when != E = x

    when != put_tty_driver(x)
    when != goto l;

(
return \(0\|x\);
|
return@p3 ...;
)

@script:python@
p1 << nr.p1;
p3 << nr.p3;
@@

print "%s: call on line %s not freed or saved before return on line %s" % (p1[0].file,p1[0].line,p3[0].line) // </smpl>

---

 drivers/serial/crisv10.c |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)
drivers/serial/crisv10.c +2 -0
index bf94a77..a467c77 100644
@@ -4419,6 +4419,7 @@ rs_init(void)
 			rs485_pa_bit)) {
 		printk(KERN_CRIT "ETRAX100LX serial: Could not allocate "
 			"RS485 pin\n");
+		put_tty_driver(driver);
 		return -EBUSY;
 	}
 #endif
@@ -4427,6 +4428,7 @@ rs_init(void)
 			rs485_port_g_bit)) {
 		printk(KERN_CRIT "ETRAX100LX serial: Could not allocate "
 			"RS485 pin\n");
+		put_tty_driver(driver);
 		return -EBUSY;
 	}
 #endif
author
#2 lore raw

PATCH 2/76 drivers/char/hvc_console.c: adjust call to put_tty_driver

In reply to Alan Cox

From: Julia Lawall <[email protected]>

The call to put_tty_driver is out of place and is applied to the wrong argument.

The function enclosing the patched code calls alloc_tty_driver and stores the result in drv. Subsequently, there are two occurrences of error handling code, one making a goto to put_tty and one making a goto to stop_thread. At the point of the first one the assignment hvc_driver = drv has not yet been executed, and from inspecting the rest of the file it seems that hvc_driver would be NULL. Thus the current call to put_tty_driver is useless, and one applied to drv is needed. The goto stop_thread is in the error handling code for a call to tty_register_driver, but the error cases in tty_register_driver do not free its argument, so it should be done here. Thus, I have moved the put_tty label after the stop_thread label, so that put_tty_driver is called in both cases.

The semantic match that finds this problem is as follows:
(http://www.emn.fr/x-info/coccinelle/)

// <smpl>
@r exists@
local idexpression x;
expression E,f;
position p1,p2,p3;
identifier l;
statement S;
@@

x = alloc_tty_driver@p1(...)
...
if (x == NULL) S
... when != E = x

    when != put_tty_driver(x)
goto@p2 l;
... when != E = x
    when != f(...,x,...)
    when any

(
return \(0\|x\);
|
return@p3 ...;
)

@script:python@
p1 << r.p1;
p2 << r.p2;
p3 << r.p3;
@@

print "%s: call on line %s not freed or saved before return on line %s via line %s" % (p1[0].file,p1[0].line,p3[0].line,p2[0].line) // </smpl>

---

 drivers/char/hvc_console.c |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)
drivers/char/hvc_console.c +2 -2
index fd64137..ec7aded 100644
@@ -819,11 +819,11 @@ static int hvc_init(void)
 	hvc_driver = drv;
 	return 0;
 
-put_tty:
-	put_tty_driver(hvc_driver);
 stop_thread:
 	kthread_stop(hvc_task);
 	hvc_task = NULL;
+put_tty:
+	put_tty_driver(drv);
 out:
 	return err;
 }
author
#3 lore raw

PATCH 3/76 coldfire: scheduled SERIAL_COLDFIRE removal

In reply to Alan Cox

From: Adrian Bunk <[email protected]>

This patch contains the scheduled removal of the obsolete SERIAL_COLDFIRE driver.

---

 Documentation/feature-removal-schedule.txt |    8 
 drivers/serial/Kconfig                     |   16 
 drivers/serial/Makefile                    |    1 
 drivers/serial/mcfserial.c                 | 1965 ----------------------------
 drivers/serial/mcfserial.h                 |   74 -
 5 files changed, 2 insertions(+), 2062 deletions(-)
 delete mode 100644 drivers/serial/mcfserial.c
 delete mode 100644 drivers/serial/mcfserial.h
Documentation/feature-removal-schedule.txt +0 -8
index 83c88ca..e5c3f9d 100644
@@ -266,14 +266,6 @@ Who:	Glauber Costa <[email protected]>
 
 ---------------------------
 
-What:	old style serial driver for ColdFire (CONFIG_SERIAL_COLDFIRE)
-When:	2.6.28
-Why:	This driver still uses the old interface and has been replaced
-	by CONFIG_SERIAL_MCF.
-Who:	Sebastian Siewior <[email protected]>
-
----------------------------
-
 What:	/sys/o2cb symlink
 When:	January 2010
 Why:	/sys/fs/o2cb is the proper location for this information - /sys/o2cb
drivers/serial/Kconfig +2 -14
index 77cb342..0db2045 100644
@@ -994,24 +994,12 @@ config SERIAL_68328_RTS_CTS
 	bool "Support RTS/CTS on 68328 serial port"
 	depends on SERIAL_68328
 
-config SERIAL_COLDFIRE
-	bool "ColdFire serial support (DEPRECATED)"
-	depends on COLDFIRE
-	help
-	  This driver supports the built-in serial ports of the Motorola ColdFire
-	  family of CPUs.
-	  This driver is deprecated because it supports only the old interface
-	  for serial drivers and features like magic keys are not working.
-	  Please switch to the new style driver because this driver will be
-	  removed soon.
-
 config SERIAL_MCF
-	bool "Coldfire serial support (new style driver)"
+	bool "Coldfire serial support"
 	depends on COLDFIRE
 	select SERIAL_CORE
 	help
-	  This new serial driver supports the Freescale Coldfire serial ports
-	  using the new serial driver subsystem.
+	  This serial driver supports the Freescale Coldfire serial ports.
 
 config SERIAL_MCF_BAUDRATE
 	int "Default baudrate for Coldfire serial ports"
drivers/serial/Makefile +0 -1
index 7e7383e..1462eb3 100644
@@ -40,7 +40,6 @@ obj-$(CONFIG_SERIAL_SUNSAB) += sunsab.o
 obj-$(CONFIG_SERIAL_MUX) += mux.o
 obj-$(CONFIG_SERIAL_68328) += 68328serial.o
 obj-$(CONFIG_SERIAL_68360) += 68360serial.o
-obj-$(CONFIG_SERIAL_COLDFIRE) += mcfserial.o
 obj-$(CONFIG_SERIAL_MCF) += mcf.o
 obj-$(CONFIG_SERIAL_PMACZILOG) += pmac_zilog.o
 obj-$(CONFIG_SERIAL_LH7A40X) += serial_lh7a40x.o
drivers/serial/mcfserial.c deleted +0 -1965

1,965 lines not on this page · raw message

drivers/serial/mcfserial.h deleted +0 -74

74 lines not on this page · raw message

author
#4 lore raw

PATCH 4/76 epca: call tty_port_init

In reply to Alan Cox

---

 drivers/char/epca.c |    5 +----
 1 files changed, 1 insertions(+), 4 deletions(-)
drivers/char/epca.c +1 -4
index 456e4ed..4998b27 100644
@@ -1376,6 +1376,7 @@ static void post_fep_init(unsigned int crd)
 		unsigned long flags;
 		u16 tseg, rseg;
 
+		tty_port_init(&ch->port);
 		ch->brdchan = bc;
 		ch->mailbox = gd;
 		INIT_WORK(&ch->tqueue, do_softint);
@@ -1510,10 +1511,6 @@ static void post_fep_init(unsigned int crd)
 		ch->fepstopca = 0;
 
 		ch->close_delay = 50;
-		ch->port.count = 0;
-		ch->port.blocked_open = 0;
-		init_waitqueue_head(&ch->port.open_wait);
-		init_waitqueue_head(&ch->port.close_wait);
 
 		spin_unlock_irqrestore(&epca_lock, flags);
 	}
author
#5 lore raw

PATCH 5/76 8250: Remove NR_IRQ usage

In reply to Alan Cox

There are plans afoot to make the IRQ ranges dynamic. In that situation we don't want drivers having their own huge arrays for per IRQ data so use a hash

---

 drivers/serial/68328serial.c |   11 +-----
 drivers/serial/8250.c        |   74 +++++++++++++++++++++++++++++++++---------
 2 files changed, 60 insertions(+), 25 deletions(-)
drivers/serial/68328serial.c +2 -9
index 381b12a..277b78d 100644
@@ -66,7 +66,6 @@
 #endif
 
 static struct m68k_serial m68k_soft[NR_PORTS];
-struct m68k_serial *IRQ_ports[NR_IRQS];
 
 static unsigned int uart_irqs[NR_PORTS] = UART_IRQ_DEFNS;
 
@@ -375,15 +374,11 @@ clear_and_return:
  */
 irqreturn_t rs_interrupt(int irq, void *dev_id)
 {
-	struct m68k_serial * info;
+	struct m68k_serial * info = dev_id;
 	m68328_uart *uart;
 	unsigned short rx;
 	unsigned short tx;
 
-	info = IRQ_ports[irq];
-	if(!info)
-	    return IRQ_NONE;
-
 	uart = &uart_addr[info->line];
 	rx = uart->urx.w;
 
@@ -1383,8 +1378,6 @@ rs68328_init(void)
 		   info->port, info->irq);
 	    printk(" is a builtin MC68328 UART\n");
 	    
-	    IRQ_ports[info->irq] = info;	/* waste of space */
-
 #ifdef CONFIG_M68VZ328
 		if (i > 0 )
 			PJSEL &= 0xCF;  /* PSW enable second port output */
@@ -1393,7 +1386,7 @@ rs68328_init(void)
 	    if (request_irq(uart_irqs[i],
 			    rs_interrupt,
 			    IRQF_DISABLED,
-			    "M68328_UART", NULL))
+			    "M68328_UART", info))
                 panic("Unable to attach 68328 serial interrupt\n");
 	}
 	local_irq_restore(flags);
drivers/serial/8250.c +58 -16

139 lines not on this page · raw message

author
#6 lore raw

PATCH 6/76 Blackfin Serial Driver: use __initdata for data, not __init

In reply to Alan Cox

From: Mike Frysinger <[email protected]>

---

 drivers/serial/bfin_5xx.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
drivers/serial/bfin_5xx.c +1 -1
index 4a0d30b..4a023c6 100644
@@ -1056,7 +1056,7 @@ static __init void early_serial_write(struct console *con, const char *s,
 	}
 }
 
-static struct __init console bfin_early_serial_console = {
+static struct __initdata console bfin_early_serial_console = {
 	.name = "early_BFuart",
 	.write = early_serial_write,
 	.device = uart_console_device,
author
#7 lore raw

PATCH 7/76 Blackfin Serial Driver: Fix bug - should suspend/resume/remove all uart ports.

In reply to Alan Cox

From: Sonic Zhang <[email protected]>

---

 drivers/serial/bfin_5xx.c |   39 ++++++++++++++++++++++-----------------
 1 files changed, 22 insertions(+), 17 deletions(-)
drivers/serial/bfin_5xx.c +22 -17
index 4a023c6..04eeef0 100644
@@ -1100,20 +1100,26 @@ static struct uart_driver bfin_serial_reg = {
 
 static int bfin_serial_suspend(struct platform_device *dev, pm_message_t state)
 {
-	struct bfin_serial_port *uart = platform_get_drvdata(dev);
+	int i;
 
-	if (uart)
-		uart_suspend_port(&bfin_serial_reg, &uart->port);
+	for (i = 0; i < nr_ports; i++) {
+		if (bfin_serial_ports[i].port.dev != &dev->dev)
+			continue;
+		uart_suspend_port(&bfin_serial_reg, &bfin_serial_ports[i].port);
+	}
 
 	return 0;
 }
 
 static int bfin_serial_resume(struct platform_device *dev)
 {
-	struct bfin_serial_port *uart = platform_get_drvdata(dev);
+	int i;
 
-	if (uart)
-		uart_resume_port(&bfin_serial_reg, &uart->port);
+	for (i = 0; i < nr_ports; i++) {
+		if (bfin_serial_ports[i].port.dev != &dev->dev)
+			continue;
+		uart_resume_port(&bfin_serial_reg, &bfin_serial_ports[i].port);
+	}
 
 	return 0;
 }
@@ -1133,27 +1139,26 @@ static int bfin_serial_probe(struct platform_device *dev)
 				continue;
 			bfin_serial_ports[i].port.dev = &dev->dev;
 			uart_add_one_port(&bfin_serial_reg, &bfin_serial_ports[i].port);
-			platform_set_drvdata(dev, &bfin_serial_ports[i]);
 		}
 	}
 
 	return 0;
 }
 
-static int bfin_serial_remove(struct platform_device *pdev)
+static int bfin_serial_remove(struct platform_device *dev)
 {
-	struct bfin_serial_port *uart = platform_get_drvdata(pdev);
-
+	int i;
 
+	for (i = 0; i < nr_ports; i++) {
+		if (bfin_serial_ports[i].port.dev != &dev->dev)
+			continue;
+		uart_remove_one_port(&bfin_serial_reg, &bfin_serial_ports[i].port);
+		bfin_serial_ports[i].port.dev = NULL;
 #ifdef CONFIG_SERIAL_BFIN_CTSRTS
-	gpio_free(uart->cts_pin);
-	gpio_free(uart->rts_pin);
+		gpio_free(bfin_serial_ports[i].cts_pin);
+		gpio_free(bfin_serial_ports[i].rts_pin);
 #endif
-
-	platform_set_drvdata(pdev, NULL);
-
-	if (uart)
-		uart_remove_one_port(&bfin_serial_reg, &uart->port);
+	}
 
 	return 0;
 }
author
#8 lore raw

PATCH 8/76 Blackfin Serial Driver: trim trailing whitespace -- no functional changes

In reply to Alan Cox

From: Mike Frysinger <[email protected]>

---

 drivers/serial/bfin_5xx.c |    8 ++++----
 1 files changed, 4 insertions(+), 4 deletions(-)
drivers/serial/bfin_5xx.c +4 -4
index 04eeef0..976de91 100644
@@ -1,7 +1,7 @@
 /*
  * Blackfin On-Chip Serial Driver
  *
- * Copyright 2006-2007 Analog Devices Inc.
+ * Copyright 2006-2008 Analog Devices Inc.
  *
  * Enter bugs at http://blackfin.uclinux.org/
  *
@@ -126,13 +126,13 @@ static int kgdb_entry_state;
 void kgdb_put_debug_char(int chr)
 {
 	struct bfin_serial_port *uart;
-	
+
 	if (CONFIG_KGDB_UART_PORT < 0
 		|| CONFIG_KGDB_UART_PORT >= BFIN_UART_NR_PORTS)
 		uart = &bfin_serial_ports[0];
 	else
 		uart = &bfin_serial_ports[CONFIG_KGDB_UART_PORT];
-	
+
 	while (!(UART_GET_LSR(uart) & THRE)) {
 		SSYNC();
 	}
@@ -152,7 +152,7 @@ int kgdb_get_debug_char(void)
 		uart = &bfin_serial_ports[0];
 	else
 		uart = &bfin_serial_ports[CONFIG_KGDB_UART_PORT];
-	
+
 	while(!(UART_GET_LSR(uart) & DR)) {
 		SSYNC();
 	}
author
#9 lore raw

PATCH 9/76 Blackfin Serial Driver: move common variables out of serial headers and into the serial driver

In reply to Alan Cox

From: Mike Frysinger <[email protected]>

move common variables out of serial headers and into the serial driver and rename "nr_ports" to "nr_active_ports" so as to easily differentiat between BFIN_UART_NR_PORTS (the # of available) and nr_ports (the # of enabled)

---

 .../mach-bf527/include/mach/bfin_serial_5xx.h      |    3 ---
 .../mach-bf533/include/mach/bfin_serial_5xx.h      |    2 --
 .../mach-bf537/include/mach/bfin_serial_5xx.h      |    3 ---
 .../mach-bf548/include/mach/bfin_serial_5xx.h      |    3 ---
 .../mach-bf561/include/mach/bfin_serial_5xx.h      |    2 --
 drivers/serial/bfin_5xx.c                          |   17 ++++++++++-------
 6 files changed, 10 insertions(+), 20 deletions(-)
arch/blackfin/mach-bf527/include/mach/bfin_serial_5xx.h +0 -3
index 2526b6e..a23d047 100644
@@ -119,7 +119,6 @@ static inline void UART_CLEAR_LSR(struct bfin_serial_port *uart)
 	bfin_write16(uart->port.membase + OFFSET_LSR, -1);
 }
 
-struct bfin_serial_port bfin_serial_ports[BFIN_UART_NR_PORTS];
 struct bfin_serial_res {
 	unsigned long uart_base_addr;
 	int uart_irq;
@@ -164,8 +163,6 @@ struct bfin_serial_res bfin_serial_resource[] = {
 #endif
 };
 
-int nr_ports = ARRAY_SIZE(bfin_serial_resource);
-
 #define DRIVER_NAME "bfin-uart"
 
 static void bfin_serial_hw_init(struct bfin_serial_port *uart)
arch/blackfin/mach-bf533/include/mach/bfin_serial_5xx.h +0 -2
index ebf592b..20471cd 100644
@@ -111,7 +111,6 @@ static inline void UART_CLEAR_LSR(struct bfin_serial_port *uart)
 	bfin_write16(uart->port.membase + OFFSET_LSR, -1);
 }
 
-struct bfin_serial_port bfin_serial_ports[BFIN_UART_NR_PORTS];
 struct bfin_serial_res {
 	unsigned long	uart_base_addr;
 	int		uart_irq;
@@ -142,7 +141,6 @@ struct bfin_serial_res bfin_serial_resource[] = {
 
 #define DRIVER_NAME "bfin-uart"
 
-int nr_ports = BFIN_UART_NR_PORTS;
 static void bfin_serial_hw_init(struct bfin_serial_port *uart)
 {
 
arch/blackfin/mach-bf537/include/mach/bfin_serial_5xx.h +0 -3
index 1bf56ff..08dfe30 100644
@@ -119,7 +119,6 @@ static inline void UART_CLEAR_LSR(struct bfin_serial_port *uart)
 	bfin_write16(uart->port.membase + OFFSET_LSR, -1);
 }
 
-struct bfin_serial_port bfin_serial_ports[BFIN_UART_NR_PORTS];
 struct bfin_serial_res {
 	unsigned long	uart_base_addr;
 	int		uart_irq;
@@ -164,8 +163,6 @@ struct bfin_serial_res bfin_serial_resource[] = {
 #endif
 };
 
-int nr_ports = ARRAY_SIZE(bfin_serial_resource);
-
 #define DRIVER_NAME "bfin-uart"
 
 static void bfin_serial_hw_init(struct bfin_serial_port *uart)
arch/blackfin/mach-bf548/include/mach/bfin_serial_5xx.h +0 -3
index 5e29446..76976b1 100644
@@ -105,7 +105,6 @@ struct bfin_serial_port {
 #endif
 };
 
-struct bfin_serial_port bfin_serial_ports[BFIN_UART_NR_PORTS];
 struct bfin_serial_res {
 	unsigned long	uart_base_addr;
 	int		uart_irq;
@@ -170,8 +169,6 @@ struct bfin_serial_res bfin_serial_resource[] = {
 #endif
 };
 
-int nr_ports = ARRAY_SIZE(bfin_serial_resource);
-
 #define DRIVER_NAME "bfin-uart"
 
 static void bfin_serial_hw_init(struct bfin_serial_port *uart)
arch/blackfin/mach-bf561/include/mach/bfin_serial_5xx.h +0 -2
index 8aa0278..6cddca4 100644
@@ -111,7 +111,6 @@ static inline void UART_CLEAR_LSR(struct bfin_serial_port *uart)
 	bfin_write16(uart->port.membase + OFFSET_LSR, -1);
 }
 
-struct bfin_serial_port bfin_serial_ports[BFIN_UART_NR_PORTS];
 struct bfin_serial_res {
 	unsigned long	uart_base_addr;
 	int		uart_irq;
@@ -142,7 +141,6 @@ struct bfin_serial_res bfin_serial_resource[] = {
 
 #define DRIVER_NAME "bfin-uart"
 
-int nr_ports = BFIN_UART_NR_PORTS;
 static void bfin_serial_hw_init(struct bfin_serial_port *uart)
 {
 
drivers/serial/bfin_5xx.c +10 -7
index 976de91..382fb8d 100644
@@ -42,6 +42,9 @@
 #define BFIN_SERIAL_MAJOR	204
 #define BFIN_SERIAL_MINOR	64
 
+static struct bfin_serial_port bfin_serial_ports[BFIN_UART_NR_PORTS];
+static int nr_active_ports = ARRAY_SIZE(bfin_serial_resource);
+
 /*
  * Setup for console. Argument comes from the menuconfig
  */
@@ -859,7 +862,7 @@ static void __init bfin_serial_init_ports(void)
 		return;
 	first = 0;
 
-	for (i = 0; i < nr_ports; i++) {
+	for (i = 0; i < nr_active_ports; i++) {
 		bfin_serial_ports[i].port.uartclk   = get_sclk();
 		bfin_serial_ports[i].port.ops       = &bfin_serial_pops;
 		bfin_serial_ports[i].port.line      = i;
@@ -961,7 +964,7 @@ bfin_serial_console_setup(struct console *co, char *options)
 	 * if so, search for the first available port that does have
 	 * console support.
 	 */
-	if (co->index == -1 || co->index >= nr_ports)
+	if (co->index == -1 || co->index >= nr_active_ports)
 		co->index = 0;
 	uart = &bfin_serial_ports[co->index];
 
@@ -1072,7 +1075,7 @@ struct console __init *bfin_earlyserial_init(unsigned int port,
 	struct bfin_serial_port *uart;
 	struct ktermios t;
 
-	if (port == -1 || port >= nr_ports)
+	if (port == -1 || port >= nr_active_ports)
 		port = 0;
 	bfin_serial_init_ports();
 	bfin_early_serial_console.index = port;
@@ -1102,7 +1105,7 @@ static int bfin_serial_suspend(struct platform_device *dev, pm_message_t state)
 {
 	int i;
 
-	for (i = 0; i < nr_ports; i++) {
+	for (i = 0; i < nr_active_ports; i++) {
 		if (bfin_serial_ports[i].port.dev != &dev->dev)
 			continue;
 		uart_suspend_port(&bfin_serial_reg, &bfin_serial_ports[i].port);
@@ -1115,7 +1118,7 @@ static int bfin_serial_resume(struct platform_device *dev)
 {
 	int i;
 
-	for (i = 0; i < nr_ports; i++) {
+	for (i = 0; i < nr_active_ports; i++) {
 		if (bfin_serial_ports[i].port.dev != &dev->dev)
 			continue;
 		uart_resume_port(&bfin_serial_reg, &bfin_serial_ports[i].port);
@@ -1134,7 +1137,7 @@ static int bfin_serial_probe(struct platform_device *dev)
 			break;
 
 	if (i < dev->num_resources) {
-		for (i = 0; i < nr_ports; i++, res++) {
+		for (i = 0; i < nr_active_ports; i++, res++) {
 			if (bfin_serial_ports[i].port.mapbase != res->start)
 				continue;
 			bfin_serial_ports[i].port.dev = &dev->dev;
@@ -1149,7 +1152,7 @@ static int bfin_serial_remove(struct platform_device *dev)
 {
 	int i;
 
-	for (i = 0; i < nr_ports; i++) {
+	for (i = 0; i < nr_active_ports; i++) {
 		if (bfin_serial_ports[i].port.dev != &dev->dev)
 			continue;
 		uart_remove_one_port(&bfin_serial_reg, &bfin_serial_ports[i].port);
author
#10 lore raw

PATCH 10/76 Blackfin Serial Driver: Remove useless stop

In reply to Alan Cox

From: Sonic Zhang <[email protected]>

---

 drivers/serial/bfin_5xx.c |    3 ---
 1 files changed, 0 insertions(+), 3 deletions(-)
drivers/serial/bfin_5xx.c +0 -3
index 382fb8d..8d2d757 100644
@@ -320,9 +320,6 @@ static void bfin_serial_tx_chars(struct bfin_serial_port *uart)
 
 	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
 		uart_write_wakeup(&uart->port);
-
-	if (uart_circ_empty(xmit))
-		bfin_serial_stop_tx(&uart->port);
 }
 
 static irqreturn_t bfin_serial_rx_int(int irq, void *dev_id)
author
#11 lore raw

PATCH 11/76 Blackfin Serial Driver: Fix bug - Don't call tx_stop in tx_transfer.

In reply to Alan Cox

From: Sonic Zhang <[email protected]>

Disable irq and return immediately.

---

 drivers/serial/bfin_5xx.c |    6 +++++-
 1 files changed, 5 insertions(+), 1 deletions(-)
drivers/serial/bfin_5xx.c +5 -1
index 8d2d757..5e20f50 100644
@@ -301,7 +301,11 @@ static void bfin_serial_tx_chars(struct bfin_serial_port *uart)
 	bfin_serial_mctrl_check(uart);
 
 	if (uart_circ_empty(xmit) || uart_tx_stopped(&uart->port)) {
-		bfin_serial_stop_tx(&uart->port);
+#ifdef CONFIG_BF54x
+		/* Clear TFI bit */
+		UART_PUT_LSR(uart, TFI);
+#endif
+		UART_CLEAR_IER(uart, ETBEI);
 		return;
 	}
 
author
#12 lore raw

PATCH 12/76 Blackfin Serial Driver: Fix bug - ircp fails on sir over Blackfin UART

In reply to Alan Cox

From: Graf Yang <[email protected]>

We now use the sir_dev/irtty_sir/uart/bfin_serial drivers framework to monitor the TX status.

---

 .../mach-bf527/include/mach/bfin_serial_5xx.h      |    3 +++
 .../mach-bf533/include/mach/bfin_serial_5xx.h      |    2 ++
 .../mach-bf537/include/mach/bfin_serial_5xx.h      |    3 +++
 .../mach-bf548/include/mach/bfin_serial_5xx.h      |    3 +++
 .../mach-bf561/include/mach/bfin_serial_5xx.h      |    2 ++
 drivers/serial/bfin_5xx.c                          |    4 ++++
 6 files changed, 17 insertions(+), 0 deletions(-)
arch/blackfin/mach-bf527/include/mach/bfin_serial_5xx.h +3 -0
index a23d047..75722d6 100644
@@ -78,6 +78,9 @@
 #  define CONFIG_UART1_RTS_PIN -1
 # endif
 #endif
+
+#define BFIN_UART_TX_FIFO_SIZE	2
+
 /*
  * The pin configuration is different from schematic
  */
arch/blackfin/mach-bf533/include/mach/bfin_serial_5xx.h +2 -0
index 20471cd..815bfe5 100644
@@ -69,6 +69,8 @@
 # endif
 #endif
 
+#define BFIN_UART_TX_FIFO_SIZE	2
+
 struct bfin_serial_port {
         struct uart_port        port;
         unsigned int            old_status;
arch/blackfin/mach-bf537/include/mach/bfin_serial_5xx.h +3 -0
index 08dfe30..b3f87e1 100644
@@ -78,6 +78,9 @@
 #  define CONFIG_UART1_RTS_PIN -1
 # endif
 #endif
+
+#define BFIN_UART_TX_FIFO_SIZE	2
+
 /*
  * The pin configuration is different from schematic
  */
arch/blackfin/mach-bf548/include/mach/bfin_serial_5xx.h +3 -0
index 76976b1..e4cf35e 100644
@@ -82,6 +82,9 @@
 #  define CONFIG_UART1_RTS_PIN -1
 # endif
 #endif
+
+#define BFIN_UART_TX_FIFO_SIZE	2
+
 /*
  * The pin configuration is different from schematic
  */
arch/blackfin/mach-bf561/include/mach/bfin_serial_5xx.h +2 -0
index 6cddca4..e0ce0c1 100644
@@ -69,6 +69,8 @@
 # endif
 #endif
 
+#define BFIN_UART_TX_FIFO_SIZE	2
+
 struct bfin_serial_port {
         struct uart_port        port;
         unsigned int            old_status;
drivers/serial/bfin_5xx.c +4 -0
index 5e20f50..a5cf0e7 100644
@@ -761,6 +761,9 @@ bfin_serial_set_termios(struct uart_port *port, struct ktermios *termios,
 	val |= UCEN;
 	UART_PUT_GCTL(uart, val);
 
+	/* Port speed changed, update the per-port timeout. */
+	uart_update_timeout(port, termios->c_cflag, baud);
+
 	spin_unlock_irqrestore(&uart->port.lock, flags);
 }
 
@@ -865,6 +868,7 @@ static void __init bfin_serial_init_ports(void)
 
 	for (i = 0; i < nr_active_ports; i++) {
 		bfin_serial_ports[i].port.uartclk   = get_sclk();
+		bfin_serial_ports[i].port.fifosize  = BFIN_UART_TX_FIFO_SIZE;
 		bfin_serial_ports[i].port.ops       = &bfin_serial_pops;
 		bfin_serial_ports[i].port.line      = i;
 		bfin_serial_ports[i].port.iotype    = UPIO_MEM;
author
#13 lore raw

PATCH 13/76 Blackfin Serial Driver: Fix bug - request UART2/3 peripheral mapped interrupts in PIO mode

In reply to Alan Cox

From: Sonic Zhang <[email protected]>

---

 arch/blackfin/kernel/bfin_dma_5xx.c |   13 ++++-----
 drivers/serial/bfin_5xx.c           |   50 +++++++++++++++++++++++++++++++++++
 2 files changed, 56 insertions(+), 7 deletions(-)
arch/blackfin/kernel/bfin_dma_5xx.c +6 -7
index 93229b3..339293d 100644
@@ -117,15 +117,14 @@ int request_dma(unsigned int channel, char *device_id)
 
 #ifdef CONFIG_BF54x
 	if (channel >= CH_UART2_RX && channel <= CH_UART3_TX) {
-		if (strncmp(device_id, "BFIN_UART", 9) == 0) {
-			dma_ch[channel].regs->peripheral_map &= 0x0FFF;
-			dma_ch[channel].regs->peripheral_map |=
+		unsigned int per_map;
+		per_map = dma_ch[channel].regs->peripheral_map & 0xFFF;
+		if (strncmp(device_id, "BFIN_UART", 9) == 0)
+			dma_ch[channel].regs->peripheral_map = per_map |
 				((channel - CH_UART2_RX + 0xC)<<12);
-		} else {
-			dma_ch[channel].regs->peripheral_map &= 0x0FFF;
-			dma_ch[channel].regs->peripheral_map |=
+		else
+			dma_ch[channel].regs->peripheral_map = per_map |
 				((channel - CH_UART2_RX + 0x6)<<12);
-		}
 	}
 #endif
 
drivers/serial/bfin_5xx.c +50 -0

62 lines not on this page · raw message

author
#14 lore raw

PATCH 14/76 tty: move tioclinux from a special case

In reply to Alan Cox

Right now we have ifdefs and hooks in the core ioctl handler for TIOCLINUX and then test if its a console. This is brain dead. Instead call the tioclinux helper from the relevant driver ioctl methods.

---

 drivers/char/tty_io.c   |    4 ----
 drivers/char/vt.c       |    2 --
 drivers/char/vt_ioctl.c |    2 ++
 3 files changed, 2 insertions(+), 6 deletions(-)
drivers/char/tty_io.c +0 -4
index e4dce87..2f05728 100644
@@ -3026,10 +3026,6 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 		return put_user(tty->ldisc.ops->num, (int __user *)p);
 	case TIOCSETD:
 		return tiocsetd(tty, p);
-#ifdef CONFIG_VT
-	case TIOCLINUX:
-		return tioclinux(tty, arg);
-#endif
 	/*
 	 * Break handling
 	 */
drivers/char/vt.c +0 -2
index 60359c3..05ca1c5 100644
@@ -2583,8 +2583,6 @@ int tioclinux(struct tty_struct *tty, unsigned long arg)
 	int lines;
 	int ret;
 
-	if (tty->driver->type != TTY_DRIVER_TYPE_CONSOLE)
-		return -EINVAL;
 	if (current->signal->tty != tty && !capable(CAP_SYS_ADMIN))
 		return -EPERM;
 	if (get_user(type, p))
drivers/char/vt_ioctl.c +2 -0
index c904e9a..8944ce5 100644
@@ -395,6 +395,8 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
  
 	kbd = kbd_table + console;
 	switch (cmd) {
+	case TIOCLINUX:
+		return tioclinux(tty, arg);
 	case KIOCSOUND:
 		if (!perm)
 			goto eperm;
author
#15 lore raw

PATCH 15/76 uml: small cleanups and note bugs to be dealt with by uml authors...

In reply to Alan Cox

---

 arch/um/drivers/line.c |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)
arch/um/drivers/line.c +2 -0
index d741f35..14a102e 100644
@@ -275,6 +275,8 @@ int line_ioctl(struct tty_struct *tty, struct file * file,
 	case TIOCGLTC:
 	case TIOCSLTC:
 #endif
+	/* Note: these are out of date as we now have TCGETS2 etc but this
+	   whole lot should probably go away */
 	case TCGETS:
 	case TCSETSF:
 	case TCSETSW:
author
#16 lore raw

PATCH 16/76 Char: merge ip2main and ip2base

In reply to Alan Cox

From: Jiri Slaby <[email protected]>

It's pretty useless to have one setup() function separated along with module_init() which only calls a function from ip2main anyway. Get rid of ip2base.

Remove also checks of always-true now.

---

 drivers/char/ip2/Makefile  |    2 -
 drivers/char/ip2/ip2base.c |  108 --------------------------------------------
 drivers/char/ip2/ip2main.c |   92 +++++++++++++++++++++++++++++++------
 3 files changed, 77 insertions(+), 125 deletions(-)
 delete mode 100644 drivers/char/ip2/ip2base.c
drivers/char/ip2/Makefile +1 -1
index 939618f..bc397d9 100644
@@ -4,5 +4,5 @@
 
 obj-$(CONFIG_COMPUTONE)         += ip2.o
 
-ip2-objs			:= ip2base.o ip2main.o
+ip2-objs			:= ip2main.o
 
drivers/char/ip2/ip2base.c deleted +0 -108

108 lines not on this page · raw message

drivers/char/ip2/ip2main.c +76 -16

140 lines not on this page · raw message

author
#17 lore raw

PATCH 17/76 ip2, cleanup globals

In reply to Alan Cox

From: Jiri Slaby <[email protected]>

- do not init .bss zeroed data to zero again (by memset or explicit assignment)
- use char [] instead of char * for string constants

---

 drivers/char/ip2/ip2main.c |   18 +++++++-----------
 1 files changed, 7 insertions(+), 11 deletions(-)
drivers/char/ip2/ip2main.c +7 -11
index 79bca61..1d46284 100644
@@ -150,12 +150,12 @@ static int ip2_read_proc(char *, char **, off_t, int, int *, void * );
 /*************/
 
 /* String constants to identify ourselves */
-static char *pcName    = "Computone IntelliPort Plus multiport driver";
-static char *pcVersion = "1.2.14";
+static const char pcName[] = "Computone IntelliPort Plus multiport driver";
+static const char pcVersion[] = "1.2.14";
 
 /* String constants for port names */
-static char *pcDriver_name   = "ip2";
-static char *pcIpl    		 = "ip2ipl";
+static const char pcDriver_name[] = "ip2";
+static const char pcIpl[] = "ip2ipl";
 
 /***********************/
 /* Function Prototypes */
@@ -237,8 +237,8 @@ static const struct file_operations ip2_ipl = {
 	.open		= ip2_ipl_open,
 }; 
 
-static unsigned long irq_counter = 0;
-static unsigned long bh_counter = 0;
+static unsigned long irq_counter;
+static unsigned long bh_counter;
 
 // Use immediate queue to service interrupts
 #define USE_IQI
@@ -286,7 +286,7 @@ MODULE_AUTHOR("Doug McNash");
 MODULE_DESCRIPTION("Computone IntelliPort Plus Driver");
 MODULE_LICENSE("GPL");
 
-static int poll_only = 0;
+static int poll_only;
 
 static int Eisa_irq;
 static int Eisa_slot;
@@ -615,10 +615,6 @@ static int ip2_loadmain(void)
 	/* Initialise the iiEllis subsystem. */
 	iiEllisInit();
 
-	/* Initialize arrays. */
-	memset( i2BoardPtrTable, 0, sizeof i2BoardPtrTable );
-	memset( DevTable, 0, sizeof DevTable );
-
 	/* Initialise all the boards we can find (up to the maximum). */
 	for ( i = 0; i < IP2_MAX_BOARDS; ++i ) {
 		switch ( ip2config.addr[i] ) { 
author
#18 lore raw

PATCH 18/76 ip2, fix sparse warnings

In reply to Alan Cox

From: Jiri Slaby <[email protected]>

---

 drivers/char/ip2/ip2main.c |   14 +++++---------
 1 files changed, 5 insertions(+), 9 deletions(-)
drivers/char/ip2/ip2main.c +5 -9
index 1d46284..098c9de 100644
@@ -375,9 +375,7 @@ have_requested_irq( char irq )
 /* handle subsequent installations of the driver. All memory allocated by the */
 /* driver should be returned since it may be unloaded from memory.            */
 /******************************************************************************/
-#ifdef MODULE
-void __exit
-ip2_cleanup_module(void)
+static void __exit ip2_cleanup_module(void)
 {
 	int err;
 	int i;
@@ -431,7 +429,8 @@ ip2_cleanup_module(void)
 			ip2config.pci_dev[i] = NULL;
 		}
 #endif
-		if ((pB = i2BoardPtrTable[i]) != 0 ) {
+		pB = i2BoardPtrTable[i];
+		if (pB != NULL) {
 			kfree ( pB );
 			i2BoardPtrTable[i] = NULL;
 		}
@@ -448,7 +447,6 @@ ip2_cleanup_module(void)
 #endif
 }
 module_exit(ip2_cleanup_module);
-#endif /* MODULE */
 
 static const struct tty_operations ip2_ops = {
 	.open            = ip2_open,
@@ -1255,9 +1253,8 @@ ip2_polled_interrupt(void)
 {
 	int i;
 	i2eBordStrPtr  pB;
-	const int irq = 0;
 
-	ip2trace (ITRC_NO_PORT, ITRC_INTR, 99, 1, irq );
+	ip2trace(ITRC_NO_PORT, ITRC_INTR, 99, 1, 0);
 
 	/* Service just the boards on the list using this irq */
 	for( i = 0; i < i2nBoards; ++i ) {
@@ -1266,9 +1263,8 @@ ip2_polled_interrupt(void)
 //		Only process those boards which match our IRQ.
 //			IRQ = 0 for polled boards, we won't poll "IRQ" boards
 
-		if ( pB && (pB->i2eUsingIrq == irq) ) {
+		if (pB && pB->i2eUsingIrq == 0)
 			ip2_irq_work(pB);
-		}
 	}
 
 	++irq_counter;
author
#19 lore raw

PATCH 19/76 ip2, init/deinit cleanup

In reply to Alan Cox

From: Jiri Slaby <[email protected]>

Cleanup of module_init/exit:
- mostly whitespace
- remove empty functions
- replace c++ comments
- remove useless prints (module loaded, unloaded)
- mark the calls as __exit and __init
- use break; and return; to save some indent levels after it
- note resource leakage

It's still mess, but now it's readable.

---

 drivers/char/ip2/i2ellis.c |   32 ---
 drivers/char/ip2/i2ellis.h |    2 
 drivers/char/ip2/ip2main.c |  415 +++++++++++++++++++++-----------------------
 3 files changed, 198 insertions(+), 251 deletions(-)
drivers/char/ip2/i2ellis.c +0 -32
index 3601017..29db44d 100644
@@ -69,38 +69,6 @@ static DEFINE_RWLOCK(Dl_spinlock);
 //=======================================================
 
 //******************************************************************************
-// Function:   iiEllisInit()
-// Parameters: None
-//
-// Returns:    Nothing
-//
-// Description:
-//
-// This routine performs any required initialization of the iiEllis subsystem.
-//
-//******************************************************************************
-static void
-iiEllisInit(void)
-{
-}
-
-//******************************************************************************
-// Function:   iiEllisCleanup()
-// Parameters: None
-//
-// Returns:    Nothing
-//
-// Description:
-//
-// This routine performs any required cleanup of the iiEllis subsystem.
-//
-//******************************************************************************
-static void
-iiEllisCleanup(void)
-{
-}
-
-//******************************************************************************
 // Function:   iiSetAddress(pB, address, delay)
 // Parameters: pB      - pointer to the board structure
 //             address - the purported I/O address of the board
drivers/char/ip2/i2ellis.h +0 -2
index c88a64e..fb6df24 100644
@@ -511,7 +511,6 @@ typedef void (*delayFunc_t)(unsigned int);
 //
 // Initialization of a board & structure is in four (five!) parts:
 //
-// 0) iiEllisInit()  - Initialize iiEllis subsystem.
 // 1) iiSetAddress() - Define the board address & delay function for a board.
 // 2) iiReset()      - Reset the board   (provided it exists)
 //       -- Note you may do this to several boards --
@@ -523,7 +522,6 @@ typedef void (*delayFunc_t)(unsigned int);
 // loadware.  To change loadware, you must begin again with step 2, resetting
 // the board again (step 1 not needed).
 
-static void iiEllisInit(void);
 static int iiSetAddress(i2eBordStrPtr, int, delayFunc_t );
 static int iiReset(i2eBordStrPtr);
 static int iiResetDelay(i2eBordStrPtr);
drivers/char/ip2/ip2main.c +198 -217

585 lines not on this page · raw message

author
#20 lore raw

PATCH 20/76 ip2: avoid add_timer with pending timer

In reply to Alan Cox

From: Akinobu Mita <[email protected]>

add_timer() is not suppose to be called when the timer is pending. ip2 driver attempts to avoid that condition by setting and resetting a flag (TimerOn) in timer function. But there is some gap between add_timer() and setting TimerOn.

This patch fix this problem by using mod_timer() and remove TimerOn which has been unnecessary by this change.

---

 drivers/char/ip2/ip2main.c |   19 ++++---------------
 1 files changed, 4 insertions(+), 15 deletions(-)
drivers/char/ip2/ip2main.c +4 -15
index 39269d1..66f52a2 100644
@@ -249,7 +249,6 @@ static unsigned long bh_counter;
  */
 #define  POLL_TIMEOUT   (jiffies + 1)
 static DEFINE_TIMER(PollTimer, ip2_poll, 0, 0);
-static char  TimerOn;
 
 #ifdef IP2DEBUG_TRACE
 /* Trace (debug) buffer data */
@@ -374,11 +373,7 @@ static void __exit ip2_cleanup_module(void)
 	int err;
 	int i;
 
-	/* Stop poll timer if we had one. */
-	if (TimerOn) {
-		del_timer(&PollTimer);
-		TimerOn = 0;
-	}
+	del_timer_sync(&PollTimer);
 
 	/* Reset the boards we have. */
 	for (i = 0; i < IP2_MAX_BOARDS; i++)
@@ -774,10 +769,8 @@ static int __init ip2_loadmain(void)
 		}
 		if (ip2config.irq[i] == CIR_POLL) {
 retry:
-			if (!TimerOn) {
-				PollTimer.expires = POLL_TIMEOUT;
-				add_timer(&PollTimer);
-				TimerOn = 1;
+			if (!timer_pending(&PollTimer)) {
+				mod_timer(&PollTimer, POLL_TIMEOUT);
 				printk(KERN_INFO "IP2: polling\n");
 			}
 		} else {
@@ -1283,16 +1276,12 @@ ip2_poll(unsigned long arg)
 {
 	ip2trace (ITRC_NO_PORT, ITRC_INTR, 100, 0 );
 
-	TimerOn = 0; // it's the truth but not checked in service
-
 	// Just polled boards, IRQ = 0 will hit all non-interrupt boards.
 	// It will NOT poll boards handled by hard interrupts.
 	// The issue of queued BH interrupts is handled in ip2_interrupt().
 	ip2_polled_interrupt();
 
-	PollTimer.expires = POLL_TIMEOUT;
-	add_timer( &PollTimer );
-	TimerOn = 1;
+	mod_timer(&PollTimer, POLL_TIMEOUT);
 
 	ip2trace (ITRC_NO_PORT, ITRC_INTR, ITRC_RETURN, 0 );
 }
author
#21 lore raw

PATCH 21/76 audit: Handle embedded NUL in TTY input auditing

In reply to Alan Cox

From: Miloslav Trmac <[email protected]>

Data read from a TTY can contain an embedded NUL byte (e.g. after pressing Ctrl-2, or sent to a PTY). After the previous patch, the data would be logged only up to the first NUL.

This patch modifies the AUDIT_TTY record to always use the hexadecimal format, which does not terminate at the first NUL byte. The vast majority of recorded TTY input data will contain either ' ' or '\n', so the hexadecimal format would have been used anyway.

---

 drivers/char/tty_audit.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
drivers/char/tty_audit.c +1 -1
index 3582f43..5787249 100644
@@ -93,7 +93,7 @@ static void tty_audit_buf_push(struct task_struct *tsk, uid_t loginuid,
 		get_task_comm(name, tsk);
 		audit_log_untrustedstring(ab, name);
 		audit_log_format(ab, " data=");
-		audit_log_n_untrustedstring(ab, buf->data, buf->valid);
+		audit_log_n_hex(ab, buf->data, buf->valid);
 		audit_log_end(ab);
 	}
 	buf->valid = 0;
author
#22 lore raw

PATCH 22/76 serial: Make uart_port's ioport "unsigned long".

In reply to Alan Cox

From: David Miller <[email protected]>

Otherwise the top 32-bits of the resource value get chopped off on 64-bit systems, and the resulting I/O accesses go to random places.

Thanks to testing and debugging by Josip Rodin, which helped track this down.

---

 include/linux/serial_core.h |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
include/linux/serial_core.h +1 -1
index 3b2f6c0..e27f216 100644
@@ -241,7 +241,7 @@ typedef unsigned int __bitwise__ upf_t;
 
 struct uart_port {
 	spinlock_t		lock;			/* port lock */
-	unsigned int		iobase;			/* in/out[bwl] */
+	unsigned long		iobase;			/* in/out[bwl] */
 	unsigned char __iomem	*membase;		/* read/write[bwl] */
 	unsigned int		irq;			/* irq number */
 	unsigned int		uartclk;		/* base uart clock */
#23 lore raw

Re: [PATCH 22/76] serial: Make uart_port's ioport "unsigned long".

Quoted 21 lines · Alan Cox

From: David Miller <[email protected]>

Otherwise the top 32-bits of the resource value get chopped off on 64-bit systems, and the resulting I/O accesses go to random places.

Thanks to testing and debugging by Josip Rodin, which helped track this down.

---

include/linux/serial_core.h | 2 +-

1 files changed, 1 insertions(+), 1 deletions(-)
include/linux/serial_core.h +0 -0
index 3b2f6c0..e27f216 100644

include/linux/serial_core.h typedef unsigned int __bitwise__ upf_t; · line 244

Quoted 5 lines
include/linux/serial_core.h +1 -1
@@ -241,7 +241,7 @@ typedef unsigned int __bitwise__ upf_t;
 
 struct uart_port {
 	spinlock_t		lock;			/* port lock */
-	unsigned int		iobase;			/* in/out[bwl] */
+	unsigned long		iobase;			/* in/out[bwl] */

Does using resource_size_t make more sense here? There are 32-bit CPUs that have 64-bit address spaces. (Perhaps not that use iobase, but it might be cleaner in general.)

josh

author
#24 lore raw

PATCH 23/76 tty: split the buffering from tty_io

In reply to Alan Cox

The two are basically independent chunks of code so lets split them up for readability and sanity. It also makes the API boundaries much clearer.

---

 drivers/char/Makefile     |    2 
 drivers/char/tty_buffer.c |  511 +++++++++++++++++++++++++++++++++++++++++++++
 drivers/char/tty_io.c     |  502 --------------------------------------------
 include/linux/tty.h       |    3 
 4 files changed, 515 insertions(+), 503 deletions(-)
 create mode 100644 drivers/char/tty_buffer.c
drivers/char/Makefile +1 -1
index 6850f6d..77ea41b 100644
@@ -7,7 +7,7 @@
 #
 FONTMAPFILE = cp437.uni
 
-obj-y	 += mem.o random.o tty_io.o n_tty.o tty_ioctl.o tty_ldisc.o 
+obj-y	 += mem.o random.o tty_io.o n_tty.o tty_ioctl.o tty_ldisc.o tty_buffer.o
 
 obj-$(CONFIG_LEGACY_PTYS)	+= pty.o
 obj-$(CONFIG_UNIX98_PTYS)	+= pty.o
drivers/char/tty_buffer.c new file +511 -0

511 lines not on this page · raw message

drivers/char/tty_io.c +0 -502

526 lines not on this page · raw message

include/linux/tty.h +3 -0
index 0cbec74..7271c62 100644
@@ -347,6 +347,9 @@ extern void __do_SAK(struct tty_struct *tty);
 extern void disassociate_ctty(int priv);
 extern void no_tty(void);
 extern void tty_flip_buffer_push(struct tty_struct *tty);
+extern void tty_buffer_free_all(struct tty_struct *tty);
+extern void tty_buffer_flush(struct tty_struct *tty);
+extern void tty_buffer_init(struct tty_struct *tty);
 extern speed_t tty_get_baud_rate(struct tty_struct *tty);
 extern speed_t tty_termios_baud_rate(struct ktermios *termios);
 extern speed_t tty_termios_input_baud_rate(struct ktermios *termios);
author
#25 lore raw

PATCH 24/76 tty: Split tty_port into its own file

In reply to Alan Cox

Not much in it yet but this will grow a lot

---

 drivers/char/Makefile   |    2 +-
 drivers/char/tty_io.c   |   36 -------------------------------
 drivers/char/tty_port.c |   55 +++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 56 insertions(+), 37 deletions(-)
 create mode 100644 drivers/char/tty_port.c
drivers/char/Makefile +1 -1
index 77ea41b..1a4247d 100644
@@ -7,7 +7,7 @@
 #
 FONTMAPFILE = cp437.uni
 
-obj-y	 += mem.o random.o tty_io.o n_tty.o tty_ioctl.o tty_ldisc.o tty_buffer.o
+obj-y	 += mem.o random.o tty_io.o n_tty.o tty_ioctl.o tty_ldisc.o tty_buffer.o tty_port.o
 
 obj-$(CONFIG_LEGACY_PTYS)	+= pty.o
 obj-$(CONFIG_UNIX98_PTYS)	+= pty.o
drivers/char/tty_io.c +0 -36
index 3a72693..7323168 100644
@@ -1139,42 +1139,6 @@ ssize_t redirected_tty_write(struct file *file, const char __user *buf,
 	return tty_write(file, buf, count, ppos);
 }
 
-void tty_port_init(struct tty_port *port)
-{
-	memset(port, 0, sizeof(*port));
-	init_waitqueue_head(&port->open_wait);
-	init_waitqueue_head(&port->close_wait);
-	mutex_init(&port->mutex);
-	port->close_delay = (50 * HZ) / 100;
-	port->closing_wait = (3000 * HZ) / 100;
-}
-EXPORT_SYMBOL(tty_port_init);
-
-int tty_port_alloc_xmit_buf(struct tty_port *port)
-{
-	/* We may sleep in get_zeroed_page() */
-	mutex_lock(&port->mutex);
-	if (port->xmit_buf == NULL)
-		port->xmit_buf = (unsigned char *)get_zeroed_page(GFP_KERNEL);
-	mutex_unlock(&port->mutex);
-	if (port->xmit_buf == NULL)
-		return -ENOMEM;
-	return 0;
-}
-EXPORT_SYMBOL(tty_port_alloc_xmit_buf);
-
-void tty_port_free_xmit_buf(struct tty_port *port)
-{
-	mutex_lock(&port->mutex);
-	if (port->xmit_buf != NULL) {
-		free_page((unsigned long)port->xmit_buf);
-		port->xmit_buf = NULL;
-	}
-	mutex_unlock(&port->mutex);
-}
-EXPORT_SYMBOL(tty_port_free_xmit_buf);
-
-
 static char ptychar[] = "pqrstuvwxyzabcde";
 
 /**
drivers/char/tty_port.c new file +55 -0

55 lines not on this page · raw message

author
#26 lore raw

PATCH 25/76 pps: Reserve a line discipline number for PPS

In reply to Alan Cox

Add a new line discipline for "pulse per second" devices connected to a serial port.

---

 include/linux/tty.h |    3 ++-
 1 files changed, 2 insertions(+), 1 deletions(-)
include/linux/tty.h +2 -1
index 7271c62..e3612c3 100644
@@ -23,7 +23,7 @@
  */
 #define NR_UNIX98_PTY_DEFAULT	4096      /* Default maximum for Unix98 ptys */
 #define NR_UNIX98_PTY_MAX	(1 << MINORBITS) /* Absolute limit */
-#define NR_LDISCS		18
+#define NR_LDISCS		19
 
 /* line disciplines */
 #define N_TTY		0
@@ -45,6 +45,7 @@
 #define N_HCI		15	/* Bluetooth HCI UART */
 #define N_GIGASET_M101	16	/* Siemens Gigaset M101 serial DECT adapter */
 #define N_SLCAN		17	/* Serial / USB serial CAN Adaptors */
+#define N_PPS		18	/* Pulse per Second */
 
 /*
  * This character is the same as _POSIX_VDISABLE: it cannot be used as
author
#27 lore raw

PATCH 26/76 tty: Add a kref count

In reply to Alan Cox

Introduce a kref to the tty structure and use it to protect the tty->signal tty references. For now we don't introduce it for anything else.

---

 drivers/char/tty_io.c |   54 ++++++++++++++++++++++++++++++++++++++++++++-----
 include/linux/tty.h   |   18 ++++++++++++++++
 kernel/fork.c         |    5 ++++-
 kernel/sys.c          |    4 +---
 4 files changed, 71 insertions(+), 10 deletions(-)
drivers/char/tty_io.c +48 -6
index 7323168..310e070 100644
@@ -559,6 +559,7 @@ static void do_tty_hangup(struct work_struct *work)
 	struct tty_ldisc *ld;
 	int    closecount = 0, n;
 	unsigned long flags;
+	int refs = 0;
 
 	if (!tty)
 		return;
@@ -625,8 +626,12 @@ static void do_tty_hangup(struct work_struct *work)
 	if (tty->session) {
 		do_each_pid_task(tty->session, PIDTYPE_SID, p) {
 			spin_lock_irq(&p->sighand->siglock);
-			if (p->signal->tty == tty)
+			if (p->signal->tty == tty) {
 				p->signal->tty = NULL;
+				/* We defer the dereferences outside fo
+				   the tasklist lock */
+				refs++;
+			}
 			if (!p->signal->leader) {
 				spin_unlock_irq(&p->sighand->siglock);
 				continue;
@@ -652,6 +657,10 @@ static void do_tty_hangup(struct work_struct *work)
 	tty->ctrl_status = 0;
 	spin_unlock_irqrestore(&tty->ctrl_lock, flags);
 
+	/* Account for the p->signal references we killed */
+	while (refs--)
+		tty_kref_put(tty);
+
 	/*
 	 * If one of the devices matches a console pointer, we
 	 * cannot just call hangup() because that will cause
@@ -1424,6 +1433,7 @@ release_mem_out:
 
 /**
  *	release_one_tty		-	release tty structure memory
+ *	@kref: kref of tty we are obliterating
  *
  *	Releases memory associated with a tty structure, and clears out the
  *	driver table slots. This function is called when a device is no longer
@@ -1433,17 +1443,19 @@ release_mem_out:
  *		tty_mutex - sometimes only
  *		takes the file list lock internally when working on the list
  *	of ttys that the driver keeps.
- *		FIXME: should we require tty_mutex is held here ??
  */
-static void release_one_tty(struct tty_struct *tty, int idx)
+static void release_one_tty(struct kref *kref)
 {
+	struct tty_struct *tty = container_of(kref, struct tty_struct, kref);
 	int devpts = tty->driver->flags & TTY_DRIVER_DEVPTS_MEM;
 	struct ktermios *tp;
+	int idx = tty->index;
 
 	if (!devpts)
 		tty->driver->ttys[idx] = NULL;
 
 	if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS) {
+		/* FIXME: Locking on ->termios array */
 		tp = tty->termios;
 		if (!devpts)
 			tty->driver->termios[idx] = NULL;
@@ -1457,6 +1469,7 @@ static void release_one_tty(struct tty_struct *tty, int idx)
 
 
 	tty->magic = 0;
+	/* FIXME: locking on tty->driver->refcount */
 	tty->driver->refcount--;
 
 	file_list_lock();
@@ -1467,6 +1480,21 @@ static void release_one_tty(struct tty_struct *tty, int idx)
 }
 
 /**
+ *	tty_kref_put		-	release a tty kref
+ *	@tty: tty device
+ *
+ *	Release a reference to a tty device and if need be let the kref
+ *	layer destruct the object for us
+ */
+
+void tty_kref_put(struct tty_struct *tty)
+{
+	if (tty)
+		kref_put(&tty->kref, release_one_tty);
+}
+EXPORT_SYMBOL(tty_kref_put);
+
+/**
  *	release_tty		-	release tty structure memory
  *
  *	Release both @tty and a possible linked partner (think pty pair),
@@ -1477,14 +1505,20 @@ static void release_one_tty(struct tty_struct *tty, int idx)
  *		takes the file list lock internally when working on the list
  *	of ttys that the driver keeps.
  *		FIXME: should we require tty_mutex is held here ??
+ *
+ *	FIXME: We want to defer the module put of the driver to the
+ *	destructor.
  */
 static void release_tty(struct tty_struct *tty, int idx)
 {
 	struct tty_driver *driver = tty->driver;
 
+	/* This should always be true but check for the moment */
+	WARN_ON(tty->index != idx);
+
 	if (tty->link)
-		release_one_tty(tty->link, idx);
-	release_one_tty(tty, idx);
+		tty_kref_put(tty->link);
+	tty_kref_put(tty);
 	module_put(driver->owner);
 }
 
@@ -2798,6 +2832,7 @@ EXPORT_SYMBOL(do_SAK);
 static void initialize_tty_struct(struct tty_struct *tty)
 {
 	memset(tty, 0, sizeof(struct tty_struct));
+	kref_init(&tty->kref);
 	tty->magic = TTY_MAGIC;
 	tty_ldisc_init(tty);
 	tty->session = NULL;
@@ -3053,9 +3088,12 @@ EXPORT_SYMBOL(tty_devnum);
 
 void proc_clear_tty(struct task_struct *p)
 {
+	struct tty_struct *tty;
 	spin_lock_irq(&p->sighand->siglock);
+	tty = p->signal->tty;
 	p->signal->tty = NULL;
 	spin_unlock_irq(&p->sighand->siglock);
+	tty_kref_put(tty);
 }
 
 /* Called under the sighand lock */
@@ -3071,9 +3109,13 @@ static void __proc_set_tty(struct task_struct *tsk, struct tty_struct *tty)
 		tty->pgrp = get_pid(task_pgrp(tsk));
 		spin_unlock_irqrestore(&tty->ctrl_lock, flags);
 		tty->session = get_pid(task_session(tsk));
+		if (tsk->signal->tty) {
+			printk(KERN_DEBUG "tty not NULL!!\n");
+			tty_kref_put(tsk->signal->tty);
+		}
 	}
 	put_pid(tsk->signal->tty_old_pgrp);
-	tsk->signal->tty = tty;
+	tsk->signal->tty = tty_kref_get(tty);
 	tsk->signal->tty_old_pgrp = NULL;
 }
 
include/linux/tty.h +18 -0
index e3612c3..b6e6c26 100644
@@ -209,6 +209,7 @@ struct tty_operations;
 
 struct tty_struct {
 	int	magic;
+	struct kref kref;
 	struct tty_driver *driver;
 	const struct tty_operations *ops;
 	int index;
@@ -311,6 +312,23 @@ extern int kmsg_redirect;
 extern void console_init(void);
 extern int vcs_init(void);
 
+/**
+ *	tty_kref_get		-	get a tty reference
+ *	@tty: tty device
+ *
+ *	Return a new reference to a tty object. The caller must hold
+ *	sufficient locks/counts to ensure that their existing reference cannot
+ *	go away
+ */
+
+extern inline struct tty_struct *tty_kref_get(struct tty_struct *tty)
+{
+	if (tty)
+		kref_get(&tty->kref);
+	return tty;
+}
+extern void tty_kref_put(struct tty_struct *tty);
+
 extern int tty_paranoia_check(struct tty_struct *tty, struct inode *inode,
 			      const char *routine);
 extern char *tty_name(struct tty_struct *tty, char *buf);
kernel/fork.c +4 -1
index 7ce2ebe..30de644 100644
@@ -802,6 +802,7 @@ static int copy_signal(unsigned long clone_flags, struct task_struct *tsk)
 
 	sig->leader = 0;	/* session leadership doesn't inherit */
 	sig->tty_old_pgrp = NULL;
+	sig->tty = NULL;
 
 	sig->utime = sig->stime = sig->cutime = sig->cstime = cputime_zero;
 	sig->gtime = cputime_zero;
@@ -838,6 +839,7 @@ static int copy_signal(unsigned long clone_flags, struct task_struct *tsk)
 void __cleanup_signal(struct signal_struct *sig)
 {
 	exit_thread_group_keys(sig);
+	tty_kref_put(sig->tty);
 	kmem_cache_free(signal_cachep, sig);
 }
 
@@ -1227,7 +1229,8 @@ static struct task_struct *copy_process(unsigned long clone_flags,
 				p->nsproxy->pid_ns->child_reaper = p;
 
 			p->signal->leader_pid = pid;
-			p->signal->tty = current->signal->tty;
+			tty_kref_put(p->signal->tty);
+			p->signal->tty = tty_kref_get(current->signal->tty);
 			set_task_pgrp(p, task_pgrp_nr(current));
 			set_task_session(p, task_session_nr(current));
 			attach_pid(p, PIDTYPE_PGID, task_pgrp(current));
kernel/sys.c +1 -3
index 038a7bc..234d945 100644
@@ -1060,9 +1060,7 @@ asmlinkage long sys_setsid(void)
 	group_leader->signal->leader = 1;
 	__set_special_pids(sid);
 
-	spin_lock(&group_leader->sighand->siglock);
-	group_leader->signal->tty = NULL;
-	spin_unlock(&group_leader->sighand->siglock);
+	proc_clear_tty(group_leader);
 
 	err = session;
 out:
#28 lore raw

Re: [PATCH 26/76] tty: Add a kref count

Quoted 2 lines · Alan Cox

Introduce a kref to the tty structure and use it to protect the tty->signal tty references. For now we don't introduce it for anything else.

[...]

Quoted 21 lines
kernel/fork.c +2 -0
index 7ce2ebe..30de644 100644
@@ -802,6 +802,7 @@ static int copy_signal(unsigned long clone_flags, struct task_struct *tsk)
 
 	sig->leader = 0;	/* session leadership doesn't inherit */
 	sig->tty_old_pgrp = NULL;
+	sig->tty = NULL;
 
 	sig->utime = sig->stime = sig->cutime = sig->cstime = cputime_zero;
 	sig->gtime = cputime_zero;
@@ -838,6 +839,7 @@ static int copy_signal(unsigned long clone_flags, struct task_struct *tsk)
 void __cleanup_signal(struct signal_struct *sig)
 {
 	exit_thread_group_keys(sig);
+	tty_kref_put(sig->tty);
 	kmem_cache_free(signal_cachep, sig);
 }
 

kernel/fork.c static struct task_struct *copy_process(unsigned long clone_flags, · line 1236

Quoted 9 lines
kernel/fork.c +2 -1
@@ -1227,7 +1229,8 @@ static struct task_struct *copy_process(unsigned long clone_flags,
 				p->nsproxy->pid_ns->child_reaper = p;
 
 			p->signal->leader_pid = pid;
-			p->signal->tty = current->signal->tty;
+			tty_kref_put(p->signal->tty);
+			p->signal->tty = tty_kref_get(current->signal->tty);
 			set_task_pgrp(p, task_pgrp_nr(current));
 			set_task_session(p, task_session_nr(current));
 			attach_pid(p, PIDTYPE_PGID, task_pgrp(current));

I'm a bit puzzled by this 'tty_kref_put(p->signal->tty)'. AFAICS, this is a noop since we are not in the CLONE_THREAD case and hence p->signal->tty == NULL. So, is it to make the code look more consistent? If so, is it worth adding extra code and cycles for this (I doubt that gcc is able to optimize this away)? What kind of future changes should this code protect against?

Thanks,

Louis

Signature · 4 lines
Dr Louis Rilling			Kerlabs
Skype: louis.rilling			Batiment Germanium
Phone: (+33|0) 6 80 89 08 23		80 avenue des Buttes de Coesmes
http://www.kerlabs.com/			35700 Rennes
author
#29 lore raw

Re: [PATCH 26/76] tty: Add a kref count

Quoted 3 lines · Louis Rilling

I'm a bit puzzled by this 'tty_kref_put(p->signal->tty)'. AFAICS, this is a noop since we are not in the CLONE_THREAD case and hence p->signal->tty == NULL.

When I first did it I was seeing non NULL values, but since then I've added the initialisation

Quoted 3 lines

So, is it to make the code look more consistent? If so, is it worth adding extra code and cycles for this (I doubt that gcc is able to optimize this away)? What kind of future changes should this code protect against?

I'll take a look, you may well be right, and if so it can become a WARN_ON() instead.

author
#30 lore raw

PATCH 27/76 tty: use krefs to protect driver module counts

In reply to Alan Cox

The tty layer keeps driver module counts that are used so the driver knows when it can be unloaded. For obvious reasons we want to tie that to the refcounting properly.

At this point the driver side itself isn't refcounted nicely but we can do that later and kref the drivers.

---

 drivers/char/tty_io.c |   17 +++++++++++------
 1 files changed, 11 insertions(+), 6 deletions(-)
drivers/char/tty_io.c +11 -6
index 310e070..fa162c9 100644
@@ -1293,6 +1293,12 @@ static int init_dev(struct tty_driver *driver, int idx,
 		o_tty = alloc_tty_struct();
 		if (!o_tty)
 			goto free_mem_out;
+		if (!try_module_get(driver->other->owner)) {
+			/* This cannot in fact currently happen */
+			free_tty_struct(o_tty);
+			o_tty = NULL;
+			goto free_mem_out;
+		}
 		initialize_tty_struct(o_tty);
 		o_tty->driver = driver->other;
 		o_tty->ops = driver->ops;
@@ -1411,8 +1417,10 @@ end_init:
 	/* Release locally allocated memory ... nothing placed in slots */
 free_mem_out:
 	kfree(o_tp);
-	if (o_tty)
+	if (o_tty) {
+		module_put(o_tty->driver->owner);
 		free_tty_struct(o_tty);
+	}
 	kfree(ltp);
 	kfree(tp);
 	free_tty_struct(tty);
@@ -1447,6 +1455,7 @@ release_mem_out:
 static void release_one_tty(struct kref *kref)
 {
 	struct tty_struct *tty = container_of(kref, struct tty_struct, kref);
+	struct tty_driver *driver = tty->driver;
 	int devpts = tty->driver->flags & TTY_DRIVER_DEVPTS_MEM;
 	struct ktermios *tp;
 	int idx = tty->index;
@@ -1471,6 +1480,7 @@ static void release_one_tty(struct kref *kref)
 	tty->magic = 0;
 	/* FIXME: locking on tty->driver->refcount */
 	tty->driver->refcount--;
+	module_put(driver->owner);
 
 	file_list_lock();
 	list_del_init(&tty->tty_files);
@@ -1506,20 +1516,15 @@ EXPORT_SYMBOL(tty_kref_put);
  *	of ttys that the driver keeps.
  *		FIXME: should we require tty_mutex is held here ??
  *
- *	FIXME: We want to defer the module put of the driver to the
- *	destructor.
  */
 static void release_tty(struct tty_struct *tty, int idx)
 {
-	struct tty_driver *driver = tty->driver;
-
 	/* This should always be true but check for the moment */
 	WARN_ON(tty->index != idx);
 
 	if (tty->link)
 		tty_kref_put(tty->link);
 	tty_kref_put(tty);
-	module_put(driver->owner);
 }
 
 /*
author
#31 lore raw

PATCH 28/76 Char: cyclades. remove bogus iomap

In reply to Alan Cox

From: Jiri Slaby <[email protected]>

readl/writel are not expected to accept iomap return value. Replace bogus mapping by standard ioremap.

---

 drivers/char/cyclades.c |   21 ++++++++++++---------
 1 files changed, 12 insertions(+), 9 deletions(-)
drivers/char/cyclades.c +12 -9
index fe6d774..5e5b1dc 100644
@@ -4993,12 +4993,14 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev,
 			device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) {
 		card_name = "Cyclom-Y";
 
-		addr0 = pci_iomap(pdev, 0, CyPCI_Yctl);
+		addr0 = ioremap_nocache(pci_resource_start(pdev, 0),
+				CyPCI_Yctl);
 		if (addr0 == NULL) {
 			dev_err(&pdev->dev, "can't remap ctl region\n");
 			goto err_reg;
 		}
-		addr2 = pci_iomap(pdev, 2, CyPCI_Ywin);
+		addr2 = ioremap_nocache(pci_resource_start(pdev, 2),
+				CyPCI_Ywin);
 		if (addr2 == NULL) {
 			dev_err(&pdev->dev, "can't remap base region\n");
 			goto err_unmap;
@@ -5013,7 +5015,8 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev,
 	} else if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Hi) {
 		struct RUNTIME_9060 __iomem *ctl_addr;
 
-		ctl_addr = addr0 = pci_iomap(pdev, 0, CyPCI_Zctl);
+		ctl_addr = addr0 = ioremap_nocache(pci_resource_start(pdev, 0),
+				CyPCI_Zctl);
 		if (addr0 == NULL) {
 			dev_err(&pdev->dev, "can't remap ctl region\n");
 			goto err_reg;
@@ -5026,8 +5029,8 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev,
 
 		mailbox = (u32)readl(&ctl_addr->mail_box_0);
 
-		addr2 = pci_iomap(pdev, 2, mailbox == ZE_V1 ?
-				CyPCI_Ze_win : CyPCI_Zwin);
+		addr2 = ioremap_nocache(pci_resource_start(pdev, 2),
+				mailbox == ZE_V1 ? CyPCI_Ze_win : CyPCI_Zwin);
 		if (addr2 == NULL) {
 			dev_err(&pdev->dev, "can't remap base region\n");
 			goto err_unmap;
@@ -5159,9 +5162,9 @@ err_null:
 	cy_card[card_no].base_addr = NULL;
 	free_irq(irq, &cy_card[card_no]);
 err_unmap:
-	pci_iounmap(pdev, addr0);
+	iounmap(addr0);
 	if (addr2)
-		pci_iounmap(pdev, addr2);
+		iounmap(addr2);
 err_reg:
 	pci_release_regions(pdev);
 err_dis:
@@ -5186,9 +5189,9 @@ static void __devexit cy_pci_remove(struct pci_dev *pdev)
 		cy_writew(cinfo->ctl_addr + 0x68,
 				readw(cinfo->ctl_addr + 0x68) & ~0x0900);
 
-	pci_iounmap(pdev, cinfo->base_addr);
+	iounmap(cinfo->base_addr);
 	if (cinfo->ctl_addr)
-		pci_iounmap(pdev, cinfo->ctl_addr);
+		iounmap(cinfo->ctl_addr);
 	if (cinfo->irq
 #ifndef CONFIG_CYZ_INTR
 		&& !IS_CYC_Z(*cinfo)
author
#32 lore raw

PATCH 29/76 Char: sx, fix io unmapping

In reply to Alan Cox

From: Jiri Slaby <[email protected]>

board->base is increased for CF cards after mapping. Use board->base2 for unmapping the region, since it holds the original/correct address.

---

 drivers/char/sx.c |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)
drivers/char/sx.c +2 -2
index c385206..5b8d7a1 100644
@@ -2504,7 +2504,7 @@ static void __devexit sx_remove_card(struct sx_board *board,
 		del_timer(&board->timer);
 		if (pdev) {
 #ifdef CONFIG_PCI
-			pci_iounmap(pdev, board->base);
+			pci_iounmap(pdev, board->base2);
 			pci_release_region(pdev, IS_CF_BOARD(board) ? 3 : 2);
 #endif
 		} else {
@@ -2703,7 +2703,7 @@ static int __devinit sx_pci_probe(struct pci_dev *pdev,
 
 	return 0;
 err_unmap:
-	pci_iounmap(pdev, board->base);
+	pci_iounmap(pdev, board->base2);
 err_reg:
 	pci_release_region(pdev, reg);
 err_flag:
author
#33 lore raw

PATCH 30/76 8250: remove a few inlines of dubious value

In reply to Alan Cox

From: \\\"Will Newton\\\" <[email protected]>

Remove some inlines from various functions that are called once, are too big to inline, or are called only from slow path code. This saves around 300 bytes of code for me.

---

 drivers/serial/8250.c |    9 ++++-----
 1 files changed, 4 insertions(+), 5 deletions(-)
drivers/serial/8250.c +4 -5
index 9f5e60d..e898edf 100644
@@ -540,7 +540,7 @@ static unsigned int serial_icr_read(struct uart_8250_port *up, int offset)
 /*
  * FIFO support.
  */
-static inline void serial8250_clear_fifos(struct uart_8250_port *p)
+static void serial8250_clear_fifos(struct uart_8250_port *p)
 {
 	if (p->capabilities & UART_CAP_FIFO) {
 		serial_outp(p, UART_FCR, UART_FCR_ENABLE_FIFO);
@@ -555,7 +555,7 @@ static inline void serial8250_clear_fifos(struct uart_8250_port *p)
  * capability" bit enabled.  Note that on XR16C850s, we need to
  * reset LCR to write to IER.
  */
-static inline void serial8250_set_sleep(struct uart_8250_port *p, int sleep)
+static void serial8250_set_sleep(struct uart_8250_port *p, int sleep)
 {
 	if (p->capabilities & UART_CAP_SLEEP) {
 		if (p->capabilities & UART_CAP_EFR) {
@@ -1428,8 +1428,7 @@ static unsigned int check_modem_status(struct uart_8250_port *up)
 /*
  * This handles the interrupt from one port.
  */
-static inline void
-serial8250_handle_port(struct uart_8250_port *up)
+static void serial8250_handle_port(struct uart_8250_port *up)
 {
 	unsigned int status;
 	unsigned long flags;
@@ -1764,7 +1763,7 @@ static void serial8250_break_ctl(struct uart_port *port, int break_state)
 /*
  *	Wait for transmitter & holding register to empty
  */
-static inline void wait_for_xmitr(struct uart_8250_port *up, int bits)
+static void wait_for_xmitr(struct uart_8250_port *up, int bits)
 {
 	unsigned int status, tmout = 10000;
 
author
#34 lore raw

PATCH 31/76 tty: Cris has a nice RS485 ioctl so we should steal it

In reply to Alan Cox

JP Tosoni observed:

"About a RS485 ioctl: could you consider the attached files which are
already in the Linux kernel (in include/asm-cris). They define a TIOCSERSETRS485 (ioctl.h), and the data structure (rs485.h) with allows to specify timings. Sounds just like what we want ?"

and he's right: sort of. Rework the structure to use flag bits and make the time delay a fixed sized field so we don't get 32/64bit problems. Add the ioctls to x86 so that people know what to add to their platform of choice.

---

 include/asm-x86/ioctls.h |    2 ++
 include/linux/serial.h   |   16 ++++++++++++++++
 2 files changed, 18 insertions(+), 0 deletions(-)
include/asm-x86/ioctls.h +2 -0
index c0c338b..2cd4775 100644
@@ -51,6 +51,8 @@
 #define TCSETS2		_IOW('T', 0x2B, struct termios2)
 #define TCSETSW2	_IOW('T', 0x2C, struct termios2)
 #define TCSETSF2	_IOW('T', 0x2D, struct termios2)
+#define TIOCGRS485	0x542E
+#define TIOCSRS485	0x542F
 #define TIOCGPTN	_IOR('T', 0x30, unsigned int)
 				/* Get Pty Number (of pty-mux device) */
 #define TIOCSPTLCK	_IOW('T', 0x31, int)  /* Lock/unlock Pty */
include/linux/serial.h +16 -0
index deb7143..1ea8d92 100644
@@ -173,6 +173,22 @@ struct serial_icounter_struct {
 	int reserved[9];
 };
 
+/*
+ * Serial interface for controlling RS485 settings on chips with suitable
+ * support. Set with TIOCSRS485 and get with TIOCGRS485 if supported by your
+ * platform. The set function returns the new state, with any unsupported bits
+ * reverted appropriately.
+ */
+
+struct serial_rs485 {
+	__u32	flags;			/* RS485 feature flags */
+#define SER_RS485_ENABLED		(1 << 0)
+#define SER_RS485_RTS_ON_SEND		(1 << 1)
+#define SER_RS485_RTS_AFTER_SEND	(1 << 2)
+	__u32	delay_rts_before_send;	/* Milliseconds */
+	__u32	padding[6];		/* Memory is cheap, new structs
+					   are a royal PITA .. */
+};
 
 #ifdef __KERNEL__
 #include <linux/compiler.h>
author
#35 lore raw

PATCH 32/76 tty: ipw need reworking

In reply to Alan Cox

This came in via another tree and unfortunately is rather broken on the tty side. Comment the apparent locking problems for someone who knows the driver to look at.

Fix the termios and other ioctl handling. The driver was calling the wrong methods for what it wanted to do but the right ones existed so its a simple fix up.
---

 drivers/char/pcmcia/ipwireless/tty.c |   19 ++++++++++---------
 1 files changed, 10 insertions(+), 9 deletions(-)
drivers/char/pcmcia/ipwireless/tty.c +10 -9
index 3a23e76..569f2f7 100644
@@ -276,6 +276,7 @@ static int ipw_write_room(struct tty_struct *linux_tty)
 	struct ipw_tty *tty = linux_tty->driver_data;
 	int room;
 
+	/* FIXME: Exactly how is the tty object locked here .. */
 	if (!tty)
 		return -ENODEV;
 
@@ -397,6 +398,7 @@ static int set_control_lines(struct ipw_tty *tty, unsigned int set,
 static int ipw_tiocmget(struct tty_struct *linux_tty, struct file *file)
 {
 	struct ipw_tty *tty = linux_tty->driver_data;
+	/* FIXME: Exactly how is the tty object locked here .. */
 
 	if (!tty)
 		return -ENODEV;
@@ -412,6 +414,7 @@ ipw_tiocmset(struct tty_struct *linux_tty, struct file *file,
 	     unsigned int set, unsigned int clear)
 {
 	struct ipw_tty *tty = linux_tty->driver_data;
+	/* FIXME: Exactly how is the tty object locked here .. */
 
 	if (!tty)
 		return -ENODEV;
@@ -433,6 +436,8 @@ static int ipw_ioctl(struct tty_struct *linux_tty, struct file *file,
 	if (!tty->open_count)
 		return -EINVAL;
 
+	/* FIXME: Exactly how is the tty object locked here .. */
+
 	switch (cmd) {
 	case TIOCGSERIAL:
 		return ipwireless_get_serial_info(tty, (void __user *) arg);
@@ -467,13 +472,6 @@ static int ipw_ioctl(struct tty_struct *linux_tty, struct file *file,
 			}
 			return 0;
 
-		case TCGETS:
-		case TCGETA:
-			return n_tty_ioctl(linux_tty, file, cmd, arg);
-
-		case TCFLSH:
-			return n_tty_ioctl(linux_tty, file, cmd, arg);
-
 		case FIONREAD:
 			{
 				int val = 0;
@@ -482,10 +480,11 @@ static int ipw_ioctl(struct tty_struct *linux_tty, struct file *file,
 					return -EFAULT;
 			}
 			return 0;
+		case TCFLSH:
+			return tty_perform_flush(linux_tty, arg);
 		}
 	}
-
-	return -ENOIOCTLCMD;
+	return tty_mode_ioctl(linux_tty, file, cmd , arg);
 }
 
 static int add_tty(dev_node_t *nodesp, int j,
@@ -588,6 +587,8 @@ void ipwireless_tty_free(struct ipw_tty *tty)
 				tty_hangup(ttyj->linux_tty);
 				/* Wait till the tty_hangup has completed */
 				flush_scheduled_work();
+				/* FIXME: Exactly how is the tty object locked here
+				   against a parallel ioctl etc */
 				mutex_lock(&ttyj->ipw_tty_mutex);
 			}
 			while (ttyj->open_count)
author
#36 lore raw

PATCH 33/76 tty: Add termiox

In reply to Alan Cox

We need a way to describe the various additional modes and flow control features that random weird hardware shows up and software such as wine wants to emulate as Windows supports them.

TCGETX/TCSETX and the termiox ioctl are a SYS5 extension that we might as well adopt. This patches adds the structures and the basic ioctl interfaces when the TCGETX etc defines are added for an architecture. Drivers wishing to use this stuff need to add new methods.

---

 drivers/char/tty_ioctl.c   |   58 ++++++++++++++++++++++++++++++++++++++++++++
 include/asm-x86/ioctls.h   |    4 +++
 include/linux/termios.h    |   15 +++++++++++
 include/linux/tty.h        |    1 +
 include/linux/tty_driver.h |    9 +++++++
 5 files changed, 87 insertions(+), 0 deletions(-)
drivers/char/tty_ioctl.c +58 -0
index bf34e45..93bfa1d 100644
@@ -579,6 +579,50 @@ static int get_termio(struct tty_struct *tty, struct termio __user *termio)
 	return 0;
 }
 
+
+#ifdef TCGETX
+
+/**
+ *	set_termiox	-	set termiox fields if possible
+ *	@tty: terminal
+ *	@arg: termiox structure from user
+ *	@opt: option flags for ioctl type
+ *
+ *	Implement the device calling points for the SYS5 termiox ioctl
+ *	interface in Linux
+ */
+
+static int set_termiox(struct tty_struct *tty, void __user *arg, int opt)
+{
+	struct termiox tnew;
+	struct tty_ldisc *ld;
+
+	if (tty->termiox == NULL)
+		return -EINVAL;
+	if (copy_from_user(&tnew, arg, sizeof(struct termiox)))
+		return -EFAULT;
+
+	ld = tty_ldisc_ref(tty);
+	if (ld != NULL) {
+		if ((opt & TERMIOS_FLUSH) && ld->ops->flush_buffer)
+			ld->ops->flush_buffer(tty);
+		tty_ldisc_deref(ld);
+	}
+	if (opt & TERMIOS_WAIT) {
+		tty_wait_until_sent(tty, 0);
+		if (signal_pending(current))
+			return -EINTR;
+	}
+
+	mutex_lock(&tty->termios_mutex);
+	if (tty->ops->set_termiox)
+		tty->ops->set_termiox(tty, &tnew);
+	mutex_unlock(&tty->termios_mutex);
+	return 0;
+}
+
+#endif
+
 static unsigned long inq_canon(struct tty_struct *tty)
 {
 	int nr, head, tail;
@@ -936,6 +980,20 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file,
 			return -EFAULT;
 			return 0;
 #endif
+#ifdef TCGETX
+	case TCGETX:
+		if (real_tty->termiox == NULL)
+			return -EINVAL;
+		if (copy_to_user(p, real_tty->termiox, sizeof(struct termiox)))
+			return -EFAULT;
+		return 0;
+	case TCSETX:
+		return set_termiox(real_tty, p, 0);
+	case TCSETXW:
+		return set_termiox(real_tty, p, TERMIOS_WAIT);
+	case TCSETXF:
+		return set_termiox(real_tty, p, TERMIOS_FLUSH);
+#endif		
 	case TIOCGSOFTCAR:
 		/* FIXME: for correctness we may need to take the termios
 		   lock here - review */
include/asm-x86/ioctls.h +4 -0
index 2cd4775..d2798f9 100644
@@ -56,6 +56,10 @@
 #define TIOCGPTN	_IOR('T', 0x30, unsigned int)
 				/* Get Pty Number (of pty-mux device) */
 #define TIOCSPTLCK	_IOW('T', 0x31, int)  /* Lock/unlock Pty */
+#define TCGETX		0x5432 /* SYS5 TCGETX compatibility */
+#define TCSETX		0x5433
+#define TCSETXF		0x5434
+#define TCSETXW		0x5435
 
 #define FIONCLEX	0x5450
 #define FIOCLEX		0x5451
include/linux/termios.h +15 -0
index 4786628..2acd0c1 100644
@@ -4,4 +4,19 @@
 #include <linux/types.h>
 #include <asm/termios.h>
 
+#define NFF	5
+
+struct termiox
+{
+	__u16	x_hflag;
+	__u16	x_cflag;
+	__u16	x_rflag[NFF];
+	__u16	x_sflag;
+};
+
+#define	RTSXOFF		0x0001		/* RTS flow control on input */
+#define	CTSXON		0x0002		/* CTS flow control on output */
+#define	DTRXOFF		0x0004		/* DTR flow control on input */
+#define DSRXON		0x0008		/* DCD flow control on output */
+
 #endif
include/linux/tty.h +1 -0
index b6e6c26..b64d10b 100644
@@ -219,6 +219,7 @@ struct tty_struct {
 	spinlock_t ctrl_lock;
 	/* Termios values are protected by the termios mutex */
 	struct ktermios *termios, *termios_locked;
+	struct termiox *termiox;	/* May be NULL for unsupported */
 	char name[64];
 	struct pid *pgrp;		/* Protected by ctrl lock */
 	struct pid *session;
include/linux/tty_driver.h +9 -0
index 16d2794..ac6e58e 100644
@@ -180,6 +180,14 @@
  *	not force errors here if they are not resizable objects (eg a serial
  *	line). See tty_do_resize() if you need to wrap the standard method
  *	in your own logic - the usual case.
+ *
+ * void (*set_termiox)(struct tty_struct *tty, struct termiox *new);
+ *
+ *	Called when the device receives a termiox based ioctl. Passes down
+ *	the requested data from user space. This method will not be invoked
+ *	unless the tty also has a valid tty->termiox pointer.
+ *
+ *	Optional: Called under the termios lock
  */
 
 #include <linux/fs.h>
@@ -220,6 +228,7 @@ struct tty_operations {
 			unsigned int set, unsigned int clear);
 	int (*resize)(struct tty_struct *tty, struct tty_struct *real_tty,
 				struct winsize *ws);
+	int (*set_termiox)(struct tty_struct *tty, struct termiox *tnew);
 #ifdef CONFIG_CONSOLE_POLL
 	int (*poll_init)(struct tty_driver *driver, int line, char *options);
 	int (*poll_get_char)(struct tty_driver *driver, int line);
author
#37 lore raw

PATCH 34/76 tty: Termios locking - sort out real_tty confusions and lock reads

In reply to Alan Cox

This moves us towards sanity and should mean our termios locking is now complete and comprehensive.
---

 drivers/char/tty_io.c    |    2 +-
 drivers/char/tty_ioctl.c |   58 ++++++++++++++++++++++++++++++----------------
 2 files changed, 39 insertions(+), 21 deletions(-)
drivers/char/tty_io.c +1 -1
index fa162c9..ac53d7f 100644
@@ -2605,7 +2605,7 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 	case TIOCSTI:
 		return tiocsti(tty, p);
 	case TIOCGWINSZ:
-		return tiocgwinsz(tty, p);
+		return tiocgwinsz(real_tty, p);
 	case TIOCSWINSZ:
 		return tiocswinsz(tty, real_tty, p);
 	case TIOCCONS:
drivers/char/tty_ioctl.c +38 -20

108 lines not on this page · raw message

author
#38 lore raw

PATCH 35/76 tty: compare the tty winsize

In reply to Alan Cox

We always use the real tty one for stuff so the pty one should not be compared. As we propogate window changes to both it doesn't currently matter but will when we tidy up the pty termios logic a bit more
---

 drivers/char/tty_io.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
drivers/char/tty_io.c +1 -1
index ac53d7f..9a76db3 100644
@@ -2133,7 +2133,7 @@ int tty_do_resize(struct tty_struct *tty, struct tty_struct *real_tty,
 
 	/* For a PTY we need to lock the tty side */
 	mutex_lock(&real_tty->termios_mutex);
-	if (!memcmp(ws, &tty->winsize, sizeof(*ws)))
+	if (!memcmp(ws, &real_tty->winsize, sizeof(*ws)))
 		goto done;
 	/* Get the PID values and reference them so we can
 	   avoid holding the tty ctrl lock while sending signals */
author
#39 lore raw

PATCH 36/76 tty: Make get_current_tty use a kref

In reply to Alan Cox

We now return a kref covered tty reference. That ensures the tty structure doesn't go away when you have a return from get_current_tty. This is not enough to protect you from most of the resources being freed behind your back - yet.

[Updated to include fixes for SELinux problems found by Andrew Morton and
an s390 leak found while debugging the former]

---

 drivers/char/tty_io.c      |   10 ++++++----
 drivers/s390/char/fs3270.c |    3 ++-
 fs/dquot.c                 |    6 +++---
 security/selinux/hooks.c   |    3 ++-
 4 files changed, 13 insertions(+), 9 deletions(-)
drivers/char/tty_io.c +6 -4
index 9a76db3..4c0e4ed 100644
@@ -786,12 +786,12 @@ void disassociate_ctty(int on_exit)
 	tty = get_current_tty();
 	if (tty) {
 		tty_pgrp = get_pid(tty->pgrp);
-		lock_kernel();
 		mutex_unlock(&tty_mutex);
-		/* XXX: here we race, there is nothing protecting tty */
+		lock_kernel();
 		if (on_exit && tty->driver->type != TTY_DRIVER_TYPE_PTY)
 			tty_vhangup(tty);
 		unlock_kernel();
+		tty_kref_put(tty);
 	} else if (on_exit) {
 		struct pid *old_pgrp;
 		spin_lock_irq(&current->sighand->siglock);
@@ -819,7 +819,6 @@ void disassociate_ctty(int on_exit)
 	spin_unlock_irq(&current->sighand->siglock);
 
 	mutex_lock(&tty_mutex);
-	/* It is possible that do_tty_hangup has free'd this tty */
 	tty = get_current_tty();
 	if (tty) {
 		unsigned long flags;
@@ -829,6 +828,7 @@ void disassociate_ctty(int on_exit)
 		tty->session = NULL;
 		tty->pgrp = NULL;
 		spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+		tty_kref_put(tty);
 	} else {
 #ifdef TTY_DEBUG_HANGUP
 		printk(KERN_DEBUG "error attempted to write to tty [0x%p]"
@@ -1806,6 +1806,8 @@ retry_open:
 		index = tty->index;
 		filp->f_flags |= O_NONBLOCK; /* Don't let /dev/tty block */
 		/* noctty = 1; */
+		/* FIXME: Should we take a driver reference ? */
+		tty_kref_put(tty);
 		goto got_driver;
 	}
 #ifdef CONFIG_VT
@@ -3135,7 +3137,7 @@ struct tty_struct *get_current_tty(void)
 {
 	struct tty_struct *tty;
 	WARN_ON_ONCE(!mutex_is_locked(&tty_mutex));
-	tty = current->signal->tty;
+	tty = tty_kref_get(current->signal->tty);
 	/*
 	 * session->tty can be changed/cleared from under us, make sure we
 	 * issue the load. The obtained pointer, when not NULL, is valid as
drivers/s390/char/fs3270.c +2 -1
index d18e6d2..3ef5425 100644
@@ -430,11 +430,12 @@ fs3270_open(struct inode *inode, struct file *filp)
 		mutex_lock(&tty_mutex);
 		tty = get_current_tty();
 		if (!tty || tty->driver->major != IBM_TTY3270_MAJOR) {
-			mutex_unlock(&tty_mutex);
+			tty_kref_put(tty);
 			rc = -ENODEV;
 			goto out;
 		}
 		minor = tty->index + RAW3270_FIRSTMINOR;
+		tty_kref_put(tty);
 		mutex_unlock(&tty_mutex);
 	}
 	/* Check if some other program is already using fullscreen mode. */
fs/dquot.c +3 -3
index 8ec4d6c..7417a6c 100644
@@ -897,8 +897,9 @@ static void print_warning(struct dquot *dquot, const int warntype)
 
 	mutex_lock(&tty_mutex);
 	tty = get_current_tty();
+	mutex_unlock(&tty_mutex);
 	if (!tty)
-		goto out_lock;
+		return;
 	tty_write_message(tty, dquot->dq_sb->s_id);
 	if (warntype == QUOTA_NL_ISOFTWARN || warntype == QUOTA_NL_BSOFTWARN)
 		tty_write_message(tty, ": warning, ");
@@ -926,8 +927,7 @@ static void print_warning(struct dquot *dquot, const int warntype)
 			break;
 	}
 	tty_write_message(tty, msg);
-out_lock:
-	mutex_unlock(&tty_mutex);
+	tty_kref_put(tty);
 }
 #endif
 
security/selinux/hooks.c +2 -1
index 03fc6a8..c856db8 100644
@@ -2122,6 +2122,7 @@ static inline void flush_unauthorized_files(struct files_struct *files)
 
 	mutex_lock(&tty_mutex);
 	tty = get_current_tty();
+	mutex_unlock(&tty_mutex);
 	if (tty) {
 		file_list_lock();
 		file = list_entry(tty->tty_files.next, typeof(*file), f_u.fu_list);
@@ -2138,8 +2139,8 @@ static inline void flush_unauthorized_files(struct files_struct *files)
 			}
 		}
 		file_list_unlock();
+		tty_kref_put(tty);
 	}
-	mutex_unlock(&tty_mutex);
 	/* Reset controlling tty. */
 	if (drop_tty)
 		no_tty();
#40 lore raw

Re: [PATCH 36/76] tty: Make get_current_tty use a kref

Quoted 8 lines · Alan Cox

We now return a kref covered tty reference. That ensures the tty structure doesn't go away when you have a return from get_current_tty. This is not enough to protect you from most of the resources being freed behind your back - yet.

[Updated to include fixes for SELinux problems found by Andrew Morton and
an s390 leak found while debugging the former]

[...]

drivers/s390/char/fs3270.c fs3270_open(struct inode *inode, struct file *filp) · line 433

Quoted 10 lines
drivers/s390/char/fs3270.c +1 -1
index d18e6d2..3ef5425 100644
@@ -430,11 +430,12 @@ fs3270_open(struct inode *inode, struct file *filp)
 		mutex_lock(&tty_mutex);
 		tty = get_current_tty();
 		if (!tty || tty->driver->major != IBM_TTY3270_MAJOR) {
-			mutex_unlock(&tty_mutex);
+			tty_kref_put(tty);

Should'nt mutex_unlock() be kept?

Louis

Quoted 8 lines
drivers/s390/char/fs3270.c +1 -0
 			rc = -ENODEV;
 			goto out;
 		}
 		minor = tty->index + RAW3270_FIRSTMINOR;
+		tty_kref_put(tty);
 		mutex_unlock(&tty_mutex);
 	}
 	/* Check if some other program is already using fullscreen mode. */
Signature · 4 lines
Dr Louis Rilling			Kerlabs
Skype: louis.rilling			Batiment Germanium
Phone: (+33|0) 6 80 89 08 23		80 avenue des Buttes de Coesmes
http://www.kerlabs.com/			35700 Rennes
author
#41 lore raw

Re: [PATCH 36/76] tty: Make get_current_tty use a kref

Quoted 6 lines · Louis Rilling

drivers/s390/char/fs3270.c fs3270_open(struct inode *inode, struct file *filp) · line 433

Quoted 4 lines
drivers/s390/char/fs3270.c +1 -1
 		tty = get_current_tty();
 		if (!tty || tty->driver->major != IBM_TTY3270_MAJOR) {
-			mutex_unlock(&tty_mutex);
+			tty_kref_put(tty);

Should'nt mutex_unlock() be kept?

Yes.. although it gets fixed later but I will fix that as it will keep the code bisectable.

author
#42 lore raw

PATCH 37/76 tty: Move tty_write_message out of kernel/printk

In reply to Alan Cox

This is pure tty code so put it in the tty layer where it can be with the locking relevant material it uses

---

 drivers/char/tty_io.c |   25 +++++++++++++++++++++++++
 kernel/printk.c       |   16 ----------------
 2 files changed, 25 insertions(+), 16 deletions(-)
drivers/char/tty_io.c +25 -0
index 4c0e4ed..913b502 100644
@@ -1081,6 +1081,31 @@ out:
 	return ret;
 }
 
+/**
+ * tty_write_message - write a message to a certain tty, not just the console.
+ * @tty: the destination tty_struct
+ * @msg: the message to write
+ *
+ * This is used for messages that need to be redirected to a specific tty.
+ * We don't put it into the syslog queue right now maybe in the future if
+ * really needed.
+ *
+ * We must still hold the BKL and test the CLOSING flag for the moment.
+ */
+
+void tty_write_message(struct tty_struct *tty, char *msg)
+{
+	lock_kernel();
+	if (tty) {
+		mutex_lock(&tty->atomic_write_lock);
+		if (tty->ops->write && !test_bit(TTY_CLOSING, &tty->flags))
+			tty->ops->write(tty, msg, strlen(msg));
+		tty_write_unlock(tty);
+	}
+	unlock_kernel();
+	return;
+}
+
 
 /**
  *	tty_write		-	write method for tty device file
kernel/printk.c +0 -16
index b51b156..a430fd0 100644
@@ -1291,22 +1291,6 @@ static int __init disable_boot_consoles(void)
 }
 late_initcall(disable_boot_consoles);
 
-/**
- * tty_write_message - write a message to a certain tty, not just the console.
- * @tty: the destination tty_struct
- * @msg: the message to write
- *
- * This is used for messages that need to be redirected to a specific tty.
- * We don't put it into the syslog queue right now maybe in the future if
- * really needed.
- */
-void tty_write_message(struct tty_struct *tty, char *msg)
-{
-	if (tty && tty->ops->write)
-		tty->ops->write(tty, msg, strlen(msg));
-	return;
-}
-
 #if defined CONFIG_PRINTK
 
 /*
author
#43 lore raw

PATCH 38/76 tty: usb-serial krefs

In reply to Alan Cox

Use kref in the USB serial drivers so that we don't free tty structures from under the URB receive handlers as has historically been the case if you were unlucky. This also gives us a framework for general tty drivers to use tty_port objects and refcount.

Contains two err->dev_err changes merged together to fix clashes in the -next tree.

---

 drivers/char/tty_port.c               |   41 ++++++++++++++++++
 drivers/usb/serial/aircable.c         |   15 ++++--
 drivers/usb/serial/belkin_sa.c        |    3 +
 drivers/usb/serial/console.c          |    8 ++-
 drivers/usb/serial/cyberjack.c        |    3 +
 drivers/usb/serial/cypress_m8.c       |    5 +-
 drivers/usb/serial/digi_acceleport.c  |   19 ++++++--
 drivers/usb/serial/empeg.c            |    8 ++-
 drivers/usb/serial/ftdi_sio.c         |   19 +++++---
 drivers/usb/serial/garmin_gps.c       |    3 +
 drivers/usb/serial/generic.c          |    3 +
 drivers/usb/serial/io_edgeport.c      |   43 ++++++++++++------
 drivers/usb/serial/io_ti.c            |   26 ++++++++---
 drivers/usb/serial/ipaq.c             |    3 +
 drivers/usb/serial/ipw.c              |    3 +
 drivers/usb/serial/ir-usb.c           |    3 +
 drivers/usb/serial/iuu_phoenix.c      |    3 +
 drivers/usb/serial/keyspan.c          |   77 +++++++++++++++++----------------
 drivers/usb/serial/keyspan_pda.c      |   16 ++++---
 drivers/usb/serial/kl5kusb105.c       |    3 +
 drivers/usb/serial/kobil_sct.c        |    3 +
 drivers/usb/serial/mct_u232.c         |    6 ++-
 drivers/usb/serial/mos7720.c          |   36 ++-------------
 drivers/usb/serial/mos7840.c          |    7 ++-
 drivers/usb/serial/navman.c           |    3 +
 drivers/usb/serial/omninet.c          |   10 +++-
 drivers/usb/serial/option.c           |   18 +++++---
 drivers/usb/serial/oti6858.c          |    3 +
 drivers/usb/serial/pl2303.c           |    4 +-
 drivers/usb/serial/safe_serial.c      |   11 +++--
 drivers/usb/serial/sierra.c           |   16 ++++---
 drivers/usb/serial/spcp8x5.c          |    3 +
 drivers/usb/serial/ti_usb_3410_5052.c |   44 ++++++++++---------
 drivers/usb/serial/usb-serial.c       |   24 ++++++----
 drivers/usb/serial/visor.c            |   18 +++++---
 drivers/usb/serial/whiteheat.c        |    8 ++-
 include/linux/tty.h                   |    3 +
 37 files changed, 313 insertions(+), 208 deletions(-)
drivers/char/tty_port.c +41 -0
index 6fadb19..553b0e9 100644
@@ -23,6 +23,7 @@ void tty_port_init(struct tty_port *port)
 	init_waitqueue_head(&port->open_wait);
 	init_waitqueue_head(&port->close_wait);
 	mutex_init(&port->mutex);
+	spin_lock_init(&port->lock);
 	port->close_delay = (50 * HZ) / 100;
 	port->closing_wait = (3000 * HZ) / 100;
 }
@@ -53,3 +54,43 @@ void tty_port_free_xmit_buf(struct tty_port *port)
 EXPORT_SYMBOL(tty_port_free_xmit_buf);
 
 
+/**
+ *	tty_port_tty_get	-	get a tty reference
+ *	@port: tty port
+ *
+ *	Return a refcount protected tty instance or NULL if the port is not
+ *	associated with a tty (eg due to close or hangup)
+ */
+
+struct tty_struct *tty_port_tty_get(struct tty_port *port)
+{
+	unsigned long flags;
+	struct tty_struct *tty;
+
+	spin_lock_irqsave(&port->lock, flags);
+	tty = tty_kref_get(port->tty);
+	spin_unlock_irqrestore(&port->lock, flags);
+	return tty;
+}
+EXPORT_SYMBOL(tty_port_tty_get);
+
+/**
+ *	tty_port_tty_set	-	set the tty of a port
+ *	@port: tty port
+ *	@tty: the tty
+ *
+ *	Associate the port and tty pair. Manages any internal refcounts.
+ *	Pass NULL to deassociate a port
+ */
+
+void tty_port_tty_set(struct tty_port *port, struct tty_struct *tty)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&port->lock, flags);
+	if (port->tty)
+		tty_kref_put(port->tty);
+	port->tty = tty;
+	spin_unlock_irqrestore(&port->lock, flags);
+}
+EXPORT_SYMBOL(tty_port_tty_set);
drivers/usb/serial/aircable.c +9 -6
index 79ea98c..99fb7dc 100644
@@ -272,7 +272,7 @@ static void aircable_read(struct work_struct *work)
 	 * 64 bytes, to ensure I do not get throttled.
 	 * Ask USB mailing list for better aproach.
 	 */
-	tty = port->port.tty;
+	tty = tty_port_tty_get(&port->port);
 
 	if (!tty) {
 		schedule_work(&priv->rx_work);
@@ -283,12 +283,13 @@ static void aircable_read(struct work_struct *work)
 	count = min(64, serial_buf_data_avail(priv->rx_buf));
 
 	if (count <= 0)
-		return; /* We have finished sending everything. */
+		goto out; /* We have finished sending everything. */
 
 	tty_prepare_flip_string(tty, &data, count);
 	if (!data) {
-		err("%s- kzalloc(%d) failed.", __func__, count);
-		return;
+		dev_err(&port->dev, "%s- kzalloc(%d) failed.",
+							__func__, count);
+		goto out;
 	}
 
 	serial_buf_get(priv->rx_buf, data, count);
@@ -297,7 +298,8 @@ static void aircable_read(struct work_struct *work)
 
 	if (serial_buf_data_avail(priv->rx_buf))
 		schedule_work(&priv->rx_work);
-
+out:		
+	tty_kref_put(tty);
 	return;
 }
 /* End of private methods */
@@ -495,7 +497,7 @@ static void aircable_read_bulk_callback(struct urb *urb)
 	usb_serial_debug_data(debug, &port->dev, __func__,
 				urb->actual_length, urb->transfer_buffer);
 
-	tty = port->port.tty;
+	tty = tty_port_tty_get(&port->port);
 	if (tty && urb->actual_length) {
 		if (urb->actual_length <= 2) {
 			/* This is an incomplete package */
@@ -527,6 +529,7 @@ static void aircable_read_bulk_callback(struct urb *urb)
 		}
 		aircable_read(&priv->rx_work);
 	}
+	tty_kref_put(tty);
 
 	/* Schedule the next read _if_ we are still open */
 	if (port->port.count) {
drivers/usb/serial/belkin_sa.c +2 -1
index 2ebe06c..1913bc7 100644
@@ -322,7 +322,7 @@ static void belkin_sa_read_int_callback(struct urb *urb)
 	 * to look in to this before committing any code.
 	 */
 	if (priv->last_lsr & BELKIN_SA_LSR_ERR) {
-		tty = port->port.tty;
+		tty = tty_port_tty_get(&port->port);
 		/* Overrun Error */
 		if (priv->last_lsr & BELKIN_SA_LSR_OE) {
 		}
@@ -335,6 +335,7 @@ static void belkin_sa_read_int_callback(struct urb *urb)
 		/* Break Indicator */
 		if (priv->last_lsr & BELKIN_SA_LSR_BI) {
 		}
+		tty_kref_put(tty);
 	}
 #endif
 	spin_unlock_irqrestore(&priv->lock, flags);
drivers/usb/serial/console.c +4 -4
index e980766..5b20de1 100644
@@ -117,7 +117,7 @@ static int usb_console_setup(struct console *co, char *options)
 	}
 
 	port = serial->port[0];
-	port->port.tty = NULL;
+	tty_port_tty_set(&port->port, NULL);
 
 	info->port = port;
 
@@ -143,7 +143,7 @@ static int usb_console_setup(struct console *co, char *options)
 			}
 			memset(&dummy, 0, sizeof(struct ktermios));
 			tty->termios = termios;
-			port->port.tty = tty;
+			tty_port_tty_set(&port->port, tty);
 		}
 
 		/* only call the device specific open if this
@@ -163,7 +163,7 @@ static int usb_console_setup(struct console *co, char *options)
 			tty_termios_encode_baud_rate(termios, baud, baud);
 			serial->type->set_termios(tty, port, &dummy);
 
-			port->port.tty = NULL;
+			tty_port_tty_set(&port->port, NULL);
 			kfree(termios);
 			kfree(tty);
 		}
@@ -176,7 +176,7 @@ out:
 	return retval;
 free_termios:
 	kfree(termios);
-	port->port.tty = NULL;
+	tty_port_tty_set(&port->port, NULL);
 free_tty:
 	kfree(tty);
 reset_open_count:
drivers/usb/serial/cyberjack.c +2 -1
index b4d7235..94ef36c 100644
@@ -384,7 +384,7 @@ static void cyberjack_read_bulk_callback(struct urb *urb)
 		return;
 	}
 
-	tty = port->port.tty;
+	tty = tty_port_tty_get(&port->port);
 	if (!tty) {
 		dbg("%s - ignoring since device not open\n", __func__);
 		return;
@@ -394,6 +394,7 @@ static void cyberjack_read_bulk_callback(struct urb *urb)
 		tty_insert_flip_string(tty, data, urb->actual_length);
 		tty_flip_buffer_push(tty);
 	}
+	tty_kref_put(tty);
 
 	spin_lock(&priv->lock);
 
drivers/usb/serial/cypress_m8.c +3 -2
index 22837a3..f3514a9 100644
@@ -1286,7 +1286,7 @@ static void cypress_read_int_callback(struct urb *urb)
 	}
 	spin_unlock_irqrestore(&priv->lock, flags);
 
-	tty = port->port.tty;
+	tty = tty_port_tty_get(&port->port);
 	if (!tty) {
 		dbg("%s - bad tty pointer - exiting", __func__);
 		return;
@@ -1362,7 +1362,7 @@ static void cypress_read_int_callback(struct urb *urb)
 					data[i]);
 			tty_insert_flip_char(tty, data[i], tty_flag);
 		}
-		tty_flip_buffer_push(port->port.tty);
+		tty_flip_buffer_push(tty);
 	}
 
 	spin_lock_irqsave(&priv->lock, flags);
@@ -1371,6 +1371,7 @@ static void cypress_read_int_callback(struct urb *urb)
 	spin_unlock_irqrestore(&priv->lock, flags);
 
 continue_read:
+	tty_kref_put(tty);
 
 	/* Continue trying to always read... unless the port has closed. */
 
drivers/usb/serial/digi_acceleport.c +13 -6
index 240aad1..5756ac6 100644
@@ -604,7 +604,9 @@ static void digi_wakeup_write_lock(struct work_struct *work)
 
 static void digi_wakeup_write(struct usb_serial_port *port)
 {
-	tty_wakeup(port->port.tty);
+	struct tty_struct *tty = tty_port_tty_get(&port->port);
+	tty_wakeup(tty);
+	tty_kref_put(tty);
 }
 
 
@@ -1668,7 +1670,7 @@ static int digi_read_inb_callback(struct urb *urb)
 {
 
 	struct usb_serial_port *port = urb->context;
-	struct tty_struct *tty = port->port.tty;
+	struct tty_struct *tty;
 	struct digi_port *priv = usb_get_serial_port_data(port);
 	int opcode = ((unsigned char *)urb->transfer_buffer)[0];
 	int len = ((unsigned char *)urb->transfer_buffer)[1];
@@ -1692,6 +1694,7 @@ static int digi_read_inb_callback(struct urb *urb)
 		return -1;
 	}
 
+	tty = tty_port_tty_get(&port->port);
 	spin_lock(&priv->dp_port_lock);
 
 	/* check for throttle; if set, do not resubmit read urb */
@@ -1735,6 +1738,7 @@ static int digi_read_inb_callback(struct urb *urb)
 		}
 	}
 	spin_unlock(&priv->dp_port_lock);
+	tty_kref_put(tty);
 
 	if (opcode == DIGI_CMD_RECEIVE_DISABLE)
 		dbg("%s: got RECEIVE_DISABLE", __func__);
@@ -1760,6 +1764,7 @@ static int digi_read_oob_callback(struct urb *urb)
 
 	struct usb_serial_port *port = urb->context;
 	struct usb_serial *serial = port->serial;
+	struct tty_struct *tty;
 	struct digi_port *priv = usb_get_serial_port_data(port);
 	int opcode, line, status, val;
 	int i;
@@ -1787,10 +1792,11 @@ static int digi_read_oob_callback(struct urb *urb)
 		if (priv == NULL)
 			return -1;
 
+		tty = tty_port_tty_get(&port->port);
 		rts = 0;
 		if (port->port.count)
-			rts = port->port.tty->termios->c_cflag & CRTSCTS;
-
+			rts = tty->termios->c_cflag & CRTSCTS;
+		
 		if (opcode == DIGI_CMD_READ_INPUT_SIGNALS) {
 			spin_lock(&priv->dp_port_lock);
 			/* convert from digi flags to termiox flags */
@@ -1798,14 +1804,14 @@ static int digi_read_oob_callback(struct urb *urb)
 				priv->dp_modem_signals |= TIOCM_CTS;
 				/* port must be open to use tty struct */
 				if (rts) {
-					port->port.tty->hw_stopped = 0;
+					tty->hw_stopped = 0;
 					digi_wakeup_write(port);
 				}
 			} else {
 				priv->dp_modem_signals &= ~TIOCM_CTS;
 				/* port must be open to use tty struct */
 				if (rts)
-					port->port.tty->hw_stopped = 1;
+					tty->hw_stopped = 1;
 			}
 			if (val & DIGI_READ_INPUT_SIGNALS_DSR)
 				priv->dp_modem_signals |= TIOCM_DSR;
@@ -1830,6 +1836,7 @@ static int digi_read_oob_callback(struct urb *urb)
 		} else if (opcode == DIGI_CMD_IFLUSH_FIFO) {
 			wake_up_interruptible(&priv->dp_flush_wait);
 		}
+		tty_kref_put(tty);
 	}
 	return 0;
 
drivers/usb/serial/empeg.c +4 -4
index a6ab5b5..1072e84 100644
@@ -33,9 +33,8 @@
  *	Moved MOD_DEC_USE_COUNT to end of empeg_close().
  *
  * (12/03/2000) gb
- *	Added port->port.tty->ldisc.set_termios(port->port.tty, NULL) to
- *	empeg_open(). This notifies the tty driver that the termios have
- *	changed.
+ *	Added tty->ldisc.set_termios(port, tty, NULL) to empeg_open().
+ *	This notifies the tty driver that the termios have changed.
  *
  * (11/13/2000) gb
  *	Moved tty->low_latency = 1 from empeg_read_bulk_callback() to
@@ -354,7 +353,7 @@ static void empeg_read_bulk_callback(struct urb *urb)
 
 	usb_serial_debug_data(debug, &port->dev, __func__,
 						urb->actual_length, data);
-	tty = port->port.tty;
+	tty = tty_port_tty_get(&port->port);
 
 	if (urb->actual_length) {
 		tty_buffer_request_room(tty, urb->actual_length);
@@ -362,6 +361,7 @@ static void empeg_read_bulk_callback(struct urb *urb)
 		tty_flip_buffer_push(tty);
 		bytes_in += urb->actual_length;
 	}
+	tty_kref_put(tty);
 
 	/* Continue trying to always read  */
 	usb_fill_bulk_urb(
drivers/usb/serial/ftdi_sio.c +11 -8
index 3dc93b5..70a3719 100644
@@ -1808,7 +1808,7 @@ static void ftdi_read_bulk_callback(struct urb *urb)
 	if (port->port.count <= 0)
 		return;
 
-	tty = port->port.tty;
+	tty = tty_port_tty_get(&port->port);
 	if (!tty) {
 		dbg("%s - bad tty pointer - exiting", __func__);
 		return;
@@ -1817,7 +1817,7 @@ static void ftdi_read_bulk_callback(struct urb *urb)
 	priv = usb_get_serial_port_data(port);
 	if (!priv) {
 		dbg("%s - bad port private data pointer - exiting", __func__);
-		return;
+		goto out;
 	}
 
 	if (urb != port->read_urb)
@@ -1827,7 +1827,7 @@ static void ftdi_read_bulk_callback(struct urb *urb)
 		/* This will happen at close every time so it is a dbg not an
 		   err */
 		dbg("(this is ok on close) nonzero read bulk status received: %d", status);
-		return;
+		goto out;
 	}
 
 	/* count data bytes, but not status bytes */
@@ -1838,7 +1838,8 @@ static void ftdi_read_bulk_callback(struct urb *urb)
 	spin_unlock_irqrestore(&priv->rx_lock, flags);
 
 	ftdi_process_read(&priv->rx_work.work);
-
+out:
+	tty_kref_put(tty);
 } /* ftdi_read_bulk_callback */
 
 
@@ -1863,7 +1864,7 @@ static void ftdi_process_read(struct work_struct *work)
 	if (port->port.count <= 0)
 		return;
 
-	tty = port->port.tty;
+	tty = tty_port_tty_get(&port->port);
 	if (!tty) {
 		dbg("%s - bad tty pointer - exiting", __func__);
 		return;
@@ -1872,13 +1873,13 @@ static void ftdi_process_read(struct work_struct *work)
 	priv = usb_get_serial_port_data(port);
 	if (!priv) {
 		dbg("%s - bad port private data pointer - exiting", __func__);
-		return;
+		goto out;
 	}
 
 	urb = port->read_urb;
 	if (!urb) {
 		dbg("%s - bad read_urb pointer - exiting", __func__);
-		return;
+		goto out;
 	}
 
 	data = urb->transfer_buffer;
@@ -2020,7 +2021,7 @@ static void ftdi_process_read(struct work_struct *work)
 			schedule_delayed_work(&priv->rx_work, 1);
 		else
 			dbg("%s - port is closed", __func__);
-		return;
+		goto out;
 	}
 
 	/* urb is completely processed */
@@ -2041,6 +2042,8 @@ static void ftdi_process_read(struct work_struct *work)
 			err("%s - failed resubmitting read urb, error %d",
 							__func__, result);
 	}
+out:
+	tty_kref_put(tty);
 } /* ftdi_process_read */
 
 
drivers/usb/serial/garmin_gps.c +2 -1
index d953820..2ad0569 100644
@@ -276,7 +276,7 @@ static inline int isAbortTrfCmnd(const unsigned char *buf)
 static void send_to_tty(struct usb_serial_port *port,
 			char *data, unsigned int actual_length)
 {
-	struct tty_struct *tty = port->port.tty;
+	struct tty_struct *tty = tty_port_tty_get(&port->port);
 
 	if (tty && actual_length) {
 
@@ -287,6 +287,7 @@ static void send_to_tty(struct usb_serial_port *port,
 		tty_insert_flip_string(tty, data, actual_length);
 		tty_flip_buffer_push(tty);
 	}
+	tty_kref_put(tty);
 }
 
 
drivers/usb/serial/generic.c +2 -1
index fe84c88..814909f 100644
@@ -330,7 +330,7 @@ static void resubmit_read_urb(struct usb_serial_port *port, gfp_t mem_flags)
 static void flush_and_resubmit_read_urb(struct usb_serial_port *port)
 {
 	struct urb *urb = port->read_urb;
-	struct tty_struct *tty = port->port.tty;
+	struct tty_struct *tty = tty_port_tty_get(&port->port);
 	int room;
 
 	/* Push data to tty */
@@ -341,6 +341,7 @@ static void flush_and_resubmit_read_urb(struct usb_serial_port *port)
 			tty_flip_buffer_push(tty);
 		}
 	}
+	tty_kref_put(tty);
 
 	resubmit_read_urb(port, GFP_ATOMIC);
 }
drivers/usb/serial/io_edgeport.c +29 -14

105 lines not on this page · raw message

drivers/usb/serial/io_ti.c +19 -7
index cb4c543..541dd8e 100644
@@ -572,7 +572,7 @@ static void chase_port(struct edgeport_port *port, unsigned long timeout,
 								int flush)
 {
 	int baud_rate;
-	struct tty_struct *tty = port->port->port.tty;
+	struct tty_struct *tty = tty_port_tty_get(&port->port->port);
 	wait_queue_t wait;
 	unsigned long flags;
 
@@ -599,6 +599,7 @@ static void chase_port(struct edgeport_port *port, unsigned long timeout,
 	if (flush)
 		edge_buf_clear(port->ep_out_buf);
 	spin_unlock_irqrestore(&port->ep_lock, flags);
+	tty_kref_put(tty);
 
 	/* wait for data to drain from the device */
 	timeout += jiffies;
@@ -1554,7 +1555,7 @@ static void handle_new_msr(struct edgeport_port *edge_port, __u8 msr)
 	/* Save the new modem status */
 	edge_port->shadow_msr = msr & 0xf0;
 
-	tty = edge_port->port->port.tty;
+	tty = tty_port_tty_get(&edge_port->port->port);
 	/* handle CTS flow control */
 	if (tty && C_CRTSCTS(tty)) {
 		if (msr & EDGEPORT_MSR_CTS) {
@@ -1564,6 +1565,7 @@ static void handle_new_msr(struct edgeport_port *edge_port, __u8 msr)
 			tty->hw_stopped = 1;
 		}
 	}
+	tty_kref_put(tty);
 
 	return;
 }
@@ -1574,6 +1576,7 @@ static void handle_new_lsr(struct edgeport_port *edge_port, int lsr_data,
 	struct async_icount *icount;
 	__u8 new_lsr = (__u8)(lsr & (__u8)(LSR_OVER_ERR | LSR_PAR_ERR |
 						LSR_FRM_ERR | LSR_BREAK));
+	struct tty_struct *tty;
 
 	dbg("%s - %02x", __func__, new_lsr);
 
@@ -1587,8 +1590,13 @@ static void handle_new_lsr(struct edgeport_port *edge_port, int lsr_data,
 		new_lsr &= (__u8)(LSR_OVER_ERR | LSR_BREAK);
 
 	/* Place LSR data byte into Rx buffer */
-	if (lsr_data && edge_port->port->port.tty)
-		edge_tty_recv(&edge_port->port->dev, edge_port->port->port.tty, &data, 1);
+	if (lsr_data) {
+		tty = tty_port_tty_get(&edge_port->port->port);
+		if (tty) {
+			edge_tty_recv(&edge_port->port->dev, tty, &data, 1);
+			tty_kref_put(tty);
+		}
+	}
 
 	/* update input line counters */
 	icount = &edge_port->icount;
@@ -1749,7 +1757,7 @@ static void edge_bulk_in_callback(struct urb *urb)
 		++data;
 	}
 
-	tty = edge_port->port->port.tty;
+	tty = tty_port_tty_get(&edge_port->port->port);
 	if (tty && urb->actual_length) {
 		usb_serial_debug_data(debug, &edge_port->port->dev,
 					__func__, urb->actual_length, data);
@@ -1761,6 +1769,7 @@ static void edge_bulk_in_callback(struct urb *urb)
 							urb->actual_length);
 		edge_port->icount.rx += urb->actual_length;
 	}
+	tty_kref_put(tty);
 
 exit:
 	/* continue read unless stopped */
@@ -1796,6 +1805,7 @@ static void edge_bulk_out_callback(struct urb *urb)
 	struct usb_serial_port *port = urb->context;
 	struct edgeport_port *edge_port = usb_get_serial_port_data(port);
 	int status = urb->status;
+	struct tty_struct *tty;
 
 	dbg("%s - port %d", __func__, port->number);
 
@@ -1818,7 +1828,9 @@ static void edge_bulk_out_callback(struct urb *urb)
 	}
 
 	/* send any buffered data */
-	edge_send(port->port.tty);
+	tty = tty_port_tty_get(&port->port);
+	edge_send(tty);
+	tty_kref_put(tty);
 }
 
 static int edge_open(struct tty_struct *tty,
@@ -1876,7 +1888,7 @@ static int edge_open(struct tty_struct *tty,
 
 	/* set up the port settings */
 	if (tty)
-		edge_set_termios(tty, port, port->port.tty->termios);
+		edge_set_termios(tty, port, tty->termios);
 
 	/* open up the port */
 
drivers/usb/serial/ipaq.c +2 -1
index cd9a2e1..2affa9c 100644
@@ -764,13 +764,14 @@ static void ipaq_read_bulk_callback(struct urb *urb)
 	usb_serial_debug_data(debug, &port->dev, __func__,
 						urb->actual_length, data);
 
-	tty = port->port.tty;
+	tty = tty_port_tty_get(&port->port);
 	if (tty && urb->actual_length) {
 		tty_buffer_request_room(tty, urb->actual_length);
 		tty_insert_flip_string(tty, data, urb->actual_length);
 		tty_flip_buffer_push(tty);
 		bytes_in += urb->actual_length;
 	}
+	tty_kref_put(tty);
 
 	/* Continue trying to always read  */
 	usb_fill_bulk_urb(port->read_urb, port->serial->dev,
drivers/usb/serial/ipw.c +2 -1
index a842025..480cac2 100644
@@ -170,12 +170,13 @@ static void ipw_read_bulk_callback(struct urb *urb)
 	usb_serial_debug_data(debug, &port->dev, __func__,
 					urb->actual_length, data);
 
-	tty = port->port.tty;
+	tty = tty_port_tty_get(&port->port);
 	if (tty && urb->actual_length) {
 		tty_buffer_request_room(tty, urb->actual_length);
 		tty_insert_flip_string(tty, data, urb->actual_length);
 		tty_flip_buffer_push(tty);
 	}
+	tty_kref_put(tty);
 
 	/* Continue trying to always read  */
 	usb_fill_bulk_urb(port->read_urb, port->serial->dev,
drivers/usb/serial/ir-usb.c +2 -1
index e59155c..45d4043 100644
@@ -465,11 +465,12 @@ static void ir_read_bulk_callback(struct urb *urb)
 			ir_baud = *data & 0x0f;
 		usb_serial_debug_data(debug, &port->dev, __func__,
 						urb->actual_length, data);
- 		tty = port->port.tty;
+		tty = tty_port_tty_get(&port->port);
 		if (tty_buffer_request_room(tty, urb->actual_length - 1)) {
 			tty_insert_flip_string(tty, data+1, urb->actual_length - 1);
 			tty_flip_buffer_push(tty);
 		}
+		tty_kref_put(tty);
 
 		/*
 		 * No break here.
drivers/usb/serial/iuu_phoenix.c +2 -1
index ddff37f..53710aa 100644
@@ -629,13 +629,14 @@ static void read_buf_callback(struct urb *urb)
 	}
 
 	dbg("%s - %i chars to write", __func__, urb->actual_length);
-	tty = port->port.tty;
+	tty = tty_port_tty_get(&port->port);
 	if (data == NULL)
 		dbg("%s - data is NULL !!!", __func__);
 	if (tty && urb->actual_length && data) {
 		tty_insert_flip_string(tty, data, urb->actual_length);
 		tty_flip_buffer_push(tty);
 	}
+	tty_kref_put(tty);
 	iuu_led_activity_on(urb);
 }
 
drivers/usb/serial/keyspan.c +40 -37

189 lines not on this page · raw message

drivers/usb/serial/keyspan_pda.c +10 -6
index 040040a..99e9a14 100644
@@ -172,8 +172,9 @@ static void keyspan_pda_wakeup_write(struct work_struct *work)
 	struct keyspan_pda_private *priv =
 		container_of(work, struct keyspan_pda_private, wakeup_work);
 	struct usb_serial_port *port = priv->port;
-
-	tty_wakeup(port->port.tty);
+	struct tty_struct *tty = tty_port_tty_get(&port->port);
+	tty_wakeup(tty);
+	tty_kref_put(tty);
 }
 
 static void keyspan_pda_request_unthrottle(struct work_struct *work)
@@ -205,7 +206,7 @@ static void keyspan_pda_request_unthrottle(struct work_struct *work)
 static void keyspan_pda_rx_interrupt(struct urb *urb)
 {
 	struct usb_serial_port *port = urb->context;
-	struct tty_struct *tty = port->port.tty;
+	struct tty_struct *tty = tty_port_tty_get(&port->port);
 	unsigned char *data = urb->transfer_buffer;
 	int retval;
 	int status = urb->status;
@@ -222,7 +223,7 @@ static void keyspan_pda_rx_interrupt(struct urb *urb)
 		/* this urb is terminated, clean up */
 		dbg("%s - urb shutting down with status: %d",
 		    __func__, status);
-		return;
+		goto out;
 	default:
 		dbg("%s - nonzero urb status received: %d",
 		    __func__, status);
@@ -261,8 +262,11 @@ static void keyspan_pda_rx_interrupt(struct urb *urb)
 exit:
 	retval = usb_submit_urb(urb, GFP_ATOMIC);
 	if (retval)
-		err("%s - usb_submit_urb failed with result %d",
-		     __func__, retval);
+		dev_err(&port->dev,
+			"%s - usb_submit_urb failed with result %d",
+			__func__, retval);
+out:
+	tty_kref_put(tty);		     
 }
 
 
drivers/usb/serial/kl5kusb105.c +2 -1
index b84dddc..ff3a07f 100644
@@ -658,7 +658,7 @@ static void klsi_105_read_bulk_callback(struct urb *urb)
 	} else {
 		int bytes_sent = ((__u8 *) data)[0] +
 				 ((unsigned int) ((__u8 *) data)[1] << 8);
-		tty = port->port.tty;
+		tty = tty_port_tty_get(&port->port);
 		/* we should immediately resubmit the URB, before attempting
 		 * to pass the data on to the tty layer. But that needs locking
 		 * against re-entry an then mixed-up data because of
@@ -679,6 +679,7 @@ static void klsi_105_read_bulk_callback(struct urb *urb)
 		tty_buffer_request_room(tty, bytes_sent);
 		tty_insert_flip_string(tty, data + 2, bytes_sent);
 		tty_flip_buffer_push(tty);
+		tty_kref_put(tty);
 
 		/* again lockless, but debug info only */
 		priv->bytes_in += bytes_sent;
drivers/usb/serial/kobil_sct.c +2 -1
index deba28e..cfcf37c 100644
@@ -383,7 +383,7 @@ static void kobil_read_int_callback(struct urb *urb)
 		return;
 	}
 
-	tty = port->port.tty;
+	tty = tty_port_tty_get(&port->port);
 	if (urb->actual_length) {
 
 		/* BEGIN DEBUG */
@@ -405,6 +405,7 @@ static void kobil_read_int_callback(struct urb *urb)
 		tty_insert_flip_string(tty, data, urb->actual_length);
 		tty_flip_buffer_push(tty);
 	}
+	tty_kref_put(tty);
 	/* someone sets the dev to 0 if the close method has been called */
 	port->interrupt_in_urb->dev = port->serial->dev;
 
drivers/usb/serial/mct_u232.c +4 -2
index 0ded8bd..9b2cef8 100644
@@ -563,10 +563,11 @@ static void mct_u232_read_int_callback(struct urb *urb)
 	 * Work-a-round: handle the 'usual' bulk-in pipe here
 	 */
 	if (urb->transfer_buffer_length > 2) {
-		tty = port->port.tty;
+		tty = tty_port_tty_get(&port->port);
 		if (urb->actual_length) {
 			tty_insert_flip_string(tty, data, urb->actual_length);
 			tty_flip_buffer_push(tty);
+			tty_kref_put(tty);
 		}
 		goto exit;
 	}
@@ -591,7 +592,7 @@ static void mct_u232_read_int_callback(struct urb *urb)
 	 * to look in to this before committing any code.
 	 */
 	if (priv->last_lsr & MCT_U232_LSR_ERR) {
-		tty = port->port.tty;
+		tty = tty_port_tty_get(&port->port);
 		/* Overrun Error */
 		if (priv->last_lsr & MCT_U232_LSR_OE) {
 		}
@@ -604,6 +605,7 @@ static void mct_u232_read_int_callback(struct urb *urb)
 		/* Break Indicator */
 		if (priv->last_lsr & MCT_U232_LSR_BI) {
 		}
+		tty_kref_put(tty);
 	}
 #endif
 	spin_unlock_irqrestore(&priv->lock, flags);
drivers/usb/serial/mos7720.c +4 -32
index 7c4917d..7b538ca 100644
@@ -216,12 +216,13 @@ static void mos7720_bulk_in_callback(struct urb *urb)
 
 	data = urb->transfer_buffer;
 
-	tty = port->port.tty;
+	tty = tty_port_tty_get(&port->port);
 	if (tty && urb->actual_length) {
 		tty_buffer_request_room(tty, urb->actual_length);
 		tty_insert_flip_string(tty, data, urb->actual_length);
 		tty_flip_buffer_push(tty);
 	}
+	tty_kref_put(tty);
 
 	if (!port->read_urb) {
 		dbg("URB KILLED !!!");
@@ -262,10 +263,11 @@ static void mos7720_bulk_out_data_callback(struct urb *urb)
 
 	dbg("Entering .........");
 
-	tty = mos7720_port->port->port.tty;
+	tty = tty_port_tty_get(&mos7720_port->port->port);
 
 	if (tty && mos7720_port->open)
 		tty_wakeup(tty);
+	tty_kref_put(tty);
 }
 
 /*
@@ -1267,29 +1269,6 @@ static int get_lsr_info(struct tty_struct *tty,
 	return 0;
 }
 
-/*
- * get_number_bytes_avail - get number of bytes available
- *
- * Purpose: Let user call ioctl to get the count of number of bytes available.
- */
-static int get_number_bytes_avail(struct moschip_port *mos7720_port,
-				  unsigned int __user *value)
-{
-	unsigned int result = 0;
-	struct tty_struct *tty = mos7720_port->port->port.tty;
-
-	if (!tty)
-		return -ENOIOCTLCMD;
-
-	result = tty->read_cnt;
-
-	dbg("%s(%d) = %d", __func__,  mos7720_port->port->number, result);
-	if (copy_to_user(value, &result, sizeof(int)))
-		return -EFAULT;
-
-	return -ENOIOCTLCMD;
-}
-
 static int set_modem_info(struct moschip_port *mos7720_port, unsigned int cmd,
 			  unsigned int __user *value)
 {
@@ -1409,13 +1388,6 @@ static int mos7720_ioctl(struct tty_struct *tty, struct file *file,
 	dbg("%s - port %d, cmd = 0x%x", __func__, port->number, cmd);
 
 	switch (cmd) {
-	case TIOCINQ:
-		/* return number of bytes available */
-		dbg("%s (%d) TIOCINQ", __func__,  port->number);
-		return get_number_bytes_avail(mos7720_port,
-					      (unsigned int __user *)arg);
-		break;
-
 	case TIOCSERGETLSR:
 		dbg("%s (%d) TIOCSERGETLSR", __func__,  port->number);
 		return get_lsr_info(tty, mos7720_port,
drivers/usb/serial/mos7840.c +4 -3
index 09d8206..60543d7 100644
@@ -709,12 +709,13 @@ static void mos7840_bulk_in_callback(struct urb *urb)
 	dbg("%s", "Entering ........... \n");
 
 	if (urb->actual_length) {
-		tty = mos7840_port->port->port.tty;
+		tty = tty_port_tty_get(&mos7840_port->port->port);
 		if (tty) {
 			tty_buffer_request_room(tty, urb->actual_length);
 			tty_insert_flip_string(tty, data, urb->actual_length);
 			dbg(" %s \n", data);
 			tty_flip_buffer_push(tty);
+			tty_kref_put(tty);
 		}
 		mos7840_port->icount.rx += urb->actual_length;
 		smp_wmb();
@@ -773,10 +774,10 @@ static void mos7840_bulk_out_data_callback(struct urb *urb)
 
 	dbg("%s \n", "Entering .........");
 
-	tty = mos7840_port->port->port.tty;
-
+	tty = tty_port_tty_get(&mos7840_port->port->port);
 	if (tty && mos7840_port->open)
 		tty_wakeup(tty);
+	tty_kref_put(tty);
 
 }
 
drivers/usb/serial/navman.c +2 -1
index d673653..bcdcbb8 100644
@@ -64,12 +64,13 @@ static void navman_read_int_callback(struct urb *urb)
 	usb_serial_debug_data(debug, &port->dev, __func__,
 			      urb->actual_length, data);
 
-	tty = port->port.tty;
+	tty = tty_port_tty_get(&port->port);
 	if (tty && urb->actual_length) {
 		tty_buffer_request_room(tty, urb->actual_length);
 		tty_insert_flip_string(tty, data, urb->actual_length);
 		tty_flip_buffer_push(tty);
 	}
+	tty_kref_put(tty);
 
 exit:
 	result = usb_submit_urb(urb, GFP_ATOMIC);
drivers/usb/serial/omninet.c +6 -4
index ae8e227..c4d70b0 100644
@@ -172,7 +172,7 @@ static int omninet_open(struct tty_struct *tty,
 	dbg("%s - port %d", __func__, port->number);
 
 	wport = serial->port[1];
-	wport->port.tty = tty;		/* FIXME */
+	tty_port_tty_set(&wport->port, tty);
 
 	/* Start reading from the device */
 	usb_fill_bulk_urb(port->read_urb, serial->dev,
@@ -229,9 +229,11 @@ static void omninet_read_bulk_callback(struct urb *urb)
 	}
 
 	if (urb->actual_length && header->oh_len) {
-		tty_insert_flip_string(port->port.tty,
-			data + OMNINET_DATAOFFSET, header->oh_len);
-		tty_flip_buffer_push(port->port.tty);
+		struct tty_struct *tty = tty_port_tty_get(&port->port);
+		tty_insert_flip_string(tty, data + OMNINET_DATAOFFSET,
+							header->oh_len);
+		tty_flip_buffer_push(tty);
+		tty_kref_put(tty);
 	}
 
 	/* Continue trying to always read  */
drivers/usb/serial/option.c +11 -7
index 73f8277..6b1727e 100644
@@ -571,14 +571,14 @@ static void option_indat_callback(struct urb *urb)
 		dbg("%s: nonzero status: %d on endpoint %02x.",
 		    __func__, status, endpoint);
 	} else {
-		tty = port->port.tty;
+		tty = tty_port_tty_get(&port->port);
 		if (urb->actual_length) {
 			tty_buffer_request_room(tty, urb->actual_length);
 			tty_insert_flip_string(tty, data, urb->actual_length);
 			tty_flip_buffer_push(tty);
-		} else {
+		} else 
 			dbg("%s: empty read urb received", __func__);
-		}
+		tty_kref_put(tty);
 
 		/* Resubmit urb so we continue receiving */
 		if (port->port.count && status != -ESHUTDOWN) {
@@ -647,9 +647,13 @@ static void option_instat_callback(struct urb *urb)
 			portdata->dsr_state = ((signals & 0x02) ? 1 : 0);
 			portdata->ri_state = ((signals & 0x08) ? 1 : 0);
 
-			if (port->port.tty && !C_CLOCAL(port->port.tty) &&
-					old_dcd_state && !portdata->dcd_state)
-				tty_hangup(port->port.tty);
+			if (old_dcd_state && !portdata->dcd_state) {
+				struct tty_struct *tty =
+						tty_port_tty_get(&port->port);
+				if (tty && !C_CLOCAL(tty))
+					tty_hangup(tty);
+				tty_kref_put(tty);
+			}
 		} else {
 			dbg("%s: type %x req %x", __func__,
 				req_pkt->bRequestType, req_pkt->bRequest);
@@ -793,7 +797,7 @@ static void option_close(struct tty_struct *tty,
 		for (i = 0; i < N_OUT_URB; i++)
 			usb_kill_urb(portdata->out_urbs[i]);
 	}
-	port->port.tty = NULL;	/* FIXME */
+	tty_port_tty_set(&port->port, NULL);
 }
 
 /* Helper functions used by option_setup_urbs */
drivers/usb/serial/oti6858.c +2 -1
index 81db571..057f72a 100644
@@ -1002,11 +1002,12 @@ static void oti6858_read_bulk_callback(struct urb *urb)
 		return;
 	}
 
-	tty = port->port.tty;
+	tty = tty_port_tty_get(&port->port);
 	if (tty != NULL && urb->actual_length > 0) {
 		tty_insert_flip_string(tty, data, urb->actual_length);
 		tty_flip_buffer_push(tty);
 	}
+	tty_kref_put(tty);
 
 	/* schedule the interrupt urb if we are still open */
 	if (port->port.count != 0) {
drivers/usb/serial/pl2303.c +2 -2
index 1ede144..ba74424 100644
@@ -1057,7 +1057,7 @@ static void pl2303_read_bulk_callback(struct urb *urb)
 		tty_flag = TTY_FRAME;
 	dbg("%s - tty_flag = %d", __func__, tty_flag);
 
-	tty = port->port.tty;
+	tty = tty_port_tty_get(&port->port);
 	if (tty && urb->actual_length) {
 		tty_buffer_request_room(tty, urb->actual_length + 1);
 		/* overrun is special, not associated with a char */
@@ -1067,7 +1067,7 @@ static void pl2303_read_bulk_callback(struct urb *urb)
 			tty_insert_flip_char(tty, data[i], tty_flag);
 		tty_flip_buffer_push(tty);
 	}
-
+	tty_kref_put(tty);
 	/* Schedule the next read _if_ we are still open */
 	if (port->port.count) {
 		urb->dev = port->serial->dev;
drivers/usb/serial/safe_serial.c +7 -4
index def52d0..72903ac 100644
@@ -217,6 +217,7 @@ static void safe_read_bulk_callback(struct urb *urb)
 	struct usb_serial_port *port =  urb->context;
 	unsigned char *data = urb->transfer_buffer;
 	unsigned char length = urb->actual_length;
+	struct tty_struct *tty;
 	int result;
 	int status = urb->status;
 
@@ -242,6 +243,7 @@ static void safe_read_bulk_callback(struct urb *urb)
 		printk("\n");
 	}
 #endif
+	tty = tty_port_tty_get(&port->port);
 	if (safe) {
 		__u16 fcs;
 		fcs = fcs_compute10(data, length, CRC10_INITFCS);
@@ -250,9 +252,9 @@ static void safe_read_bulk_callback(struct urb *urb)
 			if (actual_length <= (length - 2)) {
 				info("%s - actual: %d", __func__,
 							actual_length);
-				tty_insert_flip_string(port->port.tty,
+				tty_insert_flip_string(tty,
 							data, actual_length);
-				tty_flip_buffer_push(port->port.tty);
+				tty_flip_buffer_push(tty);
 			} else {
 				err("%s - inconsistent lengths %d:%d",
 					__func__, actual_length, length);
@@ -261,9 +263,10 @@ static void safe_read_bulk_callback(struct urb *urb)
 			err("%s - bad CRC %x", __func__, fcs);
 		}
 	} else {
-		tty_insert_flip_string(port->port.tty, data, length);
-		tty_flip_buffer_push(port->port.tty);
+		tty_insert_flip_string(tty, data, length);
+		tty_flip_buffer_push(tty);
 	}
+	tty_kref_put(tty);
 
 	/* Continue trying to always read  */
 	usb_fill_bulk_urb(urb, port->serial->dev,
drivers/usb/serial/sierra.c +9 -7
index ea1a103..8b9eaf3 100644
@@ -440,14 +440,14 @@ static void sierra_indat_callback(struct urb *urb)
 		dbg("%s: nonzero status: %d on endpoint %02x.",
 		    __func__, status, endpoint);
 	} else {
-		tty = port->port.tty;
 		if (urb->actual_length) {
+		tty = tty_port_tty_get(&port->port);
 			tty_buffer_request_room(tty, urb->actual_length);
 			tty_insert_flip_string(tty, data, urb->actual_length);
 			tty_flip_buffer_push(tty);
-		} else {
+			tty_kref_put(tty);
+		} else
 			dbg("%s: empty read urb received", __func__);
-		}
 
 		/* Resubmit urb so we continue receiving */
 		if (port->port.count && status != -ESHUTDOWN) {
@@ -485,6 +485,7 @@ static void sierra_instat_callback(struct urb *urb)
 			unsigned char signals = *((unsigned char *)
 					urb->transfer_buffer +
 					sizeof(struct usb_ctrlrequest));
+			struct tty_struct *tty;
 
 			dbg("%s: signal x%x", __func__, signals);
 
@@ -494,9 +495,11 @@ static void sierra_instat_callback(struct urb *urb)
 			portdata->dsr_state = ((signals & 0x02) ? 1 : 0);
 			portdata->ri_state = ((signals & 0x08) ? 1 : 0);
 
-			if (port->port.tty && !C_CLOCAL(port->port.tty) &&
+			tty = tty_port_tty_get(&port->port);
+			if (tty && !C_CLOCAL(tty) &&
 					old_dcd_state && !portdata->dcd_state)
-				tty_hangup(port->port.tty);
+				tty_hangup(tty);
+			tty_kref_put(tty);
 		} else {
 			dbg("%s: type %x req %x", __func__,
 				req_pkt->bRequestType, req_pkt->bRequest);
@@ -616,8 +619,7 @@ static void sierra_close(struct tty_struct *tty,
 	}
 
 	usb_kill_urb(port->interrupt_in_urb);
-
-	port->port.tty = NULL;	/* FIXME */
+	tty_port_tty_set(&port->port, NULL);
 }
 
 static int sierra_startup(struct usb_serial *serial)
drivers/usb/serial/spcp8x5.c +2 -1
index 283cf6b..1533d6e 100644
@@ -755,7 +755,7 @@ static void spcp8x5_read_bulk_callback(struct urb *urb)
 		tty_flag = TTY_FRAME;
 	dev_dbg(&port->dev, "tty_flag = %d\n", tty_flag);
 
-	tty = port->port.tty;
+	tty = tty_port_tty_get(&port->port);
 	if (tty && urb->actual_length) {
 		tty_buffer_request_room(tty, urb->actual_length + 1);
 		/* overrun is special, not associated with a char */
@@ -765,6 +765,7 @@ static void spcp8x5_read_bulk_callback(struct urb *urb)
 			tty_insert_flip_char(tty, data[i], tty_flag);
 		tty_flip_buffer_push(tty);
 	}
+	tty_kref_put(tty);
 
 	/* Schedule the next read _if_ we are still open */
 	if (port->port.count) {
drivers/usb/serial/ti_usb_3410_5052.c +23 -21

130 lines not on this page · raw message

drivers/usb/serial/usb-serial.c +15 -9
index 4f7f9e3..e7d4246 100644
@@ -214,7 +214,7 @@ static int serial_open (struct tty_struct *tty, struct file *filp)
 	/* set up our port structure making the tty driver
 	 * remember our port object, and us it */
 	tty->driver_data = port;
-	port->port.tty = tty;
+	tty_port_tty_set(&port->port, tty);
 
 	if (port->port.count == 1) {
 
@@ -246,7 +246,7 @@ bailout_module_put:
 bailout_mutex_unlock:
 	port->port.count = 0;
 	tty->driver_data = NULL;
-	port->port.tty = NULL;
+	tty_port_tty_set(&port->port, NULL);
 	mutex_unlock(&port->mutex);
 bailout_kref_put:
 	usb_serial_put(serial);
@@ -276,10 +276,11 @@ static void serial_close(struct tty_struct *tty, struct file *filp)
 		port->serial->type->close(tty, port, filp);
 
 	if (port->port.count == (port->console? 1 : 0)) {
-		if (port->port.tty) {
-			if (port->port.tty->driver_data)
-				port->port.tty->driver_data = NULL;
-			port->port.tty = NULL;
+		struct tty_struct *tty = tty_port_tty_get(&port->port);
+		if (tty) {
+			if (tty->driver_data)
+				tty->driver_data = NULL;
+			tty_port_tty_set(&port->port, NULL);
 		}
 	}
 
@@ -508,11 +509,12 @@ static void usb_serial_port_work(struct work_struct *work)
 	if (!port)
 		return;
 
-	tty = port->port.tty;
+	tty = tty_port_tty_get(&port->port);
 	if (!tty)
 		return;
 
 	tty_wakeup(tty);
+	tty_kref_put(tty);
 }
 
 static void port_release(struct device *dev)
@@ -819,6 +821,7 @@ int usb_serial_probe(struct usb_interface *interface,
 		port = kzalloc(sizeof(struct usb_serial_port), GFP_KERNEL);
 		if (!port)
 			goto probe_error;
+		tty_port_init(&port->port);
 		port->serial = serial;
 		spin_lock_init(&port->lock);
 		mutex_init(&port->mutex);
@@ -1040,8 +1043,11 @@ void usb_serial_disconnect(struct usb_interface *interface)
 	for (i = 0; i < serial->num_ports; ++i) {
 		port = serial->port[i];
 		if (port) {
-			if (port->port.tty)
-				tty_hangup(port->port.tty);
+			struct tty_struct *tty = tty_port_tty_get(&port->port);
+			if (tty) {
+				tty_hangup(tty);
+				tty_kref_put(tty);
+			}
 			kill_traffic(port);
 		}
 	}
drivers/usb/serial/visor.c +11 -7
index cf8924f..a6d1c75 100644
@@ -499,7 +499,7 @@ static void visor_read_bulk_callback(struct urb *urb)
 	int status = urb->status;
 	struct tty_struct *tty;
 	int result;
-	int available_room;
+	int available_room = 0;
 
 	dbg("%s - port %d", __func__, port->number);
 
@@ -512,13 +512,17 @@ static void visor_read_bulk_callback(struct urb *urb)
 	usb_serial_debug_data(debug, &port->dev, __func__,
 						urb->actual_length, data);
 
-	tty = port->port.tty;
-	if (tty && urb->actual_length) {
-		available_room = tty_buffer_request_room(tty,
+	if (urb->actual_length) {
+		tty = tty_port_tty_get(&port->port);
+		if (tty) {
+			available_room = tty_buffer_request_room(tty,
 							urb->actual_length);
-		if (available_room) {
-			tty_insert_flip_string(tty, data, available_room);
-			tty_flip_buffer_push(tty);
+			if (available_room) {
+				tty_insert_flip_string(tty, data,
+							available_room);
+				tty_flip_buffer_push(tty);
+			}
+			tty_kref_put(tty);
 		}
 		spin_lock(&priv->lock);
 		priv->bytes_in += available_room;
drivers/usb/serial/whiteheat.c +5 -3
index 3a9d143..11c8b97 100644
@@ -1481,7 +1481,7 @@ static void rx_data_softint(struct work_struct *work)
 	struct whiteheat_private *info =
 		container_of(work, struct whiteheat_private, rx_work);
 	struct usb_serial_port *port = info->port;
-	struct tty_struct *tty = port->port.tty;
+	struct tty_struct *tty = tty_port_tty_get(&port->port);
 	struct whiteheat_urb_wrap *wrap;
 	struct urb *urb;
 	unsigned long flags;
@@ -1493,7 +1493,7 @@ static void rx_data_softint(struct work_struct *work)
 	spin_lock_irqsave(&info->lock, flags);
 	if (info->flags & THROTTLED) {
 		spin_unlock_irqrestore(&info->lock, flags);
-		return;
+		goto out;
 	}
 
 	list_for_each_safe(tmp, tmp2, &info->rx_urb_q) {
@@ -1513,7 +1513,7 @@ static void rx_data_softint(struct work_struct *work)
 				spin_unlock_irqrestore(&info->lock, flags);
 				tty_flip_buffer_push(tty);
 				schedule_work(&info->rx_work);
-				return;
+				goto out;
 			}
 			tty_insert_flip_string(tty, urb->transfer_buffer, len);
 			sent += len;
@@ -1536,6 +1536,8 @@ static void rx_data_softint(struct work_struct *work)
 
 	if (sent)
 		tty_flip_buffer_push(tty);
+out:
+	tty_kref_put(tty);
 }
 
 
include/linux/tty.h +3 -0
index b64d10b..c30ed8d 100644
@@ -182,6 +182,7 @@ struct signal_struct;
 
 struct tty_port {
 	struct tty_struct	*tty;		/* Back pointer */
+	spinlock_t		lock;		/* Lock protecting tty field */
 	int			blocked_open;	/* Waiting to open */
 	int			count;		/* Usage count */
 	wait_queue_head_t	open_wait;	/* Open waiters */
@@ -405,6 +406,8 @@ extern int tty_write_lock(struct tty_struct *tty, int ndelay);
 extern void tty_port_init(struct tty_port *port);
 extern int tty_port_alloc_xmit_buf(struct tty_port *port);
 extern void tty_port_free_xmit_buf(struct tty_port *port);
+extern struct tty_struct *tty_port_tty_get(struct tty_port *port);
+extern void tty_port_tty_set(struct tty_port *port, struct tty_struct *tty);
 
 extern int tty_register_ldisc(int disc, struct tty_ldisc_ops *new_ldisc);
 extern int tty_unregister_ldisc(int disc);
#44 lore raw

Re: [PATCH 38/76] tty: usb-serial krefs

Quoted 4 lines · Alan Cox

Use kref in the USB serial drivers so that we don't free tty structures from under the URB receive handlers as has historically been the case if you were unlucky. This also gives us a framework for general tty drivers to use tty_port objects and refcount.

Should we be calling kref_get() and kref_put() in interrupt context? Could we just get the reference in open and then put in close when we are done with it for each driver?

thanks,

greg k-h

author
#45 lore raw

Re: [PATCH 38/76] tty: usb-serial krefs

Quoted 3 lines · Greg KH

Should we be calling kref_get() and kref_put() in interrupt context? Could we just get the reference in open and then put in close when we are done with it for each driver?

That depends how you handle hangups and interrupt synchronization. If you can be sure you will get no more interrupts before you drop the reference in close/hangup then yes that should be fine. In particular watch out for the fact that hangup/close/re-open can run pretty much in parallel with cases like

close called by user
interrupted by carrier drop causing hangup

in parallel another open begins and blocks waiting a close

(Obviously for hotplug some further care is needed on the unplug paths)

Right now USB serial doesn't actually address all those cases anyway I suspect. I wasn't going to attack that until I had a common tty_port and tty_port code to do all that work rather than trying to fix each group of drivers.

Alan

Acked-by Greg Kroah-Hartman
#46 lore raw

Re: [PATCH 38/76] tty: usb-serial krefs

Quoted 14 lines · Alan Cox
Quoted 3 lines · Greg KH

Should we be calling kref_get() and kref_put() in interrupt context? Could we just get the reference in open and then put in close when we are done with it for each driver?

That depends how you handle hangups and interrupt synchronization. If you can be sure you will get no more interrupts before you drop the reference in close/hangup then yes that should be fine. In particular watch out for the fact that hangup/close/re-open can run pretty much in parallel with cases like

close called by user
interrupted by carrier drop causing hangup

Quoted 7 lines

in parallel another open begins and blocks waiting a close

(Obviously for hotplug some further care is needed on the unplug paths)

Right now USB serial doesn't actually address all those cases anyway I suspect. I wasn't going to attack that until I had a common tty_port and tty_port code to do all that work rather than trying to fix each group of drivers.

Ok, fair enough, we can do further refinement later. All of these changes look great to me, thanks for doing them. Feel free to put a:

on the usb-serial ones if you want it.

thanks,

greg k-h

author
#47 lore raw

PATCH 39/76 tty: kref usage for isicom and moxa

In reply to Alan Cox

Rather than blindly keep taking krefs we reorder the code in a few places to pass the tty down to the right place (which is important as from the user side it is not the case that tty == port->tty in all situations). For the irq and related paths use the krefs to stop the tty being freed under us.

---

 drivers/char/isicom.c |   61 +++++++++++++++++++++++++------------------------
 drivers/char/moxa.c   |   61 +++++++++++++++++++++++++++++++------------------
 2 files changed, 69 insertions(+), 53 deletions(-)
drivers/char/isicom.c +31 -30
index 8f7cc19..7d30ee1 100644
@@ -421,17 +421,16 @@ static void isicom_tx(unsigned long _data)
 	if (retries >= 100)
 		goto unlock;
 
+	tty = tty_port_tty_get(&port->port);
+	if (tty == NULL)
+		goto put_unlock;
+
 	for (; count > 0; count--, port++) {
 		/* port not active or tx disabled to force flow control */
 		if (!(port->port.flags & ASYNC_INITIALIZED) ||
 				!(port->status & ISI_TXOK))
 			continue;
 
-		tty = port->port.tty;
-
-		if (tty == NULL)
-			continue;
-
 		txcount = min_t(short, TX_SIZE, port->xmit_cnt);
 		if (txcount <= 0 || tty->stopped || tty->hw_stopped)
 			continue;
@@ -489,6 +488,8 @@ static void isicom_tx(unsigned long _data)
 			tty_wakeup(tty);
 	}
 
+put_unlock:
+	tty_kref_put(tty);
 unlock:
 	spin_unlock_irqrestore(&isi_card[card].card_lock, flags);
 	/*	schedule another tx for hopefully in about 10ms	*/
@@ -547,7 +548,7 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id)
 		return IRQ_HANDLED;
 	}
 
-	tty = port->port.tty;
+	tty = tty_port_tty_get(&port->port);
 	if (tty == NULL) {
 		word_count = byte_count >> 1;
 		while (byte_count > 1) {
@@ -588,7 +589,7 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id)
 			}
 
 			if (port->port.flags & ASYNC_CTS_FLOW) {
-				if (port->port.tty->hw_stopped) {
+				if (tty->hw_stopped) {
 					if (header & ISI_CTS) {
 						port->port.tty->hw_stopped = 0;
 						/* start tx ing */
@@ -597,7 +598,7 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id)
 						tty_wakeup(tty);
 					}
 				} else if (!(header & ISI_CTS)) {
-					port->port.tty->hw_stopped = 1;
+					tty->hw_stopped = 1;
 					/* stop tx ing */
 					port->status &= ~(ISI_TXOK | ISI_CTS);
 				}
@@ -660,24 +661,21 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id)
 	}
 	outw(0x0000, base+0x04); /* enable interrupts */
 	spin_unlock(&card->card_lock);
+	tty_kref_put(tty);
 
 	return IRQ_HANDLED;
 }
 
-static void isicom_config_port(struct isi_port *port)
+static void isicom_config_port(struct tty_struct *tty)
 {
+	struct isi_port *port = tty->driver_data;
 	struct isi_board *card = port->card;
-	struct tty_struct *tty;
 	unsigned long baud;
 	unsigned long base = card->base;
 	u16 channel_setup, channel = port->channel,
 		shift_count = card->shift_count;
 	unsigned char flow_ctrl;
 
-	tty = port->port.tty;
-
-	if (tty == NULL)
-		return;
 	/* FIXME: Switch to new tty baud API */
 	baud = C_BAUD(tty);
 	if (baud & CBAUDEX) {
@@ -690,7 +688,7 @@ static void isicom_config_port(struct isi_port *port)
 
 		/* 1,2,3,4 => 57.6, 115.2, 230, 460 kbps resp. */
 		if (baud < 1 || baud > 4)
-			port->port.tty->termios->c_cflag &= ~CBAUDEX;
+			tty->termios->c_cflag &= ~CBAUDEX;
 		else
 			baud += 15;
 	}
@@ -797,8 +795,9 @@ static inline void isicom_setup_board(struct isi_board *bp)
 	spin_unlock_irqrestore(&bp->card_lock, flags);
 }
 
-static int isicom_setup_port(struct isi_port *port)
+static int isicom_setup_port(struct tty_struct *tty)
 {
+	struct isi_port *port = tty->driver_data;
 	struct isi_board *card = port->card;
 	unsigned long flags;
 
@@ -808,8 +807,7 @@ static int isicom_setup_port(struct isi_port *port)
 		return -ENOMEM;
 
 	spin_lock_irqsave(&card->card_lock, flags);
-	if (port->port.tty)
-		clear_bit(TTY_IO_ERROR, &port->port.tty->flags);
+	clear_bit(TTY_IO_ERROR, &tty->flags);
 	if (port->port.count == 1)
 		card->count++;
 
@@ -823,7 +821,7 @@ static int isicom_setup_port(struct isi_port *port)
 		InterruptTheCard(card->base);
 	}
 
-	isicom_config_port(port);
+	isicom_config_port(tty);
 	port->port.flags |= ASYNC_INITIALIZED;
 	spin_unlock_irqrestore(&card->card_lock, flags);
 
@@ -934,8 +932,8 @@ static int isicom_open(struct tty_struct *tty, struct file *filp)
 
 	port->port.count++;
 	tty->driver_data = port;
-	port->port.tty = tty;
-	error = isicom_setup_port(port);
+	tty_port_tty_set(&port->port, tty);
+	error = isicom_setup_port(tty);
 	if (error == 0)
 		error = block_til_ready(tty, filp, port);
 	return error;
@@ -955,15 +953,17 @@ static void isicom_shutdown_port(struct isi_port *port)
 	struct isi_board *card = port->card;
 	struct tty_struct *tty;
 
-	tty = port->port.tty;
+	tty = tty_port_tty_get(&port->port);
 
-	if (!(port->port.flags & ASYNC_INITIALIZED))
+	if (!(port->port.flags & ASYNC_INITIALIZED)) {
+		tty_kref_put(tty);
 		return;
+	}
 
 	tty_port_free_xmit_buf(&port->port);
 	port->port.flags &= ~ASYNC_INITIALIZED;
 	/* 3rd October 2000 : Vinayak P Risbud */
-	port->port.tty = NULL;
+	tty_port_tty_set(&port->port, NULL);
 
 	/*Fix done by Anil .S on 30-04-2001
 	remote login through isi port has dtr toggle problem
@@ -1243,9 +1243,10 @@ static int isicom_tiocmset(struct tty_struct *tty, struct file *file,
 	return 0;
 }
 
-static int isicom_set_serial_info(struct isi_port *port,
-	struct serial_struct __user *info)
+static int isicom_set_serial_info(struct tty_struct *tty,
+					struct serial_struct __user *info)
 {
+	struct isi_port *port = tty->driver_data;
 	struct serial_struct newinfo;
 	int reconfig_port;
 
@@ -1276,7 +1277,7 @@ static int isicom_set_serial_info(struct isi_port *port,
 	if (reconfig_port) {
 		unsigned long flags;
 		spin_lock_irqsave(&port->card->card_lock, flags);
-		isicom_config_port(port);
+		isicom_config_port(tty);
 		spin_unlock_irqrestore(&port->card->card_lock, flags);
 	}
 	unlock_kernel();
@@ -1318,7 +1319,7 @@ static int isicom_ioctl(struct tty_struct *tty, struct file *filp,
 		return isicom_get_serial_info(port, argp);
 
 	case TIOCSSERIAL:
-		return isicom_set_serial_info(port, argp);
+		return isicom_set_serial_info(tty, argp);
 
 	default:
 		return -ENOIOCTLCMD;
@@ -1341,7 +1342,7 @@ static void isicom_set_termios(struct tty_struct *tty,
 		return;
 
 	spin_lock_irqsave(&port->card->card_lock, flags);
-	isicom_config_port(port);
+	isicom_config_port(tty);
 	spin_unlock_irqrestore(&port->card->card_lock, flags);
 
 	if ((old_termios->c_cflag & CRTSCTS) &&
@@ -1419,7 +1420,7 @@ static void isicom_hangup(struct tty_struct *tty)
 
 	port->port.count = 0;
 	port->port.flags &= ~ASYNC_NORMAL_ACTIVE;
-	port->port.tty = NULL;
+	tty_port_tty_set(&port->port, NULL);
 	wake_up_interruptible(&port->port.open_wait);
 }
 
drivers/char/moxa.c +38 -23

173 lines not on this page · raw message

author
#48 lore raw

PATCH 40/76 stallion: Use krefs

In reply to Alan Cox

Use tty_port_init and krefs in the stallion drivers to protect us from devices going away underneath us. As with the other drives some rearranging is done to pass the tty structure down properly on the user side.

---

 drivers/char/Kconfig     |    4 +-
 drivers/char/istallion.c |  107 +++++++++++++++++++++++++---------------------
 drivers/char/stallion.c  |  105 ++++++++++++++++++++++++++++-----------------
 3 files changed, 123 insertions(+), 93 deletions(-)
drivers/char/Kconfig +2 -2
index caff851..700ff96 100644
@@ -350,7 +350,7 @@ config STALDRV
 
 config STALLION
 	tristate "Stallion EasyIO or EC8/32 support"
-	depends on STALDRV && BROKEN_ON_SMP && (ISA || EISA || PCI)
+	depends on STALDRV && (ISA || EISA || PCI)
 	help
 	  If you have an EasyIO or EasyConnection 8/32 multiport Stallion
 	  card, then this is for you; say Y.  Make sure to read
@@ -361,7 +361,7 @@ config STALLION
 
 config ISTALLION
 	tristate "Stallion EC8/64, ONboard, Brumby support"
-	depends on STALDRV && BROKEN_ON_SMP && (ISA || EISA || PCI)
+	depends on STALDRV && (ISA || EISA || PCI)
 	help
 	  If you have an EasyConnection 8/64, ONboard, Brumby or Stallion
 	  serial multiport card, say Y here. Make sure to read
drivers/char/istallion.c +57 -50

321 lines not on this page · raw message

drivers/char/stallion.c +64 -41

331 lines not on this page · raw message

author
#49 lore raw

PATCH 41/76 mxser: Switch to kref tty

In reply to Alan Cox

---

 drivers/char/mxser.c |  192 +++++++++++++++++++++++++++-----------------------
 1 files changed, 103 insertions(+), 89 deletions(-)
drivers/char/mxser.c +103 -89
index b638403..308cb60 100644
@@ -610,15 +610,16 @@ static int mxser_block_til_ready(struct tty_struct *tty, struct file *filp,
 	return 0;
 }
 
-static int mxser_set_baud(struct mxser_port *info, long newspd)
+static int mxser_set_baud(struct tty_struct *tty, long newspd)
 {
+	struct mxser_port *info = tty->driver_data;
 	int quot = 0, baud;
 	unsigned char cval;
 
-	if (!info->port.tty || !info->port.tty->termios)
+	if (!tty->termios)
 		return -1;
 
-	if (!(info->ioaddr))
+	if (!info->ioaddr)
 		return -1;
 
 	if (newspd > info->max_baud)
@@ -626,13 +627,13 @@ static int mxser_set_baud(struct mxser_port *info, long newspd)
 
 	if (newspd == 134) {
 		quot = 2 * info->baud_base / 269;
-		tty_encode_baud_rate(info->port.tty, 134, 134);
+		tty_encode_baud_rate(tty, 134, 134);
 	} else if (newspd) {
 		quot = info->baud_base / newspd;
 		if (quot == 0)
 			quot = 1;
 		baud = info->baud_base/quot;
-		tty_encode_baud_rate(info->port.tty, baud, baud);
+		tty_encode_baud_rate(tty, baud, baud);
 	} else {
 		quot = 0;
 	}
@@ -658,7 +659,7 @@ static int mxser_set_baud(struct mxser_port *info, long newspd)
 	outb(cval, info->ioaddr + UART_LCR);	/* reset DLAB */
 
 #ifdef BOTHER
-	if (C_BAUD(info->port.tty) == BOTHER) {
+	if (C_BAUD(tty) == BOTHER) {
 		quot = info->baud_base % newspd;
 		quot *= 8;
 		if (quot % newspd > newspd / 2) {
@@ -679,21 +680,22 @@ static int mxser_set_baud(struct mxser_port *info, long newspd)
  * This routine is called to set the UART divisor registers to match
  * the specified baud rate for a serial port.
  */
-static int mxser_change_speed(struct mxser_port *info,
-		struct ktermios *old_termios)
+static int mxser_change_speed(struct tty_struct *tty,
+					struct ktermios *old_termios)
 {
+	struct mxser_port *info = tty->driver_data;
 	unsigned cflag, cval, fcr;
 	int ret = 0;
 	unsigned char status;
 
-	if (!info->port.tty || !info->port.tty->termios)
+	if (!tty->termios)
 		return ret;
-	cflag = info->port.tty->termios->c_cflag;
-	if (!(info->ioaddr))
+	cflag = tty->termios->c_cflag;
+	if (!info->ioaddr)
 		return ret;
 
-	if (mxser_set_baud_method[info->port.tty->index] == 0)
-		mxser_set_baud(info, tty_get_baud_rate(info->port.tty));
+	if (mxser_set_baud_method[tty->index] == 0)
+		mxser_set_baud(tty, tty_get_baud_rate(tty));
 
 	/* byte size and parity */
 	switch (cflag & CSIZE) {
@@ -762,9 +764,9 @@ static int mxser_change_speed(struct mxser_port *info,
 			info->MCR |= UART_MCR_AFE;
 		} else {
 			status = inb(info->ioaddr + UART_MSR);
-			if (info->port.tty->hw_stopped) {
+			if (tty->hw_stopped) {
 				if (status & UART_MSR_CTS) {
-					info->port.tty->hw_stopped = 0;
+					tty->hw_stopped = 0;
 					if (info->type != PORT_16550A &&
 							!info->board->chip_flag) {
 						outb(info->IER & ~UART_IER_THRI,
@@ -774,11 +776,11 @@ static int mxser_change_speed(struct mxser_port *info,
 						outb(info->IER, info->ioaddr +
 								UART_IER);
 					}
-					tty_wakeup(info->port.tty);
+					tty_wakeup(tty);
 				}
 			} else {
 				if (!(status & UART_MSR_CTS)) {
-					info->port.tty->hw_stopped = 1;
+					tty->hw_stopped = 1;
 					if ((info->type != PORT_16550A) &&
 							(!info->board->chip_flag)) {
 						info->IER &= ~UART_IER_THRI;
@@ -804,21 +806,21 @@ static int mxser_change_speed(struct mxser_port *info,
 	 * Set up parity check flag
 	 */
 	info->read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
-	if (I_INPCK(info->port.tty))
+	if (I_INPCK(tty))
 		info->read_status_mask |= UART_LSR_FE | UART_LSR_PE;
-	if (I_BRKINT(info->port.tty) || I_PARMRK(info->port.tty))
+	if (I_BRKINT(tty) || I_PARMRK(tty))
 		info->read_status_mask |= UART_LSR_BI;
 
 	info->ignore_status_mask = 0;
 
-	if (I_IGNBRK(info->port.tty)) {
+	if (I_IGNBRK(tty)) {
 		info->ignore_status_mask |= UART_LSR_BI;
 		info->read_status_mask |= UART_LSR_BI;
 		/*
 		 * If we're ignore parity and break indicators, ignore
 		 * overruns too.  (For real raw support).
 		 */
-		if (I_IGNPAR(info->port.tty)) {
+		if (I_IGNPAR(tty)) {
 			info->ignore_status_mask |=
 						UART_LSR_OE |
 						UART_LSR_PE |
@@ -830,16 +832,16 @@ static int mxser_change_speed(struct mxser_port *info,
 		}
 	}
 	if (info->board->chip_flag) {
-		mxser_set_must_xon1_value(info->ioaddr, START_CHAR(info->port.tty));
-		mxser_set_must_xoff1_value(info->ioaddr, STOP_CHAR(info->port.tty));
-		if (I_IXON(info->port.tty)) {
+		mxser_set_must_xon1_value(info->ioaddr, START_CHAR(tty));
+		mxser_set_must_xoff1_value(info->ioaddr, STOP_CHAR(tty));
+		if (I_IXON(tty)) {
 			mxser_enable_must_rx_software_flow_control(
 					info->ioaddr);
 		} else {
 			mxser_disable_must_rx_software_flow_control(
 					info->ioaddr);
 		}
-		if (I_IXOFF(info->port.tty)) {
+		if (I_IXOFF(tty)) {
 			mxser_enable_must_tx_software_flow_control(
 					info->ioaddr);
 		} else {
@@ -855,7 +857,8 @@ static int mxser_change_speed(struct mxser_port *info,
 	return ret;
 }
 
-static void mxser_check_modem_status(struct mxser_port *port, int status)
+static void mxser_check_modem_status(struct tty_struct *tty,
+				struct mxser_port *port, int status)
 {
 	/* update input line counters */
 	if (status & UART_MSR_TERI)
@@ -874,10 +877,11 @@ static void mxser_check_modem_status(struct mxser_port *port, int status)
 			wake_up_interruptible(&port->port.open_wait);
 	}
 
+	tty = tty_port_tty_get(&port->port);
 	if (port->port.flags & ASYNC_CTS_FLOW) {
-		if (port->port.tty->hw_stopped) {
+		if (tty->hw_stopped) {
 			if (status & UART_MSR_CTS) {
-				port->port.tty->hw_stopped = 0;
+				tty->hw_stopped = 0;
 
 				if ((port->type != PORT_16550A) &&
 						(!port->board->chip_flag)) {
@@ -887,11 +891,11 @@ static void mxser_check_modem_status(struct mxser_port *port, int status)
 					outb(port->IER, port->ioaddr +
 							UART_IER);
 				}
-				tty_wakeup(port->port.tty);
+				tty_wakeup(tty);
 			}
 		} else {
 			if (!(status & UART_MSR_CTS)) {
-				port->port.tty->hw_stopped = 1;
+				tty->hw_stopped = 1;
 				if (port->type != PORT_16550A &&
 						!port->board->chip_flag) {
 					port->IER &= ~UART_IER_THRI;
@@ -903,8 +907,9 @@ static void mxser_check_modem_status(struct mxser_port *port, int status)
 	}
 }
 
-static int mxser_startup(struct mxser_port *info)
+static int mxser_startup(struct tty_struct *tty)
 {
+	struct mxser_port *info = tty->driver_data;
 	unsigned long page;
 	unsigned long flags;
 
@@ -921,8 +926,7 @@ static int mxser_startup(struct mxser_port *info)
 	}
 
 	if (!info->ioaddr || !info->type) {
-		if (info->port.tty)
-			set_bit(TTY_IO_ERROR, &info->port.tty->flags);
+		set_bit(TTY_IO_ERROR, &tty->flags);
 		free_page(page);
 		spin_unlock_irqrestore(&info->slock, flags);
 		return 0;
@@ -952,8 +956,8 @@ static int mxser_startup(struct mxser_port *info)
 	if (inb(info->ioaddr + UART_LSR) == 0xff) {
 		spin_unlock_irqrestore(&info->slock, flags);
 		if (capable(CAP_SYS_ADMIN)) {
-			if (info->port.tty)
-				set_bit(TTY_IO_ERROR, &info->port.tty->flags);
+			if (tty)
+				set_bit(TTY_IO_ERROR, &tty->flags);
 			return 0;
 		} else
 			return -ENODEV;
@@ -991,14 +995,13 @@ static int mxser_startup(struct mxser_port *info)
 	(void) inb(info->ioaddr + UART_IIR);
 	(void) inb(info->ioaddr + UART_MSR);
 
-	if (info->port.tty)
-		clear_bit(TTY_IO_ERROR, &info->port.tty->flags);
+	clear_bit(TTY_IO_ERROR, &tty->flags);
 	info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
 
 	/*
 	 * and set the speed of the serial port
 	 */
-	mxser_change_speed(info, NULL);
+	mxser_change_speed(tty, NULL);
 	info->port.flags |= ASYNC_INITIALIZED;
 	spin_unlock_irqrestore(&info->slock, flags);
 
@@ -1009,8 +1012,9 @@ static int mxser_startup(struct mxser_port *info)
  * This routine will shutdown a serial port; interrupts maybe disabled, and
  * DTR is dropped if the hangup on close termio flag is on.
  */
-static void mxser_shutdown(struct mxser_port *info)
+static void mxser_shutdown(struct tty_struct *tty)
 {
+	struct mxser_port *info = tty->driver_data;
 	unsigned long flags;
 
 	if (!(info->port.flags & ASYNC_INITIALIZED))
@@ -1035,7 +1039,7 @@ static void mxser_shutdown(struct mxser_port *info)
 	info->IER = 0;
 	outb(0x00, info->ioaddr + UART_IER);
 
-	if (!info->port.tty || (info->port.tty->termios->c_cflag & HUPCL))
+	if (tty->termios->c_cflag & HUPCL)
 		info->MCR &= ~(UART_MCR_DTR | UART_MCR_RTS);
 	outb(info->MCR, info->ioaddr + UART_MCR);
 
@@ -1051,8 +1055,7 @@ static void mxser_shutdown(struct mxser_port *info)
 	/* read data port to reset things */
 	(void) inb(info->ioaddr + UART_RX);
 
-	if (info->port.tty)
-		set_bit(TTY_IO_ERROR, &info->port.tty->flags);
+	set_bit(TTY_IO_ERROR, &tty->flags);
 
 	info->port.flags &= ~ASYNC_INITIALIZED;
 
@@ -1084,14 +1087,14 @@ static int mxser_open(struct tty_struct *tty, struct file *filp)
 		return -ENODEV;
 
 	tty->driver_data = info;
-	info->port.tty = tty;
+	tty_port_tty_set(&info->port, tty);
 	/*
 	 * Start up serial port
 	 */
 	spin_lock_irqsave(&info->slock, flags);
 	info->port.count++;
 	spin_unlock_irqrestore(&info->slock, flags);
-	retval = mxser_startup(info);
+	retval = mxser_startup(tty);
 	if (retval)
 		return retval;
 
@@ -1209,13 +1212,13 @@ static void mxser_close(struct tty_struct *tty, struct file *filp)
 				break;
 		}
 	}
-	mxser_shutdown(info);
+	mxser_shutdown(tty);
 
 	mxser_flush_buffer(tty);
 	tty_ldisc_flush(tty);
 
 	tty->closing = 0;
-	info->port.tty = NULL;
+	tty_port_tty_set(&info->port, NULL);
 	if (info->port.blocked_open) {
 		if (info->port.close_delay)
 			schedule_timeout_interruptible(info->port.close_delay);
@@ -1337,12 +1340,13 @@ static int mxser_chars_in_buffer(struct tty_struct *tty)
  * friends of mxser_ioctl()
  * ------------------------------------------------------------
  */
-static int mxser_get_serial_info(struct mxser_port *info,
+static int mxser_get_serial_info(struct tty_struct *tty,
 		struct serial_struct __user *retinfo)
 {
+	struct mxser_port *info = tty->driver_data;
 	struct serial_struct tmp = {
 		.type = info->type,
-		.line = info->port.tty->index,
+		.line = tty->index,
 		.port = info->ioaddr,
 		.irq = info->board->irq,
 		.flags = info->port.flags,
@@ -1357,9 +1361,10 @@ static int mxser_get_serial_info(struct mxser_port *info,
 	return 0;
 }
 
-static int mxser_set_serial_info(struct mxser_port *info,
+static int mxser_set_serial_info(struct tty_struct *tty,
 		struct serial_struct __user *new_info)
 {
+	struct mxser_port *info = tty->driver_data;
 	struct serial_struct new_serial;
 	speed_t baud;
 	unsigned long sl_flags;
@@ -1393,14 +1398,14 @@ static int mxser_set_serial_info(struct mxser_port *info,
 				(new_serial.flags & ASYNC_FLAGS));
 		info->port.close_delay = new_serial.close_delay * HZ / 100;
 		info->port.closing_wait = new_serial.closing_wait * HZ / 100;
-		info->port.tty->low_latency =
-				(info->port.flags & ASYNC_LOW_LATENCY) ? 1 : 0;
+		tty->low_latency = (info->port.flags & ASYNC_LOW_LATENCY)
+								? 1 : 0;
 		if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST &&
 				(new_serial.baud_base != info->baud_base ||
 				new_serial.custom_divisor !=
 				info->custom_divisor)) {
 			baud = new_serial.baud_base / new_serial.custom_divisor;
-			tty_encode_baud_rate(info->port.tty, baud, baud);
+			tty_encode_baud_rate(tty, baud, baud);
 		}
 	}
 
@@ -1411,11 +1416,11 @@ static int mxser_set_serial_info(struct mxser_port *info,
 	if (info->port.flags & ASYNC_INITIALIZED) {
 		if (flags != (info->port.flags & ASYNC_SPD_MASK)) {
 			spin_lock_irqsave(&info->slock, sl_flags);
-			mxser_change_speed(info, NULL);
+			mxser_change_speed(tty, NULL);
 			spin_unlock_irqrestore(&info->slock, sl_flags);
 		}
 	} else
-		retval = mxser_startup(info);
+		retval = mxser_startup(tty);
 
 	return retval;
 }
@@ -1461,7 +1466,7 @@ static int mxser_tiocmget(struct tty_struct *tty, struct file *file)
 	spin_lock_irqsave(&info->slock, flags);
 	status = inb(info->ioaddr + UART_MSR);
 	if (status & UART_MSR_ANY_DELTA)
-		mxser_check_modem_status(info, status);
+		mxser_check_modem_status(tty, info, status);
 	spin_unlock_irqrestore(&info->slock, flags);
 	return ((control & UART_MCR_RTS) ? TIOCM_RTS : 0) |
 		    ((control & UART_MCR_DTR) ? TIOCM_DTR : 0) |
@@ -1606,6 +1611,7 @@ static int __init mxser_read_register(int port, unsigned short *regs)
 static int mxser_ioctl_special(unsigned int cmd, void __user *argp)
 {
 	struct mxser_port *port;
+	struct tty_struct *tty;
 	int result, status;
 	unsigned int i, j;
 	int ret = 0;
@@ -1643,12 +1649,14 @@ static int mxser_ioctl_special(unsigned int cmd, void __user *argp)
 
 				if (!port->ioaddr)
 					goto copy;
+				
+				tty = tty_port_tty_get(&port->port);
 
-				if (!port->port.tty || !port->port.tty->termios)
+				if (!tty || !tty->termios)
 					ms.cflag = port->normal_termios.c_cflag;
 				else
-					ms.cflag = port->port.tty->termios->c_cflag;
-
+					ms.cflag = tty->termios->c_cflag;
+				tty_kref_put(tty);
 				status = inb(port->ioaddr + UART_MSR);
 				if (status & UART_MSR_DCD)
 					ms.dcd = 1;
@@ -1704,15 +1712,18 @@ static int mxser_ioctl_special(unsigned int cmd, void __user *argp)
 				me->up_txcnt[p] = port->mon_data.up_txcnt;
 				me->modem_status[p] =
 					port->mon_data.modem_status;
-				me->baudrate[p] = tty_get_baud_rate(port->port.tty);
+				tty = tty_port_tty_get(&port->port);
 
-				if (!port->port.tty || !port->port.tty->termios) {
+				if (!tty || !tty->termios) {
 					cflag = port->normal_termios.c_cflag;
 					iflag = port->normal_termios.c_iflag;
+					me->baudrate[p] = tty_termios_baud_rate(&port->normal_termios);
 				} else {
-					cflag = port->port.tty->termios->c_cflag;
-					iflag = port->port.tty->termios->c_iflag;
+					cflag = tty->termios->c_cflag;
+					iflag = tty->termios->c_iflag;
+					me->baudrate[p] = tty_get_baud_rate(tty);
 				}
+				tty_kref_put(tty);
 
 				me->databits[p] = cflag & CSIZE;
 				me->stopbits[p] = cflag & CSTOPB;
@@ -1822,12 +1833,12 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file,
 	switch (cmd) {
 	case TIOCGSERIAL:
 		lock_kernel();
-		retval = mxser_get_serial_info(info, argp);
+		retval = mxser_get_serial_info(tty, argp);
 		unlock_kernel();
 		return retval;
 	case TIOCSSERIAL:
 		lock_kernel();
-		retval = mxser_set_serial_info(info, argp);
+		retval = mxser_set_serial_info(tty, argp);
 		unlock_kernel();
 		return retval;
 	case TIOCSERGETLSR:	/* Get line status register */
@@ -1896,7 +1907,7 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file,
 
 		lock_kernel();
 		status = mxser_get_msr(info->ioaddr, 1, tty->index);
-		mxser_check_modem_status(info, status);
+		mxser_check_modem_status(tty, info, status);
 
 		mcr = inb(info->ioaddr + UART_MCR);
 		if (mcr & MOXA_MUST_MCR_XON_FLAG)
@@ -1909,7 +1920,7 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file,
 		else
 			info->mon_data.hold_reason |= NPPI_NOTIFY_XOFFXENT;
 
-		if (info->port.tty->hw_stopped)
+		if (tty->hw_stopped)
 			info->mon_data.hold_reason |= NPPI_NOTIFY_CTSHOLD;
 		else
 			info->mon_data.hold_reason &= ~NPPI_NOTIFY_CTSHOLD;
@@ -1958,7 +1969,7 @@ static void mxser_stoprx(struct tty_struct *tty)
 		}
 	}
 
-	if (info->port.tty->termios->c_cflag & CRTSCTS) {
+	if (tty->termios->c_cflag & CRTSCTS) {
 		info->MCR &= ~UART_MCR_RTS;
 		outb(info->MCR, info->ioaddr + UART_MCR);
 	}
@@ -1995,7 +2006,7 @@ static void mxser_unthrottle(struct tty_struct *tty)
 		}
 	}
 
-	if (info->port.tty->termios->c_cflag & CRTSCTS) {
+	if (tty->termios->c_cflag & CRTSCTS) {
 		info->MCR |= UART_MCR_RTS;
 		outb(info->MCR, info->ioaddr + UART_MCR);
 	}
@@ -2040,7 +2051,7 @@ static void mxser_set_termios(struct tty_struct *tty, struct ktermios *old_termi
 	unsigned long flags;
 
 	spin_lock_irqsave(&info->slock, flags);
-	mxser_change_speed(info, old_termios);
+	mxser_change_speed(tty, old_termios);
 	spin_unlock_irqrestore(&info->slock, flags);
 
 	if ((old_termios->c_cflag & CRTSCTS) &&
@@ -2138,10 +2149,10 @@ static void mxser_hangup(struct tty_struct *tty)
 	struct mxser_port *info = tty->driver_data;
 
 	mxser_flush_buffer(tty);
-	mxser_shutdown(info);
+	mxser_shutdown(tty);
 	info->port.count = 0;
 	info->port.flags &= ~ASYNC_NORMAL_ACTIVE;
-	info->port.tty = NULL;
+	tty_port_tty_set(&info->port, NULL);
 	wake_up_interruptible(&info->port.open_wait);
 }
 
@@ -2164,9 +2175,9 @@ static int mxser_rs_break(struct tty_struct *tty, int break_state)
 	return 0;
 }
 
-static void mxser_receive_chars(struct mxser_port *port, int *status)
+static void mxser_receive_chars(struct tty_struct *tty,
+				struct mxser_port *port, int *status)
 {
-	struct tty_struct *tty = port->port.tty;
 	unsigned char ch, gdl;
 	int ignored = 0;
 	int cnt = 0;
@@ -2174,9 +2185,8 @@ static void mxser_receive_chars(struct mxser_port *port, int *status)
 	int max = 256;
 
 	recv_room = tty->receive_room;
-	if ((recv_room == 0) && (!port->ldisc_stop_rx))
+	if (recv_room == 0 && !port->ldisc_stop_rx)
 		mxser_stoprx(tty);
-
 	if (port->board->chip_flag != MOXA_OTHER_UART) {
 
 		if (*status & UART_LSR_SPECIAL)
@@ -2253,7 +2263,7 @@ intr_old:
 	} while (*status & UART_LSR_DR);
 
 end_intr:
-	mxvar_log.rxcnt[port->port.tty->index] += cnt;
+	mxvar_log.rxcnt[tty->index] += cnt;
 	port->mon_data.rxcnt += cnt;
 	port->mon_data.up_rxcnt += cnt;
 
@@ -2267,14 +2277,14 @@ end_intr:
 	spin_lock(&port->slock);
 }
 
-static void mxser_transmit_chars(struct mxser_port *port)
+static void mxser_transmit_chars(struct tty_struct *tty, struct mxser_port *port)
 {
 	int count, cnt;
 
 	if (port->x_char) {
 		outb(port->x_char, port->ioaddr + UART_TX);
 		port->x_char = 0;
-		mxvar_log.txcnt[port->port.tty->index]++;
+		mxvar_log.txcnt[tty->index]++;
 		port->mon_data.txcnt++;
 		port->mon_data.up_txcnt++;
 		port->icount.tx++;
@@ -2284,8 +2294,8 @@ static void mxser_transmit_chars(struct mxser_port *port)
 	if (port->port.xmit_buf == NULL)
 		return;
 
-	if ((port->xmit_cnt <= 0) || port->port.tty->stopped ||
-			(port->port.tty->hw_stopped &&
+	if (port->xmit_cnt <= 0 || tty->stopped ||
+			(tty->hw_stopped &&
 			(port->type != PORT_16550A) &&
 			(!port->board->chip_flag))) {
 		port->IER &= ~UART_IER_THRI;
@@ -2302,14 +2312,14 @@ static void mxser_transmit_chars(struct mxser_port *port)
 		if (--port->xmit_cnt <= 0)
 			break;
 	} while (--count > 0);
-	mxvar_log.txcnt[port->port.tty->index] += (cnt - port->xmit_cnt);
+	mxvar_log.txcnt[tty->index] += (cnt - port->xmit_cnt);
 
 	port->mon_data.txcnt += (cnt - port->xmit_cnt);
 	port->mon_data.up_txcnt += (cnt - port->xmit_cnt);
 	port->icount.tx += (cnt - port->xmit_cnt);
 
-	if (port->xmit_cnt < WAKEUP_CHARS)
-		tty_wakeup(port->port.tty);
+	if (port->xmit_cnt < WAKEUP_CHARS && tty)
+		tty_wakeup(tty);
 
 	if (port->xmit_cnt <= 0) {
 		port->IER &= ~UART_IER_THRI;
@@ -2328,6 +2338,7 @@ static irqreturn_t mxser_interrupt(int irq, void *dev_id)
 	int max, irqbits, bits, msr;
 	unsigned int int_cnt, pass_counter = 0;
 	int handled = IRQ_NONE;
+	struct tty_struct *tty;
 
 	for (i = 0; i < MXSER_BOARDS; i++)
 		if (dev_id == &mxser_boards[i]) {
@@ -2360,13 +2371,15 @@ static irqreturn_t mxser_interrupt(int irq, void *dev_id)
 				if (iir & UART_IIR_NO_INT)
 					break;
 				iir &= MOXA_MUST_IIR_MASK;
-				if (!port->port.tty ||
+				tty = tty_port_tty_get(&port->port);
+				if (!tty ||
 						(port->port.flags & ASYNC_CLOSING) ||
 						!(port->port.flags &
 							ASYNC_INITIALIZED)) {
 					status = inb(port->ioaddr + UART_LSR);
 					outb(0x27, port->ioaddr + UART_FCR);
 					inb(port->ioaddr + UART_MSR);
+					tty_kref_put(tty);
 					break;
 				}
 
@@ -2387,27 +2400,28 @@ static irqreturn_t mxser_interrupt(int irq, void *dev_id)
 					    iir == MOXA_MUST_IIR_RDA ||
 					    iir == MOXA_MUST_IIR_RTO ||
 					    iir == MOXA_MUST_IIR_LSR)
-						mxser_receive_chars(port,
+						mxser_receive_chars(tty, port,
 								&status);
 
 				} else {
 					status &= port->read_status_mask;
 					if (status & UART_LSR_DR)
-						mxser_receive_chars(port,
+						mxser_receive_chars(tty, port,
 								&status);
 				}
 				msr = inb(port->ioaddr + UART_MSR);
 				if (msr & UART_MSR_ANY_DELTA)
-					mxser_check_modem_status(port, msr);
+					mxser_check_modem_status(tty, port, msr);
 
 				if (port->board->chip_flag) {
 					if (iir == 0x02 && (status &
 								UART_LSR_THRE))
-						mxser_transmit_chars(port);
+						mxser_transmit_chars(tty, port);
 				} else {
 					if (status & UART_LSR_THRE)
-						mxser_transmit_chars(port);
+						mxser_transmit_chars(tty, port);
 				}
+				tty_kref_put(tty);
 			} while (int_cnt++ < MXSER_ISR_PASS_LIMIT);
 			spin_unlock(&port->slock);
 		}
author
#50 lore raw

PATCH 42/76 tty: the vhangup syscall is racy

In reply to Alan Cox

We now have the infrastructure to sort this out but rather than teaching the syscall tty lock rules we move the hard work into a tty helper

---

 drivers/char/tty_io.c |   19 +++++++++++++++++++
 fs/open.c             |    3 +--
 2 files changed, 20 insertions(+), 2 deletions(-)
drivers/char/tty_io.c +19 -0
index 913b502..b5f57d0 100644
@@ -730,6 +730,25 @@ void tty_vhangup(struct tty_struct *tty)
 EXPORT_SYMBOL(tty_vhangup);
 
 /**
+ *	tty_vhangup_self	-	process vhangup for own ctty
+ *
+ *	Perform a vhangup on the current controlling tty
+ */
+
+void tty_vhangup_self(void)
+{
+	struct tty_struct *tty;
+
+	mutex_lock(&tty_mutex);
+	tty = get_current_tty();
+	if (tty) {
+		tty_vhangup(tty);
+		tty_kref_put(tty);
+	}
+	mutex_unlock(&tty_mutex);
+}
+
+/**
  *	tty_hung_up_p		-	was tty hung up
  *	@filp: file pointer of tty
  *
fs/open.c +1 -2
index 07da935..5596049 100644
@@ -1141,8 +1141,7 @@ EXPORT_SYMBOL(sys_close);
 asmlinkage long sys_vhangup(void)
 {
 	if (capable(CAP_SYS_TTY_CONFIG)) {
-		/* XXX: this needs locking */
-		tty_vhangup(current->signal->tty);
+		tty_vhangup_self();
 		return 0;
 	}
 	return -EPERM;
author
#51 lore raw

PATCH 43/76 tty: Redo current tty locking

In reply to Alan Cox

Currently it is sometimes locked by the tty mutex and sometimes by the sighand lock. The latter is in fact correct and now we can hand back referenced objects we can fix this up without problems around sleeping functions.

---

 drivers/char/tty_io.c    |   18 ++++--------------
 fs/dquot.c               |    2 --
 include/linux/tty.h      |    1 +
 security/selinux/hooks.c |    2 --
 4 files changed, 5 insertions(+), 18 deletions(-)
drivers/char/tty_io.c +4 -14
index b5f57d0..f40298e 100644
@@ -739,13 +739,11 @@ void tty_vhangup_self(void)
 {
 	struct tty_struct *tty;
 
-	mutex_lock(&tty_mutex);
 	tty = get_current_tty();
 	if (tty) {
 		tty_vhangup(tty);
 		tty_kref_put(tty);
 	}
-	mutex_unlock(&tty_mutex);
 }
 
 /**
@@ -801,11 +799,9 @@ void disassociate_ctty(int on_exit)
 	struct pid *tty_pgrp = NULL;
 
 
-	mutex_lock(&tty_mutex);
 	tty = get_current_tty();
 	if (tty) {
 		tty_pgrp = get_pid(tty->pgrp);
-		mutex_unlock(&tty_mutex);
 		lock_kernel();
 		if (on_exit && tty->driver->type != TTY_DRIVER_TYPE_PTY)
 			tty_vhangup(tty);
@@ -822,7 +818,6 @@ void disassociate_ctty(int on_exit)
 			kill_pgrp(old_pgrp, SIGCONT, on_exit);
 			put_pid(old_pgrp);
 		}
-		mutex_unlock(&tty_mutex);
 		return;
 	}
 	if (tty_pgrp) {
@@ -837,7 +832,6 @@ void disassociate_ctty(int on_exit)
 	current->signal->tty_old_pgrp = NULL;
 	spin_unlock_irq(&current->sighand->siglock);
 
-	mutex_lock(&tty_mutex);
 	tty = get_current_tty();
 	if (tty) {
 		unsigned long flags;
@@ -854,7 +848,6 @@ void disassociate_ctty(int on_exit)
 		       " = NULL", tty);
 #endif
 	}
-	mutex_unlock(&tty_mutex);
 
 	/* Now clear signal->tty under the lock */
 	read_lock(&tasklist_lock);
@@ -3180,14 +3173,11 @@ static void proc_set_tty(struct task_struct *tsk, struct tty_struct *tty)
 struct tty_struct *get_current_tty(void)
 {
 	struct tty_struct *tty;
-	WARN_ON_ONCE(!mutex_is_locked(&tty_mutex));
+	unsigned long flags;
+
+	spin_lock_irqsave(&current->sighand->siglock, flags);
 	tty = tty_kref_get(current->signal->tty);
-	/*
-	 * session->tty can be changed/cleared from under us, make sure we
-	 * issue the load. The obtained pointer, when not NULL, is valid as
-	 * long as we hold tty_mutex.
-	 */
-	barrier();
+	spin_unlock_irqrestore(&current->sighand->siglock, flags);
 	return tty;
 }
 EXPORT_SYMBOL_GPL(get_current_tty);
fs/dquot.c +0 -2
index 7417a6c..ad7e590 100644
@@ -895,9 +895,7 @@ static void print_warning(struct dquot *dquot, const int warntype)
 	    warntype == QUOTA_NL_BSOFTBELOW || !need_print_warning(dquot))
 		return;
 
-	mutex_lock(&tty_mutex);
 	tty = get_current_tty();
-	mutex_unlock(&tty_mutex);
 	if (!tty)
 		return;
 	tty_write_message(tty, dquot->dq_sb->s_id);
include/linux/tty.h +1 -0
index c30ed8d..e00393a 100644
@@ -361,6 +361,7 @@ extern int is_ignored(int sig);
 extern int tty_signal(int sig, struct tty_struct *tty);
 extern void tty_hangup(struct tty_struct *tty);
 extern void tty_vhangup(struct tty_struct *tty);
+extern void tty_vhangup_self(void);
 extern void tty_unhangup(struct file *filp);
 extern int tty_hung_up_p(struct file *filp);
 extern void do_SAK(struct tty_struct *tty);
security/selinux/hooks.c +0 -2
index c856db8..215cddd 100644
@@ -2120,9 +2120,7 @@ static inline void flush_unauthorized_files(struct files_struct *files)
 	long j = -1;
 	int drop_tty = 0;
 
-	mutex_lock(&tty_mutex);
 	tty = get_current_tty();
-	mutex_unlock(&tty_mutex);
 	if (tty) {
 		file_list_lock();
 		file = list_entry(tty->tty_files.next, typeof(*file), f_u.fu_list);
#52 lore raw

Re: [PATCH 43/76] tty: Redo current tty locking

Quoted 13 lines · Alan Cox
include/linux/tty.h +1 -0
index c30ed8d..e00393a 100644
@@ -361,6 +361,7 @@ extern int is_ignored(int sig);
 extern int tty_signal(int sig, struct tty_struct *tty);
 extern void tty_hangup(struct tty_struct *tty);
 extern void tty_vhangup(struct tty_struct *tty);
+extern void tty_vhangup_self(void);
 extern void tty_unhangup(struct file *filp);
 extern int tty_hung_up_p(struct file *filp);
 extern void do_SAK(struct tty_struct *tty);
Quoted 1 line

From a pedantic pov shouldn't the above be part of patch 42 - where you

actually created tty_vhangup_self()?

DF

author
#53 lore raw

PATCH 44/76 tty: Fix abusers of current->sighand->tty

In reply to Alan Cox

Various people outside the tty layer still stick their noses in behind the scenes. We need to make sure they also obey the locking and referencing rules.

---

 kernel/acct.c    |    2 +-
 kernel/auditsc.c |    9 ++++-----
 2 files changed, 5 insertions(+), 6 deletions(-)
kernel/acct.c +1 -1
index dd68b90..f6006a6 100644
@@ -548,7 +548,7 @@ static void do_acct_process(struct bsd_acct_struct *acct,
 #endif
 
 	spin_lock_irq(&current->sighand->siglock);
-	tty = current->signal->tty;
+	tty = current->signal->tty;	/* Safe as we hold the siglock */
 	ac.ac_tty = tty ? old_encode_dev(tty_devnum(tty)) : 0;
 	ac.ac_utime = encode_comp_t(jiffies_to_AHZ(cputime_to_jiffies(pacct->ac_utime)));
 	ac.ac_stime = encode_comp_t(jiffies_to_AHZ(cputime_to_jiffies(pacct->ac_stime)));
kernel/auditsc.c +4 -5
index 59cedfb..cf5bc2f 100644
@@ -246,8 +246,8 @@ static int audit_match_perm(struct audit_context *ctx, int mask)
 	unsigned n;
 	if (unlikely(!ctx))
 		return 0;
-
 	n = ctx->major;
+
 	switch (audit_classify_syscall(ctx->arch, n)) {
 	case 0:	/* native */
 		if ((mask & AUDIT_PERM_WRITE) &&
@@ -1204,13 +1204,13 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts
 				 (context->return_valid==AUDITSC_SUCCESS)?"yes":"no",
 				 context->return_code);
 
-	mutex_lock(&tty_mutex);
-	read_lock(&tasklist_lock);
+	spin_lock_irq(&tsk->sighand->siglock);
 	if (tsk->signal && tsk->signal->tty && tsk->signal->tty->name)
 		tty = tsk->signal->tty->name;
 	else
 		tty = "(none)";
-	read_unlock(&tasklist_lock);
+	spin_unlock_irq(&tsk->sighand->siglock);
+
 	audit_log_format(ab,
 		  " a0=%lx a1=%lx a2=%lx a3=%lx items=%d"
 		  " ppid=%d pid=%d auid=%u uid=%u gid=%u"
@@ -1230,7 +1230,6 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts
 		  context->egid, context->sgid, context->fsgid, tty,
 		  tsk->sessionid);
 
-	mutex_unlock(&tty_mutex);
 
 	audit_log_task_info(ab, tsk);
 	if (context->filterkey) {
author
#54 lore raw

PATCH 45/76 pty: If the administrator creates a device for a ptmx slave we should not error

In reply to Alan Cox

The open path for ptmx slaves is via the ptmx device. Opening them any other way is not allowed. Vegard Nossum found that previously this was not the case and mknod foo c 128 42; cat foo would produce nasty diagnostics

---

 drivers/char/tty_io.c |   18 ++++++++++++------
 1 files changed, 12 insertions(+), 6 deletions(-)
drivers/char/tty_io.c +12 -6
index f40298e..2e96ce0 100644
@@ -1227,7 +1227,8 @@ static void tty_line_name(struct tty_driver *driver, int index, char *p)
  *	init_dev		-	initialise a tty device
  *	@driver: tty driver we are opening a device on
  *	@idx: device index
- *	@tty: returned tty structure
+ *	@ret_tty: returned tty structure
+ *	@first_ok: ok to open a new device (used by ptmx)
  *
  *	Prepare a tty device. This may not be a "new" clean device but
  *	could also be an active device. The pty drivers require special
@@ -1248,7 +1249,7 @@ static void tty_line_name(struct tty_driver *driver, int index, char *p)
  */
 
 static int init_dev(struct tty_driver *driver, int idx,
-	struct tty_struct **ret_tty)
+	struct tty_struct **ret_tty, int first_ok)
 {
 	struct tty_struct *tty, *o_tty;
 	struct ktermios *tp, **tp_loc, *o_tp, **o_tp_loc;
@@ -1279,6 +1280,11 @@ static int init_dev(struct tty_driver *driver, int idx,
 	}
 	if (tty) goto fast_track;
 
+	if (driver->subtype == PTY_TYPE_MASTER &&
+		(driver->flags & TTY_DRIVER_DEVPTS_MEM) && !first_ok) {
+		retval = -EIO;
+		goto end_init;
+	}
 	/*
 	 * First time open is complex, especially for PTY devices.
 	 * This code guarantees that either everything succeeds and the
@@ -1413,7 +1419,7 @@ static int init_dev(struct tty_driver *driver, int idx,
 
 	if (retval)
 		goto release_mem_out;
-	 goto success;
+	goto success;
 
 	/*
 	 * This fast open can be used if the tty is already open.
@@ -1795,7 +1801,7 @@ static void release_dev(struct file *filp)
 }
 
 /**
- *	tty_open		-	open a tty device
+ *	__tty_open		-	open a tty device
  *	@inode: inode of device file
  *	@filp: file pointer to tty
  *
@@ -1874,7 +1880,7 @@ retry_open:
 		return -ENODEV;
 	}
 got_driver:
-	retval = init_dev(driver, index, &tty);
+	retval = init_dev(driver, index, &tty, 0);
 	mutex_unlock(&tty_mutex);
 	if (retval)
 		return retval;
@@ -1971,7 +1977,7 @@ static int __ptmx_open(struct inode *inode, struct file *filp)
 		return index;
 
 	mutex_lock(&tty_mutex);
-	retval = init_dev(ptm_driver, index, &tty);
+	retval = init_dev(ptm_driver, index, &tty, 1);
 	mutex_unlock(&tty_mutex);
 
 	if (retval)
author
#55 lore raw

PATCH 46/76 vt: remove bogus lock dropping

In reply to Alan Cox

For hysterical raisins the vt layer drops and retakes locks in the write method. This is a left over from the days when user/kernel data was passed directly to the tty not pre-buffered.

---

 drivers/char/vt.c |   18 ------------------
 1 files changed, 0 insertions(+), 18 deletions(-)
drivers/char/vt.c +0 -18
index 05ca1c5..ec94521 100644
@@ -2136,27 +2136,9 @@ static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int co
 	    release_console_sem();
 	    return 0;
 	}
-	release_console_sem();
-
 	orig_buf = buf;
 	orig_count = count;
 
-	/* At this point 'buf' is guaranteed to be a kernel buffer
-	 * and therefore no access to userspace (and therefore sleeping)
-	 * will be needed.  The con_buf_mtx serializes all tty based
-	 * console rendering and vcs write/read operations.  We hold
-	 * the console spinlock during the entire write.
-	 */
-
-	acquire_console_sem();
-
-	vc = tty->driver_data;
-	if (vc == NULL) {
-		printk(KERN_ERR "vt: argh, driver_data _became_ NULL !\n");
-		release_console_sem();
-		goto out;
-	}
-
 	himask = vc->vc_hi_font_mask;
 	charmask = himask ? 0x1ff : 0xff;
 
author
#56 lore raw

PATCH 47/76 tty: shutdown method

In reply to Alan Cox

Right now there are various drivers that try to use tty->count to know when they get the final close. Aristeau Rozanski showed while debugging the vt sysfs race that this isn't entirely safe.

Instead of driver side tricks to work around this introduce a shutdown which is called when the tty is being destructed. This also means that the shutdown method is tied into the refcounting.

Use this to rework the console close/sysfs logic.

Remove lots of special case code from the tty core code. The pty code can now have a shutdown() method that replaces the special case hackery in the tree free up paths.

---

 drivers/char/pty.c         |   15 ++++++++++---
 drivers/char/tty_io.c      |   49 ++++++++++++++++++++++++++------------------
 drivers/char/vt.c          |   34 +++++++++++++++----------------
 include/linux/tty.h        |    3 ++-
 include/linux/tty_driver.h |    6 +++++
 5 files changed, 65 insertions(+), 42 deletions(-)
drivers/char/pty.c +11 -4
index 76b2793..ec09c1c 100644
@@ -388,7 +388,14 @@ static int pty_unix98_ioctl(struct tty_struct *tty, struct file *file,
 	return -ENOIOCTLCMD;
 }
 
-static const struct tty_operations pty_unix98_ops = {
+static void pty_shutdown(struct tty_struct *tty)
+{
+	/* We have our own method as we don't use the tty index */
+	kfree(tty->termios);
+	kfree(tty->termios_locked);
+}
+
+static const struct tty_operations ptm_unix98_ops = {
 	.open = pty_open,
 	.close = pty_close,
 	.write = pty_write,
@@ -397,10 +404,10 @@ static const struct tty_operations pty_unix98_ops = {
 	.chars_in_buffer = pty_chars_in_buffer,
 	.unthrottle = pty_unthrottle,
 	.set_termios = pty_set_termios,
-	.ioctl = pty_unix98_ioctl
+	.ioctl = pty_unix98_ioctl,
+	.shutdown = pty_shutdown
 };
 
-
 static void __init unix98_pty_init(void)
 {
 	ptm_driver = alloc_tty_driver(NR_UNIX98_PTY_MAX);
@@ -427,7 +434,7 @@ static void __init unix98_pty_init(void)
 	ptm_driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW |
 		TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_DEVPTS_MEM;
 	ptm_driver->other = pts_driver;
-	tty_set_operations(ptm_driver, &pty_unix98_ops);
+	tty_set_operations(ptm_driver, &ptm_unix98_ops);
 
 	pts_driver->owner = THIS_MODULE;
 	pts_driver->driver_name = "pty_slave";
drivers/char/tty_io.c +29 -20

62 lines not on this page · raw message

drivers/char/vt.c +17 -17
index ec94521..37a45db 100644
@@ -2758,6 +2758,12 @@ static int con_open(struct tty_struct *tty, struct file *filp)
 		ret = vc_allocate(currcons);
 		if (ret == 0) {
 			struct vc_data *vc = vc_cons[currcons].d;
+
+			/* Still being freed */
+			if (vc->vc_tty) {
+				release_console_sem();
+				return -ERESTARTSYS;
+			}
 			tty->driver_data = vc;
 			vc->vc_tty = tty;
 
@@ -2787,25 +2793,18 @@ static int con_open(struct tty_struct *tty, struct file *filp)
  */
 static void con_close(struct tty_struct *tty, struct file *filp)
 {
-	mutex_lock(&tty_mutex);
-	acquire_console_sem();
-	if (tty && tty->count == 1) {
-		struct vc_data *vc = tty->driver_data;
+	/* Nothing to do - we defer to shutdown */
+}
 
-		if (vc)
-			vc->vc_tty = NULL;
-		tty->driver_data = NULL;
-		vcs_remove_sysfs(tty);
-		release_console_sem();
-		mutex_unlock(&tty_mutex);
-		/*
-		 * tty_mutex is released, but we still hold BKL, so there is
-		 * still exclusion against init_dev()
-		 */
-		return;
-	}
+static void con_shutdown(struct tty_struct *tty)
+{
+	struct vc_data *vc = tty->driver_data;
+	BUG_ON(vc == NULL);
+	acquire_console_sem();
+	vc->vc_tty = NULL;
+	vcs_remove_sysfs(tty);
 	release_console_sem();
-	mutex_unlock(&tty_mutex);
+	tty_shutdown(tty);
 }
 
 static int default_italic_color    = 2; // green (ASCII)
@@ -2930,6 +2929,7 @@ static const struct tty_operations con_ops = {
 	.throttle = con_throttle,
 	.unthrottle = con_unthrottle,
 	.resize = vt_resize,
+	.shutdown = con_shutdown
 };
 
 int __init vty_init(void)
include/linux/tty.h +2 -1
index e00393a..6e39c70 100644
@@ -354,7 +354,8 @@ extern void tty_throttle(struct tty_struct *tty);
 extern void tty_unthrottle(struct tty_struct *tty);
 extern int tty_do_resize(struct tty_struct *tty, struct tty_struct *real_tty,
 						struct winsize *ws);
-
+extern void tty_shutdown(struct tty_struct *tty);
+extern void tty_free_termios(struct tty_struct *tty);
 extern int is_current_pgrp_orphaned(void);
 extern struct pid *tty_get_pgrp(struct tty_struct *tty);
 extern int is_ignored(int sig);
include/linux/tty_driver.h +6 -0
index ac6e58e..2322313 100644
@@ -21,6 +21,11 @@
  *
  *	Required method.
  *
+ * void (*shutdown)(struct tty_struct * tty);
+ *
+ * 	This routine is called when a particular tty device is closed for
+ *	the last time freeing up the resources.
+ *
  * int (*write)(struct tty_struct * tty,
  * 		 const unsigned char *buf, int count);
  *
@@ -200,6 +205,7 @@ struct tty_driver;
 struct tty_operations {
 	int  (*open)(struct tty_struct * tty, struct file * filp);
 	void (*close)(struct tty_struct * tty, struct file * filp);
+	void (*shutdown)(struct tty_struct *tty);
 	int  (*write)(struct tty_struct * tty,
 		      const unsigned char *buf, int count);
 	int  (*put_char)(struct tty_struct *tty, unsigned char ch);
author
#57 lore raw

PATCH 48/76 tty: Remove more special casing and out of place code

In reply to Alan Cox

Carry on pushing code out of tty_io when it belongs to other drivers. I'm not 100% happy with some of this and it will be worth revisiting some of the exports later when the restructuring work is done.

---

 drivers/char/pty.c       |   78 +++++++++++++++++++++
 drivers/char/tty_io.c    |  169 ++++++++++------------------------------------
 drivers/char/tty_ioctl.c |   66 ++++++++++++++++--
 drivers/char/vt.c        |   30 ++++----
 include/linux/tty.h      |    6 ++
 include/linux/vt_kern.h  |    2 -
 6 files changed, 195 insertions(+), 156 deletions(-)
drivers/char/pty.c +78 -0
index ec09c1c..328e8ac 100644
@@ -23,6 +23,7 @@
 #include <linux/mm.h>
 #include <linux/init.h>
 #include <linux/sysctl.h>
+#include <linux/device.h>
 
 #include <asm/uaccess.h>
 #include <asm/system.h>
@@ -332,6 +333,8 @@ int pty_limit = NR_UNIX98_PTY_DEFAULT;
 static int pty_limit_min = 0;
 static int pty_limit_max = NR_UNIX98_PTY_MAX;
 
+static struct cdev ptmx_cdev;
+
 static struct ctl_table pty_table[] = {
 	{
 		.ctl_name	= PTY_MAX,
@@ -408,6 +411,70 @@ static const struct tty_operations ptm_unix98_ops = {
 	.shutdown = pty_shutdown
 };
 
+
+/**
+ *	ptmx_open		-	open a unix 98 pty master
+ *	@inode: inode of device file
+ *	@filp: file pointer to tty
+ *
+ *	Allocate a unix98 pty master device from the ptmx driver.
+ *
+ *	Locking: tty_mutex protects the init_dev work. tty->count should
+ * 		protect the rest.
+ *		allocated_ptys_lock handles the list of free pty numbers
+ */
+
+static int __ptmx_open(struct inode *inode, struct file *filp)
+{
+	struct tty_struct *tty;
+	int retval;
+	int index;
+
+	nonseekable_open(inode, filp);
+
+	/* find a device that is not in use. */
+	index = devpts_new_index();
+	if (index < 0)
+		return index;
+
+	mutex_lock(&tty_mutex);
+	retval = tty_init_dev(ptm_driver, index, &tty, 1);
+	mutex_unlock(&tty_mutex);
+
+	if (retval)
+		goto out;
+
+	set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */
+	filp->private_data = tty;
+	file_move(filp, &tty->tty_files);
+
+	retval = devpts_pty_new(tty->link);
+	if (retval)
+		goto out1;
+
+	retval = ptm_driver->ops->open(tty, filp);
+	if (!retval)
+		return 0;
+out1:
+	tty_release_dev(filp);
+	return retval;
+out:
+	devpts_kill_index(index);
+	return retval;
+}
+
+static int ptmx_open(struct inode *inode, struct file *filp)
+{
+	int ret;
+
+	lock_kernel();
+	ret = __ptmx_open(inode, filp);
+	unlock_kernel();
+	return ret;
+}
+
+static struct file_operations ptmx_fops;
+
 static void __init unix98_pty_init(void)
 {
 	ptm_driver = alloc_tty_driver(NR_UNIX98_PTY_MAX);
@@ -459,7 +526,18 @@ static void __init unix98_pty_init(void)
 
 	pty_table[1].data = &ptm_driver->refcount;
 	register_sysctl_table(pty_root_table);
+
+	/* Now create the /dev/ptmx special device */
+	tty_default_fops(&ptmx_fops);
+	ptmx_fops.open = ptmx_open;
+
+	cdev_init(&ptmx_cdev, &ptmx_fops);
+	if (cdev_add(&ptmx_cdev, MKDEV(TTYAUX_MAJOR, 2), 1) ||
+	    register_chrdev_region(MKDEV(TTYAUX_MAJOR, 2), 1, "/dev/ptmx") < 0)
+		panic("Couldn't register /dev/ptmx driver\n");
+	device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 2), NULL, "ptmx");
 }
+
 #else
 static inline void unix98_pty_init(void) { }
 #endif
drivers/char/tty_io.c +36 -133

365 lines not on this page · raw message

drivers/char/tty_ioctl.c +60 -6

131 lines not on this page · raw message

drivers/char/vt.c +14 -16
index 37a45db..57029fe 100644
@@ -100,10 +100,10 @@
 #include <linux/font.h>
 #include <linux/bitops.h>
 #include <linux/notifier.h>
-
-#include <asm/io.h>
+#include <linux/device.h>
+#include <linux/io.h>
 #include <asm/system.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
 
 #define MAX_NR_CON_DRIVER 16
 
@@ -2352,8 +2352,6 @@ rescan_last_byte:
 	FLUSH
 	console_conditional_schedule();
 	release_console_sem();
-
-out:
 	notify_update(vc);
 	return n;
 #undef FLUSH
@@ -2784,13 +2782,6 @@ static int con_open(struct tty_struct *tty, struct file *filp)
 	return ret;
 }
 
-/*
- * We take tty_mutex in here to prevent another thread from coming in via init_dev
- * and taking a ref against the tty while we're in the process of forgetting
- * about it and cleaning things up.
- *
- * This is because vcs_remove_sysfs() can sleep and will drop the BKL.
- */
 static void con_close(struct tty_struct *tty, struct file *filp)
 {
 	/* Nothing to do - we defer to shutdown */
@@ -2932,8 +2923,16 @@ static const struct tty_operations con_ops = {
 	.shutdown = con_shutdown
 };
 
-int __init vty_init(void)
+static struct cdev vc0_cdev;
+
+int __init vty_init(const struct file_operations *console_fops)
 {
+	cdev_init(&vc0_cdev, console_fops);
+	if (cdev_add(&vc0_cdev, MKDEV(TTY_MAJOR, 0), 1) ||
+	    register_chrdev_region(MKDEV(TTY_MAJOR, 0), 1, "/dev/vc/0") < 0)
+		panic("Couldn't register /dev/tty0 driver\n");
+	device_create(tty_class, NULL, MKDEV(TTY_MAJOR, 0), NULL, "tty0");
+
 	vcs_init();
 
 	console_driver = alloc_tty_driver(MAX_NR_CONSOLES);
@@ -2952,7 +2951,6 @@ int __init vty_init(void)
 	tty_set_operations(console_driver, &con_ops);
 	if (tty_register_driver(console_driver))
 		panic("Couldn't register console driver\n");
-
 	kbd_init();
 	console_map_init();
 #ifdef CONFIG_PROM_CONSOLE
@@ -3446,7 +3444,7 @@ int register_con_driver(const struct consw *csw, int first, int last)
 	if (retval)
 		goto err;
 
-	con_driver->dev = device_create_drvdata(vtconsole_class, NULL,
+	con_driver->dev = device_create(vtconsole_class, NULL,
 						MKDEV(0, con_driver->node),
 						NULL, "vtcon%i",
 						con_driver->node);
@@ -3557,7 +3555,7 @@ static int __init vtconsole_class_init(void)
 		struct con_driver *con = &registered_con_driver[i];
 
 		if (con->con && !con->dev) {
-			con->dev = device_create_drvdata(vtconsole_class, NULL,
+			con->dev = device_create(vtconsole_class, NULL,
 							 MKDEV(0, con->node),
 							 NULL, "vtcon%i",
 							 con->node);
include/linux/tty.h +6 -0
index 6e39c70..6cc7ccc 100644
@@ -314,6 +314,8 @@ extern int kmsg_redirect;
 extern void console_init(void);
 extern int vcs_init(void);
 
+extern struct class *tty_class;
+
 /**
  *	tty_kref_get		-	get a tty reference
  *	@tty: tty device
@@ -398,6 +400,10 @@ extern int tty_perform_flush(struct tty_struct *tty, unsigned long arg);
 extern dev_t tty_devnum(struct tty_struct *tty);
 extern void proc_clear_tty(struct task_struct *p);
 extern struct tty_struct *get_current_tty(void);
+extern void tty_default_fops(struct file_operations *fops);
+extern int tty_init_dev(struct tty_driver *driver, int idx,
+			struct tty_struct **ret_tty, int first_ok);
+extern void tty_release_dev(struct file *filp);
 
 extern struct mutex tty_mutex;
 
include/linux/vt_kern.h +1 -1
index 1cbd0a7..2f11134 100644
@@ -96,7 +96,7 @@ void change_console(struct vc_data *new_vc);
 void reset_vc(struct vc_data *vc);
 extern int unbind_con_driver(const struct consw *csw, int first, int last,
 			     int deflt);
-int vty_init(void);
+int vty_init(const struct file_operations *console_fops);
 
 /*
  * vc_screen.c shares this temporary buffer with the console write code so that
author
#58 lore raw

PATCH 49/76 tty: Move parts of tty_init_dev into new functions

In reply to Alan Cox

From: Sukadev Bhattiprolu <[email protected]>

Move the 'find-tty' and 'fast-track-open' parts of init_dev() to separate functions.

---

 drivers/char/tty_io.c |  139 +++++++++++++++++++++++++++++++------------------
 1 files changed, 87 insertions(+), 52 deletions(-)
drivers/char/tty_io.c +87 -52
index fdcc43c..a540849 100644
@@ -1204,6 +1204,80 @@ static void tty_line_name(struct tty_driver *driver, int index, char *p)
 	sprintf(p, "%s%d", driver->name, index + driver->name_base);
 }
 
+/*
+ * 	find_tty() - find an existing tty, if any
+ * 	@driver: the driver for the tty
+ * 	@idx:	 the minor number
+ *
+ * 	Return the tty, if found or ERR_PTR() otherwise.
+ *
+ * 	Locking: tty_mutex must be held. If tty is found, the mutex must
+ * 		 be held until the 'fast-open' is also done.
+ */
+struct tty_struct *find_tty(struct tty_driver *driver, int idx)
+{
+	struct tty_struct *tty;
+
+	/* check whether we're reopening an existing tty */
+	if (driver->flags & TTY_DRIVER_DEVPTS_MEM) {
+		tty = devpts_get_tty(idx);
+		/*
+		 * If we don't have a tty here on a slave open, it's because
+		 * the master already started the close process and there's
+		 * no relation between devpts file and tty anymore.
+		 */
+		if (!tty && driver->subtype == PTY_TYPE_SLAVE)
+			return ERR_PTR(-EIO);
+
+		/*
+		 * tty is safe on because we are called with tty_mutex held
+		 * and release_dev() won't change tty->count or tty->flags
+		 * without grabbing tty_mutex.
+		 */
+		if (tty && driver->subtype == PTY_TYPE_MASTER)
+			tty = tty->link;
+	} else
+		tty = driver->ttys[idx];
+	return tty;
+}
+
+/*
+ * 	fast_tty_open()	- fast re-open of an open tty
+ * 	@tty	- the tty to open
+ *
+ * 	Return 0 on success, -errno on error.
+ *
+ * 	Locking: tty_mutex must be held from the time the tty was found
+ * 		 till this open completes.
+ */
+static int fast_tty_open(struct tty_struct *tty)
+{
+	struct tty_driver *driver = tty->driver;
+
+	if (test_bit(TTY_CLOSING, &tty->flags))
+		return -EIO;
+
+	if (driver->type == TTY_DRIVER_TYPE_PTY &&
+	    driver->subtype == PTY_TYPE_MASTER) {
+		/*
+		 * special case for PTY masters: only one open permitted,
+		 * and the slave side open count is incremented as well.
+		 */
+		if (tty->count)
+			return -EIO;
+
+		tty->link->count++;
+	}
+	tty->count++;
+	tty->driver = driver; /* N.B. why do this every time?? */
+
+	/* FIXME */
+	if (!test_bit(TTY_LDISC, &tty->flags))
+		printk(KERN_ERR "fast_tty_open: no ldisc\n");
+
+	return 0;
+}
+
 /**
  *	tty_init_dev		-	initialise a tty device
  *	@driver: tty driver we are opening a device on
@@ -1238,29 +1312,21 @@ int tty_init_dev(struct tty_driver *driver, int idx,
 	int retval = 0;
 
 	/* check whether we're reopening an existing tty */
-	if (driver->flags & TTY_DRIVER_DEVPTS_MEM) {
-		tty = devpts_get_tty(idx);
-		/*
-		 * If we don't have a tty here on a slave open, it's because
-		 * the master already started the close process and there's
-		 * no relation between devpts file and tty anymore.
-		 */
-		if (!tty && driver->subtype == PTY_TYPE_SLAVE) {
-			retval = -EIO;
-			goto end_init;
-		}
-		/*
-		 * It's safe from now on because tty_init_dev() is called with
-		 * tty_mutex held and tty_release_dev() won't change tty->count
-		 * or tty->flags without having to grab tty_mutex
-		 */
-		if (tty && driver->subtype == PTY_TYPE_MASTER)
-			tty = tty->link;
-	} else {
-		tty = driver->ttys[idx];
+	tty = find_tty(driver, idx);
+	if (IS_ERR(tty)) {
+		retval = PTR_ERR(tty);
+		goto end_init;
+	}
+
+	if (tty) {
+		retval = fast_tty_open(tty);
+		if (retval)
+			return retval;
+		*ret_tty = tty;
+		return 0;
 	}
-	if (tty) goto fast_track;
 
+	/* Check if pty master is being opened multiple times */
 	if (driver->subtype == PTY_TYPE_MASTER &&
 		(driver->flags & TTY_DRIVER_DEVPTS_MEM) && !first_ok) {
 		retval = -EIO;
@@ -1400,37 +1466,6 @@ int tty_init_dev(struct tty_driver *driver, int idx,
 
 	if (retval)
 		goto release_mem_out;
-	goto success;
-
-	/*
-	 * This fast open can be used if the tty is already open.
-	 * No memory is allocated, and the only failures are from
-	 * attempting to open a closing tty or attempting multiple
-	 * opens on a pty master.
-	 */
-fast_track:
-	if (test_bit(TTY_CLOSING, &tty->flags)) {
-		retval = -EIO;
-		goto end_init;
-	}
-	if (driver->type == TTY_DRIVER_TYPE_PTY &&
-	    driver->subtype == PTY_TYPE_MASTER) {
-		/*
-		 * special case for PTY masters: only one open permitted,
-		 * and the slave side open count is incremented as well.
-		 */
-		if (tty->count) {
-			retval = -EIO;
-			goto end_init;
-		}
-		tty->link->count++;
-	}
-	tty->count++;
-	tty->driver = driver; /* N.B. why do this every time?? */
-
-	/* FIXME */
-	if (!test_bit(TTY_LDISC, &tty->flags))
-		printk(KERN_ERR "tty_init_dev but no ldisc\n");
 success:
 	*ret_tty = tty;
 
author
#59 lore raw

PATCH 50/76 tty: Clean up the tty_init_dev changes further

In reply to Alan Cox

Fix up the naming, style and extract some bits of code into the driver specific code

---

 drivers/char/pty.c         |   49 +++++++++++++++++++++++++++++++++-
 drivers/char/tty_io.c      |   64 +++++++++++++++++---------------------------
 include/linux/tty_driver.h |    9 ++++++
 3 files changed, 81 insertions(+), 41 deletions(-)
drivers/char/pty.c +48 -1
index 328e8ac..6e148ad 100644
@@ -391,6 +391,41 @@ static int pty_unix98_ioctl(struct tty_struct *tty, struct file *file,
 	return -ENOIOCTLCMD;
 }
 
+/**
+ *	ptm_unix98_lookup	-	find a pty master
+ *	@driver: ptm driver
+ *	@idx: tty index
+ *
+ *	Look up a pty master device. Called under the tty_mutex for now.
+ *	This provides our locking.
+ */
+
+static struct tty_struct *ptm_unix98_lookup(struct tty_driver *driver, int idx)
+{
+	struct tty_struct *tty = devpts_get_tty(idx);
+	if (tty)
+		tty = tty->link;
+	return tty;
+}
+
+/**
+ *	pts_unix98_lookup	-	find a pty slave
+ *	@driver: pts driver
+ *	@idx: tty index
+ *
+ *	Look up a pty master device. Called under the tty_mutex for now.
+ *	This provides our locking.
+ */
+
+static struct tty_struct *pts_unix98_lookup(struct tty_driver *driver, int idx)
+{
+	struct tty_struct *tty = devpts_get_tty(idx);
+	/* Master must be open before slave */
+	if (!tty)
+		return ERR_PTR(-EIO);
+	return tty;
+}
+
 static void pty_shutdown(struct tty_struct *tty)
 {
 	/* We have our own method as we don't use the tty index */
@@ -399,6 +434,7 @@ static void pty_shutdown(struct tty_struct *tty)
 }
 
 static const struct tty_operations ptm_unix98_ops = {
+	.lookup = ptm_unix98_lookup,
 	.open = pty_open,
 	.close = pty_close,
 	.write = pty_write,
@@ -411,6 +447,17 @@ static const struct tty_operations ptm_unix98_ops = {
 	.shutdown = pty_shutdown
 };
 
+static const struct tty_operations pty_unix98_ops = {
+	.lookup = pts_unix98_lookup,
+	.open = pty_open,
+	.close = pty_close,
+	.write = pty_write,
+	.write_room = pty_write_room,
+	.flush_buffer = pty_flush_buffer,
+	.chars_in_buffer = pty_chars_in_buffer,
+	.unthrottle = pty_unthrottle,
+	.set_termios = pty_set_termios,
+};
 
 /**
  *	ptmx_open		-	open a unix 98 pty master
@@ -517,7 +564,7 @@ static void __init unix98_pty_init(void)
 	pts_driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW |
 		TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_DEVPTS_MEM;
 	pts_driver->other = ptm_driver;
-	tty_set_operations(pts_driver, &pty_ops);
+	tty_set_operations(pts_driver, &pty_unix98_ops);
 	
 	if (tty_register_driver(ptm_driver))
 		panic("Couldn't register Unix98 ptm driver");
drivers/char/tty_io.c +24 -40

115 lines not on this page · raw message

include/linux/tty_driver.h +9 -0
index 2322313..2c5c35c 100644
@@ -7,6 +7,14 @@
  * defined; unless noted otherwise, they are optional, and can be
  * filled in with a null pointer.
  *
+ * struct tty_struct * (*lookup)(struct tty_driver *self, int idx)
+ *
+ *	Return the tty device corresponding to idx, NULL if there is not
+ *	one currently in use and an ERR_PTR value on error. Called under
+ *	tty_mutex (for now!)
+ *
+ *	Optional method. Default behaviour is to use the ttys array
+ *
  * int  (*open)(struct tty_struct * tty, struct file * filp);
  *
  * 	This routine is called when a particular tty device is opened.
@@ -203,6 +211,7 @@ struct tty_struct;
 struct tty_driver;
 
 struct tty_operations {
+	struct tty_struct * (*lookup)(struct tty_driver *driver, int idx);
 	int  (*open)(struct tty_struct * tty, struct file * filp);
 	void (*close)(struct tty_struct * tty, struct file * filp);
 	void (*shutdown)(struct tty_struct *tty);
author
#60 lore raw

PATCH 51/76 tty: kref the tty driver object

In reply to Alan Cox

---

 drivers/char/ip2/ip2main.c |    6 +-
 drivers/char/pty.c         |    5 ++
 drivers/char/tty_io.c      |  110 ++++++++++++++++++++++++--------------------
 drivers/net/wan/Kconfig    |    2 -
 include/linux/tty_driver.h |   15 ++++--
 5 files changed, 80 insertions(+), 58 deletions(-)
drivers/char/ip2/ip2main.c +3 -3
index 66f52a2..6774572 100644
@@ -264,8 +264,8 @@ static int tracewrap;
 /**********/
 
 #if defined(MODULE) && defined(IP2DEBUG_OPEN)
-#define DBG_CNT(s) printk(KERN_DEBUG "(%s): [%x] refc=%d, ttyc=%d, modc=%x -> %s\n", \
-		    tty->name,(pCh->flags),ip2_tty_driver->refcount, \
+#define DBG_CNT(s) printk(KERN_DEBUG "(%s): [%x] ttyc=%d, modc=%x -> %s\n", \
+		    tty->name,(pCh->flags), \
 		    tty->count,/*GET_USE_COUNT(module)*/0,s)
 #else
 #define DBG_CNT(s)
@@ -2893,7 +2893,7 @@ ip2_ipl_ioctl (struct file *pFile, UINT cmd, ULONG arg )
 	case 13:
 		switch ( cmd ) {
 		case 64:	/* Driver - ip2stat */
-			rc = put_user(ip2_tty_driver->refcount, pIndex++ );
+			rc = put_user(-1, pIndex++ );
 			rc = put_user(irq_counter, pIndex++  );
 			rc = put_user(bh_counter, pIndex++  );
 			break;
drivers/char/pty.c +4 -1
index 6e148ad..0fdfa05 100644
@@ -571,8 +571,11 @@ static void __init unix98_pty_init(void)
 	if (tty_register_driver(pts_driver))
 		panic("Couldn't register Unix98 pts driver");
 
+	/* FIXME: WTF */
+#if 0	
 	pty_table[1].data = &ptm_driver->refcount;
-	register_sysctl_table(pty_root_table);
+#endif	
+	register_sysctl_table(pty_root_table);	
 
 	/* Now create the /dev/ptmx special device */
 	tty_default_fops(&ptmx_fops);
drivers/char/tty_io.c +61 -49

233 lines not on this page · raw message

drivers/net/wan/Kconfig +1 -1
index 2ae2ec4..21efd99 100644
@@ -205,7 +205,7 @@ config WANXL_BUILD_FIRMWARE
 
 config PC300
 	tristate "Cyclades-PC300 support (RS-232/V.35, X.21, T1/E1 boards)"
-	depends on HDLC && PCI
+	depends on HDLC && PCI && BROKEN
 	---help---
 	  Driver for the Cyclades-PC300 synchronous communication boards.
 
include/linux/tty_driver.h +11 -4
index 2c5c35c..ba891dd 100644
@@ -253,6 +253,7 @@ struct tty_operations {
 
 struct tty_driver {
 	int	magic;		/* magic number for this structure */
+	struct kref kref;	/* Reference management */
 	struct cdev cdev;
 	struct module	*owner;
 	const char	*driver_name;
@@ -266,7 +267,6 @@ struct tty_driver {
 	short	subtype;	/* subtype of tty driver */
 	struct ktermios init_termios; /* Initial termios */
 	int	flags;		/* tty driver flags */
-	int	refcount;	/* for loadable tty drivers */
 	struct proc_dir_entry *proc_entry; /* /proc fs entry */
 	struct tty_driver *other; /* only used for the PTY driver */
 
@@ -288,12 +288,19 @@ struct tty_driver {
 
 extern struct list_head tty_drivers;
 
-struct tty_driver *alloc_tty_driver(int lines);
-void put_tty_driver(struct tty_driver *driver);
-void tty_set_operations(struct tty_driver *driver,
+extern struct tty_driver *alloc_tty_driver(int lines);
+extern void put_tty_driver(struct tty_driver *driver);
+extern void tty_set_operations(struct tty_driver *driver,
 			const struct tty_operations *op);
 extern struct tty_driver *tty_find_polling_driver(char *name, int *line);
 
+extern void tty_driver_kref_put(struct tty_driver *driver);
+extern inline struct tty_driver *tty_driver_kref_get(struct tty_driver *d)
+{
+	kref_get(&d->kref);
+	return d;
+}
+
 /* tty driver magic number */
 #define TTY_DRIVER_MAGIC		0x5402
 
author
#61 lore raw

PATCH 52/76 tty: More driver operations

In reply to Alan Cox

We have the lookup operation abstracted which is nice for pty cleanup but we really want to abstract the add/remove entries as well so that we can pull the pty code out of the tty core and create a clear defined interface for the tty driver table.

---

 drivers/char/pty.c         |   16 ++++++++++++
 drivers/char/tty_io.c      |   57 ++++++++++++++++++++++++++++++++++++--------
 include/linux/tty_driver.h |   16 ++++++++++++
 3 files changed, 79 insertions(+), 10 deletions(-)
drivers/char/pty.c +16 -0
index 0fdfa05..4e6490b 100644
@@ -433,8 +433,22 @@ static void pty_shutdown(struct tty_struct *tty)
 	kfree(tty->termios_locked);
 }
 
+/* We have no need to install and remove our tty objects as devpts does all
+   the work for us */
+
+static int pty_install(struct tty_driver *driver, struct tty_struct *tty)
+{
+	return 0;
+}
+
+static void pty_remove(struct tty_driver *driver, struct tty_struct *tty)
+{
+}
+
 static const struct tty_operations ptm_unix98_ops = {
 	.lookup = ptm_unix98_lookup,
+	.install = pty_install,
+	.remove = pty_remove,
 	.open = pty_open,
 	.close = pty_close,
 	.write = pty_write,
@@ -449,6 +463,8 @@ static const struct tty_operations ptm_unix98_ops = {
 
 static const struct tty_operations pty_unix98_ops = {
 	.lookup = pts_unix98_lookup,
+	.install = pty_install,
+	.remove = pty_remove,
 	.open = pty_open,
 	.close = pty_close,
 	.write = pty_write,
drivers/char/tty_io.c +47 -10

98 lines not on this page · raw message

include/linux/tty_driver.h +16 -0
index ba891dd..005d06a 100644
@@ -15,6 +15,20 @@
  *
  *	Optional method. Default behaviour is to use the ttys array
  *
+ * int (*install)(struct tty_driver *self, struct tty_struct *tty)
+ *
+ *	Install a new tty into the tty driver internal tables. Used in
+ *	conjunction with lookup and remove methods.
+ *
+ *	Optional method. Default behaviour is to use the ttys array
+ *
+ * void (*remove)(struct tty_driver *self, struct tty_struct *tty)
+ *
+ *	Remove a closed tty from the tty driver internal tables. Used in
+ *	conjunction with lookup and remove methods.
+ *
+ *	Optional method. Default behaviour is to use the ttys array
+ *
  * int  (*open)(struct tty_struct * tty, struct file * filp);
  *
  * 	This routine is called when a particular tty device is opened.
@@ -212,6 +226,8 @@ struct tty_driver;
 
 struct tty_operations {
 	struct tty_struct * (*lookup)(struct tty_driver *driver, int idx);
+	int  (*install)(struct tty_driver *driver, struct tty_struct *tty);
+	void (*remove)(struct tty_driver *driver, struct tty_struct *tty);
 	int  (*open)(struct tty_struct * tty, struct file * filp);
 	void (*close)(struct tty_struct * tty, struct file * filp);
 	void (*shutdown)(struct tty_struct *tty);
author
#62 lore raw

PATCH 53/76 tty: Finish fixing up the init_dev interface to use ERR_PTR

In reply to Alan Cox

Original suggestion and proposal from Sukadev Bhattiprolu.

---

 drivers/char/pty.c    |    6 ++++--
 drivers/char/tty_io.c |   52 ++++++++++++++++++++-----------------------------
 include/linux/tty.h   |    4 ++--
 3 files changed, 27 insertions(+), 35 deletions(-)
drivers/char/pty.c +4 -2
index 4e6490b..c984500 100644
@@ -501,11 +501,13 @@ static int __ptmx_open(struct inode *inode, struct file *filp)
 		return index;
 
 	mutex_lock(&tty_mutex);
-	retval = tty_init_dev(ptm_driver, index, &tty, 1);
+	tty = tty_init_dev(ptm_driver, index, 1);
 	mutex_unlock(&tty_mutex);
 
-	if (retval)
+	if (IS_ERR(tty)) {
+		retval = PTR_ERR(tty);
 		goto out;
+	}
 
 	set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */
 	filp->private_data = tty;
drivers/char/tty_io.c +21 -31

113 lines not on this page · raw message

include/linux/tty.h +2 -2
index 6cc7ccc..54523a3 100644
@@ -401,8 +401,8 @@ extern dev_t tty_devnum(struct tty_struct *tty);
 extern void proc_clear_tty(struct task_struct *p);
 extern struct tty_struct *get_current_tty(void);
 extern void tty_default_fops(struct file_operations *fops);
-extern int tty_init_dev(struct tty_driver *driver, int idx,
-			struct tty_struct **ret_tty, int first_ok);
+extern struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx,
+								int first_ok);
 extern void tty_release_dev(struct file *filp);
 
 extern struct mutex tty_mutex;
author
#63 lore raw

PATCH 54/76 tty: extract the pty init time special cases

In reply to Alan Cox

The majority of the remaining init_dev code is pty special cases. We refactor this code into the driver->install method.

---

 drivers/char/pty.c    |  126 ++++++++++++++++++++++++++++---
 drivers/char/tty_io.c |  198 +++++++++++++++++--------------------------------
 include/linux/tty.h   |    5 +
 3 files changed, 187 insertions(+), 142 deletions(-)
drivers/char/pty.c +114 -12
index c984500..c5a192d 100644
@@ -227,7 +227,58 @@ static void pty_set_termios(struct tty_struct *tty, struct ktermios *old_termios
         tty->termios->c_cflag |= (CS8 | CREAD);
 }
 
+static int pty_install(struct tty_driver *driver, struct tty_struct *tty)
+{
+	struct tty_struct *o_tty;
+	int idx = tty->index;
+	int retval;
+
+	o_tty = alloc_tty_struct();
+	if (!o_tty)
+		return -ENOMEM;
+	if (!try_module_get(driver->other->owner)) {
+		/* This cannot in fact currently happen */
+		free_tty_struct(o_tty);
+		return -ENOMEM;
+	}
+	initialize_tty_struct(o_tty, driver->other, idx);
+
+	/* We always use new tty termios data so we can do this
+	   the easy way .. */
+	retval = tty_init_termios(tty);
+	if (retval)
+		goto free_mem_out;
+
+	retval = tty_init_termios(o_tty);
+	if (retval) {
+		tty_free_termios(tty);
+		goto free_mem_out;
+	}
+	
+	/*
+	 * Everything allocated ... set up the o_tty structure.
+	 */
+	driver->other->ttys[idx] = o_tty;
+	tty_driver_kref_get(driver->other);
+	if (driver->subtype == PTY_TYPE_MASTER)
+		o_tty->count++;
+	/* Establish the links in both directions */
+	tty->link   = o_tty;
+	o_tty->link = tty;
+
+	tty_driver_kref_get(driver);
+	tty->count++;
+	driver->ttys[idx] = tty;
+	return 0;
+free_mem_out:
+	module_put(o_tty->driver->owner);
+	free_tty_struct(o_tty);
+	return -ENOMEM;
+}
+
+
 static const struct tty_operations pty_ops = {
+	.install = pty_install,
 	.open = pty_open,
 	.close = pty_close,
 	.write = pty_write,
@@ -332,6 +383,7 @@ static inline void legacy_pty_init(void) { }
 int pty_limit = NR_UNIX98_PTY_DEFAULT;
 static int pty_limit_min = 0;
 static int pty_limit_max = NR_UNIX98_PTY_MAX;
+static int pty_count = 0;
 
 static struct cdev ptmx_cdev;
 
@@ -351,6 +403,7 @@ static struct ctl_table pty_table[] = {
 		.procname	= "nr",
 		.maxlen		= sizeof(int),
 		.mode		= 0444,
+		.data		= &pty_count,
 		.proc_handler	= &proc_dointvec,
 	}, {
 		.ctl_name	= 0
@@ -426,7 +479,7 @@ static struct tty_struct *pts_unix98_lookup(struct tty_driver *driver, int idx)
 	return tty;
 }
 
-static void pty_shutdown(struct tty_struct *tty)
+static void pty_unix98_shutdown(struct tty_struct *tty)
 {
 	/* We have our own method as we don't use the tty index */
 	kfree(tty->termios);
@@ -436,19 +489,71 @@ static void pty_shutdown(struct tty_struct *tty)
 /* We have no need to install and remove our tty objects as devpts does all
    the work for us */
 
-static int pty_install(struct tty_driver *driver, struct tty_struct *tty)
+static int pty_unix98_install(struct tty_driver *driver, struct tty_struct *tty)
 {
+	struct tty_struct *o_tty;
+	int idx = tty->index;
+
+	o_tty = alloc_tty_struct();
+	if (!o_tty)
+		return -ENOMEM;
+	if (!try_module_get(driver->other->owner)) {
+		/* This cannot in fact currently happen */
+		free_tty_struct(o_tty);
+		return -ENOMEM;
+	}
+	initialize_tty_struct(o_tty, driver->other, idx);
+
+	tty->termios = kmalloc(sizeof(struct ktermios), GFP_KERNEL);
+	if (tty->termios == NULL)
+		goto free_mem_out;
+	*tty->termios = driver->init_termios;
+	tty->termios_locked = kzalloc(sizeof(struct ktermios), GFP_KERNEL);
+	if (tty->termios_locked == NULL)
+		goto free_mem_out;
+	o_tty->termios = kmalloc(sizeof(struct ktermios), GFP_KERNEL);
+	if (o_tty->termios == NULL)
+		goto free_mem_out;
+	*o_tty->termios = driver->other->init_termios;
+	o_tty->termios_locked = kzalloc(sizeof(struct ktermios), GFP_KERNEL);
+	if (o_tty->termios_locked == NULL)
+		goto free_mem_out;
+
+	tty_driver_kref_get(driver->other);
+	if (driver->subtype == PTY_TYPE_MASTER)
+		o_tty->count++;
+	/* Establish the links in both directions */
+	tty->link   = o_tty;
+	o_tty->link = tty;
+	/*
+	 * All structures have been allocated, so now we install them.
+	 * Failures after this point use release_tty to clean up, so
+	 * there's no need to null out the local pointers.
+	 */
+	tty_driver_kref_get(driver);
+	tty->count++;
+	pty_count++;
 	return 0;
+free_mem_out:
+	kfree(o_tty->termios);
+	module_put(o_tty->driver->owner);
+	free_tty_struct(o_tty);
+	kfree(tty->termios_locked);
+	kfree(tty->termios);
+	free_tty_struct(tty);
+	module_put(driver->owner);
+	return -ENOMEM;
 }
 
-static void pty_remove(struct tty_driver *driver, struct tty_struct *tty)
+static void pty_unix98_remove(struct tty_driver *driver, struct tty_struct *tty)
 {
+	pty_count--;
 }
 
 static const struct tty_operations ptm_unix98_ops = {
 	.lookup = ptm_unix98_lookup,
-	.install = pty_install,
-	.remove = pty_remove,
+	.install = pty_unix98_install,
+	.remove = pty_unix98_remove,
 	.open = pty_open,
 	.close = pty_close,
 	.write = pty_write,
@@ -458,13 +563,13 @@ static const struct tty_operations ptm_unix98_ops = {
 	.unthrottle = pty_unthrottle,
 	.set_termios = pty_set_termios,
 	.ioctl = pty_unix98_ioctl,
-	.shutdown = pty_shutdown
+	.shutdown = pty_unix98_shutdown
 };
 
 static const struct tty_operations pty_unix98_ops = {
 	.lookup = pts_unix98_lookup,
-	.install = pty_install,
-	.remove = pty_remove,
+	.install = pty_unix98_install,
+	.remove = pty_unix98_remove,
 	.open = pty_open,
 	.close = pty_close,
 	.write = pty_write,
@@ -473,6 +578,7 @@ static const struct tty_operations pty_unix98_ops = {
 	.chars_in_buffer = pty_chars_in_buffer,
 	.unthrottle = pty_unthrottle,
 	.set_termios = pty_set_termios,
+	.shutdown = pty_unix98_shutdown
 };
 
 /**
@@ -589,10 +695,6 @@ static void __init unix98_pty_init(void)
 	if (tty_register_driver(pts_driver))
 		panic("Couldn't register Unix98 pts driver");
 
-	/* FIXME: WTF */
-#if 0	
-	pty_table[1].data = &ptm_driver->refcount;
-#endif	
 	register_sysctl_table(pty_root_table);	
 
 	/* Now create the /dev/ptmx special device */
drivers/char/tty_io.c +68 -130

274 lines not on this page · raw message

include/linux/tty.h +5 -0
index 54523a3..3c7c757 100644
@@ -401,9 +401,14 @@ extern dev_t tty_devnum(struct tty_struct *tty);
 extern void proc_clear_tty(struct task_struct *p);
 extern struct tty_struct *get_current_tty(void);
 extern void tty_default_fops(struct file_operations *fops);
+extern struct tty_struct *alloc_tty_struct(void);
+extern void free_tty_struct(struct tty_struct *tty);
+extern void initialize_tty_struct(struct tty_struct *tty,
+		struct tty_driver *driver, int idx);
 extern struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx,
 								int first_ok);
 extern void tty_release_dev(struct file *filp);
+extern int tty_init_termios(struct tty_struct *tty);
 
 extern struct mutex tty_mutex;
 
author
#64 lore raw

PATCH 55/76 Move tty lookup/reopen to caller

In reply to Alan Cox

From: Sukadev Bhattiprolu <[email protected]>

Move tty_driver_lookup_tty() and tty_reopen() from tty_init_dev() into tty_open() (one of the two callers of tty_init_dev()). These calls are not really required in ptmx_open(), the other caller, since ptmx_open() would be setting up a new tty.

Changelog[v2]:
- remove the lookup and reopen calls from ptmx_open
- merge with recent changes to ttydev tree

---

 drivers/char/tty_io.c |   31 ++++++++++++++++---------------
 1 files changed, 16 insertions(+), 15 deletions(-)
drivers/char/tty_io.c +16 -15
index e881e9e..36098ee 100644
@@ -1376,19 +1376,6 @@ struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx,
 	struct tty_struct *tty;
 	int retval;
 
-	/* check whether we're reopening an existing tty */
-	tty = tty_driver_lookup_tty(driver, idx);
-
-	if (IS_ERR(tty))
-		return tty;
-
-	if (tty) {
-		retval = tty_reopen(tty);
-		if (retval)
-			return ERR_PTR(retval);
-		return tty;
-	}
-
 	/* Check if pty master is being opened multiple times */
 	if (driver->subtype == PTY_TYPE_MASTER &&
 		(driver->flags & TTY_DRIVER_DEVPTS_MEM) && !first_ok)
@@ -1790,7 +1777,7 @@ void tty_release_dev(struct file *filp)
 
 static int __tty_open(struct inode *inode, struct file *filp)
 {
-	struct tty_struct *tty;
+	struct tty_struct *tty = NULL;
 	int noctty, retval;
 	struct tty_driver *driver;
 	int index;
@@ -1847,7 +1834,21 @@ retry_open:
 		return -ENODEV;
 	}
 got_driver:
-	tty = tty_init_dev(driver, index, 0);
+	if (!tty) {
+		/* check whether we're reopening an existing tty */
+		tty = tty_driver_lookup_tty(driver, index);
+
+		if (IS_ERR(tty))
+			return PTR_ERR(tty);
+	}
+
+	if (tty) {
+		retval = tty_reopen(tty);
+		if (retval)
+			tty = ERR_PTR(retval);
+	} else
+		tty = tty_init_dev(driver, index, 0);
+
 	mutex_unlock(&tty_mutex);
 	tty_driver_kref_put(driver);
 	if (IS_ERR(tty))
author
#65 lore raw

PATCH 56/76 Add an instance parameter devpts interfaces

In reply to Alan Cox

From: Sukadev Bhattiprolu <[email protected]>

Pass-in 'inode' or 'tty' parameter to devpts interfaces. With multiple devpts instances, these parameters will be used in subsequent patches to identify the instance of devpts mounted. The parameters also help simplify devpts implementation.

Changelog[v3]:
- minor changes due to merge with ttydev updates
- rename parameters to emphasize they are ptmx or pts inodes
- pass-in tty_struct * to devpts_pty_kill() (this will help cleanup the get_node() call in a subsequent patch)

---

 drivers/char/pty.c         |   18 ++++++++++--------
 drivers/char/tty_io.c      |   14 ++++++++------
 fs/devpts/inode.c          |   11 ++++++-----
 include/linux/devpts_fs.h  |   31 +++++++++++++++++++++----------
 include/linux/tty_driver.h |    3 ++-
 5 files changed, 47 insertions(+), 30 deletions(-)
drivers/char/pty.c +10 -8
index c5a192d..a391bad 100644
@@ -60,7 +60,7 @@ static void pty_close(struct tty_struct * tty, struct file * filp)
 		set_bit(TTY_OTHER_CLOSED, &tty->flags);
 #ifdef CONFIG_UNIX98_PTYS
 		if (tty->driver == ptm_driver)
-			devpts_pty_kill(tty->index);
+			devpts_pty_kill(tty->link);
 #endif
 		tty_vhangup(tty->link);
 	}
@@ -453,9 +453,10 @@ static int pty_unix98_ioctl(struct tty_struct *tty, struct file *file,
  *	This provides our locking.
  */
 
-static struct tty_struct *ptm_unix98_lookup(struct tty_driver *driver, int idx)
+static struct tty_struct *ptm_unix98_lookup(struct tty_driver *driver,
+		struct inode *ptm_inode, int idx)
 {
-	struct tty_struct *tty = devpts_get_tty(idx);
+	struct tty_struct *tty = devpts_get_tty(ptm_inode, idx);
 	if (tty)
 		tty = tty->link;
 	return tty;
@@ -470,9 +471,10 @@ static struct tty_struct *ptm_unix98_lookup(struct tty_driver *driver, int idx)
  *	This provides our locking.
  */
 
-static struct tty_struct *pts_unix98_lookup(struct tty_driver *driver, int idx)
+static struct tty_struct *pts_unix98_lookup(struct tty_driver *driver,
+		struct inode *pts_inode, int idx)
 {
-	struct tty_struct *tty = devpts_get_tty(idx);
+	struct tty_struct *tty = devpts_get_tty(pts_inode, idx);
 	/* Master must be open before slave */
 	if (!tty)
 		return ERR_PTR(-EIO);
@@ -602,7 +604,7 @@ static int __ptmx_open(struct inode *inode, struct file *filp)
 	nonseekable_open(inode, filp);
 
 	/* find a device that is not in use. */
-	index = devpts_new_index();
+	index = devpts_new_index(inode);
 	if (index < 0)
 		return index;
 
@@ -619,7 +621,7 @@ static int __ptmx_open(struct inode *inode, struct file *filp)
 	filp->private_data = tty;
 	file_move(filp, &tty->tty_files);
 
-	retval = devpts_pty_new(tty->link);
+	retval = devpts_pty_new(inode, tty->link);
 	if (retval)
 		goto out1;
 
@@ -630,7 +632,7 @@ out1:
 	tty_release_dev(filp);
 	return retval;
 out:
-	devpts_kill_index(index);
+	devpts_kill_index(inode, index);
 	return retval;
 }
 
drivers/char/tty_io.c +8 -6
index 36098ee..9590839 100644
@@ -1213,12 +1213,13 @@ static void tty_line_name(struct tty_driver *driver, int index, char *p)
  *	be held until the 'fast-open' is also done. Will change once we
  *	have refcounting in the driver and per driver locking
  */
-struct tty_struct *tty_driver_lookup_tty(struct tty_driver *driver, int idx)
+struct tty_struct *tty_driver_lookup_tty(struct tty_driver *driver,
+		struct inode *inode, int idx)
 {
 	struct tty_struct *tty;
 
 	if (driver->ops->lookup)
-		return driver->ops->lookup(driver, idx);
+		return driver->ops->lookup(driver, inode, idx);
 
 	tty = driver->ttys[idx];
 	return tty;
@@ -1539,10 +1540,11 @@ void tty_release_dev(struct file *filp)
 	int	devpts;
 	int	idx;
 	char	buf[64];
+	struct 	inode *inode;
 
+	inode = filp->f_path.dentry->d_inode;
 	tty = (struct tty_struct *)filp->private_data;
-	if (tty_paranoia_check(tty, filp->f_path.dentry->d_inode,
-							"tty_release_dev"))
+	if (tty_paranoia_check(tty, inode, "tty_release_dev"))
 		return;
 
 	check_tty_count(tty, "tty_release_dev");
@@ -1751,7 +1753,7 @@ void tty_release_dev(struct file *filp)
 
 	/* Make this pty number available for reallocation */
 	if (devpts)
-		devpts_kill_index(idx);
+		devpts_kill_index(inode, idx);
 }
 
 /**
@@ -1836,7 +1838,7 @@ retry_open:
 got_driver:
 	if (!tty) {
 		/* check whether we're reopening an existing tty */
-		tty = tty_driver_lookup_tty(driver, index);
+		tty = tty_driver_lookup_tty(driver, inode, index);
 
 		if (IS_ERR(tty))
 			return PTR_ERR(tty);
fs/devpts/inode.c +6 -5
index 488eb42..638db9b 100644
@@ -177,7 +177,7 @@ static struct dentry *get_node(int num)
 	return lookup_one_len(s, root, sprintf(s, "%d", num));
 }
 
-int devpts_new_index(void)
+int devpts_new_index(struct inode *ptmx_inode)
 {
 	int index;
 	int ida_ret;
@@ -205,14 +205,14 @@ retry:
 	return index;
 }
 
-void devpts_kill_index(int idx)
+void devpts_kill_index(struct inode *ptmx_inode, int idx)
 {
 	mutex_lock(&allocated_ptys_lock);
 	ida_remove(&allocated_ptys, idx);
 	mutex_unlock(&allocated_ptys_lock);
 }
 
-int devpts_pty_new(struct tty_struct *tty)
+int devpts_pty_new(struct inode *ptmx_inode, struct tty_struct *tty)
 {
 	int number = tty->index; /* tty layer puts index from devpts_new_index() in here */
 	struct tty_driver *driver = tty->driver;
@@ -245,7 +245,7 @@ int devpts_pty_new(struct tty_struct *tty)
 	return 0;
 }
 
-struct tty_struct *devpts_get_tty(int number)
+struct tty_struct *devpts_get_tty(struct inode *pts_inode, int number)
 {
 	struct dentry *dentry = get_node(number);
 	struct tty_struct *tty;
@@ -262,8 +262,9 @@ struct tty_struct *devpts_get_tty(int number)
 	return tty;
 }
 
-void devpts_pty_kill(int number)
+void devpts_pty_kill(struct tty_struct *tty)
 {
+	int number = tty->index;
 	struct dentry *dentry = get_node(number);
 
 	if (!IS_ERR(dentry)) {
include/linux/devpts_fs.h +21 -10
index 154769c..5ce0e5f 100644
@@ -17,20 +17,31 @@
 
 #ifdef CONFIG_UNIX98_PTYS
 
-int devpts_new_index(void);
-void devpts_kill_index(int idx);
-int devpts_pty_new(struct tty_struct *tty);      /* mknod in devpts */
-struct tty_struct *devpts_get_tty(int number);	 /* get tty structure */
-void devpts_pty_kill(int number);		 /* unlink */
+int devpts_new_index(struct inode *ptmx_inode);
+void devpts_kill_index(struct inode *ptmx_inode, int idx);
+/* mknod in devpts */
+int devpts_pty_new(struct inode *ptmx_inode, struct tty_struct *tty);
+/* get tty structure */
+struct tty_struct *devpts_get_tty(struct inode *pts_inode, int number);
+/* unlink */
+void devpts_pty_kill(struct tty_struct *tty);
 
 #else
 
 /* Dummy stubs in the no-pty case */
-static inline int devpts_new_index(void) { return -EINVAL; }
-static inline void devpts_kill_index(int idx) { }
-static inline int devpts_pty_new(struct tty_struct *tty) { return -EINVAL; }
-static inline struct tty_struct *devpts_get_tty(int number) { return NULL; }
-static inline void devpts_pty_kill(int number) { }
+static inline int devpts_new_index(struct inode *ptmx_inode) { return -EINVAL; }
+static inline void devpts_kill_index(struct inode *ptmx_inode, int idx) { }
+static inline int devpts_pty_new(struct inode *ptmx_inode,
+				struct tty_struct *tty)
+{
+	return -EINVAL;
+}
+static inline struct tty_struct *devpts_get_tty(struct inode *pts_inode,
+		int number)
+{
+	return NULL;
+}
+static inline void devpts_pty_kill(struct tty_struct *tty) { }
 
 #endif
 
include/linux/tty_driver.h +2 -1
index 005d06a..78416b9 100644
@@ -225,7 +225,8 @@ struct tty_struct;
 struct tty_driver;
 
 struct tty_operations {
-	struct tty_struct * (*lookup)(struct tty_driver *driver, int idx);
+	struct tty_struct * (*lookup)(struct tty_driver *driver,
+			struct inode *inode, int idx);
 	int  (*install)(struct tty_driver *driver, struct tty_struct *tty);
 	void (*remove)(struct tty_driver *driver, struct tty_struct *tty);
 	int  (*open)(struct tty_struct * tty, struct file * filp);
author
#66 lore raw

PATCH 57/76 Simplify devpts_get_tty()

In reply to Alan Cox

From: Sukadev Bhattiprolu <[email protected]>

As pointed out by H. Peter Anvin, since the inode for the pty is known, we don't need to look it up.

---

 fs/devpts/inode.c |   17 +++++------------
 1 files changed, 5 insertions(+), 12 deletions(-)
fs/devpts/inode.c +5 -12
index 638db9b..b292ed7 100644
@@ -27,6 +27,7 @@
 #define DEVPTS_SUPER_MAGIC 0x1cd1
 
 #define DEVPTS_DEFAULT_MODE 0600
+#define PTMX_MINOR	2
 
 extern int pty_limit;			/* Config limit on Unix98 ptys */
 static DEFINE_IDA(allocated_ptys);
@@ -247,19 +248,11 @@ int devpts_pty_new(struct inode *ptmx_inode, struct tty_struct *tty)
 
 struct tty_struct *devpts_get_tty(struct inode *pts_inode, int number)
 {
-	struct dentry *dentry = get_node(number);
-	struct tty_struct *tty;
-
-	tty = NULL;
-	if (!IS_ERR(dentry)) {
-		if (dentry->d_inode)
-			tty = dentry->d_inode->i_private;
-		dput(dentry);
-	}
-
-	mutex_unlock(&devpts_root->d_inode->i_mutex);
+	BUG_ON(pts_inode->i_rdev == MKDEV(TTYAUX_MAJOR, PTMX_MINOR));
 
-	return tty;
+	if (pts_inode->i_sb->s_magic == DEVPTS_SUPER_MAGIC)
+		return (struct tty_struct *)pts_inode->i_private;
+	return NULL;
 }
 
 void devpts_pty_kill(struct tty_struct *tty)
author
#67 lore raw

PATCH 58/76 Simplify devpts_pty_new()

In reply to Alan Cox

From: Sukadev Bhattiprolu <[email protected]>

devpts_pty_new() is called when setting up a new pty and would not will not have an existing dentry or inode for the pty. So don't bother looking for an existing dentry - just create a new one.

---

 fs/devpts/inode.c |   11 ++++++++---
 1 files changed, 8 insertions(+), 3 deletions(-)
fs/devpts/inode.c +8 -3
index b292ed7..50e885f 100644
@@ -220,6 +220,7 @@ int devpts_pty_new(struct inode *ptmx_inode, struct tty_struct *tty)
 	dev_t device = MKDEV(driver->major, driver->minor_start+number);
 	struct dentry *dentry;
 	struct inode *inode = new_inode(devpts_mnt->mnt_sb);
+	char s[12];
 
 	/* We're supposed to be given the slave end of a pty */
 	BUG_ON(driver->type != TTY_DRIVER_TYPE_PTY);
@@ -235,9 +236,13 @@ int devpts_pty_new(struct inode *ptmx_inode, struct tty_struct *tty)
 	init_special_inode(inode, S_IFCHR|config.mode, device);
 	inode->i_private = tty;
 
-	dentry = get_node(number);
-	if (!IS_ERR(dentry) && !dentry->d_inode) {
-		d_instantiate(dentry, inode);
+	sprintf(s, "%d", number);
+
+	mutex_lock(&devpts_root->d_inode->i_mutex);
+
+	dentry = d_alloc_name(devpts_root, s);
+	if (!IS_ERR(dentry)) {
+		d_add(dentry, inode);
 		fsnotify_create(devpts_root->d_inode, dentry);
 	}
 
author
#68 lore raw

PATCH 59/76 Simplify devpts_pty_kill

In reply to Alan Cox

From: Sukadev Bhattiprolu <[email protected]>

When creating a new pty, save the pty's inode in the tty->driver_data. Use this inode in pty_kill() to identify the devpts instance. Since we now have the inode for the pty, we can skip get_node() lookup and remove the unused get_node().

TODO:
- check if the mutex_lock is needed in pty_kill().

---

 fs/devpts/inode.c |   29 ++++++++++++-----------------
 1 files changed, 12 insertions(+), 17 deletions(-)
fs/devpts/inode.c +12 -17
index 50e885f..a70d5d0 100644
@@ -170,14 +170,6 @@ static struct file_system_type devpts_fs_type = {
  * to the System V naming convention
  */
 
-static struct dentry *get_node(int num)
-{
-	char s[12];
-	struct dentry *root = devpts_root;
-	mutex_lock(&root->d_inode->i_mutex);
-	return lookup_one_len(s, root, sprintf(s, "%d", num));
-}
-
 int devpts_new_index(struct inode *ptmx_inode)
 {
 	int index;
@@ -235,6 +227,7 @@ int devpts_pty_new(struct inode *ptmx_inode, struct tty_struct *tty)
 	inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
 	init_special_inode(inode, S_IFCHR|config.mode, device);
 	inode->i_private = tty;
+	tty->driver_data = inode;
 
 	sprintf(s, "%d", number);
 
@@ -262,18 +255,20 @@ struct tty_struct *devpts_get_tty(struct inode *pts_inode, int number)
 
 void devpts_pty_kill(struct tty_struct *tty)
 {
-	int number = tty->index;
-	struct dentry *dentry = get_node(number);
+	struct inode *inode = tty->driver_data;
+	struct dentry *dentry;
 
-	if (!IS_ERR(dentry)) {
-		struct inode *inode = dentry->d_inode;
-		if (inode) {
-			inode->i_nlink--;
-			d_delete(dentry);
-			dput(dentry);
-		}
+	BUG_ON(inode->i_rdev == MKDEV(TTYAUX_MAJOR, PTMX_MINOR));
+
+	mutex_lock(&devpts_root->d_inode->i_mutex);
+
+	dentry = d_find_alias(inode);
+	if (dentry && !IS_ERR(dentry)) {
+		inode->i_nlink--;
+		d_delete(dentry);
 		dput(dentry);
 	}
+
 	mutex_unlock(&devpts_root->d_inode->i_mutex);
 }
 
author
#69 lore raw

PATCH 60/76 pty: Coding style and polish

In reply to Alan Cox

We've done the heavy lifting now its time to mop up a bit

---

 drivers/char/pty.c |   86 +++++++++++++++++++++++++++-------------------------
 1 files changed, 44 insertions(+), 42 deletions(-)
drivers/char/pty.c +44 -42
index a391bad..c3ab8c3 100644
@@ -8,10 +8,12 @@
  *  Added TTY_DO_WRITE_WAKEUP to enable n_tty to send POLL_OUT to
  *      waiting writers -- Sapan Bhatia <[email protected]>
  *
- *
+ *  When reading this code see also fs/devpts. In particular note that the
+ *  driver_data field is used by the devpts side as a binding to the devpts
+ *  inode.
  */
 
-#include <linux/module.h>	/* For EXPORT_SYMBOL */
+#include <linux/module.h>
 
 #include <linux/errno.h>
 #include <linux/interrupt.h>
@@ -24,26 +26,24 @@
 #include <linux/init.h>
 #include <linux/sysctl.h>
 #include <linux/device.h>
-
-#include <asm/uaccess.h>
-#include <asm/system.h>
+#include <linux/uaccess.h>
 #include <linux/bitops.h>
 #include <linux/devpts_fs.h>
 
+#include <asm/system.h>
+
 /* These are global because they are accessed in tty_io.c */
 #ifdef CONFIG_UNIX98_PTYS
 struct tty_driver *ptm_driver;
 static struct tty_driver *pts_driver;
 #endif
 
-static void pty_close(struct tty_struct * tty, struct file * filp)
+static void pty_close(struct tty_struct *tty, struct file *filp)
 {
-	if (!tty)
-		return;
-	if (tty->driver->subtype == PTY_TYPE_MASTER) {
-		if (tty->count > 1)
-			printk("master pty_close: count = %d!!\n", tty->count);
-	} else {
+	BUG_ON(!tty);
+	if (tty->driver->subtype == PTY_TYPE_MASTER)
+		WARN_ON(tty->count > 1);
+	else {
 		if (tty->count > 2)
 			return;
 	}
@@ -70,13 +70,13 @@ static void pty_close(struct tty_struct * tty, struct file * filp)
  * The unthrottle routine is called by the line discipline to signal
  * that it can receive more characters.  For PTY's, the TTY_THROTTLED
  * flag is always set, to force the line discipline to always call the
- * unthrottle routine when there are fewer than TTY_THRESHOLD_UNTHROTTLE 
+ * unthrottle routine when there are fewer than TTY_THRESHOLD_UNTHROTTLE
  * characters in the queue.  This is necessary since each time this
  * happens, we need to wake up any sleeping processes that could be
  * (1) trying to send data to the pty, or (2) waiting in wait_until_sent()
  * for the pty buffer to be drained.
  */
-static void pty_unthrottle(struct tty_struct * tty)
+static void pty_unthrottle(struct tty_struct *tty)
 {
 	struct tty_struct *o_tty = tty->link;
 
@@ -88,7 +88,7 @@ static void pty_unthrottle(struct tty_struct * tty)
 }
 
 /*
- * WSH 05/24/97: modified to 
+ * WSH 05/24/97: modified to
  *   (1) use space in tty->flip instead of a shared temp buffer
  *	 The flip buffers aren't being used for a pty, so there's lots
  *	 of space available.  The buffer is protected by a per-pty
@@ -101,7 +101,8 @@ static void pty_unthrottle(struct tty_struct * tty)
  * not our partners. We can't just take the other one blindly without
  * risking deadlocks.
  */
-static int pty_write(struct tty_struct * tty, const unsigned char *buf, int count)
+static int pty_write(struct tty_struct *tty, const unsigned char *buf,
+								int count)
 {
 	struct tty_struct *to = tty->link;
 	int	c;
@@ -113,7 +114,7 @@ static int pty_write(struct tty_struct * tty, const unsigned char *buf, int coun
 	if (c > count)
 		c = count;
 	to->ldisc.ops->receive_buf(to, buf, NULL, c);
-	
+
 	return c;
 }
 
@@ -129,17 +130,17 @@ static int pty_write_room(struct tty_struct *tty)
 
 /*
  *	WSH 05/24/97:  Modified for asymmetric MASTER/SLAVE behavior
- *	The chars_in_buffer() value is used by the ldisc select() function 
+ *	The chars_in_buffer() value is used by the ldisc select() function
  *	to hold off writing when chars_in_buffer > WAKEUP_CHARS (== 256).
  *	The pty driver chars_in_buffer() Master/Slave must behave differently:
  *
  *      The Master side needs to allow typed-ahead commands to accumulate
  *      while being canonicalized, so we report "our buffer" as empty until
  *	some threshold is reached, and then report the count. (Any count >
- *	WAKEUP_CHARS is regarded by select() as "full".)  To avoid deadlock 
- *	the count returned must be 0 if no canonical data is available to be 
+ *	WAKEUP_CHARS is regarded by select() as "full".)  To avoid deadlock
+ *	the count returned must be 0 if no canonical data is available to be
  *	read. (The N_TTY ldisc.chars_in_buffer now knows this.)
- *  
+ *
  *	The Slave side passes all characters in raw mode to the Master side's
  *	buffer where they can be read immediately, so in this case we can
  *	return the true count in the buffer.
@@ -156,21 +157,22 @@ static int pty_chars_in_buffer(struct tty_struct *tty)
 	/* The ldisc must report 0 if no characters available to be read */
 	count = to->ldisc.ops->chars_in_buffer(to);
 
-	if (tty->driver->subtype == PTY_TYPE_SLAVE) return count;
+	if (tty->driver->subtype == PTY_TYPE_SLAVE)
+		return count;
 
-	/* Master side driver ... if the other side's read buffer is less than 
+	/* Master side driver ... if the other side's read buffer is less than
 	 * half full, return 0 to allow writers to proceed; otherwise return
-	 * the count.  This leaves a comfortable margin to avoid overflow, 
+	 * the count.  This leaves a comfortable margin to avoid overflow,
 	 * and still allows half a buffer's worth of typed-ahead commands.
 	 */
-	return ((count < N_TTY_BUF_SIZE/2) ? 0 : count);
+	return (count < N_TTY_BUF_SIZE/2) ? 0 : count;
 }
 
 /* Set the lock flag on a pty */
-static int pty_set_lock(struct tty_struct *tty, int __user * arg)
+static int pty_set_lock(struct tty_struct *tty, int __user *arg)
 {
 	int val;
-	if (get_user(val,arg))
+	if (get_user(val, arg))
 		return -EFAULT;
 	if (val)
 		set_bit(TTY_PTY_LOCK, &tty->flags);
@@ -183,13 +185,13 @@ static void pty_flush_buffer(struct tty_struct *tty)
 {
 	struct tty_struct *to = tty->link;
 	unsigned long flags;
-	
+
 	if (!to)
 		return;
-	
+
 	if (to->ldisc.ops->flush_buffer)
 		to->ldisc.ops->flush_buffer(to);
-	
+
 	if (to->packet) {
 		spin_lock_irqsave(&tty->ctrl_lock, flags);
 		tty->ctrl_status |= TIOCPKT_FLUSHWRITE;
@@ -198,7 +200,7 @@ static void pty_flush_buffer(struct tty_struct *tty)
 	}
 }
 
-static int pty_open(struct tty_struct *tty, struct file * filp)
+static int pty_open(struct tty_struct *tty, struct file *filp)
 {
 	int	retval = -ENODEV;
 
@@ -221,10 +223,11 @@ out:
 	return retval;
 }
 
-static void pty_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
+static void pty_set_termios(struct tty_struct *tty,
+					struct ktermios *old_termios)
 {
-        tty->termios->c_cflag &= ~(CSIZE | PARENB);
-        tty->termios->c_cflag |= (CS8 | CREAD);
+	tty->termios->c_cflag &= ~(CSIZE | PARENB);
+	tty->termios->c_cflag |= (CS8 | CREAD);
 }
 
 static int pty_install(struct tty_driver *driver, struct tty_struct *tty)
@@ -254,7 +257,7 @@ static int pty_install(struct tty_driver *driver, struct tty_struct *tty)
 		tty_free_termios(tty);
 		goto free_mem_out;
 	}
-	
+
 	/*
 	 * Everything allocated ... set up the o_tty structure.
 	 */
@@ -381,9 +384,9 @@ static inline void legacy_pty_init(void) { }
  * Otherwise one can eat up all kernel memory by opening /dev/ptmx repeatedly.
  */
 int pty_limit = NR_UNIX98_PTY_DEFAULT;
-static int pty_limit_min = 0;
+static int pty_limit_min;
 static int pty_limit_max = NR_UNIX98_PTY_MAX;
-static int pty_count = 0;
+static int pty_count;
 
 static struct cdev ptmx_cdev;
 
@@ -537,11 +540,10 @@ static int pty_unix98_install(struct tty_driver *driver, struct tty_struct *tty)
 	pty_count++;
 	return 0;
 free_mem_out:
-	kfree(o_tty->termios);
+	pty_unix98_shutdown(o_tty);
 	module_put(o_tty->driver->owner);
 	free_tty_struct(o_tty);
-	kfree(tty->termios_locked);
-	kfree(tty->termios);
+	pty_unix98_shutdown(tty);
 	free_tty_struct(tty);
 	module_put(driver->owner);
 	return -ENOMEM;
@@ -691,13 +693,13 @@ static void __init unix98_pty_init(void)
 		TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_DEVPTS_MEM;
 	pts_driver->other = ptm_driver;
 	tty_set_operations(pts_driver, &pty_unix98_ops);
-	
+
 	if (tty_register_driver(ptm_driver))
 		panic("Couldn't register Unix98 ptm driver");
 	if (tty_register_driver(pts_driver))
 		panic("Couldn't register Unix98 pts driver");
 
-	register_sysctl_table(pty_root_table);	
+	register_sysctl_table(pty_root_table);
 
 	/* Now create the /dev/ptmx special device */
 	tty_default_fops(&ptmx_fops);
author
#70 lore raw

PATCH 61/76 pty: Fix allocation failure double free

In reply to Alan Cox

The updating and moving around of the pty code added a bug where both the helper and caller free the main tty struct (the pty driver must free the o_tty pair itself however).

---

 drivers/char/pty.c |    2 --
 1 files changed, 0 insertions(+), 2 deletions(-)
drivers/char/pty.c +0 -2
index c3ab8c3..3c6b791 100644
@@ -544,8 +544,6 @@ free_mem_out:
 	module_put(o_tty->driver->owner);
 	free_tty_struct(o_tty);
 	pty_unix98_shutdown(tty);
-	free_tty_struct(tty);
-	module_put(driver->owner);
 	return -ENOMEM;
 }
 
author
#71 lore raw

PATCH 62/76 pty: simplify unix98 allocation

In reply to Alan Cox

We need both termios and termios_locked so allocate them as one

---

 drivers/char/pty.c |   18 +++++++-----------
 1 files changed, 7 insertions(+), 11 deletions(-)
drivers/char/pty.c +7 -11
index 3c6b791..6d45827 100644
@@ -488,7 +488,6 @@ static void pty_unix98_shutdown(struct tty_struct *tty)
 {
 	/* We have our own method as we don't use the tty index */
 	kfree(tty->termios);
-	kfree(tty->termios_locked);
 }
 
 /* We have no need to install and remove our tty objects as devpts does all
@@ -509,20 +508,17 @@ static int pty_unix98_install(struct tty_driver *driver, struct tty_struct *tty)
 	}
 	initialize_tty_struct(o_tty, driver->other, idx);
 
-	tty->termios = kmalloc(sizeof(struct ktermios), GFP_KERNEL);
+	tty->termios = kzalloc(sizeof(struct ktermios[2]), GFP_KERNEL);
 	if (tty->termios == NULL)
 		goto free_mem_out;
 	*tty->termios = driver->init_termios;
-	tty->termios_locked = kzalloc(sizeof(struct ktermios), GFP_KERNEL);
-	if (tty->termios_locked == NULL)
-		goto free_mem_out;
-	o_tty->termios = kmalloc(sizeof(struct ktermios), GFP_KERNEL);
+	tty->termios_locked = tty->termios + 1;
+
+	o_tty->termios = kzalloc(sizeof(struct ktermios[2]), GFP_KERNEL);
 	if (o_tty->termios == NULL)
 		goto free_mem_out;
 	*o_tty->termios = driver->other->init_termios;
-	o_tty->termios_locked = kzalloc(sizeof(struct ktermios), GFP_KERNEL);
-	if (o_tty->termios_locked == NULL)
-		goto free_mem_out;
+	o_tty->termios_locked = o_tty->termios + 1;
 
 	tty_driver_kref_get(driver->other);
 	if (driver->subtype == PTY_TYPE_MASTER)
@@ -540,10 +536,10 @@ static int pty_unix98_install(struct tty_driver *driver, struct tty_struct *tty)
 	pty_count++;
 	return 0;
 free_mem_out:
-	pty_unix98_shutdown(o_tty);
+	kfree(o_tty->termios);
 	module_put(o_tty->driver->owner);
 	free_tty_struct(o_tty);
-	pty_unix98_shutdown(tty);
+	kfree(tty->termios);
 	return -ENOMEM;
 }
 
author
#72 lore raw

PATCH 63/76 tty: simplify ktermios allocation

In reply to Alan Cox

Copy the simplification from the pty unix98 special case to the generic one. This allows us to kill off driver->termios_locked entirely which is nice. We have to whack bits of the cris driver as it meddles in places it shouldn't providing its own arrays that were never used anyway.

---

 drivers/char/tty_io.c    |   46 +++++++---------------------------------------
 drivers/serial/crisv10.c |    3 ---
 2 files changed, 7 insertions(+), 42 deletions(-)
drivers/char/tty_io.c +7 -39
index 9590839..502cad6 100644
@@ -1235,27 +1235,20 @@ struct tty_struct *tty_driver_lookup_tty(struct tty_driver *driver,
 
 int tty_init_termios(struct tty_struct *tty)
 {
-	struct ktermios *tp, *ltp;
+	struct ktermios *tp;
 	int idx = tty->index;
 
 	tp = tty->driver->termios[idx];
-	ltp = tty->driver->termios_locked[idx];
 	if (tp == NULL) {
-		WARN_ON(ltp != NULL);
-		tp = kmalloc(sizeof(struct ktermios), GFP_KERNEL);
-		ltp = kzalloc(sizeof(struct ktermios), GFP_KERNEL);
-		if (tp == NULL || ltp == NULL) {
-			kfree(tp);
-			kfree(ltp);
+		tp = kzalloc(sizeof(struct ktermios[2]), GFP_KERNEL);
+		if (tp == NULL)
 			return -ENOMEM;
-		}
 		memcpy(tp, &tty->driver->init_termios,
 						sizeof(struct ktermios));
 		tty->driver->termios[idx] = tp;
-		tty->driver->termios_locked[idx] = ltp;
 	}
 	tty->termios = tp;
-	tty->termios_locked = ltp;
+	tty->termios_locked = tp + 1;
 
 	/* Compatibility until drivers always set this */
 	tty->termios->c_ispeed = tty_termios_input_baud_rate(tty->termios);
@@ -1439,10 +1432,6 @@ void tty_free_termios(struct tty_struct *tty)
 		tp = tty->termios;
 		tty->driver->termios[idx] = NULL;
 		kfree(tp);
-
-		tp = tty->termios_locked;
-		tty->driver->termios_locked[idx] = NULL;
-		kfree(tp);
 	}
 }
 EXPORT_SYMBOL(tty_free_termios);
@@ -1575,12 +1564,6 @@ void tty_release_dev(struct file *filp)
 			       idx, tty->name);
 			return;
 		}
-		if (tty->termios_locked != tty->driver->termios_locked[idx]) {
-			printk(KERN_DEBUG "tty_release_dev: driver.termios_locked[%d] not "
-			       "termios_locked for (%s)\n",
-			       idx, tty->name);
-			return;
-		}
 	}
 #endif
 
@@ -1604,13 +1587,6 @@ void tty_release_dev(struct file *filp)
 			       idx, tty->name);
 			return;
 		}
-		if (o_tty->termios_locked !=
-		      tty->driver->other->termios_locked[idx]) {
-			printk(KERN_DEBUG "tty_release_dev: other->termios_locked["
-					  "%d] not o_termios_locked for (%s)\n",
-			       idx, tty->name);
-			return;
-		}
 		if (o_tty->link != tty) {
 			printk(KERN_DEBUG "tty_release_dev: bad pty pointers\n");
 			return;
@@ -2930,18 +2906,13 @@ static void destruct_tty_driver(struct kref *kref)
 				driver->termios[i] = NULL;
 				kfree(tp);
 			}
-			tp = driver->termios_locked[i];
-			if (tp) {
-				driver->termios_locked[i] = NULL;
-				kfree(tp);
-			}
 			if (!(driver->flags & TTY_DRIVER_DYNAMIC_DEV))
 				tty_unregister_device(driver, i);
 		}
 		p = driver->ttys;
 		proc_tty_unregister_driver(driver);
 		driver->ttys = NULL;
-		driver->termios = driver->termios_locked = NULL;
+		driver->termios = NULL;
 		kfree(p);
 		cdev_del(&driver->cdev);
 	}
@@ -2978,7 +2949,7 @@ int tty_register_driver(struct tty_driver *driver)
 	void **p = NULL;
 
 	if (!(driver->flags & TTY_DRIVER_DEVPTS_MEM) && driver->num) {
-		p = kzalloc(driver->num * 3 * sizeof(void *), GFP_KERNEL);
+		p = kzalloc(driver->num * 2 * sizeof(void *), GFP_KERNEL);
 		if (!p)
 			return -ENOMEM;
 	}
@@ -3002,12 +2973,9 @@ int tty_register_driver(struct tty_driver *driver)
 	if (p) {
 		driver->ttys = (struct tty_struct **)p;
 		driver->termios = (struct ktermios **)(p + driver->num);
-		driver->termios_locked = (struct ktermios **)
-							(p + driver->num * 2);
 	} else {
 		driver->ttys = NULL;
 		driver->termios = NULL;
-		driver->termios_locked = NULL;
 	}
 
 	cdev_init(&driver->cdev, &tty_fops);
@@ -3016,7 +2984,7 @@ int tty_register_driver(struct tty_driver *driver)
 	if (error) {
 		unregister_chrdev_region(dev, driver->num);
 		driver->ttys = NULL;
-		driver->termios = driver->termios_locked = NULL;
+		driver->termios = NULL;
 		kfree(p);
 		return error;
 	}
drivers/serial/crisv10.c +0 -3
index a467c77..211c217 100644
@@ -457,7 +457,6 @@ static struct e100_serial rs_table[] = {
 #define NR_PORTS (sizeof(rs_table)/sizeof(struct e100_serial))
 
 static struct ktermios *serial_termios[NR_PORTS];
-static struct ktermios *serial_termios_locked[NR_PORTS];
 #ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER
 static struct fast_timer fast_timers[NR_PORTS];
 #endif
@@ -4448,8 +4447,6 @@ rs_init(void)
 	driver->init_termios.c_ispeed = 115200;
 	driver->init_termios.c_ospeed = 115200;
 	driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
-	driver->termios = serial_termios;
-	driver->termios_locked = serial_termios_locked;
 
 	tty_set_operations(driver, &rs_ops);
         serial_driver = driver;
author
#73 lore raw

PATCH 64/76 tty: some ICANON magic is in the wrong places

In reply to Alan Cox

Move the set up on ldisc change into the ldisc
Move the INQ/OUTQ cases into the driver not in shared ioctl code where it gives bogus answers for other ldisc values

---

 drivers/bluetooth/hci_ldisc.c |    2 +-
 drivers/char/n_hdlc.c         |    2 +-
 drivers/char/n_tty.c          |   53 +++++++++++++++++++++++++++++++++++++++--
 drivers/char/tty_ioctl.c      |   42 ++------------------------------
 include/linux/tty.h           |    2 +-
 5 files changed, 56 insertions(+), 45 deletions(-)
drivers/bluetooth/hci_ldisc.c +1 -1
index 8dfcf77..4426bb5 100644
@@ -484,7 +484,7 @@ static int hci_uart_tty_ioctl(struct tty_struct *tty, struct file * file,
 		return -EUNATCH;
 
 	default:
-		err = n_tty_ioctl(tty, file, cmd, arg);
+		err = n_tty_ioctl_helper(tty, file, cmd, arg);
 		break;
 	};
 
drivers/char/n_hdlc.c +1 -1
index 69ec639..bacb3e2 100644
@@ -764,7 +764,7 @@ static int n_hdlc_tty_ioctl(struct tty_struct *tty, struct file *file,
 		break;
 
 	default:
-		error = n_tty_ioctl (tty, file, cmd, arg);
+		error = n_tty_ioctl_helper(tty, file, cmd, arg);
 		break;
 	}
 	return error;
drivers/char/n_tty.c +51 -2

65 lines not on this page · raw message

drivers/char/tty_ioctl.c +2 -40

75 lines not on this page · raw message

include/linux/tty.h +1 -1
index 3c7c757..3b8121d 100644
@@ -466,7 +466,7 @@ static inline void tty_audit_push_task(struct task_struct *tsk,
 #endif
 
 /* tty_ioctl.c */
-extern int n_tty_ioctl(struct tty_struct *tty, struct file *file,
+extern int n_tty_ioctl_helper(struct tty_struct *tty, struct file *file,
 		       unsigned int cmd, unsigned long arg);
 
 /* serial.c */
author
#74 lore raw

PATCH 65/76 tty: Fallout from tty-move-canon-specials

In reply to Alan Cox

From: Stephen Rothwell <[email protected]>

Hi Alan,

Today's linux-next build (x86_64 allmodconfig) failed like this:

/drivers/char/tty_ioctl.c: In function 'change_termios':
drivers/isdn/capi/capi.c:1234: error: implicit declaration of function 'n_tty_ioctl' drivers/isdn/gigaset/ser-gigaset.c: In function 'gigaset_tty_ioctl':
drivers/isdn/gigaset/ser-gigaset.c:648: error: implicit declaration of function 'n_tty_ioctl'

Introduced by commit 686b5e4aea05a80e370dc931b7f4a8d03c80da54 ("tty-move-canon-specials"). I added the following patch (which may not be correct).

--
Cheers,
Stephen Rothwell [email protected]
http://www.canb.auug.org.au/~sfr/

---

 drivers/isdn/capi/capi.c           |    2 +-
 drivers/isdn/gigaset/ser-gigaset.c |    4 ++--
 2 files changed, 3 insertions(+), 3 deletions(-)
drivers/isdn/capi/capi.c +1 -1
index 871b0cb..798d7f3 100644
@@ -1231,7 +1231,7 @@ static int capinc_tty_ioctl(struct tty_struct *tty, struct file * file,
 	int error = 0;
 	switch (cmd) {
 	default:
-		error = n_tty_ioctl (tty, file, cmd, arg);
+		error = n_tty_ioctl_helper(tty, file, cmd, arg);
 		break;
 	}
 	return error;
drivers/isdn/gigaset/ser-gigaset.c +2 -2
index 5e89fa1..cc4f4e4 100644
@@ -645,7 +645,7 @@ gigaset_tty_ioctl(struct tty_struct *tty, struct file *file,
 	case TCGETS:
 	case TCGETA:
 		/* pass through to underlying serial device */
-		rc = n_tty_ioctl(tty, file, cmd, arg);
+		rc = n_tty_ioctl_helper(tty, file, cmd, arg);
 		break;
 
 	case TCFLSH:
@@ -660,7 +660,7 @@ gigaset_tty_ioctl(struct tty_struct *tty, struct file *file,
 			break;
 		}
 		/* flush the serial port's buffer */
-		rc = n_tty_ioctl(tty, file, cmd, arg);
+		rc = n_tty_ioctl_helper(tty, file, cmd, arg);
 		break;
 
 	case FIONREAD:
author
#75 lore raw

PATCH 66/76 tty: fix up gigaset a bit

In reply to Alan Cox

Stephen's fixes reminded me that gigaset is still rather broken so fix it up a bit

---

 drivers/isdn/gigaset/ser-gigaset.c |   27 ++++++++++++---------------
 1 files changed, 12 insertions(+), 15 deletions(-)
drivers/isdn/gigaset/ser-gigaset.c +12 -15
index cc4f4e4..07052ed 100644
@@ -571,6 +571,7 @@ gigaset_tty_close(struct tty_struct *tty)
 	}
 
 	/* prevent other callers from entering ldisc methods */
+	/* FIXME: should use the tty state flags */
 	tty->disc_data = NULL;
 
 	if (!cs->hw.ser)
@@ -642,10 +643,11 @@ gigaset_tty_ioctl(struct tty_struct *tty, struct file *file,
 		return -ENXIO;
 
 	switch (cmd) {
-	case TCGETS:
-	case TCGETA:
-		/* pass through to underlying serial device */
-		rc = n_tty_ioctl_helper(tty, file, cmd, arg);
+
+	case FIONREAD:
+		/* unused, always return zero */
+		val = 0;
+		rc = put_user(val, p);
 		break;
 
 	case TCFLSH:
@@ -659,20 +661,13 @@ gigaset_tty_ioctl(struct tty_struct *tty, struct file *file,
 			flush_send_queue(cs);
 			break;
 		}
-		/* flush the serial port's buffer */
-		rc = n_tty_ioctl_helper(tty, file, cmd, arg);
-		break;
-
-	case FIONREAD:
-		/* unused, always return zero */
-		val = 0;
-		rc = put_user(val, p);
-		break;
+		/* Pass through */
 
 	default:
-		rc = -ENOIOCTLCMD;
+		/* pass through to underlying serial device */
+		rc = n_tty_ioctl_helper(tty, file, cmd, arg);
+		break;
 	}
-
 	cs_put(cs);
 	return rc;
 }
@@ -680,6 +675,8 @@ gigaset_tty_ioctl(struct tty_struct *tty, struct file *file,
 /*
  * Poll on the tty.
  * Unused, always return zero.
+ *
+ * FIXME: should probably return an exception - especially on hangup
  */
 static unsigned int
 gigaset_tty_poll(struct tty_struct *tty, struct file *file, poll_table *wait)
author
#76 lore raw

PATCH 67/76 tty: Remove lots of NULL checks

In reply to Alan Cox

Many tty drivers contain 'can't happen' checks against NULL pointers passed in by the tty layer. These have never been possible to occur. Even more importantly if they ever do occur we want to know as it would be a serious bug.
---

 drivers/char/amiserial.c      |    6 ------
 drivers/char/generic_serial.c |   21 ---------------------
 drivers/char/istallion.c      |    6 ------
 drivers/char/mxser.c          |    5 -----
 drivers/char/n_r3964.c        |    9 +--------
 drivers/char/stallion.c       |   34 ----------------------------------
 6 files changed, 1 insertions(+), 80 deletions(-)
drivers/char/amiserial.c +0 -6
index 6e763e3..98821f9 100644
@@ -837,9 +837,6 @@ static int rs_put_char(struct tty_struct *tty, unsigned char ch)
 	struct async_struct *info;
 	unsigned long flags;
 
-	if (!tty)
-		return 0;
-
 	info = tty->driver_data;
 
 	if (serial_paranoia_check(info, tty->name, "rs_put_char"))
@@ -892,9 +889,6 @@ static int rs_write(struct tty_struct * tty, const unsigned char *buf, int count
 	struct async_struct *info;
 	unsigned long flags;
 
-	if (!tty)
-		return 0;
-
 	info = tty->driver_data;
 
 	if (serial_paranoia_check(info, tty->name, "rs_write"))
drivers/char/generic_serial.c +0 -21
index 19d3afb..c6090f8 100644
@@ -54,8 +54,6 @@ int gs_put_char(struct tty_struct * tty, unsigned char ch)
 
 	func_enter (); 
 
-	if (!tty) return 0;
-
 	port = tty->driver_data;
 
 	if (!port) return 0;
@@ -97,8 +95,6 @@ int gs_write(struct tty_struct * tty,
 
 	func_enter ();
 
-	if (!tty) return 0;
-
 	port = tty->driver_data;
 
 	if (!port) return 0;
@@ -185,7 +181,6 @@ static int gs_real_chars_in_buffer(struct tty_struct *tty)
 	struct gs_port *port;
 	func_enter ();
 
-	if (!tty) return 0;
 	port = tty->driver_data;
 
 	if (!port->rd) return 0;
@@ -274,8 +269,6 @@ void gs_flush_buffer(struct tty_struct *tty)
 
 	func_enter ();
 
-	if (!tty) return;
-
 	port = tty->driver_data;
 
 	if (!port) return;
@@ -296,8 +289,6 @@ void gs_flush_chars(struct tty_struct * tty)
 
 	func_enter ();
 
-	if (!tty) return;
-
 	port = tty->driver_data;
 
 	if (!port) return;
@@ -321,8 +312,6 @@ void gs_stop(struct tty_struct * tty)
 
 	func_enter ();
 
-	if (!tty) return;
-
 	port = tty->driver_data;
 
 	if (!port) return;
@@ -341,8 +330,6 @@ void gs_start(struct tty_struct * tty)
 {
 	struct gs_port *port;
 
-	if (!tty) return;
-
 	port = tty->driver_data;
 
 	if (!port) return;
@@ -393,8 +380,6 @@ void gs_hangup(struct tty_struct *tty)
 
 	func_enter ();
 
-	if (!tty) return;
-
 	port = tty->driver_data;
 	tty = port->port.tty;
 	if (!tty) 
@@ -426,8 +411,6 @@ int gs_block_til_ready(void *port_, struct file * filp)
 
 	tty = port->port.tty;
 
-	if (!tty) return 0;
-
 	gs_dprintk (GS_DEBUG_BTR, "Entering gs_block_till_ready.\n"); 
 	/*
 	 * If the device is in the middle of being closed, then block
@@ -523,8 +506,6 @@ void gs_close(struct tty_struct * tty, struct file * filp)
 	
 	func_enter ();
 
-	if (!tty) return;
-
 	port = (struct gs_port *) tty->driver_data;
 
 	if (!port) return;
@@ -621,8 +602,6 @@ void gs_set_termios (struct tty_struct * tty,
 
 	func_enter();
 
-	if (!tty) return;
-
 	port = tty->driver_data;
 
 	if (!port) return;
drivers/char/istallion.c +0 -6
index 96ee112..505d7a1 100644
@@ -1375,8 +1375,6 @@ static void stli_flushchars(struct tty_struct *tty)
 	stli_txcookrealsize = 0;
 	stli_txcooktty = NULL;
 
-	if (tty == NULL)
-		return;
 	if (cooktty == NULL)
 		return;
 	if (tty != cooktty)
@@ -1732,8 +1730,6 @@ static void stli_settermios(struct tty_struct *tty, struct ktermios *old)
 	struct ktermios *tiosp;
 	asyport_t aport;
 
-	if (tty == NULL)
-		return;
 	portp = tty->driver_data;
 	if (portp == NULL)
 		return;
@@ -1938,8 +1934,6 @@ static void stli_waituntilsent(struct tty_struct *tty, int timeout)
 	struct stliport *portp;
 	unsigned long tend;
 
-	if (tty == NULL)
-		return;
 	portp = tty->driver_data;
 	if (portp == NULL)
 		return;
drivers/char/mxser.c +0 -5
index 308cb60..8beef50 100644
@@ -616,9 +616,6 @@ static int mxser_set_baud(struct tty_struct *tty, long newspd)
 	int quot = 0, baud;
 	unsigned char cval;
 
-	if (!tty->termios)
-		return -1;
-
 	if (!info->ioaddr)
 		return -1;
 
@@ -688,8 +685,6 @@ static int mxser_change_speed(struct tty_struct *tty,
 	int ret = 0;
 	unsigned char status;
 
-	if (!tty->termios)
-		return ret;
 	cflag = tty->termios->c_cflag;
 	if (!info->ioaddr)
 		return ret;
drivers/char/n_r3964.c +1 -8
index ae377aa..c0a1df9 100644
@@ -372,15 +372,8 @@ static void remove_from_rx_queue(struct r3964_info *pInfo,
 static void put_char(struct r3964_info *pInfo, unsigned char ch)
 {
 	struct tty_struct *tty = pInfo->tty;
-
-	if (tty == NULL)
-		return;
-
 	/* FIXME: put_char should not be called from an IRQ */
-	if (tty->ops->put_char) {
-		tty->ops->put_char(tty, ch);
-	}
-	pInfo->bcc ^= ch;
+	tty_put_char(tty, ch);
 }
 
 static void flush(struct r3964_info *pInfo)
drivers/char/stallion.c +0 -34
index 81b3234..8b8f07a 100644
@@ -849,8 +849,6 @@ static void stl_flushbuffer(struct tty_struct *tty)
 
 	pr_debug("stl_flushbuffer(tty=%p)\n", tty);
 
-	if (tty == NULL)
-		return;
 	portp = tty->driver_data;
 	if (portp == NULL)
 		return;
@@ -868,8 +866,6 @@ static void stl_waituntilsent(struct tty_struct *tty, int timeout)
 
 	pr_debug("stl_waituntilsent(tty=%p,timeout=%d)\n", tty, timeout);
 
-	if (tty == NULL)
-		return;
 	portp = tty->driver_data;
 	if (portp == NULL)
 		return;
@@ -1036,8 +1032,6 @@ static int stl_putchar(struct tty_struct *tty, unsigned char ch)
 
 	pr_debug("stl_putchar(tty=%p,ch=%x)\n", tty, ch);
 
-	if (tty == NULL)
-		return -EINVAL;
 	portp = tty->driver_data;
 	if (portp == NULL)
 		return -EINVAL;
@@ -1073,8 +1067,6 @@ static void stl_flushchars(struct tty_struct *tty)
 
 	pr_debug("stl_flushchars(tty=%p)\n", tty);
 
-	if (tty == NULL)
-		return;
 	portp = tty->driver_data;
 	if (portp == NULL)
 		return;
@@ -1093,8 +1085,6 @@ static int stl_writeroom(struct tty_struct *tty)
 
 	pr_debug("stl_writeroom(tty=%p)\n", tty);
 
-	if (tty == NULL)
-		return 0;
 	portp = tty->driver_data;
 	if (portp == NULL)
 		return 0;
@@ -1125,8 +1115,6 @@ static int stl_charsinbuffer(struct tty_struct *tty)
 
 	pr_debug("stl_charsinbuffer(tty=%p)\n", tty);
 
-	if (tty == NULL)
-		return 0;
 	portp = tty->driver_data;
 	if (portp == NULL)
 		return 0;
@@ -1219,8 +1207,6 @@ static int stl_tiocmget(struct tty_struct *tty, struct file *file)
 {
 	struct stlport	*portp;
 
-	if (tty == NULL)
-		return -ENODEV;
 	portp = tty->driver_data;
 	if (portp == NULL)
 		return -ENODEV;
@@ -1236,8 +1222,6 @@ static int stl_tiocmset(struct tty_struct *tty, struct file *file,
 	struct stlport	*portp;
 	int rts = -1, dtr = -1;
 
-	if (tty == NULL)
-		return -ENODEV;
 	portp = tty->driver_data;
 	if (portp == NULL)
 		return -ENODEV;
@@ -1266,8 +1250,6 @@ static int stl_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd
 	pr_debug("stl_ioctl(tty=%p,file=%p,cmd=%x,arg=%lx)\n", tty, file, cmd,
 			arg);
 
-	if (tty == NULL)
-		return -ENODEV;
 	portp = tty->driver_data;
 	if (portp == NULL)
 		return -ENODEV;
@@ -1321,8 +1303,6 @@ static void stl_start(struct tty_struct *tty)
 
 	pr_debug("stl_start(tty=%p)\n", tty);
 
-	if (tty == NULL)
-		return;
 	portp = tty->driver_data;
 	if (portp == NULL)
 		return;
@@ -1338,8 +1318,6 @@ static void stl_settermios(struct tty_struct *tty, struct ktermios *old)
 
 	pr_debug("stl_settermios(tty=%p,old=%p)\n", tty, old);
 
-	if (tty == NULL)
-		return;
 	portp = tty->driver_data;
 	if (portp == NULL)
 		return;
@@ -1373,8 +1351,6 @@ static void stl_throttle(struct tty_struct *tty)
 
 	pr_debug("stl_throttle(tty=%p)\n", tty);
 
-	if (tty == NULL)
-		return;
 	portp = tty->driver_data;
 	if (portp == NULL)
 		return;
@@ -1393,8 +1369,6 @@ static void stl_unthrottle(struct tty_struct *tty)
 
 	pr_debug("stl_unthrottle(tty=%p)\n", tty);
 
-	if (tty == NULL)
-		return;
 	portp = tty->driver_data;
 	if (portp == NULL)
 		return;
@@ -1414,8 +1388,6 @@ static void stl_stop(struct tty_struct *tty)
 
 	pr_debug("stl_stop(tty=%p)\n", tty);
 
-	if (tty == NULL)
-		return;
 	portp = tty->driver_data;
 	if (portp == NULL)
 		return;
@@ -1436,8 +1408,6 @@ static void stl_hangup(struct tty_struct *tty)
 
 	pr_debug("stl_hangup(tty=%p)\n", tty);
 
-	if (tty == NULL)
-		return;
 	portp = tty->driver_data;
 	if (portp == NULL)
 		return;
@@ -1470,8 +1440,6 @@ static int stl_breakctl(struct tty_struct *tty, int state)
 
 	pr_debug("stl_breakctl(tty=%p,state=%d)\n", tty, state);
 
-	if (tty == NULL)
-		return -EINVAL;
 	portp = tty->driver_data;
 	if (portp == NULL)
 		return -EINVAL;
@@ -1488,8 +1456,6 @@ static void stl_sendxchar(struct tty_struct *tty, char ch)
 
 	pr_debug("stl_sendxchar(tty=%p,ch=%x)\n", tty, ch);
 
-	if (tty == NULL)
-		return;
 	portp = tty->driver_data;
 	if (portp == NULL)
 		return;
#77 lore raw

Re: [PATCH 67/76] tty: Remove lots of NULL checks

Quoted 12 lines · Alan Cox

Many tty drivers contain 'can't happen' checks against NULL pointers passed in by the tty layer. These have never been possible to occur. Even more importantly if they ever do occur we want to know as it would be a serious bug.

drivers/char/n_r3964.c +0 -0
index ae377aa..c0a1df9 100644
@@ -372,15 +372,8 @@ static void remove_from_rx_queue(struct r3964_info *pInfo,
 static void put_char(struct r3964_info *pInfo, unsigned char ch)
 {

drivers/char/n_r3964.c static void remove_from_rx_queue(struct r3964_info *pInfo, · line 383

Quoted 10 lines
drivers/char/n_r3964.c +0 -8
 	struct tty_struct *tty = pInfo->tty;
-
-	if (tty == NULL)
-		return;
-
 	/* FIXME: put_char should not be called from an IRQ */
-	if (tty->ops->put_char) {
-		tty->ops->put_char(tty, ch);
-	}
-	pInfo->bcc ^= ch;
        ^^^^^^^^^^^^^^^^

drivers/char/n_r3964.c static void remove_from_rx_queue(struct r3964_info *pInfo, · line 377

Quoted 2 lines
drivers/char/n_r3964.c +1 -0
+	tty_put_char(tty, ch);
 }

I have no idea what this `bcc' thingy does, but its removal just struck my eye...

Gr{oetje,eeting}s,

Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- [email protected]

In personal conversations with technical people, I call myself a hacker. But when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds

#78 lore raw

Re: [PATCH 67/76] tty: Remove lots of NULL checks

Quoted 2 lines

I have no idea what this `bcc' thingy does, but its removal just struck my eye...

Thanks - keeps a checksum byte per packet up to date if checksumming is in use so having the right value is a good idea.

Fixed

author
#79 lore raw

PATCH 68/76 tty: Minor tidyups and document fixes for n_tty

In reply to Alan Cox

Remove/fix some bogus NULL checks, comment some locking etc

---

 drivers/char/n_tty.c |   48 +++++++++++++++++++++++++++++++++++++-----------
 1 files changed, 37 insertions(+), 11 deletions(-)
drivers/char/n_tty.c +37 -11
index b4f5dcc..c0285b9 100644
@@ -99,6 +99,7 @@ static inline int tty_put_user(struct tty_struct *tty, unsigned char x,
 
 static void n_tty_set_room(struct tty_struct *tty)
 {
+	/* tty->read_cnt is not read locked ? */
 	int	left = N_TTY_BUF_SIZE - tty->read_cnt - 1;
 
 	/*
@@ -121,6 +122,16 @@ static void put_tty_queue_nolock(unsigned char c, struct tty_struct *tty)
 	}
 }
 
+/**
+ *	put_tty_queue		-	add character to tty
+ *	@c: character
+ *	@tty: tty device
+ *
+ *	Add a character to the tty read_buf queue. This is done under the
+ *	read_lock to serialize character addition and also to protect us
+ *	against parallel reads or flushes
+ */
+
 static void put_tty_queue(unsigned char c, struct tty_struct *tty)
 {
 	unsigned long flags;
@@ -137,14 +148,11 @@ static void put_tty_queue(unsigned char c, struct tty_struct *tty)
  *	check_unthrottle	-	allow new receive data
  *	@tty; tty device
  *
- *	Check whether to call the driver.unthrottle function.
- *	We test the TTY_THROTTLED bit first so that it always
- *	indicates the current state. The decision about whether
- *	it is worth allowing more input has been taken by the caller.
+ *	Check whether to call the driver unthrottle functions
+ *
  *	Can sleep, may be called under the atomic_read_lock mutex but
  *	this is not guaranteed.
  */
-
 static void check_unthrottle(struct tty_struct *tty)
 {
 	if (tty->count)
@@ -158,6 +166,8 @@ static void check_unthrottle(struct tty_struct *tty)
  *	Reset the read buffer counters, clear the flags,
  *	and make sure the driver is unthrottled. Called
  *	from n_tty_open() and n_tty_flush_buffer().
+ *
+ *	Locking: tty_read_lock for read fields.
  */
 static void reset_buffer_flags(struct tty_struct *tty)
 {
@@ -181,7 +191,7 @@ static void reset_buffer_flags(struct tty_struct *tty)
  *	at hangup) or when the N_TTY line discipline internally has to
  *	clean the pending queue (for example some signals).
  *
- *	Locking: ctrl_lock
+ *	Locking: ctrl_lock, read_lock.
  */
 
 static void n_tty_flush_buffer(struct tty_struct *tty)
@@ -207,6 +217,8 @@ static void n_tty_flush_buffer(struct tty_struct *tty)
  *
  *	Report the number of characters buffered to be delivered to user
  *	at this instant in time.
+ *
+ *	Locking: read_lock
  */
 
 static ssize_t n_tty_chars_in_buffer(struct tty_struct *tty)
@@ -410,6 +422,8 @@ break_out:
  *
  *	Echo user input back onto the screen. This must be called only when
  *	L_ECHO(tty) is true. Called from the driver receive_buf path.
+ *
+ *	Relies on BKL for tty column locking
  */
 
 static void echo_char(unsigned char c, struct tty_struct *tty)
@@ -422,6 +436,12 @@ static void echo_char(unsigned char c, struct tty_struct *tty)
 		opost(c, tty);
 }
 
+/**
+ *	finsh_erasing		-	complete erase
+ *	@tty: tty doing the erase
+ *
+ *	Relies on BKL for tty column locking
+ */
 static inline void finish_erasing(struct tty_struct *tty)
 {
 	if (tty->erasing) {
@@ -439,6 +459,8 @@ static inline void finish_erasing(struct tty_struct *tty)
  *	Perform erase and necessary output when an erase character is
  *	present in the stream from the driver layer. Handles the complexities
  *	of UTF-8 multibyte symbols.
+ *
+ *	Locking: read_lock for tty buffers, BKL for column/erasing state
  */
 
 static void eraser(unsigned char c, struct tty_struct *tty)
@@ -447,6 +469,7 @@ static void eraser(unsigned char c, struct tty_struct *tty)
 	int head, seen_alnums, cnt;
 	unsigned long flags;
 
+	/* FIXME: locking needed ? */
 	if (tty->read_head == tty->canon_head) {
 		/* opost('\a', tty); */		/* what do you think? */
 		return;
@@ -481,6 +504,7 @@ static void eraser(unsigned char c, struct tty_struct *tty)
 	}
 
 	seen_alnums = 0;
+	/* FIXME: Locking ?? */
 	while (tty->read_head != tty->canon_head) {
 		head = tty->read_head;
 
@@ -583,6 +607,8 @@ static void eraser(unsigned char c, struct tty_struct *tty)
  *	may caus terminal flushing to take place according to the termios
  *	settings and character used. Called from the driver receive_buf
  *	path so serialized.
+ *
+ *	Locking: ctrl_lock, read_lock (both via flush buffer)
  */
 
 static inline void isig(int sig, struct tty_struct *tty, int flush)
@@ -1007,6 +1033,8 @@ int is_ignored(int sig)
  *	and is protected from re-entry by the tty layer. The user is
  *	guaranteed that this function will not be re-entered or in progress
  *	when the ldisc is closed.
+ *
+ *	Locking: Caller holds tty->termios_mutex
  */
 
 static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old)
@@ -1266,10 +1294,7 @@ static ssize_t read_chan(struct tty_struct *tty, struct file *file,
 
 do_it_again:
 
-	if (!tty->read_buf) {
-		printk(KERN_ERR "n_tty_read_chan: read_buf == NULL?!?\n");
-		return -EIO;
-	}
+	BUG_ON(!tty->read_buf);
 
 	c = job_control(tty, file);
 	if (c < 0)
@@ -1589,7 +1614,7 @@ static unsigned long inq_canon(struct tty_struct *tty)
 {
 	int nr, head, tail;
 
-	if (!tty->canon_data || !tty->read_buf)
+	if (!tty->canon_data)
 		return 0;
 	head = tty->canon_head;
 	tail = tty->read_tail;
@@ -1613,6 +1638,7 @@ static int n_tty_ioctl(struct tty_struct *tty, struct file *file,
 	case TIOCOUTQ:
 		return put_user(tty_chars_in_buffer(tty), (int __user *) arg);
 	case TIOCINQ:
+		/* FIXME: Locking */
 		retval = tty->read_cnt;
 		if (L_ICANON(tty))
 			retval = inq_canon(tty);
author
#80 lore raw

PATCH 69/76 hso: net driver using tty without locking

In reply to Alan Cox

Checking tty == NULL doesn't help us unless we have a clear semantic for the locking of the tty object in the driver. Use the tty kref objects so that we can take references to the tty in the USB event handling paths.

---

 drivers/net/usb/hso.c |   46 +++++++++++++++++++++++++++++++++++-----------
 1 files changed, 35 insertions(+), 11 deletions(-)
drivers/net/usb/hso.c +35 -11
index 6e42b5a..b764802 100644
@@ -1028,14 +1028,14 @@ static void _hso_serial_set_termios(struct tty_struct *tty,
 	termios->c_cflag |= CS8;	/* character size 8 bits */
 
 	/* baud rate 115200 */
-	tty_encode_baud_rate(serial->tty, 115200, 115200);
+	tty_encode_baud_rate(tty, 115200, 115200);
 
 	/*
 	 * Force low_latency on; otherwise the pushes are scheduled;
 	 * this is bad as it opens up the possibility of dropping bytes
 	 * on the floor.  We don't want to drop bytes on the floor. :)
 	 */
-	serial->tty->low_latency = 1;
+	tty->low_latency = 1;
 	return;
 }
 
@@ -1061,8 +1061,10 @@ static int hso_serial_open(struct tty_struct *tty, struct file *filp)
 	kref_get(&serial->parent->ref);
 
 	/* setup */
+	spin_lock_irq(&serial->serial_lock);
 	tty->driver_data = serial;
-	serial->tty = tty;
+	serial->tty = tty_kref_get(tty);
+	spin_unlock_irq(&serial->serial_lock);
 
 	/* check for port allready opened, if not set the termios */
 	serial->open_count++;
@@ -1111,10 +1113,13 @@ static void hso_serial_close(struct tty_struct *tty, struct file *filp)
 	kref_put(&serial->parent->ref, hso_serial_ref_free);
 	if (serial->open_count <= 0) {
 		serial->open_count = 0;
-		if (serial->tty) {
+		spin_lock_irq(&serial->serial_lock);
+		if (serial->tty == tty) {
 			serial->tty->driver_data = NULL;
 			serial->tty = NULL;
+			tty_kref_put(tty);
 		}
+		spin_unlock_irq(&serial->serial_lock);
 		if (!usb_gone)
 			hso_stop_serial_device(serial->parent);
 	}
@@ -1457,6 +1462,7 @@ static void hso_std_serial_write_bulk_callback(struct urb *urb)
 {
 	struct hso_serial *serial = urb->context;
 	int status = urb->status;
+	struct tty_struct *tty;
 
 	/* sanity check */
 	if (!serial) {
@@ -1466,14 +1472,18 @@ static void hso_std_serial_write_bulk_callback(struct urb *urb)
 
 	spin_lock(&serial->serial_lock);
 	serial->tx_urb_used = 0;
+	tty = tty_kref_get(serial->tty);
 	spin_unlock(&serial->serial_lock);
 	if (status) {
 		log_usb_status(status, __func__);
+		tty_kref_put(tty);
 		return;
 	}
 	hso_put_activity(serial->parent);
-	if (serial->tty)
-		tty_wakeup(serial->tty);
+	if (tty) {
+		tty_wakeup(tty);
+		tty_kref_put(tty);
+	}
 	hso_kick_transmit(serial);
 
 	D1(" ");
@@ -1510,6 +1520,7 @@ static void ctrl_callback(struct urb *urb)
 	struct hso_serial *serial = urb->context;
 	struct usb_ctrlrequest *req;
 	int status = urb->status;
+	struct tty_struct *tty;
 
 	/* sanity check */
 	if (!serial)
@@ -1517,9 +1528,11 @@ static void ctrl_callback(struct urb *urb)
 
 	spin_lock(&serial->serial_lock);
 	serial->tx_urb_used = 0;
+	tty = tty_kref_get(serial->tty);
 	spin_unlock(&serial->serial_lock);
 	if (status) {
 		log_usb_status(status, __func__);
+		tty_kref_put(tty);
 		return;
 	}
 
@@ -1544,17 +1557,18 @@ static void ctrl_callback(struct urb *urb)
 			clear_bit(HSO_SERIAL_FLAG_RX_SENT, &serial->flags);
 	} else {
 		hso_put_activity(serial->parent);
-		if (serial->tty)
-			tty_wakeup(serial->tty);
+		if (tty)
+			tty_wakeup(tty);
 		/* response to a write command */
 		hso_kick_transmit(serial);
 	}
+	tty_kref_put(tty);
 }
 
 /* handle RX data for serial port */
 static void put_rxbuf_data(struct urb *urb, struct hso_serial *serial)
 {
-	struct tty_struct *tty = serial->tty;
+	struct tty_struct *tty;
 
 	/* Sanity check */
 	if (urb == NULL || serial == NULL) {
@@ -1562,6 +1576,10 @@ static void put_rxbuf_data(struct urb *urb, struct hso_serial *serial)
 		return;
 	}
 
+	spin_lock(&serial->serial_lock);
+	tty = tty_kref_get(serial->tty);
+	spin_unlock(&serial->serial_lock);
+
 	/* Push data to tty */
 	if (tty && urb->actual_length) {
 		D1("data to push to tty");
@@ -1569,6 +1587,7 @@ static void put_rxbuf_data(struct urb *urb, struct hso_serial *serial)
 				       urb->actual_length);
 		tty_flip_buffer_push(tty);
 	}
+	tty_kref_put(tty);
 }
 
 /* read callback for Diag and CS port */
@@ -2635,15 +2654,20 @@ static void hso_serial_ref_free(struct kref *ref)
 static void hso_free_interface(struct usb_interface *interface)
 {
 	struct hso_serial *hso_dev;
+	struct tty_struct *tty;
 	int i;
 
 	for (i = 0; i < HSO_SERIAL_TTY_MINORS; i++) {
 		if (serial_table[i]
 		    && (serial_table[i]->interface == interface)) {
 			hso_dev = dev2ser(serial_table[i]);
-			if (hso_dev->tty)
-				tty_hangup(hso_dev->tty);
+			spin_lock_irq(&hso_dev->serial_lock);
+			tty = tty_kref_get(hso_dev->tty);
+			spin_unlock_irq(&hso_dev->serial_lock);
+			if (tty)
+				tty_hangup(tty);
 			mutex_lock(&hso_dev->parent->mutex);
+			tty_kref_put(tty);
 			hso_dev->parent->usb_gone = 1;
 			mutex_unlock(&hso_dev->parent->mutex);
 			kref_put(&serial_table[i]->ref, hso_serial_ref_free);
author
#81 lore raw

PATCH 70/76 applicom: Fix an unchecked user ioctl range and an error return

In reply to Alan Cox

Closes bug #11408 by checking the card index range for command 0 Fixes the ioctl to return ENOTTY which is correct for unknown ioctls

---

 drivers/char/applicom.c |    6 ++----
 1 files changed, 2 insertions(+), 4 deletions(-)
drivers/char/applicom.c +2 -4
index 31d08b6..b899d91 100644
@@ -712,8 +712,7 @@ static int ac_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un
 	
 	IndexCard = adgl->num_card-1;
 	 
-	if(cmd != 0 && cmd != 6 &&
-	   ((IndexCard >= MAX_BOARD) || !apbs[IndexCard].RamIO)) {
+	if(cmd != 6 && ((IndexCard >= MAX_BOARD) || !apbs[IndexCard].RamIO)) {
 		static int warncount = 10;
 		if (warncount) {
 			printk( KERN_WARNING "APPLICOM driver IOCTL, bad board number %d\n",(int)IndexCard+1);
@@ -832,8 +831,7 @@ static int ac_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un
 		}
 		break;
 	default:
-		printk(KERN_INFO "APPLICOM driver ioctl, unknown function code %d\n",cmd) ;
-		ret = -EINVAL;
+		ret = -ENOTTY;
 		break;
 	}
 	Dummy = readb(apbs[IndexCard].RamIO + VERS);
author
#82 lore raw

PATCH 71/76 serial-make-uart_ports-ioport-unsigned-long-fix

In reply to Alan Cox

From: Andrew Morton <[email protected]>

---

 drivers/serial/serial_core.c |    5 ++---
 1 files changed, 2 insertions(+), 3 deletions(-)
drivers/serial/serial_core.c +2 -3
index f977c98..308588e 100644
@@ -2154,12 +2154,11 @@ uart_report_port(struct uart_driver *drv, struct uart_port *port)
 
 	switch (port->iotype) {
 	case UPIO_PORT:
-		snprintf(address, sizeof(address),
-			 "I/O 0x%x", port->iobase);
+		snprintf(address, sizeof(address), "I/O 0x%lx", port->iobase);
 		break;
 	case UPIO_HUB6:
 		snprintf(address, sizeof(address),
-			 "I/O 0x%x offset 0x%x", port->iobase, port->hub6);
+			 "I/O 0x%lx offset 0x%x", port->iobase, port->hub6);
 		break;
 	case UPIO_MEM:
 	case UPIO_MEM32:
author
#83 lore raw

PATCH 72/76 serial: allow 8250 to be used on sparc

In reply to Alan Cox

From: David Miller <[email protected]>

This requires three changes:

1) Remove !SPARC restriction in Kconfig.

2) Move Sparc specific serial drivers before 8250, so that serial console devices don't change names on us, even if 8250 finds devices.

3) Since the Sparc specific serial drivers try to use the same major/minor device namespace as 8250, some coordination is necessary. Use the sunserial_*() layer routines to allocate minor number space within TTY_MAJOR when CONFIG_SPARC.

This has no effect on other platforms.

Thanks to Josip Rodin for bringing up this issue and testing plus debugging various revisions of this patch.

---

 arch/sparc/include/asm/serial.h |    6 ++++++
 drivers/serial/8250.c           |   18 +++++++++++++++++-
 drivers/serial/Kconfig          |    1 -
 drivers/serial/Makefile         |   15 ++++++++++-----
 4 files changed, 33 insertions(+), 7 deletions(-)
 create mode 100644 arch/sparc/include/asm/serial.h
arch/sparc/include/asm/serial.h new file +6 -0
new file mode 100644
index 0000000..f90d61c
@@ -0,0 +1,6 @@
+#ifndef __SPARC_SERIAL_H
+#define __SPARC_SERIAL_H
+
+#define BASE_BAUD ( 1843200 / 16 )
+
+#endif /* __SPARC_SERIAL_H */
drivers/serial/8250.c +17 -1
index e898edf..c07afb2 100644
@@ -44,6 +44,10 @@
 
 #include "8250.h"
 
+#ifdef CONFIG_SPARC
+#include "suncore.h"
+#endif
+
 /*
  * Configuration:
  *   share_irqs - whether we pass IRQF_SHARED to request_irq().  This option
@@ -2721,7 +2725,6 @@ static struct uart_driver serial8250_reg = {
 	.dev_name		= "ttyS",
 	.major			= TTY_MAJOR,
 	.minor			= 64,
-	.nr			= UART_NR,
 	.cons			= SERIAL8250_CONSOLE,
 };
 
@@ -3003,7 +3006,12 @@ static int __init serial8250_init(void)
 		"%d ports, IRQ sharing %sabled\n", nr_uarts,
 		share_irqs ? "en" : "dis");
 
+#ifdef CONFIG_SPARC
+	ret = sunserial_register_minors(&serial8250_reg, UART_NR);
+#else
+	serial8250_reg.nr = UART_NR;
 	ret = uart_register_driver(&serial8250_reg);
+#endif
 	if (ret)
 		goto out;
 
@@ -3028,7 +3036,11 @@ static int __init serial8250_init(void)
 put_dev:
 	platform_device_put(serial8250_isa_devs);
 unreg_uart_drv:
+#ifdef CONFIG_SPARC
+	sunserial_unregister_minors(&serial8250_reg, UART_NR);
+#else
 	uart_unregister_driver(&serial8250_reg);
+#endif
 out:
 	return ret;
 }
@@ -3047,7 +3059,11 @@ static void __exit serial8250_exit(void)
 	platform_driver_unregister(&serial8250_isa_driver);
 	platform_device_unregister(isa_dev);
 
+#ifdef CONFIG_SPARC
+	sunserial_unregister_minors(&serial8250_reg, UART_NR);
+#else
 	uart_unregister_driver(&serial8250_reg);
+#endif
 }
 
 module_init(serial8250_init);
drivers/serial/Kconfig +0 -1
index 0db2045..31786b3 100644
@@ -9,7 +9,6 @@ menu "Serial drivers"
 # The new 8250/16550 serial drivers
 config SERIAL_8250
 	tristate "8250/16550 and compatible serial support"
-	depends on (BROKEN || !SPARC)
 	select SERIAL_CORE
 	---help---
 	  This selects whether you want to include the driver for the standard
drivers/serial/Makefile +10 -5
index 1462eb3..0c17c8d 100644
@@ -4,6 +4,16 @@
 
 obj-$(CONFIG_SERIAL_CORE) += serial_core.o
 obj-$(CONFIG_SERIAL_21285) += 21285.o
+
+# These Sparc drivers have to appear before others such as 8250
+# which share ttySx minor node space.  Otherwise console device
+# names change and other unplesantries.
+obj-$(CONFIG_SERIAL_SUNCORE) += suncore.o
+obj-$(CONFIG_SERIAL_SUNHV) += sunhv.o
+obj-$(CONFIG_SERIAL_SUNZILOG) += sunzilog.o
+obj-$(CONFIG_SERIAL_SUNSU) += sunsu.o
+obj-$(CONFIG_SERIAL_SUNSAB) += sunsab.o
+
 obj-$(CONFIG_SERIAL_8250) += 8250.o
 obj-$(CONFIG_SERIAL_8250_PNP) += 8250_pnp.o
 obj-$(CONFIG_SERIAL_8250_GSC) += 8250_gsc.o
@@ -31,12 +41,7 @@ obj-$(CONFIG_SERIAL_S3C2400) += s3c2400.o
 obj-$(CONFIG_SERIAL_S3C2410) += s3c2410.o
 obj-$(CONFIG_SERIAL_S3C2412) += s3c2412.o
 obj-$(CONFIG_SERIAL_S3C2440) += s3c2440.o
-obj-$(CONFIG_SERIAL_SUNCORE) += suncore.o
-obj-$(CONFIG_SERIAL_SUNHV) += sunhv.o
-obj-$(CONFIG_SERIAL_SUNZILOG) += sunzilog.o
 obj-$(CONFIG_SERIAL_IP22_ZILOG) += ip22zilog.o
-obj-$(CONFIG_SERIAL_SUNSU) += sunsu.o
-obj-$(CONFIG_SERIAL_SUNSAB) += sunsab.o
 obj-$(CONFIG_SERIAL_MUX) += mux.o
 obj-$(CONFIG_SERIAL_68328) += 68328serial.o
 obj-$(CONFIG_SERIAL_68360) += 68360serial.o
author
#84 lore raw

PATCH 73/76 serial: fix device name reporting when minor space is shared between drivers

In reply to Alan Cox

From: David S. Miller <[email protected]>

The multiple drivers share the minor space occupied by a particular major number, the actual index within the device name's space is indicated by the tty_driver->name_base + uart_port->line

Another usable formula is (uart_driver->minor - MINOR_BASE) + port->line

Use those to print the device names properly in such situations in serial_core.c and 8250.c

---

 drivers/serial/8250.c        |   22 +++++++++++++++-------
 drivers/serial/serial_core.c |    7 +++++--
 2 files changed, 20 insertions(+), 9 deletions(-)
drivers/serial/8250.c +15 -7
index c07afb2..b43dad6 100644
@@ -57,6 +57,13 @@ static unsigned int share_irqs = SERIAL8250_SHARE_IRQS;
 
 static unsigned int nr_uarts = CONFIG_SERIAL_8250_RUNTIME_UARTS;
 
+static struct uart_driver serial8250_reg;
+
+static int serial_index(struct uart_port *port)
+{
+	return (serial8250_reg.minor - 64) + port->line;
+}
+
 /*
  * Debugging.
  */
@@ -1001,7 +1008,7 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags)
 		return;
 
 	DEBUG_AUTOCONF("ttyS%d: autoconf (0x%04x, 0x%p): ",
-			up->port.line, up->port.iobase, up->port.membase);
+		       serial_index(&up->port), up->port.iobase, up->port.membase);
 
 	/*
 	 * We really do need global IRQs disabled here - we're going to
@@ -1136,8 +1143,8 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags)
 	if (up->capabilities != uart_config[up->port.type].flags) {
 		printk(KERN_WARNING
 		       "ttyS%d: detected caps %08x should be %08x\n",
-			up->port.line, up->capabilities,
-			uart_config[up->port.type].flags);
+		       serial_index(&up->port), up->capabilities,
+		       uart_config[up->port.type].flags);
 	}
 
 	up->port.fifosize = uart_config[up->port.type].fifo_size;
@@ -1902,7 +1909,8 @@ static int serial8250_startup(struct uart_port *port)
 	 */
 	if (!(up->port.flags & UPF_BUGGY_UART) &&
 	    (serial_inp(up, UART_LSR) == 0xff)) {
-		printk("ttyS%d: LSR safety check engaged!\n", up->port.line);
+		printk(KERN_INFO "ttyS%d: LSR safety check engaged!\n",
+		       serial_index(&up->port));
 		return -ENODEV;
 	}
 
@@ -1957,7 +1965,8 @@ static int serial8250_startup(struct uart_port *port)
 		 */
 		if (!(iir1 & UART_IIR_NO_INT) && (iir & UART_IIR_NO_INT)) {
 			up->bugs |= UART_BUG_THRE;
-			pr_debug("ttyS%d - using backup timer\n", port->line);
+			pr_debug("ttyS%d - using backup timer\n",
+				 serial_index(port));
 		}
 	}
 
@@ -2017,7 +2026,7 @@ static int serial8250_startup(struct uart_port *port)
 		if (!(up->bugs & UART_BUG_TXEN)) {
 			up->bugs |= UART_BUG_TXEN;
 			pr_debug("ttyS%d - enabling bad tx status workarounds\n",
-				 port->line);
+				 serial_index(port));
 		}
 	} else {
 		up->bugs &= ~UART_BUG_TXEN;
@@ -2678,7 +2687,6 @@ static int serial8250_console_early_setup(void)
 	return serial8250_find_port_for_earlycon();
 }
 
-static struct uart_driver serial8250_reg;
 static struct console serial8250_console = {
 	.name		= "ttyS",
 	.write		= serial8250_console_write,
drivers/serial/serial_core.c +5 -2
index 308588e..6bdf336 100644
@@ -2051,7 +2051,8 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *port)
 					"transmitter\n",
 			       port->dev ? port->dev->bus_id : "",
 			       port->dev ? ": " : "",
-			       drv->dev_name, port->line);
+			       drv->dev_name,
+			       drv->tty_driver->name_base + port->line);
 
 		ops->shutdown(port);
 	}
@@ -2176,7 +2177,9 @@ uart_report_port(struct uart_driver *drv, struct uart_port *port)
 	printk(KERN_INFO "%s%s%s%d at %s (irq = %d) is a %s\n",
 	       port->dev ? port->dev->bus_id : "",
 	       port->dev ? ": " : "",
-	       drv->dev_name, port->line, address, port->irq, uart_type(port));
+	       drv->dev_name,
+	       drv->tty_driver->name_base + port->line,
+	       address, port->irq, uart_type(port));
 }
 
 static void
author
#85 lore raw

PATCH 74/76 tty: tty_io.c shadows sparse fix

In reply to Alan Cox

From: Jason Wessel <[email protected]>

drivers/char/tty_io.c:1413:17: warning: symbol 'buf' shadows an earlier one drivers/char/tty_io.c:1379:20: originally declared here

---

 drivers/char/tty_io.c |    8 ++++----
 1 files changed, 4 insertions(+), 4 deletions(-)
drivers/char/tty_io.c +4 -4
index 502cad6..7053d63 100644
@@ -1026,19 +1026,19 @@ static inline ssize_t do_tty_write(
 
 	/* write_buf/write_cnt is protected by the atomic_write_lock mutex */
 	if (tty->write_cnt < chunk) {
-		unsigned char *buf;
+		unsigned char *buf_chunk;
 
 		if (chunk < 1024)
 			chunk = 1024;
 
-		buf = kmalloc(chunk, GFP_KERNEL);
-		if (!buf) {
+		buf_chunk = kmalloc(chunk, GFP_KERNEL);
+		if (!buf_chunk) {
 			ret = -ENOMEM;
 			goto out;
 		}
 		kfree(tty->write_buf);
 		tty->write_cnt = chunk;
-		tty->write_buf = buf;
+		tty->write_buf = buf_chunk;
 	}
 
 	/* Do the write .. */
author
#86 lore raw

PATCH 75/76 usb: fix pl2303 initialization

In reply to Alan Cox

From: Jason Wessel <[email protected]>

This patch removes the private check for the termios_initialized for the pl2303 usb driver. It forced the baud to 9600 on the first call to pl2303_set_termios()

Based on the tty changes in the 2.6.27 kernel, the termios passed to the *_set_termios functions is always populated the first time.

This means there is no need to privately initialize the settings the first time, and doing so will not allow the use of the kernel parameter "console=ttyUSB0,115200" as an example.

---

 drivers/usb/serial/pl2303.c |   11 -----------
 1 files changed, 0 insertions(+), 11 deletions(-)
drivers/usb/serial/pl2303.c +0 -11
index ba74424..9084378 100644
@@ -154,7 +154,6 @@ struct pl2303_private {
 	wait_queue_head_t delta_msr_wait;
 	u8 line_control;
 	u8 line_status;
-	u8 termios_initialized;
 	enum pl2303_type type;
 };
 
@@ -526,16 +525,6 @@ static void pl2303_set_termios(struct tty_struct *tty,
 
 	dbg("%s -  port %d", __func__, port->number);
 
-	spin_lock_irqsave(&priv->lock, flags);
-	if (!priv->termios_initialized) {
-		*(tty->termios) = tty_std_termios;
-		tty->termios->c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
-		tty->termios->c_ispeed = 9600;
-		tty->termios->c_ospeed = 9600;
-		priv->termios_initialized = 1;
-	}
-	spin_unlock_irqrestore(&priv->lock, flags);
-
 	/* The PL2303 is reported to lose bytes if you change
 	   serial settings even to the same values as before. Thus
 	   we actually need to filter in this specific case */
author
#87 lore raw

PATCH 76/76 ftdi: A few errors are err() that should be debug which causes much spewage

In reply to Alan Cox

Fixes #10783

---

 drivers/usb/serial/ftdi_sio.c |    6 +++---
 1 files changed, 3 insertions(+), 3 deletions(-)
drivers/usb/serial/ftdi_sio.c +3 -3
index 70a3719..c2ac129 100644
@@ -860,7 +860,7 @@ static int update_mctrl(struct usb_serial_port *port, unsigned int set,
 
 	kfree(buf);
 	if (rv < 0) {
-		err("%s Error from MODEM_CTRL urb: DTR %s, RTS %s",
+		dbg("%s Error from MODEM_CTRL urb: DTR %s, RTS %s",
 				__func__,
 				(set & TIOCM_DTR) ? "HIGH" :
 				(clear & TIOCM_DTR) ? "LOW" : "unchanged",
@@ -2259,7 +2259,7 @@ static int ftdi_tiocmget(struct tty_struct *tty, struct file *file)
 			   0, 0,
 			   buf, 1, WDR_TIMEOUT);
 		if (ret < 0) {
-			err("%s Could not get modem status of device - err: %d", __func__,
+			dbg("%s Could not get modem status of device - err: %d", __func__,
 			    ret);
 			return ret;
 		}
@@ -2278,7 +2278,7 @@ static int ftdi_tiocmget(struct tty_struct *tty, struct file *file)
 				   0, priv->interface,
 				   buf, 2, WDR_TIMEOUT);
 		if (ret < 0) {
-			err("%s Could not get modem status of device - err: %d", __func__,
+			dbg("%s Could not get modem status of device - err: %d", __func__,
 			    ret);
 			return ret;
 		}