btrfs-progs: tests: Test if mkfs.btrfs --rootdir can handle ng symlink
[platform/upstream/btrfs-progs.git] / free-space-tree.c
index a323e8a..69a4eca 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,
@@ -102,13 +188,15 @@ static int load_free_space_bitmaps(struct btrfs_fs_info *fs_info,
                        break;
                }
                if (key.objectid >= end) {
-                       fprintf(stderr, "free space bitmap starts at %Lu, beyond end of block group %Lu-%Lu\n",
+                       fprintf(stderr,
+       "free space bitmap starts at %llu, beyond end of block group %llu-%llu\n",
                                key.objectid, start, end);
                        (*errors)++;
                        break;
                }
                if (key.objectid + key.offset > end) {
-                       fprintf(stderr, "free space bitmap ends at %Lu, beyond end of block group %Lu-%Lu\n",
+                       fprintf(stderr,
+       "free space bitmap ends at %llu, beyond end of block group %llu-%llu\n",
                                key.objectid, start, end);
                        (*errors)++;
                        break;
@@ -117,7 +205,7 @@ static int load_free_space_bitmaps(struct btrfs_fs_info *fs_info,
                offset = key.objectid;
                while (offset < key.objectid + key.offset) {
                        bit = free_space_test_bit(block_group, path, offset,
-                                                 root->sectorsize);
+                                                 fs_info->sectorsize);
                        if (prev_bit == 0 && bit == 1) {
                                extent_start = offset;
                        } else if (prev_bit == 1 && bit == 0) {
@@ -125,7 +213,7 @@ static int load_free_space_bitmaps(struct btrfs_fs_info *fs_info,
                                extent_count++;
                        }
                        prev_bit = bit;
-                       offset += root->sectorsize;
+                       offset += fs_info->sectorsize;
                }
        }
 
@@ -179,13 +267,15 @@ static int load_free_space_extents(struct btrfs_fs_info *fs_info,
                        break;
                }
                if (key.objectid >= end) {
-                       fprintf(stderr, "free space extent starts at %Lu, beyond end of block group %Lu-%Lu\n",
+                       fprintf(stderr,
+       "free space extent starts at %llu, beyond end of block group %llu-%llu\n",
                                key.objectid, start, end);
                        (*errors)++;
                        break;
                }
                if (key.objectid + key.offset > end) {
-                       fprintf(stderr, "free space extent ends at %Lu, beyond end of block group %Lu-%Lu\n",
+                       fprintf(stderr,
+       "free space extent ends at %llu, beyond end of block group %llu-%llu\n",
                                key.objectid, start, end);
                        (*errors)++;
                        break;
@@ -198,12 +288,14 @@ static int load_free_space_extents(struct btrfs_fs_info *fs_info,
                        u64 prev_end = prev_start + prev_key.offset;
 
                        if (cur_start < prev_end) {
-                               fprintf(stderr, "free space extent %Lu-%Lu overlaps with previous %Lu-%Lu\n",
+                               fprintf(stderr,
+       "free space extent %llu-%llu overlaps with previous %llu-%llu\n",
                                        cur_start, cur_end,
                                        prev_start, prev_end);
                                (*errors)++;
                        } else if (cur_start == prev_end) {
-                               fprintf(stderr, "free space extent %Lu-%Lu is unmerged with previous %Lu-%Lu\n",
+                               fprintf(stderr,
+       "free space extent %llu-%llu is unmerged with previous %llu-%llu\n",
                                        cur_start, cur_end,
                                        prev_start, prev_end);
                                (*errors)++;