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 f28bde1d9 Auto-enable limit enforcement feature on the XFS file 
system, to enforce set quotas.
f28bde1d9 is described below

commit f28bde1d95791fe2e967dbc12ec49f03299c455c
Author: Ilya Pronin <[email protected]>
AuthorDate: Thu Apr 12 17:40:09 2018 -0700

    Auto-enable limit enforcement feature on the XFS file system, to enforce 
set quotas.
    
    If quotas are set for the XFS disk isolator they will only be
    enforced if the limit enforcement feature is enabled, and it
    is not always enabled by default. This change will auto-enable
    quota enforcement on the XFS disk isolator, to get the expected
    quota enforcement behavior.
---
 .../containerizer/mesos/isolators/xfs/disk.cpp     |  6 ++
 .../containerizer/mesos/isolators/xfs/utils.cpp    | 72 ++++++++++++++++++++++
 .../containerizer/mesos/isolators/xfs/utils.hpp    | 12 ++++
 src/tests/containerizer/xfs_quota_tests.cpp        | 28 +++++++++
 4 files changed, 118 insertions(+)

diff --git a/src/slave/containerizer/mesos/isolators/xfs/disk.cpp 
b/src/slave/containerizer/mesos/isolators/xfs/disk.cpp
index aa865bca5..79b0c3a6e 100644
--- a/src/slave/containerizer/mesos/isolators/xfs/disk.cpp
+++ b/src/slave/containerizer/mesos/isolators/xfs/disk.cpp
@@ -136,6 +136,12 @@ static Option<Bytes> getSandboxDisk(
 
 Try<Isolator*> XfsDiskIsolatorProcess::create(const Flags& flags)
 {
+  Try<Nothing> enable = xfs::enableQuota(flags.work_dir);
+  if (enable.isError()) {
+    return Error("Failed to enable XFS project quotas on '" +
+                  flags.work_dir + "': " + enable.error());
+  }
+
   Try<Nothing> supported = isPathSupported(flags.work_dir);
   if (supported.isError()) {
     return Error(supported.error());
diff --git a/src/slave/containerizer/mesos/isolators/xfs/utils.cpp 
b/src/slave/containerizer/mesos/isolators/xfs/utils.cpp
index e67de07b0..f4c1a8c53 100644
--- a/src/slave/containerizer/mesos/isolators/xfs/utils.cpp
+++ b/src/slave/containerizer/mesos/isolators/xfs/utils.cpp
@@ -468,6 +468,78 @@ Try<bool> isQuotaEnabled(const string& path)
   return statv.qs_flags & (FS_QUOTA_PDQ_ACCT | FS_QUOTA_PDQ_ENFD);
 }
 
+
+static Try<bool> checkQuotaFlags(const std::string& path, uint16_t mask)
+{
+  Try<string> devname = getDeviceForPath(path);
+  if (devname.isError()) {
+    return Error(devname.error());
+  }
+
+  struct fs_quota_statv statv = {FS_QSTATV_VERSION1};
+
+  // The quota `type` argument to QCMD() doesn't apply to QCMD_XGETQSTATV
+  // since it is for quota subsystem information that can include all
+  // types of quotas. Equally, the quotactl() `id` argument doesn't apply
+  // because we are getting global information rather than information for
+  // a specific identity (eg. a projectId).
+  if (::quotactl(QCMD(Q_XGETQSTATV, 0),
+                 devname.get().c_str(),
+                 0, // id
+                 reinterpret_cast<caddr_t>(&statv)) == -1) {
+    // ENOSYS means that quotas are not enabled at all.
+    if (errno == ENOSYS) {
+      return false;
+    }
+
+    return ErrnoError();
+  }
+
+  return statv.qs_flags & mask;
+}
+
+
+Try<bool> isUserQuotaEnforcementEnabled(const std::string& path)
+{
+  return checkQuotaFlags(path, FS_QUOTA_UDQ_ENFD);
+}
+
+
+Try<bool> isGroupQuotaEnforcementEnabled(const std::string& path)
+{
+  return checkQuotaFlags(path, FS_QUOTA_GDQ_ENFD);
+}
+
+
+Try<bool> isProjectQuotaEnforcementEnabled(const std::string& path)
+{
+  return checkQuotaFlags(path, FS_QUOTA_PDQ_ENFD);
+}
+
+
+Try<Nothing> enableQuota(const string& path)
+{
+  Try<string> devname = getDeviceForPath(path);
+  if (devname.isError()) {
+    return Error(devname.error());
+  }
+
+  unsigned int flags = FS_QUOTA_PDQ_ACCT | FS_QUOTA_PDQ_ENFD;
+  if (::quotactl(QCMD(Q_XQUOTAON, 0),
+                 devname->c_str(),
+                 0, // id is ignored
+                 reinterpret_cast<caddr_t>(&flags)) == -1) {
+    // EEXIST means that the desired options are already enabled.
+    if (errno == EEXIST) {
+      return Nothing();
+    }
+
+    return ErrnoError();
+  }
+
+  return Nothing();
+}
+
 } // namespace xfs {
 } // namespace internal {
 } // namespace mesos {
