Mixed back reference (FORWARD ROLLING FORMAT CHANGE)

This commit introduces a new kind of back reference for btrfs metadata.
Once a filesystem has been mounted with this commit, IT WILL NO LONGER
BE MOUNTABLE BY OLDER KERNELS.

The new back ref provides information about pointer's key, level and in which
tree the pointer lives. This information allow us to find the pointer by
searching the tree. The shortcoming of the new back ref is that it only works
for pointers in tree blocks referenced by their owner trees.

This is mostly a problem for snapshots, where resolving one of these fuzzy back
references would be O(number_of_snapshots) and quite slow.  The solution used
here is to use the fuzzy back references in the common case where a given tree
block is only referenced by one root, and use the full back references when
multiple roots have a reference
This commit is contained in:
Chris Mason 2009-05-29 16:35:30 -04:00
parent 2d39a83829
commit 95d3f20b51
15 changed files with 2764 additions and 1252 deletions

View File

@ -1,10 +1,11 @@
CC=gcc
AM_CFLAGS = -Wall -fno-strict-aliasing -D_FILE_OFFSET_BITS=64 -D_FORTIFY_SOURCE=2
AM_CFLAGS = -Wall -D_FILE_OFFSET_BITS=64 -D_FORTIFY_SOURCE=2
CFLAGS = -g -Werror -Os
objects = ctree.o disk-io.o radix-tree.o extent-tree.o print-tree.o \
root-tree.o dir-item.o file-item.o inode-item.o \
inode-map.o crc32c.o rbtree.o extent-cache.o extent_io.o \
volumes.o utils.o
#
CHECKFLAGS=-D__linux__ -Dlinux -D__STDC__ -Dunix -D__unix__ -Wbitwise \
-Wuninitialized -Wshadow -Wundef
@ -15,8 +16,7 @@ prefix ?= /usr/local
bindir = $(prefix)/bin
LIBS=-luuid
progs = btrfsctl btrfsck mkfs.btrfs btrfs-debug-tree btrfs-show btrfs-vol \
btrfstune btrfs-image
progs = btrfsctl mkfs.btrfs btrfs-debug-tree btrfs-show btrfs-vol btrfsck
# make C=1 to enable sparse
ifdef C

View File

