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

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
Loading
Loading
Loading
Loading
+73 −29
Original line number Diff line number Diff line
@@ -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 = min_t(unsigned int, num_buffers, VB2_MAX_FRAME);
	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;
	mutex_unlock(&q->mmap_lock);
	set_queue_coherency(q, non_coherent_mem);

	/*
@@ -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,
		       plane_sizes, q->alloc_devs);
	if (ret)
		return ret;
		goto error;

	/* Check that driver has set sane values */
	if (WARN_ON(!num_planes))
		return -EINVAL;
	if (WARN_ON(!num_planes)) {
		ret = -EINVAL;
		goto error;
	}

	for (i = 0; i < num_planes; i++)
		if (WARN_ON(!plane_sizes[i]))
			return -EINVAL;
		if (WARN_ON(!plane_sizes[i])) {
			ret = -EINVAL;
			goto error;
		}

	/* Finally, allocate buffers and video memory */
	allocated_buffers =
		__vb2_queue_alloc(q, memory, num_buffers, num_planes, plane_sizes);
	if (allocated_buffers == 0) {
		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,
	if (ret < 0) {
		/*
		 * 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);
		mutex_unlock(&q->mmap_lock);
@@ -895,6 +907,12 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory,
	q->waiting_for_buffers = !q->is_output;

	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);

@@ -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 plane_sizes[VB2_MAX_PLANES] = { };
	bool non_coherent_mem = flags & V4L2_MEMORY_FLAG_NON_COHERENT;
	bool no_previous_buffers = !q->num_buffers;
	int ret;

	if (q->num_buffers == VB2_MAX_FRAME) {
@@ -913,13 +932,19 @@ int vb2_core_create_bufs(struct vb2_queue *q, enum vb2_memory memory,
		return -ENOBUFS;
	}

	if (!q->num_buffers) {
	if (no_previous_buffers) {
		if (q->waiting_in_dqbuf && *count) {
			dprintk(q, 1, "another dup()ped fd is waiting for a buffer\n");
			return -EBUSY;
		}
		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;
		mutex_unlock(&q->mmap_lock);
		q->waiting_for_buffers = !q->is_output;
		set_queue_coherency(q, non_coherent_mem);
	} else {
@@ -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,
		       &num_planes, plane_sizes, q->alloc_devs);
	if (ret)
		return ret;
		goto error;

	/* Finally, allocate buffers and video memory */
	allocated_buffers = __vb2_queue_alloc(q, memory, num_buffers,
				num_planes, plane_sizes);
	if (allocated_buffers == 0) {
		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,
	if (ret < 0) {
		/*
		 * 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);
		mutex_unlock(&q->mmap_lock);
@@ -998,6 +1025,14 @@ int vb2_core_create_bufs(struct vb2_queue *q, enum vb2_memory memory,
	*count = allocated_buffers;

	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);

@@ -2164,6 +2199,22 @@ static int __find_plane_by_offset(struct vb2_queue *q, unsigned long off,
	struct vb2_buffer *vb;
	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
	 * 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)
	int ret;
	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.
	 */
@@ -2291,14 +2337,9 @@ int vb2_mmap(struct vb2_queue *q, struct vm_area_struct *vma)

	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);
	if (ret)
@@ -2351,22 +2392,25 @@ unsigned long vb2_get_unmapped_area(struct vb2_queue *q,
	void *vaddr;
	int ret;

	if (q->memory != VB2_MEMORY_MMAP) {
		dprintk(q, 1, "queue is not currently set up for mmap\n");
		return -EINVAL;
	}
	mutex_lock(&q->mmap_lock);

	/*
	 * 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);
	if (ret)
		return ret;
		goto unlock;

	vb = q->bufs[buffer];

	vaddr = vb2_plane_vaddr(vb, plane);
	mutex_unlock(&q->mmap_lock);
	return vaddr ? (unsigned long)vaddr : -EINVAL;

unlock:
	mutex_unlock(&q->mmap_lock);
	return ret;
}
EXPORT_SYMBOL_GPL(vb2_get_unmapped_area);
#endif