From 1bd456afeb8a515137e567967069fce6f8fcd23e Mon Sep 17 00:00:00 2001 From: Shuangpeng Bai Date: Mon, 6 Jul 2026 16:50:15 -0400 Subject: [PATCH] media: go7007: defer the ALSA v4l2 put until card release go7007_snd_init() already takes a v4l2_device reference for the ALSA side, but go7007_snd_remove() drops it immediately after calling snd_card_free_when_closed(). That is too early when a userspace process still has the capture PCM open. The ALSA card and its PCM callbacks remain alive until the last file is closed, so the release path can still reach struct go7007 through pcm->private_data and call go7007_snd_hw_free() after the V4L2 release path has freed the object. Move the matching v4l2_device_put() to the ALSA card private_free callback so the existing ALSA reference covers the whole deferred card lifetime. Closes: https://lore.kernel.org/r/178144969601.60470.6005237146425573205@gmail.com Fixes: d5d3a7cc127d ("[media] go7007: fix unregister/disconnect handling") Cc: stable@vger.kernel.org Signed-off-by: Shuangpeng Bai Signed-off-by: Hans Verkuil --- drivers/media/usb/go7007/snd-go7007.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/media/usb/go7007/snd-go7007.c b/drivers/media/usb/go7007/snd-go7007.c index e4b9f37be77b..01d547ad678d 100644 --- a/drivers/media/usb/go7007/snd-go7007.c +++ b/drivers/media/usb/go7007/snd-go7007.c @@ -195,6 +195,13 @@ static const struct snd_device_ops go7007_snd_device_ops = { .dev_free = go7007_snd_free, }; +static void go7007_snd_card_free(struct snd_card *card) +{ + struct go7007 *go = card->private_data; + + v4l2_device_put(&go->v4l2_dev); +} + int go7007_snd_init(struct go7007 *go) { static int dev; @@ -245,6 +252,8 @@ int go7007_snd_init(struct go7007 *go) gosnd->substream = NULL; go->snd_context = gosnd; v4l2_device_get(&go->v4l2_dev); + gosnd->card->private_data = go; + gosnd->card->private_free = go7007_snd_card_free; ++dev; return 0; @@ -263,7 +272,6 @@ int go7007_snd_remove(struct go7007 *go) snd_card_disconnect(gosnd->card); snd_card_free_when_closed(gosnd->card); - v4l2_device_put(&go->v4l2_dev); return 0; } EXPORT_SYMBOL(go7007_snd_remove);