@ -440,6 +440,42 @@ static int add_metadata(u64 start, u64 size, struct metadump_struct *md)
return 0;
}
#ifdef BTRFS_COMPAT_EXTENT_TREE_V0
static int is_tree_block(struct btrfs_root *extent_root,
struct btrfs_path *path, u64 bytenr)
{
struct extent_buffer *leaf;
struct btrfs_key key;
u64 ref_objectid;
int ret;
leaf = path->nodes[0];
while (1) {
struct btrfs_extent_ref_v0 *ref_item;
path->slots[0]++;
if (path->slots[0] >= btrfs_header_nritems(leaf)) {
ret = btrfs_next_leaf(extent_root, path);
BUG_ON(ret < 0);
if (ret > 0)
break;
leaf = path->nodes[0];
}
btrfs_item_key_to_cpu(leaf, &key, path->slots[0]);
if (key.objectid != bytenr)
break;
if (key.type != BTRFS_EXTENT_REF_V0_KEY)
continue;
ref_item = btrfs_item_ptr(leaf, path->slots[0],
struct btrfs_extent_ref_v0);
ref_objectid = btrfs_ref_objectid_v0(leaf, ref_item);
if (ref_objectid < BTRFS_FIRST_FREE_OBJECTID)
return 1;
break;
}
return 0;
}
#endif
static int create_metadump(const char *input, FILE *out, int num_threads,
int compress_level)
{
@ -447,12 +483,11 @@ static int create_metadump(const char *input, FILE *out, int num_threads,
struct btrfs_root *extent_root;
struct btrfs_path *path;
struct extent_buffer *leaf;
struct btrfs_extent_ref *ref_item;
struct btrfs_extent_item *ei;
struct btrfs_key key;
struct metadump_struct metadump;
u64 bytenr;
u64 num_bytes;
u64 ref_objectid;
int ret;
root = open_ctree(input, 0, 0);
@ -495,29 +530,26 @@ static int create_metadump(const char *input, FILE *out, int num_threads,
bytenr = key.objectid;
num_bytes = key.offset;
while (1) {
path->slots[0]++;
if (path->slots[0] >= btrfs_header_nritems(leaf)) {
ret = btrfs_next_leaf(extent_root, path);
BUG_ON(ret < 0);
if (ret > 0)
break;
leaf = path->nodes[0];
}
btrfs_item_key_to_cpu(leaf, &key, path->slots[0]);
if (key.objectid != bytenr)
break;
if (key.type != BTRFS_EXTENT_REF_KEY)
continue;
ref_item = btrfs_item_ptr(leaf, path->slots[0],
struct btrfs_extent_ref);
ref_objectid = btrfs_ref_objectid(leaf, ref_item);
if (ref_objectid < BTRFS_FIRST_FREE_OBJECTID) {
if (btrfs_item_size_nr(leaf, path->slots[0]) > sizeof(*ei)) {
ei = btrfs_item_ptr(leaf, path->slots[0],
struct btrfs_extent_item);
if (btrfs_extent_flags(leaf, ei) &
BTRFS_EXTENT_FLAG_TREE_BLOCK) {
ret = add_metadata(bytenr, num_bytes,
&metadump);
BUG_ON(ret);
break;
}
} else {
#ifdef BTRFS_COMPAT_EXTENT_TREE_V0
if (is_tree_block(extent_root, path, bytenr)) {
ret = add_metadata(bytenr, num_bytes,
&metadump);
BUG_ON(ret);
}
#else
BUG_ON(1);
#endif
}
bytenr += num_bytes;
}

731
btrfsck.c

File diff suppressed because it is too large Load Diff

View File

@ -24,4 +24,5 @@
u32 crc32c_le(u32 seed, unsigned char const *data, size_t length);
#define crc32c(seed, data, length) crc32c_le(seed, (unsigned char const *)data, length)
#define btrfs_crc32c crc32c
#endif

633
ctree.c
View File

@ -85,6 +85,7 @@ int btrfs_copy_root(struct btrfs_trans_handle *trans,
int ret = 0;
int level;
struct btrfs_root *new_root;
struct btrfs_disk_key disk_key;
new_root = kmalloc(sizeof(*new_root), GFP_NOFS);
if (!new_root)
@ -98,8 +99,12 @@ int btrfs_copy_root(struct btrfs_trans_handle *trans,
WARN_ON(root->ref_cows && trans->transid != root->last_trans);
level = btrfs_header_level(buf);
cow = btrfs_alloc_free_block(trans, new_root, buf->len, 0,
new_root_objectid, trans->transid,
if (level == 0)
btrfs_item_key(buf, &disk_key, 0);
else
btrfs_node_key(buf, &disk_key, 0);
cow = btrfs_alloc_free_block(trans, new_root, buf->len,
new_root_objectid, &disk_key,
level, buf->start, 0);
if (IS_ERR(cow)) {
kfree(new_root);
@ -109,15 +114,20 @@ int btrfs_copy_root(struct btrfs_trans_handle *trans,
copy_extent_buffer(cow, buf, 0, 0, cow->len);
btrfs_set_header_bytenr(cow, cow->start);
btrfs_set_header_generation(cow, trans->transid);
btrfs_set_header_owner(cow, new_root_objectid);
btrfs_clear_header_flag(cow, BTRFS_HEADER_FLAG_WRITTEN);
btrfs_set_header_backref_rev(cow, BTRFS_MIXED_BACKREF_REV);
btrfs_clear_header_flag(cow, BTRFS_HEADER_FLAG_WRITTEN |
BTRFS_HEADER_FLAG_RELOC);
if (new_root_objectid == BTRFS_TREE_RELOC_OBJECTID)
btrfs_set_header_flag(cow, BTRFS_HEADER_FLAG_RELOC);
else
btrfs_set_header_owner(cow, new_root_objectid);
write_extent_buffer(cow, root->fs_info->fsid,
(unsigned long)btrfs_header_fsid(cow),
BTRFS_FSID_SIZE);
WARN_ON(btrfs_header_generation(buf) > trans->transid);
ret = btrfs_inc_ref(trans, new_root, buf, cow, NULL);
ret = btrfs_inc_ref(trans, new_root, cow, 0);
kfree(new_root);
if (ret)
@ -128,6 +138,123 @@ int btrfs_copy_root(struct btrfs_trans_handle *trans,
return 0;
}
/*
* check if the tree block can be shared by multiple trees
*/
int btrfs_block_can_be_shared(struct btrfs_root *root,
struct extent_buffer *buf)
{
/*
* Tree blocks not in refernece counted trees and tree roots
* are never shared. If a block was allocated after the last
* snapshot and the block was not allocated by tree relocation,
* we know the block is not shared.
*/
if (root->ref_cows &&
buf != root->node && buf != root->commit_root &&
(btrfs_header_generation(buf) <=
btrfs_root_last_snapshot(&root->root_item) ||
btrfs_header_flag(buf, BTRFS_HEADER_FLAG_RELOC)))
return 1;
#ifdef BTRFS_COMPAT_EXTENT_TREE_V0
if (root->ref_cows &&
btrfs_header_backref_rev(buf) < BTRFS_MIXED_BACKREF_REV)
return 1;
#endif
return 0;
}
static noinline int update_ref_for_cow(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct extent_buffer *buf,
struct extent_buffer *cow)
{
u64 refs;
u64 owner;
u64 flags;
u64 new_flags = 0;
int ret;
/*
* Backrefs update rules:
*
* Always use full backrefs for extent pointers in tree block
* allocated by tree relocation.
*
* If a shared tree block is no longer referenced by its owner
* tree (btrfs_header_owner(buf) == root->root_key.objectid),
* use full backrefs for extent pointers in tree block.
*
* If a tree block is been relocating
* (root->root_key.objectid == BTRFS_TREE_RELOC_OBJECTID),
* use full backrefs for extent pointers in tree block.
* The reason for this is some operations (such as drop tree)
* are only allowed for blocks use full backrefs.
*/
if (btrfs_block_can_be_shared(root, buf)) {
ret = btrfs_lookup_extent_info(trans, root, buf->start,
buf->len, &refs, &flags);
BUG_ON(ret);
BUG_ON(refs == 0);
} else {
refs = 1;
if (root->root_key.objectid == BTRFS_TREE_RELOC_OBJECTID ||
btrfs_header_backref_rev(buf) < BTRFS_MIXED_BACKREF_REV)
flags = BTRFS_BLOCK_FLAG_FULL_BACKREF;
else
flags = 0;
}
owner = btrfs_header_owner(buf);
BUG_ON(!(flags & BTRFS_BLOCK_FLAG_FULL_BACKREF) &&
owner == BTRFS_TREE_RELOC_OBJECTID);
if (refs > 1) {
if ((owner == root->root_key.objectid ||
root->root_key.objectid == BTRFS_TREE_RELOC_OBJECTID) &&
!(flags & BTRFS_BLOCK_FLAG_FULL_BACKREF)) {
ret = btrfs_inc_ref(trans, root, buf, 1);
BUG_ON(ret);
if (root->root_key.objectid ==
BTRFS_TREE_RELOC_OBJECTID) {
ret = btrfs_dec_ref(trans, root, buf, 0);
BUG_ON(ret);
ret = btrfs_inc_ref(trans, root, cow, 1);
BUG_ON(ret);
}
new_flags |= BTRFS_BLOCK_FLAG_FULL_BACKREF;
} else {
if (root->root_key.objectid ==
BTRFS_TREE_RELOC_OBJECTID)
ret = btrfs_inc_ref(trans, root, cow, 1);
else
ret = btrfs_inc_ref(trans, root, cow, 0);
BUG_ON(ret);
}
if (new_flags != 0) {
ret = btrfs_set_block_flags(trans, root, buf->start,
buf->len, new_flags);
BUG_ON(ret);
}
} else {
if (flags & BTRFS_BLOCK_FLAG_FULL_BACKREF) {
if (root->root_key.objectid ==
BTRFS_TREE_RELOC_OBJECTID)
ret = btrfs_inc_ref(trans, root, cow, 1);
else
ret = btrfs_inc_ref(trans, root, cow, 0);
BUG_ON(ret);
ret = btrfs_dec_ref(trans, root, buf, 1);
BUG_ON(ret);
}
clean_tree_block(trans, root, buf);
}
return 0;
}
int __btrfs_cow_block(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct extent_buffer *buf,
@ -135,26 +262,25 @@ int __btrfs_cow_block(struct btrfs_trans_handle *trans,
struct extent_buffer **cow_ret,
u64 search_start, u64 empty_size)
{
u64 parent_start;
u64 generation;
struct extent_buffer *cow;
u32 nritems;
int ret = 0;
int different_trans = 0;
struct btrfs_disk_key disk_key;
int level;
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);
cow = btrfs_alloc_free_block(trans, root, buf->len, parent_start,
root->root_key.objectid, trans->transid,
generation = btrfs_header_generation(buf);
if (level == 0)
btrfs_item_key(buf, &disk_key, 0);
else
btrfs_node_key(buf, &disk_key, 0);
cow = btrfs_alloc_free_block(trans, root, buf->len,
root->root_key.objectid, &disk_key,
level, search_start, empty_size);
if (IS_ERR(cow))
return PTR_ERR(cow);
@ -162,36 +288,28 @@ int __btrfs_cow_block(struct btrfs_trans_handle *trans,
copy_extent_buffer(cow, buf, 0, 0, cow->len);
btrfs_set_header_bytenr(cow, cow->start);
btrfs_set_header_generation(cow, trans->transid);
btrfs_set_header_owner(cow, root->root_key.objectid);
btrfs_clear_header_flag(cow, BTRFS_HEADER_FLAG_WRITTEN);
btrfs_set_header_backref_rev(cow, BTRFS_MIXED_BACKREF_REV);
btrfs_clear_header_flag(cow, BTRFS_HEADER_FLAG_WRITTEN |
BTRFS_HEADER_FLAG_RELOC);
if (root->root_key.objectid == BTRFS_TREE_RELOC_OBJECTID)
btrfs_set_header_flag(cow, BTRFS_HEADER_FLAG_RELOC);
else
btrfs_set_header_owner(cow, root->root_key.objectid);
write_extent_buffer(cow, root->fs_info->fsid,
(unsigned long)btrfs_header_fsid(cow),
BTRFS_FSID_SIZE);
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, 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);
}
update_ref_for_cow(trans, root, buf, cow);
if (buf == root->node) {
root->node = cow;
extent_buffer_get(cow);
if (buf != root->commit_root) {
btrfs_free_extent(trans, root, buf->start,
buf->len, buf->start,
root->root_key.objectid,
btrfs_header_generation(buf),
level, 1);
}
btrfs_free_extent(trans, root, buf->start, buf->len,
0, root->root_key.objectid, level, 0);
free_extent_buffer(buf);
add_root_to_dirty_list(root);
} else {
@ -202,9 +320,9 @@ int __btrfs_cow_block(struct btrfs_trans_handle *trans,
trans->transid);
btrfs_mark_buffer_dirty(parent);
WARN_ON(btrfs_header_generation(parent) != trans->transid);
btrfs_free_extent(trans, root, buf->start, buf->len,
parent_start, btrfs_header_owner(parent),
btrfs_header_generation(parent), level, 1);
0, root->root_key.objectid, level, 1);
}
free_extent_buffer(buf);
btrfs_mark_buffer_dirty(cow);
@ -212,6 +330,18 @@ int __btrfs_cow_block(struct btrfs_trans_handle *trans,
return 0;
}
static inline int should_cow_block(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct extent_buffer *buf)
{
if (btrfs_header_generation(buf) == trans->transid &&
!btrfs_header_flag(buf, BTRFS_HEADER_FLAG_WRITTEN) &&
!(root->root_key.objectid != BTRFS_TREE_RELOC_OBJECTID &&
btrfs_header_flag(buf, BTRFS_HEADER_FLAG_RELOC)))
return 0;
return 1;
}
int btrfs_cow_block(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct extent_buffer *buf,
struct extent_buffer *parent, int parent_slot,
@ -232,8 +362,7 @@ int btrfs_cow_block(struct btrfs_trans_handle *trans,
(unsigned long long)root->fs_info->generation);
WARN_ON(1);
}
if (btrfs_header_generation(buf) == trans->transid &&
!btrfs_header_flag(buf, BTRFS_HEADER_FLAG_WRITTEN)) {
if (!should_cow_block(trans, root, buf)) {
*cow_ret = buf;
return 0;
}
@ -698,22 +827,15 @@ 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);
BUG_ON(ret);
add_root_to_dirty_list(root);
path->nodes[level] = NULL;
clean_tree_block(trans, root, mid);
wait_on_tree_block_writeback(root, mid);
/* once for the path */
free_extent_buffer(mid);
ret = btrfs_free_extent(trans, root, mid->start, mid->len,
mid->start, root->root_key.objectid,
btrfs_header_generation(mid),
0, root->root_key.objectid,
level, 1);
/* once for the root ptr */
free_extent_buffer(mid);
@ -764,7 +886,6 @@ static int balance_level(struct btrfs_trans_handle *trans,
ret = wret;
if (btrfs_header_nritems(right) == 0) {
u64 bytenr = right->start;
u64 generation = btrfs_header_generation(parent);
u32 blocksize = right->len;
clean_tree_block(trans, root, right);
@ -776,9 +897,9 @@ 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),
generation, level, 1);
blocksize, 0,
root->root_key.objectid,
level, 0);
if (wret)
ret = wret;
} else {
@ -813,7 +934,6 @@ static int balance_level(struct btrfs_trans_handle *trans,
}
if (btrfs_header_nritems(mid) == 0) {
/* we've managed to empty the middle node, drop it */
u64 root_gen = btrfs_header_generation(parent);
u64 bytenr = mid->start;
u32 blocksize = mid->len;
clean_tree_block(trans, root, mid);
@ -824,9 +944,8 @@ 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, level, 1);
0, root->root_key.objectid,
level, 0);
if (wret)
ret = wret;
} else {
@ -1287,8 +1406,6 @@ static int push_node_left(struct btrfs_trans_handle *trans,
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;
}
@ -1351,8 +1468,6 @@ 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;
}
@ -1372,7 +1487,6 @@ static int noinline insert_new_root(struct btrfs_trans_handle *trans,
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);
@ -1383,18 +1497,19 @@ static int noinline insert_new_root(struct btrfs_trans_handle *trans,
else
btrfs_node_key(lower, &lower_key, 0);
c = btrfs_alloc_free_block(trans, root, root->nodesize, 0,
root->root_key.objectid,
trans->transid, level,
root->node->start, 0);
c = btrfs_alloc_free_block(trans, root, root->nodesize,
root->root_key.objectid, &lower_key,
level, root->node->start, 0);
if (IS_ERR(c))
return PTR_ERR(c);
memset_extent_buffer(c, 0, 0, root->nodesize);
memset_extent_buffer(c, 0, 0, sizeof(struct btrfs_header));
btrfs_set_header_nritems(c, 1);
btrfs_set_header_level(c, level);
btrfs_set_header_bytenr(c, c->start);
btrfs_set_header_generation(c, trans->transid);
btrfs_set_header_backref_rev(c, BTRFS_MIXED_BACKREF_REV);
btrfs_set_header_owner(c, root->root_key.objectid);
write_extent_buffer(c, root->fs_info->fsid,
@ -1417,12 +1532,6 @@ static int noinline insert_new_root(struct btrfs_trans_handle *trans,
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);
BUG_ON(ret);
/* the super has an extra ref to root->node */
free_extent_buffer(old);
@ -1509,21 +1618,21 @@ static int split_node(struct btrfs_trans_handle *trans, struct btrfs_root
}
c_nritems = btrfs_header_nritems(c);
mid = (c_nritems + 1) / 2;
btrfs_node_key(c, &disk_key, mid);
btrfs_node_key(c, &disk_key, 0);
split = btrfs_alloc_free_block(trans, root, root->nodesize,
path->nodes[level + 1]->start,
root->root_key.objectid,
trans->transid, level, c->start, 0);
root->root_key.objectid,
&disk_key, level, c->start, 0);
if (IS_ERR(split))
return PTR_ERR(split);
btrfs_set_header_flags(split, btrfs_header_flags(c));
memset_extent_buffer(split, 0, 0, sizeof(struct btrfs_header));
btrfs_set_header_level(split, btrfs_header_level(c));
btrfs_set_header_bytenr(split, split->start);
btrfs_set_header_generation(split, trans->transid);
btrfs_set_header_backref_rev(split, BTRFS_MIXED_BACKREF_REV);
btrfs_set_header_owner(split, root->root_key.objectid);
btrfs_set_header_flags(split, 0);
write_extent_buffer(split, root->fs_info->fsid,
(unsigned long)btrfs_header_fsid(split),
BTRFS_FSID_SIZE);
@ -1531,7 +1640,6 @@ static int split_node(struct btrfs_trans_handle *trans, struct btrfs_root
(unsigned long)btrfs_header_chunk_tree_uuid(split),
BTRFS_UUID_SIZE);
mid = (c_nritems + 1) / 2;
copy_extent_buffer(split, c,
btrfs_node_key_ptr_offset(0),
@ -1544,16 +1652,12 @@ static int split_node(struct btrfs_trans_handle *trans, struct btrfs_root
btrfs_mark_buffer_dirty(c);
btrfs_mark_buffer_dirty(split);
btrfs_node_key(split, &disk_key, 0);
wret = insert_ptr(trans, root, path, &disk_key, split->start,
path->slots[level + 1] + 1,
level + 1);
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);
@ -1744,9 +1848,6 @@ 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;
@ -1907,10 +2008,6 @@ 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;
@ -1931,138 +2028,20 @@ static int push_leaf_left(struct btrfs_trans_handle *trans, struct btrfs_root
*
* returns 0 if all went well and < 0 on failure.
*/
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)
static noinline int copy_for_split(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct btrfs_path *path,
struct extent_buffer *l,
struct extent_buffer *right,
int slot, int mid, int nritems)
{
struct extent_buffer *l;
u32 nritems;
int mid;
int slot;
struct extent_buffer *right;
int space_needed = data_size + sizeof(struct btrfs_item);
int data_copy_size;
int rt_data_off;
int i;
int ret = 0;
int wret;
int double_split;
int num_doubles = 0;
struct btrfs_disk_key disk_key;
if (extend && data_size)
space_needed = data_size;
/* first try to make some room by pushing left and right */
if (data_size && ins_key->type != BTRFS_DIR_ITEM_KEY) {
wret = push_leaf_right(trans, root, path, data_size, 0);
if (wret < 0) {
return wret;
}
if (wret) {
wret = push_leaf_left(trans, root, path, data_size, 0);
if (wret < 0)
return wret;
}
l = path->nodes[0];
/* did the pushes work? */
if (btrfs_leaf_free_space(root, l) >= space_needed)
return 0;
}
if (!path->nodes[1]) {
ret = insert_new_root(trans, root, path, 1);
if (ret)
return ret;
}
again:
double_split = 0;
l = path->nodes[0];
slot = path->slots[0];
nritems = btrfs_header_nritems(l);
mid = (nritems + 1)/ 2;
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);
}
memset_extent_buffer(right, 0, 0, sizeof(struct btrfs_header));
btrfs_set_header_bytenr(right, right->start);
btrfs_set_header_generation(right, trans->transid);
btrfs_set_header_owner(right, root->root_key.objectid);
btrfs_set_header_level(right, 0);
write_extent_buffer(right, root->fs_info->fsid,
(unsigned long)btrfs_header_fsid(right),
BTRFS_FSID_SIZE);
write_extent_buffer(right, root->fs_info->chunk_tree_uuid,
(unsigned long)btrfs_header_chunk_tree_uuid(right),
BTRFS_UUID_SIZE);
if (mid <= slot) {
if (nritems == 1 ||
leaf_space_used(l, mid, nritems - mid) + space_needed >
BTRFS_LEAF_DATA_SIZE(root)) {
if (slot >= nritems) {
btrfs_cpu_key_to_disk(&disk_key, ins_key);
btrfs_set_header_nritems(right, 0);
wret = insert_ptr(trans, root, path,
&disk_key, right->start,
path->slots[1] + 1, 1);
if (wret)
ret = wret;
free_extent_buffer(path->nodes[0]);
path->nodes[0] = right;
path->slots[0] = 0;
path->slots[1] += 1;
return ret;
}
mid = slot;
if (mid != nritems &&
leaf_space_used(l, mid, nritems - mid) +
space_needed > BTRFS_LEAF_DATA_SIZE(root)) {
double_split = 1;
}
}
} else {
if (leaf_space_used(l, 0, mid + 1) + space_needed >
BTRFS_LEAF_DATA_SIZE(root)) {
if (!extend && data_size && slot == 0) {
btrfs_cpu_key_to_disk(&disk_key, ins_key);
btrfs_set_header_nritems(right, 0);
wret = insert_ptr(trans, root, path,
&disk_key,
right->start,
path->slots[1], 1);
if (wret)
ret = wret;
free_extent_buffer(path->nodes[0]);
path->nodes[0] = right;
path->slots[0] = 0;
if (path->slots[1] == 0) {
wret = fixup_low_keys(trans, root,
path, &disk_key, 1);
if (wret)
ret = wret;
}
return ret;
} else if ((extend || !data_size) && slot == 0) {
mid = 1;
} else {
mid = slot;
if (mid != nritems &&
leaf_space_used(l, mid, nritems - mid) +
space_needed > BTRFS_LEAF_DATA_SIZE(root)) {
double_split = 1;
}
}
}
}
nritems = nritems - mid;
btrfs_set_header_nritems(right, nritems);
data_copy_size = btrfs_item_end_nr(l, mid) - leaf_data_end(root, l);
@ -2097,24 +2076,176 @@ 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;
path->slots[0] -= mid;
path->slots[1] += 1;
} else
} else {
free_extent_buffer(right);
}
BUG_ON(path->slots[0] < 0);
if (double_split) {
return ret;
}
/*
* split the path's leaf in two, making sure there is at least data_size
* available for the resulting leaf level of the path.
*
* returns 0 if all went well and < 0 on failure.
*/
static noinline 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)
{
struct btrfs_disk_key disk_key;
struct extent_buffer *l;
u32 nritems;
int mid;
int slot;
struct extent_buffer *right;
int ret = 0;
int wret;
int split;
int num_doubles = 0;
/* first try to make some room by pushing left and right */
if (data_size && ins_key->type != BTRFS_DIR_ITEM_KEY) {
wret = push_leaf_right(trans, root, path, data_size, 0);
if (wret < 0)
return wret;
if (wret) {
wret = push_leaf_left(trans, root, path, data_size, 0);
if (wret < 0)
return wret;
}
l = path->nodes[0];
/* did the pushes work? */
if (btrfs_leaf_free_space(root, l) >= data_size)
return 0;
}
if (!path->nodes[1]) {
ret = insert_new_root(trans, root, path, 1);
if (ret)
return ret;
}
again:
split = 1;
l = path->nodes[0];
slot = path->slots[0];
nritems = btrfs_header_nritems(l);
mid = (nritems + 1) / 2;
if (mid <= slot) {
if (nritems == 1 ||
leaf_space_used(l, mid, nritems - mid) + data_size >
BTRFS_LEAF_DATA_SIZE(root)) {
if (slot >= nritems) {
split = 0;
} else {
mid = slot;
if (mid != nritems &&
leaf_space_used(l, mid, nritems - mid) +
data_size > BTRFS_LEAF_DATA_SIZE(root)) {
split = 2;
}
}
}
} else {
if (leaf_space_used(l, 0, mid) + data_size >
BTRFS_LEAF_DATA_SIZE(root)) {
if (!extend && data_size && slot == 0) {
split = 0;
} else if ((extend || !data_size) && slot == 0) {
mid = 1;
} else {
mid = slot;
if (mid != nritems &&
leaf_space_used(l, mid, nritems - mid) +
data_size > BTRFS_LEAF_DATA_SIZE(root)) {
split = 2 ;
}
}
}
}
if (split == 0)
btrfs_cpu_key_to_disk(&disk_key, ins_key);
else
btrfs_item_key(l, &disk_key, mid);
right = btrfs_alloc_free_block(trans, root, root->leafsize,
root->root_key.objectid,
&disk_key, 0, l->start, 0);
if (IS_ERR(right)) {
BUG_ON(1);
return PTR_ERR(right);
}
memset_extent_buffer(right, 0, 0, sizeof(struct btrfs_header));
btrfs_set_header_bytenr(right, right->start);
btrfs_set_header_generation(right, trans->transid);
btrfs_set_header_backref_rev(right, BTRFS_MIXED_BACKREF_REV);
btrfs_set_header_owner(right, root->root_key.objectid);
btrfs_set_header_level(right, 0);
write_extent_buffer(right, root->fs_info->fsid,
(unsigned long)btrfs_header_fsid(right),
BTRFS_FSID_SIZE);
write_extent_buffer(right, root->fs_info->chunk_tree_uuid,
(unsigned long)btrfs_header_chunk_tree_uuid(right),
BTRFS_UUID_SIZE);
if (split == 0) {
if (mid <= slot) {
btrfs_set_header_nritems(right, 0);
wret = insert_ptr(trans, root, path,
&disk_key, right->start,
path->slots[1] + 1, 1);
if (wret)
ret = wret;
free_extent_buffer(path->nodes[0]);
path->nodes[0] = right;
path->slots[0] = 0;
path->slots[1] += 1;
} else {
btrfs_set_header_nritems(right, 0);
wret = insert_ptr(trans, root, path,
&disk_key,
right->start,
path->slots[1], 1);
if (wret)
ret = wret;
free_extent_buffer(path->nodes[0]);
path->nodes[0] = right;
path->slots[0] = 0;
if (path->slots[1] == 0) {
wret = fixup_low_keys(trans, root,
path, &disk_key, 1);
if (wret)
ret = wret;
}
}
btrfs_mark_buffer_dirty(right);
return ret;
}
ret = copy_for_split(trans, root, path, l, right, slot, mid, nritems);
BUG_ON(ret);
if (split == 2) {
BUG_ON(num_doubles != 0);
num_doubles++;
goto again;
}
return ret;
}
@ -2579,6 +2710,33 @@ static int del_ptr(struct btrfs_trans_handle *trans, struct btrfs_root *root,
return ret;
}
/*
* a helper function to delete the leaf pointed to by path->slots[1] and
* path->nodes[1].
*
* This deletes the pointer in path->nodes[1] and frees the leaf
* block extent. zero is returned if it all worked out, < 0 otherwise.
*
* The path must have already been setup for deleting the leaf, including
* all the proper balancing. path->nodes[1] must be locked.
*/
static noinline int btrfs_del_leaf(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct btrfs_path *path,
struct extent_buffer *leaf)
{
int ret;
WARN_ON(btrfs_header_generation(leaf) != trans->transid);
ret = del_ptr(trans, root, path, 1, path->slots[1]);
if (ret)
return ret;
ret = btrfs_free_extent(trans, root, leaf->start, leaf->len,
0, root->root_key.objectid, 0, 0);
return ret;
}
/*
* delete the item at the leaf level in path. If that empties
* the leaf, remove it from the tree
@ -2633,17 +2791,11 @@ int btrfs_del_items(struct btrfs_trans_handle *trans, struct btrfs_root *root,
if (leaf == root->node) {
btrfs_set_header_level(leaf, 0);
} else {
u64 root_gen = btrfs_header_generation(path->nodes[1]);
clean_tree_block(trans, root, leaf);
wait_on_tree_block_writeback(root, leaf);
wret = del_ptr(trans, root, path, 1, path->slots[1]);
if (wret)
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, 1);
wret = btrfs_del_leaf(trans, root, path, leaf);
BUG_ON(ret);
if (wret)
ret = wret;
}
@ -2680,27 +2832,14 @@ int btrfs_del_items(struct btrfs_trans_handle *trans, struct btrfs_root *root,
}
if (btrfs_header_nritems(leaf) == 0) {
u64 root_gen;
u64 bytenr = leaf->start;
u32 blocksize = leaf->len;
root_gen = btrfs_header_generation(
path->nodes[1]);
clean_tree_block(trans, root, leaf);
wait_on_tree_block_writeback(root, leaf);
wret = del_ptr(trans, root, path, 1, slot);
if (wret)
ret = wret;
path->slots[1] = slot;
ret = btrfs_del_leaf(trans, root, path, leaf);
BUG_ON(ret);
free_extent_buffer(leaf);
wret = btrfs_free_extent(trans, root, bytenr,
blocksize, path->nodes[1]->start,
btrfs_header_owner(path->nodes[1]),
root_gen, 0, 1);
if (wret)
ret = wret;
} else {
btrfs_mark_buffer_dirty(leaf);
free_extent_buffer(leaf);

221
ctree.h
View File

@ -31,6 +31,8 @@ struct btrfs_trans_handle;
#define BTRFS_MAX_LEVEL 8
#define BTRFS_COMPAT_EXTENT_TREE_V0
/* holds pointers to all of the tree roots */
#define BTRFS_ROOT_TREE_OBJECTID 1ULL
@ -249,7 +251,18 @@ static inline unsigned long btrfs_chunk_item_size(int num_stripes)
}
#define BTRFS_FSID_SIZE 16
#define BTRFS_HEADER_FLAG_WRITTEN (1 << 0)
#define BTRFS_HEADER_FLAG_WRITTEN (1ULL << 0)
#define BTRFS_HEADER_FLAG_RELOC (1ULL << 1)
#define BTRFS_SUPER_FLAG_SEEDING (1ULL << 32)
#define BTRFS_SUPER_FLAG_METADUMP (1ULL << 33)
#define BTRFS_BACKREF_REV_MAX 256
#define BTRFS_BACKREF_REV_SHIFT 56
#define BTRFS_BACKREF_REV_MASK (((u64)BTRFS_BACKREF_REV_MAX - 1) << \
BTRFS_BACKREF_REV_SHIFT)
#define BTRFS_OLD_BACKREF_REV 0
#define BTRFS_MIXED_BACKREF_REV 1
/*
* every tree block (leaf or node) starts with this header.
@ -278,8 +291,6 @@ struct btrfs_header {
sizeof(struct btrfs_item) - \
sizeof(struct btrfs_file_extent_item))
#define BTRFS_SUPER_FLAG_SEEDING (1ULL << 32)
#define BTRFS_SUPER_FLAG_METADUMP (1ULL << 33)
/*
* this is a very generous portion of the super block, giving us
@ -338,9 +349,12 @@ struct btrfs_super_block {
* Compat flags that we support. If any incompat flags are set other than the
* ones specified below then we will fail to mount
*/
#define BTRFS_FEATURE_COMPAT_SUPP 0x0
#define BTRFS_FEATURE_COMPAT_RO_SUPP 0x0
#define BTRFS_FEATURE_INCOMPAT_SUPP 0x0
#define BTRFS_FEATURE_INCOMPAT_MIXED_BACKREF (1ULL << 0)
#define BTRFS_FEATURE_COMPAT_SUPP 0ULL
#define BTRFS_FEATURE_COMPAT_RO_SUPP 0ULL
#define BTRFS_FEATURE_INCOMPAT_SUPP \
BTRFS_FEATURE_INCOMPAT_MIXED_BACKREF
/*
* A leaf is full of items. offset and size tell us where to find
@ -387,32 +401,78 @@ struct btrfs_node {
* The slots array records the index of the item or block pointer
* used while walking the tree.
*/
struct btrfs_path {
struct extent_buffer *nodes[BTRFS_MAX_LEVEL];
int slots[BTRFS_MAX_LEVEL];
/* if there is real range locking, this locks field will change */
int locks[BTRFS_MAX_LEVEL];
int reada;
/* keep some upper locks as we walk down */
int lowest_level;
/*
* set by btrfs_split_item, tells search_slot to keep all locks
* and to force calls to keep space in the nodes
*/
int search_for_split;
unsigned int search_for_split:1;
unsigned int keep_locks:1;
unsigned int skip_locking:1;
unsigned int leave_spinning:1;
};
/*
* items in the extent btree are used to record the objectid of the
* owner of the block and the number of references
*/
struct btrfs_extent_item {
__le64 refs;
__le64 generation;
__le64 flags;
} __attribute__ ((__packed__));
struct btrfs_extent_item_v0 {
__le32 refs;
} __attribute__ ((__packed__));
struct btrfs_extent_ref {
#define BTRFS_MAX_EXTENT_ITEM_SIZE(r) ((BTRFS_LEAF_DATA_SIZE(r) >> 4) - \
sizeof(struct btrfs_item))
#define BTRFS_EXTENT_FLAG_DATA (1ULL << 0)
#define BTRFS_EXTENT_FLAG_TREE_BLOCK (1ULL << 1)
/* following flags only apply to tree blocks */
/* use full backrefs for extent pointers in the block*/
#define BTRFS_BLOCK_FLAG_FULL_BACKREF (1ULL << 8)
struct btrfs_tree_block_info {
struct btrfs_disk_key key;
u8 level;
} __attribute__ ((__packed__));
struct btrfs_extent_data_ref {
__le64 root;
__le64 objectid;
__le64 offset;
__le32 count;
} __attribute__ ((__packed__));
struct btrfs_shared_data_ref {
__le32 count;
} __attribute__ ((__packed__));
struct btrfs_extent_inline_ref {
u8 type;
u64 offset;
} __attribute__ ((__packed__));
struct btrfs_extent_ref_v0 {
__le64 root;
__le64 generation;
__le64 objectid;
__le32 num_refs;
__le32 count;
} __attribute__ ((__packed__));
/* dev extents record free space on individual devices. The owner
@ -626,6 +686,8 @@ struct btrfs_fs_info {
struct btrfs_root *dev_root;
struct btrfs_root *csum_root;
struct cache_tree fs_root_cache;
/* the log root tree is a directory of all the other log roots */
struct btrfs_root *log_root_tree;
@ -701,6 +763,7 @@ struct btrfs_root {
/* the dirty list is only used by non-reference counted roots */
struct list_head dirty_list;
struct cache_extent cache;
};
/*
@ -761,7 +824,18 @@ struct btrfs_root {
* are used, and how many references there are to each block
*/
#define BTRFS_EXTENT_ITEM_KEY 168
#define BTRFS_EXTENT_REF_KEY 180
#define BTRFS_TREE_BLOCK_REF_KEY 176
#define BTRFS_EXTENT_DATA_REF_KEY 178
/* old style extent backrefs */
#define BTRFS_EXTENT_REF_V0_KEY 180
#define BTRFS_SHARED_BLOCK_REF_KEY 182
#define BTRFS_SHARED_DATA_REF_KEY 184
/*
* block groups give us hints into the extent allocation trees. Which
@ -1066,24 +1140,68 @@ static inline u8 *btrfs_dev_extent_chunk_tree_uuid(struct btrfs_dev_extent *dev)
return (u8 *)((unsigned long)dev + ptr);
}
/* 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_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_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);
BTRFS_SETGET_FUNCS(extent_refs, struct btrfs_extent_item, refs, 64);
BTRFS_SETGET_FUNCS(extent_generation, struct btrfs_extent_item,
generation, 64);
BTRFS_SETGET_FUNCS(extent_flags, struct btrfs_extent_item, flags, 64);
BTRFS_SETGET_FUNCS(extent_refs_v0, struct btrfs_extent_item_v0, refs, 32);
BTRFS_SETGET_FUNCS(tree_block_level, struct btrfs_tree_block_info, level, 8);
static inline void btrfs_tree_block_key(struct extent_buffer *eb,
struct btrfs_tree_block_info *item,
struct btrfs_disk_key *key)
{
read_eb_member(eb, item, struct btrfs_tree_block_info, key, key);
}
static inline void btrfs_set_tree_block_key(struct extent_buffer *eb,
struct btrfs_tree_block_info *item,
struct btrfs_disk_key *key)
{
write_eb_member(eb, item, struct btrfs_tree_block_info, key, key);
}
BTRFS_SETGET_FUNCS(extent_data_ref_root, struct btrfs_extent_data_ref,
root, 64);
BTRFS_SETGET_FUNCS(extent_data_ref_objectid, struct btrfs_extent_data_ref,
objectid, 64);
BTRFS_SETGET_FUNCS(extent_data_ref_offset, struct btrfs_extent_data_ref,
offset, 64);
BTRFS_SETGET_FUNCS(extent_data_ref_count, struct btrfs_extent_data_ref,
count, 32);
BTRFS_SETGET_FUNCS(shared_data_ref_count, struct btrfs_shared_data_ref,
count, 32);
BTRFS_SETGET_FUNCS(extent_inline_ref_type, struct btrfs_extent_inline_ref,
type, 8);
BTRFS_SETGET_FUNCS(extent_inline_ref_offset, struct btrfs_extent_inline_ref,
offset, 64);
static inline u32 btrfs_extent_inline_ref_size(int type)
{
if (type == BTRFS_TREE_BLOCK_REF_KEY ||
type == BTRFS_SHARED_BLOCK_REF_KEY)
return sizeof(struct btrfs_extent_inline_ref);
if (type == BTRFS_SHARED_DATA_REF_KEY)
return sizeof(struct btrfs_shared_data_ref) +
sizeof(struct btrfs_extent_inline_ref);
if (type == BTRFS_EXTENT_DATA_REF_KEY)
return sizeof(struct btrfs_extent_data_ref) +
offsetof(struct btrfs_extent_inline_ref, offset);
BUG();
return 0;
}
BTRFS_SETGET_FUNCS(ref_root_v0, struct btrfs_extent_ref_v0, root, 64);
BTRFS_SETGET_FUNCS(ref_generation_v0, struct btrfs_extent_ref_v0,
generation, 64);
BTRFS_SETGET_FUNCS(ref_objectid_v0, struct btrfs_extent_ref_v0, objectid, 64);
BTRFS_SETGET_FUNCS(ref_count_v0, struct btrfs_extent_ref_v0, count, 32);
/* struct btrfs_node */
BTRFS_SETGET_FUNCS(key_blockptr, struct btrfs_key_ptr, blockptr, 64);
@ -1313,6 +1431,21 @@ static inline int btrfs_clear_header_flag(struct extent_buffer *eb, u64 flag)
return (flags & flag) == flag;
}
static inline int btrfs_header_backref_rev(struct extent_buffer *eb)
{
u64 flags = btrfs_header_flags(eb);
return flags >> BTRFS_BACKREF_REV_SHIFT;
}
static inline void btrfs_set_header_backref_rev(struct extent_buffer *eb,
int rev)
{
u64 flags = btrfs_header_flags(eb);
flags &= ~BTRFS_BACKREF_REV_MASK;
flags |= (u64)rev << BTRFS_BACKREF_REV_SHIFT;
btrfs_set_header_flags(eb, flags);
}
static inline u8 *btrfs_header_fsid(struct extent_buffer *eb)
{
unsigned long ptr = offsetof(struct btrfs_header, fsid);
@ -1521,32 +1654,30 @@ struct btrfs_block_group_cache *btrfs_find_block_group(struct btrfs_root *root,
*hint, u64 search_start,
int data, int owner);
struct extent_buffer *btrfs_alloc_free_block(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
u32 blocksize, u64 parent,
u64 root_objectid,
u64 ref_generation,
int level,
u64 hint,
u64 empty_size);
struct btrfs_root *root,
u32 blocksize, u64 root_objectid,
struct btrfs_disk_key *key, int level,
u64 hint, u64 empty_size);
int btrfs_alloc_extent(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
u64 num_bytes, u64 parent,
u64 root_objectid, u64 ref_generation,
u64 owner, u64 empty_size, u64 hint_byte,
u64 search_end, struct btrfs_key *ins, int data);
int btrfs_lookup_extent_ref(struct btrfs_trans_handle *trans,
struct btrfs_root *root, u64 bytenr,
u64 num_bytes, u32 *refs);
int btrfs_lookup_extent_info(struct btrfs_trans_handle *trans,
struct btrfs_root *root, u64 bytenr,
u64 num_bytes, u64 *refs, u64 *flags);
int btrfs_set_block_flags(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
u64 bytenr, u64 num_bytes, u64 flags);
int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
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, u64 parent,
u64 root_objectid, u64 ref_generation,
u64 owner_objectid, int pin);
struct extent_buffer *buf, int record_parent);
int btrfs_dec_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
struct extent_buffer *buf, int record_parent);
int btrfs_free_extent(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
u64 bytenr, u64 num_bytes, u64 parent,
u64 root_objectid, u64 owner, u64 offset);
int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct extent_io_tree *unpin);

