Commit b50989dc444599c8b21edc23536fc305f4e9b7d5
Committed by
Live-CD User
1 parent
e936ffd5cb
Exists in
master
and in
7 other branches
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>
Showing 1 changed file with 16 additions and 3 deletions Side-by-side Diff
drivers/char/tty_io.c
... | ... | @@ -1386,10 +1386,14 @@ |
1386 | 1386 | * tty_mutex - sometimes only |
1387 | 1387 | * takes the file list lock internally when working on the list |
1388 | 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 | 1397 | struct tty_driver *driver = tty->driver; |
1394 | 1398 | |
1395 | 1399 | if (tty->ops->shutdown) |
... | ... | @@ -1407,6 +1411,15 @@ |
1407 | 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 | 1424 | * tty_kref_put - release a tty kref |
1412 | 1425 | * @tty: tty device |
... | ... | @@ -1418,7 +1431,7 @@ |
1418 | 1431 | void tty_kref_put(struct tty_struct *tty) |
1419 | 1432 | { |
1420 | 1433 | if (tty) |
1421 | - kref_put(&tty->kref, release_one_tty); | |
1434 | + kref_put(&tty->kref, queue_release_one_tty); | |
1422 | 1435 | } |
1423 | 1436 | EXPORT_SYMBOL(tty_kref_put); |
1424 | 1437 |