On 06/06/2014 03:53 PM, Laurent Pinchart wrote: > When a fatal error occurs that render the device unusable, the only > options for a driver to signal the error condition to userspace is to > set the V4L2_BUF_FLAG_ERROR flag when dequeuing buffers and to return an > error from the buffer prepare handler when queuing buffers. > > The buffer error flag indicates a transient error and can't be used by > applications to detect fatal errors. Returning an error from vb2_qbuf() > is thus the only real indication that a fatal error occurred. However, > this is difficult to handle for multithreaded applications that requeue > buffers from a thread other than the control thread. In particular the > poll() call in the control thread will not notify userspace of the > error. > > This patch adds an explicit mechanism to report fatal errors to > userspace. Drivers can call the vb2_queue_error() function to signal a > fatal error. From this moment on, buffer preparation will return -EIO to > userspace, and vb2_poll() will set the POLLERR flag and return > immediately. The error flag is cleared when cancelling the queue, either > at stream off time (through vb2_streamoff) or when releasing the queue > with vb2_queue_release(). > > Signed-off-by: Laurent Pinchart <laurent.pinchart@xxxxxxxxxxxxxxxx> Acked-by: Hans Verkuil <hans.verkuil@xxxxxxxxx> Regards, Hans > --- > drivers/media/v4l2-core/videobuf2-core.c | 39 +++++++++++++++++++++++++++++--- > include/media/videobuf2-core.h | 3 +++ > 2 files changed, 39 insertions(+), 3 deletions(-) > > diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c > index a05f355..b1b7f78 100644 > --- a/drivers/media/v4l2-core/videobuf2-core.c > +++ b/drivers/media/v4l2-core/videobuf2-core.c > @@ -1582,6 +1582,11 @@ static int __buf_prepare(struct vb2_buffer *vb, const struct v4l2_buffer *b) > return -EINVAL; > } > > + if (q->error) { > + dprintk(1, "fatal error occurred on queue\n"); > + return -EIO; > + } > + > vb->state = VB2_BUF_STATE_PREPARING; > vb->v4l2_buf.timestamp.tv_sec = 0; > vb->v4l2_buf.timestamp.tv_usec = 0; > @@ -1877,6 +1882,11 @@ static int __vb2_wait_for_done_vb(struct vb2_queue *q, int nonblocking) > return -EINVAL; > } > > + if (q->error) { > + dprintk(1, "Queue in error state, will not wait for buffers\n"); > + return -EIO; > + } > + > if (!list_empty(&q->done_list)) { > /* > * Found a buffer that we were waiting for. > @@ -1902,7 +1912,8 @@ static int __vb2_wait_for_done_vb(struct vb2_queue *q, int nonblocking) > */ > dprintk(3, "will sleep waiting for buffers\n"); > ret = wait_event_interruptible(q->done_wq, > - !list_empty(&q->done_list) || !q->streaming); > + !list_empty(&q->done_list) || !q->streaming || > + q->error); > > /* > * We need to reevaluate both conditions again after reacquiring > @@ -2099,6 +2110,7 @@ static void __vb2_queue_cancel(struct vb2_queue *q) > q->streaming = 0; > q->start_streaming_called = 0; > q->queued_count = 0; > + q->error = 0; > > /* > * Remove all buffers from videobuf's list... > @@ -2176,6 +2188,27 @@ static int vb2_internal_streamon(struct vb2_queue *q, enum v4l2_buf_type type) > } > > /** > + * vb2_queue_error() - signal a fatal error on the queue > + * @q: videobuf2 queue > + * > + * Flag that a fatal unrecoverable error has occurred and wake up all processes > + * waiting on the queue. Polling will now set POLLERR and queuing and dequeuing > + * buffers will return -EIO. > + * > + * The error flag will be cleared when cancelling the queue, either from > + * vb2_streamoff or vb2_queue_release. Drivers should thus not call this > + * function before starting the stream, otherwise the error flag will remain set > + * until the queue is released when closing the device node. > + */ > +void vb2_queue_error(struct vb2_queue *q) > +{ > + q->error = 1; > + > + wake_up_all(&q->done_wq); > +} > +EXPORT_SYMBOL_GPL(vb2_queue_error); > + > +/** > * vb2_streamon - start streaming > * @q: videobuf2 queue > * @type: type argument passed from userspace to vidioc_streamon handler > @@ -2534,9 +2567,9 @@ unsigned int vb2_poll(struct vb2_queue *q, struct file *file, poll_table *wait) > > /* > * There is nothing to wait for if no buffer has been queued and the > - * queue isn't streaming. > + * queue isn't streaming, or if the error flag is set. > */ > - if (list_empty(&q->queued_list) && !vb2_is_streaming(q)) > + if ((list_empty(&q->queued_list) && !vb2_is_streaming(q)) || q->error) > return res | POLLERR; > > if (list_empty(&q->done_list)) > diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h > index bca25dc..e5cb2a3 100644 > --- a/include/media/videobuf2-core.h > +++ b/include/media/videobuf2-core.h > @@ -375,6 +375,7 @@ struct v4l2_fh; > * @streaming: current streaming state > * @start_streaming_called: start_streaming() was called successfully and we > * started streaming. > + * @error: a fatal error occurred on the queue > * @fileio: file io emulator internal data, used only if emulator is active > * @threadio: thread io internal data, used only if thread is active > */ > @@ -411,6 +412,7 @@ struct vb2_queue { > > unsigned int streaming:1; > unsigned int start_streaming_called:1; > + unsigned int error:1; > > struct vb2_fileio_data *fileio; > struct vb2_threadio_data *threadio; > @@ -443,6 +445,7 @@ int vb2_prepare_buf(struct vb2_queue *q, struct v4l2_buffer *b); > int __must_check vb2_queue_init(struct vb2_queue *q); > > void vb2_queue_release(struct vb2_queue *q); > +void vb2_queue_error(struct vb2_queue *q); > > int vb2_qbuf(struct vb2_queue *q, struct v4l2_buffer *b); > int vb2_expbuf(struct vb2_queue *q, struct v4l2_exportbuffer *eb); > -- To unsubscribe from this list: send the line "unsubscribe linux-media" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html