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"])
+-------------------------------------------------------------------
+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
./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}
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
{
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)
{
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)
{
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)
{
#include "snapper/Filesystem.h"
+#include "snapper/BtrfsUtils.h"
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;
private:
+ qgroup_t qgroup;
+
void addToFstab() const;
void removeFromFstab() const;
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));
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)
#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);
+ }
+
}
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);
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);
+
}
#ifdef ENABLE_LVM
&Lvm::create,
#endif
- NULL };
+ NULL
+ };
for (const func_t* func = funcs; *func != NULL; ++func)
{
}
+ 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
{
class MtabData;
+ class ConfigInfo;
class Filesystem
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;
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)