diff options
| -rw-r--r-- | fs/btrfs/ctree.h | 2 | ||||
| -rw-r--r-- | fs/btrfs/extent-tree.c | 132 |
2 files changed, 58 insertions, 76 deletions
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 6132088a577c..a68f34603b9d 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h | |||
| @@ -701,9 +701,7 @@ struct btrfs_space_info { | |||
| 701 | struct list_head list; | 701 | struct list_head list; |
| 702 | 702 | ||
| 703 | /* for controlling how we free up space for allocations */ | 703 | /* for controlling how we free up space for allocations */ |
| 704 | wait_queue_head_t allocate_wait; | ||
| 705 | wait_queue_head_t flush_wait; | 704 | wait_queue_head_t flush_wait; |
| 706 | int allocating_chunk; | ||
| 707 | int flushing; | 705 | int flushing; |
| 708 | 706 | ||
| 709 | /* for block groups in our same type */ | 707 | /* for block groups in our same type */ |
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, |
