From 208c7f740c5ff4b91fcc393ef533c202ba88fd2b Mon Sep 17 00:00:00 2001 From: Arvin Schnell Date: Mon, 30 Jun 2014 14:45:28 +0200 Subject: [PATCH] - allow to add snapshots to qgroup (prototype for fate#312751) --- configure.ac | 8 +++++++ package/snapper.changes | 5 +++++ snapper.spec.in | 2 +- snapper/Btrfs.cc | 27 ++++++++++++++++++---- snapper/Btrfs.h | 5 +++++ snapper/BtrfsUtils.cc | 50 ++++++++++++++++++++++++++++++++++++++++- snapper/BtrfsUtils.h | 9 +++++++- snapper/Filesystem.cc | 17 +++++++++++++- snapper/Filesystem.h | 4 ++++ snapper/Snapper.cc | 4 +--- 10 files changed, 120 insertions(+), 11 deletions(-) diff --git a/configure.ac b/configure.ac index 038b72d2..31032bc6 100644 --- a/configure.ac +++ b/configure.ac @@ -119,6 +119,14 @@ if test "x$enable_rollback" = "xyes"; then AC_DEFINE(ENABLE_ROLLBACK, 1, [Enable rollback support]) fi +AC_ARG_ENABLE([btrfs-quota], AC_HELP_STRING([--disable-btrfs-quota],[Disable btrfs quota support]), + [enable_btrfs_quota=$enableval],[enable_btrfs_quota=yes]) +AM_CONDITIONAL(ENABLE_BTRFS_QUOTA, [test "x$enable_btrfs_quota" = "xyes"]) + +if test "x$enable_btrfs_quota" = "xyes"; then + AC_DEFINE(ENABLE_BTRFS_QUOTA, 1, [Enable btrfs quota support]) +fi + AC_ARG_ENABLE([pam], AC_HELP_STRING([--disable-pam],[Disable pam plugin support]), [with_pam=$enableval],[with_pam=yes]) AM_CONDITIONAL(HAVE_PAM, [test "x$with_pam" = "xyes"]) diff --git a/package/snapper.changes b/package/snapper.changes index 0965e219..e46339b4 100644 --- a/package/snapper.changes +++ b/package/snapper.changes @@ -1,3 +1,8 @@ +------------------------------------------------------------------- +Mon Jun 30 14:44:25 CEST 2014 - aschnell@suse.de + +- allow to add snapshots to qgroup (prototype for fate#312751) + ------------------------------------------------------------------- Mon Jun 23 09:19:03 CEST 2014 - aschnell@suse.de diff --git a/snapper.spec.in b/snapper.spec.in index 094be3b5..335c7a3e 100644 --- a/snapper.spec.in +++ b/snapper.spec.in @@ -82,7 +82,7 @@ autoconf ./configure --libdir=%{_libdir} --prefix=%{prefix} --mandir=%{_mandir} \ --docdir=%{prefix}/share/doc/packages/snapper \ %if 0%{?suse_version} <= 1310 - --disable-rollback \ + --disable-rollback --disable-btrfs-quota \ %endif --disable-silent-rules --disable-ext4 make %{?jobs:-j%jobs} diff --git a/snapper/Btrfs.cc b/snapper/Btrfs.cc index aa37abe1..7eae0db6 100644 --- a/snapper/Btrfs.cc +++ b/snapper/Btrfs.cc @@ -69,11 +69,30 @@ namespace snapper Btrfs::Btrfs(const string& subvolume) - : Filesystem(subvolume) + : Filesystem(subvolume), qgroup(no_qgroup) { } + void + Btrfs::evalConfigInfo(const ConfigInfo& config_info) + { + string qgroup_str; + if (config_info.getValue("QGROUP", qgroup_str) && !qgroup_str.empty()) + { + try + { + qgroup = make_qgroup(qgroup_str); + } + catch (const runtime_error& e) + { + y2err("failed to parse qgroup '" << qgroup_str << "'"); + throw InvalidConfigException(); + } + } + } + + void Btrfs::createConfig(bool add_fstab) const { @@ -232,7 +251,7 @@ namespace snapper try { - create_snapshot(subvolume_dir.fd(), info_dir.fd(), "snapshot", read_only); + create_snapshot(subvolume_dir.fd(), info_dir.fd(), "snapshot", read_only, qgroup); } catch (const runtime_error& e) { @@ -247,7 +266,7 @@ namespace snapper try { - create_snapshot(snapshot_dir.fd(), info_dir.fd(), "snapshot", read_only); + create_snapshot(snapshot_dir.fd(), info_dir.fd(), "snapshot", read_only, qgroup); } catch (const runtime_error& e) { @@ -284,7 +303,7 @@ namespace snapper try { - create_snapshot(tmp_mount_dir.fd(), info_dir.fd(), "snapshot", read_only); + create_snapshot(tmp_mount_dir.fd(), info_dir.fd(), "snapshot", read_only, qgroup); } catch (const runtime_error& e) { diff --git a/snapper/Btrfs.h b/snapper/Btrfs.h index dc2a2c69..ed884c8a 100644 --- a/snapper/Btrfs.h +++ b/snapper/Btrfs.h @@ -25,6 +25,7 @@ #include "snapper/Filesystem.h" +#include "snapper/BtrfsUtils.h" namespace snapper @@ -38,6 +39,8 @@ namespace snapper Btrfs(const string& subvolume); + virtual void evalConfigInfo(const ConfigInfo& config_info); + virtual string fstype() const { return "btrfs"; } virtual void createConfig(bool add_fstab) const; @@ -68,6 +71,8 @@ namespace snapper private: + qgroup_t qgroup; + void addToFstab() const; void removeFromFstab() const; diff --git a/snapper/BtrfsUtils.cc b/snapper/BtrfsUtils.cc index f8f9d94d..7dd0e79d 100644 --- a/snapper/BtrfsUtils.cc +++ b/snapper/BtrfsUtils.cc @@ -112,7 +112,7 @@ namespace snapper void - create_snapshot(int fd, int fddst, const string& name, bool read_only) + create_snapshot(int fd, int fddst, const string& name, bool read_only, qgroup_t qgroup) { struct btrfs_ioctl_vol_args_v2 args_v2; memset(&args_v2, 0, sizeof(args_v2)); @@ -121,6 +121,24 @@ namespace snapper args_v2.flags = read_only ? BTRFS_SUBVOL_RDONLY : 0; strncpy(args_v2.name, name.c_str(), sizeof(args_v2.name) - 1); +#ifdef ENABLE_BTRFS_QUOTA + if (qgroup != no_qgroup) + { + size_t size = sizeof(btrfs_qgroup_inherit) + sizeof(((btrfs_qgroup_inherit*) 0)->qgroups[0]); + vector buffer(size, 0); + struct btrfs_qgroup_inherit* inherit = (btrfs_qgroup_inherit*) &buffer[0]; + + inherit->num_qgroups = 1; + inherit->num_ref_copies = 0; + inherit->num_excl_copies = 0; + inherit->qgroups[0] = qgroup; + + args_v2.flags |= BTRFS_SUBVOL_QGROUP_INHERIT; + args_v2.size = size; + args_v2.qgroup_inherit = inherit; + } +#endif + if (ioctl(fddst, BTRFS_IOC_SNAP_CREATE_V2, &args_v2) == 0) return; else if (errno != ENOTTY && errno != EINVAL) @@ -225,4 +243,34 @@ namespace snapper #endif + + qgroup_t + make_qgroup(uint64_t level, uint64_t id) + { + return (level << 48) | id; + } + + + qgroup_t + make_qgroup(const string& str) + { + string::size_type pos = str.find('/'); + if (pos == string::npos) + throw std::runtime_error("parsing qgroup failed"); + + std::istringstream a(str.substr(0, pos)); + uint64_t level = 0; + a >> level; + if (a.fail() || !a.eof()) + throw std::runtime_error("parsing qgroup failed"); + + std::istringstream b(str.substr(pos + 1)); + uint64_t id = 0; + b >> id; + if (b.fail() || !b.eof()) + throw std::runtime_error("parsing qgroup failed"); + + return make_qgroup(level, id); + } + } diff --git a/snapper/BtrfsUtils.h b/snapper/BtrfsUtils.h index cb49702f..4f1dd211 100644 --- a/snapper/BtrfsUtils.h +++ b/snapper/BtrfsUtils.h @@ -32,12 +32,16 @@ namespace snapper using std::string; + typedef uint64_t qgroup_t; + const qgroup_t no_qgroup = 0; + bool is_subvolume(const struct stat& stat); bool is_subvolume_read_only(int fd); void create_subvolume(int fddst, const string& name); - void create_snapshot(int fd, int fddst, const string& name, bool read_only); + void create_snapshot(int fd, int fddst, const string& name, bool read_only, + qgroup_t qgroup); void delete_subvolume(int fd, const string& name); void set_default_id(int fd, unsigned long long id); @@ -46,6 +50,9 @@ namespace snapper string get_subvolume(int fd, unsigned long long id); unsigned long long get_id(int fd); + qgroup_t make_qgroup(uint64_t level, uint64_t id); + qgroup_t make_qgroup(const string& str); + } diff --git a/snapper/Filesystem.cc b/snapper/Filesystem.cc index 7e9d51a3..dfc62f85 100644 --- a/snapper/Filesystem.cc +++ b/snapper/Filesystem.cc @@ -105,7 +105,8 @@ namespace snapper #ifdef ENABLE_LVM &Lvm::create, #endif - NULL }; + NULL + }; for (const func_t* func = funcs; *func != NULL; ++func) { @@ -119,6 +120,20 @@ namespace snapper } + Filesystem* + Filesystem::create(const ConfigInfo& config_info) + { + string fstype = "btrfs"; + config_info.getValue(KEY_FSTYPE, fstype); + + Filesystem* fs = create(fstype, config_info.getSubvolume()); + + fs->evalConfigInfo(config_info); + + return fs; + } + + SDir Filesystem::openSubvolumeDir() const { diff --git a/snapper/Filesystem.h b/snapper/Filesystem.h index a6427ec1..2a56b257 100644 --- a/snapper/Filesystem.h +++ b/snapper/Filesystem.h @@ -38,6 +38,7 @@ namespace snapper class MtabData; + class ConfigInfo; class Filesystem @@ -48,6 +49,9 @@ namespace snapper virtual ~Filesystem() {} static Filesystem* create(const string& fstype, const string& subvolume); + static Filesystem* create(const ConfigInfo& config_info); + + virtual void evalConfigInfo(const ConfigInfo& config_info) {} virtual string fstype() const = 0; diff --git a/snapper/Snapper.cc b/snapper/Snapper.cc index 78bb9ee1..88292450 100644 --- a/snapper/Snapper.cc +++ b/snapper/Snapper.cc @@ -91,9 +91,7 @@ namespace snapper throw ConfigNotFoundException(); } - string fstype = "btrfs"; - config_info->getValue(KEY_FSTYPE, fstype); - filesystem = Filesystem::create(fstype, config_info->getSubvolume()); + filesystem = Filesystem::create(*config_info); bool sync_acl; if (config_info->getValue(KEY_SYNC_ACL, sync_acl) && sync_acl == true) -- 2.47.3