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

Commit 017e5369 authored by Chris Mason's avatar Chris Mason
Browse files

Btrfs: Leaf reference cache update



This changes the reference cache to make a single cache per root
instead of one cache per transaction, and to key by the byte number
of the disk block instead of the keys inside.

This makes it much less likely to have cache misses if a snapshot
or something has an extra reference on a higher node or a leaf while
the first transaction that added the leaf into the cache is dropping.

Some throttling is added to functions that free blocks heavily so they
wait for old transactions to drop.

Signed-off-by: default avatarChris Mason <chris.mason@oracle.com>
parent 31153d81
Loading
Loading
Loading
Loading
+10 −1
Original line number Diff line number Diff line
@@ -594,7 +594,6 @@ struct btrfs_fs_info {

	spinlock_t ref_cache_lock;
	u64 total_ref_cache_size;
	u64 running_ref_cache_size;

	u64 avail_data_alloc_bits;
	u64 avail_metadata_alloc_bits;
@@ -606,10 +605,18 @@ struct btrfs_fs_info {
	void *bdev_holder;
};

struct btrfs_leaf_ref_tree {
	struct rb_root root;
	struct btrfs_leaf_ref *last;
	struct list_head list;
	spinlock_t lock;
};

/*
 * in ram representation of the tree.  extent_root is used for all allocations
 * and for the extent tree extent_root root.
 */
struct dirty_root;
struct btrfs_root {
	struct extent_buffer *node;

@@ -618,6 +625,8 @@ struct btrfs_root {

	struct extent_buffer *commit_root;
	struct btrfs_leaf_ref_tree *ref_tree;
	struct btrfs_leaf_ref_tree ref_tree_struct;
	struct dirty_root *dirty_root;

	struct btrfs_root_item root_item;
	struct btrfs_key root_key;
+5 −3
Original line number Diff line number Diff line
@@ -40,6 +40,7 @@
#include "print-tree.h"
#include "async-thread.h"
#include "locking.h"
#include "ref-cache.h"

#if 0
static int check_tree_block(struct btrfs_root *root, struct extent_buffer *buf)
@@ -737,6 +738,10 @@ static int __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize,
	spin_lock_init(&root->node_lock);
	spin_lock_init(&root->orphan_lock);
	mutex_init(&root->objectid_mutex);

	btrfs_leaf_ref_tree_init(&root->ref_tree_struct);
	root->ref_tree = &root->ref_tree_struct;

	memset(&root->root_key, 0, sizeof(root->root_key));
	memset(&root->root_item, 0, sizeof(root->root_item));
	memset(&root->defrag_progress, 0, sizeof(root->defrag_progress));
@@ -1176,9 +1181,6 @@ static int transaction_kthread(void *arg)
			goto sleep;
		}

		printk("btrfs: running reference cache size %Lu\n",
			root->fs_info->running_ref_cache_size);

		now = get_seconds();
		if (now < cur->start_time || now - cur->start_time < 30) {
			mutex_unlock(&root->fs_info->trans_mutex);
+6 −12
Original line number Diff line number Diff line
@@ -1004,8 +1004,6 @@ int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
			goto out;
		}

		btrfs_item_key_to_cpu(buf, &ref->key, 0);

		ref->bytenr = buf->start;
		ref->owner = btrfs_header_owner(buf);
		ref->generation = btrfs_header_generation(buf);
@@ -2387,19 +2385,15 @@ static void noinline reada_walk_down(struct btrfs_root *root,
	}
}

/*
 * we want to avoid as much random IO as we can with the alloc mutex
 * held, so drop the lock and do the lookup, then do it again with the
 * lock held.
 */
int drop_snap_lookup_refcount(struct btrfs_root *root, u64 start, u64 len,
			      u32 *refs)
{
	int ret;
	mutex_unlock(&root->fs_info->alloc_mutex);
	lookup_extent_ref(NULL, root, start, len, refs);
	ret = lookup_extent_ref(NULL, root, start, len, refs);
	cond_resched();
	mutex_lock(&root->fs_info->alloc_mutex);
	return lookup_extent_ref(NULL, root, start, len, refs);
	return ret;
}

/*
@@ -2472,7 +2466,7 @@ static int noinline walk_down_tree(struct btrfs_trans_handle *trans,
		if (*level == 1) {
			struct btrfs_key key;
			btrfs_node_key_to_cpu(cur, &key, path->slots[*level]);
			ref = btrfs_lookup_leaf_ref(root, &key);
			ref = btrfs_lookup_leaf_ref(root, bytenr);
			if (ref) {
				ret = drop_leaf_ref(trans, root, ref);
				BUG_ON(ret);
@@ -2482,7 +2476,6 @@ static int noinline walk_down_tree(struct btrfs_trans_handle *trans,
				break;
			}
		}

		next = btrfs_find_tree_block(root, bytenr, blocksize);
		if (!next || !btrfs_buffer_uptodate(next, ptr_gen)) {
			free_extent_buffer(next);
@@ -2672,6 +2665,7 @@ int btrfs_drop_snapshot(struct btrfs_trans_handle *trans, struct btrfs_root
			ret = -EAGAIN;
			break;
		}
		wake_up(&root->fs_info->transaction_throttle);
	}
	for (i = 0; i <= orig_level; i++) {
		if (path->nodes[i]) {
+1 −1
Original line number Diff line number Diff line
@@ -347,7 +347,7 @@ static int noinline dirty_and_release_pages(struct btrfs_trans_handle *trans,
		btrfs_update_inode(trans, root, inode);
	}
failed:
	err = btrfs_end_transaction_throttle(trans, root);
	err = btrfs_end_transaction(trans, root);
out_unlock:
	unlock_extent(io_tree, start_pos, end_of_last_block, GFP_NOFS);
	return err;
+4 −4
Original line number Diff line number Diff line
@@ -2482,7 +2482,7 @@ static int btrfs_create(struct inode *dir, struct dentry *dentry,
	btrfs_update_inode_block_group(trans, dir);
out_unlock:
	nr = trans->blocks_used;
	btrfs_end_transaction_throttle(trans, root);
	btrfs_end_transaction(trans, root);
fail:
	if (drop_inode) {
		inode_dec_link_count(inode);
@@ -2535,7 +2535,7 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir,
		drop_inode = 1;

	nr = trans->blocks_used;
	btrfs_end_transaction_throttle(trans, root);
	btrfs_end_transaction(trans, root);
fail:
	if (drop_inode) {
		inode_dec_link_count(inode);
@@ -2609,7 +2609,7 @@ static int btrfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)

out_fail:
	nr = trans->blocks_used;
	btrfs_end_transaction_throttle(trans, root);
	btrfs_end_transaction(trans, root);

out_unlock:
	if (drop_on_err)
@@ -3548,7 +3548,7 @@ static int btrfs_symlink(struct inode *dir, struct dentry *dentry,

out_unlock:
	nr = trans->blocks_used;
	btrfs_end_transaction_throttle(trans, root);
	btrfs_end_transaction(trans, root);
out_fail:
	if (drop_inode) {
		inode_dec_link_count(inode);
Loading