[gparted] Correctly show multiple "unknown device" LVM2 VG members (#670171)



commit fdb7e9fe89c951efd93a3d8d92a61a9ff995b4ee
Author: Mike Fleetwood <mike fleetwood googlemail com>
Date:   Sat Aug 18 09:12:47 2012 +0100

    Correctly show multiple "unknown device" LVM2 VG members (#670171)
    
    If an LVM2 Volume Group has two or more missing Physical Volumes, the VG
    is displayed as only having one "unknown device" because
    get_vg_members() only adds unique names to the list of members.
    
        # lvm pvcreate /dev/sda11 /dev/sda12 /dev/sda13
        # lvm vgcreate Test-VG1 /dev/sda11 /dev/sda12 /dev/sda13
        # wipefs -a /dev/sda12
        # wipefs -a /dev/sda13
        View partition information in GParted
    
    The simplest fix would be to include the PV's UUID in the cache of LVM2
    information and add PV names based on unique UUIDs being a member of the
    relevant VG.  Unfortunately "lvm pvs" seems to have a bug when
    displaying Logical Volume attributes, and there are two or more missing
    PVs, which causes one of the PVs to be displayed multiple times, rather
    than displaying each PV once.
    
    Without LV attributes, every PV is listed:
    
        # lvm pvs --nosuffix --separator , --units b -o pv_name,pv_uuid,vg_name,vg_attr 2> /dev/null
          PV,PV UUID,VG,Attr
          /dev/sda11,pJ3R51-AOPP-rKlr-CKCT-nfPS-G5FP-B5Vyjm,Test-VG1,wz-pn-
          unknown device,Y72oSm-uBcE-ktZL-OIFA-Q129-Uv1B-x5IsrA,Test-VG1,wz-pn-
          unknown device,1ESORF-7wlR-0tnO-fy2z-nOL1-MrnJ-2O5yjK,Test-VG1,wz-pn-
    
    With LV attributes, one missing PV is repeated:
    
        # lvm pvs --nosuffix --separator , --units b -o pv_name,pv_uuid,vg_name,vg_attr,lv_name,lv_attr 2> /dev/null
          PV,PV UUID,VG,Attr,LV,Attr
          /dev/sda11,pJ3R51-AOPP-rKlr-CKCT-nfPS-G5FP-B5Vyjm,Test-VG1,wz-pn-,,
          unknown device,Y72oSm-uBcE-ktZL-OIFA-Q129-Uv1B-x5IsrA,Test-VG1,wz-pn-,,
          unknown device,Y72oSm-uBcE-ktZL-OIFA-Q129-Uv1B-x5IsrA,Test-VG1,wz-pn-,,
    
    Also "lvm vgs" and "lvm lvs" don't display anything when including both
    VG and LV attributes.
    
    Instead query the LVM2 information in two separate commands, one
    querying PV attributes and one querying VG and LV attributes, saving the
    results in lvm_pv_cache and lvm_vg_cache respectively.
    
    Bug #670171 - Add LVM PV read-write support

 include/LVM2_PV_Info.h |    3 +
 src/LVM2_PV_Info.cc    |  163 +++++++++++++++++++++++++++++++----------------
 2 files changed, 110 insertions(+), 56 deletions(-)
---
diff --git a/include/LVM2_PV_Info.h b/include/LVM2_PV_Info.h
index 5e228ac..5de6989 100644
--- a/include/LVM2_PV_Info.h
+++ b/include/LVM2_PV_Info.h
@@ -51,11 +51,14 @@ private:
 	void load_lvm2_pv_info_cache() ;
 	Glib::ustring get_pv_attr_by_path( const Glib::ustring & path, unsigned int entry ) const ;
 	Glib::ustring get_pv_attr_by_row( unsigned int row, unsigned int entry ) const ;
+	Glib::ustring get_vg_attr_by_name( const Glib::ustring & vgname, unsigned int entry ) const ;
+	Glib::ustring get_vg_attr_by_row( unsigned int row, unsigned int entry ) const ;
 	static Byte_Value lvm2_pv_attr_to_num( const Glib::ustring str ) ;
 	static bool bit_set( const Glib::ustring & attr, unsigned int bit ) ;
 	static bool lvm2_pv_info_cache_initialized ;
 	static bool lvm_found ;
 	static std::vector<Glib::ustring> lvm2_pv_cache ;
+	static std::vector<Glib::ustring> lvm2_vg_cache ;
 	static std::vector<Glib::ustring> error_messages ;
 };
 
diff --git a/src/LVM2_PV_Info.cc b/src/LVM2_PV_Info.cc
index ce5d273..521ef33 100644
--- a/src/LVM2_PV_Info.cc
+++ b/src/LVM2_PV_Info.cc
@@ -25,10 +25,15 @@ enum PV_ATTRIBUTE
 	PVATTR_PV_NAME = 0,
 	PVATTR_PV_SIZE = 1,
 	PVATTR_PV_FREE = 2,
-	PVATTR_VG_NAME = 3,
-	PVATTR_VG_BITS = 4,
-	PVATTR_LV_NAME = 5,
-	PVATTR_LV_BITS = 6
+	PVATTR_VG_NAME = 3
+} ;
+
+enum VG_ATTRIBUTE
+{
+	VGATTR_VG_NAME = 0,
+	VGATTR_VG_BITS = 1,
+	VGATTR_LV_NAME = 2,
+	VGATTR_LV_BITS = 3
 } ;
 
 enum VG_BIT
@@ -45,32 +50,39 @@ enum LV_BIT
 
 //Data model:
 //  lvm2_pv_info_cache_initialized
-//                      - Has the cache been loaded let?
+//                      - Has the cache been loaded yet?
 //  lvm_found           - Is the "lvm" command available?
-//  lvm2_pv_cache       - String vector storing attributes of a PV.
-//                        Attributes are: pv_name,pv_size,pv_free,
-//                        vg_name,vg_attr,lv_name,lv_attr.  Pv_size and
-//                        pv_free are the size of the PV and number of
-//                        free bytes.  See vgs(8) and lvs(8) for details
-//                        of vg_attr and lv_attr respectively.
+//  lvm2_pv_cache       - String vector storing PV attributes: pv_name, pv_size, pv_free, vg_name.
+//                        One string per PV.
 //                        E.g.
-//                        ["/dev/sda10,2147483648,2147483648,,r-----,,",
-//                         "/dev/sda11,2143289344,2143289344,GParted-VG1,wz--n-,,",
-//                         "/dev/sda12,2143289344,1619001344,GParted-VG2,wz--n-,lvol0,-wi---",
-//                         "/dev/sda12,2143289344,1619001344,GParted-VG2,wz--n-,,",
-//                         "/dev/sda13,2143289344,830472192,GParted_VG3,wz--n-,lvol0,-wi-a-",
-//                         "/dev/sda13,2143289344,830472192,GParted_VG3,wz--n-,lvol1,-wi-a-",
-//                         "/dev/sda13,2143289344,830472192,GParted_VG3,wz--n-,,",
-//                         "/dev/sda14,2143289344,1828716544,GParted-VG4,wzx-n-,lvol0,-wi---",
-//                         "/dev/sda14,2143289344,1828716544,GParted-VG4,wzx-n-,,"]
-//  error_messages      - String vector storing whole cache error
-//                        messsages.
+//                        ["/dev/sda10,1073741824,1073741824,",
+//                         "/dev/sda11,1069547520,1069547520,Test-VG1",
+//                         "/dev/sda12,1069547520,335544320,Test_VG2",
+//                         "/dev/sda13,1069547520,0,Test_VG3",
+//                         "/dev/sda14,1069547520,566231040,Test_VG3",
+//                         "/dev/sda15,1069547520,545259520,Test-VG4"
+//                        ]
+//  lvm2_vg_cache       - String vector storing VG attributes: vg_name, vg_attr, lv_name, lv_attr.
+//                        See vgs(8) and lvs(8) for details of vg_attr and lv_attr respectively.
+//                        [",r-----,,",
+//                         "Test-VG1,wz--n-,,",
+//                         "Test_VG2,wz--n-,lvol0,-wi---",
+//                         "Test_VG2,wz--n-,lvol1,-wi---",
+//                         "Test_VG2,wz--n-,,",
+//                         "Test_VG3,wz--n-,lvol0,-wi-a-",
+//                         "Test_VG3,wz--n-,lvol0,-wi-a-",
+//                         "Test_VG3,wz--n-,,",
+//                         "Test-VG4,wzx-n-,lvol0,-wi---",
+//                         "Test-VG4,wzx-n-,,"
+//                        ]
+//  error_messages      - String vector storing whole cache error messages.
 
 
 //Initialize static data elements
 bool LVM2_PV_Info::lvm2_pv_info_cache_initialized = false ;
 bool LVM2_PV_Info::lvm_found = false ;
 std::vector<Glib::ustring> LVM2_PV_Info::lvm2_pv_cache ;
