patch "usb: gadget: uvc: fix sg handling in error case" added to usb-linus
Subsystems (3)
This is a note to let you know that I've just added the patch titled
usb: gadget: uvc: fix sg handling in error case
to my usb git tree which can be found at
git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb.git
in the usb-linus branch.
The patch will show up in the next release of the linux-next tree (usually sometime within the next 24 hours during the week.)
The patch will hopefully also be merged in Linus's tree for the next -rc kernel release.
If you have any questions about this process, please let me know.
From 0a0a2760b04814428800d48281a447a7522470ad Mon Sep 17 00:00:00 2001
From: Dan Vacura <[email protected]>
Date: Tue, 18 Oct 2022 16:50:39 -0500
Subject: usb: gadget: uvc: fix sg handling in error case
If there is a transmission error the buffer will be returned too early, causing a memory fault as subsequent requests for that buffer are still queued up to be sent. Refactor the error handling to wait for the final request to come in before reporting back the buffer to userspace for all transfer types (bulk/isoc/isoc_sg). This ensures userspace knows if the frame was successfully sent.
--- drivers/usb/gadget/function/uvc_queue.c | 8 +++++--- drivers/usb/gadget/function/uvc_video.c | 18 ++++++++++++++---- 2 files changed, 19 insertions(+), 7 deletions(-)
drivers/usb/gadget/function/uvc_queue.c +5 -3
@@ -304,6 +304,7 @@ int uvcg_queue_enable(struct uvc_video_queue *queue, int enable) queue->sequence =0 ; queue->buf_used =0 ; + queue->flags &= ~UVC_QUEUE_DROP_INCOMPLETE ; }else { ret =vb2_streamoff (&queue->queue, queue->queue.type);if (ret <0 )
@@ -329,10 +330,11 @@ int uvcg_queue_enable(struct uvc_video_queue *queue, int enable)void uvcg_complete_buffer (struct uvc_video_queue *queue,struct uvc_buffer *buf) { -if ((queue->flags &UVC_QUEUE_DROP_INCOMPLETE ) && - buf->length != buf->bytesused) { - buf->state =UVC_BUF_STATE_QUEUED ; +if (queue->flags &UVC_QUEUE_DROP_INCOMPLETE ) { + queue->flags &= ~UVC_QUEUE_DROP_INCOMPLETE ; + buf->state =UVC_BUF_STATE_ERROR ;vb2_set_plane_payload (&buf->buf.vb2_buf,0 ,0 ); +vb2_buffer_done (&buf->buf.vb2_buf,VB2_BUF_STATE_ERROR );return ; }
drivers/usb/gadget/function/uvc_video.c +14 -4
@@ -88,6 +88,7 @@ uvc_video_encode_bulk(struct usb_request *req, struct uvc_video *video, struct uvc_buffer *buf) {void *mem = req->buf; +struct uvc_request *ureq = req->context;int len = video->req_size;int ret;
@@ -113,13 +114,14 @@ uvc_video_encode_bulk(struct usb_request *req, struct uvc_video *video, video->queue.buf_used =0 ; buf->state =UVC_BUF_STATE_DONE ;list_del (&buf->queue); -uvcg_complete_buffer (&video->queue, buf); video->fid ^=UVC_STREAM_FID ; + ureq->last_buf = buf; video->payload_size =0 ; }if (video->payload_size == video->max_payload_size || + video->queue.flags &UVC_QUEUE_DROP_INCOMPLETE || buf->bytesused == video->queue.buf_used) video->payload_size =0 ; }
@@ -180,7 +182,8 @@ uvc_video_encode_isoc_sg(struct usb_request *req, struct uvc_video *video, req->length -= len; video->queue.buf_used += req->length - header_len; -if (buf->bytesused == video->queue.buf_used || !buf->sg) { +if (buf->bytesused == video->queue.buf_used || !buf->sg || + video->queue.flags &UVC_QUEUE_DROP_INCOMPLETE ) { video->queue.buf_used =0 ; buf->state =UVC_BUF_STATE_DONE ; buf->offset =0 ;
@@ -195,6 +198,7 @@ uvc_video_encode_isoc(struct usb_request *req, struct uvc_video *video, struct uvc_buffer *buf) {void *mem = req->buf; +struct uvc_request *ureq = req->context;int len = video->req_size;int ret;
@@ -209,12 +213,13 @@ uvc_video_encode_isoc(struct usb_request *req, struct uvc_video *video, req->length = video->req_size - len; -if (buf->bytesused == video->queue.buf_used) { +if (buf->bytesused == video->queue.buf_used || + video->queue.flags &UVC_QUEUE_DROP_INCOMPLETE ) { video->queue.buf_used =0 ; buf->state =UVC_BUF_STATE_DONE ;list_del (&buf->queue); -uvcg_complete_buffer (&video->queue, buf); video->fid ^=UVC_STREAM_FID ; + ureq->last_buf = buf; } }
@@ -255,6 +260,11 @@ uvc_video_complete(struct usb_ep *ep, struct usb_request *req)case 0 :break ; +case -EXDEV : +uvcg_dbg (&video->uvc->func,"VS request missed xfer.\n" ); + queue->flags |=UVC_QUEUE_DROP_INCOMPLETE ; +break ; +case -ESHUTDOWN :/* disconnect from host. */ uvcg_dbg (&video->uvc->func,"VS request cancelled.\n" );uvcg_queue_cancel (queue,1 );
Signature · 1 line
2.38.1