]> git.ipfire.org Git - thirdparty/snapper.git/commitdiff
- added function to prepare and query quota data
authorArvin Schnell <aschnell@suse.de>
Wed, 30 Mar 2016 14:12:57 +0000 (16:12 +0200)
committerArvin Schnell <aschnell@suse.de>
Wed, 30 Mar 2016 14:12:57 +0000 (16:12 +0200)
13 files changed:
snapper/Btrfs.cc
snapper/Btrfs.h
snapper/BtrfsUtils.cc
snapper/BtrfsUtils.h
snapper/Ext4.cc
snapper/Ext4.h
snapper/Filesystem.cc
snapper/Filesystem.h
snapper/Lvm.cc
snapper/Lvm.h
snapper/Snapper.cc
snapper/Snapper.h
snapper/Snapshot.cc

index de01c5775d4af4f733a3213c7da5eb2e8725a2bc..d24914f9e8cd4bc120b5400b116a8136cc81f5ff 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) [2011-2015] Novell, Inc.
+ * Copyright (c) 2016 SUSE LLC
  *
  * All Rights Reserved.
  *
@@ -276,7 +277,8 @@ namespace snapper
 
 
     void
-    Btrfs::createSnapshot(unsigned int num, unsigned int num_parent, bool read_only) const
+    Btrfs::createSnapshot(unsigned int num, unsigned int num_parent, bool read_only,
+                         bool quota) const
     {
        if (num_parent == 0)
        {
@@ -285,7 +287,8 @@ namespace snapper
 
            try
            {
-               create_snapshot(subvolume_dir.fd(), info_dir.fd(), "snapshot", read_only, qgroup);
+               create_snapshot(subvolume_dir.fd(), info_dir.fd(), "snapshot", read_only,
+                               quota ? qgroup : no_qgroup);
            }
            catch (const runtime_error& e)
            {
@@ -300,7 +303,8 @@ namespace snapper
 
            try
            {
-               create_snapshot(snapshot_dir.fd(), info_dir.fd(), "snapshot", read_only, qgroup);
+               create_snapshot(snapshot_dir.fd(), info_dir.fd(), "snapshot", read_only,
+                               quota ? qgroup : no_qgroup);
            }
            catch (const runtime_error& e)
            {
@@ -314,7 +318,7 @@ namespace snapper
 #ifdef ENABLE_ROLLBACK
 
     void
-    Btrfs::createSnapshotOfDefault(unsigned int num, bool read_only) const
+    Btrfs::createSnapshotOfDefault(unsigned int num, bool read_only, bool quota) const
     {
        SDir subvolume_dir = openSubvolumeDir();
        subvolid_t id = get_default_id(subvolume_dir.fd());
@@ -337,7 +341,8 @@ namespace snapper
 
        try
        {
-           create_snapshot(tmp_mount_dir.fd(), info_dir.fd(), "snapshot", read_only, qgroup);
+           create_snapshot(tmp_mount_dir.fd(), info_dir.fd(), "snapshot", read_only,
+                           quota ? qgroup : no_qgroup);
        }
        catch (const runtime_error& e)
        {
@@ -349,7 +354,7 @@ namespace snapper
 #else
 
     void
-    Btrfs::createSnapshotOfDefault(unsigned int num, bool read_only) const
+    Btrfs::createSnapshotOfDefault(unsigned int num, bool read_only, bool quota) const
     {
        throw std::logic_error("not implemented");
     }
index 2d45e25e0b6e5ec6398de895c2cb9fe40408433c..4a99a96a1a17c121b6c27e0930c1155519c1035b 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) [2011-2015] Novell, Inc.
+ * Copyright (c) 2016 SUSE LLC
  *
  * All Rights Reserved.
  *
@@ -59,9 +60,9 @@ namespace snapper
        virtual SDir openInfosDir() const;
        virtual SDir openSnapshotDir(unsigned int num) const;
 
-       virtual void createSnapshot(unsigned int num, unsigned int num_parent,
-                                   bool read_only) const;
-       virtual void createSnapshotOfDefault(unsigned int num, bool read_only) const;
+       virtual void createSnapshot(unsigned int num, unsigned int num_parent, bool read_only,
+                                   bool quota) const;
+       virtual void createSnapshotOfDefault(unsigned int num, bool read_only, bool quota) const;
        virtual void deleteSnapshot(unsigned int num) const;
 
        virtual bool isSnapshotMounted(unsigned int num) const;
@@ -78,6 +79,8 @@ namespace snapper
 
        virtual void sync() const;
 
+       virtual qgroup_t getQGroup() const { return qgroup; }
+
     private:
 
        qgroup_t qgroup;
index 650e013299c627a3409630b91dd61e4b7ed370cb..ef5f5e400ef02c7beb23643a1eaae8582bf0303a 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) [2011-2015] Novell, Inc.
+ * Copyright (c) 2016 SUSE LLC
  *
  * All Rights Reserved.
  *
@@ -327,6 +328,8 @@ namespace snapper
            }
        }
 
+#endif
+
 
        qgroup_t
        calc_qgroup(uint64_t level, subvolid_t id)
@@ -368,6 +371,8 @@ namespace snapper
        }
 
 
+#ifdef ENABLE_BTRFS_QUOTA
+
        void
        qgroup_create(int fd, qgroup_t qgroup)
        {
index 179577e0e28b20b2cf7845ba7450544ca8db3354..a76b5f63fba43bf2c8e455c9a496c2821b690d3d 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) [2011-2015] Novell, Inc.
+ * Copyright (c) 2016 SUSE LLC
  *
  * All Rights Reserved.
  *
index 9aa79cf4dd7c92aeb4cca6ae4e9e7f124c761802..f7f73a04245ff53d2e2d39ef359c9ed008a53c3f 100644 (file)
@@ -164,7 +164,7 @@ namespace snapper
 
 
     void
-    Ext4::createSnapshot(unsigned int num, unsigned int num_parent, bool read_only) const
+    Ext4::createSnapshot(unsigned int num, unsigned int num_parent, bool read_only, bool quota) const
     {
        if (num_parent != 0 || !read_only)
            throw std::logic_error("not implemented");
index 24e0477fafff59b34a8aeb502c4f423fdd76aca7..59d9d4cdc7fe3cb610ba142be87f7c366cae4cb7 100644 (file)
@@ -51,7 +51,7 @@ namespace snapper
        virtual SDir openSnapshotDir(unsigned int num) const;
 
        virtual void createSnapshot(unsigned int num, unsigned int num_parent,
-                                   bool read_only) const;
+                                   bool read_only, bool quota) const;
        virtual void deleteSnapshot(unsigned int num) const;
 
        virtual bool isSnapshotMounted(unsigned int num) const;
index 98a2bcb10f5a9de38e56fa8a3c3a8b9c67ed1921..48d1261cccd93baa34436ccf4e9258fe1b062223 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) [2011-2015] Novell, Inc.
+ * Copyright (c) 2016 SUSE LLC
  *
  * All Rights Reserved.
  *
