Commit 16c243e9 authored by Vivek Kasireddy's avatar Vivek Kasireddy Committed by Gerd Hoffmann

udmabuf: Add support for mapping hugepages (v4)

If the VMM's (Qemu) memory backend is backed up by memfd + Hugepages
(hugetlbfs and not THP), we have to first find the hugepage(s) where
the Guest allocations are located and then extract the regular 4k
sized subpages from them.

v2: Ensure that the subpage and hugepage offsets are calculated correctly
when the range of subpage allocations cuts across multiple hugepages.

v3: Instead of repeatedly looking up the hugepage for each subpage,
only do it when the subpage allocation crosses over into a different
hugepage. (suggested by Gerd and DW)

v4: Fix the following warning identified by checkpatch:
CHECK:OPEN_ENDED_LINE: Lines should not end with a '('

Cc: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: default avatarVivek Kasireddy <vivek.kasireddy@intel.com>
Signed-off-by: default avatarDongwon Kim <dongwon.kim@intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/20210609182915.592743-1-vivek.kasireddy@intel.com
[ kraxel: one more checkpatch format tweak ]
Signed-off-by: default avatarGerd Hoffmann <kraxel@redhat.com>
parent 6eca310e
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include <linux/shmem_fs.h> #include <linux/shmem_fs.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/udmabuf.h> #include <linux/udmabuf.h>
#include <linux/hugetlb.h>
static const u32 list_limit = 1024; /* udmabuf_create_list->count limit */ static const u32 list_limit = 1024; /* udmabuf_create_list->count limit */
static const size_t size_limit_mb = 64; /* total dmabuf size, in megabytes */ static const size_t size_limit_mb = 64; /* total dmabuf size, in megabytes */
...@@ -160,10 +161,13 @@ static long udmabuf_create(struct miscdevice *device, ...@@ -160,10 +161,13 @@ static long udmabuf_create(struct miscdevice *device,
{ {
DEFINE_DMA_BUF_EXPORT_INFO(exp_info); DEFINE_DMA_BUF_EXPORT_INFO(exp_info);
struct file *memfd = NULL; struct file *memfd = NULL;
struct address_space *mapping = NULL;
struct udmabuf *ubuf; struct udmabuf *ubuf;
struct dma_buf *buf; struct dma_buf *buf;
pgoff_t pgoff, pgcnt, pgidx, pgbuf = 0, pglimit; pgoff_t pgoff, pgcnt, pgidx, pgbuf = 0, pglimit;
struct page *page; struct page *page, *hpage = NULL;
pgoff_t subpgoff, maxsubpgs;
struct hstate *hpstate;
int seals, ret = -EINVAL; int seals, ret = -EINVAL;
u32 i, flags; u32 i, flags;
...@@ -194,7 +198,8 @@ static long udmabuf_create(struct miscdevice *device, ...@@ -194,7 +198,8 @@ static long udmabuf_create(struct miscdevice *device,
memfd = fget(list[i].memfd); memfd = fget(list[i].memfd);
if (!memfd) if (!memfd)
goto err; goto err;
if (!shmem_mapping(file_inode(memfd)->i_mapping)) mapping = file_inode(memfd)->i_mapping;
if (!shmem_mapping(mapping) && !is_file_hugepages(memfd))
goto err; goto err;
seals = memfd_fcntl(memfd, F_GET_SEALS, 0); seals = memfd_fcntl(memfd, F_GET_SEALS, 0);
if (seals == -EINVAL) if (seals == -EINVAL)
...@@ -205,17 +210,48 @@ static long udmabuf_create(struct miscdevice *device, ...@@ -205,17 +210,48 @@ static long udmabuf_create(struct miscdevice *device,
goto err; goto err;
pgoff = list[i].offset >> PAGE_SHIFT; pgoff = list[i].offset >> PAGE_SHIFT;
pgcnt = list[i].size >> PAGE_SHIFT; pgcnt = list[i].size >> PAGE_SHIFT;
if (is_file_hugepages(memfd)) {
hpstate = hstate_file(memfd);
pgoff = list[i].offset >> huge_page_shift(hpstate);
subpgoff = (list[i].offset &
~huge_page_mask(hpstate)) >> PAGE_SHIFT;
maxsubpgs = huge_page_size(hpstate) >> PAGE_SHIFT;
}
for (pgidx = 0; pgidx < pgcnt; pgidx++) { for (pgidx = 0; pgidx < pgcnt; pgidx++) {
page = shmem_read_mapping_page( if (is_file_hugepages(memfd)) {
file_inode(memfd)->i_mapping, pgoff + pgidx); if (!hpage) {
if (IS_ERR(page)) { hpage = find_get_page_flags(mapping, pgoff,
ret = PTR_ERR(page); FGP_ACCESSED);
goto err; if (IS_ERR(hpage)) {
ret = PTR_ERR(hpage);
goto err;
}
}
page = hpage + subpgoff;
get_page(page);
subpgoff++;
if (subpgoff == maxsubpgs) {
put_page(hpage);
hpage = NULL;
subpgoff = 0;
pgoff++;
}
} else {
page = shmem_read_mapping_page(mapping,
pgoff + pgidx);
if (IS_ERR(page)) {
ret = PTR_ERR(page);
goto err;
}
} }
ubuf->pages[pgbuf++] = page; ubuf->pages[pgbuf++] = page;
} }
fput(memfd); fput(memfd);
memfd = NULL; memfd = NULL;
if (hpage) {
put_page(hpage);
hpage = NULL;
}
} }
exp_info.ops = &udmabuf_ops; exp_info.ops = &udmabuf_ops;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment