mirror of
https://github.com/kdave/btrfs-progs
synced 2025-04-04 23:29:20 +00:00
Switch to byte granular allocations
This commit is contained in:
parent
08c66b7738
commit
38f79f9077
3
Makefile
3
Makefile
@ -12,7 +12,8 @@ INSTALL= install
|
||||
prefix ?= /usr/local
|
||||
bindir = $(prefix)/bin
|
||||
|
||||
progs = btrfsctl btrfsck mkfs.btrfs debug-tree
|
||||
#progs = btrfsctl btrfsck mkfs.btrfs debug-tree
|
||||
progs = btrfsctl mkfs.btrfs debug-tree
|
||||
|
||||
# make C=1 to enable sparse
|
||||
ifdef C
|
||||
|
@ -78,12 +78,12 @@ static int check_leaf(struct btrfs_root *root,
|
||||
|
||||
if (btrfs_header_level(&leaf->header) != 0) {
|
||||
fprintf(stderr, "leaf is not a leaf %llu\n",
|
||||
(unsigned long long)btrfs_header_blocknr(&leaf->header));
|
||||
(unsigned long long)btrfs_header_bytenr(&leaf->header));
|
||||
return 1;
|
||||
}
|
||||
if (btrfs_leaf_free_space(root, leaf) < 0) {
|
||||
fprintf(stderr, "leaf free space incorrect %llu %d\n",
|
||||
(unsigned long long)btrfs_header_blocknr(&leaf->header),
|
||||
(unsigned long long)btrfs_header_bytenr(&leaf->header),
|
||||
btrfs_leaf_free_space(root, leaf));
|
||||
return 1;
|
||||
}
|
||||
@ -94,7 +94,7 @@ static int check_leaf(struct btrfs_root *root,
|
||||
if (parent_key->type && memcmp(parent_key, &leaf->items[0].key,
|
||||
sizeof(struct btrfs_disk_key))) {
|
||||
fprintf(stderr, "leaf parent key incorrect %llu\n",
|
||||
(unsigned long long)btrfs_header_blocknr(&leaf->header));
|
||||
(unsigned long long)btrfs_header_bytenr(&leaf->header));
|
||||
return 1;
|
||||
}
|
||||
for (i = 0; nritems > 1 && i < nritems - 2; i++) {
|
||||
|
97
ctree.c
97
ctree.c
@ -64,9 +64,9 @@ static int btrfs_cow_block(struct btrfs_trans_handle *trans, struct btrfs_root
|
||||
*cow_ret = buf;
|
||||
return 0;
|
||||
}
|
||||
cow = btrfs_alloc_free_block(trans, root);
|
||||
memcpy(&cow->node, &buf->node, root->sectorsize);
|
||||
btrfs_set_header_blocknr(&cow->node.header, cow->blocknr);
|
||||
cow = btrfs_alloc_free_block(trans, root, buf->size);
|
||||
memcpy(&cow->node, &buf->node, buf->size);
|
||||
btrfs_set_header_bytenr(&cow->node.header, cow->bytenr);
|
||||
btrfs_set_header_owner(&cow->node.header, root->root_key.objectid);
|
||||
*cow_ret = cow;
|
||||
btrfs_inc_ref(trans, root, buf);
|
||||
@ -74,13 +74,14 @@ static int btrfs_cow_block(struct btrfs_trans_handle *trans, struct btrfs_root
|
||||
root->node = cow;
|
||||
cow->count++;
|
||||
if (buf != root->commit_root)
|
||||
btrfs_free_extent(trans, root, buf->blocknr, 1, 1);
|
||||
btrfs_free_extent(trans, root, buf->bytenr,
|
||||
buf->size, 1);
|
||||
btrfs_block_release(root, buf);
|
||||
} else {
|
||||
btrfs_set_node_blockptr(&parent->node, parent_slot,
|
||||
cow->blocknr);
|
||||
cow->bytenr);
|
||||
BUG_ON(list_empty(&parent->dirty));
|
||||
btrfs_free_extent(trans, root, buf->blocknr, 1, 1);
|
||||
btrfs_free_extent(trans, root, buf->bytenr, buf->size, 1);
|
||||
}
|
||||
btrfs_block_release(root, buf);
|
||||
return 0;
|
||||
@ -178,7 +179,7 @@ static int check_node(struct btrfs_root *root, struct btrfs_path *path,
|
||||
BUG_ON(memcmp(parent_key, &node->ptrs[0].key,
|
||||
sizeof(struct btrfs_disk_key)));
|
||||
BUG_ON(btrfs_node_blockptr(parent, parent_slot) !=
|
||||
btrfs_header_blocknr(&node->header));
|
||||
btrfs_header_bytenr(&node->header));
|
||||
}
|
||||
BUG_ON(nritems > BTRFS_NODEPTRS_PER_BLOCK(root));
|
||||
for (i = 0; nritems > 1 && i < nritems - 2; i++) {
|
||||
@ -212,7 +213,7 @@ static int check_leaf(struct btrfs_root *root, struct btrfs_path *path,
|
||||
BUG_ON(memcmp(parent_key, &leaf->items[0].key,
|
||||
sizeof(struct btrfs_disk_key)));
|
||||
BUG_ON(btrfs_node_blockptr(parent, parent_slot) !=
|
||||
btrfs_header_blocknr(&leaf->header));
|
||||
btrfs_header_bytenr(&leaf->header));
|
||||
}
|
||||
for (i = 0; nritems > 1 && i < nritems - 2; i++) {
|
||||
struct btrfs_key cpukey;
|
||||
@ -300,11 +301,13 @@ static struct btrfs_buffer *read_node_slot(struct btrfs_root *root,
|
||||
int slot)
|
||||
{
|
||||
struct btrfs_node *node = &parent_buf->node;
|
||||
int level = btrfs_header_level(&node->header);
|
||||
if (slot < 0)
|
||||
return NULL;
|
||||
if (slot >= btrfs_header_nritems(&node->header))
|
||||
return NULL;
|
||||
return read_tree_block(root, btrfs_node_blockptr(node, slot));
|
||||
return read_tree_block(root, btrfs_node_blockptr(node, slot),
|
||||
btrfs_level_size(root, level - 1));
|
||||
}
|
||||
|
||||
static int balance_level(struct btrfs_trans_handle *trans, struct btrfs_root
|
||||
@ -341,7 +344,7 @@ static int balance_level(struct btrfs_trans_handle *trans, struct btrfs_root
|
||||
*/
|
||||
if (!parent_buf) {
|
||||
struct btrfs_buffer *child;
|
||||
u64 blocknr = mid_buf->blocknr;
|
||||
u64 bytenr = mid_buf->bytenr;
|
||||
|
||||
if (btrfs_header_nritems(&mid->header) != 1)
|
||||
return 0;
|
||||
@ -356,7 +359,8 @@ static int balance_level(struct btrfs_trans_handle *trans, struct btrfs_root
|
||||
/* once for the root ptr */
|
||||
btrfs_block_release(root, mid_buf);
|
||||
clean_tree_block(trans, root, mid_buf);
|
||||
return btrfs_free_extent(trans, root, blocknr, 1, 1);
|
||||
return btrfs_free_extent(trans, root, bytenr,
|
||||
root->nodesize, 1);
|
||||
}
|
||||
parent = &parent_buf->node;
|
||||
|
||||
@ -389,7 +393,7 @@ static int balance_level(struct btrfs_trans_handle *trans, struct btrfs_root
|
||||
if (wret < 0)
|
||||
ret = wret;
|
||||
if (btrfs_header_nritems(&right->header) == 0) {
|
||||
u64 blocknr = right_buf->blocknr;
|
||||
u64 bytenr = right_buf->bytenr;
|
||||
btrfs_block_release(root, right_buf);
|
||||
clean_tree_block(trans, root, right_buf);
|
||||
right_buf = NULL;
|
||||
@ -398,7 +402,8 @@ static int balance_level(struct btrfs_trans_handle *trans, struct btrfs_root
|
||||
1);
|
||||
if (wret)
|
||||
ret = wret;
|
||||
wret = btrfs_free_extent(trans, root, blocknr, 1, 1);
|
||||
wret = btrfs_free_extent(trans, root, bytenr,
|
||||
root->nodesize, 1);
|
||||
if (wret)
|
||||
ret = wret;
|
||||
} else {
|
||||
@ -426,7 +431,7 @@ static int balance_level(struct btrfs_trans_handle *trans, struct btrfs_root
|
||||
}
|
||||
if (btrfs_header_nritems(&mid->header) == 0) {
|
||||
/* we've managed to empty the middle node, drop it */
|
||||
u64 blocknr = mid_buf->blocknr;
|
||||
u64 bytenr = mid_buf->bytenr;
|
||||
btrfs_block_release(root, mid_buf);
|
||||
clean_tree_block(trans, root, mid_buf);
|
||||
mid_buf = NULL;
|
||||
@ -434,7 +439,8 @@ static int balance_level(struct btrfs_trans_handle *trans, struct btrfs_root
|
||||
wret = del_ptr(trans, root, path, level + 1, pslot);
|
||||
if (wret)
|
||||
ret = wret;
|
||||
wret = btrfs_free_extent(trans, root, blocknr, 1, 1);
|
||||
wret = btrfs_free_extent(trans, root, bytenr,
|
||||
root->nodesize, 1);
|
||||
if (wret)
|
||||
ret = wret;
|
||||
} else {
|
||||
@ -539,7 +545,9 @@ again:
|
||||
slot = p->slots[level];
|
||||
BUG_ON(btrfs_header_nritems(&c->header) == 1);
|
||||
}
|
||||
b = read_tree_block(root, btrfs_node_blockptr(c, slot));
|
||||
b = read_tree_block(root,
|
||||
btrfs_node_blockptr(c, slot),
|
||||
btrfs_level_size(root, level - 1));
|
||||
} else {
|
||||
struct btrfs_leaf *l = (struct btrfs_leaf *)c;
|
||||
p->slots[level] = slot;
|
||||
@ -696,22 +704,24 @@ static int insert_new_root(struct btrfs_trans_handle *trans, struct btrfs_root
|
||||
BUG_ON(path->nodes[level]);
|
||||
BUG_ON(path->nodes[level-1] != root->node);
|
||||
|
||||
t = btrfs_alloc_free_block(trans, root);
|
||||
t = btrfs_alloc_free_block(trans, root, root->nodesize);
|
||||
c = &t->node;
|
||||
memset(c, 0, root->sectorsize);
|
||||
memset(c, 0, root->nodesize);
|
||||
btrfs_set_header_nritems(&c->header, 1);
|
||||
btrfs_set_header_level(&c->header, level);
|
||||
btrfs_set_header_blocknr(&c->header, t->blocknr);
|
||||
btrfs_set_header_bytenr(&c->header, t->bytenr);
|
||||
btrfs_set_header_owner(&c->header, root->root_key.objectid);
|
||||
memcpy(c->header.fsid, root->fs_info->disk_super->fsid,
|
||||
sizeof(c->header.fsid));
|
||||
lower = &path->nodes[level-1]->node;
|
||||
|
||||
if (btrfs_is_leaf(lower))
|
||||
lower_key = &((struct btrfs_leaf *)lower)->items[0].key;
|
||||
else
|
||||
lower_key = &lower->ptrs[0].key;
|
||||
|
||||
memcpy(&c->ptrs[0].key, lower_key, sizeof(struct btrfs_disk_key));
|
||||
btrfs_set_node_blockptr(c, 0, path->nodes[level - 1]->blocknr);
|
||||
btrfs_set_node_blockptr(c, 0, path->nodes[level - 1]->bytenr);
|
||||
/* the super has an extra ref to root->node */
|
||||
btrfs_block_release(root, root->node);
|
||||
root->node = t;
|
||||
@ -726,13 +736,13 @@ static int insert_new_root(struct btrfs_trans_handle *trans, struct btrfs_root
|
||||
* the node should have enough room for the pointer already
|
||||
*
|
||||
* slot and level indicate where you want the key to go, and
|
||||
* blocknr is the block the key points to.
|
||||
* bytenr is the block the key points to.
|
||||
*
|
||||
* returns zero on success and < 0 on any error
|
||||
*/
|
||||
static int insert_ptr(struct btrfs_trans_handle *trans, struct btrfs_root
|
||||
*root, struct btrfs_path *path, struct btrfs_disk_key
|
||||
*key, u64 blocknr, int slot, int level)
|
||||
*key, u64 bytenr, int slot, int level)
|
||||
{
|
||||
struct btrfs_node *lower;
|
||||
int nritems;
|
||||
@ -749,7 +759,7 @@ static int insert_ptr(struct btrfs_trans_handle *trans, struct btrfs_root
|
||||
(nritems - slot) * sizeof(struct btrfs_key_ptr));
|
||||
}
|
||||
memcpy(&lower->ptrs[slot].key, key, sizeof(struct btrfs_disk_key));
|
||||
btrfs_set_node_blockptr(lower, slot, blocknr);
|
||||
btrfs_set_node_blockptr(lower, slot, bytenr);
|
||||
btrfs_set_header_nritems(&lower->header, nritems + 1);
|
||||
BUG_ON(list_empty(&path->nodes[level]->dirty));
|
||||
return 0;
|
||||
@ -785,11 +795,11 @@ static int split_node(struct btrfs_trans_handle *trans, struct btrfs_root
|
||||
return ret;
|
||||
}
|
||||
c_nritems = btrfs_header_nritems(&c->header);
|
||||
split_buffer = btrfs_alloc_free_block(trans, root);
|
||||
split_buffer = btrfs_alloc_free_block(trans, root, root->nodesize);
|
||||
split = &split_buffer->node;
|
||||
btrfs_set_header_flags(&split->header, btrfs_header_flags(&c->header));
|
||||
btrfs_set_header_level(&split->header, btrfs_header_level(&c->header));
|
||||
btrfs_set_header_blocknr(&split->header, split_buffer->blocknr);
|
||||
btrfs_set_header_bytenr(&split->header, split_buffer->bytenr);
|
||||
btrfs_set_header_owner(&split->header, root->root_key.objectid);
|
||||
memcpy(split->header.fsid, root->fs_info->disk_super->fsid,
|
||||
sizeof(split->header.fsid));
|
||||
@ -802,7 +812,7 @@ static int split_node(struct btrfs_trans_handle *trans, struct btrfs_root
|
||||
|
||||
BUG_ON(list_empty(&t->dirty));
|
||||
wret = insert_ptr(trans, root, path, &split->ptrs[0].key,
|
||||
split_buffer->blocknr, path->slots[level + 1] + 1,
|
||||
split_buffer->bytenr, path->slots[level + 1] + 1,
|
||||
level + 1);
|
||||
if (wret)
|
||||
ret = wret;
|
||||
@ -850,8 +860,9 @@ static int push_leaf_right(struct btrfs_trans_handle *trans, struct btrfs_root
|
||||
if (slot >= btrfs_header_nritems(&upper->node.header) - 1) {
|
||||
return 1;
|
||||
}
|
||||
right_buf = read_tree_block(root, btrfs_node_blockptr(&upper->node,
|
||||
slot + 1));
|
||||
right_buf = read_tree_block(root,
|
||||
btrfs_node_blockptr(&upper->node, slot + 1),
|
||||
root->leafsize);
|
||||
right = &right_buf->leaf;
|
||||
free_space = btrfs_leaf_free_space(root, right);
|
||||
if (free_space < data_size + sizeof(struct btrfs_item)) {
|
||||
@ -956,8 +967,9 @@ static int push_leaf_left(struct btrfs_trans_handle *trans, struct btrfs_root
|
||||
if (!path->nodes[1]) {
|
||||
return 1;
|
||||
}
|
||||
t = read_tree_block(root, btrfs_node_blockptr(&path->nodes[1]->node,
|
||||
slot - 1));
|
||||
t = read_tree_block(root,
|
||||
btrfs_node_blockptr(&path->nodes[1]->node, slot - 1),
|
||||
root->leafsize);
|
||||
left = &t->leaf;
|
||||
free_space = btrfs_leaf_free_space(root, left);
|
||||
if (free_space < data_size + sizeof(struct btrfs_item)) {
|
||||
@ -1098,7 +1110,7 @@ static int split_leaf(struct btrfs_trans_handle *trans, struct btrfs_root
|
||||
slot = path->slots[0];
|
||||
nritems = btrfs_header_nritems(&l->header);
|
||||
mid = (nritems + 1)/ 2;
|
||||
right_buffer = btrfs_alloc_free_block(trans, root);
|
||||
right_buffer = btrfs_alloc_free_block(trans, root, root->leafsize);
|
||||
BUG_ON(!right_buffer);
|
||||
BUG_ON(mid == nritems);
|
||||
right = &right_buffer->leaf;
|
||||
@ -1115,7 +1127,7 @@ static int split_leaf(struct btrfs_trans_handle *trans, struct btrfs_root
|
||||
BUG();
|
||||
}
|
||||
btrfs_set_header_nritems(&right->header, nritems - mid);
|
||||
btrfs_set_header_blocknr(&right->header, right_buffer->blocknr);
|
||||
btrfs_set_header_bytenr(&right->header, right_buffer->bytenr);
|
||||
btrfs_set_header_level(&right->header, 0);
|
||||
btrfs_set_header_owner(&right->header, root->root_key.objectid);
|
||||
memcpy(right->header.fsid, root->fs_info->disk_super->fsid,
|
||||
@ -1138,7 +1150,7 @@ static int split_leaf(struct btrfs_trans_handle *trans, struct btrfs_root
|
||||
btrfs_set_header_nritems(&l->header, mid);
|
||||
ret = 0;
|
||||
wret = insert_ptr(trans, root, path, &right->items[0].key,
|
||||
right_buffer->blocknr, path->slots[1] + 1, 1);
|
||||
right_buffer->bytenr, path->slots[1] + 1, 1);
|
||||
if (wret)
|
||||
ret = wret;
|
||||
BUG_ON(list_empty(&right_buffer->dirty));
|
||||
@ -1350,7 +1362,8 @@ int btrfs_del_item(struct btrfs_trans_handle *trans, struct btrfs_root *root,
|
||||
if (wret)
|
||||
ret = wret;
|
||||
wret = btrfs_free_extent(trans, root,
|
||||
leaf_buf->blocknr, 1, 1);
|
||||
leaf_buf->bytenr,
|
||||
leaf_buf->size, 1);
|
||||
if (wret)
|
||||
ret = wret;
|
||||
}
|
||||
@ -1382,14 +1395,14 @@ int btrfs_del_item(struct btrfs_trans_handle *trans, struct btrfs_root *root,
|
||||
ret = wret;
|
||||
}
|
||||
if (btrfs_header_nritems(&leaf->header) == 0) {
|
||||
u64 blocknr = leaf_buf->blocknr;
|
||||
u64 bytenr = leaf_buf->bytenr;
|
||||
clean_tree_block(trans, root, leaf_buf);
|
||||
wret = del_ptr(trans, root, path, 1, slot);
|
||||
if (wret)
|
||||
ret = wret;
|
||||
wret = btrfs_free_extent(trans, root, bytenr,
|
||||
leaf_buf->size, 1);
|
||||
btrfs_block_release(root, leaf_buf);
|
||||
wret = btrfs_free_extent(trans, root, blocknr,
|
||||
1, 1);
|
||||
if (wret)
|
||||
ret = wret;
|
||||
} else {
|
||||
@ -1461,7 +1474,7 @@ int btrfs_next_leaf(struct btrfs_root *root, struct btrfs_path *path)
|
||||
{
|
||||
int slot;
|
||||
int level = 1;
|
||||
u64 blocknr;
|
||||
u64 bytenr;
|
||||
struct btrfs_buffer *c;
|
||||
struct btrfs_buffer *next = NULL;
|
||||
|
||||
@ -1474,10 +1487,11 @@ int btrfs_next_leaf(struct btrfs_root *root, struct btrfs_path *path)
|
||||
level++;
|
||||
continue;
|
||||
}
|
||||
blocknr = btrfs_node_blockptr(&c->node, slot);
|
||||
bytenr = btrfs_node_blockptr(&c->node, slot);
|
||||
if (next)
|
||||
btrfs_block_release(root, next);
|
||||
next = read_tree_block(root, blocknr);
|
||||
next = read_tree_block(root, bytenr,
|
||||
btrfs_level_size(root, level - 1));
|
||||
break;
|
||||
}
|
||||
path->slots[level] = slot;
|
||||
@ -1490,7 +1504,8 @@ int btrfs_next_leaf(struct btrfs_root *root, struct btrfs_path *path)
|
||||
if (!level)
|
||||
break;
|
||||
next = read_tree_block(root,
|
||||
btrfs_node_blockptr(&next->node, 0));
|
||||
btrfs_node_blockptr(&next->node, 0),
|
||||
btrfs_level_size(root, level - 1));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
122
ctree.h
122
ctree.h
@ -86,7 +86,7 @@ struct btrfs_key {
|
||||
struct btrfs_header {
|
||||
u8 csum[BTRFS_CSUM_SIZE];
|
||||
u8 fsid[16]; /* FS specific uuid */
|
||||
__le64 blocknr; /* which block this node is supposed to live in */
|
||||
__le64 bytenr; /* which block this node is supposed to live in */
|
||||
__le64 generation;
|
||||
__le64 owner;
|
||||
__le32 nritems;
|
||||
@ -110,16 +110,17 @@ struct btrfs_super_block {
|
||||
u8 csum[BTRFS_CSUM_SIZE];
|
||||
/* the first 3 fields must match struct btrfs_header */
|
||||
u8 fsid[16]; /* FS specific uuid */
|
||||
__le64 blocknr; /* this block number */
|
||||
__le64 bytenr; /* this block number */
|
||||
__le64 magic;
|
||||
__le64 generation;
|
||||
__le64 root;
|
||||
__le64 total_blocks;
|
||||
__le64 blocks_used;
|
||||
__le64 total_bytes;
|
||||
__le64 bytes_used;
|
||||
__le64 root_dir_objectid;
|
||||
__le32 sectorsize;
|
||||
__le32 nodesize;
|
||||
__le32 leafsize;
|
||||
u8 root_level;
|
||||
} __attribute__ ((__packed__));
|
||||
|
||||
/*
|
||||
@ -222,13 +223,14 @@ struct btrfs_dir_item {
|
||||
struct btrfs_root_item {
|
||||
struct btrfs_inode_item inode;
|
||||
__le64 root_dirid;
|
||||
__le64 blocknr;
|
||||
__le64 block_limit;
|
||||
__le64 blocks_used;
|
||||
__le64 bytenr;
|
||||
__le64 byte_limit;
|
||||
__le64 bytes_used;
|
||||
__le32 flags;
|
||||
__le32 refs;
|
||||
struct btrfs_disk_key drop_progress;
|
||||
u8 drop_level;
|
||||
u8 level;
|
||||
} __attribute__ ((__packed__));
|
||||
|
||||
#define BTRFS_FILE_EXTENT_REG 0
|
||||
@ -241,8 +243,8 @@ struct btrfs_file_extent_item {
|
||||
* disk space consumed by the extent, checksum blocks are included
|
||||
* in these numbers
|
||||
*/
|
||||
__le64 disk_blocknr;
|
||||
__le64 disk_num_blocks;
|
||||
__le64 disk_bytenr;
|
||||
__le64 disk_num_bytes;
|
||||
/*
|
||||
* the logical offset in file blocks (no csums)
|
||||
* this extent record is for. This allows a file extent to point
|
||||
@ -254,7 +256,7 @@ struct btrfs_file_extent_item {
|
||||
/*
|
||||
* the logical number of file blocks (no csums included)
|
||||
*/
|
||||
__le64 num_blocks;
|
||||
__le64 num_bytes;
|
||||
} __attribute__ ((__packed__));
|
||||
|
||||
struct btrfs_csum_item {
|
||||
@ -670,14 +672,14 @@ static inline void btrfs_set_key_type(struct btrfs_key *key, u32 val)
|
||||
key->type = val;
|
||||
}
|
||||
|
||||
static inline u64 btrfs_header_blocknr(struct btrfs_header *h)
|
||||
static inline u64 btrfs_header_bytenr(struct btrfs_header *h)
|
||||
{
|
||||
return le64_to_cpu(h->blocknr);
|
||||
return le64_to_cpu(h->bytenr);
|
||||
}
|
||||
|
||||
static inline void btrfs_set_header_blocknr(struct btrfs_header *h, u64 blocknr)
|
||||
static inline void btrfs_set_header_bytenr(struct btrfs_header *h, u64 bytenr)
|
||||
{
|
||||
h->blocknr = cpu_to_le64(blocknr);
|
||||
h->bytenr = cpu_to_le64(bytenr);
|
||||
}
|
||||
|
||||
static inline u64 btrfs_header_generation(struct btrfs_header *h)
|
||||
@ -738,14 +740,14 @@ static inline int btrfs_is_leaf(struct btrfs_node *n)
|
||||
return (btrfs_header_level(&n->header) == 0);
|
||||
}
|
||||
|
||||
static inline u64 btrfs_root_blocknr(struct btrfs_root_item *item)
|
||||
static inline u64 btrfs_root_bytenr(struct btrfs_root_item *item)
|
||||
{
|
||||
return le64_to_cpu(item->blocknr);
|
||||
return le64_to_cpu(item->bytenr);
|
||||
}
|
||||
|
||||
static inline void btrfs_set_root_blocknr(struct btrfs_root_item *item, u64 val)
|
||||
static inline void btrfs_set_root_bytenr(struct btrfs_root_item *item, u64 val)
|
||||
{
|
||||
item->blocknr = cpu_to_le64(val);
|
||||
item->bytenr = cpu_to_le64(val);
|
||||
}
|
||||
|
||||
static inline u64 btrfs_root_dirid(struct btrfs_root_item *item)
|
||||
@ -778,25 +780,25 @@ static inline void btrfs_set_root_flags(struct btrfs_root_item *item, u32 val)
|
||||
item->flags = cpu_to_le32(val);
|
||||
}
|
||||
|
||||
static inline void btrfs_set_root_blocks_used(struct btrfs_root_item *item,
|
||||
static inline void btrfs_set_root_bytes_used(struct btrfs_root_item *item,
|
||||
u64 val)
|
||||
{
|
||||
item->blocks_used = cpu_to_le64(val);
|
||||
item->bytes_used = cpu_to_le64(val);
|
||||
}
|
||||
|
||||
static inline u64 btrfs_root_blocks_used(struct btrfs_root_item *item)
|
||||
static inline u64 btrfs_root_bytes_used(struct btrfs_root_item *item)
|
||||
{
|
||||
return le64_to_cpu(item->blocks_used);
|
||||
return le64_to_cpu(item->bytes_used);
|
||||
}
|
||||
|
||||
static inline u64 btrfs_super_blocknr(struct btrfs_super_block *s)
|
||||
static inline u64 btrfs_super_bytenr(struct btrfs_super_block *s)
|
||||
{
|
||||
return le64_to_cpu(s->blocknr);
|
||||
return le64_to_cpu(s->bytenr);
|
||||
}
|
||||
|
||||
static inline void btrfs_set_super_blocknr(struct btrfs_super_block *s, u64 val)
|
||||
static inline void btrfs_set_super_bytenr(struct btrfs_super_block *s, u64 val)
|
||||
{
|
||||
s->blocknr = cpu_to_le64(val);
|
||||
s->bytenr = cpu_to_le64(val);
|
||||
}
|
||||
|
||||
static inline u64 btrfs_super_generation(struct btrfs_super_block *s)
|
||||
@ -810,6 +812,17 @@ static inline void btrfs_set_super_generation(struct btrfs_super_block *s,
|
||||
s->generation = cpu_to_le64(val);
|
||||
}
|
||||
|
||||
static inline u8 btrfs_super_root_level(struct btrfs_super_block *s)
|
||||
{
|
||||
return s->root_level;
|
||||
}
|
||||
|
||||
static inline void btrfs_set_super_root_level(struct btrfs_super_block *s,
|
||||
u8 val)
|
||||
{
|
||||
s->root_level = val;
|
||||
}
|
||||
|
||||
static inline u64 btrfs_super_root(struct btrfs_super_block *s)
|
||||
{
|
||||
return le64_to_cpu(s->root);
|
||||
@ -820,26 +833,26 @@ static inline void btrfs_set_super_root(struct btrfs_super_block *s, u64 val)
|
||||
s->root = cpu_to_le64(val);
|
||||
}
|
||||
|
||||
static inline u64 btrfs_super_total_blocks(struct btrfs_super_block *s)
|
||||
static inline u64 btrfs_super_total_bytes(struct btrfs_super_block *s)
|
||||
{
|
||||
return le64_to_cpu(s->total_blocks);
|
||||
return le64_to_cpu(s->total_bytes);
|
||||
}
|
||||
|
||||
static inline void btrfs_set_super_total_blocks(struct btrfs_super_block *s,
|
||||
static inline void btrfs_set_super_total_bytes(struct btrfs_super_block *s,
|
||||
u64 val)
|
||||
{
|
||||
s->total_blocks = cpu_to_le64(val);
|
||||
s->total_bytes = cpu_to_le64(val);
|
||||
}
|
||||
|
||||
static inline u64 btrfs_super_blocks_used(struct btrfs_super_block *s)
|
||||
static inline u64 btrfs_super_bytes_used(struct btrfs_super_block *s)
|
||||
{
|
||||
return le64_to_cpu(s->blocks_used);
|
||||
return le64_to_cpu(s->bytes_used);
|
||||
}
|
||||
|
||||
static inline void btrfs_set_super_blocks_used(struct btrfs_super_block *s,
|
||||
static inline void btrfs_set_super_bytes_used(struct btrfs_super_block *s,
|
||||
u64 val)
|
||||
{
|
||||
s->blocks_used = cpu_to_le64(val);
|
||||
s->bytes_used = cpu_to_le64(val);
|
||||
}
|
||||
|
||||
static inline u32 btrfs_super_sectorsize(struct btrfs_super_block *s)
|
||||
@ -904,32 +917,32 @@ static inline void btrfs_set_file_extent_type(struct btrfs_file_extent_item *e,
|
||||
static inline char *btrfs_file_extent_inline_start(struct
|
||||
btrfs_file_extent_item *e)
|
||||
{
|
||||
return (char *)(&e->disk_blocknr);
|
||||
return (char *)(&e->disk_bytenr);
|
||||
}
|
||||
|
||||
static inline u32 btrfs_file_extent_calc_inline_size(u32 datasize)
|
||||
{
|
||||
return (unsigned long)(&((struct
|
||||
btrfs_file_extent_item *)NULL)->disk_blocknr) + datasize;
|
||||
btrfs_file_extent_item *)NULL)->disk_bytenr) + datasize;
|
||||
}
|
||||
|
||||
static inline u32 btrfs_file_extent_inline_len(struct btrfs_item *e)
|
||||
{
|
||||
struct btrfs_file_extent_item *fe = NULL;
|
||||
return btrfs_item_size(e) - (unsigned long)(&fe->disk_blocknr);
|
||||
return btrfs_item_size(e) - (unsigned long)(&fe->disk_bytenr);
|
||||
}
|
||||
|
||||
static inline u64 btrfs_file_extent_disk_blocknr(struct btrfs_file_extent_item
|
||||
static inline u64 btrfs_file_extent_disk_bytenr(struct btrfs_file_extent_item
|
||||
*e)
|
||||
{
|
||||
return le64_to_cpu(e->disk_blocknr);
|
||||
return le64_to_cpu(e->disk_bytenr);
|
||||
}
|
||||
|
||||
static inline void btrfs_set_file_extent_disk_blocknr(struct
|
||||
static inline void btrfs_set_file_extent_disk_bytenr(struct
|
||||
btrfs_file_extent_item
|
||||
*e, u64 val)
|
||||
{
|
||||
e->disk_blocknr = cpu_to_le64(val);
|
||||
e->disk_bytenr = cpu_to_le64(val);
|
||||
}
|
||||
|
||||
static inline u64 btrfs_file_extent_generation(struct btrfs_file_extent_item *e)
|
||||
@ -944,17 +957,17 @@ static inline void btrfs_set_file_extent_generation(struct
|
||||
e->generation = cpu_to_le64(val);
|
||||
}
|
||||
|
||||
static inline u64 btrfs_file_extent_disk_num_blocks(struct
|
||||
static inline u64 btrfs_file_extent_disk_num_bytes(struct
|
||||
btrfs_file_extent_item *e)
|
||||
{
|
||||
return le64_to_cpu(e->disk_num_blocks);
|
||||
return le64_to_cpu(e->disk_num_bytes);
|
||||
}
|
||||
|
||||
static inline void btrfs_set_file_extent_disk_num_blocks(struct
|
||||
static inline void btrfs_set_file_extent_disk_num_bytes(struct
|
||||
btrfs_file_extent_item
|
||||
*e, u64 val)
|
||||
{
|
||||
e->disk_num_blocks = cpu_to_le64(val);
|
||||
e->disk_num_bytes = cpu_to_le64(val);
|
||||
}
|
||||
|
||||
static inline u64 btrfs_file_extent_offset(struct btrfs_file_extent_item *e)
|
||||
@ -968,17 +981,17 @@ static inline void btrfs_set_file_extent_offset(struct btrfs_file_extent_item
|
||||
e->offset = cpu_to_le64(val);
|
||||
}
|
||||
|
||||
static inline u64 btrfs_file_extent_num_blocks(struct btrfs_file_extent_item
|
||||
static inline u64 btrfs_file_extent_num_bytes(struct btrfs_file_extent_item
|
||||
*e)
|
||||
{
|
||||
return le64_to_cpu(e->num_blocks);
|
||||
return le64_to_cpu(e->num_bytes);
|
||||
}
|
||||
|
||||
static inline void btrfs_set_file_extent_num_blocks(struct
|
||||
static inline void btrfs_set_file_extent_num_bytes(struct
|
||||
btrfs_file_extent_item *e,
|
||||
u64 val)
|
||||
{
|
||||
e->num_blocks = cpu_to_le64(val);
|
||||
e->num_bytes = cpu_to_le64(val);
|
||||
}
|
||||
|
||||
/* helper function to cast into the data area of the leaf. */
|
||||
@ -986,15 +999,22 @@ static inline void btrfs_set_file_extent_num_blocks(struct
|
||||
((type *)(btrfs_leaf_data(leaf) + \
|
||||
btrfs_item_offset((leaf)->items + (slot))))
|
||||
|
||||
static inline u32 btrfs_level_size(struct btrfs_root *root, int level)
|
||||
{
|
||||
if (level == 0)
|
||||
return root->leafsize;
|
||||
return root->nodesize;
|
||||
}
|
||||
int btrfs_comp_keys(struct btrfs_disk_key *disk, struct btrfs_key *k2);
|
||||
int btrfs_extend_item(struct btrfs_trans_handle *trans, struct btrfs_root
|
||||
*root, struct btrfs_path *path, u32 data_size);
|
||||
struct btrfs_buffer *btrfs_alloc_free_block(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root);
|
||||
struct btrfs_root *root,
|
||||
u32 blocksize);
|
||||
int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
|
||||
struct btrfs_buffer *buf);
|
||||
int btrfs_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root
|
||||
*root, u64 blocknr, u64 num_blocks, int pin);
|
||||
*root, u64 bytenr, u64 num_bytes, int pin);
|
||||
int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root
|
||||
*root, struct btrfs_key *key, struct btrfs_path *p, int
|
||||
ins_len, int cow);
|
||||
|
11
debug-tree.c
11
debug-tree.c
@ -75,7 +75,8 @@ int main(int ac, char **av) {
|
||||
ri = btrfs_item_ptr(leaf, path.slots[0],
|
||||
struct btrfs_root_item);
|
||||
buf = read_tree_block(root->fs_info->tree_root,
|
||||
btrfs_root_blocknr(ri));
|
||||
btrfs_root_bytenr(ri),
|
||||
root->leafsize);
|
||||
switch(found_key.objectid) {
|
||||
case BTRFS_ROOT_TREE_OBJECTID:
|
||||
printf("root ");
|
||||
@ -93,10 +94,10 @@ int main(int ac, char **av) {
|
||||
path.slots[0]++;
|
||||
}
|
||||
btrfs_release_path(root, &path);
|
||||
printf("total blocks %llu\n",
|
||||
(unsigned long long)btrfs_super_total_blocks(&super));
|
||||
printf("blocks used %llu\n",
|
||||
(unsigned long long)btrfs_super_blocks_used(&super));
|
||||
printf("total bytes %llu\n",
|
||||
(unsigned long long)btrfs_super_total_bytes(&super));
|
||||
printf("bytes used %llu\n",
|
||||
(unsigned long long)btrfs_super_bytes_used(&super));
|
||||
uuidbuf[36] = '\0';
|
||||
uuid_unparse(super.fsid, uuidbuf);
|
||||
printf("uuid %s\n", uuidbuf);
|
||||
|
114
disk-io.c
114
disk-io.c
@ -31,20 +31,20 @@
|
||||
#include "transaction.h"
|
||||
#include "crc32c.h"
|
||||
|
||||
static int allocated_blocks = 0;
|
||||
static u64 allocated_bytes = 0;
|
||||
int cache_max = 10000;
|
||||
|
||||
int btrfs_map_bh_to_logical(struct btrfs_root *root, struct btrfs_buffer *bh,
|
||||
u64 logical)
|
||||
{
|
||||
bh->fd = root->fs_info->fp;
|
||||
bh->dev_blocknr = logical;
|
||||
bh->dev_bytenr = logical;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int check_tree_block(struct btrfs_root *root, struct btrfs_buffer *buf)
|
||||
{
|
||||
if (buf->blocknr != btrfs_header_blocknr(&buf->node.header))
|
||||
if (buf->bytenr != btrfs_header_bytenr(&buf->node.header))
|
||||
BUG();
|
||||
if (memcmp(root->fs_info->disk_super->fsid, buf->node.header.fsid,
|
||||
sizeof(buf->node.header.fsid)))
|
||||
@ -71,24 +71,28 @@ static int free_some_buffers(struct btrfs_root *root)
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct btrfs_buffer *alloc_tree_block(struct btrfs_root *root, u64 blocknr)
|
||||
struct btrfs_buffer *alloc_tree_block(struct btrfs_root *root, u64 bytenr,
|
||||
u32 blocksize)
|
||||
{
|
||||
struct btrfs_buffer *buf;
|
||||
int ret;
|
||||
|
||||
buf = malloc(sizeof(struct btrfs_buffer) + root->sectorsize);
|
||||
buf = malloc(sizeof(struct btrfs_buffer) + blocksize);
|
||||
if (!buf)
|
||||
return buf;
|
||||
allocated_blocks++;
|
||||
buf->blocknr = blocknr;
|
||||
allocated_bytes += blocksize;
|
||||
|
||||
buf->bytenr = bytenr;
|
||||
buf->count = 2;
|
||||
buf->size = blocksize;
|
||||
|
||||
INIT_LIST_HEAD(&buf->dirty);
|
||||
free_some_buffers(root);
|
||||
radix_tree_preload(GFP_KERNEL);
|
||||
ret = radix_tree_insert(&root->fs_info->cache_radix, blocknr, buf);
|
||||
ret = radix_tree_insert(&root->fs_info->cache_radix, bytenr, buf);
|
||||
radix_tree_preload_end();
|
||||
list_add_tail(&buf->cache, &root->fs_info->cache);
|
||||
root->fs_info->cache_size++;
|
||||
root->fs_info->cache_size += blocksize;
|
||||
if (ret) {
|
||||
free(buf);
|
||||
return NULL;
|
||||
@ -96,14 +100,15 @@ struct btrfs_buffer *alloc_tree_block(struct btrfs_root *root, u64 blocknr)
|
||||
return buf;
|
||||
}
|
||||
|
||||
struct btrfs_buffer *find_tree_block(struct btrfs_root *root, u64 blocknr)
|
||||
struct btrfs_buffer *find_tree_block(struct btrfs_root *root, u64 bytenr,
|
||||
u32 blocksize)
|
||||
{
|
||||
struct btrfs_buffer *buf;
|
||||
buf = radix_tree_lookup(&root->fs_info->cache_radix, blocknr);
|
||||
buf = radix_tree_lookup(&root->fs_info->cache_radix, bytenr);
|
||||
if (buf) {
|
||||
buf->count++;
|
||||
} else {
|
||||
buf = alloc_tree_block(root, blocknr);
|
||||
buf = alloc_tree_block(root, bytenr, blocksize);
|
||||
if (!buf) {
|
||||
BUG();
|
||||
return NULL;
|
||||
@ -112,23 +117,24 @@ struct btrfs_buffer *find_tree_block(struct btrfs_root *root, u64 blocknr)
|
||||
return buf;
|
||||
}
|
||||
|
||||
struct btrfs_buffer *read_tree_block(struct btrfs_root *root, u64 blocknr)
|
||||
struct btrfs_buffer *read_tree_block(struct btrfs_root *root, u64 bytenr,
|
||||
u32 blocksize)
|
||||
{
|
||||
struct btrfs_buffer *buf;
|
||||
int ret;
|
||||
buf = radix_tree_lookup(&root->fs_info->cache_radix, blocknr);
|
||||
buf = radix_tree_lookup(&root->fs_info->cache_radix, bytenr);
|
||||
if (buf) {
|
||||
buf->count++;
|
||||
if (check_tree_block(root, buf))
|
||||
BUG();
|
||||
} else {
|
||||
buf = alloc_tree_block(root, blocknr);
|
||||
buf = alloc_tree_block(root, bytenr, blocksize);
|
||||
if (!buf)
|
||||
return NULL;
|
||||
btrfs_map_bh_to_logical(root, buf, blocknr);
|
||||
ret = pread(buf->fd, &buf->node, root->sectorsize,
|
||||
buf->dev_blocknr * root->sectorsize);
|
||||
if (ret != root->sectorsize) {
|
||||
btrfs_map_bh_to_logical(root, buf, bytenr);
|
||||
ret = pread(buf->fd, &buf->node, blocksize,
|
||||
buf->dev_bytenr);
|
||||
if (ret != blocksize) {
|
||||
free(buf);
|
||||
return NULL;
|
||||
}
|
||||
@ -163,7 +169,8 @@ int clean_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root,
|
||||
int btrfs_csum_node(struct btrfs_root *root, struct btrfs_node *node)
|
||||
{
|
||||
u32 crc;
|
||||
size_t len = root->sectorsize - BTRFS_CSUM_SIZE;
|
||||
size_t len = btrfs_level_size(root, btrfs_header_level(&node->header)) -
|
||||
BTRFS_CSUM_SIZE;
|
||||
|
||||
crc = crc32c(0, (char *)(node) + BTRFS_CSUM_SIZE, len);
|
||||
memcpy(node->header.csum, &crc, BTRFS_CRC32_SIZE);
|
||||
@ -189,17 +196,17 @@ int write_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root,
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (buf->blocknr != btrfs_header_blocknr(&buf->node.header))
|
||||
if (buf->bytenr != btrfs_header_bytenr(&buf->node.header))
|
||||
BUG();
|
||||
btrfs_map_bh_to_logical(root, buf, buf->blocknr);
|
||||
btrfs_map_bh_to_logical(root, buf, buf->bytenr);
|
||||
if (check_tree_block(root, buf))
|
||||
BUG();
|
||||
|
||||
btrfs_csum_node(root, &buf->node);
|
||||
|
||||
ret = pwrite(buf->fd, &buf->node, root->sectorsize,
|
||||
buf->dev_blocknr * root->sectorsize);
|
||||
if (ret != root->sectorsize)
|
||||
ret = pwrite(buf->fd, &buf->node, buf->size,
|
||||
buf->dev_bytenr);
|
||||
if (ret != buf->size)
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
@ -226,17 +233,19 @@ static int commit_tree_roots(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_fs_info *fs_info)
|
||||
{
|
||||
int ret;
|
||||
u64 old_extent_block;
|
||||
u64 old_extent_bytenr;
|
||||
struct btrfs_root *tree_root = fs_info->tree_root;
|
||||
struct btrfs_root *extent_root = fs_info->extent_root;
|
||||
|
||||
btrfs_write_dirty_block_groups(trans, fs_info->extent_root);
|
||||
while(1) {
|
||||
old_extent_block = btrfs_root_blocknr(&extent_root->root_item);
|
||||
if (old_extent_block == extent_root->node->blocknr)
|
||||
old_extent_bytenr = btrfs_root_bytenr(&extent_root->root_item);
|
||||
if (old_extent_bytenr == extent_root->node->bytenr)
|
||||
break;
|
||||
btrfs_set_root_blocknr(&extent_root->root_item,
|
||||
extent_root->node->blocknr);
|
||||
btrfs_set_root_bytenr(&extent_root->root_item,
|
||||
extent_root->node->bytenr);
|
||||
extent_root->root_item.level =
|
||||
btrfs_header_level(&extent_root->node->node.header);
|
||||
ret = btrfs_update_root(trans, tree_root,
|
||||
&extent_root->root_key,
|
||||
&extent_root->root_item);
|
||||
@ -259,7 +268,9 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, struct
|
||||
memcpy(&snap_key, &root->root_key, sizeof(snap_key));
|
||||
root->root_key.offset++;
|
||||
|
||||
btrfs_set_root_blocknr(&root->root_item, root->node->blocknr);
|
||||
btrfs_set_root_bytenr(&root->root_item, root->node->bytenr);
|
||||
root->root_item.level =
|
||||
btrfs_header_level(&root->node->node.header);
|
||||
ret = btrfs_insert_root(trans, root->fs_info->tree_root,
|
||||
&root->root_key, &root->root_item);
|
||||
BUG_ON(ret);
|
||||
@ -304,6 +315,17 @@ static int __setup_root(struct btrfs_super_block *super,
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct btrfs_buffer *read_root_block(struct btrfs_root *root, u64 bytenr,
|
||||
u8 level)
|
||||
{
|
||||
struct btrfs_buffer *node;
|
||||
u32 size = btrfs_level_size(root, level);
|
||||
|
||||
node = read_tree_block(root, bytenr, size);
|
||||
BUG_ON(!node);
|
||||
return node;
|
||||
}
|
||||
|
||||
static int find_and_setup_root(struct btrfs_super_block *super,
|
||||
struct btrfs_root *tree_root,
|
||||
struct btrfs_fs_info *fs_info,
|
||||
@ -316,9 +338,9 @@ static int find_and_setup_root(struct btrfs_super_block *super,
|
||||
ret = btrfs_find_last_root(tree_root, objectid,
|
||||
&root->root_item, &root->root_key);
|
||||
BUG_ON(ret);
|
||||
|
||||
root->node = read_tree_block(root,
|
||||
btrfs_root_blocknr(&root->root_item));
|
||||
root->node = read_root_block(root,
|
||||
btrfs_root_bytenr(&root->root_item),
|
||||
root->root_item.level);
|
||||
BUG_ON(!root->node);
|
||||
return 0;
|
||||
}
|
||||
@ -369,7 +391,8 @@ struct btrfs_root *open_ctree_fd(int fp, struct btrfs_super_block *super)
|
||||
BUG_ON(ret < 0);
|
||||
|
||||
__setup_root(super, tree_root, fs_info, BTRFS_ROOT_TREE_OBJECTID, fp);
|
||||
tree_root->node = read_tree_block(tree_root, btrfs_super_root(super));
|
||||
tree_root->node = read_root_block(tree_root, btrfs_super_root(super),
|
||||
btrfs_super_root_level(super));
|
||||
BUG_ON(!tree_root->node);
|
||||
|
||||
ret = find_and_setup_root(super, tree_root, fs_info,
|
||||
@ -393,7 +416,9 @@ int write_ctree_super(struct btrfs_trans_handle *trans, struct btrfs_root
|
||||
{
|
||||
int ret;
|
||||
|
||||
btrfs_set_super_root(s, root->fs_info->tree_root->node->blocknr);
|
||||
btrfs_set_super_root(s, root->fs_info->tree_root->node->bytenr);
|
||||
btrfs_set_super_root_level(s,
|
||||
btrfs_header_level(&root->fs_info->tree_root->node->node.header));
|
||||
btrfs_csum_super(root, s);
|
||||
|
||||
ret = pwrite(root->fs_info->fp, s, sizeof(*s),
|
||||
@ -444,7 +469,8 @@ int close_ctree(struct btrfs_root *root, struct btrfs_super_block *s)
|
||||
root->fs_info->tree_root->node);
|
||||
btrfs_block_release(root, root->commit_root);
|
||||
free(root);
|
||||
printf("on close %d blocks are allocated\n", allocated_blocks);
|
||||
printf("on close %llu blocks are allocated\n",
|
||||
(unsigned long long)allocated_bytes);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -457,15 +483,17 @@ void btrfs_block_release(struct btrfs_root *root, struct btrfs_buffer *buf)
|
||||
BUG_ON(!list_empty(&buf->cache));
|
||||
BUG_ON(!list_empty(&buf->dirty));
|
||||
if (!radix_tree_lookup(&root->fs_info->cache_radix,
|
||||
buf->blocknr))
|
||||
buf->bytenr))
|
||||
BUG();
|
||||
radix_tree_delete(&root->fs_info->cache_radix, buf->blocknr);
|
||||
|
||||
radix_tree_delete(&root->fs_info->cache_radix, buf->bytenr);
|
||||
BUG_ON(allocated_bytes == 0);
|
||||
allocated_bytes -= buf->size;
|
||||
BUG_ON(root->fs_info->cache_size == 0);
|
||||
root->fs_info->cache_size -= buf->size;
|
||||
|
||||
memset(buf, 0, sizeof(*buf));
|
||||
free(buf);
|
||||
BUG_ON(allocated_blocks == 0);
|
||||
allocated_blocks--;
|
||||
BUG_ON(root->fs_info->cache_size == 0);
|
||||
root->fs_info->cache_size--;
|
||||
}
|
||||
}
|
||||
|
||||
|
10
disk-io.h
10
disk-io.h
@ -21,8 +21,8 @@
|
||||
#include "list.h"
|
||||
|
||||
struct btrfs_buffer {
|
||||
u64 blocknr;
|
||||
u64 dev_blocknr;
|
||||
u64 bytenr;
|
||||
u64 dev_bytenr;
|
||||
u32 size;
|
||||
int count;
|
||||
int fd;
|
||||
@ -34,8 +34,10 @@ struct btrfs_buffer {
|
||||
};
|
||||
};
|
||||
|
||||
struct btrfs_buffer *read_tree_block(struct btrfs_root *root, u64 blocknr);
|
||||
struct btrfs_buffer *find_tree_block(struct btrfs_root *root, u64 blocknr);
|
||||
struct btrfs_buffer *read_tree_block(struct btrfs_root *root, u64 bytenr,
|
||||
u32 blocksize);
|
||||
struct btrfs_buffer *find_tree_block(struct btrfs_root *root, u64 bytenr,
|
||||
u32 blocksize);
|
||||
int write_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root,
|
||||
struct btrfs_buffer *buf);
|
||||
int dirty_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root,
|
||||
|
172
extent-tree.c
172
extent-tree.c
@ -30,16 +30,8 @@ static int finish_current_insert(struct btrfs_trans_handle *trans, struct
|
||||
static int run_pending(struct btrfs_trans_handle *trans, struct btrfs_root
|
||||
*extent_root);
|
||||
|
||||
/*
|
||||
* pending extents are blocks that we're trying to allocate in the extent
|
||||
* map while trying to grow the map because of other allocations. To avoid
|
||||
* recursing, they are tagged in the radix tree and cleaned up after
|
||||
* other allocations are done. The pending tag is also used in the same
|
||||
* manner for deletes.
|
||||
*/
|
||||
|
||||
static int inc_block_ref(struct btrfs_trans_handle *trans, struct btrfs_root
|
||||
*root, u64 blocknr)
|
||||
*root, u64 bytenr, u32 blocksize)
|
||||
{
|
||||
struct btrfs_path path;
|
||||
int ret;
|
||||
@ -49,9 +41,9 @@ static int inc_block_ref(struct btrfs_trans_handle *trans, struct btrfs_root
|
||||
u32 refs;
|
||||
|
||||
btrfs_init_path(&path);
|
||||
key.objectid = blocknr;
|
||||
key.objectid = bytenr;
|
||||
btrfs_set_key_type(&key, BTRFS_EXTENT_ITEM_KEY);
|
||||
key.offset = 1;
|
||||
key.offset = blocksize;
|
||||
ret = btrfs_search_slot(trans, root->fs_info->extent_root, &key, &path,
|
||||
0, 1);
|
||||
if (ret != 0)
|
||||
@ -70,7 +62,7 @@ static int inc_block_ref(struct btrfs_trans_handle *trans, struct btrfs_root
|
||||
}
|
||||
|
||||
static int lookup_block_ref(struct btrfs_trans_handle *trans, struct btrfs_root
|
||||
*root, u64 blocknr, u32 *refs)
|
||||
*root, u64 bytenr, u32 blocksize, u32 *refs)
|
||||
{
|
||||
struct btrfs_path path;
|
||||
int ret;
|
||||
@ -78,8 +70,8 @@ static int lookup_block_ref(struct btrfs_trans_handle *trans, struct btrfs_root
|
||||
struct btrfs_leaf *l;
|
||||
struct btrfs_extent_item *item;
|
||||
btrfs_init_path(&path);
|
||||
key.objectid = blocknr;
|
||||
key.offset = 1;
|
||||
key.objectid = bytenr;
|
||||
key.offset = blocksize;
|
||||
btrfs_set_key_type(&key, BTRFS_EXTENT_ITEM_KEY);
|
||||
ret = btrfs_search_slot(trans, root->fs_info->extent_root, &key, &path,
|
||||
0, 0);
|
||||
@ -95,17 +87,18 @@ static int lookup_block_ref(struct btrfs_trans_handle *trans, struct btrfs_root
|
||||
int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
|
||||
struct btrfs_buffer *buf)
|
||||
{
|
||||
u64 blocknr;
|
||||
u64 bytenr;
|
||||
int i;
|
||||
|
||||
if (!root->ref_cows)
|
||||
return 0;
|
||||
|
||||
if (btrfs_is_leaf(&buf->node))
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < btrfs_header_nritems(&buf->node.header); i++) {
|
||||
blocknr = btrfs_node_blockptr(&buf->node, i);
|
||||
inc_block_ref(trans, root, blocknr);
|
||||
bytenr = btrfs_node_blockptr(&buf->node, i);
|
||||
inc_block_ref(trans, root, bytenr, root->nodesize);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -171,32 +164,32 @@ int btrfs_write_dirty_block_groups(struct btrfs_trans_handle *trans,
|
||||
|
||||
static int update_block_group(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root,
|
||||
u64 blocknr, u64 num, int alloc)
|
||||
u64 bytenr, u64 num, int alloc)
|
||||
{
|
||||
struct btrfs_block_group_cache *cache;
|
||||
struct btrfs_fs_info *info = root->fs_info;
|
||||
u64 total = num;
|
||||
u64 old_val;
|
||||
u64 block_in_group;
|
||||
u64 byte_in_group;
|
||||
int ret;
|
||||
|
||||
while(total) {
|
||||
ret = radix_tree_gang_lookup(&info->block_group_radix,
|
||||
(void *)&cache, blocknr, 1);
|
||||
(void *)&cache, bytenr, 1);
|
||||
if (!ret)
|
||||
return -1;
|
||||
radix_tree_tag_set(&info->block_group_radix,
|
||||
cache->key.objectid + cache->key.offset - 1,
|
||||
BTRFS_BLOCK_GROUP_DIRTY);
|
||||
|
||||
block_in_group = blocknr - cache->key.objectid;
|
||||
byte_in_group = bytenr - cache->key.objectid;
|
||||
old_val = btrfs_block_group_used(&cache->item);
|
||||
if (total > cache->key.offset - block_in_group)
|
||||
num = cache->key.offset - block_in_group;
|
||||
if (total > cache->key.offset - byte_in_group)
|
||||
num = cache->key.offset - byte_in_group;
|
||||
else
|
||||
num = total;
|
||||
total -= num;
|
||||
blocknr += num;
|
||||
bytenr += num;
|
||||
if (alloc)
|
||||
old_val += num;
|
||||
else
|
||||
@ -233,7 +226,6 @@ static int finish_current_insert(struct btrfs_trans_handle *trans, struct
|
||||
struct btrfs_key ins;
|
||||
struct btrfs_extent_item extent_item;
|
||||
int ret;
|
||||
u64 super_blocks_used, root_blocks_used;
|
||||
struct btrfs_fs_info *info = extent_root->fs_info;
|
||||
struct pending_extent *pe;
|
||||
struct pending_extent *next;
|
||||
@ -256,13 +248,6 @@ static int finish_current_insert(struct btrfs_trans_handle *trans, struct
|
||||
free_pending_extent(pe);
|
||||
pe = next;
|
||||
|
||||
|
||||
super_blocks_used = btrfs_super_blocks_used(info->disk_super);
|
||||
btrfs_set_super_blocks_used(info->disk_super,
|
||||
super_blocks_used + 1);
|
||||
root_blocks_used = btrfs_root_blocks_used(&extent_root->root_item);
|
||||
btrfs_set_root_blocks_used(&extent_root->root_item,
|
||||
root_blocks_used + 1);
|
||||
ret = btrfs_insert_item(trans, extent_root, &ins, &extent_item,
|
||||
sizeof(extent_item));
|
||||
if (ret) {
|
||||
@ -277,7 +262,7 @@ static int finish_current_insert(struct btrfs_trans_handle *trans, struct
|
||||
* remove an extent from the root, returns 0 on success
|
||||
*/
|
||||
static int __free_extent(struct btrfs_trans_handle *trans, struct btrfs_root
|
||||
*root, u64 blocknr, u64 num_blocks, int pin)
|
||||
*root, u64 bytenr, u64 num_bytes, int pin)
|
||||
{
|
||||
struct btrfs_path path;
|
||||
struct btrfs_key key;
|
||||
@ -287,10 +272,9 @@ static int __free_extent(struct btrfs_trans_handle *trans, struct btrfs_root
|
||||
struct btrfs_extent_item *ei;
|
||||
u32 refs;
|
||||
|
||||
BUG_ON(pin && num_blocks != 1);
|
||||
key.objectid = blocknr;
|
||||
key.objectid = bytenr;
|
||||
btrfs_set_key_type(&key, BTRFS_EXTENT_ITEM_KEY);
|
||||
key.offset = num_blocks;
|
||||
key.offset = num_bytes;
|
||||
|
||||
btrfs_init_path(&path);
|
||||
ret = btrfs_search_slot(trans, extent_root, &key, &path, -1, 1);
|
||||
@ -306,27 +290,27 @@ static int __free_extent(struct btrfs_trans_handle *trans, struct btrfs_root
|
||||
refs = btrfs_extent_refs(ei) - 1;
|
||||
btrfs_set_extent_refs(ei, refs);
|
||||
if (refs == 0) {
|
||||
u64 super_blocks_used, root_blocks_used;
|
||||
u64 super_bytes_used, root_bytes_used;
|
||||
if (pin) {
|
||||
int err;
|
||||
err = insert_pending_extent(&info->pinned_tree,
|
||||
blocknr, 1);
|
||||
bytenr, num_bytes);
|
||||
BUG_ON(err);
|
||||
}
|
||||
super_blocks_used = btrfs_super_blocks_used(info->disk_super);
|
||||
btrfs_set_super_blocks_used(info->disk_super,
|
||||
super_blocks_used - num_blocks);
|
||||
root_blocks_used = btrfs_root_blocks_used(&root->root_item);
|
||||
btrfs_set_root_blocks_used(&root->root_item,
|
||||
root_blocks_used - num_blocks);
|
||||
super_bytes_used = btrfs_super_bytes_used(info->disk_super);
|
||||
btrfs_set_super_bytes_used(info->disk_super,
|
||||
super_bytes_used - num_bytes);
|
||||
root_bytes_used = btrfs_root_bytes_used(&root->root_item);
|
||||
btrfs_set_root_bytes_used(&root->root_item,
|
||||
root_bytes_used - num_bytes);
|
||||
|
||||
ret = btrfs_del_item(trans, extent_root, &path);
|
||||
if (!pin && extent_root->fs_info->last_insert.objectid >
|
||||
blocknr)
|
||||
extent_root->fs_info->last_insert.objectid = blocknr;
|
||||
bytenr)
|
||||
extent_root->fs_info->last_insert.objectid = bytenr;
|
||||
if (ret)
|
||||
BUG();
|
||||
ret = update_block_group(trans, root, blocknr, num_blocks, 0);
|
||||
ret = update_block_group(trans, root, bytenr, num_bytes, 0);
|
||||
BUG_ON(ret);
|
||||
}
|
||||
btrfs_release_path(extent_root, &path);
|
||||
@ -350,7 +334,7 @@ static int del_pending_extents(struct btrfs_trans_handle *trans, struct
|
||||
while(pe) {
|
||||
remove_pending_extent(del_pending, pe);
|
||||
ret = __free_extent(trans, extent_root,
|
||||
pe->start, 1, 1);
|
||||
pe->start, pe->size, 1);
|
||||
BUG_ON(ret);
|
||||
next = next_pending_extent(pe);
|
||||
if (!next)
|
||||
@ -373,7 +357,7 @@ static int run_pending(struct btrfs_trans_handle *trans, struct btrfs_root
|
||||
* remove an extent from the root, returns 0 on success
|
||||
*/
|
||||
int btrfs_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root
|
||||
*root, u64 blocknr, u64 num_blocks, int pin)
|
||||
*root, u64 bytenr, u64 num_bytes, int pin)
|
||||
{
|
||||
struct btrfs_root *extent_root = root->fs_info->extent_root;
|
||||
int pending_ret;
|
||||
@ -381,11 +365,11 @@ int btrfs_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root
|
||||
|
||||
if (root == extent_root) {
|
||||
ret = insert_pending_extent(&root->fs_info->del_pending,
|
||||
blocknr, num_blocks);
|
||||
bytenr, num_bytes);
|
||||
BUG_ON(ret);
|
||||
return 0;
|
||||
}
|
||||
ret = __free_extent(trans, root, blocknr, num_blocks, pin);
|
||||
ret = __free_extent(trans, root, bytenr, num_bytes, pin);
|
||||
pending_ret = run_pending(trans, root->fs_info->extent_root);
|
||||
return ret ? ret : pending_ret;
|
||||
}
|
||||
@ -399,19 +383,18 @@ int btrfs_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root
|
||||
* Any available blocks before search_start are skipped.
|
||||
*/
|
||||
static int find_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root
|
||||
*orig_root, u64 num_blocks, u64 search_start, u64
|
||||
search_end, struct btrfs_key *ins)
|
||||
*orig_root, u64 total_needed, u64 search_start,
|
||||
u64 search_end, struct btrfs_key *ins)
|
||||
{
|
||||
struct btrfs_path path;
|
||||
struct btrfs_key key;
|
||||
int ret;
|
||||
u64 hole_size = 0;
|
||||
int slot = 0;
|
||||
u64 last_block = 0;
|
||||
u64 last_byte = 0;
|
||||
int start_found;
|
||||
struct btrfs_leaf *l;
|
||||
struct btrfs_root * root = orig_root->fs_info->extent_root;
|
||||
int total_needed = num_blocks;
|
||||
|
||||
if (root->fs_info->last_insert.objectid > search_start)
|
||||
search_start = root->fs_info->last_insert.objectid;
|
||||
@ -445,8 +428,8 @@ check_failed:
|
||||
start_found = 1;
|
||||
goto check_pending;
|
||||
}
|
||||
ins->objectid = last_block > search_start ?
|
||||
last_block : search_start;
|
||||
ins->objectid = last_byte > search_start ?
|
||||
last_byte : search_start;
|
||||
ins->offset = (u64)-1 - ins->objectid;
|
||||
goto check_pending;
|
||||
}
|
||||
@ -455,18 +438,18 @@ check_failed:
|
||||
goto next;
|
||||
if (key.objectid >= search_start) {
|
||||
if (start_found) {
|
||||
if (last_block < search_start)
|
||||
last_block = search_start;
|
||||
hole_size = key.objectid - last_block;
|
||||
if (last_byte < search_start)
|
||||
last_byte = search_start;
|
||||
hole_size = key.objectid - last_byte;
|
||||
if (hole_size > total_needed) {
|
||||
ins->objectid = last_block;
|
||||
ins->objectid = last_byte;
|
||||
ins->offset = hole_size;
|
||||
goto check_pending;
|
||||
}
|
||||
}
|
||||
}
|
||||
start_found = 1;
|
||||
last_block = key.objectid + key.offset;
|
||||
last_byte = key.objectid + key.offset;
|
||||
next:
|
||||
path.slots[0]++;
|
||||
}
|
||||
@ -488,7 +471,7 @@ check_pending:
|
||||
goto check_failed;
|
||||
}
|
||||
root->fs_info->last_insert.objectid = ins->objectid;
|
||||
ins->offset = num_blocks;
|
||||
ins->offset = total_needed;
|
||||
return 0;
|
||||
error:
|
||||
btrfs_release_path(root, &path);
|
||||
@ -501,14 +484,14 @@ error:
|
||||
*
|
||||
* returns 0 if everything worked, non-zero otherwise.
|
||||
*/
|
||||
static int alloc_extent(struct btrfs_trans_handle *trans, struct btrfs_root
|
||||
*root, u64 owner, u64 num_blocks,
|
||||
u64 search_start, u64
|
||||
search_end, struct btrfs_key *ins)
|
||||
static int alloc_extent(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root, u64 owner,
|
||||
u64 num_bytes, u64 search_start,
|
||||
u64 search_end, struct btrfs_key *ins)
|
||||
{
|
||||
int ret;
|
||||
int pending_ret;
|
||||
u64 super_blocks_used, root_blocks_used;
|
||||
u64 super_bytes_used, root_bytes_used;
|
||||
struct btrfs_fs_info *info = root->fs_info;
|
||||
struct btrfs_root *extent_root = info->extent_root;
|
||||
struct btrfs_extent_item extent_item;
|
||||
@ -516,23 +499,23 @@ static int alloc_extent(struct btrfs_trans_handle *trans, struct btrfs_root
|
||||
btrfs_set_extent_refs(&extent_item, 1);
|
||||
btrfs_set_extent_owner(&extent_item, owner);
|
||||
|
||||
ret = find_free_extent(trans, root, num_blocks, search_start,
|
||||
ret = find_free_extent(trans, root, num_bytes, search_start,
|
||||
search_end, ins);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
super_bytes_used = btrfs_super_bytes_used(info->disk_super);
|
||||
btrfs_set_super_bytes_used(info->disk_super, super_bytes_used +
|
||||
num_bytes);
|
||||
root_bytes_used = btrfs_root_bytes_used(&root->root_item);
|
||||
btrfs_set_root_bytes_used(&root->root_item, root_bytes_used +
|
||||
num_bytes);
|
||||
if (root == extent_root) {
|
||||
ret = insert_pending_extent(&root->fs_info->pending_tree,
|
||||
ins->objectid, ins->offset);
|
||||
BUG_ON(ret);
|
||||
return 0;
|
||||
}
|
||||
super_blocks_used = btrfs_super_blocks_used(info->disk_super);
|
||||
btrfs_set_super_blocks_used(info->disk_super, super_blocks_used +
|
||||
num_blocks);
|
||||
root_blocks_used = btrfs_root_blocks_used(&root->root_item);
|
||||
btrfs_set_root_blocks_used(&root->root_item, root_blocks_used +
|
||||
num_blocks);
|
||||
|
||||
ret = btrfs_insert_item(trans, extent_root, ins, &extent_item,
|
||||
sizeof(extent_item));
|
||||
@ -551,23 +534,24 @@ static int alloc_extent(struct btrfs_trans_handle *trans, struct btrfs_root
|
||||
* returns the tree buffer or NULL.
|
||||
*/
|
||||
struct btrfs_buffer *btrfs_alloc_free_block(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root)
|
||||
struct btrfs_root *root,
|
||||
u32 blocksize)
|
||||
{
|
||||
struct btrfs_key ins;
|
||||
int ret;
|
||||
struct btrfs_buffer *buf;
|
||||
|
||||
ret = alloc_extent(trans, root, root->root_key.objectid,
|
||||
1, 0, (unsigned long)-1, &ins);
|
||||
blocksize, 0, (unsigned long)-1, &ins);
|
||||
if (ret) {
|
||||
BUG();
|
||||
return NULL;
|
||||
}
|
||||
ret = update_block_group(trans, root, ins.objectid, ins.offset, 1);
|
||||
buf = find_tree_block(root, ins.objectid);
|
||||
buf = find_tree_block(root, ins.objectid, blocksize);
|
||||
btrfs_set_header_generation(&buf->node.header,
|
||||
root->root_key.offset + 1);
|
||||
btrfs_set_header_blocknr(&buf->node.header, buf->blocknr);
|
||||
btrfs_set_header_bytenr(&buf->node.header, buf->bytenr);
|
||||
memcpy(buf->node.header.fsid, root->fs_info->disk_super->fsid,
|
||||
sizeof(buf->node.header.fsid));
|
||||
dirty_tree_block(trans, root, buf);
|
||||
@ -584,12 +568,12 @@ static int walk_down_tree(struct btrfs_trans_handle *trans, struct btrfs_root
|
||||
{
|
||||
struct btrfs_buffer *next;
|
||||
struct btrfs_buffer *cur;
|
||||
u64 blocknr;
|
||||
u64 bytenr;
|
||||
int ret;
|
||||
u32 refs;
|
||||
|
||||
ret = lookup_block_ref(trans, root, path->nodes[*level]->blocknr,
|
||||
&refs);
|
||||
ret = lookup_block_ref(trans, root, path->nodes[*level]->bytenr,
|
||||
btrfs_level_size(root, *level), &refs);
|
||||
BUG_ON(ret);
|
||||
if (refs > 1)
|
||||
goto out;
|
||||
@ -597,20 +581,22 @@ static int walk_down_tree(struct btrfs_trans_handle *trans, struct btrfs_root
|
||||
* walk down to the last node level and free all the leaves
|
||||
*/
|
||||
while(*level > 0) {
|
||||
u32 size = btrfs_level_size(root, *level - 1);
|
||||
|
||||
cur = path->nodes[*level];
|
||||
if (path->slots[*level] >=
|
||||
btrfs_header_nritems(&cur->node.header))
|
||||
break;
|
||||
blocknr = btrfs_node_blockptr(&cur->node, path->slots[*level]);
|
||||
ret = lookup_block_ref(trans, root, blocknr, &refs);
|
||||
bytenr = btrfs_node_blockptr(&cur->node, path->slots[*level]);
|
||||
ret = lookup_block_ref(trans, root, bytenr, size, &refs);
|
||||
if (refs != 1 || *level == 1) {
|
||||
path->slots[*level]++;
|
||||
ret = btrfs_free_extent(trans, root, blocknr, 1, 1);
|
||||
ret = btrfs_free_extent(trans, root, bytenr, size, 1);
|
||||
BUG_ON(ret);
|
||||
continue;
|
||||
}
|
||||
BUG_ON(ret);
|
||||
next = read_tree_block(root, blocknr);
|
||||
next = read_tree_block(root, bytenr, size);
|
||||
if (path->nodes[*level-1])
|
||||
btrfs_block_release(root, path->nodes[*level-1]);
|
||||
path->nodes[*level-1] = next;
|
||||
@ -618,8 +604,8 @@ static int walk_down_tree(struct btrfs_trans_handle *trans, struct btrfs_root
|
||||
path->slots[*level] = 0;
|
||||
}
|
||||
out:
|
||||
ret = btrfs_free_extent(trans, root, path->nodes[*level]->blocknr, 1,
|
||||
1);
|
||||
ret = btrfs_free_extent(trans, root, path->nodes[*level]->bytenr,
|
||||
btrfs_level_size(root, *level), 1);
|
||||
btrfs_block_release(root, path->nodes[*level]);
|
||||
path->nodes[*level] = NULL;
|
||||
*level += 1;
|
||||
@ -647,8 +633,8 @@ static int walk_up_tree(struct btrfs_trans_handle *trans, struct btrfs_root
|
||||
return 0;
|
||||
} else {
|
||||
ret = btrfs_free_extent(trans, root,
|
||||
path->nodes[*level]->blocknr,
|
||||
1, 1);
|
||||
path->nodes[*level]->bytenr,
|
||||
btrfs_level_size(root, *level), 1);
|
||||
btrfs_block_release(root, path->nodes[*level]);
|
||||
path->nodes[*level] = NULL;
|
||||
*level = i + 1;
|
||||
@ -732,11 +718,11 @@ int btrfs_read_block_groups(struct btrfs_root *root)
|
||||
struct btrfs_key key;
|
||||
struct btrfs_key found_key;
|
||||
struct btrfs_leaf *leaf;
|
||||
u64 group_size_blocks = BTRFS_BLOCK_GROUP_SIZE / root->sectorsize;
|
||||
u64 group_size = BTRFS_BLOCK_GROUP_SIZE;
|
||||
|
||||
root = root->fs_info->extent_root;
|
||||
key.objectid = 0;
|
||||
key.offset = group_size_blocks;
|
||||
key.offset = group_size;
|
||||
btrfs_set_key_type(&key, BTRFS_BLOCK_GROUP_ITEM_KEY);
|
||||
btrfs_init_path(&path);
|
||||
|
||||
@ -766,7 +752,7 @@ int btrfs_read_block_groups(struct btrfs_root *root)
|
||||
found_key.offset - 1, (void *)cache);
|
||||
BUG_ON(ret);
|
||||
if (key.objectid >=
|
||||
btrfs_super_total_blocks(root->fs_info->disk_super))
|
||||
btrfs_super_total_bytes(root->fs_info->disk_super))
|
||||
break;
|
||||
}
|
||||
btrfs_release_path(root, &path);
|
||||
|
179
mkfs.c
179
mkfs.c
@ -85,55 +85,57 @@ error:
|
||||
static int make_block_groups(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root)
|
||||
{
|
||||
u64 group_size_blocks;
|
||||
u64 total_blocks;
|
||||
u64 group_size;
|
||||
u64 total_bytes;
|
||||
u64 cur_start;
|
||||
int ret;
|
||||
u64 nr = 0;
|
||||
struct btrfs_block_group_cache *cache;
|
||||
|
||||
root = root->fs_info->extent_root;
|
||||
|
||||
/* first we bootstrap the things into cache */
|
||||
group_size_blocks = BTRFS_BLOCK_GROUP_SIZE / root->sectorsize;
|
||||
group_size = BTRFS_BLOCK_GROUP_SIZE;
|
||||
cache = malloc(sizeof(*cache));
|
||||
cache->key.objectid = 0;
|
||||
cache->key.offset = group_size_blocks;
|
||||
cache->key.offset = group_size;
|
||||
btrfs_set_key_type(&cache->key, BTRFS_BLOCK_GROUP_ITEM_KEY);
|
||||
|
||||
memset(&cache->item, 0, sizeof(cache->item));
|
||||
btrfs_set_block_group_used(&cache->item,
|
||||
btrfs_super_blocks_used(root->fs_info->disk_super));
|
||||
btrfs_super_bytes_used(root->fs_info->disk_super));
|
||||
ret = radix_tree_insert(&root->fs_info->block_group_radix,
|
||||
group_size_blocks - 1, (void *)cache);
|
||||
group_size - 1, (void *)cache);
|
||||
BUG_ON(ret);
|
||||
|
||||
total_blocks = btrfs_super_total_blocks(root->fs_info->disk_super);
|
||||
cur_start = group_size_blocks;
|
||||
while(cur_start < total_blocks) {
|
||||
total_bytes = btrfs_super_total_bytes(root->fs_info->disk_super);
|
||||
cur_start = group_size;
|
||||
while(cur_start < total_bytes) {
|
||||
cache = malloc(sizeof(*cache));
|
||||
cache->key.objectid = cur_start;
|
||||
cache->key.offset = group_size_blocks;
|
||||
cache->key.offset = group_size;
|
||||
btrfs_set_key_type(&cache->key, BTRFS_BLOCK_GROUP_ITEM_KEY);
|
||||
memset(&cache->item, 0, sizeof(cache->item));
|
||||
if (nr % 3)
|
||||
cache->item.flags |= BTRFS_BLOCK_GROUP_DATA;
|
||||
|
||||
ret = radix_tree_insert(&root->fs_info->block_group_radix,
|
||||
cur_start + group_size_blocks - 1,
|
||||
cur_start + group_size - 1,
|
||||
(void *)cache);
|
||||
BUG_ON(ret);
|
||||
cur_start += group_size_blocks;
|
||||
cur_start += group_size;
|
||||
nr++;
|
||||
}
|
||||
/* then insert all the items */
|
||||
cur_start = 0;
|
||||
while(cur_start < total_blocks) {
|
||||
while(cur_start < total_bytes) {
|
||||
cache = radix_tree_lookup(&root->fs_info->block_group_radix,
|
||||
cur_start + group_size_blocks - 1);
|
||||
cur_start + group_size - 1);
|
||||
BUG_ON(!cache);
|
||||
ret = btrfs_insert_block_group(trans, root, &cache->key,
|
||||
&cache->item);
|
||||
BUG_ON(ret);
|
||||
cur_start += group_size_blocks;
|
||||
cur_start += group_size;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -174,7 +176,8 @@ err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int mkfs(int fd, char *pathname, u64 num_blocks, u32 blocksize)
|
||||
int mkfs(int fd, char *pathname, u64 num_bytes, u32 nodesize, u32 leafsize,
|
||||
u32 sectorsize)
|
||||
{
|
||||
struct btrfs_super_block super;
|
||||
struct btrfs_leaf *empty_leaf;
|
||||
@ -185,33 +188,37 @@ int mkfs(int fd, char *pathname, u64 num_blocks, u32 blocksize)
|
||||
char *block;
|
||||
int ret;
|
||||
u32 itemoff;
|
||||
u32 start_block = BTRFS_SUPER_INFO_OFFSET / blocksize;
|
||||
u32 start_block = BTRFS_SUPER_INFO_OFFSET;
|
||||
u32 first_free = BTRFS_SUPER_INFO_OFFSET + sectorsize;
|
||||
|
||||
btrfs_set_super_generation(&super, 1);
|
||||
btrfs_set_super_blocknr(&super, start_block);
|
||||
btrfs_set_super_root(&super, start_block + 1);
|
||||
btrfs_set_super_bytenr(&super, start_block);
|
||||
btrfs_set_super_root_level(&super, 0);
|
||||
btrfs_set_super_root(&super, first_free);
|
||||
strcpy((char *)(&super.magic), BTRFS_MAGIC);
|
||||
|
||||
printf("blocksize is %d\n", blocksize);
|
||||
btrfs_set_super_sectorsize(&super, blocksize);
|
||||
btrfs_set_super_leafsize(&super, blocksize);
|
||||
btrfs_set_super_nodesize(&super, blocksize);
|
||||
printf("blocksize is %d\n", leafsize);
|
||||
btrfs_set_super_sectorsize(&super, sectorsize);
|
||||
btrfs_set_super_leafsize(&super, leafsize);
|
||||
btrfs_set_super_nodesize(&super, nodesize);
|
||||
|
||||
btrfs_set_super_total_blocks(&super, num_blocks);
|
||||
btrfs_set_super_blocks_used(&super, start_block + 4);
|
||||
num_bytes = (num_bytes / sectorsize) * sectorsize;
|
||||
btrfs_set_super_total_bytes(&super, num_bytes);
|
||||
btrfs_set_super_bytes_used(&super, start_block + 3 * leafsize +
|
||||
sectorsize);
|
||||
uuid_generate(super.fsid);
|
||||
|
||||
block = malloc(blocksize);
|
||||
memset(block, 0, blocksize);
|
||||
BUG_ON(sizeof(super) > blocksize);
|
||||
block = malloc(sectorsize);
|
||||
memset(block, 0, sectorsize);
|
||||
BUG_ON(sizeof(super) > sectorsize);
|
||||
memcpy(block, &super, sizeof(super));
|
||||
ret = pwrite(fd, block, blocksize, BTRFS_SUPER_INFO_OFFSET);
|
||||
BUG_ON(ret != blocksize);
|
||||
ret = pwrite(fd, block, sectorsize, BTRFS_SUPER_INFO_OFFSET);
|
||||
BUG_ON(ret != sectorsize);
|
||||
|
||||
/* create the tree of root objects */
|
||||
empty_leaf = malloc(blocksize);
|
||||
memset(empty_leaf, 0, blocksize);
|
||||
btrfs_set_header_blocknr(&empty_leaf->header, start_block + 1);
|
||||
empty_leaf = malloc(leafsize);
|
||||
memset(empty_leaf, 0, leafsize);
|
||||
btrfs_set_header_bytenr(&empty_leaf->header, first_free);
|
||||
btrfs_set_header_nritems(&empty_leaf->header, 2);
|
||||
btrfs_set_header_generation(&empty_leaf->header, 0);
|
||||
btrfs_set_header_owner(&empty_leaf->header, BTRFS_ROOT_TREE_OBJECTID);
|
||||
@ -234,34 +241,35 @@ printf("blocksize is %d\n", blocksize);
|
||||
btrfs_set_item_size(&item, sizeof(root_item));
|
||||
btrfs_set_disk_key_type(&item.key, BTRFS_ROOT_ITEM_KEY);
|
||||
|
||||
itemoff = __BTRFS_LEAF_DATA_SIZE(blocksize) - sizeof(root_item);
|
||||
btrfs_set_root_blocknr(&root_item, start_block + 2);
|
||||
itemoff = __BTRFS_LEAF_DATA_SIZE(leafsize) - sizeof(root_item);
|
||||
btrfs_set_root_bytenr(&root_item, first_free + leafsize);
|
||||
root_item.level = 0;
|
||||
btrfs_set_item_offset(&item, itemoff);
|
||||
btrfs_set_disk_key_objectid(&item.key, BTRFS_EXTENT_TREE_OBJECTID);
|
||||
memcpy(empty_leaf->items, &item, sizeof(item));
|
||||
memcpy(btrfs_leaf_data(empty_leaf) + itemoff,
|
||||
&root_item, sizeof(root_item));
|
||||
|
||||
btrfs_set_root_blocknr(&root_item, start_block + 3);
|
||||
btrfs_set_root_blocks_used(&root_item, 1);
|
||||
btrfs_set_root_bytenr(&root_item, first_free + leafsize * 2);
|
||||
btrfs_set_root_bytes_used(&root_item, 1);
|
||||
itemoff = itemoff - sizeof(root_item);
|
||||
btrfs_set_item_offset(&item, itemoff);
|
||||
btrfs_set_disk_key_objectid(&item.key, BTRFS_FS_TREE_OBJECTID);
|
||||
memcpy(empty_leaf->items + 1, &item, sizeof(item));
|
||||
memcpy(btrfs_leaf_data(empty_leaf) + itemoff,
|
||||
&root_item, sizeof(root_item));
|
||||
ret = pwrite(fd, empty_leaf, blocksize, (start_block + 1) * blocksize);
|
||||
ret = pwrite(fd, empty_leaf, leafsize, first_free);
|
||||
|
||||
/* create the items for the extent tree */
|
||||
btrfs_set_header_blocknr(&empty_leaf->header, start_block + 2);
|
||||
btrfs_set_header_bytenr(&empty_leaf->header, first_free + leafsize);
|
||||
btrfs_set_header_nritems(&empty_leaf->header, 4);
|
||||
|
||||
/* item1, reserve blocks 0-16 */
|
||||
btrfs_set_disk_key_objectid(&item.key, 0);
|
||||
btrfs_set_disk_key_offset(&item.key, start_block + 1);
|
||||
btrfs_set_disk_key_offset(&item.key, first_free);
|
||||
btrfs_set_disk_key_type(&item.key, 0);
|
||||
btrfs_set_disk_key_type(&item.key, BTRFS_EXTENT_ITEM_KEY);
|
||||
itemoff = __BTRFS_LEAF_DATA_SIZE(blocksize) -
|
||||
itemoff = __BTRFS_LEAF_DATA_SIZE(leafsize) -
|
||||
sizeof(struct btrfs_extent_item);
|
||||
btrfs_set_item_offset(&item, itemoff);
|
||||
btrfs_set_item_size(&item, sizeof(struct btrfs_extent_item));
|
||||
@ -272,8 +280,8 @@ printf("blocksize is %d\n", blocksize);
|
||||
&extent_item, btrfs_item_size(&item));
|
||||
|
||||
/* item2, give block 17 to the root */
|
||||
btrfs_set_disk_key_objectid(&item.key, start_block + 1);
|
||||
btrfs_set_disk_key_offset(&item.key, 1);
|
||||
btrfs_set_disk_key_objectid(&item.key, first_free);
|
||||
btrfs_set_disk_key_offset(&item.key, leafsize);
|
||||
itemoff = itemoff - sizeof(struct btrfs_extent_item);
|
||||
btrfs_set_item_offset(&item, itemoff);
|
||||
memcpy(empty_leaf->items + 1, &item, sizeof(item));
|
||||
@ -281,8 +289,8 @@ printf("blocksize is %d\n", blocksize);
|
||||
&extent_item, btrfs_item_size(&item));
|
||||
|
||||
/* item3, give block 18 to the extent root */
|
||||
btrfs_set_disk_key_objectid(&item.key, start_block + 2);
|
||||
btrfs_set_disk_key_offset(&item.key, 1);
|
||||
btrfs_set_disk_key_objectid(&item.key, first_free + leafsize);
|
||||
btrfs_set_disk_key_offset(&item.key, leafsize);
|
||||
itemoff = itemoff - sizeof(struct btrfs_extent_item);
|
||||
btrfs_set_item_offset(&item, itemoff);
|
||||
memcpy(empty_leaf->items + 2, &item, sizeof(item));
|
||||
@ -290,22 +298,22 @@ printf("blocksize is %d\n", blocksize);
|
||||
&extent_item, btrfs_item_size(&item));
|
||||
|
||||
/* item4, give block 19 to the FS root */
|
||||
btrfs_set_disk_key_objectid(&item.key, start_block + 3);
|
||||
btrfs_set_disk_key_offset(&item.key, 1);
|
||||
btrfs_set_disk_key_objectid(&item.key, first_free + leafsize * 2);
|
||||
btrfs_set_disk_key_offset(&item.key, leafsize);
|
||||
itemoff = itemoff - sizeof(struct btrfs_extent_item);
|
||||
btrfs_set_item_offset(&item, itemoff);
|
||||
memcpy(empty_leaf->items + 3, &item, sizeof(item));
|
||||
memcpy(btrfs_leaf_data(empty_leaf) + btrfs_item_offset(&item),
|
||||
&extent_item, btrfs_item_size(&item));
|
||||
ret = pwrite(fd, empty_leaf, blocksize, (start_block + 2) * blocksize);
|
||||
if (ret != blocksize)
|
||||
ret = pwrite(fd, empty_leaf, leafsize, first_free + leafsize);
|
||||
if (ret != leafsize)
|
||||
return -1;
|
||||
|
||||
/* finally create the FS root */
|
||||
btrfs_set_header_blocknr(&empty_leaf->header, start_block + 3);
|
||||
btrfs_set_header_bytenr(&empty_leaf->header, first_free + leafsize * 2);
|
||||
btrfs_set_header_nritems(&empty_leaf->header, 0);
|
||||
ret = pwrite(fd, empty_leaf, blocksize, (start_block + 3) * blocksize);
|
||||
if (ret != blocksize)
|
||||
ret = pwrite(fd, empty_leaf, leafsize, first_free + leafsize * 2);
|
||||
if (ret != leafsize)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
@ -322,7 +330,14 @@ u64 device_size(int fd, struct stat *st)
|
||||
if (ioctl(fd, BLKGETSIZE64, &size) >= 0) {
|
||||
return size;
|
||||
}
|
||||
return 0; }
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void print_usage(void)
|
||||
{
|
||||
fprintf(stderr, "usage: mkfs.btrfs [ -l leafsize ] [ -n nodesize] dev [ blocks ]\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int main(int ac, char **av)
|
||||
{
|
||||
@ -332,23 +347,50 @@ int main(int ac, char **av)
|
||||
struct stat st;
|
||||
int ret;
|
||||
int i;
|
||||
char *buf = malloc(8192);
|
||||
u32 leafsize = 8 * 1024;
|
||||
u32 sectorsize = 4096;
|
||||
u32 nodesize = 8 * 1024;
|
||||
char *buf = malloc(sectorsize);
|
||||
char *realpath_name;
|
||||
|
||||
radix_tree_init();
|
||||
|
||||
if (ac >= 2) {
|
||||
file = av[1];
|
||||
if (ac == 3) {
|
||||
block_count = atoi(av[2]);
|
||||
while(1) {
|
||||
int c;
|
||||
c = getopt(ac, av, "l:n:");
|
||||
if (c < 0)
|
||||
break;
|
||||
switch(c) {
|
||||
case 'l':
|
||||
leafsize = atol(optarg);
|
||||
break;
|
||||
case 'n':
|
||||
nodesize = atol(optarg);
|
||||
break;
|
||||
default:
|
||||
print_usage();
|
||||
}
|
||||
}
|
||||
if (leafsize < sectorsize || (leafsize & (sectorsize - 1))) {
|
||||
fprintf(stderr, "Illegal leafsize %u\n", leafsize);
|
||||
exit(1);
|
||||
}
|
||||
if (nodesize < sectorsize || (nodesize & (sectorsize - 1))) {
|
||||
fprintf(stderr, "Illegal nodesize %u\n", nodesize);
|
||||
exit(1);
|
||||
}
|
||||
ac = ac - optind;
|
||||
if (ac >= 1) {
|
||||
file = av[optind];
|
||||
if (ac == 2) {
|
||||
block_count = atol(av[optind + 1]);
|
||||
if (!block_count) {
|
||||
fprintf(stderr, "error finding block count\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "usage: mkfs.btrfs file [block count]\n");
|
||||
exit(1);
|
||||
print_usage();
|
||||
}
|
||||
fd = open(file, O_RDWR);
|
||||
if (fd < 0) {
|
||||
@ -366,22 +408,24 @@ int main(int ac, char **av)
|
||||
fprintf(stderr, "unable to find %s size\n", file);
|
||||
exit(1);
|
||||
}
|
||||
block_count /= 8192;
|
||||
block_count /= sectorsize;
|
||||
}
|
||||
if (block_count < 256) {
|
||||
fprintf(stderr, "device %s is too small\n", file);
|
||||
exit(1);
|
||||
}
|
||||
memset(buf, 0, 8192);
|
||||
block_count = block_count * sectorsize;
|
||||
memset(buf, 0, sectorsize);
|
||||
for(i = 0; i < 64; i++) {
|
||||
ret = write(fd, buf, 8192);
|
||||
if (ret != 8192) {
|
||||
ret = write(fd, buf, sectorsize);
|
||||
if (ret != sectorsize) {
|
||||
fprintf(stderr, "unable to zero fill device\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
realpath_name = realpath(file, NULL);
|
||||
ret = mkfs(fd, realpath_name, block_count, 8192);
|
||||
ret = mkfs(fd, realpath_name, block_count, nodesize, leafsize,
|
||||
sectorsize);
|
||||
if (ret) {
|
||||
fprintf(stderr, "error during mkfs %d\n", ret);
|
||||
exit(1);
|
||||
@ -391,8 +435,9 @@ int main(int ac, char **av)
|
||||
fprintf(stderr, "failed to setup the root directory\n");
|
||||
exit(1);
|
||||
}
|
||||
printf("fs created on %s blocksize %d blocks %llu\n",
|
||||
file, 8192, (unsigned long long)block_count);
|
||||
printf("fs created on %s nodesize %u leafsize %u sectorsize %u bytes %llu\n",
|
||||
file, nodesize, leafsize, sectorsize,
|
||||
(unsigned long long)block_count);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
28
print-tree.c
28
print-tree.c
@ -58,7 +58,7 @@ void btrfs_print_leaf(struct btrfs_root *root, struct btrfs_leaf *l)
|
||||
u32 type;
|
||||
|
||||
printf("leaf %llu ptrs %d free space %d generation %llu owner %llu\n",
|
||||
(unsigned long long)btrfs_header_blocknr(&l->header), nr,
|
||||
(unsigned long long)btrfs_header_bytenr(&l->header), nr,
|
||||
btrfs_leaf_free_space(root, l),
|
||||
(unsigned long long)btrfs_header_generation(&l->header),
|
||||
(unsigned long long)btrfs_header_owner(&l->header));
|
||||
@ -93,8 +93,9 @@ void btrfs_print_leaf(struct btrfs_root *root, struct btrfs_leaf *l)
|
||||
break;
|
||||
case BTRFS_ROOT_ITEM_KEY:
|
||||
ri = btrfs_item_ptr(l, i, struct btrfs_root_item);
|
||||
printf("\t\troot data blocknr %llu dirid %llu refs %u\n",
|
||||
(unsigned long long)btrfs_root_blocknr(ri),
|
||||
printf("\t\troot data bytenr %llu level %d dirid %llu refs %u\n",
|
||||
(unsigned long long)btrfs_root_bytenr(ri),
|
||||
ri->level,
|
||||
(unsigned long long)btrfs_root_dirid(ri),
|
||||
btrfs_root_refs(ri));
|
||||
if (1 || btrfs_root_refs(ri) == 0) {
|
||||
@ -128,12 +129,12 @@ void btrfs_print_leaf(struct btrfs_root *root, struct btrfs_leaf *l)
|
||||
btrfs_file_extent_inline_len(l->items + i));
|
||||
break;
|
||||
}
|
||||
printf("\t\textent data disk block %llu nr %llu\n",
|
||||
(unsigned long long)btrfs_file_extent_disk_blocknr(fi),
|
||||
(unsigned long long)btrfs_file_extent_disk_num_blocks(fi));
|
||||
printf("\t\textent data disk byte %llu nr %llu\n",
|
||||
(unsigned long long)btrfs_file_extent_disk_bytenr(fi),
|
||||
(unsigned long long)btrfs_file_extent_disk_num_bytes(fi));
|
||||
printf("\t\textent data offset %llu nr %llu\n",
|
||||
(unsigned long long)btrfs_file_extent_offset(fi),
|
||||
(unsigned long long)btrfs_file_extent_num_blocks(fi));
|
||||
(unsigned long long)btrfs_file_extent_num_bytes(fi));
|
||||
break;
|
||||
case BTRFS_BLOCK_GROUP_ITEM_KEY:
|
||||
bi = btrfs_item_ptr(l, i,
|
||||
@ -155,6 +156,7 @@ void btrfs_print_tree(struct btrfs_root *root, struct btrfs_buffer *t)
|
||||
int i;
|
||||
u32 nr;
|
||||
struct btrfs_node *c;
|
||||
u32 size;
|
||||
|
||||
if (!t)
|
||||
return;
|
||||
@ -165,24 +167,28 @@ void btrfs_print_tree(struct btrfs_root *root, struct btrfs_buffer *t)
|
||||
return;
|
||||
}
|
||||
printf("node %llu level %d ptrs %d free %u generation %llu owner %llu\n",
|
||||
(unsigned long long)t->blocknr,
|
||||
(unsigned long long)t->bytenr,
|
||||
btrfs_header_level(&c->header), nr,
|
||||
(u32)BTRFS_NODEPTRS_PER_BLOCK(root) - nr,
|
||||
(unsigned long long)btrfs_header_generation(&c->header),
|
||||
(unsigned long long)btrfs_header_owner(&c->header));
|
||||
fflush(stdout);
|
||||
size = btrfs_level_size(root, btrfs_header_level(&c->header) - 1);
|
||||
for (i = 0; i < nr; i++) {
|
||||
printf("\tkey %d (%llu %x %llu) block %llu\n",
|
||||
u64 blocknr = btrfs_node_blockptr(c, i);
|
||||
printf("\tkey %d (%llu %x %llu) block %llu (%llu)\n",
|
||||
i,
|
||||
(unsigned long long)c->ptrs[i].key.objectid,
|
||||
c->ptrs[i].key.type,
|
||||
(unsigned long long)c->ptrs[i].key.offset,
|
||||
(unsigned long long)btrfs_node_blockptr(c, i));
|
||||
(unsigned long long)blocknr,
|
||||
(unsigned long long)blocknr / size);
|
||||
fflush(stdout);
|
||||
}
|
||||
for (i = 0; i < nr; i++) {
|
||||
struct btrfs_buffer *next_buf = read_tree_block(root,
|
||||
btrfs_node_blockptr(c, i));
|
||||
btrfs_node_blockptr(c, i),
|
||||
size);
|
||||
struct btrfs_node *next = &next_buf->node;
|
||||
if (btrfs_is_leaf(next) &&
|
||||
btrfs_header_level(&c->header) != 1)
|
||||
|
Loading…
Reference in New Issue
Block a user