From aec2d0b6453992c4037611a1e917203f138761bd Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Thu, 3 Nov 2011 22:54:25 -0400 Subject: [PATCH] --- yaml --- r: 274687 b: refs/heads/master c: 663350ac38c67ca388acea6e876dc6d668c232b0 h: refs/heads/master i: 274685: d1416da4a111146c9cc3090c41b6d0f7708c524e 274683: c65c6ff736a666be5fb55a5a157ff8c4c8e0d800 274679: 1f65418e9d0bec6f08b4369e180002a52a9fda01 274671: d57bc7702e49c453a59259a3f6a52d34aa00aa42 274655: 596ed21243aac8662e6d25bdd6935f1da5bdae91 274623: cc2ada45bf4e9c5bfa3263c2ecbff36f27cd5067 274559: 1334543e12951b04a972d042a4d541f41a2b5c7d 274431: 6e03995f1e32b28db55d7cd7e46ca3a8189cae77 v: v3 --- [refs] | 2 +- trunk/fs/btrfs/extent-tree.c | 86 ++++++++++++++++++++++++++++-------- 2 files changed, 68 insertions(+), 20 deletions(-) diff --git a/[refs] b/[refs] index aed3f4ff80c9..6e1affdaec91 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 6d668dda0caec537fbf28c4d91e6d18181af3cff +refs/heads/master: 663350ac38c67ca388acea6e876dc6d668c232b0 diff --git a/trunk/fs/btrfs/extent-tree.c b/trunk/fs/btrfs/extent-tree.c index 01c1f08b976a..5b84205e7685 100644 --- a/trunk/fs/btrfs/extent-tree.c +++ b/trunk/fs/btrfs/extent-tree.c @@ -3334,12 +3334,12 @@ static int do_chunk_alloc(struct btrfs_trans_handle *trans, /* * shrink metadata reservation for delalloc */ -static int shrink_delalloc(struct btrfs_trans_handle *trans, - struct btrfs_root *root, u64 to_reclaim, +static int shrink_delalloc(struct btrfs_root *root, u64 to_reclaim, bool wait_ordered) { struct btrfs_block_rsv *block_rsv; struct btrfs_space_info *space_info; + struct btrfs_trans_handle *trans; u64 reserved; u64 max_reclaim; u64 reclaimed = 0; @@ -3348,6 +3348,7 @@ static int shrink_delalloc(struct btrfs_trans_handle *trans, int loops = 0; unsigned long progress; + trans = (struct btrfs_trans_handle *)current->journal_info; block_rsv = &root->fs_info->delalloc_block_rsv; space_info = block_rsv->space_info; @@ -3417,6 +3418,60 @@ static int shrink_delalloc(struct btrfs_trans_handle *trans, 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 * @root - the root we're allocating for @@ -3436,7 +3491,6 @@ static int reserve_metadata_bytes(struct btrfs_root *root, u64 orig_bytes, int flush) { struct btrfs_space_info *space_info = block_rsv->space_info; - struct btrfs_trans_handle *trans; u64 used; u64 num_bytes = orig_bytes; int retries = 0; @@ -3445,7 +3499,6 @@ static int reserve_metadata_bytes(struct btrfs_root *root, bool flushing = false; bool wait_ordered = false; - trans = (struct btrfs_trans_handle *)current->journal_info; again: ret = 0; spin_lock(&space_info->lock); @@ -3461,7 +3514,7 @@ static int reserve_metadata_bytes(struct btrfs_root *root, * deadlock since we are waiting for the flusher to finish, but * hold the current transaction open. */ - if (trans) + if (current->journal_info) return -EAGAIN; ret = wait_event_interruptible(space_info->wait, !space_info->flush); @@ -3517,12 +3570,16 @@ static int reserve_metadata_bytes(struct btrfs_root *root, */ avail = (space_info->total_bytes - space_info->bytes_used) * 8; do_div(avail, 10); - if (space_info->bytes_pinned >= avail && flush && !trans && - !committed) { + if (space_info->bytes_pinned >= avail && flush && !committed) { space_info->flush = 1; flushing = true; 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); @@ -3575,7 +3632,7 @@ static int reserve_metadata_bytes(struct btrfs_root *root, * We do synchronous shrinking since we don't actually unreserve * 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) goto out; @@ -3592,21 +3649,12 @@ static int reserve_metadata_bytes(struct btrfs_root *root, goto again; } - ret = -EAGAIN; - if (trans) - goto out; - -commit: ret = -ENOSPC; if (committed) goto out; - trans = btrfs_join_transaction(root); - if (IS_ERR(trans)) - goto out; - ret = btrfs_commit_transaction(trans, root); + ret = may_commit_transaction(root, space_info, orig_bytes, 0); if (!ret) { - trans = NULL; committed = true; goto again; }