Use btrfs filesystem show --raw to read usage (!105)
'btrfs filesystem show' only used to report rounded human readable size
figures. Therefore the actual figure could have been anywhere within
the rounding limit. GParted also applied a heuristic to snap the file
system size figure to the partition size if the partition size was
within the rounding limit of the reported file system size [1].
btrfs-progs v4.1 added the --raw option to print the figures in bytes
[2][3][4].
# btrfs filesystem show --raw /dev/sdb1
Label: none uuid: 003a619e-856f-4b9c-bd29-4d0ae0296d66
Total devices 2 FS bytes used 178765824
devid 1 size 2147483648 used 239861760 path /dev/sdb1
devid 2 size 2147483648 used 436207616 path /dev/sdc1
Since the oldest supported distributions now use btrfs-progs v4.5.3 and
later (see the distribution End-of-Life table in the previous commit
message), unconditionally use this to get accurate figures.
[1] 7fc16a1b69
Handle btrfs tools rounding of figures (#499202)
[2] btrfs-progs: Allow "filesystem show" command to handle different units
https://git.kernel.org/pub/scm/linux/kernel/git/kdave/btrfs-progs.git/commit/?id=15379fa2257bf937cf7830c0b1b79f2daf5df72c
[3] btrfs-progs: docs: new size options for fi show
https://git.kernel.org/pub/scm/linux/kernel/git/kdave/btrfs-progs.git/commit/?id=81225f11d9ea58590476612e69211113ddb9b943
[4] Btrfs progs release 4.1
https://lore.kernel.org/linux-btrfs/20150622150023.GX6761@twin.jikos.cz/
Closes !105 - Update used btrfs file system commands, new minimum is
btrfs-progs 4.5
This commit is contained in:
parent
be895fb98e
commit
db5df60f22
|
@ -52,10 +52,9 @@ public:
|
|||
|
||||
private:
|
||||
static const BTRFS_Device & get_cache_entry( const Glib::ustring & path ) ;
|
||||
static Byte_Value btrfs_size_to_num( Glib::ustring str, Byte_Value ptn_bytes, bool scale_up ) ;
|
||||
static gdouble btrfs_size_max_delta( Glib::ustring str ) ;
|
||||
static gdouble btrfs_size_to_gdouble( Glib::ustring str ) ;
|
||||
};
|
||||
|
||||
|
||||
} //GParted
|
||||
|
||||
#endif /* GPARTED_BTRFS_H */
|
||||
|
|
165
src/btrfs.cc
165
src/btrfs.cc
|
@ -138,16 +138,17 @@ bool btrfs::check_repair( const Partition & partition, OperationDetail & operati
|
|||
operationdetail, EXEC_CHECK_STATUS);
|
||||
}
|
||||
|
||||
void btrfs::set_used_sectors( Partition & partition )
|
||||
|
||||
void btrfs::set_used_sectors(Partition& partition)
|
||||
{
|
||||
//Called when the file system is unmounted *and* when mounted.
|
||||
// Called when the file system is unmounted *and* when mounted.
|
||||
//
|
||||
// Btrfs has a volume manager layer within the file system which allows it to
|
||||
// provide multiple levels of data redundancy, RAID levels, and use multiple
|
||||
// devices both of which can be changed while the file system is mounted. To
|
||||
// achieve this btrfs has to allocate space at two different levels: (1) chunks
|
||||
// of 256 MiB or more at the volume manager level; and (2) extents at the file
|
||||
// data level.
|
||||
// achieve this btrfs has to allocate space at two different levels: (1) chunks of
|
||||
// 256 MiB or more at the volume manager level; and (2) extents at the metadata
|
||||
// and file data level.
|
||||
// References:
|
||||
// * Btrfs: Working with multiple devices
|
||||
// https://lwn.net/Articles/577961/
|
||||
|
@ -163,12 +164,13 @@ void btrfs::set_used_sectors( Partition & partition )
|
|||
// system is provided. It also reports size of the data and metadata being
|
||||
// stored, not the larger figure of the amount of space taken after redundancy is
|
||||
// applied. So it is impossible to answer the question of how much disk space is
|
||||
// being used in an individual device. Example output:
|
||||
// being used in an individual device. Example:
|
||||
//
|
||||
// Label: none uuid: 36eb51a2-2927-4c92-820f-b2f0b5cdae50
|
||||
// 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
|
||||
// # btrfs filesystem show --raw /dev/sdb1
|
||||
// Label: none uuid: 003a619e-856f-4b9c-bd29-4d0ae0296d66
|
||||
// Total devices 2 FS bytes used 178765824
|
||||
// devid 1 size 2147483648 used 239861760 path /dev/sdb1
|
||||
// devid 2 size 2147483648 used 436207616 path /dev/sdc1
|
||||
//
|
||||
// Guesstimate the per device used figure as the fraction of the file system wide
|
||||
// extent usage based on chunk usage per device.
|
||||
|
@ -190,60 +192,54 @@ void btrfs::set_used_sectors( Partition & partition )
|
|||
// devices.
|
||||
// 4) Extents can be and are relocated to other devices within the file system
|
||||
// when shrinking a device.
|
||||
Utils::execute_command("btrfs filesystem show " + Glib::shell_quote(partition.get_path()),
|
||||
Utils::execute_command("btrfs filesystem show --raw " + Glib::shell_quote(partition.get_path()),
|
||||
output, error, true);
|
||||
//In many cases the exit status doesn't reflect valid output or an error condition
|
||||
// so rely on parsing the output to determine success.
|
||||
// In many cases the exit status doesn't reflect valid output or an error
|
||||
// condition so rely on parsing the output to determine success.
|
||||
|
||||
//Extract the per device size figure. Guesstimate the per device used
|
||||
// figure as discussed above. Example output:
|
||||
// Extract the per device size figure. Guesstimate the per device used
|
||||
// figure as discussed above. Example:
|
||||
//
|
||||
// Label: none uuid: 36eb51a2-2927-4c92-820f-b2f0b5cdae50
|
||||
// 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
|
||||
// # btrfs filesystem show --raw /dev/sdb1
|
||||
// Label: none uuid: 003a619e-856f-4b9c-bd29-4d0ae0296d66
|
||||
// Total devices 2 FS bytes used 178765824
|
||||
// devid 1 size 2147483648 used 239861760 path /dev/sdb1
|
||||
// devid 2 size 2147483648 used 436207616 path /dev/sdc1
|
||||
//
|
||||
// Calculations:
|
||||
// ptn fs size = devid size
|
||||
// ptn fs used = total fs used * devid used / sum devid used
|
||||
|
||||
Byte_Value ptn_size = partition .get_byte_length() ;
|
||||
Byte_Value total_fs_used = -1 ; //total fs used
|
||||
Byte_Value sum_devid_used = 0 ; //sum devid used
|
||||
Byte_Value devid_used = -1 ; //devid used
|
||||
Byte_Value devid_size = -1 ; //devid size
|
||||
long long total_fs_used = -1;
|
||||
long long sum_devid_used = 0;
|
||||
long long devid_used = -1;
|
||||
long long devid_size = -1;
|
||||
|
||||
//Btrfs file system wide used bytes (extents and items)
|
||||
Glib::ustring str ;
|
||||
if ( ! ( str = Utils::regexp_label( output, "FS bytes used ([0-9\\.]+( ?[KMGTPE]?i?B)?)" ) ) .empty() )
|
||||
total_fs_used = Utils::round( btrfs_size_to_gdouble( str ) ) ;
|
||||
// Btrfs file system wide used bytes (extents and items)
|
||||
Glib::ustring::size_type index = output.find("FS bytes used");
|
||||
if (index < output.length())
|
||||
sscanf(output.substr(index).c_str(), "FS bytes used %lld", &total_fs_used);
|
||||
|
||||
Glib::ustring::size_type offset = 0 ;
|
||||
Glib::ustring::size_type index ;
|
||||
while ( ( index = output .find( "devid ", offset ) ) != Glib::ustring::npos )
|
||||
{
|
||||
Glib::ustring devid_path = Utils::regexp_label( output .substr( index ),
|
||||
"devid .* path (/dev/[[:graph:]]+)" ) ;
|
||||
if ( ! devid_path .empty() )
|
||||
{
|
||||
//Btrfs per devid used bytes (chunks)
|
||||
Byte_Value used = -1 ;
|
||||
if ( ! ( str = Utils::regexp_label( output .substr( index ),
|
||||
"devid .* used ([0-9\\.]+( ?[KMGTPE]?i?B)?) path" ) ) .empty() )
|
||||
// Btrfs per devid used bytes (chunks)
|
||||
long long used = -1;
|
||||
sscanf(output.substr(index).c_str(), "devid %*d size %*d used %lld path", &used);
|
||||
if (used > -1)
|
||||
{
|
||||
used = btrfs_size_to_num( str, ptn_size, false ) ;
|
||||
sum_devid_used += used ;
|
||||
if ( devid_path == partition .get_path() )
|
||||
devid_used = used ;
|
||||
}
|
||||
|
||||
if ( devid_path == partition .get_path() )
|
||||
{
|
||||
//Btrfs per device size bytes (chunks)
|
||||
if ( ! ( str = Utils::regexp_label( output .substr( index ),
|
||||
"devid .* size ([0-9\\.]+( ?[KMGTPE]?i?B)?) used " ) ) .empty() )
|
||||
devid_size = btrfs_size_to_num( str, ptn_size, true ) ;
|
||||
}
|
||||
// Btrfs per device size bytes (chunks)
|
||||
sscanf(output.substr(index).c_str(), "devid %*d size %lld used", &devid_size);
|
||||
}
|
||||
offset = index + 5 ; //Next find starts immediately after current "devid"
|
||||
}
|
||||
|
@ -482,94 +478,5 @@ const BTRFS_Device & btrfs::get_cache_entry( const Glib::ustring & path )
|
|||
return btrfs_dev ;
|
||||
}
|
||||
|
||||
//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 )
|
||||
{
|
||||
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 )
|
||||
{
|
||||
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 ;
|
||||
}
|
||||
return rawN * mult ;
|
||||
}
|
||||
|
||||
} //GParted
|
||||
|
|
Loading…
Reference in New Issue