View File

@ -39,7 +39,7 @@ static void print_extent_leaf(struct btrfs_root *root, struct extent_buffer *l)
{
int i;
struct btrfs_item *item;
struct btrfs_extent_ref *ref;
// struct btrfs_extent_ref *ref;
struct btrfs_key key;
static u64 last = 0;
static u64 last_len = 0;
@ -55,6 +55,7 @@ static void print_extent_leaf(struct btrfs_root *root, struct extent_buffer *l)
last_len = key.offset;
last = key.objectid;
break;
#if 0
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 "
@ -66,6 +67,7 @@ static void print_extent_leaf(struct btrfs_root *root, struct extent_buffer *l)
(unsigned long long)btrfs_ref_objectid(l, ref),
(unsigned long)btrfs_ref_num_refs(l, ref));
break;
#endif
};
fflush(stdout);
}

172
disk-io.c
View File

@ -365,46 +365,19 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
struct btrfs_root *root)
{
int ret = 0;
struct btrfs_root *new_root = NULL;
struct btrfs_fs_info *fs_info = root->fs_info;
if (root->commit_root == root->node)
goto commit_tree;
new_root = malloc(sizeof(*new_root));
if (!new_root)
return -ENOMEM;
memcpy(new_root, root, sizeof(*new_root));
new_root->node = root->commit_root;
free_extent_buffer(root->commit_root);
root->commit_root = NULL;
root->root_key.offset = trans->transid;
btrfs_set_root_bytenr(&root->root_item, root->node->start);
btrfs_set_root_generation(&root->root_item, root->root_key.offset);
btrfs_set_root_generation(&root->root_item, trans->transid);
root->root_item.level = btrfs_header_level(root->node);
ret = btrfs_insert_root(trans, fs_info->tree_root,
&root->root_key, &root->root_item);
BUG_ON(ret);
btrfs_set_root_refs(&new_root->root_item, 0);
ret = btrfs_update_root(trans, root->fs_info->tree_root,
&new_root->root_key, &new_root->root_item);
BUG_ON(ret);
ret = commit_tree_roots(trans, fs_info);
BUG_ON(ret);
ret = __commit_transaction(trans, root);
BUG_ON(ret);
write_ctree_super(trans, root);
btrfs_finish_extent_commit(trans, fs_info->extent_root,
&fs_info->pinned_extents);
btrfs_free_transaction(root, trans);
fs_info->running_transaction = NULL;
trans = btrfs_start_transaction(root, 1);
ret = btrfs_drop_snapshot(trans, new_root);
BUG_ON(ret);
ret = btrfs_del_root(trans, fs_info->tree_root, &new_root->root_key);
&root->root_key, &root->root_item);
BUG_ON(ret);
commit_tree:
ret = commit_tree_roots(trans, fs_info);
@ -418,10 +391,6 @@ commit_tree:
free_extent_buffer(root->commit_root);
root->commit_root = NULL;
fs_info->running_transaction = NULL;
if (new_root) {
free_extent_buffer(new_root->node);
free(new_root);
}
return 0;
}
@ -475,19 +444,36 @@ static int find_and_setup_log_root(struct btrfs_root *tree_root,
return 0;
}
int btrfs_free_fs_root(struct btrfs_fs_info *fs_info, struct btrfs_root *root)
int btrfs_free_fs_root(struct btrfs_fs_info *fs_info,
struct btrfs_root *root)
{
if (root->node)
free_extent_buffer(root->node);
if (root->commit_root)
free_extent_buffer(root->commit_root);
free(root);
kfree(root);
return 0;
}
struct btrfs_root *btrfs_read_fs_root(struct btrfs_fs_info *fs_info,
struct btrfs_key *location)
static int free_fs_roots(struct btrfs_fs_info *fs_info)
{
struct cache_extent *cache;
struct btrfs_root *root;
while (1) {
cache = find_first_cache_extent(&fs_info->fs_root_cache, 0);
if (!cache)
break;
root = container_of(cache, struct btrfs_root, cache);
remove_cache_extent(&fs_info->fs_root_cache, cache);
btrfs_free_fs_root(fs_info, root);
}
return 0;
}
struct btrfs_root *btrfs_read_fs_root_no_cache(struct btrfs_fs_info *fs_info,
struct btrfs_key *location)
{
struct btrfs_root *root;
struct btrfs_root *tree_root = fs_info->tree_root;
@ -546,6 +532,44 @@ insert:
return root;
}
struct btrfs_root *btrfs_read_fs_root(struct btrfs_fs_info *fs_info,
struct btrfs_key *location)
{
struct btrfs_root *root;
struct cache_extent *cache;
int ret;
if (location->objectid == BTRFS_ROOT_TREE_OBJECTID)
return fs_info->tree_root;
if (location->objectid == BTRFS_EXTENT_TREE_OBJECTID)
return fs_info->extent_root;
if (location->objectid == BTRFS_CHUNK_TREE_OBJECTID)
return fs_info->chunk_root;
if (location->objectid == BTRFS_DEV_TREE_OBJECTID)
return fs_info->dev_root;
if (location->objectid == BTRFS_CSUM_TREE_OBJECTID)
return fs_info->csum_root;
BUG_ON(location->objectid == BTRFS_TREE_RELOC_OBJECTID ||
location->offset != (u64)-1);
cache = find_cache_extent(&fs_info->fs_root_cache,
location->objectid, 1);
if (cache)
return container_of(cache, struct btrfs_root, cache);
root = btrfs_read_fs_root_no_cache(fs_info, location);
if (IS_ERR(root))
return root;
root->cache.start = location->objectid;
root->cache.size = 1;
ret = insert_existing_cache_extent(&fs_info->fs_root_cache,
&root->cache);
BUG_ON(ret);
return root;
}
struct btrfs_root *open_ctree(const char *filename, u64 sb_bytenr, int writes)
{
int fp;
@ -575,7 +599,7 @@ struct btrfs_root *open_ctree_fd(int fp, const char *path, u64 sb_bytenr,
u32 blocksize;
u32 stripesize;
u64 generation;
struct btrfs_root *root = malloc(sizeof(struct btrfs_root));
struct btrfs_key key;
struct btrfs_root *tree_root = malloc(sizeof(struct btrfs_root));
struct btrfs_root *extent_root = malloc(sizeof(struct btrfs_root));
struct btrfs_root *chunk_root = malloc(sizeof(struct btrfs_root));
@ -586,6 +610,7 @@ struct btrfs_root *open_ctree_fd(int fp, const char *path, u64 sb_bytenr,
struct btrfs_super_block *disk_super;
struct btrfs_fs_devices *fs_devices = NULL;
u64 total_devs;
u64 features;
if (sb_bytenr == 0)
sb_bytenr = BTRFS_SUPER_INFO_OFFSET;
@ -604,7 +629,6 @@ struct btrfs_root *open_ctree_fd(int fp, const char *path, u64 sb_bytenr,
}
memset(fs_info, 0, sizeof(*fs_info));
fs_info->fs_root = root;
fs_info->tree_root = tree_root;
fs_info->extent_root = extent_root;
fs_info->chunk_root = chunk_root;
@ -620,6 +644,7 @@ struct btrfs_root *open_ctree_fd(int fp, const char *path, u64 sb_bytenr,
extent_io_tree_init(&fs_info->pinned_extents);
extent_io_tree_init(&fs_info->pending_del);
extent_io_tree_init(&fs_info->extent_ins);
cache_tree_init(&fs_info->fs_root_cache);
cache_tree_init(&fs_info->mapping_tree.cache_tree);
@ -648,6 +673,29 @@ struct btrfs_root *open_ctree_fd(int fp, const char *path, u64 sb_bytenr,
memcpy(fs_info->fsid, &disk_super->fsid, BTRFS_FSID_SIZE);
features = btrfs_super_incompat_flags(disk_super) &
~BTRFS_FEATURE_INCOMPAT_SUPP;
if (features) {
printk("couldn't open because of unsupported "
"option features (%Lx).\n", features);
BUG_ON(1);
}
features = btrfs_super_incompat_flags(disk_super);
if (!(features & BTRFS_FEATURE_INCOMPAT_MIXED_BACKREF)) {
features |= BTRFS_FEATURE_INCOMPAT_MIXED_BACKREF;
btrfs_set_super_incompat_flags(disk_super, features);
}
features = btrfs_super_compat_ro_flags(disk_super) &
~BTRFS_FEATURE_COMPAT_RO_SUPP;
if (writes && features) {
printk("couldn't open RDWR because of unsupported "
"option features (%Lx).\n", features);
BUG_ON(1);
}
nodesize = btrfs_super_nodesize(disk_super);
leafsize = btrfs_super_leafsize(disk_super);
sectorsize = btrfs_super_sectorsize(disk_super);
@ -704,19 +752,21 @@ struct btrfs_root *open_ctree_fd(int fp, const char *path, u64 sb_bytenr,
BUG_ON(ret);
csum_root->track_dirty = 1;
ret = find_and_setup_root(tree_root, fs_info,
BTRFS_FS_TREE_OBJECTID, root);
BUG_ON(ret);
root->ref_cows = 1;
find_and_setup_log_root(tree_root, fs_info, disk_super);
btrfs_read_block_groups(root);
btrfs_read_block_groups(fs_info->tree_root);
key.objectid = BTRFS_FS_TREE_OBJECTID;
key.type = BTRFS_ROOT_ITEM_KEY;
key.offset = (u64)-1;
fs_info->fs_root = btrfs_read_fs_root(fs_info, &key);
fs_info->data_alloc_profile = (u64)-1;
fs_info->metadata_alloc_profile = (u64)-1;
fs_info->system_alloc_profile = fs_info->metadata_alloc_profile;
return root;
return fs_info->fs_root;
}
int btrfs_read_dev_super(int fd, struct btrfs_super_block *sb, u64 sb_bytenr)
@ -891,27 +941,26 @@ int close_ctree(struct btrfs_root *root)
trans = btrfs_start_transaction(root, 1);
btrfs_commit_transaction(trans, root);
trans = btrfs_start_transaction(root, 1);
ret = commit_tree_roots(trans, root->fs_info);
ret = commit_tree_roots(trans, fs_info);
BUG_ON(ret);
ret = __commit_transaction(trans, root);
BUG_ON(ret);
write_ctree_super(trans, root);
btrfs_free_transaction(root, trans);
btrfs_free_block_groups(root->fs_info);
if (root->node)
free_extent_buffer(root->node);
if (root->fs_info->extent_root->node)
free_extent_buffer(root->fs_info->extent_root->node);
if (root->fs_info->tree_root->node)
free_extent_buffer(root->fs_info->tree_root->node);
free_extent_buffer(root->commit_root);
btrfs_free_block_groups(fs_info);
if (root->fs_info->chunk_root->node)
free_extent_buffer(root->fs_info->chunk_root->node);
if (root->fs_info->dev_root->node)
free_extent_buffer(root->fs_info->dev_root->node);
if (root->fs_info->csum_root->node)
free_extent_buffer(root->fs_info->csum_root->node);
free_fs_roots(fs_info);
if (fs_info->extent_root->node)
free_extent_buffer(fs_info->extent_root->node);
if (fs_info->tree_root->node)
free_extent_buffer(fs_info->tree_root->node);
if (fs_info->chunk_root->node)
free_extent_buffer(fs_info->chunk_root->node);
if (fs_info->dev_root->node)
free_extent_buffer(fs_info->dev_root->node);
if (fs_info->csum_root->node)
free_extent_buffer(fs_info->csum_root->node);
if (root->fs_info->log_root_tree) {
if (root->fs_info->log_root_tree->node)
@ -929,7 +978,6 @@ int close_ctree(struct btrfs_root *root)
free(fs_info->tree_root);
free(fs_info->extent_root);
free(fs_info->fs_root);
free(fs_info->chunk_root);
free(fs_info->dev_root);
free(fs_info->csum_root);

View File

@ -56,6 +56,8 @@ struct extent_buffer *btrfs_find_tree_block(struct btrfs_root *root,
u64 bytenr, u32 blocksize);
struct btrfs_root *btrfs_read_fs_root(struct btrfs_fs_info *fs_info,
struct btrfs_key *location);
struct btrfs_root *btrfs_read_fs_root_no_cache(struct btrfs_fs_info *fs_info,
struct btrfs_key *location);
int btrfs_free_fs_root(struct btrfs_fs_info *fs_info, struct btrfs_root *root);
void btrfs_mark_buffer_dirty(struct extent_buffer *buf);
int btrfs_buffer_uptodate(struct extent_buffer *buf, u64 parent_transid);

File diff suppressed because it is too large Load Diff

View File

@ -202,6 +202,7 @@ int clear_extent_bits(struct extent_io_tree *tree, u64 start,
struct extent_state *state;
struct extent_state *prealloc = NULL;
struct cache_extent *node;
u64 last_end;
int err;
int set = 0;
@ -220,6 +221,7 @@ again:
state = container_of(node, struct extent_state, cache_node);
if (state->start > end)
goto out;
last_end = state->end;
/*
* | ---- desired range ---- |
@ -243,8 +245,10 @@ again:
if (err)
goto out;
if (state->end <= end) {
start = state->end + 1;
set |= clear_state_bit(tree, state, bits);
if (last_end == (u64)-1)
goto out;
start = last_end + 1;
} else {
start = state->start;
}
@ -267,6 +271,9 @@ again:
start = state->end + 1;
set |= clear_state_bit(tree, state, bits);
if (last_end == (u64)-1)
goto out;
start = last_end + 1;
goto search_again;
out:
if (prealloc)
@ -322,8 +329,10 @@ again:
if (state->start == start && state->end <= end) {
set = state->state & bits;
state->state |= bits;
start = state->end + 1;
merge_state(tree, state);
if (last_end == (u64)-1)
goto out;
start = last_end + 1;
goto search_again;
}
/*
@ -353,6 +362,9 @@ again:
state->state |= bits;
start = state->end + 1;
merge_state(tree, state);
if (last_end == (u64)-1)
goto out;
start = last_end + 1;
} else {
start = state->start;
}

View File

@ -191,6 +191,7 @@ static inline long IS_ERR(const void *ptr)
*/
#define printk(fmt, args...) fprintf(stderr, fmt, ##args)
#define KERN_CRIT ""
#define KERN_ERR ""
/*
* kmalloc/kfree

7
mkfs.c
View File

@ -173,6 +173,11 @@ static int recow_roots(struct btrfs_trans_handle *trans,
BUG_ON(ret);
free_extent_buffer(tmp);
ret = __btrfs_cow_block(trans, info->csum_root, info->csum_root->node,
NULL, 0, &tmp, 0, 0);
BUG_ON(ret);
free_extent_buffer(tmp);
return 0;
}
@ -252,7 +257,7 @@ static int create_data_reloc_tree(struct btrfs_trans_handle *trans,
location.objectid = objectid;
location.type = BTRFS_ROOT_ITEM_KEY;
location.offset = trans->transid;
location.offset = 0;
ret = btrfs_insert_root(trans, root->fs_info->tree_root,
&location, &root_item);
BUG_ON(ret);

View File

@ -159,6 +159,107 @@ static void print_file_extent_item(struct extent_buffer *eb,
btrfs_file_extent_compression(eb, fi));
}
static void print_extent_item(struct extent_buffer *eb, int slot)
{
struct btrfs_extent_item *ei;
struct btrfs_extent_inline_ref *iref;
struct btrfs_extent_data_ref *dref;
struct btrfs_shared_data_ref *sref;
struct btrfs_disk_key key;
unsigned long end;
unsigned long ptr;
int type;
u32 item_size = btrfs_item_size_nr(eb, slot);
u64 flags;
u64 offset;
if (item_size < sizeof(*ei)) {
#ifdef BTRFS_COMPAT_EXTENT_TREE_V0
struct btrfs_extent_item_v0 *ei0;
BUG_ON(item_size != sizeof(*ei0));
ei0 = btrfs_item_ptr(eb, slot, struct btrfs_extent_item_v0);
printf("\t\textent refs %u\n",
btrfs_extent_refs_v0(eb, ei0));
return;
#else
BUG();
#endif
}
ei = btrfs_item_ptr(eb, slot, struct btrfs_extent_item);
flags = btrfs_extent_flags(eb, ei);
printf("\t\textent refs %llu gen %llu flags %llu\n",
(unsigned long long)btrfs_extent_refs(eb, ei),
(unsigned long long)btrfs_extent_generation(eb, ei),
(unsigned long long)flags);
if (flags & BTRFS_EXTENT_FLAG_TREE_BLOCK) {
struct btrfs_tree_block_info *info;
info = (struct btrfs_tree_block_info *)(ei + 1);
btrfs_tree_block_key(eb, info, &key);
printf("\t\ttree block key (%llu %x %llu) level %d\n",
(unsigned long long)btrfs_disk_key_objectid(&key),
key.type,
(unsigned long long)btrfs_disk_key_offset(&key),
btrfs_tree_block_level(eb, info));
iref = (struct btrfs_extent_inline_ref *)(info + 1);
} else {
iref = (struct btrfs_extent_inline_ref *)(ei + 1);
}
ptr = (unsigned long)iref;
end = (unsigned long)ei + item_size;
while (ptr < end) {
iref = (struct btrfs_extent_inline_ref *)ptr;
type = btrfs_extent_inline_ref_type(eb, iref);
offset = btrfs_extent_inline_ref_offset(eb, iref);
switch (type) {
case BTRFS_TREE_BLOCK_REF_KEY:
printf("\t\ttree block backref root %llu\n",
(unsigned long long)offset);
break;
case BTRFS_SHARED_BLOCK_REF_KEY:
printf("\t\tshared block backref parent %llu\n",
(unsigned long long)offset);
break;
case BTRFS_EXTENT_DATA_REF_KEY:
dref = (struct btrfs_extent_data_ref *)(&iref->offset);
printf("\t\textent data backref root %llu "
"objectid %llu offset %llu count %u\n",
(unsigned long long)btrfs_extent_data_ref_root(eb, dref),
(unsigned long long)btrfs_extent_data_ref_objectid(eb, dref),
(unsigned long long)btrfs_extent_data_ref_offset(eb, dref),
btrfs_extent_data_ref_count(eb, dref));
break;
case BTRFS_SHARED_DATA_REF_KEY:
sref = (struct btrfs_shared_data_ref *)(iref + 1);
printf("\t\tshared data backref parent %llu count %u\n",
(unsigned long long)offset,
btrfs_shared_data_ref_count(eb, sref));
break;
default:
BUG();
}
ptr += btrfs_extent_inline_ref_size(type);
}
WARN_ON(ptr > end);
}
#ifdef BTRFS_COMPAT_EXTENT_TREE_V0
static void print_extent_ref_v0(struct extent_buffer *eb, int slot)
{
struct btrfs_extent_ref_v0 *ref0;
ref0 = btrfs_item_ptr(eb, slot, struct btrfs_extent_ref_v0);
printf("\t\textent back ref root %llu gen %llu "
"owner %llu num_refs %lu\n",
(unsigned long long)btrfs_ref_root_v0(eb, ref0),
(unsigned long long)btrfs_ref_generation_v0(eb, ref0),
(unsigned long long)btrfs_ref_objectid_v0(eb, ref0),
(unsigned long)btrfs_ref_count_v0(eb, ref0));
}
#endif
static void print_root_ref(struct extent_buffer *leaf, int slot, char *tag)
{
@ -214,8 +315,20 @@ static void print_key_type(u8 type)
case BTRFS_EXTENT_ITEM_KEY:
printf("EXTENT_ITEM");
break;
case BTRFS_EXTENT_REF_KEY:
printf("EXTENT_REF");
case BTRFS_TREE_BLOCK_REF_KEY:
printf("TREE_BLOCK_REF");
break;
case BTRFS_SHARED_BLOCK_REF_KEY:
printf("SHARED_BLOCK_REF");
break;
case BTRFS_EXTENT_DATA_REF_KEY:
printf("EXTENT_DATA_REF");
break;
case BTRFS_SHARED_DATA_REF_KEY:
printf("SHARED_DATA_REF");
break;
case BTRFS_EXTENT_REF_V0_KEY:
printf("EXTENT_REF_V0");
break;
case BTRFS_CSUM_ITEM_KEY:
printf("CSUM_ITEM");
@ -324,14 +437,14 @@ void btrfs_print_leaf(struct btrfs_root *root, struct extent_buffer *l)
int i;
char *str;
struct btrfs_item *item;
struct btrfs_extent_item *ei;
struct btrfs_root_item *ri;
struct btrfs_dir_item *di;
struct btrfs_inode_item *ii;
struct btrfs_file_extent_item *fi;
struct btrfs_csum_item *ci;
struct btrfs_block_group_item *bi;
struct btrfs_extent_ref *ref;
struct btrfs_extent_data_ref *dref;
struct btrfs_shared_data_ref *sref;
struct btrfs_inode_ref *iref;
struct btrfs_dev_extent *dev_extent;
struct btrfs_disk_key disk_key;
@ -410,18 +523,34 @@ void btrfs_print_leaf(struct btrfs_root *root, struct extent_buffer *l)
print_root_ref(l, i, "backref");
break;
case BTRFS_EXTENT_ITEM_KEY:
ei = btrfs_item_ptr(l, i, struct btrfs_extent_item);
printf("\t\textent data refs %u\n",
btrfs_extent_refs(l, ei));
print_extent_item(l, i);
break;
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 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)btrfs_ref_num_refs(l, ref));
case BTRFS_TREE_BLOCK_REF_KEY:
printf("\t\ttree block backref\n");
break;
case BTRFS_SHARED_BLOCK_REF_KEY:
printf("\t\tshared block backref\n");
break;
case BTRFS_EXTENT_DATA_REF_KEY:
dref = btrfs_item_ptr(l, i, struct btrfs_extent_data_ref);
printf("\t\textent data backref root %llu "
"objectid %llu offset %llu count %u\n",
(unsigned long long)btrfs_extent_data_ref_root(l, dref),
(unsigned long long)btrfs_extent_data_ref_objectid(l, dref),
(unsigned long long)btrfs_extent_data_ref_offset(l, dref),
btrfs_extent_data_ref_count(l, dref));
break;
case BTRFS_SHARED_DATA_REF_KEY:
sref = btrfs_item_ptr(l, i, struct btrfs_shared_data_ref);
printf("\t\tshared data backref count %u\n",
btrfs_shared_data_ref_count(l, sref));
break;
case BTRFS_EXTENT_REF_V0_KEY:
#ifdef BTRFS_COMPAT_EXTENT_TREE_V0
print_extent_ref_v0(l, i);
#else
BUG();
#endif
break;
case BTRFS_CSUM_ITEM_KEY:
ci = btrfs_item_ptr(l, i, struct btrfs_csum_item);

25
utils.c
View File

@ -63,7 +63,6 @@ int make_btrfs(int fd, const char *device, const char *label,
struct extent_buffer *buf;
struct btrfs_root_item root_item;
struct btrfs_disk_key disk_key;
struct btrfs_extent_ref *extent_ref;
struct btrfs_extent_item *extent_item;
struct btrfs_inode_item *inode_item;
struct btrfs_chunk *chunk;
@ -115,6 +114,7 @@ int make_btrfs(int fd, const char *device, const char *label,
btrfs_set_header_bytenr(buf, blocks[1]);
btrfs_set_header_nritems(buf, 4);
btrfs_set_header_generation(buf, 1);
btrfs_set_header_backref_rev(buf, BTRFS_MIXED_BACKREF_REV);
btrfs_set_header_owner(buf, BTRFS_ROOT_TREE_OBJECTID);
write_extent_buffer(buf, super.fsid, (unsigned long)
btrfs_header_fsid(buf), BTRFS_FSID_SIZE);
@ -200,7 +200,8 @@ int make_btrfs(int fd, const char *device, const char *label,
BUG_ON(blocks[i] < blocks[i - 1]);
/* create extent item */
itemoff = itemoff - sizeof(struct btrfs_extent_item);
itemoff -= sizeof(struct btrfs_extent_item) +
sizeof(struct btrfs_tree_block_info);
btrfs_set_disk_key_objectid(&disk_key, blocks[i]);
btrfs_set_disk_key_offset(&disk_key, leafsize);
btrfs_set_disk_key_type(&disk_key, BTRFS_EXTENT_ITEM_KEY);
@ -208,29 +209,25 @@ int make_btrfs(int fd, const char *device, const char *label,
btrfs_set_item_offset(buf, btrfs_item_nr(buf, nritems),
itemoff);
btrfs_set_item_size(buf, btrfs_item_nr(buf, nritems),
sizeof(struct btrfs_extent_item));
sizeof(struct btrfs_extent_item) +
sizeof(struct btrfs_tree_block_info));
extent_item = btrfs_item_ptr(buf, nritems,
struct btrfs_extent_item);
btrfs_set_extent_refs(buf, extent_item, 1);
btrfs_set_extent_generation(buf, extent_item, 1);
btrfs_set_extent_flags(buf, extent_item,
BTRFS_EXTENT_FLAG_TREE_BLOCK);
nritems++;
/* create extent ref */
ref_root = reference_root_table[i];
itemoff = itemoff - sizeof(struct btrfs_extent_ref);
btrfs_set_disk_key_objectid(&disk_key, blocks[i]);
btrfs_set_disk_key_offset(&disk_key, blocks[i]);
btrfs_set_disk_key_type(&disk_key, BTRFS_EXTENT_REF_KEY);
btrfs_set_disk_key_offset(&disk_key, ref_root);
btrfs_set_disk_key_type(&disk_key, BTRFS_TREE_BLOCK_REF_KEY);
btrfs_set_item_key(buf, &disk_key, nritems);
btrfs_set_item_offset(buf, btrfs_item_nr(buf, nritems),
itemoff);
btrfs_set_item_size(buf, btrfs_item_nr(buf, nritems),
sizeof(struct btrfs_extent_ref));
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, 1);
btrfs_set_ref_objectid(buf, extent_ref, 0);
btrfs_set_ref_num_refs(buf, extent_ref, 1);
btrfs_set_item_size(buf, btrfs_item_nr(buf, nritems), 0);
nritems++;
}
btrfs_set_header_bytenr(buf, blocks[2]);