Create a slightly more generic extent-caching structure
This commit is contained in:
parent
38f79f9077
commit
28de03cb0a
8 changed files with 319 additions and 229 deletions
5
Makefile
5
Makefile
|
@ -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
343
btrfsck.c
|
@ -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
21
ctree.h
|
@ -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);
|
||||||
|
|
39
disk-io.c
39
disk-io.c
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
|
@ -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
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in a new issue