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