You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mesos.apache.org by ji...@apache.org on 2016/05/23 16:47:12 UTC

mesos git commit: Skipped the bind mount of CNI net info root dir if possible.

Repository: mesos
Updated Branches:
  refs/heads/master 1fe623cae -> ecb202aef


Skipped the bind mount of CNI net info root dir if possible.

Review: https://reviews.apache.org/r/47594/


Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/ecb202ae
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/ecb202ae
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/ecb202ae

Branch: refs/heads/master
Commit: ecb202aefd62c097d0c8e8e1b52b3e7f8ccbd81b
Parents: 1fe623c
Author: Qian Zhang <zh...@cn.ibm.com>
Authored: Mon May 23 09:45:14 2016 -0700
Committer: Jie Yu <yu...@gmail.com>
Committed: Mon May 23 09:47:05 2016 -0700

----------------------------------------------------------------------
 .../mesos/isolators/network/cni/cni.cpp         | 130 ++++++++++++-------
 1 file changed, 80 insertions(+), 50 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/ecb202ae/src/slave/containerizer/mesos/isolators/network/cni/cni.cpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/mesos/isolators/network/cni/cni.cpp b/src/slave/containerizer/mesos/isolators/network/cni/cni.cpp
index dae369a..fa33f57 100644
--- a/src/slave/containerizer/mesos/isolators/network/cni/cni.cpp
+++ b/src/slave/containerizer/mesos/isolators/network/cni/cni.cpp
@@ -22,6 +22,7 @@
 #include <process/pid.hpp>
 #include <process/subprocess.hpp>
 
+#include <stout/adaptor.hpp>
 #include <stout/os.hpp>
 #include <stout/net.hpp>
 
@@ -225,78 +226,107 @@ Try<Isolator*> NetworkCniIsolatorProcess::create(const Flags& flags)
         (rootDir.isError() ? rootDir.error() : "No such file or directory"));
   }
 
-  LOG(INFO) << "Making '" << rootDir.get() << "' a shared mount";
-
   Try<fs::MountInfoTable> table = fs::MountInfoTable::read();
   if (table.isError()) {
     return Error("Failed to get mount table: " + table.error());
   }
 
+  // Trying to find the mount entry that contains the CNI network
+  // information root directory. We achieve that by doing a reverse
+  // traverse of the mount table to find the first entry whose target
+  // is a prefix of the CNI network information root directory.
   Option<fs::MountInfoTable::Entry> rootDirMount;
