[PATCH v1 0/2] udmabuf: Add back support for mapping hugetlb pages

Mike Kravetz mike.kravetz at oracle.com
Thu Jun 22 21:33:44 UTC 2023


On 06/22/23 10:25, David Hildenbrand wrote:
> On 22.06.23 09:27, Vivek Kasireddy wrote:
> 
> There are *probably* more issues on the QEMU side when udmabuf is paired
> with things like MADV_DONTNEED/FALLOC_FL_PUNCH_HOLE used for virtio-balloon,
> virtio-mem, postcopy live migration, ... for example, in the vfio/vdpa case
> we make sure that we disallow most of these, because otherwise there can be
> an accidental "disconnect" between the pages mapped into the VM (guest view)
> and the pages mapped into the IOMMU (device view), for example, after a
> reboot.
> 

Yes, this "disconnect" is still possible.  Attached is a test program I
hacked up based on the udmabuf selftest.  You can see different content
in the memfd pages and udma pages.

FYI- I can verify this new udmabuf code is not accessing struct pages of
hugetlb tail pages, as this test program BUG'ed if hugetlb vmemmap
optimization was enabled in the old udmabuf.
-- 
Mike Kravetz
-------------- next part --------------
// SPDX-License-Identifier: GPL-2.0
#define _GNU_SOURCE
#define __EXPORTED_HEADERS__

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <malloc.h>
#include <sys/mman.h>

#include <sys/ioctl.h>
#include <sys/syscall.h>
#include <linux/memfd.h>
#include <linux/udmabuf.h>

#define TEST_PREFIX	"drivers/dma-buf/udmabuf"
#define NUM_PAGES       2

static int my_getpagesize(void)
{
	/* huge page size */
	return getpagesize() * 512;
}

#if 0
static int memfd_create(const char *name, unsigned int flags)
{
	return syscall(__NR_memfd_create, name, flags);
}
#endif

int main(int argc, char *argv[])
{
	struct udmabuf_create create;
	int devfd, memfd, buf, ret;
	off_t size;
	void *mem;
	int i;
	char foo;
	int mem_fd, udma_fd;
	void *addr1, *addr2;

	devfd = open("/dev/udmabuf", O_RDWR);
	if (devfd < 0) {
		printf("%s: [skip,no-udmabuf: Unable to access DMA buffer device file]\n",
		       TEST_PREFIX);
		exit(77);
	}

	mem_fd = memfd_create("udmabuf-test", MFD_HUGETLB | MFD_ALLOW_SEALING);
	if (mem_fd < 0) {
		printf("%s: [skip,no-memfd]\n", TEST_PREFIX);
		exit(77);
	}

	ret = fcntl(mem_fd, F_ADD_SEALS, F_SEAL_SHRINK);
	if (ret < 0) {
		printf("%s: [skip,fcntl-add-seals]\n", TEST_PREFIX);
		exit(77);
	}


	size = my_getpagesize() * NUM_PAGES;
	ret = ftruncate(mem_fd, size);

	if (ret == -1) {
		printf("%s: [FAIL,memfd-truncate]\n", TEST_PREFIX);
		exit(1);
	}

	/* touch all pages */
	addr1 = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, mem_fd, 0);
	if (addr1 == MAP_FAILED) {
		printf("%s: [FAIL,mmap]\n", TEST_PREFIX);
		exit(1);
	}

	for (i = 0; i < size / getpagesize(); i++) {
		*((char *)addr1 + (i * getpagesize())) = 'a';
	}

	memset(&create, 0, sizeof(create));

#if 0
	/* should fail (offset not page aligned) */
	create.memfd  = mem_fd;
	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  = mem_fd;
	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);
	}
#endif

	/* should work */
	create.memfd  = mem_fd;
	create.offset = getpagesize() * 256;
	create.size   = getpagesize() * 4;
	udma_fd = ioctl(devfd, UDMABUF_CREATE, &create);
	if (udma_fd < 0) {
		perror("UDMABUF_CREATE");
		printf("%s: [FAIL,test-4]\n", TEST_PREFIX);
		exit(1);
	}

	printf("before hole punch\n");
	(void)getchar();
	ret = fallocate(mem_fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
		0, my_getpagesize());
	if (ret)
		perror("fallocate punch hole");
	printf("after hole punch\n");
	(void)getchar();

	for (i = 0; i < size / getpagesize(); i++) {
		*((char *)addr1 + (i * getpagesize())) = 'b';
	}

	printf("after touch again\n");
	(void)getchar();

	/* touch all pages */
	addr2 = mmap(NULL, getpagesize() * 4, PROT_READ|PROT_WRITE, MAP_SHARED, udma_fd, 0);
	if (addr2 == MAP_FAILED) {
		perror("mmap");
		printf("%s: udma_fd mmap fail\n", TEST_PREFIX);
		exit(1);
	}

	for (i = 0; i < 4; i++) {
		foo = *((char *)addr2 + (i * getpagesize()));
		printf("udmabuf %c\n", foo);
	}

	for (i = 256; i < 260; i++) {
		foo = *((char *)addr1 + (i * getpagesize()));
		printf("memfd %c\n", foo);
	}

	fprintf(stderr, "%s: ok\n", TEST_PREFIX);
	close(udma_fd);
	close(mem_fd);
	close(devfd);
	return 0;
}


More information about the dri-devel mailing list