Btrfs: use FLUSH_LIMIT for relocation in reserve_metadata_bytes

We used to allow you to set FLUSH_ALL and then just wouldn't do things like
commit transactions or wait on ordered extents if we noticed you were in a
transaction.  However now that all the flushing for FLUSH_ALL is asynchronous
we've lost the ability to tell, and we could end up deadlocking.  So instead use
FLUSH_LIMIT in reserve_metadata_bytes in relocation and then return -EAGAIN if
we error out to preserve the previous behavior.  I've also added an ASSERT() to
catch anybody else who tries to do this.  Thanks,

Signed-off-by: Josef Bacik <jbacik@fb.com>
Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
Josef Bacik 2016-05-27 13:24:13 -04:00 committed by David Sterba
parent ac2fabac42
commit 8ca17f0f59
2 changed files with 22 additions and 17 deletions

View file

@ -5135,6 +5135,8 @@ static int __reserve_metadata_bytes(struct btrfs_root *root,
int ret = 0; int ret = 0;
ASSERT(orig_bytes); ASSERT(orig_bytes);
ASSERT(!current->journal_info || flush != BTRFS_RESERVE_FLUSH_ALL);
spin_lock(&space_info->lock); spin_lock(&space_info->lock);
ret = -ENOSPC; ret = -ENOSPC;
used = space_info->bytes_used + space_info->bytes_reserved + used = space_info->bytes_used + space_info->bytes_reserved +

View file

@ -2604,25 +2604,28 @@ static int reserve_metadata_space(struct btrfs_trans_handle *trans,
trans->block_rsv = rc->block_rsv; trans->block_rsv = rc->block_rsv;
rc->reserved_bytes += num_bytes; rc->reserved_bytes += num_bytes;
/*
* We are under a transaction here so we can only do limited flushing.
* If we get an enospc just kick back -EAGAIN so we know to drop the
* transaction and try to refill when we can flush all the things.
*/
ret = btrfs_block_rsv_refill(root, rc->block_rsv, num_bytes, ret = btrfs_block_rsv_refill(root, rc->block_rsv, num_bytes,
BTRFS_RESERVE_FLUSH_ALL); BTRFS_RESERVE_FLUSH_LIMIT);
if (ret) { if (ret) {
if (ret == -EAGAIN) { tmp = rc->extent_root->nodesize * RELOCATION_RESERVED_NODES;
tmp = rc->extent_root->nodesize * while (tmp <= rc->reserved_bytes)
RELOCATION_RESERVED_NODES; tmp <<= 1;
while (tmp <= rc->reserved_bytes) /*
tmp <<= 1; * only one thread can access block_rsv at this point,
/* * so we don't need hold lock to protect block_rsv.
* only one thread can access block_rsv at this point, * we expand more reservation size here to allow enough
* so we don't need hold lock to protect block_rsv. * space for relocation and we will return eailer in
* we expand more reservation size here to allow enough * enospc case.
* space for relocation and we will return earlier in */
* enospc case. rc->block_rsv->size = tmp + rc->extent_root->nodesize *
*/ RELOCATION_RESERVED_NODES;
rc->block_rsv->size = tmp + rc->extent_root->nodesize * return -EAGAIN;
RELOCATION_RESERVED_NODES;
}
return ret;
} }
return 0; return 0;