aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAristeu Rozanski <aris@ruivo.org>2007-11-12 15:15:02 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2008-02-01 17:34:50 -0500
commit9a6b1efa6fd1ee022fdf42c91a9868c589cc95b7 (patch)
tree4ffc94dfd9fe3c2bd4723687bca32be795a59102
parent27680d232b04d434d8d49a8417429b9512ffb7c6 (diff)
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: Aristeu Rozanski <arozansk@redhat.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r--drivers/usb/serial/console.c3
-rw-r--r--drivers/usb/serial/usb-serial.c6
-rw-r--r--include/linux/usb/serial.h1
3 files changed, 7 insertions, 3 deletions
diff --git a/drivers/usb/serial/console.c b/drivers/usb/serial/console.c
index 72ab3bbf0f2e..04007c31d88d 100644
--- a/drivers/usb/serial/console.c
+++ b/drivers/usb/serial/console.c
@@ -192,8 +192,9 @@ static int usb_console_setup(struct console *co, char *options)
192 kfree (termios); 192 kfree (termios);
193 kfree (tty); 193 kfree (tty);
194 } 194 }
195 port->console = 1;
195 196
196 return retval; 197 return 0;
197} 198}
198 199
199static void usb_console_write(struct console *co, const char *buf, unsigned count) 200static void usb_console_write(struct console *co, const char *buf, unsigned count)
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
index 497e29a700ca..5c33e2471be8 100644
--- a/drivers/usb/serial/usb-serial.c
+++ b/drivers/usb/serial/usb-serial.c
@@ -264,19 +264,21 @@ static void serial_close(struct tty_struct *tty, struct file * filp)
264 } 264 }
265 265
266 --port->open_count; 266 --port->open_count;
267 if (port->open_count == 0) { 267 if (port->open_count == 0)
268 /* only call the device specific close if this 268 /* only call the device specific close if this
269 * port is being closed by the last owner */ 269 * port is being closed by the last owner */
270 port->serial->type->close(port, filp); 270 port->serial->type->close(port, filp);
271 271
272 if (port->open_count == (port->console? 1 : 0)) {
272 if (port->tty) { 273 if (port->tty) {
273 if (port->tty->driver_data) 274 if (port->tty->driver_data)
274 port->tty->driver_data = NULL; 275 port->tty->driver_data = NULL;
275 port->tty = NULL; 276 port->tty = NULL;
276 } 277 }
278 }
277 279
280 if (port->open_count == 0)
278 module_put(port->serial->type->driver.owner); 281 module_put(port->serial->type->driver.owner);
279 }
280 282
281 mutex_unlock(&port->mutex); 283 mutex_unlock(&port->mutex);
282 usb_serial_put(port->serial); 284 usb_serial_put(port->serial);
diff --git a/include/linux/usb/serial.h b/include/linux/usb/serial.h
index 488ce128885c..ef1e430f7bfa 100644
--- a/include/linux/usb/serial.h
+++ b/include/linux/usb/serial.h
@@ -92,6 +92,7 @@ struct usb_serial_port {
92 int open_count; 92 int open_count;
93 char throttled; 93 char throttled;
94 char throttle_req; 94 char throttle_req;
95 char console;
95 struct device dev; 96 struct device dev;
96}; 97};
97#define to_usb_serial_port(d) container_of(d, struct usb_serial_port, dev) 98#define to_usb_serial_port(d) container_of(d, struct usb_serial_port, dev)