From: Arvin Schnell Date: Wed, 30 Mar 2016 14:12:57 +0000 (+0200) Subject: - added function to prepare and query quota data X-Git-Tag: v0.3.3~16^2~2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=4d94edfd6189a6035011a85c55f2771e6ed9aaee;p=thirdparty%2Fsnapper.git - added function to prepare and query quota data --- diff --git a/snapper/Btrfs.cc b/snapper/Btrfs.cc index de01c577..d24914f9 100644 --- a/snapper/Btrfs.cc +++ b/snapper/Btrfs.cc @@ -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"); } diff --git a/snapper/Btrfs.h b/snapper/Btrfs.h index 2d45e25e..4a99a96a 100644 --- a/snapper/Btrfs.h +++ b/snapper/Btrfs.h @@ -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; diff --git a/snapper/BtrfsUtils.cc b/snapper/BtrfsUtils.cc index 650e0132..ef5f5e40 100644 --- a/snapper/BtrfsUtils.cc +++ b/snapper/BtrfsUtils.cc @@ -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) { diff --git a/snapper/BtrfsUtils.h b/snapper/BtrfsUtils.h index 179577e0..a76b5f63 100644 --- a/snapper/BtrfsUtils.h +++ b/snapper/BtrfsUtils.h @@ -1,5 +1,6 @@ /* * Copyright (c) [2011-2015] Novell, Inc. + * Copyright (c) 2016 SUSE LLC * * All Rights Reserved. * diff --git a/snapper/Ext4.cc b/snapper/Ext4.cc index 9aa79cf4..f7f73a04 100644 --- a/snapper/Ext4.cc +++ b/snapper/Ext4.cc @@ -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"); diff --git a/snapper/Ext4.h b/snapper/Ext4.h index 24e0477f..59d9d4cd 100644 --- a/snapper/Ext4.h +++ b/snapper/Ext4.h @@ -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; diff --git a/snapper/Filesystem.cc b/snapper/Filesystem.cc index 98a2bcb1..48d1261c 100644 --- a/snapper/Filesystem.cc +++ b/snapper/Filesystem.cc @@ -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"); } diff --git a/snapper/Filesystem.h b/snapper/Filesystem.h index 62fdad5a..023928c7 100644 --- a/snapper/Filesystem.h +++ b/snapper/Filesystem.h @@ -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; diff --git a/snapper/Lvm.cc b/snapper/Lvm.cc index 0fb90365..618549db 100644 --- a/snapper/Lvm.cc +++ b/snapper/Lvm.cc @@ -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"); diff --git a/snapper/Lvm.h b/snapper/Lvm.h index be867310..56201688 100644 --- a/snapper/Lvm.h +++ b/snapper/Lvm.h @@ -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; diff --git a/snapper/Snapper.cc b/snapper/Snapper.cc index 2fa5c91e..e931c1ed 100644 --- a/snapper/Snapper.cc +++ b/snapper/Snapper.cc @@ -1,5 +1,6 @@ /* * Copyright (c) [2011-2015] Novell, Inc. + * Copyright (c) 2016 SUSE LLC * * All Rights Reserved. * @@ -24,6 +25,7 @@ #include #include +#include #include #include #include @@ -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(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 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(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) { diff --git a/snapper/Snapper.h b/snapper/Snapper.h index 9ebd32c6..5bff93c3 100644 --- a/snapper/Snapper.h +++ b/snapper/Snapper.h @@ -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(); diff --git a/snapper/Snapshot.cc b/snapper/Snapshot.cc index 2e597dfc..d0c33f24 100644 --- a/snapper/Snapshot.cc +++ b/snapper/Snapshot.cc @@ -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()); }