[gparted] Clear btrfs file system super block mirror copies too (#705426)
- From: Curtis Gedak <gedakc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gparted] Clear btrfs file system super block mirror copies too (#705426)
- Date: Mon, 26 Aug 2013 19:10:32 +0000 (UTC)
commit 246e05559d91865dd135690a62d56144f375c26b
Author: Mike Fleetwood <mike fleetwood googlemail com>
Date: Wed Aug 14 08:21:58 2013 +0100
Clear btrfs file system super block mirror copies too (#705426)
With recent btrfs-progs, GParted failed to format a btrfs file system
over the top of an existing one. Make btrfs failed with this error:
# mkfs.btrfs /dev/sdb1
...
/dev/sdb1 appears to contain an existing filesystem (btrfs).
Use the -f option to force overwrite.
With this commit to btrfs-progs on 2013-02-19, mkfs.btrfs checks for
existing file system signatures, including all mirror copies of btrfs
super blocks, before writing to the partition.
http://git.kernel.org/cgit/linux/kernel/git/mason/btrfs-progs.git/commit/?id=2a2d8e1962e8b6cda7b0a7584f6d2fb95d442cb6
btrfs-progs: require mkfs -f force option to overwrite filesystem or partition table
Make GParted clear all the mirror copies of the btrfs file system super
blocks as erase_filesystem_signatures() is intended to prevent detection
of old signatures. This also avoids having to determine if the -f
option to mkfs.btrfs is available before trying to use it.
Closes Bug #705426 - Formatting Existing BTRFS Partition as BTRFS Fails
Because mkfs.btrfs Is Not Run with "-f"
include/Utils.h | 3 +
src/GParted_Core.cc | 151 +++++++++++++++++++++++++++++----------------------
src/Utils.cc | 12 ++++
3 files changed, 102 insertions(+), 64 deletions(-)
---
diff --git a/include/Utils.h b/include/Utils.h
index 77a5d32..c1e98d9 100644
--- a/include/Utils.h
+++ b/include/Utils.h
@@ -50,6 +50,7 @@ const Byte_Value KIBIBYTE=1024;
const Byte_Value MEBIBYTE=(KIBIBYTE * KIBIBYTE);
const Byte_Value GIBIBYTE=(MEBIBYTE * KIBIBYTE);
const Byte_Value TEBIBYTE=(GIBIBYTE * KIBIBYTE);
+const Byte_Value PEBIBYTE=(TEBIBYTE * KIBIBYTE);
const Glib::ustring UUID_RANDOM = _("(New UUID - will be randomly generated)") ;
const Glib::ustring UUID_RANDOM_NTFS_HALF = _("(Half new UUID - will be randomly generated)") ;
@@ -193,6 +194,8 @@ public:
static int get_mounted_filesystem_usage( const Glib::ustring & mountpoint,
Byte_Value & fs_size, Byte_Value & fs_free,
Glib::ustring error_message ) ;
+ static Byte_Value floor_size( Byte_Value value, Byte_Value rounding_size ) ;
+ static Byte_Value ceil_size( Byte_Value value, Byte_Value rounding_size ) ;
private:
static bool get_kernel_version( int & major_ver, int & minor_ver, int & patch_ver ) ;
diff --git a/src/GParted_Core.cc b/src/GParted_Core.cc
index 625265f..d534f14 100644
--- a/src/GParted_Core.cc
+++ b/src/GParted_Core.cc
@@ -3104,7 +3104,7 @@ bool GParted_Core::filesystem_resize_disallowed( const Partition & partition )
bool GParted_Core::erase_filesystem_signatures( const Partition & partition, OperationDetail &
operationdetail )
{
- bool overall_success ;
+ bool overall_success = true ;
operationdetail .add_child( OperationDetail(
String::ucompose( _("clear old file system signatures in %1"),
partition .get_path() ) ) ) ;
@@ -3131,84 +3131,107 @@ bool GParted_Core::erase_filesystem_signatures( const Partition & partition, Ope
}
}
- //Single copy of string for translation purposes
- /*TO TRANSLATORS: looks like wrote 68.00 KiB of zeros at byte offset 0 */
- const Glib::ustring wrote_zeros_msg = _("wrote %1 of zeros at byte offset %2") ;
-
- //Erase all file system primary super blocks including their signatures.
- // Overwrite the first 68 KiB with zeros (or larger if if the sector size is
- // larger than 4 KiB. This covers the location all supported file super blocks
- // which range offset 0 for vfat, ntfs and xfs all the way up to offset 64 KiB
- // for btrfs, reiserfs and reiser4. This is likely to also include future file
- // system super blocks too).
+ //Erase all file system super blocks, including their signatures. The specified
+ // byte ranges are converted to whole sectors (as disks fundamentally only read
+ // or write whole sectors) and written using ped_geometry_write(). Therefore
+ // don't try to surgically overwrite just the few bytes of each signature as this
+ // code overwrites whole sectors and it embeds more knowledge that is necessary.
+ //
+ // First byte range from offset 0 of length 68 KiB covers the primary super block
+ // of all currently supported file systems and is also likely to include future
+ // file system super blocks too. Only a few file systems have additional super
+ // blocks and signatures. Overwrite the btrfs super block mirror copies and the
+ // nilfs2 secondary super block.
+ //
+ // Btrfs super blocks are located at: 64 KiB, 64 MiB, 256 GiB and 1 PiB.
+ // https://btrfs.wiki.kernel.org/index.php/On-disk_Format#Superblock
+ //
+ // Nilfs2 secondary super block is located at at the last whole 4 KiB block.
+ // Ref: nilfs-utils-2.1.4/include/nilfs2_fs.h
+ // #define NILFS_SB2_OFFSET_BYTES(devsize) ((((devsize) >> 12) - 1) << 12)
+ struct {
+ Byte_Value offset; //Negative offsets work backwards from the end of the partition
+ Byte_Value rounding; //Minimum desired rounding for offset
+ Byte_Value length;
+ } ranges[] = {
+ //offset , rounding , length
+ { 0LL , 1LL , 68LL * KIBIBYTE }, //All primary super blocks
+ { 64LL * MEBIBYTE, 1LL , 4LL * KIBIBYTE }, //Btrfs super block mirror copy
+ { 256LL * GIBIBYTE, 1LL , 4LL * KIBIBYTE }, //Btrfs super block mirror copy
+ { 1LL * PEBIBYTE, 1LL , 4LL * KIBIBYTE }, //Btrfs super block mirror copy
+ { -4LL * KIBIBYTE, 4LL * KIBIBYTE, 4LL * KIBIBYTE } //Nilfs2 secondary super block
+ } ;
+ for ( unsigned int i = 0 ; overall_success && i < sizeof( ranges ) / sizeof( ranges[0] ) ; i ++ )
{
- OperationDetail & od = operationdetail .get_last_child() ;
- od .add_child( OperationDetail( _("clear primary signatures") ) ) ;
+ //Rounding is performed in multiples of the sector size because writes are in whole sectors.
+ Byte_Value rounding_size = Utils::ceil_size( ranges[i].rounding, lp_device ->sector_size ) ;
+ Byte_Value byte_offset ;
+ Byte_Value byte_len ;
- Byte_Value total_size = std::min( 64LL * KIBIBYTE + bufsize, partition .get_byte_length() ) ;
- Byte_Value written = 0LL ;
- bool zero_success = false ;
- if ( device_is_open && buf )
+ //Compute range to be erased taking into minimum desired rounding requirements and
+ // negative offsets. Range may become larger, but not smaller than requested.
+ if ( ranges[i] .offset >= 0LL )
{
- while ( written < total_size )
- {
- zero_success = ped_geometry_write( & lp_partition ->geom, buf,
- written / lp_device ->sector_size,
- bufsize / lp_device ->sector_size ) ;
- if ( ! zero_success )
- break ;
- written += bufsize ;
- }
+ byte_offset = Utils::floor_size( ranges[i] .offset, rounding_size ) ;
+ byte_len = Utils::ceil_size( ranges[i] .offset + ranges[i] .length, rounding_size )
+ - byte_offset ;
+ }
+ else //Negative offsets
+ {
+ Byte_Value notional_offset = Utils::floor_size( partition .get_byte_length() +
ranges[i] .offset, ranges[i]. rounding ) ;
+ byte_offset = Utils::floor_size( notional_offset, rounding_size ) ;
+ byte_len = Utils::ceil_size( notional_offset + ranges[i] .length, rounding_size )
+ - byte_offset ;
}
- if ( zero_success )
+ //Limit range to partition size.
+ if ( byte_offset + byte_len <= 0LL )
{
- od .get_last_child() .add_child( OperationDetail(
- String::ucompose( wrote_zeros_msg,
- Utils::format_size( written, 1 ),
- 0LL ),
- STATUS_NONE, FONT_ITALIC ) ) ;
- od .get_last_child() .set_status( STATUS_SUCCES ) ;
+ //Byte range entirely before partition start. Programmer error!
+ continue;
}
- else
+ else if ( byte_offset < 0 )
{
- od .get_last_child() .set_status( STATUS_ERROR ) ;
+ //Byte range spans partition start. Trim to fit.
+ byte_len += byte_offset ;
+ byte_offset = 0LL ;
+ }
+ if ( byte_offset >= partition .get_byte_length() )
+ {
+ //Byte range entirely after partition end. Ignore.
+ continue ;
+ }
+ else if ( byte_offset + byte_len > partition .get_byte_length() )
+ {
+ //Byte range spans partition end. Trim to fit.
+ byte_len = partition .get_byte_length() - byte_offset ;
}
- overall_success = zero_success ;
- }
- //Also erase any nilfs2 secondary super block at the end of the partition to
- // prevent erroneous detection by libparted using the signature in the secondary
- // super block. Overwrite the last full 4 KiB block with zeros (or larger if the
- // sector size is larger and possibly earlier depending on the sector alignment).
- // Ref: nilfs-utils-2.1.4/include/nilfs2_fs.h
- // #define NILFS_SB2_OFFSET_BYTES(devsize) ((((devsize) >> 12) - 1) << 12)
- if ( overall_success )
- {
OperationDetail & od = operationdetail .get_last_child() ;
- od .add_child( OperationDetail( _("clear secondary signatures") ) ) ;
-
- Byte_Value byte_offset = ( ( partition .get_byte_length() >> 12 ) - 1 ) << 12 ;
+ Byte_Value written = 0LL ;
bool zero_success = false ;
if ( device_is_open && buf )
{
- zero_success = ped_geometry_write( & lp_partition ->geom, buf,
- byte_offset / lp_device ->sector_size,
- bufsize / lp_device ->sector_size ) ;
- }
+ od .add_child( OperationDetail(
+ /*TO TRANSLATORS: looks like write 68.00 KiB of zeros at byte offset
0 */
+ String::ucompose( "write %1 of zeros at byte offset %2",
+ Utils::format_size( byte_len, 1 ),
+ byte_offset ) ) ) ;
- if ( zero_success )
- {
- od .get_last_child() .add_child( OperationDetail(
- String::ucompose( wrote_zeros_msg,
- Utils::format_size( bufsize, 1 ),
- byte_offset ),
- STATUS_NONE, FONT_ITALIC ) ) ;
- od .get_last_child() .set_status( STATUS_SUCCES ) ;
- }
- else
- {
- od .get_last_child() .set_status( STATUS_ERROR ) ;
+ while ( written < byte_len )
+ {
+ //Write in bufsize amounts. Last write may be smaller but
+ // will still be a whole number of sectors.
+ Byte_Value amount = std::min( bufsize, byte_len - written ) ;
+ zero_success = ped_geometry_write( & lp_partition ->geom, buf,
+ ( byte_offset + written ) / lp_device
->sector_size,
+ amount / lp_device ->sector_size ) ;
+ if ( ! zero_success )
+ break ;
+ written += amount ;
+ }
+
+ od .get_last_child() .set_status( zero_success ? STATUS_SUCCES : STATUS_ERROR ) ;
}
overall_success &= zero_success ;
}
diff --git a/src/Utils.cc b/src/Utils.cc
index 0968e3d..e7fcd78 100644
--- a/src/Utils.cc
+++ b/src/Utils.cc
@@ -669,6 +669,18 @@ int Utils::get_mounted_filesystem_usage( const Glib::ustring & mountpoint,
return ret ;
}
+//Round down to multiple of rounding_size
+Byte_Value Utils::floor_size( Byte_Value value, Byte_Value rounding_size )
+{
+ return value / rounding_size * rounding_size ;
+}
+
+//Round up to multiple of rounding_size
+Byte_Value Utils::ceil_size( Byte_Value value, Byte_Value rounding_size )
+{
+ return ( value + rounding_size - 1LL ) / rounding_size * rounding_size ;
+}
+
//private functions ...
//Read kernel version, reporting success or failure
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]