On Tue, May 13, 2025 at 4:31 AM Christian König
<christian.koe...@amd.com> wrote:
>
> On 5/13/25 11:27, wangtao wrote:
> > Add DMA_BUF_IOCTL_RW_FILE to save/restore data from/to a dma-buf.
>
> Similar approach where rejected before in favor of using udmabuf.
>
> Is there any reason you can't use that approach as well?

I also recently verified that udmabuf + O_DIRECT works with
sendfile(), and you can even MADV_COLLAPSE the underlying shmem if you
want.

> Regards,
> Christian.
>
> >
> > Signed-off-by: wangtao <tao.wang...@honor.com>
> > ---
> >  drivers/dma-buf/dma-buf.c    |  8 ++++++++
> >  include/linux/dma-buf.h      |  3 +++
> >  include/uapi/linux/dma-buf.h | 29 +++++++++++++++++++++++++++++
> >  3 files changed, 40 insertions(+)
> >
> > diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c
> > index 5baa83b85515..95d8b0158ffd 100644
> > --- a/drivers/dma-buf/dma-buf.c
> > +++ b/drivers/dma-buf/dma-buf.c
> > @@ -460,6 +460,7 @@ static long dma_buf_ioctl(struct file *file,
> >       struct dma_buf *dmabuf;
> >       struct dma_buf_sync sync;
> >       enum dma_data_direction direction;
> > +     struct dma_buf_rw_file kfile;
> >       int ret;
> >
> >       dmabuf = file->private_data;
> > @@ -504,6 +505,13 @@ static long dma_buf_ioctl(struct file *file,
> >               return dma_buf_import_sync_file(dmabuf, (const void __user 
> > *)arg);
> >  #endif
> >
> > +     case DMA_BUF_IOCTL_RW_FILE:
> > +             if (copy_from_user(&kfile, (void __user *) arg, 
> > sizeof(kfile)))
> > +                     return -EFAULT;
> > +             if (!dmabuf->ops->rw_file)
> > +                     return -EINVAL;
> > +             return dmabuf->ops->rw_file(dmabuf, &kfile);
> > +
> >       default:
> >               return -ENOTTY;
> >       }
> > diff --git a/include/linux/dma-buf.h b/include/linux/dma-buf.h
> > index 36216d28d8bd..de236ba2094b 100644
> > --- a/include/linux/dma-buf.h
> > +++ b/include/linux/dma-buf.h
> > @@ -22,6 +22,7 @@
> >  #include <linux/fs.h>
> >  #include <linux/dma-fence.h>
> >  #include <linux/wait.h>
> > +#include <uapi/linux/dma-buf.h>
> >
> >  struct device;
> >  struct dma_buf;
> > @@ -285,6 +286,8 @@ struct dma_buf_ops {
> >
> >       int (*vmap)(struct dma_buf *dmabuf, struct iosys_map *map);
> >       void (*vunmap)(struct dma_buf *dmabuf, struct iosys_map *map);
> > +
> > +     int (*rw_file)(struct dma_buf *dmabuf, struct dma_buf_rw_file *file);
> >  };
> >
> >  /**
> > diff --git a/include/uapi/linux/dma-buf.h b/include/uapi/linux/dma-buf.h
> > index 5a6fda66d9ad..ec9164b7b753 100644
> > --- a/include/uapi/linux/dma-buf.h
> > +++ b/include/uapi/linux/dma-buf.h
> > @@ -167,6 +167,29 @@ struct dma_buf_import_sync_file {
> >       __s32 fd;
> >  };
> >
> > +/**
> > + * struct dma_buf_rw_file - read/write file associated with a dma-buf
> > + *
> > + * Userspace can performs a DMA_BUF_IOCTL_BACK to save data from a dma-buf 
> > or
> > + * restore data to a dma-buf.
> > + */
> > +struct dma_buf_rw_file {
> > +
> > +     /** @flags: Flags indicating read/write for this dma-buf. */
> > +     __u32 flags;
> > +     /** @fd: File descriptor of the file associated with this dma-buf. */
> > +     __s32 fd;
> > +     /** @file_offset: Offset within the file where this dma-buf starts.
> > +      *
> > +      *  Offset and Length must be page-aligned for direct I/O.
> > +      */
> > +     __u64 file_offset;
> > +     /** @buf_offset: Offset within this dma-buf where the read/write 
> > starts. */
> > +     __u64 buf_offset;
> > +     /** @buf_len: Length of this dma-buf read/write. */
> > +     __u64 buf_len;
> > +};
> > +
> >  #define DMA_BUF_BASE         'b'
> >  #define DMA_BUF_IOCTL_SYNC   _IOW(DMA_BUF_BASE, 0, struct dma_buf_sync)
> >
> > @@ -179,4 +202,10 @@ struct dma_buf_import_sync_file {
> >  #define DMA_BUF_IOCTL_EXPORT_SYNC_FILE       _IOWR(DMA_BUF_BASE, 2, struct 
> > dma_buf_export_sync_file)
> >  #define DMA_BUF_IOCTL_IMPORT_SYNC_FILE       _IOW(DMA_BUF_BASE, 3, struct 
> > dma_buf_import_sync_file)
> >
> > +#define DMA_BUF_RW_FLAGS_OP_MASK (0xFF << 0)
> > +#define DMA_BUF_RW_FLAGS_READ (1 << 0) /* Restore dma-buf data */
> > +#define DMA_BUF_RW_FLAGS_WRITE (2 << 0) /* Save dma-buf data */
> > +#define DMA_BUF_RW_FLAGS_DIRECT (1u << 31) /* Direct read/write file */
> > +#define DMA_BUF_IOCTL_RW_FILE        _IOW(DMA_BUF_BASE, 4, struct 
> > dma_buf_rw_file)
> > +
> >  #endif
>
#include <cstdlib>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/sendfile.h>
#include <unistd.h>

