From 797f0b8eeb61f81da1791c3cf048b5c0abf9a550 Mon Sep 17 00:00:00 2001 From: Mike Fleetwood Date: Tue, 15 Jan 2013 13:51:04 +0000 Subject: [PATCH] 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 --- src/GParted_Core.cc | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/src/GParted_Core.cc b/src/GParted_Core.cc index fe5bd5ae..e15d5c37 100644 --- a/src/GParted_Core.cc +++ b/src/GParted_Core.cc @@ -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 ; }