• Miao Xie's avatar
    Btrfs: fix enospc error caused by wrong checks of the chunk · 9e622d6b
    Miao Xie authored
    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: default avatarMiao Xie <miaox@cn.fujitsu.com>
    Signed-off-by: default avatarChris Mason <chris.mason@oracle.com>
    9e622d6b
extent-tree.c 211 KB