master
c 1,100 lines 28.6 KB
Raw
1 /*++
2
3 Copyright (c) Microsoft. All rights reserved.
4
5 Module Name:
6
7 cgroup.c
8
9 Abstract:
10
11 This file contains unit tests for cgroup support.
12
13 N.B. This test depends on libmount, which is part of the libmount-dev
14 apt package.
15
16 N.B. To pass on native Linux this test requires cgroups to not be managed by
17 an OS daemon. cgclear can be used to remove some subsystems.
18
19 --*/
20
21 #include "lxtcommon.h"
22 #include "unittests.h"
23 #include <sys/mount.h>
24 #include <linux/capability.h>
25 #include <libgen.h>
26 #include <fcntl.h>
27 #include <stdlib.h>
28 #include <libmount/libmount.h>
29 #include <sys/mman.h>
30 #include "lxtmount.h"
31 #include <unistd.h>
32 #include <dirent.h>
33 #include <fcntl.h>
34
35 #define LXT_NAME "cgroup"
36 #define CGROUP_TEST_PATH "/data"
37 #define CGROUP_TEST_MOUNT_NAME "cgroup"
38 #define CGROUP_TEST_MOUNT_POINT_NAME "cgroup_mount_test"
39 #define CGROUP_TEST_MOUNT_POINT CGROUP_TEST_PATH "/" CGROUP_TEST_MOUNT_POINT_NAME
40 #define CGROUP_TEST_MOUNT_POINT2 "/sys/fs/cgroup"
41
42 #define CGROUP_TEST_MOUNT_POINT_DIR1_NAME "dir1"
43 #define CGROUP_TEST_MOUNT_POINT_DIR1 CGROUP_TEST_MOUNT_POINT "/" CGROUP_TEST_MOUNT_POINT_DIR1_NAME
44 #define CGROUP_TEST_MOUNT_POINT2_DIR1 CGROUP_TEST_MOUNT_POINT2 "/" CGROUP_TEST_MOUNT_POINT_DIR1_NAME
45 #define CGROUP_TEST_MOUNT_POINT_DIR1_CHILD_NAME "child"
46 #define CGROUP_TEST_MOUNT_POINT_DIR1_CHILD CGROUP_TEST_MOUNT_POINT_DIR1 "/" CGROUP_TEST_MOUNT_POINT_DIR1_CHILD_NAME
47
48 #define CGROUP_TEST_DEFAULT_BUFFER_SIZE 128
49 #define CGROUP_TEST_MAX_CGROUPS 12
50 #define CGROUP_TEST_MAX_NAME_LENGTH 32
51
52 #define CGROUP_TEST_MAX_PIDS 2048
53
54 #define CGROUP_TEST_DEVICES_DEFAULT_LIST "a *:* rwm\n"
55
56 LXT_VARIATION_HANDLER CgroupTestBasicMount;
57 LXT_VARIATION_HANDLER CgroupTestMkdir;
58 LXT_VARIATION_HANDLER CgroupTestThreads;
59 LXT_VARIATION_HANDLER CgroupTestProcfs;
60 LXT_VARIATION_HANDLER CgroupTestProcsFile;
61 LXT_VARIATION_HANDLER CgroupTestMountReuse;
62 LXT_VARIATION_HANDLER CgroupTestDevices;
63
64 //
65 // TODO_LX: Enable all files when supported.
66 //
67
68 static const LXT_CHILD_INFO g_CgroupRootChildren[] = {
69 {"cgroup.sane_behavior", DT_REG},
70 /* {"cgroup.clone_children", DT_REG},
71 {"cgroup.event_control", DT_REG}, */
72 {"cgroup.procs", DT_REG}};
73 /* {"notify_on_release", DT_REG},
74 {"release_agent", DT_REG},
75 {"tasks", DT_REG}};*/
76
77 static const LXT_CHILD_INFO g_CgroupDefaultChildren[] = {/* {"cgroup.clone_children", DT_REG},
78 {"cgroup.event_control", DT_REG}, */
79 {"cgroup.procs", DT_REG}};
80 /* {"notify_on_release", DT_REG},
81 {"release_agent", DT_REG},
82 {"tasks", DT_REG}};*/
83
84 static const LXT_CHILD_INFO g_CgroupDevicesChildren[] = {{"devices.allow", DT_REG}, {"devices.deny", DT_REG}, {"devices.list", DT_REG}};
85
86 //
87 // Global constants
88 //
89
90 static const LXT_VARIATION g_LxtVariations[] = {
91 {"cgroup - basic mount", CgroupTestBasicMount},
92 {"cgroup - mkdir", CgroupTestMkdir},
93 {"cgroup - threads", CgroupTestThreads},
94 {"cgroup - procfs", CgroupTestProcfs},
95 {"cgroup - cgroup.procs file", CgroupTestProcsFile},
96 {"cgroup - mount reuse", CgroupTestMountReuse},
97 {"cgroup - devices subsystem", CgroupTestDevices}};
98
99 static int g_TestPathMountId;
100
101 int CgroupTestEntry(int Argc, char* Argv[])
102
103 /*++
104 --*/
105
106 {
107
108 LXT_ARGS Args;
109 int Result;
110
111 //
112 // Clean-up from previous iterations.
113 //
114
115 rmdir(CGROUP_TEST_MOUNT_POINT_DIR1_CHILD);
116 rmdir(CGROUP_TEST_MOUNT_POINT_DIR1);
117 umount(CGROUP_TEST_MOUNT_POINT2);
118 umount(CGROUP_TEST_MOUNT_POINT);
119 rmdir(CGROUP_TEST_MOUNT_POINT);
120 rmdir(CGROUP_TEST_MOUNT_POINT2);
121
122 //
123 // Run the test variations.
124 //
125
126 LxtCheckResult(g_TestPathMountId = MountGetMountId(CGROUP_TEST_PATH));
127 LxtCheckResult(LxtInitialize(Argc, Argv, &Args, LXT_NAME));
128 LxtCheckResult(LxtRunVariations(&Args, g_LxtVariations, LXT_COUNT_OF(g_LxtVariations)));
129
130 //
131 // Mount cgroup with a folder to test the instance uninitialize path.
132 //
133
134 LxtCheckErrnoZeroSuccess(mkdir(CGROUP_TEST_MOUNT_POINT, 0777));
135 LxtCheckErrnoZeroSuccess(mount("mycgroupnew", CGROUP_TEST_MOUNT_POINT, CGROUP_TEST_MOUNT_NAME, 0, "devices"));
136
137 LxtCheckErrno(mkdir(CGROUP_TEST_MOUNT_POINT_DIR1, 0777));
138
139 ErrorExit:
140 LxtUninitialize();
141 return !LXT_SUCCESS(Result);
142 }
143
144 int CgroupTestBasicMount(PLXT_ARGS Args)
145
146 /*++
147
148 Description:
149
150 This routine tests the mount and umount system calls for cgroups.
151
152 Arguments:
153
154 Args - Supplies the command line arguments.
155
156 Return Value:
157
158 Returns 0 on success, -1 on failure.
159
160 --*/
161
162 {
163
164 int MountId;
165 int Result;
166
167 //
168 // Create the directory and ensure it's not a mount point yet.
169 //
170 LxtCheckErrnoZeroSuccess(mkdir(CGROUP_TEST_MOUNT_POINT, 0777));
171 LxtCheckResult(MountCheckIsNotMount(CGROUP_TEST_MOUNT_POINT));
172
173 //
174 // Mount a cgroup instance and check it was mounted.
175 //
176
177 LxtCheckErrnoZeroSuccess(mount("mycgroupnew", CGROUP_TEST_MOUNT_POINT, CGROUP_TEST_MOUNT_NAME, 0, NULL));
178
179 LxtCheckResult(
180 MountId = MountCheckIsMount(
181 CGROUP_TEST_MOUNT_POINT,
182 g_TestPathMountId,
183 "mycgroupnew",
184 CGROUP_TEST_MOUNT_NAME,
185 "/",
186 "rw,relatime",
187 "rw,devices",
188 "rw,relatime,devices",
189 0));
190
191 //
192 // Mounting again should fail.
193 //
194
195 LxtCheckErrnoFailure(mount("mycgroupnew", CGROUP_TEST_MOUNT_POINT, CGROUP_TEST_MOUNT_NAME, 0, NULL), EBUSY);
196
197 LxtCheckErrnoFailure(mount("mycgroupnew", CGROUP_TEST_MOUNT_POINT, CGROUP_TEST_MOUNT_NAME, 0, "devices"), EBUSY);
198
199 //
200 // Unmount and check it was unmounted.
201 //
202
203 LxtCheckErrnoZeroSuccess(umount(CGROUP_TEST_MOUNT_POINT));
204 LxtCheckResult(MountCheckIsNotMount(CGROUP_TEST_MOUNT_POINT));
205
206 ErrorExit:
207 umount(CGROUP_TEST_MOUNT_POINT);
208 rmdir(CGROUP_TEST_MOUNT_POINT);
209 return Result;
210 }
211
212 int CgroupTestMkdir(PLXT_ARGS Args)
213
214 /*++
215
216 Description:
217
218 This routine tests the mkdir and rmdir system calls for cgroups.
219
220 Arguments:
221
222 Args - Supplies the command line arguments.
223
224 Return Value:
225
226 Returns 0 on success, -1 on failure.
227
228 --*/
229
230 {
231
232 LXT_CHILD_INFO ChildInfo;
233 char ChildPidBuffer[CGROUP_TEST_DEFAULT_BUFFER_SIZE];
234 int ChildPidBufferLength;
235 char Path[512];
236 int ProcsFd;
237 int MountId;
238 int Result;
239
240 ProcsFd = -1;
241
242 //
243 // Mount cgroup.
244 //
245
246 LxtCheckErrnoZeroSuccess(mkdir(CGROUP_TEST_MOUNT_POINT, 0777));
247 LxtCheckErrnoZeroSuccess(mount("mycgroupnew", CGROUP_TEST_MOUNT_POINT, CGROUP_TEST_MOUNT_NAME, 0, "devices"));
248
249 //
250 // Removing the mount point root directory should fail.
251 //
252
253 LxtCheckErrnoFailure(rmdir(CGROUP_TEST_MOUNT_POINT), EBUSY);
254
255 //
256 // Create two subdirectories.
257 //
258
259 LxtCheckResult(LxtCheckDirectoryContents(CGROUP_TEST_MOUNT_POINT, g_CgroupRootChildren, LXT_COUNT_OF(g_CgroupRootChildren)));
260
261 LxtCheckErrno(mkdir(CGROUP_TEST_MOUNT_POINT_DIR1, 0777));
262 ChildInfo.FileType = DT_DIR;
263 ChildInfo.Name = CGROUP_TEST_MOUNT_POINT_DIR1_NAME;
264 LxtCheckResult(LxtCheckDirectoryContents(CGROUP_TEST_MOUNT_POINT, &ChildInfo, 1));
265
266 LxtCheckErrno(mkdir(CGROUP_TEST_MOUNT_POINT_DIR1_CHILD, 0777));
267 ChildInfo.Name = CGROUP_TEST_MOUNT_POINT_DIR1_CHILD_NAME;
268 LxtCheckResult(LxtCheckDirectoryContents(CGROUP_TEST_MOUNT_POINT_DIR1, &ChildInfo, 1));
269
270 //
271 // Removing the first directory should fail if the second one still exists,
272 // otherwise it succeeds.
273 //
274
275 LxtCheckErrnoFailure(rmdir(CGROUP_TEST_MOUNT_POINT_DIR1), EBUSY);
276 LxtCheckErrno(rmdir(CGROUP_TEST_MOUNT_POINT_DIR1_CHILD));
277 LxtCheckErrno(rmdir(CGROUP_TEST_MOUNT_POINT_DIR1));
278
279 //
280 // Check that removing the first directory fails if a thread is still
281 // associated; otherwise, it succeeds.
282 //
283
284 LxtCheckErrno(mkdir(CGROUP_TEST_MOUNT_POINT_DIR1, 0777));
285 sprintf(Path, "%s/%s", CGROUP_TEST_MOUNT_POINT_DIR1, "cgroup.procs");
286 LxtCheckErrno(ProcsFd = open(Path, O_WRONLY));
287 ChildPidBufferLength = sprintf(ChildPidBuffer, "%d\n", getpid());
288 LxtCheckErrno(write(ProcsFd, ChildPidBuffer, ChildPidBufferLength));
289 LxtClose(ProcsFd);
290 ProcsFd = -1;
291 LxtCheckErrnoFailure(rmdir(CGROUP_TEST_MOUNT_POINT_DIR1), EBUSY);
292 sprintf(Path, "%s/%s", CGROUP_TEST_MOUNT_POINT, "cgroup.procs");
293 LxtCheckErrno(ProcsFd = open(Path, O_WRONLY));
294 LxtCheckErrno(write(ProcsFd, ChildPidBuffer, ChildPidBufferLength));
295 LxtClose(ProcsFd);
296 ProcsFd = -1;
297 LxtCheckErrno(rmdir(CGROUP_TEST_MOUNT_POINT_DIR1));
298
299 //
300 // Unmount cgroup.
301 //
302
303 LxtCheckErrnoZeroSuccess(umount(CGROUP_TEST_MOUNT_POINT));
304 LxtCheckResult(MountCheckIsNotMount(CGROUP_TEST_MOUNT_POINT));
305
306 ErrorExit:
307 if (ProcsFd != -1)
308 {
309 LxtClose(ProcsFd);
310 }
311
312 rmdir(CGROUP_TEST_MOUNT_POINT_DIR1_CHILD);
313 rmdir(CGROUP_TEST_MOUNT_POINT_DIR1);
314 umount(CGROUP_TEST_MOUNT_POINT);
315 rmdir(CGROUP_TEST_MOUNT_POINT);
316 return Result;
317 }
318
319 int CgroupTestThreads(PLXT_ARGS Args)
320
321 /*++
322
323 Description:
324
325 This routine tests thread behavior with cgroups mounts.
326
327 Arguments:
328
329 Args - Supplies the command line arguments.
330
331 Return Value:
332
333 Returns 0 on success, -1 on failure.
334
335 --*/
336
337 {
338
339 pid_t ChildPid;
340 int MountId;
341 LXT_PIPE Pipe = {-1, -1};
342 int Result;
343
344 //
345 // Create a thread, mount cgroup, and signal the thread to exit to test
346 // cgroup assignment during mount.
347 //
348
349 LxtCheckResult(LxtCreatePipe(&Pipe));
350 LxtCheckResult(ChildPid = fork());
351 if (ChildPid == 0)
352 {
353 read(Pipe.Read, &Result, sizeof(Result));
354 _exit(Result);
355 }
356
357 LxtCheckErrnoZeroSuccess(mkdir(CGROUP_TEST_MOUNT_POINT, 0777));
358 LxtCheckErrnoZeroSuccess(mount("mycgroupnew", CGROUP_TEST_MOUNT_POINT, CGROUP_TEST_MOUNT_NAME, 0, NULL));
359
360 write(Pipe.Write, &Result, sizeof(Result));
361 LxtWaitPidPoll(ChildPid, 0);
362
363 //
364 // Create a thread to test cgroup inheritance.
365 //
366
367 LxtCheckResult(ChildPid = fork());
368 if (ChildPid == 0)
369 {
370 _exit(Result);
371 }
372
373 LxtWaitPidPoll(ChildPid, 0);
374
375 //
376 // Unmount and exit.
377 //
378
379 LxtCheckErrnoZeroSuccess(umount(CGROUP_TEST_MOUNT_POINT));
380 LxtCheckResult(MountCheckIsNotMount(CGROUP_TEST_MOUNT_POINT));
381
382 ErrorExit:
383 write(Pipe.Write, &Result, sizeof(Result));
384 LxtClosePipe(&Pipe);
385 umount(CGROUP_TEST_MOUNT_POINT);
386 rmdir(CGROUP_TEST_MOUNT_POINT);
387 return Result;
388 }
389
390 typedef struct _CGROUP_TEST_PROCFS_ENTRY
391 {
392 char Name[CGROUP_TEST_MAX_NAME_LENGTH];
393 int Hierarchy;
394 int NumCgroups;
395 int Enabled;
396 } CGROUP_TEST_PROCFS_ENTRY, *PCGROUP_TEST_PROCFS_ENTRY;
397
398 typedef struct _CGROUP_TEST_PROCFS
399 {
400 int EntryCount;
401 CGROUP_TEST_PROCFS_ENTRY Entries[CGROUP_TEST_MAX_CGROUPS];
402 } CGROUP_TEST_PROCFS, *PCGROUP_TEST_PROCFS;
403
404 int CgroupTestReadProcfs(PCGROUP_TEST_PROCFS Data)
405
406 /*++
407
408 Description:
409
410 This routine parses /proc/cgroups.
411
412 Arguments:
413
414 Data - Supplies a buffer to store the data
415
416 Return Value:
417
418 Returns 0 on success, -1 on failure.
419
420 --*/
421
422 {
423
424 char Line[CGROUP_TEST_DEFAULT_BUFFER_SIZE];
425 FILE* CgroupFile;
426 int NumCgroups;
427 int Result;
428
429 memset(Data, 0, sizeof(*Data));
430 CgroupFile = fopen("/proc/cgroups", "r");
431 LxtCheckNotEqual(CgroupFile, NULL, "%p");
432 if (fgets(Line, LXT_COUNT_OF(Line), CgroupFile) == NULL)
433 {
434 Result = LXT_RESULT_FAILURE;
435 LxtLogError("Failed to read header");
436 goto ErrorExit;
437 }
438
439 LxtCheckStringEqual(Line, "#subsys_name\thierarchy\tnum_cgroups\tenabled\n");
440 NumCgroups = 0;
441 while (fgets(Line, LXT_COUNT_OF(Line), CgroupFile) != NULL)
442 {
443 sscanf(
444 Line,
445 "%s\t%d\t%d\t%d",
446 Data->Entries[NumCgroups].Name,
447 &Data->Entries[NumCgroups].Hierarchy,
448 &Data->Entries[NumCgroups].NumCgroups,
449 &Data->Entries[NumCgroups].Enabled);
450
451 NumCgroups += 1;
452 }
453
454 Data->EntryCount = NumCgroups;
455
456 ErrorExit:
457 if (CgroupFile != NULL)
458 {
459 fclose(CgroupFile);
460 }
461
462 return Result;
463 }
464
465 typedef struct _CGROUP_TEST_PROCFS_PID_ENTRY
466 {
467 int Hierarchy;
468 char Subsystems[CGROUP_TEST_DEFAULT_BUFFER_SIZE];
469 char CgroupPath[CGROUP_TEST_DEFAULT_BUFFER_SIZE];
470 } CGROUP_TEST_PROCFS_PID_ENTRY, *PCGROUP_TEST_PROCFS_PID_ENTRY;
471
472 typedef struct _CGROUP_TEST_PROCFS_PID
473 {
474 int EntryCount;
475 CGROUP_TEST_PROCFS_PID_ENTRY Entries[CGROUP_TEST_MAX_CGROUPS];
476 } CGROUP_TEST_PROCFS_PID, *PCGROUP_TEST_PROCFS_PID;
477
478 int CgroupTestReadProcfsPid(PCGROUP_TEST_PROCFS_PID Data)
479
480 /*++
481
482 Description:
483
484 This routine parses /proc/self/cgroup.
485
486 Arguments:
487
488 Data - Supplies a buffer to store the data
489
490 Return Value:
491
492 Returns 0 on success, -1 on failure.
493
494 --*/
495
496 {
497
498 char Line[CGROUP_TEST_DEFAULT_BUFFER_SIZE];
499 FILE* CgroupFile;
500 int NumCgroups;
501 int Result;
502
503 memset(Data, 0, sizeof(*Data));
504 CgroupFile = fopen("/proc/self/cgroup", "r");
505 LxtCheckNotEqual(CgroupFile, NULL, "%p");
506
507 NumCgroups = 0;
508 while (fgets(Line, LXT_COUNT_OF(Line), CgroupFile) != NULL)
509 {
510 sscanf(
511 Line,
512 "%d:%[^:]:%[^:\n]",
513 &Data->Entries[NumCgroups].Hierarchy,
514 Data->Entries[NumCgroups].Subsystems,
515 Data->Entries[NumCgroups].CgroupPath);
516
517 NumCgroups += 1;
518 }
519
520 Data->EntryCount = NumCgroups;
521
522 ErrorExit:
523 if (CgroupFile != NULL)
524 {
525 fclose(CgroupFile);
526 }
527
528 return Result;
529 }
530
531 int CgroupTestProcfs(PLXT_ARGS Args)
532
533 /*++
534
535 Description:
536
537 This routine tests the cgroup procfs files.
538
539 Arguments:
540
541 Args - Supplies the command line arguments.
542
543 Return Value:
544
545 Returns 0 on success, -1 on failure.
546
547 --*/
548
549 {
550
551 int BytesRead;
552 int Found;
553 int Index;
554 int MountId;
555 CGROUP_TEST_PROCFS ProcfsNew;
556 CGROUP_TEST_PROCFS ProcfsOrig;
557 CGROUP_TEST_PROCFS_PID ProcfsPidNew;
558 CGROUP_TEST_PROCFS_PID ProcfsPidOrig;
559 int Result;
560
561 //
562 // Create the cgroup mount.
563 //
564
565 LxtCheckErrnoZeroSuccess(mkdir(CGROUP_TEST_MOUNT_POINT, 0777));
566 LxtCheckErrnoZeroSuccess(mount("mycgroupnew", CGROUP_TEST_MOUNT_POINT, CGROUP_TEST_MOUNT_NAME, 0, "devices"));
567
568 //
569 // Read the procfs files before cgroups are mounted, staring
570 // with /proc/cgroup.
571 //
572
573 LxtCheckResult(CgroupTestReadProcfs(&ProcfsNew));
574 LxtCheckNotEqual(ProcfsNew.EntryCount, 0, "%d");
575 Found = 0;
576 for (Index = 0; Index < ProcfsNew.EntryCount; ++Index)
577 {
578 LxtCheckNotEqual(ProcfsNew.Entries[Index].NumCgroups, 0, "%d");
579 LxtCheckEqual(ProcfsNew.Entries[Index].Enabled, 1, "%d");
580 if (strcmp(ProcfsNew.Entries[Index].Name, "devices") == 0)
581 {
582 LxtCheckNotEqual(Found, 1, "%d");
583 LxtCheckNotEqual(ProcfsNew.Entries[Index].Hierarchy, 0, "%d");
584 Found = 1;
585 }
586 }
587
588 LxtCheckEqual(Found, 1, "%d");
589
590 //
591 // Now /proc/self/cgroup.
592 //
593
594 LxtCheckResult(CgroupTestReadProcfsPid(&ProcfsPidNew));
595 Found = 0;
596 for (Index = 0; Index < ProcfsPidNew.EntryCount; ++Index)
597 {
598 if (strstr(ProcfsPidNew.Entries[Index].Subsystems, "devices") != NULL)
599 {
600 LxtCheckNotEqual(Found, 1, "%d");
601 LxtCheckNotEqual(ProcfsPidNew.Entries[Index].Hierarchy, 0, "%d");
602 LxtCheckStringEqual(ProcfsPidNew.Entries[Index].CgroupPath, "/");
603 Found = 1;
604 }
605 }
606
607 LxtCheckEqual(Found, 1, "%d");
608
609 //
610 // Unmount and recheck the original.
611 //
612
613 LxtCheckErrnoZeroSuccess(umount(CGROUP_TEST_MOUNT_POINT));
614 LxtCheckResult(MountCheckIsNotMount(CGROUP_TEST_MOUNT_POINT));
615
616 ErrorExit:
617 umount(CGROUP_TEST_MOUNT_POINT);
618 rmdir(CGROUP_TEST_MOUNT_POINT);
619 return Result;
620 }
621
622 int CgroupTestGetProcsFileIds(char* CgroupPath, pid_t* IdArray[], int* IdArrayCount)
623
624 /*++
625
626 Description:
627
628 This routine tests the behavior of the cgroup.procs file.
629
630 Arguments:
631
632 Path - Supplies the path to query.
633
634 IdArray - Supplies a buffer to store the array of ids.
635
636 IdArrayCount - Supplies a buffer to store the number of ids.
637
638 Return Value:
639
640 Returns 0 on success, -1 on failure.
641
642 --*/
643
644 {
645
646 pid_t* Array;
647 int Count;
648 int Index;
649 FILE* File;
650 char Line[CGROUP_TEST_DEFAULT_BUFFER_SIZE];
651 char Path[512];
652 int PathLength;
653 int Result;
654
655 Array = NULL;
656 File = NULL;
657 sprintf(Path, "%s/%s", CgroupPath, "cgroup.procs");
658 File = fopen(Path, "r");
659 LxtCheckNotEqual(File, NULL, "%p");
660 Array = LxtAlloc(sizeof(*Array) * CGROUP_TEST_MAX_PIDS);
661 if (Array == NULL)
662 {
663 Result = LXT_RESULT_FAILURE;
664 goto ErrorExit;
665 }
666
667 Count = 0;
668 while (fgets(Line, LXT_COUNT_OF(Line), File) != NULL)
669 {
670 if (Count > CGROUP_TEST_MAX_PIDS)
671 {
672 LxtLogError("Unexpected count");
673 Result = LXT_RESULT_FAILURE;
674 goto ErrorExit;
675 }
676
677 sscanf(Line, "%d\n", &Array[Count]);
678 Count += 1;
679 }
680
681 for (Index = 1; Index < Count; ++Index)
682 {
683 if (Array[Index - 1] >= Array[Index])
684 {
685 LxtLogError("Unexpected value %d, %d", Array[Index - 1], Array[Index]);
686 Result = LXT_RESULT_FAILURE;
687 goto ErrorExit;
688 }
689 }
690
691 *IdArray = Array;
692 Array = NULL;
693 *IdArrayCount = Count;
694
695 ErrorExit:
696 if (File != NULL)
697 {
698 fclose(File);
699 }
700
701 if (Array != NULL)
702 {
703 LxtFree(Array);
704 }
705
706 return Result;
707 }
708
709 int CgroupTestProcsFile(PLXT_ARGS Args)
710
711 /*++
712
713 Description:
714
715 This routine tests the behavior of the cgroup.procs file.
716
717 Arguments:
718
719 Args - Supplies the command line arguments.
720
721 Return Value:
722
723 Returns 0 on success, -1 on failure.
724
725 --*/
726
727 {
728
729 pid_t* Array;
730 pid_t ChildPid;
731 char ChildPidBuffer[CGROUP_TEST_DEFAULT_BUFFER_SIZE];
732 int ChildPidBufferLength;
733 int Count;
734 int Index;
735 int MountId;
736 char Path[512];
737 int ProcsFd;
738 LXT_PIPE Pipe = {-1, -1};
739 int Result;
740
741 Array = NULL;
742 ProcsFd = -1;
743 LxtCheckErrnoZeroSuccess(mkdir(CGROUP_TEST_MOUNT_POINT, 0777));
744 LxtCheckErrnoZeroSuccess(mount("mycgroupnew", CGROUP_TEST_MOUNT_POINT, CGROUP_TEST_MOUNT_NAME, 0, "devices"));
745
746 //
747 // Create a threadgroup and check that it is in the root folder.
748 //
749
750 LxtCheckResult(LxtCreatePipe(&Pipe));
751 LxtCheckResult(ChildPid = fork());
752 if (ChildPid == 0)
753 {
754 read(Pipe.Read, &Result, sizeof(Result));
755 _exit(0);
756 }
757
758 LxtCheckResult(CgroupTestGetProcsFileIds(CGROUP_TEST_MOUNT_POINT, &Array, &Count));
759 for (Index = 0; Index < Count; ++Index)
760 {
761 if (Array[Index] == ChildPid)
762 {
763 break;
764 }
765 }
766
767 LxtCheckNotEqual(Index, Count, "%d");
768 LxtFree(Array);
769 Array = NULL;
770
771 //
772 // Create a folder and check that it is empty.
773 //
774
775 rmdir(CGROUP_TEST_MOUNT_POINT_DIR1);
776 LxtCheckErrno(mkdir(CGROUP_TEST_MOUNT_POINT_DIR1, 0777));
777 LxtCheckResult(CgroupTestGetProcsFileIds(CGROUP_TEST_MOUNT_POINT_DIR1, &Array, &Count));
778 LxtCheckEqual(0, Count, "%d");
779 LxtFree(Array);
780 Array = NULL;
781
782 //
783 // Move the thread to the folder and check that the thread was moved.
784 //
785
786 sprintf(Path, "%s/%s", CGROUP_TEST_MOUNT_POINT_DIR1, "cgroup.procs");
787 LxtCheckErrno(ProcsFd = open(Path, O_WRONLY));
788 ChildPidBufferLength = sprintf(ChildPidBuffer, "%d\n", ChildPid);
789 LxtCheckErrno(write(ProcsFd, ChildPidBuffer, ChildPidBufferLength));
790 LxtCheckResult(CgroupTestGetProcsFileIds(CGROUP_TEST_MOUNT_POINT_DIR1, &Array, &Count));
791 for (Index = 0; Index < Count; ++Index)
792 {
793 if (Array[Index] == ChildPid)
794 {
795 break;
796 }
797 }
798
799 LxtCheckNotEqual(Index, Count, "%d");
800 LxtFree(Array);
801 Array = NULL;
802
803 LxtCheckResult(CgroupTestGetProcsFileIds(CGROUP_TEST_MOUNT_POINT, &Array, &Count));
804 for (Index = 0; Index < Count; ++Index)
805 {
806 if (Array[Index] == ChildPid)
807 {
808 break;
809 }
810 }
811
812 LxtCheckEqual(Index, Count, "%d");
813 LxtFree(Array);
814 Array = NULL;
815 LxtClose(ProcsFd);
816 ProcsFd = -1;
817
818 //
819 // Move the thread to the root and check that the thread was moved.
820 //
821
822 sprintf(Path, "%s/%s", CGROUP_TEST_MOUNT_POINT, "cgroup.procs");
823 LxtCheckErrno(ProcsFd = open(Path, O_WRONLY));
824 ChildPidBufferLength = sprintf(ChildPidBuffer, "%d\n", ChildPid);
825 LxtCheckErrno(write(ProcsFd, ChildPidBuffer, ChildPidBufferLength));
826 LxtCheckResult(CgroupTestGetProcsFileIds(CGROUP_TEST_MOUNT_POINT_DIR1, &Array, &Count));
827 LxtCheckEqual(0, Count, "%d");
828 LxtFree(Array);
829 Array = NULL;
830
831 LxtCheckResult(CgroupTestGetProcsFileIds(CGROUP_TEST_MOUNT_POINT, &Array, &Count));
832 for (Index = 0; Index < Count; ++Index)
833 {
834 if (Array[Index] == ChildPid)
835 {
836 break;
837 }
838 }
839
840 LxtCheckNotEqual(Index, Count, "%d");
841 LxtFree(Array);
842 Array = NULL;
843 LxtClose(ProcsFd);
844 ProcsFd = -1;
845
846 //
847 // Unmount and exit.
848 //
849
850 rmdir(CGROUP_TEST_MOUNT_POINT_DIR1);
851 LxtCheckErrnoZeroSuccess(umount(CGROUP_TEST_MOUNT_POINT));
852 LxtCheckResult(MountCheckIsNotMount(CGROUP_TEST_MOUNT_POINT));
853
854 ErrorExit:
855 write(Pipe.Write, &Result, sizeof(Result));
856 LxtClosePipe(&Pipe);
857 if (Array != NULL)
858 {
859 LxtFree(Array);
860 }
861
862 if (ProcsFd != -1)
863 {
864 LxtClose(ProcsFd);
865 }
866
867 umount(CGROUP_TEST_MOUNT_POINT);
868 rmdir(CGROUP_TEST_MOUNT_POINT);
869 rmdir(CGROUP_TEST_MOUNT_POINT_DIR1);
870 return Result;
871 }
872
873 int CgroupTestMountReuse(PLXT_ARGS Args)
874
875 /*++
876
877 Description:
878
879 This routine tests the behavior of reusing cgroup hierarchy mounts.
880
881 Arguments:
882
883 Args - Supplies the command line arguments.
884
885 Return Value:
886
887 Returns 0 on success, -1 on failure.
888
889 --*/
890
891 {
892
893 LXT_CHILD_INFO ChildInfo;
894 char ChildPidBuffer[CGROUP_TEST_DEFAULT_BUFFER_SIZE];
895 int ChildPidBufferLength;
896 int Found;
897 int Index;
898 char Path[512];
899 int ProcsFd;
900 CGROUP_TEST_PROCFS ProcfsNew;
901 int MountId;
902 int Result;
903
904 ProcsFd = -1;
905
906 rmdir(CGROUP_TEST_MOUNT_POINT_DIR1_CHILD);
907 rmdir(CGROUP_TEST_MOUNT_POINT_DIR1);
908 umount(CGROUP_TEST_MOUNT_POINT);
909 rmdir(CGROUP_TEST_MOUNT_POINT);
910
911 //
912 // Mount cgroup.
913 //
914
915 LxtCheckErrnoZeroSuccess(mkdir(CGROUP_TEST_MOUNT_POINT, 0777));
916 LxtCheckErrnoZeroSuccess(mount("mycgroupnew", CGROUP_TEST_MOUNT_POINT, CGROUP_TEST_MOUNT_NAME, 0, "devices"));
917
918 //
919 // A cgroup with a directory should be reported as active when unmounted
920 //
921
922 LxtCheckErrno(mkdir(CGROUP_TEST_MOUNT_POINT_DIR1, 0777));
923 LxtCheckErrno(access(CGROUP_TEST_MOUNT_POINT_DIR1, F_OK));
924 LxtCheckErrnoZeroSuccess(umount(CGROUP_TEST_MOUNT_POINT));
925 LxtCheckErrnoFailure(access(CGROUP_TEST_MOUNT_POINT_DIR1, F_OK), ENOENT);
926 LxtCheckResult(CgroupTestReadProcfs(&ProcfsNew));
927 LxtCheckNotEqual(ProcfsNew.EntryCount, 0, "%d");
928 Found = 0;
929 for (Index = 0; Index < ProcfsNew.EntryCount; ++Index)
930 {
931 LxtCheckNotEqual(ProcfsNew.Entries[Index].NumCgroups, 0, "%d");
932 LxtCheckEqual(ProcfsNew.Entries[Index].Enabled, 1, "%d");
933 if (strcmp(ProcfsNew.Entries[Index].Name, "devices") == 0)
934 {
935 LxtCheckNotEqual(Found, 1, "%d");
936 LxtCheckNotEqual(ProcfsNew.Entries[Index].Hierarchy, 0, "%d");
937 Found = 1;
938 }
939 }
940 LxtCheckEqual(Found, 1, "%d");
941
942 //
943 // When remounted the directory is present
944 //
945
946 LxtCheckErrnoZeroSuccess(mount("mycgroupnew", CGROUP_TEST_MOUNT_POINT, CGROUP_TEST_MOUNT_NAME, 0, "devices"));
947
948 LxtCheckErrno(access(CGROUP_TEST_MOUNT_POINT_DIR1, F_OK));
949
950 //
951 // When that cgroup is mounted again, the directory should be present
952 //
953
954 LxtCheckErrnoZeroSuccess(mount("mycgroupnew", CGROUP_TEST_MOUNT_POINT2, CGROUP_TEST_MOUNT_NAME, 0, "devices"));
955
956 LxtCheckErrno(access(CGROUP_TEST_MOUNT_POINT2_DIR1, F_OK));
957 umount(CGROUP_TEST_MOUNT_POINT2);
958
959 //
960 // Failing variation to check the mount all case.
961 //
962 // TODO_LX: This variation needs to be updated once multiple subsystems are
963 // supported.
964 //
965
966 LxtCheckErrnoZeroSuccess(mount("mycgroupnew", CGROUP_TEST_MOUNT_POINT2, CGROUP_TEST_MOUNT_NAME, 0, NULL));
967
968 LxtCheckErrno(access(CGROUP_TEST_MOUNT_POINT2_DIR1, F_OK));
969
970 //
971 // Unmount and exit.
972 //
973
974 rmdir(CGROUP_TEST_MOUNT_POINT_DIR1);
975 LxtCheckErrnoZeroSuccess(umount(CGROUP_TEST_MOUNT_POINT2));
976 LxtCheckErrnoZeroSuccess(umount(CGROUP_TEST_MOUNT_POINT));
977 LxtCheckResult(MountCheckIsNotMount(CGROUP_TEST_MOUNT_POINT));
978
979 ErrorExit:
980 if (ProcsFd != -1)
981 {
982 LxtClose(ProcsFd);
983 }
984
985 rmdir(CGROUP_TEST_MOUNT_POINT_DIR1_CHILD);
986 rmdir(CGROUP_TEST_MOUNT_POINT_DIR1);
987 umount(CGROUP_TEST_MOUNT_POINT2);
988 umount(CGROUP_TEST_MOUNT_POINT);
989 rmdir(CGROUP_TEST_MOUNT_POINT);
990 rmdir(CGROUP_TEST_MOUNT_POINT2);
991 return Result;
992 }
993
994 int CgroupTestDevices(PLXT_ARGS Args)
995
996 /*++
997
998 Description:
999
1000 This routine tests the files for the devices subsystem.
1001
1002 Arguments:
1003
1004 Args - Supplies the command line arguments.
1005
1006 Return Value:
1007
1008 Returns 0 on success, -1 on failure.
1009
1010 --*/
1011
1012 {
1013
1014 int BytesRead;
1015 int CgroupFd;
1016 char DevicesListBuffer[32];
1017 char Path[512];
1018 char PidBuffer[CGROUP_TEST_DEFAULT_BUFFER_SIZE];
1019 int PidBufferLength;
1020 int Result;
1021
1022 CgroupFd = -1;
1023 PidBufferLength = sprintf(PidBuffer, "%d\n", getpid());
1024
1025 //
1026 // Mount cgroup.
1027 //
1028
1029 LxtCheckErrnoZeroSuccess(mkdir(CGROUP_TEST_MOUNT_POINT, 0777));
1030 LxtCheckErrnoZeroSuccess(mount("mycgroupnew", CGROUP_TEST_MOUNT_POINT, CGROUP_TEST_MOUNT_NAME, 0, "devices"));
1031
1032 //
1033 // Check for the expected default files and devices files in the root.
1034 //
1035
1036 LxtCheckResult(LxtCheckDirectoryContents(CGROUP_TEST_MOUNT_POINT, g_CgroupRootChildren, LXT_COUNT_OF(g_CgroupRootChildren)));
1037
1038 LxtCheckResult(LxtCheckDirectoryContents(CGROUP_TEST_MOUNT_POINT, g_CgroupDevicesChildren, LXT_COUNT_OF(g_CgroupDevicesChildren)));
1039
1040 //
1041 // Check for the expected default files and devices files in a subdirectory.
1042 //
1043 // N.B. A thread has to exist in the cgroup for some files to successfully
1044 // be read.
1045 //
1046
1047 LxtCheckErrno(mkdir(CGROUP_TEST_MOUNT_POINT_DIR1, 0777));
1048 sprintf(Path, "%s/%s", CGROUP_TEST_MOUNT_POINT_DIR1, "cgroup.procs");
1049 LxtCheckErrno(CgroupFd = open(Path, O_WRONLY));
1050 LxtCheckErrno(write(CgroupFd, PidBuffer, PidBufferLength));
1051 LxtClose(CgroupFd);
1052 CgroupFd = -1;
1053 LxtCheckResult(LxtCheckDirectoryContents(CGROUP_TEST_MOUNT_POINT_DIR1, g_CgroupDefaultChildren, LXT_COUNT_OF(g_CgroupDefaultChildren)));
1054
1055 LxtCheckResult(LxtCheckDirectoryContents(CGROUP_TEST_MOUNT_POINT_DIR1, g_CgroupDevicesChildren, LXT_COUNT_OF(g_CgroupDevicesChildren)));
1056
1057 //
1058 // Check for the expected value of the devices.list file in both folders.
1059 //
1060
1061 sprintf(Path, "%s/%s", CGROUP_TEST_MOUNT_POINT, "devices.list");
1062 LxtCheckErrno(CgroupFd = open(Path, O_RDONLY));
1063 LxtCheckErrno(BytesRead = read(CgroupFd, DevicesListBuffer, sizeof(DevicesListBuffer) - 1));
1064 DevicesListBuffer[BytesRead] = 0;
1065 LxtClose(CgroupFd);
1066 CgroupFd = -1;
1067 LxtCheckStringEqual(DevicesListBuffer, CGROUP_TEST_DEVICES_DEFAULT_LIST);
1068
1069 sprintf(Path, "%s/%s", CGROUP_TEST_MOUNT_POINT_DIR1, "devices.list");
1070 LxtCheckErrno(CgroupFd = open(Path, O_RDONLY));
1071 LxtCheckErrno(BytesRead = read(CgroupFd, DevicesListBuffer, sizeof(DevicesListBuffer) - 1));
1072 DevicesListBuffer[BytesRead] = 0;
1073 LxtClose(CgroupFd);
1074 CgroupFd = -1;
1075 LxtCheckStringEqual(DevicesListBuffer, CGROUP_TEST_DEVICES_DEFAULT_LIST);
1076
1077 //
1078 // Unmount cgroup.
1079 //
1080
1081 sprintf(Path, "%s/%s", CGROUP_TEST_MOUNT_POINT, "cgroup.procs");
1082 LxtCheckErrno(CgroupFd = open(Path, O_WRONLY));
1083 LxtCheckErrno(write(CgroupFd, PidBuffer, PidBufferLength));
1084 LxtClose(CgroupFd);
1085 CgroupFd = -1;
1086 rmdir(CGROUP_TEST_MOUNT_POINT_DIR1);
1087 LxtCheckErrnoZeroSuccess(umount(CGROUP_TEST_MOUNT_POINT));
1088 LxtCheckResult(MountCheckIsNotMount(CGROUP_TEST_MOUNT_POINT));
1089
1090 ErrorExit:
1091 if (CgroupFd != -1)
1092 {
1093 LxtClose(CgroupFd);
1094 }
1095
1096 rmdir(CGROUP_TEST_MOUNT_POINT_DIR1);
1097 umount(CGROUP_TEST_MOUNT_POINT);
1098 rmdir(CGROUP_TEST_MOUNT_POINT);
1099 return Result;
1100 }