diff --git a/README b/README
index 036b81a..66146f1 100644
--- a/README
+++ b/README
@@ -164,6 +164,12 @@ For GNU/Linux distribution dmraid support, the following are required:
    - dmraid drive arrays activated on boot (e.g., dmraid -ay).
 
 
+For LVM2 Physical Volume support the following commands are required:
+   lvm             - LVM2 administration tool
+   dmsetup         - Use to query active kernel device-mapper devices
+And device-mapper support in the kernel.
+
+
 For attempt data rescue for lost partitions, the following package
 is required:
    gpart           - guesses PC-type hard disk partitions
diff --git a/include/LVM2_PV_Info.h b/include/LVM2_PV_Info.h
new file mode 100644
index 0000000..4195084
--- /dev/null
+++ b/include/LVM2_PV_Info.h
@@ -0,0 +1,58 @@
+/* Copyright (C) 2011 Mike Fleetwood
+ *
+ *  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 Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+
+/* LVM2_PV_Info
+ * 
+ * A persistent cache of information about LVM2 PVs that helps to
+ * minimize the number of executions of lvm commands used to query
+ * those attributes.
+ */
+
+#ifndef LVM2_PV_INFO_H_
+#define LVM2_PV_INFO_H_
+
+#include "../include/Utils.h"
+
+namespace GParted
+{
+
+class LVM2_PV_Info
+{
+public:
+	LVM2_PV_Info() ;
+	LVM2_PV_Info( bool do_refresh ) ;
+	~LVM2_PV_Info() ;
+	bool is_lvm2_pv_supported() ;
+	Glib::ustring get_vg_name( const Glib::ustring & path ) ;
+	Byte_Value get_free_bytes( const Glib::ustring & path ) ;
+	bool has_active_lvs( const Glib::ustring & path ) ;
+private:
+	void initialize_if_required() ;
+	void set_commands_found() ;
+	void load_lvm2_pv_info_cache() ;
+	Glib::ustring get_pv_attr( const Glib::ustring & path, unsigned int entry ) ;
+	static bool lvm2_pv_info_cache_initialized ;
+	static bool lvm_found ;
+	static bool dmsetup_found ;
+	static std::vector<Glib::ustring> lvm2_pv_cache ;
+	static Glib::ustring dmsetup_info_cache ;
+};
+
+}//GParted
+
+#endif /*LVM2_PV_INFO_H_*/
diff --git a/include/Partition.h b/include/Partition.h
index c7eaed3..45f6432 100644
--- a/include/Partition.h
+++ b/include/Partition.h
@@ -93,6 +93,7 @@ public:
 	Sector get_sector_length() const ; 
 	Glib::ustring get_path() const ;
 	std::vector<Glib::ustring> get_paths() const ;
+	void add_mountpoint( const Glib::ustring & mountpoint, bool clear_mountpoints = false ) ;
 	void add_mountpoints( const std::vector<Glib::ustring> & mountpoints, bool clear_mountpoints = false ) ;
 	Glib::ustring get_mountpoint() const ; 
 	void clear_mountpoints() ;
diff --git a/include/Utils.h b/include/Utils.h
index 27023bc..b61e0d8 100644
--- a/include/Utils.h
+++ b/include/Utils.h
@@ -70,11 +70,11 @@ enum FILESYSTEM
 	FS_HFSPLUS	= 18,
 	FS_UFS		= 19,
 	FS_NILFS2	= 20,
+	FS_LVM2_PV	= 21,
 
-	FS_USED		= 21,
-	FS_UNUSED	= 22,
+	FS_USED		= 22,
+	FS_UNUSED	= 23,
 
-	FS_LVM2		= 23,
 	FS_LUKS		= 24
 } ;
 
@@ -161,6 +161,9 @@ public:
 	static void tokenize( const Glib::ustring& str,
 	                      std::vector<Glib::ustring>& tokens,
 	                      const Glib::ustring& delimiters ) ;
+	static void split( const Glib::ustring& str,
+	                   std::vector<Glib::ustring>& result,
+	                   const Glib::ustring& delimiters     ) ;
 	static int convert_to_int(const Glib::ustring & src);
 };
 
