From patchwork Fri Nov 9 13:26:04 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrzej Pietrasiewicz X-Patchwork-Id: 10675907 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 7BB7013AD for ; Fri, 9 Nov 2018 13:26:42 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 68C0E2EA47 for ; Fri, 9 Nov 2018 13:26:42 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 5BF732EA86; Fri, 9 Nov 2018 13:26:42 +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 95E9C2EA47 for ; Fri, 9 Nov 2018 13:26:41 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727794AbeKIXHR (ORCPT ); Fri, 9 Nov 2018 18:07:17 -0500 Received: from mailout2.w1.samsung.com ([210.118.77.12]:50609 "EHLO mailout2.w1.samsung.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727667AbeKIXHR (ORCPT ); Fri, 9 Nov 2018 18:07:17 -0500 Received: from eucas1p1.samsung.com (unknown [182.198.249.206]) by mailout2.w1.samsung.com (KnoxPortal) with ESMTP id 20181109132639euoutp02678f9a3e831db955f6bbe6f44c600ab5~ld6VItB4J1265712657euoutp02a; Fri, 9 Nov 2018 13:26:39 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 mailout2.w1.samsung.com 20181109132639euoutp02678f9a3e831db955f6bbe6f44c600ab5~ld6VItB4J1265712657euoutp02a DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=samsung.com; s=mail20170921; t=1541769999; bh=0dHCtyHmoO66wYrKzyZytiyTXOTTgCISc8sEVOUTcjo=; h=From:To:Cc:Subject:Date:In-reply-to:References:From; b=AbjWvNU9WGIWjQEEkPh8qS3LcrQnbSswFyL0FxQMmWIaM7nfqvdlo/COqvv5/Fmsd Z5m9SBKmqxUM2nqUDd5gOzjWVrcwrJRj9czs2SuuClBDXJtC4bArzj2VA33EEQnpCT F1ab6fkMbugJ4f8fzOlwLi1his3AgEmy+5AHw7kk= Received: from eusmges3new.samsung.com (unknown [203.254.199.245]) by eucas1p1.samsung.com (KnoxPortal) with ESMTP id 20181109132638eucas1p109e0e29e07d6222ed4d02dc4251b4bb5~ld6UVu9tW0189001890eucas1p1p; Fri, 9 Nov 2018 13:26:38 +0000 (GMT) Received: from eucas1p2.samsung.com ( [182.198.249.207]) by eusmges3new.samsung.com (EUCPMTA) with SMTP id 8D.F3.04806.E0B85EB5; Fri, 9 Nov 2018 13:26:38 +0000 (GMT) Received: from eusmgms1.samsung.com (unknown [182.198.249.179]) by eucas1p2.samsung.com (KnoxPortal) with ESMTP id 20181109132637eucas1p22adf70310533402ab0cdf970a98f99a3~ld6TsVI9V2179721797eucas1p2E; Fri, 9 Nov 2018 13:26:37 +0000 (GMT) X-AuditID: cbfec7f5-367ff700000012c6-8b-5be58b0e8eae Received: from eusync1.samsung.com ( [203.254.199.211]) by eusmgms1.samsung.com (EUCPMTA) with SMTP id 0F.36.04284.D0B85EB5; Fri, 9 Nov 2018 13:26:37 +0000 (GMT) Received: from mcdsrvbld02.digital.local ([106.116.37.23]) by eusync1.samsung.com (Oracle Communications Messaging Server 7.0.5.31.0 64bit (built May 5 2014)) with ESMTPA id <0PHX00977HC6U050@eusync1.samsung.com>; Fri, 09 Nov 2018 13:26:37 +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: [PATCHv2] usb: gadget: f_fs: Allow scatter-gather buffers Date: Fri, 09 Nov 2018 14:26:04 +0100 Message-id: <20181109132604.28619-1-andrzej.p@samsung.com> X-Mailer: git-send-email 2.11.0 In-reply-to: <201811092046.wQMUxr1i%fengguang.wu@intel.com> X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFlrJIsWRmVeSWpSXmKPExsWy7djP87p83U+jDZ5tZbGY9bKdxWLjjPWs FsfanrBbNC9ez2axaFkrs8XaI3fZLRYcb2F1YPfYtKqTzWP/3DXsHuv+vGLy6NuyitHj8ya5 ANYoLpuU1JzMstQifbsEroy1/w6xFCzQqrh24i9LA+MvxS5GTg4JAROJ/y2r2boYuTiEBFYw SmxubWCBcD4zSvz5v4gNpur4x3mMEIlljBKfu++xQjhNTBLb1h9jBKliEzCW2HuwA8wWEZCV OHzlNzNIEbPAZCaJA3Ofs4AkhAWcJM5/PcoOYrMIqErMWLKUFcTmFbCSWNSxkxVinbzErraL YDangLXEx38r2EEGSQj0sEncengTqshFYvOv41D3CUu8Or6FHcKWkejsOMgEYddLbPqyB6pm CqPEvbneELa1xOHjEAuYBfgkJm2bDnQpB1CcV6KjTQjC9JC4dkIT4sk+RomuI/fZJjBKLmBk WMUonlpanJueWmycl1quV5yYW1yal66XnJ+7iREYgaf/Hf+6g3Hfn6RDjAIcjEo8vAF1T6KF WBPLiitzDzFKcDArifBurX4aLcSbklhZlVqUH19UmpNafIhRmoNFSZy3muFBtJBAemJJanZq akFqEUyWiYNTqoHx4oVIj6+2lX4Ztx+pWvl/etv1fr+53UymzlO7U6ffK3RnEbov6fVywvHA Vz4q91s+tCYqKedl3HkSa85m8k2C33NesurnqsrvN7nruy9H3XR0U/+rLJaVLjiN7cs6ebaf YuonYpgn112IjS49vq47b/m6ygqpPcKB6l+u8PUcP23XviTg83slluKMREMt5qLiRAD1phiG vAIAAA== X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFmpnluLIzCtJLcpLzFFi42I5/e/4ZV3e7qfRBhemi1jMetnOYrFxxnpW i2NtT9gtmhevZ7NYtKyV2WLtkbvsFguOt7A6sHtsWtXJ5rF/7hp2j3V/XjF59G1ZxejxeZNc AGsUl01Kak5mWWqRvl0CV8baf4dYChZoVVw78ZelgfGXYhcjJ4eEgInE8Y/zGLsYuTiEBJYw Sqy9+Y0Nwmlhkvj6dz4rSBWbgLHE3oMdjCC2iICsxOErv5lBipgFpjJJfN40nwkkISzgJHH+ 61F2EJtFQFVixpKlYM28AlYSizp2skKsk5fY1XYRzOYUsJb4+G8FUD0H0DYriWcvyycw8ixg ZFjFKJJaWpybnltsqFecmFtcmpeul5yfu4kRGDzbjv3cvIPx0sbgQ4wCHIxKPLwCE59EC7Em lhVX5h5ilOBgVhLh3Vr9NFqINyWxsiq1KD++qDQntfgQozQHi5I473mDyighgfTEktTs1NSC 1CKYLBMHp1QDo8QkubUPtx0Os14dY7fHUCyh03x/zvmNebNXxSjcXq6wzFL3bBqvq5OB2skF e/8XB4Sxnj2wwnXuLyXebxdXdLw+vOy1ZNjC+A1bD+78fYUt8enbB/pVPHIvv6i96nz4+Mv/ B6JnDnL61btv/Kl5yWJyoqtY5b9Ni9M2VV5dJ7/vAUMb23KFH1eUWIozEg21mIuKEwGU3TMC GgIAAA== X-CMS-MailID: 20181109132637eucas1p22adf70310533402ab0cdf970a98f99a3 X-Msg-Generator: CA CMS-TYPE: 201P X-CMS-RootMailID: 20181109132637eucas1p22adf70310533402ab0cdf970a98f99a3 References: <201811092046.wQMUxr1i%fengguang.wu@intel.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 --- v2: - added include directives for kvmalloc_array and vmalloc drivers/usb/gadget/function/f_fs.c | 94 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 89 insertions(+), 5 deletions(-) diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index 3ada83d..2d8635f 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,70 @@ 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; + unsigned long ptr; + unsigned int n_pages; + int i; + + vaddr = vmalloc(size); + if (!vaddr) + return NULL; + + n_pages = (PAGE_ALIGN((unsigned long)vaddr + size) - + ((unsigned long)vaddr & PAGE_MASK)) + >> PAGE_SHIFT; + pages = kvmalloc_array(n_pages, sizeof(struct page *), GFP_KERNEL); + if (!pages) { + vfree(vaddr); + + return NULL; + } + for (i = 0, ptr = (unsigned long)vaddr & PAGE_MASK; i < n_pages; + ++i, ptr += PAGE_SIZE) + pages[i] = vmalloc_to_page((void *)ptr); + + if (sg_alloc_table_from_pages(sg_table, pages, n_pages, + ((unsigned long)vaddr) & ~PAGE_MASK, 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 +846,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 +1002,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 +1019,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,9 +1059,17 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data) bool interrupted = false; req = ep->req; - req->buf = data; + 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,7 +1101,13 @@ 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; + 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; @@ -1053,7 +1137,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; }