@@ -163,7 +164,7 @@ namespace snapper
 
 
     void
-    Filesystem::createSnapshotOfDefault(unsigned int num, bool read_only) const
+    Filesystem::createSnapshotOfDefault(unsigned int num, bool read_only, bool quota) const
     {
        throw std::logic_error("not implemented");
     }
index 62fdad5a1758051cbc24a5b081e1edb0c9d222f7..023928c7d9ade8352f56ac60f596754fe533486f 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) [2011-2015] Novell, Inc.
+ * Copyright (c) 2016 SUSE LLC
  *
  * All Rights Reserved.
  *
@@ -66,9 +67,9 @@ namespace snapper
        virtual SDir openInfoDir(unsigned int num) const;
        virtual SDir openSnapshotDir(unsigned int num) const = 0;
 
-       virtual void createSnapshot(unsigned int num, unsigned int num_parent,
-                                   bool read_only) const = 0;
-       virtual void createSnapshotOfDefault(unsigned int num, bool read_only) const;
+       virtual void createSnapshot(unsigned int num, unsigned int num_parent, bool read_only,
+                                   bool quota) const = 0;
+       virtual void createSnapshotOfDefault(unsigned int num, bool read_only, bool quota) const;
        virtual void deleteSnapshot(unsigned int num) const = 0;
 
        virtual bool isSnapshotMounted(unsigned int num) const = 0;
