This is an automated email from the ASF dual-hosted git repository.

bmahler pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mesos.git


The following commit(s) were added to refs/heads/master by this push:
     new 15e001595 [cgroups2] Introduce cgroups2::disable to disable a 
controller.
15e001595 is described below

commit 15e001595d5cae041895e62015c3fd0b1a818f7f
Author: Devin Leamy <[email protected]>
AuthorDate: Tue Mar 26 18:26:55 2024 -0400

    [cgroups2] Introduce cgroups2::disable to disable a controller.
    
    Allows a controller to be disabled on a cgroup. A test is introduced.
    
    We additionally move the read and write utilities so that they are
    accessible when we read the cgroup.subtree_control control file.
    
    This closes #536
---
 src/linux/cgroups2.cpp                     | 117 +++++++++++++++++++----------
 src/linux/cgroups2.hpp                     |   6 ++
 src/tests/containerizer/cgroups2_tests.cpp |  35 ++++++++-
 3 files changed, 117 insertions(+), 41 deletions(-)

diff --git a/src/linux/cgroups2.cpp b/src/linux/cgroups2.cpp
index 399edfced..816251d84 100644
--- a/src/linux/cgroups2.cpp
+++ b/src/linux/cgroups2.cpp
@@ -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.
@@ -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; }
 
@@ -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()
@@ -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);
 }
 
 
diff --git a/src/linux/cgroups2.hpp b/src/linux/cgroups2.hpp
index abdfbf814..024b271a5 100644
--- a/src/linux/cgroups2.hpp
+++ b/src/linux/cgroups2.hpp
@@ -102,6 +102,12 @@ Try<Nothing> enable(
     const std::vector<std::string>& controllers);
 
 
+// Disables controllers in the cgroup. No-op 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);
 
diff --git a/src/tests/containerizer/cgroups2_tests.cpp 
b/src/tests/containerizer/cgroups2_tests.cpp
index 90f751d08..db541a5ca 100644
--- a/src/tests/containerizer/cgroups2_tests.cpp
+++ b/src/tests/containerizer/cgroups2_tests.cpp
@@ -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>
@@ -83,7 +84,8 @@ protected:
       ASSERT_SOME(cgroups2::destroy(TEST_CGROUP));
     }
 
-    // TODO(bmahler): disable the enabled_controllers.
+    ASSERT_SOME(cgroups2::controllers::disable(
+        cgroups2::ROOT_CGROUP, enabled_controllers));
 
     TemporaryDirectoryTest::TearDown();
   }
@@ -177,6 +179,37 @@ TEST_F(Cgroups2Test, ROOT_CGROUPS2_CpuStats)
   ASSERT_SOME(cgroups2::cpu::stats(TEST_CGROUP));
 }
 
+
+TEST_F(Cgroups2Test, ROOT_CGROUPS2_EnableAndDisable)
+{
+  ASSERT_SOME(enable_controllers({"cpu"}));
+
+  ASSERT_SOME(cgroups2::create(TEST_CGROUP));
+
+  // 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 {

Reply via email to