1 // SPDX-License-Identifier: GPL-2.0
2 #define _GNU_SOURCE
3
4 #include <linux/limits.h>
5 #include <unistd.h>
6 #include <stdio.h>
7 #include <signal.h>
8 #include <errno.h>
9 #include <fcntl.h>
10 #include <sys/sysinfo.h>
11 #include <string.h>
12 #include <sys/wait.h>
13 #include <sys/mman.h>
14 #include <sys/random.h>
15
16 #include "kselftest.h"
17 #include "cgroup_util.h"
18
19 static int page_size;
20
21 #define PATH_ZSWAP "/sys/module/zswap"
22 #define PATH_ZSWAP_ENABLED "/sys/module/zswap/parameters/enabled"
23 #define PATH_ZSWAP_SHRINKER_ENABLED "/sys/module/zswap/parameters/shrinker_enabled"
24 #define PATH_ZSWAP_STORED_PAGES "/sys/kernel/debug/zswap/stored_pages"
25
read_int(const char * path,size_t * value)26 static int read_int(const char *path, size_t *value)
27 {
28 FILE *file;
29 int ret = 0;
30
31 file = fopen(path, "r");
32 if (!file)
33 return -1;
34 if (fscanf(file, "%ld", value) != 1)
35 ret = -1;
36 fclose(file);
37 return ret;
38 }
39
set_min_free_kb(size_t value)40 static int set_min_free_kb(size_t value)
41 {
42 FILE *file;
43 int ret;
44
45 file = fopen("/proc/sys/vm/min_free_kbytes", "w");
46 if (!file)
47 return -1;
48 ret = fprintf(file, "%ld\n", value);
49 fclose(file);
50 return ret;
51 }
52
read_min_free_kb(size_t * value)53 static int read_min_free_kb(size_t *value)
54 {
55 return read_int("/proc/sys/vm/min_free_kbytes", value);
56 }
57
get_zswap_stored_pages(size_t * value)58 static int get_zswap_stored_pages(size_t *value)
59 {
60 return read_int(PATH_ZSWAP_STORED_PAGES, value);
61 }
62
get_cg_wb_count(const char * cg)63 static long get_cg_wb_count(const char *cg)
64 {
65 return cg_read_key_long(cg, "memory.stat", "zswpwb");
66 }
67
get_zswpout(const char * cgroup)68 static long get_zswpout(const char *cgroup)
69 {
70 return cg_read_key_long(cgroup, "memory.stat", "zswpout ");
71 }
72
allocate_and_read_bytes(const char * cgroup,void * arg)73 static int allocate_and_read_bytes(const char *cgroup, void *arg)
74 {
75 size_t size = (size_t)arg;
76 char *mem = (char *)malloc(size);
77 int ret = 0;
78
79 if (!mem)
80 return -1;
81 for (int i = 0; i < size; i += page_size)
82 mem[i] = 'a';
83
84 /* Go through the allocated memory to (z)swap in and out pages */
85 for (int i = 0; i < size; i += page_size) {
86 if (mem[i] != 'a')
87 ret = -1;
88 }
89
90 free(mem);
91 return ret;
92 }
93
allocate_bytes(const char * cgroup,void * arg)94 static int allocate_bytes(const char *cgroup, void *arg)
95 {
96 size_t size = (size_t)arg;
97 char *mem = (char *)malloc(size);
98
99 if (!mem)
100 return -1;
101 for (int i = 0; i < size; i += page_size)
102 mem[i] = 'a';
103 free(mem);
104 return 0;
105 }
106
setup_test_group_1M(const char * root,const char * name)107 static char *setup_test_group_1M(const char *root, const char *name)
108 {
109 char *group_name = cg_name(root, name);
110
111 if (!group_name)
112 return NULL;
113 if (cg_create(group_name))
114 goto fail;
115 if (cg_write(group_name, "memory.max", "1M")) {
116 cg_destroy(group_name);
117 goto fail;
118 }
119 return group_name;
120 fail:
121 free(group_name);
122 return NULL;
123 }
124
125 /*
126 * Writeback is asynchronous; poll until at least one writeback has
127 * been recorded for @cg, or until @timeout_ms has elapsed.
128 */
wait_for_writeback(const char * cg,int timeout_ms)129 static long wait_for_writeback(const char *cg, int timeout_ms)
130 {
131 long elapsed, count;
132 for (elapsed = 0; elapsed < timeout_ms; elapsed += 100) {
133 count = get_cg_wb_count(cg);
134
135 if (count < 0)
136 return -1;
137 if (count > 0)
138 return count;
139
140 usleep(100000);
141 }
142
143 return 0;
144 }
145
146 /*
147 * Sanity test to check that pages are written into zswap.
148 */
test_zswap_usage(const char * root)149 static int test_zswap_usage(const char *root)
150 {
151 long zswpout_before, zswpout_after;
152 int ret = KSFT_FAIL;
153 char *test_group;
154
155 test_group = cg_name(root, "no_shrink_test");
156 if (!test_group)
157 goto out;
158 if (cg_create(test_group))
159 goto out;
160 if (cg_write(test_group, "memory.max", "1M"))
161 goto out;
162
163 zswpout_before = get_zswpout(test_group);
164 if (zswpout_before < 0) {
165 ksft_print_msg("Failed to get zswpout\n");
166 goto out;
167 }
168
169 /* Allocate more than memory.max to push memory into zswap */
170 if (cg_run(test_group, allocate_bytes, (void *)MB(4)))
171 goto out;
172
173 /* Verify that pages come into zswap */
174 zswpout_after = get_zswpout(test_group);
175 if (zswpout_after <= zswpout_before) {
176 ksft_print_msg("zswpout does not increase after test program\n");
177 goto out;
178 }
179 ret = KSFT_PASS;
180
181 out:
182 cg_destroy(test_group);
183 free(test_group);
184 return ret;
185 }
186
187 /*
188 * Check that when memory.zswap.max = 0, no pages can go to the zswap pool for
189 * the cgroup.
190 */
test_swapin_nozswap(const char * root)191 static int test_swapin_nozswap(const char *root)
192 {
193 int ret = KSFT_FAIL;
194 char *test_group, mem_max_buf[32];
195 long swap_peak, zswpout, min_swap;
196 size_t allocation_size = page_size * 512;
197
198 min_swap = allocation_size / 4;
199 snprintf(mem_max_buf, sizeof(mem_max_buf), "%zu", allocation_size * 3/4);
200
201 test_group = cg_name(root, "no_zswap_test");
202 if (!test_group)
203 goto out;
204 if (cg_create(test_group))
205 goto out;
206 if (cg_write(test_group, "memory.max", mem_max_buf))
207 goto out;
208 if (cg_write(test_group, "memory.zswap.max", "0"))
209 goto out;
210
211 /* Allocate and read more than memory.max to trigger swapin */
212 if (cg_run(test_group, allocate_and_read_bytes, (void *)allocation_size))
213 goto out;
214
215 /* Verify that pages are swapped out, but no zswap happened */
216 swap_peak = cg_read_long(test_group, "memory.swap.peak");
217 if (swap_peak < 0) {
218 ksft_print_msg("failed to get cgroup's swap_peak\n");
219 goto out;
220 }
221
222 if (swap_peak < min_swap) {
223 ksft_print_msg("at least %ldKB of memory should be swapped out\n",
224 min_swap / 1024);
225 goto out;
226 }
227
228 zswpout = get_zswpout(test_group);
229 if (zswpout < 0) {
230 ksft_print_msg("failed to get zswpout\n");
231 goto out;
232 }
233
234 if (zswpout > 0) {
235 ksft_print_msg("zswapout > 0 when memory.zswap.max = 0\n");
236 goto out;
237 }
238
239 ret = KSFT_PASS;
240
241 out:
242 cg_destroy(test_group);
243 free(test_group);
244 return ret;
245 }
246
247 /* Simple test to verify the (z)swapin code paths */
test_zswapin(const char * root)248 static int test_zswapin(const char *root)
249 {
250 int ret = KSFT_FAIL;
251 char *test_group;
252 long zswpin;
253
254 test_group = cg_name(root, "zswapin_test");
255 if (!test_group)
256 goto out;
257 if (cg_create(test_group))
258 goto out;
259 if (cg_write(test_group, "memory.max", "8M"))
260 goto out;
261 if (cg_write(test_group, "memory.zswap.max", "max"))
262 goto out;
263
264 /* Allocate and read more than memory.max to trigger (z)swap in */
265 if (cg_run(test_group, allocate_and_read_bytes, (void *)MB(32)))
266 goto out;
267
268 zswpin = cg_read_key_long(test_group, "memory.stat", "zswpin ");
269 if (zswpin < 0) {
270 ksft_print_msg("failed to get zswpin\n");
271 goto out;
272 }
273
274 if (zswpin < MB(24) / page_size) {
275 ksft_print_msg("at least 24MB should be brought back from zswap\n");
276 goto out;
277 }
278
279 ret = KSFT_PASS;
280
281 out:
282 cg_destroy(test_group);
283 free(test_group);
284 return ret;
285 }
286
287 /*
288 * Attempt writeback with the following steps:
289 * 1. Allocate memory.
290 * 2. Reclaim memory equal to the amount that was allocated in step 1.
291 This will move it into zswap.
292 * 3. Save current zswap usage.
293 * 4. Move the memory allocated in step 1 back in from zswap.
294 * 5. Set zswap.max to 1/4 of the amount that was recorded in step 3.
295 * 6. Attempt to reclaim memory equal to the amount that was allocated,
296 this will either trigger writeback if it's enabled, or reclamation
297 will fail if writeback is disabled as there isn't enough zswap space.
298 */
attempt_writeback(const char * cgroup,void * arg)299 static int attempt_writeback(const char *cgroup, void *arg)
300 {
301 size_t memsize = page_size * 1024;
302 char buf[page_size];
303 long zswap_usage;
304 bool wb_enabled = *(bool *) arg;
305 int ret = -1;
306 char *mem;
307
308 mem = (char *)malloc(memsize);
309 if (!mem)
310 return ret;
311
312 /*
313 * Fill half of each page with increasing data, and keep other
314 * half empty, this will result in data that is still compressible
315 * and ends up in zswap, with material zswap usage.
316 */
317 for (int i = 0; i < page_size; i++)
318 buf[i] = i < page_size/2 ? (char) i : 0;
319
320 for (int i = 0; i < memsize; i += page_size)
321 memcpy(&mem[i], buf, page_size);
322
323 /* Try and reclaim allocated memory */
324 if (cg_write_numeric(cgroup, "memory.reclaim", memsize)) {
325 ksft_print_msg("Failed to reclaim all of the requested memory\n");
326 goto out;
327 }
328
329 zswap_usage = cg_read_long(cgroup, "memory.zswap.current");
330
331 /* zswpin */
332 for (int i = 0; i < memsize; i += page_size) {
333 if (memcmp(&mem[i], buf, page_size)) {
334 ksft_print_msg("invalid memory\n");
335 goto out;
336 }
337 }
338
339 if (cg_write_numeric(cgroup, "memory.zswap.max", zswap_usage/4))
340 goto out;
341
342 /*
343 * If writeback is enabled, trying to reclaim memory now will trigger a
344 * writeback as zswap.max is 1/4 of what was needed when reclaim ran the first time.
345 * If writeback is disabled, memory reclaim will fail as zswap is limited and
346 * it can't writeback to swap.
347 */
348 ret = cg_write_numeric(cgroup, "memory.reclaim", memsize);
349 if (!wb_enabled)
350 ret = (ret == -EAGAIN) ? 0 : -1;
351
352 out:
353 free(mem);
354 return ret;
355 }
356
test_zswap_writeback_one(const char * cgroup,bool wb)357 static int test_zswap_writeback_one(const char *cgroup, bool wb)
358 {
359 long zswpwb_before, zswpwb_after;
360
361 zswpwb_before = get_cg_wb_count(cgroup);
362 if (zswpwb_before != 0) {
363 ksft_print_msg("zswpwb_before = %ld instead of 0\n", zswpwb_before);
364 return -1;
365 }
366
367 if (cg_run(cgroup, attempt_writeback, (void *) &wb))
368 return -1;
369
370 /* Verify that zswap writeback occurred only if writeback was enabled */
371 if (wb)
372 zswpwb_after = wait_for_writeback(cgroup, 5000);
373 else
374 zswpwb_after = get_cg_wb_count(cgroup);
375 if (zswpwb_after < 0)
376 return -1;
377
378 if (wb != !!zswpwb_after) {
379 ksft_print_msg("zswpwb_after is %ld while wb is %s\n",
380 zswpwb_after, wb ? "enabled" : "disabled");
381 return -1;
382 }
383
384 return 0;
385 }
386
387 /* Test to verify the zswap writeback path */
test_zswap_writeback(const char * root,bool wb)388 static int test_zswap_writeback(const char *root, bool wb)
389 {
390 int ret = KSFT_FAIL;
391 char *test_group, *test_group_child = NULL;
392
393 if (cg_read_strcmp(root, "memory.zswap.writeback", "1"))
394 return KSFT_SKIP;
395
396 test_group = cg_name(root, "zswap_writeback_test");
397 if (!test_group)
398 goto out;
399 if (cg_create(test_group))
400 goto out;
401 if (cg_write(test_group, "memory.zswap.writeback", wb ? "1" : "0"))
402 goto out;
403
404 if (test_zswap_writeback_one(test_group, wb))
405 goto out;
406
407 /* Reset memory.zswap.max to max (modified by attempt_writeback), and
408 * set up child cgroup, whose memory.zswap.writeback is hardcoded to 1.
409 * Thus, the parent's setting shall be what's in effect. */
410 if (cg_write(test_group, "memory.zswap.max", "max"))
411 goto out;
412 if (cg_write(test_group, "cgroup.subtree_control", "+memory"))
413 goto out;
414
415 test_group_child = cg_name(test_group, "zswap_writeback_test_child");
416 if (!test_group_child)
417 goto out;
418 if (cg_create(test_group_child))
419 goto out;
420 if (cg_write(test_group_child, "memory.zswap.writeback", "1"))
421 goto out;
422
423 if (test_zswap_writeback_one(test_group_child, wb))
424 goto out;
425
426 ret = KSFT_PASS;
427
428 out:
429 if (test_group_child) {
430 cg_destroy(test_group_child);
431 free(test_group_child);
432 }
433 cg_destroy(test_group);
434 free(test_group);
435 return ret;
436 }
437
test_zswap_writeback_enabled(const char * root)438 static int test_zswap_writeback_enabled(const char *root)
439 {
440 return test_zswap_writeback(root, true);
441 }
442
test_zswap_writeback_disabled(const char * root)443 static int test_zswap_writeback_disabled(const char *root)
444 {
445 return test_zswap_writeback(root, false);
446 }
447
zswap_shrinker_enabled(void)448 static bool zswap_shrinker_enabled(void)
449 {
450 char value[2];
451
452 if (read_text(PATH_ZSWAP_SHRINKER_ENABLED, value, sizeof(value)) <= 0)
453 return 0;
454
455 return value[0] == 'Y';
456 }
457
458 /*
459 * When trying to store a memcg page in zswap, if the memcg hits its memory
460 * limit in zswap, writeback should affect only the zswapped pages of that
461 * memcg.
462 */
test_no_invasive_cgroup_shrink(const char * root)463 static int test_no_invasive_cgroup_shrink(const char *root)
464 {
465 int ret = KSFT_FAIL;
466 unsigned int off;
467 long zswpwb_before, zswpwb_after, zswpwb_target;
468 size_t allocation_size = page_size * 1024;
469 unsigned int nr_pages = allocation_size / page_size;
470 char zswap_max_buf[32], mem_max_buf[32];
471 char *zw_allocation = NULL, *wb_allocation = NULL;
472 char *zw_group = NULL, *wb_group = NULL;
473
474 snprintf(zswap_max_buf, sizeof(zswap_max_buf), "%d", page_size);
475 snprintf(mem_max_buf, sizeof(mem_max_buf), "%zu", allocation_size / 2);
476
477 wb_group = setup_test_group_1M(root, "per_memcg_wb_test1");
478 if (!wb_group)
479 return KSFT_FAIL;
480 if (cg_write(wb_group, "memory.zswap.max", zswap_max_buf))
481 goto out;
482 if (cg_write(wb_group, "memory.max", mem_max_buf))
483 goto out;
484
485 zw_group = setup_test_group_1M(root, "per_memcg_wb_test2");
486 if (!zw_group)
487 goto out;
488 if (cg_write(zw_group, "memory.max", mem_max_buf))
489 goto out;
490
491 /* Push some zw_group memory into zswap (simple data, easy to compress) */
492 if (cg_enter_current(zw_group))
493 goto out;
494 zw_allocation = malloc(allocation_size);
495 for (int i = 0; i < nr_pages; i++) {
496 off = (unsigned long)i * page_size;
497 memset(&zw_allocation[off], 0, page_size);
498 memset(&zw_allocation[off], 'a', page_size/4);
499 }
500 if (cg_read_key_long(zw_group, "memory.stat", "zswapped") < 1)
501 goto out;
502
503 /* If the shrinker is enabled, try to let the writebacks finish first */
504 if (zswap_shrinker_enabled())
505 sleep(5);
506
507 zswpwb_before = get_cg_wb_count(zw_group);
508 if (zswpwb_before < 0)
509 goto out;
510
511 /* Push wb_group memory into zswap with hard-to-compress data to trigger wb */
512 if (cg_enter_current(wb_group))
513 goto out;
514 wb_allocation = malloc(allocation_size);
515 if (!wb_allocation)
516 goto out;
517 for (int i = 0; i < nr_pages; i++) {
518 off = (unsigned long)i * page_size;
519 memset(&wb_allocation[off], 0, page_size);
520 getrandom(&wb_allocation[off], page_size/4, 0);
521 }
522
523 /* Verify that only zswapped memory from wb_group has been written back */
524 zswpwb_target = wait_for_writeback(wb_group, 5000);
525 zswpwb_after = get_cg_wb_count(zw_group);
526
527 if (zswpwb_target > 0 && zswpwb_before == zswpwb_after)
528 ret = KSFT_PASS;
529
530 out:
531 cg_enter_current(root);
532 if (zw_group) {
533 cg_destroy(zw_group);
534 free(zw_group);
535 }
536 if (wb_group) {
537 cg_destroy(wb_group);
538 free(wb_group);
539 }
540 if (zw_allocation)
541 free(zw_allocation);
542 if (wb_allocation)
543 free(wb_allocation);
544 return ret;
545 }
546
547 struct no_kmem_bypass_child_args {
548 size_t target_alloc_bytes;
549 size_t child_allocated;
550 };
551
no_kmem_bypass_child(const char * cgroup,void * arg)552 static int no_kmem_bypass_child(const char *cgroup, void *arg)
553 {
554 struct no_kmem_bypass_child_args *values = arg;
555 void *allocation;
556
557 allocation = malloc(values->target_alloc_bytes);
558 if (!allocation) {
559 values->child_allocated = true;
560 return -1;
561 }
562 for (long i = 0; i < values->target_alloc_bytes; i += page_size)
563 ((char *)allocation)[i] = 'a';
564 values->child_allocated = true;
565 pause();
566 free(allocation);
567 return 0;
568 }
569
570 /*
571 * When pages owned by a memcg are pushed to zswap by kswapd, they should be
572 * charged to that cgroup. This wasn't the case before commit
573 * cd08d80ecdac("mm: correctly charge compressed memory to its memcg").
574 *
575 * The test first allocates memory in a memcg, then raises min_free_kbytes to
576 * a very high value so that the allocation falls below low wm, then makes
577 * another allocation to trigger kswapd that should push the memcg-owned pages
578 * to zswap and verifies that the zswap pages are correctly charged.
579 *
580 * To be run on a VM with at most 4G of memory.
581 */
test_no_kmem_bypass(const char * root)582 static int test_no_kmem_bypass(const char *root)
583 {
584 size_t min_free_kb_high, min_free_kb_low, min_free_kb_original;
585 struct no_kmem_bypass_child_args *values;
586 size_t trigger_allocation_size;
587 int wait_child_iteration = 0;
588 long stored_pages_threshold;
589 struct sysinfo sys_info;
590 int ret = KSFT_FAIL;
591 int child_status;
592 char *test_group = NULL;
593 pid_t child_pid;
594
595 /* Read sys info and compute test values accordingly */
596 if (sysinfo(&sys_info) != 0)
597 return KSFT_FAIL;
598 if (sys_info.totalram > GB(4)) {
599 ksft_print_msg(
600 "requires less than 4GB total ram, sys_info.totalram: %.1fGB\n",
601 (double)sys_info.totalram / GB(1));
602 return KSFT_SKIP;
603 }
604 if (access(PATH_ZSWAP_STORED_PAGES, R_OK)) {
605 ksft_print_msg("debugfs not mounted at /sys/kernel/debug\n");
606 return KSFT_SKIP;
607 }
608 values = mmap(0, sizeof(struct no_kmem_bypass_child_args), PROT_READ |
609 PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
610 if (values == MAP_FAILED)
611 return KSFT_FAIL;
612 if (read_min_free_kb(&min_free_kb_original))
613 return KSFT_FAIL;
614 min_free_kb_high = sys_info.totalram / 2000;
615 min_free_kb_low = sys_info.totalram / 500000;
616 values->target_alloc_bytes = (sys_info.totalram - min_free_kb_high * 1000) +
617 sys_info.totalram * 5 / 100;
618 stored_pages_threshold = sys_info.totalram / 5 / page_size;
619 trigger_allocation_size = sys_info.totalram / 20;
620
621 /* Set up test memcg */
622 test_group = cg_name(root, "kmem_bypass_test");
623 if (!test_group)
624 goto out;
625
626 /* Spawn memcg child and wait for it to allocate */
627 set_min_free_kb(min_free_kb_low);
628 if (cg_create(test_group))
629 goto out;
630 values->child_allocated = false;
631 child_pid = cg_run_nowait(test_group, no_kmem_bypass_child, values);
632 if (child_pid < 0)
633 goto out;
634 while (!values->child_allocated && wait_child_iteration++ < 10000)
635 usleep(1000);
636
637 /* Try to wakeup kswapd and let it push child memory to zswap */
638 set_min_free_kb(min_free_kb_high);
639 for (int i = 0; i < 20; i++) {
640 size_t stored_pages;
641 char *trigger_allocation = malloc(trigger_allocation_size);
642
643 if (!trigger_allocation)
644 break;
645 for (int i = 0; i < trigger_allocation_size; i += page_size)
646 trigger_allocation[i] = 'b';
647 usleep(100000);
648 free(trigger_allocation);
649 if (get_zswap_stored_pages(&stored_pages))
650 break;
651 if (stored_pages < 0)
652 break;
653 /* If memory was pushed to zswap, verify it belongs to memcg */
654 if (stored_pages > stored_pages_threshold) {
655 int zswapped = cg_read_key_long(test_group, "memory.stat", "zswapped ");
656 int delta = stored_pages * page_size - zswapped;
657 int result_ok = delta < stored_pages * page_size / 4;
658
659 ret = result_ok ? KSFT_PASS : KSFT_FAIL;
660 break;
661 }
662 }
663
664 kill(child_pid, SIGTERM);
665 waitpid(child_pid, &child_status, 0);
666 out:
667 set_min_free_kb(min_free_kb_original);
668 cg_destroy(test_group);
669 free(test_group);
670 return ret;
671 }
672
673 struct incomp_child_args {
674 size_t size;
675 int pipefd[2];
676 int madvise_ret;
677 int madvise_errno;
678 };
679
allocate_random_and_wait(const char * cgroup,void * arg)680 static int allocate_random_and_wait(const char *cgroup, void *arg)
681 {
682 struct incomp_child_args *values = arg;
683 size_t size = values->size;
684 char *mem;
685 int fd;
686 ssize_t n;
687
688 close(values->pipefd[0]);
689
690 mem = mmap(NULL, size, PROT_READ | PROT_WRITE,
691 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
692 if (mem == MAP_FAILED)
693 return -1;
694
695 /* Fill with random data from /dev/urandom - incompressible */
696 fd = open("/dev/urandom", O_RDONLY);
697 if (fd < 0) {
698 munmap(mem, size);
699 return -1;
700 }
701
702 for (size_t i = 0; i < size; ) {
703 n = read(fd, mem + i, size - i);
704 if (n <= 0)
705 break;
706 i += n;
707 }
708 close(fd);
709
710 /* Touch all pages to ensure they're faulted in */
711 for (size_t i = 0; i < size; i += page_size)
712 mem[i] = mem[i];
713
714 /* Use MADV_PAGEOUT to push pages into zswap */
715 values->madvise_ret = madvise(mem, size, MADV_PAGEOUT);
716 values->madvise_errno = errno;
717
718 /* Notify parent that allocation and pageout are done */
719 write(values->pipefd[1], "x", 1);
720 close(values->pipefd[1]);
721
722 /* Keep memory alive for parent to check stats */
723 pause();
724 munmap(mem, size);
725 return 0;
726 }
727
get_zswap_incomp(const char * cgroup)728 static long get_zswap_incomp(const char *cgroup)
729 {
730 return cg_read_key_long(cgroup, "memory.stat", "zswap_incomp ");
731 }
732
733 /*
734 * Test that incompressible pages (random data) are tracked by zswap_incomp.
735 *
736 * The child process allocates random data within memory.max, then uses
737 * MADV_PAGEOUT to push pages into zswap. The parent waits on a pipe for
738 * the child to finish, then checks the zswap_incomp stat before the child
739 * exits (zswap_incomp is a gauge that decreases on free).
740 */
test_zswap_incompressible(const char * root)741 static int test_zswap_incompressible(const char *root)
742 {
743 int ret = KSFT_FAIL;
744 struct incomp_child_args *values;
745 char *test_group;
746 long zswap_incomp;
747 pid_t child_pid;
748 int child_status;
749 char buf;
750
751 values = mmap(0, sizeof(struct incomp_child_args), PROT_READ |
752 PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
753 if (values == MAP_FAILED)
754 return KSFT_FAIL;
755
756 if (pipe(values->pipefd)) {
757 munmap(values, sizeof(struct incomp_child_args));
758 return KSFT_FAIL;
759 }
760
761 test_group = cg_name(root, "zswap_incompressible_test");
762 if (!test_group)
763 goto out;
764 if (cg_create(test_group))
765 goto out;
766 if (cg_write(test_group, "memory.max", "32M"))
767 goto out;
768
769 values->size = MB(4);
770 child_pid = cg_run_nowait(test_group, allocate_random_and_wait, values);
771 if (child_pid < 0)
772 goto out;
773
774 close(values->pipefd[1]);
775
776 /* Wait for child to finish allocating and pageout */
777 read(values->pipefd[0], &buf, 1);
778 close(values->pipefd[0]);
779
780 zswap_incomp = get_zswap_incomp(test_group);
781 if (zswap_incomp <= 0) {
782 long zswpout = get_zswpout(test_group);
783 long zswapped = cg_read_key_long(test_group, "memory.stat", "zswapped ");
784 long zswap_b = cg_read_key_long(test_group, "memory.stat", "zswap ");
785
786 ksft_print_msg("zswap_incomp not increased: %ld\n", zswap_incomp);
787 ksft_print_msg("debug: zswpout=%ld zswapped=%ld zswap_b=%ld\n",
788 zswpout, zswapped, zswap_b);
789 ksft_print_msg("debug: madvise ret=%d errno=%d\n",
790 values->madvise_ret, values->madvise_errno);
791 goto out_kill;
792 }
793
794 ret = KSFT_PASS;
795
796 out_kill:
797 kill(child_pid, SIGTERM);
798 waitpid(child_pid, &child_status, 0);
799 out:
800 cg_destroy(test_group);
801 free(test_group);
802 munmap(values, sizeof(struct incomp_child_args));
803 return ret;
804 }
805
806 #define T(x) { x, #x }
807 struct zswap_test {
808 int (*fn)(const char *root);
809 const char *name;
810 } tests[] = {
811 T(test_zswap_usage),
812 T(test_swapin_nozswap),
813 T(test_zswapin),
814 T(test_zswap_writeback_enabled),
815 T(test_zswap_writeback_disabled),
816 T(test_no_kmem_bypass),
817 T(test_no_invasive_cgroup_shrink),
818 T(test_zswap_incompressible),
819 };
820 #undef T
821
check_zswap_enabled(void)822 static void check_zswap_enabled(void)
823 {
824 char value[2];
825
826 if (access(PATH_ZSWAP, F_OK))
827 ksft_exit_skip("zswap isn't configured\n");
828
829 if (read_text(PATH_ZSWAP_ENABLED, value, sizeof(value)) <= 0)
830 ksft_exit_fail_msg("Failed to read " PATH_ZSWAP_ENABLED "\n");
831
832 if (value[0] == 'N')
833 ksft_exit_skip("zswap is disabled (hint: echo 1 > " PATH_ZSWAP_ENABLED ")\n");
834 }
835
main(int argc,char ** argv)836 int main(int argc, char **argv)
837 {
838 char root[PATH_MAX];
839 int i;
840
841 page_size = sysconf(_SC_PAGE_SIZE);
842 if (page_size <= 0)
843 page_size = BUF_SIZE;
844
845 ksft_print_header();
846 if (cg_find_unified_root(root, sizeof(root), NULL))
847 ksft_exit_skip("cgroup v2 isn't mounted\n");
848
849 check_zswap_enabled();
850
851 /*
852 * Check that memory controller is available:
853 * memory is listed in cgroup.controllers
854 */
855 if (cg_read_strstr(root, "cgroup.controllers", "memory"))
856 ksft_exit_skip("memory controller isn't available\n");
857
858 if (cg_read_strstr(root, "cgroup.subtree_control", "memory"))
859 if (cg_write(root, "cgroup.subtree_control", "+memory"))
860 ksft_exit_skip("Failed to set memory controller\n");
861
862 ksft_set_plan(ARRAY_SIZE(tests));
863 for (i = 0; i < ARRAY_SIZE(tests); i++) {
864 switch (tests[i].fn(root)) {
865 case KSFT_PASS:
866 ksft_test_result_pass("%s\n", tests[i].name);
867 break;
868 case KSFT_SKIP:
869 ksft_test_result_skip("%s\n", tests[i].name);
870 break;
871 default:
872 ksft_test_result_fail("%s\n", tests[i].name);
873 break;
874 }
875 }
876
877 ksft_finished();
878 }
879