aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/extent-tree.c
diff options
context:
space:
mode:
authorMiao Xie <miaox@cn.fujitsu.com>2012-01-26 15:01:12 -0500
committerChris Mason <chris.mason@oracle.com>2012-01-26 15:01:12 -0500
commit9e622d6bea0202e9fe267955362c01918562c09b (patch)
tree75b73fbfec2c56ba9ccbe909586cf0f27aba96e1 /fs/btrfs/extent-tree.c
parent7ec31b548a17f773ab6289e795ed3a6820e8b56e (diff)
Btrfs: fix enospc error caused by wrong checks of the chunk
When we did sysbench test for inline files, enospc error happened easily though there was lots of free disk space which could be allocated for new chunks. Reproduce steps: # mkfs.btrfs -b $((2 * 1024 * 1024 * 1024)) <test partition> # mount <test partition> /mnt # ulimit -n 102400 # cd /mnt # sysbench --num-threads=1 --test=fileio --file-num=81920 \ > --file-total-size=80M --file-block-size=1K --file-io-mode=sync \ > --file-test-mode=seqwr prepare # sysbench --num-threads=1 --test=fileio --file-num=81920 \ > --file-total-size=80M --file-block-size=1K --file-io-mode=sync \ > --file-test-mode=seqwr run <soon later, BUG_ON() was triggered by enospc error> The reason of this bug is: Now, we can reserve space which is larger than the free space in the chunks if we have enough free disk space which can be used for new chunks. By this way, the space allocator should allocate a new chunk by force if there is no free space in the free space cache. But there are two wrong checks which break this operation. One is if (ret == -ENOSPC && num_bytes > min_alloc_size) in btrfs_reserve_extent(), it is wrong, we should try to allocate a new chunk even we fail to allocate free space by minimum allocable size. The other is if (space_info->force_alloc) force = space_info->force_alloc; in do_chunk_alloc(). It makes the allocator ignore CHUNK_ALLOC_FORCE If someone sets ->force_alloc to CHUNK_ALLOC_LIMITED, and makes the enospc error happen. Fix these two wrong checks. Especially the second one, we fix it by changing the value of CHUNK_ALLOC_LIMITED and CHUNK_ALLOC_FORCE, and make CHUNK_ALLOC_FORCE greater than CHUNK_ALLOC_LIMITED since CHUNK_ALLOC_FORCE has higher priority. And if the value which is passed in by the caller is greater than ->force_alloc, use the passed value. Signed-off-by: Miao Xie <miaox@cn.fujitsu.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.c49
1 files changed, 27 insertions, 22 deletions
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index 700879ed64cf..283af7a676a3 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -34,23 +34,24 @@
34#include "locking.h" 34#include "locking.h"
35#include "free-space-cache.h" 35#include "free-space-cache.h"
36 36
37/* control flags for do_chunk_alloc's force field 37/*
38 * control flags for do_chunk_alloc's force field
38 * CHUNK_ALLOC_NO_FORCE means to only allocate a chunk 39 * CHUNK_ALLOC_NO_FORCE means to only allocate a chunk
39 * if we really need one. 40 * if we really need one.
40 * 41 *
41 * CHUNK_ALLOC_FORCE means it must try to allocate one
42 *
43 * CHUNK_ALLOC_LIMITED means to only try and allocate one 42 * CHUNK_ALLOC_LIMITED means to only try and allocate one
44 * if we have very few chunks already allocated. This is 43 * if we have very few chunks already allocated. This is
45 * used as part of the clustering code to help make sure 44 * used as part of the clustering code to help make sure
46 * we have a good pool of storage to cluster in, without 45 * we have a good pool of storage to cluster in, without
47 * filling the FS with empty chunks 46 * filling the FS with empty chunks
48 * 47 *
48 * CHUNK_ALLOC_FORCE means it must try to allocate one
49 *
49 */ 50 */
50enum { 51enum {
51 CHUNK_ALLOC_NO_FORCE = 0, 52 CHUNK_ALLOC_NO_FORCE = 0,
52 CHUNK_ALLOC_FORCE = 1, 53 CHUNK_ALLOC_LIMITED = 1,
53 CHUNK_ALLOC_LIMITED = 2, 54 CHUNK_ALLOC_FORCE = 2,
54}; 55};
55 56
56/* 57/*
@@ -3414,7 +3415,7 @@ static int do_chunk_alloc(struct btrfs_trans_handle *trans,
3414 3415
3415again: 3416again:
3416 spin_lock(&space_info->lock); 3417 spin_lock(&space_info->lock);
3417 if (space_info->force_alloc) 3418 if (force < space_info->force_alloc)
3418 force = space_info->force_alloc; 3419 force = space_info->force_alloc;
3419 if (space_info->full) { 3420 if (space_info->full) {
3420 spin_unlock(&space_info->lock); 3421 spin_unlock(&space_info->lock);
@@ -5794,6 +5795,7 @@ int btrfs_reserve_extent(struct btrfs_trans_handle *trans,
5794 u64 search_end, struct btrfs_key *ins, 5795 u64 search_end, struct btrfs_key *ins,
5795 u64 data) 5796 u64 data)
5796{ 5797{
5798 bool final_tried = false;
5797 int ret; 5799 int ret;
5798 u64 search_start = 0; 5800 u64 search_start = 0;
5799 5801
@@ -5813,22 +5815,25 @@ again:
5813 search_start, search_end, hint_byte, 5815 search_start, search_end, hint_byte,
5814 ins, data); 5816 ins, data);
5815 5817
5816 if (ret == -ENOSPC && num_bytes > min_alloc_size) { 5818 if (ret == -ENOSPC) {
5817 num_bytes = num_bytes >> 1; 5819 if (!final_tried) {
5818 num_bytes = num_bytes & ~(root->sectorsize - 1); 5820 num_bytes = num_bytes >> 1;
5819 num_bytes = max(num_bytes, min_alloc_size); 5821 num_bytes = num_bytes & ~(root->sectorsize - 1);
5820 do_chunk_alloc(trans, root->fs_info->extent_root, 5822 num_bytes = max(num_bytes, min_alloc_size);
5821 num_bytes, data, CHUNK_ALLOC_FORCE); 5823 do_chunk_alloc(trans, root->fs_info->extent_root,
5822 goto again; 5824 num_bytes, data, CHUNK_ALLOC_FORCE);
5823 } 5825 if (num_bytes == min_alloc_size)
5824 if (ret == -ENOSPC && btrfs_test_opt(root, ENOSPC_DEBUG)) { 5826 final_tried = true;
5825 struct btrfs_space_info *sinfo; 5827 goto again;
5826 5828 } else if (btrfs_test_opt(root, ENOSPC_DEBUG)) {
5827 sinfo = __find_space_info(root->fs_info, data); 5829 struct btrfs_space_info *sinfo;
5828 printk(KERN_ERR "btrfs allocation failed flags %llu, " 5830
5829 "wanted %llu\n", (unsigned long long)data, 5831 sinfo = __find_space_info(root->fs_info, data);
5830 (unsigned long long)num_bytes); 5832 printk(KERN_ERR "btrfs allocation failed flags %llu, "
5831 dump_space_info(sinfo, num_bytes, 1); 5833 "wanted %llu\n", (unsigned long long)data,
5834 (unsigned long long)num_bytes);
5835 dump_space_info(sinfo, num_bytes, 1);
5836 }
5832 } 5837 }
5833 5838
5834 trace_btrfs_reserved_extent_alloc(root, ins->objectid, ins->offset); 5839 trace_btrfs_reserved_extent_alloc(root, ins->objectid, ins->offset);