aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char/tty_io.c
diff options
context:
space:
mode:
authorAlan Cox <alan@linux.intel.com>2009-09-19 16:13:22 -0400
committerLive-CD User <linux@linux.site>2009-09-19 16:13:22 -0400
commitb50989dc444599c8b21edc23536fc305f4e9b7d5 (patch)
tree9a340199b17a680ea41ac65bf5b8ff0c5d84cb14 /drivers/char/tty_io.c
parente936ffd5cb2b4c7ee04925c9b92b616c01f1e022 (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.c19
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 */
1390static void release_one_tty(struct kref *kref) 1393static 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
1414static 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)
1418void tty_kref_put(struct tty_struct *tty) 1431void 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}
1423EXPORT_SYMBOL(tty_kref_put); 1436EXPORT_SYMBOL(tty_kref_put);
1424 1437