ath9k_htc: fix data race between request_firmware_nowait() callback and suspend()
ath9k_hif_usb_probe() requests firmware asynchronically and there is some initialization postponed till firmware is ready. In particular, ath9k_hif_usb_firmware_cb() callback initializes hif_dev->tx.tx_buf and hif_dev->tx.tx_pending lists. At the same time, ath9k_hif_usb_suspend() iterates that lists through ath9k_hif_usb_dealloc_urbs(). If suspend happens before request_firmware_nowait() callback is called, it can lead to oops. Similar issue could be in ath9k_hif_usb_disconnect(), but it is prevented using hif_dev->fw_done completion and HIF_USB_READY flag. The patch extends this approach to suspend() as well. Found by Linux Driver Verification project (linuxtesting.org). Signed-off-by: Alexey Khoroshilov <khoroshilov@ispras.ru> Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
Родитель
a4943ccbc3
Коммит
9494849e53
|
@ -1082,7 +1082,7 @@ static void ath9k_hif_usb_firmware_fail(struct hif_device_usb *hif_dev)
|
|||
struct device *dev = &hif_dev->udev->dev;
|
||||
struct device *parent = dev->parent;
|
||||
|
||||
complete(&hif_dev->fw_done);
|
||||
complete_all(&hif_dev->fw_done);
|
||||
|
||||
if (parent)
|
||||
device_lock(parent);
|
||||
|
@ -1131,7 +1131,7 @@ static void ath9k_hif_usb_firmware_cb(const struct firmware *fw, void *context)
|
|||
|
||||
release_firmware(fw);
|
||||
hif_dev->flags |= HIF_USB_READY;
|
||||
complete(&hif_dev->fw_done);
|
||||
complete_all(&hif_dev->fw_done);
|
||||
|
||||
return;
|
||||
|
||||
|
@ -1316,7 +1316,10 @@ static int ath9k_hif_usb_suspend(struct usb_interface *interface,
|
|||
if (!(hif_dev->flags & HIF_USB_START))
|
||||
ath9k_htc_suspend(hif_dev->htc_handle);
|
||||
|
||||
ath9k_hif_usb_dealloc_urbs(hif_dev);
|
||||
wait_for_completion(&hif_dev->fw_done);
|
||||
|
||||
if (hif_dev->flags & HIF_USB_READY)
|
||||
ath9k_hif_usb_dealloc_urbs(hif_dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче