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 /* 15 * swapping01 - first time swap use results in heavy swapping 16 * 17 * This case is used for testing upstream commit: 50a1598 18 * 19 * The upstream commit fixed a issue on s390/x platform that heavy 20 * swapping might occur in some condition, however since the patch 21 * was quite general, this testcase will be run on all supported 22 * platforms to ensure no regression been introduced. 23 * 24 * Details of the upstream fix: 25 * On x86 a page without a mapper is by definition not referenced / old. 26 * The s390 architecture keeps the reference bit in the storage key and 27 * the current code will check the storage key for page without a mapper. 28 * This leads to an interesting effect: the first time an s390 system 29 * needs to write pages to swap it only finds referenced pages. This 30 * causes a lot of pages to get added and written to the swap device. 31 * To avoid this behaviour change page_referenced to query the storage 32 * key only if there is a mapper of the page. 33 * 34 * Test Strategy: 35 * Try to allocate memory which size is slightly larger than current 36 * available memory. After allocation done, continue loop for a while 37 * and calculate the used swap size. The used swap size should be small 38 * enough, else it indicates that heavy swapping is occured unexpectedly. 39 */ 40 41 #include <sys/types.h> 42 #include <sys/wait.h> 43 #include <stdio.h> 44 #include <stdlib.h> 45 #include <string.h> 46 #include <unistd.h> 47 #include "mem.h" 48 49 /* allow swapping 1 * phy_mem in maximum */ 50 #define COE_DELTA 1 51 /* will try to alloc 1.3 * phy_mem */ 52 #define COE_SLIGHT_OVER 0.3 53 54 static void init_meminfo(void); 55 static void do_alloc(void); 56 static void check_swapping(void); 57 58 static long mem_available_init; 59 static long swap_free_init; 60 static long mem_over; 61 static long mem_over_max; 62 static pid_t pid; 63 64 static void test_swapping(void) 65 { 66 #if __WORDSIZE == 32 67 tst_brk(TCONF, "test is not designed for 32-bit system."); 68 #endif 69 70 init_meminfo(); 71 72 switch (pid = SAFE_FORK()) { 73 case 0: 74 do_alloc(); 75 exit(0); 76 default: 77 check_swapping(); 78 } 79 } 80 81 static void init_meminfo(void) 82 { 83 swap_free_init = SAFE_READ_MEMINFO("SwapFree:"); 84 if (FILE_LINES_SCANF("/proc/meminfo", "MemAvailable: %ld", 85 &mem_available_init)) { 86 mem_available_init = SAFE_READ_MEMINFO("MemFree:") 87 + SAFE_READ_MEMINFO("Cached:"); 88 } 89 mem_over = mem_available_init * COE_SLIGHT_OVER; 90 mem_over_max = mem_available_init * COE_DELTA; 91 92 /* at least 10MB available physical memory needed */ 93 if (mem_available_init < 10240) 94 tst_brk(TCONF, "Not enough available mem to test."); 95 96 if (swap_free_init < mem_over_max) 97 tst_brk(TCONF, "Not enough swap space to test."); 98 } 99 100 static void do_alloc(void) 101 { 102 long mem_count; 103 void *s; 104 105 tst_res(TINFO, "available physical memory: %ld MB", 106 mem_available_init / 1024); 107 mem_count = mem_available_init + mem_over; 108 tst_res(TINFO, "try to allocate: %ld MB", mem_count / 1024); 109 s = SAFE_MALLOC(mem_count * 1024); 110 memset(s, 1, mem_count * 1024); 111 tst_res(TINFO, "memory allocated: %ld MB", mem_count / 1024); 112 if (raise(SIGSTOP) == -1) 113 tst_brk(TBROK | TERRNO, "kill"); 114 free(s); 115 } 116 117 static void check_swapping(void) 118 { 119 int status, i; 120 long swap_free_now, swapped; 121 122 /* wait child stop */ 123 SAFE_WAITPID(pid, &status, WUNTRACED); 124 if (!WIFSTOPPED(status)) 125 tst_brk(TBROK, "child was not stopped."); 126 127 /* Still occupying memory, loop for a while */ 128 i = 0; 129 while (i < 10) { 130 swap_free_now = SAFE_READ_MEMINFO("SwapFree:"); 131 sleep(1); 132 if (abs(swap_free_now - SAFE_READ_MEMINFO("SwapFree:")) < 512) 133 break; 134 135 i++; 136 } 137 138 swap_free_now = SAFE_READ_MEMINFO("SwapFree:"); 139 swapped = swap_free_init - swap_free_now; 140 if (swapped > mem_over_max) { 141 kill(pid, SIGCONT); 142 tst_brk(TFAIL, "heavy swapping detected: " 143 "%ld MB swapped.", swapped / 1024); 144 } 145 146 tst_res(TPASS, "no heavy swapping detected, %ld MB swapped.", 147 swapped / 1024); 148 kill(pid, SIGCONT); 149 /* wait child exit */ 150 SAFE_WAITPID(pid, &status, 0); 151 } 152 153 static struct tst_test test = { 154 .needs_root = 1, 155 .forks_child = 1, 156 .test_all = test_swapping, 157 }; 158