Add BlockSpecial into mount_info and fstab_info (#767842)

On some distributions having btrfs on top of LUKS encrypted partitions,
adding a second device and removing the first device used to mount the
file system causes GParted to no longer be able to report the file
system as busy or the mount points themselves.

For example, on CentOS 7, create a single btrfs file system and mount
it.  The provided /dev/mapper/sdb1_crypt name is reported, via
/proc/mounts, as the mounting device:
    # cryptsetup luksFormat --force-password /dev/sdb1
    # cryptsetup luksOpen /dev/sdb1 sdb1_crypt
    # mkfs.btrfs -L encrypted-btrfs /dev/mapper/sdb1_crypt
    # mount /dev/mapper/sdb1_crypt /mnt/1

    # ls -l /dev/mapper
    total 0
    lrwxrwxrwx. 1 root root       7 Jul  2 14:15 centos-root -> ../dm-1
    lrwxrwxrwx. 1 root root       7 Jul  2 14:15 centos-swap -> ../dm-0
    crw-------. 1 root root 10, 236 Jul  2 14:15 control
    lrwxrwxrwx. 1 root root       7 Jul  2 15:14 sdb1_crypt -> ../dm-2
    # fgrep btrfs /proc/mounts
    /dev/mapper/sdb1_crypt /mnt/1 btrfs rw,seclabel,relatime,space_cache 0 0

Add a second device to the btrfs file system:
    # cryptsetup luksFormat --force-password /dev/sdb2
    # cryptsetup luksOpen /dev/sdb2 sdb2_crypt
    # btrfs device add /dev/mapper/sdb2_crypt /mnt/1

    # ls -l /dev/mapper
    ...
    lrwxrwxrwx. 1 root root       7 Jul  2 15:12 sdb2_crypt -> ../dm-3
    # btrfs filesystem show /dev/mapper/sdb1_crypt
    Label: 'encrypted-btrfs'  uuid: 45d7b1ef-820c-4ef8-8abd-c70d928afb49
            Total devices 2 FS bytes used 32.00KiB
            devid    1 size 1022.00MiB used 12.00MiB path /dev/mapper/sdb1_crypt
            devid    2 size 1022.00MiB used 0.00B path /dev/mapper/sdb2_crypt

Remove the first mounting device from the btrfs file system.  Now the
non-canonical name /dev/dm-3 is reported, via /proc/mounts, as the
mounting device:
    # btrfs device delete /dev/mapper/sdb1_crypt /mnt/1

    # btrfs filesystem show /dev/mapper/sdb2_crypt
    Label: 'encrypted-btrfs'  uuid: 45d7b1ef-820c-4ef8-8abd-c70d928afb49
            Total devices 1 FS bytes used 96.00KiB
            devid    2 size 1022.00MiB used 144.00MiB path /dev/mapper/sdb2_crypt
    # fgrep btrfs /proc/mounts
    /dev/dm-3 /mnt/1 btrfs rw,seclabel,relatime,space_cache 0 0
    # ls -l /dev/dm-3
    brw-rw----. 1 root disk 253, 3 Jul  2 15:12 /dev/dm-3

GParted loads the mount_info mapping from /proc/mounts and with it the
/dev/dm-3 name.  When GParted is determining if the encrypted btrfs file
system is mounted or getting the mount points it is using the
/dev/mapper/sdb2_crypt name.  Therefore no information is found and the
file system is incorrectly reported as unmounted.

Fix by changing mount_info and fstab_info to use BlockSpecial objects
instead of strings so that matching is performed by major, minor device
numbers rather than by string compare.  Note that as BlockSpecial
objects are used as the key of std::map [1] mappings operator<() [2]
needs to be provided to order the key values.

[1] std::map
    http://www.cplusplus.com/reference/map/map/
[2] std::map::key_comp
    http://www.cplusplus.com/reference/map/map/key_comp/

Bug 767842 - File system usage missing when tools report alternate block
             device names
This commit is contained in:
Mike Fleetwood 2016-06-25 08:29:17 +01:00 committed by Curtis Gedak
parent ab2d4f5ee6
commit a800ca8b68
4 changed files with 51 additions and 41 deletions

View File

@ -48,6 +48,7 @@ public:
// "2. If a binary operator treats both operands equally (it leaves them unchanged),
// implement this operator as a non-member function."
bool operator==( const BlockSpecial & lhs, const BlockSpecial & rhs );
bool operator<( const BlockSpecial & lhs, const BlockSpecial & rhs );
}//GParted

View File

