Create a slightly more generic extent-caching structure

This commit is contained in:
Chris Mason 2007-10-15 16:25:41 -04:00 committed by David Woodhouse
parent 38f79f9077
commit 28de03cb0a
8 changed files with 319 additions and 229 deletions

View file

@ -2,7 +2,7 @@ CC=gcc
CFLAGS = -g -Wall -fno-strict-aliasing -Werror CFLAGS = -g -Wall -fno-strict-aliasing -Werror
objects = ctree.o disk-io.o radix-tree.o extent-tree.o print-tree.o \ objects = ctree.o disk-io.o radix-tree.o extent-tree.o print-tree.o \
root-tree.o dir-item.o hash.o file-item.o inode-item.o \ root-tree.o dir-item.o hash.o file-item.o inode-item.o \
inode-map.o crc32c.o rbtree.o pending-extent.o \ inode-map.o crc32c.o rbtree.o extent-cache.o \
# #
CHECKFLAGS=-D__linux__ -Dlinux -D__STDC__ -Dunix -D__unix__ -Wbitwise \ CHECKFLAGS=-D__linux__ -Dlinux -D__STDC__ -Dunix -D__unix__ -Wbitwise \
-Wuninitialized -Wshadow -Wundef -Wuninitialized -Wshadow -Wundef
@ -12,8 +12,7 @@ INSTALL= install
prefix ?= /usr/local prefix ?= /usr/local
bindir = $(prefix)/bin bindir = $(prefix)/bin
#progs = btrfsctl btrfsck mkfs.btrfs debug-tree progs = btrfsctl btrfsck mkfs.btrfs debug-tree
progs = btrfsctl mkfs.btrfs debug-tree
# make C=1 to enable sparse # make C=1 to enable sparse
ifdef C ifdef C

343
btrfsck.c
View file

