firewire: core: extend card->lock in fw_core_handle_bus_reset
authorNiels Dossche <dossche.niels@gmail.com>
Sat, 9 Apr 2022 04:12:43 +0000 (13:12 +0900)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 12 May 2022 10:30:05 +0000 (12:30 +0200)
commit a7ecbe92b9243edbe94772f6f2c854e4142a3345 upstream.

card->local_node and card->bm_retries are both always accessed under
card->lock.
fw_core_handle_bus_reset has a check whose condition depends on
card->local_node and whose body writes to card->bm_retries.
Both of these accesses are not under card->lock. Move the lock acquiring
of card->lock to before this check such that these accesses do happen
when card->lock is held.
fw_destroy_nodes is called inside the check.
Since fw_destroy_nodes already acquires card->lock inside its function
body, move this out to the callsites of fw_destroy_nodes.
Also add a comment to indicate which locking is necessary when calling
fw_destroy_nodes.

Cc: <stable@vger.kernel.org>
Signed-off-by: Niels Dossche <dossche.niels@gmail.com>
Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
Link: https://lore.kernel.org/r/20220409041243.603210-4-o-takashi@sakamocchi.jp
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/firewire/core-card.c
drivers/firewire/core-topology.c

index 54be881..f3b3953 100644 (file)
@@ -668,6 +668,7 @@ EXPORT_SYMBOL_GPL(fw_card_release);
 void fw_core_remove_card(struct fw_card *card)
 {
        struct fw_card_driver dummy_driver = dummy_driver_template;
+       unsigned long flags;
 
        card->driver->update_phy_reg(card, 4,
                                     PHY_LINK_ACTIVE | PHY_CONTENDER, 0);
@@ -682,7 +683,9 @@ void fw_core_remove_card(struct fw_card *card)
        dummy_driver.stop_iso           = card->driver->stop_iso;
        card->driver = &dummy_driver;
 
+       spin_lock_irqsave(&card->lock, flags);
        fw_destroy_nodes(card);
+       spin_unlock_irqrestore(&card->lock, flags);
 
        /* Wait for all users, especially device workqueue jobs, to finish. */
        fw_card_put(card);
index b63d55f..f40c815 100644 (file)
@@ -375,16 +375,13 @@ static void report_found_node(struct fw_card *card,
        card->bm_retries = 0;
 }
 
+/* Must be called with card->lock held */
 void fw_destroy_nodes(struct fw_card *card)
 {
-       unsigned long flags;
-
-       spin_lock_irqsave(&card->lock, flags);
        card->color++;
        if (card->local_node != NULL)
                for_each_fw_node(card, card->local_node, report_lost_node);
        card->local_node = NULL;
-       spin_unlock_irqrestore(&card->lock, flags);
 }
 
 static void move_tree(struct fw_node *node0, struct fw_node *node1, int port)
@@ -510,6 +507,8 @@ void fw_core_handle_bus_reset(struct fw_card *card, int node_id, int generation,
        struct fw_node *local_node;
        unsigned long flags;
 
+       spin_lock_irqsave(&card->lock, flags);
+
        /*
         * If the selfID buffer is not the immediate successor of the
         * previously processed one, we cannot reliably compare the
@@ -521,8 +520,6 @@ void fw_core_handle_bus_reset(struct fw_card *card, int node_id, int generation,
                card->bm_retries = 0;
        }
 
-       spin_lock_irqsave(&card->lock, flags);
-
        card->broadcast_channel_allocated = card->broadcast_channel_auto_allocated;
        card->node_id = node_id;
        /*