CC=gcc
-CFLAGS = -g -Wall
+CFLAGS = -g -Wall -Werror
headers = radix-tree.h ctree.h disk-io.h kerncompat.h print-tree.h list.h
objects = ctree.o disk-io.o radix-tree.o mkfs.o extent-tree.o print-tree.o \
root-tree.o dir-item.o hash.o file-item.o inode-item.o
$(check) $<
$(CC) $(CFLAGS) -c $<
-all: tester debug-tree quick-test dir-test
+all: tester debug-tree quick-test dir-test tags
debug-tree: $(objects) debug-tree.o
gcc $(CFLAGS) -o debug-tree $(objects) debug-tree.o
* Add block mapping tree (simple dm layer)
* Add simple tree locking (semaphore per tree)
* Make allocator smarter
+* Only pin blocks allocated in this transaction
+* Add transaction handles
* Do actual block accounting
* Check compat and incompat flags on the inode
* Port into the kernel
#include "disk-io.h"
#include "print-tree.h"
-static int split_node(struct btrfs_root *root, struct btrfs_path *path,
- int level);
-static int split_leaf(struct btrfs_root *root, struct btrfs_path *path,
- int data_size);
-static int push_node_left(struct btrfs_root *root, struct btrfs_buffer *dst,
- struct btrfs_buffer *src);
-static int balance_node_right(struct btrfs_root *root,
- struct btrfs_buffer *dst_buf,
+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);
+static int push_node_left(struct btrfs_trans_handle *trans, struct btrfs_root
+ *root, struct btrfs_buffer *dst, struct btrfs_buffer
+ *src);
+static int balance_node_right(struct btrfs_trans_handle *trans, struct
+ btrfs_root *root, struct btrfs_buffer *dst_buf,
struct btrfs_buffer *src_buf);
-static int del_ptr(struct btrfs_root *root, struct btrfs_path *path, int level,
- int slot);
+static int del_ptr(struct btrfs_trans_handle *trans, struct btrfs_root *root,
+ struct btrfs_path *path, int level, int slot);
inline void btrfs_init_path(struct btrfs_path *p)
{
memset(p, 0, sizeof(*p));
}
-static int btrfs_cow_block(struct btrfs_root *root,
- struct btrfs_buffer *buf,
- struct btrfs_buffer *parent,
- int parent_slot,
- struct btrfs_buffer **cow_ret)
+static 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)
{
struct btrfs_buffer *cow;
*cow_ret = buf;
return 0;
}
- cow = btrfs_alloc_free_block(root);
+ cow = btrfs_alloc_free_block(trans, root);
memcpy(&cow->node, &buf->node, root->blocksize);
btrfs_set_header_blocknr(&cow->node.header, cow->blocknr);
*cow_ret = cow;
- btrfs_inc_ref(root, buf);
+ btrfs_inc_ref(trans, root, buf);
if (buf == root->node) {
root->node = cow;
cow->count++;
if (buf != root->commit_root)
- btrfs_free_extent(root, buf->blocknr, 1, 1);
+ btrfs_free_extent(trans, root, buf->blocknr, 1, 1);
btrfs_block_release(root, buf);
} else {
btrfs_set_node_blockptr(&parent->node, parent_slot,
cow->blocknr);
BUG_ON(list_empty(&parent->dirty));
- btrfs_free_extent(root, buf->blocknr, 1, 1);
+ btrfs_free_extent(trans, root, buf->blocknr, 1, 1);
}
btrfs_block_release(root, buf);
return 0;
return read_tree_block(root, btrfs_node_blockptr(node, slot));
}
-static int balance_level(struct btrfs_root *root, struct btrfs_path *path,
- int level)
+static int balance_level(struct btrfs_trans_handle *trans, struct btrfs_root
+ *root, struct btrfs_path *path, int level)
{
struct btrfs_buffer *right_buf;
struct btrfs_buffer *mid_buf;
btrfs_block_release(root, mid_buf);
/* once for the root ptr */
btrfs_block_release(root, mid_buf);
- clean_tree_block(root, mid_buf);
- return btrfs_free_extent(root, blocknr, 1, 1);
+ clean_tree_block(trans, root, mid_buf);
+ return btrfs_free_extent(trans, root, blocknr, 1, 1);
}
parent = &parent_buf->node;
/* first, try to make some room in the middle buffer */
if (left_buf) {
- btrfs_cow_block(root, left_buf, parent_buf,
- pslot - 1, &left_buf);
+ btrfs_cow_block(trans, root, left_buf, parent_buf, pslot - 1,
+ &left_buf);
left = &left_buf->node;
orig_slot += btrfs_header_nritems(&left->header);
- wret = push_node_left(root, left_buf, mid_buf);
+ wret = push_node_left(trans, root, left_buf, mid_buf);
if (wret < 0)
ret = wret;
}
* then try to empty the right most buffer into the middle
*/
if (right_buf) {
- btrfs_cow_block(root, right_buf, parent_buf,
- pslot + 1, &right_buf);
+ btrfs_cow_block(trans, root, right_buf, parent_buf, pslot + 1,
+ &right_buf);
right = &right_buf->node;
- wret = push_node_left(root, mid_buf, right_buf);
+ wret = push_node_left(trans, root, mid_buf, right_buf);
if (wret < 0)
ret = wret;
if (btrfs_header_nritems(&right->header) == 0) {
u64 blocknr = right_buf->blocknr;
btrfs_block_release(root, right_buf);
- clean_tree_block(root, right_buf);
+ clean_tree_block(trans, root, right_buf);
right_buf = NULL;
right = NULL;
- wret = del_ptr(root, path, level + 1, pslot + 1);
+ wret = del_ptr(trans, root, path, level + 1, pslot +
+ 1);
if (wret)
ret = wret;
- wret = btrfs_free_extent(root, blocknr, 1, 1);
+ wret = btrfs_free_extent(trans, root, blocknr, 1, 1);
if (wret)
ret = wret;
} else {
* right
*/
BUG_ON(!left_buf);
- wret = balance_node_right(root, mid_buf, left_buf);
+ wret = balance_node_right(trans, root, mid_buf, left_buf);
if (wret < 0)
ret = wret;
BUG_ON(wret == 1);
/* we've managed to empty the middle node, drop it */
u64 blocknr = mid_buf->blocknr;
btrfs_block_release(root, mid_buf);
- clean_tree_block(root, mid_buf);
+ clean_tree_block(trans, root, mid_buf);
mid_buf = NULL;
mid = NULL;
- wret = del_ptr(root, path, level + 1, pslot);
+ wret = del_ptr(trans, root, path, level + 1, pslot);
if (wret)
ret = wret;
- wret = btrfs_free_extent(root, blocknr, 1, 1);
+ wret = btrfs_free_extent(trans, root, blocknr, 1, 1);
if (wret)
ret = wret;
} else {
* tree. if ins_len < 0, nodes will be merged as we walk down the tree (if
* possible)
*/
-int btrfs_search_slot(struct btrfs_root *root, struct btrfs_key *key,
- struct btrfs_path *p, int ins_len, int cow)
+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)
{
struct btrfs_buffer *b;
struct btrfs_buffer *cow_buf;
level = btrfs_header_level(&b->node.header);
if (cow) {
int wret;
- wret = btrfs_cow_block(root, b, p->nodes[level + 1],
- p->slots[level + 1], &cow_buf);
+ wret = btrfs_cow_block(trans, root, b, p->nodes[level +
+ 1], p->slots[level + 1],
+ &cow_buf);
b = cow_buf;
}
BUG_ON(!cow && ins_len);
p->slots[level] = slot;
if (ins_len > 0 && btrfs_header_nritems(&c->header) ==
BTRFS_NODEPTRS_PER_BLOCK(root)) {
- int sret = split_node(root, p, level);
+ int sret = split_node(trans, root, p, level);
BUG_ON(sret > 0);
if (sret)
return sret;
c = &b->node;
slot = p->slots[level];
} else if (ins_len < 0) {
- int sret = balance_level(root, p, level);
+ int sret = balance_level(trans, root, p,
+ level);
if (sret)
return sret;
b = p->nodes[level];
p->slots[level] = slot;
if (ins_len > 0 && btrfs_leaf_free_space(root, l) <
sizeof(struct btrfs_item) + ins_len) {
- int sret = split_leaf(root, p, ins_len);
+ int sret = split_leaf(trans, root, p, ins_len);
BUG_ON(sret > 0);
if (sret)
return sret;
* If this fails to write a tree block, it returns -1, but continues
* fixing up the blocks in ram so the tree is consistent.
*/
-static int fixup_low_keys(struct btrfs_root *root,
- struct btrfs_path *path, struct btrfs_disk_key *key,
- int level)
+static int fixup_low_keys(struct btrfs_trans_handle *trans, struct btrfs_root
+ *root, struct btrfs_path *path, struct btrfs_disk_key
+ *key, int level)
{
int i;
int ret = 0;
* returns 0 if some ptrs were pushed left, < 0 if there was some horrible
* error, and > 0 if there was no room in the left hand block.
*/
-static int push_node_left(struct btrfs_root *root, struct btrfs_buffer *dst_buf,
- struct btrfs_buffer *src_buf)
+static int push_node_left(struct btrfs_trans_handle *trans, struct btrfs_root
+ *root, struct btrfs_buffer *dst_buf, struct
+ btrfs_buffer *src_buf)
{
struct btrfs_node *src = &src_buf->node;
struct btrfs_node *dst = &dst_buf->node;
*
* this will only push up to 1/2 the contents of the left node over
*/
-static int balance_node_right(struct btrfs_root *root,
- struct btrfs_buffer *dst_buf,
+static int balance_node_right(struct btrfs_trans_handle *trans, struct
+ btrfs_root *root, struct btrfs_buffer *dst_buf,
struct btrfs_buffer *src_buf)
{
struct btrfs_node *src = &src_buf->node;
*
* returns zero on success or < 0 on failure.
*/
-static int insert_new_root(struct btrfs_root *root,
- struct btrfs_path *path, int level)
+static int insert_new_root(struct btrfs_trans_handle *trans, struct btrfs_root
+ *root, struct btrfs_path *path, int level)
{
struct btrfs_buffer *t;
struct btrfs_node *lower;
BUG_ON(path->nodes[level]);
BUG_ON(path->nodes[level-1] != root->node);
- t = btrfs_alloc_free_block(root);
+ t = btrfs_alloc_free_block(trans, root);
c = &t->node;
memset(c, 0, root->blocksize);
btrfs_set_header_nritems(&c->header, 1);
*
* returns zero on success and < 0 on any error
*/
-static int insert_ptr(struct btrfs_root *root,
- struct btrfs_path *path, struct btrfs_disk_key *key,
- u64 blocknr, int slot, int level)
+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)
{
struct btrfs_node *lower;
int nritems;
*
* returns 0 on success and < 0 on failure
*/
-static int split_node(struct btrfs_root *root, struct btrfs_path *path,
- int level)
+static int split_node(struct btrfs_trans_handle *trans, struct btrfs_root
+ *root, struct btrfs_path *path, int level)
{
struct btrfs_buffer *t;
struct btrfs_node *c;
c = &t->node;
if (t == root->node) {
/* trying to split the root, lets make a new one */
- ret = insert_new_root(root, path, level + 1);
+ ret = insert_new_root(trans, root, path, level + 1);
if (ret)
return ret;
}
c_nritems = btrfs_header_nritems(&c->header);
- split_buffer = btrfs_alloc_free_block(root);
+ split_buffer = btrfs_alloc_free_block(trans, root);
split = &split_buffer->node;
btrfs_set_header_flags(&split->header, btrfs_header_flags(&c->header));
btrfs_set_header_blocknr(&split->header, split_buffer->blocknr);
ret = 0;
BUG_ON(list_empty(&t->dirty));
- wret = insert_ptr(root, path, &split->ptrs[0].key,
+ wret = insert_ptr(trans, root, path, &split->ptrs[0].key,
split_buffer->blocknr, path->slots[level + 1] + 1,
level + 1);
if (wret)
* returns 1 if the push failed because the other node didn't have enough
* room, 0 if everything worked out and < 0 if there were major errors.
*/
-static int push_leaf_right(struct btrfs_root *root, struct btrfs_path *path,
- int data_size)
+static int push_leaf_right(struct btrfs_trans_handle *trans, struct btrfs_root
+ *root, struct btrfs_path *path, int data_size)
{
struct btrfs_buffer *left_buf = path->nodes[0];
struct btrfs_leaf *left = &left_buf->leaf;
return 1;
}
/* cow and double check */
- btrfs_cow_block(root, right_buf, upper, slot + 1, &right_buf);
+ btrfs_cow_block(trans, root, right_buf, upper, slot + 1, &right_buf);
right = &right_buf->leaf;
free_space = btrfs_leaf_free_space(root, right);
if (free_space < data_size + sizeof(struct btrfs_item)) {
* push some data in the path leaf to the left, trying to free up at
* least data_size bytes. returns zero if the push worked, nonzero otherwise
*/
-static int push_leaf_left(struct btrfs_root *root, struct btrfs_path *path,
- int data_size)
+static int push_leaf_left(struct btrfs_trans_handle *trans, struct btrfs_root
+ *root, struct btrfs_path *path, int data_size)
{
struct btrfs_buffer *right_buf = path->nodes[0];
struct btrfs_leaf *right = &right_buf->leaf;
}
/* cow and double check */
- btrfs_cow_block(root, t, path->nodes[1], slot - 1, &t);
+ btrfs_cow_block(trans, root, t, path->nodes[1], slot - 1, &t);
left = &t->leaf;
free_space = btrfs_leaf_free_space(root, left);
if (free_space < data_size + sizeof(struct btrfs_item)) {
BUG_ON(list_empty(&t->dirty));
BUG_ON(list_empty(&right_buf->dirty));
- wret = fixup_low_keys(root, path, &right->items[0].key, 1);
+ wret = fixup_low_keys(trans, root, path, &right->items[0].key, 1);
if (wret)
ret = wret;
*
* returns 0 if all went well and < 0 on failure.
*/
-static int split_leaf(struct btrfs_root *root, struct btrfs_path *path,
- int data_size)
+static int split_leaf(struct btrfs_trans_handle *trans, struct btrfs_root
+ *root, struct btrfs_path *path, int data_size)
{
struct btrfs_buffer *l_buf;
struct btrfs_leaf *l;
int ret;
int wret;
- wret = push_leaf_left(root, path, data_size);
+ wret = push_leaf_left(trans, root, path, data_size);
if (wret < 0)
return wret;
if (wret) {
- wret = push_leaf_right(root, path, data_size);
+ wret = push_leaf_right(trans, root, path, data_size);
if (wret < 0)
return wret;
}
return 0;
if (!path->nodes[1]) {
- ret = insert_new_root(root, path, 1);
+ ret = insert_new_root(trans, root, path, 1);
if (ret)
return ret;
}
slot = path->slots[0];
nritems = btrfs_header_nritems(&l->header);
mid = (nritems + 1)/ 2;
- right_buffer = btrfs_alloc_free_block(root);
+ right_buffer = btrfs_alloc_free_block(trans, root);
BUG_ON(!right_buffer);
BUG_ON(mid == nritems);
right = &right_buffer->leaf;
btrfs_set_header_nritems(&l->header, mid);
ret = 0;
- wret = insert_ptr(root, path, &right->items[0].key,
+ wret = insert_ptr(trans, root, path, &right->items[0].key,
right_buffer->blocknr, path->slots[1] + 1, 1);
if (wret)
ret = wret;
* 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.
*/
-int btrfs_insert_empty_item(struct btrfs_root *root, struct btrfs_path *path,
- struct btrfs_key *cpu_key, u32 data_size)
+int btrfs_insert_empty_item(struct btrfs_trans_handle *trans, struct btrfs_root
+ *root, struct btrfs_path *path, struct btrfs_key
+ *cpu_key, u32 data_size)
{
int ret = 0;
int slot;
/* create a root if there isn't one */
if (!root->node)
BUG();
- ret = btrfs_search_slot(root, cpu_key, path, data_size, 1);
+ ret = btrfs_search_slot(trans, root, cpu_key, path, data_size, 1);
if (ret == 0) {
btrfs_release_path(root, path);
return -EEXIST;
ret = 0;
if (slot == 0)
- ret = fixup_low_keys(root, path, &disk_key, 1);
+ ret = fixup_low_keys(trans, root, path, &disk_key, 1);
BUG_ON(list_empty(&leaf_buf->dirty));
if (btrfs_leaf_free_space(root, leaf) < 0)
* 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.
*/
-int btrfs_insert_item(struct btrfs_root *root, struct btrfs_key *cpu_key,
- void *data, u32 data_size)
+int btrfs_insert_item(struct btrfs_trans_handle *trans, struct btrfs_root
+ *root, struct btrfs_key *cpu_key, void *data, u32
+ data_size)
{
int ret = 0;
struct btrfs_path path;
u8 *ptr;
btrfs_init_path(&path);
- ret = btrfs_insert_empty_item(root, &path, cpu_key, data_size);
+ ret = btrfs_insert_empty_item(trans, root, &path, cpu_key, data_size);
if (!ret) {
ptr = btrfs_item_ptr(&path.nodes[0]->leaf, path.slots[0], u8);
memcpy(ptr, data, data_size);
* continuing all the way the root if required. The root is converted into
* a leaf if all the nodes are emptied.
*/
-static int del_ptr(struct btrfs_root *root, struct btrfs_path *path, int level,
- int slot)
+static int del_ptr(struct btrfs_trans_handle *trans, struct btrfs_root *root,
+ struct btrfs_path *path, int level, int slot)
{
struct btrfs_node *node;
struct btrfs_buffer *parent = path->nodes[level];
/* just turn the root into a leaf and break */
btrfs_set_header_level(&root->node->node.header, 0);
} else if (slot == 0) {
- wret = fixup_low_keys(root, path, &node->ptrs[0].key,
+ wret = fixup_low_keys(trans, root, path, &node->ptrs[0].key,
level + 1);
if (wret)
ret = wret;
* delete the item at the leaf level in path. If that empties
* the leaf, remove it from the tree
*/
-int btrfs_del_item(struct btrfs_root *root, struct btrfs_path *path)
+int btrfs_del_item(struct btrfs_trans_handle *trans, struct btrfs_root *root,
+ struct btrfs_path *path)
{
int slot;
struct btrfs_leaf *leaf;
btrfs_set_header_level(&leaf->header, 0);
BUG_ON(list_empty(&leaf_buf->dirty));
} else {
- clean_tree_block(root, leaf_buf);
- wret = del_ptr(root, path, 1, path->slots[1]);
+ clean_tree_block(trans, root, leaf_buf);
+ wret = del_ptr(trans, root, path, 1, path->slots[1]);
if (wret)
ret = wret;
- wret = btrfs_free_extent(root, leaf_buf->blocknr, 1, 1);
+ wret = btrfs_free_extent(trans, root,
+ leaf_buf->blocknr, 1, 1);
if (wret)
ret = wret;
}
} else {
int used = leaf_space_used(leaf, 0, nritems);
if (slot == 0) {
- wret = fixup_low_keys(root, path,
- &leaf->items[0].key, 1);
+ wret = fixup_low_keys(trans, root, path,
+ &leaf->items[0].key, 1);
if (wret)
ret = wret;
}
*/
slot = path->slots[1];
leaf_buf->count++;
- wret = push_leaf_left(root, path, 1);
+ wret = push_leaf_left(trans, root, path, 1);
if (wret < 0)
ret = wret;
if (path->nodes[0] == leaf_buf &&
btrfs_header_nritems(&leaf->header)) {
- wret = push_leaf_right(root, path, 1);
+ wret = push_leaf_right(trans, root, path, 1);
if (wret < 0)
ret = wret;
}
if (btrfs_header_nritems(&leaf->header) == 0) {
u64 blocknr = leaf_buf->blocknr;
- clean_tree_block(root, leaf_buf);
- wret = del_ptr(root, path, 1, slot);
+ clean_tree_block(trans, root, leaf_buf);
+ wret = del_ptr(trans, root, path, 1, slot);
if (wret)
ret = wret;
btrfs_block_release(root, leaf_buf);
- wret = btrfs_free_extent(root, blocknr, 1, 1);
+ wret = btrfs_free_extent(trans, root, blocknr,
+ 1, 1);
if (wret)
ret = wret;
} else {
}
return 0;
}
-
-
#include "list.h"
#include "kerncompat.h"
+struct btrfs_trans_handle;
+
#define BTRFS_MAGIC "_BtRfS_M"
#define BTRFS_ROOT_TREE_OBJECTID 1
struct btrfs_root_item root_item;
struct btrfs_key root_key;
u32 blocksize;
+ struct btrfs_trans_handle *running_transaction;
};
/* the lower bits in the key flags defines the item type */
((type *)(btrfs_leaf_data(leaf) + \
btrfs_item_offset((leaf)->items + (slot))))
-struct btrfs_buffer *btrfs_alloc_free_block(struct btrfs_root *root);
-int btrfs_inc_ref(struct btrfs_root *root, struct btrfs_buffer *buf);
-int btrfs_free_extent(struct btrfs_root *root, u64 blocknr, u64 num_blocks,
- int pin);
-int btrfs_search_slot(struct btrfs_root *root, struct btrfs_key *key,
- struct btrfs_path *p, int ins_len, int cow);
+struct btrfs_buffer *btrfs_alloc_free_block(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root);
+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);
+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);
void btrfs_release_path(struct btrfs_root *root, struct btrfs_path *p);
void btrfs_init_path(struct btrfs_path *p);
-int btrfs_del_item(struct btrfs_root *root, struct btrfs_path *path);
-int btrfs_insert_item(struct btrfs_root *root, struct btrfs_key *key,
- void *data, u32 data_size);
-int btrfs_insert_empty_item(struct btrfs_root *root, struct btrfs_path *path,
- struct btrfs_key *cpu_key, u32 data_size);
+int btrfs_del_item(struct btrfs_trans_handle *trans, struct btrfs_root *root,
+ struct btrfs_path *path);
+int btrfs_insert_item(struct btrfs_trans_handle *trans, struct btrfs_root
+ *root, struct btrfs_key *key, void *data, u32 data_size);
+int btrfs_insert_empty_item(struct btrfs_trans_handle *trans, struct btrfs_root
+ *root, struct btrfs_path *path, struct btrfs_key
+ *cpu_key, u32 data_size);
int btrfs_next_leaf(struct btrfs_root *root, struct btrfs_path *path);
int btrfs_leaf_free_space(struct btrfs_root *root, struct btrfs_leaf *leaf);
-int btrfs_drop_snapshot(struct btrfs_root *root, struct btrfs_buffer *snap);
-int btrfs_finish_extent_commit(struct btrfs_root *root);
-int btrfs_del_root(struct btrfs_root *root, struct btrfs_key *key);
-int btrfs_insert_root(struct btrfs_root *root, struct btrfs_key *key,
- struct btrfs_root_item *item);
-int btrfs_update_root(struct btrfs_root *root, struct btrfs_key *key,
- struct btrfs_root_item *item);
-int btrfs_find_last_root(struct btrfs_root *root, u64 objectid,
- struct btrfs_root_item *item, struct btrfs_key *key);
-int btrfs_insert_dir_item(struct btrfs_root *root, char *name, int name_len,
- u64 dir, u64 objectid, u8 type);
-int btrfs_lookup_dir_item(struct btrfs_root *root, struct btrfs_path *path,
- u64 dir, char *name, int name_len, int mod);
+int btrfs_drop_snapshot(struct btrfs_trans_handle *trans, struct btrfs_root
+ *root, struct btrfs_buffer *snap);
+int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans, struct
+ btrfs_root *root);
+int btrfs_del_root(struct btrfs_trans_handle *trans, struct btrfs_root *root,
+ struct btrfs_key *key);
+int btrfs_insert_root(struct btrfs_trans_handle *trans, struct btrfs_root
+ *root, struct btrfs_key *key, struct btrfs_root_item
+ *item);
+int btrfs_update_root(struct btrfs_trans_handle *trans, struct btrfs_root
+ *root, struct btrfs_key *key, struct btrfs_root_item
+ *item);
+int btrfs_find_last_root(struct btrfs_root *root, u64 objectid, struct
+ btrfs_root_item *item, struct btrfs_key *key);
+int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root
+ *root, char *name, int name_len, u64 dir, u64
+ objectid, 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);
#endif
#include "ctree.h"
#include "disk-io.h"
#include "print-tree.h"
+#include "transaction.h"
int main(int ac, char **av) {
struct btrfs_super_block super;
#include "ctree.h"
#include "disk-io.h"
#include "hash.h"
+#include "transaction.h"
-int btrfs_insert_dir_item(struct btrfs_root *root, char *name, int name_len,
- u64 dir, u64 objectid, u8 type)
+int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root
+ *root, char *name, int name_len, u64 dir, u64
+ objectid, u8 type)
{
int ret = 0;
struct btrfs_path path;
BUG_ON(ret);
btrfs_init_path(&path);
data_size = sizeof(*dir_item) + name_len;
- ret = btrfs_insert_empty_item(root, &path, &key, data_size);
+ ret = btrfs_insert_empty_item(trans, root, &path, &key, data_size);
if (ret)
goto out;
return ret;
}
-int btrfs_lookup_dir_item(struct btrfs_root *root, struct btrfs_path *path,
- u64 dir, char *name, int name_len, int mod)
+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 ret;
struct btrfs_key key;
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(root, &key, path, ins_len, cow);
+ ret = btrfs_search_slot(trans, root, &key, path, ins_len, cow);
return ret;
}
-int btrfs_match_dir_item_name(struct btrfs_root *root, struct btrfs_path *path,
- char *name, int 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 *dir_item;
char *name_ptr;
#include "disk-io.h"
#include "print-tree.h"
#include "hash.h"
+#include "transaction.h"
int keep_running = 1;
struct btrfs_super_block super;
return 0;
}
-static int ins_one(struct btrfs_root *root, struct radix_tree_root *radix)
+static int ins_one(struct btrfs_trans_handle *trans, struct btrfs_root *root,
+ struct radix_tree_root *radix)
{
int ret;
char buf[128];
find_num(radix, &oid, 0);
sprintf(buf, "str-%lu", oid);
- ret = btrfs_insert_dir_item(root, buf, strlen(buf), dir_oid, file_oid,
- 1);
+ ret = btrfs_insert_dir_item(trans, root, buf, strlen(buf), dir_oid,
+ file_oid, 1);
if (ret)
goto error;
* check
*/
btrfs_init_path(&path);
- ret = btrfs_lookup_dir_item(root, &path, dir_oid, buf, strlen(buf), 0);
+ ret = btrfs_lookup_dir_item(trans, root, &path, dir_oid, buf,
+ strlen(buf), 0);
if (ret)
goto fatal_release;
if (!btrfs_match_dir_item_name(root, &path, buf, strlen(buf))) {
return -1;
}
-static int insert_dup(struct btrfs_root *root, struct radix_tree_root *radix)
+static int insert_dup(struct btrfs_trans_handle *trans, struct btrfs_root
+ *root, struct radix_tree_root *radix)
{
int ret;
char buf[128];
return 0;
sprintf(buf, "str-%lu", oid);
- ret = btrfs_insert_dir_item(root, buf, strlen(buf), dir_oid, file_oid,
- 1);
+ ret = btrfs_insert_dir_item(trans, root, buf, strlen(buf), dir_oid,
+ file_oid, 1);
if (ret != -EEXIST) {
printf("insert on %s gave us %d\n", buf, ret);
return 1;
return 0;
}
-static int del_one(struct btrfs_root *root, struct radix_tree_root *radix)
+static int del_one(struct btrfs_trans_handle *trans, struct btrfs_root *root,
+ struct radix_tree_root *radix)
{
int ret;
char buf[128];
return 0;
sprintf(buf, "str-%lu", oid);
btrfs_init_path(&path);
- ret = btrfs_lookup_dir_item(root, &path, dir_oid, buf, strlen(buf), -1);
+ ret = btrfs_lookup_dir_item(trans, root, &path, dir_oid, buf,
+ strlen(buf), -1);
if (ret)
goto out_release;
- ret = btrfs_del_item(root, &path);
+ ret = btrfs_del_item(trans, root, &path);
if (ret)
goto out_release;
btrfs_release_path(root, &path);
return -1;
}
-static int lookup_item(struct btrfs_root *root, struct radix_tree_root *radix)
+static int lookup_item(struct btrfs_trans_handle *trans, struct btrfs_root
+ *root, struct radix_tree_root *radix)
{
struct btrfs_path path;
char buf[128];
return 0;
sprintf(buf, "str-%lu", oid);
btrfs_init_path(&path);
- ret = btrfs_lookup_dir_item(root, &path, dir_oid, buf, strlen(buf), 0);
+ ret = btrfs_lookup_dir_item(trans, root, &path, dir_oid, buf,
+ strlen(buf), 0);
btrfs_release_path(root, &path);
if (ret) {
printf("unable to find key %lu\n", oid);
return 0;
}
-static int lookup_enoent(struct btrfs_root *root, struct radix_tree_root *radix)
+static int lookup_enoent(struct btrfs_trans_handle *trans, struct btrfs_root
+ *root, struct radix_tree_root *radix)
{
struct btrfs_path path;
char buf[128];
return 0;
sprintf(buf, "str-%lu", oid);
btrfs_init_path(&path);
- ret = btrfs_lookup_dir_item(root, &path, dir_oid, buf, strlen(buf), 0);
+ ret = btrfs_lookup_dir_item(trans, root, &path, dir_oid, buf,
+ strlen(buf), 0);
btrfs_release_path(root, &path);
if (!ret) {
printf("able to find key that should not exist %lu\n", oid);
return 0;
}
-static int empty_tree(struct btrfs_root *root, struct radix_tree_root *radix,
- int nr)
+static int empty_tree(struct btrfs_trans_handle *trans, struct btrfs_root
+ *root, struct radix_tree_root *radix, int nr)
{
struct btrfs_path path;
struct btrfs_key key;
key.objectid = dir_oid;
while(nr-- >= 0) {
btrfs_init_path(&path);
- ret = btrfs_search_slot(root, &key, &path, -1, 1);
+ ret = btrfs_search_slot(trans, root, &key, &path, -1, 1);
if (ret < 0) {
btrfs_release_path(root, &path);
return ret;
BUG_ON(found_len > 128);
buf[found_len] = '\0';
found = atoi(buf + 4);
- ret = btrfs_del_item(root, &path);
+ ret = btrfs_del_item(trans, root, &path);
count++;
if (ret) {
fprintf(stderr,
return -1;
}
-static int fill_tree(struct btrfs_root *root, struct radix_tree_root *radix,
- int count)
+static int fill_tree(struct btrfs_trans_handle *trans, struct btrfs_root *root,
+ struct radix_tree_root *radix, int count)
{
int i;
int ret = 0;
for (i = 0; i < count; i++) {
- ret = ins_one(root, radix);
+ ret = ins_one(trans, root, radix);
if (ret) {
fprintf(stderr, "fill failed\n");
goto out;
}
if (i % 1000 == 0) {
- ret = btrfs_commit_transaction(root, &super);
+ ret = btrfs_commit_transaction(trans, root, &super);
if (ret) {
fprintf(stderr, "fill commit failed\n");
return ret;
return ret;
}
-static int bulk_op(struct btrfs_root *root, struct radix_tree_root *radix)
+static int bulk_op(struct btrfs_trans_handle *trans, struct btrfs_root *root,
+ struct radix_tree_root *radix)
{
int ret;
int nr = rand() % 5000;
/* do the bulk op much less frequently */
if (run_nr++ % 100)
return 0;
- ret = empty_tree(root, radix, nr);
+ ret = empty_tree(trans, root, radix, nr);
if (ret)
return ret;
- ret = fill_tree(root, radix, nr);
+ ret = fill_tree(trans, root, radix, nr);
if (ret)
return ret;
return 0;
}
-int (*ops[])(struct btrfs_root *root, struct radix_tree_root *radix) =
+int (*ops[])(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct
+ radix_tree_root *radix) =
{ ins_one, insert_dup, del_one, lookup_item,
lookup_enoent, bulk_op };
int init_fill_count = 800000;
int err = 0;
int initial_only = 0;
+ struct btrfs_trans_handle *trans;
radix_tree_init();
printf("removing old tree\n");
unlink("dbfile");
root = open_ctree("dbfile", &super);
+ trans = btrfs_start_transaction(root, 1);
signal(SIGTERM, sigstopper);
signal(SIGINT, sigstopper);
}
}
printf("initial fill\n");
- ret = fill_tree(root, &radix, init_fill_count);
+ ret = fill_tree(trans, root, &radix, init_fill_count);
printf("starting run\n");
if (ret) {
err = ret;
root = open_ctree("dbfile", &super);
}
while(count--) {
- ret = ops[op](root, &radix);
+ ret = ops[op](trans, root, &radix);
if (ret) {
fprintf(stderr, "op %d failed %d:%d\n",
op, i, iterations);
#include "radix-tree.h"
#include "ctree.h"
#include "disk-io.h"
+#include "transaction.h"
static int allocated_blocks = 0;
int cache_max = 10000;
return buf;
}
-int dirty_tree_block(struct btrfs_root *root, struct btrfs_buffer *buf)
+int dirty_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root,
+ struct btrfs_buffer *buf)
{
if (!list_empty(&buf->dirty))
return 0;
return 0;
}
-int clean_tree_block(struct btrfs_root *root, struct btrfs_buffer *buf)
+int clean_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root,
+ struct btrfs_buffer *buf)
{
if (!list_empty(&buf->dirty)) {
list_del_init(&buf->dirty);
return 0;
}
-int write_tree_block(struct btrfs_root *root, struct btrfs_buffer *buf)
+int write_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root,
+ struct btrfs_buffer *buf)
{
u64 blocknr = buf->blocknr;
loff_t offset = blocknr * root->blocksize;
return 0;
}
-static int __commit_transaction(struct btrfs_root *root)
+static int __commit_transaction(struct btrfs_trans_handle *trans, struct
+ btrfs_root *root)
{
struct btrfs_buffer *b;
int ret = 0;
while(!list_empty(&root->trans)) {
b = list_entry(root->trans.next, struct btrfs_buffer, dirty);
list_del_init(&b->dirty);
- wret = write_tree_block(root, b);
+ wret = write_tree_block(trans, root, b);
if (wret)
ret = wret;
btrfs_block_release(root, b);
return ret;
}
-static int commit_extent_and_tree_roots(struct btrfs_root *tree_root,
- struct btrfs_root *extent_root)
+static int commit_extent_and_tree_roots(struct btrfs_trans_handle *trans,
+ struct btrfs_root *tree_root, struct
+ btrfs_root *extent_root)
{
int ret;
u64 old_extent_block;
break;
btrfs_set_root_blocknr(&extent_root->root_item,
extent_root->node->blocknr);
- ret = btrfs_update_root(tree_root,
+ ret = btrfs_update_root(trans, tree_root,
&extent_root->root_key,
&extent_root->root_item);
BUG_ON(ret);
}
- __commit_transaction(extent_root);
- __commit_transaction(tree_root);
+ __commit_transaction(trans, extent_root);
+ __commit_transaction(trans, tree_root);
return 0;
}
-int btrfs_commit_transaction(struct btrfs_root *root,
- struct btrfs_super_block *s)
+int btrfs_commit_transaction(struct btrfs_trans_handle *trans, struct
+ btrfs_root *root, struct btrfs_super_block *s)
{
int ret = 0;
struct btrfs_buffer *snap = root->commit_root;
struct btrfs_key snap_key;
- ret = __commit_transaction(root);
+ ret = __commit_transaction(trans, root);
BUG_ON(ret);
if (root->commit_root == root->node)
root->root_key.offset++;
btrfs_set_root_blocknr(&root->root_item, root->node->blocknr);
- ret = btrfs_insert_root(root->tree_root, &root->root_key,
+ ret = btrfs_insert_root(trans, root->tree_root, &root->root_key,
&root->root_item);
BUG_ON(ret);
- ret = commit_extent_and_tree_roots(root->tree_root, root->extent_root);
+ ret = commit_extent_and_tree_roots(trans, root->tree_root,
+ root->extent_root);
BUG_ON(ret);
- write_ctree_super(root, s);
- btrfs_finish_extent_commit(root->extent_root);
- btrfs_finish_extent_commit(root->tree_root);
+ write_ctree_super(trans, root, s);
+ btrfs_finish_extent_commit(trans, root->extent_root);
+ btrfs_finish_extent_commit(trans, root->tree_root);
root->commit_root = root->node;
root->node->count++;
- ret = btrfs_drop_snapshot(root, snap);
+ ret = btrfs_drop_snapshot(trans, root, snap);
BUG_ON(ret);
- ret = btrfs_del_root(root->tree_root, &snap_key);
+ ret = btrfs_del_root(trans, root->tree_root, &snap_key);
BUG_ON(ret);
return ret;
return root;
}
-int write_ctree_super(struct btrfs_root *root, struct btrfs_super_block *s)
+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->tree_root->node->blocknr);
int close_ctree(struct btrfs_root *root, struct btrfs_super_block *s)
{
int ret;
- btrfs_commit_transaction(root, s);
- ret = commit_extent_and_tree_roots(root->tree_root, root->extent_root);
+ struct btrfs_trans_handle *trans;
+
+ trans = root->running_transaction;
+ btrfs_commit_transaction(trans, root, s);
+ ret = commit_extent_and_tree_roots(trans, root->tree_root,
+ root->extent_root);
BUG_ON(ret);
- write_ctree_super(root, s);
+ write_ctree_super(trans, root, s);
drop_cache(root->extent_root);
drop_cache(root->tree_root);
drop_cache(root);
struct btrfs_buffer *read_tree_block(struct btrfs_root *root, u64 blocknr);
struct btrfs_buffer *find_tree_block(struct btrfs_root *root, u64 blocknr);
-int write_tree_block(struct btrfs_root *root, struct btrfs_buffer *buf);
-int dirty_tree_block(struct btrfs_root *root, struct btrfs_buffer *buf);
-int clean_tree_block(struct btrfs_root *root, struct btrfs_buffer *buf);
-int btrfs_commit_transaction(struct btrfs_root *root,
- struct btrfs_super_block *s);
+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,
+ struct btrfs_buffer *buf);
+int clean_tree_block(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root, struct btrfs_buffer *buf);
+int btrfs_commit_transaction(struct btrfs_trans_handle *trans, struct btrfs_root
+ *root, struct btrfs_super_block *s);
struct btrfs_root *open_ctree(char *filename, struct btrfs_super_block *s);
int close_ctree(struct btrfs_root *root, struct btrfs_super_block *s);
void btrfs_block_release(struct btrfs_root *root, struct btrfs_buffer *buf);
-int write_ctree_super(struct btrfs_root *root, struct btrfs_super_block *s);
+int write_ctree_super(struct btrfs_trans_handle *trans, struct btrfs_root *root,
+ struct btrfs_super_block *s);
int mkfs(int fd, u64 num_blocks, u32 blocksize);
#define BTRFS_SUPER_INFO_OFFSET (16 * 1024)
#include "ctree.h"
#include "disk-io.h"
#include "print-tree.h"
+#include "transaction.h"
-static int find_free_extent(struct btrfs_root *orig_root, u64 num_blocks,
- u64 search_start, u64 search_end,
- struct btrfs_key *ins);
-static int finish_current_insert(struct btrfs_root *extent_root);
-static int run_pending(struct btrfs_root *extent_root);
+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);
+static int finish_current_insert(struct btrfs_trans_handle *trans, struct
+ btrfs_root *extent_root);
+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
*/
#define CTREE_EXTENT_PENDING_DEL 0
-static int inc_block_ref(struct btrfs_root *root, u64 blocknr)
+static int inc_block_ref(struct btrfs_trans_handle *trans, struct btrfs_root
+ *root, u64 blocknr)
{
struct btrfs_path path;
int ret;
struct btrfs_key ins;
u32 refs;
- find_free_extent(root->extent_root, 0, 0, (u64)-1, &ins);
+ find_free_extent(trans, root->extent_root, 0, 0, (u64)-1, &ins);
btrfs_init_path(&path);
key.objectid = blocknr;
key.flags = 0;
btrfs_set_key_type(&key, BTRFS_EXTENT_ITEM_KEY);
key.offset = 1;
- ret = btrfs_search_slot(root->extent_root, &key, &path, 0, 1);
+ ret = btrfs_search_slot(trans, root->extent_root, &key, &path, 0, 1);
if (ret != 0)
BUG();
BUG_ON(ret != 0);
BUG_ON(list_empty(&path.nodes[0]->dirty));
btrfs_release_path(root->extent_root, &path);
- finish_current_insert(root->extent_root);
- run_pending(root->extent_root);
+ finish_current_insert(trans, root->extent_root);
+ run_pending(trans, root->extent_root);
return 0;
}
-static int lookup_block_ref(struct btrfs_root *root, u64 blocknr, u32 *refs)
+static int lookup_block_ref(struct btrfs_trans_handle *trans, struct btrfs_root
+ *root, u64 blocknr, u32 *refs)
{
struct btrfs_path path;
int ret;
key.offset = 1;
key.flags = 0;
btrfs_set_key_type(&key, BTRFS_EXTENT_ITEM_KEY);
- ret = btrfs_search_slot(root->extent_root, &key, &path, 0, 0);
+ ret = btrfs_search_slot(trans, root->extent_root, &key, &path, 0, 0);
if (ret != 0)
BUG();
l = &path.nodes[0]->leaf;
return 0;
}
-int btrfs_inc_ref(struct btrfs_root *root, struct btrfs_buffer *buf)
+int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
+ struct btrfs_buffer *buf)
{
u64 blocknr;
int i;
for (i = 0; i < btrfs_header_nritems(&buf->node.header); i++) {
blocknr = btrfs_node_blockptr(&buf->node, i);
- inc_block_ref(root, blocknr);
+ inc_block_ref(trans, root, blocknr);
}
return 0;
}
-int btrfs_finish_extent_commit(struct btrfs_root *root)
+int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans, struct
+ btrfs_root *root)
{
unsigned long gang[8];
u64 first = 0;
return 0;
}
-static int finish_current_insert(struct btrfs_root *extent_root)
+static int finish_current_insert(struct btrfs_trans_handle *trans, struct
+ btrfs_root *extent_root)
{
struct btrfs_key ins;
struct btrfs_extent_item extent_item;
for (i = 0; i < extent_root->current_insert.flags; i++) {
ins.objectid = extent_root->current_insert.objectid + i;
- ret = btrfs_insert_item(extent_root, &ins, &extent_item,
- sizeof(extent_item));
+ ret = btrfs_insert_item(trans, extent_root, &ins, &extent_item,
+ sizeof(extent_item));
BUG_ON(ret);
}
extent_root->current_insert.offset = 0;
/*
* remove an extent from the root, returns 0 on success
*/
-static int __free_extent(struct btrfs_root *root, u64 blocknr, u64 num_blocks,
- int pin)
+static int __free_extent(struct btrfs_trans_handle *trans, struct btrfs_root
+ *root, u64 blocknr, u64 num_blocks, int pin)
{
struct btrfs_path path;
struct btrfs_key key;
btrfs_set_key_type(&key, BTRFS_EXTENT_ITEM_KEY);
key.offset = num_blocks;
- find_free_extent(root, 0, 0, (u64)-1, &ins);
+ find_free_extent(trans, root, 0, 0, (u64)-1, &ins);
btrfs_init_path(&path);
- ret = btrfs_search_slot(extent_root, &key, &path, -1, 1);
+ ret = btrfs_search_slot(trans, extent_root, &key, &path, -1, 1);
if (ret) {
printf("failed to find %Lu\n", key.objectid);
btrfs_print_tree(extent_root, extent_root->node);
BUG_ON(err);
radix_tree_preload_end();
}
- ret = btrfs_del_item(extent_root, &path);
+ ret = btrfs_del_item(trans, extent_root, &path);
if (!pin && extent_root->last_insert.objectid > blocknr)
extent_root->last_insert.objectid = blocknr;
if (ret)
BUG();
}
btrfs_release_path(extent_root, &path);
- finish_current_insert(extent_root);
+ finish_current_insert(trans, extent_root);
return ret;
}
* find all the blocks marked as pending in the radix tree and remove
* them from the extent map
*/
-static int del_pending_extents(struct btrfs_root *extent_root)
+static int del_pending_extents(struct btrfs_trans_handle *trans, struct
+ btrfs_root *extent_root)
{
int ret;
struct btrfs_buffer *gang[4];
if (!ret)
break;
for (i = 0; i < ret; i++) {
- ret = __free_extent(extent_root,
+ ret = __free_extent(trans, extent_root,
gang[i]->blocknr, 1, 1);
radix_tree_tag_clear(&extent_root->cache_radix,
gang[i]->blocknr,
return 0;
}
-static int run_pending(struct btrfs_root *extent_root)
+static int run_pending(struct btrfs_trans_handle *trans, struct btrfs_root
+ *extent_root)
{
while(radix_tree_tagged(&extent_root->cache_radix,
CTREE_EXTENT_PENDING_DEL))
- del_pending_extents(extent_root);
+ del_pending_extents(trans, extent_root);
return 0;
}
/*
* remove an extent from the root, returns 0 on success
*/
-int btrfs_free_extent(struct btrfs_root *root, u64 blocknr, u64 num_blocks,
- int pin)
+int btrfs_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root
+ *root, u64 blocknr, u64 num_blocks, int pin)
{
struct btrfs_root *extent_root = root->extent_root;
struct btrfs_buffer *t;
CTREE_EXTENT_PENDING_DEL);
return 0;
}
- ret = __free_extent(root, blocknr, num_blocks, pin);
- pending_ret = run_pending(root->extent_root);
+ ret = __free_extent(trans, root, blocknr, num_blocks, pin);
+ pending_ret = run_pending(trans, root->extent_root);
return ret ? ret : pending_ret;
}
* ins->offset == number of blocks
* Any available blocks before search_start are skipped.
*/
-static int find_free_extent(struct btrfs_root *orig_root, u64 num_blocks,
- u64 search_start, u64 search_end,
- struct btrfs_key *ins)
+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)
{
struct btrfs_path path;
struct btrfs_key key;
ins->objectid = search_start;
ins->offset = 0;
start_found = 0;
- ret = btrfs_search_slot(root, ins, &path, 0, 0);
+ ret = btrfs_search_slot(trans, root, ins, &path, 0, 0);
if (ret < 0)
goto error;
*
* returns 0 if everything worked, non-zero otherwise.
*/
-static int alloc_extent(struct btrfs_root *root, u64 num_blocks,
- u64 search_start, u64 search_end, u64 owner,
- struct btrfs_key *ins)
+static int alloc_extent(struct btrfs_trans_handle *trans, struct btrfs_root
+ *root, u64 num_blocks, u64 search_start, u64
+ search_end, u64 owner, struct btrfs_key *ins)
{
int ret;
int pending_ret;
extent_root->current_insert.flags++;
return 0;
}
- ret = find_free_extent(root, num_blocks, search_start,
+ ret = find_free_extent(trans, root, num_blocks, search_start,
search_end, ins);
if (ret)
return ret;
- ret = btrfs_insert_item(extent_root, ins, &extent_item,
- sizeof(extent_item));
+ ret = btrfs_insert_item(trans, extent_root, ins, &extent_item,
+ sizeof(extent_item));
- finish_current_insert(extent_root);
- pending_ret = run_pending(extent_root);
+ finish_current_insert(trans, extent_root);
+ pending_ret = run_pending(trans, extent_root);
if (ret)
return ret;
if (pending_ret)
* helper function to allocate a block for a given tree
* returns the tree buffer or NULL.
*/
-struct btrfs_buffer *btrfs_alloc_free_block(struct btrfs_root *root)
+struct btrfs_buffer *btrfs_alloc_free_block(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root)
{
struct btrfs_key ins;
int ret;
struct btrfs_buffer *buf;
- ret = alloc_extent(root, 1, 0, (unsigned long)-1,
+ ret = alloc_extent(trans, root, 1, 0, (unsigned long)-1,
btrfs_header_parentid(&root->node->node.header),
&ins);
if (ret) {
return NULL;
}
buf = find_tree_block(root, ins.objectid);
- dirty_tree_block(root, buf);
+ dirty_tree_block(trans, root, buf);
return buf;
}
* helper function for drop_snapshot, this walks down the tree dropping ref
* counts as it goes.
*/
-static int walk_down_tree(struct btrfs_root *root,
- struct btrfs_path *path, int *level)
+static int walk_down_tree(struct btrfs_trans_handle *trans, struct btrfs_root
+ *root, struct btrfs_path *path, int *level)
{
struct btrfs_buffer *next;
struct btrfs_buffer *cur;
int ret;
u32 refs;
- ret = lookup_block_ref(root, path->nodes[*level]->blocknr, &refs);
+ ret = lookup_block_ref(trans, root, path->nodes[*level]->blocknr,
+ &refs);
BUG_ON(ret);
if (refs > 1)
goto out;
btrfs_header_nritems(&cur->node.header))
break;
blocknr = btrfs_node_blockptr(&cur->node, path->slots[*level]);
- ret = lookup_block_ref(root, blocknr, &refs);
+ ret = lookup_block_ref(trans, root, blocknr, &refs);
if (refs != 1 || *level == 1) {
path->slots[*level]++;
- ret = btrfs_free_extent(root, blocknr, 1, 1);
+ ret = btrfs_free_extent(trans, root, blocknr, 1, 1);
BUG_ON(ret);
continue;
}
path->slots[*level] = 0;
}
out:
- ret = btrfs_free_extent(root, path->nodes[*level]->blocknr, 1, 1);
+ ret = btrfs_free_extent(trans, root, path->nodes[*level]->blocknr, 1,
+ 1);
btrfs_block_release(root, path->nodes[*level]);
path->nodes[*level] = NULL;
*level += 1;
* to find the first node higher up where we haven't yet gone through
* all the slots
*/
-static int walk_up_tree(struct btrfs_root *root, struct btrfs_path *path,
- int *level)
+static int walk_up_tree(struct btrfs_trans_handle *trans, struct btrfs_root
+ *root, struct btrfs_path *path, int *level)
{
int i;
int slot;
*level = i;
return 0;
} else {
- ret = btrfs_free_extent(root,
- path->nodes[*level]->blocknr, 1, 1);
+ ret = btrfs_free_extent(trans, root,
+ path->nodes[*level]->blocknr,
+ 1, 1);
btrfs_block_release(root, path->nodes[*level]);
path->nodes[*level] = NULL;
*level = i + 1;
* the tree freeing any blocks that have a ref count of zero after being
* decremented.
*/
-int btrfs_drop_snapshot(struct btrfs_root *root, struct btrfs_buffer *snap)
+int btrfs_drop_snapshot(struct btrfs_trans_handle *trans, struct btrfs_root
+ *root, struct btrfs_buffer *snap)
{
int ret = 0;
int wret;
path.nodes[level] = snap;
path.slots[level] = 0;
while(1) {
- wret = walk_down_tree(root, &path, &level);
+ wret = walk_down_tree(trans, root, &path, &level);
if (wret > 0)
break;
if (wret < 0)
ret = wret;
- wret = walk_up_tree(root, &path, &level);
+ wret = walk_up_tree(trans, root, &path, &level);
if (wret > 0)
break;
if (wret < 0)
#include "radix-tree.h"
#include "ctree.h"
#include "disk-io.h"
+#include "transaction.h"
-int btrfs_insert_inode(struct btrfs_root *root, u64 objectid,
- struct btrfs_inode_item *inode_item)
+int btrfs_insert_inode(struct btrfs_trans_handle *trans, struct btrfs_root
+ *root, u64 objectid, struct btrfs_inode_item
+ *inode_item)
{
struct btrfs_path path;
struct btrfs_key key;
key.offset = 0;
btrfs_init_path(&path);
- ret = btrfs_insert_item(root, &key, inode_item, sizeof(*inode_item));
+ ret = btrfs_insert_item(trans, root, &key, inode_item,
+ sizeof(*inode_item));
btrfs_release_path(root, &path);
return ret;
}
-int btrfs_lookup_inode(struct btrfs_root *root, struct btrfs_path *path,
- u64 objectid, int mod)
+int btrfs_lookup_inode(struct btrfs_trans_handle *trans, struct btrfs_root
+ *root, struct btrfs_path *path, u64 objectid, int mod)
{
struct btrfs_key key;
int ins_len = mod < 0 ? -1 : 0;
key.flags = 0;
btrfs_set_key_type(&key, BTRFS_INODE_ITEM_KEY);
key.offset = 0;
- return btrfs_search_slot(root, &key, path, ins_len, cow);
+ return btrfs_search_slot(trans, root, &key, path, ins_len, cow);
}
-
+#ifndef __PRINT_TREE_
+#define __PRINT_TREE_
void btrfs_print_leaf(struct btrfs_root *root, struct btrfs_leaf *l);
void btrfs_print_tree(struct btrfs_root *root, struct btrfs_buffer *t);
+#endif
#include "ctree.h"
#include "disk-io.h"
#include "print-tree.h"
+#include "transaction.h"
/* for testing only */
int next_key(int i, int max_key) {
struct btrfs_path path;
struct btrfs_super_block super;
struct btrfs_root *root;
+ struct btrfs_trans_handle *trans;
radix_tree_init();
root = open_ctree("dbfile", &super);
+ trans = btrfs_start_transaction(root, 1);
srand(55);
ins.flags = 0;
btrfs_set_key_type(&ins, BTRFS_STRING_ITEM_KEY);
fprintf(stderr, "insert %d:%d\n", num, i);
ins.objectid = num;
ins.offset = 0;
- ret = btrfs_insert_item(root, &ins, buf, strlen(buf));
+ ret = btrfs_insert_item(trans, root, &ins, buf, strlen(buf));
if (!ret)
tree_size++;
free(buf);
if (i == run_size - 5) {
- btrfs_commit_transaction(root, &super);
+ btrfs_commit_transaction(trans, root, &super);
}
}
btrfs_init_path(&path);
if (i % 10000 == 0)
fprintf(stderr, "search %d:%d\n", num, i);
- ret = btrfs_search_slot(root, &ins, &path, 0, 0);
+ ret = btrfs_search_slot(trans, root, &ins, &path, 0, 0);
if (ret) {
btrfs_print_tree(root, root->node);
printf("unable to find %d\n", num);
num = next_key(i, max_key);
ins.objectid = num;
btrfs_init_path(&path);
- ret = btrfs_search_slot(root, &ins, &path, -1, 1);
+ ret = btrfs_search_slot(trans, root, &ins, &path, -1, 1);
if (!ret) {
if (i % 10000 == 0)
fprintf(stderr, "del %d:%d\n", num, i);
- ret = btrfs_del_item(root, &path);
+ ret = btrfs_del_item(trans, root, &path);
if (ret != 0)
BUG();
tree_size--;
ins.objectid = num;
if (i % 10000 == 0)
fprintf(stderr, "insert %d:%d\n", num, i);
- ret = btrfs_insert_item(root, &ins, buf, strlen(buf));
+ ret = btrfs_insert_item(trans, root, &ins, buf, strlen(buf));
if (!ret)
tree_size++;
free(buf);
btrfs_init_path(&path);
if (i % 10000 == 0)
fprintf(stderr, "search %d:%d\n", num, i);
- ret = btrfs_search_slot(root, &ins, &path, 0, 0);
+ ret = btrfs_search_slot(trans, root, &ins, &path, 0, 0);
if (ret) {
btrfs_print_tree(root, root->node);
printf("unable to find %d\n", num);
int slot;
ins.objectid = (u64)-1;
btrfs_init_path(&path);
- ret = btrfs_search_slot(root, &ins, &path, -1, 1);
+ ret = btrfs_search_slot(trans, root, &ins, &path, -1, 1);
if (ret == 0)
BUG();
btrfs_disk_key_to_cpu(&last, &leaf->items[slot].key);
if (tree_size % 10000 == 0)
printf("big del %d:%d\n", tree_size, i);
- ret = btrfs_del_item(root, &path);
+ ret = btrfs_del_item(trans, root, &path);
if (ret != 0) {
printf("del_item returned %d\n", ret);
BUG();
printf("map before commit\n");
btrfs_print_tree(root->extent_root, root->extent_root->node);
*/
- btrfs_commit_transaction(root, &super);
+ btrfs_commit_transaction(trans, root, &super);
printf("tree size is now %d\n", tree_size);
printf("root %p commit root %p\n", root->node, root->commit_root);
printf("map tree\n");
#include "ctree.h"
#include "disk-io.h"
#include "print-tree.h"
+#include "transaction.h"
int keep_running = 1;
struct btrfs_super_block super;
return 0;
}
-static int ins_one(struct btrfs_root *root, struct radix_tree_root *radix)
+static int ins_one(struct btrfs_trans_handle *trans, struct btrfs_root *root,
+ struct radix_tree_root *radix)
{
struct btrfs_path path;
struct btrfs_key key;
btrfs_init_path(&path);
ret = setup_key(radix, &key, 0);
sprintf(buf, "str-%Lu\n", key.objectid);
- ret = btrfs_insert_item(root, &key, buf, strlen(buf));
+ ret = btrfs_insert_item(trans, root, &key, buf, strlen(buf));
if (ret)
goto error;
oid = (unsigned long)key.objectid;
return -1;
}
-static int insert_dup(struct btrfs_root *root, struct radix_tree_root *radix)
+static int insert_dup(struct btrfs_trans_handle *trans, struct btrfs_root
+ *root, struct radix_tree_root *radix)
{
struct btrfs_path path;
struct btrfs_key key;
if (ret < 0)
return 0;
sprintf(buf, "str-%Lu\n", key.objectid);
- ret = btrfs_insert_item(root, &key, buf, strlen(buf));
+ ret = btrfs_insert_item(trans, root, &key, buf, strlen(buf));
if (ret != -EEXIST) {
printf("insert on %Lu gave us %d\n", key.objectid, ret);
return 1;
return 0;
}
-static int del_one(struct btrfs_root *root, struct radix_tree_root *radix)
+static int del_one(struct btrfs_trans_handle *trans, struct btrfs_root *root,
+ struct radix_tree_root *radix)
{
struct btrfs_path path;
struct btrfs_key key;
ret = setup_key(radix, &key, 1);
if (ret < 0)
return 0;
- ret = btrfs_search_slot(root, &key, &path, -1, 1);
+ ret = btrfs_search_slot(trans, root, &key, &path, -1, 1);
if (ret)
goto error;
- ret = btrfs_del_item(root, &path);
+ ret = btrfs_del_item(trans, root, &path);
btrfs_release_path(root, &path);
if (ret != 0)
goto error;
return -1;
}
-static int lookup_item(struct btrfs_root *root, struct radix_tree_root *radix)
+static int lookup_item(struct btrfs_trans_handle *trans, struct btrfs_root
+ *root, struct radix_tree_root *radix)
{
struct btrfs_path path;
struct btrfs_key key;
ret = setup_key(radix, &key, 1);
if (ret < 0)
return 0;
- ret = btrfs_search_slot(root, &key, &path, 0, 1);
+ ret = btrfs_search_slot(trans, root, &key, &path, 0, 1);
btrfs_release_path(root, &path);
if (ret)
goto error;
return -1;
}
-static int lookup_enoent(struct btrfs_root *root, struct radix_tree_root *radix)
+static int lookup_enoent(struct btrfs_trans_handle *trans, struct btrfs_root
+ *root, struct radix_tree_root *radix)
{
struct btrfs_path path;
struct btrfs_key key;
ret = setup_key(radix, &key, 0);
if (ret < 0)
return ret;
- ret = btrfs_search_slot(root, &key, &path, 0, 0);
+ ret = btrfs_search_slot(trans, root, &key, &path, 0, 0);
btrfs_release_path(root, &path);
if (ret <= 0)
goto error;
return -1;
}
-static int empty_tree(struct btrfs_root *root, struct radix_tree_root *radix,
- int nr)
+static int empty_tree(struct btrfs_trans_handle *trans, struct btrfs_root
+ *root, struct radix_tree_root *radix, int nr)
{
struct btrfs_path path;
struct btrfs_key key;
key.objectid = (unsigned long)-1;
while(nr-- >= 0) {
btrfs_init_path(&path);
- ret = btrfs_search_slot(root, &key, &path, -1, 1);
+ ret = btrfs_search_slot(trans, root, &key, &path, -1, 1);
if (ret < 0) {
btrfs_release_path(root, &path);
return ret;
slot = path.slots[0];
found = btrfs_disk_key_objectid(
&path.nodes[0]->leaf.items[slot].key);
- ret = btrfs_del_item(root, &path);
+ ret = btrfs_del_item(trans, root, &path);
count++;
if (ret) {
fprintf(stderr,
return -1;
}
-static int fill_tree(struct btrfs_root *root, struct radix_tree_root *radix,
- int count)
+static int fill_tree(struct btrfs_trans_handle *trans, struct btrfs_root *root,
+ struct radix_tree_root *radix, int count)
{
int i;
int ret = 0;
for (i = 0; i < count; i++) {
- ret = ins_one(root, radix);
+ ret = ins_one(trans, root, radix);
if (ret) {
fprintf(stderr, "fill failed\n");
goto out;
}
if (i % 1000 == 0) {
- ret = btrfs_commit_transaction(root, &super);
+ ret = btrfs_commit_transaction(trans, root, &super);
if (ret) {
fprintf(stderr, "fill commit failed\n");
return ret;
return ret;
}
-static int bulk_op(struct btrfs_root *root, struct radix_tree_root *radix)
+static int bulk_op(struct btrfs_trans_handle *trans, struct btrfs_root *root,
+ struct radix_tree_root *radix)
{
int ret;
int nr = rand() % 5000;
/* do the bulk op much less frequently */
if (run_nr++ % 100)
return 0;
- ret = empty_tree(root, radix, nr);
+ ret = empty_tree(trans, root, radix, nr);
if (ret)
return ret;
- ret = fill_tree(root, radix, nr);
+ ret = fill_tree(trans, root, radix, nr);
if (ret)
return ret;
return 0;
}
-int (*ops[])(struct btrfs_root *root, struct radix_tree_root *radix) =
+int (*ops[])(struct btrfs_trans_handle *,
+ struct btrfs_root *root, struct radix_tree_root *radix) =
{ ins_one, insert_dup, del_one, lookup_item,
lookup_enoent, bulk_op };
key.objectid = (unsigned long)-1;
while(1) {
btrfs_init_path(&path);
- ret = btrfs_search_slot(root, &key, &path, 0, 0);
+ ret = btrfs_search_slot(NULL, root, &key, &path, 0, 0);
if (ret < 0) {
btrfs_release_path(root, &path);
return ret;
int init_fill_count = 800000;
int err = 0;
int initial_only = 0;
+ struct btrfs_trans_handle *trans;
radix_tree_init();
root = open_ctree("dbfile", &super);
fill_radix(root, &radix);
}
}
printf("initial fill\n");
- ret = fill_tree(root, &radix, init_fill_count);
+ trans = btrfs_start_transaction(root, 1);
+ ret = fill_tree(trans, root, &radix, init_fill_count);
printf("starting run\n");
if (ret) {
err = ret;
root = open_ctree("dbfile", &super);
}
while(count--) {
- ret = ops[op](root, &radix);
+ ret = ops[op](trans, root, &radix);
if (ret) {
fprintf(stderr, "op %d failed %d:%d\n",
op, i, iterations);
search_key.offset = (u32)-1;
btrfs_init_path(&path);
- ret = btrfs_search_slot(root, &search_key, &path, 0, 0);
+ ret = btrfs_search_slot(NULL, root, &search_key, &path, 0, 0);
if (ret < 0)
goto out;
BUG_ON(ret == 0);
return ret;
}
-int btrfs_update_root(struct btrfs_root *root, struct btrfs_key *key,
- struct btrfs_root_item *item)
+int btrfs_update_root(struct btrfs_trans_handle *trans, struct btrfs_root
+ *root, struct btrfs_key *key, struct btrfs_root_item
+ *item)
{
struct btrfs_path path;
struct btrfs_leaf *l;
int slot;
btrfs_init_path(&path);
- ret = btrfs_search_slot(root, key, &path, 0, 1);
+ ret = btrfs_search_slot(trans, root, key, &path, 0, 1);
if (ret < 0)
goto out;
BUG_ON(ret != 0);
return ret;
}
-int btrfs_insert_root(struct btrfs_root *root, struct btrfs_key *key,
- struct btrfs_root_item *item)
+int btrfs_insert_root(struct btrfs_trans_handle *trans, struct btrfs_root
+ *root, struct btrfs_key *key, struct btrfs_root_item
+ *item)
{
int ret;
- ret = btrfs_insert_item(root, key, item, sizeof(*item));
+ ret = btrfs_insert_item(trans, root, key, item, sizeof(*item));
BUG_ON(ret);
return ret;
}
-int btrfs_del_root(struct btrfs_root *root, struct btrfs_key *key)
+int btrfs_del_root(struct btrfs_trans_handle *trans, struct btrfs_root *root,
+ struct btrfs_key *key)
{
struct btrfs_path path;
int ret;
btrfs_init_path(&path);
- ret = btrfs_search_slot(root, key, &path, -1, 1);
+ ret = btrfs_search_slot(trans, root, key, &path, -1, 1);
if (ret < 0)
goto out;
BUG_ON(ret != 0);
- ret = btrfs_del_item(root, &path);
+ ret = btrfs_del_item(trans, root, &path);
out:
btrfs_release_path(root, &path);
return ret;
--- /dev/null
+#ifndef __TRANSACTION__
+#define __TRANSACTION__
+
+struct btrfs_trans_handle {
+ u64 transid;
+ unsigned long blocks_reserved;
+ unsigned long blocks_used;
+};
+
+static inline struct btrfs_trans_handle *
+btrfs_start_transaction(struct btrfs_root *root, int num_blocks)
+{
+ struct btrfs_trans_handle *h = malloc(sizeof(*h));
+ h->transid = root->root_key.offset;
+ h->blocks_reserved = num_blocks;
+ h->blocks_used = 0;
+ return h;
+}
+
+static inline void btrfs_free_transaction(struct btrfs_root *root,
+ struct btrfs_trans_handle *handle)
+{
+ memset(handle, 0, sizeof(*handle));
+ free(handle);
+}
+
+#endif