mirror of
https://github.com/microsoft/WSL.git
synced 2025-12-10 00:44:55 -06:00
* link: Collect WSL logs (recommended method) Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * link: Advanced Authoring Tests in C++ Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * link: CMake Documentation and Community Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * link: Collect WSL logs for networking issues Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * link: Collect WSL logs (recommended method) Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: ; otherwise, Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: a Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: access Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: accessible Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: across Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: actively Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: adapters Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: address Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: addresses Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: and Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: appropriate Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: argument Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: associated Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: attach Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: available Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: beginning Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: between Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: binaries Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: bound Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: buffer Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: buffers Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: cannot Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: canonical Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: capabilities Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: case-insensitive Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: case-sensitive Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: certified Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: command Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: committer Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: communication Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: complains Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: configuration Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: consumed Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: continue Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: converted Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: currently Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: customers Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: daemon Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: deferred Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: definitions Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: delimiter Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: delivered Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: dellink Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: derived Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: descriptor Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: destined Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: destruct Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: destructible Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: destructor Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: detach Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: differentiate Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: directories Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: disassociate Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: disposition Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: distribution Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: distro Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: duping Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: emitted Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: empty Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: environment Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: every time Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: exclusive Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: expected Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: expire Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: explicitly Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: fall back Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: false Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: fastfail Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: filesystem Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: first Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: followed Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: for Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: functionality Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: functionally Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: github Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: greater Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: guarantee Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: guaranteed Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: handles Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: hangup Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: hierarchy Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: hogwarts Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: hydrated Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: icrnl Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: implementation Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: implementing Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: initialize Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: instance Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: instantiate Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: instantiations Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: intentionally Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: interpret Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: interpreter Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: irreversibly Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: iteration Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: iterator Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: its Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: kernel Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: kmsg Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: knowledge Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: maximum Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: mirrored Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: msftconnecttest Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: multi Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: multiple Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: mutable Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: namespace Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: nonexistent Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: notifications Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: occurred Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: occurring Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: otherwise, Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: outstanding Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: overridden Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: partition Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: pass through Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: passthrough Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: performs Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: periodically Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: positional Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: precedence Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: preexisting Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: preferring Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: prepopulate Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: previous Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: privileges Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: process Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: processes Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: programmatically Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: protection Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: provided Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: reasonable Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: receive Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: received Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: red hat Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: reentrant Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: registered Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: regularly Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: relay Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: release Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: representing Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: requests Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: response Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: resurrect Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: retention Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: returned Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: security Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: semaphore Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: separate Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: separator Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: service Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: set up Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: setup Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: severely Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: should Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: signal Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: similarly Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: simple Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: simplified Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: single Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: specified Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: splitting Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: standard Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: stress Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: succeed Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: success Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: successfully Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: supplementary Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: synced Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: system Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: take Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: than Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: that opening Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: the Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: threadpool Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: to Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: true Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: truncate Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: tunneling Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: unexpected Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: uninitialize Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: unique Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: unprivileged Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: unregistered Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: untrusted Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: upgrade Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: utility Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: validating Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: variant Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: variation Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: variations Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: verify Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: visible Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: whether Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: winget Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: worker Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: written Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * spelling: wslservice Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> * format source --------- Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> Co-authored-by: Ben Hillis <benhillis@gmail.com> Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>
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 Hierarchy;
|
|
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].Hierarchy,
|
|
&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 Hierarchy;
|
|
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].Hierarchy,
|
|
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].Hierarchy, 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].Hierarchy, 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].Hierarchy, 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;
|
|
}
|