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