[alsa-devel] snd_hda_intel/snd_hda_codec_hdmi module load/unload race
Greg Kroah-Hartman
gregkh at linuxfoundation.org
Fri Dec 16 17:40:54 CET 2016
On Thu, Dec 15, 2016 at 12:32:08PM +0100, Takashi Iwai wrote:
> On Wed, 14 Dec 2016 22:00:50 +0100,
> Imre Deak wrote:
> >
> > Hi,
> >
> > I got the trace below while trying to unload (unbind) snd_hda_intel, while
> > its still loading the HDMI codec driver. IIUC what happens is:
> >
> > Task1 Task2 Task3
> > modprobe snd_hda_intel
> > schedule(azx_probe_work)
> > 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()
> > request_module(snd-hda-codec-hdmi)
> > hdmi_driver_init()
> > __driver_attach()
> > device_lock(snd_hda_intel)
> >
> > Deadlock, since azx_probe_work() will never finish and the snd_hda_intel device
> > lock will never get released.
>
> This is indeed nasty. The deadlock happens when the driver core takes
> the parent's device lock.
>
> static int __driver_attach(struct device *dev, void *data)
> {
> ....
> if (dev->parent) /* Needed for USB */
> device_lock(dev->parent);
> device_lock(dev);
> if (!dev->driver)
> driver_probe_device(drv, dev);
>
> I vaguely remember of some other issue due to the device_lock of the
> parent device. And, I guess a similar deadlock may happen not only
> with HD-audio driver but also in general with every driver using async
> probe.
>
> Greg, any good way to avoid such a deadlock? Can we make the parent
> device lock conditional somehow?
Ick, messy. I don't want to make the parent lock conditional, as it's
needed. Shouldn't the cancel_work_sync() prevent the request_module()
from running? Seems like you need to serialize your probe_work
somehow...
I don't see a way to handle this in the driver core, and no:
> --- a/sound/hda/hdac_device.c
> +++ b/sound/hda/hdac_device.c
> @@ -44,7 +44,7 @@ int snd_hdac_device_init(struct hdac_device *codec, struct hdac_bus *bus,
>
> dev = &codec->dev;
> device_initialize(dev);
> - dev->parent = bus->dev;
> + // dev->parent = bus->dev;
> dev->bus = &snd_hda_bus_type;
> dev->release = default_release;
> dev->groups = hdac_dev_attr_groups;
>
> ... but it's obviously ugly :)
That's not a good solution either :)
thanks,
greg k-h
More information about the Alsa-devel
mailing list