Commit 9a6b1efa authored by Aristeu Rozanski's avatar Aristeu Rozanski Committed by Greg Kroah-Hartman

USB: usb_serial: clean tty reference in the last close

When a usb serial adapter is used as console, the usb serial console
driver bumps the open_count on the port struct used but doesn't attach
a real tty to it (only a fake one temporaly). If this port is opened later
using the regular character device interface, the open method won't
initialize the port, which is the expected, and will receive a brand new
tty struct created by tty layer, which will be stored in port->tty.

When the last close is issued, open_count won't be 0 because of the
console usage and the port->tty will still contain the old tty value. This
is the last ttyUSB<n> close so the allocated tty will be freed by the
tty layer. The usb_serial and usb_serial_port are still in use by the
console, so port_free() won't be called (serial_close() ->
usb_serial_put() -> destroy_serial() -> port_free()), so the scheduled
work (port->work, usb_serial_port_work()) will still run. And
usb_serial_port_work() does:
(...)
        tty = port->tty;
        if (!tty)
                return;

        tty_wakeup(tty);
which causes (manually copied):

Faulting instruction address: 0x6b6b6b68
Oops: Kernel access of bad area, sig: 11 [#1]
PREEMPT PowerMac
Modules linked in: binfmt_misc ipv6 nfs lockd nfs_acl sunrpc dm_snapshot dm_mirror dm_mod hfsplus uinput ams input_polldev genrtc cpufreq_powersave i2c_powermac therm_adt746x snd_aoa_codec_tas snd_aoa_fabric_layout snd_aoa joydev snd_aoa_i2sbus snd_pcm_oss snd_mixer_oss snd_pcm snd_timer snd_page_alloc pmac_zilog serial_core evdev ide_cd cdrom snd appletouch soundcore snd_aoa_soundbus bcm43xx firmware_class usbhid ieee80211softmac ff_memless firewire_ohci firewire_core ieee80211 ieee80211_crypt crc_itu_t sungem sungem_phy uninorth_agp agpart ssb
NIP: 6b6b6b68 LR: c01b2108 CTR: 6b6b6b6b
REGS: c106de80 TRAP: 0400   Not tainted  (2.6.24-rc2)
MSR: 40009032 <EE,ME,IR,DR>  CR: 82004024  XER: 00000000
TASK = c106b4c0[5] 'events/0' THREAD: c106c000
GPR00: 6b6b6b6b c106df30 c106b4c0 c2d613a0 00009032 00000001 00001a00 00000001
GPR08: 00000008 00000000 00000000 c106c000 42004028 00000000 016ffbe0 0171a724
GPR16: 016ffcf4 00240e24 00240e70 016fee68 016ff9a4 c03046c4 c0327f50 c03046fc
GPR24: c106b6b9 c106b4c0 c101d610 c106c000 c02160fc c1eac1dc c2d613ac c2d613a0
NIP [6b6b6b68] 0x6b6b6b68
LR [c01b2108] tty_wakeup+0x6c/0x9c
Call Trace:
[c106df30] [c01b20e8] tty_wakeup+0x4c/0x9c (unreliable)
[c106df40] [c0216138] usb_serial_port_work+0x3c/0x78
[c106df50] [c00432e8] run_workqueue+0xc4/0x15c
[c106df90] [c0043798] worker_thread+0xa0/0x124
[c106dfd0] [c0048224] kthread+0x48/0x84
[c106dff0] [c00129bc] kernel_thread+0x44/0x60
Instruction dump:
XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX
XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX
Slab corruption: size-2048 start=c2d613a0, len=2048
Redzone: 0x9f911029d74e35b/0x9f911029d74e35b.
Last user: [<c01b16d8>](release_one_tty+0xbc/0xf4)
050: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b
Prev obj: start=c2d60b88, len=2048
Redzone: 0x9f911029d74e35b/0x9f911029d74e35b.
Last user: [<c00f30ec>](show_stat+0x410/0x428)
000: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b
010: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b

This patch avoids this, clearing port->tty considering if the port is
used as serial console or not
Signed-off-by: default avatarAristeu Rozanski <arozansk@redhat.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 27680d23
...@@ -192,8 +192,9 @@ static int usb_console_setup(struct console *co, char *options) ...@@ -192,8 +192,9 @@ static int usb_console_setup(struct console *co, char *options)
kfree (termios); kfree (termios);
kfree (tty); kfree (tty);
} }
port->console = 1;
return retval; return 0;
} }
static void usb_console_write(struct console *co, const char *buf, unsigned count) static void usb_console_write(struct console *co, const char *buf, unsigned count)
......
...@@ -264,19 +264,21 @@ static void serial_close(struct tty_struct *tty, struct file * filp) ...@@ -264,19 +264,21 @@ static void serial_close(struct tty_struct *tty, struct file * filp)
} }
--port->open_count; --port->open_count;
if (port->open_count == 0) { if (port->open_count == 0)
/* only call the device specific close if this /* only call the device specific close if this
* port is being closed by the last owner */ * port is being closed by the last owner */
port->serial->type->close(port, filp); port->serial->type->close(port, filp);
if (port->open_count == (port->console? 1 : 0)) {
if (port->tty) { if (port->tty) {
if (port->tty->driver_data) if (port->tty->driver_data)
port->tty->driver_data = NULL; port->tty->driver_data = NULL;
port->tty = NULL; port->tty = NULL;
} }
}
if (port->open_count == 0)
module_put(port->serial->type->driver.owner); module_put(port->serial->type->driver.owner);
}
mutex_unlock(&port->mutex); mutex_unlock(&port->mutex);
usb_serial_put(port->serial); usb_serial_put(port->serial);
......
...@@ -92,6 +92,7 @@ struct usb_serial_port { ...@@ -92,6 +92,7 @@ struct usb_serial_port {
int open_count; int open_count;
char throttled; char throttled;
char throttle_req; char throttle_req;
char console;
struct device dev; struct device dev;
}; };
#define to_usb_serial_port(d) container_of(d, struct usb_serial_port, dev) #define to_usb_serial_port(d) container_of(d, struct usb_serial_port, dev)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment