check_ksm_options.c 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. // SPDX-License-Identifier: GPL-2.0
  2. // Copyright (C) 2020 ARM Limited
  3. #define _GNU_SOURCE
  4. #include <errno.h>
  5. #include <fcntl.h>
  6. #include <signal.h>
  7. #include <stdio.h>
  8. #include <stdlib.h>
  9. #include <string.h>
  10. #include <ucontext.h>
  11. #include <sys/mman.h>
  12. #include "kselftest.h"
  13. #include "mte_common_util.h"
  14. #include "mte_def.h"
  15. #define TEST_UNIT 10
  16. #define PATH_KSM "/sys/kernel/mm/ksm/"
  17. #define MAX_LOOP 4
  18. static size_t page_sz;
  19. static unsigned long ksm_sysfs[5];
  20. static unsigned long read_sysfs(char *str)
  21. {
  22. FILE *f;
  23. unsigned long val = 0;
  24. f = fopen(str, "r");
  25. if (!f) {
  26. ksft_print_msg("ERR: missing %s\n", str);
  27. return 0;
  28. }
  29. if (fscanf(f, "%lu", &val) != 1) {
  30. ksft_print_msg("ERR: parsing %s\n", str);
  31. val = 0;
  32. }
  33. fclose(f);
  34. return val;
  35. }
  36. static void write_sysfs(char *str, unsigned long val)
  37. {
  38. FILE *f;
  39. f = fopen(str, "w");
  40. if (!f) {
  41. ksft_print_msg("ERR: missing %s\n", str);
  42. return;
  43. }
  44. fprintf(f, "%lu", val);
  45. fclose(f);
  46. }
  47. static void mte_ksm_setup(void)
  48. {
  49. ksm_sysfs[0] = read_sysfs(PATH_KSM "merge_across_nodes");
  50. write_sysfs(PATH_KSM "merge_across_nodes", 1);
  51. ksm_sysfs[1] = read_sysfs(PATH_KSM "sleep_millisecs");
  52. write_sysfs(PATH_KSM "sleep_millisecs", 0);
  53. ksm_sysfs[2] = read_sysfs(PATH_KSM "run");
  54. write_sysfs(PATH_KSM "run", 1);
  55. ksm_sysfs[3] = read_sysfs(PATH_KSM "max_page_sharing");
  56. write_sysfs(PATH_KSM "max_page_sharing", ksm_sysfs[3] + TEST_UNIT);
  57. ksm_sysfs[4] = read_sysfs(PATH_KSM "pages_to_scan");
  58. write_sysfs(PATH_KSM "pages_to_scan", ksm_sysfs[4] + TEST_UNIT);
  59. }
  60. static void mte_ksm_restore(void)
  61. {
  62. write_sysfs(PATH_KSM "merge_across_nodes", ksm_sysfs[0]);
  63. write_sysfs(PATH_KSM "sleep_millisecs", ksm_sysfs[1]);
  64. write_sysfs(PATH_KSM "run", ksm_sysfs[2]);
  65. write_sysfs(PATH_KSM "max_page_sharing", ksm_sysfs[3]);
  66. write_sysfs(PATH_KSM "pages_to_scan", ksm_sysfs[4]);
  67. }
  68. static void mte_ksm_scan(void)
  69. {
  70. int cur_count = read_sysfs(PATH_KSM "full_scans");
  71. int scan_count = cur_count + 1;
  72. int max_loop_count = MAX_LOOP;
  73. while ((cur_count < scan_count) && max_loop_count) {
  74. sleep(1);
  75. cur_count = read_sysfs(PATH_KSM "full_scans");
  76. max_loop_count--;
  77. }
  78. #ifdef DEBUG
  79. ksft_print_msg("INFO: pages_shared=%lu pages_sharing=%lu\n",
  80. read_sysfs(PATH_KSM "pages_shared"),
  81. read_sysfs(PATH_KSM "pages_sharing"));
  82. #endif
  83. }
  84. static int check_madvise_options(int mem_type, int mode, int mapping)
  85. {
  86. char *ptr;
  87. int err, ret;
  88. err = KSFT_FAIL;
  89. if (access(PATH_KSM, F_OK) == -1) {
  90. ksft_print_msg("ERR: Kernel KSM config not enabled\n");
  91. return err;
  92. }
  93. mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG);
  94. ptr = mte_allocate_memory(TEST_UNIT * page_sz, mem_type, mapping, true);
  95. if (check_allocated_memory(ptr, TEST_UNIT * page_sz, mem_type, false) != KSFT_PASS)
  96. return KSFT_FAIL;
  97. /* Insert same data in all the pages */
  98. memset(ptr, 'A', TEST_UNIT * page_sz);
  99. ret = madvise(ptr, TEST_UNIT * page_sz, MADV_MERGEABLE);
  100. if (ret) {
  101. ksft_print_msg("ERR: madvise failed to set MADV_UNMERGEABLE\n");
  102. goto madvise_err;
  103. }
  104. mte_ksm_scan();
  105. /* Tagged pages should not merge */
  106. if ((read_sysfs(PATH_KSM "pages_shared") < 1) ||
  107. (read_sysfs(PATH_KSM "pages_sharing") < (TEST_UNIT - 1)))
  108. err = KSFT_PASS;
  109. madvise_err:
  110. mte_free_memory(ptr, TEST_UNIT * page_sz, mem_type, true);
  111. return err;
  112. }
  113. int main(int argc, char *argv[])
  114. {
  115. int err;
  116. err = mte_default_setup();
  117. if (err)
  118. return err;
  119. page_sz = getpagesize();
  120. if (!page_sz) {
  121. ksft_print_msg("ERR: Unable to get page size\n");
  122. return KSFT_FAIL;
  123. }
  124. /* Register signal handlers */
  125. mte_register_signal(SIGBUS, mte_default_handler);
  126. mte_register_signal(SIGSEGV, mte_default_handler);
  127. /* Set test plan */
  128. ksft_set_plan(4);
  129. /* Enable KSM */
  130. mte_ksm_setup();
  131. evaluate_test(check_madvise_options(USE_MMAP, MTE_SYNC_ERR, MAP_PRIVATE),
  132. "Check KSM mte page merge for private mapping, sync mode and mmap memory\n");
  133. evaluate_test(check_madvise_options(USE_MMAP, MTE_ASYNC_ERR, MAP_PRIVATE),
  134. "Check KSM mte page merge for private mapping, async mode and mmap memory\n");
  135. evaluate_test(check_madvise_options(USE_MMAP, MTE_SYNC_ERR, MAP_SHARED),
  136. "Check KSM mte page merge for shared mapping, sync mode and mmap memory\n");
  137. evaluate_test(check_madvise_options(USE_MMAP, MTE_ASYNC_ERR, MAP_SHARED),
  138. "Check KSM mte page merge for shared mapping, async mode and mmap memory\n");
  139. mte_ksm_restore();
  140. mte_restore_setup();
  141. ksft_print_cnts();
  142. return ksft_get_fail_cnt() == 0 ? KSFT_PASS : KSFT_FAIL;
  143. }