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

Commit cd1bc465 authored by Chris Mason's avatar Chris Mason Committed by David Woodhouse
Browse files

Btrfs: more block allocator work

parent 9078a3e1
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -250,6 +250,8 @@ struct btrfs_block_group_item {
struct btrfs_block_group_cache {
	struct btrfs_key key;
	struct btrfs_block_group_item item;
	u64 first_free;
	u64 last_alloc;
};

struct crypto_hash;
@@ -257,7 +259,7 @@ struct btrfs_fs_info {
	struct btrfs_root *extent_root;
	struct btrfs_root *tree_root;
	struct btrfs_root *dev_root;
	struct btrfs_key last_insert;
	struct btrfs_block_group_cache *block_group_cache;
	struct radix_tree_root fs_roots_radix;
	struct radix_tree_root pending_del_radix;
	struct radix_tree_root pinned_radix;
+1 −1
Original line number Diff line number Diff line
@@ -558,7 +558,7 @@ struct btrfs_root *open_ctree(struct super_block *sb)
	}
	mutex_init(&fs_info->trans_mutex);
	mutex_init(&fs_info->fs_mutex);
	memset(&fs_info->last_insert, 0, sizeof(fs_info->last_insert));
	fs_info->block_group_cache = NULL;

	__setup_root(sb->s_blocksize, dev_root,
		     fs_info, BTRFS_DEV_TREE_OBJECTID);
+83 −12
Original line number Diff line number Diff line
@@ -12,6 +12,63 @@ static int finish_current_insert(struct btrfs_trans_handle *trans, struct
static int del_pending_extents(struct btrfs_trans_handle *trans, struct
			       btrfs_root *extent_root);

static int find_search_start(struct btrfs_root *root, int data)
{
	struct btrfs_block_group_cache *cache[8];
	struct btrfs_fs_info *info = root->fs_info;
	u64 used;
	u64 last;
	int i;
	int ret;

	cache[0] = info->block_group_cache;
	if (!cache[0])
		goto find_new;
	used = btrfs_block_group_used(&cache[0]->item);
	if (used < (cache[0]->key.offset * 3 / 2))
		return 0;
find_new:
	last = 0;
	while(1) {
		ret = radix_tree_gang_lookup_tag(&info->block_group_radix,
						 (void **)cache,
						 last, ARRAY_SIZE(cache),
						 BTRFS_BLOCK_GROUP_DIRTY);
		if (!ret)
			break;
		for (i = 0; i < ret; i++) {
			used = btrfs_block_group_used(&cache[i]->item);
			if (used < (cache[i]->key.offset * 3 / 2)) {
				info->block_group_cache = cache[i];
				cache[i]->last_alloc = cache[i]->first_free;
				return 0;
			}
			last = cache[i]->key.objectid +
				cache[i]->key.offset - 1;
		}
	}
	last = 0;
	while(1) {
		ret = radix_tree_gang_lookup(&info->block_group_radix,
						 (void **)cache,
						 last, ARRAY_SIZE(cache));
		if (!ret)
			break;
		for (i = 0; i < ret; i++) {
			used = btrfs_block_group_used(&cache[i]->item);
			if (used < (cache[i]->key.offset * 3 / 2)) {
				info->block_group_cache = cache[i];
				cache[i]->last_alloc = cache[i]->first_free;
				return 0;
			}
			last = cache[i]->key.objectid +
				cache[i]->key.offset - 1;
		}
	}
	info->block_group_cache = NULL;
	return 0;
}

int btrfs_inc_extent_ref(struct btrfs_trans_handle *trans,
				struct btrfs_root *root,
				u64 blocknr, u64 num_blocks)
@@ -205,8 +262,11 @@ static int update_block_group(struct btrfs_trans_handle *trans,
	while(total) {
		ret = radix_tree_gang_lookup(&info->block_group_radix,
					     (void **)&cache, blocknr, 1);
		if (!ret)
		if (!ret) {
			printk(KERN_CRIT "blocknr %Lu lookup failed\n",
			       blocknr);
			return -1;
		}
		block_in_group = blocknr - cache->key.objectid;
		WARN_ON(block_in_group > cache->key.offset);
		radix_tree_tag_set(&info->block_group_radix,
@@ -217,10 +277,15 @@ static int update_block_group(struct btrfs_trans_handle *trans,
		num = min(total, cache->key.offset - block_in_group);
		total -= num;
		blocknr += num;
		if (alloc)
		if (alloc) {
			old_val += num;
		else
			if (blocknr > cache->last_alloc)
				cache->last_alloc = blocknr;
		} else {
			old_val -= num;
			if (blocknr < cache->first_free)
				cache->first_free = blocknr;
		}
		btrfs_set_block_group_used(&cache->item, old_val);
	}
	return 0;
@@ -246,9 +311,7 @@ int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans, struct
			clear_radix_bit(pinned_radix, gang[i]);
		}
	}
	if (root->fs_info->last_insert.objectid > first)
		root->fs_info->last_insert.objectid = first;
	root->fs_info->last_insert.offset = 0;
	root->fs_info->block_group_cache = NULL;
	return 0;
}

@@ -466,8 +529,10 @@ static int find_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root
		num_blocks = 1;
		total_needed = min(level + 2, BTRFS_MAX_LEVEL) * 3;
	}
	if (info->last_insert.objectid > search_start)
		search_start = info->last_insert.objectid;
	find_search_start(root, 0);
	if (info->block_group_cache &&
	    info->block_group_cache->last_alloc > search_start)
		search_start = info->block_group_cache->last_alloc;

check_failed:
	btrfs_init_path(path);
@@ -567,8 +632,7 @@ static int find_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root
		      total_found < total_needed) {
			nr = total_needed - total_found - 1;
			BUG_ON(nr < 0);
			root->fs_info->extent_tree_prealloc[nr] =
				test_block;
			info->extent_tree_prealloc[nr] = test_block;
			total_found++;
			test_block++;
		}
@@ -576,9 +640,14 @@ static int find_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root
			search_start = test_block;
			goto check_failed;
		}
		root->fs_info->extent_tree_prealloc_nr = total_found;
		info->extent_tree_prealloc_nr = total_found;
	}
	ret = radix_tree_gang_lookup(&info->block_group_radix,
				     (void **)&info->block_group_cache,
				     ins->objectid, 1);
	if (ret) {
		info->block_group_cache->last_alloc = ins->objectid;
	}
	root->fs_info->last_insert.objectid = ins->objectid;
	ins->offset = num_blocks;
	btrfs_free_path(path);
	return 0;
@@ -915,6 +984,8 @@ int btrfs_read_block_groups(struct btrfs_root *root)
				    struct btrfs_block_group_item);
		memcpy(&cache->item, bi, sizeof(*bi));
		memcpy(&cache->key, &found_key, sizeof(found_key));
		cache->last_alloc = 0;
		cache->first_free = 0;
		key.objectid = found_key.objectid + found_key.offset;
		btrfs_release_path(root, path);
		ret = radix_tree_insert(&root->fs_info->block_group_radix,
+3 −0
Original line number Diff line number Diff line
@@ -223,6 +223,7 @@ static int btrfs_unlink_trans(struct btrfs_trans_handle *trans,
		btrfs_update_inode(trans, root, dir);
		drop_nlink(dentry->d_inode);
		btrfs_update_inode(trans, root, dentry->d_inode);
		dir->i_sb->s_dirt = 1;
	}
	return ret;
}
@@ -411,6 +412,7 @@ static int btrfs_truncate_in_trans(struct btrfs_trans_handle *trans,
error:
	btrfs_release_path(root, path);
	btrfs_free_path(path);
	inode->i_sb->s_dirt = 1;
	return ret;
}

@@ -935,6 +937,7 @@ static int btrfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
		goto out_fail;
	d_instantiate(dentry, inode);
	drop_on_err = 0;
	dir->i_sb->s_dirt = 1;

out_fail:
	btrfs_end_transaction(trans, root);