Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752074AbeACUdg (ORCPT + 1 other); Wed, 3 Jan 2018 15:33:36 -0500 Received: from mail.kernel.org ([198.145.29.99]:53900 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751716AbeACUda (ORCPT ); Wed, 3 Jan 2018 15:33:30 -0500 DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 5C9A621904 Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=kernel.org Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=kbingham@kernel.org From: Kieran Bingham To: linux-media@vger.kernel.org, linux-kernel@vger.kernel.org, laurent.pinchart@ideasonboard.com Cc: Olivier BRAUN , kieran.bingham@ideasonboard.com, Mauro Carvalho Chehab , Guennadi Liakhovetski , Hans Verkuil , Jaejoong Kim , Baoyou Xie , Nicolas Dufresne , Greg Kroah-Hartman , Jim Lin , Daniel Patrick Johnson Subject: [RFC/RFT PATCH 3/6] uvcvideo: Protect queue internals with helper Date: Wed, 3 Jan 2018 20:32:53 +0000 Message-Id: X-Mailer: git-send-email 2.7.4 In-Reply-To: References: In-Reply-To: References: Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Return-Path: From: Kieran Bingham The URB completion operation obtains the current buffer by reading directly into the queue internal interface. Protect this queue abstraction by providing a helper uvc_queue_get_current_buffer() which can be used by both the decode task, and the uvc_queue_next_buffer() functions. Signed-off-by: Kieran Bingham Reviewed-by: Laurent Pinchart --- drivers/media/usb/uvc/uvc_queue.c | 34 +++++++++++++++++++++++++++----- drivers/media/usb/uvc/uvc_video.c | 7 +------ drivers/media/usb/uvc/uvcvideo.h | 2 ++- 3 files changed, 32 insertions(+), 11 deletions(-) diff --git a/drivers/media/usb/uvc/uvc_queue.c b/drivers/media/usb/uvc/uvc_queue.c index c8d78b2f3de4..0711e3d9ff76 100644 --- a/drivers/media/usb/uvc/uvc_queue.c +++ b/drivers/media/usb/uvc/uvc_queue.c @@ -399,6 +399,34 @@ void uvc_queue_cancel(struct uvc_video_queue *queue, int disconnect) spin_unlock_irqrestore(&queue->irqlock, flags); } +/* + * uvc_queue_get_current_buffer: Obtain the current working output buffer + * + * Buffers may span multiple packets, and even URBs, therefore the active buffer + * remains on the queue until the EOF marker. + */ +static struct uvc_buffer * +__uvc_queue_get_current_buffer(struct uvc_video_queue *queue) +{ + if (!list_empty(&queue->irqqueue)) + return list_first_entry(&queue->irqqueue, struct uvc_buffer, + queue); + else + return NULL; +} + +struct uvc_buffer *uvc_queue_get_current_buffer(struct uvc_video_queue *queue) +{ + struct uvc_buffer *nextbuf; + unsigned long flags; + + spin_lock_irqsave(&queue->irqlock, flags); + nextbuf = __uvc_queue_get_current_buffer(queue); + spin_unlock_irqrestore(&queue->irqlock, flags); + + return nextbuf; +} + struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue, struct uvc_buffer *buf) { @@ -415,11 +443,7 @@ struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue, spin_lock_irqsave(&queue->irqlock, flags); list_del(&buf->queue); - if (!list_empty(&queue->irqqueue)) - nextbuf = list_first_entry(&queue->irqqueue, struct uvc_buffer, - queue); - else - nextbuf = NULL; + nextbuf = __uvc_queue_get_current_buffer(queue); spin_unlock_irqrestore(&queue->irqlock, flags); buf->state = buf->error ? UVC_BUF_STATE_ERROR : UVC_BUF_STATE_DONE; diff --git a/drivers/media/usb/uvc/uvc_video.c b/drivers/media/usb/uvc/uvc_video.c index 17a40c9a1fa3..045ac655313c 100644 --- a/drivers/media/usb/uvc/uvc_video.c +++ b/drivers/media/usb/uvc/uvc_video.c @@ -1322,7 +1322,6 @@ static void uvc_video_complete(struct urb *urb) struct uvc_streaming *stream = uvc_urb->stream; struct uvc_video_queue *queue = &stream->queue; struct uvc_buffer *buf = NULL; - unsigned long flags; int ret; switch (urb->status) { @@ -1343,11 +1342,7 @@ static void uvc_video_complete(struct urb *urb) return; } - spin_lock_irqsave(&queue->irqlock, flags); - if (!list_empty(&queue->irqqueue)) - buf = list_first_entry(&queue->irqqueue, struct uvc_buffer, - queue); - spin_unlock_irqrestore(&queue->irqlock, flags); + buf = uvc_queue_get_current_buffer(queue); stream->decode(uvc_urb, buf); diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h index e4bd3d68a273..f274c685087d 100644 --- a/drivers/media/usb/uvc/uvcvideo.h +++ b/drivers/media/usb/uvc/uvcvideo.h @@ -692,6 +692,8 @@ extern int uvc_queue_streamon(struct uvc_video_queue *queue, extern int uvc_queue_streamoff(struct uvc_video_queue *queue, enum v4l2_buf_type type); extern void uvc_queue_cancel(struct uvc_video_queue *queue, int disconnect); +extern struct uvc_buffer * + uvc_queue_get_current_buffer(struct uvc_video_queue *queue); extern struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue, struct uvc_buffer *buf); extern int uvc_queue_mmap(struct uvc_video_queue *queue, -- git-series 0.9.1