Re: [PATCH v2] Add udmabuf misc device

2018-04-09 Thread Daniel Vetter
On Fri, Apr 06, 2018 at 02:24:46PM +0200, Christian König wrote:
> Am 06.04.2018 um 11:33 schrieb Gerd Hoffmann:
> >Hi,
> > 
> > > The pages backing a DMA-buf are not allowed to move (at least not without 
> > > a
> > > patch set I'm currently working on), but for certain MM operations to work
> > > correctly you must be able to modify the page tables entries and move the
> > > pages backing them around.
> > > 
> > > For example try to use fork() with some copy on write pages with this
> > > approach. You will find that you have only two options to correctly handle
> > > this.
> > The fork() issue should go away with shared memory pages (no cow).
> > I guess this is the reason why vgem is internally backed by shmem.
> 
> Yes, exactly that is also an approach which should work fine. Just don't try
> to get this working with get_user_pages().
> 
> > 
> > Hmm.  So I could try to limit the udmabuf driver to shmem too (i.e.
> > have the ioctl take a shmem filehandle and offset instead of a virtual
> > address).
> > 
> > But maybe it is better then to just extend vgem, i.e. add support to
> > create gem objects from existing shmem.
> > 
> > Comments?
> 
> Yes, extending vgem instead of creating something new sounds like a good
> idea to me as well.

+1 on adding a vgem "import from shmem/memfd" ioctl. Sounds like a good
idea, and generally useful.

We might want to limit to memfd though for semantic reasons: dma-buf have
invariant size, shmem not so much. memfd can be locked down to not change
their size anymore. And iirc the core mm page invalidation protocol around
truncate() is about as bad as get_user_pages vs cow :-)
-Daniel
-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch


Re: [PATCH v2] Add udmabuf misc device

2018-04-06 Thread Christian König

Am 06.04.2018 um 11:33 schrieb Gerd Hoffmann:

   Hi,


