| From 1bd456afeb8a515137e567967069fce6f8fcd23e Mon Sep 17 00:00:00 2001 |
| From: Shuangpeng Bai <shuangpeng.kernel@gmail.com> |
| Date: Mon, 6 Jul 2026 16:50:15 -0400 |
| Subject: media: go7007: defer the ALSA v4l2 put until card release |
| |
| From: Shuangpeng Bai <shuangpeng.kernel@gmail.com> |
| |
| commit 1bd456afeb8a515137e567967069fce6f8fcd23e upstream. |
| |
| 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 <shuangpeng.kernel@gmail.com> |
| Signed-off-by: Hans Verkuil <hverkuil+cisco@kernel.org> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| drivers/media/usb/go7007/snd-go7007.c | 10 +++++++++- |
| 1 file changed, 9 insertions(+), 1 deletion(-) |
| |
| --- 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 go700 |
| .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); |