diff options
Diffstat (limited to 'fs/btrfs/extent-tree.c')
-rw-r--r-- | fs/btrfs/extent-tree.c | 90 |
1 files changed, 57 insertions, 33 deletions
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 1eef4ee01d1a..0ec8e228b89f 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c | |||
@@ -3178,8 +3178,8 @@ static int write_one_cache_group(struct btrfs_trans_handle *trans, | |||
3178 | bi = btrfs_item_ptr_offset(leaf, path->slots[0]); | 3178 | bi = btrfs_item_ptr_offset(leaf, path->slots[0]); |
3179 | write_extent_buffer(leaf, &cache->item, bi, sizeof(cache->item)); | 3179 | write_extent_buffer(leaf, &cache->item, bi, sizeof(cache->item)); |
3180 | btrfs_mark_buffer_dirty(leaf); | 3180 | btrfs_mark_buffer_dirty(leaf); |
3181 | btrfs_release_path(path); | ||
3182 | fail: | 3181 | fail: |
3182 | btrfs_release_path(path); | ||
3183 | if (ret) | 3183 | if (ret) |
3184 | btrfs_abort_transaction(trans, root, ret); | 3184 | btrfs_abort_transaction(trans, root, ret); |
3185 | return ret; | 3185 | return ret; |
@@ -3305,8 +3305,7 @@ again: | |||
3305 | 3305 | ||
3306 | spin_lock(&block_group->lock); | 3306 | spin_lock(&block_group->lock); |
3307 | if (block_group->cached != BTRFS_CACHE_FINISHED || | 3307 | if (block_group->cached != BTRFS_CACHE_FINISHED || |
3308 | !btrfs_test_opt(root, SPACE_CACHE) || | 3308 | !btrfs_test_opt(root, SPACE_CACHE)) { |
3309 | block_group->delalloc_bytes) { | ||
3310 | /* | 3309 | /* |
3311 | * don't bother trying to write stuff out _if_ | 3310 | * don't bother trying to write stuff out _if_ |
3312 | * a) we're not cached, | 3311 | * a) we're not cached, |
@@ -3408,17 +3407,14 @@ int btrfs_start_dirty_block_groups(struct btrfs_trans_handle *trans, | |||
3408 | int loops = 0; | 3407 | int loops = 0; |
3409 | 3408 | ||
3410 | spin_lock(&cur_trans->dirty_bgs_lock); | 3409 | spin_lock(&cur_trans->dirty_bgs_lock); |
3411 | if (!list_empty(&cur_trans->dirty_bgs)) { | 3410 | if (list_empty(&cur_trans->dirty_bgs)) { |
3412 | list_splice_init(&cur_trans->dirty_bgs, &dirty); | 3411 | spin_unlock(&cur_trans->dirty_bgs_lock); |
3412 | return 0; | ||
3413 | } | 3413 | } |
3414 | list_splice_init(&cur_trans->dirty_bgs, &dirty); | ||
3414 | spin_unlock(&cur_trans->dirty_bgs_lock); | 3415 | spin_unlock(&cur_trans->dirty_bgs_lock); |
3415 | 3416 | ||
3416 | again: | 3417 | again: |
3417 | if (list_empty(&dirty)) { | ||
3418 | btrfs_free_path(path); | ||
3419 | return 0; | ||
3420 | } | ||
3421 | |||
3422 | /* | 3418 | /* |
3423 | * make sure all the block groups on our dirty list actually | 3419 | * make sure all the block groups on our dirty list actually |
3424 | * exist | 3420 | * exist |
@@ -3431,18 +3427,16 @@ again: | |||
3431 | return -ENOMEM; | 3427 | return -ENOMEM; |
3432 | } | 3428 | } |
3433 | 3429 | ||
3430 | /* | ||
3431 | * cache_write_mutex is here only to save us from balance or automatic | ||
3432 | * removal of empty block groups deleting this block group while we are | ||
3433 | * writing out the cache | ||
3434 | */ | ||
3435 | mutex_lock(&trans->transaction->cache_write_mutex); | ||
3434 | while (!list_empty(&dirty)) { | 3436 | while (!list_empty(&dirty)) { |
3435 | cache = list_first_entry(&dirty, | 3437 | cache = list_first_entry(&dirty, |
3436 | struct btrfs_block_group_cache, | 3438 | struct btrfs_block_group_cache, |
3437 | dirty_list); | 3439 | dirty_list); |
3438 | |||
3439 | /* | ||
3440 | * cache_write_mutex is here only to save us from balance | ||
3441 | * deleting this block group while we are writing out the | ||
3442 | * cache | ||
3443 | */ | ||
3444 | mutex_lock(&trans->transaction->cache_write_mutex); | ||
3445 | |||
3446 | /* | 3440 | /* |
3447 | * this can happen if something re-dirties a block | 3441 | * this can happen if something re-dirties a block |
3448 | * group that is already under IO. Just wait for it to | 3442 | * group that is already under IO. Just wait for it to |
@@ -3495,7 +3489,6 @@ again: | |||
3495 | } | 3489 | } |
3496 | if (!ret) | 3490 | if (!ret) |
3497 | ret = write_one_cache_group(trans, root, path, cache); | 3491 | ret = write_one_cache_group(trans, root, path, cache); |
3498 | mutex_unlock(&trans->transaction->cache_write_mutex); | ||
3499 | 3492 | ||
3500 | /* if its not on the io list, we need to put the block group */ | 3493 | /* if its not on the io list, we need to put the block group */ |
3501 | if (should_put) | 3494 | if (should_put) |
@@ -3503,7 +3496,16 @@ again: | |||
3503 | 3496 | ||
3504 | if (ret) | 3497 | if (ret) |
3505 | break; | 3498 | break; |
3499 | |||
3500 | /* | ||
3501 | * Avoid blocking other tasks for too long. It might even save | ||
3502 | * us from writing caches for block groups that are going to be | ||
3503 | * removed. | ||
3504 | */ | ||
3505 | mutex_unlock(&trans->transaction->cache_write_mutex); | ||
3506 | mutex_lock(&trans->transaction->cache_write_mutex); | ||
3506 | } | 3507 | } |
3508 | mutex_unlock(&trans->transaction->cache_write_mutex); | ||
3507 | 3509 | ||
3508 | /* | 3510 | /* |
3509 | * go through delayed refs for all the stuff we've just kicked off | 3511 | * go through delayed refs for all the stuff we've just kicked off |
@@ -3514,8 +3516,15 @@ again: | |||
3514 | loops++; | 3516 | loops++; |
3515 | spin_lock(&cur_trans->dirty_bgs_lock); | 3517 | spin_lock(&cur_trans->dirty_bgs_lock); |
3516 | list_splice_init(&cur_trans->dirty_bgs, &dirty); | 3518 | list_splice_init(&cur_trans->dirty_bgs, &dirty); |
3519 | /* | ||
3520 | * dirty_bgs_lock protects us from concurrent block group | ||
3521 | * deletes too (not just cache_write_mutex). | ||
3522 | */ | ||
3523 | if (!list_empty(&dirty)) { | ||
3524 | spin_unlock(&cur_trans->dirty_bgs_lock); | ||
3525 | goto again; | ||
3526 | } | ||
3517 | spin_unlock(&cur_trans->dirty_bgs_lock); | 3527 | spin_unlock(&cur_trans->dirty_bgs_lock); |
3518 | goto again; | ||
3519 | } | 3528 | } |
3520 | 3529 | ||
3521 | btrfs_free_path(path); | 3530 | btrfs_free_path(path); |
@@ -7537,7 +7546,7 @@ static void unuse_block_rsv(struct btrfs_fs_info *fs_info, | |||
7537 | * returns the key for the extent through ins, and a tree buffer for | 7546 | * returns the key for the extent through ins, and a tree buffer for |
7538 | * the first block of the extent through buf. | 7547 | * the first block of the extent through buf. |
7539 | * | 7548 | * |
7540 | * returns the tree buffer or NULL. | 7549 | * returns the tree buffer or an ERR_PTR on error. |
7541 | */ | 7550 | */ |
7542 | struct extent_buffer *btrfs_alloc_tree_block(struct btrfs_trans_handle *trans, | 7551 | struct extent_buffer *btrfs_alloc_tree_block(struct btrfs_trans_handle *trans, |
7543 | struct btrfs_root *root, | 7552 | struct btrfs_root *root, |
@@ -7548,6 +7557,7 @@ struct extent_buffer *btrfs_alloc_tree_block(struct btrfs_trans_handle *trans, | |||
7548 | struct btrfs_key ins; | 7557 | struct btrfs_key ins; |
7549 | struct btrfs_block_rsv *block_rsv; | 7558 | struct btrfs_block_rsv *block_rsv; |
7550 | struct extent_buffer *buf; | 7559 | struct extent_buffer *buf; |
7560 | struct btrfs_delayed_extent_op *extent_op; | ||
7551 | u64 flags = 0; | 7561 | u64 flags = 0; |
7552 | int ret; | 7562 | int ret; |
7553 | u32 blocksize = root->nodesize; | 7563 | u32 blocksize = root->nodesize; |
@@ -7568,13 +7578,14 @@ struct extent_buffer *btrfs_alloc_tree_block(struct btrfs_trans_handle *trans, | |||
7568 | 7578 | ||
7569 | ret = btrfs_reserve_extent(root, blocksize, blocksize, | 7579 | ret = btrfs_reserve_extent(root, blocksize, blocksize, |
7570 | empty_size, hint, &ins, 0, 0); | 7580 | empty_size, hint, &ins, 0, 0); |
7571 | if (ret) { | 7581 | if (ret) |
7572 | unuse_block_rsv(root->fs_info, block_rsv, blocksize); | 7582 | goto out_unuse; |
7573 | return ERR_PTR(ret); | ||
7574 | } | ||
7575 | 7583 | ||
7576 | buf = btrfs_init_new_buffer(trans, root, ins.objectid, level); | 7584 | buf = btrfs_init_new_buffer(trans, root, ins.objectid, level); |
7577 | BUG_ON(IS_ERR(buf)); /* -ENOMEM */ | 7585 | if (IS_ERR(buf)) { |
7586 | ret = PTR_ERR(buf); | ||
7587 | goto out_free_reserved; | ||
7588 | } | ||
7578 | 7589 | ||
7579 | if (root_objectid == BTRFS_TREE_RELOC_OBJECTID) { | 7590 | if (root_objectid == BTRFS_TREE_RELOC_OBJECTID) { |
7580 | if (parent == 0) | 7591 | if (parent == 0) |
@@ -7584,9 +7595,11 @@ struct extent_buffer *btrfs_alloc_tree_block(struct btrfs_trans_handle *trans, | |||
7584 | BUG_ON(parent > 0); | 7595 | BUG_ON(parent > 0); |
7585 | 7596 | ||
7586 | if (root_objectid != BTRFS_TREE_LOG_OBJECTID) { | 7597 | if (root_objectid != BTRFS_TREE_LOG_OBJECTID) { |
7587 | struct btrfs_delayed_extent_op *extent_op; | ||
7588 | extent_op = btrfs_alloc_delayed_extent_op(); | 7598 | extent_op = btrfs_alloc_delayed_extent_op(); |
7589 | BUG_ON(!extent_op); /* -ENOMEM */ | 7599 | if (!extent_op) { |
7600 | ret = -ENOMEM; | ||
7601 | goto out_free_buf; | ||
7602 | } | ||
7590 | if (key) | 7603 | if (key) |
7591 | memcpy(&extent_op->key, key, sizeof(extent_op->key)); | 7604 | memcpy(&extent_op->key, key, sizeof(extent_op->key)); |
7592 | else | 7605 | else |
@@ -7601,13 +7614,24 @@ struct extent_buffer *btrfs_alloc_tree_block(struct btrfs_trans_handle *trans, | |||
7601 | extent_op->level = level; | 7614 | extent_op->level = level; |
7602 | 7615 | ||
7603 | ret = btrfs_add_delayed_tree_ref(root->fs_info, trans, | 7616 | ret = btrfs_add_delayed_tree_ref(root->fs_info, trans, |
7604 | ins.objectid, | 7617 | ins.objectid, ins.offset, |
7605 | ins.offset, parent, root_objectid, | 7618 | parent, root_objectid, level, |
7606 | level, BTRFS_ADD_DELAYED_EXTENT, | 7619 | BTRFS_ADD_DELAYED_EXTENT, |
7607 | extent_op, 0); | 7620 | extent_op, 0); |
7608 | BUG_ON(ret); /* -ENOMEM */ | 7621 | if (ret) |
7622 | goto out_free_delayed; | ||
7609 | } | 7623 | } |
7610 | return buf; | 7624 | return buf; |
7625 | |||
7626 | out_free_delayed: | ||
7627 | btrfs_free_delayed_extent_op(extent_op); | ||
7628 | out_free_buf: | ||
7629 | free_extent_buffer(buf); | ||
7630 | out_free_reserved: | ||
7631 | btrfs_free_reserved_extent(root, ins.objectid, ins.offset, 0); | ||
7632 | out_unuse: | ||
7633 | unuse_block_rsv(root->fs_info, block_rsv, blocksize); | ||
7634 | return ERR_PTR(ret); | ||
7611 | } | 7635 | } |
7612 | 7636 | ||
7613 | struct walk_control { | 7637 | struct walk_control { |