]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
media: v4l2-mem2mem: reorder checks in v4l2_m2m_poll()
authorMichael Tretter <m.tretter@pengutronix.de>
Thu, 27 Jun 2019 12:44:33 +0000 (08:44 -0400)
committerMauro Carvalho Chehab <mchehab+samsung@kernel.org>
Tue, 23 Jul 2019 12:46:12 +0000 (08:46 -0400)
When reaching the end of stream, V4L2 m2m clients may expect the
V4L2_EOS_EVENT. Although the V4L2_EOS_EVENT is deprecated behavior,
drivers must signal that event before dequeuing the buffer that has the
V4L2_BUF_FLAG_LAST flag set.

If a driver queues the V4L2_EOS_EVENT event and returns the buffer after
the check for events but before the check for buffers, vb2_m2m_poll()
will signal that the buffer with V4L2_BUF_FLAG_LAST can be read but not
that the V4L2_EOS_EVENT is available.

Split the check for buffers into a separate function and check for
available buffers before checking for events. This ensures that if
vb2_m2m_poll() signals POLLIN | POLLRDNORM for the V4L2_BUF_FLAG_LAST
buffer, it signals POLLPRI for the V4L2_EOS_EVENT, too.

Signed-off-by: Michael Tretter <m.tretter@pengutronix.de>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
[hverkuil-cisco@xs4all.nl: fix checkpatch alignment warning]
Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
drivers/media/v4l2-core/v4l2-mem2mem.c

index 4f517670293771c9db268d2531ff4cf0851a3876..19937dd3c6f63980eb0f48700ba96cbc0b5cf77c 100644 (file)
@@ -603,11 +603,10 @@ int v4l2_m2m_streamoff(struct file *file, struct v4l2_m2m_ctx *m2m_ctx,
 }
 EXPORT_SYMBOL_GPL(v4l2_m2m_streamoff);
 
-__poll_t v4l2_m2m_poll(struct file *file, struct v4l2_m2m_ctx *m2m_ctx,
-                          struct poll_table_struct *wait)
+static __poll_t v4l2_m2m_poll_for_data(struct file *file,
+                                      struct v4l2_m2m_ctx *m2m_ctx,
+                                      struct poll_table_struct *wait)
 {
-       struct video_device *vfd = video_devdata(file);
-       __poll_t req_events = poll_requested_events(wait);
        struct vb2_queue *src_q, *dst_q;
        struct vb2_buffer *src_vb = NULL, *dst_vb = NULL;
        __poll_t rc = 0;
@@ -619,16 +618,6 @@ __poll_t v4l2_m2m_poll(struct file *file, struct v4l2_m2m_ctx *m2m_ctx,
        poll_wait(file, &src_q->done_wq, wait);
        poll_wait(file, &dst_q->done_wq, wait);
 
-       if (test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags)) {
-               struct v4l2_fh *fh = file->private_data;
-
-               poll_wait(file, &fh->wait, wait);
-               if (v4l2_event_pending(fh))
-                       rc = EPOLLPRI;
-               if (!(req_events & (EPOLLOUT | EPOLLWRNORM | EPOLLIN | EPOLLRDNORM)))
-                       return rc;
-       }
-
        /*
         * There has to be at least one buffer queued on each queued_list, which
         * means either in driver already or waiting for driver to claim it
@@ -637,10 +626,8 @@ __poll_t v4l2_m2m_poll(struct file *file, struct v4l2_m2m_ctx *m2m_ctx,
        if ((!src_q->streaming || src_q->error ||
             list_empty(&src_q->queued_list)) &&
            (!dst_q->streaming || dst_q->error ||
-            list_empty(&dst_q->queued_list))) {
-               rc |= EPOLLERR;
-               goto end;
-       }
+            list_empty(&dst_q->queued_list)))
+               return EPOLLERR;
 
        spin_lock_irqsave(&dst_q->done_lock, flags);
        if (list_empty(&dst_q->done_list)) {
@@ -650,7 +637,7 @@ __poll_t v4l2_m2m_poll(struct file *file, struct v4l2_m2m_ctx *m2m_ctx,
                 */
                if (dst_q->last_buffer_dequeued) {
                        spin_unlock_irqrestore(&dst_q->done_lock, flags);
-                       return rc | EPOLLIN | EPOLLRDNORM;
+                       return EPOLLIN | EPOLLRDNORM;
                }
        }
        spin_unlock_irqrestore(&dst_q->done_lock, flags);
@@ -673,7 +660,27 @@ __poll_t v4l2_m2m_poll(struct file *file, struct v4l2_m2m_ctx *m2m_ctx,
                rc |= EPOLLIN | EPOLLRDNORM;
        spin_unlock_irqrestore(&dst_q->done_lock, flags);
 
-end:
+       return rc;
+}
+
+__poll_t v4l2_m2m_poll(struct file *file, struct v4l2_m2m_ctx *m2m_ctx,
+                      struct poll_table_struct *wait)
+{
+       struct video_device *vfd = video_devdata(file);
+       __poll_t req_events = poll_requested_events(wait);
+       __poll_t rc = 0;
+
+       if (req_events & (EPOLLOUT | EPOLLWRNORM | EPOLLIN | EPOLLRDNORM))
+               rc = v4l2_m2m_poll_for_data(file, m2m_ctx, wait);
+
+       if (test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags)) {
+               struct v4l2_fh *fh = file->private_data;
+
+               poll_wait(file, &fh->wait, wait);
+               if (v4l2_event_pending(fh))
+                       rc |= EPOLLPRI;
+       }
+
        return rc;
 }
 EXPORT_SYMBOL_GPL(v4l2_m2m_poll);