diff options
| author | Takashi Sakamoto <o-takashi@sakamocchi.jp> | 2026-11-02 12:30:58 +0900 |
|---|---|---|
| committer | Takashi Sakamoto <o-takashi@sakamocchi.jp> | 2026-11-03 12:55:19 +0900 |
| commit | 4acd5f806bf5569bfa3a45ea6a525936197df10c (patch) | |
| tree | 0c7a62fc8f8232c41ba265757a4cdc324f6b5410 | |
| parent | 6628e7d4c6b25c8d18f1345e3a20d21829aae7e4 (diff) | |
firewire: ohci: avoid potential deadlock when queueing AT local requests
AT local requests are retrieved from the queue in process context
(workqueue), while requests can be added to the queue from any context
through __fw_send_request(). The queue is protected by a spinlock, but
interrupts are still enabled when acquiring the lock in the former case.
This can lead to a deadlock if the same lock is acquired from interrupt
context while it is already held.
Avoid the deadlock by using a pair of spin_lock_irqsave() and
spin_unlock_irqrestore() to protect access to the queue.
Fixes: 5fe52c6aa28e ("firewire: ohci: use workqueue to handle error case of AT request/response packet queueing")
Link: https://lore.kernel.org/r/20261102033058.1184485-1-o-takashi@sakamocchi.jp
Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
| -rw-r--r-- | drivers/firewire/ohci.c | 9 |
1 files changed, 5 insertions, 4 deletions
diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c index c06e8d87239c..cf49910fa900 100644 --- a/drivers/firewire/ohci.c +++ b/drivers/firewire/ohci.c @@ -1593,12 +1593,13 @@ static void handle_at_local_packets(struct at_local *local, struct fw_ohci *ohci void (*handle_at_local_packet)(struct fw_ohci *, struct fw_packet *)) { struct fw_packet *packet; + unsigned long flags; - spin_lock(&local->lock); + spin_lock_irqsave(&local->lock, flags); while ((packet = list_first_entry_or_null(&local->list, typeof(*packet), link_for_local))) { list_del_init(&packet->link_for_local); - spin_unlock(&local->lock); + spin_unlock_irqrestore(&local->lock, flags); if (unlikely(packet->ack != 0)) { // This case is active when the call of at_context_queue_packet() returns @@ -1608,10 +1609,10 @@ static void handle_at_local_packets(struct at_local *local, struct fw_ohci *ohci handle_at_local_packet(ohci, packet); } - spin_lock(&local->lock); + spin_lock_irqsave(&local->lock, flags); } - spin_unlock(&local->lock); + spin_unlock_irqrestore(&local->lock, flags); } static void at_request_local_work(struct work_struct *work) |
