Commit d601e58c authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull btrfs updates from David Sterba:
 "This end of the year branch is intentionally not that exciting. Most
  of the changes are under the hood, but there are some minor user
  visible improvements and several performance improvements too.

  Features:

   - make send work with concurrent block group relocation.

     We're not allowed to prevent send failing or silently producing
     some bad stream but with more fine grained locking and checks it's
     possible. The send vs deduplication exclusion could reuse the same
     logic in the future.

   - new exclusive operation 'balance paused' to allow adding a device
     to filesystem with paused balance

   - new sysfs file for fsid stored in the per-device directory to help
     distinguish devices when seeding is enabled, the fsid may differ
     from the one reported by the filesystem

  Performance improvements:

   - less metadata needed for directory logging, directory deletion is
     20-40% faster

   - in zoned mode, cache zone information during mount to speed up
     repeated queries (about 50% speedup)

   - free space tree entries get indexed and searched by size (latency
     -30%, search run time -30%)

   - less contention in tree node locking when inserting a key and no
     splits are needed (files/sec in fsmark improves by 1-20%)

  Fixes:

   - fix ENOSPC failure when attempting direct IO write into NOCOW range

   - fix deadlock between quota enable and other quota operations

   - global reserve minimum calculations fixed to account for free space
     tree

   - in zoned mode, fix condition for chunk allocation that may not find
     the right zone for reuse and could lead to early ENOSPC

  Core:

   - global reserve stealing got simplified and cleaned up in evict

   - remove async transaction commit based on manual transaction refs,
     reuse existing kthread and mechanisms to let it commit transaction
     before timeout

   - preparatory work for extent tree v2, add wrappers for global tree
     roots, truncation path cleanups

   - remove readahead framework, it's a bit overengineered and used only
     for scrub, and yet it does not cover all its needs, there is
     another readahead built in the b-tree search that is now used,
     performance drop on HDD is about 5% which is acceptable and scrub
     is often throttled anyway, on SSDs there's no reported drop but
     slight improvement

   - self tests report extent tree state when error occurs

   - replace assert with debugging information when an uncommitted
     transaction is found at unmount time

  Other:

   - error handling improvements

   - other cleanups and refactoring"

* tag 'for-5.17-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux: (115 commits)
  btrfs: output more debug messages for uncommitted transaction
  btrfs: respect the max size in the header when activating swap file
  btrfs: fix argument list that the kdoc format and script verified
  btrfs: remove unnecessary parameter type from compression_decompress_bio
  btrfs: selftests: dump extent io tree if extent-io-tree test failed
  btrfs: scrub: cleanup the argument list of scrub_stripe()
  btrfs: scrub: cleanup the argument list of scrub_chunk()
  btrfs: remove reada infrastructure
  btrfs: scrub: use btrfs_path::reada for extent tree readahead
  btrfs: scrub: remove the unnecessary path parameter for scrub_raid56_parity()
  btrfs: refactor unlock_up
  btrfs: skip transaction commit after failure to create subvolume
  btrfs: zoned: fix chunk allocation condition for zoned allocator
  btrfs: add extent allocator hook to decide to allocate chunk or not
  btrfs: zoned: unset dedicated block group on allocation failure
  btrfs: zoned: drop redundant check for REQ_OP_ZONE_APPEND and btrfs_is_zoned
  btrfs: zoned: sink zone check into btrfs_repair_one_zone
  btrfs: zoned: simplify btrfs_check_meta_write_pointer
  btrfs: zoned: encapsulate inode locking for zoned relocation
  btrfs: sysfs: add devinfo/fsid to retrieve actual fsid from the device
  ...
parents 9149fe8b 36c86a9e
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -27,7 +27,7 @@ btrfs-y += super.o ctree.o extent-tree.o print-tree.o root-tree.o dir-item.o \
	   extent_io.o volumes.o async-thread.o ioctl.o locking.o orphan.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 \
	   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 space-info.o \
	   block-rsv.o delalloc-space.o block-group.o discard.o reflink.o \
	   subpage.o tree-mod-log.o
