tools/testing/selftests/mm/uffd-stress.c

Source file repositories/reference/linux-study-clean/tools/testing/selftests/mm/uffd-stress.c

File Facts

System
Linux kernel
Corpus path
tools/testing/selftests/mm/uffd-stress.c
Extension
.c
Size
15535 bytes
Lines
522
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 (bounces & BOUNCE_RANDOM) {
			if (getrandom(&page_nr, sizeof(page_nr), 0) != sizeof(page_nr))
				err("getrandom failed");
		} else
			page_nr += 1;
		page_nr %= gopts->nr_pages;
		pthread_mutex_lock(area_mutex(gopts->area_dst, page_nr, gopts));
		count = *area_count(gopts->area_dst, page_nr, gopts);
		if (count != gopts->count_verify[page_nr])
			err("page_nr %lu memory corruption %llu %llu",
			    page_nr, count, gopts->count_verify[page_nr]);
		count++;
		*area_count(gopts->area_dst, page_nr, gopts) = gopts->count_verify[page_nr] = count;
		pthread_mutex_unlock(area_mutex(gopts->area_dst, page_nr, gopts));
	}

	return NULL;
}

static int copy_page_retry(uffd_global_test_opts_t *gopts, unsigned long offset)
{
	return __copy_page(gopts, offset, true, gopts->test_uffdio_wp);
}

pthread_mutex_t uffd_read_mutex = PTHREAD_MUTEX_INITIALIZER;

static void *uffd_read_thread(void *arg)
{
	struct uffd_args *args = (struct uffd_args *)arg;
	uffd_global_test_opts_t *gopts = args->gopts;
	struct uffd_msg msg;

	pthread_mutex_unlock(&uffd_read_mutex);
	/* from here cancellation is ok */

	for (;;) {
		if (uffd_read_msg(gopts, &msg))
			continue;
		uffd_handle_page_fault(gopts, &msg, args);
	}

	return NULL;
}

static void *background_thread(void *arg)
{
	struct uffd_args *args = (struct uffd_args *) arg;
	uffd_global_test_opts_t *gopts = args->gopts;
	unsigned long cpu = (unsigned long) args->cpu;
	unsigned long page_nr, start_nr, mid_nr, end_nr;

	start_nr = cpu * gopts->nr_pages_per_cpu;
	end_nr = (cpu+1) * gopts->nr_pages_per_cpu;
	mid_nr = (start_nr + end_nr) / 2;

	/* Copy the first half of the pages */
	for (page_nr = start_nr; page_nr < mid_nr; page_nr++)
		copy_page_retry(gopts, page_nr * gopts->page_size);

	/*
	 * If we need to test uffd-wp, set it up now.  Then we'll have
	 * at least the first half of the pages mapped already which
	 * can be write-protected for testing
	 */
	if (gopts->test_uffdio_wp)
		wp_range(gopts->uffd, (unsigned long)gopts->area_dst + start_nr * gopts->page_size,
			gopts->nr_pages_per_cpu * gopts->page_size, true);

	/*
	 * Continue the 2nd half of the page copying, handling write
	 * protection faults if any
	 */
	for (page_nr = mid_nr; page_nr < end_nr; page_nr++)
		copy_page_retry(gopts, page_nr * gopts->page_size);

	return NULL;
}

static int stress(struct uffd_args *args)
{
	unsigned long cpu;
	uffd_global_test_opts_t *gopts = args->gopts;
	pthread_t locking_threads[gopts->nr_parallel];
	pthread_t uffd_threads[gopts->nr_parallel];
	pthread_t background_threads[gopts->nr_parallel];

	gopts->finished = 0;
	for (cpu = 0; cpu < gopts->nr_parallel; cpu++) {
		if (pthread_create(&locking_threads[cpu], &attr,
				   locking_thread, (void *)&args[cpu]))

Annotation

Implementation Notes