tools/testing/selftests/kvm/pre_fault_memory_test.c

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

File Facts

System
Linux kernel
Corpus path
tools/testing/selftests/kvm/pre_fault_memory_test.c
Extension
.c
Size
5976 bytes
Lines
231
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 slot_worker_data {
	struct kvm_vm *vm;
	gpa_t gpa;
	u32 flags;
	bool worker_ready;
	bool prefault_ready;
	bool recreate_slot;
};

static void *delete_slot_worker(void *__data)
{
	struct slot_worker_data *data = __data;
	struct kvm_vm *vm = data->vm;

	WRITE_ONCE(data->worker_ready, true);

	while (!READ_ONCE(data->prefault_ready))
		cpu_relax();

	vm_mem_region_delete(vm, TEST_SLOT);

	while (!READ_ONCE(data->recreate_slot))
		cpu_relax();

	vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS, data->gpa,
				    TEST_SLOT, TEST_NPAGES, data->flags);

	return NULL;
}

static void pre_fault_memory(struct kvm_vcpu *vcpu, u64 base_gpa, u64 offset,
			     u64 size, u64 expected_left, bool private)
{
	struct kvm_pre_fault_memory range = {
		.gpa = base_gpa + offset,
		.size = size,
		.flags = 0,
	};
	struct slot_worker_data data = {
		.vm = vcpu->vm,
		.gpa = base_gpa,
		.flags = private ? KVM_MEM_GUEST_MEMFD : 0,
	};
	bool slot_recreated = false;
	pthread_t slot_worker;
	int ret, save_errno;
	u64 prev;

	/*
	 * Concurrently delete (and recreate) the slot to test KVM's handling
	 * of a racing memslot deletion with prefaulting.
	 */
	pthread_create(&slot_worker, NULL, delete_slot_worker, &data);

	while (!READ_ONCE(data.worker_ready))
		cpu_relax();

	WRITE_ONCE(data.prefault_ready, true);

	for (;;) {
		prev = range.size;
		ret = __vcpu_ioctl(vcpu, KVM_PRE_FAULT_MEMORY, &range);
		save_errno = errno;
		TEST_ASSERT((range.size < prev) ^ (ret < 0),
			    "%sexpecting range.size to change on %s",
			    ret < 0 ? "not " : "",
			    ret < 0 ? "failure" : "success");

		/*
		 * Immediately retry prefaulting if KVM was interrupted by an
		 * unrelated signal/event.
		 */
		if (ret < 0 && save_errno == EINTR)
			continue;

		/*
		 * Tell the worker to recreate the slot in order to complete
		 * prefaulting (if prefault didn't already succeed before the
		 * slot was deleted) and/or to prepare for the next testcase.
		 * Wait for the worker to exit so that the next invocation of
		 * prefaulting is guaranteed to complete (assuming no KVM bugs).
		 */
		if (!slot_recreated) {
			WRITE_ONCE(data.recreate_slot, true);
			pthread_join(slot_worker, NULL);
			slot_recreated = true;

			/*
			 * Retry prefaulting to get a stable result, i.e. to
			 * avoid seeing random EAGAIN failures.  Don't retry if

Annotation

Implementation Notes