1 /* 2 * Copyright (C) 2012-2017 Red Hat, Inc. 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation; either version 2 of the License, or 7 * (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See 12 * the GNU General Public License for more details. 13 * 14 * Description: 15 * 16 * The case is designed to test min_free_kbytes tunable. 17 * 18 * The tune is used to control free memory, and system always 19 * reserve min_free_kbytes memory at least. 20 * 21 * Since the tune is not too large or too little, which will 22 * lead to the system hang, so I choose two cases, and test them 23 * on all overcommit_memory policy, at the same time, compare 24 * the current free memory with the tunable value repeatedly. 25 * 26 * a) default min_free_kbytes with all overcommit memory policy 27 * b) 2x default value with all overcommit memory policy 28 * c) 5% of MemFree or %2 MemTotal with all overcommit memory policy 29 */ 30 31 #include <sys/wait.h> 32 #include <errno.h> 33 #include <fcntl.h> 34 #include <signal.h> 35 #include <stdio.h> 36 #include <stdlib.h> 37 #include "mem.h" 38 39 #define MAP_SIZE (1UL<<20) 40 41 volatile int end; 42 static unsigned long default_tune; 43 static unsigned long orig_overcommit; 44 static unsigned long total_mem; 45 46 static void test_tune(unsigned long overcommit_policy); 47 static int eatup_mem(unsigned long overcommit_policy); 48 static void check_monitor(void); 49 static void sighandler(int signo LTP_ATTRIBUTE_UNUSED); 50 51 static void min_free_kbytes_test(void) 52 { 53 int pid, status; 54 struct sigaction sa; 55 56 sa.sa_handler = sighandler; 57 if (sigemptyset(&sa.sa_mask) < 0) 58 tst_brk(TBROK | TERRNO, "sigemptyset"); 59 sa.sa_flags = 0; 60 if (sigaction(SIGUSR1, &sa, NULL) < 0) 61 tst_brk(TBROK | TERRNO, "sigaction"); 62 63 pid = SAFE_FORK(); 64 if (pid == 0) { 65 /* startup the check monitor */ 66 check_monitor(); 67 exit(0); 68 } 69 70 test_tune(2); 71 test_tune(0); 72 test_tune(1); 73 74 SAFE_KILL(pid, SIGUSR1); 75 SAFE_WAITPID(pid, &status, WUNTRACED | WCONTINUED); 76 77 if (WIFEXITED(status) && WEXITSTATUS(status) != 0) 78 tst_res(TFAIL, 79 "check_monitor child exit with status: %d", status); 80 81 tst_res(TPASS, "min_free_kbytes test pass"); 82 } 83 84 static void test_tune(unsigned long overcommit_policy) 85 { 86 int status; 87 int pid[3]; 88 int ret, i; 89 unsigned long tune, memfree, memtotal; 90 91 set_sys_tune("overcommit_memory", overcommit_policy, 1); 92 93 for (i = 0; i < 3; i++) { 94 /* case1 */ 95 if (i == 0) 96 set_sys_tune("min_free_kbytes", default_tune, 1); 97 /* case2 */ 98 else if (i == 1) { 99 set_sys_tune("min_free_kbytes", 2 * default_tune, 1); 100 /* case3 */ 101 } else { 102 memfree = SAFE_READ_MEMINFO("MemFree:"); 103 memtotal = SAFE_READ_MEMINFO("MemTotal:"); 104 tune = memfree / 20; 105 if (tune > (memtotal / 50)) 106 tune = memtotal / 50; 107 108 set_sys_tune("min_free_kbytes", tune, 1); 109 } 110 111 fflush(stdout); 112 switch (pid[i] = fork()) { 113 case -1: 114 tst_brk(TBROK | TERRNO, "fork"); 115 case 0: 116 ret = eatup_mem(overcommit_policy); 117 exit(ret); 118 } 119 120 SAFE_WAITPID(pid[i], &status, WUNTRACED | WCONTINUED); 121 122 if (overcommit_policy == 2) { 123 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) 124 tst_res(TFAIL, 125 "child unexpectedly failed: %d", 126 status); 127 } else if (overcommit_policy == 1) { 128 if (!WIFSIGNALED(status) || WTERMSIG(status) != SIGKILL) 129 #if __WORDSIZE == 32 130 { 131 if (total_mem < 3145728UL) 132 #endif 133 tst_res(TFAIL, 134 "child unexpectedly failed: %d", 135 status); 136 #if __WORDSIZE == 32 137 /* in 32-bit system, a process allocate about 3Gb memory at most */ 138 else 139 tst_res(TINFO, "Child can't allocate " 140 ">3Gb memory in 32bit system"); 141 } 142 #endif 143 } else { 144 if (WIFEXITED(status)) { 145 if (WEXITSTATUS(status) != 0) { 146 tst_res(TFAIL, "child unexpectedly " 147 "failed: %d", status); 148 } 149 } else if (!WIFSIGNALED(status) || 150 WTERMSIG(status) != SIGKILL) { 151 tst_res(TFAIL, 152 "child unexpectedly failed: %d", 153 status); 154 } 155 } 156 } 157 } 158 159 static int eatup_mem(unsigned long overcommit_policy) 160 { 161 int ret = 0; 162 unsigned long memfree; 163 void *addrs; 164 165 memfree = SAFE_READ_MEMINFO("MemFree:"); 166 printf("memfree is %lu kB before eatup mem\n", memfree); 167 while (1) { 168 addrs = mmap(NULL, MAP_SIZE, PROT_READ | PROT_WRITE, 169 MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); 170 if (addrs == MAP_FAILED) { 171 if (overcommit_policy != 1 && errno != ENOMEM) { 172 perror("mmap"); 173 ret = -1; 174 } 175 break; 176 } 177 memset(addrs, 1, MAP_SIZE); 178 } 179 memfree = SAFE_READ_MEMINFO("MemFree:"); 180 printf("memfree is %lu kB after eatup mem\n", memfree); 181 182 return ret; 183 } 184 185 static void check_monitor(void) 186 { 187 unsigned long tune; 188 unsigned long memfree; 189 190 while (end) { 191 memfree = SAFE_READ_MEMINFO("MemFree:"); 192 tune = get_sys_tune("min_free_kbytes"); 193 194 if (memfree < tune) { 195 tst_res(TINFO, "MemFree is %lu kB, " 196 "min_free_kbytes is %lu kB", memfree, tune); 197 tst_res(TFAIL, "MemFree < min_free_kbytes"); 198 } 199 200 sleep(2); 201 } 202 } 203 204 static void sighandler(int signo LTP_ATTRIBUTE_UNUSED) 205 { 206 end = 1; 207 } 208 209 static void setup(void) 210 { 211 if (get_sys_tune("panic_on_oom")) { 212 tst_brk(TCONF, 213 "panic_on_oom is set, disable it to run these testcases"); 214 } 215 216 total_mem = SAFE_READ_MEMINFO("MemTotal:") + SAFE_READ_MEMINFO("SwapTotal:"); 217 218 default_tune = get_sys_tune("min_free_kbytes"); 219 orig_overcommit = get_sys_tune("overcommit_memory"); 220 } 221 222 static void cleanup(void) 223 { 224 set_sys_tune("min_free_kbytes", default_tune, 0); 225 set_sys_tune("overcommit_memory", orig_overcommit, 0); 226 } 227 228 static struct tst_test test = { 229 .needs_root = 1, 230 .forks_child = 1, 231 .timeout = -1, 232 .setup = setup, 233 .cleanup = cleanup, 234 .test_all = min_free_kbytes_test, 235 }; 236