[gparted] Detect busy status of multi-device btrfs file systems (#723842)
- From: Curtis Gedak <gedakc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gparted] Detect busy status of multi-device btrfs file systems (#723842)
- Date: Wed, 30 Jul 2014 17:34:38 +0000 (UTC)
commit 76e64f2905bdbe37c307bc9fab055f44914dc7b2
Author: Mike Fleetwood <mike fleetwood googlemail com>
Date: Mon Feb 17 22:39:34 2014 +0000
Detect busy status of multi-device btrfs file systems (#723842)
Busy detection of file systems works by checking if the device is
mounted (appears in the mount_info map). For a multi-device btrfs file
system this will only report one of the devices as busy, not all of
them.
# btrfs filesystem show /dev/sdb1
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
# mount /dev/sdb1 /mnt/1
# grep btrfs /proc/mounts
/dev/sdb1 /mnt/1 btrfs rw,seclabel,relatime,ssd,space_cache 0 0
GParted will only report /dev/sdb1 as busy, but not /dev/sdb2.
Add btrfs specific is_busy() method which reports the device as busy if
any of the devices in the btrfs file system are mounted. This uses a
cache which maps device membership in all btrfs file systems. The cache
is cleared on GParted refresh and incrementally populated as each btrfs
partition is checked for busy status.
WARNING:
Removal of the mounting device from a btrfs file system makes it
impossible to determine whether the file system is mounted or not for
linux <= 3.4. This is because /proc/mounts continues to show the old
device which is no longer a member of the file system.
# btrfs device delete /dev/sdb1 /mnt/1
# sync
# grep btrfs /proc/mounts
/dev/sdb1 /mnt/1 btrfs rw,seclabel,relatime,ssd,space_cache 0 0
# btrfs filesystem show /dev/sdb1
# btrfs filesystem show /dev/sdb2
Label: none uuid: 36eb51a2-2927-4c92-820f-b2f0b5cdae50
Total devices 1 FS bytes used 28.00KB
devid 2 size 2.00GB used 1.02GB path /dev/sdb2
Fixed in linux 3.5 by commit:
Btrfs: implement ->show_devname
https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=9c5085c147989d48dfe74194b48affc23f376650
Bug #723842 - GParted resizes the wrong filesystem (does not pass the
devid to btrfs filesystem resize)
include/btrfs.h | 4 +++
src/GParted_Core.cc | 3 +-
src/btrfs.cc | 74 ++++++++++++++++++++++++++++++++++++++++++++++++++-
3 files changed, 79 insertions(+), 2 deletions(-)
---
diff --git a/include/btrfs.h b/include/btrfs.h
index 6cf7744..f0828ee 100644
--- a/include/btrfs.h
+++ b/include/btrfs.h
@@ -28,6 +28,7 @@ class btrfs : public FileSystem
public:
FS get_filesystem_support() ;
void set_used_sectors( Partition & partition ) ;
+ bool is_busy( const Glib::ustring & path ) ;
void read_label( Partition & partition ) ;
bool write_label( const Partition & partition, OperationDetail & operationdetail ) ;
void read_uuid( Partition & partition ) ;
@@ -35,7 +36,10 @@ public:
bool resize( const Partition & partition_new, OperationDetail & operationdetail, bool fill_partition
= false ) ;
bool check_repair( const Partition & partition, OperationDetail & operationdetail ) ;
+ static void clear_cache() ;
+
private:
+ static const std::vector<Glib::ustring> 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/GParted_Core.cc b/src/GParted_Core.cc
index 3b3d092..a2b4ebb 100644
--- a/src/GParted_Core.cc
+++ b/src/GParted_Core.cc
@@ -179,7 +179,8 @@ void GParted_Core::set_devices_thread( std::vector<Device> * pdevices )
FS_Info fs_info( true ) ; //Refresh cache of file system information
DMRaid dmraid( true ) ; //Refresh cache of dmraid device information
LVM2_PV_Info lvm2_pv_info( true ) ; //Refresh cache of LVM2 PV information
-
+ btrfs::clear_cache() ;
+
init_maps() ;
//only probe if no devices were specified as arguments..
diff --git a/src/btrfs.cc b/src/btrfs.cc
index 788a484..0700026 100644
--- a/src/btrfs.cc
+++ b/src/btrfs.cc
@@ -17,6 +17,7 @@
#include "../include/btrfs.h"
+#include "../include/GParted_Core.h"
#include <ctype.h>
@@ -26,12 +27,21 @@ namespace GParted
bool btrfs_found = false ;
bool resize_to_same_size_fails = true ;
+//Cache of all devices in each btrfs file system 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<Glib::ustring> > btrfs_device_cache ;
+
FS btrfs::get_filesystem_support()
{
FS fs ;
fs .filesystem = GParted::FS_BTRFS ;
- fs .busy = FS::GPARTED ;
+ fs .busy = FS::EXTERNAL ;
if ( ! Glib::find_program_in_path( "mkfs.btrfs" ) .empty() )
{
@@ -121,6 +131,23 @@ FS btrfs::get_filesystem_support()
return fs ;
}
+bool btrfs::is_busy( const Glib::ustring & path )
+{
+ //A btrfs file system is busy if any of the member devices are mounted.
+ // WARNING:
+ // Removal of the mounting device from a btrfs file system makes it impossible to
+ // determine whether the file system is mounted or not for linux <= 3.4. This is
+ // because /proc/mounts continues to show the old device which is no longer a
+ // member of the file system. Fixed in linux 3.5 by commit:
+ // Btrfs: implement ->show_devname
+ //
https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=9c5085c147989d48dfe74194b48affc23f376650
+ std::vector<Glib::ustring> entry = get_cache_entry( path ) ;
+ for ( unsigned int i = 0 ; i < entry .size() ; i ++ )
+ if ( GParted_Core::is_dev_mounted( entry[ i ] ) )
+ return true ;
+ return false ;
+}
+
bool btrfs::create( const Partition & new_partition, OperationDetail & operationdetail )
{
return (! execute_command( "mkfs.btrfs -L \"" + new_partition .get_label() + "\" " + new_partition
.get_path(), operationdetail ) );
@@ -311,8 +338,53 @@ void btrfs::read_uuid( Partition & partition )
}
}
+void btrfs::clear_cache()
+{
+ btrfs_device_cache .clear() ;
+}
+
//Private methods
+//Return btrfs device cache entry, incrementally loading cache as required
+const std::vector<Glib::ustring> btrfs::get_cache_entry( const Glib::ustring & path )
+{
+ std::vector<Glib::ustring> entry = btrfs_device_cache[ path ] ;
+
+ if ( ! entry .empty() )
+ return entry ;
+
+ int exit_status ;
+ Glib::ustring output, error ;
+ 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:
+ // 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
+ 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() )
+ {
+ entry .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 ;
+}
+
//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".
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]