Input: serio_raw - perform proper locking when adding clients to list
Make sure we hold serio lock when adding clients to client list so that we do not race with serio_raw_release() removing clients from the same list. Reviewed-by: Wanlong Gao <gaowanlong@cn.fujitsu.com> Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
This commit is contained in:
@@ -106,7 +106,10 @@ static int serio_raw_open(struct inode *inode, struct file *file)
|
|||||||
file->private_data = client;
|
file->private_data = client;
|
||||||
|
|
||||||
kref_get(&serio_raw->kref);
|
kref_get(&serio_raw->kref);
|
||||||
|
|
||||||
|
serio_pause_rx(serio_raw->serio);
|
||||||
list_add_tail(&client->node, &serio_raw->client_list);
|
list_add_tail(&client->node, &serio_raw->client_list);
|
||||||
|
serio_continue_rx(serio_raw->serio);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
mutex_unlock(&serio_raw_mutex);
|
mutex_unlock(&serio_raw_mutex);
|
||||||
@@ -138,10 +141,9 @@ static int serio_raw_release(struct inode *inode, struct file *file)
|
|||||||
|
|
||||||
static int serio_raw_fetch_byte(struct serio_raw *serio_raw, char *c)
|
static int serio_raw_fetch_byte(struct serio_raw *serio_raw, char *c)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
|
||||||
int empty;
|
int empty;
|
||||||
|
|
||||||
spin_lock_irqsave(&serio_raw->serio->lock, flags);
|
serio_pause_rx(serio_raw->serio);
|
||||||
|
|
||||||
empty = serio_raw->head == serio_raw->tail;
|
empty = serio_raw->head == serio_raw->tail;
|
||||||
if (!empty) {
|
if (!empty) {
|
||||||
@@ -149,7 +151,7 @@ static int serio_raw_fetch_byte(struct serio_raw *serio_raw, char *c)
|
|||||||
serio_raw->tail = (serio_raw->tail + 1) % SERIO_RAW_QUEUE_LEN;
|
serio_raw->tail = (serio_raw->tail + 1) % SERIO_RAW_QUEUE_LEN;
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_unlock_irqrestore(&serio_raw->serio->lock, flags);
|
serio_continue_rx(serio_raw->serio);
|
||||||
|
|
||||||
return !empty;
|
return !empty;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user