1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (c) 2020 SUSE LLC <mdoucha@suse.cz>
4 */
5
6 #include <unistd.h>
7 #include <limits.h>
8 #include <sys/sysinfo.h>
9 #include <stdlib.h>
10
11 #define TST_NO_DEFAULT_MAIN
12 #include "tst_test.h"
13
14 #define BLOCKSIZE (16 * 1024 * 1024)
15
tst_pollute_memory(size_t maxsize,int fillchar)16 void tst_pollute_memory(size_t maxsize, int fillchar)
17 {
18 size_t i, map_count = 0, safety = 0, blocksize = BLOCKSIZE;
19 void **map_blocks;
20 struct sysinfo info;
21
22 SAFE_SYSINFO(&info);
23 safety = MAX(4096 * SAFE_SYSCONF(_SC_PAGESIZE), 128 * 1024 * 1024);
24 safety /= info.mem_unit;
25
26 if (info.freeswap > safety)
27 safety = 0;
28
29 /* Not enough free memory to avoid invoking OOM killer */
30 if (info.freeram <= safety)
31 return;
32
33 if (!maxsize)
34 maxsize = SIZE_MAX;
35
36 if (info.freeram - safety < maxsize / info.mem_unit)
37 maxsize = (info.freeram - safety) * info.mem_unit;
38
39 blocksize = MIN(maxsize, blocksize);
40 map_count = maxsize / blocksize;
41 map_blocks = SAFE_MALLOC(map_count * sizeof(void *));
42
43 /*
44 * Keep allocating until the first failure. The address space may be
45 * too fragmented or just smaller than maxsize.
46 */
47 for (i = 0; i < map_count; i++) {
48 map_blocks[i] = mmap(NULL, blocksize, PROT_READ | PROT_WRITE,
49 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
50
51 if (map_blocks[i] == MAP_FAILED) {
52 map_count = i;
53 break;
54 }
55
56 memset(map_blocks[i], fillchar, blocksize);
57 }
58
59 for (i = 0; i < map_count; i++)
60 SAFE_MUNMAP(map_blocks[i], blocksize);
61
62 free(map_blocks);
63 }
64