]> git.ipfire.org Git - thirdparty/snapper.git/commitdiff
- allow to add snapshots to qgroup (prototype for fate#312751) 94/head
authorArvin Schnell <aschnell@suse.de>
Mon, 30 Jun 2014 12:45:28 +0000 (14:45 +0200)
committerArvin Schnell <aschnell@suse.de>
Mon, 30 Jun 2014 12:45:28 +0000 (14:45 +0200)
configure.ac
package/snapper.changes
snapper.spec.in
snapper/Btrfs.cc
snapper/Btrfs.h
snapper/BtrfsUtils.cc
snapper/BtrfsUtils.h
snapper/Filesystem.cc
snapper/Filesystem.h
snapper/Snapper.cc

index 038b72d2fdbc9572c6c6abc6f2046be8f684a0c1..31032bc6e12a58fb9346f7cf11e31fcd83ce87ff 100644 (file)
@@ -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"])
index 0965e219fe5a5922a94a59d30fe39c3a555fd868..e46339b4eb18e78f5d00d6fc1af393d34123a907 100644 (file)
@@ -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
 
index 094be3b50b1defd20bfe8811af934b63f4ff27a7..335c7a3e74fe33a714ac147478e6b9a615099e0c 100644 (file)
@@ -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}
index aa37abe1061a1200ec9395ce9e53064b8d2a62c0..7eae0db67306a10de09259470244a9c89bd504bc 100644 (file)
@@ -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)
        {
index dc2a2c699c48dbb35e97597c1b9e50b420ac1b9d..ed884c8a7c01bb4a7b9231cf804e72bf1856a453 100644 (file)
@@ -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;
 
index f8f9d94d5d4291704918a5df37947c73f0a99dec..7dd0e79da3757c13c7a88cb6ccc007c8ee417fd9 100644 (file)
@@ -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<char> 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);
+    }
+
 }
index cb49702f1db20bbb3ce1d559c029e3f30cdfcc4d..4f1dd2113c8484a1fe342635bab28a9daa984a4b 100644 (file)
@@ -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);
+
 }
 
 
index 7e9d51a3b9906f98fa456a6e6a2d7095eec10155..dfc62f854757aeb84f0dccfb03b62c245241c51f 100644 (file)
@@ -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
     {
index a6427ec1763927200a92e451985f6d21ef580a34..2a56b257c7e23eb943610aebd35aab31e3330e2c 100644 (file)
@@ -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;
 
index 78bb9ee1d0179208673fd935b9acb1552af6cd07..88292450a4ade70144ac8b3bae039d181ab9fbfc 100644 (file)
@@ -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)