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:

    797f0b8eeb
    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)
This commit is contained in:
Mike Fleetwood 2014-03-23 21:11:13 +00:00 committed by Curtis Gedak
parent 20f52e2866
commit 3bea067596
2 changed files with 35 additions and 12 deletions

View File

@ -183,8 +183,9 @@ private:
bool update_bootsector( const Partition & partition, OperationDetail & operationdetail ) ; bool update_bootsector( const Partition & partition, OperationDetail & operationdetail ) ;
//general.. //general..
bool flush_device( PedDevice * lp_device ) ;
bool get_device_and_disk( const Glib::ustring & device_path, 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 ) ; void destroy_device_and_disk( PedDevice*& lp_device, PedDisk*& lp_disk ) ;
bool commit( PedDisk* lp_disk ) ; bool commit( PedDisk* lp_disk ) ;
bool commit_to_os( PedDisk* lp_disk, std::time_t timeout ) ; bool commit_to_os( PedDisk* lp_disk, std::time_t timeout ) ;

View File

@ -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 ] ) ) ; set_thread_status_message( String::ucompose ( _("Searching %1 partitions"), device_paths[ t ] ) ) ;
PedDevice* lp_device = NULL ; PedDevice* lp_device = NULL ;
PedDisk* lp_disk = 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() ; temp_device .Reset() ;
@ -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 // via the whole disk device will read the old data and report the file system
// as still existing. // 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 // 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 // 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 // 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 ; 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, 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() ) ; lp_device = ped_device_get( device_path .c_str() ) ;
if ( lp_device ) 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 ); lp_disk = ped_disk_new( lp_device );
//if ! disk and writeable it's probably a HD without disklabel. //if ! disk and writeable it's probably a HD without disklabel.