aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2017-01-02 05:37:04 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2017-05-14 08:00:20 -0400
commit7aa0e14336d977101193bef85af69b203bfba24f (patch)
tree2afe69e9b43007f8c3e8a659d79b6c9fe6465884
parent170e0abd886bd0ce5676e6393aab4b0148549d50 (diff)
ALSA: hda - Fix deadlock of controller device lock at unbinding
commit ab949d519601880fd46e8bc1445d6a453bf2dc09 upstream. Imre Deak reported a deadlock of HD-audio driver at unbinding while it's still in probing. Since we probe the codecs asynchronously in a work, the codec driver probe may still be kicked off while the controller itself is being unbound. And, azx_remove() tries to process all pending tasks via cancel_work_sync() for fixing the other races (see commit [0b8c82190c12: ALSA: hda - Cancel probe work instead of flush at remove]), now we may meet a bizarre deadlock: Unbind snd_hda_intel via sysfs: device_release_driver() -> device_lock(snd_hda_intel) -> azx_remove() -> cancel_work_sync(azx_probe_work) azx_probe_work(): codec driver probe() -> __driver_attach() -> device_lock(snd_hda_intel) This deadlock is caused by the fact that both device_release_driver() and driver_probe_device() take both the device and its parent locks at the same time. The codec device sets the controller device as its parent, and this lock is taken before the probe() callback is called, while the controller remove() callback gets called also with the same lock. In this patch, as an ugly workaround, we unlock the controller device temporarily during cancel_work_sync() call. The race against another bind call should be still suppressed by the parent's device lock. Reported-by: Imre Deak <imre.deak@intel.com> Fixes: 0b8c82190c12 ("ALSA: hda - Cancel probe work instead of flush at remove") Signed-off-by: Takashi Iwai <tiwai@suse.de> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--sound/pci/hda/hda_intel.c13
1 files changed, 13 insertions, 0 deletions
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index bc4462694aaf..5cb7e04fa4ba 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -2155,7 +2155,20 @@ static void azx_remove(struct pci_dev *pci)
2155 /* cancel the pending probing work */ 2155 /* cancel the pending probing work */
2156 chip = card->private_data; 2156 chip = card->private_data;
2157 hda = container_of(chip, struct hda_intel, chip); 2157 hda = container_of(chip, struct hda_intel, chip);
2158 /* FIXME: below is an ugly workaround.
2159 * Both device_release_driver() and driver_probe_device()
2160 * take *both* the device's and its parent's lock before
2161 * calling the remove() and probe() callbacks. The codec
2162 * probe takes the locks of both the codec itself and its
2163 * parent, i.e. the PCI controller dev. Meanwhile, when
2164 * the PCI controller is unbound, it takes its lock, too
2165 * ==> ouch, a deadlock!
2166 * As a workaround, we unlock temporarily here the controller
2167 * device during cancel_work_sync() call.
2168 */
2169 device_unlock(&pci->dev);
2158 cancel_work_sync(&hda->probe_work); 2170 cancel_work_sync(&hda->probe_work);
2171 device_lock(&pci->dev);
2159 2172
2160 snd_card_free(card); 2173 snd_card_free(card);
2161 } 2174 }