mremap_test.c 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Copyright 2020 Google LLC
  4. */
  5. #define _GNU_SOURCE
  6. #include <errno.h>
  7. #include <stdlib.h>
  8. #include <stdio.h>
  9. #include <string.h>
  10. #include <sys/mman.h>
  11. #include <time.h>
  12. #include <stdbool.h>
  13. #include "../kselftest.h"
  14. #define EXPECT_SUCCESS 0
  15. #define EXPECT_FAILURE 1
  16. #define NON_OVERLAPPING 0
  17. #define OVERLAPPING 1
  18. #define NS_PER_SEC 1000000000ULL
  19. #define VALIDATION_DEFAULT_THRESHOLD 4 /* 4MB */
  20. #define VALIDATION_NO_THRESHOLD 0 /* Verify the entire region */
  21. #ifndef MIN
  22. #define MIN(X, Y) ((X) < (Y) ? (X) : (Y))
  23. #define MAX(X, Y) ((X) > (Y) ? (X) : (Y))
  24. #endif
  25. #define SIZE_MB(m) ((size_t)m * (1024 * 1024))
  26. #define SIZE_KB(k) ((size_t)k * 1024)
  27. struct config {
  28. unsigned long long src_alignment;
  29. unsigned long long dest_alignment;
  30. unsigned long long region_size;
  31. int overlapping;
  32. int dest_preamble_size;
  33. };
  34. struct test {
  35. const char *name;
  36. struct config config;
  37. int expect_failure;
  38. };
  39. enum {
  40. _1KB = 1ULL << 10, /* 1KB -> not page aligned */
  41. _4KB = 4ULL << 10,
  42. _8KB = 8ULL << 10,
  43. _1MB = 1ULL << 20,
  44. _2MB = 2ULL << 20,
  45. _4MB = 4ULL << 20,
  46. _5MB = 5ULL << 20,
  47. _1GB = 1ULL << 30,
  48. _2GB = 2ULL << 30,
  49. PMD = _2MB,
  50. PUD = _1GB,
  51. };
  52. #define PTE page_size
  53. #define MAKE_TEST(source_align, destination_align, size, \
  54. overlaps, should_fail, test_name) \
  55. (struct test){ \
  56. .name = test_name, \
  57. .config = { \
  58. .src_alignment = source_align, \
  59. .dest_alignment = destination_align, \
  60. .region_size = size, \
  61. .overlapping = overlaps, \
  62. }, \
  63. .expect_failure = should_fail \
  64. }
  65. /* compute square root using binary search */
  66. static unsigned long get_sqrt(unsigned long val)
  67. {
  68. unsigned long low = 1;
  69. /* assuming rand_size is less than 1TB */
  70. unsigned long high = (1UL << 20);
  71. while (low <= high) {
  72. unsigned long mid = low + (high - low) / 2;
  73. unsigned long temp = mid * mid;
  74. if (temp == val)
  75. return mid;
  76. if (temp < val)
  77. low = mid + 1;
  78. high = mid - 1;
  79. }
  80. return low;
  81. }
  82. /*
  83. * Returns false if the requested remap region overlaps with an
  84. * existing mapping (e.g text, stack) else returns true.
  85. */
  86. static bool is_remap_region_valid(void *addr, unsigned long long size)
  87. {
  88. void *remap_addr = NULL;
  89. bool ret = true;
  90. /* Use MAP_FIXED_NOREPLACE flag to ensure region is not mapped */
  91. remap_addr = mmap(addr, size, PROT_READ | PROT_WRITE,
  92. MAP_FIXED_NOREPLACE | MAP_ANONYMOUS | MAP_SHARED,
  93. -1, 0);
  94. if (remap_addr == MAP_FAILED) {
  95. if (errno == EEXIST)
  96. ret = false;
  97. } else {
  98. munmap(remap_addr, size);
  99. }
  100. return ret;
  101. }
  102. /* Returns mmap_min_addr sysctl tunable from procfs */
  103. static unsigned long long get_mmap_min_addr(void)
  104. {
  105. FILE *fp;
  106. int n_matched;
  107. static unsigned long long addr;
  108. if (addr)
  109. return addr;
  110. fp = fopen("/proc/sys/vm/mmap_min_addr", "r");
  111. if (fp == NULL) {
  112. ksft_print_msg("Failed to open /proc/sys/vm/mmap_min_addr: %s\n",
  113. strerror(errno));
  114. exit(KSFT_SKIP);
  115. }
  116. n_matched = fscanf(fp, "%llu", &addr);
  117. if (n_matched != 1) {
  118. ksft_print_msg("Failed to read /proc/sys/vm/mmap_min_addr: %s\n",
  119. strerror(errno));
  120. fclose(fp);
  121. exit(KSFT_SKIP);
  122. }
  123. fclose(fp);
  124. return addr;
  125. }
  126. /*
  127. * Using /proc/self/maps, assert that the specified address range is contained
  128. * within a single mapping.
  129. */
  130. static bool is_range_mapped(FILE *maps_fp, unsigned long start,
  131. unsigned long end)
  132. {
  133. char *line = NULL;
  134. size_t len = 0;
  135. bool success = false;
  136. unsigned long first_val, second_val;
  137. rewind(maps_fp);
  138. while (getline(&line, &len, maps_fp) != -1) {
  139. if (sscanf(line, "%lx-%lx", &first_val, &second_val) != 2) {
  140. ksft_exit_fail_msg("cannot parse /proc/self/maps\n");
  141. break;
  142. }
  143. if (first_val <= start && second_val >= end) {
  144. success = true;
  145. break;
  146. }
  147. }
  148. return success;
  149. }
  150. /*
  151. * Returns the start address of the mapping on success, else returns
  152. * NULL on failure.
  153. */
  154. static void *get_source_mapping(struct config c)
  155. {
  156. unsigned long long addr = 0ULL;
  157. void *src_addr = NULL;
  158. unsigned long long mmap_min_addr;
  159. mmap_min_addr = get_mmap_min_addr();
  160. /*
  161. * For some tests, we need to not have any mappings below the
  162. * source mapping. Add some headroom to mmap_min_addr for this.
  163. */
  164. mmap_min_addr += 10 * _4MB;
  165. retry:
  166. addr += c.src_alignment;
  167. if (addr < mmap_min_addr)
  168. goto retry;
  169. src_addr = mmap((void *) addr, c.region_size, PROT_READ | PROT_WRITE,
  170. MAP_FIXED_NOREPLACE | MAP_ANONYMOUS | MAP_SHARED,
  171. -1, 0);
  172. if (src_addr == MAP_FAILED) {
  173. if (errno == EPERM || errno == EEXIST)
  174. goto retry;
  175. goto error;
  176. }
  177. /*
  178. * Check that the address is aligned to the specified alignment.
  179. * Addresses which have alignments that are multiples of that
  180. * specified are not considered valid. For instance, 1GB address is
  181. * 2MB-aligned, however it will not be considered valid for a
  182. * requested alignment of 2MB. This is done to reduce coincidental
  183. * alignment in the tests.
  184. */
  185. if (((unsigned long long) src_addr & (c.src_alignment - 1)) ||
  186. !((unsigned long long) src_addr & c.src_alignment)) {
  187. munmap(src_addr, c.region_size);
  188. goto retry;
  189. }
  190. if (!src_addr)
  191. goto error;
  192. return src_addr;
  193. error:
  194. ksft_print_msg("Failed to map source region: %s\n",
  195. strerror(errno));
  196. return NULL;
  197. }
  198. /*
  199. * This test validates that merge is called when expanding a mapping.
  200. * Mapping containing three pages is created, middle page is unmapped
  201. * and then the mapping containing the first page is expanded so that
  202. * it fills the created hole. The two parts should merge creating
  203. * single mapping with three pages.
  204. */
  205. static void mremap_expand_merge(FILE *maps_fp, unsigned long page_size)
  206. {
  207. char *test_name = "mremap expand merge";
  208. bool success = false;
  209. char *remap, *start;
  210. start = mmap(NULL, 3 * page_size, PROT_READ | PROT_WRITE,
  211. MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
  212. if (start == MAP_FAILED) {
  213. ksft_print_msg("mmap failed: %s\n", strerror(errno));
  214. goto out;
  215. }
  216. munmap(start + page_size, page_size);
  217. remap = mremap(start, page_size, 2 * page_size, 0);
  218. if (remap == MAP_FAILED) {
  219. ksft_print_msg("mremap failed: %s\n", strerror(errno));
  220. munmap(start, page_size);
  221. munmap(start + 2 * page_size, page_size);
  222. goto out;
  223. }
  224. success = is_range_mapped(maps_fp, (unsigned long)start,
  225. (unsigned long)(start + 3 * page_size));
  226. munmap(start, 3 * page_size);
  227. out:
  228. if (success)
  229. ksft_test_result_pass("%s\n", test_name);
  230. else
  231. ksft_test_result_fail("%s\n", test_name);
  232. }
  233. /*
  234. * Similar to mremap_expand_merge() except instead of removing the middle page,
  235. * we remove the last then attempt to remap offset from the second page. This
  236. * should result in the mapping being restored to its former state.
  237. */
  238. static void mremap_expand_merge_offset(FILE *maps_fp, unsigned long page_size)
  239. {
  240. char *test_name = "mremap expand merge offset";
  241. bool success = false;
  242. char *remap, *start;
  243. start = mmap(NULL, 3 * page_size, PROT_READ | PROT_WRITE,
  244. MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
  245. if (start == MAP_FAILED) {
  246. ksft_print_msg("mmap failed: %s\n", strerror(errno));
  247. goto out;
  248. }
  249. /* Unmap final page to ensure we have space to expand. */
  250. munmap(start + 2 * page_size, page_size);
  251. remap = mremap(start + page_size, page_size, 2 * page_size, 0);
  252. if (remap == MAP_FAILED) {
  253. ksft_print_msg("mremap failed: %s\n", strerror(errno));
  254. munmap(start, 2 * page_size);
  255. goto out;
  256. }
  257. success = is_range_mapped(maps_fp, (unsigned long)start,
  258. (unsigned long)(start + 3 * page_size));
  259. munmap(start, 3 * page_size);
  260. out:
  261. if (success)
  262. ksft_test_result_pass("%s\n", test_name);
  263. else
  264. ksft_test_result_fail("%s\n", test_name);
  265. }
  266. /*
  267. * Verify that an mremap within a range does not cause corruption
  268. * of unrelated part of range.
  269. *
  270. * Consider the following range which is 2MB aligned and is
  271. * a part of a larger 20MB range which is not shown. Each
  272. * character is 256KB below making the source and destination
  273. * 2MB each. The lower case letters are moved (s to d) and the
  274. * upper case letters are not moved. The below test verifies
  275. * that the upper case S letters are not corrupted by the
  276. * adjacent mremap.
  277. *
  278. * |DDDDddddSSSSssss|
  279. */
  280. static void mremap_move_within_range(unsigned int pattern_seed, char *rand_addr)
  281. {
  282. char *test_name = "mremap mremap move within range";
  283. void *src, *dest;
  284. int i, success = 1;
  285. size_t size = SIZE_MB(20);
  286. void *ptr = mmap(NULL, size, PROT_READ | PROT_WRITE,
  287. MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
  288. if (ptr == MAP_FAILED) {
  289. perror("mmap");
  290. success = 0;
  291. goto out;
  292. }
  293. memset(ptr, 0, size);
  294. src = ptr + SIZE_MB(6);
  295. src = (void *)((unsigned long)src & ~(SIZE_MB(2) - 1));
  296. /* Set byte pattern for source block. */
  297. memcpy(src, rand_addr, SIZE_MB(2));
  298. dest = src - SIZE_MB(2);
  299. void *new_ptr = mremap(src + SIZE_MB(1), SIZE_MB(1), SIZE_MB(1),
  300. MREMAP_MAYMOVE | MREMAP_FIXED, dest + SIZE_MB(1));
  301. if (new_ptr == MAP_FAILED) {
  302. perror("mremap");
  303. success = 0;
  304. goto out;
  305. }
  306. /* Verify byte pattern after remapping */
  307. srand(pattern_seed);
  308. for (i = 0; i < SIZE_MB(1); i++) {
  309. char c = (char) rand();
  310. if (((char *)src)[i] != c) {
  311. ksft_print_msg("Data at src at %d got corrupted due to unrelated mremap\n",
  312. i);
  313. ksft_print_msg("Expected: %#x\t Got: %#x\n", c & 0xff,
  314. ((char *) src)[i] & 0xff);
  315. success = 0;
  316. }
  317. }
  318. out:
  319. if (munmap(ptr, size) == -1)
  320. perror("munmap");
  321. if (success)
  322. ksft_test_result_pass("%s\n", test_name);
  323. else
  324. ksft_test_result_fail("%s\n", test_name);
  325. }
  326. /* Returns the time taken for the remap on success else returns -1. */
  327. static long long remap_region(struct config c, unsigned int threshold_mb,
  328. char *rand_addr)
  329. {
  330. void *addr, *src_addr, *dest_addr, *dest_preamble_addr;
  331. unsigned long long t, d;
  332. struct timespec t_start = {0, 0}, t_end = {0, 0};
  333. long long start_ns, end_ns, align_mask, ret, offset;
  334. unsigned long long threshold;
  335. unsigned long num_chunks;
  336. if (threshold_mb == VALIDATION_NO_THRESHOLD)
  337. threshold = c.region_size;
  338. else
  339. threshold = MIN(threshold_mb * _1MB, c.region_size);
  340. src_addr = get_source_mapping(c);
  341. if (!src_addr) {
  342. ret = -1;
  343. goto out;
  344. }
  345. /* Set byte pattern for source block. */
  346. memcpy(src_addr, rand_addr, threshold);
  347. /* Mask to zero out lower bits of address for alignment */
  348. align_mask = ~(c.dest_alignment - 1);
  349. /* Offset of destination address from the end of the source region */
  350. offset = (c.overlapping) ? -c.dest_alignment : c.dest_alignment;
  351. addr = (void *) (((unsigned long long) src_addr + c.region_size
  352. + offset) & align_mask);
  353. /* Remap after the destination block preamble. */
  354. addr += c.dest_preamble_size;
  355. /* See comment in get_source_mapping() */
  356. if (!((unsigned long long) addr & c.dest_alignment))
  357. addr = (void *) ((unsigned long long) addr | c.dest_alignment);
  358. /* Don't destroy existing mappings unless expected to overlap */
  359. while (!is_remap_region_valid(addr, c.region_size) && !c.overlapping) {
  360. /* Check for unsigned overflow */
  361. if (addr + c.dest_alignment < addr) {
  362. ksft_print_msg("Couldn't find a valid region to remap to\n");
  363. ret = -1;
  364. goto clean_up_src;
  365. }
  366. addr += c.dest_alignment;
  367. }
  368. if (c.dest_preamble_size) {
  369. dest_preamble_addr = mmap((void *) addr - c.dest_preamble_size, c.dest_preamble_size,
  370. PROT_READ | PROT_WRITE,
  371. MAP_FIXED_NOREPLACE | MAP_ANONYMOUS | MAP_SHARED,
  372. -1, 0);
  373. if (dest_preamble_addr == MAP_FAILED) {
  374. ksft_print_msg("Failed to map dest preamble region: %s\n",
  375. strerror(errno));
  376. ret = -1;
  377. goto clean_up_src;
  378. }
  379. /* Set byte pattern for the dest preamble block. */
  380. memcpy(dest_preamble_addr, rand_addr, c.dest_preamble_size);
  381. }
  382. clock_gettime(CLOCK_MONOTONIC, &t_start);
  383. dest_addr = mremap(src_addr, c.region_size, c.region_size,
  384. MREMAP_MAYMOVE|MREMAP_FIXED, (char *) addr);
  385. clock_gettime(CLOCK_MONOTONIC, &t_end);
  386. if (dest_addr == MAP_FAILED) {
  387. ksft_print_msg("mremap failed: %s\n", strerror(errno));
  388. ret = -1;
  389. goto clean_up_dest_preamble;
  390. }
  391. /*
  392. * Verify byte pattern after remapping. Employ an algorithm with a
  393. * square root time complexity in threshold: divide the range into
  394. * chunks, if memcmp() returns non-zero, only then perform an
  395. * iteration in that chunk to find the mismatch index.
  396. */
  397. num_chunks = get_sqrt(threshold);
  398. for (unsigned long i = 0; i < num_chunks; ++i) {
  399. size_t chunk_size = threshold / num_chunks;
  400. unsigned long shift = i * chunk_size;
  401. if (!memcmp(dest_addr + shift, rand_addr + shift, chunk_size))
  402. continue;
  403. /* brute force iteration only over mismatch segment */
  404. for (t = shift; t < shift + chunk_size; ++t) {
  405. if (((char *) dest_addr)[t] != rand_addr[t]) {
  406. ksft_print_msg("Data after remap doesn't match at offset %llu\n",
  407. t);
  408. ksft_print_msg("Expected: %#x\t Got: %#x\n", rand_addr[t] & 0xff,
  409. ((char *) dest_addr)[t] & 0xff);
  410. ret = -1;
  411. goto clean_up_dest;
  412. }
  413. }
  414. }
  415. /*
  416. * if threshold is not divisible by num_chunks, then check the
  417. * last chunk
  418. */
  419. for (t = num_chunks * (threshold / num_chunks); t < threshold; ++t) {
  420. if (((char *) dest_addr)[t] != rand_addr[t]) {
  421. ksft_print_msg("Data after remap doesn't match at offset %llu\n",
  422. t);
  423. ksft_print_msg("Expected: %#x\t Got: %#x\n", rand_addr[t] & 0xff,
  424. ((char *) dest_addr)[t] & 0xff);
  425. ret = -1;
  426. goto clean_up_dest;
  427. }
  428. }
  429. /* Verify the dest preamble byte pattern after remapping */
  430. if (!c.dest_preamble_size)
  431. goto no_preamble;
  432. num_chunks = get_sqrt(c.dest_preamble_size);
  433. for (unsigned long i = 0; i < num_chunks; ++i) {
  434. size_t chunk_size = c.dest_preamble_size / num_chunks;
  435. unsigned long shift = i * chunk_size;
  436. if (!memcmp(dest_preamble_addr + shift, rand_addr + shift,
  437. chunk_size))
  438. continue;
  439. /* brute force iteration only over mismatched segment */
  440. for (d = shift; d < shift + chunk_size; ++d) {
  441. if (((char *) dest_preamble_addr)[d] != rand_addr[d]) {
  442. ksft_print_msg("Preamble data after remap doesn't match at offset %llu\n",
  443. d);
  444. ksft_print_msg("Expected: %#x\t Got: %#x\n", rand_addr[d] & 0xff,
  445. ((char *) dest_preamble_addr)[d] & 0xff);
  446. ret = -1;
  447. goto clean_up_dest;
  448. }
  449. }
  450. }
  451. for (d = num_chunks * (c.dest_preamble_size / num_chunks); d < c.dest_preamble_size; ++d) {
  452. if (((char *) dest_preamble_addr)[d] != rand_addr[d]) {
  453. ksft_print_msg("Preamble data after remap doesn't match at offset %llu\n",
  454. d);
  455. ksft_print_msg("Expected: %#x\t Got: %#x\n", rand_addr[d] & 0xff,
  456. ((char *) dest_preamble_addr)[d] & 0xff);
  457. ret = -1;
  458. goto clean_up_dest;
  459. }
  460. }
  461. no_preamble:
  462. start_ns = t_start.tv_sec * NS_PER_SEC + t_start.tv_nsec;
  463. end_ns = t_end.tv_sec * NS_PER_SEC + t_end.tv_nsec;
  464. ret = end_ns - start_ns;
  465. /*
  466. * Since the destination address is specified using MREMAP_FIXED, subsequent
  467. * mremap will unmap any previous mapping at the address range specified by
  468. * dest_addr and region_size. This significantly affects the remap time of
  469. * subsequent tests. So we clean up mappings after each test.
  470. */
  471. clean_up_dest:
  472. munmap(dest_addr, c.region_size);
  473. clean_up_dest_preamble:
  474. if (c.dest_preamble_size && dest_preamble_addr)
  475. munmap(dest_preamble_addr, c.dest_preamble_size);
  476. clean_up_src:
  477. munmap(src_addr, c.region_size);
  478. out:
  479. return ret;
  480. }
  481. /*
  482. * Verify that an mremap aligning down does not destroy
  483. * the beginning of the mapping just because the aligned
  484. * down address landed on a mapping that maybe does not exist.
  485. */
  486. static void mremap_move_1mb_from_start(unsigned int pattern_seed,
  487. char *rand_addr)
  488. {
  489. char *test_name = "mremap move 1mb from start at 1MB+256KB aligned src";
  490. void *src = NULL, *dest = NULL;
  491. int i, success = 1;
  492. /* Config to reuse get_source_mapping() to do an aligned mmap. */
  493. struct config c = {
  494. .src_alignment = SIZE_MB(1) + SIZE_KB(256),
  495. .region_size = SIZE_MB(6)
  496. };
  497. src = get_source_mapping(c);
  498. if (!src) {
  499. success = 0;
  500. goto out;
  501. }
  502. c.src_alignment = SIZE_MB(1) + SIZE_KB(256);
  503. dest = get_source_mapping(c);
  504. if (!dest) {
  505. success = 0;
  506. goto out;
  507. }
  508. /* Set byte pattern for source block. */
  509. memcpy(src, rand_addr, SIZE_MB(2));
  510. /*
  511. * Unmap the beginning of dest so that the aligned address
  512. * falls on no mapping.
  513. */
  514. munmap(dest, SIZE_MB(1));
  515. void *new_ptr = mremap(src + SIZE_MB(1), SIZE_MB(1), SIZE_MB(1),
  516. MREMAP_MAYMOVE | MREMAP_FIXED, dest + SIZE_MB(1));
  517. if (new_ptr == MAP_FAILED) {
  518. perror("mremap");
  519. success = 0;
  520. goto out;
  521. }
  522. /* Verify byte pattern after remapping */
  523. srand(pattern_seed);
  524. for (i = 0; i < SIZE_MB(1); i++) {
  525. char c = (char) rand();
  526. if (((char *)src)[i] != c) {
  527. ksft_print_msg("Data at src at %d got corrupted due to unrelated mremap\n",
  528. i);
  529. ksft_print_msg("Expected: %#x\t Got: %#x\n", c & 0xff,
  530. ((char *) src)[i] & 0xff);
  531. success = 0;
  532. }
  533. }
  534. out:
  535. if (src && munmap(src, c.region_size) == -1)
  536. perror("munmap src");
  537. if (dest && munmap(dest, c.region_size) == -1)
  538. perror("munmap dest");
  539. if (success)
  540. ksft_test_result_pass("%s\n", test_name);
  541. else
  542. ksft_test_result_fail("%s\n", test_name);
  543. }
  544. static void run_mremap_test_case(struct test test_case, int *failures,
  545. unsigned int threshold_mb,
  546. unsigned int pattern_seed, char *rand_addr)
  547. {
  548. long long remap_time = remap_region(test_case.config, threshold_mb,
  549. rand_addr);
  550. if (remap_time < 0) {
  551. if (test_case.expect_failure)
  552. ksft_test_result_xfail("%s\n\tExpected mremap failure\n",
  553. test_case.name);
  554. else {
  555. ksft_test_result_fail("%s\n", test_case.name);
  556. *failures += 1;
  557. }
  558. } else {
  559. /*
  560. * Comparing mremap time is only applicable if entire region
  561. * was faulted in.
  562. */
  563. if (threshold_mb == VALIDATION_NO_THRESHOLD ||
  564. test_case.config.region_size <= threshold_mb * _1MB)
  565. ksft_test_result_pass("%s\n\tmremap time: %12lldns\n",
  566. test_case.name, remap_time);
  567. else
  568. ksft_test_result_pass("%s\n", test_case.name);
  569. }
  570. }
  571. static void usage(const char *cmd)
  572. {
  573. fprintf(stderr,
  574. "Usage: %s [[-t <threshold_mb>] [-p <pattern_seed>]]\n"
  575. "-t\t only validate threshold_mb of the remapped region\n"
  576. " \t if 0 is supplied no threshold is used; all tests\n"
  577. " \t are run and remapped regions validated fully.\n"
  578. " \t The default threshold used is 4MB.\n"
  579. "-p\t provide a seed to generate the random pattern for\n"
  580. " \t validating the remapped region.\n", cmd);
  581. }
  582. static int parse_args(int argc, char **argv, unsigned int *threshold_mb,
  583. unsigned int *pattern_seed)
  584. {
  585. const char *optstr = "t:p:";
  586. int opt;
  587. while ((opt = getopt(argc, argv, optstr)) != -1) {
  588. switch (opt) {
  589. case 't':
  590. *threshold_mb = atoi(optarg);
  591. break;
  592. case 'p':
  593. *pattern_seed = atoi(optarg);
  594. break;
  595. default:
  596. usage(argv[0]);
  597. return -1;
  598. }
  599. }
  600. if (optind < argc) {
  601. usage(argv[0]);
  602. return -1;
  603. }
  604. return 0;
  605. }
  606. #define MAX_TEST 15
  607. #define MAX_PERF_TEST 3
  608. int main(int argc, char **argv)
  609. {
  610. int failures = 0;
  611. int i, run_perf_tests;
  612. unsigned int threshold_mb = VALIDATION_DEFAULT_THRESHOLD;
  613. /* hard-coded test configs */
  614. size_t max_test_variable_region_size = _2GB;
  615. size_t max_test_constant_region_size = _2MB;
  616. size_t dest_preamble_size = 10 * _4MB;
  617. unsigned int pattern_seed;
  618. char *rand_addr;
  619. size_t rand_size;
  620. int num_expand_tests = 2;
  621. int num_misc_tests = 2;
  622. struct test test_cases[MAX_TEST] = {};
  623. struct test perf_test_cases[MAX_PERF_TEST];
  624. int page_size;
  625. time_t t;
  626. FILE *maps_fp;
  627. pattern_seed = (unsigned int) time(&t);
  628. if (parse_args(argc, argv, &threshold_mb, &pattern_seed) < 0)
  629. exit(EXIT_FAILURE);
  630. ksft_print_msg("Test configs:\n\tthreshold_mb=%u\n\tpattern_seed=%u\n\n",
  631. threshold_mb, pattern_seed);
  632. /*
  633. * set preallocated random array according to test configs; see the
  634. * functions for the logic of setting the size
  635. */
  636. if (!threshold_mb)
  637. rand_size = MAX(max_test_variable_region_size,
  638. max_test_constant_region_size);
  639. else
  640. rand_size = MAX(MIN(threshold_mb * _1MB,
  641. max_test_variable_region_size),
  642. max_test_constant_region_size);
  643. rand_size = MAX(dest_preamble_size, rand_size);
  644. rand_addr = (char *)mmap(NULL, rand_size, PROT_READ | PROT_WRITE,
  645. MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
  646. if (rand_addr == MAP_FAILED) {
  647. perror("mmap");
  648. ksft_exit_fail_msg("cannot mmap rand_addr\n");
  649. }
  650. /* fill stream of random bytes */
  651. srand(pattern_seed);
  652. for (unsigned long i = 0; i < rand_size; ++i)
  653. rand_addr[i] = (char) rand();
  654. page_size = sysconf(_SC_PAGESIZE);
  655. /* Expected mremap failures */
  656. test_cases[0] = MAKE_TEST(page_size, page_size, page_size,
  657. OVERLAPPING, EXPECT_FAILURE,
  658. "mremap - Source and Destination Regions Overlapping");
  659. test_cases[1] = MAKE_TEST(page_size, page_size/4, page_size,
  660. NON_OVERLAPPING, EXPECT_FAILURE,
  661. "mremap - Destination Address Misaligned (1KB-aligned)");
  662. test_cases[2] = MAKE_TEST(page_size/4, page_size, page_size,
  663. NON_OVERLAPPING, EXPECT_FAILURE,
  664. "mremap - Source Address Misaligned (1KB-aligned)");
  665. /* Src addr PTE aligned */
  666. test_cases[3] = MAKE_TEST(PTE, PTE, PTE * 2,
  667. NON_OVERLAPPING, EXPECT_SUCCESS,
  668. "8KB mremap - Source PTE-aligned, Destination PTE-aligned");
  669. /* Src addr 1MB aligned */
  670. test_cases[4] = MAKE_TEST(_1MB, PTE, _2MB, NON_OVERLAPPING, EXPECT_SUCCESS,
  671. "2MB mremap - Source 1MB-aligned, Destination PTE-aligned");
  672. test_cases[5] = MAKE_TEST(_1MB, _1MB, _2MB, NON_OVERLAPPING, EXPECT_SUCCESS,
  673. "2MB mremap - Source 1MB-aligned, Destination 1MB-aligned");
  674. /* Src addr PMD aligned */
  675. test_cases[6] = MAKE_TEST(PMD, PTE, _4MB, NON_OVERLAPPING, EXPECT_SUCCESS,
  676. "4MB mremap - Source PMD-aligned, Destination PTE-aligned");
  677. test_cases[7] = MAKE_TEST(PMD, _1MB, _4MB, NON_OVERLAPPING, EXPECT_SUCCESS,
  678. "4MB mremap - Source PMD-aligned, Destination 1MB-aligned");
  679. test_cases[8] = MAKE_TEST(PMD, PMD, _4MB, NON_OVERLAPPING, EXPECT_SUCCESS,
  680. "4MB mremap - Source PMD-aligned, Destination PMD-aligned");
  681. /* Src addr PUD aligned */
  682. test_cases[9] = MAKE_TEST(PUD, PTE, _2GB, NON_OVERLAPPING, EXPECT_SUCCESS,
  683. "2GB mremap - Source PUD-aligned, Destination PTE-aligned");
  684. test_cases[10] = MAKE_TEST(PUD, _1MB, _2GB, NON_OVERLAPPING, EXPECT_SUCCESS,
  685. "2GB mremap - Source PUD-aligned, Destination 1MB-aligned");
  686. test_cases[11] = MAKE_TEST(PUD, PMD, _2GB, NON_OVERLAPPING, EXPECT_SUCCESS,
  687. "2GB mremap - Source PUD-aligned, Destination PMD-aligned");
  688. test_cases[12] = MAKE_TEST(PUD, PUD, _2GB, NON_OVERLAPPING, EXPECT_SUCCESS,
  689. "2GB mremap - Source PUD-aligned, Destination PUD-aligned");
  690. /* Src and Dest addr 1MB aligned. 5MB mremap. */
  691. test_cases[13] = MAKE_TEST(_1MB, _1MB, _5MB, NON_OVERLAPPING, EXPECT_SUCCESS,
  692. "5MB mremap - Source 1MB-aligned, Destination 1MB-aligned");
  693. /* Src and Dest addr 1MB aligned. 5MB mremap. */
  694. test_cases[14] = MAKE_TEST(_1MB, _1MB, _5MB, NON_OVERLAPPING, EXPECT_SUCCESS,
  695. "5MB mremap - Source 1MB-aligned, Dest 1MB-aligned with 40MB Preamble");
  696. test_cases[14].config.dest_preamble_size = 10 * _4MB;
  697. perf_test_cases[0] = MAKE_TEST(page_size, page_size, _1GB, NON_OVERLAPPING, EXPECT_SUCCESS,
  698. "1GB mremap - Source PTE-aligned, Destination PTE-aligned");
  699. /*
  700. * mremap 1GB region - Page table level aligned time
  701. * comparison.
  702. */
  703. perf_test_cases[1] = MAKE_TEST(PMD, PMD, _1GB, NON_OVERLAPPING, EXPECT_SUCCESS,
  704. "1GB mremap - Source PMD-aligned, Destination PMD-aligned");
  705. perf_test_cases[2] = MAKE_TEST(PUD, PUD, _1GB, NON_OVERLAPPING, EXPECT_SUCCESS,
  706. "1GB mremap - Source PUD-aligned, Destination PUD-aligned");
  707. run_perf_tests = (threshold_mb == VALIDATION_NO_THRESHOLD) ||
  708. (threshold_mb * _1MB >= _1GB);
  709. ksft_set_plan(ARRAY_SIZE(test_cases) + (run_perf_tests ?
  710. ARRAY_SIZE(perf_test_cases) : 0) + num_expand_tests + num_misc_tests);
  711. for (i = 0; i < ARRAY_SIZE(test_cases); i++)
  712. run_mremap_test_case(test_cases[i], &failures, threshold_mb,
  713. pattern_seed, rand_addr);
  714. maps_fp = fopen("/proc/self/maps", "r");
  715. if (maps_fp == NULL) {
  716. munmap(rand_addr, rand_size);
  717. ksft_exit_fail_msg("Failed to read /proc/self/maps: %s\n", strerror(errno));
  718. }
  719. mremap_expand_merge(maps_fp, page_size);
  720. mremap_expand_merge_offset(maps_fp, page_size);
  721. fclose(maps_fp);
  722. mremap_move_within_range(pattern_seed, rand_addr);
  723. mremap_move_1mb_from_start(pattern_seed, rand_addr);
  724. if (run_perf_tests) {
  725. ksft_print_msg("\n%s\n",
  726. "mremap HAVE_MOVE_PMD/PUD optimization time comparison for 1GB region:");
  727. for (i = 0; i < ARRAY_SIZE(perf_test_cases); i++)
  728. run_mremap_test_case(perf_test_cases[i], &failures,
  729. threshold_mb, pattern_seed,
  730. rand_addr);
  731. }
  732. munmap(rand_addr, rand_size);
  733. if (failures > 0)
  734. ksft_exit_fail();
  735. else
  736. ksft_exit_pass();
  737. }