Commit 8ca17f0f authored by Josef Bacik's avatar Josef Bacik Committed by David Sterba

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: default avatarJosef Bacik <jbacik@fb.com>
Signed-off-by: default avatarDavid Sterba <dsterba@suse.com>
parent ac2fabac
...@@ -5135,6 +5135,8 @@ static int __reserve_metadata_bytes(struct btrfs_root *root, ...@@ -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, ...@@ -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;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment