[PATCH] ALSA: hda/i915 - fix list corruption with concurrent probes
Takashi Iwai
tiwai at suse.de
Fri Oct 9 14:46:55 UTC 2020
On Tue, 06 Oct 2020 18:17:22 +0200,
Kai Vehmanen wrote:
>
> From: Takashi Iwai <tiwai at suse.de>
>
> Current hdac_i915 uses a static completion instance to wait
> for i915 driver to complete the component bind.
>
> This design is not safe if multiple HDA controllers are active and
> communicating with different i915 instances, and can lead to list
> corruption and failed audio driver probe.
>
> Fix the design by moving completion mechanism to common acomp
> code and remove the related code from hdac_i915.
>
> Co-developed-by: Kai Vehmanen <kai.vehmanen at linux.intel.com>
> Signed-off-by: Kai Vehmanen <kai.vehmanen at linux.intel.com>
> Signed-off-by: Takashi Iwai <tiwai at suse.de>
Now I applied it with Fixes tag to 7b882fe3e3e8 ("ALSA: hda - handle
multiple i915 device instances").
thanks,
Takashi
> ---
> include/drm/drm_audio_component.h | 4 ++++
> sound/hda/hdac_component.c | 3 +++
> sound/hda/hdac_i915.c | 23 +++--------------------
> 3 files changed, 10 insertions(+), 20 deletions(-)
>
> diff --git a/include/drm/drm_audio_component.h b/include/drm/drm_audio_component.h
> index a45f93487039..0d36bfd1a4cd 100644
> --- a/include/drm/drm_audio_component.h
> +++ b/include/drm/drm_audio_component.h
> @@ -117,6 +117,10 @@ struct drm_audio_component {
> * @audio_ops: Ops implemented by hda driver, called by DRM driver
> */
> const struct drm_audio_component_audio_ops *audio_ops;
> + /**
> + * @master_bind_complete: completion held during component master binding
> + */
> + struct completion master_bind_complete;
> };
>
> #endif /* _DRM_AUDIO_COMPONENT_H_ */
> diff --git a/sound/hda/hdac_component.c b/sound/hda/hdac_component.c
> index 89126c6fd216..bb37e7e0bd79 100644
> --- a/sound/hda/hdac_component.c
> +++ b/sound/hda/hdac_component.c
> @@ -210,12 +210,14 @@ static int hdac_component_master_bind(struct device *dev)
> goto module_put;
> }
>
> + complete_all(&acomp->master_bind_complete);
> return 0;
>
> module_put:
> module_put(acomp->ops->owner);
> out_unbind:
> component_unbind_all(dev, acomp);
> + complete_all(&acomp->master_bind_complete);
>
> return ret;
> }
> @@ -296,6 +298,7 @@ int snd_hdac_acomp_init(struct hdac_bus *bus,
> if (!acomp)
> return -ENOMEM;
> acomp->audio_ops = aops;
> + init_completion(&acomp->master_bind_complete);
> bus->audio_component = acomp;
> devres_add(dev, acomp);
>
> diff --git a/sound/hda/hdac_i915.c b/sound/hda/hdac_i915.c
> index 5f0a1aa6ad84..454474ac5716 100644
> --- a/sound/hda/hdac_i915.c
> +++ b/sound/hda/hdac_i915.c
> @@ -11,8 +11,6 @@
> #include <sound/hda_i915.h>
> #include <sound/hda_register.h>
>
> -static struct completion bind_complete;
> -
> #define IS_HSW_CONTROLLER(pci) (((pci)->device == 0x0a0c) || \
> ((pci)->device == 0x0c0c) || \
> ((pci)->device == 0x0d0c) || \
> @@ -130,19 +128,6 @@ static bool i915_gfx_present(void)
> return pci_dev_present(ids);
> }
>
> -static int i915_master_bind(struct device *dev,
> - struct drm_audio_component *acomp)
> -{
> - complete_all(&bind_complete);
> - /* clear audio_ops here as it was needed only for completion call */
> - acomp->audio_ops = NULL;
> - return 0;
> -}
> -
> -static const struct drm_audio_component_audio_ops i915_init_ops = {
> - .master_bind = i915_master_bind
> -};
> -
> /**
> * snd_hdac_i915_init - Initialize i915 audio component
> * @bus: HDA core bus
> @@ -163,9 +148,7 @@ int snd_hdac_i915_init(struct hdac_bus *bus)
> if (!i915_gfx_present())
> return -ENODEV;
>
> - init_completion(&bind_complete);
> -
> - err = snd_hdac_acomp_init(bus, &i915_init_ops,
> + err = snd_hdac_acomp_init(bus, NULL,
> i915_component_master_match,
> sizeof(struct i915_audio_component) - sizeof(*acomp));
> if (err < 0)
> @@ -177,8 +160,8 @@ int snd_hdac_i915_init(struct hdac_bus *bus)
> if (!IS_ENABLED(CONFIG_MODULES) ||
> !request_module("i915")) {
> /* 60s timeout */
> - wait_for_completion_timeout(&bind_complete,
> - msecs_to_jiffies(60 * 1000));
> + wait_for_completion_timeout(&acomp->master_bind_complete,
> + msecs_to_jiffies(60 * 1000));
> }
> }
> if (!acomp->ops) {
> --
> 2.28.0
>
More information about the dri-devel
mailing list