btrfs-progs: Pull free space tree related code from kernel

To help implement free space tree checker in user space some kernel
function are necessary, namely iterating/deleting/adding freespace
items, some internal search functions. Functions to populate a block
group based on the extent tree. The code is largely copy/paste from
the kernel with locking eliminated (i.e free_space_lock). It supports
reading/writing of both bitmap and extent based FST trees.

Signed-off-by: Nikolay Borisov <nborisov@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
master
Nikolay Borisov 2018-10-01 17:46:16 +03:00 committed by David Sterba
parent a9ce9286f2
commit 8c028efe4a
5 changed files with 1350 additions and 6 deletions

74
ctree.c
View File

@ -1225,6 +1225,80 @@ again:
return 1;
}
/*
* Helper to use instead of search slot if no exact match is needed but
* instead the next or previous item should be returned.
* When find_higher is true, the next higher item is returned, the next lower
* otherwise.
* When return_any and find_higher are both true, and no higher item is found,
* return the next lower instead.
* When return_any is true and find_higher is false, and no lower item is found,
* return the next higher instead.
* It returns 0 if any item is found, 1 if none is found (tree empty), and
* < 0 on error
*/
int btrfs_search_slot_for_read(struct btrfs_root *root,
const struct btrfs_key *key,
struct btrfs_path *p, int find_higher,
int return_any)
{
int ret;
struct extent_buffer *leaf;
again:
ret = btrfs_search_slot(NULL, root, key, p, 0, 0);
if (ret <= 0)
return ret;
/*
* A return value of 1 means the path is at the position where the item
* should be inserted. Normally this is the next bigger item, but in
* case the previous item is the last in a leaf, path points to the
* first free slot in the previous leaf, i.e. at an invalid item.
*/
leaf = p->nodes[0];
if (find_higher) {
if (p->slots[0] >= btrfs_header_nritems(leaf)) {
ret = btrfs_next_leaf(root, p);
if (ret <= 0)
return ret;
if (!return_any)
return 1;
/*
* No higher item found, return the next lower instead
*/
return_any = 0;
find_higher = 0;
btrfs_release_path(p);
goto again;
}
} else {
if (p->slots[0] == 0) {
ret = btrfs_prev_leaf(root, p);
if (ret < 0)
return ret;
if (!ret) {
leaf = p->nodes[0];
if (p->slots[0] == btrfs_header_nritems(leaf))
p->slots[0]--;
return 0;
}
if (!return_any)
return 1;
/*
* No lower item found, return the next higher instead
*/
return_any = 0;
find_higher = 1;
btrfs_release_path(p);
goto again;
} else {
--p->slots[0];
}
}
return 0;
}
/*
* adjust the pointers going up the tree, starting at level
* making sure the right key of each node is points to 'key'.

15
ctree.h
View File

@ -1071,6 +1071,17 @@ struct btrfs_block_group_cache {
u64 flags;
int cached;
int ro;
/*
* If the free space extent count exceeds this number, convert the block
* group to bitmaps.
*/
u32 bitmap_high_thresh;
/*
* If the free space extent count drops below this number, convert the
* block group back to extents.
*/
u32 bitmap_low_thresh;
};
struct btrfs_device;
@ -2596,6 +2607,10 @@ int btrfs_split_item(struct btrfs_trans_handle *trans,
int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root
*root, struct btrfs_key *key, struct btrfs_path *p, int
ins_len, int cow);
int btrfs_search_slot_for_read(struct btrfs_root *root,
const struct btrfs_key *key,
struct btrfs_path *p, int find_higher,
int return_any);
int btrfs_find_item(struct btrfs_root *fs_root, struct btrfs_path *found_path,
u64 iobjectid, u64 ioff, u8 key_type,
struct btrfs_key *found_key);

File diff suppressed because it is too large Load Diff

View File

@ -19,8 +19,20 @@
#ifndef __BTRFS_FREE_SPACE_TREE_H__
#define __BTRFS_FREE_SPACE_TREE_H__
#define BTRFS_FREE_SPACE_BITMAP_SIZE 256
#define BTRFS_FREE_SPACE_BITMAP_BITS (BTRFS_FREE_SPACE_BITMAP_SIZE * BITS_PER_BYTE)
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);
int populate_free_space_tree(struct btrfs_trans_handle *trans,
struct btrfs_block_group_cache *block_group);
int remove_block_group_free_space(struct btrfs_trans_handle *trans,
struct btrfs_block_group_cache *block_group);
int add_to_free_space_tree(struct btrfs_trans_handle *trans, u64 start,
u64 size);
int remove_from_free_space_tree(struct btrfs_trans_handle *trans, u64 start,
u64 size);
int btrfs_create_free_space_tree(struct btrfs_fs_info *info);
#endif

View File

@ -263,6 +263,8 @@ static inline int IS_ERR_OR_NULL(const void *ptr)
return !ptr || IS_ERR(ptr);
}
#define div_u64(x, y) ((x) / (y))
/**
* swap - swap values of @a and @b
* @a: first value
@ -297,6 +299,10 @@ static inline int IS_ERR_OR_NULL(const void *ptr)
#define kfree(x) free(x)
#define vmalloc(x) malloc(x)
#define vfree(x) free(x)
#define kvzalloc(x, y) kzalloc(x,y)
#define kvfree(x) free(x)
#define memalloc_nofs_save() (0)
#define memalloc_nofs_restore(x) ((void)(x))
#ifndef BTRFS_DISABLE_BACKTRACE
static inline void assert_trace(const char *assertion, const char *filename,