Commit 663350ac authored by Josef Bacik's avatar Josef Bacik Committed by Chris Mason

Btrfs: be smarter about committing the transaction in reserve_metadata_bytes

Because of the overcommit stuff I had to make it so that we committed the
transaction all the time in reserve_metadata_bytes in case we had overcommitted
because of delayed items.  This was because previously we had no way of knowing
how much space was reserved for delayed items.  Now that we have the
delayed_block_rsv we can check it to see if committing the transaction would get
us anywhere.  This patch breaks out the committing logic into a helper function
that will check to see if committing the transaction would free enough space for
us to get anything done.  With this patch xfstests 83 goes from taking 445
seconds to taking 28 seconds on my box.  Thanks,
Signed-off-by: default avatarJosef Bacik <josef@redhat.com>
Signed-off-by: default avatarChris Mason <chris.mason@oracle.com>
parent 6d668dda
...@@ -3334,12 +3334,12 @@ static int do_chunk_alloc(struct btrfs_trans_handle *trans, ...@@ -3334,12 +3334,12 @@ static int do_chunk_alloc(struct btrfs_trans_handle *trans,
/* /*
* shrink metadata reservation for delalloc * shrink metadata reservation for delalloc
*/ */
static int shrink_delalloc(struct btrfs_trans_handle *trans, static int shrink_delalloc(struct btrfs_root *root, u64 to_reclaim,
struct btrfs_root *root, u64 to_reclaim,
bool wait_ordered) bool wait_ordered)
{ {
struct btrfs_block_rsv *block_rsv; struct btrfs_block_rsv *block_rsv;
struct btrfs_space_info *space_info; struct btrfs_space_info *space_info;
struct btrfs_trans_handle *trans;
u64 reserved; u64 reserved;
u64 max_reclaim; u64 max_reclaim;
u64 reclaimed = 0; u64 reclaimed = 0;
...@@ -3348,6 +3348,7 @@ static int shrink_delalloc(struct btrfs_trans_handle *trans, ...@@ -3348,6 +3348,7 @@ static int shrink_delalloc(struct btrfs_trans_handle *trans,
int loops = 0; int loops = 0;
unsigned long progress; unsigned long progress;
trans = (struct btrfs_trans_handle *)current->journal_info;
block_rsv = &root->fs_info->delalloc_block_rsv; block_rsv = &root->fs_info->delalloc_block_rsv;
space_info = block_rsv->space_info; space_info = block_rsv->space_info;
...@@ -3417,6 +3418,60 @@ static int shrink_delalloc(struct btrfs_trans_handle *trans, ...@@ -3417,6 +3418,60 @@ static int shrink_delalloc(struct btrfs_trans_handle *trans,
return reclaimed >= to_reclaim; return reclaimed >= to_reclaim;
} }
/**
* maybe_commit_transaction - possibly commit the transaction if its ok to
* @root - the root we're allocating for
* @bytes - the number of bytes we want to reserve
* @force - force the commit
*
* This will check to make sure that committing the transaction will actually
* get us somewhere and then commit the transaction if it does. Otherwise it
* will return -ENOSPC.
*/
static int may_commit_transaction(struct btrfs_root *root,
struct btrfs_space_info *space_info,
u64 bytes, int force)
{
struct btrfs_block_rsv *delayed_rsv = &root->fs_info->delayed_block_rsv;
struct btrfs_trans_handle *trans;
trans = (struct btrfs_trans_handle *)current->journal_info;
if (trans)
return -EAGAIN;
if (force)
goto commit;
/* See if there is enough pinned space to make this reservation */
spin_lock(&space_info->lock);
if (space_info->bytes_pinned >= bytes) {
spin_unlock(&space_info->lock);
goto commit;
}
spin_unlock(&space_info->lock);
/*
* See if there is some space in the delayed insertion reservation for
* this reservation.
*/
if (space_info != delayed_rsv->space_info)
return -ENOSPC;
spin_lock(&delayed_rsv->lock);
if (delayed_rsv->size < bytes) {
spin_unlock(&delayed_rsv->lock);
return -ENOSPC;
}
spin_unlock(&delayed_rsv->lock);
commit:
trans = btrfs_join_transaction(root);
if (IS_ERR(trans))
return -ENOSPC;
return btrfs_commit_transaction(trans, root);
}
/** /**
* reserve_metadata_bytes - try to reserve bytes from the block_rsv's space * reserve_metadata_bytes - try to reserve bytes from the block_rsv's space
* @root - the root we're allocating for * @root - the root we're allocating for
...@@ -3436,7 +3491,6 @@ static int reserve_metadata_bytes(struct btrfs_root *root, ...@@ -3436,7 +3491,6 @@ static int reserve_metadata_bytes(struct btrfs_root *root,
u64 orig_bytes, int flush) u64 orig_bytes, int flush)
{ {
struct btrfs_space_info *space_info = block_rsv->space_info; struct btrfs_space_info *space_info = block_rsv->space_info;
struct btrfs_trans_handle *trans;
u64 used; u64 used;
u64 num_bytes = orig_bytes; u64 num_bytes = orig_bytes;
int retries = 0; int retries = 0;
...@@ -3445,7 +3499,6 @@ static int reserve_metadata_bytes(struct btrfs_root *root, ...@@ -3445,7 +3499,6 @@ static int reserve_metadata_bytes(struct btrfs_root *root,
bool flushing = false; bool flushing = false;
bool wait_ordered = false; bool wait_ordered = false;
trans = (struct btrfs_trans_handle *)current->journal_info;
again: again:
ret = 0; ret = 0;
spin_lock(&space_info->lock); spin_lock(&space_info->lock);
...@@ -3461,7 +3514,7 @@ static int reserve_metadata_bytes(struct btrfs_root *root, ...@@ -3461,7 +3514,7 @@ static int reserve_metadata_bytes(struct btrfs_root *root,
* deadlock since we are waiting for the flusher to finish, but * deadlock since we are waiting for the flusher to finish, but
* hold the current transaction open. * hold the current transaction open.
*/ */
if (trans) if (current->journal_info)
return -EAGAIN; return -EAGAIN;
ret = wait_event_interruptible(space_info->wait, ret = wait_event_interruptible(space_info->wait,
!space_info->flush); !space_info->flush);
...@@ -3517,12 +3570,16 @@ static int reserve_metadata_bytes(struct btrfs_root *root, ...@@ -3517,12 +3570,16 @@ static int reserve_metadata_bytes(struct btrfs_root *root,
*/ */
avail = (space_info->total_bytes - space_info->bytes_used) * 8; avail = (space_info->total_bytes - space_info->bytes_used) * 8;
do_div(avail, 10); do_div(avail, 10);
if (space_info->bytes_pinned >= avail && flush && !trans && if (space_info->bytes_pinned >= avail && flush && !committed) {
!committed) {
space_info->flush = 1; space_info->flush = 1;
flushing = true; flushing = true;
spin_unlock(&space_info->lock); spin_unlock(&space_info->lock);
goto commit; ret = may_commit_transaction(root, space_info,
orig_bytes, 1);
if (ret)
goto out;
committed = true;
goto again;
} }
spin_lock(&root->fs_info->free_chunk_lock); spin_lock(&root->fs_info->free_chunk_lock);
...@@ -3575,7 +3632,7 @@ static int reserve_metadata_bytes(struct btrfs_root *root, ...@@ -3575,7 +3632,7 @@ static int reserve_metadata_bytes(struct btrfs_root *root,
* We do synchronous shrinking since we don't actually unreserve * We do synchronous shrinking since we don't actually unreserve
* metadata until after the IO is completed. * metadata until after the IO is completed.
*/ */
ret = shrink_delalloc(trans, root, num_bytes, wait_ordered); ret = shrink_delalloc(root, num_bytes, wait_ordered);
if (ret < 0) if (ret < 0)
goto out; goto out;
...@@ -3592,21 +3649,12 @@ static int reserve_metadata_bytes(struct btrfs_root *root, ...@@ -3592,21 +3649,12 @@ static int reserve_metadata_bytes(struct btrfs_root *root,
goto again; goto again;
} }
ret = -EAGAIN;
if (trans)
goto out;
commit:
ret = -ENOSPC; ret = -ENOSPC;
if (committed) if (committed)
goto out; goto out;
trans = btrfs_join_transaction(root); ret = may_commit_transaction(root, space_info, orig_bytes, 0);
if (IS_ERR(trans))
goto out;
ret = btrfs_commit_transaction(trans, root);
if (!ret) { if (!ret) {
trans = NULL;
committed = true; committed = true;
goto again; goto again;
} }
......
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