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