btrfs-progs: add btrfs_clear_free_space_tree() from the kernel
authorOmar Sandoval <osandov@fb.com>
Mon, 14 Nov 2016 18:43:21 +0000 (10:43 -0800)
committerDavid Sterba <dsterba@suse.com>
Wed, 23 Nov 2016 10:07:05 +0000 (11:07 +0100)
Reviewed-by: Qu Wenruo <quwenruo@cn.fujitsu.com>
Signed-off-by: Omar Sandoval <osandov@fb.com>
Signed-off-by: David Sterba <dsterba@suse.com>
ctree.h
extent-tree.c
free-space-tree.c
free-space-tree.h
root-tree.c

diff --git a/ctree.h b/ctree.h
index d67b852..b433bca 100644 (file)
--- a/ctree.h
+++ b/ctree.h
@@ -2504,6 +2504,10 @@ int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
                  struct extent_buffer *buf, int record_parent);
 int btrfs_dec_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
                  struct extent_buffer *buf, int record_parent);
+int btrfs_free_tree_block(struct btrfs_trans_handle *trans,
+                         struct btrfs_root *root,
+                         struct extent_buffer *buf,
+                         u64 parent, int last_ref);
 int btrfs_free_extent(struct btrfs_trans_handle *trans,
                      struct btrfs_root *root,
                      u64 bytenr, u64 num_bytes, u64 parent,
@@ -2664,6 +2668,8 @@ int btrfs_add_root_ref(struct btrfs_trans_handle *trans,
 int btrfs_insert_root(struct btrfs_trans_handle *trans, struct btrfs_root
                      *root, struct btrfs_key *key, struct btrfs_root_item
                      *item);
+int btrfs_del_root(struct btrfs_trans_handle *trans, struct btrfs_root *root,
+                  struct btrfs_key *key);
 int btrfs_update_root(struct btrfs_trans_handle *trans, struct btrfs_root
                      *root, struct btrfs_key *key, struct btrfs_root_item
                      *item);
index 3b1577e..b52c515 100644 (file)
@@ -2467,6 +2467,17 @@ static int del_pending_extents(struct btrfs_trans_handle *trans, struct
        return err;
 }
 
+
+int btrfs_free_tree_block(struct btrfs_trans_handle *trans,
+                         struct btrfs_root *root,
+                         struct extent_buffer *buf,
+                         u64 parent, int last_ref)
+{
+       return btrfs_free_extent(trans, root, buf->start, buf->len, parent,
+                                root->root_key.objectid,
+                                btrfs_header_level(buf), 0);
+}
+
 /*
  * remove an extent from the root, returns 0 on success
  */
index 3c7a246..f3a5126 100644 (file)
@@ -20,6 +20,7 @@
 #include "disk-io.h"
 #include "free-space-cache.h"
 #include "free-space-tree.h"
+#include "transaction.h"
 
 static struct btrfs_free_space_info *
 search_free_space_info(struct btrfs_trans_handle *trans,
@@ -67,6 +68,91 @@ static int free_space_test_bit(struct btrfs_block_group_cache *block_group,
        return !!extent_buffer_test_bit(leaf, ptr, i);
 }
 
+static int clear_free_space_tree(struct btrfs_trans_handle *trans,
+                                struct btrfs_root *root)
+{
+       struct btrfs_path *path;
+       struct btrfs_key key;
+       int nr;
+       int ret;
+
+       path = btrfs_alloc_path();
+       if (!path)
+               return -ENOMEM;
+
+       key.objectid = 0;
+       key.type = 0;
+       key.offset = 0;
+
+       while (1) {
+               ret = btrfs_search_slot(trans, root, &key, path, -1, 1);
+               if (ret < 0)
+                       goto out;
+
+               nr = btrfs_header_nritems(path->nodes[0]);
+               if (!nr)
+                       break;
+
+               path->slots[0] = 0;
+               ret = btrfs_del_items(trans, root, path, 0, nr);
+               if (ret)
+                       goto out;
+
+               btrfs_release_path(path);
+       }
+
+       ret = 0;
+out:
+       btrfs_free_path(path);
+       return ret;
+}
+
+int btrfs_clear_free_space_tree(struct btrfs_fs_info *fs_info)
+{
+       struct btrfs_trans_handle *trans;
+       struct btrfs_root *tree_root = fs_info->tree_root;
+       struct btrfs_root *free_space_root = fs_info->free_space_root;
+       int ret;
+       u64 features;
+
+       trans = btrfs_start_transaction(tree_root, 0);
+       if (IS_ERR(trans))
+               return PTR_ERR(trans);
+
+       features = btrfs_super_compat_ro_flags(fs_info->super_copy);
+       features &= ~(BTRFS_FEATURE_COMPAT_RO_FREE_SPACE_TREE_VALID |
+                     BTRFS_FEATURE_COMPAT_RO_FREE_SPACE_TREE);
+       btrfs_set_super_compat_ro_flags(fs_info->super_copy, features);
+       fs_info->free_space_root = NULL;
+
+       ret = clear_free_space_tree(trans, free_space_root);
+       if (ret)
+               goto abort;
+
+       ret = btrfs_del_root(trans, tree_root, &free_space_root->root_key);
+       if (ret)
+               goto abort;
+
+       list_del(&free_space_root->dirty_list);
+
+       ret = clean_tree_block(trans, tree_root, free_space_root->node);
+       if (ret)
+               goto abort;
+       ret = btrfs_free_tree_block(trans, free_space_root,
+                                   free_space_root->node, 0, 1);
+       if (ret)
+               goto abort;
+
+       free_extent_buffer(free_space_root->node);
+       free_extent_buffer(free_space_root->commit_root);
+       kfree(free_space_root);
+
+       ret = btrfs_commit_transaction(trans, tree_root);
+
+abort:
+       return ret;
+}
+
 static int load_free_space_bitmaps(struct btrfs_fs_info *fs_info,
                                   struct btrfs_block_group_cache *block_group,
                                   struct btrfs_path *path,
index 7529a46..4845f13 100644 (file)
@@ -19,6 +19,7 @@
 #ifndef __BTRFS_FREE_SPACE_TREE_H__
 #define __BTRFS_FREE_SPACE_TREE_H__
 
+int btrfs_clear_free_space_tree(struct btrfs_fs_info *fs_info);
 int load_free_space_tree(struct btrfs_fs_info *fs_info,
                         struct btrfs_block_group_cache *block_group);
 
index cca424e..ab01a14 100644 (file)
@@ -143,6 +143,31 @@ int btrfs_insert_root(struct btrfs_trans_handle *trans, struct btrfs_root
        return ret;
 }
 
+/* drop the root item for 'key' from 'root' */
+int btrfs_del_root(struct btrfs_trans_handle *trans, struct btrfs_root *root,
+                  struct btrfs_key *key)
+{
+       struct btrfs_path *path;
+       int ret;
+
+       path = btrfs_alloc_path();
+       if (!path)
+               return -ENOMEM;
+       ret = btrfs_search_slot(trans, root, key, path, -1, 1);
+       if (ret < 0)
+               goto out;
+
+       if (ret != 0) {
+               ret = -ENOENT;
+               goto out;
+       }
+
+       ret = btrfs_del_item(trans, root, path);
+out:
+       btrfs_free_path(path);
+       return ret;
+}
+
 /*
  * add a btrfs_root_ref item.  type is either BTRFS_ROOT_REF_KEY
  * or BTRFS_ROOT_BACKREF_KEY.