Skip to content

Commit 0ccf091

Browse files
author
Jiri Kosina
committed
HID: sensor-hub: make dyn_callback_lock IRQ-safe
dyn_callback_lock is being taken from IRQ context through hid_irq_in() -> hid_input_report() -> sensor_hub_raw_event() -> sensor_hub_get_callback(), therefore anyone else acquiring it needs to disable IRQs to disable deadlocks. Reported-by: Alexander Holler <holler@ahsoftware.de> Tested-by: Alexander Holler <holler@ahsoftware.de> Reported-by: Reyad Attiyat <reyad.attiyat@gmail.com> Signed-off-by: Jiri Kosina <jkosina@suse.cz>
1 parent d6b92c2 commit 0ccf091

File tree

1 file changed

+14
-10
lines changed

1 file changed

+14
-10
lines changed

drivers/hid/hid-sensor-hub.c

+14-10
Original file line numberDiff line numberDiff line change
@@ -159,25 +159,26 @@ int sensor_hub_register_callback(struct hid_sensor_hub_device *hsdev,
159159
{
160160
struct hid_sensor_hub_callbacks_list *callback;
161161
struct sensor_hub_data *pdata = hid_get_drvdata(hsdev->hdev);
162+
unsigned long flags;
162163

163-
spin_lock(&pdata->dyn_callback_lock);
164+
spin_lock_irqsave(&pdata->dyn_callback_lock, flags);
164165
list_for_each_entry(callback, &pdata->dyn_callback_list, list)
165166
if (callback->usage_id == usage_id &&
166167
callback->hsdev == hsdev) {
167-
spin_unlock(&pdata->dyn_callback_lock);
168+
spin_unlock_irqrestore(&pdata->dyn_callback_lock, flags);
168169
return -EINVAL;
169170
}
170171
callback = kzalloc(sizeof(*callback), GFP_ATOMIC);
171172
if (!callback) {
172-
spin_unlock(&pdata->dyn_callback_lock);
173+
spin_unlock_irqrestore(&pdata->dyn_callback_lock, flags);
173174
return -ENOMEM;
174175
}
175176
callback->hsdev = hsdev;
176177
callback->usage_callback = usage_callback;
177178
callback->usage_id = usage_id;
178179
callback->priv = NULL;
179180
list_add_tail(&callback->list, &pdata->dyn_callback_list);
180-
spin_unlock(&pdata->dyn_callback_lock);
181+
spin_unlock_irqrestore(&pdata->dyn_callback_lock, flags);
181182

182183
return 0;
183184
}
@@ -188,16 +189,17 @@ int sensor_hub_remove_callback(struct hid_sensor_hub_device *hsdev,
188189
{
189190
struct hid_sensor_hub_callbacks_list *callback;
190191
struct sensor_hub_data *pdata = hid_get_drvdata(hsdev->hdev);
192+
unsigned long flags;
191193

192-
spin_lock(&pdata->dyn_callback_lock);
194+
spin_lock_irqsave(&pdata->dyn_callback_lock, flags);
193195
list_for_each_entry(callback, &pdata->dyn_callback_list, list)
194196
if (callback->usage_id == usage_id &&
195197
callback->hsdev == hsdev) {
196198
list_del(&callback->list);
197199
kfree(callback);
198200
break;
199201
}
200-
spin_unlock(&pdata->dyn_callback_lock);
202+
spin_unlock_irqrestore(&pdata->dyn_callback_lock, flags);
201203

202204
return 0;
203205
}
@@ -378,15 +380,16 @@ static int sensor_hub_suspend(struct hid_device *hdev, pm_message_t message)
378380
{
379381
struct sensor_hub_data *pdata = hid_get_drvdata(hdev);
380382
struct hid_sensor_hub_callbacks_list *callback;
383+
unsigned long flags;
381384

382385
hid_dbg(hdev, " sensor_hub_suspend\n");
383-
spin_lock(&pdata->dyn_callback_lock);
386+
spin_lock_irqsave(&pdata->dyn_callback_lock, flags);
384387
list_for_each_entry(callback, &pdata->dyn_callback_list, list) {
385388
if (callback->usage_callback->suspend)
386389
callback->usage_callback->suspend(
387390
callback->hsdev, callback->priv);
388391
}
389-
spin_unlock(&pdata->dyn_callback_lock);
392+
spin_unlock_irqrestore(&pdata->dyn_callback_lock, flags);
390393

391394
return 0;
392395
}
@@ -395,15 +398,16 @@ static int sensor_hub_resume(struct hid_device *hdev)
395398
{
396399
struct sensor_hub_data *pdata = hid_get_drvdata(hdev);
397400
struct hid_sensor_hub_callbacks_list *callback;
401+
unsigned long flags;
398402

399403
hid_dbg(hdev, " sensor_hub_resume\n");
400-
spin_lock(&pdata->dyn_callback_lock);
404+
spin_lock_irqsave(&pdata->dyn_callback_lock, flags);
401405
list_for_each_entry(callback, &pdata->dyn_callback_list, list) {
402406
if (callback->usage_callback->resume)
403407
callback->usage_callback->resume(
404408
callback->hsdev, callback->priv);
405409
}
406-
spin_unlock(&pdata->dyn_callback_lock);
410+
spin_unlock_irqrestore(&pdata->dyn_callback_lock, flags);
407411

408412
return 0;
409413
}

0 commit comments

Comments
 (0)