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
test_swapping(void)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
init_meminfo(void)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
do_alloc(void)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
check_swapping(void)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