index 0fb9036570a30b32c7e231f312090975e85bc3d8..618549dbd8bee2c9cd32a9cdaec1009af828303a 100644 (file)
@@ -189,7 +189,7 @@ namespace snapper
 
 
     void
-    Lvm::createSnapshot(unsigned int num, unsigned int num_parent, bool read_only) const
+    Lvm::createSnapshot(unsigned int num, unsigned int num_parent, bool read_only, bool quota) const
     {
        if (num_parent != 0 || !read_only)
            throw std::logic_error("not implemented");
index be8673109f81156d2dbbf8eb50bd350790c89381..5620168861d567ea7a3bf37aa2d7e2cd4e29890f 100644 (file)
@@ -96,7 +96,7 @@ namespace snapper
        virtual SDir openSnapshotDir(unsigned int num) const;
 
        virtual void createSnapshot(unsigned int num, unsigned int num_parent,
-                                   bool read_only) const;
+                                   bool read_only, bool quota) const;
        virtual void deleteSnapshot(unsigned int num) const;
 
        virtual bool isSnapshotMounted(unsigned int num) const;
index 2fa5c91ecef2a01ed5b651c24c9488546de0a368..e931c1edfe44f1a8ee35448c28a24a78c527ba8d 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) [2011-2015] Novell, Inc.
+ * Copyright (c) 2016 SUSE LLC
  *
  * All Rights Reserved.
  *
@@ -24,6 +25,7 @@
 
 #include <sys/stat.h>
 #include <sys/types.h>
+#include <sys/statvfs.h>
 #include <glob.h>
 #include <string.h>
 #include <mntent.h>
@@ -44,6 +46,8 @@
 #include "snapper/AsciiFile.h"
 #include "snapper/Exception.h"
 #include "snapper/Hooks.h"
+#include "snapper/Btrfs.h"
+#include "snapper/BtrfsUtils.h"
 
 
 namespace snapper
@@ -625,6 +629,104 @@ namespace snapper
     }
 
 
