1f08c3bdfSopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 2f08c3bdfSopenharmony_ci/* 3f08c3bdfSopenharmony_ci * Copyright (C) 2012-2017 Red Hat, Inc. 4f08c3bdfSopenharmony_ci */ 5f08c3bdfSopenharmony_ci 6f08c3bdfSopenharmony_ci/*\ 7f08c3bdfSopenharmony_ci * [Description] 8f08c3bdfSopenharmony_ci * 9f08c3bdfSopenharmony_ci * Detect heavy swapping during first time swap use. 10f08c3bdfSopenharmony_ci * 11f08c3bdfSopenharmony_ci * This case is used for testing kernel commit: 12f08c3bdfSopenharmony_ci * 50a15981a1fa ("[S390] reference bit testing for unmapped pages") 13f08c3bdfSopenharmony_ci * 14f08c3bdfSopenharmony_ci * The upstream commit fixed a issue on s390/x platform that heavy 15f08c3bdfSopenharmony_ci * swapping might occur in some condition, however since the patch 16f08c3bdfSopenharmony_ci * was quite general, this testcase will be run on all supported 17f08c3bdfSopenharmony_ci * platforms to ensure no regression been introduced. 18f08c3bdfSopenharmony_ci * 19f08c3bdfSopenharmony_ci * Details of the kernel fix: 20f08c3bdfSopenharmony_ci * 21f08c3bdfSopenharmony_ci * On x86 a page without a mapper is by definition not referenced / old. 22f08c3bdfSopenharmony_ci * The s390 architecture keeps the reference bit in the storage key and 23f08c3bdfSopenharmony_ci * the current code will check the storage key for page without a mapper. 24f08c3bdfSopenharmony_ci * This leads to an interesting effect: the first time an s390 system 25f08c3bdfSopenharmony_ci * needs to write pages to swap it only finds referenced pages. This 26f08c3bdfSopenharmony_ci * causes a lot of pages to get added and written to the swap device. 27f08c3bdfSopenharmony_ci * To avoid this behaviour change page_referenced to query the storage 28f08c3bdfSopenharmony_ci * key only if there is a mapper of the page. 29f08c3bdfSopenharmony_ci * 30f08c3bdfSopenharmony_ci * [Algorithm] 31f08c3bdfSopenharmony_ci * 32f08c3bdfSopenharmony_ci * Try to allocate memory which size is slightly larger than current 33f08c3bdfSopenharmony_ci * available memory. After allocation done, continue loop for a while 34f08c3bdfSopenharmony_ci * and calculate the used swap size. The used swap size should be small 35f08c3bdfSopenharmony_ci * enough, else it indicates that heavy swapping is occurred unexpectedly. 36f08c3bdfSopenharmony_ci */ 37f08c3bdfSopenharmony_ci 38f08c3bdfSopenharmony_ci#include <sys/types.h> 39f08c3bdfSopenharmony_ci#include <sys/wait.h> 40f08c3bdfSopenharmony_ci#include <stdlib.h> 41f08c3bdfSopenharmony_ci#include <string.h> 42f08c3bdfSopenharmony_ci#include <unistd.h> 43f08c3bdfSopenharmony_ci#include "tst_safe_stdio.h" 44f08c3bdfSopenharmony_ci#include "lapi/abisize.h" 45f08c3bdfSopenharmony_ci#include "mem.h" 46f08c3bdfSopenharmony_ci 47f08c3bdfSopenharmony_ci/* allow swapping 1 * phy_mem in maximum */ 48f08c3bdfSopenharmony_ci#define COE_DELTA 1 49f08c3bdfSopenharmony_ci/* will try to alloc 1.3 * phy_mem */ 50f08c3bdfSopenharmony_ci#define COE_SLIGHT_OVER 0.3 51f08c3bdfSopenharmony_ci 52f08c3bdfSopenharmony_cistatic void init_meminfo(void); 53f08c3bdfSopenharmony_cistatic void do_alloc(int allow_raise); 54f08c3bdfSopenharmony_cistatic void check_swapping(void); 55f08c3bdfSopenharmony_ci 56f08c3bdfSopenharmony_cistatic long mem_available_init; 57f08c3bdfSopenharmony_cistatic long swap_free_init; 58f08c3bdfSopenharmony_cistatic long mem_over; 59f08c3bdfSopenharmony_cistatic long mem_over_max; 60f08c3bdfSopenharmony_cistatic pid_t pid; 61f08c3bdfSopenharmony_cistatic unsigned int start_runtime; 62f08c3bdfSopenharmony_ci 63f08c3bdfSopenharmony_cistatic void test_swapping(void) 64f08c3bdfSopenharmony_ci{ 65f08c3bdfSopenharmony_ci#ifdef TST_ABI32 66f08c3bdfSopenharmony_ci tst_brk(TCONF, "test is not designed for 32-bit system."); 67f08c3bdfSopenharmony_ci#endif 68f08c3bdfSopenharmony_ci FILE *file; 69f08c3bdfSopenharmony_ci char line[PATH_MAX]; 70f08c3bdfSopenharmony_ci 71f08c3bdfSopenharmony_ci start_runtime = tst_remaining_runtime(); 72f08c3bdfSopenharmony_ci 73f08c3bdfSopenharmony_ci file = SAFE_FOPEN("/proc/swaps", "r"); 74f08c3bdfSopenharmony_ci while (fgets(line, sizeof(line), file)) { 75f08c3bdfSopenharmony_ci if (strstr(line, "/dev/zram")) { 76f08c3bdfSopenharmony_ci SAFE_FCLOSE(file); 77f08c3bdfSopenharmony_ci tst_brk(TCONF, "zram-swap is being used!"); 78f08c3bdfSopenharmony_ci } 79f08c3bdfSopenharmony_ci } 80f08c3bdfSopenharmony_ci SAFE_FCLOSE(file); 81f08c3bdfSopenharmony_ci 82f08c3bdfSopenharmony_ci init_meminfo(); 83f08c3bdfSopenharmony_ci 84f08c3bdfSopenharmony_ci switch (pid = SAFE_FORK()) { 85f08c3bdfSopenharmony_ci case 0: 86f08c3bdfSopenharmony_ci do_alloc(0); 87f08c3bdfSopenharmony_ci do_alloc(1); 88f08c3bdfSopenharmony_ci exit(0); 89f08c3bdfSopenharmony_ci default: 90f08c3bdfSopenharmony_ci check_swapping(); 91f08c3bdfSopenharmony_ci } 92f08c3bdfSopenharmony_ci} 93f08c3bdfSopenharmony_ci 94f08c3bdfSopenharmony_cistatic void init_meminfo(void) 95f08c3bdfSopenharmony_ci{ 96f08c3bdfSopenharmony_ci swap_free_init = SAFE_READ_MEMINFO("SwapFree:"); 97f08c3bdfSopenharmony_ci mem_available_init = tst_available_mem(); 98f08c3bdfSopenharmony_ci mem_over = mem_available_init * COE_SLIGHT_OVER; 99f08c3bdfSopenharmony_ci mem_over_max = mem_available_init * COE_DELTA; 100f08c3bdfSopenharmony_ci 101f08c3bdfSopenharmony_ci if (swap_free_init < mem_over_max) 102f08c3bdfSopenharmony_ci tst_brk(TCONF, "Not enough swap space to test: swap_free_init(%ldkB) < mem_over_max(%ldkB)", 103f08c3bdfSopenharmony_ci swap_free_init, mem_over_max); 104f08c3bdfSopenharmony_ci} 105f08c3bdfSopenharmony_ci 106f08c3bdfSopenharmony_cistatic void do_alloc(int allow_raise) 107f08c3bdfSopenharmony_ci{ 108f08c3bdfSopenharmony_ci long mem_count; 109f08c3bdfSopenharmony_ci void *s; 110f08c3bdfSopenharmony_ci 111f08c3bdfSopenharmony_ci if (allow_raise == 1) 112f08c3bdfSopenharmony_ci tst_res(TINFO, "available physical memory: %ld MB", 113f08c3bdfSopenharmony_ci mem_available_init / 1024); 114f08c3bdfSopenharmony_ci mem_count = mem_available_init + mem_over; 115f08c3bdfSopenharmony_ci if (allow_raise == 1) 116f08c3bdfSopenharmony_ci tst_res(TINFO, "try to allocate: %ld MB", mem_count / 1024); 117f08c3bdfSopenharmony_ci s = SAFE_MALLOC(mem_count * 1024); 118f08c3bdfSopenharmony_ci memset(s, 1, mem_count * 1024); 119f08c3bdfSopenharmony_ci if ((allow_raise == 1) && (raise(SIGSTOP) == -1)) { 120f08c3bdfSopenharmony_ci tst_res(TINFO, "memory allocated: %ld MB", mem_count / 1024); 121f08c3bdfSopenharmony_ci tst_brk(TBROK | TERRNO, "kill"); 122f08c3bdfSopenharmony_ci } 123f08c3bdfSopenharmony_ci free(s); 124f08c3bdfSopenharmony_ci} 125f08c3bdfSopenharmony_ci 126f08c3bdfSopenharmony_cistatic void check_swapping(void) 127f08c3bdfSopenharmony_ci{ 128f08c3bdfSopenharmony_ci int status; 129f08c3bdfSopenharmony_ci long swap_free_now, swapped; 130f08c3bdfSopenharmony_ci 131f08c3bdfSopenharmony_ci /* wait child stop */ 132f08c3bdfSopenharmony_ci SAFE_WAITPID(pid, &status, WUNTRACED); 133f08c3bdfSopenharmony_ci if (!WIFSTOPPED(status)) 134f08c3bdfSopenharmony_ci tst_brk(TBROK, "child was not stopped."); 135f08c3bdfSopenharmony_ci 136f08c3bdfSopenharmony_ci /* Still occupying memory, loop for a while */ 137f08c3bdfSopenharmony_ci while (tst_remaining_runtime() > start_runtime/2) { 138f08c3bdfSopenharmony_ci swap_free_now = SAFE_READ_MEMINFO("SwapFree:"); 139f08c3bdfSopenharmony_ci sleep(1); 140f08c3bdfSopenharmony_ci long diff = labs(swap_free_now - SAFE_READ_MEMINFO("SwapFree:")); 141f08c3bdfSopenharmony_ci if (diff < 10) 142f08c3bdfSopenharmony_ci break; 143f08c3bdfSopenharmony_ci 144f08c3bdfSopenharmony_ci tst_res(TINFO, "SwapFree difference %li", diff); 145f08c3bdfSopenharmony_ci } 146f08c3bdfSopenharmony_ci 147f08c3bdfSopenharmony_ci swapped = SAFE_READ_PROC_STATUS(pid, "VmSwap:"); 148f08c3bdfSopenharmony_ci if (swapped > mem_over_max) { 149f08c3bdfSopenharmony_ci kill(pid, SIGCONT); 150f08c3bdfSopenharmony_ci tst_brk(TFAIL, "heavy swapping detected: " 151f08c3bdfSopenharmony_ci "%ld MB swapped.", swapped / 1024); 152f08c3bdfSopenharmony_ci } 153f08c3bdfSopenharmony_ci 154f08c3bdfSopenharmony_ci tst_res(TPASS, "no heavy swapping detected, %ld MB swapped.", 155f08c3bdfSopenharmony_ci swapped / 1024); 156f08c3bdfSopenharmony_ci kill(pid, SIGCONT); 157f08c3bdfSopenharmony_ci /* wait child exit */ 158f08c3bdfSopenharmony_ci SAFE_WAITPID(pid, &status, 0); 159f08c3bdfSopenharmony_ci} 160f08c3bdfSopenharmony_ci 161f08c3bdfSopenharmony_cistatic struct tst_test test = { 162f08c3bdfSopenharmony_ci .needs_root = 1, 163f08c3bdfSopenharmony_ci .forks_child = 1, 164f08c3bdfSopenharmony_ci .min_mem_avail = 10, 165f08c3bdfSopenharmony_ci .max_runtime = 600, 166f08c3bdfSopenharmony_ci .test_all = test_swapping, 167f08c3bdfSopenharmony_ci .needs_kconfigs = (const char *[]) { 168f08c3bdfSopenharmony_ci "CONFIG_SWAP=y", 169f08c3bdfSopenharmony_ci NULL 170f08c3bdfSopenharmony_ci }, 171f08c3bdfSopenharmony_ci .tags = (const struct tst_tag[]) { 172f08c3bdfSopenharmony_ci {"linux-git", "50a15981a1fa"}, 173f08c3bdfSopenharmony_ci {} 174f08c3bdfSopenharmony_ci } 175f08c3bdfSopenharmony_ci}; 176