[gparted] Pass devid when resizing btrfs file systems (#723842)



commit 0e980a47a24b2f030252ddc6e5106a7d0b1e303b
Author: Mike Fleetwood <mike fleetwood googlemail com>
Date:   Fri Apr 11 11:27:18 2014 +0100

    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)

 src/btrfs.cc |   16 +++++++++++++---
 1 files changed, 13 insertions(+), 3 deletions(-)
---
diff --git a/src/btrfs.cc b/src/btrfs.cc
index 52e4480..48f6aed 100644
--- a/src/btrfs.cc
+++ b/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 )


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]