Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

tty: Fix regressions caused by commit b50989dc

The following commit made console open fails while booting:

commit b50989dc444599c8b21edc23536fc305f4e9b7d5
Author: Alan Cox <alan@linux.intel.com>
Date: Sat Sep 19 13:13:22 2009 -0700

tty: make the kref destructor occur asynchronously

Due to tty release routines run in a workqueue now, error like the
following will be reported while booting:

INIT open /dev/console Input/output error

It also causes hibernation regression to appear as reported at
http://bugzilla.kernel.org/show_bug.cgi?id=14229

The reason is that now there's latency issue with closing, but when
we open a "closing not finished" tty, -EIO will be returned.

Fix it as per the following Alan's suggestion:

Fun but it's actually not a bug and the fix is wrong in itself as
the port may be closing but not yet being destructed, in which case
it seems to do the wrong thing. Opening a tty that is closing (and
could be closing for long periods) is supposed to return -EIO.

I suspect a better way to deal with this and keep the old console
timing is to split tty->shutdown into two functions.

tty->shutdown() - called synchronously just before we dump the tty
onto the waitqueue for destruction

tty->cleanup() - called when the destructor runs.

We would then do the shutdown part which can occur in IRQ context
fine, before queueing the rest of the release (from tty->magic = 0
... the end) to occur asynchronously

The USB update in -next would then need a call like

if (tty->cleanup)
tty->cleanup(tty);

at the top of the async function and the USB shutdown to be split
between shutdown and cleanup as the USB resource cleanup and final
tidy cannot occur synchronously as it needs to sleep.

In other words the logic becomes

final kref put
make object unfindable

async
clean it up

Signed-off-by: Dave Young <hidave.darkstar@gmail.com>
[ rjw: Rebased on top of 2.6.31-git, reworked the changelog. ]
Signed-off-by: "Rafael J. Wysocki" <rjw@sisk.pl>
[ Changed serial naming to match new rules, dropped tty_shutdown as per
comments from Alan Stern - Linus ]
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Dave Young and committed by
Linus Torvalds
f278a2f7 569ec4cc

+27 -15
+10 -5
drivers/char/tty_io.c
··· 1389 1389 * of ttys that the driver keeps. 1390 1390 * 1391 1391 * This method gets called from a work queue so that the driver private 1392 - * shutdown ops can sleep (needed for USB at least) 1392 + * cleanup ops can sleep (needed for USB at least) 1393 1393 */ 1394 1394 static void release_one_tty(struct work_struct *work) 1395 1395 { ··· 1397 1397 container_of(work, struct tty_struct, hangup_work); 1398 1398 struct tty_driver *driver = tty->driver; 1399 1399 1400 - if (tty->ops->shutdown) 1401 - tty->ops->shutdown(tty); 1402 - else 1403 - tty_shutdown(tty); 1400 + if (tty->ops->cleanup) 1401 + tty->ops->cleanup(tty); 1402 + 1404 1403 tty->magic = 0; 1405 1404 tty_driver_kref_put(driver); 1406 1405 module_put(driver->owner); ··· 1414 1415 static void queue_release_one_tty(struct kref *kref) 1415 1416 { 1416 1417 struct tty_struct *tty = container_of(kref, struct tty_struct, kref); 1418 + 1419 + if (tty->ops->shutdown) 1420 + tty->ops->shutdown(tty); 1421 + else 1422 + tty_shutdown(tty); 1423 + 1417 1424 /* The hangup queue is now free so we can reuse it rather than 1418 1425 waste a chunk of memory for each port */ 1419 1426 INIT_WORK(&tty->hangup_work, release_one_tty);
+6 -8
drivers/usb/serial/usb-serial.c
··· 192 192 * This is the first place a new tty gets used. Hence this is where we 193 193 * acquire references to the usb_serial structure and the driver module, 194 194 * where we store a pointer to the port, and where we do an autoresume. 195 - * All these actions are reversed in serial_release(). 195 + * All these actions are reversed in serial_cleanup(). 196 196 */ 197 197 static int serial_install(struct tty_driver *driver, struct tty_struct *tty) 198 198 { ··· 339 339 } 340 340 341 341 /** 342 - * serial_release - free resources post close/hangup 342 + * serial_cleanup - free resources post close/hangup 343 343 * @port: port to free up 344 344 * 345 345 * Do the resource freeing and refcount dropping for the port. 346 346 * Avoid freeing the console. 347 347 * 348 - * Called when the last tty kref is dropped. 348 + * Called asynchronously after the last tty kref is dropped, 349 + * and the tty layer has already done the tty_shutdown(tty); 349 350 */ 350 - static void serial_release(struct tty_struct *tty) 351 + static void serial_cleanup(struct tty_struct *tty) 351 352 { 352 353 struct usb_serial_port *port = tty->driver_data; 353 354 struct usb_serial *serial; ··· 361 360 return; 362 361 363 362 dbg("%s - port %d", __func__, port->number); 364 - 365 - /* Standard shutdown processing */ 366 - tty_shutdown(tty); 367 363 368 364 tty->driver_data = NULL; 369 365 ··· 1208 1210 .chars_in_buffer = serial_chars_in_buffer, 1209 1211 .tiocmget = serial_tiocmget, 1210 1212 .tiocmset = serial_tiocmset, 1211 - .shutdown = serial_release, 1213 + .cleanup = serial_cleanup, 1212 1214 .install = serial_install, 1213 1215 .proc_fops = &serial_proc_fops, 1214 1216 };
+11 -2
include/linux/tty_driver.h
··· 45 45 * 46 46 * void (*shutdown)(struct tty_struct * tty); 47 47 * 48 - * This routine is called when a particular tty device is closed for 49 - * the last time freeing up the resources. 48 + * This routine is called synchronously when a particular tty device 49 + * is closed for the last time freeing up the resources. 50 + * 51 + * 52 + * void (*cleanup)(struct tty_struct * tty); 53 + * 54 + * This routine is called asynchronously when a particular tty device 55 + * is closed for the last time freeing up the resources. This is 56 + * actually the second part of shutdown for routines that might sleep. 57 + * 50 58 * 51 59 * int (*write)(struct tty_struct * tty, 52 60 * const unsigned char *buf, int count); ··· 241 233 int (*open)(struct tty_struct * tty, struct file * filp); 242 234 void (*close)(struct tty_struct * tty, struct file * filp); 243 235 void (*shutdown)(struct tty_struct *tty); 236 + void (*cleanup)(struct tty_struct *tty); 244 237 int (*write)(struct tty_struct * tty, 245 238 const unsigned char *buf, int count); 246 239 int (*put_char)(struct tty_struct *tty, unsigned char ch);