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

Commit 68a82277 authored by Josef Bacik's avatar Josef Bacik Committed by Chris Mason
Browse files

Btrfs: use the global block reserve if we cannot reserve space



We call use_block_rsv right before we make an allocation in order to make sure
we have enough space.  Now normally people have called btrfs_start_transaction()
with the appropriate amount of space that we need, so we just use some of that
pre-reserved space and move along happily.  The problem is where people use
btrfs_join_transaction(), which doesn't actually reserve any space.  So we try
and reserve space here, but we cannot flush delalloc, so this forces us to
return -ENOSPC when in reality we have plenty of space.  The most common symptom
is seeing a bunch of "couldn't dirty inode" messages in syslog.  With
xfstests 224 we end up falling back to start_transaction and then doing all the
flush delalloc stuff which causes to hang for a very long time.

So instead steal from the global reserve, which is what this is meant for
anyway.  With this patch and the other 2 I have sent xfstests 224 now passes
successfully.  Thanks,

Signed-off-by: default avatarJosef Bacik <josef@redhat.com>
Signed-off-by: default avatarChris Mason <chris.mason@oracle.com>
parent e9e22899
Loading
Loading
Loading
Loading
+27 −1
Original line number Diff line number Diff line
@@ -5646,6 +5646,7 @@ use_block_rsv(struct btrfs_trans_handle *trans,
	      struct btrfs_root *root, u32 blocksize)
{
	struct btrfs_block_rsv *block_rsv;
	struct btrfs_block_rsv *global_rsv = &root->fs_info->global_block_rsv;
	int ret;

	block_rsv = get_block_rsv(trans, root);
@@ -5653,14 +5654,39 @@ use_block_rsv(struct btrfs_trans_handle *trans,
	if (block_rsv->size == 0) {
		ret = reserve_metadata_bytes(trans, root, block_rsv,
					     blocksize, 0);
		if (ret)
		/*
		 * If we couldn't reserve metadata bytes try and use some from
		 * the global reserve.
		 */
		if (ret && block_rsv != global_rsv) {
			ret = block_rsv_use_bytes(global_rsv, blocksize);
			if (!ret)
				return global_rsv;
			return ERR_PTR(ret);
		} else if (ret) {
			return ERR_PTR(ret);
		}
		return block_rsv;
	}

	ret = block_rsv_use_bytes(block_rsv, blocksize);
	if (!ret)
		return block_rsv;
	if (ret) {
		WARN_ON(1);
		ret = reserve_metadata_bytes(trans, root, block_rsv, blocksize,
					     0);
		if (!ret) {
			spin_lock(&block_rsv->lock);
			block_rsv->size += blocksize;
			spin_unlock(&block_rsv->lock);
			return block_rsv;
		} else if (ret && block_rsv != global_rsv) {
			ret = block_rsv_use_bytes(global_rsv, blocksize);
			if (!ret)
				return global_rsv;
		}
	}

	return ERR_PTR(-ENOSPC);
}