summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitry Torokhov <dtor_core@ameritech.net>2003-12-18 05:31:47 -0800
committerDmitry Torokhov <dtor_core@ameritech.net>2003-12-18 05:31:47 -0800
commit94b49086bcdff836f86cb0dabc30a018af10672e (patch)
treea4a83cf35afa0e759cba48dd5ff92c8aa3e542e8
parent9c3faa99bb13924e38e1c3250e518e722edf7984 (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.c18
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);