+std::vector<Glib::ustring> LVM2_PV_Info::lvm2_vg_cache ;
 std::vector<Glib::ustring> LVM2_PV_Info::error_messages ;
 
 LVM2_PV_Info::LVM2_PV_Info()
@@ -129,11 +141,11 @@ bool LVM2_PV_Info::has_active_lvs( const Glib::ustring & path )
 		//PV not yet included in any VG
 		return false ;
 
-	for ( unsigned int i = 0 ; i < lvm2_pv_cache .size() ; i ++ )
+	for ( unsigned int i = 0 ; i < lvm2_vg_cache .size() ; i ++ )
 	{
-		if ( vgname == get_pv_attr_by_row( i, PVATTR_VG_NAME ) )
+		if ( vgname == get_vg_attr_by_row( i, VGATTR_VG_NAME ) )
 		{
-			if ( bit_set( get_pv_attr_by_row( i, PVATTR_LV_BITS ), LVBIT_STATE ) )
+			if ( bit_set( get_vg_attr_by_row( i, VGATTR_LV_BITS ), LVBIT_STATE ) )
 				//LV in VG is active
 				return true ;
 		}
@@ -146,16 +158,7 @@ bool LVM2_PV_Info::is_vg_exported( const Glib::ustring & vgname )
 {
 	initialize_if_required() ;
 
-	for ( unsigned int i = 0 ; i < lvm2_pv_cache .size() ; i ++ )
-	{
-		if ( vgname == get_pv_attr_by_row( i, PVATTR_VG_NAME ) )
-		{
-			if ( bit_set( get_pv_attr_by_row( i, PVATTR_VG_BITS), VGBIT_EXPORTED ) )
-				//VG is exported
-				return true ;
-		}
-	}
-	return false ;
+	return bit_set( get_vg_attr_by_name( vgname, VGATTR_VG_BITS ), VGBIT_EXPORTED ) ;
 }
 
 //Return vector of PVs which are members of the VG.  Passing "" returns all empty PVs.
@@ -164,25 +167,11 @@ std::vector<Glib::ustring> LVM2_PV_Info::get_vg_members( const Glib::ustring & v
 	initialize_if_required() ;
 	std::vector<Glib::ustring> members ;
 
-	//Generate array of unique PV member names of a VG
 	for ( unsigned int i = 0 ; i < lvm2_pv_cache .size() ; i ++ )
 	{
 		if ( vgname == get_pv_attr_by_row( i, PVATTR_VG_NAME ) )
 		{
-			bool already_added = false ;
-			Glib::ustring pvname = get_pv_attr_by_row( i, PVATTR_PV_NAME ) ;
-			for ( unsigned int j = 0 ; j < members .size() ; j ++ )
-			{
-				if ( pvname == members[ j ] )
-				{
-					already_added = true ;
-					break ;
-				}
-			}
-			if ( ! already_added )
-			{
-				members .push_back( get_pv_attr_by_row( i, PVATTR_PV_NAME ) ) ;
-			}
+			members .push_back( get_pv_attr_by_row( i, PVATTR_PV_NAME ) ) ;
 		}
 	}
 
@@ -197,11 +186,11 @@ std::vector<Glib::ustring> LVM2_PV_Info::get_error_messages( const Glib::ustring
 		return error_messages ;
 
 	std::vector<Glib::ustring> partition_specific_messages ;
-	partition_specific_messages .clear() ;
 	Glib::ustring temp ;
 
 	//Check for partition specific message: partial VG
-	if ( bit_set( get_pv_attr_by_path( path, PVATTR_VG_BITS ), VGBIT_PARTIAL ) )
+	Glib::ustring vgname = get_pv_attr_by_path( path, PVATTR_VG_NAME ) ;
+	if ( bit_set( get_vg_attr_by_name( vgname, VGATTR_VG_BITS ), VGBIT_PARTIAL ) )
 	{
 		temp = _("One or more Physical Volumes belonging to the Volume Group is missing.") ;
 		temp += "\n" ;
@@ -232,8 +221,10 @@ void LVM2_PV_Info::set_command_found()
 void LVM2_PV_Info::load_lvm2_pv_info_cache()
 {
 	Glib::ustring output, error ;
+	unsigned int i ;
 
 	lvm2_pv_cache .clear() ;
+	lvm2_vg_cache .clear() ;
 	error_messages .clear() ;
 	if ( lvm_found )
 	{
@@ -242,15 +233,15 @@ void LVM2_PV_Info::load_lvm2_pv_info_cache()
 		//  is changed not using lvm commands.
 		Utils::execute_command( "lvm vgscan", output, error, true ) ;
 
-		//Load LVM2 PV attribute cache.  Output PV attributes in
-		//  PV_ATTRIBUTE order
-		Glib::ustring cmd = "lvm pvs --config \"log{command_names=0}\" --nosuffix --noheadings --separator , --units b -o pv_name,pv_size,pv_free,vg_name,vg_attr,lv_name,lv_attr" ;
+		//Load LVM2 PV attribute cache.  Output PV attributes in PV_ATTRIBUTE order
+		Glib::ustring cmd = "lvm pvs --config \"log{command_names=0}\" --nosuffix "
+		                    "--noheadings --separator , --units b -o pv_name,pv_size,pv_free,vg_name" ;
 		if ( ! Utils::execute_command( cmd, output, error, true ) )
 		{
 			if ( output != "" )
 			{
 				Utils::tokenize( output, lvm2_pv_cache, "\n" ) ;
-				for ( unsigned int i = 0 ; i < lvm2_pv_cache .size() ; i ++ )
+				for ( i = 0 ; i < lvm2_pv_cache .size() ; i ++ )
 					lvm2_pv_cache [i] = Utils::trim( lvm2_pv_cache [i] ) ;
 			}
 		}
@@ -261,6 +252,31 @@ void LVM2_PV_Info::load_lvm2_pv_info_cache()
 				error_messages .push_back ( output ) ;
 			if ( ! error .empty() )
 				error_messages .push_back ( error ) ;
+		}
+
+		//Load LVM2 VG attribute cache.  Output VG and LV attributes in VG_ATTRIBUTE order
+		cmd = "lvm pvs --config \"log{command_names=0}\" --nosuffix "
+		      "--noheadings --separator , --units b -o vg_name,vg_attr,lv_name,lv_attr" ;
+		if ( ! Utils::execute_command( cmd, output, error, true ) )
+		{
+			if ( output != "" )
+			{
+				Utils::tokenize( output, lvm2_vg_cache, "\n" ) ;
+				for ( i = 0 ; i < lvm2_vg_cache .size() ; i ++ )
+					lvm2_vg_cache [i] = Utils::trim( lvm2_vg_cache [i] ) ;
+			}
+		}
+		else
+		{
+			error_messages .push_back( cmd ) ;
+			if ( ! output .empty() )
+				error_messages .push_back ( output ) ;
+			if ( ! error .empty() )
+				error_messages .push_back ( error ) ;
+		}
+
+		if ( ! error_messages .empty() )
+		{
 			Glib::ustring temp ;
 			temp = _("An error occurred reading LVM2 configuration!") ;
 			temp += "\n" ;
@@ -308,6 +324,41 @@ Glib::ustring LVM2_PV_Info::get_pv_attr_by_row( unsigned int row, unsigned int e
 	return "" ;
 }
 
+//Return VG's nth attribute.  Performs linear search of the cache and
+//  uses the first matching VG entry.  Attributes are numbered 0 upward
+//  using VG_ATTRIBUTE enumeration.
+Glib::ustring LVM2_PV_Info::get_vg_attr_by_name( const Glib::ustring & vgname, unsigned int entry ) const
+{
+	for ( unsigned int i = 0 ; i < lvm2_vg_cache .size() ; i ++ )
+	{
+		std::vector<Glib::ustring> vg_attrs ;
+		Utils::split( lvm2_vg_cache [i], vg_attrs, "," ) ;
+		if ( VGATTR_VG_NAME < vg_attrs .size() && vgname == vg_attrs [VGATTR_VG_NAME] )
+		{
+			if ( entry < vg_attrs .size() )
+				return vg_attrs [entry] ;
+			else
+				break ;
+		}
+	}
+
+	return "" ;
+}
+
+//Return VG's nth attribute from specified cache row.  Row is numbered
+//  0 upwards and attributes are numbers numbered 0 upwards using
+//  VG_ATTRIBUTE enumeration.
+Glib::ustring LVM2_PV_Info::get_vg_attr_by_row( unsigned int row, unsigned int entry ) const
+{
+	if ( row >= lvm2_vg_cache .size() )
+		return "" ;
+	std::vector<Glib::ustring> vg_attrs ;
+	Utils::split( lvm2_vg_cache [row], vg_attrs, "," ) ;
+	if ( entry < vg_attrs .size() )
+		return vg_attrs [entry] ;
+	return "" ;
+}
+
 //Return string converted to a number, or -1 for error.
 //Used to convert PVs size or free bytes.
 Byte_Value LVM2_PV_Info::lvm2_pv_attr_to_num( const Glib::ustring str )



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]