Flush device after wiping a file system (#688882)

When just formatting an existing partition to "cleared", GParted just
uses wipefs to clear the file system signatures.  Afterwards parted/
libparted still detect the file system and GParted shows errors from the
file system specific tools reporting the file system doesn't exist.

    # wipefs /dev/sda7
    offset               type
    ----------------------------------------------------------------
    0x0                  xfs   [filesystem]
                         UUID:  28399a74-83a5-4ed7-aaf8-c76ac449fb57
    # wipefs -a /dev/sda7
    4 bytes were erased at offset 0x0 (xfs)
    they were: 58 46 53 42
    # parted /dev/sda print
    Model: ATA SAMSUNG HM500JI (scsi)
    Disk /dev/sda: 500GB
    Sector size (logical/physical): 512B/512B
    Partition Table: msdos

    Number  Start   End     Size    Type      File system     Flags
     1      1049kB  538MB   537MB   primary   ext4            boot
     2      538MB   5907MB  5369MB  primary   linux-swap(v1)
     3      5907MB  32.8GB  26.8GB  primary   ext4
     4      32.8GB  500GB   467GB   extended
     5      32.8GB  355GB   322GB   logical   ext3
     6      355GB   356GB   1074MB  logical
     7      356GB   357GB   1074MB  logical   xfs
    # xfs_db -c 'sb 0' -c 'print blocksize' -c 'print dblocks' -c 'print fdblocks' -r /dev/sda7
    xfs_db: /dev/sda7 is not a valid XFS filesystem (unexpected SB magic number 0x00000000)

Wipefs was run on the partition specific block device (/dev/sda7) where
as libparted reads the disk using the whole disk device (/dev/sda).
However as the Linux buffer cache does not provide cache coherency, the
xfs file system can still be found in the cache of /dev/sda.

Fix this by calling ped_device_sync() after wipefs as it guarantees
cache coherency.

(As documented in erase_filesystem_signatures() there are cases when
calling ped_device_sync() isn't necessary, but testing shows that the
whole processes takes at most 0.15 seconds.  As this is in the middle of
applying an operation, uses won't notice this extra time so just always
call ped_device_sync()).

Bug #688882 - Improve clearing of file system signatures
This commit is contained in:
Mike Fleetwood 2013-01-15 13:51:04 +00:00 committed by Curtis Gedak
parent d4f68eb730
commit 797f0b8eeb
1 changed files with 35 additions and 0 deletions

View File

@ -3147,6 +3147,41 @@ bool GParted_Core::erase_filesystem_signatures( const Partition & partition, Ope
od .set_status( exit_status == 0 ? STATUS_SUCCES : STATUS_N_A ) ;
}
//Linux kernel doesn't maintain buffer cache coherency between the whole disk
// device and partition devices. So even though the file system signatures
// have been overwritten on the disk via a partition device, libparted reading
// 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
// changed, which modified the partition table so GParted calls
// ped_disk_commit_to_os(). This instructs the kernel to remove all non-busy
// partitions on the disk and re-adds them, thus effectively flushing the cache
// of the disk.
//
// Opening the device and calling ped_device_sync() took 0.15 seconds or less on
// a 5400 RPM laptop hard drive. For now just always call ped_device_sync() as
// it doesn't add much time to the overall operation.
PedDevice * lp_device = ped_device_get( partition .device_path .c_str() ) ;
if ( lp_device != NULL )
{
if ( ped_device_open( lp_device ) )
{
ped_device_sync( lp_device ) ;
ped_device_close( lp_device ) ;
}
ped_device_destroy( lp_device ) ;
}
return true ;
}