mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
firewire: core: consolidate lock scopes for event waiting in dequeue function
Current implementation uses the spinlock in the card structure to serialize accesses to the event list. The dequeue_event() function yields the CPU while waiting for the condition to become true, but checks the list without acquiring the spinlock. It acquires the spinlock when operating the list, however it assumes that the list has at least one entry. This can cause problems when multiple threads execute read(2) system calls concurrently, since the list can become empty after rescheduling but before the list operation, depending on the scheduling order of the two threads. Use a wait_event variant that reacquires the lock after being rescheduled, before checking the condition. Link: https://lore.kernel.org/r/20260920104745.212753-1-o-takashi@sakamocchi.jp Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
This commit is contained in:
parent
ab2a823af3
commit
e64f2d4de1
|
|
@ -356,19 +356,27 @@ static int dequeue_event(struct client *client,
|
|||
size_t size, total;
|
||||
int i, ret;
|
||||
|
||||
ret = wait_event_interruptible(client->wait,
|
||||
!list_empty(&client->event_list) ||
|
||||
fw_device_is_shutdown(client->device));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
// After the following block, the event pointer above is guaranteed to have a correct value.
|
||||
{
|
||||
spin_lock_irq(&client->lock);
|
||||
|
||||
if (list_empty(&client->event_list) &&
|
||||
fw_device_is_shutdown(client->device))
|
||||
return -ENODEV;
|
||||
int ret = wait_event_interruptible_lock_irq(client->wait,
|
||||
!list_empty(&client->event_list) || fw_device_is_shutdown(client->device),
|
||||
client->lock);
|
||||
if (ret < 0) {
|
||||
spin_unlock_irq(&client->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (fw_device_is_shutdown(client->device)) {
|
||||
spin_unlock_irq(&client->lock);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
scoped_guard(spinlock_irq, &client->lock) {
|
||||
event = list_first_entry(&client->event_list, struct event, link);
|
||||
list_del(&event->link);
|
||||
|
||||
spin_unlock_irq(&client->lock);
|
||||
}
|
||||
|
||||
total = 0;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user