diff --git a/include/lvm2_pv.h b/include/lvm2_pv.h
new file mode 100644
index 0000000..e3a60ca
--- /dev/null
+++ b/include/lvm2_pv.h
@@ -0,0 +1,48 @@
+/* Copyright (C) 2011 Mike Fleetwood
+ *
+ *  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 Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+ 
+ 
+#ifndef LVM2_PV_H_
+#define LVM2_PV_H_
+
+#include "../include/FileSystem.h"
+
+namespace GParted
+{
+
+class lvm2_pv : public FileSystem
+{
+public:
+	FS get_filesystem_support() ;
+	void set_used_sectors( Partition & partition ) ;
+	void read_label( Partition & partition ) ;
+	bool write_label( const Partition & partition, OperationDetail & operationdetail ) ;
+	bool create( const Partition & new_partition, OperationDetail & operationdetail ) ;
+	bool resize( const Partition & partition_new, OperationDetail & operationdetail, bool fill_partition = false ) ;
+	bool move( const Partition & partition_new
+	         , const Partition & partition_old
+	         , OperationDetail & operationdetail
+	         ) ;
+	bool copy( const Glib::ustring & src_part_path,
+		   const Glib::ustring & dest_part_path,
+		   OperationDetail & operationdetail ) ;
+	bool check_repair( const Partition & partition, OperationDetail & operationdetail ) ;
+};
+
+} //GParted
+
+#endif /*LVM2_PV_H_*/
diff --git a/src/DialogFeatures.cc b/src/DialogFeatures.cc
index a3995f5..6a7f1c1 100644
--- a/src/DialogFeatures.cc
+++ b/src/DialogFeatures.cc
@@ -122,10 +122,9 @@ void DialogFeatures::load_filesystems( const std::vector<FS> & FILESYSTEMS )
 	//fill the features chart with valid file systems 
 	for ( unsigned short t = 0; t < FILESYSTEMS .size() ; t++ )
 	{
-		//Skip luks, lvm2, and unknown because these are not file systems
+		//Skip luks and unknown because these are not file systems
 		if (
-		     FILESYSTEMS[ t ] .filesystem == GParted::FS_LUKS ||
-		     FILESYSTEMS[ t ] .filesystem == GParted::FS_LVM2 ||
+		     FILESYSTEMS[ t ] .filesystem == GParted::FS_LUKS    ||
 		     FILESYSTEMS[ t ] .filesystem == GParted::FS_UNKNOWN
 		   )
 			continue ;
diff --git a/src/Dialog_Partition_Info.cc b/src/Dialog_Partition_Info.cc
index c283158..a1ab995 100644
--- a/src/Dialog_Partition_Info.cc
+++ b/src/Dialog_Partition_Info.cc
@@ -266,6 +266,14 @@ void Dialog_Partition_Info::Display_Info()
 				 */
 				str_temp = _("Active") ;
 			}
