]> git.ipfire.org Git - thirdparty/snapper.git/commitdiff
- added option --sync to delete command (fate#317066)
authorArvin Schnell <aschnell@suse.de>
Tue, 5 May 2015 13:00:37 +0000 (15:00 +0200)
committerArvin Schnell <aschnell@suse.de>
Tue, 5 May 2015 13:00:37 +0000 (15:00 +0200)
16 files changed:
client/commands.cc
client/commands.h
client/snapper.cc
doc/dbus-protocol.txt
doc/snapper.xml.in
package/snapper.changes
server/Client.cc
server/Client.h
snapper/Btrfs.cc
snapper/Btrfs.h
snapper/BtrfsUtils.cc
snapper/BtrfsUtils.h
snapper/Filesystem.cc
snapper/Filesystem.h
snapper/Snapper.cc
snapper/Snapper.h

index c046ab172c8e17c4e0238d9eff6e302102a97b3a..b45eb45a1c1b4219c22dffad9cbafab84d66f9b1 100644 (file)
@@ -381,6 +381,18 @@ command_get_xfiles(DBus::Connection& conn, const string& config_name, unsigned i
 }
 
 
+void
+command_xsync(DBus::Connection& conn, const string& config_name)
+{
+    DBus::MessageMethodCall call(SERVICE, OBJECT, INTERFACE, "Sync");
+
+    DBus::Hoho hoho(call);
+    hoho << config_name;
+
+    conn.send_with_reply_and_block(call);
+}
+
+
 vector<string>
 command_xdebug(DBus::Connection& conn)
 {
index 1805c4b9bb504b0f1458576d18c9018bb5327580..f7d799cd6da3a4fac80f293f124e3b719fb6d589 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) [2012-2014] Novell, Inc.
+ * Copyright (c) [2012-2015] Novell, Inc.
  *
  * All Rights Reserved.
  *
@@ -115,5 +115,8 @@ list<XFile>
 command_get_xfiles(DBus::Connection& conn, const string& config_name, unsigned int number1,
                   unsigned int number2);
 
+void
+command_xsync(DBus::Connection& conn, const string& config_name);
+
 vector<string>
 command_xdebug(DBus::Connection& conn);
index 51b3534abad1a5568168d167ae2cdc74ec7c4856..f7bd59a4b65e8eaf88828e2bf3783866e77c8a82 100644 (file)
@@ -844,7 +844,6 @@ command_modify(DBus::Connection* conn, Snapper* snapper)
     };
 
     GetOpts::parsed_opts opts = getopts.parse("modify", options);
-
     if (!getopts.hasArgs())
     {
        cerr << _("Command 'modify' needs at least one argument.") << endl;
@@ -878,6 +877,9 @@ help_delete()
 {
     cout << _("  Delete snapshot:") << endl
         << _("\tsnapper delete <number>") << endl
+        << endl
+        << _("    Options for 'delete' command:") << endl
+        << _("\t--sync, -s\t\t\tSync after deletion.") << endl
         << endl;
 }
 
@@ -885,13 +887,25 @@ help_delete()
 void
 command_delete(DBus::Connection* conn, Snapper* snapper)
 {
-    getopts.parse("delete", GetOpts::no_options);
+    const struct option options[] = {
+       { "sync",               no_argument,            0,      's' },
+       { 0, 0, 0, 0 }
+    };
+
+    GetOpts::parsed_opts opts = getopts.parse("delete", options);
     if (!getopts.hasArgs())
     {
        cerr << _("Command 'delete' needs at least one argument.") << endl;
        exit(EXIT_FAILURE);
     }
 
+    bool sync = false;
+
+    GetOpts::parsed_opts::const_iterator opt;
+
+    if ((opt = opts.find("sync")) != opts.end())
+       sync = true;
+
     XSnapshots snapshots = command_list_xsnapshots(*conn, config_name);
 
     list<unsigned int> nums;
@@ -924,6 +938,9 @@ command_delete(DBus::Connection* conn, Snapper* snapper)
     }
 
     command_delete_xsnapshots(*conn, config_name, nums);
+
+    if (sync)
+       command_xsync(*conn, config_name);
 }
 
 
