diff --git a/fs/btrfs/backref.c b/fs/btrfs/backref.c index 297f33850425..4cda81964dd4 100644 --- a/fs/btrfs/backref.c +++ b/fs/btrfs/backref.c @@ -18,6 +18,7 @@ #include #include +#include #include "ctree.h" #include "disk-io.h" #include "backref.h" @@ -120,20 +121,6 @@ static int find_extent_in_eb(const struct extent_buffer *eb, return 0; } -/* - * this structure records all encountered refs on the way up to the root - */ -struct prelim_ref { - struct rb_node rbnode; - u64 root_id; - struct btrfs_key key_for_search; - int level; - int count; - struct extent_inode_elem *inode_list; - u64 parent; - u64 wanted_disk_byte; -}; - struct preftree { struct rb_root root; unsigned int count; @@ -212,7 +199,8 @@ static int prelim_ref_compare(struct prelim_ref *ref1, * * Callers should assumed that newref has been freed after calling. */ -static void prelim_ref_insert(struct preftree *preftree, +static void prelim_ref_insert(const struct btrfs_fs_info *fs_info, + struct preftree *preftree, struct prelim_ref *newref) { struct rb_root *root; @@ -243,6 +231,8 @@ static void prelim_ref_insert(struct preftree *preftree, ref->inode_list = newref->inode_list; else eie->next = newref->inode_list; + trace_btrfs_prelim_ref_merge(fs_info, ref, newref, + preftree->count); ref->count += newref->count; free_pref(newref); return; @@ -250,6 +240,7 @@ static void prelim_ref_insert(struct preftree *preftree, } preftree->count++; + trace_btrfs_prelim_ref_insert(fs_info, newref, NULL, preftree->count); rb_link_node(&newref->rbnode, parent, p); rb_insert_color(&newref->rbnode, root); } @@ -308,7 +299,8 @@ static void prelim_release(struct preftree *preftree) * additional information that's available but not required to find the parent * block might help in merging entries to gain some speed. */ -static int add_prelim_ref(struct preftree *preftree, u64 root_id, +static int add_prelim_ref(const struct btrfs_fs_info *fs_info, + struct preftree *preftree, u64 root_id, const struct btrfs_key *key, int level, u64 parent, u64 wanted_disk_byte, int count, gfp_t gfp_mask) { @@ -355,21 +347,23 @@ static int add_prelim_ref(struct preftree *preftree, u64 root_id, ref->count = count; ref->parent = parent; ref->wanted_disk_byte = wanted_disk_byte; - prelim_ref_insert(preftree, ref); + prelim_ref_insert(fs_info, preftree, ref); return 0; } /* direct refs use root == 0, key == NULL */ -static int add_direct_ref(struct preftrees *preftrees, int level, u64 parent, +static int add_direct_ref(const struct btrfs_fs_info *fs_info, + struct preftrees *preftrees, int level, u64 parent, u64 wanted_disk_byte, int count, gfp_t gfp_mask) { - return add_prelim_ref(&preftrees->direct, 0, NULL, level, parent, - wanted_disk_byte, count, gfp_mask); + return add_prelim_ref(fs_info, &preftrees->direct, 0, NULL, level, + parent, wanted_disk_byte, count, gfp_mask); } /* indirect refs use parent == 0 */ -static int add_indirect_ref(struct preftrees *preftrees, u64 root_id, +static int add_indirect_ref(const struct btrfs_fs_info *fs_info, + struct preftrees *preftrees, u64 root_id, const struct btrfs_key *key, int level, u64 wanted_disk_byte, int count, gfp_t gfp_mask) { @@ -377,7 +371,7 @@ static int add_indirect_ref(struct preftrees *preftrees, u64 root_id, if (!key) tree = &preftrees->indirect_missing_keys; - return add_prelim_ref(tree, root_id, key, level, 0, + return add_prelim_ref(fs_info, tree, root_id, key, level, 0, wanted_disk_byte, count, gfp_mask); } @@ -631,7 +625,7 @@ static int resolve_indirect_refs(struct btrfs_fs_info *fs_info, * and return directly. */ if (err == -ENOENT) { - prelim_ref_insert(&preftrees->direct, ref); + prelim_ref_insert(fs_info, &preftrees->direct, ref); continue; } else if (err) { free_pref(ref); @@ -659,11 +653,11 @@ static int resolve_indirect_refs(struct btrfs_fs_info *fs_info, memcpy(new_ref, ref, sizeof(*ref)); new_ref->parent = node->val; new_ref->inode_list = unode_aux_to_inode_list(node); - prelim_ref_insert(&preftrees->direct, new_ref); + prelim_ref_insert(fs_info, &preftrees->direct, new_ref); } /* Now it's a direct ref, put it in the the direct tree */ - prelim_ref_insert(&preftrees->direct, ref); + prelim_ref_insert(fs_info, &preftrees->direct, ref); ulist_reinit(parents); } @@ -707,7 +701,7 @@ static int add_missing_keys(struct btrfs_fs_info *fs_info, btrfs_node_key_to_cpu(eb, &ref->key_for_search, 0); btrfs_tree_read_unlock(eb); free_extent_buffer(eb); - prelim_ref_insert(&preftrees->indirect, ref); + prelim_ref_insert(fs_info, &preftrees->indirect, ref); } return 0; } @@ -716,7 +710,8 @@ static int add_missing_keys(struct btrfs_fs_info *fs_info, * add all currently queued delayed refs from this head whose seq nr is * smaller or equal that seq to the list */ -static int add_delayed_refs(struct btrfs_delayed_ref_head *head, u64 seq, +static int add_delayed_refs(const struct btrfs_fs_info *fs_info, + struct btrfs_delayed_ref_head *head, u64 seq, struct preftrees *preftrees, u64 *total_refs, u64 inum) { @@ -759,8 +754,9 @@ static int add_delayed_refs(struct btrfs_delayed_ref_head *head, u64 seq, struct btrfs_delayed_tree_ref *ref; ref = btrfs_delayed_node_to_tree_ref(node); - ret = add_indirect_ref(preftrees, ref->root, &tmp_op_key, - ref->level + 1, node->bytenr, + ret = add_indirect_ref(fs_info, preftrees, ref->root, + &tmp_op_key, ref->level + 1, + node->bytenr, node->ref_mod * sgn, GFP_ATOMIC); break; @@ -771,9 +767,9 @@ static int add_delayed_refs(struct btrfs_delayed_ref_head *head, u64 seq, ref = btrfs_delayed_node_to_tree_ref(node); - ret = add_direct_ref(preftrees, ref->level + 1, - ref->parent, node->bytenr, - node->ref_mod * sgn, + ret = add_direct_ref(fs_info, preftrees, + ref->level + 1, ref->parent, + node->bytenr, node->ref_mod * sgn, GFP_ATOMIC); break; } @@ -795,8 +791,8 @@ static int add_delayed_refs(struct btrfs_delayed_ref_head *head, u64 seq, break; } - ret = add_indirect_ref(preftrees, ref->root, &key, 0, - node->bytenr, + ret = add_indirect_ref(fs_info, preftrees, ref->root, + &key, 0, node->bytenr, node->ref_mod * sgn, GFP_ATOMIC); break; @@ -807,8 +803,8 @@ static int add_delayed_refs(struct btrfs_delayed_ref_head *head, u64 seq, ref = btrfs_delayed_node_to_data_ref(node); - ret = add_direct_ref(preftrees, 0, ref->parent, - node->bytenr, + ret = add_direct_ref(fs_info, preftrees, 0, + ref->parent, node->bytenr, node->ref_mod * sgn, GFP_ATOMIC); break; @@ -826,7 +822,8 @@ static int add_delayed_refs(struct btrfs_delayed_ref_head *head, u64 seq, /* * add all inline backrefs for bytenr to the list */ -static int add_inline_refs(struct btrfs_path *path, u64 bytenr, +static int add_inline_refs(const struct btrfs_fs_info *fs_info, + struct btrfs_path *path, u64 bytenr, int *info_level, struct preftrees *preftrees, u64 *total_refs, u64 inum) { @@ -883,7 +880,8 @@ static int add_inline_refs(struct btrfs_path *path, u64 bytenr, switch (type) { case BTRFS_SHARED_BLOCK_REF_KEY: - ret = add_direct_ref(preftrees, *info_level + 1, offset, + ret = add_direct_ref(fs_info, preftrees, + *info_level + 1, offset, bytenr, 1, GFP_NOFS); break; case BTRFS_SHARED_DATA_REF_KEY: { @@ -893,14 +891,14 @@ static int add_inline_refs(struct btrfs_path *path, u64 bytenr, sdref = (struct btrfs_shared_data_ref *)(iref + 1); count = btrfs_shared_data_ref_count(leaf, sdref); - ret = add_direct_ref(preftrees, 0, offset, + ret = add_direct_ref(fs_info, preftrees, 0, offset, bytenr, count, GFP_NOFS); break; } case BTRFS_TREE_BLOCK_REF_KEY: - ret = add_indirect_ref(preftrees, offset, NULL, - *info_level + 1, bytenr, 1, - GFP_NOFS); + ret = add_indirect_ref(fs_info, preftrees, offset, + NULL, *info_level + 1, + bytenr, 1, GFP_NOFS); break; case BTRFS_EXTENT_DATA_REF_KEY: { struct btrfs_extent_data_ref *dref; @@ -921,8 +919,9 @@ static int add_inline_refs(struct btrfs_path *path, u64 bytenr, root = btrfs_extent_data_ref_root(leaf, dref); - ret = add_indirect_ref(preftrees, root, &key, 0, bytenr, - count, GFP_NOFS); + ret = add_indirect_ref(fs_info, preftrees, root, + &key, 0, bytenr, count, + GFP_NOFS); break; } default: @@ -973,9 +972,9 @@ static int add_keyed_refs(struct btrfs_fs_info *fs_info, switch (key.type) { case BTRFS_SHARED_BLOCK_REF_KEY: /* SHARED DIRECT METADATA backref */ - ret = add_direct_ref(preftrees, info_level + 1, - key.offset, bytenr, 1, - GFP_NOFS); + ret = add_direct_ref(fs_info, preftrees, + info_level + 1, key.offset, + bytenr, 1, GFP_NOFS); break; case BTRFS_SHARED_DATA_REF_KEY: { /* SHARED DIRECT FULL backref */ @@ -985,15 +984,16 @@ static int add_keyed_refs(struct btrfs_fs_info *fs_info, sdref = btrfs_item_ptr(leaf, slot, struct btrfs_shared_data_ref); count = btrfs_shared_data_ref_count(leaf, sdref); - ret = add_direct_ref(preftrees, 0, key.offset, bytenr, - count, GFP_NOFS); + ret = add_direct_ref(fs_info, preftrees, 0, + key.offset, bytenr, count, + GFP_NOFS); break; } case BTRFS_TREE_BLOCK_REF_KEY: /* NORMAL INDIRECT METADATA backref */ - ret = add_indirect_ref(preftrees, key.offset, NULL, - info_level + 1, bytenr, 1, - GFP_NOFS); + ret = add_indirect_ref(fs_info, preftrees, key.offset, + NULL, info_level + 1, bytenr, + 1, GFP_NOFS); break; case BTRFS_EXTENT_DATA_REF_KEY: { /* NORMAL INDIRECT DATA backref */ @@ -1015,8 +1015,9 @@ static int add_keyed_refs(struct btrfs_fs_info *fs_info, } root = btrfs_extent_data_ref_root(leaf, dref); - ret = add_indirect_ref(preftrees, root, &key, 0, bytenr, - count, GFP_NOFS); + ret = add_indirect_ref(fs_info, preftrees, root, + &key, 0, bytenr, count, + GFP_NOFS); break; } default: @@ -1129,8 +1130,8 @@ again: goto again; } spin_unlock(&delayed_refs->lock); - ret = add_delayed_refs(head, time_seq, &preftrees, - &total_refs, inum); + ret = add_delayed_refs(fs_info, head, time_seq, + &preftrees, &total_refs, inum); mutex_unlock(&head->mutex); if (ret) goto out; @@ -1150,8 +1151,9 @@ again: if (key.objectid == bytenr && (key.type == BTRFS_EXTENT_ITEM_KEY || key.type == BTRFS_METADATA_ITEM_KEY)) { - ret = add_inline_refs(path, bytenr, &info_level, - &preftrees, &total_refs, inum); + ret = add_inline_refs(fs_info, path, bytenr, + &info_level, &preftrees, + &total_refs, inum); if (ret) goto out; ret = add_keyed_refs(fs_info, path, bytenr, info_level, diff --git a/fs/btrfs/backref.h b/fs/btrfs/backref.h index f9428aaaa77a..e410335841aa 100644 --- a/fs/btrfs/backref.h +++ b/fs/btrfs/backref.h @@ -72,4 +72,16 @@ int btrfs_check_shared(struct btrfs_root *root, u64 inum, u64 bytenr); int __init btrfs_prelim_ref_init(void); void btrfs_prelim_ref_exit(void); + +struct prelim_ref { + struct rb_node rbnode; + u64 root_id; + struct btrfs_key key_for_search; + int level; + int count; + struct extent_inode_elem *inode_list; + u64 parent; + u64 wanted_disk_byte; +}; + #endif diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index 12540b6104b5..58650f2e0f17 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c @@ -61,6 +61,7 @@ #include "tests/btrfs-tests.h" #include "qgroup.h" +#include "backref.h" #define CREATE_TRACE_POINTS #include diff --git a/include/trace/events/btrfs.h b/include/trace/events/btrfs.h index 42560feb9920..90d25085762f 100644 --- a/include/trace/events/btrfs.h +++ b/include/trace/events/btrfs.h @@ -26,6 +26,7 @@ struct btrfs_work; struct __btrfs_workqueue; struct btrfs_qgroup_extent_record; struct btrfs_qgroup; +struct prelim_ref; #define show_ref_type(type) \ __print_symbolic(type, \ @@ -1636,6 +1637,63 @@ TRACE_EVENT(qgroup_meta_reserve, show_root_type(__entry->refroot), __entry->diff) ); +DECLARE_EVENT_CLASS(btrfs__prelim_ref, + TP_PROTO(const struct btrfs_fs_info *fs_info, + const struct prelim_ref *oldref, + const struct prelim_ref *newref, u64 tree_size), + TP_ARGS(fs_info, newref, oldref, tree_size), + + TP_STRUCT__entry_btrfs( + __field( u64, root_id ) + __field( u64, objectid ) + __field( u8, type ) + __field( u64, offset ) + __field( int, level ) + __field( int, old_count ) + __field( u64, parent ) + __field( u64, bytenr ) + __field( int, mod_count ) + __field( u64, tree_size ) + ), + + TP_fast_assign_btrfs(fs_info, + __entry->root_id = oldref->root_id; + __entry->objectid = oldref->key_for_search.objectid; + __entry->type = oldref->key_for_search.type; + __entry->offset = oldref->key_for_search.offset; + __entry->level = oldref->level; + __entry->old_count = oldref->count; + __entry->parent = oldref->parent; + __entry->bytenr = oldref->wanted_disk_byte; + __entry->mod_count = newref ? newref->count : 0; + __entry->tree_size = tree_size; + ), + + TP_printk_btrfs("root_id=%llu key=[%llu,%u,%llu] level=%d count=[%d+%d=%d] parent=%llu wanted_disk_byte=%llu nodes=%llu", + (unsigned long long)__entry->root_id, + (unsigned long long)__entry->objectid, __entry->type, + (unsigned long long)__entry->offset, __entry->level, + __entry->old_count, __entry->mod_count, + __entry->old_count + __entry->mod_count, + (unsigned long long)__entry->parent, + (unsigned long long)__entry->bytenr, + (unsigned long long)__entry->tree_size) +); + +DEFINE_EVENT(btrfs__prelim_ref, btrfs_prelim_ref_merge, + TP_PROTO(const struct btrfs_fs_info *fs_info, + const struct prelim_ref *oldref, + const struct prelim_ref *newref, u64 tree_size), + TP_ARGS(fs_info, oldref, newref, tree_size) +); + +DEFINE_EVENT(btrfs__prelim_ref, btrfs_prelim_ref_insert, + TP_PROTO(const struct btrfs_fs_info *fs_info, + const struct prelim_ref *oldref, + const struct prelim_ref *newref, u64 tree_size), + TP_ARGS(fs_info, oldref, newref, tree_size) +); + #endif /* _TRACE_BTRFS_H */ /* This part must be outside protection */