[v7] Add udmabuf misc device

Gurchetan Singh gurchetansingh at chromium.org
Thu Sep 13 03:24:00 UTC 2018


On Wed, Sep 12, 2018 at 12:03 AM Yann Droneaud <ydroneaud at opteya.com> wrote:
>
> Hi,
>
> Le lundi 27 août 2018 à 11:34 +0200, Gerd Hoffmann a écrit :
> > 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.

Something like this is definitely needed.  I assume one flow will be:

1) guest compositor allocates a buffer using udmabuf
2) 3D driver imports the udmabuf and renders to it
3) qemu turns this udmabuf into a host dma-buf
4) host compositor displays this dma-buf

In that case, how does the guest know about the host's stride /
alignment restrictions?  For example, x-tiling on Intel (good for
display) needs to have a stride that's a multiple of 512 bytes.

> >
> > qemu test branch:
> >   https://git.kraxel.org/cgit/qemu/log/?h=sirius/udmabuf
> >
> > Cc: David Airlie <airlied at linux.ie>
> > Cc: Tomeu Vizoso <tomeu.vizoso at collabora.com>
> > Cc: Laurent Pinchart <laurent.pinchart at ideasonboard.com>
> > Cc: Daniel Vetter <daniel at ffwll.ch>
> > Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
> > Acked-by: Daniel Vetter <daniel.vetter at ffwll.ch>
> > ---
> >  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                                       |  16 ++
> >  drivers/dma-buf/Kconfig                           |   8 +
> >  drivers/dma-buf/Makefile                          |   1 +
> >  tools/testing/selftests/drivers/dma-buf/Makefile  |   5 +
> >  8 files changed, 447 insertions(+)
> >  create mode 100644 include/uapi/linux/udmabuf.h
> >  create mode 100644 drivers/dma-buf/udmabuf.c
> >  create mode 100644 tools/testing/selftests/drivers/dma-buf/udmabuf.c
> >  create mode 100644 tools/testing/selftests/drivers/dma-buf/Makefile
> >
> > diff --git a/include/uapi/linux/udmabuf.h
> > b/include/uapi/linux/udmabuf.h
> > new file mode 100644
> > index 0000000000..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 <linux/types.h>
> > +#include <linux/ioctl.h>
> > +
> > +#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
> > +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++) {
>
> You need to check .__pad for unsupported value:
>
>                 if (list[i].__pad) {
>                         ret = -EINVAL;
>                         goto err_free_ubuf;
>                 }
>
> > +             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;
>
> You need to check .flags for unsupported value:
>
>         if (head->flags & ~UDMABUF_FLAGS_CLOEXEC)
>                  return -EINVAL;
>
> (at the beginning of the function, of course).
>
> > +     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;
> > +}
> > +
>
> Regards
>
> --
> Yann Droneaud
> OPTEYA
>
>
> _______________________________________________
> dri-devel mailing list
> dri-devel at lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel


More information about the dri-devel mailing list