diff --git a/src/slave/containerizer/mesos/isolators/xfs/utils.hpp 
b/src/slave/containerizer/mesos/isolators/xfs/utils.hpp
index ee83f59ea..a7535f6d7 100644
--- a/src/slave/containerizer/mesos/isolators/xfs/utils.hpp
+++ b/src/slave/containerizer/mesos/isolators/xfs/utils.hpp
@@ -145,6 +145,18 @@ Try<Nothing> setProjectId(
 Try<Nothing> clearProjectId(
     const std::string& directory);
 
+
+// Test whether XFS user, group or project quotas enforcement are
+// enabled on the filesystem at the given path.
+Try<bool> isUserQuotaEnforcementEnabled(const std::string& path);
+Try<bool> isGroupQuotaEnforcementEnabled(const std::string& path);
+Try<bool> isProjectQuotaEnforcementEnabled(const std::string& path);
+
+
+// Enable XFS project quotas (accounting and enforcement) on the
+// filesystem at the given path.
+Try<Nothing> enableQuota(const std::string& path);
+
 } // namespace xfs {
 } // namespace internal {
 } // namespace mesos {
diff --git a/src/tests/containerizer/xfs_quota_tests.cpp 
b/src/tests/containerizer/xfs_quota_tests.cpp
index 3333fe742..b3b42df8c 100644
--- a/src/tests/containerizer/xfs_quota_tests.cpp
+++ b/src/tests/containerizer/xfs_quota_tests.cpp
@@ -346,6 +346,16 @@ INSTANTIATE_TEST_CASE_P(
     ParamDiskQuota::Printer());
 
 
+// ROOT_XFS_NoProjectQuotaEnforcement sets up an XFS filesystem on
+// loopback with no project quota enforcement.
+class ROOT_XFS_NoProjectQuotaEnforcement : public ROOT_XFS_TestBase
+{
+public:
+  ROOT_XFS_NoProjectQuotaEnforcement()
+    : ROOT_XFS_TestBase("usrquota,grpquota,pqnoenforce") {}
+};
+
+
 TEST_F(ROOT_XFS_QuotaTest, QuotaGetSet)
 {
   prid_t projectId = 44;
@@ -2421,6 +2431,24 @@ TEST_F(ROOT_XFS_NoProjectQuota, CheckQuotaEnabled)
 }
 
 
+TEST_F(ROOT_XFS_NoProjectQuotaEnforcement, CheckQuotaEnabled)
+{
+  EXPECT_SOME_EQ(true, xfs::isUserQuotaEnforcementEnabled(mountPoint.get()));
+  EXPECT_SOME_EQ(true, xfs::isGroupQuotaEnforcementEnabled(mountPoint.get()));
+  EXPECT_SOME_EQ(
+      false, xfs::isProjectQuotaEnforcementEnabled(mountPoint.get()));
+
+  slave::Flags flags = CreateSlaveFlags();
+  Try<mesos::slave::Isolator*> isolator = 
XfsDiskIsolatorProcess::create(flags);
+  EXPECT_SOME(isolator);
+  delete isolator.get();
+
+  EXPECT_SOME_EQ(true, xfs::isUserQuotaEnforcementEnabled(mountPoint.get()));
+  EXPECT_SOME_EQ(true, xfs::isGroupQuotaEnforcementEnabled(mountPoint.get()));
+  EXPECT_SOME_EQ(true, 
xfs::isProjectQuotaEnforcementEnabled(mountPoint.get()));
+}
+
+
 // Verify that we correctly detect that project quotas are enabled.
 TEST_F(ROOT_XFS_QuotaTest, CheckQuotaEnabled)
 {

Reply via email to