vm_util.c 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. // SPDX-License-Identifier: GPL-2.0
  2. #include <string.h>
  3. #include <fcntl.h>
  4. #include "../kselftest.h"
  5. #include "vm_util.h"
  6. #define PMD_SIZE_FILE_PATH "/sys/kernel/mm/transparent_hugepage/hpage_pmd_size"
  7. #define SMAP_FILE_PATH "/proc/self/smaps"
  8. #define MAX_LINE_LENGTH 500
  9. uint64_t pagemap_get_entry(int fd, char *start)
  10. {
  11. const unsigned long pfn = (unsigned long)start / getpagesize();
  12. uint64_t entry;
  13. int ret;
  14. ret = pread(fd, &entry, sizeof(entry), pfn * sizeof(entry));
  15. if (ret != sizeof(entry))
  16. ksft_exit_fail_msg("reading pagemap failed\n");
  17. return entry;
  18. }
  19. bool pagemap_is_softdirty(int fd, char *start)
  20. {
  21. uint64_t entry = pagemap_get_entry(fd, start);
  22. // Check if dirty bit (55th bit) is set
  23. return entry & 0x0080000000000000ull;
  24. }
  25. void clear_softdirty(void)
  26. {
  27. int ret;
  28. const char *ctrl = "4";
  29. int fd = open("/proc/self/clear_refs", O_WRONLY);
  30. if (fd < 0)
  31. ksft_exit_fail_msg("opening clear_refs failed\n");
  32. ret = write(fd, ctrl, strlen(ctrl));
  33. close(fd);
  34. if (ret != strlen(ctrl))
  35. ksft_exit_fail_msg("writing clear_refs failed\n");
  36. }
  37. bool check_for_pattern(FILE *fp, const char *pattern, char *buf, size_t len)
  38. {
  39. while (fgets(buf, len, fp)) {
  40. if (!strncmp(buf, pattern, strlen(pattern)))
  41. return true;
  42. }
  43. return false;
  44. }
  45. uint64_t read_pmd_pagesize(void)
  46. {
  47. int fd;
  48. char buf[20];
  49. ssize_t num_read;
  50. fd = open(PMD_SIZE_FILE_PATH, O_RDONLY);
  51. if (fd == -1)
  52. ksft_exit_fail_msg("Open hpage_pmd_size failed\n");
  53. num_read = read(fd, buf, 19);
  54. if (num_read < 1) {
  55. close(fd);
  56. ksft_exit_fail_msg("Read hpage_pmd_size failed\n");
  57. }
  58. buf[num_read] = '\0';
  59. close(fd);
  60. return strtoul(buf, NULL, 10);
  61. }
  62. bool __check_huge(void *addr, char *pattern, int nr_hpages,
  63. uint64_t hpage_size)
  64. {
  65. uint64_t thp = -1;
  66. int ret;
  67. FILE *fp;
  68. char buffer[MAX_LINE_LENGTH];
  69. char addr_pattern[MAX_LINE_LENGTH];
  70. ret = snprintf(addr_pattern, MAX_LINE_LENGTH, "%08lx-",
  71. (unsigned long) addr);
  72. if (ret >= MAX_LINE_LENGTH)
  73. ksft_exit_fail_msg("%s: Pattern is too long\n", __func__);
  74. fp = fopen(SMAP_FILE_PATH, "r");
  75. if (!fp)
  76. ksft_exit_fail_msg("%s: Failed to open file %s\n", __func__, SMAP_FILE_PATH);
  77. if (!check_for_pattern(fp, addr_pattern, buffer, sizeof(buffer)))
  78. goto err_out;
  79. /*
  80. * Fetch the pattern in the same block and check the number of
  81. * hugepages.
  82. */
  83. if (!check_for_pattern(fp, pattern, buffer, sizeof(buffer)))
  84. goto err_out;
  85. snprintf(addr_pattern, MAX_LINE_LENGTH, "%s%%9ld kB", pattern);
  86. if (sscanf(buffer, addr_pattern, &thp) != 1)
  87. ksft_exit_fail_msg("Reading smap error\n");
  88. err_out:
  89. fclose(fp);
  90. return thp == (nr_hpages * (hpage_size >> 10));
  91. }
  92. bool check_huge_anon(void *addr, int nr_hpages, uint64_t hpage_size)
  93. {
  94. return __check_huge(addr, "AnonHugePages: ", nr_hpages, hpage_size);
  95. }
  96. bool check_huge_file(void *addr, int nr_hpages, uint64_t hpage_size)
  97. {
  98. return __check_huge(addr, "FilePmdMapped:", nr_hpages, hpage_size);
  99. }
  100. bool check_huge_shmem(void *addr, int nr_hpages, uint64_t hpage_size)
  101. {
  102. return __check_huge(addr, "ShmemPmdMapped:", nr_hpages, hpage_size);
  103. }