Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 00142756 authored by Jeff Mahoney's avatar Jeff Mahoney Committed by David Sterba
Browse files

btrfs: backref, add tracepoints for prelim_ref insertion and merging



This patch adds a tracepoint event for prelim_ref insertion and
merging.  For each, the ref being inserted or merged and the count
of tree nodes is issued.

Signed-off-by: default avatarJeff Mahoney <jeffm@suse.com>
Reviewed-by: default avatarDavid Sterba <dsterba@suse.com>
Signed-off-by: default avatarDavid Sterba <dsterba@suse.com>
parent 6c336b21
Loading
Loading
Loading
Loading
+60 −58
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@

#include <linux/mm.h>
#include <linux/rbtree.h>
#include <trace/events/btrfs.h>
#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 @@ static int find_parent_nodes(struct btrfs_trans_handle *trans,
				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 @@ static int find_parent_nodes(struct btrfs_trans_handle *trans,
		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,
+12 −0
Original line number Diff line number Diff line
@@ -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
+1 −0
Original line number Diff line number Diff line
@@ -61,6 +61,7 @@
#include "tests/btrfs-tests.h"

#include "qgroup.h"
#include "backref.h"
#define CREATE_TRACE_POINTS
#include <trace/events/btrfs.h>

+58 −0
Original line number Diff line number Diff line
@@ -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 */