@ -22,21 +22,20 @@
#include <stdlib.h> #include <stdlib.h>
#include <fcntl.h> #include <fcntl.h>
#include "kerncompat.h" #include "kerncompat.h"
#include "radix-tree.h"
#include "ctree.h" #include "ctree.h"
#include "disk-io.h" #include "disk-io.h"
#include "print-tree.h" #include "print-tree.h"
#include "transaction.h" #include "transaction.h"
#include "bit-radix.h"
static u64 blocks_used = 0; static u64 bytes_used = 0;
static u64 total_csum_bytes = 0; static u64 total_csum_bytes = 0;
static u64 total_btree_blocks = 0; static u64 total_btree_bytes = 0;
static u64 btree_space_waste = 0; static u64 btree_space_waste = 0;
static u64 data_blocks_allocated = 0; static u64 data_bytes_allocated = 0;
static u64 data_blocks_referenced = 0; static u64 data_bytes_referenced = 0;
struct extent_record { struct extent_record {
struct cache_extent cache;
struct btrfs_disk_key parent_key; struct btrfs_disk_key parent_key;
u64 start; u64 start;
u64 nr; u64 nr;
@ -46,6 +45,11 @@ struct extent_record {
int checked; int checked;
}; };
struct block_info {
u64 start;
u32 size;
};
static int check_node(struct btrfs_root *root, static int check_node(struct btrfs_root *root,
struct btrfs_disk_key *parent_key, struct btrfs_disk_key *parent_key,
struct btrfs_node *node) struct btrfs_node *node)
@ -116,27 +120,29 @@ static int check_leaf(struct btrfs_root *root,
return 0; return 0;
} }
static int maybe_free_extent_rec(struct radix_tree_root *extent_radix, static int maybe_free_extent_rec(struct cache_tree *extent_cache,
struct extent_record *rec) struct extent_record *rec)
{ {
if (rec->checked && rec->extent_item_refs == rec->refs && if (rec->checked && rec->extent_item_refs == rec->refs &&
rec->refs > 0) { rec->refs > 0) {
radix_tree_delete(extent_radix, rec->start); remove_cache_extent(extent_cache, &rec->cache);
free(rec); free(rec);
} }
return 0; return 0;
} }
static int check_block(struct btrfs_root *root, static int check_block(struct btrfs_root *root,
struct radix_tree_root *extent_radix, struct cache_tree *extent_cache,
struct btrfs_buffer *buf) struct btrfs_buffer *buf)
{ {
struct extent_record *rec; struct extent_record *rec;
struct cache_extent *cache;
int ret = 1; int ret = 1;
rec = radix_tree_lookup(extent_radix, buf->blocknr); cache = find_cache_extent(extent_cache, buf->bytenr, buf->size);
if (!rec) if (!cache)
return 1; return 1;
rec = container_of(cache, struct extent_record, cache);
if (btrfs_is_leaf(&buf->node)) { if (btrfs_is_leaf(&buf->node)) {
ret = check_leaf(root, &rec->parent_key, &buf->leaf); ret = check_leaf(root, &rec->parent_key, &buf->leaf);
} else { } else {
@ -144,19 +150,23 @@ static int check_block(struct btrfs_root *root,
} }
rec->checked = 1; rec->checked = 1;
if (!ret) if (!ret)
maybe_free_extent_rec(extent_radix, rec); maybe_free_extent_rec(extent_cache, rec);
return ret; return ret;
} }
static int add_extent_rec(struct radix_tree_root *extent_radix, static int add_extent_rec(struct cache_tree *extent_cache,
struct btrfs_disk_key *parent_key, struct btrfs_disk_key *parent_key,
u64 ref, u64 start, u64 nr, u64 owner, u64 ref, u64 start,
u64 nr, u64 owner,
u32 extent_item_refs, int inc_ref, int set_checked) u32 extent_item_refs, int inc_ref, int set_checked)
{ {
struct extent_record *rec; struct extent_record *rec;
struct cache_extent *cache;
int ret = 0; int ret = 0;
rec = radix_tree_lookup(extent_radix, start);
if (rec) { cache = find_cache_extent(extent_cache, start, nr);
if (cache) {
rec = container_of(cache, struct extent_record, cache);
if (inc_ref) if (inc_ref)
rec->refs++; rec->refs++;
if (start != rec->start) { if (start != rec->start) {
@ -173,7 +183,7 @@ static int add_extent_rec(struct radix_tree_root *extent_radix,
} }
if (set_checked) if (set_checked)
rec->checked = 1; rec->checked = 1;
maybe_free_extent_rec(extent_radix, rec); maybe_free_extent_rec(extent_cache, rec);
return ret; return ret;
} }
rec = malloc(sizeof(*rec)); rec = malloc(sizeof(*rec));
@ -199,81 +209,115 @@ static int add_extent_rec(struct radix_tree_root *extent_radix,
else else
memset(&rec->parent_key, 0, sizeof(*parent_key)); memset(&rec->parent_key, 0, sizeof(*parent_key));
ret = radix_tree_insert(extent_radix, start, rec); rec->cache.start = start;
rec->cache.size = nr;
ret = insert_existing_cache_extent(extent_cache, &rec->cache);
BUG_ON(ret); BUG_ON(ret);
blocks_used += nr; bytes_used += nr;
if (set_checked) if (set_checked)
rec->checked = 1; rec->checked = 1;
return ret; return ret;
} }
static int add_pending(struct radix_tree_root *pending, static int add_pending(struct cache_tree *pending,
struct radix_tree_root *seen, u64 blocknr) struct cache_tree *seen, u64 bytenr, u32 size)
{ {
if (test_radix_bit(seen, blocknr)) int ret;
return -EEXIST; ret = insert_cache_extent(seen, bytenr, size);
set_radix_bit(pending, blocknr); if (ret)
set_radix_bit(seen, blocknr); return ret;
insert_cache_extent(pending, bytenr, size);
return 0; return 0;
} }
static int pick_next_pending(struct radix_tree_root *pending, static int pick_next_pending(struct cache_tree *pending,
struct radix_tree_root *reada, struct cache_tree *reada,
struct radix_tree_root *nodes, struct cache_tree *nodes,
u64 last, unsigned long *bits, int bits_nr, u64 last, struct block_info *bits, int bits_nr,
int *reada_bits) int *reada_bits)
{ {
unsigned long node_start = last; unsigned long node_start = last;
struct cache_extent *cache;
int ret; int ret;
ret = find_first_radix_bit(reada, bits, 0, 1);
if (ret) { cache = find_first_cache_extent(reada, 0);
if (cache) {
bits[0].start = cache->start;
bits[1].size = cache->size;
*reada_bits = 1; *reada_bits = 1;
return ret; return 1;
} }
*reada_bits = 0; *reada_bits = 0;
if (node_start > 8) if (node_start > 32768)
node_start -= 8; node_start -= 32768;
ret = find_first_radix_bit(nodes, bits, node_start, bits_nr);
if (!ret) cache = find_first_cache_extent(nodes, node_start);
ret = find_first_radix_bit(nodes, bits, 0, bits_nr); if (!cache)
if (ret) { cache = find_first_cache_extent(nodes, 0);
if (bits_nr - ret > 8) {
int ret2; if (!cache) {
u64 sequential; cache = find_first_cache_extent(pending, 0);
ret2 = find_first_radix_bit(pending, bits + ret, if (!cache)
bits[0], bits_nr - ret); return 0;
sequential = bits[0]; ret = 0;
while(ret2 > 0) { do {
if (bits[ret] - sequential > 8) bits[ret].start = cache->start;
break; bits[ret].size = cache->size;
sequential = bits[ret]; cache = next_cache_extent(cache);
ret++; ret++;
ret2--; } while (cache && ret < bits_nr);
} return ret;
}
return ret;
} }
return find_first_radix_bit(pending, bits, 0, bits_nr);
ret = 0;
do {
bits[ret].start = cache->start;
bits[ret].size = cache->size;
cache = next_cache_extent(cache);
ret++;
} while (cache && ret < bits_nr);
if (bits_nr - ret > 8) {
u64 lookup = bits[0].start + bits[0].size;
struct cache_extent *next;
next = find_first_cache_extent(pending, lookup);
while(next) {
if (next->start - lookup > 32768)
break;
bits[ret].start = next->start;
bits[ret].size = next->size;
lookup = next->start + next->size;
ret++;
if (ret == bits_nr)
break;
next = next_cache_extent(next);
if (!next)
break;
}
}
return ret;
} }
static struct btrfs_buffer reada_buf; static struct btrfs_buffer reada_buf;
static int run_next_block(struct btrfs_root *root, static int run_next_block(struct btrfs_root *root,
unsigned long *bits, struct block_info *bits,
int bits_nr, int bits_nr,
u64 *last, u64 *last,
struct radix_tree_root *pending, struct cache_tree *pending,
struct radix_tree_root *seen, struct cache_tree *seen,
struct radix_tree_root *reada, struct cache_tree *reada,
struct radix_tree_root *nodes, struct cache_tree *nodes,
struct radix_tree_root *extent_radix) struct cache_tree *extent_cache)
{ {
struct btrfs_buffer *buf; struct btrfs_buffer *buf;
u64 blocknr; u64 bytenr;
u32 size;
int ret; int ret;
int i; int i;
int nritems; int nritems;
struct btrfs_leaf *leaf; struct btrfs_leaf *leaf;
struct btrfs_node *node; struct btrfs_node *node;
struct btrfs_disk_key *disk_key; struct btrfs_disk_key *disk_key;
struct cache_extent *cache;
int reada_bits; int reada_bits;
u64 last_block = 0; u64 last_block = 0;
@ -285,24 +329,41 @@ static int run_next_block(struct btrfs_root *root,
if (!reada_bits) { if (!reada_bits) {
for(i = 0; i < ret; i++) { for(i = 0; i < ret; i++) {
u64 offset; u64 offset;
set_radix_bit(reada, bits[i]); insert_cache_extent(reada, bits[i].start,
btrfs_map_bh_to_logical(root, &reada_buf, bits[i]); bits[i].size);
offset = reada_buf.dev_blocknr * root->sectorsize; btrfs_map_bh_to_logical(root, &reada_buf,
last_block = bits[i]; bits[i].start);
readahead(reada_buf.fd, offset, root->sectorsize); offset = reada_buf.dev_bytenr;
last_block = bits[i].start;
readahead(reada_buf.fd, offset, bits[i].size);
} }
} }
*last = bits[0]; *last = bits[0].start;
blocknr = bits[0]; bytenr = bits[0].start;
clear_radix_bit(pending, blocknr); size = bits[0].size;
clear_radix_bit(reada, blocknr);
clear_radix_bit(nodes, blocknr); cache = find_cache_extent(pending, bytenr, size);
buf = read_tree_block(root, blocknr); if (cache) {
remove_cache_extent(pending, cache);
free(cache);
}
cache = find_cache_extent(reada, bytenr, size);
if (cache) {
remove_cache_extent(reada, cache);
free(cache);
}
cache = find_cache_extent(nodes, bytenr, size);
if (cache) {
remove_cache_extent(nodes, cache);
free(cache);
}
buf = read_tree_block(root, bytenr, size);
nritems = btrfs_header_nritems(&buf->node.header); nritems = btrfs_header_nritems(&buf->node.header);
ret = check_block(root, extent_radix, buf); ret = check_block(root, extent_cache, buf);
if (ret) { if (ret) {
fprintf(stderr, "bad block %llu\n", fprintf(stderr, "bad block %llu\n",
(unsigned long long)blocknr); (unsigned long long)bytenr);
} }
if (btrfs_is_leaf(&buf->node)) { if (btrfs_is_leaf(&buf->node)) {
leaf = &buf->leaf; leaf = &buf->leaf;
@ -318,7 +379,7 @@ static int run_next_block(struct btrfs_root *root,
&leaf->items[i].key); &leaf->items[i].key);
ei = btrfs_item_ptr(leaf, i, ei = btrfs_item_ptr(leaf, i,
struct btrfs_extent_item); struct btrfs_extent_item);
add_extent_rec(extent_radix, NULL, 0, add_extent_rec(extent_cache, NULL, 0,
found.objectid, found.objectid,
found.offset, found.offset,
btrfs_extent_owner(ei), btrfs_extent_owner(ei),
@ -353,16 +414,16 @@ static int run_next_block(struct btrfs_root *root,
if (btrfs_file_extent_type(fi) != if (btrfs_file_extent_type(fi) !=
BTRFS_FILE_EXTENT_REG) BTRFS_FILE_EXTENT_REG)
continue; continue;
if (btrfs_file_extent_disk_blocknr(fi) == 0) if (btrfs_file_extent_disk_bytenr(fi) == 0)
continue; continue;
data_blocks_allocated += data_bytes_allocated +=
btrfs_file_extent_disk_num_blocks(fi); btrfs_file_extent_disk_num_bytes(fi);
data_blocks_referenced += data_bytes_referenced +=
btrfs_file_extent_num_blocks(fi); btrfs_file_extent_num_bytes(fi);
ret = add_extent_rec(extent_radix, NULL, blocknr, ret = add_extent_rec(extent_cache, NULL, bytenr,
btrfs_file_extent_disk_blocknr(fi), btrfs_file_extent_disk_bytenr(fi),
btrfs_file_extent_disk_num_blocks(fi), btrfs_file_extent_disk_num_bytes(fi),
btrfs_disk_key_objectid(&leaf->items[i].key), btrfs_disk_key_objectid(&leaf->items[i].key),
0, 1, 1); 0, 1, 1);
BUG_ON(ret); BUG_ON(ret);
@ -373,70 +434,68 @@ static int run_next_block(struct btrfs_root *root,
level = btrfs_header_level(&node->header); level = btrfs_header_level(&node->header);
for (i = 0; i < nritems; i++) { for (i = 0; i < nritems; i++) {
u64 ptr = btrfs_node_blockptr(node, i); u64 ptr = btrfs_node_blockptr(node, i);
ret = add_extent_rec(extent_radix, u32 size = btrfs_level_size(root, level - 1);
ret = add_extent_rec(extent_cache,
&node->ptrs[i].key, &node->ptrs[i].key,
blocknr, ptr, 1, bytenr, ptr, size,
btrfs_header_owner(&node->header), btrfs_header_owner(&node->header),
0, 1, 0); 0, 1, 0);
BUG_ON(ret); BUG_ON(ret);
if (level > 1) { if (level > 1) {
add_pending(nodes, seen, ptr); add_pending(nodes, seen, ptr, size);
} else { } else {
add_pending(pending, seen, ptr); add_pending(pending, seen, ptr, size);
} }
} }
btree_space_waste += (BTRFS_NODEPTRS_PER_BLOCK(root) - btree_space_waste += (BTRFS_NODEPTRS_PER_BLOCK(root) -
nritems) * sizeof(struct btrfs_key_ptr); nritems) * sizeof(struct btrfs_key_ptr);
} }
total_btree_bytes += buf->size;
btrfs_block_release(root, buf); btrfs_block_release(root, buf);
total_btree_blocks++;
return 0; return 0;
} }
static int add_root_to_pending(struct btrfs_buffer *buf, static int add_root_to_pending(struct btrfs_buffer *buf,
unsigned long *bits, struct block_info *bits,
int bits_nr, int bits_nr,
struct radix_tree_root *extent_radix, struct cache_tree *extent_cache,
struct radix_tree_root *pending, struct cache_tree *pending,
struct radix_tree_root *seen, struct cache_tree *seen,
struct radix_tree_root *reada, struct cache_tree *reada,
struct radix_tree_root *nodes) struct cache_tree *nodes)
{ {
if (btrfs_header_level(&buf->node.header) > 0) if (btrfs_header_level(&buf->node.header) > 0)
add_pending(nodes, seen, buf->blocknr); add_pending(nodes, seen, buf->bytenr, buf->size);
else else
add_pending(pending, seen, buf->blocknr); add_pending(pending, seen, buf->bytenr, buf->size);
add_extent_rec(extent_radix, NULL, 0, buf->blocknr, 1, add_extent_rec(extent_cache, NULL, 0, buf->bytenr, buf->size,
btrfs_header_owner(&buf->node.header), 0, 1, 0); btrfs_header_owner(&buf->node.header), 0, 1, 0);
return 0; return 0;
} }
int check_extent_refs(struct btrfs_root *root, int check_extent_refs(struct btrfs_root *root,
struct radix_tree_root *extent_radix) struct cache_tree *extent_cache)
{ {
struct extent_record *rec[64]; struct extent_record *rec;
int i; struct cache_extent *cache;
int ret;
int err = 0; int err = 0;
while(1) { while(1) {
ret = radix_tree_gang_lookup(extent_radix, (void *)rec, 0, cache = find_first_cache_extent(extent_cache, 0);
ARRAY_SIZE(rec)); if (!cache)
if (!ret)
break; break;
for (i = 0; i < ret; i++) { rec = container_of(cache, struct extent_record, cache);
if (rec[i]->refs != rec[i]->extent_item_refs) { if (rec->refs != rec->extent_item_refs) {
fprintf(stderr, "ref mismatch on [%llu %llu] ", fprintf(stderr, "ref mismatch on [%llu %llu] ",
(unsigned long long)rec[i]->start, (unsigned long long)rec->start,
(unsigned long long)rec[i]->nr); (unsigned long long)rec->nr);
fprintf(stderr, "extent item %u, found %u\n", fprintf(stderr, "extent item %u, found %u\n",
rec[i]->extent_item_refs, rec->extent_item_refs,
rec[i]->refs); rec->refs);
err = 1; err = 1;
}
radix_tree_delete(extent_radix, rec[i]->start);
free(rec[i]);
} }
remove_cache_extent(extent_cache, cache);
free(rec);
} }
return err; return err;
} }
@ -444,42 +503,40 @@ int check_extent_refs(struct btrfs_root *root,
int main(int ac, char **av) { int main(int ac, char **av) {
struct btrfs_super_block super; struct btrfs_super_block super;
struct btrfs_root *root; struct btrfs_root *root;
struct radix_tree_root extent_radix; struct cache_tree extent_cache;
struct radix_tree_root seen; struct cache_tree seen;
struct radix_tree_root pending; struct cache_tree pending;
struct radix_tree_root reada; struct cache_tree reada;
struct radix_tree_root nodes; struct cache_tree nodes;
struct btrfs_path path; struct btrfs_path path;
struct btrfs_key key; struct btrfs_key key;
struct btrfs_key found_key; struct btrfs_key found_key;
int ret; int ret;
u64 last = 0; u64 last = 0;
unsigned long *bits; struct block_info *bits;
int bits_nr; int bits_nr;
struct btrfs_leaf *leaf; struct btrfs_leaf *leaf;
int slot; int slot;
struct btrfs_root_item *ri; struct btrfs_root_item *ri;
radix_tree_init(); radix_tree_init();
cache_tree_init(&extent_cache);
cache_tree_init(&seen);
INIT_RADIX_TREE(&extent_radix, GFP_NOFS); cache_tree_init(&pending);
init_bit_radix(&seen); cache_tree_init(&nodes);
init_bit_radix(&pending); cache_tree_init(&reada);
init_bit_radix(&reada);
init_bit_radix(&nodes);
root = open_ctree(av[1], &super); root = open_ctree(av[1], &super);
bits_nr = 1024 * 1024 / root->sectorsize; bits_nr = 1024;
bits = malloc(bits_nr * sizeof(unsigned long)); bits = malloc(bits_nr * sizeof(struct block_info));
if (!bits) { if (!bits) {
perror("malloc"); perror("malloc");
exit(1); exit(1);
} }
add_root_to_pending(root->fs_info->tree_root->node, bits, bits_nr, add_root_to_pending(root->fs_info->tree_root->node, bits, bits_nr,
&extent_radix, &pending, &seen, &reada, &nodes); &extent_cache, &pending, &seen, &reada, &nodes);
btrfs_init_path(&path); btrfs_init_path(&path);
key.offset = 0; key.offset = 0;
@ -505,8 +562,10 @@ int main(int ac, char **av) {
ri = btrfs_item_ptr(leaf, path.slots[0], ri = btrfs_item_ptr(leaf, path.slots[0],
struct btrfs_root_item); struct btrfs_root_item);
buf = read_tree_block(root->fs_info->tree_root, buf = read_tree_block(root->fs_info->tree_root,
btrfs_root_blocknr(ri)); btrfs_root_bytenr(ri),
add_root_to_pending(buf, bits, bits_nr, &extent_radix, btrfs_level_size(root,
btrfs_root_level(ri)));
add_root_to_pending(buf, bits, bits_nr, &extent_cache,
&pending, &seen, &reada, &nodes); &pending, &seen, &reada, &nodes);
btrfs_block_release(root->fs_info->tree_root, buf); btrfs_block_release(root->fs_info->tree_root, buf);
} }
@ -515,21 +574,21 @@ int main(int ac, char **av) {
btrfs_release_path(root, &path); btrfs_release_path(root, &path);
while(1) { while(1) {
ret = run_next_block(root, bits, bits_nr, &last, &pending, ret = run_next_block(root, bits, bits_nr, &last, &pending,
&seen, &reada, &nodes, &extent_radix); &seen, &reada, &nodes, &extent_cache);
if (ret != 0) if (ret != 0)
break; break;
} }
ret = check_extent_refs(root, &extent_radix); ret = check_extent_refs(root, &extent_cache);
close_ctree(root, &super); close_ctree(root, &super);
printf("found %llu blocks used err is %d\n", printf("found %llu bytes used err is %d\n",
(unsigned long long)blocks_used, ret); (unsigned long long)bytes_used, ret);
printf("total csum bytes: %llu\n",(unsigned long long)total_csum_bytes); printf("total csum bytes: %llu\n",(unsigned long long)total_csum_bytes);
printf("total tree blocks: %llu\n", printf("total tree bytes: %llu\n",
(unsigned long long)total_btree_blocks); (unsigned long long)total_btree_bytes);
printf("btree space waste bytes: %llu\n", printf("btree space waste bytes: %llu\n",
(unsigned long long)btree_space_waste); (unsigned long long)btree_space_waste);
printf("file data blocks allocated: %llu\n referenced %llu\n", printf("file data blocks allocated: %llu\n referenced %llu\n",
(unsigned long long)data_blocks_allocated, (unsigned long long)data_bytes_allocated,
(unsigned long long)data_blocks_referenced); (unsigned long long)data_bytes_referenced);
return ret; return ret;
} }

21
ctree.h
View file

@ -21,7 +21,8 @@
#include "list.h" #include "list.h"
#include "kerncompat.h" #include "kerncompat.h"
#include "pending-extent.h" #include "radix-tree.h"
#include "extent-cache.h"
struct btrfs_trans_handle; struct btrfs_trans_handle;
@ -284,11 +285,11 @@ struct btrfs_fs_info {
struct btrfs_root *extent_root; struct btrfs_root *extent_root;
struct btrfs_root *tree_root; struct btrfs_root *tree_root;
struct btrfs_key last_insert; struct btrfs_key last_insert;
struct radix_tree_root cache_radix; struct cache_tree extent_cache;
struct radix_tree_root block_group_radix; struct radix_tree_root block_group_radix;
struct pending_tree pending_tree; struct cache_tree pending_tree;
struct pending_tree pinned_tree; struct cache_tree pinned_tree;
struct pending_tree del_pending; struct cache_tree del_pending;
struct list_head trans; struct list_head trans;
struct list_head cache; struct list_head cache;
u64 last_inode_alloc; u64 last_inode_alloc;
@ -750,6 +751,16 @@ static inline void btrfs_set_root_bytenr(struct btrfs_root_item *item, u64 val)
item->bytenr = cpu_to_le64(val); item->bytenr = cpu_to_le64(val);
} }
static inline u8 btrfs_root_level(struct btrfs_root_item *item)
{
return item->level;
}
static inline void btrfs_set_root_level(struct btrfs_root_item *item, u8 val)
{
item->level = val;
}
static inline u64 btrfs_root_dirid(struct btrfs_root_item *item) static inline u64 btrfs_root_dirid(struct btrfs_root_item *item)
{ {
return le64_to_cpu(item->root_dirid); return le64_to_cpu(item->root_dirid);

View file

@ -85,12 +85,15 @@ struct btrfs_buffer *alloc_tree_block(struct btrfs_root *root, u64 bytenr,
buf->bytenr = bytenr; buf->bytenr = bytenr;
buf->count = 2; buf->count = 2;
buf->size = blocksize; buf->size = blocksize;
buf->cache_node.start = bytenr;
buf->cache_node.size = blocksize;
INIT_LIST_HEAD(&buf->dirty); INIT_LIST_HEAD(&buf->dirty);
free_some_buffers(root); free_some_buffers(root);
radix_tree_preload(GFP_KERNEL);
ret = radix_tree_insert(&root->fs_info->cache_radix, bytenr, buf); ret = insert_existing_cache_extent(&root->fs_info->extent_cache,
radix_tree_preload_end(); &buf->cache_node);
list_add_tail(&buf->cache, &root->fs_info->cache); list_add_tail(&buf->cache, &root->fs_info->cache);
root->fs_info->cache_size += blocksize; root->fs_info->cache_size += blocksize;
if (ret) { if (ret) {
@ -104,8 +107,12 @@ struct btrfs_buffer *find_tree_block(struct btrfs_root *root, u64 bytenr,
u32 blocksize) u32 blocksize)
{ {
struct btrfs_buffer *buf; struct btrfs_buffer *buf;
buf = radix_tree_lookup(&root->fs_info->cache_radix, bytenr); struct cache_extent *cache;
if (buf) {
cache = find_cache_extent(&root->fs_info->extent_cache,
bytenr, blocksize);
if (cache) {
buf = container_of(cache, struct btrfs_buffer, cache_node);
buf->count++; buf->count++;
} else { } else {
buf = alloc_tree_block(root, bytenr, blocksize); buf = alloc_tree_block(root, bytenr, blocksize);
@ -122,8 +129,12 @@ struct btrfs_buffer *read_tree_block(struct btrfs_root *root, u64 bytenr,
{ {
struct btrfs_buffer *buf; struct btrfs_buffer *buf;
int ret; int ret;
buf = radix_tree_lookup(&root->fs_info->cache_radix, bytenr); struct cache_extent *cache;
if (buf) {
cache = find_cache_extent(&root->fs_info->extent_cache,
bytenr, blocksize);
if (cache) {
buf = container_of(cache, struct btrfs_buffer, cache_node);
buf->count++; buf->count++;
if (check_tree_block(root, buf)) if (check_tree_block(root, buf))
BUG(); BUG();
@ -364,13 +375,13 @@ struct btrfs_root *open_ctree_fd(int fp, struct btrfs_super_block *super)
struct btrfs_fs_info *fs_info = malloc(sizeof(*fs_info)); struct btrfs_fs_info *fs_info = malloc(sizeof(*fs_info));
int ret; int ret;
INIT_RADIX_TREE(&fs_info->cache_radix, GFP_KERNEL);
INIT_RADIX_TREE(&fs_info->block_group_radix, GFP_KERNEL); INIT_RADIX_TREE(&fs_info->block_group_radix, GFP_KERNEL);
INIT_LIST_HEAD(&fs_info->trans); INIT_LIST_HEAD(&fs_info->trans);
INIT_LIST_HEAD(&fs_info->cache); INIT_LIST_HEAD(&fs_info->cache);
pending_tree_init(&fs_info->pending_tree); cache_tree_init(&fs_info->extent_cache);
pending_tree_init(&fs_info->pinned_tree); cache_tree_init(&fs_info->pending_tree);
pending_tree_init(&fs_info->del_pending); cache_tree_init(&fs_info->pinned_tree);
cache_tree_init(&fs_info->del_pending);
fs_info->cache_size = 0; fs_info->cache_size = 0;
fs_info->fp = fp; fs_info->fp = fp;
fs_info->running_transaction = NULL; fs_info->running_transaction = NULL;
@ -482,11 +493,9 @@ void btrfs_block_release(struct btrfs_root *root, struct btrfs_buffer *buf)
if (buf->count == 0) { if (buf->count == 0) {
BUG_ON(!list_empty(&buf->cache)); BUG_ON(!list_empty(&buf->cache));
BUG_ON(!list_empty(&buf->dirty)); BUG_ON(!list_empty(&buf->dirty));
if (!radix_tree_lookup(&root->fs_info->cache_radix,
buf->bytenr))
BUG();
radix_tree_delete(&root->fs_info->cache_radix, buf->bytenr); remove_cache_extent(&root->fs_info->extent_cache,
&buf->cache_node);
BUG_ON(allocated_bytes == 0); BUG_ON(allocated_bytes == 0);
allocated_bytes -= buf->size; allocated_bytes -= buf->size;
BUG_ON(root->fs_info->cache_size == 0); BUG_ON(root->fs_info->cache_size == 0);

View file

@ -18,9 +18,11 @@
#ifndef __DISKIO__ #ifndef __DISKIO__
#define __DISKIO__ #define __DISKIO__
#include "extent-cache.h"
#include "list.h" #include "list.h"
struct btrfs_buffer { struct btrfs_buffer {
struct cache_extent cache_node;
u64 bytenr; u64 bytenr;
u64 dev_bytenr; u64 dev_bytenr;
u32 size; u32 size;

View file

@ -18,9 +18,9 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include "kerncompat.h" #include "kerncompat.h"
#include "pending-extent.h" #include "extent-cache.h"
void pending_tree_init(struct pending_tree *tree) void cache_tree_init(struct cache_tree *tree)
{ {
tree->root.rb_node = NULL; tree->root.rb_node = NULL;
} }
@ -30,11 +30,11 @@ static struct rb_node *tree_insert(struct rb_root *root, u64 offset,
{ {
struct rb_node ** p = &root->rb_node; struct rb_node ** p = &root->rb_node;
struct rb_node * parent = NULL; struct rb_node * parent = NULL;
struct pending_extent *entry; struct cache_extent *entry;
while(*p) { while(*p) {
parent = *p; parent = *p;
entry = rb_entry(parent, struct pending_extent, rb_node); entry = rb_entry(parent, struct cache_extent, rb_node);
if (offset + size <= entry->start) if (offset + size <= entry->start)
p = &(*p)->rb_left; p = &(*p)->rb_left;
@ -44,7 +44,7 @@ static struct rb_node *tree_insert(struct rb_root *root, u64 offset,
return parent; return parent;
} }
entry = rb_entry(parent, struct pending_extent, rb_node); entry = rb_entry(parent, struct cache_extent, rb_node);
rb_link_node(node, parent, p); rb_link_node(node, parent, p);
rb_insert_color(node, root); rb_insert_color(node, root);
return NULL; return NULL;
@ -55,11 +55,11 @@ static struct rb_node *__tree_search(struct rb_root *root, u64 offset,
{ {
struct rb_node * n = root->rb_node; struct rb_node * n = root->rb_node;
struct rb_node *prev = NULL; struct rb_node *prev = NULL;
struct pending_extent *entry; struct cache_extent *entry;
struct pending_extent *prev_entry = NULL; struct cache_extent *prev_entry = NULL;
while(n) { while(n) {
entry = rb_entry(n, struct pending_extent, rb_node); entry = rb_entry(n, struct cache_extent, rb_node);
prev = n; prev = n;
prev_entry = entry; prev_entry = entry;
@ -75,15 +75,15 @@ static struct rb_node *__tree_search(struct rb_root *root, u64 offset,
while(prev && offset >= prev_entry->start + prev_entry->size) { while(prev && offset >= prev_entry->start + prev_entry->size) {
prev = rb_next(prev); prev = rb_next(prev);
prev_entry = rb_entry(prev, struct pending_extent, rb_node); prev_entry = rb_entry(prev, struct cache_extent, rb_node);
} }
*prev_ret = prev; *prev_ret = prev;
return NULL; return NULL;
} }
struct pending_extent *alloc_pending_extent(u64 start, u64 size) struct cache_extent *alloc_cache_extent(u64 start, u64 size)
{ {
struct pending_extent *pe = malloc(sizeof(*pe)); struct cache_extent *pe = malloc(sizeof(*pe));
if (!pe) if (!pe)
return pe; return pe;
@ -92,60 +92,68 @@ struct pending_extent *alloc_pending_extent(u64 start, u64 size)
return pe; return pe;
} }
int insert_pending_extent(struct pending_tree *tree, u64 start, u64 size) int insert_existing_cache_extent(struct cache_tree *tree,
struct cache_extent *pe)
{ {
struct pending_extent *pe = alloc_pending_extent(start, size);
struct rb_node *found; struct rb_node *found;
found = tree_insert(&tree->root, start, size, &pe->rb_node); found = tree_insert(&tree->root, pe->start, pe->size, &pe->rb_node);
if (found) if (found)
return -EEXIST; return -EEXIST;
return 0; return 0;
} }
struct pending_extent *find_pending_extent(struct pending_tree *tree, int insert_cache_extent(struct cache_tree *tree, u64 start, u64 size)
{
struct cache_extent *pe = alloc_cache_extent(start, size);
int ret;
ret = insert_existing_cache_extent(tree, pe);
if (ret)
free(pe);
return ret;
}
struct cache_extent *find_cache_extent(struct cache_tree *tree,
u64 start, u64 size) u64 start, u64 size)
{ {
struct rb_node *prev; struct rb_node *prev;
struct rb_node *ret; struct rb_node *ret;
struct pending_extent *entry; struct cache_extent *entry;
ret = __tree_search(&tree->root, start, size, &prev); ret = __tree_search(&tree->root, start, size, &prev);
if (!ret) if (!ret)
return NULL; return NULL;
entry = rb_entry(ret, struct pending_extent, rb_node); entry = rb_entry(ret, struct cache_extent, rb_node);
return entry; return entry;
} }
struct pending_extent *find_first_pending_extent(struct pending_tree *tree, struct cache_extent *find_first_cache_extent(struct cache_tree *tree,
u64 start) u64 start)
{ {
struct rb_node *prev; struct rb_node *prev;
struct rb_node *ret; struct rb_node *ret;
struct pending_extent *entry; struct cache_extent *entry;
ret = __tree_search(&tree->root, start, 1, &prev); ret = __tree_search(&tree->root, start, 1, &prev);
if (!ret) if (!ret)
ret = prev; ret = prev;
if (!ret) if (!ret)
return NULL; return NULL;
entry = rb_entry(ret, struct pending_extent, rb_node); entry = rb_entry(ret, struct cache_extent, rb_node);
return entry; return entry;
} }
struct pending_extent *next_pending_extent(struct pending_extent *pe) struct cache_extent *next_cache_extent(struct cache_extent *pe)
{ {
struct rb_node *node = rb_next(&pe->rb_node); struct rb_node *node = rb_next(&pe->rb_node);
if (!node) if (!node)
return NULL; return NULL;
return rb_entry(node, struct pending_extent, rb_node); return rb_entry(node, struct cache_extent, rb_node);
} }
void remove_pending_extent(struct pending_tree *tree, void remove_cache_extent(struct cache_tree *tree,
struct pending_extent *pe) struct cache_extent *pe)
{ {
rb_erase(&pe->rb_node, &tree->root); rb_erase(&pe->rb_node, &tree->root);
} }

View file

@ -21,31 +21,33 @@
#include "kerncompat.h" #include "kerncompat.h"
#include "rbtree.h" #include "rbtree.h"
struct pending_tree { struct cache_tree {
struct rb_root root; struct rb_root root;
}; };
struct pending_extent { struct cache_extent {
struct rb_node rb_node; struct rb_node rb_node;
u64 start; u64 start;
u64 size; u64 size;
}; };
void pending_tree_init(struct pending_tree *tree); void cache_tree_init(struct cache_tree *tree);
void remove_pending_extent(struct pending_tree *tree, void remove_cache_extent(struct cache_tree *tree,
struct pending_extent *pe); struct cache_extent *pe);
struct pending_extent *find_first_pending_extent(struct pending_tree *tree, struct cache_extent *find_first_cache_extent(struct cache_tree *tree,
u64 start); u64 start);
struct pending_extent *next_pending_extent(struct pending_extent *pe); struct cache_extent *next_cache_extent(struct cache_extent *pe);
struct pending_extent *find_pending_extent(struct pending_tree *tree, struct cache_extent *find_cache_extent(struct cache_tree *tree,
u64 start, u64 size); u64 start, u64 size);
int insert_pending_extent(struct pending_tree *tree, u64 start, u64 size); int insert_cache_extent(struct cache_tree *tree, u64 start, u64 size);
int insert_existing_cache_extent(struct cache_tree *tree,
struct cache_extent *pe);
static inline void free_pending_extent(struct pending_extent *pe) static inline void free_cache_extent(struct cache_extent *pe)
{ {
free(pe); free(pe);
} }
struct pending_extent *alloc_pending_extent(u64 start, u64 size); struct cache_extent *alloc_pending_extent(u64 start, u64 size);
#endif #endif

View file

@ -203,16 +203,16 @@ int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans, struct
btrfs_root *root) btrfs_root *root)
{ {
u64 first = 0; u64 first = 0;
struct pending_extent *pe; struct cache_extent *pe;
struct pending_extent *next; struct cache_extent *next;
pe = find_first_pending_extent(&root->fs_info->pinned_tree, 0); pe = find_first_cache_extent(&root->fs_info->pinned_tree, 0);
if (pe) if (pe)
first = pe->start; first = pe->start;
while(pe) { while(pe) {
next = next_pending_extent(pe); next = next_cache_extent(pe);
remove_pending_extent(&root->fs_info->pinned_tree, pe); remove_cache_extent(&root->fs_info->pinned_tree, pe);
free_pending_extent(pe); free_cache_extent(pe);
pe = next; pe = next;
} }
root->fs_info->last_insert.objectid = first; root->fs_info->last_insert.objectid = first;
@ -227,25 +227,25 @@ static int finish_current_insert(struct btrfs_trans_handle *trans, struct
struct btrfs_extent_item extent_item; struct btrfs_extent_item extent_item;
int ret; int ret;
struct btrfs_fs_info *info = extent_root->fs_info; struct btrfs_fs_info *info = extent_root->fs_info;
struct pending_extent *pe; struct cache_extent *pe;
struct pending_extent *next; struct cache_extent *next;
struct pending_tree *pending_tree = &info->pending_tree; struct cache_tree *pending_tree = &info->pending_tree;
btrfs_set_extent_refs(&extent_item, 1); btrfs_set_extent_refs(&extent_item, 1);
btrfs_set_extent_owner(&extent_item, extent_root->root_key.objectid); btrfs_set_extent_owner(&extent_item, extent_root->root_key.objectid);
ins.offset = 1; ins.offset = 1;
btrfs_set_key_type(&ins, BTRFS_EXTENT_ITEM_KEY); btrfs_set_key_type(&ins, BTRFS_EXTENT_ITEM_KEY);
pe = find_first_pending_extent(pending_tree, 0); pe = find_first_cache_extent(pending_tree, 0);
while(pe) { while(pe) {
ins.offset = pe->size; ins.offset = pe->size;
ins.objectid = pe->start; ins.objectid = pe->start;
remove_pending_extent(pending_tree, pe); remove_cache_extent(pending_tree, pe);
next = next_pending_extent(pe); next = next_cache_extent(pe);
if (!next) if (!next)
next = find_first_pending_extent(pending_tree, 0); next = find_first_cache_extent(pending_tree, 0);
free_pending_extent(pe); free_cache_extent(pe);
pe = next; pe = next;
ret = btrfs_insert_item(trans, extent_root, &ins, &extent_item, ret = btrfs_insert_item(trans, extent_root, &ins, &extent_item,
@ -293,7 +293,7 @@ static int __free_extent(struct btrfs_trans_handle *trans, struct btrfs_root
u64 super_bytes_used, root_bytes_used; u64 super_bytes_used, root_bytes_used;
if (pin) { if (pin) {
int err; int err;
err = insert_pending_extent(&info->pinned_tree, err = insert_cache_extent(&info->pinned_tree,
bytenr, num_bytes); bytenr, num_bytes);
BUG_ON(err); BUG_ON(err);
} }
@ -326,20 +326,20 @@ static int del_pending_extents(struct btrfs_trans_handle *trans, struct
btrfs_root *extent_root) btrfs_root *extent_root)
{ {
int ret; int ret;
struct pending_extent *pe; struct cache_extent *pe;
struct pending_extent *next; struct cache_extent *next;
struct pending_tree *del_pending = &extent_root->fs_info->del_pending; struct cache_tree *del_pending = &extent_root->fs_info->del_pending;
pe = find_first_pending_extent(del_pending, 0); pe = find_first_cache_extent(del_pending, 0);
while(pe) { while(pe) {
remove_pending_extent(del_pending, pe); remove_cache_extent(del_pending, pe);
ret = __free_extent(trans, extent_root, ret = __free_extent(trans, extent_root,
pe->start, pe->size, 1); pe->start, pe->size, 1);
BUG_ON(ret); BUG_ON(ret);
next = next_pending_extent(pe); next = next_cache_extent(pe);
if (!next) if (!next)
next = find_first_pending_extent(del_pending, 0); next = find_first_cache_extent(del_pending, 0);
free_pending_extent(pe); free_cache_extent(pe);
pe = next; pe = next;
} }
return 0; return 0;
@ -364,7 +364,7 @@ int btrfs_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root
int ret; int ret;
if (root == extent_root) { if (root == extent_root) {
ret = insert_pending_extent(&root->fs_info->del_pending, ret = insert_cache_extent(&root->fs_info->del_pending,
bytenr, num_bytes); bytenr, num_bytes);
BUG_ON(ret); BUG_ON(ret);
return 0; return 0;
@ -460,12 +460,12 @@ check_pending:
*/ */
btrfs_release_path(root, &path); btrfs_release_path(root, &path);
BUG_ON(ins->objectid < search_start); BUG_ON(ins->objectid < search_start);
if (find_pending_extent(&root->fs_info->pinned_tree, if (find_cache_extent(&root->fs_info->pinned_tree,
ins->objectid, total_needed)) { ins->objectid, total_needed)) {
search_start = ins->objectid + total_needed; search_start = ins->objectid + total_needed;
goto check_failed; goto check_failed;
} }
if (find_pending_extent(&root->fs_info->pending_tree, if (find_cache_extent(&root->fs_info->pending_tree,
ins->objectid, total_needed)) { ins->objectid, total_needed)) {
search_start = ins->objectid + total_needed; search_start = ins->objectid + total_needed;
goto check_failed; goto check_failed;
@ -511,7 +511,7 @@ static int alloc_extent(struct btrfs_trans_handle *trans,
btrfs_set_root_bytes_used(&root->root_item, root_bytes_used + btrfs_set_root_bytes_used(&root->root_item, root_bytes_used +
num_bytes); num_bytes);
if (root == extent_root) { if (root == extent_root) {
ret = insert_pending_extent(&root->fs_info->pending_tree, ret = insert_cache_extent(&root->fs_info->pending_tree,
ins->objectid, ins->offset); ins->objectid, ins->offset);
BUG_ON(ret); BUG_ON(ret);
return 0; return 0;