]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph-client.git/commitdiff
fbnic: close fw_log race between users and teardown
authorChengfeng Ye <dg573847474@gmail.com>
Wed, 11 Feb 2026 19:13:29 +0000 (19:13 +0000)
committerJakub Kicinski <kuba@kernel.org>
Fri, 13 Feb 2026 20:30:28 +0000 (12:30 -0800)
Fixes a theoretical race on fw_log between the teardown path and fw_log
write functions.

fw_log is written inside fbnic_fw_log_write() and can be reached from
the mailbox handler fbnic_fw_msix_intr(), but fw_log is freed before
IRQ/MBX teardown during cleanup, resulting in a potential data race of
dereferencing a freed/null variable.

Possible Interleaving Scenario:
  CPU0: fbnic_fw_msix_intr() // Entry
          fbnic_fw_log_write()
            if (fbnic_fw_log_ready())   // true
            ... preempt ...
  CPU1: fbnic_remove() // Entry
          fbnic_fw_log_free()
            vfree(log->data_start);
            log->data_start = NULL;
  CPU0: continues, walks log->entries or writes to log->data_start

The initialization also has an incorrect order problem, as the fw_log
is currently allocated after MBX setup during initialization.
Fix the problems by adjusting the synchronization order to put
initialization in place before the mailbox is enabled, and not cleared
until after the mailbox has been disabled.

Fixes: ecc53b1b46c89 ("eth: fbnic: Enable firmware logging")
Signed-off-by: Chengfeng Ye <dg573847474@gmail.com>
Link: https://patch.msgid.link/20260211191329.530886-1-dg573847474@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/net/ethernet/meta/fbnic/fbnic_fw_log.c
drivers/net/ethernet/meta/fbnic/fbnic_pci.c

index 85a883dba385fe9e371de5b90a2c6265d38b0a6c..d8a9a7d7c2375ff5fdde9e357de848ec6e10ba5f 100644 (file)
@@ -51,8 +51,6 @@ int fbnic_fw_log_init(struct fbnic_dev *fbd)
        log->data_start = data;
        log->data_end = data + FBNIC_FW_LOG_SIZE;
 
-       fbnic_fw_log_enable(fbd, true);
-
        return 0;
 }
 
@@ -63,7 +61,6 @@ void fbnic_fw_log_free(struct fbnic_dev *fbd)
        if (!fbnic_fw_log_ready(fbd))
                return;
 
-       fbnic_fw_log_disable(fbd);
        INIT_LIST_HEAD(&log->entries);
        log->size = 0;
        vfree(log->data_start);
index 6f9389748a7d90112bf804ca8dfa8f00882a893e..3fa9d1910daa1ec273b9a9a2bd27754b8640d6f5 100644 (file)
@@ -311,11 +311,17 @@ static int fbnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                goto free_irqs;
        }
 
+       err = fbnic_fw_log_init(fbd);
+       if (err)
+               dev_warn(fbd->dev,
+                        "Unable to initialize firmware log buffer: %d\n",
+                        err);
+
        err = fbnic_fw_request_mbx(fbd);
        if (err) {
                dev_err(&pdev->dev,
                        "Firmware mailbox initialization failure\n");
-               goto free_irqs;
+               goto free_fw_log;
        }
 
        /* Send the request to enable the FW logging to host. Note if this
@@ -323,11 +329,7 @@ static int fbnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
         * possible the FW is just too old to support the logging and needs
         * to be updated.
         */
-       err = fbnic_fw_log_init(fbd);
-       if (err)
-               dev_warn(fbd->dev,
-                        "Unable to initialize firmware log buffer: %d\n",
-                        err);
+       fbnic_fw_log_enable(fbd, true);
 
        fbnic_devlink_register(fbd);
        fbnic_devlink_otp_check(fbd, "error detected during probe");
@@ -374,6 +376,8 @@ init_failure_mode:
          * firmware updates for fixes.
          */
        return 0;
+free_fw_log:
+       fbnic_fw_log_free(fbd);
 free_irqs:
        fbnic_free_irqs(fbd);
 err_destroy_health:
@@ -408,8 +412,9 @@ static void fbnic_remove(struct pci_dev *pdev)
        fbnic_hwmon_unregister(fbd);
        fbnic_dbg_fbd_exit(fbd);
        fbnic_devlink_unregister(fbd);
-       fbnic_fw_log_free(fbd);
+       fbnic_fw_log_disable(fbd);
        fbnic_fw_free_mbx(fbd);
+       fbnic_fw_log_free(fbd);
        fbnic_free_irqs(fbd);
 
        fbnic_devlink_health_destroy(fbd);