diff options
author | Alan Cox <alan@linux.intel.com> | 2009-09-19 16:13:22 -0400 |
---|---|---|
committer | Live-CD User <linux@linux.site> | 2009-09-19 16:13:22 -0400 |
commit | b50989dc444599c8b21edc23536fc305f4e9b7d5 (patch) | |
tree | 9a340199b17a680ea41ac65bf5b8ff0c5d84cb14 /drivers/char/tty_io.c | |
parent | e936ffd5cb2b4c7ee04925c9b92b616c01f1e022 (diff) |
tty: make the kref destructor occur asynchronously
We want to be able to sleep in the destructor for USB at least. It isn't a
hot path so just pushing it to a work queue doesn't really cause any
difficulty.
Signed-off-by: Alan Cox <alan@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/char/tty_io.c')
-rw-r--r-- | drivers/char/tty_io.c | 19 |
1 files changed, 16 insertions, 3 deletions
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index 938448067738..385cca7074da 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c | |||
@@ -1386,10 +1386,14 @@ EXPORT_SYMBOL(tty_shutdown); | |||
1386 | * tty_mutex - sometimes only | 1386 | * tty_mutex - sometimes only |
1387 | * takes the file list lock internally when working on the list | 1387 | * takes the file list lock internally when working on the list |
1388 | * of ttys that the driver keeps. | 1388 | * of ttys that the driver keeps. |
1389 | * | ||
1390 | * This method gets called from a work queue so that the driver private | ||
1391 | * shutdown ops can sleep (needed for USB at least) | ||
1389 | */ | 1392 | */ |
1390 | static void release_one_tty(struct kref *kref) | 1393 | static void release_one_tty(struct work_struct *work) |
1391 | { | 1394 | { |
1392 | struct tty_struct *tty = container_of(kref, struct tty_struct, kref); | 1395 | struct tty_struct *tty = |
1396 | container_of(work, struct tty_struct, hangup_work); | ||
1393 | struct tty_driver *driver = tty->driver; | 1397 | struct tty_driver *driver = tty->driver; |
1394 | 1398 | ||
1395 | if (tty->ops->shutdown) | 1399 | if (tty->ops->shutdown) |
@@ -1407,6 +1411,15 @@ static void release_one_tty(struct kref *kref) | |||
1407 | free_tty_struct(tty); | 1411 | free_tty_struct(tty); |
1408 | } | 1412 | } |
1409 | 1413 | ||
1414 | static void queue_release_one_tty(struct kref *kref) | ||
1415 | { | ||
1416 | struct tty_struct *tty = container_of(kref, struct tty_struct, kref); | ||
1417 | /* The hangup queue is now free so we can reuse it rather than | ||
1418 | waste a chunk of memory for each port */ | ||
1419 | INIT_WORK(&tty->hangup_work, release_one_tty); | ||
1420 | schedule_work(&tty->hangup_work); | ||
1421 | } | ||
1422 | |||
1410 | /** | 1423 | /** |
1411 | * tty_kref_put - release a tty kref | 1424 | * tty_kref_put - release a tty kref |
1412 | * @tty: tty device | 1425 | * @tty: tty device |
@@ -1418,7 +1431,7 @@ static void release_one_tty(struct kref *kref) | |||
1418 | void tty_kref_put(struct tty_struct *tty) | 1431 | void tty_kref_put(struct tty_struct *tty) |
1419 | { | 1432 | { |
1420 | if (tty) | 1433 | if (tty) |
1421 | kref_put(&tty->kref, release_one_tty); | 1434 | kref_put(&tty->kref, queue_release_one_tty); |
1422 | } | 1435 | } |
1423 | EXPORT_SYMBOL(tty_kref_put); | 1436 | EXPORT_SYMBOL(tty_kref_put); |
1424 | 1437 | ||