^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) #define _GNU_SOURCE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) #include <fcntl.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) #include <limits.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) #include <signal.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) #include <stdio.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) #include <stdlib.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) #include <stdbool.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <string.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <unistd.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <sys/mman.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <sys/wait.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #ifndef MADV_PAGEOUT
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #define MADV_PAGEOUT 21
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #define BASE_ADDR ((void *)(1UL << 30))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) static unsigned long hpage_pmd_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) static unsigned long page_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) static int hpage_pmd_nr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #define THP_SYSFS "/sys/kernel/mm/transparent_hugepage/"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #define PID_SMAPS "/proc/self/smaps"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) enum thp_enabled {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) THP_ALWAYS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) THP_MADVISE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) THP_NEVER,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) static const char *thp_enabled_strings[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) "always",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) "madvise",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) "never",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) NULL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) enum thp_defrag {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) THP_DEFRAG_ALWAYS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) THP_DEFRAG_DEFER,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) THP_DEFRAG_DEFER_MADVISE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) THP_DEFRAG_MADVISE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) THP_DEFRAG_NEVER,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) static const char *thp_defrag_strings[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) "always",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) "defer",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) "defer+madvise",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) "madvise",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) "never",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) NULL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) enum shmem_enabled {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) SHMEM_ALWAYS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) SHMEM_WITHIN_SIZE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) SHMEM_ADVISE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) SHMEM_NEVER,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) SHMEM_DENY,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) SHMEM_FORCE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) static const char *shmem_enabled_strings[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) "always",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) "within_size",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) "advise",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) "never",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) "deny",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) "force",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) NULL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) struct khugepaged_settings {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) bool defrag;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) unsigned int alloc_sleep_millisecs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) unsigned int scan_sleep_millisecs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) unsigned int max_ptes_none;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) unsigned int max_ptes_swap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) unsigned int max_ptes_shared;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) unsigned long pages_to_scan;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) struct settings {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) enum thp_enabled thp_enabled;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) enum thp_defrag thp_defrag;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) enum shmem_enabled shmem_enabled;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) bool debug_cow;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) bool use_zero_page;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) struct khugepaged_settings khugepaged;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) static struct settings default_settings = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) .thp_enabled = THP_MADVISE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) .thp_defrag = THP_DEFRAG_ALWAYS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) .shmem_enabled = SHMEM_NEVER,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) .debug_cow = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) .use_zero_page = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) .khugepaged = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) .defrag = 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) .alloc_sleep_millisecs = 10,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) .scan_sleep_millisecs = 10,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) static struct settings saved_settings;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) static bool skip_settings_restore;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) static int exit_status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) static void success(const char *msg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) printf(" \e[32m%s\e[0m\n", msg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) static void fail(const char *msg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) printf(" \e[31m%s\e[0m\n", msg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) exit_status++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) static int read_file(const char *path, char *buf, size_t buflen)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) int fd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) ssize_t numread;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) fd = open(path, O_RDONLY);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) if (fd == -1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) numread = read(fd, buf, buflen - 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) if (numread < 1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) close(fd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) buf[numread] = '\0';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) close(fd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) return (unsigned int) numread;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) static int write_file(const char *path, const char *buf, size_t buflen)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) int fd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) ssize_t numwritten;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) fd = open(path, O_WRONLY);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) if (fd == -1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) numwritten = write(fd, buf, buflen - 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) close(fd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) if (numwritten < 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) return (unsigned int) numwritten;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) static int read_string(const char *name, const char *strings[])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) char path[PATH_MAX];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) char buf[256];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) char *c;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) ret = snprintf(path, PATH_MAX, THP_SYSFS "%s", name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) if (ret >= PATH_MAX) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) printf("%s: Pathname is too long\n", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) exit(EXIT_FAILURE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) if (!read_file(path, buf, sizeof(buf))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) perror(path);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) exit(EXIT_FAILURE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) c = strchr(buf, '[');
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) if (!c) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) printf("%s: Parse failure\n", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) exit(EXIT_FAILURE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) c++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) memmove(buf, c, sizeof(buf) - (c - buf));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) c = strchr(buf, ']');
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) if (!c) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) printf("%s: Parse failure\n", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) exit(EXIT_FAILURE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) *c = '\0';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) while (strings[ret]) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) if (!strcmp(strings[ret], buf))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) ret++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) printf("Failed to parse %s\n", name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) exit(EXIT_FAILURE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) static void write_string(const char *name, const char *val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) char path[PATH_MAX];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) ret = snprintf(path, PATH_MAX, THP_SYSFS "%s", name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) if (ret >= PATH_MAX) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) printf("%s: Pathname is too long\n", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) exit(EXIT_FAILURE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) if (!write_file(path, val, strlen(val) + 1)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) perror(path);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) exit(EXIT_FAILURE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) static const unsigned long read_num(const char *name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) char path[PATH_MAX];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) char buf[21];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) ret = snprintf(path, PATH_MAX, THP_SYSFS "%s", name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) if (ret >= PATH_MAX) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) printf("%s: Pathname is too long\n", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) exit(EXIT_FAILURE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) ret = read_file(path, buf, sizeof(buf));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) perror("read_file(read_num)");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) exit(EXIT_FAILURE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) return strtoul(buf, NULL, 10);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) static void write_num(const char *name, unsigned long num)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) char path[PATH_MAX];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) char buf[21];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) ret = snprintf(path, PATH_MAX, THP_SYSFS "%s", name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) if (ret >= PATH_MAX) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) printf("%s: Pathname is too long\n", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) exit(EXIT_FAILURE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) sprintf(buf, "%ld", num);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) if (!write_file(path, buf, strlen(buf) + 1)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) perror(path);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) exit(EXIT_FAILURE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) static void write_settings(struct settings *settings)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) struct khugepaged_settings *khugepaged = &settings->khugepaged;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) write_string("enabled", thp_enabled_strings[settings->thp_enabled]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) write_string("defrag", thp_defrag_strings[settings->thp_defrag]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) write_string("shmem_enabled",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) shmem_enabled_strings[settings->shmem_enabled]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) write_num("debug_cow", settings->debug_cow);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) write_num("use_zero_page", settings->use_zero_page);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) write_num("khugepaged/defrag", khugepaged->defrag);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) write_num("khugepaged/alloc_sleep_millisecs",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) khugepaged->alloc_sleep_millisecs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) write_num("khugepaged/scan_sleep_millisecs",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) khugepaged->scan_sleep_millisecs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) write_num("khugepaged/max_ptes_none", khugepaged->max_ptes_none);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) write_num("khugepaged/max_ptes_swap", khugepaged->max_ptes_swap);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) write_num("khugepaged/max_ptes_shared", khugepaged->max_ptes_shared);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) write_num("khugepaged/pages_to_scan", khugepaged->pages_to_scan);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) static void restore_settings(int sig)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) if (skip_settings_restore)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) printf("Restore THP and khugepaged settings...");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) write_settings(&saved_settings);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) success("OK");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) if (sig)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) exit(EXIT_FAILURE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) exit(exit_status);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) static void save_settings(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) printf("Save THP and khugepaged settings...");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) saved_settings = (struct settings) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) .thp_enabled = read_string("enabled", thp_enabled_strings),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) .thp_defrag = read_string("defrag", thp_defrag_strings),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) .shmem_enabled =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) read_string("shmem_enabled", shmem_enabled_strings),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) .debug_cow = read_num("debug_cow"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) .use_zero_page = read_num("use_zero_page"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) saved_settings.khugepaged = (struct khugepaged_settings) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) .defrag = read_num("khugepaged/defrag"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) .alloc_sleep_millisecs =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) read_num("khugepaged/alloc_sleep_millisecs"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) .scan_sleep_millisecs =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) read_num("khugepaged/scan_sleep_millisecs"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) .max_ptes_none = read_num("khugepaged/max_ptes_none"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) .max_ptes_swap = read_num("khugepaged/max_ptes_swap"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) .max_ptes_shared = read_num("khugepaged/max_ptes_shared"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) .pages_to_scan = read_num("khugepaged/pages_to_scan"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) success("OK");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) signal(SIGTERM, restore_settings);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) signal(SIGINT, restore_settings);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) signal(SIGHUP, restore_settings);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) signal(SIGQUIT, restore_settings);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) static void adjust_settings(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) printf("Adjust settings...");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) write_settings(&default_settings);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) success("OK");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) #define MAX_LINE_LENGTH 500
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) static bool check_for_pattern(FILE *fp, char *pattern, char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) while (fgets(buf, MAX_LINE_LENGTH, fp) != NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) if (!strncmp(buf, pattern, strlen(pattern)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) static bool check_huge(void *addr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) bool thp = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) FILE *fp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) char buffer[MAX_LINE_LENGTH];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) char addr_pattern[MAX_LINE_LENGTH];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) ret = snprintf(addr_pattern, MAX_LINE_LENGTH, "%08lx-",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) (unsigned long) addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) if (ret >= MAX_LINE_LENGTH) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) printf("%s: Pattern is too long\n", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) exit(EXIT_FAILURE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) fp = fopen(PID_SMAPS, "r");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) if (!fp) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) printf("%s: Failed to open file %s\n", __func__, PID_SMAPS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) exit(EXIT_FAILURE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) if (!check_for_pattern(fp, addr_pattern, buffer))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) goto err_out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) ret = snprintf(addr_pattern, MAX_LINE_LENGTH, "AnonHugePages:%10ld kB",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) hpage_pmd_size >> 10);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) if (ret >= MAX_LINE_LENGTH) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) printf("%s: Pattern is too long\n", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) exit(EXIT_FAILURE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) * Fetch the AnonHugePages: in the same block and check whether it got
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) * the expected number of hugeepages next.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) if (!check_for_pattern(fp, "AnonHugePages:", buffer))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) goto err_out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) if (strncmp(buffer, addr_pattern, strlen(addr_pattern)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) goto err_out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) thp = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) err_out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) fclose(fp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) return thp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) static bool check_swap(void *addr, unsigned long size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) bool swap = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) FILE *fp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) char buffer[MAX_LINE_LENGTH];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) char addr_pattern[MAX_LINE_LENGTH];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) ret = snprintf(addr_pattern, MAX_LINE_LENGTH, "%08lx-",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) (unsigned long) addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) if (ret >= MAX_LINE_LENGTH) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) printf("%s: Pattern is too long\n", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) exit(EXIT_FAILURE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) fp = fopen(PID_SMAPS, "r");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) if (!fp) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) printf("%s: Failed to open file %s\n", __func__, PID_SMAPS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) exit(EXIT_FAILURE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) if (!check_for_pattern(fp, addr_pattern, buffer))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) goto err_out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) ret = snprintf(addr_pattern, MAX_LINE_LENGTH, "Swap:%19ld kB",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) size >> 10);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) if (ret >= MAX_LINE_LENGTH) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) printf("%s: Pattern is too long\n", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) exit(EXIT_FAILURE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) * Fetch the Swap: in the same block and check whether it got
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) * the expected number of hugeepages next.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) if (!check_for_pattern(fp, "Swap:", buffer))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) goto err_out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) if (strncmp(buffer, addr_pattern, strlen(addr_pattern)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) goto err_out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) swap = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) err_out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) fclose(fp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) return swap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) static void *alloc_mapping(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) void *p;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) p = mmap(BASE_ADDR, hpage_pmd_size, PROT_READ | PROT_WRITE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) if (p != BASE_ADDR) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) printf("Failed to allocate VMA at %p\n", BASE_ADDR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) exit(EXIT_FAILURE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) return p;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) static void fill_memory(int *p, unsigned long start, unsigned long end)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) for (i = start / page_size; i < end / page_size; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) p[i * page_size / sizeof(*p)] = i + 0xdead0000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) static void validate_memory(int *p, unsigned long start, unsigned long end)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) for (i = start / page_size; i < end / page_size; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) if (p[i * page_size / sizeof(*p)] != i + 0xdead0000) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) printf("Page %d is corrupted: %#x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) i, p[i * page_size / sizeof(*p)]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) exit(EXIT_FAILURE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) #define TICK 500000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) static bool wait_for_scan(const char *msg, char *p)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) int full_scans;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) int timeout = 6; /* 3 seconds */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) /* Sanity check */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) if (check_huge(p)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) printf("Unexpected huge page\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) exit(EXIT_FAILURE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) madvise(p, hpage_pmd_size, MADV_HUGEPAGE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) /* Wait until the second full_scan completed */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) full_scans = read_num("khugepaged/full_scans") + 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) printf("%s...", msg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) while (timeout--) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) if (check_huge(p))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) if (read_num("khugepaged/full_scans") >= full_scans)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) printf(".");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) usleep(TICK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) madvise(p, hpage_pmd_size, MADV_NOHUGEPAGE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) return timeout == -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) static void alloc_at_fault(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) struct settings settings = default_settings;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) char *p;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) settings.thp_enabled = THP_ALWAYS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) write_settings(&settings);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) p = alloc_mapping();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) *p = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) printf("Allocate huge page on fault...");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) if (check_huge(p))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) success("OK");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) fail("Fail");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) write_settings(&default_settings);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) madvise(p, page_size, MADV_DONTNEED);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) printf("Split huge PMD on MADV_DONTNEED...");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) if (!check_huge(p))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) success("OK");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) fail("Fail");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) munmap(p, hpage_pmd_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) static void collapse_full(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) void *p;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) p = alloc_mapping();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) fill_memory(p, 0, hpage_pmd_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) if (wait_for_scan("Collapse fully populated PTE table", p))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) fail("Timeout");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) else if (check_huge(p))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) success("OK");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) fail("Fail");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) validate_memory(p, 0, hpage_pmd_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) munmap(p, hpage_pmd_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) static void collapse_empty(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) void *p;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) p = alloc_mapping();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) if (wait_for_scan("Do not collapse empty PTE table", p))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) fail("Timeout");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) else if (check_huge(p))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) fail("Fail");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) success("OK");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) munmap(p, hpage_pmd_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) static void collapse_single_pte_entry(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) void *p;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) p = alloc_mapping();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) fill_memory(p, 0, page_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) if (wait_for_scan("Collapse PTE table with single PTE entry present", p))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) fail("Timeout");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) else if (check_huge(p))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) success("OK");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) fail("Fail");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) validate_memory(p, 0, page_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) munmap(p, hpage_pmd_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) static void collapse_max_ptes_none(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) int max_ptes_none = hpage_pmd_nr / 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) struct settings settings = default_settings;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) void *p;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) settings.khugepaged.max_ptes_none = max_ptes_none;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) write_settings(&settings);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) p = alloc_mapping();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) fill_memory(p, 0, (hpage_pmd_nr - max_ptes_none - 1) * page_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) if (wait_for_scan("Do not collapse with max_ptes_none exceeded", p))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) fail("Timeout");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) else if (check_huge(p))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) fail("Fail");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) success("OK");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) validate_memory(p, 0, (hpage_pmd_nr - max_ptes_none - 1) * page_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) fill_memory(p, 0, (hpage_pmd_nr - max_ptes_none) * page_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) if (wait_for_scan("Collapse with max_ptes_none PTEs empty", p))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) fail("Timeout");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) else if (check_huge(p))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) success("OK");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) fail("Fail");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) validate_memory(p, 0, (hpage_pmd_nr - max_ptes_none) * page_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) munmap(p, hpage_pmd_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) write_settings(&default_settings);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) static void collapse_swapin_single_pte(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) void *p;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) p = alloc_mapping();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) fill_memory(p, 0, hpage_pmd_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) printf("Swapout one page...");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) if (madvise(p, page_size, MADV_PAGEOUT)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) perror("madvise(MADV_PAGEOUT)");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) exit(EXIT_FAILURE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) if (check_swap(p, page_size)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) success("OK");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) fail("Fail");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) if (wait_for_scan("Collapse with swapping in single PTE entry", p))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) fail("Timeout");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) else if (check_huge(p))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) success("OK");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) fail("Fail");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) validate_memory(p, 0, hpage_pmd_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) munmap(p, hpage_pmd_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) static void collapse_max_ptes_swap(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) int max_ptes_swap = read_num("khugepaged/max_ptes_swap");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) void *p;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) p = alloc_mapping();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) fill_memory(p, 0, hpage_pmd_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) printf("Swapout %d of %d pages...", max_ptes_swap + 1, hpage_pmd_nr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) if (madvise(p, (max_ptes_swap + 1) * page_size, MADV_PAGEOUT)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) perror("madvise(MADV_PAGEOUT)");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) exit(EXIT_FAILURE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) if (check_swap(p, (max_ptes_swap + 1) * page_size)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) success("OK");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) fail("Fail");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) if (wait_for_scan("Do not collapse with max_ptes_swap exceeded", p))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) fail("Timeout");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) else if (check_huge(p))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) fail("Fail");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) success("OK");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) validate_memory(p, 0, hpage_pmd_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) fill_memory(p, 0, hpage_pmd_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) printf("Swapout %d of %d pages...", max_ptes_swap, hpage_pmd_nr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) if (madvise(p, max_ptes_swap * page_size, MADV_PAGEOUT)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) perror("madvise(MADV_PAGEOUT)");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) exit(EXIT_FAILURE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) if (check_swap(p, max_ptes_swap * page_size)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) success("OK");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) fail("Fail");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) if (wait_for_scan("Collapse with max_ptes_swap pages swapped out", p))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) fail("Timeout");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) else if (check_huge(p))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687) success("OK");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) fail("Fail");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) validate_memory(p, 0, hpage_pmd_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) munmap(p, hpage_pmd_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) static void collapse_single_pte_entry_compound(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) void *p;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699) p = alloc_mapping();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701) printf("Allocate huge page...");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702) madvise(p, hpage_pmd_size, MADV_HUGEPAGE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703) fill_memory(p, 0, hpage_pmd_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704) if (check_huge(p))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705) success("OK");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) fail("Fail");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708) madvise(p, hpage_pmd_size, MADV_NOHUGEPAGE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710) printf("Split huge page leaving single PTE mapping compound page...");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711) madvise(p + page_size, hpage_pmd_size - page_size, MADV_DONTNEED);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712) if (!check_huge(p))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) success("OK");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715) fail("Fail");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717) if (wait_for_scan("Collapse PTE table with single PTE mapping compound page", p))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718) fail("Timeout");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719) else if (check_huge(p))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720) success("OK");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722) fail("Fail");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723) validate_memory(p, 0, page_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724) munmap(p, hpage_pmd_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727) static void collapse_full_of_compound(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729) void *p;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731) p = alloc_mapping();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733) printf("Allocate huge page...");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734) madvise(p, hpage_pmd_size, MADV_HUGEPAGE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735) fill_memory(p, 0, hpage_pmd_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736) if (check_huge(p))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737) success("OK");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739) fail("Fail");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741) printf("Split huge page leaving single PTE page table full of compound pages...");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742) madvise(p, page_size, MADV_NOHUGEPAGE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743) madvise(p, hpage_pmd_size, MADV_NOHUGEPAGE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744) if (!check_huge(p))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745) success("OK");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747) fail("Fail");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749) if (wait_for_scan("Collapse PTE table full of compound pages", p))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750) fail("Timeout");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751) else if (check_huge(p))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752) success("OK");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754) fail("Fail");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755) validate_memory(p, 0, hpage_pmd_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756) munmap(p, hpage_pmd_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759) static void collapse_compound_extreme(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 761) void *p;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 762) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 763)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 764) p = alloc_mapping();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 765) for (i = 0; i < hpage_pmd_nr; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 766) printf("\rConstruct PTE page table full of different PTE-mapped compound pages %3d/%d...",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 767) i + 1, hpage_pmd_nr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 768)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 769) madvise(BASE_ADDR, hpage_pmd_size, MADV_HUGEPAGE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 770) fill_memory(BASE_ADDR, 0, hpage_pmd_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 771) if (!check_huge(BASE_ADDR)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 772) printf("Failed to allocate huge page\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 773) exit(EXIT_FAILURE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 774) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 775) madvise(BASE_ADDR, hpage_pmd_size, MADV_NOHUGEPAGE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 776)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 777) p = mremap(BASE_ADDR - i * page_size,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 778) i * page_size + hpage_pmd_size,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 779) (i + 1) * page_size,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 780) MREMAP_MAYMOVE | MREMAP_FIXED,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 781) BASE_ADDR + 2 * hpage_pmd_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 782) if (p == MAP_FAILED) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 783) perror("mremap+unmap");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 784) exit(EXIT_FAILURE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 785) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 786)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 787) p = mremap(BASE_ADDR + 2 * hpage_pmd_size,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 788) (i + 1) * page_size,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 789) (i + 1) * page_size + hpage_pmd_size,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 790) MREMAP_MAYMOVE | MREMAP_FIXED,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 791) BASE_ADDR - (i + 1) * page_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 792) if (p == MAP_FAILED) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 793) perror("mremap+alloc");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 794) exit(EXIT_FAILURE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 795) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 796) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 797)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 798) munmap(BASE_ADDR, hpage_pmd_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 799) fill_memory(p, 0, hpage_pmd_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 800) if (!check_huge(p))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 801) success("OK");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 802) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 803) fail("Fail");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 804)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 805) if (wait_for_scan("Collapse PTE table full of different compound pages", p))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 806) fail("Timeout");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 807) else if (check_huge(p))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 808) success("OK");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 809) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 810) fail("Fail");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 811)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 812) validate_memory(p, 0, hpage_pmd_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 813) munmap(p, hpage_pmd_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 814) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 815)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 816) static void collapse_fork(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 817) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 818) int wstatus;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 819) void *p;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 820)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 821) p = alloc_mapping();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 822)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 823) printf("Allocate small page...");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 824) fill_memory(p, 0, page_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 825) if (!check_huge(p))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 826) success("OK");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 827) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 828) fail("Fail");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 829)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 830) printf("Share small page over fork()...");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 831) if (!fork()) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 832) /* Do not touch settings on child exit */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 833) skip_settings_restore = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 834) exit_status = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 835)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 836) if (!check_huge(p))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 837) success("OK");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 838) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 839) fail("Fail");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 840)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 841) fill_memory(p, page_size, 2 * page_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 842)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 843) if (wait_for_scan("Collapse PTE table with single page shared with parent process", p))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 844) fail("Timeout");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 845) else if (check_huge(p))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 846) success("OK");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 847) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 848) fail("Fail");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 849)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 850) validate_memory(p, 0, page_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 851) munmap(p, hpage_pmd_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 852) exit(exit_status);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 853) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 854)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 855) wait(&wstatus);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 856) exit_status += WEXITSTATUS(wstatus);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 857)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 858) printf("Check if parent still has small page...");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 859) if (!check_huge(p))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 860) success("OK");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 861) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 862) fail("Fail");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 863) validate_memory(p, 0, page_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 864) munmap(p, hpage_pmd_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 865) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 866)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 867) static void collapse_fork_compound(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 868) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 869) int wstatus;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 870) void *p;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 871)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 872) p = alloc_mapping();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 873)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 874) printf("Allocate huge page...");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 875) madvise(p, hpage_pmd_size, MADV_HUGEPAGE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 876) fill_memory(p, 0, hpage_pmd_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 877) if (check_huge(p))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 878) success("OK");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 879) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 880) fail("Fail");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 881)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 882) printf("Share huge page over fork()...");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 883) if (!fork()) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 884) /* Do not touch settings on child exit */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 885) skip_settings_restore = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 886) exit_status = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 887)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 888) if (check_huge(p))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 889) success("OK");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 890) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 891) fail("Fail");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 892)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 893) printf("Split huge page PMD in child process...");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 894) madvise(p, page_size, MADV_NOHUGEPAGE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 895) madvise(p, hpage_pmd_size, MADV_NOHUGEPAGE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 896) if (!check_huge(p))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 897) success("OK");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 898) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 899) fail("Fail");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 900) fill_memory(p, 0, page_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 901)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 902) write_num("khugepaged/max_ptes_shared", hpage_pmd_nr - 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 903) if (wait_for_scan("Collapse PTE table full of compound pages in child", p))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 904) fail("Timeout");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 905) else if (check_huge(p))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 906) success("OK");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 907) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 908) fail("Fail");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 909) write_num("khugepaged/max_ptes_shared",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 910) default_settings.khugepaged.max_ptes_shared);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 911)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 912) validate_memory(p, 0, hpage_pmd_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 913) munmap(p, hpage_pmd_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 914) exit(exit_status);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 915) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 916)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 917) wait(&wstatus);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 918) exit_status += WEXITSTATUS(wstatus);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 919)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 920) printf("Check if parent still has huge page...");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 921) if (check_huge(p))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 922) success("OK");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 923) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 924) fail("Fail");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 925) validate_memory(p, 0, hpage_pmd_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 926) munmap(p, hpage_pmd_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 927) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 928)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 929) static void collapse_max_ptes_shared()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 930) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 931) int max_ptes_shared = read_num("khugepaged/max_ptes_shared");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 932) int wstatus;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 933) void *p;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 934)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 935) p = alloc_mapping();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 936)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 937) printf("Allocate huge page...");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 938) madvise(p, hpage_pmd_size, MADV_HUGEPAGE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 939) fill_memory(p, 0, hpage_pmd_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 940) if (check_huge(p))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 941) success("OK");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 942) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 943) fail("Fail");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 944)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 945) printf("Share huge page over fork()...");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 946) if (!fork()) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 947) /* Do not touch settings on child exit */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 948) skip_settings_restore = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 949) exit_status = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 950)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 951) if (check_huge(p))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 952) success("OK");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 953) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 954) fail("Fail");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 955)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 956) printf("Trigger CoW on page %d of %d...",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 957) hpage_pmd_nr - max_ptes_shared - 1, hpage_pmd_nr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 958) fill_memory(p, 0, (hpage_pmd_nr - max_ptes_shared - 1) * page_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 959) if (!check_huge(p))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 960) success("OK");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 961) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 962) fail("Fail");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 963)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 964) if (wait_for_scan("Do not collapse with max_ptes_shared exceeded", p))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 965) fail("Timeout");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 966) else if (!check_huge(p))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 967) success("OK");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 968) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 969) fail("Fail");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 970)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 971) printf("Trigger CoW on page %d of %d...",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 972) hpage_pmd_nr - max_ptes_shared, hpage_pmd_nr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 973) fill_memory(p, 0, (hpage_pmd_nr - max_ptes_shared) * page_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 974) if (!check_huge(p))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 975) success("OK");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 976) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 977) fail("Fail");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 978)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 979)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 980) if (wait_for_scan("Collapse with max_ptes_shared PTEs shared", p))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 981) fail("Timeout");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 982) else if (check_huge(p))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 983) success("OK");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 984) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 985) fail("Fail");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 986)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 987) validate_memory(p, 0, hpage_pmd_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 988) munmap(p, hpage_pmd_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 989) exit(exit_status);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 990) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 991)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 992) wait(&wstatus);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 993) exit_status += WEXITSTATUS(wstatus);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 994)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 995) printf("Check if parent still has huge page...");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 996) if (check_huge(p))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 997) success("OK");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 998) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 999) fail("Fail");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1000) validate_memory(p, 0, hpage_pmd_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1001) munmap(p, hpage_pmd_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1002) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1003)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1004) int main(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1005) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1006) setbuf(stdout, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1007)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1008) page_size = getpagesize();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1009) hpage_pmd_size = read_num("hpage_pmd_size");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1010) hpage_pmd_nr = hpage_pmd_size / page_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1011)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1012) default_settings.khugepaged.max_ptes_none = hpage_pmd_nr - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1013) default_settings.khugepaged.max_ptes_swap = hpage_pmd_nr / 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1014) default_settings.khugepaged.max_ptes_shared = hpage_pmd_nr / 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1015) default_settings.khugepaged.pages_to_scan = hpage_pmd_nr * 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1016)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1017) save_settings();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1018) adjust_settings();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1019)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1020) alloc_at_fault();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1021) collapse_full();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1022) collapse_empty();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1023) collapse_single_pte_entry();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1024) collapse_max_ptes_none();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1025) collapse_swapin_single_pte();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1026) collapse_max_ptes_swap();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1027) collapse_single_pte_entry_compound();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1028) collapse_full_of_compound();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1029) collapse_compound_extreme();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1030) collapse_fork();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1031) collapse_fork_compound();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1032) collapse_max_ptes_shared();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1033)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1034) restore_settings(0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1035) }