btrfs-progs: prevent mkfs from aborting with small volume
v2 cover btrfs-progs: prevent mkfs from aborting with small volume
Here are 3 patches to avoid undesired aborts of mkfs.btrfs. These are based on top of Chris's btrfs-progs.git:
git://git.kernel.org/pub/scm/linux/kernel/git/mason/btrfs-progs.git
Thanks,
H.Seto
Hidetoshi Seto (3):
btrfs-progs: error if device for mkfs is too small
btrfs-progs: error if device have no space to make primary chunks
btrfs-progs: calculate available blocks on device properly
ctree.h | 8 +++++ mkfs.c | 23 +++++++++++++ volumes.c | 104 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 129 insertions(+), 6 deletions(-)
PATCH v2 1/3 btrfs-progs: error if device for mkfs is too small
Eric pointed out that mkfs abort if specified volume is too small:
# truncate --size=2m testfile # ./mkfs.btrfs testfile : SMALL VOLUME: forcing mixed metadata/data groups mkfs.btrfs: volumes.c:852: btrfs_alloc_chunk: Assertion `!(ret)' failed. Aborted (core dumped)
As the first step to fix problems around there, let mkfs to report error if the size of target volume is less than the size of the first system block group, BTRFS_MKFS_SYSTEM_GROUP_SIZE (= 4MB).
--- mkfs.c | 6 ++++++ 1 files changed, 6 insertions(+), 0 deletions(-)
mkfs.c +6 -0
@@ -1422,6 +1422,12 @@ int main(int ac, char **av) } } +/* To create the first block group and chunk 0 in make_btrfs */ +if (dev_block_count <BTRFS_MKFS_SYSTEM_GROUP_SIZE ) { +fprintf (stderr,"device is too small to make filesystem\n" ); +exit (1 ); + } + blocks[0 ] =BTRFS_SUPER_INFO_OFFSET ;for (i =1 ; i <7 ; i++) { blocks[i] = BTRFS_SUPER_INFO_OFFSET + 1024 * 1024 +
Signature · 1 line
1.7.1
PATCH v2 2/3 btrfs-progs: error if device have no space to make primary chunks
In reply to Hidetoshi SetoThe previous patch works fine if the size of specified volume to mkfs is less than 4MB. However usually btrfs requires more than 4MB to work, and the minimum preferred size is depending on the raid setting etc.
This patch let mkfs print error message if it cannot allocate one of chunks should be there at first.
[before]
# truncate --size=4500K testfile # ./mkfs.btrfs -f testfile : SMALL VOLUME: forcing mixed metadata/data groups mkfs.btrfs: mkfs.c:84: make_root_dir: Assertion `!(ret)' failed. Aborted (core dumped)
[After]
# truncate --size=4500K testfile # ./mkfs.btrfs -f testfile : SMALL VOLUME: forcing mixed metadata/data groups no space to alloc data/metadata chunk failed to setup the root directory
TBD is calculate minimum size for setting and put it in the error message to let user know how large amount of volume is required.
--- mkfs.c | 17 +++++++++++++++++ 1 files changed, 17 insertions(+), 0 deletions(-)
mkfs.c +17 -0
@@ -81,6 +81,11 @@ static int make_root_dir(struct btrfs_root *root, int mixed) &chunk_start, &chunk_size,BTRFS_BLOCK_GROUP_METADATA | BTRFS_BLOCK_GROUP_DATA); +if (ret == -ENOSPC ) { +fprintf (stderr, +"no space to alloc data/metadata chunk\n" ); + goto err; + }BUG_ON (ret); ret = btrfs_make_block_group(trans, root, 0, BTRFS_BLOCK_GROUP_METADATA |
@@ -93,6 +98,10 @@ static int make_root_dir(struct btrfs_root *root, int mixed) ret =btrfs_alloc_chunk (trans, root->fs_info->extent_root, &chunk_start, &chunk_size,BTRFS_BLOCK_GROUP_METADATA ); +if (ret == -ENOSPC ) { +fprintf (stderr,"no space to alloc metadata chunk\n" ); + goto err; + }BUG_ON (ret); ret = btrfs_make_block_group(trans, root, 0, BTRFS_BLOCK_GROUP_METADATA,
@@ -110,6 +119,10 @@ static int make_root_dir(struct btrfs_root *root, int mixed) ret =btrfs_alloc_chunk (trans, root->fs_info->extent_root, &chunk_start, &chunk_size,BTRFS_BLOCK_GROUP_DATA ); +if (ret == -ENOSPC ) { +fprintf (stderr,"no space to alloc data chunk\n" ); + goto err; + }BUG_ON (ret); ret = btrfs_make_block_group(trans, root, 0, BTRFS_BLOCK_GROUP_DATA,
@@ -181,6 +194,10 @@ static int create_one_raid_group(struct btrfs_trans_handle *trans, ret =btrfs_alloc_chunk (trans, root->fs_info->extent_root, &chunk_start, &chunk_size, type); +if (ret == -ENOSPC ) { +fprintf (stderr,"not enough free space\n" ); +exit (1 ); + }BUG_ON (ret); ret = btrfs_make_block_group(trans, root->fs_info->extent_root, 0, type, BTRFS_FIRST_CHUNK_TREE_OBJECTID,
Signature · 1 line
1.7.1
PATCH v2 3/3 btrfs-progs: calculate available blocks on device properly
In reply to Hidetoshi SetoI found that mkfs.btrfs aborts when assigned multi volumes contain a small volume:
# parted /dev/sdf p Model: LSI MegaRAID SAS RMB (scsi) Disk /dev/sdf: 72.8GB Sector size (logical/physical): 512B/512B Partition Table: msdos
Number Start End Size Type File system Flags 1 32.3kB 72.4GB 72.4GB primary 2 72.4GB 72.8GB 461MB primary
# ./mkfs.btrfs -f /dev/sdf1 /dev/sdf2 : SMALL VOLUME: forcing mixed metadata/data groups adding device /dev/sdf2 id 2 mkfs.btrfs: volumes.c:852: btrfs_alloc_chunk: Assertion `!(ret)' failed. Aborted (core dumped)
This failure of btrfs_alloc_chunk was caused by following steps:
1) since there is only small space in the small device, mkfs was going to allocate a chunk from free space as much as available. So mkfs called btrfs_alloc_chunk with
size = device->total_bytes - device->used_bytes.
2) (According to the comment in source code, to avoid overwriting superblock,) btrfs_alloc_chunk starts taking chunks at an offset of 1MB. It means that the layout of a disk will be like:
[[1MB at beginning for sb][allocated chunks]* ... free space ... ]
and you can see that the available free space for allocation is:
avail = device->total_bytes - device->used_bytes - 1MB.
3) Therefore there is only free space 1MB less than requested. damn.
Quoted 1 line
From further investigations I also found that this issue is easily
reproduced by using -A, --alloc-start option:
# truncate --size=1G testfile # ./mkfs.btrfs -A900M -f testfile : mkfs.btrfs: volumes.c:852: btrfs_alloc_chunk: Assertion `!(ret)' failed. Aborted (core dumped)
In this case there is only 100MB for allocation but btrfs_alloc_chunk was going to allocate more than the 100MB.
The root cause of both of above troubles is a same simple bug:btrfs_chunk_alloc does not calculate available bytes properly even though it researches how many devices have enough room to have a chunk to be allocated.
So this patch introduces new function btrfs_device_avail_bytes() which returns available bytes for allocation in specified device.
--- ctree.h | 8 +++++ volumes.c | 104 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 106 insertions(+), 6 deletions(-)
ctree.h +8 -0
@@ -811,6 +811,14 @@ struct btrfs_csum_item {u8 csum; } __attribute__ ((__packed__)); +/* +* We don't want to overwrite 1M at the beginning of device, even though +* there is our 1st superblock at 64k. Some possible reasons: +* - the first 64k blank is useful for some boot loader/manager +* - the first 1M could be scratched by buggy partitioner or somesuch +*/ +#define BTRFS_BLOCK_RESERVED_1M_FOR_SUPER ((u64)1024 * 1024) +/* tag for the radix tree of block groups in ram */ #define BTRFS_BLOCK_GROUP_DATA (1ULL << 0)#define BTRFS_BLOCK_GROUP_SYSTEM (1ULL << 1)
volumes.c +98 -6
135 lines not on this page · raw message
Signature · 1 line
1.7.1