]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
media: pci: ivtv: Don't create fake v4l2_fh
authorLaurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Sun, 10 Aug 2025 01:29:54 +0000 (04:29 +0300)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 3 Dec 2025 11:45:09 +0000 (12:45 +0100)
[ Upstream commit cc6e8d1ccea792d8550428e0831e3a35b0ccfddc ]

The ivtv driver has a structure named ivtv_open_id that models an open
file handle for the device. It embeds a v4l2_fh instance for file
handles that correspond to a V4L2 video device, and stores a pointer to
that v4l2_fh in struct ivtv_stream to identify which open file handle
owns a particular stream.

In addition to video devices, streams can be owned by ALSA PCM devices.
Those devices do not make use of the v4l2_fh instance for obvious
reasons, but the snd_ivtv_pcm_capture_open() function still initializes
a "fake" v4l2_fh for the sole purpose of using it as an open file handle
identifier. The v4l2_fh is not properly destroyed when the ALSA PCM
device is closed, leading to possible resource leaks.

Fortunately, the v4l2_fh instance pointed to by ivtv_stream is not
accessed, only the pointer value is used for comparison. Replace it with
a pointer to the ivtv_open_id structure that embeds the v4l2_fh, and
don't initialize the v4l2_fh for ALSA PCM devices.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Signed-off-by: Hans Verkuil <hverkuil+cisco@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
drivers/media/pci/ivtv/ivtv-alsa-pcm.c
drivers/media/pci/ivtv/ivtv-driver.h
drivers/media/pci/ivtv/ivtv-fileops.c
drivers/media/pci/ivtv/ivtv-irq.c

index 9e6019a159f4c5e47b39e91d9cadf1de7562f7b1..0b6b77aa29dd202fed6ba1d77cc0a49d0e5943e9 100644 (file)
@@ -150,14 +150,12 @@ static int snd_ivtv_pcm_capture_open(struct snd_pcm_substream *substream)
 
        s = &itv->streams[IVTV_ENC_STREAM_TYPE_PCM];
 
-       v4l2_fh_init(&item.fh, &s->vdev);
        item.itv = itv;
        item.type = s->type;
 
        /* See if the stream is available */
        if (ivtv_claim_stream(&item, item.type)) {
                /* No, it's already in use */
-               v4l2_fh_exit(&item.fh);
                snd_ivtv_unlock(itvsc);
                return -EBUSY;
        }
index 90f38552bd3623d57256e36c186ff9de02d1cf39..8a48b4533a02f5af1e6946a37201f85d0183d9bc 100644 (file)
@@ -325,6 +325,7 @@ struct ivtv_queue {
 };
 
 struct ivtv;                           /* forward reference */
