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 "lapi/abisize.h" 38#include "mem.h" 39 40#define MAP_SIZE (1UL<<20) 41 42volatile int end; 43static long default_tune = -1; 44static unsigned long total_mem; 45 46static void test_tune(unsigned long overcommit_policy); 47static int eatup_mem(unsigned long overcommit_policy); 48static void check_monitor(void); 49static void sighandler(int signo LTP_ATTRIBUTE_UNUSED); 50 51static 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 84static 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#ifdef TST_ABI32 130 { 131 if (total_mem < 3145728UL) 132#endif 133 tst_res(TFAIL, 134 "child unexpectedly failed: %d", 135 status); 136#ifdef TST_ABI32 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 159static 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 185static 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 204static void sighandler(int signo LTP_ATTRIBUTE_UNUSED) 205{ 206 end = 1; 207} 208 209static 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} 220 221static struct tst_test test = { 222 .needs_root = 1, 223 .forks_child = 1, 224 .max_runtime = TST_UNLIMITED_RUNTIME, 225 .setup = setup, 226 .test_all = min_free_kbytes_test, 227 .save_restore = (const struct tst_path_val[]) { 228 {"/proc/sys/vm/overcommit_memory", NULL, TST_SR_TBROK}, 229 {"/proc/sys/vm/min_free_kbytes", NULL, TST_SR_TBROK}, 230 {} 231 }, 232}; 233