Added support for getting shared and slave mount peer group ID. Review: https://reviews.apache.org/r/38855
Project: http://git-wip-us.apache.org/repos/asf/mesos/repo Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/68a9d950 Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/68a9d950 Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/68a9d950 Branch: refs/heads/master Commit: 68a9d95090c8a84fff0ca0a350e678f9617e1a3e Parents: a6f1cf3 Author: Jie Yu <[email protected]> Authored: Tue Sep 29 10:36:19 2015 -0700 Committer: Jie Yu <[email protected]> Committed: Tue Sep 29 16:15:11 2015 -0700 ---------------------------------------------------------------------- src/linux/fs.cpp | 33 +++++++++ src/linux/fs.hpp | 12 +++- src/tests/containerizer/fs_tests.cpp | 113 ++++++++++++++++++++++++++---- 3 files changed, 144 insertions(+), 14 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/mesos/blob/68a9d950/src/linux/fs.cpp ---------------------------------------------------------------------- diff --git a/src/linux/fs.cpp b/src/linux/fs.cpp index 8631d89..27dc3e4 100644 --- a/src/linux/fs.cpp +++ b/src/linux/fs.cpp @@ -22,6 +22,7 @@ #include <linux/limits.h> +#include <stout/check.hpp> #include <stout/error.hpp> #include <stout/numify.hpp> #include <stout/path.hpp> @@ -146,6 +147,38 @@ Try<MountInfoTable::Entry> MountInfoTable::Entry::parse(const string& s) } +Option<int> MountInfoTable::Entry::shared() const +{ + foreach (const string& token, strings::tokenize(optionalFields, " ")) { + if (strings::startsWith(token, "shared:")) { + Try<int> id = numify<int>( + strings::remove(token, "shared:", strings::PREFIX)); + + CHECK_SOME(id); + return id.get(); + } + } + + return None(); +} + + +Option<int> MountInfoTable::Entry::master() const +{ + foreach (const string& token, strings::tokenize(optionalFields, " ")) { + if (strings::startsWith(token, "master:")) { + Try<int> id = numify<int>( + strings::remove(token, "master:", strings::PREFIX)); + + CHECK_SOME(id); + return id.get(); + } + } + + return None(); +} + + bool MountTable::Entry::hasOption(const string& option) const { struct mntent mntent; http://git-wip-us.apache.org/repos/asf/mesos/blob/68a9d950/src/linux/fs.hpp ---------------------------------------------------------------------- diff --git a/src/linux/fs.hpp b/src/linux/fs.hpp index f3aa0c2..0eb1642 100644 --- a/src/linux/fs.hpp +++ b/src/linux/fs.hpp @@ -167,8 +167,18 @@ struct MountInfoTable { // See the /proc/[pid]/mountinfo section in 'man proc' for further // details on each field. struct Entry { + static Try<Entry> parse(const std::string& s); + Entry() {} + // Returns the ID of the peer group in which this mount resides. + // Returns none if this mount is not a shared mount. + Option<int> shared() const; + + // Returns the ID of the peer group in which this mount's master + // resides in. Returns none if this mount is not a slave mount. + Option<int> master() const; + int id; // mountinfo[1]: mount ID. int parent; // mountinfo[2]: parent ID. dev_t devno; // mountinfo[3]: st_dev. @@ -190,8 +200,6 @@ struct MountInfoTable { std::string type; // mountinfo[9]: filesystem type. std::string source; // mountinfo[10]: source dev, other. - - static Try<Entry> parse(const std::string& s); }; // If pid is None() the "self" is used, i.e., the mountinfo table http://git-wip-us.apache.org/repos/asf/mesos/blob/68a9d950/src/tests/containerizer/fs_tests.cpp ---------------------------------------------------------------------- diff --git a/src/tests/containerizer/fs_tests.cpp b/src/tests/containerizer/fs_tests.cpp index 34d3c41..7fb4133 100644 --- a/src/tests/containerizer/fs_tests.cpp +++ b/src/tests/containerizer/fs_tests.cpp @@ -24,20 +24,27 @@ #include <stout/gtest.hpp> #include <stout/none.hpp> #include <stout/option.hpp> +#include <stout/os.hpp> #include <stout/try.hpp> #include "linux/fs.hpp" +#include "tests/utils.hpp" + +using std::string; + +using mesos::internal::fs::MountTable; +using mesos::internal::fs::FileSystemTable; +using mesos::internal::fs::MountInfoTable; + namespace mesos { namespace internal { namespace tests { -using fs::MountTable; -using fs::FileSystemTable; -using fs::MountInfoTable; +class FsTest : public TemporaryDirectoryTest {}; -TEST(FsTest, MountTableRead) +TEST_F(FsTest, MountTableRead) { Try<MountTable> table = MountTable::read(_PATH_MOUNTED); @@ -59,7 +66,7 @@ TEST(FsTest, MountTableRead) } -TEST(FsTest, MountTableHasOption) +TEST_F(FsTest, MountTableHasOption) { Try<MountTable> table = MountTable::read(_PATH_MOUNTED); @@ -77,7 +84,7 @@ TEST(FsTest, MountTableHasOption) } -TEST(FsTest, FileSystemTableRead) +TEST_F(FsTest, FileSystemTableRead) { Try<FileSystemTable> table = FileSystemTable::read(); @@ -96,10 +103,10 @@ TEST(FsTest, FileSystemTableRead) } -TEST(FsTest, MountInfoTableParse) +TEST_F(FsTest, MountInfoTableParse) { // Parse a private mount (no optional fields). - const std::string privateMount = + const string privateMount = "19 1 8:1 / / rw,relatime - ext4 /dev/sda1 rw,seclabel,data=ordered"; Try<MountInfoTable::Entry> entry = MountInfoTable::Entry::parse(privateMount); @@ -116,7 +123,7 @@ TEST(FsTest, MountInfoTableParse) EXPECT_EQ("/dev/sda1", entry.get().source); // Parse a shared mount (includes one optional field). - const std::string sharedMount = + const string sharedMount = "19 1 8:1 / / rw,relatime shared:2 - ext4 /dev/sda1 rw,seclabel"; entry = MountInfoTable::Entry::parse(sharedMount); @@ -134,10 +141,10 @@ TEST(FsTest, MountInfoTableParse) } -TEST(FsTest, DISABLED_MountInfoTableRead) +TEST_F(FsTest, DISABLED_MountInfoTableRead) { // Examine the calling process's mountinfo table. - Try<fs::MountInfoTable> table = fs::MountInfoTable::read(); + Try<MountInfoTable> table = MountInfoTable::read(); ASSERT_SOME(table); // Every system should have at least a rootfs mounted. @@ -151,7 +158,7 @@ TEST(FsTest, DISABLED_MountInfoTableRead) EXPECT_SOME(root); // Repeat for pid 1. - table = fs::MountInfoTable::read(1); + table = MountInfoTable::read(1); ASSERT_SOME(table); // Every system should have at least a rootfs mounted. @@ -165,6 +172,88 @@ TEST(FsTest, DISABLED_MountInfoTableRead) EXPECT_SOME(root); } + +TEST_F(FsTest, ROOT_SharedMount) +{ + string directory = os::getcwd(); + + // Do a self bind mount of the temporary directory. + ASSERT_SOME(fs::mount(directory, directory, None(), MS_BIND, None())); + + // Mark the mount as a shared mount. + ASSERT_SOME(fs::mount(None(), directory, None(), MS_SHARED, None())); + + // Find the above mount in the mount table. + Try<MountInfoTable> table = MountInfoTable::read(); + ASSERT_SOME(table); + + Option<MountInfoTable::Entry> entry; + foreach (const MountInfoTable::Entry& _entry, table.get().entries) { + if (_entry.target == directory) { + entry = _entry; + } + } + + ASSERT_SOME(entry); + EXPECT_SOME(entry.get().shared()); + + // Clean up the mount. + EXPECT_SOME(fs::unmount(directory)); +} + + +TEST_F(FsTest, ROOT_SlaveMount) +{ + string directory = os::getcwd(); + + // Do a self bind mount of the temporary directory. + ASSERT_SOME(fs::mount(directory, directory, None(), MS_BIND, None())); + + // Mark the mount as a shared mount of its own peer group. + ASSERT_SOME(fs::mount(None(), directory, None(), MS_PRIVATE, None())); + ASSERT_SOME(fs::mount(None(), directory, None(), MS_SHARED, None())); + + // Create a sub-mount under 'directory'. + string source = path::join(directory, "source"); + string target = path::join(directory, "target"); + + ASSERT_SOME(os::mkdir(source)); + ASSERT_SOME(os::mkdir(target)); + + ASSERT_SOME(fs::mount(source, target, None(), MS_BIND, None())); + + // Mark the sub-mount as a slave mount. + ASSERT_SOME(fs::mount(None(), target, None(), MS_SLAVE, None())); + + // Find the above sub-mount in the mount table, and check if it is a + // slave mount as expected. + Try<MountInfoTable> table = MountInfoTable::read(); + ASSERT_SOME(table); + + Option<MountInfoTable::Entry> parent; + Option<MountInfoTable::Entry> child; + foreach (const MountInfoTable::Entry& entry, table.get().entries) { + if (entry.target == directory) { + ASSERT_NONE(parent); + parent = entry; + } else if (entry.target == target) { + ASSERT_NONE(child); + child = entry; + } + } + + ASSERT_SOME(parent); + ASSERT_SOME(child); + + EXPECT_SOME(parent.get().shared()); + EXPECT_SOME(child.get().master()); + EXPECT_EQ(child.get().master(), parent.get().shared()); + + // Clean up the mount. + EXPECT_SOME(fs::unmount(target)); + EXPECT_SOME(fs::unmount(directory)); +} + } // namespace tests { } // namespace internal { } // namespace mesos {
