tools/testing/selftests/kvm/demand_paging_test.c

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

File Facts

System
Linux kernel
Corpus path
tools/testing/selftests/kvm/demand_paging_test.c
Extension
.c
Size
10413 bytes
Lines
361
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

struct test_params {
	int uffd_mode;
	bool single_uffd;
	useconds_t uffd_delay;
	int readers_per_uffd;
	enum vm_mem_backing_src_type src_type;
	bool partition_vcpu_memory_access;
};

static void prefault_mem(void *alias, u64 len)
{
	size_t p;

	TEST_ASSERT(alias != NULL, "Alias required for minor faults");
	for (p = 0; p < (len / demand_paging_size); ++p) {
		memcpy(alias + (p * demand_paging_size),
		       guest_data_prototype, demand_paging_size);
	}
}

static void run_test(enum vm_guest_mode mode, void *arg)
{
	struct memstress_vcpu_args *vcpu_args;
	struct test_params *p = arg;
	struct uffd_desc **uffd_descs = NULL;
	u64 uffd_region_size;
	struct timespec start;
	struct timespec ts_diff;
	double vcpu_paging_rate;
	struct kvm_vm *vm;
	int i, num_uffds = 0;

	vm = memstress_create_vm(mode, nr_vcpus, guest_percpu_mem_size, 1,
				 p->src_type, p->partition_vcpu_memory_access);

	demand_paging_size = get_backing_src_pagesz(p->src_type);

	guest_data_prototype = malloc(demand_paging_size);
	TEST_ASSERT(guest_data_prototype,
		    "Failed to allocate buffer for guest data pattern");
	memset(guest_data_prototype, 0xAB, demand_paging_size);

	if (p->uffd_mode == UFFDIO_REGISTER_MODE_MINOR) {
		num_uffds = p->single_uffd ? 1 : nr_vcpus;
		for (i = 0; i < num_uffds; i++) {
			vcpu_args = &memstress_args.vcpu_args[i];
			prefault_mem(addr_gpa2alias(vm, vcpu_args->gpa),
				     vcpu_args->pages * memstress_args.guest_page_size);
		}
	}

	if (p->uffd_mode) {
		num_uffds = p->single_uffd ? 1 : nr_vcpus;
		uffd_region_size = nr_vcpus * guest_percpu_mem_size / num_uffds;

		uffd_descs = malloc(num_uffds * sizeof(struct uffd_desc *));
		TEST_ASSERT(uffd_descs, "Memory allocation failed");
		for (i = 0; i < num_uffds; i++) {
			struct memstress_vcpu_args *vcpu_args;
			void *vcpu_hva;

			vcpu_args = &memstress_args.vcpu_args[i];

			/* Cache the host addresses of the region */
			vcpu_hva = addr_gpa2hva(vm, vcpu_args->gpa);
			/*
			 * Set up user fault fd to handle demand paging
			 * requests.
			 */
			uffd_descs[i] = uffd_setup_demand_paging(
				p->uffd_mode, p->uffd_delay, vcpu_hva,
				uffd_region_size,
				p->readers_per_uffd,
				&handle_uffd_page_request);
		}
	}

	pr_info("Finished creating vCPUs and starting uffd threads\n");

	clock_gettime(CLOCK_MONOTONIC, &start);
	memstress_start_vcpu_threads(nr_vcpus, vcpu_worker);
	pr_info("Started all vCPUs\n");

	memstress_join_vcpu_threads(nr_vcpus);
	ts_diff = timespec_elapsed(start);
	pr_info("All vCPU threads joined\n");

	if (p->uffd_mode) {
		/* Tell the user fault fd handler threads to quit */
		for (i = 0; i < num_uffds; i++)

Annotation

Implementation Notes