[gparted] Flush devices when scanning to prevent reading stale signatures (#723842)



commit 3bea067596e3e2d6513cda2a66df1b3e4fa432fb
Author: Mike Fleetwood <mike fleetwood googlemail com>
Date:   Sun Mar 23 21:11:13 2014 +0000

    Flush devices when scanning to prevent reading stale signatures (#723842)
    
    While one partition is busy, reformat another partition from the command
    line.  Afterwards parted/libparted still detects the original file
    system and GParted shows errors from the file system specific tools
    reporting the new file system doesn't exist.  Only limitation is that
    the new new file system must be recognised by libparted (or by GParted's
    fallback file system signature detection).
    
    Case #1, File system reformatting:
    
        # parted /dev/sdb print
        Model: ATA SAMSUNG SSD UM41 (scsi)
        Disk /dev/sdb: 8012MB
        Sector size (logical/physical): 512B/512B
        Partition Table: msdos
    
        Number  Start   End     Size    Type     File system  Flags
         1      1049kB  2149MB  2147MB  primary  ext2
         2      2149MB  4296MB  2147MB  primary  ext2
        # mount | fgrep sdb
        /dev/sdb1 on /mnt/1 type ext2 (rw)
    
        # mkfs.xfs -f /dev/sdb2
        # blkid /dev/sdb2
        /dev/sdb2: UUID="c31823a2-b81b-46fa-8246-0a59695e4834" TYPE="xfs"
        # parted /dev/sdb print
        Model: ATA SAMSUNG SSD UM41 (scsi)
        Disk /dev/sdb: 8012MB
        Sector size (logical/physical): 512B/512B
        Partition Table: msdos
    
        Number  Start   End     Size    Type     File system  Flags
         1      1049kB  2149MB  2147MB  primary  ext2
         2      2149MB  4296MB  2147MB  primary  ext2
        # e2label /dev/sdb2
        e2label: Bad magic number in super-block while trying to open /dev/sdb2
        Couldn't find valid filesystem superblock.
        # dumpe2fs /dev/sdb2
        dumpe2fs 1.41.12 (17-May-2010)
        dumpe2fs: Bad magic number in super-block while trying to open /dev/sdb2
        Couldn't find valid filesystem superblock.
    
    Case #2, Removing device from multi-device btrfs:
    
        # btrfs filesystem show /dev/sdb1
        Label: none  uuid: a05db434-efd5-4e8c-902f-05f89a88b610
                Total devices 2 FS bytes used 156.00KB
                devid    2 size 2.00GB used 512.00MB path /dev/sdb2
                devid    1 size 2.00GB used 240.75MB path /dev/sdb1
    
        # mount /dev/sdb1 /mnt/1
        # btrfs device delete /dev/sdb2
        # btrfs filesystem show /dev/sdb1
        Label: none  uuid: a05db434-efd5-4e8c-902f-05f89a88b610
                Total devices 1 FS bytes used 92.00KB
                devid    1 size 2.00GB used 714.25MB path /dev/sdb1
        # btrfs filesystem show /dev/sdb2
    
    and GParted reports this error for partition /dev/sdb2:
        Unable to read the contents of this file system!
        Because of this some operations may be unavailable.
        The cause might be a missing software package.
        The following list of software packages is required for btrfs
        file system support:  btrfs-tools.
    
    This is another case of libparted reading from the whole disk device
    (/dev/sdb) yet the file system tools use the partition specific block
    device (/dev/sdb2), and the Linux buffer cache not providing cache
    coherency.  Previous scenario was fixed with:
    
        797f0b8eeb61f81da1791c3cf048b5c0abf9a550
        Flush device after wiping a file system (#688882)
    
    This affects libparted 2.0 to 3.1 inclusive and is fixed by:
    
        http://git.savannah.gnu.org/cgit/parted.git/commit/?id=fb99ba5ebd0dc34204fc9f1014131d5d494805bc
        Revert "linux-commit: do not unnecessarily open partition device nodes"
    
    Fix by calling ped_device_sync() to guarantee cache coherency for each
    device during scanning.
    
    Bug #723842 - GParted resizes the wrong filesystem (does not pass the
                  devid to btrfs filesystem resize)

 include/GParted_Core.h |    3 ++-
 src/GParted_Core.cc    |   44 +++++++++++++++++++++++++++++++++-----------
 2 files changed, 35 insertions(+), 12 deletions(-)
---
diff --git a/include/GParted_Core.h b/include/GParted_Core.h
index b51271b..195bca2 100644
--- a/include/GParted_Core.h
+++ b/include/GParted_Core.h
@@ -183,8 +183,9 @@ private:
        bool update_bootsector( const Partition & partition, OperationDetail & operationdetail ) ;
 
        //general..     
+       bool flush_device( PedDevice * lp_device ) ;
        bool get_device_and_disk( const Glib::ustring & device_path,
-                                 PedDevice*& lp_device, PedDisk*& lp_disk, bool strict = true ) ;
+                                 PedDevice*& lp_device, PedDisk*& lp_disk, bool strict = true, bool flush = 
false ) ;
        void destroy_device_and_disk( PedDevice*& lp_device, PedDisk*& lp_disk ) ;
        bool commit( PedDisk* lp_disk ) ;
        bool commit_to_os( PedDisk* lp_disk, std::time_t timeout ) ;
diff --git a/src/GParted_Core.cc b/src/GParted_Core.cc
index 16839c0..b8b5d89 100644
--- a/src/GParted_Core.cc
+++ b/src/GParted_Core.cc
@@ -288,7 +288,7 @@ void GParted_Core::set_devices_thread( std::vector<Device> * pdevices )
                set_thread_status_message( String::ucompose ( _("Searching %1 partitions"), device_paths[ t ] 
) ) ;
                PedDevice* lp_device = NULL ;
                PedDisk* lp_disk = NULL ;
-               if ( get_device_and_disk( device_paths[ t ], lp_device, lp_disk, false ) )
+               if ( get_device_and_disk( device_paths[ t ], lp_device, lp_disk, false, true ) )
                {
                        temp_device .Reset() ;
 
@@ -313,7 +313,7 @@ void GParted_Core::set_devices_thread( std::vector<Device> * pdevices )
                        {
                                temp_device .disktype = lp_disk ->type ->name ;
                                temp_device .max_prims = ped_disk_get_max_primary_partition_count( lp_disk ) ;
-                               
+
                                set_device_partitions( temp_device, lp_device, lp_disk ) ;
                                set_mountpoints( temp_device .partitions ) ;
                                set_used_sectors( temp_device .partitions, lp_disk ) ;
@@ -3393,14 +3393,6 @@ bool GParted_Core::erase_filesystem_signatures( const Partition & partition, Ope
        //  via the whole disk device will read the old data and report the file system
        //  as still existing.
        //
-       //  Libparted >= 2.0 works around this by calling ioctl(fd, BLKFLSBUF) to flush
-       //  the cache when opening the whole disk device, but only for kernels before
-       //  2.6.0.
-       //  Ref: parted v3.1-52-g1c659d5 ./libparted/arch/linux.c linux_open()
-       //  1657         /* With kernels < 2.6 flush cache for cache coherence issues */
-       //  1658         if (!_have_kern26())
-       //  1659                 _flush_cache (dev);
-       //
        //  Calling ped_device_sync() to flush the cache is required when the partition is
        //  just being cleared.  However the sync can be skipped when the wipe is being
        //  performed as part of writing a new file system as the partition type is also
@@ -3521,12 +3513,42 @@ bool GParted_Core::update_bootsector( const Partition & partition, OperationDeta
        return true ;
 }
 
+//Flush the Linux kernel caches, and therefore ensure coherency between the caches of the
+//  whole disk device and the partition devices.
+//
+//  Libparted >= 2.0 works around this by calling ioctl(fd, BLKFLSBUF) to flush the cache
+//  when opening the whole disk device, but only for kernels before 2.6.0.
+//  Ref: parted v3.1-52-g1c659d5 ./libparted/arch/linux.c linux_open()
+//  1657         /* With kernels < 2.6 flush cache for cache coherence issues */
+//  1658         if (!_have_kern26())
+//  1659                 _flush_cache (dev);
+//
+//  Libparted >= v3.1-61-gfb99ba5 works around this for all kernel versions.
+//  Ref: parted v3.1-61-gfb99ba5 ./libparted/arch/linux.c linux_open()
+//  1640         _flush_cache (dev);
+bool GParted_Core::flush_device( PedDevice * lp_device )
+{
+       bool success = false ;
+       if ( ped_device_open( lp_device ) )
+       {
+               success = ped_device_sync( lp_device ) ;
+               ped_device_close( lp_device ) ;
+       }
+       return success ;
+}
+
 bool GParted_Core::get_device_and_disk( const Glib::ustring & device_path,
-                                        PedDevice*& lp_device, PedDisk*& lp_disk, bool strict )
+                                        PedDevice*& lp_device, PedDisk*& lp_disk, bool strict, bool flush )
 {
        lp_device = ped_device_get( device_path .c_str() ) ;
        if ( lp_device )
        {
+               if ( flush )
+                       //Force cache coherency before reading the partition table so that
+                       //  libparted reading the whole disk device and the file system
+                       //  tools reading the partition devices read the same data.
+                       flush_device( lp_device ) ;
+
                lp_disk = ped_disk_new( lp_device );
        
                //if ! disk and writeable it's probably a HD without disklabel.


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