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;
Chris Mason
2007-Dec-19 05:45 UTC
[Btrfs-devel][PATCH]Update btrfs-progs to handle backrefs
On Wed, 19 Dec 2007 20:37:32 +0800 "Yan Zheng" <yanzheng@21cn.com> wrote:> 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.cGreat, thanks for doing this. For the functions in extent-tree.c that get exported, could you please change their name to start with btrfs_ A few other comments below:> --- a/ctree.h Fri Dec 14 11:00:30 2007 -0500 > +++ b/ctree.h Wed Dec 19 19:52:02 2007 +0800 > @@ -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))))Why switch away from btrfs_item_offset_nr?> > 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; > }This code is buggy (even before your changes ;). A new transaction should be started to drop the snapshot and delete the old root. -chris