tools/testing/selftests/kvm/lib/userfaultfd_util.c

Source file repositories/reference/linux-study-clean/tools/testing/selftests/kvm/lib/userfaultfd_util.c

File Facts

System
Linux kernel
Corpus path
tools/testing/selftests/kvm/lib/userfaultfd_util.c
Extension
.c
Size
5877 bytes
Lines
207
Domain
Support Tooling And Documentation
Bucket
tools
Inferred role
Support Tooling And Documentation: implementation source
Status
source implementation candidate

Why This File Exists

Repository support layer: documentation, build tooling, samples, user-space helper tools, generated initramfs support, licenses, and validation utilities.

Dependency Surface

Detected Declarations

Annotated Snippet

if (evt.data.u32 == 1) {
			char tmp_chr;

			TEST_ASSERT(!(evt.events & (EPOLLERR | EPOLLHUP)),
				    "Reader thread received EPOLLERR or EPOLLHUP on pipe.");
			r = read(reader_args->pipe, &tmp_chr, 1);
			TEST_ASSERT(r == 1,
				    "Error reading pipefd in uffd reader thread");
			break;
		}

		TEST_ASSERT(!(evt.events & (EPOLLERR | EPOLLHUP)),
			    "Reader thread received EPOLLERR or EPOLLHUP on uffd.");

		r = read(uffd, &msg, sizeof(msg));
		if (r == -1) {
			TEST_ASSERT(errno == EAGAIN,
				    "Error reading from UFFD: errno = %d", errno);
			continue;
		}

		TEST_ASSERT(r == sizeof(msg),
			    "Read on uffd returned unexpected number of bytes (%d)", r);

		if (!(msg.event & UFFD_EVENT_PAGEFAULT))
			continue;

		if (reader_args->delay)
			usleep(reader_args->delay);
		r = reader_args->handler(reader_args->uffd_mode, uffd, &msg);
		TEST_ASSERT(r >= 0,
			    "Reader thread handler fn returned negative value %d", r);
		pages++;
	}

	ts_diff = timespec_elapsed(start);
	PER_VCPU_DEBUG("userfaulted %ld pages over %ld.%.9lds. (%f/sec)\n",
		       pages, ts_diff.tv_sec, ts_diff.tv_nsec,
		       pages / ((double)ts_diff.tv_sec + (double)ts_diff.tv_nsec / NSEC_PER_SEC));

	return NULL;
}

struct uffd_desc *uffd_setup_demand_paging(int uffd_mode, useconds_t delay,
					   void *hva, u64 len,
					   u64 num_readers,
					   uffd_handler_t handler)
{
	struct uffd_desc *uffd_desc;
	bool is_minor = (uffd_mode == UFFDIO_REGISTER_MODE_MINOR);
	int uffd;
	struct uffdio_api uffdio_api;
	struct uffdio_register uffdio_register;
	u64 expected_ioctls = ((u64)1) << _UFFDIO_COPY;
	int ret, i;

	PER_PAGE_DEBUG("Userfaultfd %s mode, faults resolved with %s\n",
		       is_minor ? "MINOR" : "MISSING",
		       is_minor ? "UFFDIO_CONTINUE" : "UFFDIO_COPY");

	uffd_desc = malloc(sizeof(struct uffd_desc));
	TEST_ASSERT(uffd_desc, "Failed to malloc uffd descriptor");

	uffd_desc->pipefds = calloc(sizeof(int), num_readers);
	TEST_ASSERT(uffd_desc->pipefds, "Failed to alloc pipes");

	uffd_desc->readers = calloc(sizeof(pthread_t), num_readers);
	TEST_ASSERT(uffd_desc->readers, "Failed to alloc reader threads");

	uffd_desc->reader_args = calloc(sizeof(struct uffd_reader_args), num_readers);
	TEST_ASSERT(uffd_desc->reader_args, "Failed to alloc reader_args");

	uffd_desc->num_readers = num_readers;

	/* In order to get minor faults, prefault via the alias. */
	if (is_minor)
		expected_ioctls = ((u64)1) << _UFFDIO_CONTINUE;

	uffd = syscall(__NR_userfaultfd, O_CLOEXEC | O_NONBLOCK);
	TEST_ASSERT(uffd >= 0, "uffd creation failed, errno: %d", errno);

	uffdio_api.api = UFFD_API;
	uffdio_api.features = 0;
	TEST_ASSERT(ioctl(uffd, UFFDIO_API, &uffdio_api) != -1,
		    "ioctl UFFDIO_API failed: %" PRIu64,
		    (u64)uffdio_api.api);

	uffdio_register.range.start = (u64)hva;
	uffdio_register.range.len = len;
	uffdio_register.mode = uffd_mode;

Annotation

Implementation Notes