+43 −34
Original line number Diff line number Diff line
@@ -950,7 +950,7 @@ static int add_inline_refs(const struct btrfs_fs_info *fs_info,
	leaf = path->nodes[0];
	slot = path->slots[0];

	item_size = btrfs_item_size_nr(leaf, slot);
	item_size = btrfs_item_size(leaf, slot);
	BUG_ON(item_size < sizeof(*ei));

	ei = btrfs_item_ptr(leaf, slot, struct btrfs_extent_item);
@@ -1049,12 +1049,12 @@ static int add_inline_refs(const struct btrfs_fs_info *fs_info,
 *
 * Returns 0 on success, <0 on error, or BACKREF_FOUND_SHARED.
 */
static int add_keyed_refs(struct btrfs_fs_info *fs_info,
static int add_keyed_refs(struct btrfs_root *extent_root,
			  struct btrfs_path *path, u64 bytenr,
			  int info_level, struct preftrees *preftrees,
			  struct share_check *sc)
{
	struct btrfs_root *extent_root = fs_info->extent_root;
	struct btrfs_fs_info *fs_info = extent_root->fs_info;
	int ret;
	int slot;
	struct extent_buffer *leaf;
@@ -1170,6 +1170,7 @@ static int find_parent_nodes(struct btrfs_trans_handle *trans,
			     struct ulist *roots, const u64 *extent_item_pos,
			     struct share_check *sc, bool ignore_offset)
{
	struct btrfs_root *root = btrfs_extent_root(fs_info, bytenr);
	struct btrfs_key key;
	struct btrfs_path *path;
	struct btrfs_delayed_ref_root *delayed_refs = NULL;
@@ -1203,28 +1204,26 @@ static int find_parent_nodes(struct btrfs_trans_handle *trans,
	if (time_seq == BTRFS_SEQ_LAST)
		path->skip_locking = 1;

	/*
	 * grab both a lock on the path and a lock on the delayed ref head.
	 * We need both to get a consistent picture of how the refs look
	 * at a specified point in time
	 */
again:
	head = NULL;

	ret = btrfs_search_slot(NULL, fs_info->extent_root, &key, path, 0, 0);
	ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
	if (ret < 0)
		goto out;
	BUG_ON(ret == 0);
	if (ret == 0) {
		/* This shouldn't happen, indicates a bug or fs corruption. */
		ASSERT(ret != 0);
		ret = -EUCLEAN;
		goto out;
	}

#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS
	if (trans && likely(trans->type != __TRANS_DUMMY) &&
	    time_seq != BTRFS_SEQ_LAST) {
#else
	if (trans && time_seq != BTRFS_SEQ_LAST) {
#endif
		/*
		 * look if there are updates for this ref queued and lock the
		 * head
		 * We have a specific time_seq we care about and trans which
		 * means we have the path lock, we need to grab the ref head and
		 * lock it so we have a consistent view of the refs at the given
		 * time.
		 */
		delayed_refs = &trans->transaction->delayed_refs;
		spin_lock(&delayed_refs->lock);
@@ -1271,7 +1270,7 @@ static int find_parent_nodes(struct btrfs_trans_handle *trans,
					      &info_level, &preftrees, sc);
			if (ret)
				goto out;
			ret = add_keyed_refs(fs_info, path, bytenr, info_level,
			ret = add_keyed_refs(root, path, bytenr, info_level,
					     &preftrees, sc);
			if (ret)
				goto out;
@@ -1360,10 +1359,18 @@ static int find_parent_nodes(struct btrfs_trans_handle *trans,
				goto out;
			if (!ret && extent_item_pos) {
				/*
				 * we've recorded that parent, so we must extend
				 * its inode list here
				 * We've recorded that parent, so we must extend
				 * its inode list here.
				 *
				 * However if there was corruption we may not
				 * have found an eie, return an error in this
				 * case.
				 */
				BUG_ON(!eie);
				ASSERT(eie);
				if (!eie) {
					ret = -EUCLEAN;
					goto out;
				}
				while (eie->next)
					eie = eie->next;
				eie->next = ref->inode_list;
@@ -1740,6 +1747,7 @@ int extent_from_logical(struct btrfs_fs_info *fs_info, u64 logical,
			struct btrfs_path *path, struct btrfs_key *found_key,
			u64 *flags_ret)
{
	struct btrfs_root *extent_root = btrfs_extent_root(fs_info, logical);
	int ret;
	u64 flags;
	u64 size = 0;
@@ -1755,11 +1763,11 @@ int extent_from_logical(struct btrfs_fs_info *fs_info, u64 logical,
	key.objectid = logical;
	key.offset = (u64)-1;

	ret = btrfs_search_slot(NULL, fs_info->extent_root, &key, path, 0, 0);
	ret = btrfs_search_slot(NULL, extent_root, &key, path, 0, 0);
	if (ret < 0)
		return ret;

	ret = btrfs_previous_extent_item(fs_info->extent_root, path, 0);
	ret = btrfs_previous_extent_item(extent_root, path, 0);
	if (ret) {
		if (ret > 0)
			ret = -ENOENT;
@@ -1779,7 +1787,7 @@ int extent_from_logical(struct btrfs_fs_info *fs_info, u64 logical,
	}

	eb = path->nodes[0];
	item_size = btrfs_item_size_nr(eb, path->slots[0]);
	item_size = btrfs_item_size(eb, path->slots[0]);
	BUG_ON(item_size < sizeof(*ei));

	ei = btrfs_item_ptr(eb, path->slots[0], struct btrfs_extent_item);
@@ -1962,7 +1970,7 @@ int iterate_extent_inodes(struct btrfs_fs_info *fs_info,
			extent_item_objectid);

	if (!search_commit_root) {
		trans = btrfs_attach_transaction(fs_info->extent_root);
		trans = btrfs_attach_transaction(fs_info->tree_root);
		if (IS_ERR(trans)) {
			if (PTR_ERR(trans) != -ENOENT &&
			    PTR_ERR(trans) != -EROFS)
@@ -2058,7 +2066,6 @@ static int iterate_inode_refs(u64 inum, struct btrfs_root *fs_root,
	u64 parent = 0;
	int found = 0;
	struct extent_buffer *eb;
	struct btrfs_item *item;
	struct btrfs_inode_ref *iref;
	struct btrfs_key found_key;

@@ -2084,10 +2091,9 @@ static int iterate_inode_refs(u64 inum, struct btrfs_root *fs_root,
		}
		btrfs_release_path(path);

		item = btrfs_item_nr(slot);
		iref = btrfs_item_ptr(eb, slot, struct btrfs_inode_ref);

		for (cur = 0; cur < btrfs_item_size(eb, item); cur += len) {
		for (cur = 0; cur < btrfs_item_size(eb, slot); cur += len) {
			name_len = btrfs_inode_ref_name_len(eb, iref);
			/* path must be released before calling iterate()! */
			btrfs_debug(fs_root->fs_info,
@@ -2143,7 +2149,7 @@ static int iterate_inode_extrefs(u64 inum, struct btrfs_root *fs_root,
		}
		btrfs_release_path(path);

		item_size = btrfs_item_size_nr(eb, slot);
		item_size = btrfs_item_size(eb, slot);
		ptr = btrfs_item_ptr_offset(eb, slot);
		cur_offset = 0;

@@ -2330,6 +2336,7 @@ struct btrfs_backref_iter *btrfs_backref_iter_alloc(
int btrfs_backref_iter_start(struct btrfs_backref_iter *iter, u64 bytenr)
{
	struct btrfs_fs_info *fs_info = iter->fs_info;
	struct btrfs_root *extent_root = btrfs_extent_root(fs_info, bytenr);
	struct btrfs_path *path = iter->path;
	struct btrfs_extent_item *ei;
	struct btrfs_key key;
@@ -2340,7 +2347,7 @@ int btrfs_backref_iter_start(struct btrfs_backref_iter *iter, u64 bytenr)
	key.offset = (u64)-1;
	iter->bytenr = bytenr;

	ret = btrfs_search_slot(NULL, fs_info->extent_root, &key, path, 0, 0);
	ret = btrfs_search_slot(NULL, extent_root, &key, path, 0, 0);
	if (ret < 0)
		return ret;
	if (ret == 0) {
@@ -2364,7 +2371,7 @@ int btrfs_backref_iter_start(struct btrfs_backref_iter *iter, u64 bytenr)
	iter->item_ptr = (u32)btrfs_item_ptr_offset(path->nodes[0],
						    path->slots[0]);
	iter->end_ptr = (u32)(iter->item_ptr +
			btrfs_item_size_nr(path->nodes[0], path->slots[0]));
			btrfs_item_size(path->nodes[0], path->slots[0]));
	ei = btrfs_item_ptr(path->nodes[0], path->slots[0],
			    struct btrfs_extent_item);

@@ -2383,7 +2390,7 @@ int btrfs_backref_iter_start(struct btrfs_backref_iter *iter, u64 bytenr)

	/* If there is no inline backref, go search for keyed backref */
	if (iter->cur_ptr >= iter->end_ptr) {
		ret = btrfs_next_item(fs_info->extent_root, path);
		ret = btrfs_next_item(extent_root, path);

		/* No inline nor keyed ref */
		if (ret > 0) {
@@ -2404,7 +2411,7 @@ int btrfs_backref_iter_start(struct btrfs_backref_iter *iter, u64 bytenr)
		iter->cur_ptr = (u32)btrfs_item_ptr_offset(path->nodes[0],
							   path->slots[0]);
		iter->item_ptr = iter->cur_ptr;
		iter->end_ptr = (u32)(iter->item_ptr + btrfs_item_size_nr(
		iter->end_ptr = (u32)(iter->item_ptr + btrfs_item_size(
				      path->nodes[0], path->slots[0]));
	}

@@ -2427,6 +2434,7 @@ int btrfs_backref_iter_start(struct btrfs_backref_iter *iter, u64 bytenr)
int btrfs_backref_iter_next(struct btrfs_backref_iter *iter)
{
	struct extent_buffer *eb = btrfs_backref_get_eb(iter);
	struct btrfs_root *extent_root;
	struct btrfs_path *path = iter->path;
	struct btrfs_extent_inline_ref *iref;
	int ret;
@@ -2457,7 +2465,8 @@ int btrfs_backref_iter_next(struct btrfs_backref_iter *iter)
	}

	/* We're at keyed items, there is no inline item, go to the next one */
	ret = btrfs_next_item(iter->fs_info->extent_root, iter->path);
	extent_root = btrfs_extent_root(iter->fs_info, iter->bytenr);
	ret = btrfs_next_item(extent_root, iter->path);
	if (ret)
		return ret;

@@ -2469,7 +2478,7 @@ int btrfs_backref_iter_next(struct btrfs_backref_iter *iter)
	iter->item_ptr = (u32)btrfs_item_ptr_offset(path->nodes[0],
					path->slots[0]);
	iter->cur_ptr = iter->item_ptr;
	iter->end_ptr = iter->item_ptr + (u32)btrfs_item_size_nr(path->nodes[0],
	iter->end_ptr = iter->item_ptr + (u32)btrfs_item_size(path->nodes[0],
						path->slots[0]);
	return 0;
}
+15 −20
Original line number Diff line number Diff line
@@ -514,7 +514,7 @@ static int load_extent_tree_free(struct btrfs_caching_control *caching_ctl)
{
	struct btrfs_block_group *block_group = caching_ctl->block_group;
	struct btrfs_fs_info *fs_info = block_group->fs_info;
	struct btrfs_root *extent_root = fs_info->extent_root;
	struct btrfs_root *extent_root;
	struct btrfs_path *path;
	struct extent_buffer *leaf;
	struct btrfs_key key;
@@ -529,6 +529,7 @@ static int load_extent_tree_free(struct btrfs_caching_control *caching_ctl)
		return -ENOMEM;

	last = max_t(u64, block_group->start, BTRFS_SUPER_INFO_OFFSET);
	extent_root = btrfs_extent_root(fs_info, last);

#ifdef CONFIG_BTRFS_DEBUG
	/*
@@ -841,7 +842,7 @@ static int remove_block_group_item(struct btrfs_trans_handle *trans,
	struct btrfs_key key;
	int ret;

	root = fs_info->extent_root;
	root = btrfs_block_group_root(fs_info);
	key.objectid = block_group->start;
	key.type = BTRFS_BLOCK_GROUP_ITEM_KEY;
	key.offset = block_group->length;
@@ -1106,6 +1107,7 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans,
struct btrfs_trans_handle *btrfs_start_trans_remove_block_group(
		struct btrfs_fs_info *fs_info, const u64 chunk_offset)
{
	struct btrfs_root *root = btrfs_block_group_root(fs_info);
	struct extent_map_tree *em_tree = &fs_info->mapping_tree;
	struct extent_map *em;
	struct map_lookup *map;
@@ -1139,8 +1141,7 @@ struct btrfs_trans_handle *btrfs_start_trans_remove_block_group(
	num_items = 3 + map->num_stripes;
	free_extent_map(em);

	return btrfs_start_transaction_fallback_global_rsv(fs_info->extent_root,
							   num_items);
	return btrfs_start_transaction_fallback_global_rsv(root, num_items);
}

/*
@@ -1508,7 +1509,6 @@ void btrfs_reclaim_bgs_work(struct work_struct *work)
		container_of(work, struct btrfs_fs_info, reclaim_bgs_work);
	struct btrfs_block_group *bg;
	struct btrfs_space_info *space_info;
	LIST_HEAD(again_list);

	if (!test_bit(BTRFS_FS_OPEN, &fs_info->flags))
		return;
@@ -1585,18 +1585,14 @@ void btrfs_reclaim_bgs_work(struct work_struct *work)
				div64_u64(zone_unusable * 100, bg->length));
		trace_btrfs_reclaim_block_group(bg);
		ret = btrfs_relocate_chunk(fs_info, bg->start);
		if (ret && ret != -EAGAIN)
		if (ret)
			btrfs_err(fs_info, "error relocating chunk %llu",
				  bg->start);

next:
		spin_lock(&fs_info->unused_bgs_lock);
		if (ret == -EAGAIN && list_empty(&bg->bg_list))
			list_add_tail(&bg->bg_list, &again_list);
		else
		btrfs_put_block_group(bg);
		spin_lock(&fs_info->unused_bgs_lock);
	}
	list_splice_tail(&again_list, &fs_info->reclaim_bgs);
	spin_unlock(&fs_info->unused_bgs_lock);
	mutex_unlock(&fs_info->reclaim_bgs_lock);
	btrfs_exclop_finish(fs_info);
@@ -1678,7 +1674,7 @@ static int find_first_block_group(struct btrfs_fs_info *fs_info,
				  struct btrfs_path *path,
				  struct btrfs_key *key)
{
	struct btrfs_root *root = fs_info->extent_root;
	struct btrfs_root *root = btrfs_block_group_root(fs_info);
	int ret;
	struct btrfs_key found_key;
	struct extent_buffer *leaf;
@@ -2165,6 +2161,7 @@ static int fill_dummy_bgs(struct btrfs_fs_info *fs_info)

int btrfs_read_block_groups(struct btrfs_fs_info *info)
{
	struct btrfs_root *root = btrfs_block_group_root(info);
	struct btrfs_path *path;
	int ret;
	struct btrfs_block_group *cache;
@@ -2173,7 +2170,7 @@ int btrfs_read_block_groups(struct btrfs_fs_info *info)
	int need_clear = 0;
	u64 cache_gen;

	if (!info->extent_root)
	if (!root)
		return fill_dummy_bgs(info);

	key.objectid = 0;
@@ -2276,7 +2273,7 @@ static int insert_block_group_item(struct btrfs_trans_handle *trans,
{
	struct btrfs_fs_info *fs_info = trans->fs_info;
	struct btrfs_block_group_item bgi;
	struct btrfs_root *root;
	struct btrfs_root *root = btrfs_block_group_root(fs_info);
	struct btrfs_key key;

	spin_lock(&block_group->lock);
@@ -2289,7 +2286,6 @@ static int insert_block_group_item(struct btrfs_trans_handle *trans,
	key.offset = block_group->length;
	spin_unlock(&block_group->lock);

	root = fs_info->extent_root;
	return btrfs_insert_item(trans, root, &key, &bgi, sizeof(bgi));
}

@@ -2543,12 +2539,13 @@ int btrfs_inc_block_group_ro(struct btrfs_block_group *cache,
{
	struct btrfs_fs_info *fs_info = cache->fs_info;
	struct btrfs_trans_handle *trans;
	struct btrfs_root *root = btrfs_block_group_root(fs_info);
	u64 alloc_flags;
	int ret;
	bool dirty_bg_running;

	do {
		trans = btrfs_join_transaction(fs_info->extent_root);
		trans = btrfs_join_transaction(root);
		if (IS_ERR(trans))
			return PTR_ERR(trans);

@@ -2653,7 +2650,7 @@ static int update_block_group_item(struct btrfs_trans_handle *trans,
{
	struct btrfs_fs_info *fs_info = trans->fs_info;
	int ret;
	struct btrfs_root *root = fs_info->extent_root;
	struct btrfs_root *root = btrfs_block_group_root(fs_info);
	unsigned long bi;
	struct extent_buffer *leaf;
	struct btrfs_block_group_item bgi;
@@ -3790,7 +3787,7 @@ static void reserve_chunk_space(struct btrfs_trans_handle *trans,
	}

	if (!ret) {
		ret = btrfs_block_rsv_add(fs_info->chunk_root,
		ret = btrfs_block_rsv_add(fs_info,
					  &fs_info->chunk_block_rsv,
					  bytes, BTRFS_RESERVE_NO_FLUSH);
		if (!ret)
@@ -3911,9 +3908,7 @@ int btrfs_free_block_groups(struct btrfs_fs_info *info)
		list_del_init(&block_group->bg_list);
		btrfs_put_block_group(block_group);
	}
	spin_unlock(&info->unused_bgs_lock);

	spin_lock(&info->unused_bgs_lock);
	while (!list_empty(&info->reclaim_bgs)) {
		block_group = list_first_entry(&info->reclaim_bgs,
					       struct btrfs_block_group,
+50 −34
Original line number Diff line number Diff line
@@ -6,6 +6,7 @@
#include "space-info.h"
#include "transaction.h"
#include "block-group.h"
#include "disk-io.h"

/*
 * HOW DO BLOCK RESERVES WORK
@@ -208,7 +209,7 @@ void btrfs_free_block_rsv(struct btrfs_fs_info *fs_info,
	kfree(rsv);
}

int btrfs_block_rsv_add(struct btrfs_root *root,
int btrfs_block_rsv_add(struct btrfs_fs_info *fs_info,
			struct btrfs_block_rsv *block_rsv, u64 num_bytes,
			enum btrfs_reserve_flush_enum flush)
{
@@ -217,7 +218,7 @@ int btrfs_block_rsv_add(struct btrfs_root *root,
	if (num_bytes == 0)
		return 0;

	ret = btrfs_reserve_metadata_bytes(root, block_rsv, num_bytes, flush);
	ret = btrfs_reserve_metadata_bytes(fs_info, block_rsv, num_bytes, flush);
	if (!ret)
		btrfs_block_rsv_add_bytes(block_rsv, num_bytes, true);

@@ -241,7 +242,7 @@ int btrfs_block_rsv_check(struct btrfs_block_rsv *block_rsv, int min_factor)
	return ret;
}

int btrfs_block_rsv_refill(struct btrfs_root *root,
int btrfs_block_rsv_refill(struct btrfs_fs_info *fs_info,
			   struct btrfs_block_rsv *block_rsv, u64 min_reserved,
			   enum btrfs_reserve_flush_enum flush)
{
@@ -262,7 +263,7 @@ int btrfs_block_rsv_refill(struct btrfs_root *root,
	if (!ret)
		return 0;

	ret = btrfs_reserve_metadata_bytes(root, block_rsv, num_bytes, flush);
	ret = btrfs_reserve_metadata_bytes(fs_info, block_rsv, num_bytes, flush);
	if (!ret) {
		btrfs_block_rsv_add_bytes(block_rsv, num_bytes, false);
		return 0;
@@ -351,23 +352,29 @@ void btrfs_update_global_block_rsv(struct btrfs_fs_info *fs_info)
{
	struct btrfs_block_rsv *block_rsv = &fs_info->global_block_rsv;
	struct btrfs_space_info *sinfo = block_rsv->space_info;
	u64 num_bytes;
	unsigned min_items;
	struct btrfs_root *root, *tmp;
	u64 num_bytes = btrfs_root_used(&fs_info->tree_root->root_item);
	unsigned int min_items = 1;

	/*
	 * The global block rsv is based on the size of the extent tree, the
	 * checksum tree and the root tree.  If the fs is empty we want to set
	 * it to a minimal amount for safety.
	 *
	 * We also are going to need to modify the minimum of the tree root and
	 * any global roots we could touch.
	 */
	num_bytes = btrfs_root_used(&fs_info->extent_root->root_item) +
		btrfs_root_used(&fs_info->csum_root->root_item) +
		btrfs_root_used(&fs_info->tree_root->root_item);

	/*
	 * We at a minimum are going to modify the csum root, the tree root, and
	 * the extent root.
	 */
	min_items = 3;
	read_lock(&fs_info->global_root_lock);
	rbtree_postorder_for_each_entry_safe(root, tmp, &fs_info->global_root_tree,
					     rb_node) {
		if (root->root_key.objectid == BTRFS_EXTENT_TREE_OBJECTID ||
		    root->root_key.objectid == BTRFS_CSUM_TREE_OBJECTID ||
		    root->root_key.objectid == BTRFS_FREE_SPACE_TREE_OBJECTID) {
			num_bytes += btrfs_root_used(&root->root_item);
			min_items++;
		}
	}
	read_unlock(&fs_info->global_root_lock);

	/*
	 * But we also want to reserve enough space so we can do the fallback
@@ -412,6 +419,30 @@ void btrfs_update_global_block_rsv(struct btrfs_fs_info *fs_info)
	spin_unlock(&sinfo->lock);
}

void btrfs_init_root_block_rsv(struct btrfs_root *root)
{
	struct btrfs_fs_info *fs_info = root->fs_info;

	switch (root->root_key.objectid) {
	case BTRFS_CSUM_TREE_OBJECTID:
	case BTRFS_EXTENT_TREE_OBJECTID:
	case BTRFS_FREE_SPACE_TREE_OBJECTID:
		root->block_rsv = &fs_info->delayed_refs_rsv;
		break;
	case BTRFS_ROOT_TREE_OBJECTID:
	case BTRFS_DEV_TREE_OBJECTID:
	case BTRFS_QUOTA_TREE_OBJECTID:
		root->block_rsv = &fs_info->global_block_rsv;
		break;
	case BTRFS_CHUNK_TREE_OBJECTID:
		root->block_rsv = &fs_info->chunk_block_rsv;
		break;
	default:
		root->block_rsv = NULL;
		break;
	}
}

void btrfs_init_global_block_rsv(struct btrfs_fs_info *fs_info)
{
	struct btrfs_space_info *space_info;
@@ -426,22 +457,6 @@ void btrfs_init_global_block_rsv(struct btrfs_fs_info *fs_info)
	fs_info->delayed_block_rsv.space_info = space_info;
	fs_info->delayed_refs_rsv.space_info = space_info;

	/*
	 * Our various recovery options can leave us with NULL roots, so check
	 * here and just bail before we go dereferencing NULLs everywhere.
	 */
	if (!fs_info->extent_root || !fs_info->csum_root ||
	    !fs_info->dev_root || !fs_info->chunk_root || !fs_info->tree_root)
		return;

	fs_info->extent_root->block_rsv = &fs_info->delayed_refs_rsv;
	fs_info->csum_root->block_rsv = &fs_info->delayed_refs_rsv;
	fs_info->dev_root->block_rsv = &fs_info->global_block_rsv;
	fs_info->tree_root->block_rsv = &fs_info->global_block_rsv;
	if (fs_info->quota_root)
		fs_info->quota_root->block_rsv = &fs_info->global_block_rsv;
	fs_info->chunk_root->block_rsv = &fs_info->chunk_block_rsv;

	btrfs_update_global_block_rsv(fs_info);
}

@@ -467,8 +482,9 @@ static struct btrfs_block_rsv *get_block_rsv(
	struct btrfs_block_rsv *block_rsv = NULL;

	if (test_bit(BTRFS_ROOT_SHAREABLE, &root->state) ||
	    (root == fs_info->csum_root && trans->adding_csums) ||
	    (root == fs_info->uuid_root))
	    (root == fs_info->uuid_root) ||
	    (trans->adding_csums &&
	     root->root_key.objectid == BTRFS_CSUM_TREE_OBJECTID))
		block_rsv = trans->block_rsv;

	if (!block_rsv)
@@ -523,7 +539,7 @@ struct btrfs_block_rsv *btrfs_use_block_rsv(struct btrfs_trans_handle *trans,
				block_rsv->type, ret);
	}
try_reserve:
	ret = btrfs_reserve_metadata_bytes(root, block_rsv, blocksize,
	ret = btrfs_reserve_metadata_bytes(fs_info, block_rsv, blocksize,
					   BTRFS_RESERVE_NO_FLUSH);
	if (!ret)
		return block_rsv;
+3 −2
Original line number Diff line number Diff line
@@ -50,6 +50,7 @@ struct btrfs_block_rsv {
};

void btrfs_init_block_rsv(struct btrfs_block_rsv *rsv, unsigned short type);
void btrfs_init_root_block_rsv(struct btrfs_root *root);
struct btrfs_block_rsv *btrfs_alloc_block_rsv(struct btrfs_fs_info *fs_info,
					      unsigned short type);
void btrfs_init_metadata_block_rsv(struct btrfs_fs_info *fs_info,
@@ -57,11 +58,11 @@ void btrfs_init_metadata_block_rsv(struct btrfs_fs_info *fs_info,
				   unsigned short type);
void btrfs_free_block_rsv(struct btrfs_fs_info *fs_info,
			  struct btrfs_block_rsv *rsv);
int btrfs_block_rsv_add(struct btrfs_root *root,
int btrfs_block_rsv_add(struct btrfs_fs_info *fs_info,
			struct btrfs_block_rsv *block_rsv, u64 num_bytes,
			enum btrfs_reserve_flush_enum flush);
int btrfs_block_rsv_check(struct btrfs_block_rsv *block_rsv, int min_factor);
int btrfs_block_rsv_refill(struct btrfs_root *root,
int btrfs_block_rsv_refill(struct btrfs_fs_info *fs_info,
			   struct btrfs_block_rsv *block_rsv, u64 min_reserved,
			   enum btrfs_reserve_flush_enum flush);
int btrfs_block_rsv_migrate(struct btrfs_block_rsv *src_rsv,
Loading