From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=0.7 required=3.0 tests=DKIM_SIGNED, HEADER_FROM_DIFFERENT_DOMAINS,MAILING_LIST_MULTI,SPF_PASS,T_DKIM_INVALID, UNWANTED_LANGUAGE_BODY,URIBL_BLOCKED,USER_AGENT_MUTT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 4EF13C6778A for ; Tue, 3 Jul 2018 08:38:13 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id D20BF23EDB for ; Tue, 3 Jul 2018 08:38:12 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (1024-bit key) header.d=ffwll.ch header.i=@ffwll.ch header.b="jMAwdvzb" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org D20BF23EDB Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=ffwll.ch Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754665AbeGCIiH (ORCPT ); Tue, 3 Jul 2018 04:38:07 -0400 Received: from mail-ed1-f68.google.com ([209.85.208.68]:43732 "EHLO mail-ed1-f68.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754309AbeGCIiC (ORCPT ); Tue, 3 Jul 2018 04:38:02 -0400 Received: by mail-ed1-f68.google.com with SMTP id u11-v6so997631eds.10 for ; Tue, 03 Jul 2018 01:38:01 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ffwll.ch; s=google; h=sender:date:from:to:cc:subject:message-id:mail-followup-to :references:mime-version:content-disposition:in-reply-to:user-agent; bh=J3xyWGG6ZXebSzSEbg3ED9ghEns3bxafjdwoLEd2TME=; b=jMAwdvzbKZFOG8PxFV8Taw+tNqNPoSLw+MEWs82ST2/mRbSMNkLEPLcVeaYcvsenPw Smj2ma0zqmRHxISjdd9jkJJrsuq8fPbQyTS7nCr68ZQlvRkSu1DE3W2nBWfvo7K8ocLq mEd1D2ywapDOqGUXM9o2RSOEvDe+5GC7zSOiM= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:date:from:to:cc:subject:message-id :mail-followup-to:references:mime-version:content-disposition :in-reply-to:user-agent; bh=J3xyWGG6ZXebSzSEbg3ED9ghEns3bxafjdwoLEd2TME=; b=DsSXfMZE/vSUpWh5YJ8YoYQ+YDGfEHyRXLdnJJYQ6u70S0nrRJTDrdqjzaDuK8rlH6 8tdVHCw2jkEkWzmjJceUjmn9JNAUkLDsXOHxobVM7mTUWkTSUK6zIOD211h9JwW7nIDC VgykTrDI65ra9rCalzcEayImGF+SwD93k54gR7Bup+v1yVZdJBUXLJJnc8TzHuBD97uY GrERzeA8wK9DOJILmICb2eyjoVDcqdSKkPDj1aDUKnHD2/i4qXQ8etwHo8LjYYSHXxOd 1Vrwh9otbaEEVqSMW/9E8RfvSXqJSag02uzrcSCSkNA2bLLgSb+7Lr24TESuvzag1W35 QCzg== X-Gm-Message-State: APt69E2t9pKKSzZjOX3nxr/+ttq2B2Ti2VgoMTufjLhQggafdP4R3m1+ 0qlsNZvCoWVrRS6gBeEPTtvDWQ== X-Google-Smtp-Source: AAOMgpc7vNMFt1OYV4WmPcGD8e4Ahoqth7co13KFUAVzqFSZUGwVAStH+NXtNjThGVogu3RD3fKseQ== X-Received: by 2002:a50:88c2:: with SMTP id d60-v6mr26718310edd.281.1530607080825; Tue, 03 Jul 2018 01:38:00 -0700 (PDT) Received: from phenom.ffwll.local ([2a02:168:5628:0:496f:7dc5:66d7:a057]) by smtp.gmail.com with ESMTPSA id d11-v6sm391380edr.24.2018.07.03.01.37.59 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Tue, 03 Jul 2018 01:37:59 -0700 (PDT) Date: Tue, 3 Jul 2018 10:37:57 +0200 From: Daniel Vetter To: Gerd Hoffmann Cc: dri-devel@lists.freedesktop.org, David Airlie , Tomeu Vizoso , Laurent Pinchart , Daniel Vetter , Jonathan Corbet , Sumit Semwal , Shuah Khan , "open list:DOCUMENTATION" , open list , "open list:DMA BUFFER SHARING FRAMEWORK" , "moderated list:DMA BUFFER SHARING FRAMEWORK" , "open list:KERNEL SELFTEST FRAMEWORK" Subject: Re: [PATCH v6] Add udmabuf misc device Message-ID: <20180703083757.GG7880@phenom.ffwll.local> Mail-Followup-To: Gerd Hoffmann , dri-devel@lists.freedesktop.org, David Airlie , Tomeu Vizoso , Laurent Pinchart , Jonathan Corbet , Sumit Semwal , Shuah Khan , "open list:DOCUMENTATION" , open list , "open list:DMA BUFFER SHARING FRAMEWORK" , "moderated list:DMA BUFFER SHARING FRAMEWORK" , "open list:KERNEL SELFTEST FRAMEWORK" References: <20180703075359.30349-1-kraxel@redhat.com> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <20180703075359.30349-1-kraxel@redhat.com> X-Operating-System: Linux phenom 4.16.0-2-amd64 User-Agent: Mutt/1.10.0 (2018-05-17) Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org On Tue, Jul 03, 2018 at 09:53:58AM +0200, 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. > > qemu test branch: > https://git.kraxel.org/cgit/qemu/log/?h=sirius/udmabuf > > Cc: David Airlie > Cc: Tomeu Vizoso > Cc: Laurent Pinchart > Cc: Daniel Vetter > Signed-off-by: Gerd Hoffmann I think some ack for a 2nd use-case, like virtio-wl or whatever would be really cool. To give us some assurance that this is generically useful. Plus an ack from dma-buf folks (nag them on irc, you don't have them on Cc here). Then this is imo good to go. I assume you'll push it to drm-misc, like all the other dma-buf stuff? -Daniel > --- > Documentation/ioctl/ioctl-number.txt | 1 + > include/uapi/linux/udmabuf.h | 33 +++ > drivers/dma-buf/udmabuf.c | 287 ++++++++++++++++++++++ > tools/testing/selftests/drivers/dma-buf/udmabuf.c | 96 ++++++++ > MAINTAINERS | 8 + > drivers/dma-buf/Kconfig | 8 + > drivers/dma-buf/Makefile | 1 + > tools/testing/selftests/drivers/dma-buf/Makefile | 5 + > 8 files changed, 439 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/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt > index 480c8609dc..6636dea476 100644 > --- a/Documentation/ioctl/ioctl-number.txt > +++ b/Documentation/ioctl/ioctl-number.txt > @@ -271,6 +271,7 @@ Code Seq#(hex) Include File Comments > 't' 90-91 linux/toshiba.h toshiba and toshiba_acpi SMM > 'u' 00-1F linux/smb_fs.h gone > 'u' 20-3F linux/uvcvideo.h USB video class host driver > +'u' 40-4f linux/udmabuf.h userspace dma-buf misc device > 'v' 00-1F linux/ext2_fs.h conflict! > 'v' 00-1F linux/fs.h conflict! > 'v' 00-0F linux/sonypi.h conflict! > diff --git a/include/uapi/linux/udmabuf.h b/include/uapi/linux/udmabuf.h > new file mode 100644 > index 0000000000..46b6532ed8 > --- /dev/null > +++ b/include/uapi/linux/udmabuf.h > @@ -0,0 +1,33 @@ > +/* 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; > +}; > + > +struct udmabuf_create_item { > + __u32 memfd; > + __u32 __pad; > + __u64 offset; > + __u64 size; > +}; > + > +struct udmabuf_create_list { > + __u32 flags; > + __u32 count; > + struct udmabuf_create_item list[]; > +}; > + > +#define UDMABUF_CREATE _IOW('u', 0x42, struct udmabuf_create) > +#define UDMABUF_CREATE_LIST _IOW('u', 0x43, struct udmabuf_create_list) > + > +#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..8e24204526 > --- /dev/null > +++ b/drivers/dma-buf/udmabuf.c > @@ -0,0 +1,287 @@ > +// SPDX-License-Identifier: GPL-2.0 > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include > + > +struct udmabuf { > + 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 | VM_MAYSHARE)) == 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]); > + kfree(ubuf->pages); > + kfree(ubuf); > +} > + > +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 void kunmap_udmabuf(struct dma_buf *buf, unsigned long page_num, > + void *vaddr) > +{ > + kunmap(vaddr); > +} > + > +static struct dma_buf_ops udmabuf_ops = { > + .map_dma_buf = map_udmabuf, > + .unmap_dma_buf = unmap_udmabuf, > + .release = release_udmabuf, > + .map = kmap_udmabuf, > + .unmap = kunmap_udmabuf, > + .mmap = mmap_udmabuf, > +}; > + > +#define SEALS_WANTED (F_SEAL_SHRINK) > +#define SEALS_DENIED (F_SEAL_WRITE) > + > +static long udmabuf_create(struct udmabuf_create_list *head, > + struct udmabuf_create_item *list) > +{ > + DEFINE_DMA_BUF_EXPORT_INFO(exp_info); > + struct file *memfd = NULL; > + struct udmabuf *ubuf; > + struct dma_buf *buf; > + pgoff_t pgoff, pgcnt, pgidx, pgbuf; > + struct page *page; > + int seals, ret = -EINVAL; > + u32 i, flags; > + > + ubuf = kzalloc(sizeof(struct udmabuf), GFP_KERNEL); > + if (!ubuf) > + return -ENOMEM; > + > + for (i = 0; i < head->count; i++) { > + if (!IS_ALIGNED(list[i].offset, PAGE_SIZE)) > + goto err_free_ubuf; > + if (!IS_ALIGNED(list[i].size, PAGE_SIZE)) > + goto err_free_ubuf; > + ubuf->pagecount += list[i].size >> PAGE_SHIFT; > + } > + ubuf->pages = kmalloc_array(ubuf->pagecount, sizeof(struct page *), > + GFP_KERNEL); > + if (!ubuf->pages) { > + ret = -ENOMEM; > + goto err_free_ubuf; > + } > + > + pgbuf = 0; > + for (i = 0; i < head->count; i++) { > + memfd = fget(list[i].memfd); > + if (!memfd) > + goto err_put_pages; > + if (!shmem_mapping(file_inode(memfd)->i_mapping)) > + goto err_put_pages; > + seals = memfd_fcntl(memfd, F_GET_SEALS, 0); > + if (seals == -EINVAL || > + (seals & SEALS_WANTED) != SEALS_WANTED || > + (seals & SEALS_DENIED) != 0) > + goto err_put_pages; > + pgoff = list[i].offset >> PAGE_SHIFT; > + pgcnt = list[i].size >> PAGE_SHIFT; > + for (pgidx = 0; pgidx < pgcnt; pgidx++) { > + page = shmem_read_mapping_page( > + file_inode(memfd)->i_mapping, pgoff + pgidx); > + if (IS_ERR(page)) { > + ret = PTR_ERR(page); > + goto err_put_pages; > + } > + ubuf->pages[pgbuf++] = page; > + } > + fput(memfd); > + } > + memfd = NULL; > + > + 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 (head->flags & UDMABUF_FLAGS_CLOEXEC) > + flags |= O_CLOEXEC; > + return dma_buf_fd(buf, flags); > + > +err_put_pages: > + while (pgbuf > 0) > + put_page(ubuf->pages[--pgbuf]); > +err_free_ubuf: > + fput(memfd); > + kfree(ubuf->pages); > + kfree(ubuf); > + return ret; > +} > + > +static long udmabuf_ioctl_create(struct file *filp, unsigned long arg) > +{ > + struct udmabuf_create create; > + struct udmabuf_create_list head; > + struct udmabuf_create_item list; > + > + if (copy_from_user(&create, (void __user *)arg, > + sizeof(struct udmabuf_create))) > + return -EFAULT; > + > + head.flags = create.flags; > + head.count = 1; > + list.memfd = create.memfd; > + list.offset = create.offset; > + list.size = create.size; > + > + return udmabuf_create(&head, &list); > +} > + > +static long udmabuf_ioctl_create_list(struct file *filp, unsigned long arg) > +{ > + struct udmabuf_create_list head; > + struct udmabuf_create_item *list; > + int ret = -EINVAL; > + u32 lsize; > + > + if (copy_from_user(&head, (void __user *)arg, sizeof(head))) > + return -EFAULT; > + if (head.count > 1024) > + return -EINVAL; > + lsize = sizeof(struct udmabuf_create_item) * head.count; > + list = memdup_user((void __user *)(arg + sizeof(head)), lsize); > + if (IS_ERR(list)) > + return PTR_ERR(list); > + > + ret = udmabuf_create(&head, list); > + kfree(list); > + 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; > + case UDMABUF_CREATE_LIST: > + ret = udmabuf_ioctl_create_list(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..376b1d6730 > --- /dev/null > +++ b/tools/testing/selftests/drivers/dma-buf/udmabuf.c > @@ -0,0 +1,96 @@ > +// SPDX-License-Identifier: GPL-2.0 > +#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/MAINTAINERS b/MAINTAINERS > index 07d1576fc7..a8e1bb3bc3 100644 > --- a/MAINTAINERS > +++ b/MAINTAINERS > @@ -14638,6 +14638,14 @@ S: Maintained > F: Documentation/filesystems/udf.txt > F: fs/udf/ > > +UDMABUF DRIVER > +M: Gerd Hoffmann > +L: dri-devel@lists.freedesktop.org > +S: Maintained > +F: drivers/dma-buf/udmabuf.c > +F: include/uapi/linux/udmabuf.h > +F: tools/testing/selftests/drivers/dma-buf/udmabuf.c > + > UDRAW TABLET > M: Bastien Nocera > L: linux-input@vger.kernel.org > diff --git a/drivers/dma-buf/Kconfig b/drivers/dma-buf/Kconfig > index ed3b785bae..338129eb12 100644 > --- a/drivers/dma-buf/Kconfig > +++ b/drivers/dma-buf/Kconfig > @@ -30,4 +30,12 @@ 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 > + help > + A driver to let userspace turn memfd regions into dma-bufs. > + Qemu can use this to create host dmabufs for guest framebuffers. > + > 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 > -- > 2.9.3 > -- Daniel Vetter Software Engineer, Intel Corporation http://blog.ffwll.ch From mboxrd@z Thu Jan 1 00:00:00 1970 Return-path: Received: from mail-ed1-f68.google.com ([209.85.208.68]:46399 "EHLO mail-ed1-f68.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753560AbeGCIiC (ORCPT ); Tue, 3 Jul 2018 04:38:02 -0400 Received: by mail-ed1-f68.google.com with SMTP id r17-v6so994861edo.13 for ; Tue, 03 Jul 2018 01:38:01 -0700 (PDT) Date: Tue, 3 Jul 2018 10:37:57 +0200 From: Daniel Vetter To: Gerd Hoffmann Cc: dri-devel@lists.freedesktop.org, David Airlie , Tomeu Vizoso , Laurent Pinchart , Daniel Vetter , Jonathan Corbet , Sumit Semwal , Shuah Khan , "open list:DOCUMENTATION" , open list , "open list:DMA BUFFER SHARING FRAMEWORK" , "moderated list:DMA BUFFER SHARING FRAMEWORK" , "open list:KERNEL SELFTEST FRAMEWORK" Subject: Re: [PATCH v6] Add udmabuf misc device Message-ID: <20180703083757.GG7880@phenom.ffwll.local> References: <20180703075359.30349-1-kraxel@redhat.com> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <20180703075359.30349-1-kraxel@redhat.com> Sender: linux-media-owner@vger.kernel.org List-ID: On Tue, Jul 03, 2018 at 09:53:58AM +0200, 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. > > qemu test branch: > https://git.kraxel.org/cgit/qemu/log/?h=sirius/udmabuf > > Cc: David Airlie > Cc: Tomeu Vizoso > Cc: Laurent Pinchart > Cc: Daniel Vetter > Signed-off-by: Gerd Hoffmann I think some ack for a 2nd use-case, like virtio-wl or whatever would be really cool. To give us some assurance that this is generically useful. Plus an ack from dma-buf folks (nag them on irc, you don't have them on Cc here). Then this is imo good to go. I assume you'll push it to drm-misc, like all the other dma-buf stuff? -Daniel > --- > Documentation/ioctl/ioctl-number.txt | 1 + > include/uapi/linux/udmabuf.h | 33 +++ > drivers/dma-buf/udmabuf.c | 287 ++++++++++++++++++++++ > tools/testing/selftests/drivers/dma-buf/udmabuf.c | 96 ++++++++ > MAINTAINERS | 8 + > drivers/dma-buf/Kconfig | 8 + > drivers/dma-buf/Makefile | 1 + > tools/testing/selftests/drivers/dma-buf/Makefile | 5 + > 8 files changed, 439 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/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt > index 480c8609dc..6636dea476 100644 > --- a/Documentation/ioctl/ioctl-number.txt > +++ b/Documentation/ioctl/ioctl-number.txt > @@ -271,6 +271,7 @@ Code Seq#(hex) Include File Comments > 't' 90-91 linux/toshiba.h toshiba and toshiba_acpi SMM > 'u' 00-1F linux/smb_fs.h gone > 'u' 20-3F linux/uvcvideo.h USB video class host driver > +'u' 40-4f linux/udmabuf.h userspace dma-buf misc device > 'v' 00-1F linux/ext2_fs.h conflict! > 'v' 00-1F linux/fs.h conflict! > 'v' 00-0F linux/sonypi.h conflict! > diff --git a/include/uapi/linux/udmabuf.h b/include/uapi/linux/udmabuf.h > new file mode 100644 > index 0000000000..46b6532ed8 > --- /dev/null > +++ b/include/uapi/linux/udmabuf.h > @@ -0,0 +1,33 @@ > +/* 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; > +}; > + > +struct udmabuf_create_item { > + __u32 memfd; > + __u32 __pad; > + __u64 offset; > + __u64 size; > +}; > + > +struct udmabuf_create_list { > + __u32 flags; > + __u32 count; > + struct udmabuf_create_item list[]; > +}; > + > +#define UDMABUF_CREATE _IOW('u', 0x42, struct udmabuf_create) > +#define UDMABUF_CREATE_LIST _IOW('u', 0x43, struct udmabuf_create_list) > + > +#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..8e24204526 > --- /dev/null > +++ b/drivers/dma-buf/udmabuf.c > @@ -0,0 +1,287 @@ > +// SPDX-License-Identifier: GPL-2.0 > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include > + > +struct udmabuf { > + 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 | VM_MAYSHARE)) == 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]); > + kfree(ubuf->pages); > + kfree(ubuf); > +} > + > +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 void kunmap_udmabuf(struct dma_buf *buf, unsigned long page_num, > + void *vaddr) > +{ > + kunmap(vaddr); > +} > + > +static struct dma_buf_ops udmabuf_ops = { > + .map_dma_buf = map_udmabuf, > + .unmap_dma_buf = unmap_udmabuf, > + .release = release_udmabuf, > + .map = kmap_udmabuf, > + .unmap = kunmap_udmabuf, > + .mmap = mmap_udmabuf, > +}; > + > +#define SEALS_WANTED (F_SEAL_SHRINK) > +#define SEALS_DENIED (F_SEAL_WRITE) > + > +static long udmabuf_create(struct udmabuf_create_list *head, > + struct udmabuf_create_item *list) > +{ > + DEFINE_DMA_BUF_EXPORT_INFO(exp_info); > + struct file *memfd = NULL; > + struct udmabuf *ubuf; > + struct dma_buf *buf; > + pgoff_t pgoff, pgcnt, pgidx, pgbuf; > + struct page *page; > + int seals, ret = -EINVAL; > + u32 i, flags; > + > + ubuf = kzalloc(sizeof(struct udmabuf), GFP_KERNEL); > + if (!ubuf) > + return -ENOMEM; > + > + for (i = 0; i < head->count; i++) { > + if (!IS_ALIGNED(list[i].offset, PAGE_SIZE)) > + goto err_free_ubuf; > + if (!IS_ALIGNED(list[i].size, PAGE_SIZE)) > + goto err_free_ubuf; > + ubuf->pagecount += list[i].size >> PAGE_SHIFT; > + } > + ubuf->pages = kmalloc_array(ubuf->pagecount, sizeof(struct page *), > + GFP_KERNEL); > + if (!ubuf->pages) { > + ret = -ENOMEM; > + goto err_free_ubuf; > + } > + > + pgbuf = 0; > + for (i = 0; i < head->count; i++) { > + memfd = fget(list[i].memfd); > + if (!memfd) > + goto err_put_pages; > + if (!shmem_mapping(file_inode(memfd)->i_mapping)) > + goto err_put_pages; > + seals = memfd_fcntl(memfd, F_GET_SEALS, 0); > + if (seals == -EINVAL || > + (seals & SEALS_WANTED) != SEALS_WANTED || > + (seals & SEALS_DENIED) != 0) > + goto err_put_pages; > + pgoff = list[i].offset >> PAGE_SHIFT; > + pgcnt = list[i].size >> PAGE_SHIFT; > + for (pgidx = 0; pgidx < pgcnt; pgidx++) { > + page = shmem_read_mapping_page( > + file_inode(memfd)->i_mapping, pgoff + pgidx); > + if (IS_ERR(page)) { > + ret = PTR_ERR(page); > + goto err_put_pages; > + } > + ubuf->pages[pgbuf++] = page; > + } > + fput(memfd); > + } > + memfd = NULL; > + > + 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 (head->flags & UDMABUF_FLAGS_CLOEXEC) > + flags |= O_CLOEXEC; > + return dma_buf_fd(buf, flags); > + > +err_put_pages: > + while (pgbuf > 0) > + put_page(ubuf->pages[--pgbuf]); > +err_free_ubuf: > + fput(memfd); > + kfree(ubuf->pages); > + kfree(ubuf); > + return ret; > +} > + > +static long udmabuf_ioctl_create(struct file *filp, unsigned long arg) > +{ > + struct udmabuf_create create; > + struct udmabuf_create_list head; > + struct udmabuf_create_item list; > + > + if (copy_from_user(&create, (void __user *)arg, > + sizeof(struct udmabuf_create))) > + return -EFAULT; > + > + head.flags = create.flags; > + head.count = 1; > + list.memfd = create.memfd; > + list.offset = create.offset; > + list.size = create.size; > + > + return udmabuf_create(&head, &list); > +} > + > +static long udmabuf_ioctl_create_list(struct file *filp, unsigned long arg) > +{ > + struct udmabuf_create_list head; > + struct udmabuf_create_item *list; > + int ret = -EINVAL; > + u32 lsize; > + > + if (copy_from_user(&head, (void __user *)arg, sizeof(head))) > + return -EFAULT; > + if (head.count > 1024) > + return -EINVAL; > + lsize = sizeof(struct udmabuf_create_item) * head.count; > + list = memdup_user((void __user *)(arg + sizeof(head)), lsize); > + if (IS_ERR(list)) > + return PTR_ERR(list); > + > + ret = udmabuf_create(&head, list); > + kfree(list); > + 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; > + case UDMABUF_CREATE_LIST: > + ret = udmabuf_ioctl_create_list(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..376b1d6730 > --- /dev/null > +++ b/tools/testing/selftests/drivers/dma-buf/udmabuf.c > @@ -0,0 +1,96 @@ > +// SPDX-License-Identifier: GPL-2.0 > +#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/MAINTAINERS b/MAINTAINERS > index 07d1576fc7..a8e1bb3bc3 100644 > --- a/MAINTAINERS > +++ b/MAINTAINERS > @@ -14638,6 +14638,14 @@ S: Maintained > F: Documentation/filesystems/udf.txt > F: fs/udf/ > > +UDMABUF DRIVER > +M: Gerd Hoffmann > +L: dri-devel@lists.freedesktop.org > +S: Maintained > +F: drivers/dma-buf/udmabuf.c > +F: include/uapi/linux/udmabuf.h > +F: tools/testing/selftests/drivers/dma-buf/udmabuf.c > + > UDRAW TABLET > M: Bastien Nocera > L: linux-input@vger.kernel.org > diff --git a/drivers/dma-buf/Kconfig b/drivers/dma-buf/Kconfig > index ed3b785bae..338129eb12 100644 > --- a/drivers/dma-buf/Kconfig > +++ b/drivers/dma-buf/Kconfig > @@ -30,4 +30,12 @@ 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 > + help > + A driver to let userspace turn memfd regions into dma-bufs. > + Qemu can use this to create host dmabufs for guest framebuffers. > + > 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 > -- > 2.9.3 > -- Daniel Vetter Software Engineer, Intel Corporation http://blog.ffwll.ch From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.1 (2015-04-28) on archive.lwn.net X-Spam-Level: X-Spam-Status: No, score=-5.6 required=5.0 tests=DKIM_SIGNED, HEADER_FROM_DIFFERENT_DOMAINS,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI, T_DKIM_INVALID autolearn=unavailable autolearn_force=no version=3.4.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by archive.lwn.net (Postfix) with ESMTP id A05597DE6E for ; Tue, 3 Jul 2018 08:38:23 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754500AbeGCIiH (ORCPT ); Tue, 3 Jul 2018 04:38:07 -0400 Received: from mail-ed1-f67.google.com ([209.85.208.67]:36978 "EHLO mail-ed1-f67.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754359AbeGCIiC (ORCPT ); Tue, 3 Jul 2018 04:38:02 -0400 Received: by mail-ed1-f67.google.com with SMTP id v22-v6so1011126edq.4 for ; Tue, 03 Jul 2018 01:38:01 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ffwll.ch; s=google; h=sender:date:from:to:cc:subject:message-id:mail-followup-to :references:mime-version:content-disposition:in-reply-to:user-agent; bh=J3xyWGG6ZXebSzSEbg3ED9ghEns3bxafjdwoLEd2TME=; b=jMAwdvzbKZFOG8PxFV8Taw+tNqNPoSLw+MEWs82ST2/mRbSMNkLEPLcVeaYcvsenPw Smj2ma0zqmRHxISjdd9jkJJrsuq8fPbQyTS7nCr68ZQlvRkSu1DE3W2nBWfvo7K8ocLq mEd1D2ywapDOqGUXM9o2RSOEvDe+5GC7zSOiM= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:date:from:to:cc:subject:message-id :mail-followup-to:references:mime-version:content-disposition :in-reply-to:user-agent; bh=J3xyWGG6ZXebSzSEbg3ED9ghEns3bxafjdwoLEd2TME=; b=fhvpYkhGpwMXq7bVVpVR3zC3IRA2f9XAK02TlHR35xRX7askDoXSMzDP5SWkNunNvg ifbekMDcIlkT7FgU/bVZio0HLIWueoWWKyBGQS0dWvzfBabotJjup9i3K/Im3PXq3/I2 ImK5oxvx80Cx2/KAd0jilxbKUg8ne4LMAvmDIFLYYsYfAvAnsjyVMMCDHTin0KVpZjCU InXVq7hVWNL2Zwi+rt08YV5o4F72CR/Wrb8YsCPEwiU6oieZDxnwv+fGecBq72Y6ypV4 Lf6/Oqw9kaJ1anjSBOLMChmQeywSLdUJTWglx6rDE6XO5JonWcQCPQ/g2fZC5VgKhEzl 9IBg== X-Gm-Message-State: APt69E0y+DcDTvq5jZi5SRL9C/ek/eKO1KGkBaBiIwiq8RuN3ABd917l aZTtdMfeFyNIXXsC2JxuMjq8EA== X-Google-Smtp-Source: AAOMgpc7vNMFt1OYV4WmPcGD8e4Ahoqth7co13KFUAVzqFSZUGwVAStH+NXtNjThGVogu3RD3fKseQ== X-Received: by 2002:a50:88c2:: with SMTP id d60-v6mr26718310edd.281.1530607080825; Tue, 03 Jul 2018 01:38:00 -0700 (PDT) Received: from phenom.ffwll.local ([2a02:168:5628:0:496f:7dc5:66d7:a057]) by smtp.gmail.com with ESMTPSA id d11-v6sm391380edr.24.2018.07.03.01.37.59 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Tue, 03 Jul 2018 01:37:59 -0700 (PDT) Date: Tue, 3 Jul 2018 10:37:57 +0200 From: Daniel Vetter To: Gerd Hoffmann Cc: dri-devel@lists.freedesktop.org, David Airlie , Tomeu Vizoso , Laurent Pinchart , Daniel Vetter , Jonathan Corbet , Sumit Semwal , Shuah Khan , "open list:DOCUMENTATION" , open list , "open list:DMA BUFFER SHARING FRAMEWORK" , "moderated list:DMA BUFFER SHARING FRAMEWORK" , "open list:KERNEL SELFTEST FRAMEWORK" Subject: Re: [PATCH v6] Add udmabuf misc device Message-ID: <20180703083757.GG7880@phenom.ffwll.local> Mail-Followup-To: Gerd Hoffmann , dri-devel@lists.freedesktop.org, David Airlie , Tomeu Vizoso , Laurent Pinchart , Jonathan Corbet , Sumit Semwal , Shuah Khan , "open list:DOCUMENTATION" , open list , "open list:DMA BUFFER SHARING FRAMEWORK" , "moderated list:DMA BUFFER SHARING FRAMEWORK" , "open list:KERNEL SELFTEST FRAMEWORK" References: <20180703075359.30349-1-kraxel@redhat.com> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <20180703075359.30349-1-kraxel@redhat.com> X-Operating-System: Linux phenom 4.16.0-2-amd64 User-Agent: Mutt/1.10.0 (2018-05-17) Sender: linux-doc-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-doc@vger.kernel.org On Tue, Jul 03, 2018 at 09:53:58AM +0200, 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. > > qemu test branch: > https://git.kraxel.org/cgit/qemu/log/?h=sirius/udmabuf > > Cc: David Airlie > Cc: Tomeu Vizoso > Cc: Laurent Pinchart > Cc: Daniel Vetter > Signed-off-by: Gerd Hoffmann I think some ack for a 2nd use-case, like virtio-wl or whatever would be really cool. To give us some assurance that this is generically useful. Plus an ack from dma-buf folks (nag them on irc, you don't have them on Cc here). Then this is imo good to go. I assume you'll push it to drm-misc, like all the other dma-buf stuff? -Daniel > --- > Documentation/ioctl/ioctl-number.txt | 1 + > include/uapi/linux/udmabuf.h | 33 +++ > drivers/dma-buf/udmabuf.c | 287 ++++++++++++++++++++++ > tools/testing/selftests/drivers/dma-buf/udmabuf.c | 96 ++++++++ > MAINTAINERS | 8 + > drivers/dma-buf/Kconfig | 8 + > drivers/dma-buf/Makefile | 1 + > tools/testing/selftests/drivers/dma-buf/Makefile | 5 + > 8 files changed, 439 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/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt > index 480c8609dc..6636dea476 100644 > --- a/Documentation/ioctl/ioctl-number.txt > +++ b/Documentation/ioctl/ioctl-number.txt > @@ -271,6 +271,7 @@ Code Seq#(hex) Include File Comments > 't' 90-91 linux/toshiba.h toshiba and toshiba_acpi SMM > 'u' 00-1F linux/smb_fs.h gone > 'u' 20-3F linux/uvcvideo.h USB video class host driver > +'u' 40-4f linux/udmabuf.h userspace dma-buf misc device > 'v' 00-1F linux/ext2_fs.h conflict! > 'v' 00-1F linux/fs.h conflict! > 'v' 00-0F linux/sonypi.h conflict! > diff --git a/include/uapi/linux/udmabuf.h b/include/uapi/linux/udmabuf.h > new file mode 100644 > index 0000000000..46b6532ed8 > --- /dev/null > +++ b/include/uapi/linux/udmabuf.h > @@ -0,0 +1,33 @@ > +/* 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; > +}; > + > +struct udmabuf_create_item { > + __u32 memfd; > + __u32 __pad; > + __u64 offset; > + __u64 size; > +}; > + > +struct udmabuf_create_list { > + __u32 flags; > + __u32 count; > + struct udmabuf_create_item list[]; > +}; > + > +#define UDMABUF_CREATE _IOW('u', 0x42, struct udmabuf_create) > +#define UDMABUF_CREATE_LIST _IOW('u', 0x43, struct udmabuf_create_list) > + > +#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..8e24204526 > --- /dev/null > +++ b/drivers/dma-buf/udmabuf.c > @@ -0,0 +1,287 @@ > +// SPDX-License-Identifier: GPL-2.0 > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include > + > +struct udmabuf { > + 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 | VM_MAYSHARE)) == 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]); > + kfree(ubuf->pages); > + kfree(ubuf); > +} > + > +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 void kunmap_udmabuf(struct dma_buf *buf, unsigned long page_num, > + void *vaddr) > +{ > + kunmap(vaddr); > +} > + > +static struct dma_buf_ops udmabuf_ops = { > + .map_dma_buf = map_udmabuf, > + .unmap_dma_buf = unmap_udmabuf, > + .release = release_udmabuf, > + .map = kmap_udmabuf, > + .unmap = kunmap_udmabuf, > + .mmap = mmap_udmabuf, > +}; > + > +#define SEALS_WANTED (F_SEAL_SHRINK) > +#define SEALS_DENIED (F_SEAL_WRITE) > + > +static long udmabuf_create(struct udmabuf_create_list *head, > + struct udmabuf_create_item *list) > +{ > + DEFINE_DMA_BUF_EXPORT_INFO(exp_info); > + struct file *memfd = NULL; > + struct udmabuf *ubuf; > + struct dma_buf *buf; > + pgoff_t pgoff, pgcnt, pgidx, pgbuf; > + struct page *page; > + int seals, ret = -EINVAL; > + u32 i, flags; > + > + ubuf = kzalloc(sizeof(struct udmabuf), GFP_KERNEL); > + if (!ubuf) > + return -ENOMEM; > + > + for (i = 0; i < head->count; i++) { > + if (!IS_ALIGNED(list[i].offset, PAGE_SIZE)) > + goto err_free_ubuf; > + if (!IS_ALIGNED(list[i].size, PAGE_SIZE)) > + goto err_free_ubuf; > + ubuf->pagecount += list[i].size >> PAGE_SHIFT; > + } > + ubuf->pages = kmalloc_array(ubuf->pagecount, sizeof(struct page *), > + GFP_KERNEL); > + if (!ubuf->pages) { > + ret = -ENOMEM; > + goto err_free_ubuf; > + } > + > + pgbuf = 0; > + for (i = 0; i < head->count; i++) { > + memfd = fget(list[i].memfd); > + if (!memfd) > + goto err_put_pages; > + if (!shmem_mapping(file_inode(memfd)->i_mapping)) > + goto err_put_pages; > + seals = memfd_fcntl(memfd, F_GET_SEALS, 0); > + if (seals == -EINVAL || > + (seals & SEALS_WANTED) != SEALS_WANTED || > + (seals & SEALS_DENIED) != 0) > + goto err_put_pages; > + pgoff = list[i].offset >> PAGE_SHIFT; > + pgcnt = list[i].size >> PAGE_SHIFT; > + for (pgidx = 0; pgidx < pgcnt; pgidx++) { > + page = shmem_read_mapping_page( > + file_inode(memfd)->i_mapping, pgoff + pgidx); > + if (IS_ERR(page)) { > + ret = PTR_ERR(page); > + goto err_put_pages; > + } > + ubuf->pages[pgbuf++] = page; > + } > + fput(memfd); > + } > + memfd = NULL; > + > + 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 (head->flags & UDMABUF_FLAGS_CLOEXEC) > + flags |= O_CLOEXEC; > + return dma_buf_fd(buf, flags); > + > +err_put_pages: > + while (pgbuf > 0) > + put_page(ubuf->pages[--pgbuf]); > +err_free_ubuf: > + fput(memfd); > + kfree(ubuf->pages); > + kfree(ubuf); > + return ret; > +} > + > +static long udmabuf_ioctl_create(struct file *filp, unsigned long arg) > +{ > + struct udmabuf_create create; > + struct udmabuf_create_list head; > + struct udmabuf_create_item list; > + > + if (copy_from_user(&create, (void __user *)arg, > + sizeof(struct udmabuf_create))) > + return -EFAULT; > + > + head.flags = create.flags; > + head.count = 1; > + list.memfd = create.memfd; > + list.offset = create.offset; > + list.size = create.size; > + > + return udmabuf_create(&head, &list); > +} > + > +static long udmabuf_ioctl_create_list(struct file *filp, unsigned long arg) > +{ > + struct udmabuf_create_list head; > + struct udmabuf_create_item *list; > + int ret = -EINVAL; > + u32 lsize; > + > + if (copy_from_user(&head, (void __user *)arg, sizeof(head))) > + return -EFAULT; > + if (head.count > 1024) > + return -EINVAL; > + lsize = sizeof(struct udmabuf_create_item) * head.count; > + list = memdup_user((void __user *)(arg + sizeof(head)), lsize); > + if (IS_ERR(list)) > + return PTR_ERR(list); > + > + ret = udmabuf_create(&head, list); > + kfree(list); > + 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; > + case UDMABUF_CREATE_LIST: > + ret = udmabuf_ioctl_create_list(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..376b1d6730 > --- /dev/null > +++ b/tools/testing/selftests/drivers/dma-buf/udmabuf.c > @@ -0,0 +1,96 @@ > +// SPDX-License-Identifier: GPL-2.0 > +#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/MAINTAINERS b/MAINTAINERS > index 07d1576fc7..a8e1bb3bc3 100644 > --- a/MAINTAINERS > +++ b/MAINTAINERS > @@ -14638,6 +14638,14 @@ S: Maintained > F: Documentation/filesystems/udf.txt > F: fs/udf/ > > +UDMABUF DRIVER > +M: Gerd Hoffmann > +L: dri-devel@lists.freedesktop.org > +S: Maintained > +F: drivers/dma-buf/udmabuf.c > +F: include/uapi/linux/udmabuf.h > +F: tools/testing/selftests/drivers/dma-buf/udmabuf.c > + > UDRAW TABLET > M: Bastien Nocera > L: linux-input@vger.kernel.org > diff --git a/drivers/dma-buf/Kconfig b/drivers/dma-buf/Kconfig > index ed3b785bae..338129eb12 100644 > --- a/drivers/dma-buf/Kconfig > +++ b/drivers/dma-buf/Kconfig > @@ -30,4 +30,12 @@ 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 > + help > + A driver to let userspace turn memfd regions into dma-bufs. > + Qemu can use this to create host dmabufs for guest framebuffers. > + > 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 > -- > 2.9.3 > -- Daniel Vetter Software Engineer, Intel Corporation http://blog.ffwll.ch -- To unsubscribe from this list: send the line "unsubscribe linux-doc" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html From mboxrd@z Thu Jan 1 00:00:00 1970 From: daniel at ffwll.ch (Daniel Vetter) Date: Tue, 3 Jul 2018 10:37:57 +0200 Subject: [PATCH v6] Add udmabuf misc device In-Reply-To: <20180703075359.30349-1-kraxel@redhat.com> References: <20180703075359.30349-1-kraxel@redhat.com> Message-ID: <20180703083757.GG7880@phenom.ffwll.local> On Tue, Jul 03, 2018 at 09:53:58AM +0200, 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. > > qemu test branch: > https://git.kraxel.org/cgit/qemu/log/?h=sirius/udmabuf > > Cc: David Airlie > Cc: Tomeu Vizoso > Cc: Laurent Pinchart > Cc: Daniel Vetter > Signed-off-by: Gerd Hoffmann I think some ack for a 2nd use-case, like virtio-wl or whatever would be really cool. To give us some assurance that this is generically useful. Plus an ack from dma-buf folks (nag them on irc, you don't have them on Cc here). Then this is imo good to go. I assume you'll push it to drm-misc, like all the other dma-buf stuff? -Daniel > --- > Documentation/ioctl/ioctl-number.txt | 1 + > include/uapi/linux/udmabuf.h | 33 +++ > drivers/dma-buf/udmabuf.c | 287 ++++++++++++++++++++++ > tools/testing/selftests/drivers/dma-buf/udmabuf.c | 96 ++++++++ > MAINTAINERS | 8 + > drivers/dma-buf/Kconfig | 8 + > drivers/dma-buf/Makefile | 1 + > tools/testing/selftests/drivers/dma-buf/Makefile | 5 + > 8 files changed, 439 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/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt > index 480c8609dc..6636dea476 100644 > --- a/Documentation/ioctl/ioctl-number.txt > +++ b/Documentation/ioctl/ioctl-number.txt > @@ -271,6 +271,7 @@ Code Seq#(hex) Include File Comments > 't' 90-91 linux/toshiba.h toshiba and toshiba_acpi SMM > 'u' 00-1F linux/smb_fs.h gone > 'u' 20-3F linux/uvcvideo.h USB video class host driver > +'u' 40-4f linux/udmabuf.h userspace dma-buf misc device > 'v' 00-1F linux/ext2_fs.h conflict! > 'v' 00-1F linux/fs.h conflict! > 'v' 00-0F linux/sonypi.h conflict! > diff --git a/include/uapi/linux/udmabuf.h b/include/uapi/linux/udmabuf.h > new file mode 100644 > index 0000000000..46b6532ed8 > --- /dev/null > +++ b/include/uapi/linux/udmabuf.h > @@ -0,0 +1,33 @@ > +/* 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; > +}; > + > +struct udmabuf_create_item { > + __u32 memfd; > + __u32 __pad; > + __u64 offset; > + __u64 size; > +}; > + > +struct udmabuf_create_list { > + __u32 flags; > + __u32 count; > + struct udmabuf_create_item list[]; > +}; > + > +#define UDMABUF_CREATE _IOW('u', 0x42, struct udmabuf_create) > +#define UDMABUF_CREATE_LIST _IOW('u', 0x43, struct udmabuf_create_list) > + > +#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..8e24204526 > --- /dev/null > +++ b/drivers/dma-buf/udmabuf.c > @@ -0,0 +1,287 @@ > +// SPDX-License-Identifier: GPL-2.0 > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include > + > +struct udmabuf { > + 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 | VM_MAYSHARE)) == 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]); > + kfree(ubuf->pages); > + kfree(ubuf); > +} > + > +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 void kunmap_udmabuf(struct dma_buf *buf, unsigned long page_num, > + void *vaddr) > +{ > + kunmap(vaddr); > +} > + > +static struct dma_buf_ops udmabuf_ops = { > + .map_dma_buf = map_udmabuf, > + .unmap_dma_buf = unmap_udmabuf, > + .release = release_udmabuf, > + .map = kmap_udmabuf, > + .unmap = kunmap_udmabuf, > + .mmap = mmap_udmabuf, > +}; > + > +#define SEALS_WANTED (F_SEAL_SHRINK) > +#define SEALS_DENIED (F_SEAL_WRITE) > + > +static long udmabuf_create(struct udmabuf_create_list *head, > + struct udmabuf_create_item *list) > +{ > + DEFINE_DMA_BUF_EXPORT_INFO(exp_info); > + struct file *memfd = NULL; > + struct udmabuf *ubuf; > + struct dma_buf *buf; > + pgoff_t pgoff, pgcnt, pgidx, pgbuf; > + struct page *page; > + int seals, ret = -EINVAL; > + u32 i, flags; > + > + ubuf = kzalloc(sizeof(struct udmabuf), GFP_KERNEL); > + if (!ubuf) > + return -ENOMEM; > + > + for (i = 0; i < head->count; i++) { > + if (!IS_ALIGNED(list[i].offset, PAGE_SIZE)) > + goto err_free_ubuf; > + if (!IS_ALIGNED(list[i].size, PAGE_SIZE)) > + goto err_free_ubuf; > + ubuf->pagecount += list[i].size >> PAGE_SHIFT; > + } > + ubuf->pages = kmalloc_array(ubuf->pagecount, sizeof(struct page *), > + GFP_KERNEL); > + if (!ubuf->pages) { > + ret = -ENOMEM; > + goto err_free_ubuf; > + } > + > + pgbuf = 0; > + for (i = 0; i < head->count; i++) { > + memfd = fget(list[i].memfd); > + if (!memfd) > + goto err_put_pages; > + if (!shmem_mapping(file_inode(memfd)->i_mapping)) > + goto err_put_pages; > + seals = memfd_fcntl(memfd, F_GET_SEALS, 0); > + if (seals == -EINVAL || > + (seals & SEALS_WANTED) != SEALS_WANTED || > + (seals & SEALS_DENIED) != 0) > + goto err_put_pages; > + pgoff = list[i].offset >> PAGE_SHIFT; > + pgcnt = list[i].size >> PAGE_SHIFT; > + for (pgidx = 0; pgidx < pgcnt; pgidx++) { > + page = shmem_read_mapping_page( > + file_inode(memfd)->i_mapping, pgoff + pgidx); > + if (IS_ERR(page)) { > + ret = PTR_ERR(page); > + goto err_put_pages; > + } > + ubuf->pages[pgbuf++] = page; > + } > + fput(memfd); > + } > + memfd = NULL; > + > + 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 (head->flags & UDMABUF_FLAGS_CLOEXEC) > + flags |= O_CLOEXEC; > + return dma_buf_fd(buf, flags); > + > +err_put_pages: > + while (pgbuf > 0) > + put_page(ubuf->pages[--pgbuf]); > +err_free_ubuf: > + fput(memfd); > + kfree(ubuf->pages); > + kfree(ubuf); > + return ret; > +} > + > +static long udmabuf_ioctl_create(struct file *filp, unsigned long arg) > +{ > + struct udmabuf_create create; > + struct udmabuf_create_list head; > + struct udmabuf_create_item list; > + > + if (copy_from_user(&create, (void __user *)arg, > + sizeof(struct udmabuf_create))) > + return -EFAULT; > + > + head.flags = create.flags; > + head.count = 1; > + list.memfd = create.memfd; > + list.offset = create.offset; > + list.size = create.size; > + > + return udmabuf_create(&head, &list); > +} > + > +static long udmabuf_ioctl_create_list(struct file *filp, unsigned long arg) > +{ > + struct udmabuf_create_list head; > + struct udmabuf_create_item *list; > + int ret = -EINVAL; > + u32 lsize; > + > + if (copy_from_user(&head, (void __user *)arg, sizeof(head))) > + return -EFAULT; > + if (head.count > 1024) > + return -EINVAL; > + lsize = sizeof(struct udmabuf_create_item) * head.count; > + list = memdup_user((void __user *)(arg + sizeof(head)), lsize); > + if (IS_ERR(list)) > + return PTR_ERR(list); > + > + ret = udmabuf_create(&head, list); > + kfree(list); > + 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; > + case UDMABUF_CREATE_LIST: > + ret = udmabuf_ioctl_create_list(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..376b1d6730 > --- /dev/null > +++ b/tools/testing/selftests/drivers/dma-buf/udmabuf.c > @@ -0,0 +1,96 @@ > +// SPDX-License-Identifier: GPL-2.0 > +#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/MAINTAINERS b/MAINTAINERS > index 07d1576fc7..a8e1bb3bc3 100644 > --- a/MAINTAINERS > +++ b/MAINTAINERS > @@ -14638,6 +14638,14 @@ S: Maintained > F: Documentation/filesystems/udf.txt > F: fs/udf/ > > +UDMABUF DRIVER > +M: Gerd Hoffmann > +L: dri-devel at lists.freedesktop.org > +S: Maintained > +F: drivers/dma-buf/udmabuf.c > +F: include/uapi/linux/udmabuf.h > +F: tools/testing/selftests/drivers/dma-buf/udmabuf.c > + > UDRAW TABLET > M: Bastien Nocera > L: linux-input at vger.kernel.org > diff --git a/drivers/dma-buf/Kconfig b/drivers/dma-buf/Kconfig > index ed3b785bae..338129eb12 100644 > --- a/drivers/dma-buf/Kconfig > +++ b/drivers/dma-buf/Kconfig > @@ -30,4 +30,12 @@ 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 > + help > + A driver to let userspace turn memfd regions into dma-bufs. > + Qemu can use this to create host dmabufs for guest framebuffers. > + > 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 > -- > 2.9.3 > -- Daniel Vetter Software Engineer, Intel Corporation http://blog.ffwll.ch -- To unsubscribe from this list: send the line "unsubscribe linux-kselftest" in the body of a message to majordomo at vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html From mboxrd@z Thu Jan 1 00:00:00 1970 From: daniel@ffwll.ch (Daniel Vetter) Date: Tue, 3 Jul 2018 10:37:57 +0200 Subject: [PATCH v6] Add udmabuf misc device In-Reply-To: <20180703075359.30349-1-kraxel@redhat.com> References: <20180703075359.30349-1-kraxel@redhat.com> Message-ID: <20180703083757.GG7880@phenom.ffwll.local> Content-Type: text/plain; charset="UTF-8" Message-ID: <20180703083757.kbOAwwSBEu1xs7E-oNXjgj6vq4J_PF6xAJ3QUD5gCs4@z> On Tue, Jul 03, 2018@09:53:58AM +0200, 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. > > qemu test branch: > https://git.kraxel.org/cgit/qemu/log/?h=sirius/udmabuf > > Cc: David Airlie > Cc: Tomeu Vizoso > Cc: Laurent Pinchart > Cc: Daniel Vetter > Signed-off-by: Gerd Hoffmann I think some ack for a 2nd use-case, like virtio-wl or whatever would be really cool. To give us some assurance that this is generically useful. Plus an ack from dma-buf folks (nag them on irc, you don't have them on Cc here). Then this is imo good to go. I assume you'll push it to drm-misc, like all the other dma-buf stuff? -Daniel > --- > Documentation/ioctl/ioctl-number.txt | 1 + > include/uapi/linux/udmabuf.h | 33 +++ > drivers/dma-buf/udmabuf.c | 287 ++++++++++++++++++++++ > tools/testing/selftests/drivers/dma-buf/udmabuf.c | 96 ++++++++ > MAINTAINERS | 8 + > drivers/dma-buf/Kconfig | 8 + > drivers/dma-buf/Makefile | 1 + > tools/testing/selftests/drivers/dma-buf/Makefile | 5 + > 8 files changed, 439 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/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt > index 480c8609dc..6636dea476 100644 > --- a/Documentation/ioctl/ioctl-number.txt > +++ b/Documentation/ioctl/ioctl-number.txt > @@ -271,6 +271,7 @@ Code Seq#(hex) Include File Comments > 't' 90-91 linux/toshiba.h toshiba and toshiba_acpi SMM > 'u' 00-1F linux/smb_fs.h gone > 'u' 20-3F linux/uvcvideo.h USB video class host driver > +'u' 40-4f linux/udmabuf.h userspace dma-buf misc device > 'v' 00-1F linux/ext2_fs.h conflict! > 'v' 00-1F linux/fs.h conflict! > 'v' 00-0F linux/sonypi.h conflict! > diff --git a/include/uapi/linux/udmabuf.h b/include/uapi/linux/udmabuf.h > new file mode 100644 > index 0000000000..46b6532ed8 > --- /dev/null > +++ b/include/uapi/linux/udmabuf.h > @@ -0,0 +1,33 @@ > +/* 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; > +}; > + > +struct udmabuf_create_item { > + __u32 memfd; > + __u32 __pad; > + __u64 offset; > + __u64 size; > +}; > + > +struct udmabuf_create_list { > + __u32 flags; > + __u32 count; > + struct udmabuf_create_item list[]; > +}; > + > +#define UDMABUF_CREATE _IOW('u', 0x42, struct udmabuf_create) > +#define UDMABUF_CREATE_LIST _IOW('u', 0x43, struct udmabuf_create_list) > + > +#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..8e24204526 > --- /dev/null > +++ b/drivers/dma-buf/udmabuf.c > @@ -0,0 +1,287 @@ > +// SPDX-License-Identifier: GPL-2.0 > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include > + > +struct udmabuf { > + 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 | VM_MAYSHARE)) == 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]); > + kfree(ubuf->pages); > + kfree(ubuf); > +} > + > +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 void kunmap_udmabuf(struct dma_buf *buf, unsigned long page_num, > + void *vaddr) > +{ > + kunmap(vaddr); > +} > + > +static struct dma_buf_ops udmabuf_ops = { > + .map_dma_buf = map_udmabuf, > + .unmap_dma_buf = unmap_udmabuf, > + .release = release_udmabuf, > + .map = kmap_udmabuf, > + .unmap = kunmap_udmabuf, > + .mmap = mmap_udmabuf, > +}; > + > +#define SEALS_WANTED (F_SEAL_SHRINK) > +#define SEALS_DENIED (F_SEAL_WRITE) > + > +static long udmabuf_create(struct udmabuf_create_list *head, > + struct udmabuf_create_item *list) > +{ > + DEFINE_DMA_BUF_EXPORT_INFO(exp_info); > + struct file *memfd = NULL; > + struct udmabuf *ubuf; > + struct dma_buf *buf; > + pgoff_t pgoff, pgcnt, pgidx, pgbuf; > + struct page *page; > + int seals, ret = -EINVAL; > + u32 i, flags; > + > + ubuf = kzalloc(sizeof(struct udmabuf), GFP_KERNEL); > + if (!ubuf) > + return -ENOMEM; > + > + for (i = 0; i < head->count; i++) { > + if (!IS_ALIGNED(list[i].offset, PAGE_SIZE)) > + goto err_free_ubuf; > + if (!IS_ALIGNED(list[i].size, PAGE_SIZE)) > + goto err_free_ubuf; > + ubuf->pagecount += list[i].size >> PAGE_SHIFT; > + } > + ubuf->pages = kmalloc_array(ubuf->pagecount, sizeof(struct page *), > + GFP_KERNEL); > + if (!ubuf->pages) { > + ret = -ENOMEM; > + goto err_free_ubuf; > + } > + > + pgbuf = 0; > + for (i = 0; i < head->count; i++) { > + memfd = fget(list[i].memfd); > + if (!memfd) > + goto err_put_pages; > + if (!shmem_mapping(file_inode(memfd)->i_mapping)) > + goto err_put_pages; > + seals = memfd_fcntl(memfd, F_GET_SEALS, 0); > + if (seals == -EINVAL || > + (seals & SEALS_WANTED) != SEALS_WANTED || > + (seals & SEALS_DENIED) != 0) > + goto err_put_pages; > + pgoff = list[i].offset >> PAGE_SHIFT; > + pgcnt = list[i].size >> PAGE_SHIFT; > + for (pgidx = 0; pgidx < pgcnt; pgidx++) { > + page = shmem_read_mapping_page( > + file_inode(memfd)->i_mapping, pgoff + pgidx); > + if (IS_ERR(page)) { > + ret = PTR_ERR(page); > + goto err_put_pages; > + } > + ubuf->pages[pgbuf++] = page; > + } > + fput(memfd); > + } > + memfd = NULL; > + > + 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 (head->flags & UDMABUF_FLAGS_CLOEXEC) > + flags |= O_CLOEXEC; > + return dma_buf_fd(buf, flags); > + > +err_put_pages: > + while (pgbuf > 0) > + put_page(ubuf->pages[--pgbuf]); > +err_free_ubuf: > + fput(memfd); > + kfree(ubuf->pages); > + kfree(ubuf); > + return ret; > +} > + > +static long udmabuf_ioctl_create(struct file *filp, unsigned long arg) > +{ > + struct udmabuf_create create; > + struct udmabuf_create_list head; > + struct udmabuf_create_item list; > + > + if (copy_from_user(&create, (void __user *)arg, > + sizeof(struct udmabuf_create))) > + return -EFAULT; > + > + head.flags = create.flags; > + head.count = 1; > + list.memfd = create.memfd; > + list.offset = create.offset; > + list.size = create.size; > + > + return udmabuf_create(&head, &list); > +} > + > +static long udmabuf_ioctl_create_list(struct file *filp, unsigned long arg) > +{ > + struct udmabuf_create_list head; > + struct udmabuf_create_item *list; > + int ret = -EINVAL; > + u32 lsize; > + > + if (copy_from_user(&head, (void __user *)arg, sizeof(head))) > + return -EFAULT; > + if (head.count > 1024) > + return -EINVAL; > + lsize = sizeof(struct udmabuf_create_item) * head.count; > + list = memdup_user((void __user *)(arg + sizeof(head)), lsize); > + if (IS_ERR(list)) > + return PTR_ERR(list); > + > + ret = udmabuf_create(&head, list); > + kfree(list); > + 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; > + case UDMABUF_CREATE_LIST: > + ret = udmabuf_ioctl_create_list(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..376b1d6730 > --- /dev/null > +++ b/tools/testing/selftests/drivers/dma-buf/udmabuf.c > @@ -0,0 +1,96 @@ > +// SPDX-License-Identifier: GPL-2.0 > +#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/MAINTAINERS b/MAINTAINERS > index 07d1576fc7..a8e1bb3bc3 100644 > --- a/MAINTAINERS > +++ b/MAINTAINERS > @@ -14638,6 +14638,14 @@ S: Maintained > F: Documentation/filesystems/udf.txt > F: fs/udf/ > > +UDMABUF DRIVER > +M: Gerd Hoffmann > +L: dri-devel at lists.freedesktop.org > +S: Maintained > +F: drivers/dma-buf/udmabuf.c > +F: include/uapi/linux/udmabuf.h > +F: tools/testing/selftests/drivers/dma-buf/udmabuf.c > + > UDRAW TABLET > M: Bastien Nocera > L: linux-input at vger.kernel.org > diff --git a/drivers/dma-buf/Kconfig b/drivers/dma-buf/Kconfig > index ed3b785bae..338129eb12 100644 > --- a/drivers/dma-buf/Kconfig > +++ b/drivers/dma-buf/Kconfig > @@ -30,4 +30,12 @@ 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 > + help > + A driver to let userspace turn memfd regions into dma-bufs. > + Qemu can use this to create host dmabufs for guest framebuffers. > + > 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 > -- > 2.9.3 > -- Daniel Vetter Software Engineer, Intel Corporation http://blog.ffwll.ch -- To unsubscribe from this list: send the line "unsubscribe linux-kselftest" in the body of a message to majordomo at vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html From mboxrd@z Thu Jan 1 00:00:00 1970 From: Daniel Vetter Subject: Re: [PATCH v6] Add udmabuf misc device Date: Tue, 3 Jul 2018 10:37:57 +0200 Message-ID: <20180703083757.GG7880@phenom.ffwll.local> References: <20180703075359.30349-1-kraxel@redhat.com> Mime-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: base64 Return-path: Received: from mail-ed1-x544.google.com (mail-ed1-x544.google.com [IPv6:2a00:1450:4864:20::544]) by gabe.freedesktop.org (Postfix) with ESMTPS id 3DED86E348 for ; Tue, 3 Jul 2018 08:38:02 +0000 (UTC) Received: by mail-ed1-x544.google.com with SMTP id b12-v6so1002612edt.8 for ; Tue, 03 Jul 2018 01:38:02 -0700 (PDT) Content-Disposition: inline In-Reply-To: <20180703075359.30349-1-kraxel@redhat.com> List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" To: Gerd Hoffmann Cc: "open list:KERNEL SELFTEST FRAMEWORK" , Tomeu Vizoso , Jonathan Corbet , David Airlie , "open list:DOCUMENTATION" , open list , dri-devel@lists.freedesktop.org, "moderated list:DMA BUFFER SHARING FRAMEWORK" , Laurent Pinchart , Shuah Khan , "open list:DMA BUFFER SHARING FRAMEWORK" List-Id: dri-devel@lists.freedesktop.org T24gVHVlLCBKdWwgMDMsIDIwMTggYXQgMDk6NTM6NThBTSArMDIwMCwgR2VyZCBIb2ZmbWFubiB3 cm90ZToKPiBBIGRyaXZlciB0byBsZXQgdXNlcnNwYWNlIHR1cm4gbWVtZmQgcmVnaW9ucyBpbnRv IGRtYS1idWZzLgo+IAo+IFVzZSBjYXNlOiAgQWxsb3dzIHFlbXUgY3JlYXRlIGRtYWJ1ZnMgZm9y IHRoZSB2Z2EgZnJhbWVidWZmZXIgb3IKPiB2aXJ0aW8tZ3B1IHJlc3NvdXJjZXMuICBUaGVuIHRo ZXkgY2FuIGJlIHBhc3NlZCBhcm91bmQgdG8gZGlzcGxheQo+IHRob3NlIGd1ZXN0IHRoaW5ncyBv biB0aGUgaG9zdC4gIFRvIHNwaWNlIGNsaWVudCBmb3IgY2xhc3NpYyBmdWxsCj4gZnJhbWVidWZm ZXIgZGlzcGxheSwgYW5kIGhvcGVmdWxseSBzb21lIGRheSB0byB3YXlsYW5kIHNlcnZlciBmb3IK PiBzZWFtbGVzcyBndWVzdCB3aW5kb3cgZGlzcGxheS4KPiAKPiBxZW11IHRlc3QgYnJhbmNoOgo+ ICAgaHR0cHM6Ly9naXQua3JheGVsLm9yZy9jZ2l0L3FlbXUvbG9nLz9oPXNpcml1cy91ZG1hYnVm Cj4gCj4gQ2M6IERhdmlkIEFpcmxpZSA8YWlybGllZEBsaW51eC5pZT4KPiBDYzogVG9tZXUgVml6 b3NvIDx0b21ldS52aXpvc29AY29sbGFib3JhLmNvbT4KPiBDYzogTGF1cmVudCBQaW5jaGFydCA8 bGF1cmVudC5waW5jaGFydEBpZGVhc29uYm9hcmQuY29tPgo+IENjOiBEYW5pZWwgVmV0dGVyIDxk YW5pZWxAZmZ3bGwuY2g+Cj4gU2lnbmVkLW9mZi1ieTogR2VyZCBIb2ZmbWFubiA8a3JheGVsQHJl ZGhhdC5jb20+CgpJIHRoaW5rIHNvbWUgYWNrIGZvciBhIDJuZCB1c2UtY2FzZSwgbGlrZSB2aXJ0 aW8td2wgb3Igd2hhdGV2ZXIgd291bGQgYmUKcmVhbGx5IGNvb2wuIFRvIGdpdmUgdXMgc29tZSBh c3N1cmFuY2UgdGhhdCB0aGlzIGlzIGdlbmVyaWNhbGx5IHVzZWZ1bC4KUGx1cyBhbiBhY2sgZnJv bSBkbWEtYnVmIGZvbGtzIChuYWcgdGhlbSBvbiBpcmMsIHlvdSBkb24ndCBoYXZlIHRoZW0gb24g Q2MKaGVyZSkuIFRoZW4gdGhpcyBpcyBpbW8gZ29vZCB0byBnby4KCkkgYXNzdW1lIHlvdSdsbCBw dXNoIGl0IHRvIGRybS1taXNjLCBsaWtlIGFsbCB0aGUgb3RoZXIgZG1hLWJ1ZiBzdHVmZj8KLURh bmllbAoKPiAtLS0KPiAgRG9jdW1lbnRhdGlvbi9pb2N0bC9pb2N0bC1udW1iZXIudHh0ICAgICAg ICAgICAgICB8ICAgMSArCj4gIGluY2x1ZGUvdWFwaS9saW51eC91ZG1hYnVmLmggICAgICAgICAg ICAgICAgICAgICAgfCAgMzMgKysrCj4gIGRyaXZlcnMvZG1hLWJ1Zi91ZG1hYnVmLmMgICAgICAg ICAgICAgICAgICAgICAgICAgfCAyODcgKysrKysrKysrKysrKysrKysrKysrKwo+ICB0b29scy90 ZXN0aW5nL3NlbGZ0ZXN0cy9kcml2ZXJzL2RtYS1idWYvdWRtYWJ1Zi5jIHwgIDk2ICsrKysrKysr Cj4gIE1BSU5UQUlORVJTICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfCAg IDggKwo+ICBkcml2ZXJzL2RtYS1idWYvS2NvbmZpZyAgICAgICAgICAgICAgICAgICAgICAgICAg IHwgICA4ICsKPiAgZHJpdmVycy9kbWEtYnVmL01ha2VmaWxlICAgICAgICAgICAgICAgICAgICAg ICAgICB8ICAgMSArCj4gIHRvb2xzL3Rlc3Rpbmcvc2VsZnRlc3RzL2RyaXZlcnMvZG1hLWJ1Zi9N YWtlZmlsZSAgfCAgIDUgKwo+ICA4IGZpbGVzIGNoYW5nZWQsIDQzOSBpbnNlcnRpb25zKCspCj4g IGNyZWF0ZSBtb2RlIDEwMDY0NCBpbmNsdWRlL3VhcGkvbGludXgvdWRtYWJ1Zi5oCj4gIGNyZWF0 ZSBtb2RlIDEwMDY0NCBkcml2ZXJzL2RtYS1idWYvdWRtYWJ1Zi5jCj4gIGNyZWF0ZSBtb2RlIDEw MDY0NCB0b29scy90ZXN0aW5nL3NlbGZ0ZXN0cy9kcml2ZXJzL2RtYS1idWYvdWRtYWJ1Zi5jCj4g IGNyZWF0ZSBtb2RlIDEwMDY0NCB0b29scy90ZXN0aW5nL3NlbGZ0ZXN0cy9kcml2ZXJzL2RtYS1i dWYvTWFrZWZpbGUKPiAKPiBkaWZmIC0tZ2l0IGEvRG9jdW1lbnRhdGlvbi9pb2N0bC9pb2N0bC1u dW1iZXIudHh0IGIvRG9jdW1lbnRhdGlvbi9pb2N0bC9pb2N0bC1udW1iZXIudHh0Cj4gaW5kZXgg NDgwYzg2MDlkYy4uNjYzNmRlYTQ3NiAxMDA2NDQKPiAtLS0gYS9Eb2N1bWVudGF0aW9uL2lvY3Rs L2lvY3RsLW51bWJlci50eHQKPiArKysgYi9Eb2N1bWVudGF0aW9uL2lvY3RsL2lvY3RsLW51bWJl ci50eHQKPiBAQCAtMjcxLDYgKzI3MSw3IEBAIENvZGUgIFNlcSMoaGV4KQlJbmNsdWRlIEZpbGUJ CUNvbW1lbnRzCj4gICd0Jwk5MC05MQlsaW51eC90b3NoaWJhLmgJCXRvc2hpYmEgYW5kIHRvc2hp YmFfYWNwaSBTTU0KPiAgJ3UnCTAwLTFGCWxpbnV4L3NtYl9mcy5oCQlnb25lCj4gICd1JwkyMC0z RglsaW51eC91dmN2aWRlby5oCVVTQiB2aWRlbyBjbGFzcyBob3N0IGRyaXZlcgo+ICsndScJNDAt NGYJbGludXgvdWRtYWJ1Zi5oCQl1c2Vyc3BhY2UgZG1hLWJ1ZiBtaXNjIGRldmljZQo+ICAndicJ MDAtMUYJbGludXgvZXh0Ml9mcy5oCQljb25mbGljdCEKPiAgJ3YnCTAwLTFGCWxpbnV4L2ZzLmgJ CWNvbmZsaWN0IQo+ICAndicJMDAtMEYJbGludXgvc29ueXBpLmgJCWNvbmZsaWN0IQo+IGRpZmYg LS1naXQgYS9pbmNsdWRlL3VhcGkvbGludXgvdWRtYWJ1Zi5oIGIvaW5jbHVkZS91YXBpL2xpbnV4 L3VkbWFidWYuaAo+IG5ldyBmaWxlIG1vZGUgMTAwNjQ0Cj4gaW5kZXggMDAwMDAwMDAwMC4uNDZi NjUzMmVkOAo+IC0tLSAvZGV2L251bGwKPiArKysgYi9pbmNsdWRlL3VhcGkvbGludXgvdWRtYWJ1 Zi5oCj4gQEAgLTAsMCArMSwzMyBAQAo+ICsvKiBTUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogR1BM LTIuMCBXSVRIIExpbnV4LXN5c2NhbGwtbm90ZSAqLwo+ICsjaWZuZGVmIF9VQVBJX0xJTlVYX1VE TUFCVUZfSAo+ICsjZGVmaW5lIF9VQVBJX0xJTlVYX1VETUFCVUZfSAo+ICsKPiArI2luY2x1ZGUg PGxpbnV4L3R5cGVzLmg+Cj4gKyNpbmNsdWRlIDxsaW51eC9pb2N0bC5oPgo+ICsKPiArI2RlZmlu ZSBVRE1BQlVGX0ZMQUdTX0NMT0VYRUMJMHgwMQo+ICsKPiArc3RydWN0IHVkbWFidWZfY3JlYXRl IHsKPiArCV9fdTMyIG1lbWZkOwo+ICsJX191MzIgZmxhZ3M7Cj4gKwlfX3U2NCBvZmZzZXQ7Cj4g KwlfX3U2NCBzaXplOwo+ICt9Owo+ICsKPiArc3RydWN0IHVkbWFidWZfY3JlYXRlX2l0ZW0gewo+ ICsJX191MzIgbWVtZmQ7Cj4gKwlfX3UzMiBfX3BhZDsKPiArCV9fdTY0IG9mZnNldDsKPiArCV9f dTY0IHNpemU7Cj4gK307Cj4gKwo+ICtzdHJ1Y3QgdWRtYWJ1Zl9jcmVhdGVfbGlzdCB7Cj4gKwlf X3UzMiBmbGFnczsKPiArCV9fdTMyIGNvdW50Owo+ICsJc3RydWN0IHVkbWFidWZfY3JlYXRlX2l0 ZW0gbGlzdFtdOwo+ICt9Owo+ICsKPiArI2RlZmluZSBVRE1BQlVGX0NSRUFURSAgICAgICBfSU9X KCd1JywgMHg0Miwgc3RydWN0IHVkbWFidWZfY3JlYXRlKQo+ICsjZGVmaW5lIFVETUFCVUZfQ1JF QVRFX0xJU1QgIF9JT1coJ3UnLCAweDQzLCBzdHJ1Y3QgdWRtYWJ1Zl9jcmVhdGVfbGlzdCkKPiAr Cj4gKyNlbmRpZiAvKiBfVUFQSV9MSU5VWF9VRE1BQlVGX0ggKi8KPiBkaWZmIC0tZ2l0IGEvZHJp dmVycy9kbWEtYnVmL3VkbWFidWYuYyBiL2RyaXZlcnMvZG1hLWJ1Zi91ZG1hYnVmLmMKPiBuZXcg ZmlsZSBtb2RlIDEwMDY0NAo+IGluZGV4IDAwMDAwMDAwMDAuLjhlMjQyMDQ1MjYKPiAtLS0gL2Rl di9udWxsCj4gKysrIGIvZHJpdmVycy9kbWEtYnVmL3VkbWFidWYuYwo+IEBAIC0wLDAgKzEsMjg3 IEBACj4gKy8vIFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBHUEwtMi4wCj4gKyNpbmNsdWRlIDxs aW51eC9pbml0Lmg+Cj4gKyNpbmNsdWRlIDxsaW51eC9tb2R1bGUuaD4KPiArI2luY2x1ZGUgPGxp bnV4L2RldmljZS5oPgo+ICsjaW5jbHVkZSA8bGludXgva2VybmVsLmg+Cj4gKyNpbmNsdWRlIDxs aW51eC9zbGFiLmg+Cj4gKyNpbmNsdWRlIDxsaW51eC9taXNjZGV2aWNlLmg+Cj4gKyNpbmNsdWRl IDxsaW51eC9kbWEtYnVmLmg+Cj4gKyNpbmNsdWRlIDxsaW51eC9oaWdobWVtLmg+Cj4gKyNpbmNs dWRlIDxsaW51eC9jcmVkLmg+Cj4gKyNpbmNsdWRlIDxsaW51eC9zaG1lbV9mcy5oPgo+ICsjaW5j bHVkZSA8bGludXgvbWVtZmQuaD4KPiArCj4gKyNpbmNsdWRlIDx1YXBpL2xpbnV4L3VkbWFidWYu aD4KPiArCj4gK3N0cnVjdCB1ZG1hYnVmIHsKPiArCXUzMiBwYWdlY291bnQ7Cj4gKwlzdHJ1Y3Qg cGFnZSAqKnBhZ2VzOwo+ICt9Owo+ICsKPiArc3RhdGljIGludCB1ZG1hYnVmX3ZtX2ZhdWx0KHN0 cnVjdCB2bV9mYXVsdCAqdm1mKQo+ICt7Cj4gKwlzdHJ1Y3Qgdm1fYXJlYV9zdHJ1Y3QgKnZtYSA9 IHZtZi0+dm1hOwo+ICsJc3RydWN0IHVkbWFidWYgKnVidWYgPSB2bWEtPnZtX3ByaXZhdGVfZGF0 YTsKPiArCj4gKwlpZiAoV0FSTl9PTih2bWYtPnBnb2ZmID49IHVidWYtPnBhZ2Vjb3VudCkpCj4g KwkJcmV0dXJuIFZNX0ZBVUxUX1NJR0JVUzsKPiArCj4gKwl2bWYtPnBhZ2UgPSB1YnVmLT5wYWdl c1t2bWYtPnBnb2ZmXTsKPiArCWdldF9wYWdlKHZtZi0+cGFnZSk7Cj4gKwlyZXR1cm4gMDsKPiAr fQo+ICsKPiArc3RhdGljIGNvbnN0IHN0cnVjdCB2bV9vcGVyYXRpb25zX3N0cnVjdCB1ZG1hYnVm X3ZtX29wcyA9IHsKPiArCS5mYXVsdCA9IHVkbWFidWZfdm1fZmF1bHQsCj4gK307Cj4gKwo+ICtz dGF0aWMgaW50IG1tYXBfdWRtYWJ1ZihzdHJ1Y3QgZG1hX2J1ZiAqYnVmLCBzdHJ1Y3Qgdm1fYXJl YV9zdHJ1Y3QgKnZtYSkKPiArewo+ICsJc3RydWN0IHVkbWFidWYgKnVidWYgPSBidWYtPnByaXY7 Cj4gKwo+ICsJaWYgKCh2bWEtPnZtX2ZsYWdzICYgKFZNX1NIQVJFRCB8IFZNX01BWVNIQVJFKSkg PT0gMCkKPiArCQlyZXR1cm4gLUVJTlZBTDsKPiArCj4gKwl2bWEtPnZtX29wcyA9ICZ1ZG1hYnVm X3ZtX29wczsKPiArCXZtYS0+dm1fcHJpdmF0ZV9kYXRhID0gdWJ1ZjsKPiArCXJldHVybiAwOwo+ ICt9Cj4gKwo+ICtzdGF0aWMgc3RydWN0IHNnX3RhYmxlICptYXBfdWRtYWJ1ZihzdHJ1Y3QgZG1h X2J1Zl9hdHRhY2htZW50ICphdCwKPiArCQkJCSAgICBlbnVtIGRtYV9kYXRhX2RpcmVjdGlvbiBk aXJlY3Rpb24pCj4gK3sKPiArCXN0cnVjdCB1ZG1hYnVmICp1YnVmID0gYXQtPmRtYWJ1Zi0+cHJp djsKPiArCXN0cnVjdCBzZ190YWJsZSAqc2c7Cj4gKwo+ICsJc2cgPSBremFsbG9jKHNpemVvZigq c2cpLCBHRlBfS0VSTkVMKTsKPiArCWlmICghc2cpCj4gKwkJZ290byBlcnIxOwo+ICsJaWYgKHNn X2FsbG9jX3RhYmxlX2Zyb21fcGFnZXMoc2csIHVidWYtPnBhZ2VzLCB1YnVmLT5wYWdlY291bnQs Cj4gKwkJCQkgICAgICAwLCB1YnVmLT5wYWdlY291bnQgPDwgUEFHRV9TSElGVCwKPiArCQkJCSAg ICAgIEdGUF9LRVJORUwpIDwgMCkKPiArCQlnb3RvIGVycjI7Cj4gKwlpZiAoIWRtYV9tYXBfc2co YXQtPmRldiwgc2ctPnNnbCwgc2ctPm5lbnRzLCBkaXJlY3Rpb24pKQo+ICsJCWdvdG8gZXJyMzsK PiArCj4gKwlyZXR1cm4gc2c7Cj4gKwo+ICtlcnIzOgo+ICsJc2dfZnJlZV90YWJsZShzZyk7Cj4g K2VycjI6Cj4gKwlrZnJlZShzZyk7Cj4gK2VycjE6Cj4gKwlyZXR1cm4gRVJSX1BUUigtRU5PTUVN KTsKPiArfQo+ICsKPiArc3RhdGljIHZvaWQgdW5tYXBfdWRtYWJ1ZihzdHJ1Y3QgZG1hX2J1Zl9h dHRhY2htZW50ICphdCwKPiArCQkJICBzdHJ1Y3Qgc2dfdGFibGUgKnNnLAo+ICsJCQkgIGVudW0g ZG1hX2RhdGFfZGlyZWN0aW9uIGRpcmVjdGlvbikKPiArewo+ICsJc2dfZnJlZV90YWJsZShzZyk7 Cj4gKwlrZnJlZShzZyk7Cj4gK30KPiArCj4gK3N0YXRpYyB2b2lkIHJlbGVhc2VfdWRtYWJ1Zihz dHJ1Y3QgZG1hX2J1ZiAqYnVmKQo+ICt7Cj4gKwlzdHJ1Y3QgdWRtYWJ1ZiAqdWJ1ZiA9IGJ1Zi0+ cHJpdjsKPiArCXBnb2ZmX3QgcGc7Cj4gKwo+ICsJZm9yIChwZyA9IDA7IHBnIDwgdWJ1Zi0+cGFn ZWNvdW50OyBwZysrKQo+ICsJCXB1dF9wYWdlKHVidWYtPnBhZ2VzW3BnXSk7Cj4gKwlrZnJlZSh1 YnVmLT5wYWdlcyk7Cj4gKwlrZnJlZSh1YnVmKTsKPiArfQo+ICsKPiArc3RhdGljIHZvaWQgKmtt YXBfdWRtYWJ1ZihzdHJ1Y3QgZG1hX2J1ZiAqYnVmLCB1bnNpZ25lZCBsb25nIHBhZ2VfbnVtKQo+ ICt7Cj4gKwlzdHJ1Y3QgdWRtYWJ1ZiAqdWJ1ZiA9IGJ1Zi0+cHJpdjsKPiArCXN0cnVjdCBwYWdl ICpwYWdlID0gdWJ1Zi0+cGFnZXNbcGFnZV9udW1dOwo+ICsKPiArCXJldHVybiBrbWFwKHBhZ2Up Owo+ICt9Cj4gKwo+ICtzdGF0aWMgdm9pZCBrdW5tYXBfdWRtYWJ1ZihzdHJ1Y3QgZG1hX2J1ZiAq YnVmLCB1bnNpZ25lZCBsb25nIHBhZ2VfbnVtLAo+ICsJCQkgICB2b2lkICp2YWRkcikKPiArewo+ ICsJa3VubWFwKHZhZGRyKTsKPiArfQo+ICsKPiArc3RhdGljIHN0cnVjdCBkbWFfYnVmX29wcyB1 ZG1hYnVmX29wcyA9IHsKPiArCS5tYXBfZG1hX2J1ZgkgID0gbWFwX3VkbWFidWYsCj4gKwkudW5t YXBfZG1hX2J1ZgkgID0gdW5tYXBfdWRtYWJ1ZiwKPiArCS5yZWxlYXNlCSAgPSByZWxlYXNlX3Vk bWFidWYsCj4gKwkubWFwCQkgID0ga21hcF91ZG1hYnVmLAo+ICsJLnVubWFwCQkgID0ga3VubWFw X3VkbWFidWYsCj4gKwkubW1hcAkJICA9IG1tYXBfdWRtYWJ1ZiwKPiArfTsKPiArCj4gKyNkZWZp bmUgU0VBTFNfV0FOVEVEIChGX1NFQUxfU0hSSU5LKQo+ICsjZGVmaW5lIFNFQUxTX0RFTklFRCAo Rl9TRUFMX1dSSVRFKQo+ICsKPiArc3RhdGljIGxvbmcgdWRtYWJ1Zl9jcmVhdGUoc3RydWN0IHVk bWFidWZfY3JlYXRlX2xpc3QgKmhlYWQsCj4gKwkJCSAgIHN0cnVjdCB1ZG1hYnVmX2NyZWF0ZV9p dGVtICpsaXN0KQo+ICt7Cj4gKwlERUZJTkVfRE1BX0JVRl9FWFBPUlRfSU5GTyhleHBfaW5mbyk7 Cj4gKwlzdHJ1Y3QgZmlsZSAqbWVtZmQgPSBOVUxMOwo+ICsJc3RydWN0IHVkbWFidWYgKnVidWY7 Cj4gKwlzdHJ1Y3QgZG1hX2J1ZiAqYnVmOwo+ICsJcGdvZmZfdCBwZ29mZiwgcGdjbnQsIHBnaWR4 LCBwZ2J1ZjsKPiArCXN0cnVjdCBwYWdlICpwYWdlOwo+ICsJaW50IHNlYWxzLCByZXQgPSAtRUlO VkFMOwo+ICsJdTMyIGksIGZsYWdzOwo+ICsKPiArCXVidWYgPSBremFsbG9jKHNpemVvZihzdHJ1 Y3QgdWRtYWJ1ZiksIEdGUF9LRVJORUwpOwo+ICsJaWYgKCF1YnVmKQo+ICsJCXJldHVybiAtRU5P TUVNOwo+ICsKPiArCWZvciAoaSA9IDA7IGkgPCBoZWFkLT5jb3VudDsgaSsrKSB7Cj4gKwkJaWYg KCFJU19BTElHTkVEKGxpc3RbaV0ub2Zmc2V0LCBQQUdFX1NJWkUpKQo+ICsJCQlnb3RvIGVycl9m cmVlX3VidWY7Cj4gKwkJaWYgKCFJU19BTElHTkVEKGxpc3RbaV0uc2l6ZSwgUEFHRV9TSVpFKSkK PiArCQkJZ290byBlcnJfZnJlZV91YnVmOwo+ICsJCXVidWYtPnBhZ2Vjb3VudCArPSBsaXN0W2ld LnNpemUgPj4gUEFHRV9TSElGVDsKPiArCX0KPiArCXVidWYtPnBhZ2VzID0ga21hbGxvY19hcnJh eSh1YnVmLT5wYWdlY291bnQsIHNpemVvZihzdHJ1Y3QgcGFnZSAqKSwKPiArCQkJCSAgICBHRlBf S0VSTkVMKTsKPiArCWlmICghdWJ1Zi0+cGFnZXMpIHsKPiArCQlyZXQgPSAtRU5PTUVNOwo+ICsJ CWdvdG8gZXJyX2ZyZWVfdWJ1ZjsKPiArCX0KPiArCj4gKwlwZ2J1ZiA9IDA7Cj4gKwlmb3IgKGkg PSAwOyBpIDwgaGVhZC0+Y291bnQ7IGkrKykgewo+ICsJCW1lbWZkID0gZmdldChsaXN0W2ldLm1l bWZkKTsKPiArCQlpZiAoIW1lbWZkKQo+ICsJCQlnb3RvIGVycl9wdXRfcGFnZXM7Cj4gKwkJaWYg KCFzaG1lbV9tYXBwaW5nKGZpbGVfaW5vZGUobWVtZmQpLT5pX21hcHBpbmcpKQo+ICsJCQlnb3Rv IGVycl9wdXRfcGFnZXM7Cj4gKwkJc2VhbHMgPSBtZW1mZF9mY250bChtZW1mZCwgRl9HRVRfU0VB TFMsIDApOwo+ICsJCWlmIChzZWFscyA9PSAtRUlOVkFMIHx8Cj4gKwkJICAgIChzZWFscyAmIFNF QUxTX1dBTlRFRCkgIT0gU0VBTFNfV0FOVEVEIHx8Cj4gKwkJICAgIChzZWFscyAmIFNFQUxTX0RF TklFRCkgIT0gMCkKPiArCQkJZ290byBlcnJfcHV0X3BhZ2VzOwo+ICsJCXBnb2ZmID0gbGlzdFtp XS5vZmZzZXQgPj4gUEFHRV9TSElGVDsKPiArCQlwZ2NudCA9IGxpc3RbaV0uc2l6ZSAgID4+IFBB R0VfU0hJRlQ7Cj4gKwkJZm9yIChwZ2lkeCA9IDA7IHBnaWR4IDwgcGdjbnQ7IHBnaWR4KyspIHsK PiArCQkJcGFnZSA9IHNobWVtX3JlYWRfbWFwcGluZ19wYWdlKAo+ICsJCQkJZmlsZV9pbm9kZSht ZW1mZCktPmlfbWFwcGluZywgcGdvZmYgKyBwZ2lkeCk7Cj4gKwkJCWlmIChJU19FUlIocGFnZSkp IHsKPiArCQkJCXJldCA9IFBUUl9FUlIocGFnZSk7Cj4gKwkJCQlnb3RvIGVycl9wdXRfcGFnZXM7 Cj4gKwkJCX0KPiArCQkJdWJ1Zi0+cGFnZXNbcGdidWYrK10gPSBwYWdlOwo+ICsJCX0KPiArCQlm cHV0KG1lbWZkKTsKPiArCX0KPiArCW1lbWZkID0gTlVMTDsKPiArCj4gKwlleHBfaW5mby5vcHMg ID0gJnVkbWFidWZfb3BzOwo+ICsJZXhwX2luZm8uc2l6ZSA9IHVidWYtPnBhZ2Vjb3VudCA8PCBQ QUdFX1NISUZUOwo+ICsJZXhwX2luZm8ucHJpdiA9IHVidWY7Cj4gKwo+ICsJYnVmID0gZG1hX2J1 Zl9leHBvcnQoJmV4cF9pbmZvKTsKPiArCWlmIChJU19FUlIoYnVmKSkgewo+ICsJCXJldCA9IFBU Ul9FUlIoYnVmKTsKPiArCQlnb3RvIGVycl9wdXRfcGFnZXM7Cj4gKwl9Cj4gKwo+ICsJZmxhZ3Mg PSAwOwo+ICsJaWYgKGhlYWQtPmZsYWdzICYgVURNQUJVRl9GTEFHU19DTE9FWEVDKQo+ICsJCWZs YWdzIHw9IE9fQ0xPRVhFQzsKPiArCXJldHVybiBkbWFfYnVmX2ZkKGJ1ZiwgZmxhZ3MpOwo+ICsK PiArZXJyX3B1dF9wYWdlczoKPiArCXdoaWxlIChwZ2J1ZiA+IDApCj4gKwkJcHV0X3BhZ2UodWJ1 Zi0+cGFnZXNbLS1wZ2J1Zl0pOwo+ICtlcnJfZnJlZV91YnVmOgo+ICsJZnB1dChtZW1mZCk7Cj4g KwlrZnJlZSh1YnVmLT5wYWdlcyk7Cj4gKwlrZnJlZSh1YnVmKTsKPiArCXJldHVybiByZXQ7Cj4g K30KPiArCj4gK3N0YXRpYyBsb25nIHVkbWFidWZfaW9jdGxfY3JlYXRlKHN0cnVjdCBmaWxlICpm aWxwLCB1bnNpZ25lZCBsb25nIGFyZykKPiArewo+ICsJc3RydWN0IHVkbWFidWZfY3JlYXRlIGNy ZWF0ZTsKPiArCXN0cnVjdCB1ZG1hYnVmX2NyZWF0ZV9saXN0IGhlYWQ7Cj4gKwlzdHJ1Y3QgdWRt YWJ1Zl9jcmVhdGVfaXRlbSBsaXN0Owo+ICsKPiArCWlmIChjb3B5X2Zyb21fdXNlcigmY3JlYXRl LCAodm9pZCBfX3VzZXIgKilhcmcsCj4gKwkJCSAgIHNpemVvZihzdHJ1Y3QgdWRtYWJ1Zl9jcmVh dGUpKSkKPiArCQlyZXR1cm4gLUVGQVVMVDsKPiArCj4gKwloZWFkLmZsYWdzICA9IGNyZWF0ZS5m bGFnczsKPiArCWhlYWQuY291bnQgID0gMTsKPiArCWxpc3QubWVtZmQgID0gY3JlYXRlLm1lbWZk Owo+ICsJbGlzdC5vZmZzZXQgPSBjcmVhdGUub2Zmc2V0Owo+ICsJbGlzdC5zaXplICAgPSBjcmVh dGUuc2l6ZTsKPiArCj4gKwlyZXR1cm4gdWRtYWJ1Zl9jcmVhdGUoJmhlYWQsICZsaXN0KTsKPiAr fQo+ICsKPiArc3RhdGljIGxvbmcgdWRtYWJ1Zl9pb2N0bF9jcmVhdGVfbGlzdChzdHJ1Y3QgZmls ZSAqZmlscCwgdW5zaWduZWQgbG9uZyBhcmcpCj4gK3sKPiArCXN0cnVjdCB1ZG1hYnVmX2NyZWF0 ZV9saXN0IGhlYWQ7Cj4gKwlzdHJ1Y3QgdWRtYWJ1Zl9jcmVhdGVfaXRlbSAqbGlzdDsKPiArCWlu dCByZXQgPSAtRUlOVkFMOwo+ICsJdTMyIGxzaXplOwo+ICsKPiArCWlmIChjb3B5X2Zyb21fdXNl cigmaGVhZCwgKHZvaWQgX191c2VyICopYXJnLCBzaXplb2YoaGVhZCkpKQo+ICsJCXJldHVybiAt RUZBVUxUOwo+ICsJaWYgKGhlYWQuY291bnQgPiAxMDI0KQo+ICsJCXJldHVybiAtRUlOVkFMOwo+ ICsJbHNpemUgPSBzaXplb2Yoc3RydWN0IHVkbWFidWZfY3JlYXRlX2l0ZW0pICogaGVhZC5jb3Vu dDsKPiArCWxpc3QgPSBtZW1kdXBfdXNlcigodm9pZCBfX3VzZXIgKikoYXJnICsgc2l6ZW9mKGhl YWQpKSwgbHNpemUpOwo+ICsJaWYgKElTX0VSUihsaXN0KSkKPiArCQlyZXR1cm4gUFRSX0VSUihs aXN0KTsKPiArCj4gKwlyZXQgPSB1ZG1hYnVmX2NyZWF0ZSgmaGVhZCwgbGlzdCk7Cj4gKwlrZnJl ZShsaXN0KTsKPiArCXJldHVybiByZXQ7Cj4gK30KPiArCj4gK3N0YXRpYyBsb25nIHVkbWFidWZf aW9jdGwoc3RydWN0IGZpbGUgKmZpbHAsIHVuc2lnbmVkIGludCBpb2N0bCwKPiArCQkJICB1bnNp Z25lZCBsb25nIGFyZykKPiArewo+ICsJbG9uZyByZXQ7Cj4gKwo+ICsJc3dpdGNoIChpb2N0bCkg ewo+ICsJY2FzZSBVRE1BQlVGX0NSRUFURToKPiArCQlyZXQgPSB1ZG1hYnVmX2lvY3RsX2NyZWF0 ZShmaWxwLCBhcmcpOwo+ICsJCWJyZWFrOwo+ICsJY2FzZSBVRE1BQlVGX0NSRUFURV9MSVNUOgo+ ICsJCXJldCA9IHVkbWFidWZfaW9jdGxfY3JlYXRlX2xpc3QoZmlscCwgYXJnKTsKPiArCQlicmVh azsKPiArCWRlZmF1bHQ6Cj4gKwkJcmV0ID0gLUVJTlZBTDsKPiArCQlicmVhazsKPiArCX0KPiAr CXJldHVybiByZXQ7Cj4gK30KPiArCj4gK3N0YXRpYyBjb25zdCBzdHJ1Y3QgZmlsZV9vcGVyYXRp b25zIHVkbWFidWZfZm9wcyA9IHsKPiArCS5vd25lcgkJPSBUSElTX01PRFVMRSwKPiArCS51bmxv Y2tlZF9pb2N0bCA9IHVkbWFidWZfaW9jdGwsCj4gK307Cj4gKwo+ICtzdGF0aWMgc3RydWN0IG1p c2NkZXZpY2UgdWRtYWJ1Zl9taXNjID0gewo+ICsJLm1pbm9yICAgICAgICAgID0gTUlTQ19EWU5B TUlDX01JTk9SLAo+ICsJLm5hbWUgICAgICAgICAgID0gInVkbWFidWYiLAo+ICsJLmZvcHMgICAg ICAgICAgID0gJnVkbWFidWZfZm9wcywKPiArfTsKPiArCj4gK3N0YXRpYyBpbnQgX19pbml0IHVk bWFidWZfZGV2X2luaXQodm9pZCkKPiArewo+ICsJcmV0dXJuIG1pc2NfcmVnaXN0ZXIoJnVkbWFi dWZfbWlzYyk7Cj4gK30KPiArCj4gK3N0YXRpYyB2b2lkIF9fZXhpdCB1ZG1hYnVmX2Rldl9leGl0 KHZvaWQpCj4gK3sKPiArCW1pc2NfZGVyZWdpc3RlcigmdWRtYWJ1Zl9taXNjKTsKPiArfQo+ICsK PiArbW9kdWxlX2luaXQodWRtYWJ1Zl9kZXZfaW5pdCkKPiArbW9kdWxlX2V4aXQodWRtYWJ1Zl9k ZXZfZXhpdCkKPiArCj4gK01PRFVMRV9BVVRIT1IoIkdlcmQgSG9mZm1hbm4gPGtyYXhlbEByZWRo YXQuY29tPiIpOwo+ICtNT0RVTEVfTElDRU5TRSgiR1BMIHYyIik7Cj4gZGlmZiAtLWdpdCBhL3Rv b2xzL3Rlc3Rpbmcvc2VsZnRlc3RzL2RyaXZlcnMvZG1hLWJ1Zi91ZG1hYnVmLmMgYi90b29scy90 ZXN0aW5nL3NlbGZ0ZXN0cy9kcml2ZXJzL2RtYS1idWYvdWRtYWJ1Zi5jCj4gbmV3IGZpbGUgbW9k ZSAxMDA2NDQKPiBpbmRleCAwMDAwMDAwMDAwLi4zNzZiMWQ2NzMwCj4gLS0tIC9kZXYvbnVsbAo+ ICsrKyBiL3Rvb2xzL3Rlc3Rpbmcvc2VsZnRlc3RzL2RyaXZlcnMvZG1hLWJ1Zi91ZG1hYnVmLmMK PiBAQCAtMCwwICsxLDk2IEBACj4gKy8vIFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBHUEwtMi4w Cj4gKyNpbmNsdWRlIDxzdGRpby5oPgo+ICsjaW5jbHVkZSA8c3RkbGliLmg+Cj4gKyNpbmNsdWRl IDx1bmlzdGQuaD4KPiArI2luY2x1ZGUgPHN0cmluZy5oPgo+ICsjaW5jbHVkZSA8ZXJybm8uaD4K PiArI2luY2x1ZGUgPGZjbnRsLmg+Cj4gKyNpbmNsdWRlIDxtYWxsb2MuaD4KPiArCj4gKyNpbmNs dWRlIDxzeXMvaW9jdGwuaD4KPiArI2luY2x1ZGUgPHN5cy9zeXNjYWxsLmg+Cj4gKyNpbmNsdWRl IDxsaW51eC9tZW1mZC5oPgo+ICsjaW5jbHVkZSA8bGludXgvdWRtYWJ1Zi5oPgo+ICsKPiArI2Rl ZmluZSBURVNUX1BSRUZJWAkiZHJpdmVycy9kbWEtYnVmL3VkbWFidWYiCj4gKyNkZWZpbmUgTlVN X1BBR0VTICAgICAgIDQKPiArCj4gK3N0YXRpYyBpbnQgbWVtZmRfY3JlYXRlKGNvbnN0IGNoYXIg Km5hbWUsIHVuc2lnbmVkIGludCBmbGFncykKPiArewo+ICsJcmV0dXJuIHN5c2NhbGwoX19OUl9t ZW1mZF9jcmVhdGUsIG5hbWUsIGZsYWdzKTsKPiArfQo+ICsKPiAraW50IG1haW4oaW50IGFyZ2Ms IGNoYXIgKmFyZ3ZbXSkKPiArewo+ICsJc3RydWN0IHVkbWFidWZfY3JlYXRlIGNyZWF0ZTsKPiAr CWludCBkZXZmZCwgbWVtZmQsIGJ1ZiwgcmV0Owo+ICsJb2ZmX3Qgc2l6ZTsKPiArCXZvaWQgKm1l bTsKPiArCj4gKwlkZXZmZCA9IG9wZW4oIi9kZXYvdWRtYWJ1ZiIsIE9fUkRXUik7Cj4gKwlpZiAo ZGV2ZmQgPCAwKSB7Cj4gKwkJcHJpbnRmKCIlczogW3NraXAsbm8tdWRtYWJ1Zl1cbiIsIFRFU1Rf UFJFRklYKTsKPiArCQlleGl0KDc3KTsKPiArCX0KPiArCj4gKwltZW1mZCA9IG1lbWZkX2NyZWF0 ZSgidWRtYWJ1Zi10ZXN0IiwgTUZEX0NMT0VYRUMpOwo+ICsJaWYgKG1lbWZkIDwgMCkgewo+ICsJ CXByaW50ZigiJXM6IFtza2lwLG5vLW1lbWZkXVxuIiwgVEVTVF9QUkVGSVgpOwo+ICsJCWV4aXQo NzcpOwo+ICsJfQo+ICsKPiArCXNpemUgPSBnZXRwYWdlc2l6ZSgpICogTlVNX1BBR0VTOwo+ICsJ cmV0ID0gZnRydW5jYXRlKG1lbWZkLCBzaXplKTsKPiArCWlmIChyZXQgPT0gLTEpIHsKPiArCQlw cmludGYoIiVzOiBbRkFJTCxtZW1mZC10cnVuY2F0ZV1cbiIsIFRFU1RfUFJFRklYKTsKPiArCQll eGl0KDEpOwo+ICsJfQo+ICsKPiArCW1lbXNldCgmY3JlYXRlLCAwLCBzaXplb2YoY3JlYXRlKSk7 Cj4gKwo+ICsJLyogc2hvdWxkIGZhaWwgKG9mZnNldCBub3QgcGFnZSBhbGlnbmVkKSAqLwo+ICsJ Y3JlYXRlLm1lbWZkICA9IG1lbWZkOwo+ICsJY3JlYXRlLm9mZnNldCA9IGdldHBhZ2VzaXplKCkv MjsKPiArCWNyZWF0ZS5zaXplICAgPSBnZXRwYWdlc2l6ZSgpOwo+ICsJYnVmID0gaW9jdGwoZGV2 ZmQsIFVETUFCVUZfQ1JFQVRFLCAmY3JlYXRlKTsKPiArCWlmIChidWYgPj0gMCkgewo+ICsJCXBy aW50ZigiJXM6IFtGQUlMLHRlc3QtMV1cbiIsIFRFU1RfUFJFRklYKTsKPiArCQlleGl0KDEpOwo+ ICsJfQo+ICsKPiArCS8qIHNob3VsZCBmYWlsIChzaXplIG5vdCBtdWx0aXBsZSBvZiBwYWdlKSAq Lwo+ICsJY3JlYXRlLm1lbWZkICA9IG1lbWZkOwo+ICsJY3JlYXRlLm9mZnNldCA9IDA7Cj4gKwlj cmVhdGUuc2l6ZSAgID0gZ2V0cGFnZXNpemUoKS8yOwo+ICsJYnVmID0gaW9jdGwoZGV2ZmQsIFVE TUFCVUZfQ1JFQVRFLCAmY3JlYXRlKTsKPiArCWlmIChidWYgPj0gMCkgewo+ICsJCXByaW50Zigi JXM6IFtGQUlMLHRlc3QtMl1cbiIsIFRFU1RfUFJFRklYKTsKPiArCQlleGl0KDEpOwo+ICsJfQo+ ICsKPiArCS8qIHNob3VsZCBmYWlsIChub3QgbWVtZmQpICovCj4gKwljcmVhdGUubWVtZmQgID0g MDsgLyogc3RkaW4gKi8KPiArCWNyZWF0ZS5vZmZzZXQgPSAwOwo+ICsJY3JlYXRlLnNpemUgICA9 IHNpemU7Cj4gKwlidWYgPSBpb2N0bChkZXZmZCwgVURNQUJVRl9DUkVBVEUsICZjcmVhdGUpOwo+ ICsJaWYgKGJ1ZiA+PSAwKSB7Cj4gKwkJcHJpbnRmKCIlczogW0ZBSUwsdGVzdC0zXVxuIiwgVEVT VF9QUkVGSVgpOwo+ICsJCWV4aXQoMSk7Cj4gKwl9Cj4gKwo+ICsJLyogc2hvdWxkIHdvcmsgKi8K PiArCWNyZWF0ZS5tZW1mZCAgPSBtZW1mZDsKPiArCWNyZWF0ZS5vZmZzZXQgPSAwOwo+ICsJY3Jl YXRlLnNpemUgICA9IHNpemU7Cj4gKwlidWYgPSBpb2N0bChkZXZmZCwgVURNQUJVRl9DUkVBVEUs ICZjcmVhdGUpOwo+ICsJaWYgKGJ1ZiA8IDApIHsKPiArCQlwcmludGYoIiVzOiBbRkFJTCx0ZXN0 LTRdXG4iLCBURVNUX1BSRUZJWCk7Cj4gKwkJZXhpdCgxKTsKPiArCX0KPiArCj4gKwlmcHJpbnRm KHN0ZGVyciwgIiVzOiBva1xuIiwgVEVTVF9QUkVGSVgpOwo+ICsJY2xvc2UoYnVmKTsKPiArCWNs b3NlKG1lbWZkKTsKPiArCWNsb3NlKGRldmZkKTsKPiArCXJldHVybiAwOwo+ICt9Cj4gZGlmZiAt LWdpdCBhL01BSU5UQUlORVJTIGIvTUFJTlRBSU5FUlMKPiBpbmRleCAwN2QxNTc2ZmM3Li5hOGUx YmIzYmMzIDEwMDY0NAo+IC0tLSBhL01BSU5UQUlORVJTCj4gKysrIGIvTUFJTlRBSU5FUlMKPiBA QCAtMTQ2MzgsNiArMTQ2MzgsMTQgQEAgUzoJTWFpbnRhaW5lZAo+ICBGOglEb2N1bWVudGF0aW9u L2ZpbGVzeXN0ZW1zL3VkZi50eHQKPiAgRjoJZnMvdWRmLwo+ICAKPiArVURNQUJVRiBEUklWRVIK PiArTToJR2VyZCBIb2ZmbWFubiA8a3JheGVsQHJlZGhhdC5jb20+Cj4gK0w6CWRyaS1kZXZlbEBs aXN0cy5mcmVlZGVza3RvcC5vcmcKPiArUzoJTWFpbnRhaW5lZAo+ICtGOglkcml2ZXJzL2RtYS1i dWYvdWRtYWJ1Zi5jCj4gK0Y6CWluY2x1ZGUvdWFwaS9saW51eC91ZG1hYnVmLmgKPiArRjoJdG9v bHMvdGVzdGluZy9zZWxmdGVzdHMvZHJpdmVycy9kbWEtYnVmL3VkbWFidWYuYwo+ICsKPiAgVURS QVcgVEFCTEVUCj4gIE06CUJhc3RpZW4gTm9jZXJhIDxoYWRlc3NAaGFkZXNzLm5ldD4KPiAgTDoJ bGludXgtaW5wdXRAdmdlci5rZXJuZWwub3JnCj4gZGlmZiAtLWdpdCBhL2RyaXZlcnMvZG1hLWJ1 Zi9LY29uZmlnIGIvZHJpdmVycy9kbWEtYnVmL0tjb25maWcKPiBpbmRleCBlZDNiNzg1YmFlLi4z MzgxMjllYjEyIDEwMDY0NAo+IC0tLSBhL2RyaXZlcnMvZG1hLWJ1Zi9LY29uZmlnCj4gKysrIGIv ZHJpdmVycy9kbWEtYnVmL0tjb25maWcKPiBAQCAtMzAsNCArMzAsMTIgQEAgY29uZmlnIFNXX1NZ TkMKPiAgCSAgV0FSTklORzogaW1wcm9wZXIgdXNlIG9mIHRoaXMgY2FuIHJlc3VsdCBpbiBkZWFk bG9ja2luZyBrZXJuZWwKPiAgCSAgZHJpdmVycyBmcm9tIHVzZXJzcGFjZS4gSW50ZW5kZWQgZm9y IHRlc3QgYW5kIGRlYnVnIG9ubHkuCj4gIAo+ICtjb25maWcgVURNQUJVRgo+ICsJYm9vbCAidXNl cnNwYWNlIGRtYWJ1ZiBtaXNjIGRyaXZlciIKPiArCWRlZmF1bHQgbgo+ICsJZGVwZW5kcyBvbiBE TUFfU0hBUkVEX0JVRkZFUgo+ICsJaGVscAo+ICsJICBBIGRyaXZlciB0byBsZXQgdXNlcnNwYWNl IHR1cm4gbWVtZmQgcmVnaW9ucyBpbnRvIGRtYS1idWZzLgo+ICsJICBRZW11IGNhbiB1c2UgdGhp cyB0byBjcmVhdGUgaG9zdCBkbWFidWZzIGZvciBndWVzdCBmcmFtZWJ1ZmZlcnMuCj4gKwo+ICBl bmRtZW51Cj4gZGlmZiAtLWdpdCBhL2RyaXZlcnMvZG1hLWJ1Zi9NYWtlZmlsZSBiL2RyaXZlcnMv ZG1hLWJ1Zi9NYWtlZmlsZQo+IGluZGV4IGMzM2JmODg2MzEuLjA5MTNhNmNjYWIgMTAwNjQ0Cj4g LS0tIGEvZHJpdmVycy9kbWEtYnVmL01ha2VmaWxlCj4gKysrIGIvZHJpdmVycy9kbWEtYnVmL01h a2VmaWxlCj4gQEAgLTEsMyArMSw0IEBACj4gIG9iai15IDo9IGRtYS1idWYubyBkbWEtZmVuY2Uu byBkbWEtZmVuY2UtYXJyYXkubyByZXNlcnZhdGlvbi5vIHNlcW5vLWZlbmNlLm8KPiAgb2JqLSQo Q09ORklHX1NZTkNfRklMRSkJCSs9IHN5bmNfZmlsZS5vCj4gIG9iai0kKENPTkZJR19TV19TWU5D KQkJKz0gc3dfc3luYy5vIHN5bmNfZGVidWcubwo+ICtvYmotJChDT05GSUdfVURNQUJVRikJCSs9 IHVkbWFidWYubwo+IGRpZmYgLS1naXQgYS90b29scy90ZXN0aW5nL3NlbGZ0ZXN0cy9kcml2ZXJz L2RtYS1idWYvTWFrZWZpbGUgYi90b29scy90ZXN0aW5nL3NlbGZ0ZXN0cy9kcml2ZXJzL2RtYS1i dWYvTWFrZWZpbGUKPiBuZXcgZmlsZSBtb2RlIDEwMDY0NAo+IGluZGV4IDAwMDAwMDAwMDAuLjQx NTRjM2Q3YWEKPiAtLS0gL2Rldi9udWxsCj4gKysrIGIvdG9vbHMvdGVzdGluZy9zZWxmdGVzdHMv ZHJpdmVycy9kbWEtYnVmL01ha2VmaWxlCj4gQEAgLTAsMCArMSw1IEBACj4gK0NGTEFHUyArPSAt SS4uLy4uLy4uLy4uLy4uL3Vzci9pbmNsdWRlLwo+ICsKPiArVEVTVF9HRU5fUFJPR1MgOj0gdWRt YWJ1Zgo+ICsKPiAraW5jbHVkZSAuLi8uLi9saWIubWsKPiAtLSAKPiAyLjkuMwo+IAoKLS0gCkRh bmllbCBWZXR0ZXIKU29mdHdhcmUgRW5naW5lZXIsIEludGVsIENvcnBvcmF0aW9uCmh0dHA6Ly9i bG9nLmZmd2xsLmNoCl9fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19f X19fCmRyaS1kZXZlbCBtYWlsaW5nIGxpc3QKZHJpLWRldmVsQGxpc3RzLmZyZWVkZXNrdG9wLm9y ZwpodHRwczovL2xpc3RzLmZyZWVkZXNrdG9wLm9yZy9tYWlsbWFuL2xpc3RpbmZvL2RyaS1kZXZl bAo=