Commit 098e5edc authored by Hans Verkuil's avatar Hans Verkuil Committed by Linus Torvalds

media: videobuf2-core: take mmap_lock in vb2_get_unmapped_area()

While vb2_mmap took the mmap_lock mutex, vb2_get_unmapped_area didn't.
Add this.

Also take this opportunity to move the 'q->memory != VB2_MEMORY_MMAP'
check and vb2_fileio_is_active() check into __find_plane_by_offset() so
both vb2_mmap and vb2_get_unmapped_area do the same checks.

Since q->memory is checked while mmap_lock is held, also take that lock
in reqbufs and create_bufs when it is set, and set it back to
MEMORY_UNKNOWN on error.

Fixes: f035eb4e ("[media] videobuf2: fix lockdep warning")
Signed-off-by: default avatarHans Verkuil <hverkuil-cisco@xs4all.nl>
Acked-by: default avatarTomasz Figa <tfiga@chromium.org>
Reviewed-by: default avatarRicardo Ribalda <ribalda@chromium.org>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@kernel.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 8ed710da
...@@ -813,7 +813,13 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory, ...@@ -813,7 +813,13 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory,
num_buffers = max_t(unsigned int, *count, q->min_buffers_needed); num_buffers = max_t(unsigned int, *count, q->min_buffers_needed);
num_buffers = min_t(unsigned int, num_buffers, VB2_MAX_FRAME); num_buffers = min_t(unsigned int, num_buffers, VB2_MAX_FRAME);
memset(q->alloc_devs, 0, sizeof(q->alloc_devs)); memset(q->alloc_devs, 0, sizeof(q->alloc_devs));
/*
* Set this now to ensure that drivers see the correct q->memory value
* in the queue_setup op.
*/
mutex_lock(&q->mmap_lock);
q->memory = memory; q->memory = memory;
mutex_unlock(&q->mmap_lock);
set_queue_coherency(q, non_coherent_mem); set_queue_coherency(q, non_coherent_mem);
/* /*
...@@ -823,22 +829,27 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory, ...@@ -823,22 +829,27 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory,
ret = call_qop(q, queue_setup, q, &num_buffers, &num_planes, ret = call_qop(q, queue_setup, q, &num_buffers, &num_planes,
plane_sizes, q->alloc_devs); plane_sizes, q->alloc_devs);
if (ret) if (ret)
return ret; goto error;
/* Check that driver has set sane values */ /* Check that driver has set sane values */
if (WARN_ON(!num_planes)) if (WARN_ON(!num_planes)) {
return -EINVAL; ret = -EINVAL;
goto error;
}
for (i = 0; i < num_planes; i++) for (i = 0; i < num_planes; i++)
if (WARN_ON(!plane_sizes[i])) if (WARN_ON(!plane_sizes[i])) {
return -EINVAL; ret = -EINVAL;
goto error;
}
/* 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, plane_sizes); __vb2_queue_alloc(q, memory, num_buffers, num_planes, plane_sizes);
if (allocated_buffers == 0) { if (allocated_buffers == 0) {
dprintk(q, 1, "memory allocation failed\n"); dprintk(q, 1, "memory allocation failed\n");
return -ENOMEM; ret = -ENOMEM;
goto error;
} }
/* /*
...@@ -879,7 +890,8 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory, ...@@ -879,7 +890,8 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory,
if (ret < 0) { if (ret < 0) {
/* /*
* Note: __vb2_queue_free() will subtract 'allocated_buffers' * Note: __vb2_queue_free() will subtract 'allocated_buffers'
* from q->num_buffers. * from q->num_buffers and it will reset q->memory to
* VB2_MEMORY_UNKNOWN.
*/ */
__vb2_queue_free(q, allocated_buffers); __vb2_queue_free(q, allocated_buffers);
mutex_unlock(&q->mmap_lock); mutex_unlock(&q->mmap_lock);
...@@ -895,6 +907,12 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory, ...@@ -895,6 +907,12 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory,
q->waiting_for_buffers = !q->is_output; q->waiting_for_buffers = !q->is_output;
return 0; return 0;
error:
mutex_lock(&q->mmap_lock);
q->memory = VB2_MEMORY_UNKNOWN;
mutex_unlock(&q->mmap_lock);
return ret;
} }
EXPORT_SYMBOL_GPL(vb2_core_reqbufs); EXPORT_SYMBOL_GPL(vb2_core_reqbufs);
...@@ -906,6 +924,7 @@ int vb2_core_create_bufs(struct vb2_queue *q, enum vb2_memory memory, ...@@ -906,6 +924,7 @@ int vb2_core_create_bufs(struct vb2_queue *q, enum vb2_memory memory,
unsigned int num_planes = 0, num_buffers, allocated_buffers; unsigned int num_planes = 0, num_buffers, allocated_buffers;
unsigned plane_sizes[VB2_MAX_PLANES] = { }; unsigned plane_sizes[VB2_MAX_PLANES] = { };
bool non_coherent_mem = flags & V4L2_MEMORY_FLAG_NON_COHERENT; bool non_coherent_mem = flags & V4L2_MEMORY_FLAG_NON_COHERENT;
bool no_previous_buffers = !q->num_buffers;
int ret; int ret;
if (q->num_buffers == VB2_MAX_FRAME) { if (q->num_buffers == VB2_MAX_FRAME) {
...@@ -913,13 +932,19 @@ int vb2_core_create_bufs(struct vb2_queue *q, enum vb2_memory memory, ...@@ -913,13 +932,19 @@ int vb2_core_create_bufs(struct vb2_queue *q, enum vb2_memory memory,
return -ENOBUFS; return -ENOBUFS;
} }
if (!q->num_buffers) { if (no_previous_buffers) {
if (q->waiting_in_dqbuf && *count) { if (q->waiting_in_dqbuf && *count) {
dprintk(q, 1, "another dup()ped fd is waiting for a buffer\n"); dprintk(q, 1, "another dup()ped fd is waiting for a buffer\n");
return -EBUSY; return -EBUSY;
} }
memset(q->alloc_devs, 0, sizeof(q->alloc_devs)); memset(q->alloc_devs, 0, sizeof(q->alloc_devs));
/*
* Set this now to ensure that drivers see the correct q->memory
* value in the queue_setup op.
*/
mutex_lock(&q->mmap_lock);
q->memory = memory; q->memory = memory;
mutex_unlock(&q->mmap_lock);
q->waiting_for_buffers = !q->is_output; q->waiting_for_buffers = !q->is_output;
set_queue_coherency(q, non_coherent_mem); set_queue_coherency(q, non_coherent_mem);
} else { } else {
...@@ -945,14 +970,15 @@ int vb2_core_create_bufs(struct vb2_queue *q, enum vb2_memory memory, ...@@ -945,14 +970,15 @@ int vb2_core_create_bufs(struct vb2_queue *q, enum vb2_memory memory,
ret = call_qop(q, queue_setup, q, &num_buffers, ret = call_qop(q, queue_setup, q, &num_buffers,
&num_planes, plane_sizes, q->alloc_devs); &num_planes, plane_sizes, q->alloc_devs);
if (ret) if (ret)
return ret; goto error;
/* 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, plane_sizes); num_planes, plane_sizes);
if (allocated_buffers == 0) { if (allocated_buffers == 0) {
dprintk(q, 1, "memory allocation failed\n"); dprintk(q, 1, "memory allocation failed\n");
return -ENOMEM; ret = -ENOMEM;
goto error;
} }
/* /*
...@@ -983,7 +1009,8 @@ int vb2_core_create_bufs(struct vb2_queue *q, enum vb2_memory memory, ...@@ -983,7 +1009,8 @@ int vb2_core_create_bufs(struct vb2_queue *q, enum vb2_memory memory,
if (ret < 0) { if (ret < 0) {
/* /*
* Note: __vb2_queue_free() will subtract 'allocated_buffers' * Note: __vb2_queue_free() will subtract 'allocated_buffers'
* from q->num_buffers. * from q->num_buffers and it will reset q->memory to
* VB2_MEMORY_UNKNOWN.
*/ */
__vb2_queue_free(q, allocated_buffers); __vb2_queue_free(q, allocated_buffers);
mutex_unlock(&q->mmap_lock); mutex_unlock(&q->mmap_lock);
...@@ -998,6 +1025,14 @@ int vb2_core_create_bufs(struct vb2_queue *q, enum vb2_memory memory, ...@@ -998,6 +1025,14 @@ int vb2_core_create_bufs(struct vb2_queue *q, enum vb2_memory memory,
*count = allocated_buffers; *count = allocated_buffers;
return 0; return 0;
error:
if (no_previous_buffers) {
mutex_lock(&q->mmap_lock);
q->memory = VB2_MEMORY_UNKNOWN;
mutex_unlock(&q->mmap_lock);
}
return ret;
} }
EXPORT_SYMBOL_GPL(vb2_core_create_bufs); EXPORT_SYMBOL_GPL(vb2_core_create_bufs);
...@@ -2164,6 +2199,22 @@ static int __find_plane_by_offset(struct vb2_queue *q, unsigned long off, ...@@ -2164,6 +2199,22 @@ static int __find_plane_by_offset(struct vb2_queue *q, unsigned long off,
struct vb2_buffer *vb; struct vb2_buffer *vb;
unsigned int buffer, plane; unsigned int buffer, plane;
/*
* Sanity checks to ensure the lock is held, MEMORY_MMAP is
* used and fileio isn't active.
*/
lockdep_assert_held(&q->mmap_lock);
if (q->memory != VB2_MEMORY_MMAP) {
dprintk(q, 1, "queue is not currently set up for mmap\n");
return -EINVAL;
}
if (vb2_fileio_is_active(q)) {
dprintk(q, 1, "file io in progress\n");
return -EBUSY;
}
/* /*
* Go over all buffers and their planes, comparing the given offset * Go over all buffers and their planes, comparing the given offset
* with an offset assigned to each plane. If a match is found, * with an offset assigned to each plane. If a match is found,
...@@ -2265,11 +2316,6 @@ int vb2_mmap(struct vb2_queue *q, struct vm_area_struct *vma) ...@@ -2265,11 +2316,6 @@ int vb2_mmap(struct vb2_queue *q, struct vm_area_struct *vma)
int ret; int ret;
unsigned long length; unsigned long length;
if (q->memory != VB2_MEMORY_MMAP) {
dprintk(q, 1, "queue is not currently set up for mmap\n");
return -EINVAL;
}
/* /*
* Check memory area access mode. * Check memory area access mode.
*/ */
...@@ -2291,14 +2337,9 @@ int vb2_mmap(struct vb2_queue *q, struct vm_area_struct *vma) ...@@ -2291,14 +2337,9 @@ int vb2_mmap(struct vb2_queue *q, struct vm_area_struct *vma)
mutex_lock(&q->mmap_lock); mutex_lock(&q->mmap_lock);
if (vb2_fileio_is_active(q)) {
dprintk(q, 1, "mmap: file io in progress\n");
ret = -EBUSY;
goto unlock;
}
/* /*
* Find the plane corresponding to the offset passed by userspace. * Find the plane corresponding to the offset passed by userspace. This
* will return an error if not MEMORY_MMAP or file I/O is in progress.
*/ */
ret = __find_plane_by_offset(q, off, &buffer, &plane); ret = __find_plane_by_offset(q, off, &buffer, &plane);
if (ret) if (ret)
...@@ -2351,22 +2392,25 @@ unsigned long vb2_get_unmapped_area(struct vb2_queue *q, ...@@ -2351,22 +2392,25 @@ unsigned long vb2_get_unmapped_area(struct vb2_queue *q,
void *vaddr; void *vaddr;
int ret; int ret;
if (q->memory != VB2_MEMORY_MMAP) { mutex_lock(&q->mmap_lock);
dprintk(q, 1, "queue is not currently set up for mmap\n");
return -EINVAL;
}
/* /*
* Find the plane corresponding to the offset passed by userspace. * Find the plane corresponding to the offset passed by userspace. This
* will return an error if not MEMORY_MMAP or file I/O is in progress.
*/ */
ret = __find_plane_by_offset(q, off, &buffer, &plane); ret = __find_plane_by_offset(q, off, &buffer, &plane);
if (ret) if (ret)
return ret; goto unlock;
vb = q->bufs[buffer]; vb = q->bufs[buffer];
vaddr = vb2_plane_vaddr(vb, plane); vaddr = vb2_plane_vaddr(vb, plane);
mutex_unlock(&q->mmap_lock);
return vaddr ? (unsigned long)vaddr : -EINVAL; return vaddr ? (unsigned long)vaddr : -EINVAL;
unlock:
mutex_unlock(&q->mmap_lock);
return ret;
} }
EXPORT_SYMBOL_GPL(vb2_get_unmapped_area); EXPORT_SYMBOL_GPL(vb2_get_unmapped_area);
#endif #endif
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment