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>
This commit is contained in:
parent
e936ffd5cb
commit
b50989dc44
1 changed files with 16 additions and 3 deletions
|
@ -1386,10 +1386,14 @@ EXPORT_SYMBOL(tty_shutdown);
|
||||||
* tty_mutex - sometimes only
|
* tty_mutex - sometimes only
|
||||||
* takes the file list lock internally when working on the list
|
* takes the file list lock internally when working on the list
|
||||||
* of ttys that the driver keeps.
|
* of ttys that the driver keeps.
|
||||||
|
*
|
||||||
|
* This method gets called from a work queue so that the driver private
|
||||||
|
* shutdown ops can sleep (needed for USB at least)
|
||||||
*/
|
*/
|
||||||
static void release_one_tty(struct kref *kref)
|
static void release_one_tty(struct work_struct *work)
|
||||||
{
|
{
|
||||||
struct tty_struct *tty = container_of(kref, struct tty_struct, kref);
|
struct tty_struct *tty =
|
||||||
|
container_of(work, struct tty_struct, hangup_work);
|
||||||
struct tty_driver *driver = tty->driver;
|
struct tty_driver *driver = tty->driver;
|
||||||
|
|
||||||
if (tty->ops->shutdown)
|
if (tty->ops->shutdown)
|
||||||
|
@ -1407,6 +1411,15 @@ static void release_one_tty(struct kref *kref)
|
||||||
free_tty_struct(tty);
|
free_tty_struct(tty);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void queue_release_one_tty(struct kref *kref)
|
||||||
|
{
|
||||||
|
struct tty_struct *tty = container_of(kref, struct tty_struct, kref);
|
||||||
|
/* The hangup queue is now free so we can reuse it rather than
|
||||||
|
waste a chunk of memory for each port */
|
||||||
|
INIT_WORK(&tty->hangup_work, release_one_tty);
|
||||||
|
schedule_work(&tty->hangup_work);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* tty_kref_put - release a tty kref
|
* tty_kref_put - release a tty kref
|
||||||
* @tty: tty device
|
* @tty: tty device
|
||||||
|
@ -1418,7 +1431,7 @@ static void release_one_tty(struct kref *kref)
|
||||||
void tty_kref_put(struct tty_struct *tty)
|
void tty_kref_put(struct tty_struct *tty)
|
||||||
{
|
{
|
||||||
if (tty)
|
if (tty)
|
||||||
kref_put(&tty->kref, release_one_tty);
|
kref_put(&tty->kref, queue_release_one_tty);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(tty_kref_put);
|
EXPORT_SYMBOL(tty_kref_put);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue