diff options
author | Yan, Zheng <zheng.yan@oracle.com> | 2010-05-16 10:49:58 -0400 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2010-05-25 10:34:52 -0400 |
commit | 8929ecfa50f266163832eeacfbc3642ed5eb83b6 (patch) | |
tree | e0177748af36d49d5f652cff0e421a8268cf7194 /fs/btrfs/extent-tree.c | |
parent | 0ca1f7ceb1991099ed5273885ebcf4323948c72e (diff) |
Btrfs: Introduce global metadata reservation
Reserve metadata space for extent tree, checksum tree and root tree
Signed-off-by: Yan Zheng <zheng.yan@oracle.com>
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/extent-tree.c')
-rw-r--r-- | fs/btrfs/extent-tree.c | 147 |
1 files changed, 128 insertions, 19 deletions
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index b1822e752b4a..cb814a71800d 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c | |||
@@ -2895,10 +2895,9 @@ int btrfs_check_data_free_space(struct inode *inode, u64 bytes) | |||
2895 | again: | 2895 | again: |
2896 | /* make sure we have enough space to handle the data first */ | 2896 | /* make sure we have enough space to handle the data first */ |
2897 | spin_lock(&data_sinfo->lock); | 2897 | spin_lock(&data_sinfo->lock); |
2898 | used = data_sinfo->bytes_used + data_sinfo->bytes_delalloc + | 2898 | used = data_sinfo->bytes_used + data_sinfo->bytes_reserved + |
2899 | data_sinfo->bytes_reserved + data_sinfo->bytes_pinned + | 2899 | data_sinfo->bytes_pinned + data_sinfo->bytes_readonly + |
2900 | data_sinfo->bytes_readonly + data_sinfo->bytes_may_use + | 2900 | data_sinfo->bytes_may_use; |
2901 | data_sinfo->bytes_super; | ||
2902 | 2901 | ||
2903 | if (used + bytes > data_sinfo->total_bytes) { | 2902 | if (used + bytes > data_sinfo->total_bytes) { |
2904 | struct btrfs_trans_handle *trans; | 2903 | struct btrfs_trans_handle *trans; |
@@ -2922,7 +2921,7 @@ alloc: | |||
2922 | bytes + 2 * 1024 * 1024, | 2921 | bytes + 2 * 1024 * 1024, |
2923 | alloc_target, 0); | 2922 | alloc_target, 0); |
2924 | btrfs_end_transaction(trans, root); | 2923 | btrfs_end_transaction(trans, root); |
2925 | if (ret) | 2924 | if (ret < 0) |
2926 | return ret; | 2925 | return ret; |
2927 | 2926 | ||
2928 | if (!data_sinfo) { | 2927 | if (!data_sinfo) { |
@@ -2945,11 +2944,10 @@ alloc: | |||
2945 | goto again; | 2944 | goto again; |
2946 | } | 2945 | } |
2947 | 2946 | ||
2948 | printk(KERN_ERR "no space left, need %llu, %llu delalloc bytes" | 2947 | printk(KERN_ERR "no space left, need %llu, %llu bytes_used, " |
2949 | ", %llu bytes_used, %llu bytes_reserved, " | 2948 | "%llu bytes_reserved, " "%llu bytes_pinned, " |
2950 | "%llu bytes_pinned, %llu bytes_readonly, %llu may use " | 2949 | "%llu bytes_readonly, %llu may use %llu total\n", |
2951 | "%llu total\n", (unsigned long long)bytes, | 2950 | (unsigned long long)bytes, |
2952 | (unsigned long long)data_sinfo->bytes_delalloc, | ||
2953 | (unsigned long long)data_sinfo->bytes_used, | 2951 | (unsigned long long)data_sinfo->bytes_used, |
2954 | (unsigned long long)data_sinfo->bytes_reserved, | 2952 | (unsigned long long)data_sinfo->bytes_reserved, |
2955 | (unsigned long long)data_sinfo->bytes_pinned, | 2953 | (unsigned long long)data_sinfo->bytes_pinned, |
@@ -3464,6 +3462,91 @@ void btrfs_block_rsv_release(struct btrfs_root *root, | |||
3464 | block_rsv_release_bytes(block_rsv, global_rsv, num_bytes); | 3462 | block_rsv_release_bytes(block_rsv, global_rsv, num_bytes); |
3465 | } | 3463 | } |
3466 | 3464 | ||
3465 | /* | ||
3466 | * helper to calculate size of global block reservation. | ||
3467 | * the desired value is sum of space used by extent tree, | ||
3468 | * checksum tree and root tree | ||
3469 | */ | ||
3470 | static u64 calc_global_metadata_size(struct btrfs_fs_info *fs_info) | ||
3471 | { | ||
3472 | struct btrfs_space_info *sinfo; | ||
3473 | u64 num_bytes; | ||
3474 | u64 meta_used; | ||
3475 | u64 data_used; | ||
3476 | int csum_size = btrfs_super_csum_size(&fs_info->super_copy); | ||
3477 | #if 0 | ||
3478 | /* | ||
3479 | * per tree used space accounting can be inaccuracy, so we | ||
3480 | * can't rely on it. | ||
3481 | */ | ||
3482 | spin_lock(&fs_info->extent_root->accounting_lock); | ||
3483 | num_bytes = btrfs_root_used(&fs_info->extent_root->root_item); | ||
3484 | spin_unlock(&fs_info->extent_root->accounting_lock); | ||
3485 | |||
3486 | spin_lock(&fs_info->csum_root->accounting_lock); | ||
3487 | num_bytes += btrfs_root_used(&fs_info->csum_root->root_item); | ||
3488 | spin_unlock(&fs_info->csum_root->accounting_lock); | ||
3489 | |||
3490 | spin_lock(&fs_info->tree_root->accounting_lock); | ||
3491 | num_bytes += btrfs_root_used(&fs_info->tree_root->root_item); | ||
3492 | spin_unlock(&fs_info->tree_root->accounting_lock); | ||
3493 | #endif | ||
3494 | sinfo = __find_space_info(fs_info, BTRFS_BLOCK_GROUP_DATA); | ||
3495 | spin_lock(&sinfo->lock); | ||
3496 | data_used = sinfo->bytes_used; | ||
3497 | spin_unlock(&sinfo->lock); | ||
3498 | |||
3499 | sinfo = __find_space_info(fs_info, BTRFS_BLOCK_GROUP_METADATA); | ||
3500 | spin_lock(&sinfo->lock); | ||
3501 | meta_used = sinfo->bytes_used; | ||
3502 | spin_unlock(&sinfo->lock); | ||
3503 | |||
3504 | num_bytes = (data_used >> fs_info->sb->s_blocksize_bits) * | ||
3505 | csum_size * 2; | ||
3506 | num_bytes += div64_u64(data_used + meta_used, 50); | ||
3507 | |||
3508 | if (num_bytes * 3 > meta_used) | ||
3509 | num_bytes = div64_u64(meta_used, 3); | ||
3510 | |||
3511 | return ALIGN(num_bytes, fs_info->extent_root->leafsize << 10); | ||
3512 | } | ||
3513 | |||
3514 | static void update_global_block_rsv(struct btrfs_fs_info *fs_info) | ||
3515 | { | ||
3516 | struct btrfs_block_rsv *block_rsv = &fs_info->global_block_rsv; | ||
3517 | struct btrfs_space_info *sinfo = block_rsv->space_info; | ||
3518 | u64 num_bytes; | ||
3519 | |||
3520 | num_bytes = calc_global_metadata_size(fs_info); | ||
3521 | |||
3522 | spin_lock(&block_rsv->lock); | ||
3523 | spin_lock(&sinfo->lock); | ||
3524 | |||
3525 | block_rsv->size = num_bytes; | ||
3526 | |||
3527 | num_bytes = sinfo->bytes_used + sinfo->bytes_pinned + | ||
3528 | sinfo->bytes_reserved + sinfo->bytes_readonly; | ||
3529 | |||
3530 | if (sinfo->total_bytes > num_bytes) { | ||
3531 | num_bytes = sinfo->total_bytes - num_bytes; | ||
3532 | block_rsv->reserved += num_bytes; | ||
3533 | sinfo->bytes_reserved += num_bytes; | ||
3534 | } | ||
3535 | |||
3536 | if (block_rsv->reserved >= block_rsv->size) { | ||
3537 | num_bytes = block_rsv->reserved - block_rsv->size; | ||
3538 | sinfo->bytes_reserved -= num_bytes; | ||
3539 | block_rsv->reserved = block_rsv->size; | ||
3540 | block_rsv->full = 1; | ||
3541 | } | ||
3542 | #if 0 | ||
3543 | printk(KERN_INFO"global block rsv size %llu reserved %llu\n", | ||
3544 | block_rsv->size, block_rsv->reserved); | ||
3545 | #endif | ||
3546 | spin_unlock(&sinfo->lock); | ||
3547 | spin_unlock(&block_rsv->lock); | ||
3548 | } | ||
3549 | |||
3467 | static void init_global_block_rsv(struct btrfs_fs_info *fs_info) | 3550 | static void init_global_block_rsv(struct btrfs_fs_info *fs_info) |
3468 | { | 3551 | { |
3469 | struct btrfs_space_info *space_info; | 3552 | struct btrfs_space_info *space_info; |
@@ -3473,11 +3556,36 @@ static void init_global_block_rsv(struct btrfs_fs_info *fs_info) | |||
3473 | fs_info->chunk_block_rsv.priority = 10; | 3556 | fs_info->chunk_block_rsv.priority = 10; |
3474 | 3557 | ||
3475 | space_info = __find_space_info(fs_info, BTRFS_BLOCK_GROUP_METADATA); | 3558 | space_info = __find_space_info(fs_info, BTRFS_BLOCK_GROUP_METADATA); |
3559 | fs_info->global_block_rsv.space_info = space_info; | ||
3560 | fs_info->global_block_rsv.priority = 10; | ||
3561 | fs_info->global_block_rsv.refill_used = 1; | ||
3562 | fs_info->delalloc_block_rsv.space_info = space_info; | ||
3476 | fs_info->trans_block_rsv.space_info = space_info; | 3563 | fs_info->trans_block_rsv.space_info = space_info; |
3477 | fs_info->empty_block_rsv.space_info = space_info; | 3564 | fs_info->empty_block_rsv.space_info = space_info; |
3478 | fs_info->empty_block_rsv.priority = 10; | 3565 | fs_info->empty_block_rsv.priority = 10; |
3479 | 3566 | ||
3567 | fs_info->extent_root->block_rsv = &fs_info->global_block_rsv; | ||
3568 | fs_info->csum_root->block_rsv = &fs_info->global_block_rsv; | ||
3569 | fs_info->dev_root->block_rsv = &fs_info->global_block_rsv; | ||
3570 | fs_info->tree_root->block_rsv = &fs_info->global_block_rsv; | ||
3480 | fs_info->chunk_root->block_rsv = &fs_info->chunk_block_rsv; | 3571 | fs_info->chunk_root->block_rsv = &fs_info->chunk_block_rsv; |
3572 | |||
3573 | btrfs_add_durable_block_rsv(fs_info, &fs_info->global_block_rsv); | ||
3574 | |||
3575 | btrfs_add_durable_block_rsv(fs_info, &fs_info->delalloc_block_rsv); | ||
3576 | |||
3577 | update_global_block_rsv(fs_info); | ||
3578 | } | ||
3579 | |||
3580 | static void release_global_block_rsv(struct btrfs_fs_info *fs_info) | ||
3581 | { | ||
3582 | block_rsv_release_bytes(&fs_info->global_block_rsv, NULL, (u64)-1); | ||
3583 | WARN_ON(fs_info->delalloc_block_rsv.size > 0); | ||
3584 | WARN_ON(fs_info->delalloc_block_rsv.reserved > 0); | ||
3585 | WARN_ON(fs_info->trans_block_rsv.size > 0); | ||
3586 | WARN_ON(fs_info->trans_block_rsv.reserved > 0); | ||
3587 | WARN_ON(fs_info->chunk_block_rsv.size > 0); | ||
3588 | WARN_ON(fs_info->chunk_block_rsv.reserved > 0); | ||
3481 | } | 3589 | } |
3482 | 3590 | ||
3483 | static u64 calc_trans_metadata_size(struct btrfs_root *root, int num_items) | 3591 | static u64 calc_trans_metadata_size(struct btrfs_root *root, int num_items) |
@@ -3826,6 +3934,8 @@ int btrfs_prepare_extent_commit(struct btrfs_trans_handle *trans, | |||
3826 | fs_info->pinned_extents = &fs_info->freed_extents[0]; | 3934 | fs_info->pinned_extents = &fs_info->freed_extents[0]; |
3827 | 3935 | ||
3828 | up_write(&fs_info->extent_commit_sem); | 3936 | up_write(&fs_info->extent_commit_sem); |
3937 | |||
3938 | update_global_block_rsv(fs_info); | ||
3829 | return 0; | 3939 | return 0; |
3830 | } | 3940 | } |
3831 | 3941 | ||
@@ -4818,19 +4928,16 @@ static void dump_space_info(struct btrfs_space_info *info, u64 bytes, | |||
4818 | printk(KERN_INFO "space_info has %llu free, is %sfull\n", | 4928 | printk(KERN_INFO "space_info has %llu free, is %sfull\n", |
4819 | (unsigned long long)(info->total_bytes - info->bytes_used - | 4929 | (unsigned long long)(info->total_bytes - info->bytes_used - |
4820 | info->bytes_pinned - info->bytes_reserved - | 4930 | info->bytes_pinned - info->bytes_reserved - |
4821 | info->bytes_super), | 4931 | info->bytes_readonly), |
4822 | (info->full) ? "" : "not "); | 4932 | (info->full) ? "" : "not "); |
4823 | printk(KERN_INFO "space_info total=%llu, pinned=%llu, delalloc=%llu," | 4933 | printk(KERN_INFO "space_info total=%llu, used=%llu, pinned=%llu, " |
4824 | " may_use=%llu, used=%llu, root=%llu, super=%llu, reserved=%llu" | 4934 | "reserved=%llu, may_use=%llu, readonly=%llu\n", |
4825 | "\n", | ||
4826 | (unsigned long long)info->total_bytes, | 4935 | (unsigned long long)info->total_bytes, |
4936 | (unsigned long long)info->bytes_used, | ||
4827 | (unsigned long long)info->bytes_pinned, | 4937 | (unsigned long long)info->bytes_pinned, |
4828 | (unsigned long long)info->bytes_delalloc, | 4938 | (unsigned long long)info->bytes_reserved, |
4829 | (unsigned long long)info->bytes_may_use, | 4939 | (unsigned long long)info->bytes_may_use, |
4830 | (unsigned long long)info->bytes_used, | 4940 | (unsigned long long)info->bytes_readonly); |
4831 | (unsigned long long)info->bytes_root, | ||
4832 | (unsigned long long)info->bytes_super, | ||
4833 | (unsigned long long)info->bytes_reserved); | ||
4834 | spin_unlock(&info->lock); | 4941 | spin_unlock(&info->lock); |
4835 | 4942 | ||
4836 | if (!dump_block_groups) | 4943 | if (!dump_block_groups) |
@@ -7727,6 +7834,8 @@ int btrfs_free_block_groups(struct btrfs_fs_info *info) | |||
7727 | */ | 7834 | */ |
7728 | synchronize_rcu(); | 7835 | synchronize_rcu(); |
7729 | 7836 | ||
7837 | release_global_block_rsv(info); | ||
7838 | |||
7730 | while(!list_empty(&info->space_info)) { | 7839 | while(!list_empty(&info->space_info)) { |
7731 | space_info = list_entry(info->space_info.next, | 7840 | space_info = list_entry(info->space_info.next, |
7732 | struct btrfs_space_info, | 7841 | struct btrfs_space_info, |