mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2025-01-04 04:44:37 +08:00
media: videobuf2-core: take mmap_lock in vb2_get_unmapped_area()
[ Upstream commit098e5edc5d
] 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:f035eb4e97
("[media] videobuf2: fix lockdep warning") Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl> Acked-by: Tomasz Figa <tfiga@chromium.org> Reviewed-by: Ricardo Ribalda <ribalda@chromium.org> Signed-off-by: Mauro Carvalho Chehab <mchehab@kernel.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
parent
5d0fa6fc88
commit
22d800b378
@ -788,7 +788,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);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Ask the driver how many buffers and planes per buffer it requires.
|
* Ask the driver how many buffers and planes per buffer it requires.
|
||||||
@ -797,22 +803,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -853,7 +864,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);
|
||||||
@ -869,6 +881,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);
|
||||||
|
|
||||||
@ -879,6 +897,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 no_previous_buffers = !q->num_buffers;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (q->num_buffers == VB2_MAX_FRAME) {
|
if (q->num_buffers == VB2_MAX_FRAME) {
|
||||||
@ -886,13 +905,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;
|
||||||
} else {
|
} else {
|
||||||
if (q->memory != memory) {
|
if (q->memory != memory) {
|
||||||
@ -915,14 +940,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -953,7 +979,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);
|
||||||
@ -968,6 +995,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);
|
||||||
|
|
||||||
@ -2124,6 +2159,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,
|
||||||
@ -2225,11 +2276,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.
|
||||||
*/
|
*/
|
||||||
@ -2251,14 +2297,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)
|
||||||
@ -2311,22 +2352,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
|
||||||
|
Loading…
Reference in New Issue
Block a user