Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
117 changes: 77 additions & 40 deletions src/linux/cgroups2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,44 @@ Try<Nothing> write(
const T& value);


template <>
Try<string> read(const string& cgroup, const string& control)
{
return os::read(path::join(cgroups2::path(cgroup), control));
}


template <>
Try<uint64_t> read(const string& cgroup, const string& control)
{
Try<string> content = read<string>(cgroup, control);
if (content.isError()) {
return Error(content.error());
}

return numify<uint64_t>(strings::trim(*content));
}


template <>
Try<Nothing> write(
const string& cgroup,
const string& control,
const string& value)
{
return os::write(path::join(cgroups2::path(cgroup), control), value);
}


template <>
Try<Nothing> write(
const string& cgroup,
const string& control,
const uint64_t& value)
{
return write(cgroup, control, stringify(value));
}

namespace control {

// Interface files found in all cgroups.
Expand Down Expand Up @@ -106,6 +144,13 @@ struct State
_disabled.insert(controller);
}

void disable(const set<string>& controllers)
{
foreach (const string& controller, controllers) {
disable(controller);
}
}

set<string> enabled() const { return _enabled; }
set<string> disabled() const { return _disabled; }

Expand Down Expand Up @@ -148,48 +193,31 @@ std::ostream& operator<<(std::ostream& stream, const State& state)
return stream;
}

} // namespace subtree_control {

} // namespace control {


template <>
Try<string> read(const string& cgroup, const string& control)
Try<State> read(const string& cgroup)
{
return os::read(path::join(cgroups2::path(cgroup), control));
}

Try<string> contents =
cgroups2::read<string>(cgroup, cgroups2::control::SUBTREE_CONTROLLERS);

template <>
Try<uint64_t> read(const string& cgroup, const string& control)
{
Try<string> content = read<string>(cgroup, control);
if (content.isError()) {
return Error(content.error());
if (contents.isError()) {
return Error(
"Failed to read 'cgroup.subtree_control' for cgroup '" + cgroup + "': "
+ contents.error());
}

return numify<uint64_t>(strings::trim(*content));
return State::parse(*contents);
}


template <>
Try<Nothing> write(
const string& cgroup,
const string& control,
const string& value)
Try<Nothing> write(const string& cgroup, const State& state)
{
return os::write(path::join(cgroups2::path(cgroup), control), value);
return cgroups2::write(
cgroup, control::SUBTREE_CONTROLLERS, stringify(state));
}

} // namespace subtree_control {

template <>
Try<Nothing> write(
const string& cgroup,
const string& control,
const uint64_t& value)
{
return write(cgroup, control, stringify(value));
}
} // namespace control {


bool enabled()
Expand Down Expand Up @@ -418,20 +446,29 @@ Try<set<string>> available(const string& cgroup)

Try<Nothing> enable(const string& cgroup, const vector<string>& controllers)
{
Try<string> contents =
cgroups2::read<string>(cgroup, cgroups2::control::SUBTREE_CONTROLLERS);
using State = control::subtree_control::State;
Try<State> control = cgroups2::control::subtree_control::read(cgroup);

if (contents.isError()) {
return Error(contents.error());
if (control.isError()) {
return Error(control.error());
}

control->enable(controllers);
return cgroups2::control::subtree_control::write(cgroup, *control);
}


Try<Nothing> disable(const string& cgroup, const set<string>& controllers)
{
using State = control::subtree_control::State;
State control = State::parse(*contents);
control.enable(controllers);
return cgroups2::write(
cgroup,
control::SUBTREE_CONTROLLERS,
stringify(control));
Try<State> control = cgroups2::control::subtree_control::read(cgroup);

if (control.isError()) {
return Error(control.error());
}

control->disable(controllers);
return cgroups2::control::subtree_control::write(cgroup, *control);
}


Expand Down
7 changes: 7 additions & 0 deletions src/linux/cgroups2.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,13 @@ Try<Nothing> enable(
const std::vector<std::string>& controllers);


// Disables `controllers` in the cgroup. Is a NOP if the controller is not
// enabled.
Try<Nothing> disable(
const std::string& cgroup,
const std::set<std::string>& controllers);


// Get all the controllers that are enabled for a cgroup.
Try<std::set<std::string>> enabled(const std::string& cgroup);

Expand Down
33 changes: 32 additions & 1 deletion src/tests/containerizer/cgroups2_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include <process/gtest.hpp>

#include <stout/exit.hpp>
#include <stout/foreach.hpp>
#include <stout/set.hpp>
#include <stout/tests/utils.hpp>
#include <stout/try.hpp>
Expand Down Expand Up @@ -83,7 +84,8 @@ class Cgroups2Test : public TemporaryDirectoryTest
ASSERT_SOME(cgroups2::destroy(TEST_CGROUP));
}

// TODO(bmahler): disable the enabled_controllers.
ASSERT_SOME(cgroups2::controllers::disable(
cgroups2::ROOT_CGROUP, enabled_controllers));

TemporaryDirectoryTest::TearDown();
}
Expand Down Expand Up @@ -177,6 +179,35 @@ TEST_F(Cgroups2Test, ROOT_CGROUPS2_CpuStats)
ASSERT_SOME(cgroups2::cpu::stats(TEST_CGROUP));
}


TEST_F(Cgroups2Test, ROOT_CGROUPS2_EnableAndDisable)
{
ASSERT_SOME(cgroups2::create(TEST_CGROUP));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we want to call enable_controllers here to ensure the root cgroup has the cpu controller enabled, right?


// Check that "cpu" not enabled.
Try<set<string>> enabled = cgroups2::controllers::enabled(TEST_CGROUP);
EXPECT_SOME(enabled);
EXPECT_EQ(0u, enabled->count("cpu"));

// Enable "cpu".
EXPECT_SOME(cgroups2::controllers::enable(TEST_CGROUP, {"cpu"}));
EXPECT_SOME(cgroups2::controllers::enable(TEST_CGROUP, {"cpu"})); // NOP

// Check that "cpu" is enabled.
enabled = cgroups2::controllers::enabled(TEST_CGROUP);
EXPECT_SOME(enabled);
EXPECT_EQ(1u, enabled->count("cpu"));

// Disable "cpu".
EXPECT_SOME(cgroups2::controllers::disable(TEST_CGROUP, {"cpu"}));
EXPECT_SOME(cgroups2::controllers::disable(TEST_CGROUP, {"cpu"})); // NOP

// Check that "cpu" not enabled.
enabled = cgroups2::controllers::enabled(TEST_CGROUP);
EXPECT_SOME(enabled);
EXPECT_EQ(0u, enabled->count("cpu"));
}

} // namespace tests {

} // namespace internal {
Expand Down