tools/testing/selftests/mm/mkdirty.c

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

File Facts

System
Linux kernel
Corpus path
tools/testing/selftests/mm/mkdirty.c
Extension
.c
Size
9064 bytes
Lines
381
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

// SPDX-License-Identifier: GPL-2.0-only
/*
 * Test handling of code that might set PTE/PMD dirty in read-only VMAs.
 * Setting a PTE/PMD dirty must not accidentally set the PTE/PMD writable.
 *
 * Copyright 2023, Red Hat, Inc.
 *
 * Author(s): David Hildenbrand <david@redhat.com>
 */
#include <fcntl.h>
#include <signal.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <stdbool.h>
#include <stdint.h>
#include <sys/mman.h>
#include <setjmp.h>
#include <sys/syscall.h>
#include <sys/ioctl.h>
#include <linux/userfaultfd.h>
#include <linux/mempolicy.h>

#include "kselftest.h"
#include "vm_util.h"

static size_t pagesize;
static size_t thpsize;
static int mem_fd;
static int pagemap_fd;
static sigjmp_buf env;

static void signal_handler(int sig)
{
	if (sig == SIGSEGV)
		siglongjmp(env, 1);
	siglongjmp(env, 2);
}

static void do_test_write_sigsegv(char *mem)
{
	char orig = *mem;
	int ret;

	if (signal(SIGSEGV, signal_handler) == SIG_ERR) {
		ksft_test_result_fail("signal() failed\n");
		return;
	}

	ret = sigsetjmp(env, 1);
	if (!ret)
		*mem = orig + 1;

	if (signal(SIGSEGV, SIG_DFL) == SIG_ERR)
		ksft_test_result_fail("signal() failed\n");

	ksft_test_result(ret == 1 && *mem == orig,
			 "SIGSEGV generated, page not modified\n");
}

static char *mmap_thp_range(int prot, char **_mmap_mem, size_t *_mmap_size)
{
	const size_t mmap_size = 2 * thpsize;
	char *mem, *mmap_mem;

	mmap_mem = mmap(NULL, mmap_size, prot, MAP_PRIVATE|MAP_ANON,
			-1, 0);
	if (mmap_mem == MAP_FAILED) {
		ksft_test_result_fail("mmap() failed\n");
		return MAP_FAILED;
	}
	mem = (char *)(((uintptr_t)mmap_mem + thpsize) & ~(thpsize - 1));

	if (madvise(mem, thpsize, MADV_HUGEPAGE)) {
		ksft_test_result_skip("MADV_HUGEPAGE failed\n");
		munmap(mmap_mem, mmap_size);
		return MAP_FAILED;
	}

	*_mmap_mem = mmap_mem;
	*_mmap_size = mmap_size;
	return mem;
}

static void test_ptrace_write(void)
{
	char data = 1;
	char *mem;
	int ret;

Annotation

Implementation Notes