Skip to contentSkip to conversation

Btrfs: use per-cpu pools for reserving metadata space

PATCH New Josef Bacik 1 participant 1 message Jan 11, 2010 Btrfs file system

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 Btrfs: use per-cpu pools for reserving metadata space

Currently every time we do a metadata reservation we have to take the spin lock on the metadata space info structure and then calculate how much space we have and then do the reservation and so-on. This isn't terrible, but on beefier boxes this begins to cause problems. The other thing is that this lets us run right up to the edge of the space.

Enter the per-cpu pools. Instead of calculating out how much space we have left for every reservation, we only do it when we read/add new block groups to the space info, or whenever we commit the transaction. Then we only take 80% of the free space and distribute it among all the cpu's evenly (or according to usage once everything gets going). This will allow us to play a little fast and loose with our reservation stuff.

All reservations just increment the pool's reserved count, and then as allocations occur we add those to the pool's used count. If a pool doesn't have enough space to handle its reserved amount and used amount we simply try to steal from other pools, and then start flushing delalloc and other such things that we've always done.

Testing this gives us no regressions in the single CPU case, and then gives us a 10% jump in dbench on a box with 16 CPUs.

I'm hoping that this new approach will let us do things like throttle the worst case scenario calculation based on how much we reserve versus how much is used. Thanks,

---
 fs/btrfs/ctree.h        |   11 +-
 fs/btrfs/disk-io.c      |   17 ++
 fs/btrfs/extent-tree.c  |  565 ++++++++++++++++++++++++++++++++++-------------
 fs/btrfs/inode.c        |    1 +
 fs/btrfs/ordered-data.c |    1 +
 fs/btrfs/transaction.c  |    2 +
 6 files changed, 446 insertions(+), 151 deletions(-)
fs/btrfs/ctree.h +9 -2
index 8c57180..1a4014b 100644
@@ -666,6 +666,13 @@ struct btrfs_block_group_item {
 	__le64 flags;
 } __attribute__ ((__packed__));
 
+struct btrfs_reserved_space_pool {
+	u64 total_bytes;
+	u64 reserved_bytes;
+	u64 used_bytes;
+	spinlock_t lock;
+};
+
 struct btrfs_space_info {
 	u64 flags;
 
@@ -688,8 +695,6 @@ struct btrfs_space_info {
 				   chunks for this space */
 	int force_alloc;	/* set if we need to force a chunk alloc for
 				   this space */
-	int force_delalloc;	/* make people start doing filemap_flush until
-				   we're under a threshold */
 
 	struct list_head list;
 
@@ -980,6 +985,7 @@ struct btrfs_fs_info {
 	unsigned metadata_ratio;
 
 	void *bdev_holder;
+	struct btrfs_reserved_space_pool *reserved_space_pool;
 };
 
 /*
@@ -2051,6 +2057,7 @@ void btrfs_delalloc_reserve_space(struct btrfs_root *root, struct inode *inode,
 				 u64 bytes);
 void btrfs_delalloc_free_space(struct btrfs_root *root, struct inode *inode,
 			      u64 bytes);
+void btrfs_init_space_pools(struct btrfs_fs_info *fs_info);
 /* ctree.c */
 int btrfs_bin_search(struct extent_buffer *eb, struct btrfs_key *key,
 		     int level, int *slot);
fs/btrfs/disk-io.c +17 -0
index 02b6afb..d02a6ea 100644
@@ -1575,6 +1575,7 @@ struct btrfs_root *open_ctree(struct super_block *sb,
 	struct btrfs_root *log_tree_root;
 
 	int ret;
+	int i;
 	int err = -EINVAL;
 
 	struct btrfs_super_block *disk_super;
@@ -1917,8 +1918,23 @@ struct btrfs_root *open_ctree(struct super_block *sb,
 
 	csum_root->track_dirty = 1;
 
+	fs_info->reserved_space_pool =
+		alloc_percpu(struct btrfs_reserved_space_pool);
+	if (!fs_info->reserved_space_pool)
+		goto fail_csum_root;
+
+	for_each_possible_cpu(i) {
+		struct btrfs_reserved_space_pool *pool;
+		pool = per_cpu_ptr(fs_info->reserved_space_pool, i);
+		spin_lock_init(&pool->lock);
+		pool->total_bytes = 0;
+		pool->reserved_bytes = 0;
+		pool->used_bytes = 0;
+	}
+
 	btrfs_read_block_groups(extent_root);
 
+	btrfs_init_space_pools(fs_info);
 	fs_info->generation = generation;
 	fs_info->last_trans_committed = generation;
 	fs_info->data_alloc_profile = (u64)-1;
@@ -2442,6 +2458,7 @@ int close_ctree(struct btrfs_root *root)
 	free_extent_buffer(root->fs_info->csum_root->commit_root);
 
 	btrfs_free_block_groups(root->fs_info);
+	free_percpu(fs_info->reserved_space_pool);
 
 	del_fs_roots(fs_info);
 
fs/btrfs/extent-tree.c +416 -149

731 lines not on this page · raw message

fs/btrfs/inode.c +1 -0
index b383e53..b5a36b3 100644
@@ -1340,6 +1340,7 @@ static int btrfs_clear_bit_hook(struct inode *inode,
 
 		if (bits & EXTENT_DO_ACCOUNTING) {
 			spin_lock(&BTRFS_I(inode)->accounting_lock);
+			BUG_ON(!BTRFS_I(inode)->outstanding_extents);
 			BTRFS_I(inode)->outstanding_extents--;
 			spin_unlock(&BTRFS_I(inode)->accounting_lock);
 			btrfs_unreserve_metadata_for_delalloc(root, inode, 1);
fs/btrfs/ordered-data.c +1 -0
index 5799bc4..031dcc5 100644
@@ -307,6 +307,7 @@ int btrfs_remove_ordered_extent(struct inode *inode,
 	set_bit(BTRFS_ORDERED_COMPLETE, &entry->flags);
 
 	spin_lock(&BTRFS_I(inode)->accounting_lock);
+	BUG_ON(!BTRFS_I(inode)->outstanding_extents);
 	BTRFS_I(inode)->outstanding_extents--;
 	spin_unlock(&BTRFS_I(inode)->accounting_lock);
 	btrfs_unreserve_metadata_for_delalloc(BTRFS_I(inode)->root,
fs/btrfs/transaction.c +2 -0
index c207e8c..37f755a 100644
@@ -1056,6 +1056,8 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
 
 	btrfs_prepare_extent_commit(trans, root);
 
+	btrfs_init_space_pools(root->fs_info);
+
 	cur_trans = root->fs_info->running_transaction;
 	spin_lock(&root->fs_info->new_trans_lock);
 	root->fs_info->running_transaction = NULL;
Signature · 1 line
1.5.4.3