Fallback to reading mount command output instead of /etc/mtab (#723842)
With linux 3.5 and later, the device used to mount a btrfs file system
is updated in /proc/mounts when the previous mounting device is removed
from the file system. Most recent distributions make /etc/mtab a
symbolic link to /proc/mounts. However some still have /etc/mtab as a
plain file only updated by mount and umount, thus showing the old device
name which is no longer part of the file system.
On Ubuntu 13.10, which has /etc/mtab as a plain file managed by mount
and umount:
# mkfs.btrfs /dev/sdb1
# mount /dev/sdb1 /mnt/1
# btrfs device add /dev/sdb2 /mnt/1
# btrfs device delete /dev/sdb1 /mnt/1
# sync
# btrfs filesystem show /dev/sdb1
# btrfs filesystem show /dev/sdb2
Label: none uuid: e47775a6-e5ad-4fb4-9ea4-1570aa5b4009
Total devices 2 FS bytes used 28.00KB
devid 2 size 2.00GB used 272.00MB path /dev/sdb2
# fgrep btrfs /proc/mounts
/dev/sdb2 /mnt/1 btrfs rw,relatime,space_cache 0 0
# ls -l /etc/mtab
-rw-r--r-- 1 root root 842 Apr 15 19:41 /etc/mtab
# fgrep btrfs /etc/mtab
/dev/sdb1 /mnt/1 btrfs rw 0 0
This causes GParted to report /dev/sdb1 as busy and mounted at /mnt/1
when it is no longer mounted. This effects recent releases of Ubuntu,
13.04, 13.10 and 14.04.
Either /etc/mtab is a symlink and is identical to /proc/mounts or
/etc/mtab is a plain file with wrong information. Fix by not reading
mounted file systems from /etc/mtab.
However old distributions only contain 'rootfs' and '/dev/root' device
names for the / (root) file system with '/dev/root' being a block device
rather than a symlink to the true device. For example from CentOS 5.x:
# fgrep ' / ' /proc/mounts
rootfs / rootfs rw 0 0
/dev/root / ext3 rw,data=ordered 0 0
# ls -l /dev/root
brw------- 1 root root 8, 3 Jun 4 2013 /dev/root
This prevents identification, and therefore busy detection, of the
device containing the / (root) file system. Used to read /etc/mtab to
get the root file system device name.
# fgrep ' / ' /etc/mtab
/dev/sda3 / ext3 rw 0 0
# ls -l /dev/sda3
brw-r----- 1 root disk 8, 3 Jun 4 2013 /dev/sda3
As per commit:
409096f739
improved scanning for root mountpoint (/) ...
but, as discussed above, this contains an out of date device name after
the mounting device has been dynamically removed from a multi-device
btrfs, thus identifying the wrong device as busy. Instead fall back to
reading mounted file systems from the output of the mount command, but
only when required.
# mount | fgrep ' / '
/dev/sda3 on / type ext3 (rw)
Bug #723842 - GParted resizes the wrong filesystem (does not pass the
devid to btrfs filesystem resize)
This commit is contained in:
parent
d47783eff8
commit
4b63e46a4e
|
@ -70,11 +70,14 @@ private:
|
||||||
static void init_maps() ;
|
static void init_maps() ;
|
||||||
void set_thread_status_message( Glib::ustring msg ) ;
|
void set_thread_status_message( Glib::ustring msg ) ;
|
||||||
static void read_mountpoints_from_file( const Glib::ustring & filename,
|
static void read_mountpoints_from_file( const Glib::ustring & filename,
|
||||||
std::map< Glib::ustring,
|
std::map< Glib::ustring, std::vector<Glib::ustring> > & map ) ;
|
||||||
std::vector<Glib::ustring> > & map ) ;
|
static void add_node_and_mountpoint( std::map< Glib::ustring, std::vector<Glib::ustring> > & map,
|
||||||
|
Glib::ustring & node,
|
||||||
|
Glib::ustring & mountpoint ) ;
|
||||||
static void read_mountpoints_from_file_swaps( const Glib::ustring & filename,
|
static void read_mountpoints_from_file_swaps( const Glib::ustring & filename,
|
||||||
std::map< Glib::ustring,
|
std::map< Glib::ustring, std::vector<Glib::ustring> > & map ) ;
|
||||||
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 ) ;
|
||||||
Glib::ustring get_partition_path( PedPartition * lp_partition ) ;
|
Glib::ustring get_partition_path( PedPartition * lp_partition ) ;
|
||||||
void set_device_partitions( Device & device, PedDevice* lp_device, PedDisk* lp_disk ) ;
|
void set_device_partitions( Device & device, PedDevice* lp_device, PedDisk* lp_disk ) ;
|
||||||
GParted::FILESYSTEM get_filesystem( PedDevice* lp_device, PedPartition* lp_partition,
|
GParted::FILESYSTEM get_filesystem( PedDevice* lp_device, PedPartition* lp_partition,
|
||||||
|
|
|
@ -909,7 +909,20 @@ void GParted_Core::init_maps()
|
||||||
|
|
||||||
read_mountpoints_from_file( "/proc/mounts", mount_info ) ;
|
read_mountpoints_from_file( "/proc/mounts", mount_info ) ;
|
||||||
read_mountpoints_from_file_swaps( "/proc/swaps", mount_info ) ;
|
read_mountpoints_from_file_swaps( "/proc/swaps", mount_info ) ;
|
||||||
read_mountpoints_from_file( "/etc/mtab", mount_info ) ;
|
|
||||||
|
if ( ! have_rootfs_dev( mount_info ) )
|
||||||
|
//Old distributions only contain 'rootfs' and '/dev/root' device names for
|
||||||
|
// the / (root) file system in /proc/mounts with '/dev/root' being a
|
||||||
|
// block device rather than a symlink to the true device. This prevents
|
||||||
|
// identification, and therefore busy detection, of the device containing
|
||||||
|
// the / (root) file system. Used to read /etc/mtab to get the root file
|
||||||
|
// system device name, but this contains an out of date device name after
|
||||||
|
// the mounting device has been dynamically removed from a multi-device
|
||||||
|
// btrfs, thus identifying the wrong device as busy. Instead fall back
|
||||||
|
// to reading mounted file systems from the output of the mount command,
|
||||||
|
// but only when required.
|
||||||
|
read_mountpoints_from_mount_command( mount_info ) ;
|
||||||
|
|
||||||
read_mountpoints_from_file( "/etc/fstab", fstab_info ) ;
|
read_mountpoints_from_file( "/etc/fstab", fstab_info ) ;
|
||||||
|
|
||||||
//sort the mount points and remove duplicates.. (no need to do this for fstab_info)
|
//sort the mount points and remove duplicates.. (no need to do this for fstab_info)
|
||||||
|
@ -940,6 +953,7 @@ void GParted_Core::read_mountpoints_from_file(
|
||||||
while ( (p = getmntent(fp)) != NULL )
|
while ( (p = getmntent(fp)) != NULL )
|
||||||
{
|
{
|
||||||
Glib::ustring node = p->mnt_fsname ;
|
Glib::ustring node = p->mnt_fsname ;
|
||||||
|
Glib::ustring mountpoint = p->mnt_dir ;
|
||||||
|
|
||||||
Glib::ustring uuid = Utils::regexp_label( node, "^UUID=(.*)" ) ;
|
Glib::ustring uuid = Utils::regexp_label( node, "^UUID=(.*)" ) ;
|
||||||
if ( ! uuid .empty() )
|
if ( ! uuid .empty() )
|
||||||
|
@ -950,16 +964,24 @@ void GParted_Core::read_mountpoints_from_file(
|
||||||
node = fs_info .get_path_by_label( label ) ;
|
node = fs_info .get_path_by_label( label ) ;
|
||||||
|
|
||||||
if ( ! node .empty() )
|
if ( ! node .empty() )
|
||||||
{
|
add_node_and_mountpoint( map, node, mountpoint ) ;
|
||||||
Glib::ustring mountpoint = p->mnt_dir ;
|
}
|
||||||
|
|
||||||
|
endmntent( fp ) ;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GParted_Core::add_node_and_mountpoint(
|
||||||
|
std::map< Glib::ustring, std::vector<Glib::ustring> > & map,
|
||||||
|
Glib::ustring & node,
|
||||||
|
Glib::ustring & mountpoint )
|
||||||
|
{
|
||||||
//Only add node path(s) if mount point exists
|
//Only add node path(s) if mount point exists
|
||||||
if ( file_test( mountpoint, Glib::FILE_TEST_EXISTS ) )
|
if ( file_test( mountpoint, Glib::FILE_TEST_EXISTS ) )
|
||||||
{
|
{
|
||||||
map[ node ] .push_back( mountpoint ) ;
|
map[ node ] .push_back( mountpoint ) ;
|
||||||
|
|
||||||
//If node is a symbolic link (e.g., /dev/root)
|
//If node is a symbolic link (e.g., /dev/root)
|
||||||
// then find real path and add entry
|
// then find real path and add entry too
|
||||||
if ( file_test( node, Glib::FILE_TEST_IS_SYMLINK ) )
|
if ( file_test( node, Glib::FILE_TEST_IS_SYMLINK ) )
|
||||||
{
|
{
|
||||||
char c_str[4096+1] ;
|
char c_str[4096+1] ;
|
||||||
|
@ -968,10 +990,6 @@ void GParted_Core::read_mountpoints_from_file(
|
||||||
map[ c_str ] .push_back( mountpoint ) ;
|
map[ c_str ] .push_back( mountpoint ) ;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
endmntent( fp ) ;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GParted_Core::read_mountpoints_from_file_swaps(
|
void GParted_Core::read_mountpoints_from_file_swaps(
|
||||||
|
@ -994,6 +1012,42 @@ 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 )
|
||||||
|
{
|
||||||
|
std::map< Glib::ustring, std::vector<Glib::ustring> >::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" )
|
||||||
|
return true ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false ;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GParted_Core::read_mountpoints_from_mount_command(
|
||||||
|
std::map< Glib::ustring, std::vector<Glib::ustring> > & map )
|
||||||
|
{
|
||||||
|
Glib::ustring output ;
|
||||||
|
Glib::ustring error ;
|
||||||
|
if ( ! Utils::execute_command( "mount", output, error, true ) )
|
||||||
|
{
|
||||||
|
std::vector<Glib::ustring> lines ;
|
||||||
|
Utils::split( output, lines, "\n") ;
|
||||||
|
for ( unsigned int i = 0 ; i < lines .size() ; i ++ )
|
||||||
|
{
|
||||||
|
//Process line like "/dev/sda3 on / type ext4 (rw)"
|
||||||
|
Glib::ustring node = Utils::regexp_label( lines[ i ], "^([^[:blank:]]+) on " ) ;
|
||||||
|
Glib::ustring mountpoint = Utils::regexp_label( lines[ i ], "^[^[:blank:]]+ on ([^[:blank:]]+) " ) ;
|
||||||
|
if ( ! node .empty() )
|
||||||
|
add_node_and_mountpoint( map, node, mountpoint ) ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Glib::ustring GParted_Core::get_partition_path( PedPartition * lp_partition )
|
Glib::ustring GParted_Core::get_partition_path( PedPartition * lp_partition )
|
||||||
{
|
{
|
||||||
char * lp_path; //we have to free the result of ped_partition_get_path()
|
char * lp_path; //we have to free the result of ped_partition_get_path()
|
||||||
|
|
Loading…
Reference in New Issue