[Btrfs-devel][PATCH]Update btrfs-progs to handle backrefs
Yan Zheng
yanzheng at 21cn.com
Wed Dec 19 04:37:32 PST 2007
Hello,
This patch updates btrfs-progs according to kernel module's code. It
updates btrfs-progs to properly handle back reference and exports some
functions in extent-tree.c
Regards
YZ
----
diff -r a1a37f51dcb2 ctree.c
--- a/ctree.c Fri Dec 14 11:00:30 2007 -0500
+++ b/ctree.c Wed Dec 19 19:52:02 2007 +0800
@@ -53,10 +53,10 @@ void btrfs_release_path(struct btrfs_roo
}
memset(p, 0, sizeof(*p));
}
+
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)
+ *root, struct btrfs_buffer *buf, struct btrfs_buffer
+ *parent, int parent_slot, struct btrfs_buffer **cow_ret)
{
struct btrfs_buffer *cow;
u64 root_gen;
diff -r a1a37f51dcb2 ctree.h
--- a/ctree.h Fri Dec 14 11:00:30 2007 -0500
+++ b/ctree.h Wed Dec 19 19:52:02 2007 +0800
@@ -432,8 +432,8 @@ BTRFS_SETGET_STACK_FUNCS(inode_compat_fl
BTRFS_SETGET_STACK_FUNCS(inode_compat_flags, struct btrfs_inode_item,
compat_flags, 16);
-BTRFS_SETGET_STACK_FUNCS(timpsec_sec, struct btrfs_inode_timespec, sec, 64);
-BTRFS_SETGET_STACK_FUNCS(timpsec_nsec, struct btrfs_inode_timespec, nsec, 32);
+BTRFS_SETGET_STACK_FUNCS(timespec_sec, struct btrfs_inode_timespec, sec, 64);
+BTRFS_SETGET_STACK_FUNCS(timespec_nsec, struct btrfs_inode_timespec, nsec, 32);
BTRFS_SETGET_STACK_FUNCS(extent_refs, struct btrfs_extent_item, refs, 32);
BTRFS_SETGET_STACK_FUNCS(inode_ref_name_len, struct btrfs_inode_ref,
@@ -607,7 +607,7 @@ BTRFS_SETGET_STACK_FUNCS(file_extent_num
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)))
+ btrfs_item_offset((leaf)->items + (slot))))
static inline u32 btrfs_level_size(struct btrfs_root *root, int level)
{
@@ -616,9 +616,28 @@ static inline u32 btrfs_level_size(struc
return root->nodesize;
}
int btrfs_comp_keys(struct btrfs_disk_key *disk, struct btrfs_key *k2);
+int update_block_group(struct btrfs_trans_handle *trans, struct btrfs_root
+ *root, u64 bytenr, u64 num, int alloc);
+int btrfs_extent_post_op(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root);
struct btrfs_buffer *btrfs_alloc_free_block(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
u32 blocksize);
+u64 hash_extent_ref(u64 root_objectid, u64 ref_generation, u64 owner,
+ u64 owner_offset);
+int lookup_extent_backref(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root, struct btrfs_path *path,
+ u64 bytenr, u64 root_objectid, u64 ref_generation,
+ u64 owner, u64 owner_offset, int del);
+int insert_extent_backref(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root, struct btrfs_path *path,
+ u64 bytenr, u64 root_objectid, u64 ref_generation,
+ u64 owner, u64 owner_offset);
+int lookup_block_ref(struct btrfs_trans_handle *trans, struct btrfs_root
+ *root, u64 bytenr, u32 blocksize, u32 *refs);
+int inc_block_ref(struct btrfs_trans_handle *trans, struct btrfs_root
+ *root, u64 bytenr, u32 blocksize, u64 root_objectid,
+ u64 ref_generation, u64 owner, u64 owner_offset);
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,
diff -r a1a37f51dcb2 disk-io.c
--- a/disk-io.c Fri Dec 14 11:00:30 2007 -0500
+++ b/disk-io.c Wed Dec 19 19:52:02 2007 +0800
@@ -298,12 +298,13 @@ int btrfs_commit_transaction(struct btrf
btrfs_finish_extent_commit(trans, root->fs_info->extent_root);
btrfs_finish_extent_commit(trans, root->fs_info->tree_root);
+ 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->commit_root = root->node;
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);
btrfs_free_transaction(root, trans);
return ret;
}
diff -r a1a37f51dcb2 extent-tree.c
--- a/extent-tree.c Fri Dec 14 11:00:30 2007 -0500
+++ b/extent-tree.c Wed Dec 19 19:52:02 2007 +0800
@@ -31,8 +31,8 @@ static int run_pending(struct btrfs_tran
static int run_pending(struct btrfs_trans_handle *trans, struct btrfs_root
*extent_root);
-static u64 hash_extent_ref(u64 root_objectid, u64 ref_generation,
- u64 owner, u64 owner_offset)
+u64 hash_extent_ref(u64 root_objectid, u64 ref_generation,
+ u64 owner, u64 owner_offset)
{
u32 high_crc = ~(u32)0;
u32 low_crc = ~(u32)0;
@@ -55,15 +55,22 @@ static int match_extent_ref(struct btrfs
static int match_extent_ref(struct btrfs_extent_ref *disk_ref,
struct btrfs_extent_ref *cpu_ref)
{
- int ret = memcmp(cpu_ref, disk_ref, sizeof(*cpu_ref));
+ int ret;
+ int len;
+
+ if (cpu_ref->objectid)
+ len = sizeof(*cpu_ref);
+ else
+ len = 2 * sizeof(u64);
+ ret = memcmp(cpu_ref, disk_ref, len);
return ret == 0;
}
-static int lookup_extent_backref(struct btrfs_trans_handle *trans,
- struct btrfs_root *root,
- struct btrfs_path *path, u64 bytenr,
- u64 root_objectid, u64 ref_generation,
- u64 owner, u64 owner_offset, int del)
+int lookup_extent_backref(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root,
+ struct btrfs_path *path, u64 bytenr,
+ u64 root_objectid, u64 ref_generation,
+ u64 owner, u64 owner_offset, int del)
{
u64 hash;
struct btrfs_key key;
@@ -126,11 +133,11 @@ out:
return ret;
}
-static int insert_extent_backref(struct btrfs_trans_handle *trans,
- struct btrfs_root *root,
- struct btrfs_path *path, u64 bytenr,
- u64 root_objectid, u64 ref_generation,
- u64 owner, u64 owner_offset)
+int insert_extent_backref(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root,
+ struct btrfs_path *path, u64 bytenr,
+ u64 root_objectid, u64 ref_generation,
+ u64 owner, u64 owner_offset)
{
u64 hash;
struct btrfs_key key;
@@ -156,6 +163,7 @@ static int insert_extent_backref(struct
if (match_extent_ref(disk_ref, &ref))
goto out;
key.offset++;
+ btrfs_release_path(root, path);
ret = btrfs_insert_empty_item(trans, root, path, &key,
sizeof(ref));
}
@@ -164,16 +172,16 @@ static int insert_extent_backref(struct
disk_ref = btrfs_item_ptr(&path->nodes[0]->leaf, path->slots[0],
struct btrfs_extent_ref);
memcpy(disk_ref, &ref, sizeof(ref));
- dirty_tree_block(trans, root, path->nodes[0]);
+ BUG_ON(list_empty(&path->nodes[0]->dirty));
out:
btrfs_release_path(root, path);
return ret;
}
-static int inc_block_ref(struct btrfs_trans_handle *trans, struct btrfs_root
- *root, u64 bytenr, u32 blocksize,
- u64 root_objectid, u64 ref_generation,
- u64 owner, u64 owner_offset)
+int inc_block_ref(struct btrfs_trans_handle *trans, struct btrfs_root
+ *root, u64 bytenr, u32 blocksize,
+ u64 root_objectid, u64 ref_generation,
+ u64 owner, u64 owner_offset)
{
struct btrfs_path path;
int ret;
@@ -209,8 +217,8 @@ static int inc_block_ref(struct btrfs_tr
return 0;
}
-static int lookup_block_ref(struct btrfs_trans_handle *trans, struct btrfs_root
- *root, u64 bytenr, u32 blocksize, u32 *refs)
+int lookup_block_ref(struct btrfs_trans_handle *trans, struct btrfs_root
+ *root, u64 bytenr, u32 blocksize, u32 *refs)
{
struct btrfs_path path;
int ret;
@@ -226,38 +234,66 @@ static int lookup_block_ref(struct btrfs
ret = btrfs_search_slot(trans, root->fs_info->extent_root, &key, &path,
0, 0);
if (ret != 0)
- BUG();
+ goto out;
l = &path.nodes[0]->leaf;
item = btrfs_item_ptr(l, path.slots[0], struct btrfs_extent_item);
*refs = btrfs_extent_refs(item);
+out:
btrfs_release_path(root->fs_info->extent_root, &path);
- return 0;
+ return ret;
}
int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
struct btrfs_buffer *buf)
{
u64 bytenr;
- u32 blocksize;
+ u32 nritems;
+ struct btrfs_key key;
+ struct btrfs_file_extent_item *fi;
int i;
int level;
+ int ret;
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, blocksize,
- root->root_key.objectid, trans->transid, 0, 0);
- }
-
- return 0;
+ level = btrfs_header_level(&buf->node.header);
+ nritems = btrfs_header_nritems(&buf->node.header);
+ for (i = 0; i < nritems; i++) {
+ if (level == 0) {
+ u64 disk_bytenr;
+ btrfs_disk_key_to_cpu(&key, &buf->leaf.items[i].key);
+ if (btrfs_key_type(&key) != BTRFS_EXTENT_DATA_KEY)
+ continue;
+ fi = btrfs_item_ptr(&buf->leaf, i,
+ struct btrfs_file_extent_item);
+ if (btrfs_file_extent_type(fi) ==
+ BTRFS_FILE_EXTENT_INLINE)
+ continue;
+ disk_bytenr = btrfs_file_extent_disk_bytenr(fi);
+ if (disk_bytenr == 0)
+ continue;
+ ret = inc_block_ref(trans, root, disk_bytenr,
+ btrfs_file_extent_disk_num_bytes(fi),
+ root->root_key.objectid, trans->transid,
+ key.objectid, key.offset);
+ if (ret)
+ goto fail;
+ } else {
+ btrfs_disk_key_to_cpu(&key, &buf->node.ptrs[i].key);
+ bytenr = btrfs_node_blockptr(&buf->node, i);
+ ret = inc_block_ref(trans, root, bytenr,
+ btrfs_level_size(root, level - 1),
+ root->root_key.objectid, trans->transid,
+ level - 1, key.objectid);
+ if (ret)
+ goto fail;
+ }
+ }
+ return 0;
+fail:
+ BUG();
+ return ret;
}
int btrfs_inc_root_ref(struct btrfs_trans_handle *trans,
@@ -326,9 +362,9 @@ int btrfs_write_dirty_block_groups(struc
return werr;
}
-static int update_block_group(struct btrfs_trans_handle *trans,
- struct btrfs_root *root,
- u64 bytenr, u64 num, int alloc)
+int update_block_group(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root,
+ u64 bytenr, u64 num, int alloc)
{
struct btrfs_block_group_cache *bg;
struct cache_extent *cache;
@@ -388,12 +424,15 @@ static int finish_current_insert(struct
{
struct btrfs_key ins;
struct btrfs_extent_item extent_item;
- int ret;
struct btrfs_fs_info *info = extent_root->fs_info;
+ struct btrfs_buffer *buf;
struct cache_extent *pe;
struct cache_extent *next;
struct cache_tree *pending_tree = &info->pending_tree;
+ struct btrfs_disk_key *first_key;
struct btrfs_path path;
+ int ret;
+ int level;
btrfs_init_path(&path);
btrfs_set_extent_refs(&extent_item, 1);
@@ -419,10 +458,18 @@ static int finish_current_insert(struct
}
BUG_ON(ret);
- ret = insert_extent_backref(trans, extent_root, &path,
- ins.objectid,
- extent_root->root_key.objectid,
- 0, 0, 0);
+ buf = read_tree_block(extent_root, ins.objectid, ins.offset);
+ level = btrfs_header_level(&buf->node.header);
+ if (level == 0) {
+ first_key = &buf->leaf.items[0].key;
+ } else {
+ first_key = &buf->node.ptrs[0].key;
+ }
+
+ ret = insert_extent_backref(trans, extent_root, &path,
+ ins.objectid, extent_root->root_key.objectid,
+ 0, level, btrfs_disk_key_objectid(first_key));
+ btrfs_block_release(extent_root, buf);
BUG_ON(ret);
}
return 0;
@@ -490,11 +537,10 @@ static int __free_extent(struct btrfs_tr
root_bytes_used - num_bytes);
ret = btrfs_del_item(trans, extent_root, &path);
+ BUG_ON(ret);
if (!pin && extent_root->fs_info->last_insert.objectid >
bytenr)
extent_root->fs_info->last_insert.objectid = bytenr;
- if (ret)
- BUG();
ret = update_block_group(trans, root, bytenr, num_bytes, 0);
BUG_ON(ret);
}
@@ -539,6 +585,13 @@ static int run_pending(struct btrfs_tran
return 0;
}
+int btrfs_extent_post_op(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root)
+{
+ finish_current_insert(trans, root->fs_info->extent_root);
+ del_pending_extents(trans, root->fs_info->extent_root);
+ return 0;
+}
/*
* remove an extent from the root, returns 0 on success
@@ -711,6 +764,7 @@ static int alloc_extent(struct btrfs_tra
ret = find_free_extent(trans, root, num_bytes, search_start,
search_end, ins);
+ BUG_ON(ret);
if (ret)
return ret;
@@ -777,8 +831,45 @@ struct btrfs_buffer *btrfs_alloc_free_bl
memcpy(buf->node.header.fsid, root->fs_info->disk_super->fsid,
sizeof(buf->node.header.fsid));
dirty_tree_block(trans, root, buf);
+ trans->blocks_used++;
return buf;
-
+}
+
+static int drop_leaf_ref(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root, struct btrfs_buffer *buf)
+{
+ u64 leaf_owner;
+ u64 leaf_generation;
+ struct btrfs_key key;
+ struct btrfs_leaf *leaf = &buf->leaf;
+ struct btrfs_file_extent_item *fi;
+ int i;
+ int nritems;
+ int ret;
+
+ nritems = btrfs_header_nritems(&leaf->header);
+ leaf_owner = btrfs_header_owner(&leaf->header);
+ leaf_generation = btrfs_header_generation(&leaf->header);
+
+ for (i = 0; i < nritems; i++) {
+ u64 disk_bytenr;
+
+ btrfs_disk_key_to_cpu(&key, &leaf->items[i].key);
+ if (btrfs_key_type(&key) != BTRFS_EXTENT_DATA_KEY)
+ continue;
+ fi = btrfs_item_ptr(leaf, i, struct btrfs_file_extent_item);
+ if (btrfs_file_extent_type(fi) == BTRFS_FILE_EXTENT_INLINE)
+ continue;
+ disk_bytenr = btrfs_file_extent_disk_bytenr(fi);
+ if (disk_bytenr == 0)
+ continue;
+ ret = btrfs_free_extent(trans, root, disk_bytenr,
+ btrfs_file_extent_disk_num_bytes(fi),
+ leaf_owner, leaf_generation,
+ key.objectid, key.offset, 0);
+ BUG_ON(ret);
+ }
+ return 0;
}
/*
@@ -805,16 +896,22 @@ static int walk_down_tree(struct btrfs_t
/*
* walk down to the last node level and free all the leaves
*/
- while(*level > 0) {
+ while(*level >= 0) {
u32 size = btrfs_level_size(root, *level - 1);
cur = path->nodes[*level];
if (path->slots[*level] >=
btrfs_header_nritems(&cur->node.header))
break;
+ if (*level == 0) {
+ ret = drop_leaf_ref(trans, root, cur);
+ BUG_ON(ret);
+ break;
+ }
bytenr = btrfs_node_blockptr(&cur->node, path->slots[*level]);
ret = lookup_block_ref(trans, root, bytenr, size, &refs);
- if (refs != 1 || *level == 1) {
+ BUG_ON(ret);
+ if (refs != 1) {
parent = path->nodes[*level];
root_owner = btrfs_header_owner(&parent->node.header);
root_gen =
@@ -834,12 +931,14 @@ static int walk_down_tree(struct btrfs_t
path->slots[*level] = 0;
}
out:
- if (*level == BTRFS_MAX_LEVEL - 1 || !path->nodes[*level + 1])
+ if (path->nodes[*level] == root->commit_root) {
+ root_owner = root->root_key.objectid;
parent = path->nodes[*level];
- else
+ } else {
parent = path->nodes[*level + 1];
-
- root_owner = btrfs_header_owner(&parent->node.header);
+ root_owner = btrfs_header_owner(&parent->node.header);
+ }
+
root_gen = btrfs_header_generation(&parent->node.header);
ret = btrfs_free_extent(trans, root, path->nodes[*level]->bytenr,
btrfs_level_size(root, *level),
@@ -864,7 +963,7 @@ static int walk_up_tree(struct btrfs_tra
int ret;
u64 root_owner;
u64 root_gen;
- struct btrfs_buffer *parent;
+ struct btrfs_node *node;
for(i = *level; i < BTRFS_MAX_LEVEL - 1 && path->nodes[i]; i++) {
slot = path->slots[i];
if (slot <
@@ -873,14 +972,14 @@ static int walk_up_tree(struct btrfs_tra
*level = i;
return 0;
} else {
- if (path->nodes[*level] == root->node)
- parent = path->nodes[*level];
- else
- parent = path->nodes[*level + 1];
-
- root_owner = btrfs_header_owner(&parent->node.header);
- root_gen =
- btrfs_header_generation(&parent->node.header);
+ if (path->nodes[*level] == root->commit_root) {
+ node = &path->nodes[*level]->node;
+ root_owner = root->root_key.objectid;
+ } else {
+ node = &path->nodes[*level + 1]->node;
+ root_owner = btrfs_header_owner(&node->header);
+ }
+ root_gen = btrfs_header_generation(&node->header);
ret = btrfs_free_extent(trans, root,
path->nodes[*level]->bytenr,
btrfs_level_size(root, *level),
diff -r a1a37f51dcb2 inode-item.c
--- a/inode-item.c Fri Dec 14 11:00:30 2007 -0500
+++ b/inode-item.c Wed Dec 19 19:52:02 2007 +0800
@@ -24,6 +24,35 @@
#include "disk-io.h"
#include "transaction.h"
+int find_name_in_backref(struct btrfs_path *path, const char * name,
+ int name_len, struct btrfs_inode_ref **ref_ret)
+{
+ struct btrfs_leaf *leaf;
+ struct btrfs_inode_ref *ref;
+ char *ptr;
+ char *name_ptr;
+ u32 item_size;
+ u32 cur_offset = 0;
+ int len;
+
+ leaf = &path->nodes[0]->leaf;
+ item_size = btrfs_item_size(leaf->items + path->slots[0]);
+ ptr = btrfs_item_ptr(leaf, path->slots[0], char);
+ while (cur_offset < item_size) {
+ ref = (struct btrfs_inode_ref *)(ptr + cur_offset);
+ len = btrfs_inode_ref_name_len(ref);
+ name_ptr = (char *)(ref + 1);
+ cur_offset += len + sizeof(*ref);
+ if (len != name_len)
+ continue;
+ if (memcmp(name, name_ptr, name_len) == 0) {
+ *ref_ret = ref;
+ return 1;
+ }
+ }
+ return 0;
+}
+
int btrfs_insert_inode_ref(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
const char *name, int name_len,
@@ -31,6 +60,7 @@ int btrfs_insert_inode_ref(struct btrfs_
{
struct btrfs_path path;
struct btrfs_key key;
+ struct btrfs_leaf *leaf;
struct btrfs_inode_ref *ref;
char *ptr;
int ret;
@@ -44,23 +74,21 @@ int btrfs_insert_inode_ref(struct btrfs_
ret = btrfs_insert_empty_item(trans, root, &path, &key,
ins_len);
if (ret == -EEXIST) {
-#if 0
u32 old_size;
- if (find_name_in_backref(path, name, name_len, &ref))
+ if (find_name_in_backref(&path, name, name_len, &ref))
goto out;
- old_size = btrfs_item_size_nr(path->nodes[0], path->slots[0]);
- ret = btrfs_extend_item(trans, root, path, ins_len);
+ leaf = &path.nodes[0]->leaf;
+ old_size = btrfs_item_size(leaf->items + path.slots[0]);
+ ret = btrfs_extend_item(trans, root, &path, ins_len);
BUG_ON(ret);
- ref = btrfs_item_ptr(path->nodes[0], path->slots[0],
+ ref = btrfs_item_ptr(leaf, path.slots[0],
struct btrfs_inode_ref);
ref = (struct btrfs_inode_ref *)((unsigned long)ref + old_size);
- btrfs_set_inode_ref_name_len(path->nodes[0], ref, name_len);
- ptr = (unsigned long)(ref + 1);
+ btrfs_set_inode_ref_name_len(ref, name_len);
+ ptr = (char *)(ref + 1);
ret = 0;
-#endif
- goto out;
} else if (ret < 0) {
goto out;
} else {
@@ -70,8 +98,7 @@ int btrfs_insert_inode_ref(struct btrfs_
ptr = (char *)(ref + 1);
}
memcpy(ptr, name, name_len);
- dirty_tree_block(trans, root, path.nodes[0]);
-
+ BUG_ON(list_empty(&path.nodes[0]->dirty));
out:
btrfs_release_path(root, &path);
return ret;
More information about the Btrfs-devel
mailing list