Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4e5a4d8a authored by Hans Verkuil's avatar Hans Verkuil Committed by Mauro Carvalho Chehab
Browse files

[media] vb2: fix read/write regression



Commit 88e26870 ("vb2: Improve file I/O
emulation to handle buffers in any order") broke read/write support if
the size of the buffer being read/written is less than the size of the
image.

When the commit was tested originally I used qv4l2, which calls read()
with exactly the size of the image. But if you try 'cat /dev/video0'
then it will fail and typically hang after reading two buffers.

This patch fixes the behavior by adding a new cur_index field that
contains the index of the field currently being filled/read, or it
is num_buffers in which case a new buffer needs to be dequeued.

The old index field has been renamed to initial_index in order to be
a bit more descriptive.

This has been tested with both read and write.

Signed-off-by: default avatarHans Verkuil <hans.verkuil@cisco.com>
Tested-by: default avatarHans Verkuil <hans.verkuil@cisco.com>
Cc: Andy Walls <awalls@md.metrocast.net>
Signed-off-by: default avatarMauro Carvalho Chehab <m.chehab@samsung.com>
parent 249f5a58
Loading
Loading
Loading
Loading
+40 −6
Original line number Diff line number Diff line
@@ -2310,6 +2310,22 @@ struct vb2_fileio_buf {
/**
 * struct vb2_fileio_data - queue context used by file io emulator
 *
 * @cur_index:	the index of the buffer currently being read from or
 *		written to. If equal to q->num_buffers then a new buffer
 *		must be dequeued.
 * @initial_index: in the read() case all buffers are queued up immediately
 *		in __vb2_init_fileio() and __vb2_perform_fileio() just cycles
 *		buffers. However, in the write() case no buffers are initially
 *		queued, instead whenever a buffer is full it is queued up by
 *		__vb2_perform_fileio(). Only once all available buffers have
 *		been queued up will __vb2_perform_fileio() start to dequeue
 *		buffers. This means that initially __vb2_perform_fileio()
 *		needs to know what buffer index to use when it is queuing up
 *		the buffers for the first time. That initial index is stored
 *		in this field. Once it is equal to q->num_buffers all
 *		available buffers have been queued and __vb2_perform_fileio()
 *		should start the normal dequeue/queue cycle.
 *
 * vb2 provides a compatibility layer and emulator of file io (read and
 * write) calls on top of streaming API. For proper operation it required
 * this structure to save the driver state between each call of the read
@@ -2319,7 +2335,8 @@ struct vb2_fileio_data {
	struct v4l2_requestbuffers req;
	struct v4l2_buffer b;
	struct vb2_fileio_buf bufs[VIDEO_MAX_FRAME];
	unsigned int index;
	unsigned int cur_index;
	unsigned int initial_index;
	unsigned int q_count;
	unsigned int dq_count;
	unsigned int flags;
@@ -2419,7 +2436,12 @@ static int __vb2_init_fileio(struct vb2_queue *q, int read)
				goto err_reqbufs;
			fileio->bufs[i].queued = 1;
		}
		fileio->index = q->num_buffers;
		/*
		 * All buffers have been queued, so mark that by setting
		 * initial_index to q->num_buffers
		 */
		fileio->initial_index = q->num_buffers;
		fileio->cur_index = q->num_buffers;
	}

	/*
@@ -2498,7 +2520,7 @@ static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_
	/*
	 * Check if we need to dequeue the buffer.
	 */
	index = fileio->index;
	index = fileio->cur_index;
	if (index >= q->num_buffers) {
		/*
		 * Call vb2_dqbuf to get buffer back.
@@ -2512,7 +2534,7 @@ static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_
			return ret;
		fileio->dq_count += 1;

		index = fileio->b.index;
		fileio->cur_index = index = fileio->b.index;
		buf = &fileio->bufs[index];

		/*
@@ -2588,8 +2610,20 @@ static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_
		buf->queued = 1;
		buf->size = vb2_plane_size(q->bufs[index], 0);
		fileio->q_count += 1;
		if (fileio->index < q->num_buffers)
			fileio->index++;
		/*
		 * If we are queuing up buffers for the first time, then
		 * increase initial_index by one.
		 */
		if (fileio->initial_index < q->num_buffers)
			fileio->initial_index++;
		/*
		 * The next buffer to use is either a buffer that's going to be
		 * queued for the first time (initial_index < q->num_buffers)
		 * or it is equal to q->num_buffers, meaning that the next
		 * time we need to dequeue a buffer since we've now queued up
		 * all the 'first time' buffers.
		 */
		fileio->cur_index = fileio->initial_index;
	}

	/*