From 287526681d37e88a83c96c06513eda2db852c163 Mon Sep 17 00:00:00 2001 From: Mike Fleetwood Date: Thu, 10 Apr 2014 22:28:40 +0100 Subject: [PATCH] Add devid to the cache of btrfs device information (#723842) Bug #723842 - GParted resizes the wrong filesystem (does not pass the devid to btrfs filesystem resize) --- include/btrfs.h | 9 +++++++- src/btrfs.cc | 59 +++++++++++++++++++++++++++++++------------------ 2 files changed, 46 insertions(+), 22 deletions(-) diff --git a/include/btrfs.h b/include/btrfs.h index 693c6866..f7320968 100644 --- a/include/btrfs.h +++ b/include/btrfs.h @@ -23,6 +23,13 @@ namespace GParted { + +struct BTRFS_Device +{ + int devid ; + std::vector members ; +} ; + class btrfs : public FileSystem { public: @@ -40,7 +47,7 @@ public: static Glib::ustring get_mount_device( const Glib::ustring & path ) ; private: - static const std::vector get_cache_entry( const Glib::ustring & path ) ; + 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 ) ; diff --git a/src/btrfs.cc b/src/btrfs.cc index 30b668fe..52e44807 100644 --- a/src/btrfs.cc +++ b/src/btrfs.cc @@ -27,14 +27,14 @@ namespace GParted bool btrfs_found = false ; bool resize_to_same_size_fails = true ; -//Cache of all devices in each btrfs file system by device +//Cache of required btrfs file system device information by device // E.g. For a single device btrfs on /dev/sda2 and a three device btrfs // on /dev/sd[bcd]1 the cache would be: -// btrfs_device_cache["/dev/sda2"] = ["/dev/sda2"] -// btrfs_device_cache["/dev/sdb1"] = ["/dev/sdd1", "/dev/sdc1", "/dev/sdb1"] -// btrfs_device_cache["/dev/sdc1"] = ["/dev/sdd1", "/dev/sdc1", "/dev/sdb1"] -// btrfs_device_cache["/dev/sdd1"] = ["/dev/sdd1", "/dev/sdc1", "/dev/sdb1"] -std::map< Glib::ustring, std::vector > btrfs_device_cache ; +// btrfs_device_cache["/dev/sda2"] = {devid=1, members=["/dev/sda2"]} +// btrfs_device_cache["/dev/sdb1"] = {devid=1, members=["/dev/sdd1", "/dev/sdc1", "/dev/sdb1"]} +// btrfs_device_cache["/dev/sdc1"] = {devid=2, members=["/dev/sdd1", "/dev/sdc1", "/dev/sdb1"]} +// btrfs_device_cache["/dev/sdd1"] = {devid=3, members=["/dev/sdd1", "/dev/sdc1", "/dev/sdb1"]} +std::map btrfs_device_cache ; FS btrfs::get_filesystem_support() { @@ -430,32 +430,33 @@ void btrfs::clear_cache() // Return empty string if not found (not mounted). Glib::ustring btrfs::get_mount_device( const Glib::ustring & path ) { - std::vector entry = get_cache_entry( path ) ; - for ( unsigned int i = 0 ; i < entry .size() ; i ++ ) - if ( GParted_Core::is_dev_mounted( entry[ i ] ) ) - return entry[ i ] ; + BTRFS_Device btrfs_dev = get_cache_entry( path ) ; + for ( unsigned int i = 0 ; i < btrfs_dev .members .size() ; i ++ ) + if ( GParted_Core::is_dev_mounted( btrfs_dev .members[ i ] ) ) + return btrfs_dev .members[ i ] ; return "" ; } //Private methods //Return btrfs device cache entry, incrementally loading cache as required -const std::vector btrfs::get_cache_entry( const Glib::ustring & path ) +const BTRFS_Device & btrfs::get_cache_entry( const Glib::ustring & path ) { - std::vector entry = btrfs_device_cache[ path ] ; - - if ( ! entry .empty() ) - return entry ; + std::map::const_iterator bd_iter = btrfs_device_cache .find( path ) ; + if ( bd_iter != btrfs_device_cache .end() ) + return bd_iter ->second ; int exit_status ; Glib::ustring output, error ; + std::vector devid_list ; + std::vector path_list ; if ( btrfs_found ) exit_status = Utils::execute_command( "btrfs filesystem show " + path, output, error, true ) ; else exit_status = Utils::execute_command( "btrfs-show " + path, output, error, true ) ; if ( ! exit_status ) { - //Extract path for each devid from output like this: + //Extract devid and path for each device from output like this: // 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 @@ -464,19 +465,35 @@ const std::vector btrfs::get_cache_entry( const Glib::ustring & p Glib::ustring::size_type index ; while ( ( index = output .find( "devid ", offset ) ) != Glib::ustring::npos ) { + int devid = -1 ; + sscanf( output .substr( index ) .c_str(), "devid %d", &devid ) ; Glib::ustring devid_path = Utils::regexp_label( output .substr( index ), "devid .* path (/dev/[[:graph:]]+)" ) ; - if ( ! devid_path .empty() ) + if ( devid > -1 && ! devid_path .empty() ) { - entry .push_back( devid_path ) ; + devid_list .push_back( devid ) ; + path_list .push_back( devid_path ) ; } offset = index + 5 ; //Next find starts immediately after current "devid" } } //Add cache entries for all found devices - for ( unsigned int i = 0 ; i < entry .size() ; i ++ ) - btrfs_device_cache[ entry[ i ] ] = entry ; - return entry ; + for ( unsigned int i = 0 ; i < devid_list .size() ; i ++ ) + { + BTRFS_Device btrfs_dev ; + btrfs_dev .devid = devid_list[ i ] ; + btrfs_dev .members = path_list ; + btrfs_device_cache[ path_list[ i ] ] = btrfs_dev ; + } + + bd_iter = btrfs_device_cache .find( path ) ; + if ( bd_iter != btrfs_device_cache .end() ) + return bd_iter ->second ; + + //If "btrfs filesystem show" / "btrfs-show" commands not found, returned non-zero + // exit status or failed to parse information return an "unknown" record + static BTRFS_Device btrfs_dev = { -1, } ; + return btrfs_dev ; } //Return the value of a btrfs tool formatted size, including reversing