You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mesos.apache.org by be...@apache.org on 2012/05/31 01:42:03 UTC

svn commit: r1344507 - in /incubator/mesos/trunk/src: Makefile.am linux/fs.cpp linux/fs.hpp tests/fs_tests.cpp

Author: benh
Date: Wed May 30 23:42:02 2012
New Revision: 1344507

URL: http://svn.apache.org/viewvc?rev=1344507&view=rev
Log:
Add utilities to monitor and control file systems on Linux (contributed by Jie Yu, https://reviews.apache.org/r/5186).

Added:
    incubator/mesos/trunk/src/linux/fs.cpp
    incubator/mesos/trunk/src/linux/fs.hpp
    incubator/mesos/trunk/src/tests/fs_tests.cpp
Modified:
    incubator/mesos/trunk/src/Makefile.am

Modified: incubator/mesos/trunk/src/Makefile.am
URL: http://svn.apache.org/viewvc/incubator/mesos/trunk/src/Makefile.am?rev=1344507&r1=1344506&r2=1344507&view=diff
==============================================================================
--- incubator/mesos/trunk/src/Makefile.am (original)
+++ incubator/mesos/trunk/src/Makefile.am Wed May 30 23:42:02 2012
@@ -172,9 +172,11 @@ nodist_pkginclude_HEADERS = ../include/m
 
 if OS_LINUX
   libmesos_no_third_party_la_SOURCES += slave/lxc_isolation_module.cpp
+  libmesos_no_third_party_la_SOURCES += linux/fs.cpp
   libmesos_no_third_party_la_SOURCES += linux/proc.cpp
 else
   EXTRA_DIST += slave/lxc_isolation_module.cpp
+  EXTRA_DIST += linux/fs.cpp
   EXTRA_DIST += linux/proc.cpp
 endif
 
@@ -193,10 +195,11 @@ libmesos_no_third_party_la_SOURCES += co
 	common/strings.hpp common/values.hpp				\
 	configurator/configuration.hpp configurator/configurator.hpp	\
 	configurator/option.hpp detector/detector.hpp			\
-	launcher/launcher.hpp linux/proc.hpp local/local.hpp		\
-	master/allocator.hpp master/allocator_factory.hpp		\
-	master/constants.hpp master/frameworks_manager.hpp		\
-	master/http.hpp master/master.hpp master/simple_allocator.hpp	\
+	launcher/launcher.hpp linux/fs.hpp linux/proc.hpp		\
+	local/local.hpp master/allocator.hpp				\
+	master/allocator_factory.hpp master/constants.hpp		\
+	master/frameworks_manager.hpp master/http.hpp			\
+	master/master.hpp master/simple_allocator.hpp			\
 	master/slaves_manager.hpp master/webui.hpp			\
 	messages/messages.hpp slave/constants.hpp slave/http.hpp	\
 	slave/isolation_module.hpp slave/isolation_module_factory.hpp	\
@@ -759,6 +762,7 @@ mesos_tests_LDADD = ../third_party/libgm
 mesos_tests_DEPENDENCIES = # Initialized to allow += below.
 
 if OS_LINUX
+  mesos_tests_SOURCES += tests/fs_tests.cpp
   mesos_tests_SOURCES += tests/proc_tests.cpp
 endif
 

Added: incubator/mesos/trunk/src/linux/fs.cpp
URL: http://svn.apache.org/viewvc/incubator/mesos/trunk/src/linux/fs.cpp?rev=1344507&view=auto
==============================================================================
--- incubator/mesos/trunk/src/linux/fs.cpp (added)
+++ incubator/mesos/trunk/src/linux/fs.cpp Wed May 30 23:42:02 2012
@@ -0,0 +1,183 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <linux/limits.h>
+
+#include "common/lock.hpp"
+
+#include "linux/fs.hpp"
+
+
+namespace mesos {
+namespace internal {
+namespace fs {
+
+
+// Lock for guarding accesses to fstab functions.
+static Lock* fstabLock = new Lock(new pthread_mutex_t);
+// Lock for guarding accesses to mntent functions.
+static Lock* mntentLock = new Lock(new pthread_mutex_t);
+
+
+bool MountTable::Entry::hasOption(const std::string& option)
+{
+  struct mntent mntent;
+  mntent.mnt_fsname = const_cast<char*>(fsname.c_str());
+  mntent.mnt_dir = const_cast<char*>(dir.c_str());
+  mntent.mnt_type = const_cast<char*>(type.c_str());
+  mntent.mnt_opts = const_cast<char*>(opts.c_str());
+  mntent.mnt_freq = freq;
+  mntent.mnt_passno = passno;
+  return ::hasmntopt(&mntent, option.c_str()) != NULL;
+}
+
+
+Try<MountTable> MountTable::read(const std::string& path)
+{
+  MountTable table;
+
+  FILE* file = ::setmntent(path.c_str(), "r");
+  if (file == NULL) {
+    return Try<MountTable>::error("Failed to open " + path);
+  }
+
+  while (true) {
+#if defined(_BSD_SOURCE) || defined(_SVID_SOURCE)
+    // Reentrant version exists.
+    struct mntent mntentBuffer;
+    char strBuffer[PATH_MAX];
+    struct mntent* mntent = ::getmntent_r(file, &mntentBuffer, strBuffer,
+                                          sizeof(strBuffer));
+    if (mntent == NULL) {
+      // NULL means the end of enties.
+      break;
+    }
+
+    MountTable::Entry entry(mntent->mnt_fsname,
+                            mntent->mnt_dir,
+                            mntent->mnt_type,
+                            mntent->mnt_opts,
+                            mntent->mnt_freq,
+                            mntent->mnt_passno);
+    table.entries.push_back(entry);
+#else
+    // Reentrant version does not exist. Use locks.
+    mntentLock->lock();
+    {
+      struct mntent* mntent = ::getmntent(file);
+      if (mntent == NULL) {
+        // NULL means the end of enties.
+        mntentLock->unlock();
+        break;
+      }
+
+      MountTable::Entry entry(mntent->mnt_fsname,
+                              mntent->mnt_dir,
+                              mntent->mnt_type,
+                              mntent->mnt_opts,
+                              mntent->mnt_freq,
+                              mntent->mnt_passno);
+      table.entries.push_back(entry);
+    }
+    mntentLock->unlock();
+#endif
+  }
+
+  ::endmntent(file);
+
+  return table;
+}
+
+
+Try<FileSystemTable> FileSystemTable::read()
+{
+  FileSystemTable table;
+
+  // Use locks since fstab functions are not thread-safe.
+  fstabLock->lock();
+  {
+    // Open file _PATH_FSTAB (/etc/fstab).
+    if (::setfsent() == 0) {
+      fstabLock->unlock();
+      return Try<FileSystemTable>::error("Failed to open file system table");
+    }
+
+    while (true) {
+      struct fstab* fstab = ::getfsent();
+      if (fstab == NULL) {
+        // NULL means the end of enties.
+        break;
+      }
+
+      FileSystemTable::Entry entry(fstab->fs_spec,
+                                   fstab->fs_file,
+                                   fstab->fs_vfstype,
+                                   fstab->fs_mntops,
+                                   fstab->fs_type,
+                                   fstab->fs_freq,
+                                   fstab->fs_passno);
+      table.entries.push_back(entry);
+    }
+
+    ::endfsent();
+  }
+  fstabLock->unlock();
+
+  return table;
+}
+
+
+Try<bool> mount(const std::string& source,
+                const std::string& target,
+                const std::string& type,
+                unsigned long flags,
+                const void* data)
+{
+  // The prototype of function 'mount' on Linux is as follows:
+  // int mount(const char *source, const char *target,
+  //           const char *filesystemtype, unsigned long mountflags,
+  //           const void *data);
+  if (::mount(source.c_str(), target.c_str(), type.c_str(), flags, data) < 0) {
+    return Try<bool>::error(
+        "Failed to mount " + source + " at " + target + ": " + strerror(errno));
+  }
+
+  return true;
+}
+
+
+Try<bool> unmount(const std::string& target, int flags)
+{
+  // The prototype of function 'umount2' on Linux is as follows:
+  // int umount2(const char *target, int flags);
+  if (::umount2(target.c_str(), flags) < 0) {
+    return Try<bool>::error(
+        "Failed to unmount " + target + ": " + strerror(errno));
+  }
+
+  return true;
+}
+
+
+} // namespace fs {
+} // namespace internal {
+} // namespace mesos {

Added: incubator/mesos/trunk/src/linux/fs.hpp
URL: http://svn.apache.org/viewvc/incubator/mesos/trunk/src/linux/fs.hpp?rev=1344507&view=auto
==============================================================================
--- incubator/mesos/trunk/src/linux/fs.hpp (added)
+++ incubator/mesos/trunk/src/linux/fs.hpp Wed May 30 23:42:02 2012
@@ -0,0 +1,148 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __FS_HPP__
+#define __FS_HPP__
+
+#include <fstab.h>
+#include <mntent.h>
+
+#include <sys/mount.h>
+
+#include <string>
+#include <vector>
+
+#include "common/try.hpp"
+
+
+namespace mesos {
+namespace internal {
+namespace fs {
+
+
+// Structure describing a mount table (e.g. /etc/mtab or /proc/mounts).
+struct MountTable {
+  // Structure describing a mount table entry. This is a wrapper for struct
+  // mntent defined in <mntent.h>.
+  struct Entry {
+    Entry() : freq(0), passno(0) {}
+
+    Entry(const std::string& _fsname,
+          const std::string& _dir,
+          const std::string& _type,
+          const std::string& _opts,
+          int _freq,
+          int _passno)
+      : fsname(_fsname),
+        dir(_dir),
+        type(_type),
+        opts(_opts),
+        freq(_freq),
+        passno(_passno)
+    {}
+
+    // Check whether a given mount option exists in a mount table entry.
+    // @param   option    The given mount option.
+    // @return  Whether the given mount option exists.
+    bool hasOption(const std::string& option);
+
+    std::string fsname; // Device or server for filesystem.
+    std::string dir;    // Directory mounted on.
+    std::string type;   // Type of filesystem: ufs, nfs, etc.
+    std::string opts;   // Comma-separated options for fs.
+    int freq;           // Dump frequency (in days).
+    int passno;         // Pass number for `fsck'.
+  };
+
+  // Read the mount table from a file.
+  // @param   path    The path of the file storing the mount table.
+  // @return  An instance of MountTable if success.
+  static Try<MountTable> read(const std::string& path);
+
+  std::vector<Entry> entries;
+};
+
+
+// Structure describing a file system table (e.g. /etc/fstab).
+struct FileSystemTable {
+  // Structure describing a file system table entry. This is a wrapper for
+  // struct fstab defined in <fstab.h>
+  struct Entry {
+    Entry() : freq(0), passno(0) {}
+
+    Entry(const std::string& _spec,
+          const std::string& _file,
+          const std::string& _vfstype,
+          const std::string& _mntops,
+          const std::string& _type,
+          int _freq,
+          int _passno)
+      : spec(_spec),
+        file(_file),
+        vfstype(_vfstype),
+        mntops(_mntops),
+        type(_type),
+        freq(_freq),
+        passno(_passno)
+    {}
+
+    std::string spec;     // Block special device name.
+    std::string file;     // File system path prefix.
+    std::string vfstype;  // File system type, ufs, nfs.
+    std::string mntops;   // Mount options ala -o.
+    std::string type;     // FSTAB_* from fs_mntops.
+    int freq;             // Dump frequency, in days.
+    int passno;           // Pass number on parallel dump.
+  };
+
+  // Read the file system table from a file.
+  // @param   path    The path of the file storing the file system table.
+  // @return  An instance of FileSystemTable if success.
+  static Try<FileSystemTable> read();
+
+  std::vector<Entry> entries;
+};
+
+
+// Mount a file system.
+// @param   source    Specify the file system (often a device name).
+// @param   target    Directory to be attached to.
+// @param   type      File system type (listed in /proc/filesystems).
+// @param   flags     Mount flags.
+// @param   data      Extra data interpreted by different file systems.
+// @return  Whether the mount operation successes.
+Try<bool> mount(const std::string& source,
+                const std::string& target,
+                const std::string& type,
+                unsigned long flags,
+                const void* data);
+
+
+// Unmount a file system.
+// @param   target    The (topmost) directory where the file system attaches.
+// @param   flags     Unmount flags.
+// @return  Whether the unmount operation successes.
+Try<bool> unmount(const std::string& target, int flags = 0);
+
+
+} // namespace fs {
+} // namespace internal {
+} // namespace mesos {
+
+
+#endif // __FS_HPP__

Added: incubator/mesos/trunk/src/tests/fs_tests.cpp
URL: http://svn.apache.org/viewvc/incubator/mesos/trunk/src/tests/fs_tests.cpp?rev=1344507&view=auto
==============================================================================
--- incubator/mesos/trunk/src/tests/fs_tests.cpp (added)
+++ incubator/mesos/trunk/src/tests/fs_tests.cpp Wed May 30 23:42:02 2012
@@ -0,0 +1,97 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <paths.h>
+
+#include <gmock/gmock.h>
+
+#include "common/option.hpp"
+#include "common/try.hpp"
+
+#include "common/foreach.hpp"
+#include "linux/fs.hpp"
+
+using namespace mesos;
+using namespace mesos::internal;
+
+using fs::MountTable;
+using fs::FileSystemTable;
+
+
+TEST(FsTest, MountTableRead)
+{
+  Try<MountTable> table = MountTable::read(_PATH_MOUNTED);
+
+  ASSERT_TRUE(table.isSome());
+
+  Option<MountTable::Entry> root = Option<MountTable::Entry>::none();
+  Option<MountTable::Entry> proc = Option<MountTable::Entry>::none();
+  foreach (const MountTable::Entry& entry, table.get().entries) {
+    if (entry.dir == "/") {
+      root = entry;
+    } else if (entry.dir == "/proc") {
+      proc = entry;
+    }
+  }
+
+  EXPECT_TRUE(root.isSome());
+  ASSERT_TRUE(proc.isSome());
+  EXPECT_EQ(proc.get().type, "proc");
+}
+
+
+TEST(FsTest, MountTableHasOption)
+{
+  Try<MountTable> table = MountTable::read(_PATH_MOUNTED);
+
+  ASSERT_TRUE(table.isSome());
+
+  Option<MountTable::Entry> proc = Option<MountTable::Entry>::none();
+  foreach (const MountTable::Entry& entry, table.get().entries) {
+    if (entry.dir == "/proc") {
+      proc = entry;
+    }
+  }
+
+  ASSERT_TRUE(proc.isSome());
+  EXPECT_TRUE(proc.get().hasOption("rw"));
+  EXPECT_TRUE(proc.get().hasOption("noexec"));
+  EXPECT_TRUE(proc.get().hasOption("nodev"));
+}
+
+
+TEST(FsTest, FileSystemTableRead)
+{
+  Try<FileSystemTable> table = FileSystemTable::read();
+
+  ASSERT_TRUE(table.isSome());
+
+  Option<FileSystemTable::Entry> root = Option<FileSystemTable::Entry>::none();
+  Option<FileSystemTable::Entry> proc = Option<FileSystemTable::Entry>::none();
+  foreach (const FileSystemTable::Entry& entry, table.get().entries) {
+    if (entry.file == "/") {
+      root = entry;
+    } else if (entry.file == "/proc") {
+      proc = entry;
+    }
+  }
+
+  EXPECT_TRUE(root.isSome());
+  ASSERT_TRUE(proc.isSome());
+  EXPECT_EQ(proc.get().vfstype, "proc");
+}