+			else if ( partition .filesystem == FS_LVM2_PV )
+			{
+				/* TO TRANSLATORS:  myvgname active
+				 * means that the partition is part of an LVM volume group and that
+				 * volume group is active and being used by the operating system.
+				 */
+				str_temp = String::ucompose( _("%1 active"), partition .get_mountpoint() ) ;
+			}
 			else if ( partition .get_mountpoints() .size() )
 			{
 				str_temp = String::ucompose( 
@@ -290,6 +298,23 @@ void Dialog_Partition_Info::Display_Info()
 			 */
 			str_temp = _("Not active") ;
 		}
+		else if ( partition .filesystem == FS_LVM2_PV )
+		{
+			Glib::ustring mount_point = partition .get_mountpoint() ;
+			if ( mount_point .empty() )
+				/* TO TRANSLATORS:  Not active (Not part of any volume group)
+				 * means that the partition is not yet part of an LVM volume
+				 * group and therefore is not active and can not yet be used by
+				 * the operating system.
+				 */
+				str_temp = _("Not active (Not part of any volume group)") ;
+			else
+				/* TO TRANSLATORS:  myvgname not active
+				 * means that the partition is part of an LVM volume group but
+				 * the volume group is not active and not being used by the operating system.
+				 */
+				str_temp = String::ucompose( _("%1 not active"), mount_point ) ;
+		}
 		else
 		{
 			/* TO TRANSLATORS:  Not mounted
diff --git a/src/Dialog_Partition_New.cc b/src/Dialog_Partition_New.cc
index 495ddf7..4d3647d 100644
--- a/src/Dialog_Partition_New.cc
+++ b/src/Dialog_Partition_New.cc
@@ -49,7 +49,7 @@ void Dialog_Partition_New::Set_Data( const Partition & partition,
 	for ( unsigned int t = this ->FILESYSTEMS .size( ) ; t > 0 ; t-- )
 	{
 		if ( this ->FILESYSTEMS[ t ] .filesystem == GParted::FS_UNKNOWN ||
-		     this ->FILESYSTEMS[ t ] .filesystem == GParted::FS_LVM2 ||
+		     this ->FILESYSTEMS[ t ] .filesystem == GParted::FS_LVM2_PV ||
 		     this ->FILESYSTEMS[ t ] .filesystem == GParted::FS_LUKS
 		   )
 			this ->FILESYSTEMS .erase( this->FILESYSTEMS .begin() + t ) ;
diff --git a/src/GParted_Core.cc b/src/GParted_Core.cc
index 9c6b116..765444a 100644
--- a/src/GParted_Core.cc
+++ b/src/GParted_Core.cc
@@ -21,6 +21,7 @@
 #include "../include/DMRaid.h"
 #include "../include/SWRaid.h"
 #include "../include/FS_Info.h"
+#include "../include/LVM2_PV_Info.h"
 #include "../include/OperationCopy.h"
 #include "../include/OperationCreate.h"
 #include "../include/OperationDelete.h"
@@ -37,6 +38,7 @@
 #include "../include/fat16.h"
 #include "../include/fat32.h"
 #include "../include/linux_swap.h"
+#include "../include/lvm2_pv.h"
 #include "../include/reiserfs.h"
 #include "../include/nilfs2.h"
 #include "../include/ntfs.h"
@@ -124,6 +126,9 @@ void GParted_Core::find_supported_filesystems()
 	
 	linux_swap fs_linux_swap;
 	FILESYSTEMS .push_back( fs_linux_swap .get_filesystem_support() ) ;
+	
+	lvm2_pv fs_lvm2_pv;
+	FILESYSTEMS .push_back( fs_lvm2_pv .get_filesystem_support() ) ;
 
 	nilfs2 fs_nilfs2;
 	FILESYSTEMS .push_back( fs_nilfs2 .get_filesystem_support() ) ;
@@ -143,10 +148,6 @@ void GParted_Core::find_supported_filesystems()
 	xfs fs_xfs;
 	FILESYSTEMS .push_back( fs_xfs .get_filesystem_support() ) ;
 
-	//lvm2 physical volume -- not a file system
-	fs_notsupp .filesystem = GParted::FS_LVM2 ;
-	FILESYSTEMS .push_back( fs_notsupp ) ;
-
 	//luks encryption-- not a file system
 	fs_notsupp .filesystem = GParted::FS_LUKS ;
 	FILESYSTEMS .push_back( fs_notsupp ) ;
@@ -170,6 +171,7 @@ void GParted_Core::set_devices( std::vector<Device> & devices )
 	FS_Info fs_info( true ) ;  //Refresh cache of file system information
 	DMRaid dmraid( true ) ;    //Refresh cache of dmraid device information
 	SWRaid swraid( true ) ;    //Refresh cache of swraid device information
+	LVM2_PV_Info lvm2_pv_info( true ) ;	//Refresh cache of LVM2 PV information
 	
 	init_maps() ;
 	
@@ -899,6 +901,7 @@ void GParted_Core::set_device_partitions( Device & device )
 #ifndef USE_LIBPARTED_DMRAID
 	DMRaid dmraid ;    //Use cache of dmraid device information
 #endif
+	LVM2_PV_Info lvm2_pv_info ;
 
 	//clear partitions
 	device .partitions .clear() ;
@@ -934,7 +937,8 @@ void GParted_Core::set_device_partitions( Device & device )
 				}
 				else
 #endif
-					partition_is_busy = ped_partition_is_busy( lp_partition ) ;
+					partition_is_busy = ped_partition_is_busy( lp_partition ) ||
+					                    lvm2_pv_info .has_active_lvs( partition_path ) ;
 
 				partition_temp .Set( device .get_path(),
 						     partition_path,
@@ -976,7 +980,8 @@ void GParted_Core::set_device_partitions( Device & device )
 				}
 				else
 #endif
-					partition_is_busy = ped_partition_is_busy( lp_partition ) ;
+					partition_is_busy = ped_partition_is_busy( lp_partition ) ||
+					                    lvm2_pv_info .has_active_lvs( partition_path ) ;
 
 				partition_temp .Set( device .get_path(),
 						     partition_path, 
@@ -1113,6 +1118,8 @@ GParted::FILESYSTEM GParted_Core::get_filesystem()
 		          fs_type == "linux-swap(old)" ||
 		          fs_type == "swap" )
 			return GParted::FS_LINUX_SWAP ;
+		else if ( fs_type == "LVM2_member" )
+			return GParted::FS_LVM2_PV ;
 		else if ( fs_type == "fat16" )
 			return GParted::FS_FAT16 ;
 		else if ( fs_type == "fat32" )
@@ -1183,10 +1190,7 @@ GParted::FILESYSTEM GParted_Core::get_filesystem()
 		if (    0 == memcmp( magic1, "LABELONE", 8 )
 		     && 0 == memcmp( magic2, "LVM2", 4 ) )
 		{
-			temp = _( "Logical Volume Management is not yet supported." ) ;
-			temp += "\n" ;
-			partition_temp .messages .push_back( temp ) ;
-			return GParted::FS_LVM2 ;
+			return GParted::FS_LVM2_PV ;
 		}
 	}
 
@@ -1310,13 +1314,14 @@ void GParted_Core::set_mountpoints( std::vector<Partition> & partitions )
 #ifndef USE_LIBPARTED_DMRAID
 	DMRaid dmraid ;	//Use cache of dmraid device information
 #endif
+	LVM2_PV_Info lvm2_pv_info ;
 	for ( unsigned int t = 0 ; t < partitions .size() ; t++ )
 	{
 		if ( ( partitions[ t ] .type == GParted::TYPE_PRIMARY ||
 		       partitions[ t ] .type == GParted::TYPE_LOGICAL
 		     ) &&
 		     partitions[ t ] .filesystem != GParted::FS_LINUX_SWAP &&
-		     partitions[ t ] .filesystem != GParted::FS_LVM2 &&
+		     partitions[ t ] .filesystem != GParted::FS_LVM2_PV    &&
 		     partitions[ t ] .filesystem != GParted::FS_LUKS
 		   )
 		{
@@ -1373,6 +1378,12 @@ void GParted_Core::set_mountpoints( std::vector<Partition> & partitions )
 		}
 		else if ( partitions[ t ] .type == GParted::TYPE_EXTENDED )
 			set_mountpoints( partitions[ t ] .logicals ) ;
+		else if ( partitions[ t ] .filesystem == GParted::FS_LVM2_PV )
+		{
+			Glib::ustring vgname = lvm2_pv_info. get_vg_name( partitions[t].get_path() ) ;
+			if ( ! vgname .empty() )
+				partitions[ t ] .add_mountpoint( vgname ) ;
+		}
 	}
 }
 	
@@ -1383,15 +1394,14 @@ void GParted_Core::set_used_sectors( std::vector<Partition> & partitions )
 	for ( unsigned int t = 0 ; t < partitions .size() ; t++ )
 	{
 		if ( partitions[ t ] .filesystem != GParted::FS_LINUX_SWAP &&
-		     partitions[ t ] .filesystem != GParted::FS_LUKS &&
-		     partitions[ t ] .filesystem != GParted::FS_LVM2 &&
+		     partitions[ t ] .filesystem != GParted::FS_LUKS       &&
 		     partitions[ t ] .filesystem != GParted::FS_UNKNOWN
 		   )
 		{
 			if ( partitions[ t ] .type == GParted::TYPE_PRIMARY ||
 			     partitions[ t ] .type == GParted::TYPE_LOGICAL ) 
 			{
-				if ( partitions[ t ] .busy )
+				if ( partitions[ t ] .busy && partitions[t] .filesystem != GParted::FS_LVM2_PV )
 				{
 					if ( partitions[ t ] .get_mountpoints() .size() > 0  )
 					{
@@ -2952,6 +2962,7 @@ bool GParted_Core::set_proper_filesystem( const FILESYSTEM & filesystem )
 		case FS_EXT3		: p_filesystem = new ext3() ; 		break ;
 		case FS_EXT4		: p_filesystem = new ext4() ; 		break ;
 		case FS_LINUX_SWAP	: p_filesystem = new linux_swap() ; 	break ;
+		case FS_LVM2_PV		: p_filesystem = new lvm2_pv() ;	break ;
 		case FS_FAT16		: p_filesystem = new fat16() ; 		break ;
 		case FS_FAT32		: p_filesystem = new fat32() ; 		break ;
 		case FS_NILFS2		: p_filesystem = new nilfs2() ;		break ;
diff --git a/src/LVM2_PV_Info.cc b/src/LVM2_PV_Info.cc
new file mode 100644
index 0000000..6146fe4
--- /dev/null
+++ b/src/LVM2_PV_Info.cc
@@ -0,0 +1,187 @@
+/* Copyright (C) 2011 Mike Fleetwood
+ *
+ *  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 Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "../include/LVM2_PV_Info.h"
+
+namespace GParted
+{
+
+enum PV_ATTRIBUTE
+{
+	PVATTR_PV_NAME = 0,
+	PVATTR_VG_NAME = 1,
+	PVATTR_PV_FREE = 2
+} ;
+
+//Data model:
+//  lvm2_pv_info_cache_initialized
+//                      - Has the cache been loaded let?
+//  lvm_found           - Is the "lvm" command available?
+//  dmsetup_found       - Is the "dmsetup" command available?
+//  lvm2_pv_cache       - String vector storing attributes of a PV.
+//                        Attributes are: pv_name,vg_name,pv_free.
+//                        Pv_free is the number of free bytes.
+//                        E.g.
+//                        ["/dev/sda6,vg_test,4022337536",
+//                         "/dev/sda8,vg_test2,5087690752",
+//                         "/dev/sda10,,2147483648"]
+//  dmsetup_info_cache  - String storing active LVs.  E.g.
+//                        "vg_test-lvol1\nvg_test-lvol0\nvg_test2-lvol0\n"
+
+//Initialize static data elements
+bool LVM2_PV_Info::lvm2_pv_info_cache_initialized = false ;
+bool LVM2_PV_Info::lvm_found = false ;
+bool LVM2_PV_Info::dmsetup_found = false ;
+std::vector<Glib::ustring> LVM2_PV_Info::lvm2_pv_cache ;
+Glib::ustring LVM2_PV_Info::dmsetup_info_cache = "" ;
+
+LVM2_PV_Info::LVM2_PV_Info()
+{
+}
+
+LVM2_PV_Info::LVM2_PV_Info( bool do_refresh )
+{
+	if ( do_refresh )
+	{
+		set_commands_found() ;
+		load_lvm2_pv_info_cache() ;
+		lvm2_pv_info_cache_initialized = true ;
+	}
+}
+
+LVM2_PV_Info::~LVM2_PV_Info()
+{
+}
+
+bool LVM2_PV_Info::is_lvm2_pv_supported()
+{
+	if ( ! lvm2_pv_info_cache_initialized )
+		set_commands_found() ;
+	return ( lvm_found && dmsetup_found ) ;
+}
+
+Glib::ustring LVM2_PV_Info::get_vg_name( const Glib::ustring & path )
+{
+	initialize_if_required() ;
+	return get_pv_attr( path, PVATTR_VG_NAME ) ;
+}
+
+//Return number of free bytes in the PV, or -1 for error.
+Byte_Value LVM2_PV_Info::get_free_bytes( const Glib::ustring & path )
+{
+	initialize_if_required() ;
+	Byte_Value free_bytes = -1 ;
+	Glib::ustring fb_str = get_pv_attr( path, PVATTR_PV_FREE ) ;
+	if ( fb_str != "" )
+	{
+		gchar * suffix ;
+		free_bytes = (Byte_Value) g_ascii_strtoll( fb_str .c_str(), & suffix, 10 ) ;
+		if ( free_bytes < 0 || ( free_bytes == 0 && suffix == fb_str ) )
+			//Negative number or conversion failed
+			free_bytes = -1 ;
+	}
+	return free_bytes ;
+}
+
+//Report if any LVs are active in the VG stored in the PV.
+bool LVM2_PV_Info::has_active_lvs( const Glib::ustring & path )
+{
+	initialize_if_required() ;
+	Glib::ustring vgname = get_pv_attr( path, PVATTR_VG_NAME ) ;
+	if ( vgname == "" )
+		//PV not yet included in any VG
+		return false ;
+
+	Glib::ustring regexp = "^(" + vgname + ")-" ;
+	Glib::ustring match = Utils::regexp_label( dmsetup_info_cache, regexp ) ;
+	return ( match == vgname ) ;
+}
+
+//Private methods
+
+void LVM2_PV_Info::initialize_if_required()
+{
+	if ( ! lvm2_pv_info_cache_initialized )
+	{
+		set_commands_found() ;
+		load_lvm2_pv_info_cache() ;
+		lvm2_pv_info_cache_initialized = true ;
+	}
+}
+
+void LVM2_PV_Info::set_commands_found()
+{
+	//Set status of commands found
+	lvm_found = ( ! Glib::find_program_in_path( "lvm" ) .empty() ) ;
+	dmsetup_found = ( ! Glib::find_program_in_path( "dmsetup" ) .empty() ) ;
+}
+
+void LVM2_PV_Info::load_lvm2_pv_info_cache()
+{
+	Glib::ustring output, error ;
+
+	//Load LVM2 PV attribute cache
+	lvm2_pv_cache .clear() ;
+	if ( lvm_found )
+	{
+		//The OS is expected to fully enable LVM, this scan does
+		//  not do the full job.  It is included incase anything
+		//  is changed not using lvm commands.
+		Utils::execute_command( "lvm vgscan", output, error, true ) ;
+		//Output PV attributes, in PV_ATTRIBUTE order
+		if ( ! Utils::execute_command( "lvm pvs --config \"log{command_names=0}\" --nosuffix --noheadings --separator , --units b -o pv_name,vg_name,pv_free", output, error, true ) )
+		{
+			if ( output != "" )
+				Utils::tokenize( output, lvm2_pv_cache, " \n" ) ;
+		}
+	}
+
+	//Load dmsetup info cache.  This is a list of active LV names as
+	//reported by the kernel's device-mapper driver.
+	dmsetup_info_cache = "" ;
+	if ( dmsetup_found )
+	{
+		if ( ! Utils::execute_command( "dmsetup info --columns --noheadings --separator , -o name", output, error, true ) )
+		{
+			Glib::ustring match = Utils::regexp_label( output, "^(No devices found).*" ) ;
+			if ( match != "No devices found" )
+				dmsetup_info_cache = output ;
+		}
+	}
+}
+
+//Return PV's nth attribute.  Attributes are numbered 0 upwards for:
+//  pv_name,vg_name,pv_free
+Glib::ustring LVM2_PV_Info::get_pv_attr( const Glib::ustring & path, unsigned int entry )
+{
+	for ( unsigned int i = 0 ; i < lvm2_pv_cache .size() ; i ++ )
+	{
+		std::vector<Glib::ustring> pv_attrs ;
+		Utils::split( lvm2_pv_cache [i], pv_attrs, "," ) ;
+		if ( path == pv_attrs [PVATTR_PV_NAME] )
+		{
+			if ( entry < pv_attrs .size() )
+				return pv_attrs [entry] ;
+			else
+				break ;
+		}
+	}
+
+	return "" ;
+}
+
+}//GParted
diff --git a/src/Makefile.am b/src/Makefile.am
index d3b0b5d..785bc7c 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -31,6 +31,7 @@ gpartedbin_SOURCES = \
 	FS_Info.cc				\
 	GParted_Core.cc			\
 	HBoxOperations.cc		\
+	LVM2_PV_Info.cc			\
 	Operation.cc			\
 	OperationCopy.cc		\
 	OperationCheck.cc		\
@@ -57,6 +58,7 @@ gpartedbin_SOURCES = \
 	hfsplus.cc			\
 	jfs.cc				\
 	linux_swap.cc			\
+	lvm2_pv.cc			\
 	main.cc				\
 	nilfs2.cc			\
 	ntfs.cc				\
diff --git a/src/Partition.cc b/src/Partition.cc
index 882da8a..741243a 100644
--- a/src/Partition.cc
+++ b/src/Partition.cc
@@ -81,7 +81,7 @@ void Partition::Set(	const Glib::ustring & device_path,
 
 void Partition::Set_Unused( Sector sectors_unused )
 {
-	if ( sectors_unused < get_sector_length() )
+	if ( sectors_unused <= get_sector_length() )
 	{
 		this ->sectors_unused = sectors_unused ;
 		this ->sectors_used = ( sectors_unused == -1 ) ? -1 : get_sector_length() - sectors_unused ;
@@ -207,6 +207,14 @@ void Partition::sort_paths_and_remove_duplicates()
 	std::sort( paths .begin(), paths .end(), compare_paths ) ;
 }
 
+void Partition::add_mountpoint( const Glib::ustring & mountpoint, bool clear_mountpoints ) 
+{
+	if ( clear_mountpoints )
+		this ->mountpoints .clear() ;
+
+	this ->mountpoints .push_back( mountpoint ) ;
+}
+
 void Partition::add_mountpoints( const std::vector<Glib::ustring> & mountpoints, bool clear_mountpoints ) 
 {
 	if ( clear_mountpoints )
diff --git a/src/Utils.cc b/src/Utils.cc
index c257f73..0875600 100644
--- a/src/Utils.cc
+++ b/src/Utils.cc
@@ -91,7 +91,7 @@ Glib::ustring Utils::get_color( FILESYSTEM filesystem )
 		case FS_UFS			: return "#D1940C" ;	//accent yellow dark
 		case FS_USED		: return "#F8F8BA" ;	// ~ light tan yellow
 		case FS_UNUSED		: return "#FFFFFF" ;	//white
-		case FS_LVM2		: return "#CC9966" ;	// ~ medium brown
+		case FS_LVM2_PV		: return "#CC9966" ;	// ~ medium brown
 		case FS_LUKS		: return "#625B81" ;	//purple dark
 
 		default				: return "#000000" ;
@@ -158,7 +158,7 @@ Glib::ustring Utils::get_filesystem_string( FILESYSTEM filesystem )
 		case FS_UFS		: return "ufs" ;
 		case FS_USED		: return _("used") ;
 		case FS_UNUSED		: return _("unused") ;
-		case FS_LVM2		: return "lvm2" ;
+		case FS_LVM2_PV		: return "lvm2 pv" ;
 		case FS_LUKS		: return "crypt-luks" ;
 
 		default			: return "" ;
@@ -179,6 +179,7 @@ Glib::ustring Utils::get_filesystem_software( FILESYSTEM filesystem )
 		case FS_HFSPLUS     : return "hfsprogs" ;
 		case FS_JFS         : return "jfsutils" ;
 		case FS_LINUX_SWAP  : return "util-linux" ;
+		case FS_LVM2_PV     : return "lvm2" ;
 		case FS_NILFS2      : return "nilfs-utils" ;
 		case FS_NTFS        : return "ntfsprogs" ;
 		case FS_REISER4     : return "reiser4progs" ;
@@ -499,6 +500,30 @@ void Utils::tokenize( const Glib::ustring& str,
 	}
 }
 
+//Split string on every delimiter, appending to the vector.  Inspired by:
+//  http://stackoverflow.com/questions/236129/how-to-split-a-string-in-c/3616605#3616605
+//  E.g. using Utils::split(str, result, ":") for str -> result
+//  "" -> []   "a" -> ["a"]   "::" -> ["","",""]   ":a::bb" -> ["","a","","bb"]
+void Utils::split( const Glib::ustring& str,
+                   std::vector<Glib::ustring>& result,
+                   const Glib::ustring& delimiters     )
+{
+	//Special case zero length string to empty vector
+	if ( str == "" )
+		return ;
+	Glib::ustring::size_type fromPos  = 0 ;
+	Glib::ustring::size_type delimPos = str.find_first_of( delimiters );
+	while ( Glib::ustring::npos != delimPos )
+	{
+		Glib::ustring word( str, fromPos, delimPos - fromPos ) ;
+		result .push_back( word ) ;
+		fromPos = delimPos + 1 ;
+		delimPos = str.find_first_of( delimiters, fromPos ) ;
+	}
+	Glib::ustring word( str, fromPos ) ;
+	result. push_back( word ) ;
+}
+
 // Converts a Glib::ustring into a int
 int Utils::convert_to_int(const Glib::ustring & src)
 {
diff --git a/src/Win_GParted.cc b/src/Win_GParted.cc
index 0a92c62..60edf08 100644
--- a/src/Win_GParted.cc
+++ b/src/Win_GParted.cc
@@ -400,8 +400,8 @@ Gtk::Menu * Win_GParted::create_format_menu()
 	{
 		//Skip luks, lvm2, and unknown because these are not file systems
 		if (
-		     gparted_core .get_filesystems()[ t ] .filesystem == GParted::FS_LUKS ||
-		     gparted_core .get_filesystems()[ t ] .filesystem == GParted::FS_LVM2 ||
+		     gparted_core .get_filesystems()[ t ] .filesystem == GParted::FS_LUKS    ||
+		     gparted_core .get_filesystems()[ t ] .filesystem == GParted::FS_LVM2_PV ||
 		     gparted_core .get_filesystems()[ t ] .filesystem == GParted::FS_UNKNOWN
 		   )
 			continue ;
@@ -919,7 +919,8 @@ void Win_GParted::set_valid_operations()
 	//only unmount is allowed (if ! extended)
 	if ( selected_partition .busy )	
 	{
-		if ( selected_partition .type != GParted::TYPE_EXTENDED )
+		if ( selected_partition .type != GParted::TYPE_EXTENDED    &&
+		     selected_partition .filesystem != GParted::FS_LVM2_PV    )
 			allow_toggle_swap_mount_state( true ) ;
 
 		return ;
@@ -1017,7 +1018,11 @@ void Win_GParted::set_valid_operations()
 		if ( selected_partition .status == GParted::STAT_REAL && fs .write_label )
 			allow_label_partition( true ) ;
 
-		if ( selected_partition .get_mountpoints() .size() )
+		//Generate Mount on sub menu, except for LVM2 PVs
+		//  borrowing mount point to display the VGNAME
+		if (   selected_partition .filesystem != GParted::FS_LVM2_PV
+		    && selected_partition .get_mountpoints() .size()
+		   )
 		{
 			allow_toggle_swap_mount_state( true ) ;
 			
diff --git a/src/lvm2_pv.cc b/src/lvm2_pv.cc
new file mode 100644
index 0000000..b5c57a7
--- /dev/null
+++ b/src/lvm2_pv.cc
@@ -0,0 +1,87 @@
+/* Copyright (C) 2011 Mike Fleetwood
+ *
+ *  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 Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+ 
+ 
+#include "../include/LVM2_PV_Info.h"
+#include "../include/lvm2_pv.h"
+
+namespace GParted
+{
+
+FS lvm2_pv::get_filesystem_support()
+{
+	FS fs ;
+	fs .filesystem = GParted::FS_LVM2_PV ;
+
+	LVM2_PV_Info lvm2_pv_info ;
+	if ( lvm2_pv_info .is_lvm2_pv_supported() )
+	{
+		fs .read = GParted::FS::EXTERNAL ;
+	}
+
+	return fs ;
+}
+
+void lvm2_pv::set_used_sectors( Partition & partition ) 
+{
+	LVM2_PV_Info lvm2_pv_info ;
+	Byte_Value free_bytes = lvm2_pv_info .get_free_bytes( partition .get_path() ) ;
+	if ( free_bytes >= 0 )
+		partition .Set_Unused( Utils::round( double(free_bytes) / double(partition .sector_size) ) ) ;
+}
+
+void lvm2_pv::read_label( Partition & partition )
+{
+	return ;
+}
+
+bool lvm2_pv::write_label( const Partition & partition, OperationDetail & operationdetail )
+{
+	return true ;
+}
+
+bool lvm2_pv::create( const Partition & new_partition, OperationDetail & operationdetail )
+{
+	return true ;
+}
+
+bool lvm2_pv::resize( const Partition & partition_new, OperationDetail & operationdetail, bool fill_partition )
+{
+	return true ;
+}
+
+bool lvm2_pv::move( const Partition & partition_new
+                  , const Partition & partition_old
+                  , OperationDetail & operationdetail
+               )
+{
+	return true ;
+}
+
+bool lvm2_pv::copy( const Glib::ustring & src_part_path,
+		    const Glib::ustring & dest_part_path,
+		    OperationDetail & operationdetail )
+{
+	return true ;
+}
+
+bool lvm2_pv::check_repair( const Partition & partition, OperationDetail & operationdetail )
+{
+	return true ;
+}
+	
+} //GParted
