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 {

Reply via email to