mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	btrfs: move the space_info handling code to space-info.c
These are the basic init and lookup functions and some helper functions, fairly straightforward before the bad stuff starts. Reviewed-by: Nikolay Borisov <nborisov@suse.com> Signed-off-by: Josef Bacik <josef@toxicpanda.com> Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
		
							parent
							
								
									d44b72aa12
								
							
						
					
					
						commit
						280c290881
					
				
					 4 changed files with 204 additions and 187 deletions
				
			
		| 
						 | 
				
			
			@ -10,7 +10,7 @@ btrfs-y += super.o ctree.o extent-tree.o print-tree.o root-tree.o dir-item.o \
 | 
			
		|||
	   export.o tree-log.o free-space-cache.o zlib.o lzo.o zstd.o \
 | 
			
		||||
	   compression.o delayed-ref.o relocation.o delayed-inode.o scrub.o \
 | 
			
		||||
	   reada.o backref.o ulist.o qgroup.o send.o dev-replace.o raid56.o \
 | 
			
		||||
	   uuid-tree.o props.o free-space-tree.o tree-checker.o
 | 
			
		||||
	   uuid-tree.o props.o free-space-tree.o tree-checker.o space-info.o
 | 
			
		||||
 | 
			
		||||
btrfs-$(CONFIG_BTRFS_FS_POSIX_ACL) += acl.o
 | 
			
		||||
btrfs-$(CONFIG_BTRFS_FS_CHECK_INTEGRITY) += check-integrity.o
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -713,25 +713,6 @@ struct btrfs_block_group_cache *btrfs_lookup_block_group(
 | 
			
		|||
	return block_group_cache_tree_search(info, bytenr, 1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct btrfs_space_info *__find_space_info(struct btrfs_fs_info *info,
 | 
			
		||||
						  u64 flags)
 | 
			
		||||
{
 | 
			
		||||
	struct list_head *head = &info->space_info;
 | 
			
		||||
	struct btrfs_space_info *found;
 | 
			
		||||
 | 
			
		||||
	flags &= BTRFS_BLOCK_GROUP_TYPE_MASK;
 | 
			
		||||
 | 
			
		||||
	rcu_read_lock();
 | 
			
		||||
	list_for_each_entry_rcu(found, head, list) {
 | 
			
		||||
		if (found->flags & flags) {
 | 
			
		||||
			rcu_read_unlock();
 | 
			
		||||
			return found;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	rcu_read_unlock();
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static u64 generic_ref_to_space_flags(struct btrfs_ref *ref)
 | 
			
		||||
{
 | 
			
		||||
	if (ref->type == BTRFS_REF_METADATA) {
 | 
			
		||||
| 
						 | 
				
			
			@ -749,7 +730,7 @@ static void add_pinned_bytes(struct btrfs_fs_info *fs_info,
 | 
			
		|||
	struct btrfs_space_info *space_info;
 | 
			
		||||
	u64 flags = generic_ref_to_space_flags(ref);
 | 
			
		||||
 | 
			
		||||
	space_info = __find_space_info(fs_info, flags);
 | 
			
		||||
	space_info = btrfs_find_space_info(fs_info, flags);
 | 
			
		||||
	ASSERT(space_info);
 | 
			
		||||
	percpu_counter_add_batch(&space_info->total_bytes_pinned, ref->len,
 | 
			
		||||
		    BTRFS_TOTAL_BYTES_PINNED_BATCH);
 | 
			
		||||
| 
						 | 
				
			
			@ -761,27 +742,12 @@ static void sub_pinned_bytes(struct btrfs_fs_info *fs_info,
 | 
			
		|||
	struct btrfs_space_info *space_info;
 | 
			
		||||
	u64 flags = generic_ref_to_space_flags(ref);
 | 
			
		||||
 | 
			
		||||
	space_info = __find_space_info(fs_info, flags);
 | 
			
		||||
	space_info = btrfs_find_space_info(fs_info, flags);
 | 
			
		||||
	ASSERT(space_info);
 | 
			
		||||
	percpu_counter_add_batch(&space_info->total_bytes_pinned, -ref->len,
 | 
			
		||||
		    BTRFS_TOTAL_BYTES_PINNED_BATCH);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * after adding space to the filesystem, we need to clear the full flags
 | 
			
		||||
 * on all the space infos.
 | 
			
		||||
 */
 | 
			
		||||
void btrfs_clear_space_info_full(struct btrfs_fs_info *info)
 | 
			
		||||
{
 | 
			
		||||
	struct list_head *head = &info->space_info;
 | 
			
		||||
	struct btrfs_space_info *found;
 | 
			
		||||
 | 
			
		||||
	rcu_read_lock();
 | 
			
		||||
	list_for_each_entry_rcu(found, head, list)
 | 
			
		||||
		found->full = 0;
 | 
			
		||||
	rcu_read_unlock();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* simple helper to search for an existing data extent at a given offset */
 | 
			
		||||
int btrfs_lookup_data_extent(struct btrfs_fs_info *fs_info, u64 start, u64 len)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -2449,7 +2415,7 @@ void btrfs_cleanup_ref_head_accounting(struct btrfs_fs_info *fs_info,
 | 
			
		|||
			flags = BTRFS_BLOCK_GROUP_SYSTEM;
 | 
			
		||||
		else
 | 
			
		||||
			flags = BTRFS_BLOCK_GROUP_METADATA;
 | 
			
		||||
		space_info = __find_space_info(fs_info, flags);
 | 
			
		||||
		space_info = btrfs_find_space_info(fs_info, flags);
 | 
			
		||||
		ASSERT(space_info);
 | 
			
		||||
		percpu_counter_add_batch(&space_info->total_bytes_pinned,
 | 
			
		||||
				   -head->num_bytes,
 | 
			
		||||
| 
						 | 
				
			
			@ -3821,93 +3787,6 @@ void btrfs_wait_nocow_writers(struct btrfs_block_group_cache *bg)
 | 
			
		|||
	wait_var_event(&bg->nocow_writers, !atomic_read(&bg->nocow_writers));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const char *alloc_name(u64 flags)
 | 
			
		||||
{
 | 
			
		||||
	switch (flags) {
 | 
			
		||||
	case BTRFS_BLOCK_GROUP_METADATA|BTRFS_BLOCK_GROUP_DATA:
 | 
			
		||||
		return "mixed";
 | 
			
		||||
	case BTRFS_BLOCK_GROUP_METADATA:
 | 
			
		||||
		return "metadata";
 | 
			
		||||
	case BTRFS_BLOCK_GROUP_DATA:
 | 
			
		||||
		return "data";
 | 
			
		||||
	case BTRFS_BLOCK_GROUP_SYSTEM:
 | 
			
		||||
		return "system";
 | 
			
		||||
	default:
 | 
			
		||||
		WARN_ON(1);
 | 
			
		||||
		return "invalid-combination";
 | 
			
		||||
	};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int create_space_info(struct btrfs_fs_info *info, u64 flags)
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
	struct btrfs_space_info *space_info;
 | 
			
		||||
	int i;
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	space_info = kzalloc(sizeof(*space_info), GFP_NOFS);
 | 
			
		||||
	if (!space_info)
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
 | 
			
		||||
	ret = percpu_counter_init(&space_info->total_bytes_pinned, 0,
 | 
			
		||||
				 GFP_KERNEL);
 | 
			
		||||
	if (ret) {
 | 
			
		||||
		kfree(space_info);
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < BTRFS_NR_RAID_TYPES; i++)
 | 
			
		||||
		INIT_LIST_HEAD(&space_info->block_groups[i]);
 | 
			
		||||
	init_rwsem(&space_info->groups_sem);
 | 
			
		||||
	spin_lock_init(&space_info->lock);
 | 
			
		||||
	space_info->flags = flags & BTRFS_BLOCK_GROUP_TYPE_MASK;
 | 
			
		||||
	space_info->force_alloc = CHUNK_ALLOC_NO_FORCE;
 | 
			
		||||
	init_waitqueue_head(&space_info->wait);
 | 
			
		||||
	INIT_LIST_HEAD(&space_info->ro_bgs);
 | 
			
		||||
	INIT_LIST_HEAD(&space_info->tickets);
 | 
			
		||||
	INIT_LIST_HEAD(&space_info->priority_tickets);
 | 
			
		||||
 | 
			
		||||
	ret = kobject_init_and_add(&space_info->kobj, &space_info_ktype,
 | 
			
		||||
				    info->space_info_kobj, "%s",
 | 
			
		||||
				    alloc_name(space_info->flags));
 | 
			
		||||
	if (ret) {
 | 
			
		||||
		kobject_put(&space_info->kobj);
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	list_add_rcu(&space_info->list, &info->space_info);
 | 
			
		||||
	if (flags & BTRFS_BLOCK_GROUP_DATA)
 | 
			
		||||
		info->data_sinfo = space_info;
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void update_space_info(struct btrfs_fs_info *info, u64 flags,
 | 
			
		||||
			     u64 total_bytes, u64 bytes_used,
 | 
			
		||||
			     u64 bytes_readonly,
 | 
			
		||||
			     struct btrfs_space_info **space_info)
 | 
			
		||||
{
 | 
			
		||||
	struct btrfs_space_info *found;
 | 
			
		||||
	int factor;
 | 
			
		||||
 | 
			
		||||
	factor = btrfs_bg_type_to_factor(flags);
 | 
			
		||||
 | 
			
		||||
	found = __find_space_info(info, flags);
 | 
			
		||||
	ASSERT(found);
 | 
			
		||||
	spin_lock(&found->lock);
 | 
			
		||||
	found->total_bytes += total_bytes;
 | 
			
		||||
	found->disk_total += total_bytes * factor;
 | 
			
		||||
	found->bytes_used += bytes_used;
 | 
			
		||||
	found->disk_used += bytes_used * factor;
 | 
			
		||||
	found->bytes_readonly += bytes_readonly;
 | 
			
		||||
	if (total_bytes > 0)
 | 
			
		||||
		found->full = 0;
 | 
			
		||||
	btrfs_space_info_add_new_bytes(info, found, total_bytes -
 | 
			
		||||
				       bytes_used - bytes_readonly);
 | 
			
		||||
	spin_unlock(&found->lock);
 | 
			
		||||
	*space_info = found;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void set_avail_alloc_bits(struct btrfs_fs_info *fs_info, u64 flags)
 | 
			
		||||
{
 | 
			
		||||
	u64 extra_flags = chunk_to_extended(flags) &
 | 
			
		||||
| 
						 | 
				
			
			@ -4055,15 +3934,6 @@ u64 btrfs_system_alloc_profile(struct btrfs_fs_info *fs_info)
 | 
			
		|||
	return get_alloc_profile(fs_info, BTRFS_BLOCK_GROUP_SYSTEM);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static u64 btrfs_space_info_used(struct btrfs_space_info *s_info,
 | 
			
		||||
				 bool may_use_included)
 | 
			
		||||
{
 | 
			
		||||
	ASSERT(s_info);
 | 
			
		||||
	return s_info->bytes_used + s_info->bytes_reserved +
 | 
			
		||||
		s_info->bytes_pinned + s_info->bytes_readonly +
 | 
			
		||||
		(may_use_included ? s_info->bytes_may_use : 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int btrfs_alloc_data_chunk_ondemand(struct btrfs_inode *inode, u64 bytes)
 | 
			
		||||
{
 | 
			
		||||
	struct btrfs_root *root = inode->root;
 | 
			
		||||
| 
						 | 
				
			
			@ -4339,7 +4209,7 @@ void check_system_chunk(struct btrfs_trans_handle *trans, u64 type)
 | 
			
		|||
	 */
 | 
			
		||||
	lockdep_assert_held(&fs_info->chunk_mutex);
 | 
			
		||||
 | 
			
		||||
	info = __find_space_info(fs_info, BTRFS_BLOCK_GROUP_SYSTEM);
 | 
			
		||||
	info = btrfs_find_space_info(fs_info, BTRFS_BLOCK_GROUP_SYSTEM);
 | 
			
		||||
	spin_lock(&info->lock);
 | 
			
		||||
	left = info->total_bytes - btrfs_space_info_used(info, true);
 | 
			
		||||
	spin_unlock(&info->lock);
 | 
			
		||||
| 
						 | 
				
			
			@ -4399,7 +4269,7 @@ int btrfs_chunk_alloc(struct btrfs_trans_handle *trans, u64 flags,
 | 
			
		|||
	if (trans->allocating_chunk)
 | 
			
		||||
		return -ENOSPC;
 | 
			
		||||
 | 
			
		||||
	space_info = __find_space_info(fs_info, flags);
 | 
			
		||||
	space_info = btrfs_find_space_info(fs_info, flags);
 | 
			
		||||
	ASSERT(space_info);
 | 
			
		||||
 | 
			
		||||
	do {
 | 
			
		||||
| 
						 | 
				
			
			@ -4627,7 +4497,7 @@ static void shrink_delalloc(struct btrfs_fs_info *fs_info, u64 to_reclaim,
 | 
			
		|||
	to_reclaim = items * EXTENT_SIZE_PER_ITEM;
 | 
			
		||||
 | 
			
		||||
	trans = (struct btrfs_trans_handle *)current->journal_info;
 | 
			
		||||
	space_info = __find_space_info(fs_info, BTRFS_BLOCK_GROUP_METADATA);
 | 
			
		||||
	space_info = btrfs_find_space_info(fs_info, BTRFS_BLOCK_GROUP_METADATA);
 | 
			
		||||
 | 
			
		||||
	delalloc_bytes = percpu_counter_sum_positive(
 | 
			
		||||
						&fs_info->delalloc_bytes);
 | 
			
		||||
| 
						 | 
				
			
			@ -4965,7 +4835,7 @@ static void btrfs_async_reclaim_metadata_space(struct work_struct *work)
 | 
			
		|||
	u64 last_tickets_id;
 | 
			
		||||
 | 
			
		||||
	fs_info = container_of(work, struct btrfs_fs_info, async_reclaim_work);
 | 
			
		||||
	space_info = __find_space_info(fs_info, BTRFS_BLOCK_GROUP_METADATA);
 | 
			
		||||
	space_info = btrfs_find_space_info(fs_info, BTRFS_BLOCK_GROUP_METADATA);
 | 
			
		||||
 | 
			
		||||
	spin_lock(&space_info->lock);
 | 
			
		||||
	to_reclaim = btrfs_calc_reclaim_metadata_size(fs_info, space_info,
 | 
			
		||||
| 
						 | 
				
			
			@ -5611,7 +5481,7 @@ void btrfs_init_metadata_block_rsv(struct btrfs_fs_info *fs_info,
 | 
			
		|||
				   unsigned short type)
 | 
			
		||||
{
 | 
			
		||||
	btrfs_init_block_rsv(rsv, type);
 | 
			
		||||
	rsv->space_info = __find_space_info(fs_info,
 | 
			
		||||
	rsv->space_info = btrfs_find_space_info(fs_info,
 | 
			
		||||
					    BTRFS_BLOCK_GROUP_METADATA);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -5836,10 +5706,10 @@ static void init_global_block_rsv(struct btrfs_fs_info *fs_info)
 | 
			
		|||
{
 | 
			
		||||
	struct btrfs_space_info *space_info;
 | 
			
		||||
 | 
			
		||||
	space_info = __find_space_info(fs_info, BTRFS_BLOCK_GROUP_SYSTEM);
 | 
			
		||||
	space_info = btrfs_find_space_info(fs_info, BTRFS_BLOCK_GROUP_SYSTEM);
 | 
			
		||||
	fs_info->chunk_block_rsv.space_info = space_info;
 | 
			
		||||
 | 
			
		||||
	space_info = __find_space_info(fs_info, BTRFS_BLOCK_GROUP_METADATA);
 | 
			
		||||
	space_info = btrfs_find_space_info(fs_info, BTRFS_BLOCK_GROUP_METADATA);
 | 
			
		||||
	fs_info->global_block_rsv.space_info = space_info;
 | 
			
		||||
	fs_info->trans_block_rsv.space_info = space_info;
 | 
			
		||||
	fs_info->empty_block_rsv.space_info = space_info;
 | 
			
		||||
| 
						 | 
				
			
			@ -5948,7 +5818,7 @@ int btrfs_subvolume_reserve_metadata(struct btrfs_root *root,
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	num_bytes = btrfs_calc_trans_metadata_size(fs_info, items);
 | 
			
		||||
	rsv->space_info = __find_space_info(fs_info,
 | 
			
		||||
	rsv->space_info = btrfs_find_space_info(fs_info,
 | 
			
		||||
					    BTRFS_BLOCK_GROUP_METADATA);
 | 
			
		||||
	ret = btrfs_block_rsv_add(root, rsv, num_bytes,
 | 
			
		||||
				  BTRFS_RESERVE_FLUSH_ALL);
 | 
			
		||||
| 
						 | 
				
			
			@ -7743,7 +7613,7 @@ static noinline int find_free_extent(struct btrfs_fs_info *fs_info,
 | 
			
		|||
 | 
			
		||||
	trace_find_free_extent(fs_info, num_bytes, empty_size, flags);
 | 
			
		||||
 | 
			
		||||
	space_info = __find_space_info(fs_info, flags);
 | 
			
		||||
	space_info = btrfs_find_space_info(fs_info, flags);
 | 
			
		||||
	if (!space_info) {
 | 
			
		||||
		btrfs_err(fs_info, "No space info for %llu", flags);
 | 
			
		||||
		return -ENOSPC;
 | 
			
		||||
| 
						 | 
				
			
			@ -8097,7 +7967,7 @@ int btrfs_reserve_extent(struct btrfs_root *root, u64 ram_bytes,
 | 
			
		|||
		} else if (btrfs_test_opt(fs_info, ENOSPC_DEBUG)) {
 | 
			
		||||
			struct btrfs_space_info *sinfo;
 | 
			
		||||
 | 
			
		||||
			sinfo = __find_space_info(fs_info, flags);
 | 
			
		||||
			sinfo = btrfs_find_space_info(fs_info, flags);
 | 
			
		||||
			btrfs_err(fs_info,
 | 
			
		||||
				  "allocation failed flags %llu, wanted %llu",
 | 
			
		||||
				  flags, num_bytes);
 | 
			
		||||
| 
						 | 
				
			
			@ -10130,7 +10000,7 @@ void btrfs_add_raid_kobjects(struct btrfs_fs_info *fs_info)
 | 
			
		|||
	spin_unlock(&fs_info->pending_raid_kobjs_lock);
 | 
			
		||||
 | 
			
		||||
	list_for_each_entry(rkobj, &list, list) {
 | 
			
		||||
		space_info = __find_space_info(fs_info, rkobj->flags);
 | 
			
		||||
		space_info = btrfs_find_space_info(fs_info, rkobj->flags);
 | 
			
		||||
 | 
			
		||||
		ret = kobject_add(&rkobj->kobj, &space_info->kobj,
 | 
			
		||||
				"%s", btrfs_bg_type_to_raid_name(rkobj->flags));
 | 
			
		||||
| 
						 | 
				
			
			@ -10397,9 +10267,9 @@ int btrfs_read_block_groups(struct btrfs_fs_info *info)
 | 
			
		|||
		}
 | 
			
		||||
 | 
			
		||||
		trace_btrfs_add_block_group(info, cache, 0);
 | 
			
		||||
		update_space_info(info, cache->flags, found_key.offset,
 | 
			
		||||
				  btrfs_block_group_used(&cache->item),
 | 
			
		||||
				  cache->bytes_super, &space_info);
 | 
			
		||||
		btrfs_update_space_info(info, cache->flags, found_key.offset,
 | 
			
		||||
					btrfs_block_group_used(&cache->item),
 | 
			
		||||
					cache->bytes_super, &space_info);
 | 
			
		||||
 | 
			
		||||
		cache->space_info = space_info;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -10533,7 +10403,7 @@ int btrfs_make_block_group(struct btrfs_trans_handle *trans, u64 bytes_used,
 | 
			
		|||
	 * assigned to our block group. We want our bg to be added to the rbtree
 | 
			
		||||
	 * with its ->space_info set.
 | 
			
		||||
	 */
 | 
			
		||||
	cache->space_info = __find_space_info(fs_info, cache->flags);
 | 
			
		||||
	cache->space_info = btrfs_find_space_info(fs_info, cache->flags);
 | 
			
		||||
	ASSERT(cache->space_info);
 | 
			
		||||
 | 
			
		||||
	ret = btrfs_add_block_group_cache(fs_info, cache);
 | 
			
		||||
| 
						 | 
				
			
			@ -10548,7 +10418,7 @@ int btrfs_make_block_group(struct btrfs_trans_handle *trans, u64 bytes_used,
 | 
			
		|||
	 * the rbtree, update the space info's counters.
 | 
			
		||||
	 */
 | 
			
		||||
	trace_btrfs_add_block_group(fs_info, cache, 1);
 | 
			
		||||
	update_space_info(fs_info, cache->flags, size, bytes_used,
 | 
			
		||||
	btrfs_update_space_info(fs_info, cache->flags, size, bytes_used,
 | 
			
		||||
				cache->bytes_super, &cache->space_info);
 | 
			
		||||
	update_global_block_rsv(fs_info);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -11085,43 +10955,6 @@ void btrfs_delete_unused_bgs(struct btrfs_fs_info *fs_info)
 | 
			
		|||
	spin_unlock(&fs_info->unused_bgs_lock);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int btrfs_init_space_info(struct btrfs_fs_info *fs_info)
 | 
			
		||||
{
 | 
			
		||||
	struct btrfs_super_block *disk_super;
 | 
			
		||||
	u64 features;
 | 
			
		||||
	u64 flags;
 | 
			
		||||
	int mixed = 0;
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	disk_super = fs_info->super_copy;
 | 
			
		||||
	if (!btrfs_super_root(disk_super))
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
 | 
			
		||||
	features = btrfs_super_incompat_flags(disk_super);
 | 
			
		||||
	if (features & BTRFS_FEATURE_INCOMPAT_MIXED_GROUPS)
 | 
			
		||||
		mixed = 1;
 | 
			
		||||
 | 
			
		||||
	flags = BTRFS_BLOCK_GROUP_SYSTEM;
 | 
			
		||||
	ret = create_space_info(fs_info, flags);
 | 
			
		||||
	if (ret)
 | 
			
		||||
		goto out;
 | 
			
		||||
 | 
			
		||||
	if (mixed) {
 | 
			
		||||
		flags = BTRFS_BLOCK_GROUP_METADATA | BTRFS_BLOCK_GROUP_DATA;
 | 
			
		||||
		ret = create_space_info(fs_info, flags);
 | 
			
		||||
	} else {
 | 
			
		||||
		flags = BTRFS_BLOCK_GROUP_METADATA;
 | 
			
		||||
		ret = create_space_info(fs_info, flags);
 | 
			
		||||
		if (ret)
 | 
			
		||||
			goto out;
 | 
			
		||||
 | 
			
		||||
		flags = BTRFS_BLOCK_GROUP_DATA;
 | 
			
		||||
		ret = create_space_info(fs_info, flags);
 | 
			
		||||
	}
 | 
			
		||||
out:
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int btrfs_error_unpin_extent_range(struct btrfs_fs_info *fs_info,
 | 
			
		||||
				   u64 start, u64 end)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										174
									
								
								fs/btrfs/space-info.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										174
									
								
								fs/btrfs/space-info.c
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,174 @@
 | 
			
		|||
// SPDX-License-Identifier: GPL-2.0
 | 
			
		||||
 | 
			
		||||
#include "ctree.h"
 | 
			
		||||
#include "space-info.h"
 | 
			
		||||
#include "sysfs.h"
 | 
			
		||||
#include "volumes.h"
 | 
			
		||||
 | 
			
		||||
u64 btrfs_space_info_used(struct btrfs_space_info *s_info,
 | 
			
		||||
			  bool may_use_included)
 | 
			
		||||
{
 | 
			
		||||
	ASSERT(s_info);
 | 
			
		||||
	return s_info->bytes_used + s_info->bytes_reserved +
 | 
			
		||||
		s_info->bytes_pinned + s_info->bytes_readonly +
 | 
			
		||||
		(may_use_included ? s_info->bytes_may_use : 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * after adding space to the filesystem, we need to clear the full flags
 | 
			
		||||
 * on all the space infos.
 | 
			
		||||
 */
 | 
			
		||||
void btrfs_clear_space_info_full(struct btrfs_fs_info *info)
 | 
			
		||||
{
 | 
			
		||||
	struct list_head *head = &info->space_info;
 | 
			
		||||
	struct btrfs_space_info *found;
 | 
			
		||||
 | 
			
		||||
	rcu_read_lock();
 | 
			
		||||
	list_for_each_entry_rcu(found, head, list)
 | 
			
		||||
		found->full = 0;
 | 
			
		||||
	rcu_read_unlock();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const char *alloc_name(u64 flags)
 | 
			
		||||
{
 | 
			
		||||
	switch (flags) {
 | 
			
		||||
	case BTRFS_BLOCK_GROUP_METADATA|BTRFS_BLOCK_GROUP_DATA:
 | 
			
		||||
		return "mixed";
 | 
			
		||||
	case BTRFS_BLOCK_GROUP_METADATA:
 | 
			
		||||
		return "metadata";
 | 
			
		||||
	case BTRFS_BLOCK_GROUP_DATA:
 | 
			
		||||
		return "data";
 | 
			
		||||
	case BTRFS_BLOCK_GROUP_SYSTEM:
 | 
			
		||||
		return "system";
 | 
			
		||||
	default:
 | 
			
		||||
		WARN_ON(1);
 | 
			
		||||
		return "invalid-combination";
 | 
			
		||||
	};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int create_space_info(struct btrfs_fs_info *info, u64 flags)
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
	struct btrfs_space_info *space_info;
 | 
			
		||||
	int i;
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	space_info = kzalloc(sizeof(*space_info), GFP_NOFS);
 | 
			
		||||
	if (!space_info)
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
 | 
			
		||||
	ret = percpu_counter_init(&space_info->total_bytes_pinned, 0,
 | 
			
		||||
				 GFP_KERNEL);
 | 
			
		||||
	if (ret) {
 | 
			
		||||
		kfree(space_info);
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < BTRFS_NR_RAID_TYPES; i++)
 | 
			
		||||
		INIT_LIST_HEAD(&space_info->block_groups[i]);
 | 
			
		||||
	init_rwsem(&space_info->groups_sem);
 | 
			
		||||
	spin_lock_init(&space_info->lock);
 | 
			
		||||
	space_info->flags = flags & BTRFS_BLOCK_GROUP_TYPE_MASK;
 | 
			
		||||
	space_info->force_alloc = CHUNK_ALLOC_NO_FORCE;
 | 
			
		||||
	init_waitqueue_head(&space_info->wait);
 | 
			
		||||
	INIT_LIST_HEAD(&space_info->ro_bgs);
 | 
			
		||||
	INIT_LIST_HEAD(&space_info->tickets);
 | 
			
		||||
	INIT_LIST_HEAD(&space_info->priority_tickets);
 | 
			
		||||
 | 
			
		||||
	ret = kobject_init_and_add(&space_info->kobj, &space_info_ktype,
 | 
			
		||||
				    info->space_info_kobj, "%s",
 | 
			
		||||
				    alloc_name(space_info->flags));
 | 
			
		||||
	if (ret) {
 | 
			
		||||
		kobject_put(&space_info->kobj);
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	list_add_rcu(&space_info->list, &info->space_info);
 | 
			
		||||
	if (flags & BTRFS_BLOCK_GROUP_DATA)
 | 
			
		||||
		info->data_sinfo = space_info;
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int btrfs_init_space_info(struct btrfs_fs_info *fs_info)
 | 
			
		||||
{
 | 
			
		||||
	struct btrfs_super_block *disk_super;
 | 
			
		||||
	u64 features;
 | 
			
		||||
	u64 flags;
 | 
			
		||||
	int mixed = 0;
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	disk_super = fs_info->super_copy;
 | 
			
		||||
	if (!btrfs_super_root(disk_super))
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
 | 
			
		||||
	features = btrfs_super_incompat_flags(disk_super);
 | 
			
		||||
	if (features & BTRFS_FEATURE_INCOMPAT_MIXED_GROUPS)
 | 
			
		||||
		mixed = 1;
 | 
			
		||||
 | 
			
		||||
	flags = BTRFS_BLOCK_GROUP_SYSTEM;
 | 
			
		||||
	ret = create_space_info(fs_info, flags);
 | 
			
		||||
	if (ret)
 | 
			
		||||
		goto out;
 | 
			
		||||
 | 
			
		||||
	if (mixed) {
 | 
			
		||||
		flags = BTRFS_BLOCK_GROUP_METADATA | BTRFS_BLOCK_GROUP_DATA;
 | 
			
		||||
		ret = create_space_info(fs_info, flags);
 | 
			
		||||
	} else {
 | 
			
		||||
		flags = BTRFS_BLOCK_GROUP_METADATA;
 | 
			
		||||
		ret = create_space_info(fs_info, flags);
 | 
			
		||||
		if (ret)
 | 
			
		||||
			goto out;
 | 
			
		||||
 | 
			
		||||
		flags = BTRFS_BLOCK_GROUP_DATA;
 | 
			
		||||
		ret = create_space_info(fs_info, flags);
 | 
			
		||||
	}
 | 
			
		||||
out:
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void btrfs_update_space_info(struct btrfs_fs_info *info, u64 flags,
 | 
			
		||||
			     u64 total_bytes, u64 bytes_used,
 | 
			
		||||
			     u64 bytes_readonly,
 | 
			
		||||
			     struct btrfs_space_info **space_info)
 | 
			
		||||
{
 | 
			
		||||
	struct btrfs_space_info *found;
 | 
			
		||||
	int factor;
 | 
			
		||||
 | 
			
		||||
	factor = btrfs_bg_type_to_factor(flags);
 | 
			
		||||
 | 
			
		||||
	found = btrfs_find_space_info(info, flags);
 | 
			
		||||
	ASSERT(found);
 | 
			
		||||
	spin_lock(&found->lock);
 | 
			
		||||
	found->total_bytes += total_bytes;
 | 
			
		||||
	found->disk_total += total_bytes * factor;
 | 
			
		||||
	found->bytes_used += bytes_used;
 | 
			
		||||
	found->disk_used += bytes_used * factor;
 | 
			
		||||
	found->bytes_readonly += bytes_readonly;
 | 
			
		||||
	if (total_bytes > 0)
 | 
			
		||||
		found->full = 0;
 | 
			
		||||
	btrfs_space_info_add_new_bytes(info, found,
 | 
			
		||||
				       total_bytes - bytes_used -
 | 
			
		||||
				       bytes_readonly);
 | 
			
		||||
	spin_unlock(&found->lock);
 | 
			
		||||
	*space_info = found;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct btrfs_space_info *btrfs_find_space_info(struct btrfs_fs_info *info,
 | 
			
		||||
					       u64 flags)
 | 
			
		||||
{
 | 
			
		||||
	struct list_head *head = &info->space_info;
 | 
			
		||||
	struct btrfs_space_info *found;
 | 
			
		||||
 | 
			
		||||
	flags &= BTRFS_BLOCK_GROUP_TYPE_MASK;
 | 
			
		||||
 | 
			
		||||
	rcu_read_lock();
 | 
			
		||||
	list_for_each_entry_rcu(found, head, list) {
 | 
			
		||||
		if (found->flags & flags) {
 | 
			
		||||
			rcu_read_unlock();
 | 
			
		||||
			return found;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	rcu_read_unlock();
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -81,5 +81,15 @@ void btrfs_space_info_add_new_bytes(struct btrfs_fs_info *fs_info,
 | 
			
		|||
void btrfs_space_info_add_old_bytes(struct btrfs_fs_info *fs_info,
 | 
			
		||||
				    struct btrfs_space_info *space_info,
 | 
			
		||||
				    u64 num_bytes);
 | 
			
		||||
int btrfs_init_space_info(struct btrfs_fs_info *fs_info);
 | 
			
		||||
void btrfs_update_space_info(struct btrfs_fs_info *info, u64 flags,
 | 
			
		||||
			     u64 total_bytes, u64 bytes_used,
 | 
			
		||||
			     u64 bytes_readonly,
 | 
			
		||||
			     struct btrfs_space_info **space_info);
 | 
			
		||||
struct btrfs_space_info *btrfs_find_space_info(struct btrfs_fs_info *info,
 | 
			
		||||
					       u64 flags);
 | 
			
		||||
u64 btrfs_space_info_used(struct btrfs_space_info *s_info,
 | 
			
		||||
			  bool may_use_included);
 | 
			
		||||
void btrfs_clear_space_info_full(struct btrfs_fs_info *info);
 | 
			
		||||
 | 
			
		||||
#endif /* BTRFS_SPACE_INFO_H */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue