gparted/src/btrfs.cc

405 lines
13 KiB
C++
Raw Normal View History

/* Copyright (C) 2009,2010 Luca Bruno <lucab@debian.org>
* Copyright (C) 2010, 2011 Curtis Gedak
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include "../include/btrfs.h"
Handle btrfs tools rounding of figures (#499202) The btrfs programs only provide approximations of file system sizes because they display figures using binary prefix multipliers to two decimal places of precision. E.g. 2.00GB. For partition sizes where the contained file system size rounds upwards, GParted will fail to read the file system usage and report a warning because the file system will appear to be larger than the partition. For example, create a 2047 MiB partition containing a btrfs file system and display its size. # btrfs filesystem show Label: none uuid: 92535375-5e76-4a70-896a-8d796a577993 Total devices 1 FS bytes used 28.00KB devid 1 size 2.00GB used 240.62MB path /dev/sda12 The file system size appears to be 2048 MiB, but that is larger than the partition, hence the issue GParted has. (Actually uses the btrfs devid size which is the size of the btrfs file system within the partition in question). This issue is new with the fix for Bug #499202 because it queries the file system sizes for the first time. The same issue could theoretically occur previously, but with the used figure (FS bytes used). This would have been virtually impossible to trigger because btrfs file system would have to have been greater than 99% full, but btrfs has been notorious for early reporting of file system full. The fix is that if a btrfs file system size appears larger than the partition size, but the minimum possible size which could have been rounded to the reported figure is within the partition size use the smaller partition size instead. Apply the method to the used figure too, in case the file system is 100% full. Also if the btrfs file system size appears smaller than the partition size, but the maximum possible size which could have been rounded to the reported figure is within the partition size use the larger partition size instead to avoid reporting, presumably false, unallocated space. Not applied to file system used figure. Bug 499202 - gparted does not see the difference if partition size differs from filesystem size
2012-05-30 06:41:59 -06:00
#include <ctype.h>
namespace GParted
{
bool btrfs_found = false ;
bool resize_to_same_size_fails = true ;
FS btrfs::get_filesystem_support()
{
FS fs ;
fs .filesystem = GParted::FS_BTRFS ;
if ( ! Glib::find_program_in_path( "mkfs.btrfs" ) .empty() )
{
fs .create = GParted::FS::EXTERNAL ;
fs .create_with_label = GParted::FS::EXTERNAL ;
}
if ( ! Glib::find_program_in_path( "btrfsck" ) .empty() )
fs .check = GParted::FS::EXTERNAL ;
btrfs_found = ( ! Glib::find_program_in_path( "btrfs" ) .empty() ) ;
if ( btrfs_found )
{
//Use newer btrfs multi-tool control command. No need
// to test for filesystem show and filesystem resize
// sub-commands as they were always included.
fs .read = GParted::FS::EXTERNAL ;
fs .read_label = FS::EXTERNAL ;
fs .read_uuid = FS::EXTERNAL ;
//Resizing of btrfs requires mount, umount and kernel
// support as well as btrfs filesystem resize
if ( ! Glib::find_program_in_path( "mount" ) .empty()
&& ! Glib::find_program_in_path( "umount" ) .empty()
&& fs .check
&& Utils::kernel_supports_fs( "btrfs" )
)
{
fs .grow = FS::EXTERNAL ;
if ( fs .read ) //needed to determine a minimum file system size.
fs .shrink = FS::EXTERNAL ;
}
//Test for labelling capability in btrfs command
if ( ! Utils::execute_command( "btrfs filesystem label --help", output, error, true ) )
fs .write_label = FS::EXTERNAL;
}
else
{
//Fall back to using btrfs-show and btrfsctl, which
// were depreciated October 2011
if ( ! Glib::find_program_in_path( "btrfs-show" ) .empty() )
{
fs .read = GParted::FS::EXTERNAL ;
fs .read_label = FS::EXTERNAL ;
fs .read_uuid = FS::EXTERNAL ;
}
//Resizing of btrfs requires btrfsctl, mount, umount
// and kernel support
if ( ! Glib::find_program_in_path( "btrfsctl" ) .empty()
&& ! Glib::find_program_in_path( "mount" ) .empty()
&& ! Glib::find_program_in_path( "umount" ) .empty()
&& fs .check
&& Utils::kernel_supports_fs( "btrfs" )
)
{
fs .grow = FS::EXTERNAL ;
if ( fs .read ) //needed to determine a minimum file system size.
fs .shrink = FS::EXTERNAL ;
}
}
if ( fs .check )
{
fs .copy = GParted::FS::GPARTED ;
fs .move = GParted::FS::GPARTED ;
}
fs .online_read = FS::GPARTED ;
#ifdef ENABLE_ONLINE_RESIZE
if ( Utils::kernel_version_at_least( 3, 6, 0 ) )
{
fs .online_grow = fs .grow ;
fs .online_shrink = fs .shrink ;
}
#endif
fs .MIN = 256 * MEBIBYTE ;
//Linux before version 3.2 fails when resizing btrfs file system
// to the same size.
resize_to_same_size_fails = ! Utils::kernel_version_at_least( 3, 2, 0 ) ;
return fs ;
}
bool btrfs::create( const Partition & new_partition, OperationDetail & operationdetail )
{
Make GParted recognise reading blank file system labels (#685656) GParted doesn't notice when a file system label is changed to blank. GParted first calls the file system specific read_label() method. When the label is blank read_label() correctly sets partition.label to the zero length string. Second GParted_Core::set_device_partitions() treats the zero length string to mean that the label is unset and calls FS_Info::get_label() to retrieve it from the cache of blkid output. Blkid also doesn't notice when the file system label has been changed to blank so reports the previous label. Hence GParted displays the previous file system label. Fix by making label a private member variable of the class Partition and providing access methods set_label(), get_label() and label_known() which track whether the label has been set or not. This only fixes the fault for file systems which use file system specific commands to read the label and when these tools are installed. Otherwise GParted uses, or has to fall back on using, the buggy blkid command to read the file system label. NOTE: Many of the file system specific read_label() methods use a tool which outputs more than just the label and use Utils::regexp_label() to match leading text and the label itself. If the surrounding text changes or disappears altogether to indicated a blank label, regexp_label() doesn't match anything and returns the zero length string. This is exactly what is required and is passed to set_label() to set the label to blank. Bug 685656 - GParted doesn't notice when file system label is changed to blank
2012-10-08 07:23:17 -06:00
return (! execute_command( "mkfs.btrfs -L \"" + new_partition .get_label() + "\" " + new_partition .get_path(), operationdetail ) );
}
bool btrfs::check_repair( const Partition & partition, OperationDetail & operationdetail )
{
return (! execute_command( "btrfsck " + partition .get_path(), operationdetail )) ;
}
void btrfs::set_used_sectors( Partition & partition )
{
if ( btrfs_found )
exit_status = Utils::execute_command( "btrfs filesystem show " + partition .get_path(), output, error, true ) ;
else
exit_status = Utils::execute_command( "btrfs-show " + partition .get_path(), output, error, true ) ;
if ( ! exit_status )
{
//FIXME: Improve free space calculation for multi-device
// btrfs file systems. Currently uses the size of the
// btrfs device in this partition (spot on) and the
// file system wide used bytes (wrong for multi-device
// file systems).
Handle btrfs tools rounding of figures (#499202) The btrfs programs only provide approximations of file system sizes because they display figures using binary prefix multipliers to two decimal places of precision. E.g. 2.00GB. For partition sizes where the contained file system size rounds upwards, GParted will fail to read the file system usage and report a warning because the file system will appear to be larger than the partition. For example, create a 2047 MiB partition containing a btrfs file system and display its size. # btrfs filesystem show Label: none uuid: 92535375-5e76-4a70-896a-8d796a577993 Total devices 1 FS bytes used 28.00KB devid 1 size 2.00GB used 240.62MB path /dev/sda12 The file system size appears to be 2048 MiB, but that is larger than the partition, hence the issue GParted has. (Actually uses the btrfs devid size which is the size of the btrfs file system within the partition in question). This issue is new with the fix for Bug #499202 because it queries the file system sizes for the first time. The same issue could theoretically occur previously, but with the used figure (FS bytes used). This would have been virtually impossible to trigger because btrfs file system would have to have been greater than 99% full, but btrfs has been notorious for early reporting of file system full. The fix is that if a btrfs file system size appears larger than the partition size, but the minimum possible size which could have been rounded to the reported figure is within the partition size use the smaller partition size instead. Apply the method to the used figure too, in case the file system is 100% full. Also if the btrfs file system size appears smaller than the partition size, but the maximum possible size which could have been rounded to the reported figure is within the partition size use the larger partition size instead to avoid reporting, presumably false, unallocated space. Not applied to file system used figure. Bug 499202 - gparted does not see the difference if partition size differs from filesystem size
2012-05-30 06:41:59 -06:00
Byte_Value ptn_bytes = partition .get_byte_length() ;
Glib::ustring str ;
//Btrfs file system device size
Glib::ustring regexp = "devid .* size ([0-9\\.]+( ?[KMGTPE]?i?B)?) .* path " + partition .get_path() ;
if ( ! ( str = Utils::regexp_label( output, regexp ) ) .empty() )
Handle btrfs tools rounding of figures (#499202) The btrfs programs only provide approximations of file system sizes because they display figures using binary prefix multipliers to two decimal places of precision. E.g. 2.00GB. For partition sizes where the contained file system size rounds upwards, GParted will fail to read the file system usage and report a warning because the file system will appear to be larger than the partition. For example, create a 2047 MiB partition containing a btrfs file system and display its size. # btrfs filesystem show Label: none uuid: 92535375-5e76-4a70-896a-8d796a577993 Total devices 1 FS bytes used 28.00KB devid 1 size 2.00GB used 240.62MB path /dev/sda12 The file system size appears to be 2048 MiB, but that is larger than the partition, hence the issue GParted has. (Actually uses the btrfs devid size which is the size of the btrfs file system within the partition in question). This issue is new with the fix for Bug #499202 because it queries the file system sizes for the first time. The same issue could theoretically occur previously, but with the used figure (FS bytes used). This would have been virtually impossible to trigger because btrfs file system would have to have been greater than 99% full, but btrfs has been notorious for early reporting of file system full. The fix is that if a btrfs file system size appears larger than the partition size, but the minimum possible size which could have been rounded to the reported figure is within the partition size use the smaller partition size instead. Apply the method to the used figure too, in case the file system is 100% full. Also if the btrfs file system size appears smaller than the partition size, but the maximum possible size which could have been rounded to the reported figure is within the partition size use the larger partition size instead to avoid reporting, presumably false, unallocated space. Not applied to file system used figure. Bug 499202 - gparted does not see the difference if partition size differs from filesystem size
2012-05-30 06:41:59 -06:00
T = btrfs_size_to_num( str, ptn_bytes, true ) ;
//Btrfs file system wide used bytes
if ( ! ( str = Utils::regexp_label( output, "FS bytes used ([0-9\\.]+( ?[KMGTPE]?i?B)?)" ) ) .empty() )
Handle btrfs tools rounding of figures (#499202) The btrfs programs only provide approximations of file system sizes because they display figures using binary prefix multipliers to two decimal places of precision. E.g. 2.00GB. For partition sizes where the contained file system size rounds upwards, GParted will fail to read the file system usage and report a warning because the file system will appear to be larger than the partition. For example, create a 2047 MiB partition containing a btrfs file system and display its size. # btrfs filesystem show Label: none uuid: 92535375-5e76-4a70-896a-8d796a577993 Total devices 1 FS bytes used 28.00KB devid 1 size 2.00GB used 240.62MB path /dev/sda12 The file system size appears to be 2048 MiB, but that is larger than the partition, hence the issue GParted has. (Actually uses the btrfs devid size which is the size of the btrfs file system within the partition in question). This issue is new with the fix for Bug #499202 because it queries the file system sizes for the first time. The same issue could theoretically occur previously, but with the used figure (FS bytes used). This would have been virtually impossible to trigger because btrfs file system would have to have been greater than 99% full, but btrfs has been notorious for early reporting of file system full. The fix is that if a btrfs file system size appears larger than the partition size, but the minimum possible size which could have been rounded to the reported figure is within the partition size use the smaller partition size instead. Apply the method to the used figure too, in case the file system is 100% full. Also if the btrfs file system size appears smaller than the partition size, but the maximum possible size which could have been rounded to the reported figure is within the partition size use the larger partition size instead to avoid reporting, presumably false, unallocated space. Not applied to file system used figure. Bug 499202 - gparted does not see the difference if partition size differs from filesystem size
2012-05-30 06:41:59 -06:00
N = T - btrfs_size_to_num( str, ptn_bytes, false ) ;
if ( T > -1 && N > -1 )
{
T = Utils::round( T / double(partition .sector_size) ) ;
N = Utils::round( N / double(partition .sector_size) ) ;
partition .set_sector_usage( T, N );
}
}
else
{
if ( ! output .empty() )
partition .messages .push_back( output ) ;
if ( ! error .empty() )
partition .messages .push_back( error ) ;
}
}
bool btrfs::write_label( const Partition & partition, OperationDetail & operationdetail )
{
Make GParted recognise reading blank file system labels (#685656) GParted doesn't notice when a file system label is changed to blank. GParted first calls the file system specific read_label() method. When the label is blank read_label() correctly sets partition.label to the zero length string. Second GParted_Core::set_device_partitions() treats the zero length string to mean that the label is unset and calls FS_Info::get_label() to retrieve it from the cache of blkid output. Blkid also doesn't notice when the file system label has been changed to blank so reports the previous label. Hence GParted displays the previous file system label. Fix by making label a private member variable of the class Partition and providing access methods set_label(), get_label() and label_known() which track whether the label has been set or not. This only fixes the fault for file systems which use file system specific commands to read the label and when these tools are installed. Otherwise GParted uses, or has to fall back on using, the buggy blkid command to read the file system label. NOTE: Many of the file system specific read_label() methods use a tool which outputs more than just the label and use Utils::regexp_label() to match leading text and the label itself. If the surrounding text changes or disappears altogether to indicated a blank label, regexp_label() doesn't match anything and returns the zero length string. This is exactly what is required and is passed to set_label() to set the label to blank. Bug 685656 - GParted doesn't notice when file system label is changed to blank
2012-10-08 07:23:17 -06:00
return ! execute_command( "btrfs filesystem label " + partition .get_path() + " \"" + partition .get_label() + "\"", operationdetail ) ;
}
bool btrfs::resize( const Partition & partition_new, OperationDetail & operationdetail, bool fill_partition )
{
bool success = true ;
Glib::ustring mount_point ;
if ( ! partition_new .busy )
{
mount_point = mk_temp_dir( "", operationdetail ) ;
if ( mount_point .empty() )
return false ;
success &= ! execute_command( "mount -v -t btrfs " + partition_new .get_path() + " " + mount_point,
operationdetail, true ) ;
}
else
mount_point = partition_new .get_mountpoint() ;
if ( success )
{
Glib::ustring size ;
if ( ! fill_partition )
size = Utils::num_to_str( floor( Utils::sector_to_unit(
partition_new .get_sector_length(), partition_new .sector_size, UNIT_KIB ) ) ) + "K" ;
else
size = "max" ;
Glib::ustring cmd ;
if ( btrfs_found )
cmd = "btrfs filesystem resize " + size + " " + mount_point ;
else
cmd = "btrfsctl -r " + size + " " + mount_point ;
exit_status = execute_command( cmd, operationdetail, false ) ;
bool resize_succeeded = ( exit_status == 0 ) ;
if ( resize_to_same_size_fails )
{
//Linux before version 3.2 fails when resizing a
// btrfs file system to the same size with ioctl()
// returning -1 EINVAL (Invalid argument) from the
// kernel btrfs code.
// * Btrfs filesystem resize reports this as exit
// status 30:
// ERROR: Unable to resize '/MOUNTPOINT'
// * Btrfsctl -r reports this as exit status 1:
// ioctl:: Invalid argument
// WARNING:
// Ignoring these errors could mask real failures,
// but not ignoring them will cause resizing to the
// same size as part of check operation to fail.
resize_succeeded = ( exit_status == 0
|| ( btrfs_found && exit_status == 30<<8 )
|| ( ! btrfs_found && exit_status == 1<<8 )
) ;
}
operationdetail .get_last_child() .set_status( resize_succeeded ? STATUS_SUCCES : STATUS_ERROR ) ;
success &= resize_succeeded ;
if ( ! partition_new .busy )
success &= ! execute_command( "umount -v " + mount_point, operationdetail, true ) ;
}
if ( ! partition_new .busy )
rm_temp_dir( mount_point, operationdetail ) ;
return success ;
}
void btrfs::read_label( Partition & partition )
{
if ( btrfs_found )
{
exit_status = Utils::execute_command( "btrfs filesystem show " + partition .get_path(), output, error, true ) ;
if ( ! exit_status )
{
Make GParted recognise reading blank file system labels (#685656) GParted doesn't notice when a file system label is changed to blank. GParted first calls the file system specific read_label() method. When the label is blank read_label() correctly sets partition.label to the zero length string. Second GParted_Core::set_device_partitions() treats the zero length string to mean that the label is unset and calls FS_Info::get_label() to retrieve it from the cache of blkid output. Blkid also doesn't notice when the file system label has been changed to blank so reports the previous label. Hence GParted displays the previous file system label. Fix by making label a private member variable of the class Partition and providing access methods set_label(), get_label() and label_known() which track whether the label has been set or not. This only fixes the fault for file systems which use file system specific commands to read the label and when these tools are installed. Otherwise GParted uses, or has to fall back on using, the buggy blkid command to read the file system label. NOTE: Many of the file system specific read_label() methods use a tool which outputs more than just the label and use Utils::regexp_label() to match leading text and the label itself. If the surrounding text changes or disappears altogether to indicated a blank label, regexp_label() doesn't match anything and returns the zero length string. This is exactly what is required and is passed to set_label() to set the label to blank. Bug 685656 - GParted doesn't notice when file system label is changed to blank
2012-10-08 07:23:17 -06:00
partition .set_label( Utils::regexp_label( output, "^Label: '(.*)' uuid:" ) ) ;
//Btrfs filesystem show encloses the label in single
// quotes or reports "none" without single quotes, so
Make GParted recognise reading blank file system labels (#685656) GParted doesn't notice when a file system label is changed to blank. GParted first calls the file system specific read_label() method. When the label is blank read_label() correctly sets partition.label to the zero length string. Second GParted_Core::set_device_partitions() treats the zero length string to mean that the label is unset and calls FS_Info::get_label() to retrieve it from the cache of blkid output. Blkid also doesn't notice when the file system label has been changed to blank so reports the previous label. Hence GParted displays the previous file system label. Fix by making label a private member variable of the class Partition and providing access methods set_label(), get_label() and label_known() which track whether the label has been set or not. This only fixes the fault for file systems which use file system specific commands to read the label and when these tools are installed. Otherwise GParted uses, or has to fall back on using, the buggy blkid command to read the file system label. NOTE: Many of the file system specific read_label() methods use a tool which outputs more than just the label and use Utils::regexp_label() to match leading text and the label itself. If the surrounding text changes or disappears altogether to indicated a blank label, regexp_label() doesn't match anything and returns the zero length string. This is exactly what is required and is passed to set_label() to set the label to blank. Bug 685656 - GParted doesn't notice when file system label is changed to blank
2012-10-08 07:23:17 -06:00
// the cases are distinguishable and this regexp won't
// match the no label case. In the no match case
// regexp_label() returns "" and this is used to set
// the set the blank label.
}
}
else
{
exit_status = Utils::execute_command( "btrfs-show " + partition .get_path(), output, error, true ) ;
if ( ! exit_status )
{
Glib::ustring label = Utils::regexp_label( output, "^Label: (.*) uuid:" ) ;
//Btrfs-show reports "none" when there is no label, but
// this is indistinguishable from the label actually
// being "none". Assume no label case.
if ( label != "none" )
Make GParted recognise reading blank file system labels (#685656) GParted doesn't notice when a file system label is changed to blank. GParted first calls the file system specific read_label() method. When the label is blank read_label() correctly sets partition.label to the zero length string. Second GParted_Core::set_device_partitions() treats the zero length string to mean that the label is unset and calls FS_Info::get_label() to retrieve it from the cache of blkid output. Blkid also doesn't notice when the file system label has been changed to blank so reports the previous label. Hence GParted displays the previous file system label. Fix by making label a private member variable of the class Partition and providing access methods set_label(), get_label() and label_known() which track whether the label has been set or not. This only fixes the fault for file systems which use file system specific commands to read the label and when these tools are installed. Otherwise GParted uses, or has to fall back on using, the buggy blkid command to read the file system label. NOTE: Many of the file system specific read_label() methods use a tool which outputs more than just the label and use Utils::regexp_label() to match leading text and the label itself. If the surrounding text changes or disappears altogether to indicated a blank label, regexp_label() doesn't match anything and returns the zero length string. This is exactly what is required and is passed to set_label() to set the label to blank. Bug 685656 - GParted doesn't notice when file system label is changed to blank
2012-10-08 07:23:17 -06:00
partition .set_label( label ) ;
else
partition .set_label( "" ) ;
}
}
if ( exit_status )
{
if ( ! output .empty() )
partition .messages .push_back( output ) ;
if ( ! error .empty() )
partition .messages .push_back( error ) ;
}
}
void btrfs::read_uuid( Partition & partition )
{
if ( btrfs_found )
{
exit_status = Utils::execute_command( "btrfs filesystem show " + partition .get_path(), output, error, true ) ;
if ( ! exit_status )
{
partition .uuid = Utils::regexp_label( output, "uuid:[[:blank:]]*(" RFC4122_NONE_NIL_UUID_REGEXP ")" ) ;
}
}
else
{
exit_status = Utils::execute_command( "btrfs-show " + partition .get_path(), output, error, true ) ;
if ( ! exit_status )
{
partition .uuid = Utils::regexp_label( output, "uuid:[[:blank:]]*(" RFC4122_NONE_NIL_UUID_REGEXP ")" ) ;
}
}
if ( exit_status )
{
if ( ! output .empty() )
partition .messages .push_back( output ) ;
if ( ! error .empty() )
partition .messages .push_back( error ) ;
}
}
Handle btrfs tools rounding of figures (#499202) The btrfs programs only provide approximations of file system sizes because they display figures using binary prefix multipliers to two decimal places of precision. E.g. 2.00GB. For partition sizes where the contained file system size rounds upwards, GParted will fail to read the file system usage and report a warning because the file system will appear to be larger than the partition. For example, create a 2047 MiB partition containing a btrfs file system and display its size. # btrfs filesystem show Label: none uuid: 92535375-5e76-4a70-896a-8d796a577993 Total devices 1 FS bytes used 28.00KB devid 1 size 2.00GB used 240.62MB path /dev/sda12 The file system size appears to be 2048 MiB, but that is larger than the partition, hence the issue GParted has. (Actually uses the btrfs devid size which is the size of the btrfs file system within the partition in question). This issue is new with the fix for Bug #499202 because it queries the file system sizes for the first time. The same issue could theoretically occur previously, but with the used figure (FS bytes used). This would have been virtually impossible to trigger because btrfs file system would have to have been greater than 99% full, but btrfs has been notorious for early reporting of file system full. The fix is that if a btrfs file system size appears larger than the partition size, but the minimum possible size which could have been rounded to the reported figure is within the partition size use the smaller partition size instead. Apply the method to the used figure too, in case the file system is 100% full. Also if the btrfs file system size appears smaller than the partition size, but the maximum possible size which could have been rounded to the reported figure is within the partition size use the larger partition size instead to avoid reporting, presumably false, unallocated space. Not applied to file system used figure. Bug 499202 - gparted does not see the difference if partition size differs from filesystem size
2012-05-30 06:41:59 -06:00
//Private methods
//Return the value of a btrfs tool formatted size, including reversing
// changes in certain cases caused by using binary prefix multipliers
// and rounding to two decimal places of precision. E.g. "2.00GB".
Byte_Value btrfs::btrfs_size_to_num( Glib::ustring str, Byte_Value ptn_bytes, bool scale_up )
Handle btrfs tools rounding of figures (#499202) The btrfs programs only provide approximations of file system sizes because they display figures using binary prefix multipliers to two decimal places of precision. E.g. 2.00GB. For partition sizes where the contained file system size rounds upwards, GParted will fail to read the file system usage and report a warning because the file system will appear to be larger than the partition. For example, create a 2047 MiB partition containing a btrfs file system and display its size. # btrfs filesystem show Label: none uuid: 92535375-5e76-4a70-896a-8d796a577993 Total devices 1 FS bytes used 28.00KB devid 1 size 2.00GB used 240.62MB path /dev/sda12 The file system size appears to be 2048 MiB, but that is larger than the partition, hence the issue GParted has. (Actually uses the btrfs devid size which is the size of the btrfs file system within the partition in question). This issue is new with the fix for Bug #499202 because it queries the file system sizes for the first time. The same issue could theoretically occur previously, but with the used figure (FS bytes used). This would have been virtually impossible to trigger because btrfs file system would have to have been greater than 99% full, but btrfs has been notorious for early reporting of file system full. The fix is that if a btrfs file system size appears larger than the partition size, but the minimum possible size which could have been rounded to the reported figure is within the partition size use the smaller partition size instead. Apply the method to the used figure too, in case the file system is 100% full. Also if the btrfs file system size appears smaller than the partition size, but the maximum possible size which could have been rounded to the reported figure is within the partition size use the larger partition size instead to avoid reporting, presumably false, unallocated space. Not applied to file system used figure. Bug 499202 - gparted does not see the difference if partition size differs from filesystem size
2012-05-30 06:41:59 -06:00
{
Byte_Value size_bytes = Utils::round( btrfs_size_to_gdouble( str ) ) ;
gdouble delta = btrfs_size_max_delta( str ) ;
Byte_Value upper_size = size_bytes + ceil( delta ) ;
Byte_Value lower_size = size_bytes - floor( delta ) ;
if ( size_bytes > ptn_bytes && lower_size <= ptn_bytes )
{
//Scale value down to partition size:
// The btrfs tool reported size appears larger than the partition
// size, but the minimum possible size which could have been rounded
// to the reported figure is within the partition size so use the
// smaller partition size instead. Applied to FS device size and FS
// wide used bytes.
// ............| ptn_bytes
// [ x ) size_bytes with upper & lower size
// x scaled down size_bytes
// Do this to avoid the FS size or used bytes being larger than the
// partition size and GParted failing to read the file system usage and
// report a warning.
size_bytes = ptn_bytes ;
}
else if ( scale_up && size_bytes < ptn_bytes && upper_size > ptn_bytes )
{
//Scale value up to partition size:
// The btrfs tool reported size appears smaller than the partition
// size, but the maximum possible size which could have been rounded
// to the reported figure is within the partition size so use the
// larger partition size instead. Applied to FS device size only.
// ............| ptn_bytes
// [ x ) size_bytes with upper & lower size
// x scaled up size_bytes
// Make an assumption that the file system actually fills the
// partition, rather than is slightly smaller to avoid false reporting
// of unallocated space.
size_bytes = ptn_bytes ;
}
return size_bytes ;
}
//Return maximum delta for which num +/- delta would be rounded by btrfs
// tools to str. E.g. btrfs_size_max_delta("2.00GB") -> 5368709.12
gdouble btrfs::btrfs_size_max_delta( Glib::ustring str )
Handle btrfs tools rounding of figures (#499202) The btrfs programs only provide approximations of file system sizes because they display figures using binary prefix multipliers to two decimal places of precision. E.g. 2.00GB. For partition sizes where the contained file system size rounds upwards, GParted will fail to read the file system usage and report a warning because the file system will appear to be larger than the partition. For example, create a 2047 MiB partition containing a btrfs file system and display its size. # btrfs filesystem show Label: none uuid: 92535375-5e76-4a70-896a-8d796a577993 Total devices 1 FS bytes used 28.00KB devid 1 size 2.00GB used 240.62MB path /dev/sda12 The file system size appears to be 2048 MiB, but that is larger than the partition, hence the issue GParted has. (Actually uses the btrfs devid size which is the size of the btrfs file system within the partition in question). This issue is new with the fix for Bug #499202 because it queries the file system sizes for the first time. The same issue could theoretically occur previously, but with the used figure (FS bytes used). This would have been virtually impossible to trigger because btrfs file system would have to have been greater than 99% full, but btrfs has been notorious for early reporting of file system full. The fix is that if a btrfs file system size appears larger than the partition size, but the minimum possible size which could have been rounded to the reported figure is within the partition size use the smaller partition size instead. Apply the method to the used figure too, in case the file system is 100% full. Also if the btrfs file system size appears smaller than the partition size, but the maximum possible size which could have been rounded to the reported figure is within the partition size use the larger partition size instead to avoid reporting, presumably false, unallocated space. Not applied to file system used figure. Bug 499202 - gparted does not see the difference if partition size differs from filesystem size
2012-05-30 06:41:59 -06:00
{
Glib::ustring limit_str ;
//Create limit_str. E.g. str = "2.00GB" -> limit_str = "0.005GB"
for ( Glib::ustring::iterator p = str .begin() ; p != str .end() ; p ++ )
{
if ( isdigit( *p ) )
limit_str .append( "0" ) ;
else if ( *p == '.' )
limit_str .append( "." ) ;
else
{
limit_str .append( "5" ) ;
limit_str .append( p, str .end() ) ;
break ;
}
}
gdouble max_delta = btrfs_size_to_gdouble( limit_str ) ;
return max_delta ;
}
//Return the value of a btrfs tool formatted size.
// E.g. btrfs_size_to_gdouble("2.00GB") -> 2147483648.0
gdouble btrfs::btrfs_size_to_gdouble( Glib::ustring str )
{
gchar * suffix ;
gdouble rawN = g_ascii_strtod( str .c_str(), & suffix ) ;
while ( isspace( suffix[0] ) ) //Skip white space before suffix
suffix ++ ;
unsigned long long mult ;
switch ( suffix[0] )
{
case 'K': mult = KIBIBYTE ; break ;
case 'M': mult = MEBIBYTE ; break ;
case 'G': mult = GIBIBYTE ; break ;
case 'T': mult = TEBIBYTE ; break ;
case 'P': mult = PEBIBYTE ; break ;
case 'E': mult = EXBIBYTE ; break ;
default: mult = 1 ; break ;
}
Handle btrfs tools rounding of figures (#499202) The btrfs programs only provide approximations of file system sizes because they display figures using binary prefix multipliers to two decimal places of precision. E.g. 2.00GB. For partition sizes where the contained file system size rounds upwards, GParted will fail to read the file system usage and report a warning because the file system will appear to be larger than the partition. For example, create a 2047 MiB partition containing a btrfs file system and display its size. # btrfs filesystem show Label: none uuid: 92535375-5e76-4a70-896a-8d796a577993 Total devices 1 FS bytes used 28.00KB devid 1 size 2.00GB used 240.62MB path /dev/sda12 The file system size appears to be 2048 MiB, but that is larger than the partition, hence the issue GParted has. (Actually uses the btrfs devid size which is the size of the btrfs file system within the partition in question). This issue is new with the fix for Bug #499202 because it queries the file system sizes for the first time. The same issue could theoretically occur previously, but with the used figure (FS bytes used). This would have been virtually impossible to trigger because btrfs file system would have to have been greater than 99% full, but btrfs has been notorious for early reporting of file system full. The fix is that if a btrfs file system size appears larger than the partition size, but the minimum possible size which could have been rounded to the reported figure is within the partition size use the smaller partition size instead. Apply the method to the used figure too, in case the file system is 100% full. Also if the btrfs file system size appears smaller than the partition size, but the maximum possible size which could have been rounded to the reported figure is within the partition size use the larger partition size instead to avoid reporting, presumably false, unallocated space. Not applied to file system used figure. Bug 499202 - gparted does not see the difference if partition size differs from filesystem size
2012-05-30 06:41:59 -06:00
return rawN * mult ;
}
} //GParted