diff mbox series

media: vb2: Allow reqbufs(0) with "in use" MMAP buffers

Message ID 20181113150621.22276-1-p.zabel@pengutronix.de (mailing list archive)
State New, archived
Headers show
Series media: vb2: Allow reqbufs(0) with "in use" MMAP buffers | expand

Commit Message

Philipp Zabel Nov. 13, 2018, 3:06 p.m. UTC
From: John Sheu <sheu@chromium.org>

Videobuf2 presently does not allow VIDIOC_REQBUFS to destroy outstanding
buffers if the queue is of type V4L2_MEMORY_MMAP, and if the buffers are
considered "in use".  This is different behavior than for other memory
types and prevents us from deallocating buffers in following two cases:

1) There are outstanding mmap()ed views on the buffer. However even if
   we put the buffer in reqbufs(0), there will be remaining references,
   due to vma .open/close() adjusting vb2 buffer refcount appropriately.
   This means that the buffer will be in fact freed only when the last
   mmap()ed view is unmapped.

2) Buffer has been exported as a DMABUF. Refcount of the vb2 buffer
   is managed properly by VB2 DMABUF ops, i.e. incremented on DMABUF
   get and decremented on DMABUF release. This means that the buffer
   will be alive until all importers release it.

Considering both cases above, there does not seem to be any need to
prevent reqbufs(0) operation, because buffer lifetime is already
properly managed by both mmap() and DMABUF code paths. Let's remove it
and allow userspace freeing the queue (and potentially allocating a new
one) even though old buffers might be still in processing.

To let userspace know that the kernel now supports orphaning buffers
that are still in use, add a new V4L2_BUF_CAP_SUPPORTS_ORPHANED_BUFS
to be set by reqbufs and create_bufs.

Signed-off-by: John Sheu <sheu@chromium.org>
Reviewed-by: Pawel Osciak <posciak@chromium.org>
Reviewed-by: Tomasz Figa <tfiga@chromium.org>
Signed-off-by: Tomasz Figa <tfiga@chromium.org>
[p.zabel@pengutronix.de: moved __vb2_queue_cancel out of the mmap_lock
 and added V4L2_BUF_CAP_SUPPORTS_ORPHANED_BUFS]
Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
---
 .../media/common/videobuf2/videobuf2-core.c   | 26 +------------------
 .../media/common/videobuf2/videobuf2-v4l2.c   |  2 +-
 include/uapi/linux/videodev2.h                |  1 +
 3 files changed, 3 insertions(+), 26 deletions(-)

Comments

Philipp Zabel Nov. 13, 2018, 3:08 p.m. UTC | #1
Sorry, that should have said [PATCH v2].

regards
Philipp
Hans Verkuil Nov. 13, 2018, 3:43 p.m. UTC | #2
Hi Philipp,

On 11/13/18 16:06, Philipp Zabel wrote:
> From: John Sheu <sheu@chromium.org>
> 
> Videobuf2 presently does not allow VIDIOC_REQBUFS to destroy outstanding
> buffers if the queue is of type V4L2_MEMORY_MMAP, and if the buffers are
> considered "in use".  This is different behavior than for other memory
> types and prevents us from deallocating buffers in following two cases:
> 
> 1) There are outstanding mmap()ed views on the buffer. However even if
>    we put the buffer in reqbufs(0), there will be remaining references,
>    due to vma .open/close() adjusting vb2 buffer refcount appropriately.
>    This means that the buffer will be in fact freed only when the last
>    mmap()ed view is unmapped.
> 
> 2) Buffer has been exported as a DMABUF. Refcount of the vb2 buffer
>    is managed properly by VB2 DMABUF ops, i.e. incremented on DMABUF
>    get and decremented on DMABUF release. This means that the buffer
>    will be alive until all importers release it.
> 
> Considering both cases above, there does not seem to be any need to
> prevent reqbufs(0) operation, because buffer lifetime is already
> properly managed by both mmap() and DMABUF code paths. Let's remove it
> and allow userspace freeing the queue (and potentially allocating a new
> one) even though old buffers might be still in processing.
> 
> To let userspace know that the kernel now supports orphaning buffers
> that are still in use, add a new V4L2_BUF_CAP_SUPPORTS_ORPHANED_BUFS
> to be set by reqbufs and create_bufs.

Looks good, but I have some questions:

1) does v4l2-compliance together with vivid (easiest to test) still work?
   I don't think I have a proper test for this in v4l2-compliance, but
   I'm not 100% certain. If it fails with this patch, then please provide
   a fix for v4l2-compliance as well.

2) I would like to see a new test in v4l2-compliance for this: i.e. if
   the capability is set, then check that you can call REQBUFS(0) before
   unmapping all buffers. Ditto with dmabuffers.

I said during the media summit that I wanted to be more strict about
requiring compliance tests before adding new features, so you're the
unlucky victim of that :-)

Look for munmap_bufs in v4l2-test-buffers.cpp (the MMAP case). The dmabuf
tests are a bit trickier since I noticed that I never actually close
the dmabuf fds in v4l2-compliance. This will fix that:

diff --git a/utils/v4l2-compliance/v4l2-test-buffers.cpp b/utils/v4l2-compliance/v4l2-test-buffers.cpp
index c59a56d9..03639301 100644
--- a/utils/v4l2-compliance/v4l2-test-buffers.cpp
+++ b/utils/v4l2-compliance/v4l2-test-buffers.cpp
@@ -1201,6 +1201,7 @@ int testDmaBuf(struct node *expbuf_node, struct node *node, unsigned frame_count
 		fail_on_test(captureBufs(node, q, m2m_q, frame_count, true));
 		fail_on_test(node->streamoff(q.g_type()));
 		fail_on_test(node->streamoff(q.g_type()));
+		exp_q.close_exported_fds();
 	}
 	return 0;
 }

What is also missing in testDmaBuf is calling q.reqbufs(node, 0) to free all
buffers, and I never munmap the buffers by calling q.munmap_bufs(node);

In other words, clearly I never wrote proper tests for the behavior of mmap()/dmabuf
and REQBUFS(0).

Regards,

	Hans

