Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.15.
   1// SPDX-License-Identifier: GPL-2.0
   2#define _GNU_SOURCE
   3#include <stdio.h>
   4#include <fcntl.h>
   5#include <string.h>
   6#include <sys/mman.h>
   7#include <errno.h>
   8#include <malloc.h>
   9#include "vm_util.h"
  10#include "../kselftest.h"
  11#include <linux/types.h>
  12#include <linux/memfd.h>
  13#include <linux/userfaultfd.h>
  14#include <linux/fs.h>
  15#include <sys/ioctl.h>
  16#include <sys/stat.h>
  17#include <math.h>
  18#include <asm/unistd.h>
  19#include <pthread.h>
  20#include <sys/resource.h>
  21#include <assert.h>
  22#include <sys/ipc.h>
  23#include <sys/shm.h>
  24
  25#define PAGEMAP_BITS_ALL		(PAGE_IS_WPALLOWED | PAGE_IS_WRITTEN |	\
  26					 PAGE_IS_FILE | PAGE_IS_PRESENT |	\
  27					 PAGE_IS_SWAPPED | PAGE_IS_PFNZERO |	\
  28					 PAGE_IS_HUGE)
  29#define PAGEMAP_NON_WRITTEN_BITS	(PAGE_IS_WPALLOWED | PAGE_IS_FILE |	\
  30					 PAGE_IS_PRESENT | PAGE_IS_SWAPPED |	\
  31					 PAGE_IS_PFNZERO | PAGE_IS_HUGE)
  32
  33#define TEST_ITERATIONS 100
  34#define PAGEMAP "/proc/self/pagemap"
  35int pagemap_fd;
  36int uffd;
  37int page_size;
  38int hpage_size;
  39const char *progname;
  40
  41#define LEN(region)	((region.end - region.start)/page_size)
  42
  43static long pagemap_ioctl(void *start, int len, void *vec, int vec_len, int flag,
  44			  int max_pages, long required_mask, long anyof_mask, long excluded_mask,
  45			  long return_mask)
  46{
  47	struct pm_scan_arg arg;
  48
  49	arg.start = (uintptr_t)start;
  50	arg.end = (uintptr_t)(start + len);
  51	arg.vec = (uintptr_t)vec;
  52	arg.vec_len = vec_len;
  53	arg.flags = flag;
  54	arg.size = sizeof(struct pm_scan_arg);
  55	arg.max_pages = max_pages;
  56	arg.category_mask = required_mask;
  57	arg.category_anyof_mask = anyof_mask;
  58	arg.category_inverted = excluded_mask;
  59	arg.return_mask = return_mask;
  60
  61	return ioctl(pagemap_fd, PAGEMAP_SCAN, &arg);
  62}
  63
  64static long pagemap_ioc(void *start, int len, void *vec, int vec_len, int flag,
  65			int max_pages, long required_mask, long anyof_mask, long excluded_mask,
  66			long return_mask, long *walk_end)
  67{
  68	struct pm_scan_arg arg;
  69	int ret;
  70
  71	arg.start = (uintptr_t)start;
  72	arg.end = (uintptr_t)(start + len);
  73	arg.vec = (uintptr_t)vec;
  74	arg.vec_len = vec_len;
  75	arg.flags = flag;
  76	arg.size = sizeof(struct pm_scan_arg);
  77	arg.max_pages = max_pages;
  78	arg.category_mask = required_mask;
  79	arg.category_anyof_mask = anyof_mask;
  80	arg.category_inverted = excluded_mask;
  81	arg.return_mask = return_mask;
  82
  83	ret = ioctl(pagemap_fd, PAGEMAP_SCAN, &arg);
  84
  85	if (walk_end)
  86		*walk_end = arg.walk_end;
  87
  88	return ret;
  89}
  90
  91
  92int init_uffd(void)
  93{
  94	struct uffdio_api uffdio_api;
  95
  96	uffd = syscall(__NR_userfaultfd, O_CLOEXEC | O_NONBLOCK | UFFD_USER_MODE_ONLY);
  97	if (uffd == -1)
  98		return uffd;
  99
 100	uffdio_api.api = UFFD_API;
 101	uffdio_api.features = UFFD_FEATURE_WP_UNPOPULATED | UFFD_FEATURE_WP_ASYNC |
 102			      UFFD_FEATURE_WP_HUGETLBFS_SHMEM;
 103	if (ioctl(uffd, UFFDIO_API, &uffdio_api))
 104		return -1;
 105
 106	if (!(uffdio_api.api & UFFDIO_REGISTER_MODE_WP) ||
 107	    !(uffdio_api.features & UFFD_FEATURE_WP_UNPOPULATED) ||
 108	    !(uffdio_api.features & UFFD_FEATURE_WP_ASYNC) ||
 109	    !(uffdio_api.features & UFFD_FEATURE_WP_HUGETLBFS_SHMEM))
 110		return -1;
 111
 112	return 0;
 113}
 114
 115int wp_init(void *lpBaseAddress, int dwRegionSize)
 116{
 117	struct uffdio_register uffdio_register;
 118	struct uffdio_writeprotect wp;
 119
 120	uffdio_register.range.start = (unsigned long)lpBaseAddress;
 121	uffdio_register.range.len = dwRegionSize;
 122	uffdio_register.mode = UFFDIO_REGISTER_MODE_WP;
 123	if (ioctl(uffd, UFFDIO_REGISTER, &uffdio_register))
 124		ksft_exit_fail_msg("ioctl(UFFDIO_REGISTER) %d %s\n", errno, strerror(errno));
 125
 126	if (!(uffdio_register.ioctls & UFFDIO_WRITEPROTECT))
 127		ksft_exit_fail_msg("ioctl set is incorrect\n");
 128
 129	wp.range.start = (unsigned long)lpBaseAddress;
 130	wp.range.len = dwRegionSize;
 131	wp.mode = UFFDIO_WRITEPROTECT_MODE_WP;
 132
 133	if (ioctl(uffd, UFFDIO_WRITEPROTECT, &wp))
 134		ksft_exit_fail_msg("ioctl(UFFDIO_WRITEPROTECT)\n");
 135
 136	return 0;
 137}
 138
 139int wp_free(void *lpBaseAddress, int dwRegionSize)
 140{
 141	struct uffdio_register uffdio_register;
 142
 143	uffdio_register.range.start = (unsigned long)lpBaseAddress;
 144	uffdio_register.range.len = dwRegionSize;
 145	uffdio_register.mode = UFFDIO_REGISTER_MODE_WP;
 146	if (ioctl(uffd, UFFDIO_UNREGISTER, &uffdio_register.range))
 147		ksft_exit_fail_msg("ioctl unregister failure\n");
 148	return 0;
 149}
 150
 151int wp_addr_range(void *lpBaseAddress, int dwRegionSize)
 152{
 153	if (pagemap_ioctl(lpBaseAddress, dwRegionSize, NULL, 0,
 154			  PM_SCAN_WP_MATCHING | PM_SCAN_CHECK_WPASYNC,
 155			  0, PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN) < 0)
 156		ksft_exit_fail_msg("error %d %d %s\n", 1, errno, strerror(errno));
 157
 158	return 0;
 159}
 160
 161void *gethugetlb_mem(int size, int *shmid)
 162{
 163	char *mem;
 164
 165	if (shmid) {
 166		*shmid = shmget(2, size, SHM_HUGETLB | IPC_CREAT | SHM_R | SHM_W);
 167		if (*shmid < 0)
 168			return NULL;
 169
 170		mem = shmat(*shmid, 0, 0);
 171		if (mem == (char *)-1) {
 172			shmctl(*shmid, IPC_RMID, NULL);
 173			ksft_exit_fail_msg("Shared memory attach failure\n");
 174		}
 175	} else {
 176		mem = mmap(NULL, size, PROT_READ | PROT_WRITE,
 177			   MAP_ANONYMOUS | MAP_HUGETLB | MAP_PRIVATE, -1, 0);
 178		if (mem == MAP_FAILED)
 179			return NULL;
 180	}
 181
 182	return mem;
 183}
 184
 185int userfaultfd_tests(void)
 186{
 187	int mem_size, vec_size, written, num_pages = 16;
 188	char *mem, *vec;
 189
 190	mem_size = num_pages * page_size;
 191	mem = mmap(NULL, mem_size, PROT_NONE, MAP_PRIVATE | MAP_ANON, -1, 0);
 192	if (mem == MAP_FAILED)
 193		ksft_exit_fail_msg("error nomem\n");
 194
 195	wp_init(mem, mem_size);
 196
 197	/* Change protection of pages differently */
 198	mprotect(mem, mem_size/8, PROT_READ|PROT_WRITE);
 199	mprotect(mem + 1 * mem_size/8, mem_size/8, PROT_READ);
 200	mprotect(mem + 2 * mem_size/8, mem_size/8, PROT_READ|PROT_WRITE);
 201	mprotect(mem + 3 * mem_size/8, mem_size/8, PROT_READ);
 202	mprotect(mem + 4 * mem_size/8, mem_size/8, PROT_READ|PROT_WRITE);
 203	mprotect(mem + 5 * mem_size/8, mem_size/8, PROT_NONE);
 204	mprotect(mem + 6 * mem_size/8, mem_size/8, PROT_READ|PROT_WRITE);
 205	mprotect(mem + 7 * mem_size/8, mem_size/8, PROT_READ);
 206
 207	wp_addr_range(mem + (mem_size/16), mem_size - 2 * (mem_size/8));
 208	wp_addr_range(mem, mem_size);
 209
 210	vec_size = mem_size/page_size;
 211	vec = malloc(sizeof(struct page_region) * vec_size);
 212
 213	written = pagemap_ioctl(mem, mem_size, vec, 1, PM_SCAN_WP_MATCHING | PM_SCAN_CHECK_WPASYNC,
 214				vec_size - 2, PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN);
 215	if (written < 0)
 216		ksft_exit_fail_msg("error %d %d %s\n", written, errno, strerror(errno));
 217
 218	ksft_test_result(written == 0, "%s all new pages must not be written (dirty)\n", __func__);
 219
 220	wp_free(mem, mem_size);
 221	munmap(mem, mem_size);
 222	free(vec);
 223	return 0;
 224}
 225
 226int get_reads(struct page_region *vec, int vec_size)
 227{
 228	int i, sum = 0;
 229
 230	for (i = 0; i < vec_size; i++)
 231		sum += LEN(vec[i]);
 232
 233	return sum;
 234}
 235
 236int sanity_tests_sd(void)
 237{
 238	int mem_size, vec_size, ret, ret2, ret3, i, num_pages = 1000, total_pages = 0;
 239	int total_writes, total_reads, reads, count;
 240	struct page_region *vec, *vec2;
 241	char *mem, *m[2];
 242	long walk_end;
 243
 244	vec_size = num_pages/2;
 245	mem_size = num_pages * page_size;
 246
 247	vec = malloc(sizeof(struct page_region) * vec_size);
 248	if (!vec)
 249		ksft_exit_fail_msg("error nomem\n");
 250
 251	vec2 = malloc(sizeof(struct page_region) * vec_size);
 252	if (!vec2)
 253		ksft_exit_fail_msg("error nomem\n");
 254
 255	mem = mmap(NULL, mem_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
 256	if (mem == MAP_FAILED)
 257		ksft_exit_fail_msg("error nomem\n");
 258
 259	wp_init(mem, mem_size);
 260	wp_addr_range(mem, mem_size);
 261
 262	/* 1. wrong operation */
 263	ksft_test_result(pagemap_ioctl(mem, 0, vec, vec_size, 0,
 264				       0, PAGEMAP_BITS_ALL, 0, 0, PAGEMAP_BITS_ALL) == 0,
 265			 "%s Zero range size is valid\n", __func__);
 266
 267	ksft_test_result(pagemap_ioctl(mem, mem_size, NULL, vec_size, 0,
 268				       0, PAGEMAP_BITS_ALL, 0, 0, PAGEMAP_BITS_ALL) < 0,
 269			 "%s output buffer must be specified with size\n", __func__);
 270
 271	ksft_test_result(pagemap_ioctl(mem, mem_size, vec, 0, 0,
 272				       0, PAGEMAP_BITS_ALL, 0, 0, PAGEMAP_BITS_ALL) == 0,
 273			 "%s output buffer can be 0\n", __func__);
 274
 275	ksft_test_result(pagemap_ioctl(mem, mem_size, 0, 0, 0,
 276				       0, PAGEMAP_BITS_ALL, 0, 0, PAGEMAP_BITS_ALL) == 0,
 277			 "%s output buffer can be 0\n", __func__);
 278
 279	ksft_test_result(pagemap_ioctl(mem, mem_size, vec, vec_size, -1,
 280				       0, PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN) < 0,
 281			 "%s wrong flag specified\n", __func__);
 282
 283	ksft_test_result(pagemap_ioctl(mem, mem_size, vec, vec_size,
 284				       PM_SCAN_WP_MATCHING | PM_SCAN_CHECK_WPASYNC | 0xFF,
 285				       0, PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN) < 0,
 286			 "%s flag has extra bits specified\n", __func__);
 287
 288	ksft_test_result(pagemap_ioctl(mem, mem_size, vec, vec_size, 0,
 289				       0, 0, 0, 0, PAGE_IS_WRITTEN) >= 0,
 290			 "%s no selection mask is specified\n", __func__);
 291
 292	ksft_test_result(pagemap_ioctl(mem, mem_size, vec, vec_size, 0,
 293				       0, PAGE_IS_WRITTEN, PAGE_IS_WRITTEN, 0, 0) == 0,
 294			 "%s no return mask is specified\n", __func__);
 295
 296	ksft_test_result(pagemap_ioctl(mem, mem_size, vec, vec_size, 0,
 297				       0, PAGE_IS_WRITTEN, 0, 0, 0x1000) < 0,
 298			 "%s wrong return mask specified\n", __func__);
 299
 300	ksft_test_result(pagemap_ioctl(mem, mem_size, vec, vec_size,
 301				       PM_SCAN_WP_MATCHING | PM_SCAN_CHECK_WPASYNC,
 302				       0, 0xFFF, PAGE_IS_WRITTEN, 0, PAGE_IS_WRITTEN) < 0,
 303			 "%s mixture of correct and wrong flag\n", __func__);
 304
 305	ksft_test_result(pagemap_ioctl(mem, mem_size, vec, vec_size,
 306				       PM_SCAN_WP_MATCHING | PM_SCAN_CHECK_WPASYNC,
 307				       0, 0, 0, PAGEMAP_BITS_ALL, PAGE_IS_WRITTEN) >= 0,
 308			 "%s PAGEMAP_BITS_ALL can be specified with PM_SCAN_WP_MATCHING | PM_SCAN_CHECK_WPASYNC\n",
 309			 __func__);
 310
 311	/* 2. Clear area with larger vec size */
 312	ret = pagemap_ioctl(mem, mem_size, vec, vec_size,
 313			    PM_SCAN_WP_MATCHING | PM_SCAN_CHECK_WPASYNC, 0,
 314			    PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN);
 315	ksft_test_result(ret >= 0, "%s Clear area with larger vec size\n", __func__);
 316
 317	/* 3. Repeated pattern of written and non-written pages */
 318	for (i = 0; i < mem_size; i += 2 * page_size)
 319		mem[i]++;
 320
 321	ret = pagemap_ioctl(mem, mem_size, vec, vec_size, 0, 0, PAGE_IS_WRITTEN, 0,
 322			    0, PAGE_IS_WRITTEN);
 323	if (ret < 0)
 324		ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno));
 325
 326	ksft_test_result(ret == mem_size/(page_size * 2),
 327			 "%s Repeated pattern of written and non-written pages\n", __func__);
 328
 329	/* 4. Repeated pattern of written and non-written pages in parts */
 330	ret = pagemap_ioctl(mem, mem_size, vec, vec_size,
 331			    PM_SCAN_WP_MATCHING | PM_SCAN_CHECK_WPASYNC,
 332			    num_pages/2 - 2, PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN);
 333	if (ret < 0)
 334		ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno));
 335
 336	ret2 = pagemap_ioctl(mem, mem_size, vec, 2, 0, 0, PAGE_IS_WRITTEN, 0, 0,
 337			     PAGE_IS_WRITTEN);
 338	if (ret2 < 0)
 339		ksft_exit_fail_msg("error %d %d %s\n", ret2, errno, strerror(errno));
 340
 341	ret3 = pagemap_ioctl(mem, mem_size, vec, vec_size,
 342			     PM_SCAN_WP_MATCHING | PM_SCAN_CHECK_WPASYNC,
 343			     0, PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN);
 344	if (ret3 < 0)
 345		ksft_exit_fail_msg("error %d %d %s\n", ret3, errno, strerror(errno));
 346
 347	ksft_test_result((ret + ret3) == num_pages/2 && ret2 == 2,
 348			 "%s Repeated pattern of written and non-written pages in parts %d %d %d\n",
 349			 __func__, ret, ret3, ret2);
 350
 351	/* 5. Repeated pattern of written and non-written pages max_pages */
 352	for (i = 0; i < mem_size; i += 2 * page_size)
 353		mem[i]++;
 354	mem[(mem_size/page_size - 1) * page_size]++;
 355
 356	ret = pagemap_ioctl(mem, mem_size, vec, vec_size,
 357			    PM_SCAN_WP_MATCHING | PM_SCAN_CHECK_WPASYNC,
 358			    num_pages/2, PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN);
 359	if (ret < 0)
 360		ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno));
 361
 362	ret2 = pagemap_ioctl(mem, mem_size, vec, vec_size,
 363			     PM_SCAN_WP_MATCHING | PM_SCAN_CHECK_WPASYNC,
 364			     0, PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN);
 365	if (ret2 < 0)
 366		ksft_exit_fail_msg("error %d %d %s\n", ret2, errno, strerror(errno));
 367
 368	ksft_test_result(ret == num_pages/2 && ret2 == 1,
 369			 "%s Repeated pattern of written and non-written pages max_pages\n",
 370			 __func__);
 371
 372	/* 6. only get 2 dirty pages and clear them as well */
 373	vec_size = mem_size/page_size;
 374	memset(mem, -1, mem_size);
 375
 376	/* get and clear second and third pages */
 377	ret = pagemap_ioctl(mem + page_size, 2 * page_size, vec, 1,
 378			    PM_SCAN_WP_MATCHING | PM_SCAN_CHECK_WPASYNC,
 379			    2, PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN);
 380	if (ret < 0)
 381		ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno));
 382
 383	ret2 = pagemap_ioctl(mem, mem_size, vec2, vec_size, 0, 0,
 384			      PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN);
 385	if (ret2 < 0)
 386		ksft_exit_fail_msg("error %d %d %s\n", ret2, errno, strerror(errno));
 387
 388	ksft_test_result(ret == 1 && LEN(vec[0]) == 2 &&
 389			 vec[0].start == (uintptr_t)(mem + page_size) &&
 390			 ret2 == 2 && LEN(vec2[0]) == 1 && vec2[0].start == (uintptr_t)mem &&
 391			 LEN(vec2[1]) == vec_size - 3 &&
 392			 vec2[1].start == (uintptr_t)(mem + 3 * page_size),
 393			 "%s only get 2 written pages and clear them as well\n", __func__);
 394
 395	wp_free(mem, mem_size);
 396	munmap(mem, mem_size);
 397
 398	/* 7. Two regions */
 399	m[0] = mmap(NULL, mem_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
 400	if (m[0] == MAP_FAILED)
 401		ksft_exit_fail_msg("error nomem\n");
 402	m[1] = mmap(NULL, mem_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
 403	if (m[1] == MAP_FAILED)
 404		ksft_exit_fail_msg("error nomem\n");
 405
 406	wp_init(m[0], mem_size);
 407	wp_init(m[1], mem_size);
 408	wp_addr_range(m[0], mem_size);
 409	wp_addr_range(m[1], mem_size);
 410
 411	memset(m[0], 'a', mem_size);
 412	memset(m[1], 'b', mem_size);
 413
 414	wp_addr_range(m[0], mem_size);
 415
 416	ret = pagemap_ioctl(m[1], mem_size, vec, 1, 0, 0, PAGE_IS_WRITTEN, 0, 0,
 417			    PAGE_IS_WRITTEN);
 418	if (ret < 0)
 419		ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno));
 420
 421	ksft_test_result(ret == 1 && LEN(vec[0]) == mem_size/page_size,
 422			 "%s Two regions\n", __func__);
 423
 424	wp_free(m[0], mem_size);
 425	wp_free(m[1], mem_size);
 426	munmap(m[0], mem_size);
 427	munmap(m[1], mem_size);
 428
 429	free(vec);
 430	free(vec2);
 431
 432	/* 8. Smaller vec */
 433	mem_size = 1050 * page_size;
 434	vec_size = mem_size/(page_size*2);
 435
 436	vec = malloc(sizeof(struct page_region) * vec_size);
 437	if (!vec)
 438		ksft_exit_fail_msg("error nomem\n");
 439
 440	mem = mmap(NULL, mem_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
 441	if (mem == MAP_FAILED)
 442		ksft_exit_fail_msg("error nomem\n");
 443
 444	wp_init(mem, mem_size);
 445	wp_addr_range(mem, mem_size);
 446
 447	ret = pagemap_ioctl(mem, mem_size, vec, vec_size,
 448			    PM_SCAN_WP_MATCHING | PM_SCAN_CHECK_WPASYNC, 0,
 449			    PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN);
 450	if (ret < 0)
 451		ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno));
 452
 453	for (i = 0; i < mem_size/page_size; i += 2)
 454		mem[i * page_size]++;
 455
 456	ret = pagemap_ioctl(mem, mem_size, vec, vec_size,
 457			    PM_SCAN_WP_MATCHING | PM_SCAN_CHECK_WPASYNC,
 458			    mem_size/(page_size*5), PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN);
 459	if (ret < 0)
 460		ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno));
 461
 462	total_pages += ret;
 463
 464	ret = pagemap_ioctl(mem, mem_size, vec, vec_size,
 465			    PM_SCAN_WP_MATCHING | PM_SCAN_CHECK_WPASYNC,
 466			    mem_size/(page_size*5), PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN);
 467	if (ret < 0)
 468		ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno));
 469
 470	total_pages += ret;
 471
 472	ret = pagemap_ioctl(mem, mem_size, vec, vec_size,
 473			    PM_SCAN_WP_MATCHING | PM_SCAN_CHECK_WPASYNC,
 474			    mem_size/(page_size*5), PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN);
 475	if (ret < 0)
 476		ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno));
 477
 478	total_pages += ret;
 479
 480	ksft_test_result(total_pages == mem_size/(page_size*2), "%s Smaller max_pages\n", __func__);
 481
 482	free(vec);
 483	wp_free(mem, mem_size);
 484	munmap(mem, mem_size);
 485	total_pages = 0;
 486
 487	/* 9. Smaller vec */
 488	mem_size = 10000 * page_size;
 489	vec_size = 50;
 490
 491	vec = malloc(sizeof(struct page_region) * vec_size);
 492	if (!vec)
 493		ksft_exit_fail_msg("error nomem\n");
 494
 495	mem = mmap(NULL, mem_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
 496	if (mem == MAP_FAILED)
 497		ksft_exit_fail_msg("error nomem\n");
 498
 499	wp_init(mem, mem_size);
 500	wp_addr_range(mem, mem_size);
 501
 502	for (count = 0; count < TEST_ITERATIONS; count++) {
 503		total_writes = total_reads = 0;
 504		walk_end = (long)mem;
 505
 506		for (i = 0; i < mem_size; i += page_size) {
 507			if (rand() % 2) {
 508				mem[i]++;
 509				total_writes++;
 510			}
 511		}
 512
 513		while (total_reads < total_writes) {
 514			ret = pagemap_ioc((void *)walk_end, mem_size-(walk_end - (long)mem), vec,
 515					  vec_size, PM_SCAN_WP_MATCHING | PM_SCAN_CHECK_WPASYNC,
 516					  0, PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN, &walk_end);
 517			if (ret < 0)
 518				ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno));
 519
 520			if (ret > vec_size)
 521				break;
 522
 523			reads = get_reads(vec, ret);
 524			total_reads += reads;
 525		}
 526
 527		if (total_reads != total_writes)
 528			break;
 529	}
 530
 531	ksft_test_result(count == TEST_ITERATIONS, "Smaller vec\n");
 532
 533	free(vec);
 534	wp_free(mem, mem_size);
 535	munmap(mem, mem_size);
 536
 537	/* 10. Walk_end tester */
 538	vec_size = 1000;
 539	mem_size = vec_size * page_size;
 540
 541	vec = malloc(sizeof(struct page_region) * vec_size);
 542	if (!vec)
 543		ksft_exit_fail_msg("error nomem\n");
 544
 545	mem = mmap(NULL, mem_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
 546	if (mem == MAP_FAILED)
 547		ksft_exit_fail_msg("error nomem\n");
 548
 549	wp_init(mem, mem_size);
 550	wp_addr_range(mem, mem_size);
 551
 552	memset(mem, 0, mem_size);
 553
 554	ret = pagemap_ioc(mem, 0, vec, vec_size, 0,
 555			  0, PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN, &walk_end);
 556	if (ret < 0)
 557		ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno));
 558	ksft_test_result(ret == 0 && walk_end == (long)mem,
 559			 "Walk_end: Same start and end address\n");
 560
 561	ret = pagemap_ioc(mem, 0, vec, vec_size, PM_SCAN_WP_MATCHING | PM_SCAN_CHECK_WPASYNC,
 562			  0, PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN, &walk_end);
 563	if (ret < 0)
 564		ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno));
 565	ksft_test_result(ret == 0 && walk_end == (long)mem,
 566			 "Walk_end: Same start and end with WP\n");
 567
 568	ret = pagemap_ioc(mem, 0, vec, 0, PM_SCAN_WP_MATCHING | PM_SCAN_CHECK_WPASYNC,
 569			  0, PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN, &walk_end);
 570	if (ret < 0)
 571		ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno));
 572	ksft_test_result(ret == 0 && walk_end == (long)mem,
 573			 "Walk_end: Same start and end with 0 output buffer\n");
 574
 575	ret = pagemap_ioc(mem, mem_size, vec, vec_size, 0,
 576			  0, PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN, &walk_end);
 577	if (ret < 0)
 578		ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno));
 579	ksft_test_result(ret == 1 && walk_end == (long)(mem + mem_size),
 580			 "Walk_end: Big vec\n");
 581
 582	ret = pagemap_ioc(mem, mem_size, vec, 1, 0,
 583			  0, PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN, &walk_end);
 584	if (ret < 0)
 585		ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno));
 586	ksft_test_result(ret == 1 && walk_end == (long)(mem + mem_size),
 587			 "Walk_end: vec of minimum length\n");
 588
 589	ret = pagemap_ioc(mem, mem_size, vec, 1, 0,
 590			  vec_size, PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN, &walk_end);
 591	if (ret < 0)
 592		ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno));
 593	ksft_test_result(ret == 1 && walk_end == (long)(mem + mem_size),
 594			 "Walk_end: Max pages specified\n");
 595
 596	ret = pagemap_ioc(mem, mem_size, vec, vec_size, 0,
 597			  vec_size/2, PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN, &walk_end);
 598	if (ret < 0)
 599		ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno));
 600	ksft_test_result(ret == 1 && walk_end == (long)(mem + mem_size/2),
 601			 "Walk_end: Half max pages\n");
 602
 603	ret = pagemap_ioc(mem, mem_size, vec, vec_size, 0,
 604			  1, PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN, &walk_end);
 605	if (ret < 0)
 606		ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno));
 607	ksft_test_result(ret == 1 && walk_end == (long)(mem + page_size),
 608			 "Walk_end: 1 max page\n");
 609
 610	ret = pagemap_ioc(mem, mem_size, vec, vec_size, 0,
 611			  -1, PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN, &walk_end);
 612	if (ret < 0)
 613		ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno));
 614	ksft_test_result(ret == 1 && walk_end == (long)(mem + mem_size),
 615			 "Walk_end: max pages\n");
 616
 617	wp_addr_range(mem, mem_size);
 618	for (i = 0; i < mem_size; i += 2 * page_size)
 619		mem[i]++;
 620
 621	ret = pagemap_ioc(mem, mem_size, vec, vec_size, 0,
 622			  0, PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN, &walk_end);
 623	if (ret < 0)
 624		ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno));
 625	ksft_test_result(ret == vec_size/2 && walk_end == (long)(mem + mem_size),
 626			 "Walk_end sparse: Big vec\n");
 627
 628	ret = pagemap_ioc(mem, mem_size, vec, 1, 0,
 629			  0, PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN, &walk_end);
 630	if (ret < 0)
 631		ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno));
 632	ksft_test_result(ret == 1 && walk_end == (long)(mem + page_size * 2),
 633			 "Walk_end sparse: vec of minimum length\n");
 634
 635	ret = pagemap_ioc(mem, mem_size, vec, 1, 0,
 636			  vec_size, PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN, &walk_end);
 637	if (ret < 0)
 638		ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno));
 639	ksft_test_result(ret == 1 && walk_end == (long)(mem + page_size * 2),
 640			 "Walk_end sparse: Max pages specified\n");
 641
 642	ret = pagemap_ioc(mem, mem_size, vec, vec_size/2, 0,
 643			  vec_size, PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN, &walk_end);
 644	if (ret < 0)
 645		ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno));
 646	ksft_test_result(ret == vec_size/2 && walk_end == (long)(mem + mem_size),
 647			 "Walk_end sparse: Max pages specified\n");
 648
 649	ret = pagemap_ioc(mem, mem_size, vec, vec_size, 0,
 650			  vec_size, PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN, &walk_end);
 651	if (ret < 0)
 652		ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno));
 653	ksft_test_result(ret == vec_size/2 && walk_end == (long)(mem + mem_size),
 654			 "Walk_end sparse: Max pages specified\n");
 655
 656	ret = pagemap_ioc(mem, mem_size, vec, vec_size, 0,
 657			  vec_size/2, PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN, &walk_end);
 658	if (ret < 0)
 659		ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno));
 660	ksft_test_result(ret == vec_size/2 && walk_end == (long)(mem + mem_size),
 661			 "Walk_endsparse : Half max pages\n");
 662
 663	ret = pagemap_ioc(mem, mem_size, vec, vec_size, 0,
 664			  1, PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN, &walk_end);
 665	if (ret < 0)
 666		ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno));
 667	ksft_test_result(ret == 1 && walk_end == (long)(mem + page_size * 2),
 668			 "Walk_end: 1 max page\n");
 669
 670	free(vec);
 671	wp_free(mem, mem_size);
 672	munmap(mem, mem_size);
 673
 674	return 0;
 675}
 676
 677int base_tests(char *prefix, char *mem, int mem_size, int skip)
 678{
 679	int vec_size, written;
 680	struct page_region *vec, *vec2;
 681
 682	if (skip) {
 683		ksft_test_result_skip("%s all new pages must not be written (dirty)\n", prefix);
 684		ksft_test_result_skip("%s all pages must be written (dirty)\n", prefix);
 685		ksft_test_result_skip("%s all pages dirty other than first and the last one\n",
 686				      prefix);
 687		ksft_test_result_skip("%s PM_SCAN_WP_MATCHING | PM_SCAN_CHECK_WPASYNC\n", prefix);
 688		ksft_test_result_skip("%s only middle page dirty\n", prefix);
 689		ksft_test_result_skip("%s only two middle pages dirty\n", prefix);
 690		return 0;
 691	}
 692
 693	vec_size = mem_size/page_size;
 694	vec = malloc(sizeof(struct page_region) * vec_size);
 695	vec2 = malloc(sizeof(struct page_region) * vec_size);
 696
 697	/* 1. all new pages must be not be written (dirty) */
 698	written = pagemap_ioctl(mem, mem_size, vec, 1, PM_SCAN_WP_MATCHING | PM_SCAN_CHECK_WPASYNC,
 699				vec_size - 2, PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN);
 700	if (written < 0)
 701		ksft_exit_fail_msg("error %d %d %s\n", written, errno, strerror(errno));
 702
 703	ksft_test_result(written == 0, "%s all new pages must not be written (dirty)\n", prefix);
 704
 705	/* 2. all pages must be written */
 706	memset(mem, -1, mem_size);
 707
 708	written = pagemap_ioctl(mem, mem_size, vec, 1, 0, 0, PAGE_IS_WRITTEN, 0, 0,
 709			      PAGE_IS_WRITTEN);
 710	if (written < 0)
 711		ksft_exit_fail_msg("error %d %d %s\n", written, errno, strerror(errno));
 712
 713	ksft_test_result(written == 1 && LEN(vec[0]) == mem_size/page_size,
 714			 "%s all pages must be written (dirty)\n", prefix);
 715
 716	/* 3. all pages dirty other than first and the last one */
 717	written = pagemap_ioctl(mem, mem_size, vec, 1, PM_SCAN_WP_MATCHING | PM_SCAN_CHECK_WPASYNC,
 718				0, PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN);
 719	if (written < 0)
 720		ksft_exit_fail_msg("error %d %d %s\n", written, errno, strerror(errno));
 721
 722	memset(mem + page_size, 0, mem_size - (2 * page_size));
 723
 724	written = pagemap_ioctl(mem, mem_size, vec, 1, PM_SCAN_WP_MATCHING | PM_SCAN_CHECK_WPASYNC,
 725				0, PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN);
 726	if (written < 0)
 727		ksft_exit_fail_msg("error %d %d %s\n", written, errno, strerror(errno));
 728
 729	ksft_test_result(written == 1 && LEN(vec[0]) >= vec_size - 2 && LEN(vec[0]) <= vec_size,
 730			 "%s all pages dirty other than first and the last one\n", prefix);
 731
 732	written = pagemap_ioctl(mem, mem_size, vec, 1, 0, 0,
 733				PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN);
 734	if (written < 0)
 735		ksft_exit_fail_msg("error %d %d %s\n", written, errno, strerror(errno));
 736
 737	ksft_test_result(written == 0,
 738			 "%s PM_SCAN_WP_MATCHING | PM_SCAN_CHECK_WPASYNC\n", prefix);
 739
 740	/* 4. only middle page dirty */
 741	written = pagemap_ioctl(mem, mem_size, vec, 1, PM_SCAN_WP_MATCHING | PM_SCAN_CHECK_WPASYNC,
 742				0, PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN);
 743	if (written < 0)
 744		ksft_exit_fail_msg("error %d %d %s\n", written, errno, strerror(errno));
 745
 746	mem[vec_size/2 * page_size]++;
 747
 748	written = pagemap_ioctl(mem, mem_size, vec, vec_size, 0, 0, PAGE_IS_WRITTEN,
 749				0, 0, PAGE_IS_WRITTEN);
 750	if (written < 0)
 751		ksft_exit_fail_msg("error %d %d %s\n", written, errno, strerror(errno));
 752
 753	ksft_test_result(written == 1 && LEN(vec[0]) >= 1,
 754			 "%s only middle page dirty\n", prefix);
 755
 756	/* 5. only two middle pages dirty and walk over only middle pages */
 757	written = pagemap_ioctl(mem, mem_size, vec, 1, PM_SCAN_WP_MATCHING | PM_SCAN_CHECK_WPASYNC,
 758				0, PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN | PAGE_IS_HUGE);
 759	if (written < 0)
 760		ksft_exit_fail_msg("error %d %d %s\n", written, errno, strerror(errno));
 761
 762	mem[vec_size/2 * page_size]++;
 763	mem[(vec_size/2 + 1) * page_size]++;
 764
 765	written = pagemap_ioctl(&mem[vec_size/2 * page_size], 2 * page_size, vec, 1, 0,
 766				0, PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN | PAGE_IS_HUGE);
 767	if (written < 0)
 768		ksft_exit_fail_msg("error %d %d %s\n", written, errno, strerror(errno));
 769
 770	ksft_test_result(written == 1 && vec[0].start == (uintptr_t)(&mem[vec_size/2 * page_size])
 771			 && LEN(vec[0]) == 2,
 772			 "%s only two middle pages dirty\n", prefix);
 773
 774	free(vec);
 775	free(vec2);
 776	return 0;
 777}
 778
 779void *gethugepage(int map_size)
 780{
 781	int ret;
 782	char *map;
 783
 784	map = memalign(hpage_size, map_size);
 785	if (!map)
 786		ksft_exit_fail_msg("memalign failed %d %s\n", errno, strerror(errno));
 787
 788	ret = madvise(map, map_size, MADV_HUGEPAGE);
 789	if (ret)
 790		return NULL;
 791
 792	memset(map, 0, map_size);
 793
 794	return map;
 795}
 796
 797int hpage_unit_tests(void)
 798{
 799	char *map;
 800	int ret, ret2;
 801	size_t num_pages = 10;
 802	int map_size = hpage_size * num_pages;
 803	int vec_size = map_size/page_size;
 804	struct page_region *vec, *vec2;
 805
 806	vec = malloc(sizeof(struct page_region) * vec_size);
 807	vec2 = malloc(sizeof(struct page_region) * vec_size);
 808	if (!vec || !vec2)
 809		ksft_exit_fail_msg("malloc failed\n");
 810
 811	map = gethugepage(map_size);
 812	if (map) {
 813		wp_init(map, map_size);
 814		wp_addr_range(map, map_size);
 815
 816		/* 1. all new huge page must not be written (dirty) */
 817		ret = pagemap_ioctl(map, map_size, vec, vec_size,
 818				    PM_SCAN_WP_MATCHING | PM_SCAN_CHECK_WPASYNC, 0,
 819				    PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN);
 820		if (ret < 0)
 821			ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno));
 822
 823		ksft_test_result(ret == 0, "%s all new huge page must not be written (dirty)\n",
 824				 __func__);
 825
 826		/* 2. all the huge page must not be written */
 827		ret = pagemap_ioctl(map, map_size, vec, vec_size, 0, 0,
 828				    PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN);
 829		if (ret < 0)
 830			ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno));
 831
 832		ksft_test_result(ret == 0, "%s all the huge page must not be written\n", __func__);
 833
 834		/* 3. all the huge page must be written and clear dirty as well */
 835		memset(map, -1, map_size);
 836		ret = pagemap_ioctl(map, map_size, vec, vec_size,
 837				    PM_SCAN_WP_MATCHING | PM_SCAN_CHECK_WPASYNC,
 838				    0, PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN);
 839		if (ret < 0)
 840			ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno));
 841
 842		ksft_test_result(ret == 1 && vec[0].start == (uintptr_t)map &&
 843				 LEN(vec[0]) == vec_size && vec[0].categories == PAGE_IS_WRITTEN,
 844				 "%s all the huge page must be written and clear\n", __func__);
 845
 846		/* 4. only middle page written */
 847		wp_free(map, map_size);
 848		free(map);
 849		map = gethugepage(map_size);
 850		wp_init(map, map_size);
 851		wp_addr_range(map, map_size);
 852		map[vec_size/2 * page_size]++;
 853
 854		ret = pagemap_ioctl(map, map_size, vec, vec_size, 0, 0,
 855				    PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN);
 856		if (ret < 0)
 857			ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno));
 858
 859		ksft_test_result(ret == 1 && LEN(vec[0]) > 0,
 860				 "%s only middle page written\n", __func__);
 861
 862		wp_free(map, map_size);
 863		free(map);
 864	} else {
 865		ksft_test_result_skip("%s all new huge page must be written\n", __func__);
 866		ksft_test_result_skip("%s all the huge page must not be written\n", __func__);
 867		ksft_test_result_skip("%s all the huge page must be written and clear\n", __func__);
 868		ksft_test_result_skip("%s only middle page written\n", __func__);
 869	}
 870
 871	/* 5. clear first half of huge page */
 872	map = gethugepage(map_size);
 873	if (map) {
 874		wp_init(map, map_size);
 875		wp_addr_range(map, map_size);
 876
 877		memset(map, 0, map_size);
 878
 879		wp_addr_range(map, map_size/2);
 880
 881		ret = pagemap_ioctl(map, map_size, vec, vec_size, 0, 0,
 882				    PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN);
 883		if (ret < 0)
 884			ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno));
 885
 886		ksft_test_result(ret == 1 && LEN(vec[0]) == vec_size/2 &&
 887				 vec[0].start == (uintptr_t)(map + map_size/2),
 888				 "%s clear first half of huge page\n", __func__);
 889		wp_free(map, map_size);
 890		free(map);
 891	} else {
 892		ksft_test_result_skip("%s clear first half of huge page\n", __func__);
 893	}
 894
 895	/* 6. clear first half of huge page with limited buffer */
 896	map = gethugepage(map_size);
 897	if (map) {
 898		wp_init(map, map_size);
 899		wp_addr_range(map, map_size);
 900
 901		memset(map, 0, map_size);
 902
 903		ret = pagemap_ioctl(map, map_size, vec, vec_size,
 904				    PM_SCAN_WP_MATCHING | PM_SCAN_CHECK_WPASYNC,
 905				    vec_size/2, PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN);
 906		if (ret < 0)
 907			ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno));
 908
 909		ret = pagemap_ioctl(map, map_size, vec, vec_size, 0, 0,
 910				    PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN);
 911		if (ret < 0)
 912			ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno));
 913
 914		ksft_test_result(ret == 1 && LEN(vec[0]) == vec_size/2 &&
 915				 vec[0].start == (uintptr_t)(map + map_size/2),
 916				 "%s clear first half of huge page with limited buffer\n",
 917				 __func__);
 918		wp_free(map, map_size);
 919		free(map);
 920	} else {
 921		ksft_test_result_skip("%s clear first half of huge page with limited buffer\n",
 922				      __func__);
 923	}
 924
 925	/* 7. clear second half of huge page */
 926	map = gethugepage(map_size);
 927	if (map) {
 928		wp_init(map, map_size);
 929		wp_addr_range(map, map_size);
 930
 931		memset(map, -1, map_size);
 932
 933		ret = pagemap_ioctl(map + map_size/2, map_size/2, vec, vec_size,
 934				    PM_SCAN_WP_MATCHING | PM_SCAN_CHECK_WPASYNC, vec_size/2,
 935				    PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN);
 936		if (ret < 0)
 937			ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno));
 938
 939		ret = pagemap_ioctl(map, map_size, vec, vec_size, 0, 0,
 940				    PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN);
 941		if (ret < 0)
 942			ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno));
 943
 944		ksft_test_result(ret == 1 && LEN(vec[0]) == vec_size/2,
 945				 "%s clear second half huge page\n", __func__);
 946		wp_free(map, map_size);
 947		free(map);
 948	} else {
 949		ksft_test_result_skip("%s clear second half huge page\n", __func__);
 950	}
 951
 952	/* 8. get half huge page */
 953	map = gethugepage(map_size);
 954	if (map) {
 955		wp_init(map, map_size);
 956		wp_addr_range(map, map_size);
 957
 958		memset(map, -1, map_size);
 959		usleep(100);
 960
 961		ret = pagemap_ioctl(map, map_size, vec, 1,
 962				    PM_SCAN_WP_MATCHING | PM_SCAN_CHECK_WPASYNC,
 963				    hpage_size/(2*page_size), PAGE_IS_WRITTEN, 0, 0,
 964				    PAGE_IS_WRITTEN);
 965		if (ret < 0)
 966			ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno));
 967
 968		ksft_test_result(ret == 1 && LEN(vec[0]) == hpage_size/(2*page_size),
 969				 "%s get half huge page\n", __func__);
 970
 971		ret2 = pagemap_ioctl(map, map_size, vec, vec_size, 0, 0,
 972				    PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN);
 973		if (ret2 < 0)
 974			ksft_exit_fail_msg("error %d %d %s\n", ret2, errno, strerror(errno));
 975
 976		ksft_test_result(ret2 == 1 && LEN(vec[0]) == (map_size - hpage_size/2)/page_size,
 977				 "%s get half huge page\n", __func__);
 978
 979		wp_free(map, map_size);
 980		free(map);
 981	} else {
 982		ksft_test_result_skip("%s get half huge page\n", __func__);
 983		ksft_test_result_skip("%s get half huge page\n", __func__);
 984	}
 985
 986	free(vec);
 987	free(vec2);
 988	return 0;
 989}
 990
 991int unmapped_region_tests(void)
 992{
 993	void *start = (void *)0x10000000;
 994	int written, len = 0x00040000;
 995	int vec_size = len / page_size;
 996	struct page_region *vec = malloc(sizeof(struct page_region) * vec_size);
 997
 998	/* 1. Get written pages */
 999	written = pagemap_ioctl(start, len, vec, vec_size, 0, 0,
1000				PAGEMAP_NON_WRITTEN_BITS, 0, 0, PAGEMAP_NON_WRITTEN_BITS);
1001	if (written < 0)
1002		ksft_exit_fail_msg("error %d %d %s\n", written, errno, strerror(errno));
1003
1004	ksft_test_result(written >= 0, "%s Get status of pages\n", __func__);
1005
1006	free(vec);
1007	return 0;
1008}
1009
1010static void test_simple(void)
1011{
1012	int i;
1013	char *map;
1014	struct page_region vec;
1015
1016	map = aligned_alloc(page_size, page_size);
1017	if (!map)
1018		ksft_exit_fail_msg("aligned_alloc failed\n");
1019
1020	wp_init(map, page_size);
1021	wp_addr_range(map, page_size);
1022
1023	for (i = 0 ; i < TEST_ITERATIONS; i++) {
1024		if (pagemap_ioctl(map, page_size, &vec, 1, 0, 0,
1025				  PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN) == 1) {
1026			ksft_print_msg("written bit was 1, but should be 0 (i=%d)\n", i);
1027			break;
1028		}
1029
1030		wp_addr_range(map, page_size);
1031		/* Write something to the page to get the written bit enabled on the page */
1032		map[0]++;
1033
1034		if (pagemap_ioctl(map, page_size, &vec, 1, 0, 0,
1035				  PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN) == 0) {
1036			ksft_print_msg("written bit was 0, but should be 1 (i=%d)\n", i);
1037			break;
1038		}
1039
1040		wp_addr_range(map, page_size);
1041	}
1042	wp_free(map, page_size);
1043	free(map);
1044
1045	ksft_test_result(i == TEST_ITERATIONS, "Test %s\n", __func__);
1046}
1047
1048int sanity_tests(void)
1049{
1050	int mem_size, vec_size, ret, fd, i, buf_size;
1051	struct page_region *vec;
1052	char *mem, *fmem;
1053	struct stat sbuf;
1054	char *tmp_buf;
1055
1056	/* 1. wrong operation */
1057	mem_size = 10 * page_size;
1058	vec_size = mem_size / page_size;
1059
1060	vec = malloc(sizeof(struct page_region) * vec_size);
1061	mem = mmap(NULL, mem_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
1062	if (mem == MAP_FAILED || vec == MAP_FAILED)
1063		ksft_exit_fail_msg("error nomem\n");
1064
1065	wp_init(mem, mem_size);
1066	wp_addr_range(mem, mem_size);
1067
1068	ksft_test_result(pagemap_ioctl(mem, mem_size, vec, vec_size,
1069				       PM_SCAN_WP_MATCHING | PM_SCAN_CHECK_WPASYNC,
1070				       0, PAGEMAP_BITS_ALL, 0, 0, PAGEMAP_BITS_ALL) >= 0,
1071			 "%s WP op can be specified with !PAGE_IS_WRITTEN\n", __func__);
1072	ksft_test_result(pagemap_ioctl(mem, mem_size, vec, vec_size, 0, 0,
1073				       PAGEMAP_BITS_ALL, 0, 0, PAGEMAP_BITS_ALL) >= 0,
1074			 "%s required_mask specified\n", __func__);
1075	ksft_test_result(pagemap_ioctl(mem, mem_size, vec, vec_size, 0, 0,
1076				       0, PAGEMAP_BITS_ALL, 0, PAGEMAP_BITS_ALL) >= 0,
1077			 "%s anyof_mask specified\n", __func__);
1078	ksft_test_result(pagemap_ioctl(mem, mem_size, vec, vec_size, 0, 0,
1079				       0, 0, PAGEMAP_BITS_ALL, PAGEMAP_BITS_ALL) >= 0,
1080			 "%s excluded_mask specified\n", __func__);
1081	ksft_test_result(pagemap_ioctl(mem, mem_size, vec, vec_size, 0, 0,
1082				       PAGEMAP_BITS_ALL, PAGEMAP_BITS_ALL, 0,
1083				       PAGEMAP_BITS_ALL) >= 0,
1084			 "%s required_mask and anyof_mask specified\n", __func__);
1085	wp_free(mem, mem_size);
1086	munmap(mem, mem_size);
1087
1088	/* 2. Get sd and present pages with anyof_mask */
1089	mem = mmap(NULL, mem_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
1090	if (mem == MAP_FAILED)
1091		ksft_exit_fail_msg("error nomem\n");
1092	wp_init(mem, mem_size);
1093	wp_addr_range(mem, mem_size);
1094
1095	memset(mem, 0, mem_size);
1096
1097	ret = pagemap_ioctl(mem, mem_size, vec, vec_size, 0, 0,
1098			    0, PAGEMAP_BITS_ALL, 0, PAGEMAP_BITS_ALL);
1099	ksft_test_result(ret >= 0 && vec[0].start == (uintptr_t)mem && LEN(vec[0]) == vec_size &&
1100			 (vec[0].categories & (PAGE_IS_WRITTEN | PAGE_IS_PRESENT)) ==
1101			 (PAGE_IS_WRITTEN | PAGE_IS_PRESENT),
1102			 "%s Get sd and present pages with anyof_mask\n", __func__);
1103
1104	/* 3. Get sd and present pages with required_mask */
1105	ret = pagemap_ioctl(mem, mem_size, vec, vec_size, 0, 0,
1106			    PAGEMAP_BITS_ALL, 0, 0, PAGEMAP_BITS_ALL);
1107	ksft_test_result(ret >= 0 && vec[0].start == (uintptr_t)mem && LEN(vec[0]) == vec_size &&
1108			 (vec[0].categories & (PAGE_IS_WRITTEN | PAGE_IS_PRESENT)) ==
1109			 (PAGE_IS_WRITTEN | PAGE_IS_PRESENT),
1110			 "%s Get all the pages with required_mask\n", __func__);
1111
1112	/* 4. Get sd and present pages with required_mask and anyof_mask */
1113	ret = pagemap_ioctl(mem, mem_size, vec, vec_size, 0, 0,
1114			    PAGE_IS_WRITTEN, PAGE_IS_PRESENT, 0, PAGEMAP_BITS_ALL);
1115	ksft_test_result(ret >= 0 && vec[0].start == (uintptr_t)mem && LEN(vec[0]) == vec_size &&
1116			 (vec[0].categories & (PAGE_IS_WRITTEN | PAGE_IS_PRESENT)) ==
1117			 (PAGE_IS_WRITTEN | PAGE_IS_PRESENT),
1118			 "%s Get sd and present pages with required_mask and anyof_mask\n",
1119			 __func__);
1120
1121	/* 5. Don't get sd pages */
1122	ret = pagemap_ioctl(mem, mem_size, vec, vec_size, 0, 0,
1123			    PAGE_IS_WRITTEN, 0, PAGE_IS_WRITTEN, PAGEMAP_BITS_ALL);
1124	ksft_test_result(ret == 0, "%s Don't get sd pages\n", __func__);
1125
1126	/* 6. Don't get present pages */
1127	ret = pagemap_ioctl(mem, mem_size, vec, vec_size, 0, 0,
1128			    PAGE_IS_PRESENT, 0, PAGE_IS_PRESENT, PAGEMAP_BITS_ALL);
1129	ksft_test_result(ret == 0, "%s Don't get present pages\n", __func__);
1130
1131	wp_free(mem, mem_size);
1132	munmap(mem, mem_size);
1133
1134	/* 8. Find written present pages with return mask */
1135	mem = mmap(NULL, mem_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
1136	if (mem == MAP_FAILED)
1137		ksft_exit_fail_msg("error nomem\n");
1138	wp_init(mem, mem_size);
1139	wp_addr_range(mem, mem_size);
1140
1141	memset(mem, 0, mem_size);
1142
1143	ret = pagemap_ioctl(mem, mem_size, vec, vec_size,
1144			    PM_SCAN_WP_MATCHING | PM_SCAN_CHECK_WPASYNC, 0,
1145			    0, PAGEMAP_BITS_ALL, 0, PAGE_IS_WRITTEN);
1146	ksft_test_result(ret >= 0 && vec[0].start == (uintptr_t)mem && LEN(vec[0]) == vec_size &&
1147			 vec[0].categories == PAGE_IS_WRITTEN,
1148			 "%s Find written present pages with return mask\n", __func__);
1149	wp_free(mem, mem_size);
1150	munmap(mem, mem_size);
1151
1152	/* 9. Memory mapped file */
1153	fd = open(progname, O_RDONLY);
1154	if (fd < 0)
1155		ksft_exit_fail_msg("%s Memory mapped file\n", __func__);
1156
1157	ret = stat(progname, &sbuf);
1158	if (ret < 0)
1159		ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno));
1160
1161	fmem = mmap(NULL, sbuf.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
1162	if (fmem == MAP_FAILED)
1163		ksft_exit_fail_msg("error nomem %d %s\n", errno, strerror(errno));
1164
1165	tmp_buf = malloc(sbuf.st_size);
1166	memcpy(tmp_buf, fmem, sbuf.st_size);
1167
1168	ret = pagemap_ioctl(fmem, sbuf.st_size, vec, vec_size, 0, 0,
1169			    0, PAGEMAP_NON_WRITTEN_BITS, 0, PAGEMAP_NON_WRITTEN_BITS);
1170
1171	ksft_test_result(ret >= 0 && vec[0].start == (uintptr_t)fmem &&
1172			 LEN(vec[0]) == ceilf((float)sbuf.st_size/page_size) &&
1173			 (vec[0].categories & PAGE_IS_FILE),
1174			 "%s Memory mapped file\n", __func__);
1175
1176	munmap(fmem, sbuf.st_size);
1177	close(fd);
1178
1179	/* 10. Create and read/write to a memory mapped file */
1180	buf_size = page_size * 10;
1181
1182	fd = open(__FILE__".tmp2", O_RDWR | O_CREAT, 0666);
1183	if (fd < 0)
1184		ksft_exit_fail_msg("Read/write to memory: %s\n",
1185				   strerror(errno));
1186
1187	for (i = 0; i < buf_size; i++)
1188		if (write(fd, "c", 1) < 0)
1189			ksft_exit_fail_msg("Create and read/write to a memory mapped file\n");
1190
1191	fmem = mmap(NULL, buf_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
1192	if (fmem == MAP_FAILED)
1193		ksft_exit_fail_msg("error nomem %d %s\n", errno, strerror(errno));
1194
1195	wp_init(fmem, buf_size);
1196	wp_addr_range(fmem, buf_size);
1197
1198	for (i = 0; i < buf_size; i++)
1199		fmem[i] = 'z';
1200
1201	msync(fmem, buf_size, MS_SYNC);
1202
1203	ret = pagemap_ioctl(fmem, buf_size, vec, vec_size, 0, 0,
1204			    PAGE_IS_WRITTEN, PAGE_IS_PRESENT | PAGE_IS_SWAPPED | PAGE_IS_FILE, 0,
1205			    PAGEMAP_BITS_ALL);
1206
1207	ksft_test_result(ret >= 0 && vec[0].start == (uintptr_t)fmem &&
1208			 LEN(vec[0]) == (buf_size/page_size) &&
1209			 (vec[0].categories & PAGE_IS_WRITTEN),
1210			 "%s Read/write to memory\n", __func__);
1211
1212	wp_free(fmem, buf_size);
1213	munmap(fmem, buf_size);
1214	close(fd);
1215
1216	free(vec);
1217	return 0;
1218}
1219
1220int mprotect_tests(void)
1221{
1222	int ret;
1223	char *mem, *mem2;
1224	struct page_region vec;
1225	int pagemap_fd = open("/proc/self/pagemap", O_RDONLY);
1226
1227	if (pagemap_fd < 0) {
1228		fprintf(stderr, "open() failed\n");
1229		exit(1);
1230	}
1231
1232	/* 1. Map two pages */
1233	mem = mmap(0, 2 * page_size, PROT_READ|PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
1234	if (mem == MAP_FAILED)
1235		ksft_exit_fail_msg("error nomem\n");
1236	wp_init(mem, 2 * page_size);
1237	wp_addr_range(mem, 2 * page_size);
1238
1239	/* Populate both pages. */
1240	memset(mem, 1, 2 * page_size);
1241
1242	ret = pagemap_ioctl(mem, 2 * page_size, &vec, 1, 0, 0, PAGE_IS_WRITTEN,
1243			    0, 0, PAGE_IS_WRITTEN);
1244	if (ret < 0)
1245		ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno));
1246
1247	ksft_test_result(ret == 1 && LEN(vec) == 2, "%s Both pages written\n", __func__);
1248
1249	/* 2. Start tracking */
1250	wp_addr_range(mem, 2 * page_size);
1251
1252	ksft_test_result(pagemap_ioctl(mem, 2 * page_size, &vec, 1, 0, 0,
1253				       PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN) == 0,
1254			 "%s Both pages are not written (dirty)\n", __func__);
1255
1256	/* 3. Remap the second page */
1257	mem2 = mmap(mem + page_size, page_size, PROT_READ|PROT_WRITE,
1258		    MAP_PRIVATE|MAP_ANON|MAP_FIXED, -1, 0);
1259	if (mem2 == MAP_FAILED)
1260		ksft_exit_fail_msg("error nomem\n");
1261	wp_init(mem2, page_size);
1262	wp_addr_range(mem2, page_size);
1263
1264	/* Protect + unprotect. */
1265	mprotect(mem, page_size, PROT_NONE);
1266	mprotect(mem, 2 * page_size, PROT_READ);
1267	mprotect(mem, 2 * page_size, PROT_READ|PROT_WRITE);
1268
1269	/* Modify both pages. */
1270	memset(mem, 2, 2 * page_size);
1271
1272	/* Protect + unprotect. */
1273	mprotect(mem, page_size, PROT_NONE);
1274	mprotect(mem, page_size, PROT_READ);
1275	mprotect(mem, page_size, PROT_READ|PROT_WRITE);
1276
1277	ret = pagemap_ioctl(mem, 2 * page_size, &vec, 1, 0, 0, PAGE_IS_WRITTEN,
1278			    0, 0, PAGE_IS_WRITTEN);
1279	if (ret < 0)
1280		ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno));
1281
1282	ksft_test_result(ret == 1 && LEN(vec) == 2,
1283			 "%s Both pages written after remap and mprotect\n", __func__);
1284
1285	/* 4. Clear and make the pages written */
1286	wp_addr_range(mem, 2 * page_size);
1287
1288	memset(mem, 'A', 2 * page_size);
1289
1290	ret = pagemap_ioctl(mem, 2 * page_size, &vec, 1, 0, 0, PAGE_IS_WRITTEN,
1291			    0, 0, PAGE_IS_WRITTEN);
1292	if (ret < 0)
1293		ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno));
1294
1295	ksft_test_result(ret == 1 && LEN(vec) == 2,
1296			 "%s Clear and make the pages written\n", __func__);
1297
1298	wp_free(mem, 2 * page_size);
1299	munmap(mem, 2 * page_size);
1300	return 0;
1301}
1302
1303/* transact test */
1304static const unsigned int nthreads = 6, pages_per_thread = 32, access_per_thread = 8;
1305static pthread_barrier_t start_barrier, end_barrier;
1306static unsigned int extra_thread_faults;
1307static unsigned int iter_count = 1000;
1308static volatile int finish;
1309
1310static ssize_t get_dirty_pages_reset(char *mem, unsigned int count,
1311				     int reset, int page_size)
1312{
1313	struct pm_scan_arg arg = {0};
1314	struct page_region rgns[256];
1315	int i, j, cnt, ret;
1316
1317	arg.size = sizeof(struct pm_scan_arg);
1318	arg.start = (uintptr_t)mem;
1319	arg.max_pages = count;
1320	arg.end = (uintptr_t)(mem + count * page_size);
1321	arg.vec = (uintptr_t)rgns;
1322	arg.vec_len = sizeof(rgns) / sizeof(*rgns);
1323	if (reset)
1324		arg.flags |= PM_SCAN_WP_MATCHING | PM_SCAN_CHECK_WPASYNC;
1325	arg.category_mask = PAGE_IS_WRITTEN;
1326	arg.return_mask = PAGE_IS_WRITTEN;
1327
1328	ret = ioctl(pagemap_fd, PAGEMAP_SCAN, &arg);
1329	if (ret < 0)
1330		ksft_exit_fail_msg("ioctl failed\n");
1331
1332	cnt = 0;
1333	for (i = 0; i < ret; ++i) {
1334		if (rgns[i].categories != PAGE_IS_WRITTEN)
1335			ksft_exit_fail_msg("wrong flags\n");
1336
1337		for (j = 0; j < LEN(rgns[i]); ++j)
1338			cnt++;
1339	}
1340
1341	return cnt;
1342}
1343
1344void *thread_proc(void *mem)
1345{
1346	int *m = mem;
1347	long curr_faults, faults;
1348	struct rusage r;
1349	unsigned int i;
1350	int ret;
1351
1352	if (getrusage(RUSAGE_THREAD, &r))
1353		ksft_exit_fail_msg("getrusage\n");
1354
1355	curr_faults = r.ru_minflt;
1356
1357	while (!finish) {
1358		ret = pthread_barrier_wait(&start_barrier);
1359		if (ret && ret != PTHREAD_BARRIER_SERIAL_THREAD)
1360			ksft_exit_fail_msg("pthread_barrier_wait\n");
1361
1362		for (i = 0; i < access_per_thread; ++i)
1363			__atomic_add_fetch(m + i * (0x1000 / sizeof(*m)), 1, __ATOMIC_SEQ_CST);
1364
1365		ret = pthread_barrier_wait(&end_barrier);
1366		if (ret && ret != PTHREAD_BARRIER_SERIAL_THREAD)
1367			ksft_exit_fail_msg("pthread_barrier_wait\n");
1368
1369		if (getrusage(RUSAGE_THREAD, &r))
1370			ksft_exit_fail_msg("getrusage\n");
1371
1372		faults = r.ru_minflt - curr_faults;
1373		if (faults < access_per_thread)
1374			ksft_exit_fail_msg("faults < access_per_thread");
1375
1376		__atomic_add_fetch(&extra_thread_faults, faults - access_per_thread,
1377				   __ATOMIC_SEQ_CST);
1378		curr_faults = r.ru_minflt;
1379	}
1380
1381	return NULL;
1382}
1383
1384static void transact_test(int page_size)
1385{
1386	unsigned int i, count, extra_pages;
1387	pthread_t th;
1388	char *mem;
1389	int ret, c;
1390
1391	if (pthread_barrier_init(&start_barrier, NULL, nthreads + 1))
1392		ksft_exit_fail_msg("pthread_barrier_init\n");
1393
1394	if (pthread_barrier_init(&end_barrier, NULL, nthreads + 1))
1395		ksft_exit_fail_msg("pthread_barrier_init\n");
1396
1397	mem = mmap(NULL, 0x1000 * nthreads * pages_per_thread, PROT_READ | PROT_WRITE,
1398		   MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
1399	if (mem == MAP_FAILED)
1400		ksft_exit_fail_msg("Error mmap %s.\n", strerror(errno));
1401
1402	wp_init(mem, 0x1000 * nthreads * pages_per_thread);
1403	wp_addr_range(mem, 0x1000 * nthreads * pages_per_thread);
1404
1405	memset(mem, 0, 0x1000 * nthreads * pages_per_thread);
1406
1407	count = get_dirty_pages_reset(mem, nthreads * pages_per_thread, 1, page_size);
1408	ksft_test_result(count > 0, "%s count %d\n", __func__, count);
1409	count = get_dirty_pages_reset(mem, nthreads * pages_per_thread, 1, page_size);
1410	ksft_test_result(count == 0, "%s count %d\n", __func__, count);
1411
1412	finish = 0;
1413	for (i = 0; i < nthreads; ++i)
1414		pthread_create(&th, NULL, thread_proc, mem + 0x1000 * i * pages_per_thread);
1415
1416	extra_pages = 0;
1417	for (i = 0; i < iter_count; ++i) {
1418		count = 0;
1419
1420		ret = pthread_barrier_wait(&start_barrier);
1421		if (ret && ret != PTHREAD_BARRIER_SERIAL_THREAD)
1422			ksft_exit_fail_msg("pthread_barrier_wait\n");
1423
1424		count = get_dirty_pages_reset(mem, nthreads * pages_per_thread, 1,
1425					      page_size);
1426
1427		ret = pthread_barrier_wait(&end_barrier);
1428		if (ret && ret != PTHREAD_BARRIER_SERIAL_THREAD)
1429			ksft_exit_fail_msg("pthread_barrier_wait\n");
1430
1431		if (count > nthreads * access_per_thread)
1432			ksft_exit_fail_msg("Too big count %d expected %d, iter %d\n",
1433					   count, nthreads * access_per_thread, i);
1434
1435		c = get_dirty_pages_reset(mem, nthreads * pages_per_thread, 1, page_size);
1436		count += c;
1437
1438		if (c > nthreads * access_per_thread) {
1439			ksft_test_result_fail(" %s count > nthreads\n", __func__);
1440			return;
1441		}
1442
1443		if (count != nthreads * access_per_thread) {
1444			/*
1445			 * The purpose of the test is to make sure that no page updates are lost
1446			 * when the page updates and read-resetting soft dirty flags are performed
1447			 * in parallel. However, it is possible that the application will get the
1448			 * soft dirty flags twice on the two consecutive read-resets. This seems
1449			 * unavoidable as soft dirty flag is handled in software through page faults
1450			 * in kernel. While the updating the flags is supposed to be synchronized
1451			 * between page fault handling and read-reset, it is possible that
1452			 * read-reset happens after page fault PTE update but before the application
1453			 * re-executes write instruction. So read-reset gets the flag, clears write
1454			 * access and application gets page fault again for the same write.
1455			 */
1456			if (count < nthreads * access_per_thread) {
1457				ksft_test_result_fail("Lost update, iter %d, %d vs %d.\n", i, count,
1458						      nthreads * access_per_thread);
1459				return;
1460			}
1461
1462			extra_pages += count - nthreads * access_per_thread;
1463		}
1464	}
1465
1466	pthread_barrier_wait(&start_barrier);
1467	finish = 1;
1468	pthread_barrier_wait(&end_barrier);
1469
1470	ksft_test_result_pass("%s Extra pages %u (%.1lf%%), extra thread faults %d.\n", __func__,
1471			      extra_pages,
1472			      100.0 * extra_pages / (iter_count * nthreads * access_per_thread),
1473			      extra_thread_faults);
1474}
1475
1476int main(int argc, char *argv[])
1477{
1478	int mem_size, shmid, buf_size, fd, i, ret;
1479	char *mem, *map, *fmem;
1480	struct stat sbuf;
1481
1482	progname = argv[0];
1483
1484	ksft_print_header();
1485
1486	if (init_uffd())
1487		return ksft_exit_pass();
1488
1489	ksft_set_plan(115);
1490
1491	page_size = getpagesize();
1492	hpage_size = read_pmd_pagesize();
1493
1494	pagemap_fd = open(PAGEMAP, O_RDONLY);
1495	if (pagemap_fd < 0)
1496		return -EINVAL;
1497
1498	/* 1. Sanity testing */
1499	sanity_tests_sd();
1500
1501	/* 2. Normal page testing */
1502	mem_size = 10 * page_size;
1503	mem = mmap(NULL, mem_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
1504	if (mem == MAP_FAILED)
1505		ksft_exit_fail_msg("error nomem\n");
1506	wp_init(mem, mem_size);
1507	wp_addr_range(mem, mem_size);
1508
1509	base_tests("Page testing:", mem, mem_size, 0);
1510
1511	wp_free(mem, mem_size);
1512	munmap(mem, mem_size);
1513
1514	/* 3. Large page testing */
1515	mem_size = 512 * 10 * page_size;
1516	mem = mmap(NULL, mem_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
1517	if (mem == MAP_FAILED)
1518		ksft_exit_fail_msg("error nomem\n");
1519	wp_init(mem, mem_size);
1520	wp_addr_range(mem, mem_size);
1521
1522	base_tests("Large Page testing:", mem, mem_size, 0);
1523
1524	wp_free(mem, mem_size);
1525	munmap(mem, mem_size);
1526
1527	/* 4. Huge page testing */
1528	map = gethugepage(hpage_size);
1529	if (map) {
1530		wp_init(map, hpage_size);
1531		wp_addr_range(map, hpage_size);
1532		base_tests("Huge page testing:", map, hpage_size, 0);
1533		wp_free(map, hpage_size);
1534		free(map);
1535	} else {
1536		base_tests("Huge page testing:", NULL, 0, 1);
1537	}
1538
1539	/* 5. SHM Hugetlb page testing */
1540	mem_size = 2*1024*1024;
1541	mem = gethugetlb_mem(mem_size, &shmid);
1542	if (mem) {
1543		wp_init(mem, mem_size);
1544		wp_addr_range(mem, mem_size);
1545
1546		base_tests("Hugetlb shmem testing:", mem, mem_size, 0);
1547
1548		wp_free(mem, mem_size);
1549		shmctl(shmid, IPC_RMID, NULL);
1550	} else {
1551		base_tests("Hugetlb shmem testing:", NULL, 0, 1);
1552	}
1553
1554	/* 6. Hugetlb page testing */
1555	mem = gethugetlb_mem(mem_size, NULL);
1556	if (mem) {
1557		wp_init(mem, mem_size);
1558		wp_addr_range(mem, mem_size);
1559
1560		base_tests("Hugetlb mem testing:", mem, mem_size, 0);
1561
1562		wp_free(mem, mem_size);
1563	} else {
1564		base_tests("Hugetlb mem testing:", NULL, 0, 1);
1565	}
1566
1567	/* 7. File Hugetlb testing */
1568	mem_size = 2*1024*1024;
1569	fd = memfd_create("uffd-test", MFD_HUGETLB | MFD_NOEXEC_SEAL);
1570	mem = mmap(NULL, mem_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
1571	if (mem) {
1572		wp_init(mem, mem_size);
1573		wp_addr_range(mem, mem_size);
1574
1575		base_tests("Hugetlb shmem testing:", mem, mem_size, 0);
1576
1577		wp_free(mem, mem_size);
1578		shmctl(shmid, IPC_RMID, NULL);
1579	} else {
1580		base_tests("Hugetlb shmem testing:", NULL, 0, 1);
1581	}
1582	close(fd);
1583
1584	/* 8. File memory testing */
1585	buf_size = page_size * 10;
1586
1587	fd = open(__FILE__".tmp0", O_RDWR | O_CREAT, 0777);
1588	if (fd < 0)
1589		ksft_exit_fail_msg("Create and read/write to a memory mapped file: %s\n",
1590				   strerror(errno));
1591
1592	for (i = 0; i < buf_size; i++)
1593		if (write(fd, "c", 1) < 0)
1594			ksft_exit_fail_msg("Create and read/write to a memory mapped file\n");
1595
1596	ret = stat(__FILE__".tmp0", &sbuf);
1597	if (ret < 0)
1598		ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno));
1599
1600	fmem = mmap(NULL, sbuf.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
1601	if (fmem == MAP_FAILED)
1602		ksft_exit_fail_msg("error nomem %d %s\n", errno, strerror(errno));
1603
1604	wp_init(fmem, sbuf.st_size);
1605	wp_addr_range(fmem, sbuf.st_size);
1606
1607	base_tests("File memory testing:", fmem, sbuf.st_size, 0);
1608
1609	wp_free(fmem, sbuf.st_size);
1610	munmap(fmem, sbuf.st_size);
1611	close(fd);
1612
1613	/* 9. File memory testing */
1614	buf_size = page_size * 10;
1615
1616	fd = memfd_create(__FILE__".tmp00", MFD_NOEXEC_SEAL);
1617	if (fd < 0)
1618		ksft_exit_fail_msg("Create and read/write to a memory mapped file: %s\n",
1619				   strerror(errno));
1620
1621	if (ftruncate(fd, buf_size))
1622		ksft_exit_fail_msg("Error ftruncate\n");
1623
1624	for (i = 0; i < buf_size; i++)
1625		if (write(fd, "c", 1) < 0)
1626			ksft_exit_fail_msg("Create and read/write to a memory mapped file\n");
1627
1628	fmem = mmap(NULL, buf_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
1629	if (fmem == MAP_FAILED)
1630		ksft_exit_fail_msg("error nomem %d %s\n", errno, strerror(errno));
1631
1632	wp_init(fmem, buf_size);
1633	wp_addr_range(fmem, buf_size);
1634
1635	base_tests("File anonymous memory testing:", fmem, buf_size, 0);
1636
1637	wp_free(fmem, buf_size);
1638	munmap(fmem, buf_size);
1639	close(fd);
1640
1641	/* 10. Huge page tests */
1642	hpage_unit_tests();
1643
1644	/* 11. Iterative test */
1645	test_simple();
1646
1647	/* 12. Mprotect test */
1648	mprotect_tests();
1649
1650	/* 13. Transact test */
1651	transact_test(page_size);
1652
1653	/* 14. Sanity testing */
1654	sanity_tests();
1655
1656	/*15. Unmapped address test */
1657	unmapped_region_tests();
1658
1659	/* 16. Userfaultfd tests */
1660	userfaultfd_tests();
1661
1662	close(pagemap_fd);
1663	return ksft_exit_pass();
1664}