Update btrfs-progs to better match the kernel

master
Yan 2007-12-05 10:41:38 -05:00 committed by David Woodhouse
parent 1c2b38fe25
commit 07a4f1b81d
8 changed files with 836 additions and 134 deletions

478
ctree.c
View File

@ -19,15 +19,15 @@
#include <stdio.h>
#include <stdlib.h>
#include "kerncompat.h"
#include "radix-tree.h"
#include "ctree.h"
#include "disk-io.h"
#include "transaction.h"
#include "print-tree.h"
static int split_node(struct btrfs_trans_handle *trans, struct btrfs_root
*root, struct btrfs_path *path, int level);
static int split_leaf(struct btrfs_trans_handle *trans, struct btrfs_root
*root, struct btrfs_path *path, int data_size);
*root, struct btrfs_key *ins_key,
struct btrfs_path *path, int data_size, int extend);
static int push_node_left(struct btrfs_trans_handle *trans, struct btrfs_root
*root, struct btrfs_buffer *dst, struct btrfs_buffer
*src);
@ -52,8 +52,7 @@ void btrfs_release_path(struct btrfs_root *root, struct btrfs_path *p)
}
memset(p, 0, sizeof(*p));
}
static int btrfs_cow_block(struct btrfs_trans_handle *trans, struct btrfs_root
int btrfs_cow_block(struct btrfs_trans_handle *trans, struct btrfs_root
*root, struct btrfs_buffer *buf, struct btrfs_buffer
*parent, int parent_slot, struct btrfs_buffer
**cow_ret)
@ -67,6 +66,7 @@ static int btrfs_cow_block(struct btrfs_trans_handle *trans, struct btrfs_root
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_generation(&cow->node.header, trans->transid);
btrfs_set_header_owner(&cow->node.header, root->root_key.objectid);
*cow_ret = cow;
btrfs_inc_ref(trans, root, buf);
@ -476,6 +476,128 @@ static int balance_level(struct btrfs_trans_handle *trans, struct btrfs_root
btrfs_block_release(root, left_buf);
return ret;
}
static int push_nodes_for_insert(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct btrfs_path *path, int level)
{
struct btrfs_node *right;
struct btrfs_node *mid;
struct btrfs_node *left;
struct btrfs_node *parent;
struct btrfs_buffer *right_buf;
struct btrfs_buffer *mid_buf;
struct btrfs_buffer *left_buf;
struct btrfs_buffer *parent_buf = NULL;
int ret = 0;
int wret;
int pslot;
int orig_slot = path->slots[level];
u64 orig_ptr;
if (level == 0)
return 1;
mid_buf = path->nodes[level];
mid = &mid_buf->node;
orig_ptr = btrfs_node_blockptr(mid, orig_slot);
if (level < BTRFS_MAX_LEVEL - 1)
parent_buf = path->nodes[level + 1];
pslot = path->slots[level + 1];
if (!parent_buf)
return 1;
parent = &parent_buf->node;
left_buf = read_node_slot(root, parent_buf, pslot - 1);
left = &left_buf->node;
/* first, try to make some room in the middle buffer */
if (left_buf) {
u32 left_nr;
left_nr = btrfs_header_nritems(&left->header);
if (left_nr >= BTRFS_NODEPTRS_PER_BLOCK(root) - 1) {
wret = 1;
} else {
ret = btrfs_cow_block(trans, root, left_buf,
parent_buf, pslot - 1,
&left_buf);
left = &left_buf->node;
if (ret)
wret = 1;
else {
wret = push_node_left(trans, root,
left_buf, mid_buf);
}
}
if (wret < 0)
ret = wret;
if (wret == 0) {
orig_slot += left_nr;
memcpy(&parent->ptrs[pslot].key, &mid->ptrs[0].key,
sizeof(struct btrfs_disk_key));
BUG_ON(list_empty(&parent_buf->dirty));
if (btrfs_header_nritems(&left->header) > orig_slot) {
path->nodes[level] = left_buf;
path->slots[level + 1] -= 1;
path->slots[level] = orig_slot;
btrfs_block_release(root, mid_buf);
} else {
orig_slot -=
btrfs_header_nritems(&left->header);
path->slots[level] = orig_slot;
btrfs_block_release(root, left_buf);
}
return 0;
}
btrfs_block_release(root, left_buf);
}
right_buf = read_node_slot(root, parent_buf, pslot + 1);
right = &right_buf->node;
/*
* then try to empty the right most buffer into the middle
*/
if (right_buf) {
u32 right_nr;
right_nr = btrfs_header_nritems(&right->header);
if (right_nr >= BTRFS_NODEPTRS_PER_BLOCK(root) - 1) {
wret = 1;
} else {
ret = btrfs_cow_block(trans, root, right_buf,
parent_buf, pslot + 1,
&right_buf);
right = &right_buf->node;
if (ret)
wret = 1;
else {
wret = balance_node_right(trans, root,
right_buf, mid_buf);
}
}
if (wret < 0)
ret = wret;
if (wret == 0) {
memcpy(&parent->ptrs[pslot + 1].key,
&right->ptrs[0].key,
sizeof(struct btrfs_disk_key));
BUG_ON(list_empty(&parent_buf->dirty));
if (btrfs_header_nritems(&mid->header) <= orig_slot) {
path->nodes[level] = right_buf;
path->slots[level + 1] += 1;
path->slots[level] = orig_slot -
btrfs_header_nritems(&mid->header);
btrfs_block_release(root, mid_buf);
} else {
btrfs_block_release(root, right_buf);
}
return 0;
}
btrfs_block_release(root, right_buf);
}
return 1;
}
/*
* look for key in the tree. path is filled in with nodes along the way
@ -495,7 +617,6 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root
ins_len, int cow)
{
struct btrfs_buffer *b;
struct btrfs_buffer *cow_buf;
struct btrfs_node *c;
int slot;
int ret;
@ -508,10 +629,14 @@ again:
level = btrfs_header_level(&b->node.header);
if (cow) {
int wret;
wret = btrfs_cow_block(trans, root, b, p->nodes[level +
1], p->slots[level + 1],
&cow_buf);
b = cow_buf;
wret = btrfs_cow_block(trans, root, b,
p->nodes[level + 1],
p->slots[level + 1],
&b);
if (wret) {
btrfs_block_release(root, b);
return wret;
}
}
BUG_ON(!cow && ins_len);
c = &b->node;
@ -524,8 +649,8 @@ again:
if (ret && slot > 0)
slot -= 1;
p->slots[level] = slot;
if (ins_len > 0 && btrfs_header_nritems(&c->header) ==
BTRFS_NODEPTRS_PER_BLOCK(root)) {
if (ins_len > 0 && btrfs_header_nritems(&c->header) >=
BTRFS_NODEPTRS_PER_BLOCK(root) - 1) {
int sret = split_node(trans, root, p, level);
BUG_ON(sret > 0);
if (sret)
@ -539,8 +664,10 @@ again:
if (sret)
return sret;
b = p->nodes[level];
if (!b)
if (!b) {
btrfs_release_path(NULL, p);
goto again;
}
c = &b->node;
slot = p->slots[level];
BUG_ON(btrfs_header_nritems(&c->header) == 1);
@ -553,7 +680,8 @@ again:
p->slots[level] = slot;
if (ins_len > 0 && btrfs_leaf_free_space(root, l) <
sizeof(struct btrfs_item) + ins_len) {
int sret = split_leaf(trans, root, p, ins_len);
int sret = split_leaf(trans, root, key,
p, ins_len, ret == 0);
BUG_ON(sret > 0);
if (sret)
return sret;
@ -665,10 +793,9 @@ static int balance_node_right(struct btrfs_trans_handle *trans, struct
if (push_items <= 0) {
return 1;
}
max_push = src_nritems / 2 + 1;
/* don't try to empty the node */
if (max_push > src_nritems)
if (max_push >= src_nritems)
return 1;
if (max_push < push_items)
push_items = max_push;
@ -703,13 +830,13 @@ 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, root->nodesize);
c = &t->node;
memset(c, 0, root->nodesize);
memset(&c->header, 0, sizeof(c->header));
btrfs_set_header_nritems(&c->header, 1);
btrfs_set_header_level(&c->header, level);
btrfs_set_header_bytenr(&c->header, t->bytenr);
btrfs_set_header_generation(&c->header, trans->transid);
btrfs_set_header_owner(&c->header, root->root_key.objectid);
memcpy(c->header.fsid, root->fs_info->disk_super->fsid,
sizeof(c->header.fsid));
@ -719,9 +846,9 @@ static int insert_new_root(struct btrfs_trans_handle *trans, struct btrfs_root
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]->bytenr);
BUG_ON(list_empty(&t->dirty));
/* the super has an extra ref to root->node */
btrfs_block_release(root, root->node);
root->node = t;
@ -793,6 +920,15 @@ static int split_node(struct btrfs_trans_handle *trans, struct btrfs_root
ret = insert_new_root(trans, root, path, level + 1);
if (ret)
return ret;
} else {
ret = push_nodes_for_insert(trans, root, path, level);
t = path->nodes[level];
c = &t->node;
if (!ret && btrfs_header_nritems(&c->header) <
BTRFS_NODEPTRS_PER_BLOCK(root) - 1)
return 0;
if (ret < 0)
return ret;
}
c_nritems = btrfs_header_nritems(&c->header);
split_buffer = btrfs_alloc_free_block(trans, root, root->nodesize);
@ -800,6 +936,7 @@ static int split_node(struct btrfs_trans_handle *trans, struct btrfs_root
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_bytenr(&split->header, split_buffer->bytenr);
btrfs_set_header_generation(&split->header, trans->transid);
btrfs_set_header_owner(&split->header, root->root_key.objectid);
memcpy(split->header.fsid, root->fs_info->disk_super->fsid,
sizeof(split->header.fsid));
@ -836,7 +973,8 @@ static int split_node(struct btrfs_trans_handle *trans, struct btrfs_root
* room, 0 if everything worked out and < 0 if there were major errors.
*/
static int push_leaf_right(struct btrfs_trans_handle *trans, struct btrfs_root
*root, struct btrfs_path *path, int data_size)
*root, struct btrfs_path *path, int data_size,
int empty)
{
struct btrfs_buffer *left_buf = path->nodes[0];
struct btrfs_leaf *left = &left_buf->leaf;
@ -844,14 +982,14 @@ static int push_leaf_right(struct btrfs_trans_handle *trans, struct btrfs_root
struct btrfs_buffer *right_buf;
struct btrfs_buffer *upper;
int slot;
int i;
u32 i;
int free_space;
int push_space = 0;
int push_items = 0;
struct btrfs_item *item;
u32 left_nritems;
u32 nr;
u32 right_nritems;
slot = path->slots[1];
if (!path->nodes[1]) {
return 1;
@ -877,9 +1015,19 @@ static int push_leaf_right(struct btrfs_trans_handle *trans, struct btrfs_root
btrfs_block_release(root, right_buf);
return 1;
}
left_nritems = btrfs_header_nritems(&left->header);
for (i = left_nritems - 1; i >= 0; i--) {
if (left_nritems == 0) {
btrfs_block_release(root, right_buf);
return 1;
}
if (empty)
nr = 0;
else
nr = 1;
i = left_nritems - 1;
while (i >= nr) {
item = left->items + i;
if (path->slots[0] == i)
push_space += data_size + sizeof(*item);
@ -888,6 +1036,9 @@ static int push_leaf_right(struct btrfs_trans_handle *trans, struct btrfs_root
break;
push_items++;
push_space += btrfs_item_size(item) + sizeof(*item);
if (i == 0)
break;
i--;
}
if (push_items == 0) {
btrfs_block_release(root, right_buf);
@ -944,7 +1095,8 @@ static int push_leaf_right(struct btrfs_trans_handle *trans, struct btrfs_root
* least data_size bytes. returns zero if the push worked, nonzero otherwise
*/
static int push_leaf_left(struct btrfs_trans_handle *trans, struct btrfs_root
*root, struct btrfs_path *path, int data_size)
*root, struct btrfs_path *path, int data_size,
int empty)
{
struct btrfs_buffer *right_buf = path->nodes[0];
struct btrfs_leaf *right = &right_buf->leaf;
@ -957,9 +1109,10 @@ static int push_leaf_left(struct btrfs_trans_handle *trans, struct btrfs_root
int push_items = 0;
struct btrfs_item *item;
u32 old_left_nritems;
u32 right_nritems;
u32 nr;
int ret = 0;
int wret;
slot = path->slots[1];
if (slot == 0) {
return 1;
@ -967,6 +1120,11 @@ static int push_leaf_left(struct btrfs_trans_handle *trans, struct btrfs_root
if (!path->nodes[1]) {
return 1;
}
right_nritems = btrfs_header_nritems(&right->header);
if (right_nritems == 0) {
return 1;
}
t = read_tree_block(root,
btrfs_node_blockptr(&path->nodes[1]->node, slot - 1),
root->leafsize);
@ -985,8 +1143,12 @@ static int push_leaf_left(struct btrfs_trans_handle *trans, struct btrfs_root
btrfs_block_release(root, t);
return 1;
}
if (empty)
nr = right_nritems;
else
nr = right_nritems - 1;
for (i = 0; i < btrfs_header_nritems(&right->header); i++) {
for (i = 0; i < nr; i++) {
item = right->items + i;
if (path->slots[0] == i)
push_space += data_size + sizeof(*item);
@ -1020,22 +1182,21 @@ static int push_leaf_left(struct btrfs_trans_handle *trans, struct btrfs_root
old_left_nritems - 1)));
}
btrfs_set_header_nritems(&left->header, old_left_nritems + push_items);
/* fixup right node */
push_space = btrfs_item_offset(right->items + push_items - 1) -
leaf_data_end(root, right);
memmove(btrfs_leaf_data(right) + BTRFS_LEAF_DATA_SIZE(root) -
push_space, btrfs_leaf_data(right) +
leaf_data_end(root, right), push_space);
memmove(right->items, right->items + push_items,
(btrfs_header_nritems(&right->header) - push_items) *
sizeof(struct btrfs_item));
btrfs_set_header_nritems(&right->header,
btrfs_header_nritems(&right->header) -
push_items);
if (push_items < right_nritems) {
push_space = btrfs_item_offset(right->items + push_items - 1) -
leaf_data_end(root, right);
memmove(btrfs_leaf_data(right) + BTRFS_LEAF_DATA_SIZE(root) -
push_space, btrfs_leaf_data(right) +
leaf_data_end(root, right), push_space);
memmove(right->items, right->items + push_items,
(right_nritems - push_items) *
sizeof(struct btrfs_item));
}
right_nritems -= push_items;
btrfs_set_header_nritems(&right->header, right_nritems);
push_space = BTRFS_LEAF_DATA_SIZE(root);
for (i = 0; i < btrfs_header_nritems(&right->header); i++) {
for (i = 0; i < right_nritems; i++) {
btrfs_set_item_offset(right->items + i, push_space -
btrfs_item_size(right->items + i));
push_space = btrfs_item_offset(right->items + i);
@ -1069,7 +1230,8 @@ 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_path *path, int data_size)
*root, struct btrfs_key *ins_key,
struct btrfs_path *path, int data_size, int extend)
{
struct btrfs_buffer *l_buf;
struct btrfs_leaf *l;
@ -1082,67 +1244,125 @@ static int split_leaf(struct btrfs_trans_handle *trans, struct btrfs_root
int data_copy_size;
int rt_data_off;
int i;
int ret;
int ret = 0;
int wret;
int double_split;
int num_doubles = 0;
struct btrfs_disk_key disk_key;
if (extend)
space_needed = data_size;
/* first try to make some room by pushing left and right */
wret = push_leaf_left(trans, root, path, data_size);
if (wret < 0)
return wret;
if (wret) {
wret = push_leaf_right(trans, root, path, data_size);
if (wret < 0)
if (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_buf = path->nodes[0];
l = &l_buf->leaf;
/* did the pushes work? */
if (btrfs_leaf_free_space(root, l) >= space_needed)
return 0;
}
l_buf = path->nodes[0];
l = &l_buf->leaf;
/* did the pushes work? */
if (btrfs_leaf_free_space(root, l) >=
sizeof(struct btrfs_item) + data_size)
return 0;
if (!path->nodes[1]) {
ret = insert_new_root(trans, root, path, 1);
if (ret)
return ret;
}
again:
double_split = 0;
l_buf = path->nodes[0];
l = &l_buf->leaf;
slot = path->slots[0];
nritems = btrfs_header_nritems(&l->header);
mid = (nritems + 1)/ 2;
right_buffer = btrfs_alloc_free_block(trans, root, root->leafsize);
BUG_ON(!right_buffer);
BUG_ON(mid == nritems);
right = &right_buffer->leaf;
memset(&right->header, 0, sizeof(right->header));
if (mid <= slot) {
/* FIXME, just alloc a new leaf here */
if (leaf_space_used(l, mid, nritems - mid) + space_needed >
BTRFS_LEAF_DATA_SIZE(root))
BUG();
} else {
/* FIXME, just alloc a new leaf here */
if (leaf_space_used(l, 0, mid + 1) + space_needed >
BTRFS_LEAF_DATA_SIZE(root))
BUG();
}
btrfs_set_header_nritems(&right->header, nritems - mid);
btrfs_set_header_bytenr(&right->header, right_buffer->bytenr);
btrfs_set_header_generation(&right->header, trans->transid);
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,
sizeof(right->header.fsid));
data_copy_size = btrfs_item_end(l->items + mid) -
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->header, 0);
wret = insert_ptr(trans, root, path,
&disk_key, right_buffer->bytenr,
path->slots[1] + 1, 1);
if (wret)
ret = wret;
btrfs_block_release(root, path->nodes[0]);
path->nodes[0] = right_buffer;
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) + space_needed >
BTRFS_LEAF_DATA_SIZE(root)) {
if (!extend && slot == 0) {
btrfs_cpu_key_to_disk(&disk_key, ins_key);
btrfs_set_header_nritems(&right->header, 0);
wret = insert_ptr(trans, root, path,
&disk_key,
right_buffer->bytenr,
path->slots[1], 1);
if (wret)
ret = wret;
btrfs_block_release(root, path->nodes[0]);
path->nodes[0] = right_buffer;
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 && 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->header, nritems);
data_copy_size = btrfs_item_end(l->items + mid) -
leaf_data_end(root, l);
memcpy(right->items, l->items + mid,
(nritems - mid) * sizeof(struct btrfs_item));
nritems * sizeof(struct btrfs_item));
memcpy(btrfs_leaf_data(right) + BTRFS_LEAF_DATA_SIZE(root) -
data_copy_size, btrfs_leaf_data(l) +
leaf_data_end(root, l), data_copy_size);
rt_data_off = BTRFS_LEAF_DATA_SIZE(root) -
btrfs_item_end(l->items + mid);
for (i = 0; i < btrfs_header_nritems(&right->header); i++) {
for (i = 0; i < nritems; i++) {
u32 ioff = btrfs_item_offset(right->items + i);
btrfs_set_item_offset(right->items + i, ioff + rt_data_off);
}
@ -1153,6 +1373,7 @@ static int split_leaf(struct btrfs_trans_handle *trans, struct btrfs_root
right_buffer->bytenr, path->slots[1] + 1, 1);
if (wret)
ret = wret;
BUG_ON(list_empty(&right_buffer->dirty));
BUG_ON(list_empty(&l_buf->dirty));
BUG_ON(path->slots[0] != slot);
@ -1163,10 +1384,15 @@ static int split_leaf(struct btrfs_trans_handle *trans, struct btrfs_root
path->slots[1] += 1;
} else
btrfs_block_release(root, right_buffer);
BUG_ON(path->slots[0] < 0);
if (double_split) {
BUG_ON(num_doubles != 0);
num_doubles++;
goto again;
}
return ret;
}
/*
* Given a key and some data, insert an item into the tree.
* This does all the path init required, making room in the tree if needed.
@ -1385,12 +1611,12 @@ int btrfs_del_item(struct btrfs_trans_handle *trans, struct btrfs_root *root,
*/
slot = path->slots[1];
leaf_buf->count++;
wret = push_leaf_left(trans, root, path, 1);
wret = push_leaf_right(trans, root, path, 1, 1);
if (wret < 0)
ret = wret;
if (path->nodes[0] == leaf_buf &&
btrfs_header_nritems(&leaf->header)) {
wret = push_leaf_right(trans, root, path, 1);
wret = push_leaf_left(trans, root, path, 1, 1);
if (wret < 0)
ret = wret;
}
@ -1412,6 +1638,101 @@ int btrfs_del_item(struct btrfs_trans_handle *trans, struct btrfs_root *root,
}
return ret;
}
int btrfs_truncate_item(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct btrfs_path *path,
u32 new_size, int from_end)
{
int ret = 0;
int slot;
int slot_orig;
struct btrfs_leaf *leaf;
struct btrfs_item *item;
u32 nritems;
unsigned int data_end;
unsigned int old_data_start;
unsigned int old_size;
unsigned int size_diff;
int i;
slot_orig = path->slots[0];
leaf = &path->nodes[0]->leaf;
slot = path->slots[0];
old_size = btrfs_item_size(leaf->items + slot);
if (old_size == new_size)
return 0;
nritems = btrfs_header_nritems(&leaf->header);
data_end = leaf_data_end(root, leaf);
old_data_start = btrfs_item_offset(leaf->items + slot);
size_diff = old_size - new_size;
BUG_ON(slot < 0);
BUG_ON(slot >= nritems);
/*
* item0..itemN ... dataN.offset..dataN.size .. data0.size
*/
/* first correct the data pointers */
for (i = slot; i < nritems; i++) {
u32 ioff;
item = leaf->items + i;
ioff = btrfs_item_offset(item);
btrfs_set_item_offset(item, ioff + size_diff);
}
/* shift the data */
if (from_end) {
memmove(btrfs_leaf_data(leaf) + data_end + size_diff,
btrfs_leaf_data(leaf) + data_end,
old_data_start + new_size - data_end);
} else {
struct btrfs_disk_key *disk_key;
u64 offset;
disk_key = &leaf->items[slot].key;
if (btrfs_disk_key_type(disk_key) == BTRFS_EXTENT_DATA_KEY) {
char *ptr;
struct btrfs_file_extent_item *fi;
fi = btrfs_item_ptr(leaf, slot,
struct btrfs_file_extent_item);
fi = (struct btrfs_file_extent_item *)(
(unsigned long)fi - size_diff);
if (btrfs_file_extent_type(fi) ==
BTRFS_FILE_EXTENT_INLINE) {
ptr = btrfs_item_ptr(leaf, slot, char);
memmove(ptr, (char *)fi,
offsetof(struct btrfs_file_extent_item,
disk_bytenr));
}
}
memmove(btrfs_leaf_data(leaf) + data_end + size_diff,
btrfs_leaf_data(leaf) + data_end,
old_data_start - data_end);
offset = btrfs_disk_key_offset(disk_key);
btrfs_set_disk_key_offset(disk_key, offset + size_diff);
if (slot == 0)
fixup_low_keys(trans, root, path, disk_key, 1);
}
item = leaf->items + slot;
btrfs_set_item_size(item, new_size);
BUG_ON(list_empty(&path->nodes[0]->dirty));
ret = 0;
if (btrfs_leaf_free_space(root, leaf) < 0) {
btrfs_print_leaf(root, leaf);
BUG();
}
return ret;
}
int btrfs_extend_item(struct btrfs_trans_handle *trans, struct btrfs_root
*root, struct btrfs_path *path, u32 data_size)
@ -1507,5 +1828,6 @@ int btrfs_next_leaf(struct btrfs_root *root, struct btrfs_path *path)
btrfs_node_blockptr(&next->node, 0),
btrfs_level_size(root, level - 1));
}
check_leaf(root, path, 0);
return 0;
}

64
ctree.h
View File

@ -23,9 +23,8 @@
#include "kerncompat.h"
#include "radix-tree.h"
#include "extent-cache.h"
struct btrfs_root;
struct btrfs_trans_handle;
#define BTRFS_MAGIC "_B2RfS_M"
#define BTRFS_ROOT_TREE_OBJECTID 1ULL
@ -102,7 +101,9 @@ struct btrfs_header {
(sizeof(struct btrfs_disk_key) + sizeof(u64)))
#define __BTRFS_LEAF_DATA_SIZE(bs) ((bs) - sizeof(struct btrfs_header))
#define BTRFS_LEAF_DATA_SIZE(r) (__BTRFS_LEAF_DATA_SIZE(r->leafsize))
#define BTRFS_MAX_INLINE_DATA_SIZE(r) (BTRFS_LEAF_DATA_SIZE(r) - \
sizeof(struct btrfs_item) - \
sizeof(struct btrfs_file_extent_item))
struct btrfs_buffer;
/*
* the super block basically lists the main trees of the FS
@ -759,6 +760,17 @@ static inline void btrfs_set_root_bytenr(struct btrfs_root_item *item, u64 val)
item->bytenr = cpu_to_le64(val);
}
static inline u64 btrfs_root_byte_limit(struct btrfs_root_item *item)
{
return le64_to_cpu(item->byte_limit);
}
static inline void btrfs_set_root_byte_limit(struct btrfs_root_item *item,
u64 val)
{
item->byte_limit = cpu_to_le64(val);
}
static inline u8 btrfs_root_level(struct btrfs_root_item *item)
{
return item->level;
@ -1028,6 +1040,9 @@ static inline void btrfs_set_file_extent_num_bytes(struct
#define btrfs_item_ptr(leaf, slot, type) \
((type *)(btrfs_leaf_data(leaf) + \
btrfs_item_offset((leaf)->items + (slot))))
#define btrfs_item_ptr_offset(leaf, slot) \
((unsigned long)(btrfs_leaf_data(leaf) + \
btrfs_item_offset_nr(leaf, slot)))
static inline u32 btrfs_level_size(struct btrfs_root *root, int level)
{
@ -1036,15 +1051,25 @@ static inline u32 btrfs_level_size(struct btrfs_root *root, int level)
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,
u32 blocksize);
int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
struct btrfs_buffer *buf);
int btrfs_inc_root_ref(struct btrfs_trans_handle *trans,
struct btrfs_root *root);
int btrfs_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root
*root, u64 bytenr, u64 num_bytes, int pin);
int btrfs_cow_block(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct btrfs_buffer *buf,
struct btrfs_buffer *parent, int parent_slot,
struct btrfs_buffer **cow_ret);
int btrfs_extend_item(struct btrfs_trans_handle *trans, struct btrfs_root
*root, struct btrfs_path *path, u32 data_size);
int btrfs_truncate_item(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct btrfs_path *path,
u32 new_size, int from_end);
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);
@ -1076,11 +1101,16 @@ int btrfs_find_last_root(struct btrfs_root *root, u64 objectid, struct
int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root
*root, char *name, int name_len, u64 dir,
struct btrfs_key *location, u8 type);
int btrfs_lookup_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root
*root, struct btrfs_path *path, u64 dir, char *name,
int name_len, int mod);
int btrfs_match_dir_item_name(struct btrfs_root *root, struct btrfs_path *path,
char *name, int name_len);
struct btrfs_dir_item *btrfs_lookup_dir_item(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct btrfs_path *path,
u64 dir, char *name, int name_len, int mod);
struct btrfs_dir_item *btrfs_match_dir_item_name(struct btrfs_root *root,
struct btrfs_path *path,
const char *name, int name_len);
int btrfs_delete_one_dir_name(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct btrfs_path *path,
struct btrfs_dir_item *di);
int btrfs_find_free_objectid(struct btrfs_trans_handle *trans,
struct btrfs_root *fs_root,
u64 dirid, u64 *objectid);
@ -1097,4 +1127,18 @@ int btrfs_insert_block_group(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct btrfs_key *key,
struct btrfs_block_group_item *bi);
/* file-item.c */
int btrfs_insert_file_extent(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
u64 objectid, u64 pos, u64 offset,
u64 disk_num_bytes, u64 num_bytes);
int btrfs_insert_inline_file_extent(struct btrfs_trans_handle *trans,
struct btrfs_root *root, u64 objectid,
u64 offset, char *buffer, size_t size);
int btrfs_lookup_csum(struct btrfs_trans_handle *trans, struct btrfs_root
*root, struct btrfs_path *path, u64 objectid,
u64 offset, int cow, struct btrfs_csum_item **item_ret);
int btrfs_csum_file_block(struct btrfs_trans_handle *trans, struct btrfs_root
*root, struct btrfs_inode_item *inode,
u64 objectid, u64 offset, char *data, size_t len);
#endif

View File

@ -30,21 +30,25 @@ static struct btrfs_dir_item *insert_with_overflow(struct
struct btrfs_root *root,
struct btrfs_path *path,
struct btrfs_key *cpu_key,
u32 data_size)
u32 data_size,
const char *name,
int name_len)
{
int ret;
char *ptr;
struct btrfs_item *item;
struct btrfs_leaf *leaf;
ret = btrfs_insert_empty_item(trans, root, path, cpu_key, data_size);
if (ret == -EEXIST) {
ret = btrfs_extend_item(trans, root, path, data_size);
BUG_ON(ret > 0);
if (ret)
struct btrfs_dir_item *di;
di = btrfs_match_dir_item_name(root, path, name, name_len);
if (di)
return NULL;
ret = btrfs_extend_item(trans, root, path, data_size);
}
BUG_ON(ret > 0);
if (ret)
return NULL;
leaf = &path->nodes[0]->leaf;
item = leaf->items + path->slots[0];
ptr = btrfs_item_ptr(leaf, path->slots[0], char);
@ -75,7 +79,8 @@ int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root
BUG_ON(ret);
btrfs_init_path(&path);
data_size = sizeof(*dir_item) + name_len;
dir_item = insert_with_overflow(trans, root, &path, &key, data_size);
dir_item = insert_with_overflow(trans, root, &path, &key, data_size,
name, name_len);
if (!dir_item) {
ret = -1;
goto out;
@ -94,7 +99,8 @@ int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root
btrfs_release_path(root, &path);
btrfs_set_key_type(&key, BTRFS_DIR_INDEX_KEY);
key.offset = location->objectid;
dir_item = insert_with_overflow(trans, root, &path, &key, data_size);
dir_item = insert_with_overflow(trans, root, &path, &key, data_size,
name, name_len);
if (!dir_item) {
ret = -1;
goto out;
@ -109,37 +115,95 @@ out:
btrfs_release_path(root, &path);
return ret;
}
int btrfs_lookup_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root
*root, struct btrfs_path *path, u64 dir, char *name,
int name_len, int mod)
struct btrfs_dir_item *btrfs_lookup_dir_item(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct btrfs_path *path, u64 dir,
char *name, int name_len, int mod)
{
int ret;
struct btrfs_key key;
int ins_len = mod < 0 ? -1 : 0;
int cow = mod != 0;
struct btrfs_key found_key;
struct btrfs_leaf *leaf;
key.objectid = dir;
btrfs_set_key_type(&key, BTRFS_DIR_ITEM_KEY);
ret = btrfs_name_hash(name, name_len, &key.offset);
BUG_ON(ret);
ret = btrfs_search_slot(trans, root, &key, path, ins_len, cow);
return ret;
if (ret < 0)
return NULL;
if (ret > 0) {
if (path->slots[0] == 0)
return NULL;
path->slots[0]--;
}
leaf = &path->nodes[0]->leaf;
btrfs_disk_key_to_cpu(&found_key, &leaf->items[path->slots[0]].key);
if (found_key.objectid != dir ||
btrfs_key_type(&found_key) != BTRFS_DIR_ITEM_KEY ||
found_key.offset != key.offset)
return NULL;
return btrfs_match_dir_item_name(root, path, name, name_len);
}
int btrfs_match_dir_item_name(struct btrfs_root *root,
struct btrfs_path *path, char
*name, int name_len)
struct btrfs_dir_item *btrfs_match_dir_item_name(struct btrfs_root *root,
struct btrfs_path *path,
const char *name, int name_len)
{
struct btrfs_dir_item *dir_item;
u32 cur = 0;
u32 this_len;
u32 total_len;
char *name_ptr;
struct btrfs_leaf *leaf;
struct btrfs_dir_item *dir_item;
dir_item = btrfs_item_ptr(&path->nodes[0]->leaf, path->slots[0],
struct btrfs_dir_item);
if (btrfs_dir_name_len(dir_item) != name_len)
return 0;
name_ptr = (char *)(dir_item + 1);
if (memcmp(name_ptr, name, name_len))
return 0;
return 1;
leaf = &path->nodes[0]->leaf;
dir_item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_dir_item);
total_len = btrfs_item_size(leaf->items + path->slots[0]);
while(cur < total_len) {
this_len = sizeof(*dir_item) + btrfs_dir_name_len(dir_item) +
btrfs_dir_data_len(dir_item);
name_ptr = (char *)(dir_item + 1);
if (btrfs_dir_name_len(dir_item) == name_len &&
memcmp(name, name_ptr, name_len) == 0)
return dir_item;
cur += this_len;
dir_item = (struct btrfs_dir_item *)((char *)dir_item +
this_len);
}
return NULL;
}
int btrfs_delete_one_dir_name(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct btrfs_path *path,
struct btrfs_dir_item *di)
{
struct btrfs_leaf *leaf;
u32 sub_item_len;
u32 item_len;
int ret = 0;
leaf = &path->nodes[0]->leaf;
sub_item_len = sizeof(*di) + btrfs_dir_name_len(di) +
btrfs_dir_data_len(di);
item_len = btrfs_item_size(leaf->items + path->slots[0]);
if (sub_item_len == item_len) {
ret = btrfs_del_item(trans, root, path);
} else {
char *ptr = (char *)di;
char *start = btrfs_item_ptr(leaf, path->slots[0], char);
memmove(ptr, ptr + sub_item_len,
item_len - (ptr + sub_item_len - start));
ret = btrfs_truncate_item(trans, root, path,
item_len - sub_item_len, 1);
}
return 0;
}

View File

@ -302,11 +302,9 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, struct
root->node->count++;
ret = btrfs_drop_snapshot(trans, root, snap);
BUG_ON(ret);
ret = btrfs_del_root(trans, root->fs_info->tree_root, &snap_key);
BUG_ON(ret);
root->fs_info->generation = root->root_key.offset + 1;
btrfs_free_transaction(root, trans);
return ret;
}
@ -420,7 +418,7 @@ struct btrfs_root *open_ctree_fd(int fp, struct btrfs_super_block *super)
root->commit_root = root->node;
root->node->count++;
root->ref_cows = 1;
root->fs_info->generation = root->root_key.offset + 1;
root->fs_info->generation = btrfs_super_generation(super) + 1;
btrfs_read_block_groups(root);
return root;
}
@ -429,8 +427,8 @@ int write_ctree_super(struct btrfs_trans_handle *trans, struct btrfs_root
*root, struct btrfs_super_block *s)
{
int ret;
btrfs_set_super_root(s, root->fs_info->tree_root->node->bytenr);
btrfs_set_super_generation(s, trans->transid);
btrfs_set_super_root_level(s,
btrfs_header_level(&root->fs_info->tree_root->node->node.header));
btrfs_csum_super(root, s);
@ -460,17 +458,17 @@ int close_ctree(struct btrfs_root *root, struct btrfs_super_block *s)
{
int ret;
struct btrfs_trans_handle *trans;
trans = root->fs_info->running_transaction;
trans = btrfs_start_transaction(root, 1);
btrfs_commit_transaction(trans, root, s);
trans = btrfs_start_transaction(root, 1);
ret = commit_tree_roots(trans, root->fs_info);
BUG_ON(ret);
ret = __commit_transaction(trans, root);
BUG_ON(ret);
write_ctree_super(trans, root, s);
btrfs_free_transaction(root, trans);
drop_cache(root);
BUG_ON(!list_empty(&root->fs_info->trans));
btrfs_free_block_groups(root->fs_info);
close(root->fs_info->fp);
if (root->node)

View File

@ -88,21 +88,34 @@ int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
struct btrfs_buffer *buf)
{
u64 bytenr;
u32 blocksize;
int i;
int level;
if (!root->ref_cows)
return 0;
level = btrfs_header_level(&buf->node.header) - 1;
blocksize = btrfs_level_size(root, level);
if (btrfs_is_leaf(&buf->node))
return 0;
for (i = 0; i < btrfs_header_nritems(&buf->node.header); i++) {
bytenr = btrfs_node_blockptr(&buf->node, i);
inc_block_ref(trans, root, bytenr, root->nodesize);
inc_block_ref(trans, root, bytenr, blocksize);
}
return 0;
}
int btrfs_inc_root_ref(struct btrfs_trans_handle *trans,
struct btrfs_root *root)
{
return inc_block_ref(trans, root, root->node->bytenr,
root->node->size);
}
static int write_one_cache_group(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct btrfs_path *path,
@ -525,9 +538,8 @@ static int alloc_extent(struct btrfs_trans_handle *trans,
ret = insert_cache_extent(&root->fs_info->pending_tree,
ins->objectid, ins->offset);
BUG_ON(ret);
return 0;
goto update_block;
}
ret = btrfs_insert_item(trans, extent_root, ins, &extent_item,
sizeof(extent_item));
@ -537,9 +549,11 @@ static int alloc_extent(struct btrfs_trans_handle *trans,
return ret;
if (pending_ret)
return pending_ret;
update_block:
ret = update_block_group(trans, root, ins->objectid, ins->offset, 1);
BUG_ON(ret);
return 0;
}
/*
* helper function to allocate a block for a given tree
* returns the tree buffer or NULL.
@ -551,14 +565,12 @@ struct btrfs_buffer *btrfs_alloc_free_block(struct btrfs_trans_handle *trans,
struct btrfs_key ins;
int ret;
struct btrfs_buffer *buf;
ret = alloc_extent(trans, root, root->root_key.objectid,
blocksize, 0, (unsigned long)-1, &ins);
blocksize, 0, (u64)-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, blocksize);
btrfs_set_header_generation(&buf->node.header,
root->root_key.offset + 1);

View File

@ -23,9 +23,272 @@
#include "ctree.h"
#include "disk-io.h"
#include "transaction.h"
#include "crc32c.h"
#define MAX_CSUM_ITEMS(r) ((((BTRFS_LEAF_DATA_SIZE(r) - \
sizeof(struct btrfs_item) * 2) / \
BTRFS_CRC32_SIZE) - 1))
int btrfs_create_file(struct btrfs_trans_handle *trans,
struct btrfs_root *root, u64 dirid, u64 *objectid)
{
return 0;
}
int btrfs_insert_file_extent(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
u64 objectid, u64 pos,
u64 offset, u64 disk_num_bytes,
u64 num_bytes)
{
int ret = 0;
struct btrfs_file_extent_item *item;
struct btrfs_key file_key;
struct btrfs_path path;
struct btrfs_leaf *leaf;
btrfs_init_path(&path);
file_key.objectid = objectid;
file_key.offset = pos;
btrfs_set_key_type(&file_key, BTRFS_EXTENT_DATA_KEY);
ret = btrfs_insert_empty_item(trans, root, &path, &file_key,
sizeof(*item));
if (ret < 0)
goto out;
BUG_ON(ret);
leaf = &path.nodes[0]->leaf;
item = btrfs_item_ptr(leaf, path.slots[0],
struct btrfs_file_extent_item);
btrfs_set_file_extent_disk_bytenr(item, offset);
btrfs_set_file_extent_disk_num_bytes(item, disk_num_bytes);
btrfs_set_file_extent_offset(item, 0);
btrfs_set_file_extent_num_bytes(item, num_bytes);
btrfs_set_file_extent_generation(item, trans->transid);
btrfs_set_file_extent_type(item, BTRFS_FILE_EXTENT_REG);
out:
btrfs_release_path(root, &path);
return ret;
}
int btrfs_insert_inline_file_extent(struct btrfs_trans_handle *trans,
struct btrfs_root *root, u64 objectid,
u64 offset, char *buffer, size_t size)
{
int ret;
char *ptr;
u32 datasize;
struct btrfs_key key;
struct btrfs_path path;
struct btrfs_leaf *leaf;
struct btrfs_file_extent_item *ei;
btrfs_init_path(&path);
key.objectid = objectid;
key.offset = offset;
btrfs_set_key_type(&key, BTRFS_EXTENT_DATA_KEY);
datasize = btrfs_file_extent_calc_inline_size(size);
ret = btrfs_insert_empty_item(trans, root, &path, &key,
datasize);
BUG_ON(ret);
leaf = &path.nodes[0]->leaf;
ei = btrfs_item_ptr(leaf, path.slots[0],
struct btrfs_file_extent_item);
btrfs_set_file_extent_generation(ei, trans->transid);
btrfs_set_file_extent_type(ei, BTRFS_FILE_EXTENT_INLINE);
ptr = btrfs_file_extent_inline_start(ei);
memcpy(ptr, buffer, size);
btrfs_release_path(root, &path);
return 0;
}
int btrfs_lookup_csum(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct btrfs_path *path,
u64 objectid, u64 offset, int cow,
struct btrfs_csum_item **item_ret)
{
int ret;
int slot;
struct btrfs_key file_key;
struct btrfs_key found_key;
struct btrfs_csum_item *item;
struct btrfs_leaf *leaf;
u64 csum_offset = 0;
int csums_in_item;
file_key.objectid = objectid;
file_key.offset = offset;
btrfs_set_key_type(&file_key, BTRFS_CSUM_ITEM_KEY);
ret = btrfs_search_slot(trans, root, &file_key, path, 0, cow);
if (ret < 0)
goto fail;
leaf = &path->nodes[0]->leaf;
if (ret > 0) {
if (path->slots[0] == 0)
goto fail;
path->slots[0]--;
slot = path->slots[0];
btrfs_disk_key_to_cpu(&found_key, &leaf->items[slot].key);
if (btrfs_key_type(&found_key) != BTRFS_CSUM_ITEM_KEY ||
found_key.objectid != objectid) {
goto fail;
}
csum_offset = (offset - found_key.offset) / root->sectorsize;
csums_in_item = btrfs_item_size(&leaf->items[slot]);
csums_in_item /= BTRFS_CRC32_SIZE;
if (csum_offset >= csums_in_item) {
ret = -EFBIG;
goto fail;
}
ret = 0;
}
item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_csum_item);
item = (struct btrfs_csum_item *)((unsigned char *)item +
csum_offset * BTRFS_CRC32_SIZE);
*item_ret = item;
fail:
if (ret > 0)
ret = -ENOENT;
return ret;
}
int btrfs_csum_file_block(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct btrfs_inode_item *inode,
u64 objectid, u64 offset,
char *data, size_t len)
{
int ret;
int slot;
struct btrfs_key file_key;
struct btrfs_key found_key;
u64 next_offset = (u64)-1;
int found_next = 0;
struct btrfs_path path;
struct btrfs_csum_item *item;
struct btrfs_leaf *leaf = NULL;
u64 csum_offset;
u32 csum_result = ~(u32)0;
u32 nritems;
u32 ins_size;
btrfs_init_path(&path);
file_key.objectid = objectid;
file_key.offset = offset;
btrfs_set_key_type(&file_key, BTRFS_CSUM_ITEM_KEY);
ret = btrfs_lookup_csum(trans, root, &path, objectid,
offset, 1, &item);
if (!ret) {
leaf = &path.nodes[0]->leaf;
goto found;
}
if (ret != -EFBIG && ret != -ENOENT)
goto fail;
leaf = &path.nodes[0]->leaf;
if (ret == -EFBIG) {
u32 item_size;
slot = path.slots[0];
/* we found one, but it isn't big enough yet */
item_size = btrfs_item_size(&leaf->items[slot]);
if ((item_size / BTRFS_CRC32_SIZE) >= MAX_CSUM_ITEMS(root)) {
/* already at max size, make a new one */
goto insert;
}
} else {
slot = path.slots[0] + 1;
/* we didn't find a csum item, insert one */
nritems = btrfs_header_nritems(&leaf->header);
if (path.slots[0] >= nritems - 1) {
ret = btrfs_next_leaf(root, &path);
if (ret == 1)
found_next = 1;
if (ret != 0)
goto insert;
slot = 0;
}
btrfs_disk_key_to_cpu(&found_key, &leaf->items[slot].key);
if (found_key.objectid != objectid ||
found_key.type != BTRFS_CSUM_ITEM_KEY) {
found_next = 1;
goto insert;
}
next_offset = found_key.offset;
found_next = 1;
goto insert;
}
/*
* at this point, we know the tree has an item, but it isn't big
* enough yet to put our csum in. Grow it
*/
btrfs_release_path(root, &path);
ret = btrfs_search_slot(trans, root, &file_key, &path,
BTRFS_CRC32_SIZE, 1);
if (ret < 0)
goto fail;
BUG_ON(ret == 0);
if (path.slots[0] == 0) {
goto insert;
}
path.slots[0]--;
slot = path.slots[0];
leaf = &path.nodes[0]->leaf;
btrfs_disk_key_to_cpu(&found_key, &leaf->items[slot].key);
csum_offset = (offset - found_key.offset) / root->sectorsize;
if (btrfs_key_type(&found_key) != BTRFS_CSUM_ITEM_KEY ||
found_key.objectid != objectid ||
csum_offset >= MAX_CSUM_ITEMS(root)) {
goto insert;
}
if (csum_offset >= btrfs_item_size(&leaf->items[slot]) /
BTRFS_CRC32_SIZE) {
u32 diff = (csum_offset + 1) * BTRFS_CRC32_SIZE;
diff = diff - btrfs_item_size(&leaf->items[slot]);
if (diff != BTRFS_CRC32_SIZE)
goto insert;
ret = btrfs_extend_item(trans, root, &path, diff);
BUG_ON(ret);
goto csum;
}
insert:
btrfs_release_path(root, &path);
csum_offset = 0;
if (found_next) {
u64 tmp;
if (next_offset > btrfs_inode_size(inode))
next_offset = btrfs_inode_size(inode);
tmp = next_offset - offset + root->sectorsize - 1;
tmp /= root->sectorsize;
if (tmp > MAX_CSUM_ITEMS(root))
tmp = MAX_CSUM_ITEMS(root);
ins_size = BTRFS_CRC32_SIZE * tmp;
} else {
ins_size = BTRFS_CRC32_SIZE;
}
ret = btrfs_insert_empty_item(trans, root, &path, &file_key,
ins_size);
if (ret < 0)
goto fail;
BUG_ON(ret != 0);
csum:
slot = path.slots[0];
leaf = &path.nodes[0]->leaf;
item = btrfs_item_ptr(leaf, slot, struct btrfs_csum_item);
item = (struct btrfs_csum_item *)((unsigned char *)item +
csum_offset * BTRFS_CRC32_SIZE);
found:
csum_result = crc32c(csum_result, data, len);
csum_result = ~cpu_to_le32(csum_result);
memcpy(item, &csum_result, BTRFS_CRC32_SIZE);
ret = 0;
fail:
btrfs_release_path(root, &path);
return ret;
}

View File

@ -18,9 +18,9 @@
#ifndef __KERNCOMPAT
#define __KERNCOMPAT
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <endian.h>
#include <byteswap.h>
@ -124,10 +124,6 @@ static inline int test_bit(int nr, const volatile unsigned long *addr)
#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})
#define ENOMEM 5
#define EEXIST 6
#ifdef __CHECKER__
#define __CHECK_ENDIAN__
#define __bitwise __bitwise__

View File

@ -28,8 +28,11 @@ struct btrfs_trans_handle {
static inline struct btrfs_trans_handle *
btrfs_start_transaction(struct btrfs_root *root, int num_blocks)
{
struct btrfs_fs_info *fs_info = root->fs_info;
struct btrfs_trans_handle *h = malloc(sizeof(*h));
h->transid = root->root_key.offset;
fs_info->running_transaction = h;
fs_info->generation++;
h->transid = fs_info->generation;
h->blocks_reserved = num_blocks;
h->blocks_used = 0;
return h;