@ -18,6 +18,7 @@
#ifndef GPARTED_GPARTED_CORE_H
#define GPARTED_GPARTED_CORE_H
#include "../include/BlockSpecial.h"
#include "../include/FileSystem.h"
#include "../include/Operation.h"
#include "../include/Partition.h"
@ -75,19 +76,20 @@ public:
Byte_Value sector_size,
bool inside_extended );
typedef std::map<BlockSpecial, std::vector<Glib::ustring> > MountMapping;
private:
//detectionstuff..
static void init_maps() ;
void set_thread_status_message( Glib::ustring msg ) ;
static void read_mountpoints_from_file( const Glib::ustring & filename,
std::map< Glib::ustring, std::vector<Glib::ustring> > & map ) ;
static void add_node_and_mountpoint( std::map< Glib::ustring, std::vector<Glib::ustring> > & map,
static void read_mountpoints_from_file( const Glib::ustring & filename, MountMapping & map );
static void add_node_and_mountpoint( MountMapping & map,
Glib::ustring & node,
Glib::ustring & mountpoint ) ;
static void read_mountpoints_from_file_swaps( const Glib::ustring & filename,
std::map< Glib::ustring, std::vector<Glib::ustring> > & map ) ;
static bool have_rootfs_dev( std::map< Glib::ustring, std::vector<Glib::ustring> > & map ) ;
static void read_mountpoints_from_mount_command( std::map< Glib::ustring, std::vector<Glib::ustring> > & map ) ;
MountMapping & map );
static bool have_rootfs_dev( MountMapping & map );
static void read_mountpoints_from_mount_command( MountMapping & map );
static Glib::ustring get_partition_path( PedPartition * lp_partition );
void set_device_serial_number( Device & device );
void set_device_partitions( Device & device, PedDevice* lp_device, PedDisk* lp_disk ) ;

View File

@ -52,4 +52,14 @@ bool operator==( const BlockSpecial & lhs, const BlockSpecial & rhs )
return lhs.m_name == rhs.m_name;
}
bool operator<( const BlockSpecial & lhs, const BlockSpecial & rhs )
{
if ( lhs.m_major == 0 && rhs.m_major == 0 && lhs.m_minor == 0 && rhs.m_minor == 0 )
// Two non-block special files are ordered by name.
return lhs.m_name < rhs.m_name;
else
// Block special files are ordered by major, minor device numbers.
return lhs.m_major < rhs.m_major || ( lhs.m_major == rhs.m_major && lhs.m_minor < rhs.m_minor );
}
} //GParted

View File

@ -17,6 +17,7 @@
#include "../include/Win_GParted.h"
#include "../include/GParted_Core.h"
#include "../include/BlockSpecial.h"
#include "../include/DMRaid.h"
#include "../include/FS_Info.h"
#include "../include/LVM2_PV_Info.h"
@ -69,17 +70,18 @@ namespace GParted
const std::time_t SETTLE_DEVICE_PROBE_MAX_WAIT_SECONDS = 1;
const std::time_t SETTLE_DEVICE_APPLY_MAX_WAIT_SECONDS = 10;
//mount_info - Associative array mapping currently mounted devices to
// one or more mount points. E.g.
// mount_info["/dev/sda1"] -> ["/boot"]
// mount_info["/dev/sda2"] -> [""] (swap)
// mount_info["/dev/sda3"] -> ["/"]
//fstab_info - Associative array mapping configured devices to one or
// more mount points read from /etc/fstab. E.g.
// fstab_info["/dev/sda1"] -> ["/boot"]
// fstab_info["/dev/sda3"] -> ["/"]
static std::map< Glib::ustring, std::vector<Glib::ustring> > mount_info ;
static std::map< Glib::ustring, std::vector<Glib::ustring> > fstab_info ;
// Associative array mapping currently mounted devices to one or more mount points.
// E.g.
// mount_info[BlockSpecial("/dev/sda1")] -> ["/boot"]
// mount_info[BlockSpecial("/dev/sda2")] -> [""] (swap)
// mount_info[BlockSpecial("/dev/sda3")] -> ["/"]
static GParted_Core::MountMapping mount_info;
// Associative array mapping configured devices to one or more mount points read from
// /etc/fstab. E.g.
// fstab_info[BlockSpecial("/dev/sda1")] -> ["/boot"]
// fstab_info[BlockSpecial("/dev/sda3")] -> ["/"]
static GParted_Core::MountMapping fstab_info;
static bool udevadm_found = false;
static bool udevsettle_found = false;
@ -968,13 +970,13 @@ std::vector<Glib::ustring> GParted_Core::get_disklabeltypes()
//Return whether the device path, such as /dev/sda3, is mounted or not
bool GParted_Core::is_dev_mounted( const Glib::ustring & path )
{
std::map< Glib::ustring, std::vector<Glib::ustring> >::iterator iter_mp = mount_info .find( path ) ;
MountMapping::iterator iter_mp = mount_info.find( BlockSpecial( path ) );
return iter_mp != mount_info .end() ;
}
std::vector<Glib::ustring> GParted_Core::get_all_mountpoints()
{
std::map< Glib::ustring, std::vector<Glib::ustring> >::iterator iter_mp ;
MountMapping::iterator iter_mp;
std::vector<Glib::ustring> mountpoints ;
for ( iter_mp = mount_info .begin() ; iter_mp != mount_info .end() ; ++iter_mp )
@ -1042,7 +1044,7 @@ void GParted_Core::init_maps()
read_mountpoints_from_file( "/etc/fstab", fstab_info ) ;
//sort the mount points and remove duplicates.. (no need to do this for fstab_info)
std::map< Glib::ustring, std::vector<Glib::ustring> >::iterator iter_mp ;
MountMapping::iterator iter_mp;
for ( iter_mp = mount_info .begin() ; iter_mp != mount_info .end() ; ++iter_mp )
{
std::sort( iter_mp ->second .begin(), iter_mp ->second .end() ) ;
@ -1053,9 +1055,7 @@ void GParted_Core::init_maps()
}
}
void GParted_Core::read_mountpoints_from_file(
const Glib::ustring & filename,
std::map< Glib::ustring, std::vector<Glib::ustring> > & map )
void GParted_Core::read_mountpoints_from_file( const Glib::ustring & filename, MountMapping & map )
{
FS_Info fs_info ; //Use cache of file system information
@ -1086,15 +1086,14 @@ void GParted_Core::read_mountpoints_from_file(
endmntent( fp ) ;
}
void GParted_Core::add_node_and_mountpoint(
std::map< Glib::ustring, std::vector<Glib::ustring> > & map,
Glib::ustring & node,
Glib::ustring & mountpoint )
void GParted_Core::add_node_and_mountpoint( MountMapping & map,
Glib::ustring & node,
Glib::ustring & mountpoint )
{
//Only add node path(s) if mount point exists
if ( file_test( mountpoint, Glib::FILE_TEST_EXISTS ) )
{
map[ node ] .push_back( mountpoint ) ;
map[BlockSpecial( node )].push_back( mountpoint );
//If node is a symbolic link (e.g., /dev/root)
// then find real path and add entry too
@ -1103,16 +1102,15 @@ void GParted_Core::add_node_and_mountpoint(
char * rpath = realpath( node.c_str(), NULL );
if ( rpath != NULL )
{
map[rpath].push_back( mountpoint );
map[BlockSpecial( rpath )].push_back( mountpoint );
free( rpath );
}
}
}
}
void GParted_Core::read_mountpoints_from_file_swaps(
const Glib::ustring & filename,
std::map< Glib::ustring, std::vector<Glib::ustring> > & map )
void GParted_Core::read_mountpoints_from_file_swaps( const Glib::ustring & filename,
MountMapping & map )
{
std::string line ;
std::string node ;
@ -1124,7 +1122,7 @@ void GParted_Core::read_mountpoints_from_file_swaps(
{
node = Utils::regexp_label( line, "^(/[^ ]+)" ) ;
if ( node .size() > 0 )
map[ node ] .push_back( "" /* no mountpoint for swap */ ) ;
map[BlockSpecial( node )].push_back( "" /* no mountpoint for swap */ );
}
file .close() ;
}
@ -1132,22 +1130,21 @@ void GParted_Core::read_mountpoints_from_file_swaps(
//Return true only if the map contains a device name for the / (root) file system other
// than 'rootfs' and '/dev/root'
bool GParted_Core::have_rootfs_dev( std::map< Glib::ustring, std::vector<Glib::ustring> > & map )
bool GParted_Core::have_rootfs_dev( MountMapping & map )
{
std::map< Glib::ustring, std::vector<Glib::ustring> >::iterator iter_mp ;
MountMapping::iterator iter_mp;
for ( iter_mp = mount_info .begin() ; iter_mp != mount_info .end() ; iter_mp ++ )
{
if ( ! iter_mp ->second .empty() && iter_mp ->second[ 0 ] == "/" )
{
if ( iter_mp ->first != "rootfs" && iter_mp ->first != "/dev/root" )
if ( iter_mp->first.m_name != "rootfs" && iter_mp->first.m_name != "/dev/root" )
return true ;
}
}
return false ;
}
void GParted_Core::read_mountpoints_from_mount_command(
std::map< Glib::ustring, std::vector<Glib::ustring> > & map )
void GParted_Core::read_mountpoints_from_mount_command( MountMapping & map )
{
Glib::ustring output ;
Glib::ustring error ;
@ -1870,8 +1867,8 @@ void GParted_Core::set_mountpoints( Partition & partition )
}
else // Not busy file system
{
std::map< Glib::ustring, std::vector<Glib::ustring> >::iterator iter_mp;
iter_mp = fstab_info.find( partition.get_path() );
MountMapping::iterator iter_mp;
iter_mp = fstab_info.find( BlockSpecial( partition.get_path() ) );
if ( iter_mp != fstab_info.end() )
partition.add_mountpoints( iter_mp->second );
}
@ -1886,7 +1883,7 @@ bool GParted_Core::set_mountpoints_helper( Partition & partition, const Glib::us
else
search_path = path ;
std::map< Glib::ustring, std::vector<Glib::ustring> >::iterator iter_mp = mount_info .find( search_path ) ;
MountMapping::iterator iter_mp = mount_info.find( BlockSpecial( search_path ) );
if ( iter_mp != mount_info .end() )
{
partition .add_mountpoints( iter_mp ->second ) ;