+struct ivtv_open_id;
 
 struct ivtv_stream {
        /* These first four fields are always set, even if the stream
@@ -334,7 +335,7 @@ struct ivtv_stream {
        const char *name;               /* name of the stream */
        int type;                       /* stream type */
 
-       struct v4l2_fh *fh;             /* pointer to the streaming filehandle */
+       struct ivtv_open_id *id;        /* pointer to the streaming ivtv_open_id */
        spinlock_t qlock;               /* locks access to the queues */
        unsigned long s_flags;          /* status flags, see above */
        int dma;                        /* can be PCI_DMA_TODEVICE, PCI_DMA_FROMDEVICE or PCI_DMA_NONE */
index 4202c3a47d33e6ae15aeca22585d1e9423df6f6c..7ed0d2d85253e5a46dfc95b9cf0c84f29d5ed1d8 100644 (file)
@@ -38,16 +38,16 @@ int ivtv_claim_stream(struct ivtv_open_id *id, int type)
 
        if (test_and_set_bit(IVTV_F_S_CLAIMED, &s->s_flags)) {
                /* someone already claimed this stream */
-               if (s->fh == &id->fh) {
+               if (s->id == id) {
                        /* yes, this file descriptor did. So that's OK. */
                        return 0;
                }
-               if (s->fh == NULL && (type == IVTV_DEC_STREAM_TYPE_VBI ||
+               if (s->id == NULL && (type == IVTV_DEC_STREAM_TYPE_VBI ||
                                         type == IVTV_ENC_STREAM_TYPE_VBI)) {
                        /* VBI is handled already internally, now also assign
                           the file descriptor to this stream for external
                           reading of the stream. */
-                       s->fh = &id->fh;
+                       s->id = id;
                        IVTV_DEBUG_INFO("Start Read VBI\n");
                        return 0;
                }
@@ -55,7 +55,7 @@ int ivtv_claim_stream(struct ivtv_open_id *id, int type)
                IVTV_DEBUG_INFO("Stream %d is busy\n", type);
                return -EBUSY;
        }
-       s->fh = &id->fh;
+       s->id = id;
        if (type == IVTV_DEC_STREAM_TYPE_VBI) {
                /* Enable reinsertion interrupt */
                ivtv_clear_irq_mask(itv, IVTV_IRQ_DEC_VBI_RE_INSERT);
@@ -93,7 +93,7 @@ void ivtv_release_stream(struct ivtv_stream *s)
        struct ivtv *itv = s->itv;
        struct ivtv_stream *s_vbi;
 
-       s->fh = NULL;
+       s->id = NULL;
        if ((s->type == IVTV_DEC_STREAM_TYPE_VBI || s->type == IVTV_ENC_STREAM_TYPE_VBI) &&
                test_bit(IVTV_F_S_INTERNAL_USE, &s->s_flags)) {
                /* this stream is still in use internally */
@@ -125,7 +125,7 @@ void ivtv_release_stream(struct ivtv_stream *s)
                /* was already cleared */
                return;
        }
-       if (s_vbi->fh) {
+       if (s_vbi->id) {
                /* VBI stream still claimed by a file descriptor */
                return;
        }
@@ -349,7 +349,7 @@ static ssize_t ivtv_read(struct ivtv_stream *s, char __user *ubuf, size_t tot_co
        size_t tot_written = 0;
        int single_frame = 0;
 
-       if (atomic_read(&itv->capturing) == 0 && s->fh == NULL) {
+       if (atomic_read(&itv->capturing) == 0 && s->id == NULL) {
                /* shouldn't happen */
                IVTV_DEBUG_WARN("Stream %s not initialized before read\n", s->name);
                return -EIO;
@@ -819,7 +819,7 @@ void ivtv_stop_capture(struct ivtv_open_id *id, int gop_end)
                     id->type == IVTV_ENC_STREAM_TYPE_VBI) &&
                    test_bit(IVTV_F_S_INTERNAL_USE, &s->s_flags)) {
                        /* Also used internally, don't stop capturing */
-                       s->fh = NULL;
+                       s->id = NULL;
                }
                else {
                        ivtv_stop_v4l2_encode_stream(s, gop_end);
@@ -903,7 +903,7 @@ int ivtv_v4l2_close(struct file *filp)
        v4l2_fh_exit(fh);
 
        /* Easy case first: this stream was never claimed by us */
-       if (s->fh != &id->fh)
+       if (s->id != id)
                goto close_done;
 
        /* 'Unclaim' this stream */
index e39bf64c5c715bcaa867cbfc5acf71f0d47a0722..404335e5aff4ec9fc4f5c8a8736499edb4c867f1 100644 (file)
@@ -305,7 +305,7 @@ static void dma_post(struct ivtv_stream *s)
                        ivtv_process_vbi_data(itv, buf, 0, s->type);
                        s->q_dma.bytesused += buf->bytesused;
                }
-               if (s->fh == NULL) {
+               if (s->id == NULL) {
                        ivtv_queue_move(s, &s->q_dma, NULL, &s->q_free, 0);
                        return;
                }
@@ -330,7 +330,7 @@ static void dma_post(struct ivtv_stream *s)
                set_bit(IVTV_F_I_HAVE_WORK, &itv->i_flags);
        }
 
-       if (s->fh)
+       if (s->id)
                wake_up(&s->waitq);
 }