This source file includes following definitions.
- test_memcg_subtree_control
- alloc_anon_50M_check
- alloc_pagecache_50M_check
- test_memcg_current
- alloc_pagecache_50M
- alloc_pagecache_50M_noexit
- alloc_anon_noexit
- cg_test_proc_killed
- test_memcg_min
- test_memcg_low
- alloc_pagecache_max_30M
- test_memcg_high
- test_memcg_max
- alloc_anon_50M_check_swap
- test_memcg_swap_max
- test_memcg_oom_events
- tcp_server
- tcp_client
- test_memcg_sock
- test_memcg_oom_group_leaf_events
- test_memcg_oom_group_parent_events
- test_memcg_oom_group_score_events
- main
1
2 #define _GNU_SOURCE
3
4 #include <linux/limits.h>
5 #include <linux/oom.h>
6 #include <fcntl.h>
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <sys/stat.h>
11 #include <sys/types.h>
12 #include <unistd.h>
13 #include <sys/socket.h>
14 #include <sys/wait.h>
15 #include <arpa/inet.h>
16 #include <netinet/in.h>
17 #include <netdb.h>
18 #include <errno.h>
19
20 #include "../kselftest.h"
21 #include "cgroup_util.h"
22
23
24
25
26
27 static int test_memcg_subtree_control(const char *root)
28 {
29 char *parent, *child, *parent2 = NULL, *child2 = NULL;
30 int ret = KSFT_FAIL;
31 char buf[PAGE_SIZE];
32
33
34 parent = cg_name(root, "memcg_test_0");
35 child = cg_name(root, "memcg_test_0/memcg_test_1");
36 if (!parent || !child)
37 goto cleanup_free;
38
39 if (cg_create(parent))
40 goto cleanup_free;
41
42 if (cg_write(parent, "cgroup.subtree_control", "+memory"))
43 goto cleanup_parent;
44
45 if (cg_create(child))
46 goto cleanup_parent;
47
48 if (cg_read_strstr(child, "cgroup.controllers", "memory"))
49 goto cleanup_child;
50
51
52 parent2 = cg_name(root, "memcg_test_1");
53 child2 = cg_name(root, "memcg_test_1/memcg_test_1");
54 if (!parent2 || !child2)
55 goto cleanup_free2;
56
57 if (cg_create(parent2))
58 goto cleanup_free2;
59
60 if (cg_create(child2))
61 goto cleanup_parent2;
62
63 if (cg_read(child2, "cgroup.controllers", buf, sizeof(buf)))
64 goto cleanup_all;
65
66 if (!cg_read_strstr(child2, "cgroup.controllers", "memory"))
67 goto cleanup_all;
68
69 ret = KSFT_PASS;
70
71 cleanup_all:
72 cg_destroy(child2);
73 cleanup_parent2:
74 cg_destroy(parent2);
75 cleanup_free2:
76 free(parent2);
77 free(child2);
78 cleanup_child:
79 cg_destroy(child);
80 cleanup_parent:
81 cg_destroy(parent);
82 cleanup_free:
83 free(parent);
84 free(child);
85
86 return ret;
87 }
88
89 static int alloc_anon_50M_check(const char *cgroup, void *arg)
90 {
91 size_t size = MB(50);
92 char *buf, *ptr;
93 long anon, current;
94 int ret = -1;
95
96 buf = malloc(size);
97 for (ptr = buf; ptr < buf + size; ptr += PAGE_SIZE)
98 *ptr = 0;
99
100 current = cg_read_long(cgroup, "memory.current");
101 if (current < size)
102 goto cleanup;
103
104 if (!values_close(size, current, 3))
105 goto cleanup;
106
107 anon = cg_read_key_long(cgroup, "memory.stat", "anon ");
108 if (anon < 0)
109 goto cleanup;
110
111 if (!values_close(anon, current, 3))
112 goto cleanup;
113
114 ret = 0;
115 cleanup:
116 free(buf);
117 return ret;
118 }
119
120 static int alloc_pagecache_50M_check(const char *cgroup, void *arg)
121 {
122 size_t size = MB(50);
123 int ret = -1;
124 long current, file;
125 int fd;
126
127 fd = get_temp_fd();
128 if (fd < 0)
129 return -1;
130
131 if (alloc_pagecache(fd, size))
132 goto cleanup;
133
134 current = cg_read_long(cgroup, "memory.current");
135 if (current < size)
136 goto cleanup;
137
138 file = cg_read_key_long(cgroup, "memory.stat", "file ");
139 if (file < 0)
140 goto cleanup;
141
142 if (!values_close(file, current, 10))
143 goto cleanup;
144
145 ret = 0;
146
147 cleanup:
148 close(fd);
149 return ret;
150 }
151
152
153
154
155
156
157 static int test_memcg_current(const char *root)
158 {
159 int ret = KSFT_FAIL;
160 long current;
161 char *memcg;
162
163 memcg = cg_name(root, "memcg_test");
164 if (!memcg)
165 goto cleanup;
166
167 if (cg_create(memcg))
168 goto cleanup;
169
170 current = cg_read_long(memcg, "memory.current");
171 if (current != 0)
172 goto cleanup;
173
174 if (cg_run(memcg, alloc_anon_50M_check, NULL))
175 goto cleanup;
176
177 if (cg_run(memcg, alloc_pagecache_50M_check, NULL))
178 goto cleanup;
179
180 ret = KSFT_PASS;
181
182 cleanup:
183 cg_destroy(memcg);
184 free(memcg);
185
186 return ret;
187 }
188
189 static int alloc_pagecache_50M(const char *cgroup, void *arg)
190 {
191 int fd = (long)arg;
192
193 return alloc_pagecache(fd, MB(50));
194 }
195
196 static int alloc_pagecache_50M_noexit(const char *cgroup, void *arg)
197 {
198 int fd = (long)arg;
199 int ppid = getppid();
200
201 if (alloc_pagecache(fd, MB(50)))
202 return -1;
203
204 while (getppid() == ppid)
205 sleep(1);
206
207 return 0;
208 }
209
210 static int alloc_anon_noexit(const char *cgroup, void *arg)
211 {
212 int ppid = getppid();
213
214 if (alloc_anon(cgroup, arg))
215 return -1;
216
217 while (getppid() == ppid)
218 sleep(1);
219
220 return 0;
221 }
222
223
224
225
226
227 static int cg_test_proc_killed(const char *cgroup)
228 {
229 int limit;
230
231 for (limit = 10; limit > 0; limit--) {
232 if (cg_read_strcmp(cgroup, "cgroup.procs", "") == 0)
233 return 0;
234
235 usleep(100000);
236 }
237 return -1;
238 }
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264 static int test_memcg_min(const char *root)
265 {
266 int ret = KSFT_FAIL;
267 char *parent[3] = {NULL};
268 char *children[4] = {NULL};
269 long c[4];
270 int i, attempts;
271 int fd;
272
273 fd = get_temp_fd();
274 if (fd < 0)
275 goto cleanup;
276
277 parent[0] = cg_name(root, "memcg_test_0");
278 if (!parent[0])
279 goto cleanup;
280
281 parent[1] = cg_name(parent[0], "memcg_test_1");
282 if (!parent[1])
283 goto cleanup;
284
285 parent[2] = cg_name(parent[0], "memcg_test_2");
286 if (!parent[2])
287 goto cleanup;
288
289 if (cg_create(parent[0]))
290 goto cleanup;
291
292 if (cg_read_long(parent[0], "memory.min")) {
293 ret = KSFT_SKIP;
294 goto cleanup;
295 }
296
297 if (cg_write(parent[0], "cgroup.subtree_control", "+memory"))
298 goto cleanup;
299
300 if (cg_write(parent[0], "memory.max", "200M"))
301 goto cleanup;
302
303 if (cg_write(parent[0], "memory.swap.max", "0"))
304 goto cleanup;
305
306 if (cg_create(parent[1]))
307 goto cleanup;
308
309 if (cg_write(parent[1], "cgroup.subtree_control", "+memory"))
310 goto cleanup;
311
312 if (cg_create(parent[2]))
313 goto cleanup;
314
315 for (i = 0; i < ARRAY_SIZE(children); i++) {
316 children[i] = cg_name_indexed(parent[1], "child_memcg", i);
317 if (!children[i])
318 goto cleanup;
319
320 if (cg_create(children[i]))
321 goto cleanup;
322
323 if (i == 2)
324 continue;
325
326 cg_run_nowait(children[i], alloc_pagecache_50M_noexit,
327 (void *)(long)fd);
328 }
329
330 if (cg_write(parent[0], "memory.min", "50M"))
331 goto cleanup;
332 if (cg_write(parent[1], "memory.min", "50M"))
333 goto cleanup;
334 if (cg_write(children[0], "memory.min", "75M"))
335 goto cleanup;
336 if (cg_write(children[1], "memory.min", "25M"))
337 goto cleanup;
338 if (cg_write(children[2], "memory.min", "500M"))
339 goto cleanup;
340 if (cg_write(children[3], "memory.min", "0"))
341 goto cleanup;
342
343 attempts = 0;
344 while (!values_close(cg_read_long(parent[1], "memory.current"),
345 MB(150), 3)) {
346 if (attempts++ > 5)
347 break;
348 sleep(1);
349 }
350
351 if (cg_run(parent[2], alloc_anon, (void *)MB(148)))
352 goto cleanup;
353
354 if (!values_close(cg_read_long(parent[1], "memory.current"), MB(50), 3))
355 goto cleanup;
356
357 for (i = 0; i < ARRAY_SIZE(children); i++)
358 c[i] = cg_read_long(children[i], "memory.current");
359
360 if (!values_close(c[0], MB(33), 10))
361 goto cleanup;
362
363 if (!values_close(c[1], MB(17), 10))
364 goto cleanup;
365
366 if (!values_close(c[2], 0, 1))
367 goto cleanup;
368
369 if (!cg_run(parent[2], alloc_anon, (void *)MB(170)))
370 goto cleanup;
371
372 if (!values_close(cg_read_long(parent[1], "memory.current"), MB(50), 3))
373 goto cleanup;
374
375 ret = KSFT_PASS;
376
377 cleanup:
378 for (i = ARRAY_SIZE(children) - 1; i >= 0; i--) {
379 if (!children[i])
380 continue;
381
382 cg_destroy(children[i]);
383 free(children[i]);
384 }
385
386 for (i = ARRAY_SIZE(parent) - 1; i >= 0; i--) {
387 if (!parent[i])
388 continue;
389
390 cg_destroy(parent[i]);
391 free(parent[i]);
392 }
393 close(fd);
394 return ret;
395 }
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420 static int test_memcg_low(const char *root)
421 {
422 int ret = KSFT_FAIL;
423 char *parent[3] = {NULL};
424 char *children[4] = {NULL};
425 long low, oom;
426 long c[4];
427 int i;
428 int fd;
429
430 fd = get_temp_fd();
431 if (fd < 0)
432 goto cleanup;
433
434 parent[0] = cg_name(root, "memcg_test_0");
435 if (!parent[0])
436 goto cleanup;
437
438 parent[1] = cg_name(parent[0], "memcg_test_1");
439 if (!parent[1])
440 goto cleanup;
441
442 parent[2] = cg_name(parent[0], "memcg_test_2");
443 if (!parent[2])
444 goto cleanup;
445
446 if (cg_create(parent[0]))
447 goto cleanup;
448
449 if (cg_read_long(parent[0], "memory.low"))
450 goto cleanup;
451
452 if (cg_write(parent[0], "cgroup.subtree_control", "+memory"))
453 goto cleanup;
454
455 if (cg_write(parent[0], "memory.max", "200M"))
456 goto cleanup;
457
458 if (cg_write(parent[0], "memory.swap.max", "0"))
459 goto cleanup;
460
461 if (cg_create(parent[1]))
462 goto cleanup;
463
464 if (cg_write(parent[1], "cgroup.subtree_control", "+memory"))
465 goto cleanup;
466
467 if (cg_create(parent[2]))
468 goto cleanup;
469
470 for (i = 0; i < ARRAY_SIZE(children); i++) {
471 children[i] = cg_name_indexed(parent[1], "child_memcg", i);
472 if (!children[i])
473 goto cleanup;
474
475 if (cg_create(children[i]))
476 goto cleanup;
477
478 if (i == 2)
479 continue;
480
481 if (cg_run(children[i], alloc_pagecache_50M, (void *)(long)fd))
482 goto cleanup;
483 }
484
485 if (cg_write(parent[0], "memory.low", "50M"))
486 goto cleanup;
487 if (cg_write(parent[1], "memory.low", "50M"))
488 goto cleanup;
489 if (cg_write(children[0], "memory.low", "75M"))
490 goto cleanup;
491 if (cg_write(children[1], "memory.low", "25M"))
492 goto cleanup;
493 if (cg_write(children[2], "memory.low", "500M"))
494 goto cleanup;
495 if (cg_write(children[3], "memory.low", "0"))
496 goto cleanup;
497
498 if (cg_run(parent[2], alloc_anon, (void *)MB(148)))
499 goto cleanup;
500
501 if (!values_close(cg_read_long(parent[1], "memory.current"), MB(50), 3))
502 goto cleanup;
503
504 for (i = 0; i < ARRAY_SIZE(children); i++)
505 c[i] = cg_read_long(children[i], "memory.current");
506
507 if (!values_close(c[0], MB(33), 10))
508 goto cleanup;
509
510 if (!values_close(c[1], MB(17), 10))
511 goto cleanup;
512
513 if (!values_close(c[2], 0, 1))
514 goto cleanup;
515
516 if (cg_run(parent[2], alloc_anon, (void *)MB(166))) {
517 fprintf(stderr,
518 "memory.low prevents from allocating anon memory\n");
519 goto cleanup;
520 }
521
522 for (i = 0; i < ARRAY_SIZE(children); i++) {
523 oom = cg_read_key_long(children[i], "memory.events", "oom ");
524 low = cg_read_key_long(children[i], "memory.events", "low ");
525
526 if (oom)
527 goto cleanup;
528 if (i < 2 && low <= 0)
529 goto cleanup;
530 if (i >= 2 && low)
531 goto cleanup;
532 }
533
534 ret = KSFT_PASS;
535
536 cleanup:
537 for (i = ARRAY_SIZE(children) - 1; i >= 0; i--) {
538 if (!children[i])
539 continue;
540
541 cg_destroy(children[i]);
542 free(children[i]);
543 }
544
545 for (i = ARRAY_SIZE(parent) - 1; i >= 0; i--) {
546 if (!parent[i])
547 continue;
548
549 cg_destroy(parent[i]);
550 free(parent[i]);
551 }
552 close(fd);
553 return ret;
554 }
555
556 static int alloc_pagecache_max_30M(const char *cgroup, void *arg)
557 {
558 size_t size = MB(50);
559 int ret = -1;
560 long current;
561 int fd;
562
563 fd = get_temp_fd();
564 if (fd < 0)
565 return -1;
566
567 if (alloc_pagecache(fd, size))
568 goto cleanup;
569
570 current = cg_read_long(cgroup, "memory.current");
571 if (current <= MB(29) || current > MB(30))
572 goto cleanup;
573
574 ret = 0;
575
576 cleanup:
577 close(fd);
578 return ret;
579
580 }
581
582
583
584
585
586
587 static int test_memcg_high(const char *root)
588 {
589 int ret = KSFT_FAIL;
590 char *memcg;
591 long high;
592
593 memcg = cg_name(root, "memcg_test");
594 if (!memcg)
595 goto cleanup;
596
597 if (cg_create(memcg))
598 goto cleanup;
599
600 if (cg_read_strcmp(memcg, "memory.high", "max\n"))
601 goto cleanup;
602
603 if (cg_write(memcg, "memory.swap.max", "0"))
604 goto cleanup;
605
606 if (cg_write(memcg, "memory.high", "30M"))
607 goto cleanup;
608
609 if (cg_run(memcg, alloc_anon, (void *)MB(100)))
610 goto cleanup;
611
612 if (!cg_run(memcg, alloc_pagecache_50M_check, NULL))
613 goto cleanup;
614
615 if (cg_run(memcg, alloc_pagecache_max_30M, NULL))
616 goto cleanup;
617
618 high = cg_read_key_long(memcg, "memory.events", "high ");
619 if (high <= 0)
620 goto cleanup;
621
622 ret = KSFT_PASS;
623
624 cleanup:
625 cg_destroy(memcg);
626 free(memcg);
627
628 return ret;
629 }
630
631
632
633
634
635
636 static int test_memcg_max(const char *root)
637 {
638 int ret = KSFT_FAIL;
639 char *memcg;
640 long current, max;
641
642 memcg = cg_name(root, "memcg_test");
643 if (!memcg)
644 goto cleanup;
645
646 if (cg_create(memcg))
647 goto cleanup;
648
649 if (cg_read_strcmp(memcg, "memory.max", "max\n"))
650 goto cleanup;
651
652 if (cg_write(memcg, "memory.swap.max", "0"))
653 goto cleanup;
654
655 if (cg_write(memcg, "memory.max", "30M"))
656 goto cleanup;
657
658
659 if (!cg_run(memcg, alloc_anon, (void *)MB(100)))
660 goto cleanup;
661
662 if (cg_run(memcg, alloc_pagecache_max_30M, NULL))
663 goto cleanup;
664
665 current = cg_read_long(memcg, "memory.current");
666 if (current > MB(30) || !current)
667 goto cleanup;
668
669 max = cg_read_key_long(memcg, "memory.events", "max ");
670 if (max <= 0)
671 goto cleanup;
672
673 ret = KSFT_PASS;
674
675 cleanup:
676 cg_destroy(memcg);
677 free(memcg);
678
679 return ret;
680 }
681
682 static int alloc_anon_50M_check_swap(const char *cgroup, void *arg)
683 {
684 long mem_max = (long)arg;
685 size_t size = MB(50);
686 char *buf, *ptr;
687 long mem_current, swap_current;
688 int ret = -1;
689
690 buf = malloc(size);
691 for (ptr = buf; ptr < buf + size; ptr += PAGE_SIZE)
692 *ptr = 0;
693
694 mem_current = cg_read_long(cgroup, "memory.current");
695 if (!mem_current || !values_close(mem_current, mem_max, 3))
696 goto cleanup;
697
698 swap_current = cg_read_long(cgroup, "memory.swap.current");
699 if (!swap_current ||
700 !values_close(mem_current + swap_current, size, 3))
701 goto cleanup;
702
703 ret = 0;
704 cleanup:
705 free(buf);
706 return ret;
707 }
708
709
710
711
712
713 static int test_memcg_swap_max(const char *root)
714 {
715 int ret = KSFT_FAIL;
716 char *memcg;
717 long max;
718
719 if (!is_swap_enabled())
720 return KSFT_SKIP;
721
722 memcg = cg_name(root, "memcg_test");
723 if (!memcg)
724 goto cleanup;
725
726 if (cg_create(memcg))
727 goto cleanup;
728
729 if (cg_read_long(memcg, "memory.swap.current")) {
730 ret = KSFT_SKIP;
731 goto cleanup;
732 }
733
734 if (cg_read_strcmp(memcg, "memory.max", "max\n"))
735 goto cleanup;
736
737 if (cg_read_strcmp(memcg, "memory.swap.max", "max\n"))
738 goto cleanup;
739
740 if (cg_write(memcg, "memory.swap.max", "30M"))
741 goto cleanup;
742
743 if (cg_write(memcg, "memory.max", "30M"))
744 goto cleanup;
745
746
747 if (!cg_run(memcg, alloc_anon, (void *)MB(100)))
748 goto cleanup;
749
750 if (cg_read_key_long(memcg, "memory.events", "oom ") != 1)
751 goto cleanup;
752
753 if (cg_read_key_long(memcg, "memory.events", "oom_kill ") != 1)
754 goto cleanup;
755
756 if (cg_run(memcg, alloc_anon_50M_check_swap, (void *)MB(30)))
757 goto cleanup;
758
759 max = cg_read_key_long(memcg, "memory.events", "max ");
760 if (max <= 0)
761 goto cleanup;
762
763 ret = KSFT_PASS;
764
765 cleanup:
766 cg_destroy(memcg);
767 free(memcg);
768
769 return ret;
770 }
771
772
773
774
775
776
777 static int test_memcg_oom_events(const char *root)
778 {
779 int ret = KSFT_FAIL;
780 char *memcg;
781
782 memcg = cg_name(root, "memcg_test");
783 if (!memcg)
784 goto cleanup;
785
786 if (cg_create(memcg))
787 goto cleanup;
788
789 if (cg_write(memcg, "memory.max", "30M"))
790 goto cleanup;
791
792 if (cg_write(memcg, "memory.swap.max", "0"))
793 goto cleanup;
794
795 if (!cg_run(memcg, alloc_anon, (void *)MB(100)))
796 goto cleanup;
797
798 if (cg_read_strcmp(memcg, "cgroup.procs", ""))
799 goto cleanup;
800
801 if (cg_read_key_long(memcg, "memory.events", "oom ") != 1)
802 goto cleanup;
803
804 if (cg_read_key_long(memcg, "memory.events", "oom_kill ") != 1)
805 goto cleanup;
806
807 ret = KSFT_PASS;
808
809 cleanup:
810 cg_destroy(memcg);
811 free(memcg);
812
813 return ret;
814 }
815
816 struct tcp_server_args {
817 unsigned short port;
818 int ctl[2];
819 };
820
821 static int tcp_server(const char *cgroup, void *arg)
822 {
823 struct tcp_server_args *srv_args = arg;
824 struct sockaddr_in6 saddr = { 0 };
825 socklen_t slen = sizeof(saddr);
826 int sk, client_sk, ctl_fd, yes = 1, ret = -1;
827
828 close(srv_args->ctl[0]);
829 ctl_fd = srv_args->ctl[1];
830
831 saddr.sin6_family = AF_INET6;
832 saddr.sin6_addr = in6addr_any;
833 saddr.sin6_port = htons(srv_args->port);
834
835 sk = socket(AF_INET6, SOCK_STREAM, 0);
836 if (sk < 0)
837 return ret;
838
839 if (setsockopt(sk, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0)
840 goto cleanup;
841
842 if (bind(sk, (struct sockaddr *)&saddr, slen)) {
843 write(ctl_fd, &errno, sizeof(errno));
844 goto cleanup;
845 }
846
847 if (listen(sk, 1))
848 goto cleanup;
849
850 ret = 0;
851 if (write(ctl_fd, &ret, sizeof(ret)) != sizeof(ret)) {
852 ret = -1;
853 goto cleanup;
854 }
855
856 client_sk = accept(sk, NULL, NULL);
857 if (client_sk < 0)
858 goto cleanup;
859
860 ret = -1;
861 for (;;) {
862 uint8_t buf[0x100000];
863
864 if (write(client_sk, buf, sizeof(buf)) <= 0) {
865 if (errno == ECONNRESET)
866 ret = 0;
867 break;
868 }
869 }
870
871 close(client_sk);
872
873 cleanup:
874 close(sk);
875 return ret;
876 }
877
878 static int tcp_client(const char *cgroup, unsigned short port)
879 {
880 const char server[] = "localhost";
881 struct addrinfo *ai;
882 char servport[6];
883 int retries = 0x10;
884 int sk, ret;
885
886 snprintf(servport, sizeof(servport), "%hd", port);
887 ret = getaddrinfo(server, servport, NULL, &ai);
888 if (ret)
889 return ret;
890
891 sk = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
892 if (sk < 0)
893 goto free_ainfo;
894
895 ret = connect(sk, ai->ai_addr, ai->ai_addrlen);
896 if (ret < 0)
897 goto close_sk;
898
899 ret = KSFT_FAIL;
900 while (retries--) {
901 uint8_t buf[0x100000];
902 long current, sock;
903
904 if (read(sk, buf, sizeof(buf)) <= 0)
905 goto close_sk;
906
907 current = cg_read_long(cgroup, "memory.current");
908 sock = cg_read_key_long(cgroup, "memory.stat", "sock ");
909
910 if (current < 0 || sock < 0)
911 goto close_sk;
912
913 if (current < sock)
914 goto close_sk;
915
916 if (values_close(current, sock, 10)) {
917 ret = KSFT_PASS;
918 break;
919 }
920 }
921
922 close_sk:
923 close(sk);
924 free_ainfo:
925 freeaddrinfo(ai);
926 return ret;
927 }
928
929
930
931
932
933
934
935
936
937 static int test_memcg_sock(const char *root)
938 {
939 int bind_retries = 5, ret = KSFT_FAIL, pid, err;
940 unsigned short port;
941 char *memcg;
942
943 memcg = cg_name(root, "memcg_test");
944 if (!memcg)
945 goto cleanup;
946
947 if (cg_create(memcg))
948 goto cleanup;
949
950 while (bind_retries--) {
951 struct tcp_server_args args;
952
953 if (pipe(args.ctl))
954 goto cleanup;
955
956 port = args.port = 1000 + rand() % 60000;
957
958 pid = cg_run_nowait(memcg, tcp_server, &args);
959 if (pid < 0)
960 goto cleanup;
961
962 close(args.ctl[1]);
963 if (read(args.ctl[0], &err, sizeof(err)) != sizeof(err))
964 goto cleanup;
965 close(args.ctl[0]);
966
967 if (!err)
968 break;
969 if (err != EADDRINUSE)
970 goto cleanup;
971
972 waitpid(pid, NULL, 0);
973 }
974
975 if (err == EADDRINUSE) {
976 ret = KSFT_SKIP;
977 goto cleanup;
978 }
979
980 if (tcp_client(memcg, port) != KSFT_PASS)
981 goto cleanup;
982
983 waitpid(pid, &err, 0);
984 if (WEXITSTATUS(err))
985 goto cleanup;
986
987 if (cg_read_long(memcg, "memory.current") < 0)
988 goto cleanup;
989
990 if (cg_read_key_long(memcg, "memory.stat", "sock "))
991 goto cleanup;
992
993 ret = KSFT_PASS;
994
995 cleanup:
996 cg_destroy(memcg);
997 free(memcg);
998
999 return ret;
1000 }
1001
1002
1003
1004
1005
1006
1007 static int test_memcg_oom_group_leaf_events(const char *root)
1008 {
1009 int ret = KSFT_FAIL;
1010 char *parent, *child;
1011
1012 parent = cg_name(root, "memcg_test_0");
1013 child = cg_name(root, "memcg_test_0/memcg_test_1");
1014
1015 if (!parent || !child)
1016 goto cleanup;
1017
1018 if (cg_create(parent))
1019 goto cleanup;
1020
1021 if (cg_create(child))
1022 goto cleanup;
1023
1024 if (cg_write(parent, "cgroup.subtree_control", "+memory"))
1025 goto cleanup;
1026
1027 if (cg_write(child, "memory.max", "50M"))
1028 goto cleanup;
1029
1030 if (cg_write(child, "memory.swap.max", "0"))
1031 goto cleanup;
1032
1033 if (cg_write(child, "memory.oom.group", "1"))
1034 goto cleanup;
1035
1036 cg_run_nowait(parent, alloc_anon_noexit, (void *) MB(60));
1037 cg_run_nowait(child, alloc_anon_noexit, (void *) MB(1));
1038 cg_run_nowait(child, alloc_anon_noexit, (void *) MB(1));
1039 if (!cg_run(child, alloc_anon, (void *)MB(100)))
1040 goto cleanup;
1041
1042 if (cg_test_proc_killed(child))
1043 goto cleanup;
1044
1045 if (cg_read_key_long(child, "memory.events", "oom_kill ") <= 0)
1046 goto cleanup;
1047
1048 if (cg_read_key_long(parent, "memory.events", "oom_kill ") != 0)
1049 goto cleanup;
1050
1051 ret = KSFT_PASS;
1052
1053 cleanup:
1054 if (child)
1055 cg_destroy(child);
1056 if (parent)
1057 cg_destroy(parent);
1058 free(child);
1059 free(parent);
1060
1061 return ret;
1062 }
1063
1064
1065
1066
1067
1068
1069 static int test_memcg_oom_group_parent_events(const char *root)
1070 {
1071 int ret = KSFT_FAIL;
1072 char *parent, *child;
1073
1074 parent = cg_name(root, "memcg_test_0");
1075 child = cg_name(root, "memcg_test_0/memcg_test_1");
1076
1077 if (!parent || !child)
1078 goto cleanup;
1079
1080 if (cg_create(parent))
1081 goto cleanup;
1082
1083 if (cg_create(child))
1084 goto cleanup;
1085
1086 if (cg_write(parent, "memory.max", "80M"))
1087 goto cleanup;
1088
1089 if (cg_write(parent, "memory.swap.max", "0"))
1090 goto cleanup;
1091
1092 if (cg_write(parent, "memory.oom.group", "1"))
1093 goto cleanup;
1094
1095 cg_run_nowait(parent, alloc_anon_noexit, (void *) MB(60));
1096 cg_run_nowait(child, alloc_anon_noexit, (void *) MB(1));
1097 cg_run_nowait(child, alloc_anon_noexit, (void *) MB(1));
1098
1099 if (!cg_run(child, alloc_anon, (void *)MB(100)))
1100 goto cleanup;
1101
1102 if (cg_test_proc_killed(child))
1103 goto cleanup;
1104 if (cg_test_proc_killed(parent))
1105 goto cleanup;
1106
1107 ret = KSFT_PASS;
1108
1109 cleanup:
1110 if (child)
1111 cg_destroy(child);
1112 if (parent)
1113 cg_destroy(parent);
1114 free(child);
1115 free(parent);
1116
1117 return ret;
1118 }
1119
1120
1121
1122
1123
1124
1125 static int test_memcg_oom_group_score_events(const char *root)
1126 {
1127 int ret = KSFT_FAIL;
1128 char *memcg;
1129 int safe_pid;
1130
1131 memcg = cg_name(root, "memcg_test_0");
1132
1133 if (!memcg)
1134 goto cleanup;
1135
1136 if (cg_create(memcg))
1137 goto cleanup;
1138
1139 if (cg_write(memcg, "memory.max", "50M"))
1140 goto cleanup;
1141
1142 if (cg_write(memcg, "memory.swap.max", "0"))
1143 goto cleanup;
1144
1145 if (cg_write(memcg, "memory.oom.group", "1"))
1146 goto cleanup;
1147
1148 safe_pid = cg_run_nowait(memcg, alloc_anon_noexit, (void *) MB(1));
1149 if (set_oom_adj_score(safe_pid, OOM_SCORE_ADJ_MIN))
1150 goto cleanup;
1151
1152 cg_run_nowait(memcg, alloc_anon_noexit, (void *) MB(1));
1153 if (!cg_run(memcg, alloc_anon, (void *)MB(100)))
1154 goto cleanup;
1155
1156 if (cg_read_key_long(memcg, "memory.events", "oom_kill ") != 3)
1157 goto cleanup;
1158
1159 if (kill(safe_pid, SIGKILL))
1160 goto cleanup;
1161
1162 ret = KSFT_PASS;
1163
1164 cleanup:
1165 if (memcg)
1166 cg_destroy(memcg);
1167 free(memcg);
1168
1169 return ret;
1170 }
1171
1172
1173 #define T(x) { x, #x }
1174 struct memcg_test {
1175 int (*fn)(const char *root);
1176 const char *name;
1177 } tests[] = {
1178 T(test_memcg_subtree_control),
1179 T(test_memcg_current),
1180 T(test_memcg_min),
1181 T(test_memcg_low),
1182 T(test_memcg_high),
1183 T(test_memcg_max),
1184 T(test_memcg_oom_events),
1185 T(test_memcg_swap_max),
1186 T(test_memcg_sock),
1187 T(test_memcg_oom_group_leaf_events),
1188 T(test_memcg_oom_group_parent_events),
1189 T(test_memcg_oom_group_score_events),
1190 };
1191 #undef T
1192
1193 int main(int argc, char **argv)
1194 {
1195 char root[PATH_MAX];
1196 int i, ret = EXIT_SUCCESS;
1197
1198 if (cg_find_unified_root(root, sizeof(root)))
1199 ksft_exit_skip("cgroup v2 isn't mounted\n");
1200
1201
1202
1203
1204
1205 if (cg_read_strstr(root, "cgroup.controllers", "memory"))
1206 ksft_exit_skip("memory controller isn't available\n");
1207
1208 if (cg_read_strstr(root, "cgroup.subtree_control", "memory"))
1209 if (cg_write(root, "cgroup.subtree_control", "+memory"))
1210 ksft_exit_skip("Failed to set memory controller\n");
1211
1212 for (i = 0; i < ARRAY_SIZE(tests); i++) {
1213 switch (tests[i].fn(root)) {
1214 case KSFT_PASS:
1215 ksft_test_result_pass("%s\n", tests[i].name);
1216 break;
1217 case KSFT_SKIP:
1218 ksft_test_result_skip("%s\n", tests[i].name);
1219 break;
1220 default:
1221 ret = EXIT_FAILURE;
1222 ksft_test_result_fail("%s\n", tests[i].name);
1223 break;
1224 }
1225 }
1226
1227 return ret;
1228 }