The pages backing a DMA-buf are not allowed to move (at least not without a
patch set I'm currently working on), but for certain MM operations to work
correctly you must be able to modify the page tables entries and move the
pages backing them around.

For example try to use fork() with some copy on write pages with this
approach. You will find that you have only two options to correctly handle
this.

The fork() issue should go away with shared memory pages (no cow).
I guess this is the reason why vgem is internally backed by shmem.


Yes, exactly that is also an approach which should work fine. Just don't 
try to get this working with get_user_pages().




Hmm.  So I could try to limit the udmabuf driver to shmem too (i.e.
have the ioctl take a shmem filehandle and offset instead of a virtual
address).

But maybe it is better then to just extend vgem, i.e. add support to
create gem objects from existing shmem.

Comments?


Yes, extending vgem instead of creating something new sounds like a good 
idea to me as well.


Regards,
Christian.



cheers,
   Gerd





Re: [PATCH v2] Add udmabuf misc device

2018-04-06 Thread Gerd Hoffmann
  Hi,

> The pages backing a DMA-buf are not allowed to move (at least not without a
> patch set I'm currently working on), but for certain MM operations to work
> correctly you must be able to modify the page tables entries and move the
> pages backing them around.
> 
> For example try to use fork() with some copy on write pages with this
> approach. You will find that you have only two options to correctly handle
> this.

The fork() issue should go away with shared memory pages (no cow).
I guess this is the reason why vgem is internally backed by shmem.

Hmm.  So I could try to limit the udmabuf driver to shmem too (i.e.
have the ioctl take a shmem filehandle and offset instead of a virtual
address).

But maybe it is better then to just extend vgem, i.e. add support to
create gem objects from existing shmem.

Comments?

cheers,
  Gerd



Re: [PATCH v2] Add udmabuf misc device

2018-03-16 Thread Christian König

Am 16.03.2018 um 08:46 schrieb Gerd Hoffmann:

A driver to let userspace turn iovecs 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.

Those dma-bufs are accounted against user's shm mlock bucket as the
pages are effectively locked in memory.


Sorry to disappoint you, but we have investigated the same idea for 
userptr use quite extensively and found that whole approach doesn't work.


The pages backing a DMA-buf are not allowed to move (at least not 
without a patch set I'm currently working on), but for certain MM 
operations to work correctly you must be able to modify the page tables 
entries and move the pages backing them around.


For example try to use fork() with some copy on write pages with this 
approach. You will find that you have only two options to correctly 
handle this.


Either you access memory which could no longer belong to your process, 
which in turn is major security no-go.


Or you use a MM notifier, but without being able to unmap DMA-bufs that 
won't work and you will certainly create a deadlock.


Even with the patch set I'm currently working on the MM notifier 
approach is a real beast to get right.


Regards,
Christian.



Cc: David Airlie 
Cc: Tomeu Vizoso 
Cc: Daniel Vetter 
Signed-off-by: Gerd Hoffmann 
---
  include/uapi/linux/udmabuf.h  |  23 ++
  drivers/dma-buf/udmabuf.c | 261 ++
  tools/testing/selftests/drivers/dma-buf/udmabuf.c |  69 ++
  drivers/dma-buf/Kconfig   |   7 +
  drivers/dma-buf/Makefile  |   1 +
  tools/testing/selftests/drivers/dma-buf/Makefile  |   5 +
  6 files changed, 366 insertions(+)
  create mode 100644 include/uapi/linux/udmabuf.h
  create mode 100644 drivers/dma-buf/udmabuf.c
  create mode 100644 tools/testing/selftests/drivers/dma-buf/udmabuf.c
  create mode 100644 tools/testing/selftests/drivers/dma-buf/Makefile

diff --git a/include/uapi/linux/udmabuf.h b/include/uapi/linux/udmabuf.h
new file mode 100644
index 00..54ceba203a
--- /dev/null
+++ b/include/uapi/linux/udmabuf.h
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef _UAPI_LINUX_UDMABUF_H
+#define _UAPI_LINUX_UDMABUF_H
+
+#include 
+#include 
+
+struct udmabuf_iovec {
+   __u64 base;
+   __u64 len;
+};
+
+#define UDMABUF_FLAGS_CLOEXEC  0x01
+
+struct udmabuf_create {
+   __u32 flags;
+   __u32 niov;
+   struct udmabuf_iovec iovs[];
+};
+
+#define UDMABUF_CREATE _IOW(0x42, 0x23, struct udmabuf_create)
+
+#endif /* _UAPI_LINUX_UDMABUF_H */
diff --git a/drivers/dma-buf/udmabuf.c b/drivers/dma-buf/udmabuf.c
new file mode 100644
index 00..664ab4ee4e
--- /dev/null
+++ b/drivers/dma-buf/udmabuf.c
@@ -0,0 +1,261 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include 
+
+struct udmabuf {
+   u32 pagecount;
+   struct page **pages;
+   struct user_struct *owner;
+};
+
+static int udmabuf_vm_fault(struct vm_fault *vmf)
+{
+   struct vm_area_struct *vma = vmf->vma;
+   struct udmabuf *ubuf = vma->vm_private_data;
+
+   if (WARN_ON(vmf->pgoff >= ubuf->pagecount))
+   return VM_FAULT_SIGBUS;
+
+   vmf->page = ubuf->pages[vmf->pgoff];
+   get_page(vmf->page);
+   return 0;
+}
+
+static const struct vm_operations_struct udmabuf_vm_ops = {
+   .fault = udmabuf_vm_fault,
+};
+
+static int mmap_udmabuf(struct dma_buf *buf, struct vm_area_struct *vma)
+{
+   struct udmabuf *ubuf = buf->priv;
+
+   if ((vma->vm_flags & VM_SHARED) == 0)
+   return -EINVAL;
+
+   vma->vm_ops = _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:
+  

Re: [PATCH v2] Add udmabuf misc device

2018-03-16 Thread Greg KH
On Fri, Mar 16, 2018 at 08:46:49AM +0100, Gerd Hoffmann wrote:
> --- /dev/null
> +++ b/tools/testing/selftests/drivers/dma-buf/udmabuf.c
> @@ -0,0 +1,69 @@
> +#include 
> +#include 
> +#include 
> +#include 
> +#include 
> +#include 
> +#include 

No license text at all?  Come on, I already made one commit in the tree
that touched 11k files, I don't want to have to do it again :)

thanks,

greg k-h


Re: [PATCH v2] Add udmabuf misc device

2018-03-16 Thread Greg KH
On Fri, Mar 16, 2018 at 08:46:49AM +0100, Gerd Hoffmann wrote:
> --- /dev/null
> +++ b/drivers/dma-buf/udmabuf.c
> @@ -0,0 +1,261 @@
> +/*
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */

No SPDX line or copyright here?  You put it in the .h file :(

thanks,

greg k-h


[PATCH v2] Add udmabuf misc device

2018-03-16 Thread Gerd Hoffmann
A driver to let userspace turn iovecs 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.

Those dma-bufs are accounted against user's shm mlock bucket as the
pages are effectively locked in memory.

Cc: David Airlie 
Cc: Tomeu Vizoso 
Cc: Daniel Vetter 
Signed-off-by: Gerd Hoffmann 
---
 include/uapi/linux/udmabuf.h  |  23 ++
 drivers/dma-buf/udmabuf.c | 261 ++
 tools/testing/selftests/drivers/dma-buf/udmabuf.c |  69 ++
 drivers/dma-buf/Kconfig   |   7 +
 drivers/dma-buf/Makefile  |   1 +
 tools/testing/selftests/drivers/dma-buf/Makefile  |   5 +
 6 files changed, 366 insertions(+)
 create mode 100644 include/uapi/linux/udmabuf.h
 create mode 100644 drivers/dma-buf/udmabuf.c
 create mode 100644 tools/testing/selftests/drivers/dma-buf/udmabuf.c
 create mode 100644 tools/testing/selftests/drivers/dma-buf/Makefile

diff --git a/include/uapi/linux/udmabuf.h b/include/uapi/linux/udmabuf.h
new file mode 100644
index 00..54ceba203a
--- /dev/null
+++ b/include/uapi/linux/udmabuf.h
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef _UAPI_LINUX_UDMABUF_H
+#define _UAPI_LINUX_UDMABUF_H
+
+#include 
+#include 
+
+struct udmabuf_iovec {
+   __u64 base;
+   __u64 len;
+};
+
+#define UDMABUF_FLAGS_CLOEXEC  0x01
+
+struct udmabuf_create {
+   __u32 flags;
+   __u32 niov;
+   struct udmabuf_iovec iovs[];
+};
+
+#define UDMABUF_CREATE _IOW(0x42, 0x23, struct udmabuf_create)
+
+#endif /* _UAPI_LINUX_UDMABUF_H */
diff --git a/drivers/dma-buf/udmabuf.c b/drivers/dma-buf/udmabuf.c
new file mode 100644
index 00..664ab4ee4e
--- /dev/null
+++ b/drivers/dma-buf/udmabuf.c
@@ -0,0 +1,261 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include 
+
+struct udmabuf {
+   u32 pagecount;
+   struct page **pages;
+   struct user_struct *owner;
+};
+
+static int udmabuf_vm_fault(struct vm_fault *vmf)
+{
+   struct vm_area_struct *vma = vmf->vma;
+   struct udmabuf *ubuf = vma->vm_private_data;
+
+   if (WARN_ON(vmf->pgoff >= ubuf->pagecount))
+   return VM_FAULT_SIGBUS;
+
+   vmf->page = ubuf->pages[vmf->pgoff];
+   get_page(vmf->page);
+   return 0;
+}
+
+static const struct vm_operations_struct udmabuf_vm_ops = {
+   .fault = udmabuf_vm_fault,
+};
+
+static int mmap_udmabuf(struct dma_buf *buf, struct vm_area_struct *vma)
+{
+   struct udmabuf *ubuf = buf->priv;
+
+   if ((vma->vm_flags & VM_SHARED) == 0)
+   return -EINVAL;
+
+   vma->vm_ops = _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]);
+   user_shm_unlock(ubuf->pagecount << PAGE_SHIFT, ubuf->owner);
+   free_uid(ubuf->owner);
+   kfree(ubuf->pages);
+   kfree(ubuf);
+}
+
+static void *kmap_atomic_udmabuf(struct dma_buf *buf, unsigned long page_num)
+{
+   struct udmabuf *ubuf = buf->priv;
+   struct page *page = ubuf->pages[page_num];
+
+   return kmap_atomic(page);
+}
+
+static void *kmap_udmabuf(struct dma_buf *buf, unsigned long page_num)
+{
+   struct udmabuf *ubuf = buf->priv;
+   struct page *page =