Received: by 2002:ac0:a5b6:0:0:0:0:0 with SMTP id m51-v6csp3170295imm; Tue, 29 May 2018 02:17:20 -0700 (PDT) X-Google-Smtp-Source: AB8JxZrBBXzhhuPWAZkQYx0xLBiCbfPSZCcKm/ALCzJM7XE2FEhKbgXt4c9i6iMSK/3e9g4wzyqs X-Received: by 2002:a17:902:7008:: with SMTP id y8-v6mr16580067plk.141.1527585440802; Tue, 29 May 2018 02:17:20 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1527585440; cv=none; d=google.com; s=arc-20160816; b=WXXYhi3JuVKuuAKI/ihPwTAnABIo63ecM7i8Qd5X+BixRqkb8kIMcPUi7Lvbzeyyl3 0+J53pJLnwXQAUjKzyhFg8XYwY7GGztQHjHHx77AucUXi+MYx1M0iOvG4KBcFXJzzSPI VPvZMvrMxCqSDu0kNOQEgjMLpsPq+S7HGj3SXHfihOQr7m6sunapzdgeR7ZqDW2qsbBf Vw0/uO2e9gWbG7JC+mIC7RXxo+WE4p54yNjYGuR8F8rRynp1KPvzekHm/EQrsDKMcBe/ jLBSL10JiYk4BEkHtlFYecgYHQwrClN3txUsb+8X0W0zGHGR61zc4/cOGMJ2ivjCoGw/ HShw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-language :content-transfer-encoding:in-reply-to:mime-version:user-agent:date :message-id:from:references:cc:to:subject:dkim-signature :arc-authentication-results; bh=2AKbwCB1A36z4yutWqEUTHfIkie+XFQWwGCGTH24ugU=; b=LZgwqYRSsIN1+d8NFMLjUDdT++UE8N87t8ak5goBY1c5LLrL8CCnmY5AuPr54lWH+T uTVBIdocucqe48YA0U1OaOc4IFj6jGOAHNpLTNOhRt6hgHefz6/pGjSS9Vfi5fLMKUPP bcvZr03x81KxNSB/SJ11+kJuNsb5Ok9j//j+H3ZFVHpEwF6yeO80SOrhygbwDUvQd5bp B+TFpq1RsMA3U3188I2N9dnUy32B79ROaOr/iOgvYzP/76pv7MMSn0N/efn0BgvrT0aD jAPbyoL7ZATOg7JntTjCPh9jCW5FXwrRNRmxG2bNqFkTI/RzBXtcu4LcqNx50+DJEi5l nwGw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@gmail.com header.s=20161025 header.b=vS4RS07M; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id f34-v6si31028289ple.52.2018.05.29.02.17.05; Tue, 29 May 2018 02:17:20 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@gmail.com header.s=20161025 header.b=vS4RS07M; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932655AbeE2JQZ (ORCPT + 99 others); Tue, 29 May 2018 05:16:25 -0400 Received: from mail-wr0-f195.google.com ([209.85.128.195]:40885 "EHLO mail-wr0-f195.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S932284AbeE2JQU (ORCPT ); Tue, 29 May 2018 05:16:20 -0400 Received: by mail-wr0-f195.google.com with SMTP id l41-v6so24237555wre.7; Tue, 29 May 2018 02:16:19 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=subject:to:cc:references:from:message-id:date:user-agent :mime-version:in-reply-to:content-transfer-encoding:content-language; bh=2AKbwCB1A36z4yutWqEUTHfIkie+XFQWwGCGTH24ugU=; b=vS4RS07M4fSqlQ5UGTDjPQPYEtqfoJFKUmy27RL+S8eLHYCEfjxvJOTXljoQRCexqx LD5MP+EODWnSQXGjKJdlTgWzLvCzvbJBj/Ez3GXgWtkv+jhbVojYSOcbvj6LaBvip2EQ jfR+4husqhGfcyPZvIz7EbzSr5zqbY1gVPGgtIOf2mKF9fb8IQjUDlEq2uUYrONC9hQ8 fupfydgycP5LMKPBkCfjK6ahSBi8TOmnEWGpTmgz6YlT9bNJH8Eazzn6kWpgQNUVmUT5 mUisBd4u01wrIck7jE2e+U83JmsswAnL3sRef+hssxTRfh9QDJi8azfGhGDEhGbqn3XB CiCA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:subject:to:cc:references:from:message-id:date :user-agent:mime-version:in-reply-to:content-transfer-encoding :content-language; bh=2AKbwCB1A36z4yutWqEUTHfIkie+XFQWwGCGTH24ugU=; b=kSXO2DkXelyyM1l+Fp0jJUzUx5GAr8z0w6f3a46stCdl1/B7cflh5QxACzPqqGhNCh nxWXXipgS04kEc4ugl4vpjHUqHLhCNn4t1Aq7LyIvI33mlSBWsHqiMCVQ/kUn5xC92h8 IHRDJ/AyyTwL9L/sIw2xBAuCd2xpaefuFGZki8gRPsZu/8yOiLbPaz/wl56J7ccN7/DD X4FvCt+nTf65hVhXdruouY7vX9rTX2n6EwaFhYR60vSKv9P/UAXLMVxnDltEUzTSxTbB rPeWvlNlYz4y8Fes3/zMAuGaGxT1k8xAcmW2KSz2u5Ok4TCjrstaEz1re9RfAeB0dWPK BQ+A== X-Gm-Message-State: ALKqPwdNRgiTS2oiLm0JhMfZiWO+wvvssQ3ts17drwFWFAWz4NmDyswO 3lRGLSizxQRxEfjw0oB0Mqma0sWYn7M= X-Received: by 2002:a19:380a:: with SMTP id f10-v6mr8756202lfa.47.1527585378726; Tue, 29 May 2018 02:16:18 -0700 (PDT) Received: from [10.17.182.9] (ll-52.209.223.85.sovam.net.ua. [85.223.209.52]) by smtp.gmail.com with ESMTPSA id q25-v6sm6275631ljj.68.2018.05.29.02.16.17 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 29 May 2018 02:16:17 -0700 (PDT) Subject: Re: [PATCH v3] Add udmabuf misc device To: Gerd Hoffmann , dri-devel@lists.freedesktop.org Cc: "open list:KERNEL SELFTEST FRAMEWORK" , Tomeu Vizoso , David Airlie , open list , "moderated list:DMA BUFFER SHARING FRAMEWORK" , Shuah Khan , "open list:DMA BUFFER SHARING FRAMEWORK" References: <20180525140808.12714-1-kraxel@redhat.com> From: Oleksandr Andrushchenko Message-ID: <0ad0606e-3201-e203-ec93-8718d7938751@gmail.com> Date: Tue, 29 May 2018 12:16:16 +0300 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Thunderbird/52.7.0 MIME-Version: 1.0 In-Reply-To: <20180525140808.12714-1-kraxel@redhat.com> Content-Type: text/plain; charset=utf-8; format=flowed Content-Transfer-Encoding: 7bit Content-Language: en-US Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org On 05/25/2018 05:08 PM, Gerd Hoffmann wrote: > A driver to let userspace turn memfd regions into dma-bufs. > > Use case: Allows qemu create dmabufs for the vga framebuffer or > virtio-gpu ressources. Then they can be passed around to display > those guest things on the host. To spice client for classic full > framebuffer display, and hopefully some day to wayland server for > seamless guest window display. > > Note: Initial revision which supports a single region only so it > can't handle virtio-gpu ressources yet. > > qemu test branch: > https://git.kraxel.org/cgit/qemu/log/?h=sirius/udmabuf > > Cc: David Airlie > Cc: Tomeu Vizoso > Cc: Daniel Vetter > Signed-off-by: Gerd Hoffmann > --- > include/uapi/linux/udmabuf.h | 19 ++ > drivers/dma-buf/udmabuf.c | 240 ++++++++++++++++++++++ > tools/testing/selftests/drivers/dma-buf/udmabuf.c | 95 +++++++++ > drivers/dma-buf/Kconfig | 7 + > drivers/dma-buf/Makefile | 1 + > tools/testing/selftests/drivers/dma-buf/Makefile | 5 + > 6 files changed, 367 insertions(+) > create mode 100644 include/uapi/linux/udmabuf.h > create mode 100644 drivers/dma-buf/udmabuf.c > create mode 100644 tools/testing/selftests/drivers/dma-buf/udmabuf.c > create mode 100644 tools/testing/selftests/drivers/dma-buf/Makefile > > diff --git a/include/uapi/linux/udmabuf.h b/include/uapi/linux/udmabuf.h > new file mode 100644 > index 0000000000..2fbe69cf05 > --- /dev/null > +++ b/include/uapi/linux/udmabuf.h > @@ -0,0 +1,19 @@ > +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ > +#ifndef _UAPI_LINUX_UDMABUF_H > +#define _UAPI_LINUX_UDMABUF_H > + > +#include > +#include > + > +#define UDMABUF_FLAGS_CLOEXEC 0x01 > + > +struct udmabuf_create { > + __u32 memfd; > + __u32 flags; > + __u64 offset; > + __u64 size; > +}; > + > +#define UDMABUF_CREATE _IOW(0x42, 0x23, struct udmabuf_create) > + > +#endif /* _UAPI_LINUX_UDMABUF_H */ > diff --git a/drivers/dma-buf/udmabuf.c b/drivers/dma-buf/udmabuf.c > new file mode 100644 > index 0000000000..f9600dc985 > --- /dev/null > +++ b/drivers/dma-buf/udmabuf.c > @@ -0,0 +1,240 @@ > +/* > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License version 2 as > + * published by the Free Software Foundation. > + */ > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include > + > +struct udmabuf { > + struct file *filp; > + u32 pagecount; > + struct page **pages; > +}; > + > +static int udmabuf_vm_fault(struct vm_fault *vmf) > +{ > + struct vm_area_struct *vma = vmf->vma; > + struct udmabuf *ubuf = vma->vm_private_data; > + > + if (WARN_ON(vmf->pgoff >= ubuf->pagecount)) > + return VM_FAULT_SIGBUS; > + > + vmf->page = ubuf->pages[vmf->pgoff]; > + get_page(vmf->page); > + return 0; > +} > + > +static const struct vm_operations_struct udmabuf_vm_ops = { > + .fault = udmabuf_vm_fault, > +}; > + > +static int mmap_udmabuf(struct dma_buf *buf, struct vm_area_struct *vma) > +{ > + struct udmabuf *ubuf = buf->priv; > + > + if ((vma->vm_flags & VM_SHARED) == 0) > + return -EINVAL; > + > + vma->vm_ops = &udmabuf_vm_ops; > + vma->vm_private_data = ubuf; > + return 0; > +} > + > +static struct sg_table *map_udmabuf(struct dma_buf_attachment *at, > + enum dma_data_direction direction) > +{ > + struct udmabuf *ubuf = at->dmabuf->priv; > + struct sg_table *sg; > + > + sg = kzalloc(sizeof(*sg), GFP_KERNEL); > + if (!sg) > + goto err1; > + if (sg_alloc_table_from_pages(sg, ubuf->pages, ubuf->pagecount, > + 0, ubuf->pagecount << PAGE_SHIFT, > + GFP_KERNEL) < 0) > + goto err2; > + if (!dma_map_sg(at->dev, sg->sgl, sg->nents, direction)) > + goto err3; > + > + return sg; > + > +err3: > + sg_free_table(sg); > +err2: > + kfree(sg); > +err1: > + return ERR_PTR(-ENOMEM); > +} > + > +static void unmap_udmabuf(struct dma_buf_attachment *at, > + struct sg_table *sg, > + enum dma_data_direction direction) > +{ > + sg_free_table(sg); > + kfree(sg); > +} > + > +static void release_udmabuf(struct dma_buf *buf) > +{ > + struct udmabuf *ubuf = buf->priv; > + pgoff_t pg; > + > + for (pg = 0; pg < ubuf->pagecount; pg++) > + put_page(ubuf->pages[pg]); > + fput(ubuf->filp); > + kfree(ubuf->pages); > + kfree(ubuf); > +} > + > +static void *kmap_atomic_udmabuf(struct dma_buf *buf, unsigned long page_num) > +{ > + struct udmabuf *ubuf = buf->priv; > + struct page *page = ubuf->pages[page_num]; > + > + return kmap_atomic(page); > +} > + > +static void *kmap_udmabuf(struct dma_buf *buf, unsigned long page_num) > +{ > + struct udmabuf *ubuf = buf->priv; > + struct page *page = ubuf->pages[page_num]; > + > + return kmap(page); > +} > + > +static struct dma_buf_ops udmabuf_ops = { > + .map_dma_buf = map_udmabuf, > + .unmap_dma_buf = unmap_udmabuf, > + .release = release_udmabuf, > + .map_atomic = kmap_atomic_udmabuf, > + .map = kmap_udmabuf, > + .mmap = mmap_udmabuf, > +}; > + > +static long udmabuf_ioctl_create(struct file *filp, unsigned long arg) > +{ > + DEFINE_DMA_BUF_EXPORT_INFO(exp_info); > + struct udmabuf_create create; > + struct udmabuf *ubuf; > + struct dma_buf *buf; > + pgoff_t pgoff, pgidx; > + struct page *page; > + int ret = -EINVAL; > + u32 flags; > + > + if (copy_from_user(&create, (void __user *)arg, > + sizeof(struct udmabuf_create))) > + return -EFAULT; > + > + if (!IS_ALIGNED(create.offset, PAGE_SIZE)) > + return -EINVAL; > + if (!IS_ALIGNED(create.size, PAGE_SIZE)) > + return -EINVAL; > + > + ubuf = kzalloc(sizeof(struct udmabuf), GFP_KERNEL); > + if (!ubuf) > + return -ENOMEM; > + > + ubuf->filp = fget(create.memfd); > + if (!ubuf->filp) > + goto err_free_ubuf; > + if (!shmem_mapping(file_inode(ubuf->filp)->i_mapping)) > + goto err_free_ubuf; > + > + ubuf->pagecount = create.size >> PAGE_SHIFT; > + ubuf->pages = kmalloc_array(ubuf->pagecount, sizeof(struct page*), > + GFP_KERNEL); > + if (!ubuf->pages) { > + ret = -ENOMEM; > + goto err_free_ubuf; > + } > + > + pgoff = create.offset >> PAGE_SHIFT; > + for (pgidx = 0; pgidx < ubuf->pagecount; pgidx++) { > + page = shmem_read_mapping_page( > + file_inode(ubuf->filp)->i_mapping, pgoff + pgidx); > + if (IS_ERR(page)) { > + ret = PTR_ERR(buf); > + goto err_put_pages; > + } > + ubuf->pages[pgidx] = page; > + } > + > + exp_info.ops = &udmabuf_ops; > + exp_info.size = ubuf->pagecount << PAGE_SHIFT; > + exp_info.priv = ubuf; > + > + buf = dma_buf_export(&exp_info); > + if (IS_ERR(buf)) { > + ret = PTR_ERR(buf); > + goto err_put_pages; > + } > + > + flags = 0; > + if (create.flags & UDMABUF_FLAGS_CLOEXEC) > + flags |= O_CLOEXEC; > + return dma_buf_fd(buf, flags); > + > +err_put_pages: > + while (pgidx > 0) > + put_page(ubuf->pages[--pgidx]); > +err_free_ubuf: > + fput(ubuf->filp); > + kfree(ubuf->pages); > + kfree(ubuf); > + return ret; > +} > + > +static long udmabuf_ioctl(struct file *filp, unsigned int ioctl, > + unsigned long arg) > +{ > + long ret; > + > + switch (ioctl) { > + case UDMABUF_CREATE: > + ret = udmabuf_ioctl_create(filp, arg); > + break; > + default: > + ret = -EINVAL; > + break; > + } > + return ret; > +} > + > +static const struct file_operations udmabuf_fops = { > + .owner = THIS_MODULE, > + .unlocked_ioctl = udmabuf_ioctl, > +}; > + > +static struct miscdevice udmabuf_misc = { > + .minor = MISC_DYNAMIC_MINOR, > + .name = "udmabuf", > + .fops = &udmabuf_fops, > +}; > + > +static int __init udmabuf_dev_init(void) > +{ > + return misc_register(&udmabuf_misc); > +} > + > +static void __exit udmabuf_dev_exit(void) > +{ > + misc_deregister(&udmabuf_misc); > +} > + > +module_init(udmabuf_dev_init) > +module_exit(udmabuf_dev_exit) > + > +MODULE_AUTHOR("Gerd Hoffmann "); > +MODULE_LICENSE("GPL v2"); > diff --git a/tools/testing/selftests/drivers/dma-buf/udmabuf.c b/tools/testing/selftests/drivers/dma-buf/udmabuf.c > new file mode 100644 > index 0000000000..d46c58b0dd > --- /dev/null > +++ b/tools/testing/selftests/drivers/dma-buf/udmabuf.c > @@ -0,0 +1,95 @@ > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include > +#include > +#include > +#include > + > +#define TEST_PREFIX "drivers/dma-buf/udmabuf" > +#define NUM_PAGES 4 > + > +static int memfd_create(const char *name, unsigned int flags) > +{ > + return syscall(__NR_memfd_create, name, flags); > +} > + > +int main(int argc, char *argv[]) > +{ > + struct udmabuf_create create; > + int devfd, memfd, buf, ret; > + off_t size; > + void *mem; > + > + devfd = open("/dev/udmabuf", O_RDWR); > + if (devfd < 0) { > + printf("%s: [skip,no-udmabuf]\n", TEST_PREFIX); > + exit(77); > + } > + > + memfd = memfd_create("udmabuf-test", MFD_CLOEXEC); > + if (memfd < 0) { > + printf("%s: [skip,no-memfd]\n", TEST_PREFIX); > + exit(77); > + } > + > + size = getpagesize() * NUM_PAGES; > + ret = ftruncate(memfd, size); > + if (ret == -1) { > + printf("%s: [FAIL,memfd-truncate]\n", TEST_PREFIX); > + exit(1); > + } > + > + memset(&create, 0, sizeof(create)); > + > + /* should fail (offset not page aligned) */ > + create.memfd = memfd; > + create.offset = getpagesize()/2; > + create.size = getpagesize(); > + buf = ioctl(devfd, UDMABUF_CREATE, &create); > + if (buf >= 0) { > + printf("%s: [FAIL,test-1]\n", TEST_PREFIX); > + exit(1); > + } > + > + /* should fail (size not multiple of page) */ > + create.memfd = memfd; > + create.offset = 0; > + create.size = getpagesize()/2; > + buf = ioctl(devfd, UDMABUF_CREATE, &create); > + if (buf >= 0) { > + printf("%s: [FAIL,test-2]\n", TEST_PREFIX); > + exit(1); > + } > + > + /* should fail (not memfd) */ > + create.memfd = 0; /* stdin */ > + create.offset = 0; > + create.size = size; > + buf = ioctl(devfd, UDMABUF_CREATE, &create); > + if (buf >= 0) { > + printf("%s: [FAIL,test-3]\n", TEST_PREFIX); > + exit(1); > + } > + > + /* should work */ > + create.memfd = memfd; > + create.offset = 0; > + create.size = size; > + buf = ioctl(devfd, UDMABUF_CREATE, &create); > + if (buf < 0) { > + printf("%s: [FAIL,test-4]\n", TEST_PREFIX); > + exit(1); > + } > + > + fprintf(stderr, "%s: ok\n", TEST_PREFIX); > + close(buf); > + close(memfd); > + close(devfd); > + return 0; > +} > diff --git a/drivers/dma-buf/Kconfig b/drivers/dma-buf/Kconfig > index ed3b785bae..19be3ec62d 100644 > --- a/drivers/dma-buf/Kconfig > +++ b/drivers/dma-buf/Kconfig > @@ -30,4 +30,11 @@ config SW_SYNC > WARNING: improper use of this can result in deadlocking kernel > drivers from userspace. Intended for test and debug only. > > +config UDMABUF > + bool "userspace dmabuf misc driver" > + default n > + depends on DMA_SHARED_BUFFER Don't you want "select DMA_SHARED_BUFFER" here instead? > + ---help--- > + A driver to let userspace turn iovs into dma-bufs. > + > endmenu > diff --git a/drivers/dma-buf/Makefile b/drivers/dma-buf/Makefile > index c33bf88631..0913a6ccab 100644 > --- a/drivers/dma-buf/Makefile > +++ b/drivers/dma-buf/Makefile > @@ -1,3 +1,4 @@ > obj-y := dma-buf.o dma-fence.o dma-fence-array.o reservation.o seqno-fence.o > obj-$(CONFIG_SYNC_FILE) += sync_file.o > obj-$(CONFIG_SW_SYNC) += sw_sync.o sync_debug.o > +obj-$(CONFIG_UDMABUF) += udmabuf.o > diff --git a/tools/testing/selftests/drivers/dma-buf/Makefile b/tools/testing/selftests/drivers/dma-buf/Makefile > new file mode 100644 > index 0000000000..4154c3d7aa > --- /dev/null > +++ b/tools/testing/selftests/drivers/dma-buf/Makefile > @@ -0,0 +1,5 @@ > +CFLAGS += -I../../../../../usr/include/ > + > +TEST_GEN_PROGS := udmabuf > + > +include ../../lib.mk