summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTakashi Sakamoto <o-takashi@sakamocchi.jp>2026-11-02 12:30:58 +0900
committerTakashi Sakamoto <o-takashi@sakamocchi.jp>2026-11-03 12:55:19 +0900
commit4acd5f806bf5569bfa3a45ea6a525936197df10c (patch)
tree0c7a62fc8f8232c41ba265757a4cdc324f6b5410
parent6628e7d4c6b25c8d18f1345e3a20d21829aae7e4 (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.c9
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)