Pass devid when resizing btrfs file systems (#723842)
GParted doesn't specify the devid when resizing a btrfs file system, so the kernel defaults to resizing devid 1. On a multi-device btrfs this may not be the same partition which GParted is resizing. This will result in file system truncation and corruption. Shrinking the wrong partition example: 1) Create a btrfs file system spanning 2 partitions: # mkfs.btrfs /dev/sdb1 /dev/sdb2 # btrfs filesystem show /dev/sdb1 Label: none uuid: 41654265-9840-45c4-aca1-55989da358d6 Total devices 2 FS bytes used 112.00KiB devid 1 size 2.00GiB used 437.50MiB path /dev/sdb1 devid 2 size 2.00GiB used 417.50MiB path /dev/sdb2 2) Resize /dev/sdb2 down to 1 GiB using GParted. This command was run: btrfs filesystem resize 1048576K /tmp/gparted-ddyGRh which resized devid 1 (/dev/sdb1) to 1 GiB: # btrfs filesystem show /dev/sdb1 Label: none uuid: 41654265-9840-45c4-aca1-55989da358d6 Total devices 2 FS bytes used 256.00KiB devid 1 size 1.00GiB used 437.50MiB path /dev/sdb1 devid 2 size 2.00GiB used 417.50MiB path /dev/sdb2 but GParted instead resized /dev/sdb2 to 1 GiB: # sfdisk -s /dev/sdb1 2097152 # sfdisk -s /dev/sdb2 1048576 Even on a single device btrfs devid 1 may no longer exist if the file system has had the initial device removed from it. Example: 1) Create a single btrfs file system, add a second device and remove the first: # mkfs.btrfs /dev/sdb1 # mount /dev/sdb1 /mnt/1 # btrfs device add /dev/sdb2 /mnt/1 # btrfs device remove /dev/sdb1 /mnt/1 # umount /mnt/1 # btrfs filesystem show /dev/sdb2 Label: none uuid: 2cbf3ac3-1344-472a-a0c7-1476d23bdc9f Total devices 1 FS bytes used 256.00KiB devid 2 size 2.00GiB used 480.00MiB path /dev/sdb2 2) Again resize /dev/sdb2 down to 1 GiB using GParted. This command was run: btrfs filesystem resize 1048576K /tmp/gparted-ddyGRh but it failed with: ERROR: unable to resize 'tmp/gparted-lEyGaY' - No such device A more informative error message was written to syslog: # tail -1 /var/log/messages Mar 12 14:15:01 localhost kernel: btrfs: resizer unable to find device 1 This is with Linux kernel 3.13.5 on Fedora 20, circa March 2014. Fix by specifying the devid when resizing (part of) a btrfs file system. Example command specifying devid 2: btrfs filesystem resize 2:1048576K /tmp/1 This will always work because it is the kernel which interprets the devid colon size parameter and has always done so since btrfs was first added to the kernel in version 2.6.32 [1]. Reference: [1] linux v2.6.32 fs/btrfs/ioctl.c btrfs_ioctl_resize() https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/fs/btrfs/ioctl.c?id=v2.6.32#n578 Bug #723842 - GParted resizes the wrong filesystem (does not pass the devid to btrfs filesystem resize)
This commit is contained in:
parent
287526681d
commit
0e980a47a2
16
src/btrfs.cc
16
src/btrfs.cc
|
@ -291,6 +291,16 @@ bool btrfs::write_label( const Partition & partition, OperationDetail & operatio
|
|||
bool btrfs::resize( const Partition & partition_new, OperationDetail & operationdetail, bool fill_partition )
|
||||
{
|
||||
bool success = true ;
|
||||
Glib::ustring path = partition_new .get_path() ;
|
||||
|
||||
BTRFS_Device btrfs_dev = get_cache_entry( path ) ;
|
||||
if ( btrfs_dev .devid == -1 )
|
||||
{
|
||||
operationdetail .add_child( OperationDetail(
|
||||
String::ucompose( _("Failed to find devid for path %1"), path ), STATUS_ERROR ) ) ;
|
||||
return false ;
|
||||
}
|
||||
Glib::ustring devid_str = Utils::num_to_str( btrfs_dev .devid ) ;
|
||||
|
||||
Glib::ustring mount_point ;
|
||||
if ( ! partition_new .busy )
|
||||
|
@ -298,7 +308,7 @@ bool btrfs::resize( const Partition & partition_new, OperationDetail & operation
|
|||
mount_point = mk_temp_dir( "", operationdetail ) ;
|
||||
if ( mount_point .empty() )
|
||||
return false ;
|
||||
success &= ! execute_command( "mount -v -t btrfs " + partition_new .get_path() + " " + mount_point,
|
||||
success &= ! execute_command( "mount -v -t btrfs " + path + " " + mount_point,
|
||||
operationdetail, true ) ;
|
||||
}
|
||||
else
|
||||
|
@ -314,9 +324,9 @@ bool btrfs::resize( const Partition & partition_new, OperationDetail & operation
|
|||
size = "max" ;
|
||||
Glib::ustring cmd ;
|
||||
if ( btrfs_found )
|
||||
cmd = "btrfs filesystem resize " + size + " " + mount_point ;
|
||||
cmd = "btrfs filesystem resize " + devid_str + ":" + size + " " + mount_point ;
|
||||
else
|
||||
cmd = "btrfsctl -r " + size + " " + mount_point ;
|
||||
cmd = "btrfsctl -r " + devid_str + ":" + size + " " + mount_point ;
|
||||
exit_status = execute_command( cmd, operationdetail, false ) ;
|
||||
bool resize_succeeded = ( exit_status == 0 ) ;
|
||||
if ( resize_to_same_size_fails )
|
||||
|
|
Loading…
Reference in New Issue