@@ -1088,7 +1105,6 @@ command_diff(DBus::Connection* conn, Snapper* snapper)
     };
 
     GetOpts::parsed_opts opts = getopts.parse("diff", options);
-
     if (getopts.numArgs() < 1)
     {
        cerr << _("Command 'diff' needs at least one argument.") << endl;
@@ -1472,7 +1488,6 @@ void
 command_xa_diff(DBus::Connection* conn, Snapper* snapper)
 {
     GetOpts::parsed_opts opts = getopts.parse("xadiff", GetOpts::no_options);
-
     if (getopts.numArgs() < 1)
     {
         cerr << _("Command 'xadiff' needs at least one argument.") << endl;
index dfbf41e6d90980fa0d0c636e64d7717071a0fd2b..8df609be4b55cd8fe35e7ccd029eb332f6fa1b5f 100644 (file)
@@ -42,6 +42,8 @@ method GetMountPoint config-name number
 Snapshots mounted with user-request set to false will be unmounted (delayed)
 after the client disconnects.
 
+method Sync config-name
+
 
 method CreateComparison config-name number1 number2
 method DeleteComparison config-name number1 number2
index 3b0061dc8ddcd86fb393728402d2eb8b91b5a803..4b000d04c31c9b5ff082eb994fc0226e50e51372 100644 (file)
        <replaceable>number1-number2</replaceable></option></term>
        <listitem>
          <para>Delete a snapshot or a range of snapshots.</para>
+         <variablelist>
+           <varlistentry>
+             <term><option>-s, --sync</option></term>
+             <listitem>
+               <para>Sync the filesystem after deleting the snapshots. The
+               details depend on the filesystem type.</para>
+               <para>Btrfs normally asynchronously frees space after deleting
+               snapshots. With this option snapper will wait until the space once used by the
+               deleted snapshots is actually available again.</para>
+             </listitem>
+           </varlistentry>
+         </variablelist>
        </listitem>
       </varlistentry>
 
index c00311df16742f62f1cae8494fa6073e3ebdcb14..c6adbf798ef223670d58af0ba60911d238eed6a0 100644 (file)
@@ -1,3 +1,8 @@
+-------------------------------------------------------------------
+Tue May 05 14:08:03 CEST 2015 - aschnell@suse.de
+
+- added option --sync to delete command (fate#317066)
+
 -------------------------------------------------------------------
 Tue Apr 14 17:58:17 CEST 2015 - aschnell@suse.de
 
index ab6b803abc57a244a2dee451c4372c50cae8b65a..dccf64185ee7a9462d1c4906ab0be7c17323f00d 100644 (file)
@@ -1287,6 +1287,30 @@ Client::get_files(DBus::Connection& conn, DBus::Message& msg)
 }
 
 
+void
+Client::sync(DBus::Connection& conn, DBus::Message& msg)
+{
+    string config_name;
+
+    DBus::Hihi hihi(msg);
+    hihi >> config_name;
+
+    y2deb("Sync config_name:" << config_name);
+
+    MetaSnappers::iterator it = meta_snappers.find(config_name);
+
+    check_permission(conn, msg, *it);
+
+    Snapper* snapper = it->getSnapper();
+
+    snapper->syncFilesystem();
+
+    DBus::MessageMethodReturn reply(msg);
+
+    conn.send(reply);
+}
+
+
 void
 Client::debug(DBus::Connection& conn, DBus::Message& msg) const
 {
@@ -1403,6 +1427,8 @@ Client::dispatch(DBus::Connection& conn, DBus::Message& msg)
            delete_comparison(conn, msg);
        else if (msg.is_method_call(INTERFACE, "GetFiles"))
            get_files(conn, msg);
+       else if (msg.is_method_call(INTERFACE, "Sync"))
+           sync(conn, msg);
        else if (msg.is_method_call(INTERFACE, "Debug"))
            debug(conn, msg);
        else
index 267d0d946b30f073b507e73364005e646822e994..b24e66f25f54d6182688dc3d11a9a34d08bf532d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) [2012-2014] Novell, Inc.
+ * Copyright (c) [2012-2015] Novell, Inc.
  *
  * All Rights Reserved.
  *
@@ -104,6 +104,7 @@ public:
     void create_comparison(DBus::Connection& conn, DBus::Message& msg);
     void delete_comparison(DBus::Connection& conn, DBus::Message& msg);
     void get_files(DBus::Connection& conn, DBus::Message& msg);
+    void sync(DBus::Connection& conn, DBus::Message& msg);
     void debug(DBus::Connection& conn, DBus::Message& msg) const;
 
     void dispatch(DBus::Connection& conn, DBus::Message& msg);
index 83510b78a2762a1c00217ae2b2678d8fffc3cb09..bf5560edfdbc5ac19ac38234e4314e2ca1b52b80 100644 (file)
@@ -305,7 +305,7 @@ namespace snapper
     Btrfs::createSnapshotOfDefault(unsigned int num, bool read_only) const
     {
        SDir subvolume_dir = openSubvolumeDir();
-       unsigned long long id = get_default_id(subvolume_dir.fd());
+       subvolid_t id = get_default_id(subvolume_dir.fd());
        string name = get_subvolume(subvolume_dir.fd(), id);
 
        bool found = false;
@@ -352,7 +352,11 @@ namespace snapper
 
        try
        {
+           subvolid_t subvolid = get_id(openSnapshotDir(num).fd());
+
            delete_subvolume(info_dir.fd(), "snapshot");
+
+           deleted_subvolids.push_back(subvolid);
        }
        catch (const runtime_error& e)
        {
@@ -1359,13 +1363,13 @@ namespace snapper
            if (num == 0)
            {
                SDir subvolume_dir = openSubvolumeDir();
-               unsigned long long id = get_id(subvolume_dir.fd());
+               subvolid_t id = get_id(subvolume_dir.fd());
                set_default_id(subvolume_dir.fd(), id);
            }
            else
            {
                SDir snapshot_dir = openSnapshotDir(num);
-               unsigned long long id = get_id(snapshot_dir.fd());
+               subvolid_t id = get_id(snapshot_dir.fd());
 
                SDir subvolume_dir = openSubvolumeDir();
                set_default_id(subvolume_dir.fd(), id);
@@ -1389,6 +1393,28 @@ namespace snapper
 #endif
 
 
+    void
+    Btrfs::sync() const
+    {
+       SDir subvolume_dir = openSubvolumeDir();
+
+       BtrfsUtils::sync(subvolume_dir.fd());
+
+       if (!deleted_subvolids.empty())
+       {
+           for (subvolid_t subvolid : deleted_subvolids)
+           {
+               while (!does_subvolume_exist(subvolume_dir.fd(), subvolid))
+                   sleep(1);
+           }
+
+           deleted_subvolids.clear();
+
+           BtrfsUtils::sync(subvolume_dir.fd());
+       }
+    }
+
+
 #ifdef ENABLE_ROLLBACK
 
     class MntTable
index b0e100146e4cf49139f2eea6e6e479f2eea73f17..2d45e25e0b6e5ec6398de895c2cb9fe40408433c 100644 (file)
@@ -31,6 +31,9 @@
 namespace snapper
 {
 
+    using namespace BtrfsUtils;
+
+
     class Btrfs : public Filesystem
     {
     public:
@@ -73,10 +76,14 @@ namespace snapper
 
        virtual void setDefault(unsigned int num) const;
 
+       virtual void sync() const;
+
     private:
 
        qgroup_t qgroup;
 
+       mutable vector<subvolid_t> deleted_subvolids;
+
        void addToFstabHelper(const string& default_subvolume_name) const;
        void removeFromFstabHelper() const;
 
index 7dd0e79da3757c13c7a88cb6ccc007c8ee417fd9..b89553fbfe237a039683071fd8c9c17b6699828f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) [2011-2014] Novell, Inc.
+ * Copyright (c) [2011-2015] Novell, Inc.
  *
  * All Rights Reserved.
  *
@@ -77,200 +77,237 @@ struct btrfs_ioctl_vol_args_v2
 namespace snapper
 {
 
-    // See btrfsprogs source code for references.
+    namespace BtrfsUtils
+    {
 
+       // See btrfsprogs source code for references.
 
-    bool
-    is_subvolume(const struct stat& stat)
-    {
-       return stat.st_ino == 256 && S_ISDIR(stat.st_mode);
-    }
 
+       bool
+       is_subvolume(const struct stat& stat)
+       {
+           return stat.st_ino == 256 && S_ISDIR(stat.st_mode);
+       }
 
-    bool
-    is_subvolume_read_only(int fd)
-    {
-       __u64 flags;
-       if (ioctl(fd, BTRFS_IOC_SUBVOL_GETFLAGS, &flags) != 0)
-           throw runtime_error_with_errno("ioctl(BTRFS_IOC_SUBVOL_GETFLAGS) failed", errno);
 
-       return flags & BTRFS_SUBVOL_RDONLY;
-    }
+       bool
+       is_subvolume_read_only(int fd)
+       {
+           __u64 flags;
+           if (ioctl(fd, BTRFS_IOC_SUBVOL_GETFLAGS, &flags) != 0)
+               throw runtime_error_with_errno("ioctl(BTRFS_IOC_SUBVOL_GETFLAGS) failed", errno);
 
+           return flags & BTRFS_SUBVOL_RDONLY;
+       }
 
-    void
-    create_subvolume(int fddst, const string& name)
-    {
-       struct btrfs_ioctl_vol_args args;
-       memset(&args, 0, sizeof(args));
 
-       strncpy(args.name, name.c_str(), sizeof(args.name) - 1);
+       void
+       create_subvolume(int fddst, const string& name)
+       {
+           struct btrfs_ioctl_vol_args args;
+           memset(&args, 0, sizeof(args));
 
-       if (ioctl(fddst, BTRFS_IOC_SUBVOL_CREATE, &args) != 0)
-           throw runtime_error_with_errno("ioctl(BTRFS_IOC_SUBVOL_CREATE) failed", errno);
-    }
+           strncpy(args.name, name.c_str(), sizeof(args.name) - 1);
 
+           if (ioctl(fddst, BTRFS_IOC_SUBVOL_CREATE, &args) != 0)
+               throw runtime_error_with_errno("ioctl(BTRFS_IOC_SUBVOL_CREATE) failed", errno);
+       }
 
-    void
-    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.fd = fd;
-       args_v2.flags = read_only ? BTRFS_SUBVOL_RDONLY : 0;
-       strncpy(args_v2.name, name.c_str(), sizeof(args_v2.name) - 1);
+       void
+       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.fd = fd;
+           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;
-       }
+           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)
-           throw runtime_error_with_errno("ioctl(BTRFS_IOC_SNAP_CREATE_V2) failed", errno);
+           if (ioctl(fddst, BTRFS_IOC_SNAP_CREATE_V2, &args_v2) == 0)
+               return;
+           else if (errno != ENOTTY && errno != EINVAL)
+               throw runtime_error_with_errno("ioctl(BTRFS_IOC_SNAP_CREATE_V2) failed", errno);
 
-       struct btrfs_ioctl_vol_args args;
-       memset(&args, 0, sizeof(args));
+           struct btrfs_ioctl_vol_args args;
+           memset(&args, 0, sizeof(args));
 
-       args.fd = fd;
-       strncpy(args.name, name.c_str(), sizeof(args.name) - 1);
+           args.fd = fd;
+           strncpy(args.name, name.c_str(), sizeof(args.name) - 1);
 
-       if (ioctl(fddst, BTRFS_IOC_SNAP_CREATE, &args) != 0)
-           throw runtime_error_with_errno("ioctl(BTRFS_IOC_SNAP_CREATE) failed", errno);
-    }
+           if (ioctl(fddst, BTRFS_IOC_SNAP_CREATE, &args) != 0)
+               throw runtime_error_with_errno("ioctl(BTRFS_IOC_SNAP_CREATE) failed", errno);
+       }
 
 
-    void
-    delete_subvolume(int fd, const string& name)
-    {
-       struct btrfs_ioctl_vol_args args;
-       memset(&args, 0, sizeof(args));
+       void
+       delete_subvolume(int fd, const string& name)
+       {
+           struct btrfs_ioctl_vol_args args;
+           memset(&args, 0, sizeof(args));
 
-       strncpy(args.name, name.c_str(), sizeof(args.name) - 1);
+           strncpy(args.name, name.c_str(), sizeof(args.name) - 1);
 
-       if (ioctl(fd, BTRFS_IOC_SNAP_DESTROY, &args) != 0)
-           throw runtime_error_with_errno("ioctl(BTRFS_IOC_SNAP_DESTROY) failed", errno);
-    }
+           if (ioctl(fd, BTRFS_IOC_SNAP_DESTROY, &args) != 0)
+               throw runtime_error_with_errno("ioctl(BTRFS_IOC_SNAP_DESTROY) failed", errno);
+       }
 
 
 #ifdef ENABLE_ROLLBACK
 
-    void
-    set_default_id(int fd, unsigned long long id)
-    {
-       if (ioctl(fd, BTRFS_IOC_DEFAULT_SUBVOL, &id) != 0)
-           throw runtime_error_with_errno("ioctl(BTRFS_IOC_DEFAULT_SUBVOL) failed", errno);
-    }
+       void
+       set_default_id(int fd, subvolid_t id)
+       {
+           if (ioctl(fd, BTRFS_IOC_DEFAULT_SUBVOL, &id) != 0)
+               throw runtime_error_with_errno("ioctl(BTRFS_IOC_DEFAULT_SUBVOL) failed", errno);
+       }
 
 
-    unsigned long long
-    get_default_id(int fd)
-    {
-       struct btrfs_ioctl_search_args args;
-       memset(&args, 0, sizeof(args));
-
-       struct btrfs_ioctl_search_key* sk = &args.key;
-       sk->tree_id = BTRFS_ROOT_TREE_OBJECTID;
-       sk->nr_items = 1;
-       sk->max_objectid = BTRFS_ROOT_TREE_DIR_OBJECTID;
-       sk->min_objectid = BTRFS_ROOT_TREE_DIR_OBJECTID;
-       sk->max_type = BTRFS_DIR_ITEM_KEY;
-       sk->min_type = BTRFS_DIR_ITEM_KEY;
-       sk->max_offset = (__u64) -1;
-       sk->max_transid = (__u64) -1;
-
-       if (ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args) != 0)
-           throw runtime_error_with_errno("ioctl(BTRFS_IOC_TREE_SEARCH) failed", errno);
-
-       if (sk->nr_items == 0)
-           throw std::runtime_error("sk->nr_items == 0");
-
-       struct btrfs_ioctl_search_header* sh = (struct btrfs_ioctl_search_header*) args.buf;
-       if (sh->type != BTRFS_DIR_ITEM_KEY)
-           throw std::runtime_error("sh->type != BTRFS_DIR_ITEM_KEY");
-
-       struct btrfs_dir_item* di = (struct btrfs_dir_item*)(sh + 1);
-       int name_len = btrfs_stack_dir_name_len(di);
-       const char* name = (const char*)(di + 1);
-       if (strncmp("default", name, name_len) != 0)
-           throw std::runtime_error("name != default");
-
-       return btrfs_disk_key_objectid(&di->location);
-    }
+       subvolid_t
+       get_default_id(int fd)
+       {
+           struct btrfs_ioctl_search_args args;
+           memset(&args, 0, sizeof(args));
+
+           struct btrfs_ioctl_search_key* sk = &args.key;
+           sk->tree_id = BTRFS_ROOT_TREE_OBJECTID;
+           sk->nr_items = 1;
+           sk->max_objectid = BTRFS_ROOT_TREE_DIR_OBJECTID;
+           sk->min_objectid = BTRFS_ROOT_TREE_DIR_OBJECTID;
+           sk->max_type = BTRFS_DIR_ITEM_KEY;
+           sk->min_type = BTRFS_DIR_ITEM_KEY;
+           sk->max_offset = (__u64) -1;
+           sk->max_transid = (__u64) -1;
+
+           if (ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args) != 0)
+               throw runtime_error_with_errno("ioctl(BTRFS_IOC_TREE_SEARCH) failed", errno);
+
+           if (sk->nr_items == 0)
+               throw std::runtime_error("sk->nr_items == 0");
+
+           struct btrfs_ioctl_search_header* sh = (struct btrfs_ioctl_search_header*) args.buf;
+           if (sh->type != BTRFS_DIR_ITEM_KEY)
+               throw std::runtime_error("sh->type != BTRFS_DIR_ITEM_KEY");
+
+           struct btrfs_dir_item* di = (struct btrfs_dir_item*)(sh + 1);
+           int name_len = btrfs_stack_dir_name_len(di);
+           const char* name = (const char*)(di + 1);
+           if (strncmp("default", name, name_len) != 0)
+               throw std::runtime_error("name != default");
+
+           return btrfs_disk_key_objectid(&di->location);
+       }
 
 
-    string
-    get_subvolume(int fd, unsigned long long id)
-    {
-       char path[BTRFS_PATH_NAME_MAX + 1];
+       string
+       get_subvolume(int fd, subvolid_t id)
+       {
+           char path[BTRFS_PATH_NAME_MAX + 1];
 
-       if (btrfs_subvolid_resolve(fd, path, sizeof(path), id) != 0)
-           throw std::runtime_error("btrfs_subvolid_resolve failed");
+           if (btrfs_subvolid_resolve(fd, path, sizeof(path), id) != 0)
+               throw std::runtime_error("btrfs_subvolid_resolve failed");
 
-       path[BTRFS_PATH_NAME_MAX] = '\0';
-       return path;
-    }
+           path[BTRFS_PATH_NAME_MAX] = '\0';
+           return path;
+       }
 
+#endif
 
-    unsigned long long
-    get_id(int fd)
-    {
-       struct btrfs_ioctl_ino_lookup_args args;
-       memset(&args, 0, sizeof(args));
-       args.treeid = 0;
-       args.objectid = BTRFS_FIRST_FREE_OBJECTID;
 
-       if (ioctl(fd, BTRFS_IOC_INO_LOOKUP, &args) != 0)
-           throw runtime_error_with_errno("ioctl(BTRFS_IOC_INO_LOOKUP) failed", errno);
+       subvolid_t
+       get_id(int fd)
+       {
+           struct btrfs_ioctl_ino_lookup_args args;
+           memset(&args, 0, sizeof(args));
+           args.treeid = 0;
+           args.objectid = BTRFS_FIRST_FREE_OBJECTID;
 
-       return args.treeid;
-    }
+           if (ioctl(fd, BTRFS_IOC_INO_LOOKUP, &args) != 0)
+               throw runtime_error_with_errno("ioctl(BTRFS_IOC_INO_LOOKUP) failed", errno);
 
-#endif
+           return args.treeid;
+       }
 
 
-    qgroup_t
-    make_qgroup(uint64_t level, uint64_t id)
-    {
-       return (level << 48) | id;
-    }
+       qgroup_t
+       make_qgroup(uint64_t level, subvolid_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);
+       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));
+           subvolid_t id = 0;
+           b >> id;
+           if (b.fail() || !b.eof())
+               throw std::runtime_error("parsing qgroup failed");
+
+           return make_qgroup(level, id);
+       }
+
+
+       bool
+       does_subvolume_exist(int fd, subvolid_t subvolid)
+       {
+           struct btrfs_ioctl_search_args args;
+           struct btrfs_ioctl_search_key* sk = &args.key;
+
+           sk->tree_id = BTRFS_ROOT_TREE_OBJECTID;
+           sk->min_objectid = subvolid;
+           sk->max_objectid = subvolid;
+           sk->min_type = BTRFS_ROOT_ITEM_KEY;
+           sk->max_type = BTRFS_ROOT_ITEM_KEY;
+           sk->min_offset = 0;
+           sk->max_offset = (u64) -1;
+           sk->min_transid = 0;
+           sk->max_transid = (u64) -1;
+           sk->nr_items = 1;
+
+           if (ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args) != 0)
+               throw runtime_error_with_errno("ioctl(BTRFS_IOC_TREE_SEARCH) failed", errno);
+
+           return sk->nr_items == 0;
+       }
+
+
+       void
+       sync(int fd)
+       {
+           if (ioctl(fd, BTRFS_IOC_SYNC) != 0)
+               throw runtime_error_with_errno("ioctl(BTRFS_IOC_SYNC) failed", errno);
+       }
+
     }
 
 }
