summaryrefslogtreecommitdiff
path: root/extent-tree.c
diff options
context:
space:
mode:
authorQu Wenruo <quwenruo@cn.fujitsu.com>2015-07-07 16:15:27 +0800
committerDavid Sterba <dsterba@suse.com>2015-07-10 14:39:39 +0200
commit80fc1e0fc61f0929fee545917127a0585dfdacf9 (patch)
tree3f85c3664bf595b1c92ddbc28c1b5ffad0ee9a88 /extent-tree.c
parent00827cad8e36a6f55d344c92a15fb4cd3c596378 (diff)
btrfs-progs: extent-tree: Introduce btrfs_free_block_group function
This function will be used to free a empty chunk. This provides the basis for later temp chunk cleanup. Signed-off-by: Qu Wenruo <quwenruo@cn.fujitsu.com> Signed-off-by: David Sterba <dsterba@suse.com>
Diffstat (limited to 'extent-tree.c')
-rw-r--r--extent-tree.c80
1 files changed, 80 insertions, 0 deletions
diff --git a/extent-tree.c b/extent-tree.c
index 07aee9e4..ac582e05 100644
--- a/extent-tree.c
+++ b/extent-tree.c
@@ -3743,6 +3743,86 @@ out:
return ret;
}
+int btrfs_free_block_group(struct btrfs_trans_handle *trans,
+ struct btrfs_fs_info *fs_info, u64 bytenr, u64 len)
+{
+ struct btrfs_root *extent_root = fs_info->extent_root;
+ struct btrfs_path *path;
+ struct btrfs_block_group_item *bgi;
+ struct btrfs_key key;
+ int ret = 0;
+
+ path = btrfs_alloc_path();
+ if (!path)
+ return -ENOMEM;
+
+ key.objectid = bytenr;
+ key.type = BTRFS_BLOCK_GROUP_ITEM_KEY;
+ key.offset = len;
+
+ /* Double check the block group to ensure it's empty */
+ ret = btrfs_search_slot(trans, extent_root, &key, path, 0, 0);
+ if (ret > 0) {
+ ret = -ENONET;
+ goto out;
+ }
+ if (ret < 0)
+ goto out;
+
+ bgi = btrfs_item_ptr(path->nodes[0], path->slots[0],
+ struct btrfs_block_group_item);
+ if (btrfs_disk_block_group_used(path->nodes[0], bgi)) {
+ fprintf(stderr,
+ "WARNING: block group [%llu,%llu) is not empty\n",
+ bytenr, bytenr + len);
+ ret = -EINVAL;
+ goto out;
+ }
+ btrfs_release_path(path);
+
+ /*
+ * Now pin all space in the block group, to prevent further transaction
+ * allocate space from it.
+ * Every operation needs a transaction must be in the range.
+ */
+ btrfs_pin_extent(fs_info, bytenr, len);
+
+ /* delete block group item and chunk item */
+ ret = free_block_group_item(trans, fs_info, bytenr, len);
+ if (ret < 0) {
+ fprintf(stderr,
+ "failed to free block group item for [%llu,%llu)\n",
+ bytenr, bytenr + len);
+ btrfs_unpin_extent(fs_info, bytenr, len);
+ goto out;
+ }
+
+ ret = free_chunk_dev_extent_items(trans, fs_info, bytenr);
+ if (ret < 0) {
+ fprintf(stderr,
+ "failed to dev extents belongs to [%llu,%llu)\n",
+ bytenr, bytenr + len);
+ btrfs_unpin_extent(fs_info, bytenr, len);
+ goto out;
+ }
+ ret = free_chunk_item(trans, fs_info, bytenr, len);
+ if (ret < 0) {
+ fprintf(stderr,
+ "failed to free chunk for [%llu,%llu)\n",
+ bytenr, bytenr + len);
+ btrfs_unpin_extent(fs_info, bytenr, len);
+ goto out;
+ }
+
+ /* Now release the block_group_cache */
+ ret = free_block_group_cache(trans, fs_info, bytenr, len);
+ btrfs_unpin_extent(fs_info, bytenr, len);
+
+out:
+ btrfs_free_path(path);
+ return ret;
+}
+
/*
* Fixup block accounting. The initial block accounting created by
* make_block_groups isn't accuracy in this case.