diff options
author | Yan, Zheng <zheng.yan@oracle.com> | 2010-05-16 10:46:25 -0400 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2010-05-25 10:34:48 -0400 |
commit | 424499dbd0c4d88742bf581b5714b27fb44b9fef (patch) | |
tree | f46a76c8f23c7045b18b31a9206d0b22f324aad1 /fs/btrfs/extent-tree.c | |
parent | b742bb82f1676d50103ade0ba89bfb79debabe73 (diff) |
Btrfs: Kill allocate_wait in space_info
We already have fs_info->chunk_mutex to avoid concurrent
chunk creation.
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 | 132 |
1 files changed, 58 insertions, 74 deletions
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index f5db03669ead..2c95507c9abb 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c | |||
@@ -71,6 +71,9 @@ static int find_next_key(struct btrfs_path *path, int level, | |||
71 | struct btrfs_key *key); | 71 | struct btrfs_key *key); |
72 | static void dump_space_info(struct btrfs_space_info *info, u64 bytes, | 72 | static void dump_space_info(struct btrfs_space_info *info, u64 bytes, |
73 | int dump_block_groups); | 73 | int dump_block_groups); |
74 | static int maybe_allocate_chunk(struct btrfs_trans_handle *trans, | ||
75 | struct btrfs_root *root, | ||
76 | struct btrfs_space_info *sinfo, u64 num_bytes); | ||
74 | 77 | ||
75 | static noinline int | 78 | static noinline int |
76 | block_group_cache_done(struct btrfs_block_group_cache *cache) | 79 | block_group_cache_done(struct btrfs_block_group_cache *cache) |
@@ -2691,7 +2694,6 @@ static int update_space_info(struct btrfs_fs_info *info, u64 flags, | |||
2691 | INIT_LIST_HEAD(&found->block_groups[i]); | 2694 | INIT_LIST_HEAD(&found->block_groups[i]); |
2692 | init_rwsem(&found->groups_sem); | 2695 | init_rwsem(&found->groups_sem); |
2693 | init_waitqueue_head(&found->flush_wait); | 2696 | init_waitqueue_head(&found->flush_wait); |
2694 | init_waitqueue_head(&found->allocate_wait); | ||
2695 | spin_lock_init(&found->lock); | 2697 | spin_lock_init(&found->lock); |
2696 | found->flags = flags & (BTRFS_BLOCK_GROUP_DATA | | 2698 | found->flags = flags & (BTRFS_BLOCK_GROUP_DATA | |
2697 | BTRFS_BLOCK_GROUP_SYSTEM | | 2699 | BTRFS_BLOCK_GROUP_SYSTEM | |
@@ -3004,71 +3006,6 @@ flush: | |||
3004 | wake_up(&info->flush_wait); | 3006 | wake_up(&info->flush_wait); |
3005 | } | 3007 | } |
3006 | 3008 | ||
3007 | static int maybe_allocate_chunk(struct btrfs_root *root, | ||
3008 | struct btrfs_space_info *info) | ||
3009 | { | ||
3010 | struct btrfs_super_block *disk_super = &root->fs_info->super_copy; | ||
3011 | struct btrfs_trans_handle *trans; | ||
3012 | bool wait = false; | ||
3013 | int ret = 0; | ||
3014 | u64 min_metadata; | ||
3015 | u64 free_space; | ||
3016 | |||
3017 | free_space = btrfs_super_total_bytes(disk_super); | ||
3018 | /* | ||
3019 | * we allow the metadata to grow to a max of either 10gb or 5% of the | ||
3020 | * space in the volume. | ||
3021 | */ | ||
3022 | min_metadata = min((u64)10 * 1024 * 1024 * 1024, | ||
3023 | div64_u64(free_space * 5, 100)); | ||
3024 | if (info->total_bytes >= min_metadata) { | ||
3025 | spin_unlock(&info->lock); | ||
3026 | return 0; | ||
3027 | } | ||
3028 | |||
3029 | if (info->full) { | ||
3030 | spin_unlock(&info->lock); | ||
3031 | return 0; | ||
3032 | } | ||
3033 | |||
3034 | if (!info->allocating_chunk) { | ||
3035 | info->force_alloc = 1; | ||
3036 | info->allocating_chunk = 1; | ||
3037 | } else { | ||
3038 | wait = true; | ||
3039 | } | ||
3040 | |||
3041 | spin_unlock(&info->lock); | ||
3042 | |||
3043 | if (wait) { | ||
3044 | wait_event(info->allocate_wait, | ||
3045 | !info->allocating_chunk); | ||
3046 | return 1; | ||
3047 | } | ||
3048 | |||
3049 | trans = btrfs_start_transaction(root, 1); | ||
3050 | if (!trans) { | ||
3051 | ret = -ENOMEM; | ||
3052 | goto out; | ||
3053 | } | ||
3054 | |||
3055 | ret = do_chunk_alloc(trans, root->fs_info->extent_root, | ||
3056 | 4096 + 2 * 1024 * 1024, | ||
3057 | info->flags, 0); | ||
3058 | btrfs_end_transaction(trans, root); | ||
3059 | if (ret) | ||
3060 | goto out; | ||
3061 | out: | ||
3062 | spin_lock(&info->lock); | ||
3063 | info->allocating_chunk = 0; | ||
3064 | spin_unlock(&info->lock); | ||
3065 | wake_up(&info->allocate_wait); | ||
3066 | |||
3067 | if (ret) | ||
3068 | return 0; | ||
3069 | return 1; | ||
3070 | } | ||
3071 | |||
3072 | /* | 3009 | /* |
3073 | * Reserve metadata space for delalloc. | 3010 | * Reserve metadata space for delalloc. |
3074 | */ | 3011 | */ |
@@ -3109,7 +3046,8 @@ again: | |||
3109 | flushed++; | 3046 | flushed++; |
3110 | 3047 | ||
3111 | if (flushed == 1) { | 3048 | if (flushed == 1) { |
3112 | if (maybe_allocate_chunk(root, meta_sinfo)) | 3049 | if (maybe_allocate_chunk(NULL, root, meta_sinfo, |
3050 | num_bytes)) | ||
3113 | goto again; | 3051 | goto again; |
3114 | flushed++; | 3052 | flushed++; |
3115 | } else { | 3053 | } else { |
@@ -3224,7 +3162,8 @@ again: | |||
3224 | if (used > meta_sinfo->total_bytes) { | 3162 | if (used > meta_sinfo->total_bytes) { |
3225 | retries++; | 3163 | retries++; |
3226 | if (retries == 1) { | 3164 | if (retries == 1) { |
3227 | if (maybe_allocate_chunk(root, meta_sinfo)) | 3165 | if (maybe_allocate_chunk(NULL, root, meta_sinfo, |
3166 | num_bytes)) | ||
3228 | goto again; | 3167 | goto again; |
3229 | retries++; | 3168 | retries++; |
3230 | } else { | 3169 | } else { |
@@ -3421,13 +3360,28 @@ static void force_metadata_allocation(struct btrfs_fs_info *info) | |||
3421 | rcu_read_unlock(); | 3360 | rcu_read_unlock(); |
3422 | } | 3361 | } |
3423 | 3362 | ||
3363 | static int should_alloc_chunk(struct btrfs_space_info *sinfo, | ||
3364 | u64 alloc_bytes) | ||
3365 | { | ||
3366 | u64 num_bytes = sinfo->total_bytes - sinfo->bytes_readonly; | ||
3367 | |||
3368 | if (sinfo->bytes_used + sinfo->bytes_reserved + | ||
3369 | alloc_bytes + 256 * 1024 * 1024 < num_bytes) | ||
3370 | return 0; | ||
3371 | |||
3372 | if (sinfo->bytes_used + sinfo->bytes_reserved + | ||
3373 | alloc_bytes < div_factor(num_bytes, 8)) | ||
3374 | return 0; | ||
3375 | |||
3376 | return 1; | ||
3377 | } | ||
3378 | |||
3424 | static int do_chunk_alloc(struct btrfs_trans_handle *trans, | 3379 | static int do_chunk_alloc(struct btrfs_trans_handle *trans, |
3425 | struct btrfs_root *extent_root, u64 alloc_bytes, | 3380 | struct btrfs_root *extent_root, u64 alloc_bytes, |
3426 | u64 flags, int force) | 3381 | u64 flags, int force) |
3427 | { | 3382 | { |
3428 | struct btrfs_space_info *space_info; | 3383 | struct btrfs_space_info *space_info; |
3429 | struct btrfs_fs_info *fs_info = extent_root->fs_info; | 3384 | struct btrfs_fs_info *fs_info = extent_root->fs_info; |
3430 | u64 thresh; | ||
3431 | int ret = 0; | 3385 | int ret = 0; |
3432 | 3386 | ||
3433 | mutex_lock(&fs_info->chunk_mutex); | 3387 | mutex_lock(&fs_info->chunk_mutex); |
@@ -3450,11 +3404,7 @@ static int do_chunk_alloc(struct btrfs_trans_handle *trans, | |||
3450 | goto out; | 3404 | goto out; |
3451 | } | 3405 | } |
3452 | 3406 | ||
3453 | thresh = space_info->total_bytes - space_info->bytes_readonly; | 3407 | if (!force && !should_alloc_chunk(space_info, alloc_bytes)) { |
3454 | thresh = div_factor(thresh, 8); | ||
3455 | if (!force && | ||
3456 | (space_info->bytes_used + space_info->bytes_pinned + | ||
3457 | space_info->bytes_reserved + alloc_bytes) < thresh) { | ||
3458 | spin_unlock(&space_info->lock); | 3408 | spin_unlock(&space_info->lock); |
3459 | goto out; | 3409 | goto out; |
3460 | } | 3410 | } |
@@ -3476,6 +3426,8 @@ static int do_chunk_alloc(struct btrfs_trans_handle *trans, | |||
3476 | spin_lock(&space_info->lock); | 3426 | spin_lock(&space_info->lock); |
3477 | if (ret) | 3427 | if (ret) |
3478 | space_info->full = 1; | 3428 | space_info->full = 1; |
3429 | else | ||
3430 | ret = 1; | ||
3479 | space_info->force_alloc = 0; | 3431 | space_info->force_alloc = 0; |
3480 | spin_unlock(&space_info->lock); | 3432 | spin_unlock(&space_info->lock); |
3481 | out: | 3433 | out: |
@@ -3483,6 +3435,38 @@ out: | |||
3483 | return ret; | 3435 | return ret; |
3484 | } | 3436 | } |
3485 | 3437 | ||
3438 | static int maybe_allocate_chunk(struct btrfs_trans_handle *trans, | ||
3439 | struct btrfs_root *root, | ||
3440 | struct btrfs_space_info *sinfo, u64 num_bytes) | ||
3441 | { | ||
3442 | int ret; | ||
3443 | int end_trans = 0; | ||
3444 | |||
3445 | if (sinfo->full) | ||
3446 | return 0; | ||
3447 | |||
3448 | spin_lock(&sinfo->lock); | ||
3449 | ret = should_alloc_chunk(sinfo, num_bytes + 2 * 1024 * 1024); | ||
3450 | spin_unlock(&sinfo->lock); | ||
3451 | if (!ret) | ||
3452 | return 0; | ||
3453 | |||
3454 | if (!trans) { | ||
3455 | trans = btrfs_join_transaction(root, 1); | ||
3456 | BUG_ON(IS_ERR(trans)); | ||
3457 | end_trans = 1; | ||
3458 | } | ||
3459 | |||
3460 | ret = do_chunk_alloc(trans, root->fs_info->extent_root, | ||
3461 | num_bytes + 2 * 1024 * 1024, | ||
3462 | get_alloc_profile(root, sinfo->flags), 0); | ||
3463 | |||
3464 | if (end_trans) | ||
3465 | btrfs_end_transaction(trans, root); | ||
3466 | |||
3467 | return ret == 1 ? 1 : 0; | ||
3468 | } | ||
3469 | |||
3486 | static int update_block_group(struct btrfs_trans_handle *trans, | 3470 | static int update_block_group(struct btrfs_trans_handle *trans, |
3487 | struct btrfs_root *root, | 3471 | struct btrfs_root *root, |
3488 | u64 bytenr, u64 num_bytes, int alloc, | 3472 | u64 bytenr, u64 num_bytes, int alloc, |