Full back reference support

This patch makes the back reference system to explicit record the
location of parent node for all types of extents. The location of
parent node is placed into the offset field of backref key. Every
time a tree block is balanced, the back references for the affected
lower level extents are updated.
master
Zheng Yan 2008-09-23 12:29:10 -04:00 committed by David Woodhouse
parent cea88ec1d7
commit 428b7fa630
9 changed files with 931 additions and 668 deletions

116
btrfsck.c
View File

@ -38,12 +38,14 @@ static u64 data_bytes_referenced = 0;
struct extent_backref {
struct list_head list;
u64 parent;
u64 root;
u64 generation;
u64 owner;
u64 offset;
u32 num_refs;
u32 found_ref;
int found_extent_tree;
int found_ref;
};
struct extent_record {
@ -156,34 +158,51 @@ static int all_backpointers_checked(struct extent_record *rec, int print_errs)
err = 1;
if (!print_errs)
goto out;
fprintf(stderr, "Backref %llu [%llu %llu %llu %llu] "
"not found in extent tree\n",
fprintf(stderr, "Backref %llu parent %llu"
" [%llu %llu %llu %llu %lu]"
" not found in extent tree\n",
(unsigned long long)rec->start,
(unsigned long long)back->parent,
(unsigned long long)back->root,
(unsigned long long)back->generation,
(unsigned long long)back->owner,
(unsigned long long)back->offset);
(unsigned long long)back->offset,
(unsigned long)back->num_refs);
}
if (!back->found_ref) {
err = 1;
if (!print_errs)
goto out;
fprintf(stderr, "Backref %llu [%llu %llu %llu %llu] "
"not referenced\n",
fprintf(stderr, "Backref %llu parent %llu"
" [%llu %llu %llu %llu %lu]"
" not referenced\n",
(unsigned long long)rec->start,
(unsigned long long)back->parent,
(unsigned long long)back->root,
(unsigned long long)back->generation,
(unsigned long long)back->owner,
(unsigned long long)back->offset);
(unsigned long long)back->offset,
(unsigned long)back->num_refs);
}
found++;
if (back->found_ref != back->num_refs) {
err = 1;
if (!print_errs)
goto out;
fprintf(stderr, "Incorrect local backref count "
"on %llu parent %llu found %u wanted %u\n",
(unsigned long long)rec->start,
(unsigned long long)back->parent,
back->found_ref, back->num_refs);
}
found += back->found_ref;
}
if (found != rec->refs) {
err = 1;
if (!print_errs)
goto out;
fprintf(stderr, "Incorrect backref count on %llu found %u "
"wanted %u\n", (unsigned long long)rec->start,
fprintf(stderr, "Incorrect global backref count "
"on %llu found %u wanted %u\n",
(unsigned long long)rec->start,
found, rec->refs);
}
out:
@ -239,8 +258,7 @@ static int check_block(struct btrfs_root *root,
}
static struct extent_backref *find_backref(struct extent_record *rec,
u64 root, u64 gen,
u64 owner, u64 owner_offset)
u64 parent, u64 root, u64 gen)
{
struct list_head *cur = rec->backrefs.next;
struct extent_backref *back;
@ -248,11 +266,9 @@ static struct extent_backref *find_backref(struct extent_record *rec,
while(cur != &rec->backrefs) {
back = list_entry(cur, struct extent_backref, list);
cur = cur->next;
if (back->root != root || gen != back->generation)
if (back->parent != parent)
continue;
if (owner < BTRFS_FIRST_FREE_OBJECTID)
return back;
if (owner != back->owner || owner_offset != back->offset)
if (back->root != root || back->generation != gen)
continue;
return back;
}
@ -260,14 +276,16 @@ static struct extent_backref *find_backref(struct extent_record *rec,
}
static struct extent_backref *alloc_backref(struct extent_record *rec,
u64 root, u64 gen, u64 owner,
u64 owner_offset)
u64 parent, u64 root, u64 gen,
u64 owner, u64 owner_offset)
{
struct extent_backref *ref = malloc(sizeof(*ref));
ref->parent = parent;
ref->root = root;
ref->generation = gen;
ref->owner = owner;
ref->offset = owner_offset;
ref->num_refs = 0;
ref->found_extent_tree = 0;
ref->found_ref = 0;
list_add_tail(&ref->list, &rec->backrefs);
@ -351,16 +369,13 @@ static int add_extent_rec(struct cache_tree *extent_cache,
}
static int add_backref(struct cache_tree *extent_cache, u64 bytenr,
u64 root, u64 gen, u64 owner, u64 owner_offset,
int found_ref)
u64 parent, u64 root, u64 gen, u64 owner,
u64 owner_offset, u32 num_refs, int found_ref)
{
struct extent_record *rec;
struct extent_backref *back;
struct cache_extent *cache;
if (root < BTRFS_FS_TREE_OBJECTID)
gen = 0;
cache = find_cache_extent(extent_cache, bytenr, 1);
if (!cache) {
add_extent_rec(extent_cache, NULL, 0, bytenr, 1, 0, 0, 0);
@ -373,31 +388,41 @@ static int add_backref(struct cache_tree *extent_cache, u64 bytenr,
if (rec->start != bytenr) {
abort();
}
back = find_backref(rec, root, gen, owner, owner_offset);
back = find_backref(rec, parent, root, gen);
if (!back)
back = alloc_backref(rec, root, gen, owner, owner_offset);
back = alloc_backref(rec, parent, root, gen, owner,
owner_offset);
if (found_ref) {
if (back->found_ref) {
fprintf(stderr, "Back ref already exists for %llu "
"root %llu gen %llu owner %llu offset %llu\n",
if (back->found_ref > 0 &&
back->owner < BTRFS_FIRST_FREE_OBJECTID) {
fprintf(stderr, "Extent back ref already exists "
"for %llu parent %llu root %llu gen %llu "
"owner %llu offset %llu num_refs %lu\n",
(unsigned long long)parent,
(unsigned long long)bytenr,
(unsigned long long)root,
(unsigned long long)gen,
(unsigned long long)owner,
(unsigned long long)owner_offset);
(unsigned long long)owner_offset,
(unsigned long)num_refs);
}
back->found_ref = 1;
BUG_ON(num_refs != 1);
back->found_ref += 1;
} else {
if (back->found_extent_tree) {
fprintf(stderr, "Extent back ref already exists "
"for %llu root %llu gen %llu owner %llu "
"offset %llu\n", (unsigned long long)bytenr,
"for %llu parent %llu root %llu gen %llu "
"owner %llu offset %llu num_refs %lu\n",
(unsigned long long)parent,
(unsigned long long)bytenr,
(unsigned long long)root,
(unsigned long long)gen,
(unsigned long long)owner,
(unsigned long long)owner_offset);
(unsigned long long)owner_offset,
(unsigned long)num_refs);
}
back->num_refs = num_refs;
back->found_extent_tree = 1;
}
return 0;
@ -589,13 +614,14 @@ static int run_next_block(struct btrfs_root *root,
BTRFS_EXTENT_REF_KEY) {
ref = btrfs_item_ptr(buf, i,
struct btrfs_extent_ref);
add_backref(extent_cache,
btrfs_disk_key_objectid(&disk_key),
btrfs_ref_root(buf, ref),
btrfs_ref_generation(buf, ref),
btrfs_ref_objectid(buf, ref),
btrfs_ref_offset(buf, ref), 0);
btrfs_disk_key_objectid(&disk_key),
btrfs_disk_key_offset(&disk_key),
btrfs_ref_root(buf, ref),
btrfs_ref_generation(buf, ref),
btrfs_ref_objectid(buf, ref),
btrfs_ref_offset(buf, ref),
btrfs_ref_num_refs(buf, ref), 0);
continue;
}
if (btrfs_disk_key_type(&disk_key) !=
@ -622,10 +648,11 @@ static int run_next_block(struct btrfs_root *root,
0, 1, 1);
add_backref(extent_cache,
btrfs_file_extent_disk_bytenr(buf, fi),
buf->start,
btrfs_header_owner(buf),
btrfs_header_generation(buf),
btrfs_disk_key_objectid(&disk_key),
btrfs_disk_key_offset(&disk_key), 1);
btrfs_disk_key_offset(&disk_key), 1, 1);
BUG_ON(ret);
}
} else {
@ -641,11 +668,10 @@ static int run_next_block(struct btrfs_root *root,
0, 1, 0);
BUG_ON(ret);
add_backref(extent_cache, ptr,
add_backref(extent_cache, ptr, buf->start,
btrfs_header_owner(buf),
btrfs_header_generation(buf),
level - 1,
btrfs_disk_key_objectid(&disk_key), 1);
level - 1, 0, 1, 1);
if (level > 1) {
add_pending(nodes, seen, ptr, size);
@ -677,9 +703,9 @@ static int add_root_to_pending(struct extent_buffer *buf,
add_extent_rec(extent_cache, NULL, 0, buf->start, buf->len,
0, 1, 0);
add_backref(extent_cache, buf->start, root_objectid,
add_backref(extent_cache, buf->start, buf->start, root_objectid,
btrfs_header_generation(buf),
btrfs_header_level(buf), 0, 1);
btrfs_header_level(buf), 0, 1, 1);
return 0;
}

View File

@ -317,6 +317,8 @@ static int record_file_extent(struct btrfs_trans_handle *trans,
int ret;
struct btrfs_fs_info *info = root->fs_info;
struct btrfs_root *extent_root = info->extent_root;
struct extent_buffer *leaf;
struct btrfs_file_extent_item *fi;
struct btrfs_key ins_key;
struct btrfs_path path;
struct btrfs_extent_item extent_item;
@ -324,13 +326,15 @@ static int record_file_extent(struct btrfs_trans_handle *trans,
u64 nblocks;
u64 bytes_used;
ret = btrfs_insert_file_extent(trans, root, objectid, file_pos,
disk_bytenr, num_bytes, num_bytes);
if (ret || disk_bytenr == 0)
if (disk_bytenr == 0) {
ret = btrfs_insert_file_extent(trans, root, objectid,
file_pos, disk_bytenr,
num_bytes, num_bytes);
return ret;
}
btrfs_init_path(&path);
nblocks = btrfs_stack_inode_nblocks(inode) + num_bytes / 512;
btrfs_set_stack_inode_nblocks(inode, nblocks);
if (checksum) {
u64 offset;
char *buffer;
@ -355,36 +359,53 @@ static int record_file_extent(struct btrfs_trans_handle *trans,
goto fail;
}
ins_key.objectid = objectid;
ins_key.offset = file_pos;
btrfs_set_key_type(&ins_key, BTRFS_EXTENT_DATA_KEY);
ret = btrfs_insert_empty_item(trans, root, &path, &ins_key,
sizeof(*fi));
if (ret)
goto fail;
leaf = path.nodes[0];
fi = btrfs_item_ptr(leaf, path.slots[0],
struct btrfs_file_extent_item);
btrfs_set_file_extent_generation(leaf, fi, trans->transid);
btrfs_set_file_extent_type(leaf, fi, BTRFS_FILE_EXTENT_REG);
btrfs_set_file_extent_disk_bytenr(leaf, fi, disk_bytenr);
btrfs_set_file_extent_disk_num_bytes(leaf, fi, num_bytes);
btrfs_set_file_extent_offset(leaf, fi, 0);
btrfs_set_file_extent_num_bytes(leaf, fi, num_bytes);
btrfs_mark_buffer_dirty(leaf);
nblocks = btrfs_stack_inode_nblocks(inode) + num_bytes / 512;
btrfs_set_stack_inode_nblocks(inode, nblocks);
bytes_used = btrfs_root_used(&root->root_item);
btrfs_set_root_used(&root->root_item, bytes_used + num_bytes);
ins_key.objectid = disk_bytenr;
ins_key.offset = num_bytes;
btrfs_set_key_type(&ins_key, BTRFS_EXTENT_ITEM_KEY);
btrfs_set_stack_extent_refs(&extent_item, 1);
btrfs_set_stack_extent_refs(&extent_item, 0);
ret = btrfs_insert_item(trans, extent_root, &ins_key,
&extent_item, sizeof(extent_item));
if (ret == 0) {
bytes_used = btrfs_super_bytes_used(&info->super_copy);
btrfs_set_super_bytes_used(&info->super_copy, bytes_used +
num_bytes);
btrfs_init_path(&path);
ret = btrfs_insert_extent_backref(trans, extent_root, &path,
disk_bytenr, root->root_key.objectid,
trans->transid, objectid, file_pos);
if (ret)
goto fail;
ret = btrfs_update_block_group(trans, root, disk_bytenr,
num_bytes, 1, 0);
} else if (ret == -EEXIST) {
ret = btrfs_inc_extent_ref(trans, root, disk_bytenr, num_bytes,
root->root_key.objectid,
trans->transid, objectid, file_pos);
} else if (ret != -EEXIST) {
goto fail;
}
btrfs_extent_post_op(trans, extent_root);
ret = btrfs_inc_extent_ref(trans, root, disk_bytenr, num_bytes,
leaf->start, root->root_key.objectid,
trans->transid, objectid, file_pos);
if (ret)
goto fail;
btrfs_extent_post_op(trans, extent_root);
return 0;
ret = 0;
fail:
btrfs_release_path(root, &path);
return ret;
}
@ -1795,6 +1816,13 @@ static int relocate_one_reference(struct btrfs_trans_handle *trans,
ret = btrfs_del_item(trans, root, &path);
if (ret)
goto fail;
ret = btrfs_free_extent(trans, root, extent_start, extent_size,
leaf->start, root_owner, root_gen, objectid,
offset, 0);
if (ret)
goto fail;
btrfs_release_path(root, &path);
key.objectid = objectid;
@ -1887,8 +1915,6 @@ static int relocate_one_reference(struct btrfs_trans_handle *trans,
btrfs_mark_buffer_dirty(leaf);
btrfs_release_path(root, &path);
ret = btrfs_free_extent(trans, root, extent_start, extent_size,
root_owner, root_gen, objectid, offset, 0);
fail:
btrfs_release_path(root, &path);
return ret;

204
ctree.c
View File

@ -82,10 +82,8 @@ int btrfs_copy_root(struct btrfs_trans_handle *trans,
struct extent_buffer **cow_ret, u64 new_root_objectid)
{
struct extent_buffer *cow;
u32 nritems;
int ret = 0;
int level;
struct btrfs_key first_key;
struct btrfs_root *new_root;
new_root = kmalloc(sizeof(*new_root), GFP_NOFS);
@ -100,19 +98,9 @@ int btrfs_copy_root(struct btrfs_trans_handle *trans,
WARN_ON(root->ref_cows && trans->transid != root->last_trans);
level = btrfs_header_level(buf);
nritems = btrfs_header_nritems(buf);
if (nritems) {
if (level == 0)
btrfs_item_key_to_cpu(buf, &first_key, 0);
else
btrfs_node_key_to_cpu(buf, &first_key, 0);
} else {
first_key.objectid = 0;
}
cow = __btrfs_alloc_free_block(trans, new_root, buf->len,
new_root_objectid,
trans->transid, first_key.objectid,
level, buf->start, 0);
cow = btrfs_alloc_free_block(trans, new_root, buf->len, 0,
new_root_objectid, trans->transid,
level, buf->start, 0);
if (IS_ERR(cow)) {
kfree(new_root);
return PTR_ERR(cow);
@ -125,7 +113,7 @@ int btrfs_copy_root(struct btrfs_trans_handle *trans,
btrfs_clear_header_flag(cow, BTRFS_HEADER_FLAG_WRITTEN);
WARN_ON(btrfs_header_generation(buf) > trans->transid);
ret = btrfs_inc_ref(trans, new_root, buf);
ret = btrfs_inc_ref(trans, new_root, buf, cow, NULL);
kfree(new_root);
if (ret)
@ -143,38 +131,27 @@ int __btrfs_cow_block(struct btrfs_trans_handle *trans,
struct extent_buffer **cow_ret,
u64 search_start, u64 empty_size)
{
u64 root_gen;
u64 parent_start;
struct extent_buffer *cow;
u32 nritems;
int ret = 0;
int different_trans = 0;
int level;
struct btrfs_key first_key;
if (root->ref_cows) {
root_gen = trans->transid;
} else {
root_gen = 0;
}
WARN_ON(root->ref_cows && trans->transid !=
root->fs_info->running_transaction->transid);
WARN_ON(root->ref_cows && trans->transid != root->last_trans);
if (parent)
parent_start = parent->start;
else
parent_start = 0;
level = btrfs_header_level(buf);
nritems = btrfs_header_nritems(buf);
if (nritems) {
if (level == 0)
btrfs_item_key_to_cpu(buf, &first_key, 0);
else
btrfs_node_key_to_cpu(buf, &first_key, 0);
} else {
first_key.objectid = 0;
}
cow = __btrfs_alloc_free_block(trans, root, buf->len,
root->root_key.objectid,
root_gen, first_key.objectid, level,
search_start, empty_size);
cow = btrfs_alloc_free_block(trans, root, buf->len, parent_start,
root->root_key.objectid, trans->transid,
level, search_start, empty_size);
if (IS_ERR(cow))
return PTR_ERR(cow);
@ -187,26 +164,29 @@ int __btrfs_cow_block(struct btrfs_trans_handle *trans,
WARN_ON(btrfs_header_generation(buf) > trans->transid);
if (btrfs_header_generation(buf) != trans->transid) {
different_trans = 1;
ret = btrfs_inc_ref(trans, root, buf);
ret = btrfs_inc_ref(trans, root, buf, cow, NULL);
if (ret)
return ret;
} else {
ret = btrfs_update_ref(trans, root, buf, cow, 0, nritems);
if (ret)
return ret;
clean_tree_block(trans, root, buf);
}
if (buf == root->node) {
root_gen = btrfs_header_generation(buf);
root->node = cow;
extent_buffer_get(cow);
if (buf != root->commit_root) {
btrfs_free_extent(trans, root, buf->start,
buf->len, root->root_key.objectid,
root_gen, 0, 0, 1);
buf->len, buf->start,
root->root_key.objectid,
btrfs_header_generation(buf),
0, 0, 1);
}
free_extent_buffer(buf);
add_root_to_dirty_list(root);
} else {
root_gen = btrfs_header_generation(parent);
btrfs_set_node_blockptr(parent, parent_slot,
cow->start);
WARN_ON(trans->transid == 0);
@ -215,8 +195,8 @@ int __btrfs_cow_block(struct btrfs_trans_handle *trans,
btrfs_mark_buffer_dirty(parent);
WARN_ON(btrfs_header_generation(parent) != trans->transid);
btrfs_free_extent(trans, root, buf->start, buf->len,
btrfs_header_owner(parent), root_gen,
0, 0, 1);
parent_start, btrfs_header_owner(parent),
btrfs_header_generation(parent), 0, 0, 1);
}
free_extent_buffer(buf);
btrfs_mark_buffer_dirty(cow);
@ -710,6 +690,14 @@ static int balance_level(struct btrfs_trans_handle *trans,
BUG_ON(ret);
root->node = child;
ret = btrfs_update_extent_ref(trans, root, child->start,
mid->start, child->start,
root->root_key.objectid,
trans->transid,
level - 1, 0);
BUG_ON(ret);
add_root_to_dirty_list(root);
path->nodes[level] = NULL;
clean_tree_block(trans, root, mid);
@ -717,7 +705,7 @@ static int balance_level(struct btrfs_trans_handle *trans,
/* once for the path */
free_extent_buffer(mid);
ret = btrfs_free_extent(trans, root, mid->start, mid->len,
root->root_key.objectid,
mid->start, root->root_key.objectid,
btrfs_header_generation(mid), 0, 0, 1);
/* once for the root ptr */
free_extent_buffer(mid);
@ -780,7 +768,7 @@ static int balance_level(struct btrfs_trans_handle *trans,
if (wret)
ret = wret;
wret = btrfs_free_extent(trans, root, bytenr,
blocksize,
blocksize, parent->start,
btrfs_header_owner(parent),
generation, 0, 0, 1);
if (wret)
@ -828,6 +816,7 @@ static int balance_level(struct btrfs_trans_handle *trans,
if (wret)
ret = wret;
wret = btrfs_free_extent(trans, root, bytenr, blocksize,
parent->start,
btrfs_header_owner(parent),
root_gen, 0, 0, 1);
if (wret)
@ -1194,6 +1183,41 @@ static int fixup_low_keys(struct btrfs_trans_handle *trans,
return ret;
}
/*
* update item key.
*
* This function isn't completely safe. It's the caller's responsibility
* that the new key won't break the order
*/
int btrfs_set_item_key_safe(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct btrfs_path *path,
struct btrfs_key *new_key)
{
struct btrfs_disk_key disk_key;
struct extent_buffer *eb;
int slot;
eb = path->nodes[0];
slot = path->slots[0];
if (slot > 0) {
btrfs_item_key(eb, &disk_key, slot - 1);
if (btrfs_comp_keys(&disk_key, new_key) >= 0)
return -1;
}
if (slot < btrfs_header_nritems(eb) - 1) {
btrfs_item_key(eb, &disk_key, slot + 1);
if (btrfs_comp_keys(&disk_key, new_key) <= 0)
return -1;
}
btrfs_cpu_key_to_disk(&disk_key, new_key);
btrfs_set_item_key(eb, &disk_key, slot);
btrfs_mark_buffer_dirty(eb);
if (slot == 0)
fixup_low_keys(trans, root, path, &disk_key, 1);
return 0;
}
/*
* try to push data from one node into the next node left in the
* tree.
@ -1253,6 +1277,9 @@ static int push_node_left(struct btrfs_trans_handle *trans,
btrfs_set_header_nritems(dst, dst_nritems + push_items);
btrfs_mark_buffer_dirty(src);
btrfs_mark_buffer_dirty(dst);
ret = btrfs_update_ref(trans, root, src, dst, dst_nritems, push_items);
BUG_ON(ret);
return ret;
}
@ -1314,6 +1341,9 @@ static int balance_node_right(struct btrfs_trans_handle *trans,
btrfs_mark_buffer_dirty(src);
btrfs_mark_buffer_dirty(dst);
ret = btrfs_update_ref(trans, root, src, dst, 0, push_items);
BUG_ON(ret);
return ret;
}
@ -1328,32 +1358,29 @@ static int noinline insert_new_root(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct btrfs_path *path, int level)
{
u64 root_gen;
u64 lower_gen;
struct extent_buffer *lower;
struct extent_buffer *c;
struct extent_buffer *old;
struct btrfs_disk_key lower_key;
int ret;
BUG_ON(path->nodes[level]);
BUG_ON(path->nodes[level-1] != root->node);
if (root->ref_cows)
root_gen = trans->transid;
else
root_gen = 0;
lower = path->nodes[level-1];
if (level == 1)
btrfs_item_key(lower, &lower_key, 0);
else
btrfs_node_key(lower, &lower_key, 0);
c = __btrfs_alloc_free_block(trans, root, root->nodesize,
c = btrfs_alloc_free_block(trans, root, root->nodesize, 0,
root->root_key.objectid,
root_gen, lower_key.objectid, level,
trans->transid, level,
root->node->start, 0);
if (IS_ERR(c))
return PTR_ERR(c);
memset_extent_buffer(c, 0, 0, root->nodesize);
btrfs_set_header_nritems(c, 1);
btrfs_set_header_level(c, level);
@ -1372,31 +1399,28 @@ static int noinline insert_new_root(struct btrfs_trans_handle *trans,
btrfs_set_node_key(c, &lower_key, 0);
btrfs_set_node_blockptr(c, 0, lower->start);
lower_gen = btrfs_header_generation(lower);
WARN_ON(lower_gen == 0);
WARN_ON(lower_gen != trans->transid);
btrfs_set_node_ptr_generation(c, 0, lower_gen);
btrfs_mark_buffer_dirty(c);
/* the super has an extra ref to root->node */
free_extent_buffer(root->node);
old = root->node;
root->node = c;
ret = btrfs_update_extent_ref(trans, root, lower->start,
lower->start, c->start,
root->root_key.objectid,
trans->transid, level - 1, 0);
BUG_ON(ret);
/* the super has an extra ref to root->node */
free_extent_buffer(old);
add_root_to_dirty_list(root);
extent_buffer_get(c);
path->nodes[level] = c;
path->slots[level] = 0;
if (root->ref_cows && lower_gen != trans->transid) {
struct btrfs_path *back_path = btrfs_alloc_path();
int ret;
ret = btrfs_insert_extent_backref(trans,
root->fs_info->extent_root,
path, lower->start,
root->root_key.objectid,
trans->transid, 0, 0);
BUG_ON(ret);
btrfs_free_path(back_path);
}
return 0;
}
@ -1450,7 +1474,6 @@ static int insert_ptr(struct btrfs_trans_handle *trans, struct btrfs_root
static int split_node(struct btrfs_trans_handle *trans, struct btrfs_root
*root, struct btrfs_path *path, int level)
{
u64 root_gen;
struct extent_buffer *c;
struct extent_buffer *split;
struct btrfs_disk_key disk_key;
@ -1477,17 +1500,12 @@ static int split_node(struct btrfs_trans_handle *trans, struct btrfs_root
}
c_nritems = btrfs_header_nritems(c);
if (root->ref_cows)
root_gen = trans->transid;
else
root_gen = 0;
btrfs_node_key(c, &disk_key, 0);
split = __btrfs_alloc_free_block(trans, root, root->nodesize,
split = btrfs_alloc_free_block(trans, root, root->nodesize,
path->nodes[level + 1]->start,
root->root_key.objectid,
root_gen,
btrfs_disk_key_objectid(&disk_key),
level, c->start, 0);
trans->transid, level, c->start, 0);
if (IS_ERR(split))
return PTR_ERR(split);
@ -1524,6 +1542,9 @@ static int split_node(struct btrfs_trans_handle *trans, struct btrfs_root
if (wret)
ret = wret;
ret = btrfs_update_ref(trans, root, c, split, 0, c_nritems - mid);
BUG_ON(ret);
if (path->slots[level] >= mid) {
path->slots[level] -= mid;
free_extent_buffer(c);
@ -1714,6 +1735,9 @@ static int push_leaf_right(struct btrfs_trans_handle *trans, struct btrfs_root
btrfs_set_node_key(upper, &disk_key, slot + 1);
btrfs_mark_buffer_dirty(upper);
ret = btrfs_update_ref(trans, root, left, right, 0, push_items);
BUG_ON(ret);
/* then fixup the leaf pointer in the path */
if (path->slots[0] >= left_nritems) {
path->slots[0] -= left_nritems;
@ -1874,6 +1898,10 @@ static int push_leaf_left(struct btrfs_trans_handle *trans, struct btrfs_root
if (wret)
ret = wret;
ret = btrfs_update_ref(trans, root, right, left,
old_left_nritems, push_items);
BUG_ON(ret);
/* then fixup the leaf pointer in the path */
if (path->slots[0] < push_items) {
path->slots[0] += old_left_nritems;
@ -1898,7 +1926,6 @@ static int split_leaf(struct btrfs_trans_handle *trans, struct btrfs_root
*root, struct btrfs_key *ins_key,
struct btrfs_path *path, int data_size, int extend)
{
u64 root_gen;
struct extent_buffer *l;
u32 nritems;
int mid;
@ -1917,11 +1944,6 @@ static int split_leaf(struct btrfs_trans_handle *trans, struct btrfs_root
if (extend)
space_needed = data_size;
if (root->ref_cows)
root_gen = trans->transid;
else
root_gen = 0;
/* first try to make some room by pushing left and right */
if (ins_key->type != BTRFS_DIR_ITEM_KEY) {
wret = push_leaf_right(trans, root, path, data_size, 0);
@ -1952,12 +1974,10 @@ again:
nritems = btrfs_header_nritems(l);
mid = (nritems + 1)/ 2;
btrfs_item_key(l, &disk_key, 0);
right = __btrfs_alloc_free_block(trans, root, root->leafsize,
root->root_key.objectid,
root_gen, disk_key.objectid, 0,
l->start, 0);
right = btrfs_alloc_free_block(trans, root, root->leafsize,
path->nodes[1]->start,
root->root_key.objectid,
trans->transid, 0, l->start, 0);
if (IS_ERR(right)) {
BUG_ON(1);
return PTR_ERR(right);
@ -2068,6 +2088,9 @@ again:
btrfs_mark_buffer_dirty(l);
BUG_ON(path->slots[0] != slot);
ret = btrfs_update_ref(trans, root, l, right, 0, nritems);
BUG_ON(ret);
if (mid <= slot) {
free_extent_buffer(path->nodes[0]);
path->nodes[0] = right;
@ -2495,6 +2518,7 @@ int btrfs_del_items(struct btrfs_trans_handle *trans, struct btrfs_root *root,
ret = wret;
wret = btrfs_free_extent(trans, root,
leaf->start, leaf->len,
path->nodes[1]->start,
btrfs_header_owner(path->nodes[1]),
root_gen, 0, 0, 1);
if (wret)
@ -2549,7 +2573,7 @@ int btrfs_del_items(struct btrfs_trans_handle *trans, struct btrfs_root *root,
free_extent_buffer(leaf);
wret = btrfs_free_extent(trans, root, bytenr,
blocksize,
blocksize, path->nodes[1]->start,
btrfs_header_owner(path->nodes[1]),
root_gen, 0, 0, 1);
if (wret)

65
ctree.h
View File

@ -27,7 +27,7 @@
struct btrfs_root;
struct btrfs_trans_handle;
#define BTRFS_MAGIC "_B8RfS_M"
#define BTRFS_MAGIC "_B9RfS_M"
#define BTRFS_MAX_LEVEL 8
@ -60,14 +60,24 @@ struct btrfs_trans_handle;
/* does write ahead logging to speed up fsyncs */
#define BTRFS_TREE_LOG_OBJECTID -6ULL
#define BTRFS_TREE_LOG_FIXUP_OBJECTID -7ULL
/* space balancing */
#define BTRFS_TREE_RELOC_OBJECTID -8ULL
#define BTRFS_DATA_RELOC_TREE_OBJECTID -9ULL
/* dummy objectid represents multiple objectids */
#define BTRFS_MULTIPLE_OBJECTIDS -255ULL
/*
* All files have objectids higher than this.
* All files have objectids in this range.
*/
#define BTRFS_FIRST_FREE_OBJECTID 256ULL
#define BTRFS_LAST_FREE_OBJECTID -256ULL
#define BTRFS_FIRST_CHUNK_TREE_OBJECTID 256ULL
/*
* the device items go into the chunk tree. The key is in the form
* [ 1 BTRFS_DEV_ITEM_KEY device_id ]
@ -342,6 +352,7 @@ struct btrfs_extent_ref {
__le64 generation;
__le64 objectid;
__le64 offset;
__le32 num_refs;
} __attribute__ ((__packed__));
/* dev extents record free space on individual devices. The owner
@ -906,22 +917,25 @@ static inline u8 *btrfs_dev_extent_chunk_tree_uuid(struct btrfs_dev_extent *dev)
return (u8 *)((unsigned long)dev + ptr);
}
/* struct btrfs_extent_item */
BTRFS_SETGET_FUNCS(extent_refs, struct btrfs_extent_item, refs, 32);
/* struct btrfs_extent_ref */
BTRFS_SETGET_FUNCS(ref_root, struct btrfs_extent_ref, root, 64);
BTRFS_SETGET_FUNCS(ref_generation, struct btrfs_extent_ref, generation, 64);
BTRFS_SETGET_FUNCS(ref_objectid, struct btrfs_extent_ref, objectid, 64);
BTRFS_SETGET_FUNCS(ref_offset, struct btrfs_extent_ref, offset, 64);
BTRFS_SETGET_FUNCS(ref_num_refs, struct btrfs_extent_ref, num_refs, 32);
BTRFS_SETGET_STACK_FUNCS(stack_ref_root, struct btrfs_extent_ref, root, 64);
BTRFS_SETGET_STACK_FUNCS(stack_ref_generation, struct btrfs_extent_ref,
generation, 64);
BTRFS_SETGET_STACK_FUNCS(stack_ref_objectid, struct btrfs_extent_ref,
objectid, 64);
BTRFS_SETGET_STACK_FUNCS(stack_ref_offset, struct btrfs_extent_ref, offset, 64);
BTRFS_SETGET_STACK_FUNCS(stack_ref_offset, struct btrfs_extent_ref,
offset, 64);
BTRFS_SETGET_STACK_FUNCS(stack_ref_num_refs, struct btrfs_extent_ref,
num_refs, 32);
/* struct btrfs_extent_item */
BTRFS_SETGET_FUNCS(extent_refs, struct btrfs_extent_item, refs, 32);
BTRFS_SETGET_STACK_FUNCS(stack_extent_refs, struct btrfs_extent_item,
refs, 32);
@ -1291,9 +1305,6 @@ static inline u32 btrfs_level_size(struct btrfs_root *root, int level) {
btrfs_item_offset_nr(leaf, slot)))
/* extent-tree.c */
u32 btrfs_count_snapshots_in_path(struct btrfs_root *root,
struct btrfs_path *count_path,
u64 first_extent);
int btrfs_extent_post_op(struct btrfs_trans_handle *trans,
struct btrfs_root *root);
int btrfs_copy_pinned(struct btrfs_root *root, struct extent_io_tree *copy);
@ -1304,18 +1315,11 @@ struct btrfs_block_group_cache *btrfs_find_block_group(struct btrfs_root *root,
struct btrfs_block_group_cache
*hint, u64 search_start,
int data, int owner);
int btrfs_inc_root_ref(struct btrfs_trans_handle *trans,
struct btrfs_root *root, u64 owner_objectid);
struct extent_buffer *btrfs_alloc_free_block(struct btrfs_trans_handle *trans,
struct btrfs_root *root, u32 size,
u64 root_objectid,
u64 hint, u64 empty_size);
struct extent_buffer *__btrfs_alloc_free_block(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
u32 blocksize,
u32 blocksize, u64 parent,
u64 root_objectid,
u64 ref_generation,
u64 first_objectid,
int level,
u64 hint,
u64 empty_size);
@ -1324,19 +1328,25 @@ int btrfs_grow_extent_tree(struct btrfs_trans_handle *trans,
int btrfs_shrink_extent_tree(struct btrfs_root *root, u64 new_size);
int btrfs_insert_extent_backref(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct btrfs_path *path, u64 bytenr,
struct btrfs_path *path,
u64 bytenr, u64 parent,
u64 root_objectid, u64 ref_generation,
u64 owner, u64 owner_offset);
int btrfs_alloc_extent(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
u64 num_bytes, u64 root_objectid, u64 ref_generation,
u64 num_bytes, u64 parent,
u64 root_objectid, u64 ref_generation,
u64 owner, u64 owner_offset,
u64 empty_size, u64 hint_byte,
u64 search_end, struct btrfs_key *ins, int data);
int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
struct extent_buffer *buf);
struct extent_buffer *orig_buf, struct extent_buffer *buf,
u32 *nr_extents);
int btrfs_update_ref(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct extent_buffer *orig_buf,
struct extent_buffer *buf, int start_slot, int nr);
int btrfs_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root
*root, u64 bytenr, u64 num_bytes,
*root, u64 bytenr, u64 num_bytes, u64 parent,
u64 root_objectid, u64 ref_generation,
u64 owner_objectid, u64 owner_offset, int pin);
int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans,
@ -1344,9 +1354,14 @@ int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans,
struct extent_io_tree *unpin);
int btrfs_inc_extent_ref(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
u64 bytenr, u64 num_bytes,
u64 bytenr, u64 num_bytes, u64 parent,
u64 root_objectid, u64 ref_generation,
u64 owner, u64 owner_offset);
int btrfs_update_extent_ref(struct btrfs_trans_handle *trans,
struct btrfs_root *root, u64 bytenr,
u64 orig_parent, u64 parent,
u64 root_objectid, u64 ref_generation,
u64 owner_objectid, u64 owner_offset);
int btrfs_write_dirty_block_groups(struct btrfs_trans_handle *trans,
struct btrfs_root *root);
int btrfs_free_block_groups(struct btrfs_fs_info *info);
@ -1357,8 +1372,6 @@ int btrfs_make_block_group(struct btrfs_trans_handle *trans,
u64 size);
int btrfs_make_block_groups(struct btrfs_trans_handle *trans,
struct btrfs_root *root);
u64 btrfs_hash_extent_ref(u64 root_objectid, u64 ref_generation,
u64 owner, u64 owner_offset);
int btrfs_update_block_group(struct btrfs_trans_handle *trans,
struct btrfs_root *root, u64 bytenr, u64 num,
int alloc, int mark_free);
@ -1429,7 +1442,9 @@ int btrfs_prev_leaf(struct btrfs_root *root, struct btrfs_path *path);
int btrfs_leaf_free_space(struct btrfs_root *root, struct extent_buffer *leaf);
int btrfs_drop_snapshot(struct btrfs_trans_handle *trans, struct btrfs_root
*root);
int btrfs_set_item_key_safe(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct btrfs_path *path,
struct btrfs_key *new_key);
/* root-item.c */
int btrfs_del_root(struct btrfs_trans_handle *trans, struct btrfs_root *root,

View File

@ -58,13 +58,14 @@ static void print_extent_leaf(struct btrfs_root *root, struct extent_buffer *l)
case BTRFS_EXTENT_REF_KEY:
ref = btrfs_item_ptr(l, i, struct btrfs_extent_ref);
printf("%llu %llu extent back ref root %llu gen %llu "
"owner %llu offset %llu\n",
"owner %llu offset %llu num_refs %lu\n",
(unsigned long long)last,
(unsigned long long)last_len,
(unsigned long long)btrfs_ref_root(l, ref),
(unsigned long long)btrfs_ref_generation(l, ref),
(unsigned long long)btrfs_ref_objectid(l, ref),
(unsigned long long)btrfs_ref_offset(l, ref));
(unsigned long long)btrfs_ref_offset(l, ref),
(unsigned long)btrfs_ref_num_refs(l, ref));
break;
};
fflush(stdout);

File diff suppressed because it is too large Load Diff

21
mkfs.c
View File

@ -69,8 +69,8 @@ static u64 parse_size(char *s)
return atol(s) * mult;
}
static int make_root_dir(int fd, const char *device_name) {
struct btrfs_root *root;
static int make_root_dir(struct btrfs_root *root)
{
struct btrfs_trans_handle *trans;
struct btrfs_key location;
u64 bytes_used;
@ -78,12 +78,6 @@ static int make_root_dir(int fd, const char *device_name) {
u64 chunk_size = 0;
int ret;
root = open_ctree_fd(fd, device_name, 0, O_RDWR);
if (!root) {
fprintf(stderr, "ctree init failed\n");
return -1;
}
trans = btrfs_start_transaction(root, 1);
bytes_used = btrfs_super_bytes_used(&root->fs_info->super_copy);
@ -119,7 +113,6 @@ static int make_root_dir(int fd, const char *device_name) {
chunk_start, chunk_size);
BUG_ON(ret);
// ret = btrfs_make_block_group(trans, root, 0, 1);
ret = btrfs_make_root_dir(trans, root->fs_info->tree_root,
BTRFS_ROOT_TREE_DIR_OBJECTID);
if (ret)
@ -143,7 +136,6 @@ static int make_root_dir(int fd, const char *device_name) {
goto err;
btrfs_commit_transaction(trans, root);
ret = close_ctree(root);
err:
return ret;
}
@ -405,13 +397,15 @@ int main(int ac, char **av)
fprintf(stderr, "error during mkfs %d\n", ret);
exit(1);
}
ret = make_root_dir(fd, file);
root = open_ctree(file, 0, O_RDWR);
root->fs_info->alloc_start = alloc_start;
ret = make_root_dir(root);
if (ret) {
fprintf(stderr, "failed to setup the root directory\n");
exit(1);
}
root = open_ctree(file, 0, O_RDWR);
root->fs_info->alloc_start = alloc_start;
trans = btrfs_start_transaction(root, 1);
if (ac == 0)
@ -463,6 +457,7 @@ int main(int ac, char **av)
raid_groups:
ret = create_raid_groups(trans, root, data_profile,
metadata_profile);
BUG_ON(ret);
printf("fs created label %s on %s\n\tnodesize %u leafsize %u "
"sectorsize %u size %s\n",

View File

@ -213,11 +213,12 @@ void btrfs_print_leaf(struct btrfs_root *root, struct extent_buffer *l)
case BTRFS_EXTENT_REF_KEY:
ref = btrfs_item_ptr(l, i, struct btrfs_extent_ref);
printf("\t\textent back ref root %llu gen %llu "
"owner %llu offset %llu\n",
"owner %llu offset %llu, num_refs %lu\n",
(unsigned long long)btrfs_ref_root(l, ref),
(unsigned long long)btrfs_ref_generation(l, ref),
(unsigned long long)btrfs_ref_objectid(l, ref),
(unsigned long long)btrfs_ref_offset(l, ref));
(unsigned long long)btrfs_ref_offset(l, ref),
(unsigned long)btrfs_ref_num_refs(l, ref));
break;
case BTRFS_CSUM_ITEM_KEY:
ci = btrfs_item_ptr(l, i, struct btrfs_csum_item);

13
utils.c
View File

@ -74,9 +74,7 @@ int make_btrfs(int fd, const char *device, const char *label,
int ret;
u32 itemoff;
u32 nritems = 0;
u64 hash;
u64 first_free;
u64 ref_gen;
u64 ref_root;
u32 array_size;
u32 item_size;
@ -213,15 +211,9 @@ int make_btrfs(int fd, const char *device, const char *label,
/* create extent ref */
ref_root = reference_root_table[i];
if (ref_root == BTRFS_FS_TREE_OBJECTID)
ref_gen = 1;
else
ref_gen = 0;
hash = btrfs_hash_extent_ref(ref_root, ref_gen, 0, 0);
itemoff = itemoff - sizeof(struct btrfs_extent_ref);
btrfs_set_disk_key_objectid(&disk_key, blocks[i]);
btrfs_set_disk_key_offset(&disk_key, hash);
btrfs_set_disk_key_offset(&disk_key, blocks[i]);
btrfs_set_disk_key_type(&disk_key, BTRFS_EXTENT_REF_KEY);
btrfs_set_item_key(buf, &disk_key, nritems);
btrfs_set_item_offset(buf, btrfs_item_nr(buf, nritems),
@ -231,9 +223,10 @@ int make_btrfs(int fd, const char *device, const char *label,
extent_ref = btrfs_item_ptr(buf, nritems,
struct btrfs_extent_ref);
btrfs_set_ref_root(buf, extent_ref, ref_root);
btrfs_set_ref_generation(buf, extent_ref, ref_gen);
btrfs_set_ref_generation(buf, extent_ref, 1);
btrfs_set_ref_objectid(buf, extent_ref, 0);
btrfs_set_ref_offset(buf, extent_ref, 0);
btrfs_set_ref_num_refs(buf, extent_ref, 1);
nritems++;
}
btrfs_set_header_bytenr(buf, blocks[2]);