> 
> Signed-off-by: John Sheu <sheu@chromium.org>
> Reviewed-by: Pawel Osciak <posciak@chromium.org>
> Reviewed-by: Tomasz Figa <tfiga@chromium.org>
> Signed-off-by: Tomasz Figa <tfiga@chromium.org>
> [p.zabel@pengutronix.de: moved __vb2_queue_cancel out of the mmap_lock
>  and added V4L2_BUF_CAP_SUPPORTS_ORPHANED_BUFS]
> Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
> ---
>  .../media/common/videobuf2/videobuf2-core.c   | 26 +------------------
>  .../media/common/videobuf2/videobuf2-v4l2.c   |  2 +-
>  include/uapi/linux/videodev2.h                |  1 +
>  3 files changed, 3 insertions(+), 26 deletions(-)
> 
> diff --git a/drivers/media/common/videobuf2/videobuf2-core.c b/drivers/media/common/videobuf2/videobuf2-core.c
> index 975ff5669f72..608459450c1e 100644
> --- a/drivers/media/common/videobuf2/videobuf2-core.c
> +++ b/drivers/media/common/videobuf2/videobuf2-core.c
> @@ -553,20 +553,6 @@ bool vb2_buffer_in_use(struct vb2_queue *q, struct vb2_buffer *vb)
>  }
>  EXPORT_SYMBOL(vb2_buffer_in_use);
>  
> -/*
> - * __buffers_in_use() - return true if any buffers on the queue are in use and
> - * the queue cannot be freed (by the means of REQBUFS(0)) call
> - */
> -static bool __buffers_in_use(struct vb2_queue *q)
> -{
> -	unsigned int buffer;
> -	for (buffer = 0; buffer < q->num_buffers; ++buffer) {
> -		if (vb2_buffer_in_use(q, q->bufs[buffer]))
> -			return true;
> -	}
> -	return false;
> -}
> -
>  void vb2_core_querybuf(struct vb2_queue *q, unsigned int index, void *pb)
>  {
>  	call_void_bufop(q, fill_user_buffer, q->bufs[index], pb);
> @@ -674,23 +660,13 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory,
>  
>  	if (*count == 0 || q->num_buffers != 0 ||
>  	    (q->memory != VB2_MEMORY_UNKNOWN && q->memory != memory)) {
> -		/*
> -		 * We already have buffers allocated, so first check if they
> -		 * are not in use and can be freed.
> -		 */
> -		mutex_lock(&q->mmap_lock);
> -		if (q->memory == VB2_MEMORY_MMAP && __buffers_in_use(q)) {
> -			mutex_unlock(&q->mmap_lock);
> -			dprintk(1, "memory in use, cannot free\n");
> -			return -EBUSY;
> -		}
> -
>  		/*
>  		 * Call queue_cancel to clean up any buffers in the
>  		 * QUEUED state which is possible if buffers were prepared or
>  		 * queued without ever calling STREAMON.
>  		 */
>  		__vb2_queue_cancel(q);
> +		mutex_lock(&q->mmap_lock);
>  		ret = __vb2_queue_free(q, q->num_buffers);
>  		mutex_unlock(&q->mmap_lock);
>  		if (ret)
> diff --git a/drivers/media/common/videobuf2/videobuf2-v4l2.c b/drivers/media/common/videobuf2/videobuf2-v4l2.c
> index a17033ab2c22..f02d452ceeb9 100644
> --- a/drivers/media/common/videobuf2/videobuf2-v4l2.c
> +++ b/drivers/media/common/videobuf2/videobuf2-v4l2.c
> @@ -624,7 +624,7 @@ EXPORT_SYMBOL(vb2_querybuf);
>  
>  static void fill_buf_caps(struct vb2_queue *q, u32 *caps)
>  {
> -	*caps = 0;
> +	*caps = V4L2_BUF_CAP_SUPPORTS_ORPHANED_BUFS;
>  	if (q->io_modes & VB2_MMAP)
>  		*caps |= V4L2_BUF_CAP_SUPPORTS_MMAP;
>  	if (q->io_modes & VB2_USERPTR)
> diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
> index c8e8ff810190..2a223835214c 100644
> --- a/include/uapi/linux/videodev2.h
> +++ b/include/uapi/linux/videodev2.h
> @@ -879,6 +879,7 @@ struct v4l2_requestbuffers {
>  #define V4L2_BUF_CAP_SUPPORTS_USERPTR	(1 << 1)
>  #define V4L2_BUF_CAP_SUPPORTS_DMABUF	(1 << 2)
>  #define V4L2_BUF_CAP_SUPPORTS_REQUESTS	(1 << 3)
> +#define V4L2_BUF_CAP_SUPPORTS_ORPHANED_BUFS (1 << 4)
>  
>  /**
>   * struct v4l2_plane - plane info for multi-planar buffers
>
Sakari Ailus Nov. 13, 2018, 10:27 p.m. UTC | #3
Hi Philipp,

On Tue, Nov 13, 2018 at 04:06:21PM +0100, Philipp Zabel wrote:
> From: John Sheu <sheu@chromium.org>
> 
> Videobuf2 presently does not allow VIDIOC_REQBUFS to destroy outstanding
> buffers if the queue is of type V4L2_MEMORY_MMAP, and if the buffers are
> considered "in use".  This is different behavior than for other memory
> types and prevents us from deallocating buffers in following two cases:
> 
> 1) There are outstanding mmap()ed views on the buffer. However even if
>    we put the buffer in reqbufs(0), there will be remaining references,
>    due to vma .open/close() adjusting vb2 buffer refcount appropriately.
>    This means that the buffer will be in fact freed only when the last
>    mmap()ed view is unmapped.
> 
> 2) Buffer has been exported as a DMABUF. Refcount of the vb2 buffer
>    is managed properly by VB2 DMABUF ops, i.e. incremented on DMABUF
>    get and decremented on DMABUF release. This means that the buffer
>    will be alive until all importers release it.
> 
> Considering both cases above, there does not seem to be any need to
> prevent reqbufs(0) operation, because buffer lifetime is already
> properly managed by both mmap() and DMABUF code paths. Let's remove it
> and allow userspace freeing the queue (and potentially allocating a new
> one) even though old buffers might be still in processing.
> 
> To let userspace know that the kernel now supports orphaning buffers
> that are still in use, add a new V4L2_BUF_CAP_SUPPORTS_ORPHANED_BUFS
> to be set by reqbufs and create_bufs.
> 
> Signed-off-by: John Sheu <sheu@chromium.org>
> Reviewed-by: Pawel Osciak <posciak@chromium.org>
> Reviewed-by: Tomasz Figa <tfiga@chromium.org>
> Signed-off-by: Tomasz Figa <tfiga@chromium.org>
> [p.zabel@pengutronix.de: moved __vb2_queue_cancel out of the mmap_lock
>  and added V4L2_BUF_CAP_SUPPORTS_ORPHANED_BUFS]
> Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>

This lets the user to allocate lots of mmap'ed buffers that are pinned in
physical memory. Considering that we don't really have a proper mechanism
to limit that anyway,

Acked-by: Sakari Ailus <sakari.ailus@linux.intel.com>

That said, the patch must be accompanied by the documentation change in
Documentation/media/uapi/v4l/vidioc-reqbufs.rst .

I wonder what Hans thinks.

> ---
>  .../media/common/videobuf2/videobuf2-core.c   | 26 +------------------
>  .../media/common/videobuf2/videobuf2-v4l2.c   |  2 +-
>  include/uapi/linux/videodev2.h                |  1 +
>  3 files changed, 3 insertions(+), 26 deletions(-)
> 
> diff --git a/drivers/media/common/videobuf2/videobuf2-core.c b/drivers/media/common/videobuf2/videobuf2-core.c
> index 975ff5669f72..608459450c1e 100644
> --- a/drivers/media/common/videobuf2/videobuf2-core.c
> +++ b/drivers/media/common/videobuf2/videobuf2-core.c
> @@ -553,20 +553,6 @@ bool vb2_buffer_in_use(struct vb2_queue *q, struct vb2_buffer *vb)
>  }
>  EXPORT_SYMBOL(vb2_buffer_in_use);
>  
> -/*
> - * __buffers_in_use() - return true if any buffers on the queue are in use and
> - * the queue cannot be freed (by the means of REQBUFS(0)) call
> - */
> -static bool __buffers_in_use(struct vb2_queue *q)
> -{
> -	unsigned int buffer;
> -	for (buffer = 0; buffer < q->num_buffers; ++buffer) {
> -		if (vb2_buffer_in_use(q, q->bufs[buffer]))
> -			return true;
> -	}
> -	return false;
> -}
> -
>  void vb2_core_querybuf(struct vb2_queue *q, unsigned int index, void *pb)
>  {
>  	call_void_bufop(q, fill_user_buffer, q->bufs[index], pb);
> @@ -674,23 +660,13 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory,
>  
>  	if (*count == 0 || q->num_buffers != 0 ||
>  	    (q->memory != VB2_MEMORY_UNKNOWN && q->memory != memory)) {
> -		/*
> -		 * We already have buffers allocated, so first check if they
> -		 * are not in use and can be freed.
> -		 */
> -		mutex_lock(&q->mmap_lock);
> -		if (q->memory == VB2_MEMORY_MMAP && __buffers_in_use(q)) {
> -			mutex_unlock(&q->mmap_lock);
> -			dprintk(1, "memory in use, cannot free\n");
> -			return -EBUSY;
> -		}
> -
>  		/*
>  		 * Call queue_cancel to clean up any buffers in the
>  		 * QUEUED state which is possible if buffers were prepared or
>  		 * queued without ever calling STREAMON.
>  		 */
>  		__vb2_queue_cancel(q);
> +		mutex_lock(&q->mmap_lock);
>  		ret = __vb2_queue_free(q, q->num_buffers);
>  		mutex_unlock(&q->mmap_lock);
>  		if (ret)
> diff --git a/drivers/media/common/videobuf2/videobuf2-v4l2.c b/drivers/media/common/videobuf2/videobuf2-v4l2.c
> index a17033ab2c22..f02d452ceeb9 100644
> --- a/drivers/media/common/videobuf2/videobuf2-v4l2.c
> +++ b/drivers/media/common/videobuf2/videobuf2-v4l2.c
> @@ -624,7 +624,7 @@ EXPORT_SYMBOL(vb2_querybuf);
>  
>  static void fill_buf_caps(struct vb2_queue *q, u32 *caps)
>  {
> -	*caps = 0;
> +	*caps = V4L2_BUF_CAP_SUPPORTS_ORPHANED_BUFS;
>  	if (q->io_modes & VB2_MMAP)
>  		*caps |= V4L2_BUF_CAP_SUPPORTS_MMAP;
>  	if (q->io_modes & VB2_USERPTR)
> diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
> index c8e8ff810190..2a223835214c 100644
> --- a/include/uapi/linux/videodev2.h
> +++ b/include/uapi/linux/videodev2.h
> @@ -879,6 +879,7 @@ struct v4l2_requestbuffers {
>  #define V4L2_BUF_CAP_SUPPORTS_USERPTR	(1 << 1)
>  #define V4L2_BUF_CAP_SUPPORTS_DMABUF	(1 << 2)
>  #define V4L2_BUF_CAP_SUPPORTS_REQUESTS	(1 << 3)
> +#define V4L2_BUF_CAP_SUPPORTS_ORPHANED_BUFS (1 << 4)
>  
>  /**
>   * struct v4l2_plane - plane info for multi-planar buffers
Nicolas Dufresne Nov. 13, 2018, 11:51 p.m. UTC | #4
Le mercredi 14 novembre 2018 à 00:27 +0200, Sakari Ailus a écrit :
> Hi Philipp,
> 
> On Tue, Nov 13, 2018 at 04:06:21PM +0100, Philipp Zabel wrote:
> > From: John Sheu <sheu@chromium.org>
> > 
> > Videobuf2 presently does not allow VIDIOC_REQBUFS to destroy outstanding
> > buffers if the queue is of type V4L2_MEMORY_MMAP, and if the buffers are
> > considered "in use".  This is different behavior than for other memory
> > types and prevents us from deallocating buffers in following two cases:
> > 
> > 1) There are outstanding mmap()ed views on the buffer. However even if
> >    we put the buffer in reqbufs(0), there will be remaining references,
> >    due to vma .open/close() adjusting vb2 buffer refcount appropriately.
> >    This means that the buffer will be in fact freed only when the last
> >    mmap()ed view is unmapped.
> > 
> > 2) Buffer has been exported as a DMABUF. Refcount of the vb2 buffer
> >    is managed properly by VB2 DMABUF ops, i.e. incremented on DMABUF
> >    get and decremented on DMABUF release. This means that the buffer
> >    will be alive until all importers release it.
> > 
> > Considering both cases above, there does not seem to be any need to
> > prevent reqbufs(0) operation, because buffer lifetime is already
> > properly managed by both mmap() and DMABUF code paths. Let's remove it
> > and allow userspace freeing the queue (and potentially allocating a new
> > one) even though old buffers might be still in processing.
> > 
> > To let userspace know that the kernel now supports orphaning buffers
> > that are still in use, add a new V4L2_BUF_CAP_SUPPORTS_ORPHANED_BUFS
> > to be set by reqbufs and create_bufs.
> > 
> > Signed-off-by: John Sheu <sheu@chromium.org>
> > Reviewed-by: Pawel Osciak <posciak@chromium.org>
> > Reviewed-by: Tomasz Figa <tfiga@chromium.org>
> > Signed-off-by: Tomasz Figa <tfiga@chromium.org>
> > [p.zabel@pengutronix.de: moved __vb2_queue_cancel out of the mmap_lock
> >  and added V4L2_BUF_CAP_SUPPORTS_ORPHANED_BUFS]
> > Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
> 
> This lets the user to allocate lots of mmap'ed buffers that are pinned in
> physical memory. Considering that we don't really have a proper mechanism
> to limit that anyway,

It's currently limited to 32 buffers. It's not worst then DRM dumb
buffers which will let you allocate as much as you want.

> 
> Acked-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> 
> That said, the patch must be accompanied by the documentation change in
> Documentation/media/uapi/v4l/vidioc-reqbufs.rst .
> 
> I wonder what Hans thinks.
> 
> > ---
> >  .../media/common/videobuf2/videobuf2-core.c   | 26 +------------------
> >  .../media/common/videobuf2/videobuf2-v4l2.c   |  2 +-
> >  include/uapi/linux/videodev2.h                |  1 +
> >  3 files changed, 3 insertions(+), 26 deletions(-)
> > 
> > diff --git a/drivers/media/common/videobuf2/videobuf2-core.c b/drivers/media/common/videobuf2/videobuf2-core.c
> > index 975ff5669f72..608459450c1e 100644
> > --- a/drivers/media/common/videobuf2/videobuf2-core.c
> > +++ b/drivers/media/common/videobuf2/videobuf2-core.c
> > @@ -553,20 +553,6 @@ bool vb2_buffer_in_use(struct vb2_queue *q, struct vb2_buffer *vb)
> >  }
> >  EXPORT_SYMBOL(vb2_buffer_in_use);
> >  
> > -/*
> > - * __buffers_in_use() - return true if any buffers on the queue are in use and
> > - * the queue cannot be freed (by the means of REQBUFS(0)) call
> > - */
> > -static bool __buffers_in_use(struct vb2_queue *q)
> > -{
> > -	unsigned int buffer;
> > -	for (buffer = 0; buffer < q->num_buffers; ++buffer) {
> > -		if (vb2_buffer_in_use(q, q->bufs[buffer]))
> > -			return true;
> > -	}
> > -	return false;
> > -}
> > -
> >  void vb2_core_querybuf(struct vb2_queue *q, unsigned int index, void *pb)
> >  {
> >  	call_void_bufop(q, fill_user_buffer, q->bufs[index], pb);
> > @@ -674,23 +660,13 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory,
> >  
> >  	if (*count == 0 || q->num_buffers != 0 ||
> >  	    (q->memory != VB2_MEMORY_UNKNOWN && q->memory != memory)) {
> > -		/*
> > -		 * We already have buffers allocated, so first check if they
> > -		 * are not in use and can be freed.
> > -		 */
> > -		mutex_lock(&q->mmap_lock);
> > -		if (q->memory == VB2_MEMORY_MMAP && __buffers_in_use(q)) {
> > -			mutex_unlock(&q->mmap_lock);
> > -			dprintk(1, "memory in use, cannot free\n");
> > -			return -EBUSY;
> > -		}
> > -
> >  		/*
> >  		 * Call queue_cancel to clean up any buffers in the
> >  		 * QUEUED state which is possible if buffers were prepared or
> >  		 * queued without ever calling STREAMON.
> >  		 */
> >  		__vb2_queue_cancel(q);
> > +		mutex_lock(&q->mmap_lock);
> >  		ret = __vb2_queue_free(q, q->num_buffers);
> >  		mutex_unlock(&q->mmap_lock);
> >  		if (ret)
> > diff --git a/drivers/media/common/videobuf2/videobuf2-v4l2.c b/drivers/media/common/videobuf2/videobuf2-v4l2.c
> > index a17033ab2c22..f02d452ceeb9 100644
> > --- a/drivers/media/common/videobuf2/videobuf2-v4l2.c
> > +++ b/drivers/media/common/videobuf2/videobuf2-v4l2.c
> > @@ -624,7 +624,7 @@ EXPORT_SYMBOL(vb2_querybuf);
> >  
> >  static void fill_buf_caps(struct vb2_queue *q, u32 *caps)
> >  {
> > -	*caps = 0;
> > +	*caps = V4L2_BUF_CAP_SUPPORTS_ORPHANED_BUFS;
> >  	if (q->io_modes & VB2_MMAP)
> >  		*caps |= V4L2_BUF_CAP_SUPPORTS_MMAP;
> >  	if (q->io_modes & VB2_USERPTR)
> > diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
> > index c8e8ff810190..2a223835214c 100644
> > --- a/include/uapi/linux/videodev2.h
> > +++ b/include/uapi/linux/videodev2.h
> > @@ -879,6 +879,7 @@ struct v4l2_requestbuffers {
> >  #define V4L2_BUF_CAP_SUPPORTS_USERPTR	(1 << 1)
> >  #define V4L2_BUF_CAP_SUPPORTS_DMABUF	(1 << 2)
> >  #define V4L2_BUF_CAP_SUPPORTS_REQUESTS	(1 << 3)
> > +#define V4L2_BUF_CAP_SUPPORTS_ORPHANED_BUFS (1 << 4)
> >  
> >  /**
> >   * struct v4l2_plane - plane info for multi-planar buffers
Tomasz Figa Nov. 14, 2018, 3:08 a.m. UTC | #5
On Wed, Nov 14, 2018 at 8:51 AM Nicolas Dufresne <nicolas@ndufresne.ca> wrote:
>
> Le mercredi 14 novembre 2018 à 00:27 +0200, Sakari Ailus a écrit :
> > Hi Philipp,
> >
> > On Tue, Nov 13, 2018 at 04:06:21PM +0100, Philipp Zabel wrote:
> > > From: John Sheu <sheu@chromium.org>
> > >
> > > Videobuf2 presently does not allow VIDIOC_REQBUFS to destroy outstanding
> > > buffers if the queue is of type V4L2_MEMORY_MMAP, and if the buffers are
> > > considered "in use".  This is different behavior than for other memory
> > > types and prevents us from deallocating buffers in following two cases:
> > >
> > > 1) There are outstanding mmap()ed views on the buffer. However even if
> > >    we put the buffer in reqbufs(0), there will be remaining references,
> > >    due to vma .open/close() adjusting vb2 buffer refcount appropriately.
> > >    This means that the buffer will be in fact freed only when the last
> > >    mmap()ed view is unmapped.
> > >
> > > 2) Buffer has been exported as a DMABUF. Refcount of the vb2 buffer
> > >    is managed properly by VB2 DMABUF ops, i.e. incremented on DMABUF
> > >    get and decremented on DMABUF release. This means that the buffer
> > >    will be alive until all importers release it.
> > >
> > > Considering both cases above, there does not seem to be any need to
> > > prevent reqbufs(0) operation, because buffer lifetime is already
> > > properly managed by both mmap() and DMABUF code paths. Let's remove it
> > > and allow userspace freeing the queue (and potentially allocating a new
> > > one) even though old buffers might be still in processing.
> > >
> > > To let userspace know that the kernel now supports orphaning buffers
> > > that are still in use, add a new V4L2_BUF_CAP_SUPPORTS_ORPHANED_BUFS
> > > to be set by reqbufs and create_bufs.
> > >
> > > Signed-off-by: John Sheu <sheu@chromium.org>
> > > Reviewed-by: Pawel Osciak <posciak@chromium.org>
> > > Reviewed-by: Tomasz Figa <tfiga@chromium.org>
> > > Signed-off-by: Tomasz Figa <tfiga@chromium.org>
> > > [p.zabel@pengutronix.de: moved __vb2_queue_cancel out of the mmap_lock
> > >  and added V4L2_BUF_CAP_SUPPORTS_ORPHANED_BUFS]
> > > Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
> >
> > This lets the user to allocate lots of mmap'ed buffers that are pinned in
> > physical memory. Considering that we don't really have a proper mechanism
> > to limit that anyway,
>
> It's currently limited to 32 buffers. It's not worst then DRM dumb
> buffers which will let you allocate as much as you want.
>

32 buffers for one mem2mem instance. One can open many of those and
allocate more anyway.

I think it's a part of the global problem of DMA memory not being
accounted to the process allocating...

Best regards,
Tomasz

> >
> > Acked-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> >
> > That said, the patch must be accompanied by the documentation change in
> > Documentation/media/uapi/v4l/vidioc-reqbufs.rst .
> >
> > I wonder what Hans thinks.
> >
> > > ---
> > >  .../media/common/videobuf2/videobuf2-core.c   | 26 +------------------
> > >  .../media/common/videobuf2/videobuf2-v4l2.c   |  2 +-
> > >  include/uapi/linux/videodev2.h                |  1 +
> > >  3 files changed, 3 insertions(+), 26 deletions(-)
> > >
> > > diff --git a/drivers/media/common/videobuf2/videobuf2-core.c b/drivers/media/common/videobuf2/videobuf2-core.c
> > > index 975ff5669f72..608459450c1e 100644
> > > --- a/drivers/media/common/videobuf2/videobuf2-core.c
> > > +++ b/drivers/media/common/videobuf2/videobuf2-core.c
> > > @@ -553,20 +553,6 @@ bool vb2_buffer_in_use(struct vb2_queue *q, struct vb2_buffer *vb)
> > >  }
> > >  EXPORT_SYMBOL(vb2_buffer_in_use);
> > >
> > > -/*
> > > - * __buffers_in_use() - return true if any buffers on the queue are in use and
> > > - * the queue cannot be freed (by the means of REQBUFS(0)) call
> > > - */
> > > -static bool __buffers_in_use(struct vb2_queue *q)
> > > -{
> > > -   unsigned int buffer;
> > > -   for (buffer = 0; buffer < q->num_buffers; ++buffer) {
> > > -           if (vb2_buffer_in_use(q, q->bufs[buffer]))
> > > -                   return true;
> > > -   }
> > > -   return false;
> > > -}
> > > -
> > >  void vb2_core_querybuf(struct vb2_queue *q, unsigned int index, void *pb)
> > >  {
> > >     call_void_bufop(q, fill_user_buffer, q->bufs[index], pb);
> > > @@ -674,23 +660,13 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory,
> > >
> > >     if (*count == 0 || q->num_buffers != 0 ||
> > >         (q->memory != VB2_MEMORY_UNKNOWN && q->memory != memory)) {
> > > -           /*
> > > -            * We already have buffers allocated, so first check if they
> > > -            * are not in use and can be freed.
> > > -            */
> > > -           mutex_lock(&q->mmap_lock);
> > > -           if (q->memory == VB2_MEMORY_MMAP && __buffers_in_use(q)) {
> > > -                   mutex_unlock(&q->mmap_lock);
> > > -                   dprintk(1, "memory in use, cannot free\n");
> > > -                   return -EBUSY;
> > > -           }
> > > -
> > >             /*
> > >              * Call queue_cancel to clean up any buffers in the
> > >              * QUEUED state which is possible if buffers were prepared or
> > >              * queued without ever calling STREAMON.
> > >              */
> > >             __vb2_queue_cancel(q);
> > > +           mutex_lock(&q->mmap_lock);
> > >             ret = __vb2_queue_free(q, q->num_buffers);
> > >             mutex_unlock(&q->mmap_lock);
> > >             if (ret)
> > > diff --git a/drivers/media/common/videobuf2/videobuf2-v4l2.c b/drivers/media/common/videobuf2/videobuf2-v4l2.c
> > > index a17033ab2c22..f02d452ceeb9 100644
> > > --- a/drivers/media/common/videobuf2/videobuf2-v4l2.c
> > > +++ b/drivers/media/common/videobuf2/videobuf2-v4l2.c
> > > @@ -624,7 +624,7 @@ EXPORT_SYMBOL(vb2_querybuf);
> > >
> > >  static void fill_buf_caps(struct vb2_queue *q, u32 *caps)
> > >  {
> > > -   *caps = 0;
> > > +   *caps = V4L2_BUF_CAP_SUPPORTS_ORPHANED_BUFS;
> > >     if (q->io_modes & VB2_MMAP)
> > >             *caps |= V4L2_BUF_CAP_SUPPORTS_MMAP;
> > >     if (q->io_modes & VB2_USERPTR)
> > > diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
> > > index c8e8ff810190..2a223835214c 100644
> > > --- a/include/uapi/linux/videodev2.h
> > > +++ b/include/uapi/linux/videodev2.h
> > > @@ -879,6 +879,7 @@ struct v4l2_requestbuffers {
> > >  #define V4L2_BUF_CAP_SUPPORTS_USERPTR      (1 << 1)
> > >  #define V4L2_BUF_CAP_SUPPORTS_DMABUF       (1 << 2)
> > >  #define V4L2_BUF_CAP_SUPPORTS_REQUESTS     (1 << 3)
> > > +#define V4L2_BUF_CAP_SUPPORTS_ORPHANED_BUFS (1 << 4)
> > >
> > >  /**
> > >   * struct v4l2_plane - plane info for multi-planar buffers
>
Philipp Zabel Nov. 14, 2018, 9:43 a.m. UTC | #6
Hi Sakari,

On Wed, 2018-11-14 at 00:27 +0200, Sakari Ailus wrote:
[...]
> This lets the user to allocate lots of mmap'ed buffers that are pinned in
> physical memory.

This is already possible without this patch, by closing the fd instead
of calling reqbufs(0).

> Considering that we don't really have a proper mechanism
> to limit that anyway,
> 
> Acked-by: Sakari Ailus <sakari.ailus@linux.intel.com>
>
> That said, the patch must be accompanied by the documentation change in
> Documentation/media/uapi/v4l/vidioc-reqbufs.rst .

Oh right, thanks. I'll add V4L2_BUF_CAP_SUPPORTS_ORPHANED_BUFS to
_v4l2-buf-capabilities in v2.

regards
Philipp
Philipp Zabel Nov. 14, 2018, 2:43 p.m. UTC | #7
Hi Hans,

On Tue, 2018-11-13 at 16:43 +0100, Hans Verkuil wrote:
> Hi Philipp,
> 
> On 11/13/18 16:06, Philipp Zabel wrote:
> > From: John Sheu <sheu@chromium.org>
> > 
> > Videobuf2 presently does not allow VIDIOC_REQBUFS to destroy outstanding
> > buffers if the queue is of type V4L2_MEMORY_MMAP, and if the buffers are
> > considered "in use".  This is different behavior than for other memory
> > types and prevents us from deallocating buffers in following two cases:
> > 
> > 1) There are outstanding mmap()ed views on the buffer. However even if
> >    we put the buffer in reqbufs(0), there will be remaining references,
> >    due to vma .open/close() adjusting vb2 buffer refcount appropriately.
> >    This means that the buffer will be in fact freed only when the last
> >    mmap()ed view is unmapped.
> > 
> > 2) Buffer has been exported as a DMABUF. Refcount of the vb2 buffer
> >    is managed properly by VB2 DMABUF ops, i.e. incremented on DMABUF
> >    get and decremented on DMABUF release. This means that the buffer
> >    will be alive until all importers release it.
> > 
> > Considering both cases above, there does not seem to be any need to
> > prevent reqbufs(0) operation, because buffer lifetime is already
> > properly managed by both mmap() and DMABUF code paths. Let's remove it
> > and allow userspace freeing the queue (and potentially allocating a new
> > one) even though old buffers might be still in processing.
> > 
> > To let userspace know that the kernel now supports orphaning buffers
> > that are still in use, add a new V4L2_BUF_CAP_SUPPORTS_ORPHANED_BUFS
> > to be set by reqbufs and create_bufs.
> 
> Looks good, but I have some questions:
> 
> 1) does v4l2-compliance together with vivid (easiest to test) still work?
>    I don't think I have a proper test for this in v4l2-compliance, but
>    I'm not 100% certain. If it fails with this patch, then please provide
>    a fix for v4l2-compliance as well.

I have tested on v4.20-rc2 with 92539d3eda2c ("media: v4l: event: Add
subscription to list before calling "add" operation") and this patch
applied:

$ modprobe vivid no_error_inj=1
vivid-000: V4L2 capture device registered as video15
vivid-000: V4L2 output device registered as video16

$ v4l2-compliance -d 15 -s 1 --expbuf-device 16
v4l2-compliance SHA: 98b4c9f276a18535b5691e5f350f59ffbf5a9aa5, 32 bits
...
Total: 112, Succeeded: 112, Failed: 0, Warnings: 4

The warnings are:
		warn: v4l2-test-formats.cpp(1426): doioctl(node, VIDIOC_CROPCAP, &cap)
	test Cropping: OK
(one per input) and:
		warn: v4l2-test-controls.cpp(845): V4L2_CID_DV_RX_POWER_PRESENT not found for input 3
	test VIDIOC_(UN)SUBSCRIBE_EVENT/DQEVENT: OK

> 2) I would like to see a new test in v4l2-compliance for this: i.e. if
>    the capability is set, then check that you can call REQBUFS(0) before
>    unmapping all buffers. Ditto with dmabuffers.
>
> I said during the media summit that I wanted to be more strict about
> requiring compliance tests before adding new features, so you're the
> unlucky victim of that :-)

That's fair. The SHA above is actually a lie, I had one patch applied.

regards
Philipp
Hans Verkuil Nov. 14, 2018, 3:25 p.m. UTC | #8
On 11/14/18 15:43, Philipp Zabel wrote:
> Hi Hans,
> 
> On Tue, 2018-11-13 at 16:43 +0100, Hans Verkuil wrote:
>> Hi Philipp,
>>
>> On 11/13/18 16:06, Philipp Zabel wrote:
>>> From: John Sheu <sheu@chromium.org>
>>>
>>> Videobuf2 presently does not allow VIDIOC_REQBUFS to destroy outstanding
>>> buffers if the queue is of type V4L2_MEMORY_MMAP, and if the buffers are
>>> considered "in use".  This is different behavior than for other memory
>>> types and prevents us from deallocating buffers in following two cases:
>>>
>>> 1) There are outstanding mmap()ed views on the buffer. However even if
>>>    we put the buffer in reqbufs(0), there will be remaining references,
>>>    due to vma .open/close() adjusting vb2 buffer refcount appropriately.
>>>    This means that the buffer will be in fact freed only when the last
>>>    mmap()ed view is unmapped.
>>>
>>> 2) Buffer has been exported as a DMABUF. Refcount of the vb2 buffer
>>>    is managed properly by VB2 DMABUF ops, i.e. incremented on DMABUF
>>>    get and decremented on DMABUF release. This means that the buffer
>>>    will be alive until all importers release it.
>>>
>>> Considering both cases above, there does not seem to be any need to
>>> prevent reqbufs(0) operation, because buffer lifetime is already
>>> properly managed by both mmap() and DMABUF code paths. Let's remove it
>>> and allow userspace freeing the queue (and potentially allocating a new
>>> one) even though old buffers might be still in processing.
>>>
>>> To let userspace know that the kernel now supports orphaning buffers
>>> that are still in use, add a new V4L2_BUF_CAP_SUPPORTS_ORPHANED_BUFS
>>> to be set by reqbufs and create_bufs.
>>
>> Looks good, but I have some questions:
>>
>> 1) does v4l2-compliance together with vivid (easiest to test) still work?
>>    I don't think I have a proper test for this in v4l2-compliance, but
>>    I'm not 100% certain. If it fails with this patch, then please provide
>>    a fix for v4l2-compliance as well.
> 
> I have tested on v4.20-rc2 with 92539d3eda2c ("media: v4l: event: Add
> subscription to list before calling "add" operation") and this patch
> applied:
> 
> $ modprobe vivid no_error_inj=1
> vivid-000: V4L2 capture device registered as video15
> vivid-000: V4L2 output device registered as video16
> 
> $ v4l2-compliance -d 15 -s 1 --expbuf-device 16
> v4l2-compliance SHA: 98b4c9f276a18535b5691e5f350f59ffbf5a9aa5, 32 bits
> ...
> Total: 112, Succeeded: 112, Failed: 0, Warnings: 4
> 
> The warnings are:
> 		warn: v4l2-test-formats.cpp(1426): doioctl(node, VIDIOC_CROPCAP, &cap)

Will be fixed when https://patchwork.linuxtv.org/patch/52811/ is merged.

> 	test Cropping: OK
> (one per input) and:
> 		warn: v4l2-test-controls.cpp(845): V4L2_CID_DV_RX_POWER_PRESENT not found for input 3

Waiting for a volunteer to teach vivid to properly emulate an HDMI connector.

So this looks good.

Will look at the v4l2-compliance patch tomorrow.

Regards,

	Hans

> 	test VIDIOC_(UN)SUBSCRIBE_EVENT/DQEVENT: OK
> 
>> 2) I would like to see a new test in v4l2-compliance for this: i.e. if
>>    the capability is set, then check that you can call REQBUFS(0) before
>>    unmapping all buffers. Ditto with dmabuffers.
>>
>> I said during the media summit that I wanted to be more strict about
>> requiring compliance tests before adding new features, so you're the
>> unlucky victim of that :-)
> 
> That's fair. The SHA above is actually a lie, I had one patch applied.
> 
> regards
> Philipp
>
Laurent Pinchart Nov. 14, 2018, 7:52 p.m. UTC | #9
Hi Hans,

On Tuesday, 13 November 2018 17:43:48 EET Hans Verkuil wrote:
> On 11/13/18 16:06, Philipp Zabel wrote:
> > From: John Sheu <sheu@chromium.org>
> > 
> > Videobuf2 presently does not allow VIDIOC_REQBUFS to destroy outstanding
> > buffers if the queue is of type V4L2_MEMORY_MMAP, and if the buffers are
> > considered "in use".  This is different behavior than for other memory
> > types and prevents us from deallocating buffers in following two cases:
> > 
> > 1) There are outstanding mmap()ed views on the buffer. However even if
> >    we put the buffer in reqbufs(0), there will be remaining references,
> >    due to vma .open/close() adjusting vb2 buffer refcount appropriately.
> >    This means that the buffer will be in fact freed only when the last
> >    mmap()ed view is unmapped.
> > 
> > 2) Buffer has been exported as a DMABUF. Refcount of the vb2 buffer
> >    is managed properly by VB2 DMABUF ops, i.e. incremented on DMABUF
> >    get and decremented on DMABUF release. This means that the buffer
> >    will be alive until all importers release it.
> > 
> > Considering both cases above, there does not seem to be any need to
> > prevent reqbufs(0) operation, because buffer lifetime is already
> > properly managed by both mmap() and DMABUF code paths. Let's remove it
> > and allow userspace freeing the queue (and potentially allocating a new
> > one) even though old buffers might be still in processing.
> > 
> > To let userspace know that the kernel now supports orphaning buffers
> > that are still in use, add a new V4L2_BUF_CAP_SUPPORTS_ORPHANED_BUFS
> > to be set by reqbufs and create_bufs.
> 
> Looks good, but I have some questions:
> 
> 1) does v4l2-compliance together with vivid (easiest to test) still work?
>    I don't think I have a proper test for this in v4l2-compliance, but
>    I'm not 100% certain. If it fails with this patch, then please provide
>    a fix for v4l2-compliance as well.
> 
> 2) I would like to see a new test in v4l2-compliance for this: i.e. if
>    the capability is set, then check that you can call REQBUFS(0) before
>    unmapping all buffers. Ditto with dmabuffers.
> 
> I said during the media summit that I wanted to be more strict about
> requiring compliance tests before adding new features, so you're the
> unlucky victim of that :-)

Do you have plans to refactor and document the v4l2-compliance internals to 
make it easier ?

> Look for munmap_bufs in v4l2-test-buffers.cpp (the MMAP case). The dmabuf
> tests are a bit trickier since I noticed that I never actually close
> the dmabuf fds in v4l2-compliance. This will fix that:
> 
> diff --git a/utils/v4l2-compliance/v4l2-test-buffers.cpp
> b/utils/v4l2-compliance/v4l2-test-buffers.cpp index c59a56d9..03639301
> 100644
> --- a/utils/v4l2-compliance/v4l2-test-buffers.cpp
> +++ b/utils/v4l2-compliance/v4l2-test-buffers.cpp
> @@ -1201,6 +1201,7 @@ int testDmaBuf(struct node *expbuf_node, struct node
> *node, unsigned frame_count fail_on_test(captureBufs(node, q, m2m_q,
> frame_count, true));
>  		fail_on_test(node->streamoff(q.g_type()));
>  		fail_on_test(node->streamoff(q.g_type()));
> +		exp_q.close_exported_fds();
>  	}
>  	return 0;
>  }
> 
> What is also missing in testDmaBuf is calling q.reqbufs(node, 0) to free all
> buffers, and I never munmap the buffers by calling q.munmap_bufs(node);
> 
> In other words, clearly I never wrote proper tests for the behavior of
> mmap()/dmabuf and REQBUFS(0).
> 
> Regards,
> 
> 	Hans
> 
> > Signed-off-by: John Sheu <sheu@chromium.org>
> > Reviewed-by: Pawel Osciak <posciak@chromium.org>
> > Reviewed-by: Tomasz Figa <tfiga@chromium.org>
> > Signed-off-by: Tomasz Figa <tfiga@chromium.org>
> > [p.zabel@pengutronix.de: moved __vb2_queue_cancel out of the mmap_lock
> > 
> >  and added V4L2_BUF_CAP_SUPPORTS_ORPHANED_BUFS]
> > 
> > Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
> > ---
> > 
> >  .../media/common/videobuf2/videobuf2-core.c   | 26 +------------------
> >  .../media/common/videobuf2/videobuf2-v4l2.c   |  2 +-
> >  include/uapi/linux/videodev2.h                |  1 +
> >  3 files changed, 3 insertions(+), 26 deletions(-)
> > 
> > diff --git a/drivers/media/common/videobuf2/videobuf2-core.c
> > b/drivers/media/common/videobuf2/videobuf2-core.c index
> > 975ff5669f72..608459450c1e 100644
> > --- a/drivers/media/common/videobuf2/videobuf2-core.c
> > +++ b/drivers/media/common/videobuf2/videobuf2-core.c
> > @@ -553,20 +553,6 @@ bool vb2_buffer_in_use(struct vb2_queue *q, struct
> > vb2_buffer *vb)> 
> >  }
> >  EXPORT_SYMBOL(vb2_buffer_in_use);
> > 
> > -/*
> > - * __buffers_in_use() - return true if any buffers on the queue are in
> > use and - * the queue cannot be freed (by the means of REQBUFS(0)) call
> > - */
> > -static bool __buffers_in_use(struct vb2_queue *q)
> > -{
> > -	unsigned int buffer;
> > -	for (buffer = 0; buffer < q->num_buffers; ++buffer) {
> > -		if (vb2_buffer_in_use(q, q->bufs[buffer]))
> > -			return true;
> > -	}
> > -	return false;
> > -}
> > -
> > 
> >  void vb2_core_querybuf(struct vb2_queue *q, unsigned int index, void *pb)
> >  {
> >  
> >  	call_void_bufop(q, fill_user_buffer, q->bufs[index], pb);
> > 
> > @@ -674,23 +660,13 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum
> > vb2_memory memory,> 
> >  	if (*count == 0 || q->num_buffers != 0 ||
> >  	
> >  	    (q->memory != VB2_MEMORY_UNKNOWN && q->memory != memory)) {
> > 
> > -		/*
> > -		 * We already have buffers allocated, so first check if they
> > -		 * are not in use and can be freed.
> > -		 */
> > -		mutex_lock(&q->mmap_lock);
> > -		if (q->memory == VB2_MEMORY_MMAP && __buffers_in_use(q)) {
> > -			mutex_unlock(&q->mmap_lock);
> > -			dprintk(1, "memory in use, cannot free\n");
> > -			return -EBUSY;
> > -		}
> > -
> > 
> >  		/*
> >  		
> >  		 * Call queue_cancel to clean up any buffers in the
> >  		 * QUEUED state which is possible if buffers were prepared or
> >  		 * queued without ever calling STREAMON.
> >  		 */
> >  		
> >  		__vb2_queue_cancel(q);
> > 
> > +		mutex_lock(&q->mmap_lock);
> > 
> >  		ret = __vb2_queue_free(q, q->num_buffers);
> >  		mutex_unlock(&q->mmap_lock);
> >  		if (ret)
> > 
> > diff --git a/drivers/media/common/videobuf2/videobuf2-v4l2.c
> > b/drivers/media/common/videobuf2/videobuf2-v4l2.c index
> > a17033ab2c22..f02d452ceeb9 100644
> > --- a/drivers/media/common/videobuf2/videobuf2-v4l2.c
> > +++ b/drivers/media/common/videobuf2/videobuf2-v4l2.c
> > @@ -624,7 +624,7 @@ EXPORT_SYMBOL(vb2_querybuf);
> > 
> >  static void fill_buf_caps(struct vb2_queue *q, u32 *caps)
> >  {
> > 
> > -	*caps = 0;
> > +	*caps = V4L2_BUF_CAP_SUPPORTS_ORPHANED_BUFS;
> > 
> >  	if (q->io_modes & VB2_MMAP)
> >  	
> >  		*caps |= V4L2_BUF_CAP_SUPPORTS_MMAP;
> >  	
> >  	if (q->io_modes & VB2_USERPTR)
> > 
> > diff --git a/include/uapi/linux/videodev2.h
> > b/include/uapi/linux/videodev2.h index c8e8ff810190..2a223835214c 100644
> > --- a/include/uapi/linux/videodev2.h
> > +++ b/include/uapi/linux/videodev2.h
> > @@ -879,6 +879,7 @@ struct v4l2_requestbuffers {
> > 
> >  #define V4L2_BUF_CAP_SUPPORTS_USERPTR	(1 << 1)
> >  #define V4L2_BUF_CAP_SUPPORTS_DMABUF	(1 << 2)
> >  #define V4L2_BUF_CAP_SUPPORTS_REQUESTS	(1 << 3)
> > 
> > +#define V4L2_BUF_CAP_SUPPORTS_ORPHANED_BUFS (1 << 4)
> > 
> >  /**
> >  
> >   * struct v4l2_plane - plane info for multi-planar buffers
Hans Verkuil Nov. 15, 2018, 7:30 a.m. UTC | #10
On 11/14/2018 08:52 PM, Laurent Pinchart wrote:
> Hi Hans,
> 
> On Tuesday, 13 November 2018 17:43:48 EET Hans Verkuil wrote:
>> On 11/13/18 16:06, Philipp Zabel wrote:
>>> From: John Sheu <sheu@chromium.org>
>>>
>>> Videobuf2 presently does not allow VIDIOC_REQBUFS to destroy outstanding
>>> buffers if the queue is of type V4L2_MEMORY_MMAP, and if the buffers are
>>> considered "in use".  This is different behavior than for other memory
>>> types and prevents us from deallocating buffers in following two cases:
>>>
>>> 1) There are outstanding mmap()ed views on the buffer. However even if
>>>    we put the buffer in reqbufs(0), there will be remaining references,
>>>    due to vma .open/close() adjusting vb2 buffer refcount appropriately.
>>>    This means that the buffer will be in fact freed only when the last
>>>    mmap()ed view is unmapped.
>>>
>>> 2) Buffer has been exported as a DMABUF. Refcount of the vb2 buffer
>>>    is managed properly by VB2 DMABUF ops, i.e. incremented on DMABUF
>>>    get and decremented on DMABUF release. This means that the buffer
>>>    will be alive until all importers release it.
>>>
>>> Considering both cases above, there does not seem to be any need to
>>> prevent reqbufs(0) operation, because buffer lifetime is already
>>> properly managed by both mmap() and DMABUF code paths. Let's remove it
>>> and allow userspace freeing the queue (and potentially allocating a new
>>> one) even though old buffers might be still in processing.
>>>
>>> To let userspace know that the kernel now supports orphaning buffers
>>> that are still in use, add a new V4L2_BUF_CAP_SUPPORTS_ORPHANED_BUFS
>>> to be set by reqbufs and create_bufs.
>>
>> Looks good, but I have some questions:
>>
>> 1) does v4l2-compliance together with vivid (easiest to test) still work?
>>    I don't think I have a proper test for this in v4l2-compliance, but
>>    I'm not 100% certain. If it fails with this patch, then please provide
>>    a fix for v4l2-compliance as well.
>>
>> 2) I would like to see a new test in v4l2-compliance for this: i.e. if
>>    the capability is set, then check that you can call REQBUFS(0) before
>>    unmapping all buffers. Ditto with dmabuffers.
>>
>> I said during the media summit that I wanted to be more strict about
>> requiring compliance tests before adding new features, so you're the
>> unlucky victim of that :-)
> 
> Do you have plans to refactor and document the v4l2-compliance internals to 
> make it easier ?

Yes. I hope to be able to set aside one or two days for that in the next two
weeks.

Regards,

	Hans
Laurent Pinchart Nov. 15, 2018, 7:49 a.m. UTC | #11
Hi Hans,


On Thursday, 15 November 2018 09:30:55 EET Hans Verkuil wrote:
> On 11/14/2018 08:52 PM, Laurent Pinchart wrote:
> > On Tuesday, 13 November 2018 17:43:48 EET Hans Verkuil wrote:
> >> On 11/13/18 16:06, Philipp Zabel wrote:
> >>> From: John Sheu <sheu@chromium.org>
> >>> 
> >>> Videobuf2 presently does not allow VIDIOC_REQBUFS to destroy outstanding
> >>> buffers if the queue is of type V4L2_MEMORY_MMAP, and if the buffers are
> >>> considered "in use".  This is different behavior than for other memory
> >>> types and prevents us from deallocating buffers in following two cases:
> >>> 
> >>> 1) There are outstanding mmap()ed views on the buffer. However even if
> >>>    we put the buffer in reqbufs(0), there will be remaining references,
> >>>    due to vma .open/close() adjusting vb2 buffer refcount appropriately.
> >>>    This means that the buffer will be in fact freed only when the last
> >>>    mmap()ed view is unmapped.
> >>> 
> >>> 2) Buffer has been exported as a DMABUF. Refcount of the vb2 buffer
> >>>    is managed properly by VB2 DMABUF ops, i.e. incremented on DMABUF
> >>>    get and decremented on DMABUF release. This means that the buffer
> >>>    will be alive until all importers release it.
> >>> 
> >>> Considering both cases above, there does not seem to be any need to
> >>> prevent reqbufs(0) operation, because buffer lifetime is already
> >>> properly managed by both mmap() and DMABUF code paths. Let's remove it
> >>> and allow userspace freeing the queue (and potentially allocating a new
> >>> one) even though old buffers might be still in processing.
> >>> 
> >>> To let userspace know that the kernel now supports orphaning buffers
> >>> that are still in use, add a new V4L2_BUF_CAP_SUPPORTS_ORPHANED_BUFS
> >>> to be set by reqbufs and create_bufs.
> >> 
> >> Looks good, but I have some questions:
> >> 
> >> 1) does v4l2-compliance together with vivid (easiest to test) still work?
> >>    I don't think I have a proper test for this in v4l2-compliance, but
> >>    I'm not 100% certain. If it fails with this patch, then please provide
> >>    a fix for v4l2-compliance as well.
> >> 
> >> 2) I would like to see a new test in v4l2-compliance for this: i.e. if
> >>    the capability is set, then check that you can call REQBUFS(0) before
> >>    unmapping all buffers. Ditto with dmabuffers.
> >> 
> >> I said during the media summit that I wanted to be more strict about
> >> requiring compliance tests before adding new features, so you're the
> >> unlucky victim of that :-)
> > 
> > Do you have plans to refactor and document the v4l2-compliance internals
> > to make it easier ?
> 
> Yes. I hope to be able to set aside one or two days for that in the next two
> weeks.

That would be great ! Let me know if you would like to discuss how the code 
base could be refactored.
Hans Verkuil Nov. 15, 2018, 8 a.m. UTC | #12
On 11/15/2018 08:49 AM, Laurent Pinchart wrote:
> Hi Hans,
> 
> 
> On Thursday, 15 November 2018 09:30:55 EET Hans Verkuil wrote:
>> On 11/14/2018 08:52 PM, Laurent Pinchart wrote:
>>> On Tuesday, 13 November 2018 17:43:48 EET Hans Verkuil wrote:
>>>> On 11/13/18 16:06, Philipp Zabel wrote:
>>>>> From: John Sheu <sheu@chromium.org>
>>>>>
>>>>> Videobuf2 presently does not allow VIDIOC_REQBUFS to destroy outstanding
>>>>> buffers if the queue is of type V4L2_MEMORY_MMAP, and if the buffers are
>>>>> considered "in use".  This is different behavior than for other memory
>>>>> types and prevents us from deallocating buffers in following two cases:
>>>>>
>>>>> 1) There are outstanding mmap()ed views on the buffer. However even if
>>>>>    we put the buffer in reqbufs(0), there will be remaining references,
>>>>>    due to vma .open/close() adjusting vb2 buffer refcount appropriately.
>>>>>    This means that the buffer will be in fact freed only when the last
>>>>>    mmap()ed view is unmapped.
>>>>>
>>>>> 2) Buffer has been exported as a DMABUF. Refcount of the vb2 buffer
>>>>>    is managed properly by VB2 DMABUF ops, i.e. incremented on DMABUF
>>>>>    get and decremented on DMABUF release. This means that the buffer
>>>>>    will be alive until all importers release it.
>>>>>
>>>>> Considering both cases above, there does not seem to be any need to
>>>>> prevent reqbufs(0) operation, because buffer lifetime is already
>>>>> properly managed by both mmap() and DMABUF code paths. Let's remove it
>>>>> and allow userspace freeing the queue (and potentially allocating a new
>>>>> one) even though old buffers might be still in processing.
>>>>>
>>>>> To let userspace know that the kernel now supports orphaning buffers
>>>>> that are still in use, add a new V4L2_BUF_CAP_SUPPORTS_ORPHANED_BUFS
>>>>> to be set by reqbufs and create_bufs.
>>>>
>>>> Looks good, but I have some questions:
>>>>
>>>> 1) does v4l2-compliance together with vivid (easiest to test) still work?
>>>>    I don't think I have a proper test for this in v4l2-compliance, but
>>>>    I'm not 100% certain. If it fails with this patch, then please provide
>>>>    a fix for v4l2-compliance as well.
>>>>
>>>> 2) I would like to see a new test in v4l2-compliance for this: i.e. if
>>>>    the capability is set, then check that you can call REQBUFS(0) before
>>>>    unmapping all buffers. Ditto with dmabuffers.
>>>>
>>>> I said during the media summit that I wanted to be more strict about
>>>> requiring compliance tests before adding new features, so you're the
>>>> unlucky victim of that :-)
>>>
>>> Do you have plans to refactor and document the v4l2-compliance internals
>>> to make it easier ?
>>
>> Yes. I hope to be able to set aside one or two days for that in the next two
>> weeks.
> 
> That would be great ! Let me know if you would like to discuss how the code 
> base could be refactored.
> 

I'm happy to hear your ideas, but I only have one day for refactoring, so it is
very limited what can be done.

Frankly, it is mainly v4l2-test-buffers.cpp that I would like to split up in
two parts: one for the tests that do not require actual streaming and one part
for all the streaming tests.

Documentation (esp. cv4l-helpers.h which is used a lot) is much more important
and I wanted to spend the second day on that.

Regards,

	Hans
diff mbox series

Patch

diff --git a/drivers/media/common/videobuf2/videobuf2-core.c b/drivers/media/common/videobuf2/videobuf2-core.c
index 975ff5669f72..608459450c1e 100644
--- a/drivers/media/common/videobuf2/videobuf2-core.c
+++ b/drivers/media/common/videobuf2/videobuf2-core.c
@@ -553,20 +553,6 @@  bool vb2_buffer_in_use(struct vb2_queue *q, struct vb2_buffer *vb)
 }
 EXPORT_SYMBOL(vb2_buffer_in_use);
 
-/*
- * __buffers_in_use() - return true if any buffers on the queue are in use and
- * the queue cannot be freed (by the means of REQBUFS(0)) call
- */
-static bool __buffers_in_use(struct vb2_queue *q)
-{
-	unsigned int buffer;
-	for (buffer = 0; buffer < q->num_buffers; ++buffer) {
-		if (vb2_buffer_in_use(q, q->bufs[buffer]))
-			return true;
-	}
-	return false;
-}
-
 void vb2_core_querybuf(struct vb2_queue *q, unsigned int index, void *pb)
 {
 	call_void_bufop(q, fill_user_buffer, q->bufs[index], pb);
@@ -674,23 +660,13 @@  int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory,
 
 	if (*count == 0 || q->num_buffers != 0 ||
 	    (q->memory != VB2_MEMORY_UNKNOWN && q->memory != memory)) {
-		/*
-		 * We already have buffers allocated, so first check if they
-		 * are not in use and can be freed.
-		 */
-		mutex_lock(&q->mmap_lock);
-		if (q->memory == VB2_MEMORY_MMAP && __buffers_in_use(q)) {
-			mutex_unlock(&q->mmap_lock);
-			dprintk(1, "memory in use, cannot free\n");
-			return -EBUSY;
-		}
-
 		/*
 		 * Call queue_cancel to clean up any buffers in the
 		 * QUEUED state which is possible if buffers were prepared or
 		 * queued without ever calling STREAMON.
 		 */
 		__vb2_queue_cancel(q);
+		mutex_lock(&q->mmap_lock);
 		ret = __vb2_queue_free(q, q->num_buffers);
 		mutex_unlock(&q->mmap_lock);
 		if (ret)
diff --git a/drivers/media/common/videobuf2/videobuf2-v4l2.c b/drivers/media/common/videobuf2/videobuf2-v4l2.c
index a17033ab2c22..f02d452ceeb9 100644
--- a/drivers/media/common/videobuf2/videobuf2-v4l2.c
+++ b/drivers/media/common/videobuf2/videobuf2-v4l2.c
@@ -624,7 +624,7 @@  EXPORT_SYMBOL(vb2_querybuf);
 
 static void fill_buf_caps(struct vb2_queue *q, u32 *caps)
 {
-	*caps = 0;
+	*caps = V4L2_BUF_CAP_SUPPORTS_ORPHANED_BUFS;
 	if (q->io_modes & VB2_MMAP)
 		*caps |= V4L2_BUF_CAP_SUPPORTS_MMAP;
 	if (q->io_modes & VB2_USERPTR)
diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
index c8e8ff810190..2a223835214c 100644
--- a/include/uapi/linux/videodev2.h
+++ b/include/uapi/linux/videodev2.h
@@ -879,6 +879,7 @@  struct v4l2_requestbuffers {
 #define V4L2_BUF_CAP_SUPPORTS_USERPTR	(1 << 1)
 #define V4L2_BUF_CAP_SUPPORTS_DMABUF	(1 << 2)
 #define V4L2_BUF_CAP_SUPPORTS_REQUESTS	(1 << 3)
+#define V4L2_BUF_CAP_SUPPORTS_ORPHANED_BUFS (1 << 4)
 
 /**
  * struct v4l2_plane - plane info for multi-planar buffers