#include <linux/mm.h>
#include <linux/rbtree.h>
+#include <trace/events/btrfs.h>
#include "ctree.h"
#include "disk-io.h"
#include "backref.h"
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;
*
* 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;
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;
}
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);
}
* 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)
{
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)
{
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);
}
* 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);
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);
}
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;
}
* 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)
{
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;
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;
}
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;
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;
/*
* 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)
{
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: {
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;
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:
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 */
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 */
}
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:
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;
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,
struct __btrfs_workqueue;
struct btrfs_qgroup_extent_record;
struct btrfs_qgroup;
+struct prelim_ref;
#define show_ref_type(type) \
__print_symbolic(type, \
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 */