1f08c3bdfSopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 2f08c3bdfSopenharmony_ci/* 3f08c3bdfSopenharmony_ci * Copyright (C) 2023 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com> 4f08c3bdfSopenharmony_ci */ 5f08c3bdfSopenharmony_ci 6f08c3bdfSopenharmony_ci/*\ 7f08c3bdfSopenharmony_ci * [Description] 8f08c3bdfSopenharmony_ci * 9f08c3bdfSopenharmony_ci * Allocate anonymous memory pages inside child and reclaim it with 10f08c3bdfSopenharmony_ci * MADV_PAGEOUT. Then check if memory pages have been swapped out by looking 11f08c3bdfSopenharmony_ci * at smaps information. 12f08c3bdfSopenharmony_ci * 13f08c3bdfSopenharmony_ci * The advice might be ignored for some pages in the range when it is 14f08c3bdfSopenharmony_ci * not applicable, so test passes if swap memory increases after 15f08c3bdfSopenharmony_ci * reclaiming memory with MADV_PAGEOUT. 16f08c3bdfSopenharmony_ci */ 17f08c3bdfSopenharmony_ci 18f08c3bdfSopenharmony_ci#define _GNU_SOURCE 19f08c3bdfSopenharmony_ci 20f08c3bdfSopenharmony_ci#include <sys/mman.h> 21f08c3bdfSopenharmony_ci#include "tst_test.h" 22f08c3bdfSopenharmony_ci#include "lapi/mmap.h" 23f08c3bdfSopenharmony_ci#include "lapi/syscalls.h" 24f08c3bdfSopenharmony_ci#include "process_madvise.h" 25f08c3bdfSopenharmony_ci 26f08c3bdfSopenharmony_ci#define MEM_CHILD (1 * TST_MB) 27f08c3bdfSopenharmony_ci 28f08c3bdfSopenharmony_cistatic void **data_ptr; 29f08c3bdfSopenharmony_ci 30f08c3bdfSopenharmony_cistatic void child_alloc(void) 31f08c3bdfSopenharmony_ci{ 32f08c3bdfSopenharmony_ci char data[MEM_CHILD]; 33f08c3bdfSopenharmony_ci struct addr_mapping map_before; 34f08c3bdfSopenharmony_ci struct addr_mapping map_after; 35f08c3bdfSopenharmony_ci 36f08c3bdfSopenharmony_ci memset(data, 'a', MEM_CHILD); 37f08c3bdfSopenharmony_ci 38f08c3bdfSopenharmony_ci tst_res(TINFO, "Allocate memory: %d bytes", MEM_CHILD); 39f08c3bdfSopenharmony_ci 40f08c3bdfSopenharmony_ci *data_ptr = SAFE_MMAP(NULL, MEM_CHILD, 41f08c3bdfSopenharmony_ci PROT_READ | PROT_WRITE, 42f08c3bdfSopenharmony_ci MAP_SHARED | MAP_ANONYMOUS, -1, 0); 43f08c3bdfSopenharmony_ci 44f08c3bdfSopenharmony_ci memset(*data_ptr, 'a', MEM_CHILD); 45f08c3bdfSopenharmony_ci 46f08c3bdfSopenharmony_ci memset(&map_before, 0, sizeof(struct addr_mapping)); 47f08c3bdfSopenharmony_ci read_address_mapping((unsigned long)*data_ptr, &map_before); 48f08c3bdfSopenharmony_ci 49f08c3bdfSopenharmony_ci TST_CHECKPOINT_WAKE_AND_WAIT(0); 50f08c3bdfSopenharmony_ci 51f08c3bdfSopenharmony_ci memset(&map_after, 0, sizeof(struct addr_mapping)); 52f08c3bdfSopenharmony_ci read_address_mapping((unsigned long)*data_ptr, &map_after); 53f08c3bdfSopenharmony_ci 54f08c3bdfSopenharmony_ci if (memcmp(*data_ptr, data, MEM_CHILD) != 0) { 55f08c3bdfSopenharmony_ci tst_res(TFAIL, "Dirty memory after reclaiming it"); 56f08c3bdfSopenharmony_ci return; 57f08c3bdfSopenharmony_ci } 58f08c3bdfSopenharmony_ci 59f08c3bdfSopenharmony_ci SAFE_MUNMAP(*data_ptr, MEM_CHILD); 60f08c3bdfSopenharmony_ci *data_ptr = NULL; 61f08c3bdfSopenharmony_ci 62f08c3bdfSopenharmony_ci TST_EXP_EXPR(map_before.swap < map_after.swap, 63f08c3bdfSopenharmony_ci "Most of the memory has been swapped out: %dkB out of %dkB", 64f08c3bdfSopenharmony_ci map_after.swap - map_before.swap, 65f08c3bdfSopenharmony_ci MEM_CHILD / TST_KB); 66f08c3bdfSopenharmony_ci} 67f08c3bdfSopenharmony_ci 68f08c3bdfSopenharmony_cistatic void setup(void) 69f08c3bdfSopenharmony_ci{ 70f08c3bdfSopenharmony_ci data_ptr = SAFE_MMAP(NULL, sizeof(void *), 71f08c3bdfSopenharmony_ci PROT_READ | PROT_WRITE, 72f08c3bdfSopenharmony_ci MAP_SHARED | MAP_ANONYMOUS, -1, 0); 73f08c3bdfSopenharmony_ci} 74f08c3bdfSopenharmony_ci 75f08c3bdfSopenharmony_cistatic void cleanup(void) 76f08c3bdfSopenharmony_ci{ 77f08c3bdfSopenharmony_ci if (*data_ptr) 78f08c3bdfSopenharmony_ci SAFE_MUNMAP(*data_ptr, MEM_CHILD); 79f08c3bdfSopenharmony_ci 80f08c3bdfSopenharmony_ci if (data_ptr) 81f08c3bdfSopenharmony_ci SAFE_MUNMAP(data_ptr, sizeof(void *)); 82f08c3bdfSopenharmony_ci} 83f08c3bdfSopenharmony_ci 84f08c3bdfSopenharmony_cistatic void run(void) 85f08c3bdfSopenharmony_ci{ 86f08c3bdfSopenharmony_ci int ret; 87f08c3bdfSopenharmony_ci int pidfd; 88f08c3bdfSopenharmony_ci pid_t pid_alloc; 89f08c3bdfSopenharmony_ci struct iovec vec; 90f08c3bdfSopenharmony_ci 91f08c3bdfSopenharmony_ci pid_alloc = SAFE_FORK(); 92f08c3bdfSopenharmony_ci if (!pid_alloc) { 93f08c3bdfSopenharmony_ci child_alloc(); 94f08c3bdfSopenharmony_ci return; 95f08c3bdfSopenharmony_ci } 96f08c3bdfSopenharmony_ci 97f08c3bdfSopenharmony_ci TST_CHECKPOINT_WAIT(0); 98f08c3bdfSopenharmony_ci 99f08c3bdfSopenharmony_ci tst_res(TINFO, "Reclaim memory using MADV_PAGEOUT"); 100f08c3bdfSopenharmony_ci 101f08c3bdfSopenharmony_ci pidfd = SAFE_PIDFD_OPEN(pid_alloc, 0); 102f08c3bdfSopenharmony_ci 103f08c3bdfSopenharmony_ci vec.iov_base = *data_ptr; 104f08c3bdfSopenharmony_ci vec.iov_len = MEM_CHILD; 105f08c3bdfSopenharmony_ci 106f08c3bdfSopenharmony_ci ret = tst_syscall(__NR_process_madvise, pidfd, &vec, 1UL, 107f08c3bdfSopenharmony_ci MADV_PAGEOUT, 0UL); 108f08c3bdfSopenharmony_ci 109f08c3bdfSopenharmony_ci if (ret == -1) 110f08c3bdfSopenharmony_ci tst_brk(TBROK | TERRNO, "process_madvise failed"); 111f08c3bdfSopenharmony_ci 112f08c3bdfSopenharmony_ci if (ret != MEM_CHILD) 113f08c3bdfSopenharmony_ci tst_brk(TBROK, "process_madvise reclaimed only %d bytes", ret); 114f08c3bdfSopenharmony_ci 115f08c3bdfSopenharmony_ci TST_CHECKPOINT_WAKE(0); 116f08c3bdfSopenharmony_ci} 117f08c3bdfSopenharmony_ci 118f08c3bdfSopenharmony_cistatic struct tst_test test = { 119f08c3bdfSopenharmony_ci .setup = setup, 120f08c3bdfSopenharmony_ci .cleanup = cleanup, 121f08c3bdfSopenharmony_ci .test_all = run, 122f08c3bdfSopenharmony_ci .forks_child = 1, 123f08c3bdfSopenharmony_ci .min_kver = "5.10", 124f08c3bdfSopenharmony_ci .needs_checkpoints = 1, 125f08c3bdfSopenharmony_ci .needs_root = 1, 126f08c3bdfSopenharmony_ci .min_swap_avail = MEM_CHILD / TST_KB, 127f08c3bdfSopenharmony_ci .needs_kconfigs = (const char *[]) { 128f08c3bdfSopenharmony_ci "CONFIG_SWAP=y", 129f08c3bdfSopenharmony_ci NULL 130f08c3bdfSopenharmony_ci }, 131f08c3bdfSopenharmony_ci}; 132