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

Commit 8c2a3ca2 authored by Josef Bacik's avatar Josef Bacik Committed by Chris Mason
Browse files

Btrfs: space leak tracepoints



This in addition to a script in my btrfs-tracing tree will help track down space
leaks when we're getting space left over in block groups on umount.  Thanks,

Signed-off-by: default avatarJosef Bacik <josef@redhat.com>
parent 90290e19
Loading
Loading
Loading
Loading
+33 −12
Original line number Diff line number Diff line
@@ -595,8 +595,12 @@ static int btrfs_delayed_item_reserve_metadata(struct btrfs_trans_handle *trans,

	num_bytes = btrfs_calc_trans_metadata_size(root, 1);
	ret = btrfs_block_rsv_migrate(src_rsv, dst_rsv, num_bytes);
	if (!ret)
	if (!ret) {
		trace_btrfs_space_reservation(root->fs_info, "delayed_item",
					      item->key.objectid,
					      num_bytes, 1);
		item->bytes_reserved = num_bytes;
	}

	return ret;
}
@@ -610,6 +614,9 @@ static void btrfs_delayed_item_release_metadata(struct btrfs_root *root,
		return;

	rsv = &root->fs_info->delayed_block_rsv;
	trace_btrfs_space_reservation(root->fs_info, "delayed_item",
				      item->key.objectid, item->bytes_reserved,
				      0);
	btrfs_block_rsv_release(root, rsv,
				item->bytes_reserved);
}
@@ -624,7 +631,7 @@ static int btrfs_delayed_inode_reserve_metadata(
	struct btrfs_block_rsv *dst_rsv;
	u64 num_bytes;
	int ret;
	int release = false;
	bool release = false;

	src_rsv = trans->block_rsv;
	dst_rsv = &root->fs_info->delayed_block_rsv;
@@ -651,8 +658,13 @@ static int btrfs_delayed_inode_reserve_metadata(
		 */
		if (ret == -EAGAIN)
			ret = -ENOSPC;
		if (!ret)
		if (!ret) {
			node->bytes_reserved = num_bytes;
			trace_btrfs_space_reservation(root->fs_info,
						      "delayed_inode",
						      btrfs_ino(inode),
						      num_bytes, 1);
		}
		return ret;
	} else if (src_rsv == &root->fs_info->delalloc_block_rsv) {
		spin_lock(&BTRFS_I(inode)->lock);
@@ -707,11 +719,17 @@ static int btrfs_delayed_inode_reserve_metadata(
	 * reservation here.  I think it may be time for a documentation page on
	 * how block rsvs. work.
	 */
	if (!ret)
	if (!ret) {
		trace_btrfs_space_reservation(root->fs_info, "delayed_inode",
					      btrfs_ino(inode), num_bytes, 1);
		node->bytes_reserved = num_bytes;
	}

	if (release)
	if (release) {
		trace_btrfs_space_reservation(root->fs_info, "delalloc",
					      btrfs_ino(inode), num_bytes, 0);
		btrfs_block_rsv_release(root, src_rsv, num_bytes);
	}

	return ret;
}
@@ -725,6 +743,8 @@ static void btrfs_delayed_inode_release_metadata(struct btrfs_root *root,
		return;

	rsv = &root->fs_info->delayed_block_rsv;
	trace_btrfs_space_reservation(root->fs_info, "delayed_inode",
				      node->inode_id, node->bytes_reserved, 0);
	btrfs_block_rsv_release(root, rsv,
				node->bytes_reserved);
	node->bytes_reserved = 0;
@@ -1372,13 +1392,6 @@ int btrfs_insert_delayed_dir_index(struct btrfs_trans_handle *trans,
		goto release_node;
	}

	ret = btrfs_delayed_item_reserve_metadata(trans, root, delayed_item);
	/*
	 * we have reserved enough space when we start a new transaction,
	 * so reserving metadata failure is impossible
	 */
	BUG_ON(ret);

	delayed_item->key.objectid = btrfs_ino(dir);
	btrfs_set_key_type(&delayed_item->key, BTRFS_DIR_INDEX_KEY);
	delayed_item->key.offset = index;
@@ -1391,6 +1404,14 @@ int btrfs_insert_delayed_dir_index(struct btrfs_trans_handle *trans,
	dir_item->type = type;
	memcpy((char *)(dir_item + 1), name, name_len);

	ret = btrfs_delayed_item_reserve_metadata(trans, root, delayed_item);
	/*
	 * we have reserved enough space when we start a new transaction,
	 * so reserving metadata failure is impossible
	 */
	BUG_ON(ret);


	mutex_lock(&delayed_node->mutex);
	ret = __btrfs_add_delayed_insertion_item(delayed_node, delayed_item);
	if (unlikely(ret)) {
+50 −8
Original line number Diff line number Diff line
@@ -3310,6 +3310,8 @@ int btrfs_check_data_free_space(struct inode *inode, u64 bytes)
		return -ENOSPC;
	}
	data_sinfo->bytes_may_use += bytes;
	trace_btrfs_space_reservation(root->fs_info, "space_info",
				      (u64)data_sinfo, bytes, 1);
	spin_unlock(&data_sinfo->lock);

	return 0;
@@ -3329,6 +3331,8 @@ void btrfs_free_reserved_data_space(struct inode *inode, u64 bytes)
	data_sinfo = BTRFS_I(inode)->space_info;
	spin_lock(&data_sinfo->lock);
	data_sinfo->bytes_may_use -= bytes;
	trace_btrfs_space_reservation(root->fs_info, "space_info",
				      (u64)data_sinfo, bytes, 0);
	spin_unlock(&data_sinfo->lock);
}

@@ -3686,6 +3690,10 @@ static int reserve_metadata_bytes(struct btrfs_root *root,
	if (used <= space_info->total_bytes) {
		if (used + orig_bytes <= space_info->total_bytes) {
			space_info->bytes_may_use += orig_bytes;
			trace_btrfs_space_reservation(root->fs_info,
						      "space_info",
						      (u64)space_info,
						      orig_bytes, 1);
			ret = 0;
		} else {
			/*
@@ -3753,6 +3761,10 @@ static int reserve_metadata_bytes(struct btrfs_root *root,

		if (used + num_bytes < space_info->total_bytes + avail) {
			space_info->bytes_may_use += orig_bytes;
			trace_btrfs_space_reservation(root->fs_info,
						      "space_info",
						      (u64)space_info,
						      orig_bytes, 1);
			ret = 0;
		} else {
			wait_ordered = true;
@@ -3859,7 +3871,8 @@ static void block_rsv_add_bytes(struct btrfs_block_rsv *block_rsv,
	spin_unlock(&block_rsv->lock);
}

static void block_rsv_release_bytes(struct btrfs_block_rsv *block_rsv,
static void block_rsv_release_bytes(struct btrfs_fs_info *fs_info,
				    struct btrfs_block_rsv *block_rsv,
				    struct btrfs_block_rsv *dest, u64 num_bytes)
{
	struct btrfs_space_info *space_info = block_rsv->space_info;
@@ -3895,6 +3908,9 @@ static void block_rsv_release_bytes(struct btrfs_block_rsv *block_rsv,
		if (num_bytes) {
			spin_lock(&space_info->lock);
			space_info->bytes_may_use -= num_bytes;
			trace_btrfs_space_reservation(fs_info, "space_info",
						      (u64)space_info,
						      num_bytes, 0);
			space_info->reservation_progress++;
			spin_unlock(&space_info->lock);
		}
@@ -4051,7 +4067,8 @@ void btrfs_block_rsv_release(struct btrfs_root *root,
	if (global_rsv->full || global_rsv == block_rsv ||
	    block_rsv->space_info != global_rsv->space_info)
		global_rsv = NULL;
	block_rsv_release_bytes(block_rsv, global_rsv, num_bytes);
	block_rsv_release_bytes(root->fs_info, block_rsv, global_rsv,
				num_bytes);
}

/*
@@ -4110,11 +4127,15 @@ static void update_global_block_rsv(struct btrfs_fs_info *fs_info)
		num_bytes = sinfo->total_bytes - num_bytes;
		block_rsv->reserved += num_bytes;
		sinfo->bytes_may_use += num_bytes;
		trace_btrfs_space_reservation(fs_info, "space_info",
					      (u64)sinfo, num_bytes, 1);
	}

	if (block_rsv->reserved >= block_rsv->size) {
		num_bytes = block_rsv->reserved - block_rsv->size;
		sinfo->bytes_may_use -= num_bytes;
		trace_btrfs_space_reservation(fs_info, "space_info",
					      (u64)sinfo, num_bytes, 0);
		sinfo->reservation_progress++;
		block_rsv->reserved = block_rsv->size;
		block_rsv->full = 1;
@@ -4149,7 +4170,8 @@ static void init_global_block_rsv(struct btrfs_fs_info *fs_info)

static void release_global_block_rsv(struct btrfs_fs_info *fs_info)
{
	block_rsv_release_bytes(&fs_info->global_block_rsv, NULL, (u64)-1);
	block_rsv_release_bytes(fs_info, &fs_info->global_block_rsv, NULL,
				(u64)-1);
	WARN_ON(fs_info->delalloc_block_rsv.size > 0);
	WARN_ON(fs_info->delalloc_block_rsv.reserved > 0);
	WARN_ON(fs_info->trans_block_rsv.size > 0);
@@ -4166,6 +4188,8 @@ void btrfs_trans_release_metadata(struct btrfs_trans_handle *trans,
	if (!trans->bytes_reserved)
		return;

	trace_btrfs_space_reservation(root->fs_info, "transaction", (u64)trans,
				      trans->bytes_reserved, 0);
	btrfs_block_rsv_release(root, trans->block_rsv, trans->bytes_reserved);
	trans->bytes_reserved = 0;
}
@@ -4183,6 +4207,8 @@ int btrfs_orphan_reserve_metadata(struct btrfs_trans_handle *trans,
	 * when we are truly done with the orphan item.
	 */
	u64 num_bytes = btrfs_calc_trans_metadata_size(root, 1);
	trace_btrfs_space_reservation(root->fs_info, "orphan",
				      btrfs_ino(inode), num_bytes, 1);
	return block_rsv_migrate_bytes(src_rsv, dst_rsv, num_bytes);
}

@@ -4190,6 +4216,8 @@ void btrfs_orphan_release_metadata(struct inode *inode)
{
	struct btrfs_root *root = BTRFS_I(inode)->root;
	u64 num_bytes = btrfs_calc_trans_metadata_size(root, 1);
	trace_btrfs_space_reservation(root->fs_info, "orphan",
				      btrfs_ino(inode), num_bytes, 0);
	btrfs_block_rsv_release(root, root->orphan_block_rsv, num_bytes);
}

@@ -4370,8 +4398,13 @@ int btrfs_delalloc_reserve_metadata(struct inode *inode, u64 num_bytes)
		if (dropped)
			to_free += btrfs_calc_trans_metadata_size(root, dropped);

		if (to_free)
		if (to_free) {
			btrfs_block_rsv_release(root, block_rsv, to_free);
			trace_btrfs_space_reservation(root->fs_info,
						      "delalloc",
						      btrfs_ino(inode),
						      to_free, 0);
		}
		return ret;
	}

@@ -4383,6 +4416,9 @@ int btrfs_delalloc_reserve_metadata(struct inode *inode, u64 num_bytes)
	BTRFS_I(inode)->reserved_extents += nr_extents;
	spin_unlock(&BTRFS_I(inode)->lock);

	if (to_reserve)
		trace_btrfs_space_reservation(root->fs_info,"delalloc",
					      btrfs_ino(inode), to_reserve, 1);
	block_rsv_add_bytes(block_rsv, to_reserve, 1);

	return 0;
@@ -4412,6 +4448,8 @@ void btrfs_delalloc_release_metadata(struct inode *inode, u64 num_bytes)
	if (dropped > 0)
		to_free += btrfs_calc_trans_metadata_size(root, dropped);

	trace_btrfs_space_reservation(root->fs_info, "delalloc",
				      btrfs_ino(inode), to_free, 0);
	btrfs_block_rsv_release(root, &root->fs_info->delalloc_block_rsv,
				to_free);
}
@@ -4666,7 +4704,10 @@ static int btrfs_update_reserved_bytes(struct btrfs_block_group_cache *cache,
			cache->reserved += num_bytes;
			space_info->bytes_reserved += num_bytes;
			if (reserve == RESERVE_ALLOC) {
				BUG_ON(space_info->bytes_may_use < num_bytes);
				trace_btrfs_space_reservation(cache->fs_info,
							      "space_info",
							      (u64)space_info,
							      num_bytes, 0);
				space_info->bytes_may_use -= num_bytes;
			}
		}
@@ -6126,10 +6167,11 @@ use_block_rsv(struct btrfs_trans_handle *trans,
	return ERR_PTR(-ENOSPC);
}

static void unuse_block_rsv(struct btrfs_block_rsv *block_rsv, u32 blocksize)
static void unuse_block_rsv(struct btrfs_fs_info *fs_info,
			    struct btrfs_block_rsv *block_rsv, u32 blocksize)
{
	block_rsv_add_bytes(block_rsv, blocksize, 0);
	block_rsv_release_bytes(block_rsv, NULL, 0);
	block_rsv_release_bytes(fs_info, block_rsv, NULL, 0);
}

/*
@@ -6159,7 +6201,7 @@ struct extent_buffer *btrfs_alloc_free_block(struct btrfs_trans_handle *trans,
	ret = btrfs_reserve_extent(trans, root, blocksize, blocksize,
				   empty_size, hint, (u64)-1, &ins, 0);
	if (ret) {
		unuse_block_rsv(block_rsv, blocksize);
		unuse_block_rsv(root->fs_info, block_rsv, blocksize);
		return ERR_PTR(ret);
	}

+4 −0
Original line number Diff line number Diff line
@@ -438,6 +438,8 @@ int btrfs_save_ino_cache(struct btrfs_root *root,
					  trans->bytes_reserved);
	if (ret)
		goto out;
	trace_btrfs_space_reservation(root->fs_info, "ino_cache", (u64)trans,
				      trans->bytes_reserved, 1);
again:
	inode = lookup_free_ino_inode(root, path);
	if (IS_ERR(inode) && PTR_ERR(inode) != -ENOENT) {
@@ -498,6 +500,8 @@ int btrfs_save_ino_cache(struct btrfs_root *root,
out_put:
	iput(inode);
out_release:
	trace_btrfs_space_reservation(root->fs_info, "ino_cache", (u64)trans,
				      trans->bytes_reserved, 0);
	btrfs_block_rsv_release(root, trans->block_rsv, trans->bytes_reserved);
out:
	trans->block_rsv = rsv;
+2 −0
Original line number Diff line number Diff line
@@ -326,6 +326,8 @@ static struct btrfs_trans_handle *start_transaction(struct btrfs_root *root,
	}

	if (num_bytes) {
		trace_btrfs_space_reservation(root->fs_info, "transaction",
					      (u64)h, num_bytes, 1);
		h->block_rsv = &root->fs_info->trans_block_rsv;
		h->bytes_reserved = num_bytes;
	}
+30 −0
Original line number Diff line number Diff line
@@ -55,6 +55,8 @@ struct extent_buffer;
	{ BTRFS_BLOCK_GROUP_DUP,	"DUP"}, \
	{ BTRFS_BLOCK_GROUP_RAID10,	"RAID10"}

#define BTRFS_UUID_SIZE 16

TRACE_EVENT(btrfs_transaction_commit,

	TP_PROTO(struct btrfs_root *root),
@@ -632,6 +634,34 @@ TRACE_EVENT(btrfs_cow_block,
		  __entry->cow_level)
);

TRACE_EVENT(btrfs_space_reservation,

	TP_PROTO(struct btrfs_fs_info *fs_info, char *type, u64 val,
		 u64 bytes, int reserve),

	TP_ARGS(fs_info, type, val, bytes, reserve),

	TP_STRUCT__entry(
		__array(	u8,	fsid,	BTRFS_UUID_SIZE	)
		__string(	type,	type			)
		__field(	u64,	val			)
		__field(	u64,	bytes			)
		__field(	int,	reserve			)
	),

	TP_fast_assign(
		memcpy(__entry->fsid, fs_info->fsid, BTRFS_UUID_SIZE);
		__assign_str(type, type);
		__entry->val		= val;
		__entry->bytes		= bytes;
		__entry->reserve	= reserve;
	),

	TP_printk("%pU: %s: %Lu %s %Lu", __entry->fsid, __get_str(type),
		  __entry->val, __entry->reserve ? "reserve" : "release",
		  __entry->bytes)
);

DECLARE_EVENT_CLASS(btrfs__reserved_extent,

	TP_PROTO(struct btrfs_root *root, u64 start, u64 len),