mirror of
https://github.com/kdave/btrfs-progs
synced 2025-04-24 20:17:57 +00:00
btrfs-progs: check: switch to iterating over the backref_tree
We now have two data structures that can be used to iterate the same data set, and there may be quite a few of them in memory. Eliminating the list_head member will reduce memory consumption while iterating over the extent backrefs. Signed-off-by: Jeff Mahoney <jeffm@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
parent
756105181e
commit
ad39e6252b
81
cmds-check.c
81
cmds-check.c
@ -85,7 +85,6 @@ enum btrfs_check_mode {
|
|||||||
static enum btrfs_check_mode check_mode = CHECK_MODE_DEFAULT;
|
static enum btrfs_check_mode check_mode = CHECK_MODE_DEFAULT;
|
||||||
|
|
||||||
struct extent_backref {
|
struct extent_backref {
|
||||||
struct list_head list;
|
|
||||||
struct rb_node node;
|
struct rb_node node;
|
||||||
unsigned int is_data:1;
|
unsigned int is_data:1;
|
||||||
unsigned int found_extent_tree:1;
|
unsigned int found_extent_tree:1;
|
||||||
@ -94,11 +93,6 @@ struct extent_backref {
|
|||||||
unsigned int broken:1;
|
unsigned int broken:1;
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline struct extent_backref* to_extent_backref(struct list_head *entry)
|
|
||||||
{
|
|
||||||
return list_entry(entry, struct extent_backref, list);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline struct extent_backref* rb_node_to_extent_backref(struct rb_node *node)
|
static inline struct extent_backref* rb_node_to_extent_backref(struct rb_node *node)
|
||||||
{
|
{
|
||||||
return rb_entry(node, struct extent_backref, node);
|
return rb_entry(node, struct extent_backref, node);
|
||||||
@ -5483,16 +5477,14 @@ static int do_check_fs_roots(struct btrfs_fs_info *fs_info,
|
|||||||
|
|
||||||
static int all_backpointers_checked(struct extent_record *rec, int print_errs)
|
static int all_backpointers_checked(struct extent_record *rec, int print_errs)
|
||||||
{
|
{
|
||||||
struct list_head *cur = rec->backrefs.next;
|
struct extent_backref *back, *tmp;
|
||||||
struct extent_backref *back;
|
|
||||||
struct tree_backref *tback;
|
struct tree_backref *tback;
|
||||||
struct data_backref *dback;
|
struct data_backref *dback;
|
||||||
u64 found = 0;
|
u64 found = 0;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
|
||||||
while(cur != &rec->backrefs) {
|
rbtree_postorder_for_each_entry_safe(back, tmp,
|
||||||
back = to_extent_backref(cur);
|
&rec->backref_tree, node) {
|
||||||
cur = cur->next;
|
|
||||||
if (!back->found_extent_tree) {
|
if (!back->found_extent_tree) {
|
||||||
err = 1;
|
err = 1;
|
||||||
if (!print_errs)
|
if (!print_errs)
|
||||||
@ -5595,17 +5587,16 @@ out:
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int free_all_extent_backrefs(struct extent_record *rec)
|
static void __free_one_backref(struct rb_node *node)
|
||||||
{
|
{
|
||||||
struct extent_backref *back;
|
struct extent_backref *back = rb_node_to_extent_backref(node);
|
||||||
struct list_head *cur;
|
|
||||||
while (!list_empty(&rec->backrefs)) {
|
|
||||||
cur = rec->backrefs.next;
|
|
||||||
back = to_extent_backref(cur);
|
|
||||||
list_del(cur);
|
|
||||||
free(back);
|
free(back);
|
||||||
}
|
}
|
||||||
return 0;
|
|
||||||
|
static void free_all_extent_backrefs(struct extent_record *rec)
|
||||||
|
{
|
||||||
|
rb_free_nodes(&rec->backref_tree, __free_one_backref);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void free_extent_record_cache(struct cache_tree *extent_cache)
|
static void free_extent_record_cache(struct cache_tree *extent_cache)
|
||||||
@ -5644,7 +5635,7 @@ static int check_owner_ref(struct btrfs_root *root,
|
|||||||
struct extent_record *rec,
|
struct extent_record *rec,
|
||||||
struct extent_buffer *buf)
|
struct extent_buffer *buf)
|
||||||
{
|
{
|
||||||
struct extent_backref *node;
|
struct extent_backref *node, *tmp;
|
||||||
struct tree_backref *back;
|
struct tree_backref *back;
|
||||||
struct btrfs_root *ref_root;
|
struct btrfs_root *ref_root;
|
||||||
struct btrfs_key key;
|
struct btrfs_key key;
|
||||||
@ -5654,7 +5645,8 @@ static int check_owner_ref(struct btrfs_root *root,
|
|||||||
int found = 0;
|
int found = 0;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
list_for_each_entry(node, &rec->backrefs, list) {
|
rbtree_postorder_for_each_entry_safe(node, tmp,
|
||||||
|
&rec->backref_tree, node) {
|
||||||
if (node->is_data)
|
if (node->is_data)
|
||||||
continue;
|
continue;
|
||||||
if (!node->found_ref)
|
if (!node->found_ref)
|
||||||
@ -5699,14 +5691,12 @@ static int check_owner_ref(struct btrfs_root *root,
|
|||||||
|
|
||||||
static int is_extent_tree_record(struct extent_record *rec)
|
static int is_extent_tree_record(struct extent_record *rec)
|
||||||
{
|
{
|
||||||
struct list_head *cur = rec->backrefs.next;
|
struct extent_backref *node, *tmp;
|
||||||
struct extent_backref *node;
|
|
||||||
struct tree_backref *back;
|
struct tree_backref *back;
|
||||||
int is_extent = 0;
|
int is_extent = 0;
|
||||||
|
|
||||||
while(cur != &rec->backrefs) {
|
rbtree_postorder_for_each_entry_safe(node, tmp,
|
||||||
node = to_extent_backref(cur);
|
&rec->backref_tree, node) {
|
||||||
cur = cur->next;
|
|
||||||
if (node->is_data)
|
if (node->is_data)
|
||||||
return 0;
|
return 0;
|
||||||
back = to_tree_backref(node);
|
back = to_tree_backref(node);
|
||||||
@ -6116,7 +6106,6 @@ static struct tree_backref *alloc_tree_backref(struct extent_record *rec,
|
|||||||
ref->root = root;
|
ref->root = root;
|
||||||
ref->node.full_backref = 0;
|
ref->node.full_backref = 0;
|
||||||
}
|
}
|
||||||
list_add_tail(&ref->node.list, &rec->backrefs);
|
|
||||||
|
|
||||||
return ref;
|
return ref;
|
||||||
}
|
}
|
||||||
@ -6186,7 +6175,6 @@ static struct data_backref *alloc_data_backref(struct extent_record *rec,
|
|||||||
ref->bytes = max_size;
|
ref->bytes = max_size;
|
||||||
ref->found_ref = 0;
|
ref->found_ref = 0;
|
||||||
ref->num_refs = 0;
|
ref->num_refs = 0;
|
||||||
list_add_tail(&ref->node.list, &rec->backrefs);
|
|
||||||
if (max_size > rec->max_size)
|
if (max_size > rec->max_size)
|
||||||
rec->max_size = max_size;
|
rec->max_size = max_size;
|
||||||
return ref;
|
return ref;
|
||||||
@ -6219,12 +6207,12 @@ static void check_extent_type(struct extent_record *rec)
|
|||||||
* Check SYSTEM extent, as it's also marked as metadata, we can only
|
* Check SYSTEM extent, as it's also marked as metadata, we can only
|
||||||
* make sure it's a SYSTEM extent by its backref
|
* make sure it's a SYSTEM extent by its backref
|
||||||
*/
|
*/
|
||||||
if (!list_empty(&rec->backrefs)) {
|
if (!RB_EMPTY_ROOT(&rec->backref_tree)) {
|
||||||
struct extent_backref *node;
|
struct extent_backref *node;
|
||||||
struct tree_backref *tback;
|
struct tree_backref *tback;
|
||||||
u64 bg_type;
|
u64 bg_type;
|
||||||
|
|
||||||
node = to_extent_backref(rec->backrefs.next);
|
node = rb_node_to_extent_backref(rb_first(&rec->backref_tree));
|
||||||
if (node->is_data) {
|
if (node->is_data) {
|
||||||
/* tree block shouldn't have data backref */
|
/* tree block shouldn't have data backref */
|
||||||
rec->wrong_chunk_type = 1;
|
rec->wrong_chunk_type = 1;
|
||||||
@ -8217,7 +8205,7 @@ static int free_extent_hook(struct btrfs_trans_handle *trans,
|
|||||||
back->node.found_extent_tree = 0;
|
back->node.found_extent_tree = 0;
|
||||||
|
|
||||||
if (!back->node.found_extent_tree && back->node.found_ref) {
|
if (!back->node.found_extent_tree && back->node.found_ref) {
|
||||||
list_del(&back->node.list);
|
rb_erase(&back->node.node, &rec->backref_tree);
|
||||||
free(back);
|
free(back);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -8236,7 +8224,7 @@ static int free_extent_hook(struct btrfs_trans_handle *trans,
|
|||||||
back->node.found_extent_tree = 0;
|
back->node.found_extent_tree = 0;
|
||||||
}
|
}
|
||||||
if (!back->node.found_extent_tree && back->node.found_ref) {
|
if (!back->node.found_extent_tree && back->node.found_ref) {
|
||||||
list_del(&back->node.list);
|
rb_erase(&back->node.node, &rec->backref_tree);
|
||||||
free(back);
|
free(back);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -8677,7 +8665,7 @@ out:
|
|||||||
static int verify_backrefs(struct btrfs_fs_info *info, struct btrfs_path *path,
|
static int verify_backrefs(struct btrfs_fs_info *info, struct btrfs_path *path,
|
||||||
struct extent_record *rec)
|
struct extent_record *rec)
|
||||||
{
|
{
|
||||||
struct extent_backref *back;
|
struct extent_backref *back, *tmp;
|
||||||
struct data_backref *dback;
|
struct data_backref *dback;
|
||||||
struct extent_entry *entry, *best = NULL;
|
struct extent_entry *entry, *best = NULL;
|
||||||
LIST_HEAD(entries);
|
LIST_HEAD(entries);
|
||||||
@ -8693,7 +8681,8 @@ static int verify_backrefs(struct btrfs_fs_info *info, struct btrfs_path *path,
|
|||||||
if (rec->metadata)
|
if (rec->metadata)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
list_for_each_entry(back, &rec->backrefs, list) {
|
rbtree_postorder_for_each_entry_safe(back, tmp,
|
||||||
|
&rec->backref_tree, node) {
|
||||||
if (back->full_backref || !back->is_data)
|
if (back->full_backref || !back->is_data)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@ -8819,7 +8808,8 @@ static int verify_backrefs(struct btrfs_fs_info *info, struct btrfs_path *path,
|
|||||||
* Ok great we all agreed on an extent record, let's go find the real
|
* Ok great we all agreed on an extent record, let's go find the real
|
||||||
* references and fix up the ones that don't match.
|
* references and fix up the ones that don't match.
|
||||||
*/
|
*/
|
||||||
list_for_each_entry(back, &rec->backrefs, list) {
|
rbtree_postorder_for_each_entry_safe(back, tmp,
|
||||||
|
&rec->backref_tree, node) {
|
||||||
if (back->full_backref || !back->is_data)
|
if (back->full_backref || !back->is_data)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@ -9043,7 +9033,7 @@ static int find_possible_backrefs(struct btrfs_fs_info *info,
|
|||||||
struct extent_record *rec)
|
struct extent_record *rec)
|
||||||
{
|
{
|
||||||
struct btrfs_root *root;
|
struct btrfs_root *root;
|
||||||
struct extent_backref *back;
|
struct extent_backref *back, *tmp;
|
||||||
struct data_backref *dback;
|
struct data_backref *dback;
|
||||||
struct cache_extent *cache;
|
struct cache_extent *cache;
|
||||||
struct btrfs_file_extent_item *fi;
|
struct btrfs_file_extent_item *fi;
|
||||||
@ -9051,7 +9041,8 @@ static int find_possible_backrefs(struct btrfs_fs_info *info,
|
|||||||
u64 bytenr, bytes;
|
u64 bytenr, bytes;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
list_for_each_entry(back, &rec->backrefs, list) {
|
rbtree_postorder_for_each_entry_safe(back, tmp,
|
||||||
|
&rec->backref_tree, node) {
|
||||||
/* Don't care about full backrefs (poor unloved backrefs) */
|
/* Don't care about full backrefs (poor unloved backrefs) */
|
||||||
if (back->full_backref || !back->is_data)
|
if (back->full_backref || !back->is_data)
|
||||||
continue;
|
continue;
|
||||||
@ -9139,7 +9130,7 @@ static int record_orphan_data_extents(struct btrfs_fs_info *fs_info,
|
|||||||
{
|
{
|
||||||
struct btrfs_key key;
|
struct btrfs_key key;
|
||||||
struct btrfs_root *dest_root;
|
struct btrfs_root *dest_root;
|
||||||
struct extent_backref *back;
|
struct extent_backref *back, *tmp;
|
||||||
struct data_backref *dback;
|
struct data_backref *dback;
|
||||||
struct orphan_data_extent *orphan;
|
struct orphan_data_extent *orphan;
|
||||||
struct btrfs_path path;
|
struct btrfs_path path;
|
||||||
@ -9149,7 +9140,8 @@ static int record_orphan_data_extents(struct btrfs_fs_info *fs_info,
|
|||||||
if (rec->metadata)
|
if (rec->metadata)
|
||||||
return 1;
|
return 1;
|
||||||
btrfs_init_path(&path);
|
btrfs_init_path(&path);
|
||||||
list_for_each_entry(back, &rec->backrefs, list) {
|
rbtree_postorder_for_each_entry_safe(back, tmp,
|
||||||
|
&rec->backref_tree, node) {
|
||||||
if (back->full_backref || !back->is_data ||
|
if (back->full_backref || !back->is_data ||
|
||||||
!back->found_extent_tree)
|
!back->found_extent_tree)
|
||||||
continue;
|
continue;
|
||||||
@ -9217,9 +9209,8 @@ static int fixup_extent_refs(struct btrfs_fs_info *info,
|
|||||||
struct btrfs_trans_handle *trans = NULL;
|
struct btrfs_trans_handle *trans = NULL;
|
||||||
int ret;
|
int ret;
|
||||||
struct btrfs_path path;
|
struct btrfs_path path;
|
||||||
struct list_head *cur = rec->backrefs.next;
|
|
||||||
struct cache_extent *cache;
|
struct cache_extent *cache;
|
||||||
struct extent_backref *back;
|
struct extent_backref *back, *tmp;
|
||||||
int allocated = 0;
|
int allocated = 0;
|
||||||
u64 flags = 0;
|
u64 flags = 0;
|
||||||
|
|
||||||
@ -9267,10 +9258,8 @@ static int fixup_extent_refs(struct btrfs_fs_info *info,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* step three, recreate all the refs we did find */
|
/* step three, recreate all the refs we did find */
|
||||||
while(cur != &rec->backrefs) {
|
rbtree_postorder_for_each_entry_safe(back, tmp,
|
||||||
back = to_extent_backref(cur);
|
&rec->backref_tree, node) {
|
||||||
cur = cur->next;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* if we didn't find any references, don't create a
|
* if we didn't find any references, don't create a
|
||||||
* new extent record
|
* new extent record
|
||||||
|
Loading…
Reference in New Issue
Block a user