#include <linux/udmabuf.h>

namespace {

int createMemfd(size_t bytes, unsigned int flags) {

    int fd(memfd_create("memfd_test", flags));
    if (fd == -1) {
        perror("memfd_create");
        return -1;
    }

    int rc = ftruncate(fd, bytes);
    if (rc == -1) {
        perror("ftruncate");
        return -1;
    }

    return fd;
}

int createUdmabuf(size_t bytes, int memfd) {
    int udmabuf_dev_fd(open("/dev/udmabuf", O_RDONLY));
    if (udmabuf_dev_fd == -1) {
        perror("udmabuf open");
        return -1;
    }

    struct udmabuf_create create;
    create.memfd = memfd;
    create.flags = UDMABUF_FLAGS_CLOEXEC;
    create.offset = 0;
    create.size = bytes;

    int dmabuf_fd(ioctl(udmabuf_dev_fd, UDMABUF_CREATE, &create));
    if (dmabuf_fd == -1) perror("UDMABUF_CREATE");

    return dmabuf_fd;
}

} // anonymous namespace


int main(int argc, char **argv) {
	size_t bytes = 1ull << 30;

	int memfd = createMemfd(bytes, MFD_ALLOW_SEALING);
	if (memfd < 0) return EXIT_FAILURE;

	if (fcntl(memfd, F_ADD_SEALS, F_SEAL_SHRINK) < 0) {
		perror("F_SEAL_SHRINK");
		return EXIT_FAILURE;
	}

    if (ftruncate(memfd, bytes)) {
        perror("ftruncate");
        return EXIT_FAILURE;
    }

    int bigfile = open(argv[1], O_RDONLY | O_DIRECT);
    if (bigfile < 0) {
        perror("open");
        return EXIT_FAILURE;
    }

    off_t offset = 0;
    for (ssize_t n = sendfile(memfd, bigfile, &offset, bytes - offset);
         offset < bytes && n > 0;
         n = sendfile(memfd, bigfile, &offset, bytes - offset))
    {}
    printf("Offset %ld\n", offset);

    int udmabuf = createUdmabuf(bytes, memfd);
    if (udmabuf < 0) return EXIT_FAILURE;

    return EXIT_SUCCESS;
}

Reply via email to