-  foreach (const fs::MountInfoTable::Entry& entry, table.get().entries) {
-    if (entry.target == rootDir.get()) {
+  foreach (const fs::MountInfoTable::Entry& entry,
+           adaptor::reverse(table->entries)) {
+    if (strings::startsWith(rootDir.get(), entry.target)) {
       rootDirMount = entry;
       break;
     }
   }
 
-  // Do a self bind mount if needed. If the mount already exists, make
-  // sure it is a shared mount of its own peer group.
+  // It's unlikely that we cannot find 'rootDirMount' because '/' is
+  // always mounted and will be the 'rootDirMount' if no other mounts
+  // found in between.
   if (rootDirMount.isNone()) {
-    Try<string> mount = os::shell(
-        "mount --bind %s %s && "
-        "mount --make-slave %s && "
-        "mount --make-shared %s",
-        rootDir.get().c_str(),
-        rootDir.get().c_str(),
-        rootDir.get().c_str(),
-        rootDir.get().c_str());
+    return Error(
+        "Cannot find the mount containing CNI network information"
+        " root directory");
+  }
 
-    if (mount.isError()) {
-      return Error(
-          "Failed to self bind mount '" + rootDir.get() +
-          "' and make it a shared mount: " + mount.error());
-    }
+  // If 'rootDirMount' is a shared mount in its own peer group, then
+  // we don't need to do anything. Otherwise, we need to do a self
+  // bind mount of CNI network information root directory to make sure
+  // it's a shared mount in its own peer group.
+  bool bindMountNeeded = false;
+
+  if (rootDirMount->shared().isNone()) {
+    bindMountNeeded = true;
   } else {
-    if (rootDirMount.get().shared().isNone()) {
-      // This is the case where the CNI network information root directory
-      // mount is not a shared mount yet (possibly due to agent crash while
-      // preparing the directory mount). It's safe to re-do the following.
+    foreach (const fs::MountInfoTable::Entry& entry, table->entries) {
+      // Skip 'rootDirMount' and any mount underneath it. Also, we
+      // skip those mounts whose targets are not the parent of the CNI
+      // network information root directory because even if they are
+      // in the same peer group as the CNI network information root
+      // directory mount, it won't affect it.
+      if (entry.id != rootDirMount->id &&
+          !strings::startsWith(entry.target, rootDir.get()) &&
+          entry.shared() == rootDirMount->shared() &&
+          strings::startsWith(rootDir.get(), entry.target)) {
+        bindMountNeeded = true;
+        break;
+      }
+    }
+  }
+
+  if (bindMountNeeded) {
+    if (rootDirMount->target != rootDir.get()) {
+      // This is the case where the CNI network information root
+      // directory mount does not exist in the mount table (e.g., a
+      // new host running Mesos agent for the first time).
+      LOG(INFO) << "Bind mounting '" << rootDir.get()
+                << "' and making it a shared mount";
+
+      // NOTE: Instead of using fs::mount to perform the bind mount,
+      // we use the shell command here because the syscall 'mount'
+      // does not update the mount table (i.e., /etc/mtab). In other
+      // words, the mount will not be visible if the operator types
+      // command 'mount'. Since this mount will still be presented
+      // after all containers and the slave are stopped, it's better
+      // to make it visible. It's OK to use the blocking os::shell
+      // here because 'create' will only be invoked during
+      // initialization.
       Try<string> mount = os::shell(
-          "mount --make-slave %s && "
+          "mount --bind %s %s && "
+          "mount --make-private %s && "
           "mount --make-shared %s",
-          rootDir.get().c_str(),
-          rootDir.get().c_str());
+          rootDir->c_str(),
+          rootDir->c_str(),
+          rootDir->c_str(),
+          rootDir->c_str());
 
       if (mount.isError()) {
         return Error(
-            "Failed to self bind mount '" + rootDir.get() +
+            "Failed to bind mount '" + rootDir.get() +
             "' and make it a shared mount: " + mount.error());
       }
     } else {
-      // We need to make sure that the shared mount is in its own peer
-      // group. To check that, we need to get the parent mount.
-      foreach (const fs::MountInfoTable::Entry& entry, table.get().entries) {
-        if (entry.id == rootDirMount.get().parent) {
-          // If the CNI network information root directory mount and its
-          // parent mount are in the same peer group, we need to re-do the
-          // following commands so that they are in different peer groups.
-          if (entry.shared() == rootDirMount.get().shared()) {
-            Try<string> mount = os::shell(
-                "mount --make-slave %s && "
-                "mount --make-shared %s",
-                rootDir.get().c_str(),
-                rootDir.get().c_str());
-
-            if (mount.isError()) {
-              return Error(
-                  "Failed to self bind mount '" + rootDir.get() +
-                  "' and make it a shared mount: " + mount.error());
-            }
-          }
-
-          break;
-        }
+      // This is the case where the CNI network information root
+      // directory mount is in the mount table, but it's not a shared
+      // mount in its own peer group (possibly due to agent crash
+      // while preparing the CNI network information root directory
+      // mount). It's safe to re-do the following.
+      LOG(INFO) << "Making '" << rootDir.get() << "' a shared mount";
+
+      Try<string> mount = os::shell(
+          "mount --make-private %s && "
+          "mount --make-shared %s",
+          rootDir->c_str(),
+          rootDir->c_str());
+
+      if (mount.isError()) {
+        return Error(
+            "Failed to make '" + rootDir.get() +
+            "' a shared mount: " + mount.error());
       }
     }
   }