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 991fb042e [cgroups] Add helper functions for device Entry.
991fb042e is described below
commit 991fb042e763f21dd3f695ed2ed5814b8a2a5190
Author: Jason Zhou <[email protected]>
AuthorDate: Fri Jul 19 16:26:20 2024 -0400
[cgroups] Add helper functions for device Entry.
Currently, the Entry class does not have readable helper functions for
determining whether the device accesses represented by one Entry would
be a subset of that of another. In addition, we want more readable ways
to determine if a device has wildcards present and if it has any
accesses specified.
These additions will streamline the logic in the DeviceManager
DeviceManager, which will heavily utilize the Entry class, improving
code readability.
Review: https://reviews.apache.org/r/75096/
---
src/linux/cgroups.cpp | 42 +++++++++++-
src/linux/cgroups.hpp | 9 +++
src/tests/containerizer/cgroups_tests.cpp | 110 ++++++++++++++++++++++++++++++
3 files changed, 158 insertions(+), 3 deletions(-)
diff --git a/src/linux/cgroups.cpp b/src/linux/cgroups.cpp
index c42894933..3dae320bd 100644
--- a/src/linux/cgroups.cpp
+++ b/src/linux/cgroups.cpp
@@ -2914,9 +2914,45 @@ bool Entry::is_catch_all() const
}
-Try<vector<Entry>> list(
- const string& hierarchy,
- const string& cgroup)
+bool Entry::encompasses(const Entry& other) const
+{
+ if (*this == other) {
+ return true;
+ }
+
+ if (selector.major.isSome() && selector.major != other.selector.major) {
+ return false;
+ }
+
+ if (selector.minor.isSome() && selector.minor != other.selector.minor) {
+ return false;
+ }
+
+ if (selector.type != Entry::Selector::Type::ALL
+ && selector.type != other.selector.type) {
+ return false;
+ }
+
+ if ((!access.mknod && other.access.mknod)
+ || (!access.read && other.access.read)
+ || (!access.write && other.access.write)) {
+ return false;
+ }
+
+ return true;
+}
+
+
+bool Entry::Access::none() const { return !mknod && !read && !write; }
+
+
+bool Entry::Selector::has_wildcard() const
+{
+ return major.isNone() || minor.isNone() || type ==
Entry::Selector::Type::ALL;
+}
+
+
+Try<vector<Entry>> list(const string& hierarchy, const string& cgroup)
{
Try<string> read = cgroups::read(hierarchy, cgroup, "devices.list");
diff --git a/src/linux/cgroups.hpp b/src/linux/cgroups.hpp
index eaa4cdf9f..4fefb5c3b 100644
--- a/src/linux/cgroups.hpp
+++ b/src/linux/cgroups.hpp
@@ -933,8 +933,13 @@ namespace devices {
struct Entry
{
static Try<Entry> parse(const std::string& s);
+
+ // Returns true iff entry matches all devices accesses.
bool is_catch_all() const;
+ // Returns true iff this entry fully contains the other's device accesses.
+ bool encompasses(const Entry& other) const;
+
struct Selector
{
enum class Type
@@ -947,6 +952,9 @@ struct Entry
Type type;
Option<unsigned int> major; // Matches all `major` numbers if None.
Option<unsigned int> minor; // Matches all `minor` numbers if None.
+
+ // Returns iff major or minor are wildcards or if type == ALL.
+ bool has_wildcard() const;
};
struct Access
@@ -954,6 +962,7 @@ struct Entry
bool read;
bool write;
bool mknod;
+ bool none() const;
};
Selector selector;
diff --git a/src/tests/containerizer/cgroups_tests.cpp
b/src/tests/containerizer/cgroups_tests.cpp
index 0f4967ff1..e4ca7933b 100644
--- a/src/tests/containerizer/cgroups_tests.cpp
+++ b/src/tests/containerizer/cgroups_tests.cpp
@@ -1407,6 +1407,116 @@ TEST_F(CgroupsAnyHierarchyDevicesTest,
ROOT_CGROUPS_Devices)
ASSERT_SOME(cgroups::assign(hierarchy, "", ::getpid()));
}
+
+TEST(DevicesTest, SubsetHelperTest)
+{
+ cgroups::devices::Entry subset =
+ CHECK_NOTERROR(cgroups::devices::Entry::parse("c 3:1 rwm"));
+ cgroups::devices::Entry superset =
+ CHECK_NOTERROR(cgroups::devices::Entry::parse("c *:1 rwm"));
+
+ EXPECT_TRUE(subset.encompasses(subset));
+ EXPECT_TRUE(superset.encompasses(superset));
+ EXPECT_FALSE(subset.encompasses(superset));
+ EXPECT_TRUE(superset.encompasses(subset));
+
+ superset = CHECK_NOTERROR(cgroups::devices::Entry::parse("c 3:* rwm"));
+ EXPECT_TRUE(subset.encompasses(subset));
+ EXPECT_TRUE(superset.encompasses(superset));
+ EXPECT_FALSE(subset.encompasses(superset));
+ EXPECT_TRUE(superset.encompasses(subset));
+
+ superset = CHECK_NOTERROR(cgroups::devices::Entry::parse("a"));
+ EXPECT_TRUE(subset.encompasses(subset));
+ EXPECT_TRUE(superset.encompasses(superset));
+ EXPECT_FALSE(subset.encompasses(superset));
+ EXPECT_TRUE(superset.encompasses(subset));
+
+ subset = CHECK_NOTERROR(cgroups::devices::Entry::parse("c 3:1 rm"));
+ superset = CHECK_NOTERROR(cgroups::devices::Entry::parse("c 3:1 rwm"));
+ EXPECT_TRUE(subset.encompasses(subset));
+ EXPECT_TRUE(superset.encompasses(superset));
+ EXPECT_FALSE(subset.encompasses(superset));
+ EXPECT_TRUE(superset.encompasses(subset));
+
+ subset = CHECK_NOTERROR(cgroups::devices::Entry::parse("b 3:1 rm"));
+ EXPECT_TRUE(subset.encompasses(subset));
+ EXPECT_TRUE(superset.encompasses(superset));
+ EXPECT_FALSE(subset.encompasses(superset));
+ EXPECT_FALSE(superset.encompasses(subset));
+}
+
+
+TEST(DevicesTest, AccessNoneTest)
+{
+ cgroups::devices::Entry::Access access;
+
+ access.read = false;
+ access.write = false;
+ access.mknod = false;
+ EXPECT_TRUE(access.none());
+
+ access.read = true;
+ access.write = false;
+ access.mknod = false;
+ EXPECT_FALSE(access.none());
+
+ access.read = false;
+ access.write = true;
+ access.mknod = false;
+ EXPECT_FALSE(access.none());
+
+ access.read = false;
+ access.write = false;
+ access.mknod = true;
+ EXPECT_FALSE(access.none());
+
+ access.read = true;
+ access.write = true;
+ access.mknod = false;
+ EXPECT_FALSE(access.none());
+
+ access.read = true;
+ access.write = false;
+ access.mknod = true;
+ EXPECT_FALSE(access.none());
+
+ access.read = false;
+ access.write = true;
+ access.mknod = true;
+ EXPECT_FALSE(access.none());
+
+ access.read = true;
+ access.write = true;
+ access.mknod = true;
+ EXPECT_FALSE(access.none());
+}
+
+
+TEST(DeviceTest, SelectorWildcardTest)
+{
+ cgroups::devices::Entry::Selector selector;
+ selector.type = cgroups::devices::Entry::Selector::Type::ALL;
+ selector.major = 1;
+ selector.minor = 1;
+ EXPECT_TRUE(selector.has_wildcard());
+
+ selector.type = cgroups::devices::Entry::Selector::Type::BLOCK;
+ selector.major = Option<unsigned int>::none();
+ selector.minor = 1;
+ EXPECT_TRUE(selector.has_wildcard());
+
+ selector.type = cgroups::devices::Entry::Selector::Type::BLOCK;
+ selector.major = 1;
+ selector.minor = Option<unsigned int>::none();
+ EXPECT_TRUE(selector.has_wildcard());
+
+ selector.type = cgroups::devices::Entry::Selector::Type::BLOCK;
+ selector.major = 1;
+ selector.minor = 1;
+ EXPECT_FALSE(selector.has_wildcard());
+}
+
} // namespace tests {
} // namespace internal {
} // namespace mesos {