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:
parent
ac2fabac42
commit
8ca17f0f59
|
@ -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 +
|
||||||
|
|
|
@ -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 *
|
|
||||||
RELOCATION_RESERVED_NODES;
|
|
||||||
while (tmp <= rc->reserved_bytes)
|
while (tmp <= rc->reserved_bytes)
|
||||||
tmp <<= 1;
|
tmp <<= 1;
|
||||||
/*
|
/*
|
||||||
* only one thread can access block_rsv at this point,
|
* only one thread can access block_rsv at this point,
|
||||||
* so we don't need hold lock to protect block_rsv.
|
* so we don't need hold lock to protect block_rsv.
|
||||||
* we expand more reservation size here to allow enough
|
* we expand more reservation size here to allow enough
|
||||||
* space for relocation and we will return earlier in
|
* space for relocation and we will return eailer in
|
||||||
* enospc case.
|
* enospc case.
|
||||||
*/
|
*/
|
||||||
rc->block_rsv->size = tmp + rc->extent_root->nodesize *
|
rc->block_rsv->size = tmp + rc->extent_root->nodesize *
|
||||||
RELOCATION_RESERVED_NODES;
|
RELOCATION_RESERVED_NODES;
|
||||||
}
|
return -EAGAIN;
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
Loading…
Reference in a new issue