brintos

brintos / linux-shallow public Read only

0
0
Text · 5.5 KiB · bdfa5d0 Raw
214 lines · c
1// SPDX-License-Identifier: GPL-2.02#include <stdio.h>3#include <string.h>4#include <stdbool.h>5#include <fcntl.h>6#include <stdint.h>7#include <malloc.h>8#include <sys/mman.h>9#include "../kselftest.h"10#include "vm_util.h"11 12#define PAGEMAP_FILE_PATH "/proc/self/pagemap"13#define TEST_ITERATIONS 1000014 15static void test_simple(int pagemap_fd, int pagesize)16{17	int i;18	char *map;19 20	map = aligned_alloc(pagesize, pagesize);21	if (!map)22		ksft_exit_fail_msg("mmap failed\n");23 24	clear_softdirty();25 26	for (i = 0 ; i < TEST_ITERATIONS; i++) {27		if (pagemap_is_softdirty(pagemap_fd, map) == 1) {28			ksft_print_msg("dirty bit was 1, but should be 0 (i=%d)\n", i);29			break;30		}31 32		clear_softdirty();33		// Write something to the page to get the dirty bit enabled on the page34		map[0]++;35 36		if (pagemap_is_softdirty(pagemap_fd, map) == 0) {37			ksft_print_msg("dirty bit was 0, but should be 1 (i=%d)\n", i);38			break;39		}40 41		clear_softdirty();42	}43	free(map);44 45	ksft_test_result(i == TEST_ITERATIONS, "Test %s\n", __func__);46}47 48static void test_vma_reuse(int pagemap_fd, int pagesize)49{50	char *map, *map2;51 52	map = mmap(NULL, pagesize, (PROT_READ | PROT_WRITE), (MAP_PRIVATE | MAP_ANON), -1, 0);53	if (map == MAP_FAILED)54		ksft_exit_fail_msg("mmap failed");55 56	// The kernel always marks new regions as soft dirty57	ksft_test_result(pagemap_is_softdirty(pagemap_fd, map) == 1,58			 "Test %s dirty bit of allocated page\n", __func__);59 60	clear_softdirty();61	munmap(map, pagesize);62 63	map2 = mmap(NULL, pagesize, (PROT_READ | PROT_WRITE), (MAP_PRIVATE | MAP_ANON), -1, 0);64	if (map2 == MAP_FAILED)65		ksft_exit_fail_msg("mmap failed");66 67	// Dirty bit is set for new regions even if they are reused68	if (map == map2)69		ksft_test_result(pagemap_is_softdirty(pagemap_fd, map2) == 1,70				 "Test %s dirty bit of reused address page\n", __func__);71	else72		ksft_test_result_skip("Test %s dirty bit of reused address page\n", __func__);73 74	munmap(map2, pagesize);75}76 77static void test_hugepage(int pagemap_fd, int pagesize)78{79	char *map;80	int i, ret;81	size_t hpage_len = read_pmd_pagesize();82 83	if (!hpage_len)84		ksft_exit_fail_msg("Reading PMD pagesize failed");85 86	map = memalign(hpage_len, hpage_len);87	if (!map)88		ksft_exit_fail_msg("memalign failed\n");89 90	ret = madvise(map, hpage_len, MADV_HUGEPAGE);91	if (ret)92		ksft_exit_fail_msg("madvise failed %d\n", ret);93 94	for (i = 0; i < hpage_len; i++)95		map[i] = (char)i;96 97	if (check_huge_anon(map, 1, hpage_len)) {98		ksft_test_result_pass("Test %s huge page allocation\n", __func__);99 100		clear_softdirty();101		for (i = 0 ; i < TEST_ITERATIONS ; i++) {102			if (pagemap_is_softdirty(pagemap_fd, map) == 1) {103				ksft_print_msg("dirty bit was 1, but should be 0 (i=%d)\n", i);104				break;105			}106 107			clear_softdirty();108			// Write something to the page to get the dirty bit enabled on the page109			map[0]++;110 111			if (pagemap_is_softdirty(pagemap_fd, map) == 0) {112				ksft_print_msg("dirty bit was 0, but should be 1 (i=%d)\n", i);113				break;114			}115			clear_softdirty();116		}117 118		ksft_test_result(i == TEST_ITERATIONS, "Test %s huge page dirty bit\n", __func__);119	} else {120		// hugepage allocation failed. skip these tests121		ksft_test_result_skip("Test %s huge page allocation\n", __func__);122		ksft_test_result_skip("Test %s huge page dirty bit\n", __func__);123	}124	free(map);125}126 127static void test_mprotect(int pagemap_fd, int pagesize, bool anon)128{129	const char *type[] = {"file", "anon"};130	const char *fname = "./soft-dirty-test-file";131	int test_fd;132	char *map;133 134	if (anon) {135		map = mmap(NULL, pagesize, PROT_READ|PROT_WRITE,136			   MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);137		if (!map)138			ksft_exit_fail_msg("anon mmap failed\n");139	} else {140		test_fd = open(fname, O_RDWR | O_CREAT, 0664);141		if (test_fd < 0) {142			ksft_test_result_skip("Test %s open() file failed\n", __func__);143			return;144		}145		unlink(fname);146		ftruncate(test_fd, pagesize);147		map = mmap(NULL, pagesize, PROT_READ|PROT_WRITE,148			   MAP_SHARED, test_fd, 0);149		if (!map)150			ksft_exit_fail_msg("file mmap failed\n");151	}152 153	*map = 1;154	ksft_test_result(pagemap_is_softdirty(pagemap_fd, map) == 1,155			 "Test %s-%s dirty bit of new written page\n",156			 __func__, type[anon]);157	clear_softdirty();158	ksft_test_result(pagemap_is_softdirty(pagemap_fd, map) == 0,159			 "Test %s-%s soft-dirty clear after clear_refs\n",160			 __func__, type[anon]);161	mprotect(map, pagesize, PROT_READ);162	ksft_test_result(pagemap_is_softdirty(pagemap_fd, map) == 0,163			 "Test %s-%s soft-dirty clear after marking RO\n",164			 __func__, type[anon]);165	mprotect(map, pagesize, PROT_READ|PROT_WRITE);166	ksft_test_result(pagemap_is_softdirty(pagemap_fd, map) == 0,167			 "Test %s-%s soft-dirty clear after marking RW\n",168			 __func__, type[anon]);169	*map = 2;170	ksft_test_result(pagemap_is_softdirty(pagemap_fd, map) == 1,171			 "Test %s-%s soft-dirty after rewritten\n",172			 __func__, type[anon]);173 174	munmap(map, pagesize);175 176	if (!anon)177		close(test_fd);178}179 180static void test_mprotect_anon(int pagemap_fd, int pagesize)181{182	test_mprotect(pagemap_fd, pagesize, true);183}184 185static void test_mprotect_file(int pagemap_fd, int pagesize)186{187	test_mprotect(pagemap_fd, pagesize, false);188}189 190int main(int argc, char **argv)191{192	int pagemap_fd;193	int pagesize;194 195	ksft_print_header();196	ksft_set_plan(15);197 198	pagemap_fd = open(PAGEMAP_FILE_PATH, O_RDONLY);199	if (pagemap_fd < 0)200		ksft_exit_fail_msg("Failed to open %s\n", PAGEMAP_FILE_PATH);201 202	pagesize = getpagesize();203 204	test_simple(pagemap_fd, pagesize);205	test_vma_reuse(pagemap_fd, pagesize);206	test_hugepage(pagemap_fd, pagesize);207	test_mprotect_anon(pagemap_fd, pagesize);208	test_mprotect_file(pagemap_fd, pagesize);209 210	close(pagemap_fd);211 212	ksft_finished();213}214