aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/extent-tree.c
diff options
context:
space:
mode:
authorJosef Bacik <josef@redhat.com>2011-06-07 16:07:44 -0400
committerJosef Bacik <josef@redhat.com>2011-07-11 09:58:48 -0400
commitfdb5effd5c2a7e01dc3a4217bb194e2d3a5b160f (patch)
treef5eac07be3a5844179a020fd185ff377fb39961a /fs/btrfs/extent-tree.c
parentb5009945be18023942ce28327893c7bc1e58fe54 (diff)
Btrfs: serialize flushers in reserve_metadata_bytes
We keep having problems with early enospc, and that's because our method of making space is inherently racy. The problem is we can have one guy trying to make space for himself, and in the meantime people come in and steal his reservation. In order to stop this we make a waitqueue and put anybody who comes into reserve_metadata_bytes on that waitqueue if somebody is trying to make more space. Thanks, Signed-off-by: Josef Bacik <josef@redhat.com>
Diffstat (limited to 'fs/btrfs/extent-tree.c')
-rw-r--r--fs/btrfs/extent-tree.c69
1 files changed, 48 insertions, 21 deletions
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index 0ed5fe03a06a..340c14715091 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -2932,6 +2932,8 @@ static int update_space_info(struct btrfs_fs_info *info, u64 flags,
2932 found->full = 0; 2932 found->full = 0;
2933 found->force_alloc = CHUNK_ALLOC_NO_FORCE; 2933 found->force_alloc = CHUNK_ALLOC_NO_FORCE;
2934 found->chunk_alloc = 0; 2934 found->chunk_alloc = 0;
2935 found->flush = 0;
2936 init_waitqueue_head(&found->wait);
2935 *space_info = found; 2937 *space_info = found;
2936 list_add_rcu(&found->list, &info->space_info); 2938 list_add_rcu(&found->list, &info->space_info);
2937 atomic_set(&found->caching_threads, 0); 2939 atomic_set(&found->caching_threads, 0);
@@ -3314,6 +3316,14 @@ static int shrink_delalloc(struct btrfs_trans_handle *trans,
3314 if (reserved == 0) 3316 if (reserved == 0)
3315 return 0; 3317 return 0;
3316 3318
3319 smp_mb();
3320 if (root->fs_info->delalloc_bytes == 0) {
3321 if (trans)
3322 return 0;
3323 btrfs_wait_ordered_extents(root, 0, 0);
3324 return 0;
3325 }
3326
3317 max_reclaim = min(reserved, to_reclaim); 3327 max_reclaim = min(reserved, to_reclaim);
3318 3328
3319 while (loops < 1024) { 3329 while (loops < 1024) {
@@ -3356,6 +3366,8 @@ static int shrink_delalloc(struct btrfs_trans_handle *trans,
3356 } 3366 }
3357 3367
3358 } 3368 }
3369 if (reclaimed >= to_reclaim && !trans)
3370 btrfs_wait_ordered_extents(root, 0, 0);
3359 return reclaimed >= to_reclaim; 3371 return reclaimed >= to_reclaim;
3360} 3372}
3361 3373
@@ -3380,15 +3392,36 @@ static int reserve_metadata_bytes(struct btrfs_trans_handle *trans,
3380 u64 num_bytes = orig_bytes; 3392 u64 num_bytes = orig_bytes;
3381 int retries = 0; 3393 int retries = 0;
3382 int ret = 0; 3394 int ret = 0;
3383 bool reserved = false;
3384 bool committed = false; 3395 bool committed = false;
3396 bool flushing = false;
3385 3397
3386again: 3398again:
3387 ret = -ENOSPC; 3399 ret = 0;
3388 if (reserved)
3389 num_bytes = 0;
3390
3391 spin_lock(&space_info->lock); 3400 spin_lock(&space_info->lock);
3401 /*
3402 * We only want to wait if somebody other than us is flushing and we are
3403 * actually alloed to flush.
3404 */
3405 while (flush && !flushing && space_info->flush) {
3406 spin_unlock(&space_info->lock);
3407 /*
3408 * If we have a trans handle we can't wait because the flusher
3409 * may have to commit the transaction, which would mean we would
3410 * deadlock since we are waiting for the flusher to finish, but
3411 * hold the current transaction open.
3412 */
3413 if (trans)
3414 return -EAGAIN;
3415 ret = wait_event_interruptible(space_info->wait,
3416 !space_info->flush);
3417 /* Must have been interrupted, return */
3418 if (ret)
3419 return -EINTR;
3420
3421 spin_lock(&space_info->lock);
3422 }
3423
3424 ret = -ENOSPC;
3392 unused = space_info->bytes_used + space_info->bytes_reserved + 3425 unused = space_info->bytes_used + space_info->bytes_reserved +
3393 space_info->bytes_pinned + space_info->bytes_readonly + 3426 space_info->bytes_pinned + space_info->bytes_readonly +
3394 space_info->bytes_may_use; 3427 space_info->bytes_may_use;
@@ -3403,8 +3436,7 @@ again:
3403 if (unused <= space_info->total_bytes) { 3436 if (unused <= space_info->total_bytes) {
3404 unused = space_info->total_bytes - unused; 3437 unused = space_info->total_bytes - unused;
3405 if (unused >= num_bytes) { 3438 if (unused >= num_bytes) {
3406 if (!reserved) 3439 space_info->bytes_reserved += orig_bytes;
3407 space_info->bytes_reserved += orig_bytes;
3408 ret = 0; 3440 ret = 0;
3409 } else { 3441 } else {
3410 /* 3442 /*
@@ -3429,17 +3461,14 @@ again:
3429 * to reclaim space we can actually use it instead of somebody else 3461 * to reclaim space we can actually use it instead of somebody else
3430 * stealing it from us. 3462 * stealing it from us.
3431 */ 3463 */
3432 if (ret && !reserved) { 3464 if (ret && flush) {
3433 space_info->bytes_reserved += orig_bytes; 3465 flushing = true;
3434 reserved = true; 3466 space_info->flush = 1;
3435 } 3467 }
3436 3468
3437 spin_unlock(&space_info->lock); 3469 spin_unlock(&space_info->lock);
3438 3470
3439 if (!ret) 3471 if (!ret || !flush)
3440 return 0;
3441
3442 if (!flush)
3443 goto out; 3472 goto out;
3444 3473
3445 /* 3474 /*
@@ -3447,9 +3476,7 @@ again:
3447 * metadata until after the IO is completed. 3476 * metadata until after the IO is completed.
3448 */ 3477 */
3449 ret = shrink_delalloc(trans, root, num_bytes, 1); 3478 ret = shrink_delalloc(trans, root, num_bytes, 1);
3450 if (ret > 0) 3479 if (ret < 0)
3451 return 0;
3452 else if (ret < 0)
3453 goto out; 3480 goto out;
3454 3481
3455 /* 3482 /*
@@ -3462,11 +3489,11 @@ again:
3462 goto again; 3489 goto again;
3463 } 3490 }
3464 3491
3465 spin_lock(&space_info->lock);
3466 /* 3492 /*
3467 * Not enough space to be reclaimed, don't bother committing the 3493 * Not enough space to be reclaimed, don't bother committing the
3468 * transaction. 3494 * transaction.
3469 */ 3495 */
3496 spin_lock(&space_info->lock);
3470 if (space_info->bytes_pinned < orig_bytes) 3497 if (space_info->bytes_pinned < orig_bytes)
3471 ret = -ENOSPC; 3498 ret = -ENOSPC;
3472 spin_unlock(&space_info->lock); 3499 spin_unlock(&space_info->lock);
@@ -3489,12 +3516,12 @@ again:
3489 } 3516 }
3490 3517
3491out: 3518out:
3492 if (reserved) { 3519 if (flushing) {
3493 spin_lock(&space_info->lock); 3520 spin_lock(&space_info->lock);
3494 space_info->bytes_reserved -= orig_bytes; 3521 space_info->flush = 0;
3522 wake_up_all(&space_info->wait);
3495 spin_unlock(&space_info->lock); 3523 spin_unlock(&space_info->lock);
3496 } 3524 }
3497
3498 return ret; 3525 return ret;
3499} 3526}
3500 3527