index 4f1dd2113c8484a1fe342635bab28a9daa984a4b..5e9eb49445b5262a614f0ab4f7c231fae82c41de 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) [2011-2014] Novell, Inc.
+ * Copyright (c) [2011-2015] Novell, Inc.
  *
  * All Rights Reserved.
  *
@@ -32,26 +32,37 @@ namespace snapper
     using std::string;
 
 
-    typedef uint64_t qgroup_t;
-    const qgroup_t no_qgroup = 0;
+    namespace BtrfsUtils
+    {
 
-    bool is_subvolume(const struct stat& stat);
+       typedef uint64_t subvolid_t;
 
-    bool is_subvolume_read_only(int fd);
+       typedef uint64_t qgroup_t;
+       const qgroup_t no_qgroup = 0;
 
-    void create_subvolume(int fddst, const string& name);
-    void create_snapshot(int fd, int fddst, const string& name, bool read_only,
-                        qgroup_t qgroup);
-    void delete_subvolume(int fd, const string& name);
+       bool is_subvolume(const struct stat& stat);
 
-    void set_default_id(int fd, unsigned long long id);
-    unsigned long long get_default_id(int fd);
+       bool is_subvolume_read_only(int fd);
 
-    string get_subvolume(int fd, unsigned long long id);
-    unsigned long long get_id(int fd);
+       bool does_subvolume_exist(int fd, subvolid_t id);
 
-    qgroup_t make_qgroup(uint64_t level, uint64_t id);
-    qgroup_t make_qgroup(const string& str);
+       void create_subvolume(int fddst, const string& name);
+       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, subvolid_t id);
+       subvolid_t get_default_id(int fd);
+
+       string get_subvolume(int fd, subvolid_t id);
+       subvolid_t get_id(int fd);
+
+       qgroup_t make_qgroup(uint64_t level, subvolid_t id);
+       qgroup_t make_qgroup(const string& str);
+
+       void sync(int fd);
+
+    }
 
 }
 
index e24f29ec4ec92eddc016ed97cc87b995c910cc48..045cb83a97f177d65a7d9cd7bfd437818a674c1e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) [2011-2013] Novell, Inc.
+ * Copyright (c) [2011-2015] Novell, Inc.
  *
  * All Rights Reserved.
  *
@@ -174,4 +174,10 @@ namespace snapper
        throw std::logic_error("not implemented");
     }
 
+
+    void
+    Filesystem::sync() const
+    {
+    }
+
 }
index 23e2a949ae4bac0e108fac0c00ac689c70deb018..62fdad5a1758051cbc24a5b081e1edb0c9d222f7 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) [2011-2014] Novell, Inc.
+ * Copyright (c) [2011-2015] Novell, Inc.
  *
  * All Rights Reserved.
  *
@@ -83,6 +83,8 @@ namespace snapper
 
        virtual void setDefault(unsigned int num) const;
 
+       virtual void sync() const;
+
     protected:
 
        const string subvolume;
index b6d61f943058bb2a5327e303a71f377c222ac7f3..955155d4f5a8e13af2a6332d501887bcd1520415 100644 (file)
@@ -492,6 +492,13 @@ namespace snapper
     }
 
 
+    void
+    Snapper::syncFilesystem() const
+    {
+       filesystem->sync();
+    }
+
+
     static void
     set_acl_permissions(acl_entry_t entry)
     {
index bc5ea1b8a53cdfec8b35e7818e5894f38b1c3f2b..e942b3104a55a29f2015a82fae77d9889233cd7c 100644 (file)
@@ -153,6 +153,8 @@ namespace snapper
 
        void syncAcl() const;
 
+       void syncFilesystem() const;
+
        static const char* compileVersion();
        static const char* compileFlags();