diff options
| author | Jakub Kicinski <kuba@kernel.org> | 2026-05-22 16:13:06 -0700 |
|---|---|---|
| committer | Jakub Kicinski <kuba@kernel.org> | 2026-05-26 08:19:32 -0700 |
| commit | 7a84b965ffc12030af63cd10a8f3a1123ff39b7a (patch) | |
| tree | 2fa36ace96cb08b92633c6e826c7f5a5440a0471 /net | |
| parent | fb7f511d62692661846c47f199e0afe25c2982db (diff) | |
| download | linux-next-history-7a84b965ffc12030af63cd10a8f3a1123ff39b7a.tar.gz | |
ethtool: module: avoid racy updates to dev->ethtool bitfield
When reviewing other changes Gemini points out that we currently
update module_fw_flash_in_progress without holding any locks.
Since module_fw_flash_in_progress is part of a bitfield this
is not great, updates to other fields may be lost.
We could use a bool and sprinkle some READ_ONCE/WRITE_ONCE here
but seems like the issue is rather than the work is an unusual
writer. The other writers already hold the right locks. So just
very briefly take these locks when the work completes.
Note that nothing ever cancels the FW update work, so there's
no concern with deadlocks vs cancel.
Fixes: 32b4c8b53ee7 ("ethtool: Add ability to flash transceiver modules' firmware")
Reviewed-by: Maxime Chevallier <maxime.chevallier@bootlin.com>
Reviewed-by: Danielle Ratson <danieller@nvidia.com>
Link: https://patch.msgid.link/20260522231312.1710836-4-kuba@kernel.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Diffstat (limited to 'net')
| -rw-r--r-- | net/ethtool/module.c | 12 |
1 files changed, 10 insertions, 2 deletions
diff --git a/net/ethtool/module.c b/net/ethtool/module.c index 392c03935e5ef..cdb85e19a23b4 100644 --- a/net/ethtool/module.c +++ b/net/ethtool/module.c @@ -221,14 +221,22 @@ static void module_flash_fw_work_list_del(struct list_head *list) static void module_flash_fw_work(struct work_struct *work) { struct ethtool_module_fw_flash *module_fw; + struct net_device *dev; module_fw = container_of(work, struct ethtool_module_fw_flash, work); + dev = module_fw->fw_update.dev; ethtool_cmis_fw_update(&module_fw->fw_update); module_flash_fw_work_list_del(&module_fw->list); - module_fw->fw_update.dev->ethtool->module_fw_flash_in_progress = false; - netdev_put(module_fw->fw_update.dev, &module_fw->dev_tracker); + + rtnl_lock(); + netdev_lock_ops(dev); + dev->ethtool->module_fw_flash_in_progress = false; + netdev_unlock_ops(dev); + rtnl_unlock(); + + netdev_put(dev, &module_fw->dev_tracker); release_firmware(module_fw->fw_update.fw); kfree(module_fw); } |
