struct extent_backref {
struct list_head list;
- struct rb_node node;
unsigned int is_data:1;
unsigned int found_extent_tree:1;
unsigned int full_backref:1;
return list_entry(entry, struct extent_backref, list);
}
-static inline struct extent_backref* rb_node_to_extent_backref(struct rb_node *node)
-{
- return rb_entry(node, struct extent_backref, node);
-}
-
struct data_backref {
struct extent_backref node;
union {
return container_of(back, struct data_backref, node);
}
-static int compare_data_backref(struct rb_node *node1, struct rb_node *node2)
-{
- struct extent_backref *ext1 = rb_node_to_extent_backref(node1);
- struct extent_backref *ext2 = rb_node_to_extent_backref(node2);
- struct data_backref *back1 = to_data_backref(ext1);
- struct data_backref *back2 = to_data_backref(ext2);
-
- WARN_ON(!ext1->is_data);
- WARN_ON(!ext2->is_data);
-
- /* parent and root are a union, so this covers both */
- if (back1->parent > back2->parent)
- return 1;
- if (back1->parent < back2->parent)
- return -1;
-
- /* This is a full backref and the parents match. */
- if (back1->node.full_backref)
- return 0;
-
- if (back1->owner > back2->owner)
- return 1;
- if (back1->owner < back2->owner)
- return -1;
-
- if (back1->offset > back2->offset)
- return 1;
- if (back1->offset < back2->offset)
- return -1;
-
- if (back1->bytes > back2->bytes)
- return 1;
- if (back1->bytes < back2->bytes)
- return -1;
-
- if (back1->found_ref && back2->found_ref) {
- if (back1->disk_bytenr > back2->disk_bytenr)
- return 1;
- if (back1->disk_bytenr < back2->disk_bytenr)
- return -1;
-
- if (back1->found_ref > back2->found_ref)
- return 1;
- if (back1->found_ref < back2->found_ref)
- return -1;
- }
-
- return 0;
-}
-
/*
* Much like data_backref, just removed the undetermined members
* and change it to use list_head.
return container_of(back, struct tree_backref, node);
}
-static int compare_tree_backref(struct rb_node *node1, struct rb_node *node2)
-{
- struct extent_backref *ext1 = rb_node_to_extent_backref(node1);
- struct extent_backref *ext2 = rb_node_to_extent_backref(node2);
- struct tree_backref *back1 = to_tree_backref(ext1);
- struct tree_backref *back2 = to_tree_backref(ext2);
-
- WARN_ON(ext1->is_data);
- WARN_ON(ext2->is_data);
-
- /* parent and root are a union, so this covers both */
- if (back1->parent > back2->parent)
- return 1;
- if (back1->parent < back2->parent)
- return -1;
-
- return 0;
-}
-
-static int compare_extent_backref(struct rb_node *node1, struct rb_node *node2)
-{
- struct extent_backref *ext1 = rb_node_to_extent_backref(node1);
- struct extent_backref *ext2 = rb_node_to_extent_backref(node2);
-
- if (ext1->is_data > ext2->is_data)
- return 1;
-
- if (ext1->is_data < ext2->is_data)
- return -1;
-
- if (ext1->full_backref > ext2->full_backref)
- return 1;
- if (ext1->full_backref < ext2->full_backref)
- return -1;
-
- if (ext1->is_data)
- return compare_data_backref(node1, node2);
- else
- return compare_tree_backref(node1, node2);
-}
-
/* Explicit initialization for extent_record::flag_block_full_backref */
enum { FLAG_UNSET = 2 };
struct extent_record {
struct list_head backrefs;
struct list_head dups;
- struct rb_root backref_tree;
struct list_head list;
struct cache_extent cache;
struct btrfs_disk_key parent_key;
return ret;
}
-
static struct tree_backref *find_tree_backref(struct extent_record *rec,
u64 parent, u64 root)
{
- struct rb_node *node;
- struct tree_backref *back = NULL;
- struct tree_backref match = {
- .node = {
- .is_data = 0,
- },
- };
+ struct list_head *cur = rec->backrefs.next;
+ struct extent_backref *node;
+ struct tree_backref *back;
- if (parent) {
- match.parent = parent;
- match.node.full_backref = 1;
- } else {
- match.root = root;
+ while(cur != &rec->backrefs) {
+ node = to_extent_backref(cur);
+ cur = cur->next;
+ if (node->is_data)
+ continue;
+ back = to_tree_backref(node);
+ if (parent > 0) {
+ if (!node->full_backref)
+ continue;
+ if (parent == back->parent)
+ return back;
+ } else {
+ if (node->full_backref)
+ continue;
+ if (back->root == root)
+ return back;
+ }
}
-
- node = rb_search(&rec->backref_tree, &match.node.node,
- (rb_compare_keys)compare_extent_backref, NULL);
- if (node)
- back = to_tree_backref(rb_node_to_extent_backref(node));
-
- return back;
+ return NULL;
}
static struct tree_backref *alloc_tree_backref(struct extent_record *rec,
ref->node.full_backref = 0;
}
list_add_tail(&ref->node.list, &rec->backrefs);
- rb_insert(&rec->backref_tree, &ref->node.node, compare_extent_backref);
return ref;
}
int found_ref,
u64 disk_bytenr, u64 bytes)
{
- struct rb_node *node;
- struct data_backref *back = NULL;
- struct data_backref match = {
- .node = {
- .is_data = 1,
- },
- .owner = owner,
- .offset = offset,
- .bytes = bytes,
- .found_ref = found_ref,
- .disk_bytenr = disk_bytenr,
- };
+ struct list_head *cur = rec->backrefs.next;
+ struct extent_backref *node;
+ struct data_backref *back;
- if (parent) {
- match.parent = parent;
- match.node.full_backref = 1;
- } else {
- match.root = root;
+ while(cur != &rec->backrefs) {
+ node = to_extent_backref(cur);
+ cur = cur->next;
+ if (!node->is_data)
+ continue;
+ back = to_data_backref(node);
+ if (parent > 0) {
+ if (!node->full_backref)
+ continue;
+ if (parent == back->parent)
+ return back;
+ } else {
+ if (node->full_backref)
+ continue;
+ if (back->root == root && back->owner == owner &&
+ back->offset == offset) {
+ if (found_ref && node->found_ref &&
+ (back->bytes != bytes ||
+ back->disk_bytenr != disk_bytenr))
+ continue;
+ return back;
+ }
+ }
}
-
- node = rb_search(&rec->backref_tree, &match.node.node,
- (rb_compare_keys)compare_extent_backref, NULL);
- if (node)
- back = to_data_backref(rb_node_to_extent_backref(node));
-
- return back;
+ return NULL;
}
static struct data_backref *alloc_data_backref(struct extent_record *rec,
ref->found_ref = 0;
ref->num_refs = 0;
list_add_tail(&ref->node.list, &rec->backrefs);
- rb_insert(&rec->backref_tree, &ref->node.node, compare_extent_backref);
if (max_size > rec->max_size)
rec->max_size = max_size;
return ref;
INIT_LIST_HEAD(&rec->backrefs);
INIT_LIST_HEAD(&rec->dups);
INIT_LIST_HEAD(&rec->list);
- rec->backref_tree = RB_ROOT;
memcpy(&rec->parent_key, &tmpl->parent_key, sizeof(tmpl->parent_key));
rec->cache.start = tmpl->start;
rec->cache.size = tmpl->nr;