mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-27 03:10:12 +00:00
[media] videobuf2-core: fix plane_sizes handling in VIDIOC_CREATE_BUFS
The handling of q->plane_sizes was wrong in vb2_core_create_bufs(). The q->plane_sizes array was global and it was overwritten by create_bufs. So if reqbufs was called with e.g. size 100000 then q->plane_sizes[0] would be set to 100000. If create_bufs was called afterwards with size 200000, then q->plane_sizes[0] would be overwritten with the new value. Calling create_bufs again for size 100000 would cause an error since 100000 is now less than q->plane_sizes[0]. This patch fixes this problem by 1) removing q->plane_sizes and using the vb->planes[].length field instead, and 2) by introducing a min_length field in struct vb2_plane. This field is set to the plane size as returned by the queue_setup op and is the minimum required plane size. So user pointers or dmabufs should all be at least this size. Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com> Reported-by: Sakari Ailus <sakari.ailus@linux.intel.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
This commit is contained in:
parent
20eedf0e16
commit
58e1ba3ce6
2 changed files with 24 additions and 19 deletions
|
@ -203,7 +203,7 @@ static int __vb2_buf_mem_alloc(struct vb2_buffer *vb)
|
||||||
* NOTE: mmapped areas should be page aligned
|
* NOTE: mmapped areas should be page aligned
|
||||||
*/
|
*/
|
||||||
for (plane = 0; plane < vb->num_planes; ++plane) {
|
for (plane = 0; plane < vb->num_planes; ++plane) {
|
||||||
unsigned long size = PAGE_ALIGN(q->plane_sizes[plane]);
|
unsigned long size = PAGE_ALIGN(vb->planes[plane].length);
|
||||||
|
|
||||||
mem_priv = call_ptr_memop(vb, alloc, q->alloc_ctx[plane],
|
mem_priv = call_ptr_memop(vb, alloc, q->alloc_ctx[plane],
|
||||||
size, dma_dir, q->gfp_flags);
|
size, dma_dir, q->gfp_flags);
|
||||||
|
@ -212,7 +212,6 @@ static int __vb2_buf_mem_alloc(struct vb2_buffer *vb)
|
||||||
|
|
||||||
/* Associate allocator private data with this plane */
|
/* Associate allocator private data with this plane */
|
||||||
vb->planes[plane].mem_priv = mem_priv;
|
vb->planes[plane].mem_priv = mem_priv;
|
||||||
vb->planes[plane].length = q->plane_sizes[plane];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -322,7 +321,8 @@ static void __setup_offsets(struct vb2_buffer *vb)
|
||||||
* Returns the number of buffers successfully allocated.
|
* Returns the number of buffers successfully allocated.
|
||||||
*/
|
*/
|
||||||
static int __vb2_queue_alloc(struct vb2_queue *q, enum vb2_memory memory,
|
static int __vb2_queue_alloc(struct vb2_queue *q, enum vb2_memory memory,
|
||||||
unsigned int num_buffers, unsigned int num_planes)
|
unsigned int num_buffers, unsigned int num_planes,
|
||||||
|
const unsigned plane_sizes[VB2_MAX_PLANES])
|
||||||
{
|
{
|
||||||
unsigned int buffer, plane;
|
unsigned int buffer, plane;
|
||||||
struct vb2_buffer *vb;
|
struct vb2_buffer *vb;
|
||||||
|
@ -342,8 +342,10 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum vb2_memory memory,
|
||||||
vb->index = q->num_buffers + buffer;
|
vb->index = q->num_buffers + buffer;
|
||||||
vb->type = q->type;
|
vb->type = q->type;
|
||||||
vb->memory = memory;
|
vb->memory = memory;
|
||||||
for (plane = 0; plane < num_planes; ++plane)
|
for (plane = 0; plane < num_planes; ++plane) {
|
||||||
vb->planes[plane].length = q->plane_sizes[plane];
|
vb->planes[plane].length = plane_sizes[plane];
|
||||||
|
vb->planes[plane].min_length = plane_sizes[plane];
|
||||||
|
}
|
||||||
q->bufs[vb->index] = vb;
|
q->bufs[vb->index] = vb;
|
||||||
|
|
||||||
/* Allocate video buffer memory for the MMAP type */
|
/* Allocate video buffer memory for the MMAP type */
|
||||||
|
@ -352,8 +354,8 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum vb2_memory memory,
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dprintk(1, "failed allocating memory for "
|
dprintk(1, "failed allocating memory for "
|
||||||
"buffer %d\n", buffer);
|
"buffer %d\n", buffer);
|
||||||
kfree(vb);
|
|
||||||
q->bufs[vb->index] = NULL;
|
q->bufs[vb->index] = NULL;
|
||||||
|
kfree(vb);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
__setup_offsets(vb);
|
__setup_offsets(vb);
|
||||||
|
@ -690,6 +692,7 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory,
|
||||||
unsigned int *count)
|
unsigned int *count)
|
||||||
{
|
{
|
||||||
unsigned int num_buffers, allocated_buffers, num_planes = 0;
|
unsigned int num_buffers, allocated_buffers, num_planes = 0;
|
||||||
|
unsigned plane_sizes[VB2_MAX_PLANES] = { };
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (q->streaming) {
|
if (q->streaming) {
|
||||||
|
@ -733,7 +736,6 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory,
|
||||||
*/
|
*/
|
||||||
num_buffers = min_t(unsigned int, *count, VB2_MAX_FRAME);
|
num_buffers = min_t(unsigned int, *count, VB2_MAX_FRAME);
|
||||||
num_buffers = max_t(unsigned int, num_buffers, q->min_buffers_needed);
|
num_buffers = max_t(unsigned int, num_buffers, q->min_buffers_needed);
|
||||||
memset(q->plane_sizes, 0, sizeof(q->plane_sizes));
|
|
||||||
memset(q->alloc_ctx, 0, sizeof(q->alloc_ctx));
|
memset(q->alloc_ctx, 0, sizeof(q->alloc_ctx));
|
||||||
q->memory = memory;
|
q->memory = memory;
|
||||||
|
|
||||||
|
@ -742,13 +744,13 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory,
|
||||||
* Driver also sets the size and allocator context for each plane.
|
* Driver also sets the size and allocator context for each plane.
|
||||||
*/
|
*/
|
||||||
ret = call_qop(q, queue_setup, q, &num_buffers, &num_planes,
|
ret = call_qop(q, queue_setup, q, &num_buffers, &num_planes,
|
||||||
q->plane_sizes, q->alloc_ctx);
|
plane_sizes, q->alloc_ctx);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
/* Finally, allocate buffers and video memory */
|
/* Finally, allocate buffers and video memory */
|
||||||
allocated_buffers =
|
allocated_buffers =
|
||||||
__vb2_queue_alloc(q, memory, num_buffers, num_planes);
|
__vb2_queue_alloc(q, memory, num_buffers, num_planes, plane_sizes);
|
||||||
if (allocated_buffers == 0) {
|
if (allocated_buffers == 0) {
|
||||||
dprintk(1, "memory allocation failed\n");
|
dprintk(1, "memory allocation failed\n");
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
@ -775,7 +777,7 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory,
|
||||||
num_planes = 0;
|
num_planes = 0;
|
||||||
|
|
||||||
ret = call_qop(q, queue_setup, q, &num_buffers,
|
ret = call_qop(q, queue_setup, q, &num_buffers,
|
||||||
&num_planes, q->plane_sizes, q->alloc_ctx);
|
&num_planes, plane_sizes, q->alloc_ctx);
|
||||||
|
|
||||||
if (!ret && allocated_buffers < num_buffers)
|
if (!ret && allocated_buffers < num_buffers)
|
||||||
ret = -ENOMEM;
|
ret = -ENOMEM;
|
||||||
|
@ -832,6 +834,7 @@ int vb2_core_create_bufs(struct vb2_queue *q, enum vb2_memory memory,
|
||||||
const unsigned requested_sizes[])
|
const unsigned requested_sizes[])
|
||||||
{
|
{
|
||||||
unsigned int num_planes = 0, num_buffers, allocated_buffers;
|
unsigned int num_planes = 0, num_buffers, allocated_buffers;
|
||||||
|
unsigned plane_sizes[VB2_MAX_PLANES] = { };
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (q->num_buffers == VB2_MAX_FRAME) {
|
if (q->num_buffers == VB2_MAX_FRAME) {
|
||||||
|
@ -840,7 +843,6 @@ int vb2_core_create_bufs(struct vb2_queue *q, enum vb2_memory memory,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!q->num_buffers) {
|
if (!q->num_buffers) {
|
||||||
memset(q->plane_sizes, 0, sizeof(q->plane_sizes));
|
|
||||||
memset(q->alloc_ctx, 0, sizeof(q->alloc_ctx));
|
memset(q->alloc_ctx, 0, sizeof(q->alloc_ctx));
|
||||||
q->memory = memory;
|
q->memory = memory;
|
||||||
q->waiting_for_buffers = !q->is_output;
|
q->waiting_for_buffers = !q->is_output;
|
||||||
|
@ -850,7 +852,7 @@ int vb2_core_create_bufs(struct vb2_queue *q, enum vb2_memory memory,
|
||||||
|
|
||||||
if (requested_planes && requested_sizes) {
|
if (requested_planes && requested_sizes) {
|
||||||
num_planes = requested_planes;
|
num_planes = requested_planes;
|
||||||
memcpy(q->plane_sizes, requested_sizes, sizeof(q->plane_sizes));
|
memcpy(plane_sizes, requested_sizes, sizeof(plane_sizes));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -858,13 +860,13 @@ int vb2_core_create_bufs(struct vb2_queue *q, enum vb2_memory memory,
|
||||||
* buffer and their sizes are acceptable
|
* buffer and their sizes are acceptable
|
||||||
*/
|
*/
|
||||||
ret = call_qop(q, queue_setup, q, &num_buffers,
|
ret = call_qop(q, queue_setup, q, &num_buffers,
|
||||||
&num_planes, q->plane_sizes, q->alloc_ctx);
|
&num_planes, plane_sizes, q->alloc_ctx);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
/* Finally, allocate buffers and video memory */
|
/* Finally, allocate buffers and video memory */
|
||||||
allocated_buffers = __vb2_queue_alloc(q, memory, num_buffers,
|
allocated_buffers = __vb2_queue_alloc(q, memory, num_buffers,
|
||||||
num_planes);
|
num_planes, plane_sizes);
|
||||||
if (allocated_buffers == 0) {
|
if (allocated_buffers == 0) {
|
||||||
dprintk(1, "memory allocation failed\n");
|
dprintk(1, "memory allocation failed\n");
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
@ -881,7 +883,7 @@ int vb2_core_create_bufs(struct vb2_queue *q, enum vb2_memory memory,
|
||||||
* queue driver has set up
|
* queue driver has set up
|
||||||
*/
|
*/
|
||||||
ret = call_qop(q, queue_setup, q, &num_buffers,
|
ret = call_qop(q, queue_setup, q, &num_buffers,
|
||||||
&num_planes, q->plane_sizes, q->alloc_ctx);
|
&num_planes, plane_sizes, q->alloc_ctx);
|
||||||
|
|
||||||
if (!ret && allocated_buffers < num_buffers)
|
if (!ret && allocated_buffers < num_buffers)
|
||||||
ret = -ENOMEM;
|
ret = -ENOMEM;
|
||||||
|
@ -1097,11 +1099,12 @@ static int __qbuf_userptr(struct vb2_buffer *vb, const void *pb)
|
||||||
"reacquiring memory\n", plane);
|
"reacquiring memory\n", plane);
|
||||||
|
|
||||||
/* Check if the provided plane buffer is large enough */
|
/* Check if the provided plane buffer is large enough */
|
||||||
if (planes[plane].length < q->plane_sizes[plane]) {
|
if (planes[plane].length < vb->planes[plane].min_length) {
|
||||||
dprintk(1, "provided buffer size %u is less than "
|
dprintk(1, "provided buffer size %u is less than "
|
||||||
"setup size %u for plane %d\n",
|
"setup size %u for plane %d\n",
|
||||||
planes[plane].length,
|
planes[plane].length,
|
||||||
q->plane_sizes[plane], plane);
|
vb->planes[plane].min_length,
|
||||||
|
plane);
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
@ -1214,7 +1217,7 @@ static int __qbuf_dmabuf(struct vb2_buffer *vb, const void *pb)
|
||||||
if (planes[plane].length == 0)
|
if (planes[plane].length == 0)
|
||||||
planes[plane].length = dbuf->size;
|
planes[plane].length = dbuf->size;
|
||||||
|
|
||||||
if (planes[plane].length < q->plane_sizes[plane]) {
|
if (planes[plane].length < vb->planes[plane].min_length) {
|
||||||
dprintk(1, "invalid dmabuf length for plane %d\n",
|
dprintk(1, "invalid dmabuf length for plane %d\n",
|
||||||
plane);
|
plane);
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
|
|
|
@ -129,6 +129,8 @@ struct vb2_mem_ops {
|
||||||
* @dbuf_mapped: flag to show whether dbuf is mapped or not
|
* @dbuf_mapped: flag to show whether dbuf is mapped or not
|
||||||
* @bytesused: number of bytes occupied by data in the plane (payload)
|
* @bytesused: number of bytes occupied by data in the plane (payload)
|
||||||
* @length: size of this plane (NOT the payload) in bytes
|
* @length: size of this plane (NOT the payload) in bytes
|
||||||
|
* @min_length: minimum required size of this plane (NOT the payload) in bytes.
|
||||||
|
* @length is always greater or equal to @min_length.
|
||||||
* @offset: when memory in the associated struct vb2_buffer is
|
* @offset: when memory in the associated struct vb2_buffer is
|
||||||
* VB2_MEMORY_MMAP, equals the offset from the start of
|
* VB2_MEMORY_MMAP, equals the offset from the start of
|
||||||
* the device memory for this plane (or is a "cookie" that
|
* the device memory for this plane (or is a "cookie" that
|
||||||
|
@ -150,6 +152,7 @@ struct vb2_plane {
|
||||||
unsigned int dbuf_mapped;
|
unsigned int dbuf_mapped;
|
||||||
unsigned int bytesused;
|
unsigned int bytesused;
|
||||||
unsigned int length;
|
unsigned int length;
|
||||||
|
unsigned int min_length;
|
||||||
union {
|
union {
|
||||||
unsigned int offset;
|
unsigned int offset;
|
||||||
unsigned long userptr;
|
unsigned long userptr;
|
||||||
|
@ -489,7 +492,6 @@ struct vb2_queue {
|
||||||
wait_queue_head_t done_wq;
|
wait_queue_head_t done_wq;
|
||||||
|
|
||||||
void *alloc_ctx[VB2_MAX_PLANES];
|
void *alloc_ctx[VB2_MAX_PLANES];
|
||||||
unsigned int plane_sizes[VB2_MAX_PLANES];
|
|
||||||
|
|
||||||
unsigned int streaming:1;
|
unsigned int streaming:1;
|
||||||
unsigned int start_streaming_called:1;
|
unsigned int start_streaming_called:1;
|
||||||
|
|
Loading…
Reference in a new issue