diff options
| author | Dmitry Torokhov <dtor_core@ameritech.net> | 2003-12-18 05:31:47 -0800 |
|---|---|---|
| committer | Dmitry Torokhov <dtor_core@ameritech.net> | 2003-12-18 05:31:47 -0800 |
| commit | 94b49086bcdff836f86cb0dabc30a018af10672e (patch) | |
| tree | a4a83cf35afa0e759cba48dd5ff92c8aa3e542e8 | |
| parent | 9c3faa99bb13924e38e1c3250e518e722edf7984 (diff) | |
[PATCH] serio: possible race between port removal and kseriod
Input: There is a possibility that serio might get deleted while there
are outstanding events involving that serio waiting for kseriod
to process them. Invalidate them so kseriod thread will just
drop dead events.
| -rw-r--r-- | drivers/input/serio/serio.c | 18 |
1 files changed, 16 insertions, 2 deletions
diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c index 4f20e7eab7a8..225762d29bc4 100644 --- a/drivers/input/serio/serio.c +++ b/drivers/input/serio/serio.c @@ -87,6 +87,15 @@ static void serio_find_dev(struct serio *serio) static DECLARE_WAIT_QUEUE_HEAD(serio_wait); static DECLARE_COMPLETION(serio_exited); +static void serio_invalidate_pending_events(struct serio *serio) +{ + struct serio_event *event; + + list_for_each_entry(event, &serio_event_list, node) + if (event->serio == serio) + event->serio = NULL; +} + void serio_handle_events(void) { struct list_head *node, *next; @@ -95,17 +104,21 @@ void serio_handle_events(void) list_for_each_safe(node, next, &serio_event_list) { event = container_of(node, struct serio_event, node); + down(&serio_sem); + if (event->serio == NULL) + goto event_done; + switch (event->type) { case SERIO_RESCAN : - down(&serio_sem); if (event->serio->dev && event->serio->dev->disconnect) event->serio->dev->disconnect(event->serio); serio_find_dev(event->serio); - up(&serio_sem); break; default: break; } +event_done: + up(&serio_sem); list_del_init(node); kfree(event); } @@ -192,6 +205,7 @@ void serio_unregister_port(struct serio *serio) */ void __serio_unregister_port(struct serio *serio) { + serio_invalidate_pending_events(serio); list_del_init(&serio->node); if (serio->dev && serio->dev->disconnect) serio->dev->disconnect(serio); |
