From patchwork Tue Nov 13 13:16:21 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrzej Pietrasiewicz X-Patchwork-Id: 10680627 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 00DEE1709 for ; Tue, 13 Nov 2018 13:16:37 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id E0A402A385 for ; Tue, 13 Nov 2018 13:16:36 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id CFAE32A4DE; Tue, 13 Nov 2018 13:16:36 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-8.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 198E32A385 for ; Tue, 13 Nov 2018 13:16:36 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1733272AbeKMXOk (ORCPT ); Tue, 13 Nov 2018 18:14:40 -0500 Received: from mailout2.w1.samsung.com ([210.118.77.12]:32873 "EHLO mailout2.w1.samsung.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1733261AbeKMXOk (ORCPT ); Tue, 13 Nov 2018 18:14:40 -0500 Received: from eucas1p1.samsung.com (unknown [182.198.249.206]) by mailout2.w1.samsung.com (KnoxPortal) with ESMTP id 20181113131632euoutp02127d015253fe5ab89632ab46115a2098~msWpY4z-Z0554205542euoutp02A; Tue, 13 Nov 2018 13:16:32 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 mailout2.w1.samsung.com 20181113131632euoutp02127d015253fe5ab89632ab46115a2098~msWpY4z-Z0554205542euoutp02A DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=samsung.com; s=mail20170921; t=1542114992; bh=GX8mm2lOtxDcGaCAy366VzxwiWV9yHiIB0vYdHTo/do=; h=From:To:Cc:Subject:Date:In-reply-to:References:From; b=UGHzhwpw+RW59ve8bU+c7U2hra2P8XrBS7JM2Lz7QgJPBCtFvZJMxJ5aN1CMx+nbF FbWSxoumGjykAD/yDYw4zJD0tEUjQzkmEZf0gzgmpQup7p+URDUfA7vaiUt/wuaged KIBvwJHgViqh+jIbZJtqHOP623/g0dx49M5KMq2k= Received: from eusmges1new.samsung.com (unknown [203.254.199.242]) by eucas1p1.samsung.com (KnoxPortal) with ESMTP id 20181113131631eucas1p12590772924ef7e59b5161d0ff0f6a5ac~msWooRTZl0622806228eucas1p1Z; Tue, 13 Nov 2018 13:16:31 +0000 (GMT) Received: from eucas1p1.samsung.com ( [182.198.249.206]) by eusmges1new.samsung.com (EUCPMTA) with SMTP id 39.E1.04441.FAECAEB5; Tue, 13 Nov 2018 13:16:31 +0000 (GMT) Received: from eusmgms2.samsung.com (unknown [182.198.249.180]) by eucas1p2.samsung.com (KnoxPortal) with ESMTP id 20181113131631eucas1p22091664348fd25e209d718250c0d286b~msWn_w76W1625616256eucas1p2e; Tue, 13 Nov 2018 13:16:31 +0000 (GMT) X-AuditID: cbfec7f2-5c9ff70000001159-5f-5beaceaf34d3 Received: from eusync3.samsung.com ( [203.254.199.213]) by eusmgms2.samsung.com (EUCPMTA) with SMTP id F1.06.04128.FAECAEB5; Tue, 13 Nov 2018 13:16:31 +0000 (GMT) Received: from mcdsrvbld02.digital.local ([106.116.37.23]) by eusync3.samsung.com (Oracle Communications Messaging Server 7.0.5.31.0 64bit (built May 5 2014)) with ESMTPA id <0PI4007WTVJDG840@eusync3.samsung.com>; Tue, 13 Nov 2018 13:16:31 +0000 (GMT) From: Andrzej Pietrasiewicz To: linux-usb@vger.kernel.org Cc: Andrzej Pietrasiewicz , Greg Kroah-Hartman , Felipe Balbi , Marek Szyprowski , Bartlomiej Zolnierkiewicz , Michal Nazarewicz Subject: [PATCHv3] usb: gadget: f_fs: Allow scatter-gather buffers Date: Tue, 13 Nov 2018 14:16:21 +0100 Message-id: <20181113131621.32117-1-andrzej.p@samsung.com> X-Mailer: git-send-email 2.11.0 In-reply-to: <20181109132604.28619-1-andrzej.p@samsung.com> X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFlrJIsWRmVeSWpSXmKPExsWy7djPc7rrz72KNph5Utti1st2FouNM9az Whxre8Ju0bx4PZvFomWtzBZrj9xlt1hwvIXVgd1j06pONo/9c9ewe6z784rJo2/LKkaPz5vk AlijuGxSUnMyy1KL9O0SuDIenf3PWvBYq2LnrYusDYxHlboYOTkkBEwkVlycy97FyMUhJLCC UeLvue9MEM5nRond526xwFQt3TARKrGMUWLnzT9QLU1MEk2zn7CDVLEJGEvsPdjBCGKLCMhK HL7ymxmkiFlgMpPEgbnPwUYJCzhJrDu5kwnEZhFQlXgwqxMszitgJdF0ZBHUOnmJXW0XWUFs TgFribXrd4NtkxDoYJNYeXo/O0SRi8TnHdehGoQlXh3fAhWXkbg8uRsqXi+x6cseNgh7CqPE vbneELa1xOHjEAuYBfgkJm2bDnQpB1CcV6KjTQiixENi0dGTYCOFBPoYJW7ccpzAKLmAkWEV o3hqaXFuemqxYV5quV5xYm5xaV66XnJ+7iZGYASe/nf80w7Gr5eSDjEKcDAq8fCemP4yWog1 say4MvcQowQHs5II706TV9FCvCmJlVWpRfnxRaU5qcWHGKU5WJTEeasZHkQLCaQnlqRmp6YW pBbBZJk4OKUaGEVCpBz1LE86u7a8/rvptsfOCF/pxqNdAu1iNw8+7vLkXn3/d9Xx/Uu8lc3/ MBlm5njz+/Y2yUumS66XmP+VM/yG51z5N3zHHzW9+n3iyLWVV2sWb03SmTZ7kc7Sw2X5B/xv 9GUK9E3j3By4+fdm37qXtseqBXrP1P5XOHgveF5RjbTu85YZZUosxRmJhlrMRcWJAOX7gW+8 AgAA X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFupgluLIzCtJLcpLzFFi42I5/e/4Vd31515FGxy8xmQx62U7i8XGGetZ LY61PWG3aF68ns1i0bJWZou1R+6yWyw43sLqwO6xaVUnm8f+uWvYPdb9ecXk0bdlFaPH501y AaxRXDYpqTmZZalF+nYJXBmPzv5nLXisVbHz1kXWBsajSl2MnBwSAiYSSzdMZOpi5OIQEljC KHFi9nl2CKeFSeLZpXtsIFVsAsYSew92MILYIgKyEoev/GYGKWIWmMok8XnTfCaQhLCAk8S6 kzvBbBYBVYkHszpZQGxeASuJpiOLWCDWyUvsarvICmJzClhLrF2/mx3EFgKq2fL4P+MERp4F jAyrGEVSS4tz03OLjfSKE3OLS/PS9ZLzczcxAsNn27GfW3Ywdr0LPsQowMGoxMN7YvrLaCHW xLLiytxDjBIczEoivDtNXkUL8aYkVlalFuXHF5XmpBYfYpTmYFES5z1vUBklJJCeWJKanZpa kFoEk2Xi4JRqYNyzV9Xw4U/1bz33vapeHjjnm9qp4bOg8DMr+yPmr0Hv7v3+EsvQs31/mlSg t+WL++mvSowy83jUIjTZb615VVrbqsW04NztpxfTQ9tTdFiiGnnFI2IdfNO17x73sWnxNplx ye3QJ/67Bp+y+oKNb26KO/Vjhq2U68mK6TzuJ4sml26QSc04pMRSnJFoqMVcVJwIAHw9O34b AgAA X-CMS-MailID: 20181113131631eucas1p22091664348fd25e209d718250c0d286b X-Msg-Generator: CA CMS-TYPE: 201P X-CMS-RootMailID: 20181113131631eucas1p22091664348fd25e209d718250c0d286b References: <20181109132604.28619-1-andrzej.p@samsung.com> Sender: linux-usb-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-usb@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Some protocols implemented in userspace with FunctionFS might require large buffers, e.g. 64kB or more. Currently the said memory is allocated with kmalloc, which might fail should system memory be highly fragmented. On the other hand, some UDC hardware allows scatter-gather operation and this patch takes advantage of this capability: if the requested buffer is larger than PAGE_SIZE and the UDC allows scatter-gather operation, then the buffer is allocated with vmalloc and a scatterlist describing it is created and passed to usb request. Signed-off-by: Andrzej Pietrasiewicz --- v3: - simplified calculating number of pages the vmalloc'ed buffer occupies - simplified types in ffs_build_sg_list() - whitespace corrections v2: - added include directives for kvmalloc_array and vmalloc drivers/usb/gadget/function/f_fs.c | 94 +++++++++++++++++++++++++++++++++++--- 1 file changed, 87 insertions(+), 7 deletions(-) diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index 3ada83d..c27bc05 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -18,9 +18,12 @@ #include #include #include +#include #include +#include #include #include +#include #include #include @@ -219,6 +222,8 @@ struct ffs_io_data { struct usb_ep *ep; struct usb_request *req; + struct sg_table sgt; + bool use_sg; struct ffs_data *ffs; }; @@ -750,6 +755,66 @@ static ssize_t ffs_copy_to_iter(void *data, int data_len, struct iov_iter *iter) return ret; } +/* + * allocate a virtually contiguous buffer and create a scatterlist describing it + * @sg_table - pointer to a place to be filled with sg_table contents + * @size - required buffer size + */ +static void *ffs_build_sg_list(struct sg_table *sg_table, size_t size) +{ + struct page **pages; + void *vaddr, *ptr; + unsigned int n_pages; + int i; + + vaddr = vmalloc(size); + if (!vaddr) + return NULL; + + n_pages = PAGE_ALIGN(size) >> PAGE_SHIFT; + pages = kvmalloc_array(n_pages, sizeof(struct page *), GFP_KERNEL); + if (!pages) { + vfree(vaddr); + + return NULL; + } + for (i = 0, ptr = vaddr; i < n_pages; ++i, ptr += PAGE_SIZE) + pages[i] = vmalloc_to_page(ptr); + + if (sg_alloc_table_from_pages(sg_table, pages, n_pages, + (unsigned long)vaddr, size, GFP_KERNEL)) { + kvfree(pages); + vfree(vaddr); + + return NULL; + } + kvfree(pages); + + return vaddr; +} + +static inline void *ffs_alloc_buffer(struct ffs_io_data *io_data, + size_t data_len) +{ + if (io_data->use_sg) + return ffs_build_sg_list(&io_data->sgt, data_len); + + return kmalloc(data_len, GFP_KERNEL); +} + +static inline void ffs_free_buffer(struct ffs_io_data *io_data) +{ + if (!io_data->buf) + return; + + if (io_data->use_sg) { + sg_free_table(&io_data->sgt); + vfree(io_data->buf); + } else { + kfree(io_data->buf); + } +} + static void ffs_user_copy_worker(struct work_struct *work) { struct ffs_io_data *io_data = container_of(work, struct ffs_io_data, @@ -777,7 +842,7 @@ static void ffs_user_copy_worker(struct work_struct *work) if (io_data->read) kfree(io_data->to_free); - kfree(io_data->buf); + ffs_free_buffer(io_data); kfree(io_data); } @@ -933,6 +998,7 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data) * earlier */ gadget = epfile->ffs->gadget; + io_data->use_sg = gadget->sg_supported && data_len > PAGE_SIZE; spin_lock_irq(&epfile->ffs->eps_lock); /* In the meantime, endpoint got disabled or changed. */ @@ -949,7 +1015,7 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data) data_len = usb_ep_align_maybe(gadget, ep->ep, data_len); spin_unlock_irq(&epfile->ffs->eps_lock); - data = kmalloc(data_len, GFP_KERNEL); + data = ffs_alloc_buffer(io_data, data_len); if (unlikely(!data)) { ret = -ENOMEM; goto error_mutex; @@ -989,8 +1055,16 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data) bool interrupted = false; req = ep->req; - req->buf = data; - req->length = data_len; + if (io_data->use_sg) { + req->buf = NULL; + req->sg = io_data->sgt.sgl; + req->num_sgs = io_data->sgt.nents; + } else { + req->buf = data; + } + req->length = data_len; + + io_data->buf = data; req->context = &done; req->complete = ffs_epfile_io_complete; @@ -1023,8 +1097,14 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data) } else if (!(req = usb_ep_alloc_request(ep->ep, GFP_ATOMIC))) { ret = -ENOMEM; } else { - req->buf = data; - req->length = data_len; + if (io_data->use_sg) { + req->buf = NULL; + req->sg = io_data->sgt.sgl; + req->num_sgs = io_data->sgt.nents; + } else { + req->buf = data; + } + req->length = data_len; io_data->buf = data; io_data->ep = ep->ep; @@ -1053,7 +1133,7 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data) error_mutex: mutex_unlock(&epfile->mutex); error: - kfree(data); + ffs_free_buffer(io_data); return ret; }