mirror of
https://github.com/microsoft/WSL.git
synced 2025-07-03 07:23:20 +00:00
1101 lines
29 KiB
C
1101 lines
29 KiB
C
![]() |
/*++
|
||
|
|
||
|
Copyright (c) Microsoft. All rights reserved.
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
cgroup.c
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
This file contains unit tests for cgroup support.
|
||
|
|
||
|
N.B. This test depends on libmount, which is part of the libmount-dev
|
||
|
apt package.
|
||
|
|
||
|
N.B. To pass on native Linux this test requires cgroups to not be managed by
|
||
|
an OS daemon. cgclear can be used to remove some subsystems.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
#include "lxtcommon.h"
|
||
|
#include "unittests.h"
|
||
|
#include <sys/mount.h>
|
||
|
#include <linux/capability.h>
|
||
|
#include <libgen.h>
|
||
|
#include <fcntl.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <libmount/libmount.h>
|
||
|
#include <sys/mman.h>
|
||
|
#include "lxtmount.h"
|
||
|
#include <unistd.h>
|
||
|
#include <dirent.h>
|
||
|
#include <fcntl.h>
|
||
|
|
||
|
#define LXT_NAME "cgroup"
|
||
|
#define CGROUP_TEST_PATH "/data"
|
||
|
#define CGROUP_TEST_MOUNT_NAME "cgroup"
|
||
|
#define CGROUP_TEST_MOUNT_POINT_NAME "cgroup_mount_test"
|
||
|
#define CGROUP_TEST_MOUNT_POINT CGROUP_TEST_PATH "/" CGROUP_TEST_MOUNT_POINT_NAME
|
||
|
#define CGROUP_TEST_MOUNT_POINT2 "/sys/fs/cgroup"
|
||
|
|
||
|
#define CGROUP_TEST_MOUNT_POINT_DIR1_NAME "dir1"
|
||
|
#define CGROUP_TEST_MOUNT_POINT_DIR1 CGROUP_TEST_MOUNT_POINT "/" CGROUP_TEST_MOUNT_POINT_DIR1_NAME
|
||
|
#define CGROUP_TEST_MOUNT_POINT2_DIR1 CGROUP_TEST_MOUNT_POINT2 "/" CGROUP_TEST_MOUNT_POINT_DIR1_NAME
|
||
|
#define CGROUP_TEST_MOUNT_POINT_DIR1_CHILD_NAME "child"
|
||
|
#define CGROUP_TEST_MOUNT_POINT_DIR1_CHILD CGROUP_TEST_MOUNT_POINT_DIR1 "/" CGROUP_TEST_MOUNT_POINT_DIR1_CHILD_NAME
|
||
|
|
||
|
#define CGROUP_TEST_DEFAULT_BUFFER_SIZE 128
|
||
|
#define CGROUP_TEST_MAX_CGROUPS 12
|
||
|
#define CGROUP_TEST_MAX_NAME_LENGTH 32
|
||
|
|
||
|
#define CGROUP_TEST_MAX_PIDS 2048
|
||
|
|
||
|
#define CGROUP_TEST_DEVICES_DEFAULT_LIST "a *:* rwm\n"
|
||
|
|
||
|
LXT_VARIATION_HANDLER CgroupTestBasicMount;
|
||
|
LXT_VARIATION_HANDLER CgroupTestMkdir;
|
||
|
LXT_VARIATION_HANDLER CgroupTestThreads;
|
||
|
LXT_VARIATION_HANDLER CgroupTestProcfs;
|
||
|
LXT_VARIATION_HANDLER CgroupTestProcsFile;
|
||
|
LXT_VARIATION_HANDLER CgroupTestMountReuse;
|
||
|
LXT_VARIATION_HANDLER CgroupTestDevices;
|
||
|
|
||
|
//
|
||
|
// TODO_LX: Enable all files when supported.
|
||
|
//
|
||
|
|
||
|
static const LXT_CHILD_INFO g_CgroupRootChildren[] = {
|
||
|
{"cgroup.sane_behavior", DT_REG},
|
||
|
/* {"cgroup.clone_children", DT_REG},
|
||
|
{"cgroup.event_control", DT_REG}, */
|
||
|
{"cgroup.procs", DT_REG}};
|
||
|
/* {"notify_on_release", DT_REG},
|
||
|
{"release_agent", DT_REG},
|
||
|
{"tasks", DT_REG}};*/
|
||
|
|
||
|
static const LXT_CHILD_INFO g_CgroupDefaultChildren[] = {/* {"cgroup.clone_children", DT_REG},
|
||
|
{"cgroup.event_control", DT_REG}, */
|
||
|
{"cgroup.procs", DT_REG}};
|
||
|
/* {"notify_on_release", DT_REG},
|
||
|
{"release_agent", DT_REG},
|
||
|
{"tasks", DT_REG}};*/
|
||
|
|
||
|
static const LXT_CHILD_INFO g_CgroupDevicesChildren[] = {{"devices.allow", DT_REG}, {"devices.deny", DT_REG}, {"devices.list", DT_REG}};
|
||
|
|
||
|
//
|
||
|
// Global constants
|
||
|
//
|
||
|
|
||
|
static const LXT_VARIATION g_LxtVariations[] = {
|
||
|
{"cgroup - basic mount", CgroupTestBasicMount},
|
||
|
{"cgroup - mkdir", CgroupTestMkdir},
|
||
|
{"cgroup - threads", CgroupTestThreads},
|
||
|
{"cgroup - procfs", CgroupTestProcfs},
|
||
|
{"cgroup - cgroup.procs file", CgroupTestProcsFile},
|
||
|
{"cgroup - mount reuse", CgroupTestMountReuse},
|
||
|
{"cgroup - devices subsystem", CgroupTestDevices}};
|
||
|
|
||
|
static int g_TestPathMountId;
|
||
|
|
||
|
int CgroupTestEntry(int Argc, char* Argv[])
|
||
|
|
||
|
/*++
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
|
||
|
LXT_ARGS Args;
|
||
|
int Result;
|
||
|
|
||
|
//
|
||
|
// Clean-up from previous iterations.
|
||
|
//
|
||
|
|
||
|
rmdir(CGROUP_TEST_MOUNT_POINT_DIR1_CHILD);
|
||
|
rmdir(CGROUP_TEST_MOUNT_POINT_DIR1);
|
||
|
umount(CGROUP_TEST_MOUNT_POINT2);
|
||
|
umount(CGROUP_TEST_MOUNT_POINT);
|
||
|
rmdir(CGROUP_TEST_MOUNT_POINT);
|
||
|
rmdir(CGROUP_TEST_MOUNT_POINT2);
|
||
|
|
||
|
//
|
||
|
// Run the test variations.
|
||
|
//
|
||
|
|
||
|
LxtCheckResult(g_TestPathMountId = MountGetMountId(CGROUP_TEST_PATH));
|
||
|
LxtCheckResult(LxtInitialize(Argc, Argv, &Args, LXT_NAME));
|
||
|
LxtCheckResult(LxtRunVariations(&Args, g_LxtVariations, LXT_COUNT_OF(g_LxtVariations)));
|
||
|
|
||
|
//
|
||
|
// Mount cgroup with a folder to test the instance uninitialize path.
|
||
|
//
|
||
|
|
||
|
LxtCheckErrnoZeroSuccess(mkdir(CGROUP_TEST_MOUNT_POINT, 0777));
|
||
|
LxtCheckErrnoZeroSuccess(mount("mycgroupnew", CGROUP_TEST_MOUNT_POINT, CGROUP_TEST_MOUNT_NAME, 0, "devices"));
|
||
|
|
||
|
LxtCheckErrno(mkdir(CGROUP_TEST_MOUNT_POINT_DIR1, 0777));
|
||
|
|
||
|
ErrorExit:
|
||
|
LxtUninitialize();
|
||
|
return !LXT_SUCCESS(Result);
|
||
|
}
|
||
|
|
||
|
int CgroupTestBasicMount(PLXT_ARGS Args)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Description:
|
||
|
|
||
|
This routine tests the mount and umount system calls for cgroups.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Args - Supplies the command line arguments.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
Returns 0 on success, -1 on failure.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
|
||
|
int MountId;
|
||
|
int Result;
|
||
|
|
||
|
//
|
||
|
// Create the directory and ensure it's not a mount point yet.
|
||
|
//
|
||
|
LxtCheckErrnoZeroSuccess(mkdir(CGROUP_TEST_MOUNT_POINT, 0777));
|
||
|
LxtCheckResult(MountCheckIsNotMount(CGROUP_TEST_MOUNT_POINT));
|
||
|
|
||
|
//
|
||
|
// Mount a cgroup instance and check it was mounted.
|
||
|
//
|
||
|
|
||
|
LxtCheckErrnoZeroSuccess(mount("mycgroupnew", CGROUP_TEST_MOUNT_POINT, CGROUP_TEST_MOUNT_NAME, 0, NULL));
|
||
|
|
||
|
LxtCheckResult(
|
||
|
MountId = MountCheckIsMount(
|
||
|
CGROUP_TEST_MOUNT_POINT,
|
||
|
g_TestPathMountId,
|
||
|
"mycgroupnew",
|
||
|
CGROUP_TEST_MOUNT_NAME,
|
||
|
"/",
|
||
|
"rw,relatime",
|
||
|
"rw,devices",
|
||
|
"rw,relatime,devices",
|
||
|
0));
|
||
|
|
||
|
//
|
||
|
// Mounting again should fail.
|
||
|
//
|
||
|
|
||
|
LxtCheckErrnoFailure(mount("mycgroupnew", CGROUP_TEST_MOUNT_POINT, CGROUP_TEST_MOUNT_NAME, 0, NULL), EBUSY);
|
||
|
|
||
|
LxtCheckErrnoFailure(mount("mycgroupnew", CGROUP_TEST_MOUNT_POINT, CGROUP_TEST_MOUNT_NAME, 0, "devices"), EBUSY);
|
||
|
|
||
|
//
|
||
|
// Unmount and check it was unmounted.
|
||
|
//
|
||
|
|
||
|
LxtCheckErrnoZeroSuccess(umount(CGROUP_TEST_MOUNT_POINT));
|
||
|
LxtCheckResult(MountCheckIsNotMount(CGROUP_TEST_MOUNT_POINT));
|
||
|
|
||
|
ErrorExit:
|
||
|
umount(CGROUP_TEST_MOUNT_POINT);
|
||
|
rmdir(CGROUP_TEST_MOUNT_POINT);
|
||
|
return Result;
|
||
|
}
|
||
|
|
||
|
int CgroupTestMkdir(PLXT_ARGS Args)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Description:
|
||
|
|
||
|
This routine tests the mkdir and rmdir system calls for cgroups.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Args - Supplies the command line arguments.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
Returns 0 on success, -1 on failure.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
|
||
|
LXT_CHILD_INFO ChildInfo;
|
||
|
char ChildPidBuffer[CGROUP_TEST_DEFAULT_BUFFER_SIZE];
|
||
|
int ChildPidBufferLength;
|
||
|
char Path[512];
|
||
|
int ProcsFd;
|
||
|
int MountId;
|
||
|
int Result;
|
||
|
|
||
|
ProcsFd = -1;
|
||
|
|
||
|
//
|
||
|
// Mount cgroup.
|
||
|
//
|
||
|
|
||
|
LxtCheckErrnoZeroSuccess(mkdir(CGROUP_TEST_MOUNT_POINT, 0777));
|
||
|
LxtCheckErrnoZeroSuccess(mount("mycgroupnew", CGROUP_TEST_MOUNT_POINT, CGROUP_TEST_MOUNT_NAME, 0, "devices"));
|
||
|
|
||
|
//
|
||
|
// Removing the mount point root directory should fail.
|
||
|
//
|
||
|
|
||
|
LxtCheckErrnoFailure(rmdir(CGROUP_TEST_MOUNT_POINT), EBUSY);
|
||
|
|
||
|
//
|
||
|
// Create two subdirectories.
|
||
|
//
|
||
|
|
||
|
LxtCheckResult(LxtCheckDirectoryContents(CGROUP_TEST_MOUNT_POINT, g_CgroupRootChildren, LXT_COUNT_OF(g_CgroupRootChildren)));
|
||
|
|
||
|
LxtCheckErrno(mkdir(CGROUP_TEST_MOUNT_POINT_DIR1, 0777));
|
||
|
ChildInfo.FileType = DT_DIR;
|
||
|
ChildInfo.Name = CGROUP_TEST_MOUNT_POINT_DIR1_NAME;
|
||
|
LxtCheckResult(LxtCheckDirectoryContents(CGROUP_TEST_MOUNT_POINT, &ChildInfo, 1));
|
||
|
|
||
|
LxtCheckErrno(mkdir(CGROUP_TEST_MOUNT_POINT_DIR1_CHILD, 0777));
|
||
|
ChildInfo.Name = CGROUP_TEST_MOUNT_POINT_DIR1_CHILD_NAME;
|
||
|
LxtCheckResult(LxtCheckDirectoryContents(CGROUP_TEST_MOUNT_POINT_DIR1, &ChildInfo, 1));
|
||
|
|
||
|
//
|
||
|
// Removing the first directory should fail if the second one still exists,
|
||
|
// otherwise it succeeds.
|
||
|
//
|
||
|
|
||
|
LxtCheckErrnoFailure(rmdir(CGROUP_TEST_MOUNT_POINT_DIR1), EBUSY);
|
||
|
LxtCheckErrno(rmdir(CGROUP_TEST_MOUNT_POINT_DIR1_CHILD));
|
||
|
LxtCheckErrno(rmdir(CGROUP_TEST_MOUNT_POINT_DIR1));
|
||
|
|
||
|
//
|
||
|
// Check that removing the first directory fails if a thread is still
|
||
|
// associated, otherwise it succeeds.
|
||
|
//
|
||
|
|
||
|
LxtCheckErrno(mkdir(CGROUP_TEST_MOUNT_POINT_DIR1, 0777));
|
||
|
sprintf(Path, "%s/%s", CGROUP_TEST_MOUNT_POINT_DIR1, "cgroup.procs");
|
||
|
LxtCheckErrno(ProcsFd = open(Path, O_WRONLY));
|
||
|
ChildPidBufferLength = sprintf(ChildPidBuffer, "%d\n", getpid());
|
||
|
LxtCheckErrno(write(ProcsFd, ChildPidBuffer, ChildPidBufferLength));
|
||
|
LxtClose(ProcsFd);
|
||
|
ProcsFd = -1;
|
||
|
LxtCheckErrnoFailure(rmdir(CGROUP_TEST_MOUNT_POINT_DIR1), EBUSY);
|
||
|
sprintf(Path, "%s/%s", CGROUP_TEST_MOUNT_POINT, "cgroup.procs");
|
||
|
LxtCheckErrno(ProcsFd = open(Path, O_WRONLY));
|
||
|
LxtCheckErrno(write(ProcsFd, ChildPidBuffer, ChildPidBufferLength));
|
||
|
LxtClose(ProcsFd);
|
||
|
ProcsFd = -1;
|
||
|
LxtCheckErrno(rmdir(CGROUP_TEST_MOUNT_POINT_DIR1));
|
||
|
|
||
|
//
|
||
|
// Unmount cgroup.
|
||
|
//
|
||
|
|
||
|
LxtCheckErrnoZeroSuccess(umount(CGROUP_TEST_MOUNT_POINT));
|
||
|
LxtCheckResult(MountCheckIsNotMount(CGROUP_TEST_MOUNT_POINT));
|
||
|
|
||
|
ErrorExit:
|
||
|
if (ProcsFd != -1)
|
||
|
{
|
||
|
LxtClose(ProcsFd);
|
||
|
}
|
||
|
|
||
|
rmdir(CGROUP_TEST_MOUNT_POINT_DIR1_CHILD);
|
||
|
rmdir(CGROUP_TEST_MOUNT_POINT_DIR1);
|
||
|
umount(CGROUP_TEST_MOUNT_POINT);
|
||
|
rmdir(CGROUP_TEST_MOUNT_POINT);
|
||
|
return Result;
|
||
|
}
|
||
|
|
||
|
int CgroupTestThreads(PLXT_ARGS Args)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Description:
|
||
|
|
||
|
This routine tests thread behavior with cgroups mounts.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Args - Supplies the command line arguments.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
Returns 0 on success, -1 on failure.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
|
||
|
pid_t ChildPid;
|
||
|
int MountId;
|
||
|
LXT_PIPE Pipe = {-1, -1};
|
||
|
int Result;
|
||
|
|
||
|
//
|
||
|
// Create a thread, mount cgroup, and signal the thread to exit to test
|
||
|
// cgroup assignment during mount.
|
||
|
//
|
||
|
|
||
|
LxtCheckResult(LxtCreatePipe(&Pipe));
|
||
|
LxtCheckResult(ChildPid = fork());
|
||
|
if (ChildPid == 0)
|
||
|
{
|
||
|
read(Pipe.Read, &Result, sizeof(Result));
|
||
|
_exit(Result);
|
||
|
}
|
||
|
|
||
|
LxtCheckErrnoZeroSuccess(mkdir(CGROUP_TEST_MOUNT_POINT, 0777));
|
||
|
LxtCheckErrnoZeroSuccess(mount("mycgroupnew", CGROUP_TEST_MOUNT_POINT, CGROUP_TEST_MOUNT_NAME, 0, NULL));
|
||
|
|
||
|
write(Pipe.Write, &Result, sizeof(Result));
|
||
|
LxtWaitPidPoll(ChildPid, 0);
|
||
|
|
||
|
//
|
||
|
// Create a thread to test cgroup inheritance.
|
||
|
//
|
||
|
|
||
|
LxtCheckResult(ChildPid = fork());
|
||
|
if (ChildPid == 0)
|
||
|
{
|
||
|
_exit(Result);
|
||
|
}
|
||
|
|
||
|
LxtWaitPidPoll(ChildPid, 0);
|
||
|
|
||
|
//
|
||
|
// Unmount and exit.
|
||
|
//
|
||
|
|
||
|
LxtCheckErrnoZeroSuccess(umount(CGROUP_TEST_MOUNT_POINT));
|
||
|
LxtCheckResult(MountCheckIsNotMount(CGROUP_TEST_MOUNT_POINT));
|
||
|
|
||
|
ErrorExit:
|
||
|
write(Pipe.Write, &Result, sizeof(Result));
|
||
|
LxtClosePipe(&Pipe);
|
||
|
umount(CGROUP_TEST_MOUNT_POINT);
|
||
|
rmdir(CGROUP_TEST_MOUNT_POINT);
|
||
|
return Result;
|
||
|
}
|
||
|
|
||
|
typedef struct _CGROUP_TEST_PROCFS_ENTRY
|
||
|
{
|
||
|
char Name[CGROUP_TEST_MAX_NAME_LENGTH];
|
||
|
int Hierarcy;
|
||
|
int NumCgroups;
|
||
|
int Enabled;
|
||
|
} CGROUP_TEST_PROCFS_ENTRY, *PCGROUP_TEST_PROCFS_ENTRY;
|
||
|
|
||
|
typedef struct _CGROUP_TEST_PROCFS
|
||
|
{
|
||
|
int EntryCount;
|
||
|
CGROUP_TEST_PROCFS_ENTRY Entries[CGROUP_TEST_MAX_CGROUPS];
|
||
|
} CGROUP_TEST_PROCFS, *PCGROUP_TEST_PROCFS;
|
||
|
|
||
|
int CgroupTestReadProcfs(PCGROUP_TEST_PROCFS Data)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Description:
|
||
|
|
||
|
This routine parses /proc/cgroups.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Data - Supplies a buffer to store the data
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
Returns 0 on success, -1 on failure.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
|
||
|
char Line[CGROUP_TEST_DEFAULT_BUFFER_SIZE];
|
||
|
FILE* CgroupFile;
|
||
|
int NumCgroups;
|
||
|
int Result;
|
||
|
|
||
|
memset(Data, 0, sizeof(*Data));
|
||
|
CgroupFile = fopen("/proc/cgroups", "r");
|
||
|
LxtCheckNotEqual(CgroupFile, NULL, "%p");
|
||
|
if (fgets(Line, LXT_COUNT_OF(Line), CgroupFile) == NULL)
|
||
|
{
|
||
|
Result = LXT_RESULT_FAILURE;
|
||
|
LxtLogError("Failed to read header");
|
||
|
goto ErrorExit;
|
||
|
}
|
||
|
|
||
|
LxtCheckStringEqual(Line, "#subsys_name\thierarchy\tnum_cgroups\tenabled\n");
|
||
|
NumCgroups = 0;
|
||
|
while (fgets(Line, LXT_COUNT_OF(Line), CgroupFile) != NULL)
|
||
|
{
|
||
|
sscanf(
|
||
|
Line,
|
||
|
"%s\t%d\t%d\t%d",
|
||
|
Data->Entries[NumCgroups].Name,
|
||
|
&Data->Entries[NumCgroups].Hierarcy,
|
||
|
&Data->Entries[NumCgroups].NumCgroups,
|
||
|
&Data->Entries[NumCgroups].Enabled);
|
||
|
|
||
|
NumCgroups += 1;
|
||
|
}
|
||
|
|
||
|
Data->EntryCount = NumCgroups;
|
||
|
|
||
|
ErrorExit:
|
||
|
if (CgroupFile != NULL)
|
||
|
{
|
||
|
fclose(CgroupFile);
|
||
|
}
|
||
|
|
||
|
return Result;
|
||
|
}
|
||
|
|
||
|
typedef struct _CGROUP_TEST_PROCFS_PID_ENTRY
|
||
|
{
|
||
|
int Hierarcy;
|
||
|
char Subsystems[CGROUP_TEST_DEFAULT_BUFFER_SIZE];
|
||
|
char CgroupPath[CGROUP_TEST_DEFAULT_BUFFER_SIZE];
|
||
|
} CGROUP_TEST_PROCFS_PID_ENTRY, *PCGROUP_TEST_PROCFS_PID_ENTRY;
|
||
|
|
||
|
typedef struct _CGROUP_TEST_PROCFS_PID
|
||
|
{
|
||
|
int EntryCount;
|
||
|
CGROUP_TEST_PROCFS_PID_ENTRY Entries[CGROUP_TEST_MAX_CGROUPS];
|
||
|
} CGROUP_TEST_PROCFS_PID, *PCGROUP_TEST_PROCFS_PID;
|
||
|
|
||
|
int CgroupTestReadProcfsPid(PCGROUP_TEST_PROCFS_PID Data)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Description:
|
||
|
|
||
|
This routine parses /proc/self/cgroup.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Data - Supplies a buffer to store the data
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
Returns 0 on success, -1 on failure.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
|
||
|
char Line[CGROUP_TEST_DEFAULT_BUFFER_SIZE];
|
||
|
FILE* CgroupFile;
|
||
|
int NumCgroups;
|
||
|
int Result;
|
||
|
|
||
|
memset(Data, 0, sizeof(*Data));
|
||
|
CgroupFile = fopen("/proc/self/cgroup", "r");
|
||
|
LxtCheckNotEqual(CgroupFile, NULL, "%p");
|
||
|
|
||
|
NumCgroups = 0;
|
||
|
while (fgets(Line, LXT_COUNT_OF(Line), CgroupFile) != NULL)
|
||
|
{
|
||
|
sscanf(
|
||
|
Line,
|
||
|
"%d:%[^:]:%[^:\n]",
|
||
|
&Data->Entries[NumCgroups].Hierarcy,
|
||
|
Data->Entries[NumCgroups].Subsystems,
|
||
|
Data->Entries[NumCgroups].CgroupPath);
|
||
|
|
||
|
NumCgroups += 1;
|
||
|
}
|
||
|
|
||
|
Data->EntryCount = NumCgroups;
|
||
|
|
||
|
ErrorExit:
|
||
|
if (CgroupFile != NULL)
|
||
|
{
|
||
|
fclose(CgroupFile);
|
||
|
}
|
||
|
|
||
|
return Result;
|
||
|
}
|
||
|
|
||
|
int CgroupTestProcfs(PLXT_ARGS Args)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Description:
|
||
|
|
||
|
This routine tests the cgroup procfs files.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Args - Supplies the command line arguments.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
Returns 0 on success, -1 on failure.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
|
||
|
int BytesRead;
|
||
|
int Found;
|
||
|
int Index;
|
||
|
int MountId;
|
||
|
CGROUP_TEST_PROCFS ProcfsNew;
|
||
|
CGROUP_TEST_PROCFS ProcfsOrig;
|
||
|
CGROUP_TEST_PROCFS_PID ProcfsPidNew;
|
||
|
CGROUP_TEST_PROCFS_PID ProcfsPidOrig;
|
||
|
int Result;
|
||
|
|
||
|
//
|
||
|
// Create the cgroup mount.
|
||
|
//
|
||
|
|
||
|
LxtCheckErrnoZeroSuccess(mkdir(CGROUP_TEST_MOUNT_POINT, 0777));
|
||
|
LxtCheckErrnoZeroSuccess(mount("mycgroupnew", CGROUP_TEST_MOUNT_POINT, CGROUP_TEST_MOUNT_NAME, 0, "devices"));
|
||
|
|
||
|
//
|
||
|
// Read the procfs files before cgroups are mounted, staring
|
||
|
// with /proc/cgroup.
|
||
|
//
|
||
|
|
||
|
LxtCheckResult(CgroupTestReadProcfs(&ProcfsNew));
|
||
|
LxtCheckNotEqual(ProcfsNew.EntryCount, 0, "%d");
|
||
|
Found = 0;
|
||
|
for (Index = 0; Index < ProcfsNew.EntryCount; ++Index)
|
||
|
{
|
||
|
LxtCheckNotEqual(ProcfsNew.Entries[Index].NumCgroups, 0, "%d");
|
||
|
LxtCheckEqual(ProcfsNew.Entries[Index].Enabled, 1, "%d");
|
||
|
if (strcmp(ProcfsNew.Entries[Index].Name, "devices") == 0)
|
||
|
{
|
||
|
LxtCheckNotEqual(Found, 1, "%d");
|
||
|
LxtCheckNotEqual(ProcfsNew.Entries[Index].Hierarcy, 0, "%d");
|
||
|
Found = 1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
LxtCheckEqual(Found, 1, "%d");
|
||
|
|
||
|
//
|
||
|
// Now /proc/self/cgroup.
|
||
|
//
|
||
|
|
||
|
LxtCheckResult(CgroupTestReadProcfsPid(&ProcfsPidNew));
|
||
|
Found = 0;
|
||
|
for (Index = 0; Index < ProcfsPidNew.EntryCount; ++Index)
|
||
|
{
|
||
|
if (strstr(ProcfsPidNew.Entries[Index].Subsystems, "devices") != NULL)
|
||
|
{
|
||
|
LxtCheckNotEqual(Found, 1, "%d");
|
||
|
LxtCheckNotEqual(ProcfsPidNew.Entries[Index].Hierarcy, 0, "%d");
|
||
|
LxtCheckStringEqual(ProcfsPidNew.Entries[Index].CgroupPath, "/");
|
||
|
Found = 1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
LxtCheckEqual(Found, 1, "%d");
|
||
|
|
||
|
//
|
||
|
// Unmount and recheck the original.
|
||
|
//
|
||
|
|
||
|
LxtCheckErrnoZeroSuccess(umount(CGROUP_TEST_MOUNT_POINT));
|
||
|
LxtCheckResult(MountCheckIsNotMount(CGROUP_TEST_MOUNT_POINT));
|
||
|
|
||
|
ErrorExit:
|
||
|
umount(CGROUP_TEST_MOUNT_POINT);
|
||
|
rmdir(CGROUP_TEST_MOUNT_POINT);
|
||
|
return Result;
|
||
|
}
|
||
|
|
||
|
int CgroupTestGetProcsFileIds(char* CgroupPath, pid_t* IdArray[], int* IdArrayCount)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Description:
|
||
|
|
||
|
This routine tests the behavior of the cgroup.procs file.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Path - Supplies the path to query.
|
||
|
|
||
|
IdArray - Supplies a buffer to store the array of ids.
|
||
|
|
||
|
IdArrayCount - Supplies a buffer to store the number of ids.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
Returns 0 on success, -1 on failure.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
|
||
|
pid_t* Array;
|
||
|
int Count;
|
||
|
int Index;
|
||
|
FILE* File;
|
||
|
char Line[CGROUP_TEST_DEFAULT_BUFFER_SIZE];
|
||
|
char Path[512];
|
||
|
int PathLength;
|
||
|
int Result;
|
||
|
|
||
|
Array = NULL;
|
||
|
File = NULL;
|
||
|
sprintf(Path, "%s/%s", CgroupPath, "cgroup.procs");
|
||
|
File = fopen(Path, "r");
|
||
|
LxtCheckNotEqual(File, NULL, "%p");
|
||
|
Array = LxtAlloc(sizeof(*Array) * CGROUP_TEST_MAX_PIDS);
|
||
|
if (Array == NULL)
|
||
|
{
|
||
|
Result = LXT_RESULT_FAILURE;
|
||
|
goto ErrorExit;
|
||
|
}
|
||
|
|
||
|
Count = 0;
|
||
|
while (fgets(Line, LXT_COUNT_OF(Line), File) != NULL)
|
||
|
{
|
||
|
if (Count > CGROUP_TEST_MAX_PIDS)
|
||
|
{
|
||
|
LxtLogError("Unexpected count");
|
||
|
Result = LXT_RESULT_FAILURE;
|
||
|
goto ErrorExit;
|
||
|
}
|
||
|
|
||
|
sscanf(Line, "%d\n", &Array[Count]);
|
||
|
Count += 1;
|
||
|
}
|
||
|
|
||
|
for (Index = 1; Index < Count; ++Index)
|
||
|
{
|
||
|
if (Array[Index - 1] >= Array[Index])
|
||
|
{
|
||
|
LxtLogError("Unexpected value %d, %d", Array[Index - 1], Array[Index]);
|
||
|
Result = LXT_RESULT_FAILURE;
|
||
|
goto ErrorExit;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
*IdArray = Array;
|
||
|
Array = NULL;
|
||
|
*IdArrayCount = Count;
|
||
|
|
||
|
ErrorExit:
|
||
|
if (File != NULL)
|
||
|
{
|
||
|
fclose(File);
|
||
|
}
|
||
|
|
||
|
if (Array != NULL)
|
||
|
{
|
||
|
LxtFree(Array);
|
||
|
}
|
||
|
|
||
|
return Result;
|
||
|
}
|
||
|
|
||
|
int CgroupTestProcsFile(PLXT_ARGS Args)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Description:
|
||
|
|
||
|
This routine tests the behavior of the cgroup.procs file.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Args - Supplies the command line arguments.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
Returns 0 on success, -1 on failure.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
|
||
|
pid_t* Array;
|
||
|
pid_t ChildPid;
|
||
|
char ChildPidBuffer[CGROUP_TEST_DEFAULT_BUFFER_SIZE];
|
||
|
int ChildPidBufferLength;
|
||
|
int Count;
|
||
|
int Index;
|
||
|
int MountId;
|
||
|
char Path[512];
|
||
|
int ProcsFd;
|
||
|
LXT_PIPE Pipe = {-1, -1};
|
||
|
int Result;
|
||
|
|
||
|
Array = NULL;
|
||
|
ProcsFd = -1;
|
||
|
LxtCheckErrnoZeroSuccess(mkdir(CGROUP_TEST_MOUNT_POINT, 0777));
|
||
|
LxtCheckErrnoZeroSuccess(mount("mycgroupnew", CGROUP_TEST_MOUNT_POINT, CGROUP_TEST_MOUNT_NAME, 0, "devices"));
|
||
|
|
||
|
//
|
||
|
// Create a threadgroup and check that it is in the root folder.
|
||
|
//
|
||
|
|
||
|
LxtCheckResult(LxtCreatePipe(&Pipe));
|
||
|
LxtCheckResult(ChildPid = fork());
|
||
|
if (ChildPid == 0)
|
||
|
{
|
||
|
read(Pipe.Read, &Result, sizeof(Result));
|
||
|
_exit(0);
|
||
|
}
|
||
|
|
||
|
LxtCheckResult(CgroupTestGetProcsFileIds(CGROUP_TEST_MOUNT_POINT, &Array, &Count));
|
||
|
for (Index = 0; Index < Count; ++Index)
|
||
|
{
|
||
|
if (Array[Index] == ChildPid)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
LxtCheckNotEqual(Index, Count, "%d");
|
||
|
LxtFree(Array);
|
||
|
Array = NULL;
|
||
|
|
||
|
//
|
||
|
// Create a folder and check that it is empty.
|
||
|
//
|
||
|
|
||
|
rmdir(CGROUP_TEST_MOUNT_POINT_DIR1);
|
||
|
LxtCheckErrno(mkdir(CGROUP_TEST_MOUNT_POINT_DIR1, 0777));
|
||
|
LxtCheckResult(CgroupTestGetProcsFileIds(CGROUP_TEST_MOUNT_POINT_DIR1, &Array, &Count));
|
||
|
LxtCheckEqual(0, Count, "%d");
|
||
|
LxtFree(Array);
|
||
|
Array = NULL;
|
||
|
|
||
|
//
|
||
|
// Move the thread to the folder and check that the thread was moved.
|
||
|
//
|
||
|
|
||
|
sprintf(Path, "%s/%s", CGROUP_TEST_MOUNT_POINT_DIR1, "cgroup.procs");
|
||
|
LxtCheckErrno(ProcsFd = open(Path, O_WRONLY));
|
||
|
ChildPidBufferLength = sprintf(ChildPidBuffer, "%d\n", ChildPid);
|
||
|
LxtCheckErrno(write(ProcsFd, ChildPidBuffer, ChildPidBufferLength));
|
||
|
LxtCheckResult(CgroupTestGetProcsFileIds(CGROUP_TEST_MOUNT_POINT_DIR1, &Array, &Count));
|
||
|
for (Index = 0; Index < Count; ++Index)
|
||
|
{
|
||
|
if (Array[Index] == ChildPid)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
LxtCheckNotEqual(Index, Count, "%d");
|
||
|
LxtFree(Array);
|
||
|
Array = NULL;
|
||
|
|
||
|
LxtCheckResult(CgroupTestGetProcsFileIds(CGROUP_TEST_MOUNT_POINT, &Array, &Count));
|
||
|
for (Index = 0; Index < Count; ++Index)
|
||
|
{
|
||
|
if (Array[Index] == ChildPid)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
LxtCheckEqual(Index, Count, "%d");
|
||
|
LxtFree(Array);
|
||
|
Array = NULL;
|
||
|
LxtClose(ProcsFd);
|
||
|
ProcsFd = -1;
|
||
|
|
||
|
//
|
||
|
// Move the thread to the root and check that the thread was moved.
|
||
|
//
|
||
|
|
||
|
sprintf(Path, "%s/%s", CGROUP_TEST_MOUNT_POINT, "cgroup.procs");
|
||
|
LxtCheckErrno(ProcsFd = open(Path, O_WRONLY));
|
||
|
ChildPidBufferLength = sprintf(ChildPidBuffer, "%d\n", ChildPid);
|
||
|
LxtCheckErrno(write(ProcsFd, ChildPidBuffer, ChildPidBufferLength));
|
||
|
LxtCheckResult(CgroupTestGetProcsFileIds(CGROUP_TEST_MOUNT_POINT_DIR1, &Array, &Count));
|
||
|
LxtCheckEqual(0, Count, "%d");
|
||
|
LxtFree(Array);
|
||
|
Array = NULL;
|
||
|
|
||
|
LxtCheckResult(CgroupTestGetProcsFileIds(CGROUP_TEST_MOUNT_POINT, &Array, &Count));
|
||
|
for (Index = 0; Index < Count; ++Index)
|
||
|
{
|
||
|
if (Array[Index] == ChildPid)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
LxtCheckNotEqual(Index, Count, "%d");
|
||
|
LxtFree(Array);
|
||
|
Array = NULL;
|
||
|
LxtClose(ProcsFd);
|
||
|
ProcsFd = -1;
|
||
|
|
||
|
//
|
||
|
// Unmount and exit.
|
||
|
//
|
||
|
|
||
|
rmdir(CGROUP_TEST_MOUNT_POINT_DIR1);
|
||
|
LxtCheckErrnoZeroSuccess(umount(CGROUP_TEST_MOUNT_POINT));
|
||
|
LxtCheckResult(MountCheckIsNotMount(CGROUP_TEST_MOUNT_POINT));
|
||
|
|
||
|
ErrorExit:
|
||
|
write(Pipe.Write, &Result, sizeof(Result));
|
||
|
LxtClosePipe(&Pipe);
|
||
|
if (Array != NULL)
|
||
|
{
|
||
|
LxtFree(Array);
|
||
|
}
|
||
|
|
||
|
if (ProcsFd != -1)
|
||
|
{
|
||
|
LxtClose(ProcsFd);
|
||
|
}
|
||
|
|
||
|
umount(CGROUP_TEST_MOUNT_POINT);
|
||
|
rmdir(CGROUP_TEST_MOUNT_POINT);
|
||
|
rmdir(CGROUP_TEST_MOUNT_POINT_DIR1);
|
||
|
return Result;
|
||
|
}
|
||
|
|
||
|
int CgroupTestMountReuse(PLXT_ARGS Args)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Description:
|
||
|
|
||
|
This routine tests the behavior of reusing cgroup hierarchy mounts.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Args - Supplies the command line arguments.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
Returns 0 on success, -1 on failure.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
|
||
|
LXT_CHILD_INFO ChildInfo;
|
||
|
char ChildPidBuffer[CGROUP_TEST_DEFAULT_BUFFER_SIZE];
|
||
|
int ChildPidBufferLength;
|
||
|
int Found;
|
||
|
int Index;
|
||
|
char Path[512];
|
||
|
int ProcsFd;
|
||
|
CGROUP_TEST_PROCFS ProcfsNew;
|
||
|
int MountId;
|
||
|
int Result;
|
||
|
|
||
|
ProcsFd = -1;
|
||
|
|
||
|
rmdir(CGROUP_TEST_MOUNT_POINT_DIR1_CHILD);
|
||
|
rmdir(CGROUP_TEST_MOUNT_POINT_DIR1);
|
||
|
umount(CGROUP_TEST_MOUNT_POINT);
|
||
|
rmdir(CGROUP_TEST_MOUNT_POINT);
|
||
|
|
||
|
//
|
||
|
// Mount cgroup.
|
||
|
//
|
||
|
|
||
|
LxtCheckErrnoZeroSuccess(mkdir(CGROUP_TEST_MOUNT_POINT, 0777));
|
||
|
LxtCheckErrnoZeroSuccess(mount("mycgroupnew", CGROUP_TEST_MOUNT_POINT, CGROUP_TEST_MOUNT_NAME, 0, "devices"));
|
||
|
|
||
|
//
|
||
|
// A cgroup with a directory should be reported as active when unmounted
|
||
|
//
|
||
|
|
||
|
LxtCheckErrno(mkdir(CGROUP_TEST_MOUNT_POINT_DIR1, 0777));
|
||
|
LxtCheckErrno(access(CGROUP_TEST_MOUNT_POINT_DIR1, F_OK));
|
||
|
LxtCheckErrnoZeroSuccess(umount(CGROUP_TEST_MOUNT_POINT));
|
||
|
LxtCheckErrnoFailure(access(CGROUP_TEST_MOUNT_POINT_DIR1, F_OK), ENOENT);
|
||
|
LxtCheckResult(CgroupTestReadProcfs(&ProcfsNew));
|
||
|
LxtCheckNotEqual(ProcfsNew.EntryCount, 0, "%d");
|
||
|
Found = 0;
|
||
|
for (Index = 0; Index < ProcfsNew.EntryCount; ++Index)
|
||
|
{
|
||
|
LxtCheckNotEqual(ProcfsNew.Entries[Index].NumCgroups, 0, "%d");
|
||
|
LxtCheckEqual(ProcfsNew.Entries[Index].Enabled, 1, "%d");
|
||
|
if (strcmp(ProcfsNew.Entries[Index].Name, "devices") == 0)
|
||
|
{
|
||
|
LxtCheckNotEqual(Found, 1, "%d");
|
||
|
LxtCheckNotEqual(ProcfsNew.Entries[Index].Hierarcy, 0, "%d");
|
||
|
Found = 1;
|
||
|
}
|
||
|
}
|
||
|
LxtCheckEqual(Found, 1, "%d");
|
||
|
|
||
|
//
|
||
|
// When remounted the directory is present
|
||
|
//
|
||
|
|
||
|
LxtCheckErrnoZeroSuccess(mount("mycgroupnew", CGROUP_TEST_MOUNT_POINT, CGROUP_TEST_MOUNT_NAME, 0, "devices"));
|
||
|
|
||
|
LxtCheckErrno(access(CGROUP_TEST_MOUNT_POINT_DIR1, F_OK));
|
||
|
|
||
|
//
|
||
|
// When that cgroup is mounted again, the directory should be present
|
||
|
//
|
||
|
|
||
|
LxtCheckErrnoZeroSuccess(mount("mycgroupnew", CGROUP_TEST_MOUNT_POINT2, CGROUP_TEST_MOUNT_NAME, 0, "devices"));
|
||
|
|
||
|
LxtCheckErrno(access(CGROUP_TEST_MOUNT_POINT2_DIR1, F_OK));
|
||
|
umount(CGROUP_TEST_MOUNT_POINT2);
|
||
|
|
||
|
//
|
||
|
// Failing variation to check the mount all case.
|
||
|
//
|
||
|
// TODO_LX: This variation needs to be updated once multiple subsystems are
|
||
|
// supported.
|
||
|
//
|
||
|
|
||
|
LxtCheckErrnoZeroSuccess(mount("mycgroupnew", CGROUP_TEST_MOUNT_POINT2, CGROUP_TEST_MOUNT_NAME, 0, NULL));
|
||
|
|
||
|
LxtCheckErrno(access(CGROUP_TEST_MOUNT_POINT2_DIR1, F_OK));
|
||
|
|
||
|
//
|
||
|
// Unmount and exit.
|
||
|
//
|
||
|
|
||
|
rmdir(CGROUP_TEST_MOUNT_POINT_DIR1);
|
||
|
LxtCheckErrnoZeroSuccess(umount(CGROUP_TEST_MOUNT_POINT2));
|
||
|
LxtCheckErrnoZeroSuccess(umount(CGROUP_TEST_MOUNT_POINT));
|
||
|
LxtCheckResult(MountCheckIsNotMount(CGROUP_TEST_MOUNT_POINT));
|
||
|
|
||
|
ErrorExit:
|
||
|
if (ProcsFd != -1)
|
||
|
{
|
||
|
LxtClose(ProcsFd);
|
||
|
}
|
||
|
|
||
|
rmdir(CGROUP_TEST_MOUNT_POINT_DIR1_CHILD);
|
||
|
rmdir(CGROUP_TEST_MOUNT_POINT_DIR1);
|
||
|
umount(CGROUP_TEST_MOUNT_POINT2);
|
||
|
umount(CGROUP_TEST_MOUNT_POINT);
|
||
|
rmdir(CGROUP_TEST_MOUNT_POINT);
|
||
|
rmdir(CGROUP_TEST_MOUNT_POINT2);
|
||
|
return Result;
|
||
|
}
|
||
|
|
||
|
int CgroupTestDevices(PLXT_ARGS Args)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Description:
|
||
|
|
||
|
This routine tests the files for the devices subsystem.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Args - Supplies the command line arguments.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
Returns 0 on success, -1 on failure.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
|
||
|
int BytesRead;
|
||
|
int CgroupFd;
|
||
|
char DevicesListBuffer[32];
|
||
|
char Path[512];
|
||
|
char PidBuffer[CGROUP_TEST_DEFAULT_BUFFER_SIZE];
|
||
|
int PidBufferLength;
|
||
|
int Result;
|
||
|
|
||
|
CgroupFd = -1;
|
||
|
PidBufferLength = sprintf(PidBuffer, "%d\n", getpid());
|
||
|
|
||
|
//
|
||
|
// Mount cgroup.
|
||
|
//
|
||
|
|
||
|
LxtCheckErrnoZeroSuccess(mkdir(CGROUP_TEST_MOUNT_POINT, 0777));
|
||
|
LxtCheckErrnoZeroSuccess(mount("mycgroupnew", CGROUP_TEST_MOUNT_POINT, CGROUP_TEST_MOUNT_NAME, 0, "devices"));
|
||
|
|
||
|
//
|
||
|
// Check for the expected default files and devices files in the root.
|
||
|
//
|
||
|
|
||
|
LxtCheckResult(LxtCheckDirectoryContents(CGROUP_TEST_MOUNT_POINT, g_CgroupRootChildren, LXT_COUNT_OF(g_CgroupRootChildren)));
|
||
|
|
||
|
LxtCheckResult(LxtCheckDirectoryContents(CGROUP_TEST_MOUNT_POINT, g_CgroupDevicesChildren, LXT_COUNT_OF(g_CgroupDevicesChildren)));
|
||
|
|
||
|
//
|
||
|
// Check for the expected default files and devices files in a subdirectory.
|
||
|
//
|
||
|
// N.B. A thread has to exist in the cgroup for some files to successfully
|
||
|
// be read.
|
||
|
//
|
||
|
|
||
|
LxtCheckErrno(mkdir(CGROUP_TEST_MOUNT_POINT_DIR1, 0777));
|
||
|
sprintf(Path, "%s/%s", CGROUP_TEST_MOUNT_POINT_DIR1, "cgroup.procs");
|
||
|
LxtCheckErrno(CgroupFd = open(Path, O_WRONLY));
|
||
|
LxtCheckErrno(write(CgroupFd, PidBuffer, PidBufferLength));
|
||
|
LxtClose(CgroupFd);
|
||
|
CgroupFd = -1;
|
||
|
LxtCheckResult(LxtCheckDirectoryContents(CGROUP_TEST_MOUNT_POINT_DIR1, g_CgroupDefaultChildren, LXT_COUNT_OF(g_CgroupDefaultChildren)));
|
||
|
|
||
|
LxtCheckResult(LxtCheckDirectoryContents(CGROUP_TEST_MOUNT_POINT_DIR1, g_CgroupDevicesChildren, LXT_COUNT_OF(g_CgroupDevicesChildren)));
|
||
|
|
||
|
//
|
||
|
// Check for the expected value of the devices.list file in both folders.
|
||
|
//
|
||
|
|
||
|
sprintf(Path, "%s/%s", CGROUP_TEST_MOUNT_POINT, "devices.list");
|
||
|
LxtCheckErrno(CgroupFd = open(Path, O_RDONLY));
|
||
|
LxtCheckErrno(BytesRead = read(CgroupFd, DevicesListBuffer, sizeof(DevicesListBuffer) - 1));
|
||
|
DevicesListBuffer[BytesRead] = 0;
|
||
|
LxtClose(CgroupFd);
|
||
|
CgroupFd = -1;
|
||
|
LxtCheckStringEqual(DevicesListBuffer, CGROUP_TEST_DEVICES_DEFAULT_LIST);
|
||
|
|
||
|
sprintf(Path, "%s/%s", CGROUP_TEST_MOUNT_POINT_DIR1, "devices.list");
|
||
|
LxtCheckErrno(CgroupFd = open(Path, O_RDONLY));
|
||
|
LxtCheckErrno(BytesRead = read(CgroupFd, DevicesListBuffer, sizeof(DevicesListBuffer) - 1));
|
||
|
DevicesListBuffer[BytesRead] = 0;
|
||
|
LxtClose(CgroupFd);
|
||
|
CgroupFd = -1;
|
||
|
LxtCheckStringEqual(DevicesListBuffer, CGROUP_TEST_DEVICES_DEFAULT_LIST);
|
||
|
|
||
|
//
|
||
|
// Unmount cgroup.
|
||
|
//
|
||
|
|
||
|
sprintf(Path, "%s/%s", CGROUP_TEST_MOUNT_POINT, "cgroup.procs");
|
||
|
LxtCheckErrno(CgroupFd = open(Path, O_WRONLY));
|
||
|
LxtCheckErrno(write(CgroupFd, PidBuffer, PidBufferLength));
|
||
|
LxtClose(CgroupFd);
|
||
|
CgroupFd = -1;
|
||
|
rmdir(CGROUP_TEST_MOUNT_POINT_DIR1);
|
||
|
LxtCheckErrnoZeroSuccess(umount(CGROUP_TEST_MOUNT_POINT));
|
||
|
LxtCheckResult(MountCheckIsNotMount(CGROUP_TEST_MOUNT_POINT));
|
||
|
|
||
|
ErrorExit:
|
||
|
if (CgroupFd != -1)
|
||
|
{
|
||
|
LxtClose(CgroupFd);
|
||
|
}
|
||
|
|
||
|
rmdir(CGROUP_TEST_MOUNT_POINT_DIR1);
|
||
|
umount(CGROUP_TEST_MOUNT_POINT);
|
||
|
rmdir(CGROUP_TEST_MOUNT_POINT);
|
||
|
return Result;
|
||
|
}
|