From d8c537e71f3dce8a8d03dddfcbcac71ef2e2cdc4 Mon Sep 17 00:00:00 2001 From: Omar Sandoval Date: Tue, 29 Sep 2015 20:51:44 -0700 Subject: [PATCH] btrfs-progs: add basic awareness of the free space tree To start, let's tell btrfs-progs to read the free space root and how to print the on-disk format of the free space tree. However, we're not adding the FREE_SPACE_TREE read-only compat bit to the set of supported bits because progs doesn't know how to keep the free space tree consistent. Signed-off-by: Omar Sandoval Signed-off-by: David Sterba --- btrfs-debug-tree.c | 4 ++++ ctree.h | 49 ++++++++++++++++++++++++++++++++++++++++++++++++- disk-io.c | 16 +++++++++++++++- print-tree.c | 25 +++++++++++++++++++++++++ 4 files changed, 92 insertions(+), 2 deletions(-) diff --git a/btrfs-debug-tree.c b/btrfs-debug-tree.c index 8adc39f..72dd787 100644 --- a/btrfs-debug-tree.c +++ b/btrfs-debug-tree.c @@ -376,6 +376,10 @@ again: if (!skip) printf("uuid"); break; + case BTRFS_FREE_SPACE_TREE_OBJECTID: + if (!skip) + printf("free space"); + break; case BTRFS_MULTIPLE_OBJECTIDS: if (!skip) { printf("multiple"); diff --git a/ctree.h b/ctree.h index c57f9ca..a37f3d1 100644 --- a/ctree.h +++ b/ctree.h @@ -76,6 +76,9 @@ struct btrfs_free_space_ctl; /* for storing items that use the BTRFS_UUID_KEY* */ #define BTRFS_UUID_TREE_OBJECTID 9ULL +/* tracks free space in block groups. */ +#define BTRFS_FREE_SPACE_TREE_OBJECTID 10ULL + /* for storing balance parameters in the root tree */ #define BTRFS_BALANCE_OBJECTID -4ULL @@ -453,6 +456,8 @@ struct btrfs_super_block { * Compat flags that we support. If any incompat flags are set other than the * ones specified below then we will fail to mount */ +#define BTRFS_FEATURE_COMPAT_RO_FREE_SPACE_TREE (1ULL << 0) + #define BTRFS_FEATURE_INCOMPAT_MIXED_BACKREF (1ULL << 0) #define BTRFS_FEATURE_INCOMPAT_DEFAULT_SUBVOL (1ULL << 1) #define BTRFS_FEATURE_INCOMPAT_MIXED_GROUPS (1ULL << 2) @@ -476,9 +481,10 @@ struct btrfs_super_block { #define BTRFS_FEATURE_INCOMPAT_SKINNY_METADATA (1ULL << 8) #define BTRFS_FEATURE_INCOMPAT_NO_HOLES (1ULL << 9) - #define BTRFS_FEATURE_COMPAT_SUPP 0ULL + #define BTRFS_FEATURE_COMPAT_RO_SUPP 0ULL + #define BTRFS_FEATURE_INCOMPAT_SUPP \ (BTRFS_FEATURE_INCOMPAT_MIXED_BACKREF | \ BTRFS_FEATURE_INCOMPAT_DEFAULT_SUBVOL | \ @@ -898,6 +904,13 @@ struct btrfs_block_group_item { __le64 flags; } __attribute__ ((__packed__)); +struct btrfs_free_space_info { + __le32 extent_count; + __le32 flags; +} __attribute__ ((__packed__)); + +#define BTRFS_FREE_SPACE_USING_BITMAPS (1ULL << 0) + struct btrfs_qgroup_info_item { __le64 generation; __le64 referenced; @@ -965,6 +978,7 @@ struct btrfs_fs_info { struct btrfs_root *dev_root; struct btrfs_root *csum_root; struct btrfs_root *quota_root; + struct btrfs_root *free_space_root; struct rb_root fs_root_tree; @@ -1157,6 +1171,27 @@ struct btrfs_root { */ #define BTRFS_BLOCK_GROUP_ITEM_KEY 192 +/* + * Every block group is represented in the free space tree by a free space info + * item, which stores some accounting information. It is keyed on + * (block_group_start, FREE_SPACE_INFO, block_group_length). + */ +#define BTRFS_FREE_SPACE_INFO_KEY 198 + +/* + * A free space extent tracks an extent of space that is free in a block group. + * It is keyed on (start, FREE_SPACE_EXTENT, length). + */ +#define BTRFS_FREE_SPACE_EXTENT_KEY 199 + +/* + * When a block group becomes very fragmented, we convert it to use bitmaps + * instead of extents. A free space bitmap is keyed on + * (start, FREE_SPACE_BITMAP, length); the corresponding item is a bitmap with + * (length / sectorsize) bits. + */ +#define BTRFS_FREE_SPACE_BITMAP_KEY 200 + #define BTRFS_DEV_EXTENT_KEY 204 #define BTRFS_DEV_ITEM_KEY 216 #define BTRFS_CHUNK_ITEM_KEY 228 @@ -1394,6 +1429,11 @@ BTRFS_SETGET_FUNCS(disk_block_group_flags, BTRFS_SETGET_STACK_FUNCS(block_group_flags, struct btrfs_block_group_item, flags, 64); +/* struct btrfs_free_space_info */ +BTRFS_SETGET_FUNCS(free_space_extent_count, struct btrfs_free_space_info, + extent_count, 32); +BTRFS_SETGET_FUNCS(free_space_flags, struct btrfs_free_space_info, flags, 32); + /* struct btrfs_inode_ref */ BTRFS_SETGET_FUNCS(inode_ref_name_len, struct btrfs_inode_ref, name_len, 16); BTRFS_SETGET_STACK_FUNCS(stack_inode_ref_name_len, struct btrfs_inode_ref, name_len, 16); @@ -2193,6 +2233,13 @@ static inline int btrfs_fs_incompat(struct btrfs_fs_info *fs_info, u64 flag) return !!(btrfs_super_incompat_flags(disk_super) & flag); } +static inline int btrfs_fs_compat_ro(struct btrfs_fs_info *fs_info, u64 flag) +{ + struct btrfs_super_block *disk_super; + disk_super = fs_info->super_copy; + return !!(btrfs_super_compat_ro_flags(disk_super) & flag); +} + /* helper function to cast into the data area of the leaf. */ #define btrfs_item_ptr(leaf, slot, type) \ ((type *)(btrfs_leaf_data(leaf) + \ diff --git a/disk-io.c b/disk-io.c index 83bdb27..bd0444b 100644 --- a/disk-io.c +++ b/disk-io.c @@ -811,6 +811,7 @@ void btrfs_free_fs_info(struct btrfs_fs_info *fs_info) free(fs_info->dev_root); free(fs_info->csum_root); free(fs_info->quota_root); + free(fs_info->free_space_root); free(fs_info->super_copy); free(fs_info->log_root_tree); free(fs_info); @@ -830,12 +831,13 @@ struct btrfs_fs_info *btrfs_new_fs_info(int writable, u64 sb_bytenr) fs_info->dev_root = calloc(1, sizeof(struct btrfs_root)); fs_info->csum_root = calloc(1, sizeof(struct btrfs_root)); fs_info->quota_root = calloc(1, sizeof(struct btrfs_root)); + fs_info->free_space_root = calloc(1, sizeof(struct btrfs_root)); fs_info->super_copy = calloc(1, BTRFS_SUPER_INFO_SIZE); if (!fs_info->tree_root || !fs_info->extent_root || !fs_info->chunk_root || !fs_info->dev_root || !fs_info->csum_root || !fs_info->quota_root || - !fs_info->super_copy) + !fs_info->free_space_root || !fs_info->super_copy) goto free_all; extent_io_tree_init(&fs_info->extent_cache); @@ -1016,6 +1018,16 @@ int btrfs_setup_all_roots(struct btrfs_fs_info *fs_info, u64 root_tree_bytenr, if (ret == 0) fs_info->quota_enabled = 1; + if (btrfs_fs_compat_ro(fs_info, BTRFS_FEATURE_COMPAT_RO_FREE_SPACE_TREE)) { + ret = find_and_setup_root(root, fs_info, BTRFS_FREE_SPACE_TREE_OBJECTID, + fs_info->free_space_root); + if (ret) { + printk("Couldn't read free space tree\n"); + return -EIO; + } + fs_info->free_space_root->track_dirty = 1; + } + ret = find_and_setup_log_root(root, fs_info, sb); if (ret) { printk("Couldn't setup log root tree\n"); @@ -1041,6 +1053,8 @@ int btrfs_setup_all_roots(struct btrfs_fs_info *fs_info, u64 root_tree_bytenr, void btrfs_release_all_roots(struct btrfs_fs_info *fs_info) { + if (fs_info->free_space_root) + free_extent_buffer(fs_info->free_space_root->node); if (fs_info->quota_root) free_extent_buffer(fs_info->quota_root->node); if (fs_info->csum_root) diff --git a/print-tree.c b/print-tree.c index 4d4c3a2..6704ff6 100644 --- a/print-tree.c +++ b/print-tree.c @@ -619,6 +619,15 @@ static void print_key_type(u64 objectid, u8 type) case BTRFS_BLOCK_GROUP_ITEM_KEY: printf("BLOCK_GROUP_ITEM"); break; + case BTRFS_FREE_SPACE_INFO_KEY: + printf("FREE_SPACE_INFO"); + break; + case BTRFS_FREE_SPACE_EXTENT_KEY: + printf("FREE_SPACE_EXTENT"); + break; + case BTRFS_FREE_SPACE_BITMAP_KEY: + printf("FREE_SPACE_BITMAP"); + break; case BTRFS_CHUNK_ITEM_KEY: printf("CHUNK_ITEM"); break; @@ -737,6 +746,9 @@ static void print_objectid(u64 objectid, u8 type) case BTRFS_UUID_TREE_OBJECTID: printf("UUID_TREE"); break; + case BTRFS_FREE_SPACE_TREE_OBJECTID: + printf("FREE_SPACE_TREE"); + break; case BTRFS_MULTIPLE_OBJECTIDS: printf("MULTIPLE"); break; @@ -819,6 +831,7 @@ void btrfs_print_leaf(struct btrfs_root *root, struct extent_buffer *l) struct btrfs_dev_extent *dev_extent; struct btrfs_disk_key disk_key; struct btrfs_block_group_item bg_item; + struct btrfs_free_space_info *free_info; struct btrfs_dir_log_item *dlog; struct btrfs_qgroup_info_item *qg_info; struct btrfs_qgroup_limit_item *qg_limit; @@ -956,6 +969,18 @@ void btrfs_print_leaf(struct btrfs_root *root, struct extent_buffer *l) (unsigned long long)btrfs_block_group_chunk_objectid(&bg_item), flags_str); break; + case BTRFS_FREE_SPACE_INFO_KEY: + free_info = btrfs_item_ptr(l, i, struct btrfs_free_space_info); + printf("\t\tfree space info extent count %u flags %u\n", + (unsigned)btrfs_free_space_extent_count(l, free_info), + (unsigned)btrfs_free_space_flags(l, free_info)); + break; + case BTRFS_FREE_SPACE_EXTENT_KEY: + printf("\t\tfree space extent\n"); + break; + case BTRFS_FREE_SPACE_BITMAP_KEY: + printf("\t\tfree space bitmap\n"); + break; case BTRFS_CHUNK_ITEM_KEY: print_chunk(l, btrfs_item_ptr(l, i, struct btrfs_chunk)); break; -- 2.7.4