+    void
+    Snapper::prepareQuota() const
+    {
+#ifdef ENABLE_BTRFS_QUOTA
+
+       const Btrfs* btrfs = dynamic_cast<const Btrfs*>(getFilesystem());
+       if (!btrfs)
+           SN_THROW(QuotaException("quota only supported with btrfs"));
+
+       if (btrfs->getQGroup() == no_qgroup)
+           SN_THROW(QuotaException("qgroup not set"));
+
+       SDir subvolume_dir = openSubvolumeDir();
+
+       vector<qgroup_t> children = BtrfsUtils::qgroup_query_children(subvolume_dir.fd(),
+                                                                     btrfs->getQGroup());
+       sort(children.begin(), children.end());
+
+       // Iterate all snapshot and ensure that those and only those with a
+       // cleanup algorithm are included in the high level qgroup.
+
+       for (const Snapshot& snapshot : snapshots)
+       {
+           if (snapshot.isCurrent())
+               continue;
+
+           BtrfsUtils::subvolid_t subvolid = get_id(snapshot.openSnapshotDir().fd());
+           BtrfsUtils::qgroup_t qgroup = calc_qgroup(0, subvolid);
+
+           bool included = binary_search(children.begin(), children.end(), qgroup);
+
+           if (!snapshot.getCleanup().empty() && !included)
+           {
+               BtrfsUtils::qgroup_assign(subvolume_dir.fd(), qgroup, btrfs->getQGroup());
+           }
+           else if (snapshot.getCleanup().empty() && included)
+           {
+               BtrfsUtils::qgroup_remove(subvolume_dir.fd(), qgroup, btrfs->getQGroup());
+           }
+       }
+
+       // Strictly speaking the rescan is not needed if we did not assign or
+       // remove qgroups. On the other hand the consistency of qgroup data
+       // before our modifications is not guaranteed. The status flag is
+       // unfortunately not reliable, see
+       // https://bugzilla.suse.com/show_bug.cgi?id=972508#c5.
+
+       quota_rescan(subvolume_dir.fd());
+
+#else
+
+       SN_THROW(QuotaException("not implemented"));
+       __builtin_unreachable();
+
+#endif
+    }
+
+
+    QuotaData
+    Snapper::queryQuotaData() const
+    {
+#ifdef ENABLE_BTRFS_QUOTA
+
+       const Btrfs* btrfs = dynamic_cast<const Btrfs*>(getFilesystem());
+       if (!btrfs)
+           SN_THROW(QuotaException("quota only supported with btrfs"));
+
+       if (btrfs->getQGroup() == no_qgroup)
+           SN_THROW(QuotaException("qgroup not set"));
+
+       QuotaData quota_data;
+
+       SDir subvolume_dir = openSubvolumeDir();
+
+       BtrfsUtils::sync(subvolume_dir.fd());
+
+       struct statvfs64 fsbuf;
+       if (fstatvfs64(subvolume_dir.fd(), &fsbuf) != 0)
+           SN_THROW(QuotaException("statvfs64 failed"));
+       quota_data.size = fsbuf.f_blocks * fsbuf.f_bsize;
+
+       BtrfsUtils::QGroupUsage qgroup_usage = BtrfsUtils::qgroup_query_usage(subvolume_dir.fd(),
+                                                                             btrfs->getQGroup());
+       quota_data.used = qgroup_usage.exclusive;
+
+       y2mil("size:" << quota_data.size << " used:" << quota_data.used);
+
+       return quota_data;
+
+#else
+
+       SN_THROW(QuotaException("not implemented"));
+       __builtin_unreachable();
+
+#endif
+    }
+
+
     static bool
     is_subpath(const string& a, const string& b)
     {
index 9ebd32c6b9e586df1dacaab7112cdebe76e2cd96..5bff93c3a0e7b184c096450156ebd811d8b3dd0e 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) [2011-2015] Novell, Inc.
+ * Copyright (c) 2016 SUSE LLC
  *
  * All Rights Reserved.
  *
@@ -95,6 +96,18 @@ namespace snapper
        explicit DeleteConfigFailedException(const char* msg) : Exception(msg) {}
     };
 
+    struct QuotaException : public Exception
+    {
+       explicit QuotaException(const char* msg) : Exception(msg) {}
+    };
+
+
+    struct QuotaData
+    {
+       uint64_t size;
+       uint64_t used;
+    };
+
 
     class Snapper : private boost::noncopyable
     {
@@ -145,6 +158,10 @@ namespace snapper
 
        void syncFilesystem() const;
 
+       void prepareQuota() const;
+
+       QuotaData queryQuotaData() const;
+
        static const char* compileVersion();
        static const char* compileFlags();
 
index 2e597dfc37a7407b7cdf99c8146ef5cf77cd116b..d0c33f241b2c584209989ad5fe0e5cfc0bd46dd3 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) [2011-2015] Novell, Inc.
+ * Copyright (c) 2016 SUSE LLC
  *
  * All Rights Reserved.
  *
@@ -505,7 +506,7 @@ namespace snapper
        if (isCurrent())
            SN_THROW(IllegalSnapshotException());
 
-       snapper->getFilesystem()->createSnapshot(num, num_parent, read_only);
+       snapper->getFilesystem()->createSnapshot(num, num_parent, read_only, !cleanup.empty());
     }
 
 
@@ -515,7 +516,7 @@ namespace snapper
        if (isCurrent())
            SN_THROW(IllegalSnapshotException());
 
-       snapper->getFilesystem()->createSnapshotOfDefault(num, read_only);
+       snapper->getFilesystem()->createSnapshotOfDefault(num, read_only, !cleanup.empty());
     }