Pass device and partition names to blkid (#131)

A user reported that GParted would hang at "scanning all devices...",
when a fully working disk was named on the command line, but another
device on the machine was hung.

This can be replicated like this:
(on Ubuntu 20.04 LTS for it's NBD support)

1. Export and import NBD:
    # truncate -s 1G /tmp/disk-1G.img
    # nbd-server -C /dev/null 9000 /tmp/disk-1G.img
    # nbd-client localhost 9000 /dev/nbd0

2. Hang the NBD server and therefore /dev/nbd0:
    # killall -STOP nbd-server

3. Run GParted:
    $ gparted /dev/sda

Tracing GParted shows that execution of blkid never returns.

    # strace -f -tt -q -bexecve -eexecve ./gpartedbin 2>&1 1> /dev/null | fgrep -v ENOENT
    ...
    [pid 37823] 13:56:24.814139 execve("/usr/sbin/mkudffs", ["mkudffs", "--help"], 0x55e2a3f2d230 /* 20 vars */ <detached ...>
    [pid 37814] 13:56:24.829246 --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=37823, si_uid=0, si_status=1, si_utime=0, si_stime=0} ---
    [pid 37825] 13:56:25.376796 execve("/usr/sbin/blkid", ["blkid", "-v"], 0x55e2a3f2d230 /* 20 vars */ <detached ...>
    [pid 37824] 13:56:25.380824 --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=37825, si_uid=0, si_status=0, si_utime=0, si_stime=0} ---
    [pid 37826] 13:56:25.402512 execve("/usr/sbin/blkid", ["blkid"], 0x55e2a3f2d230 /* 20 vars */ <detached ...>

Tracking of blkid shows that it hangs on either the open of or first
read from /dev/nbd0.

    # strace blkid
    ...
    lstat("/dev", {st_mode=S_IFDIR|0755, st_size=4560, ...}) = 0
    lstat("/dev/nbd0", {st_mode=S_IFBLK|0660, st_rdev=makedev(0x2b, 0), ...}) = 0
    stat("/dev/nbd0", {st_mode=S_IFBLK|0660, st_rdev=makedev(0x2b, 0), ...}) = 0
    lstat("/dev", {st_mode=S_IFDIR|0755, st_size=4560, ...}) = 0
    lstat("/dev/nbd0", {st_mode=S_IFBLK|0660, st_rdev=makedev(0x2b, 0), ...}) = 0
    access("/dev/nbd0", F_OK)               = 0
    stat("/dev/nbd0", {st_mode=S_IFBLK|0660, st_rdev=makedev(0x2b, 0), ...}) = 0
    openat(AT_FDCWD, "/sys/dev/block/43:0", O_RDONLY|O_CLOEXEC) = 4
    openat(4, "dm/uuid", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
    close(4)                                = 0
    openat(AT_FDCWD, "/dev/nbd0", O_RDONLY|O_CLOEXEC

Clean up:

1. Resume NBD server:
    # killall -CONT nbd-server

2. Delete NBD setup:
    # nbd-client -d /dev/nbd0
    # killall nbd-server
    # rm /tmp/disk-1G.img

Fix this by making GParted specify the whole disk device and partition
names that it is interested in to blkid, rather than letting blkid scan
and report all block devices.  Do this both when GParted determines the
devices for itself and when they are named on the command line.

Also update example blkid command output being parsed and cache value
with this change to how blkid is executed.

Closes #131 - GParted hangs when non-named device is hung
This commit is contained in:
Mike Fleetwood 2021-01-24 14:33:04 +00:00 committed by Curtis Gedak
parent 75bda733bb
commit 8b35892ea5
3 changed files with 34 additions and 39 deletions

View file

@ -38,7 +38,7 @@ struct FS_Entry
class FS_Info
{
public:
static void load_cache_for_paths( const std::vector<Glib::ustring> &device_paths );
static void load_cache_for_paths(const std::vector<Glib::ustring>& paths);
static Glib::ustring get_fs_type( const Glib::ustring & path );
static Glib::ustring get_label( const Glib::ustring & path, bool & found );
static Glib::ustring get_uuid( const Glib::ustring & path );
@ -49,9 +49,9 @@ private:
static void initialize_if_required();
static void set_commands_found();
static const FS_Entry & get_cache_entry_by_path( const Glib::ustring & path );
static void load_fs_info_cache();
static void load_fs_info_cache(const std::vector<Glib::ustring>& paths);
static void load_fs_info_cache_extra_for_path( const Glib::ustring & path );
static bool run_blkid_load_cache( const Glib::ustring & path = "" );
static bool run_blkid_load_cache(const std::vector<Glib::ustring>& paths);
static void update_fs_info_cache_all_labels();
static bool run_blkid_update_cache_one_label( FS_Entry & fs_entry );

View file

@ -37,33 +37,32 @@ bool FS_Info::need_blkid_vfat_cache_update_workaround = true;
// Vector of file system information.
// E.g.
// (Note BS(path) is a short hand for constructor BlockSpecial(path)).
// //path , type , sec_type, uuid , have_label, label
// [{BS("/dev/sda1") , "xfs" , "" , "f828ee8c-1e16-4ca9-b234-e4949dcd4bd1" , false , "" },
// {BS("/dev/sda2") , "LVM2_member", "" , "p31pR5-qPLm-YICz-O09i-sB4u-mAH2-GVSNWG", false , "" },
// {BS("/dev/block/8:2") , "LVM2_member", "" , "p31pR5-qPLm-YICz-O09i-sB4u-mAH2-GVSNWG", false , "" },
// {BS("/dev/mapper/centos-root"), "xfs" , "" , "a195605d-22c1-422d-9213-1ed67f1eee46" , false , "" },
// {BS("/dev/mapper/centos-swap"), "swap" , "" , "8d419cb6-c663-4db7-b91c-6bcef8418a4d" , false , "" },
// {BS("/dev/sdb1") , "ext3" , "ext2" , "f218c3b8-237e-4fbe-92c5-76623bba4062" , true , "test-ext3" },
// {BS("/dev/sdb2") , "vfat" , "msdos" , "9F87-1061" , true , "TEST-FAT16"},
// {BS("/dev/sdb3") , "" , "" , "" , false , "" }
// //path , type , sec_type, uuid , have_label, label
// [{BS("/dev/sda") , "" , "" , "" , false , "" },
// {BS("/dev/sda1"), "xfs" , "" , "f828ee8c-1e16-4ca9-b234-e4949dcd4bd1" , false , "" },
// {BS("/dev/sda2"), "LVM2_member", "" , "p31pR5-qPLm-YICz-O09i-sB4u-mAH2-GVSNWG", false , "" },
// {BS("/dev/sdb") , "" , "" , "" , false , "" },
// {BS("/dev/sdb1"), "ext3" , "ext2" , "f218c3b8-237e-4fbe-92c5-76623bba4062" , true , "test-ext3" },
// {BS("/dev/sdb2"), "vfat" , "msdos" , "9F87-1061" , true , "TEST-FAT16"},
// {BS("/dev/sdb3"), "" , "" , "" , false , "" }
// ]
std::vector<FS_Entry> FS_Info::fs_info_cache;
void FS_Info::load_cache_for_paths( const std::vector<Glib::ustring> &device_paths )
void FS_Info::load_cache_for_paths(const std::vector<Glib::ustring>& paths)
{
set_commands_found();
load_fs_info_cache();
load_fs_info_cache(paths);
fs_info_cache_initialized = true;
const BlockSpecial empty_bs = BlockSpecial();
for ( unsigned int i = 0 ; i < device_paths.size() ; i ++ )
for (unsigned int i = 0; i < paths.size(); i++)
{
const FS_Entry & fs_entry = get_cache_entry_by_path( device_paths[i] );
const FS_Entry& fs_entry = get_cache_entry_by_path(paths[i]);
if ( fs_entry.path == empty_bs )
{
// Run "blkid PATH" and load entry into cache for missing entries.
load_fs_info_cache_extra_for_path( device_paths[i] );
load_fs_info_cache_extra_for_path(paths[i]);
}
}
}
@ -165,7 +164,8 @@ void FS_Info::initialize_if_required()
if ( ! fs_info_cache_initialized )
{
set_commands_found();
load_fs_info_cache();
std::vector<Glib::ustring> empty;
load_fs_info_cache(empty);
fs_info_cache_initialized = true;
}
}
@ -204,11 +204,12 @@ const FS_Entry & FS_Info::get_cache_entry_by_path( const Glib::ustring & path )
return not_found;
}
void FS_Info::load_fs_info_cache()
void FS_Info::load_fs_info_cache(const std::vector<Glib::ustring>& paths)
{
fs_info_cache.clear();
// Run "blkid" and load entries into the cache.
run_blkid_load_cache();
run_blkid_load_cache(paths);
// (#771244) Ensure the cache has entries for all whole disk devices, even if
// those entries are blank. Needed so that an ISO9660 image stored on a whole
@ -228,7 +229,9 @@ void FS_Info::load_fs_info_cache()
void FS_Info::load_fs_info_cache_extra_for_path( const Glib::ustring & path )
{
bool entry_added = run_blkid_load_cache( path );
std::vector<Glib::ustring> one_path;
one_path.push_back(path);
bool entry_added = run_blkid_load_cache(one_path);
if ( ! entry_added )
{
// Ran "blkid PATH" but didn't find details suitable for loading as a
@ -238,17 +241,19 @@ void FS_Info::load_fs_info_cache_extra_for_path( const Glib::ustring & path )
}
}
bool FS_Info::run_blkid_load_cache( const Glib::ustring & path )
bool FS_Info::run_blkid_load_cache(const std::vector<Glib::ustring>& paths)
{
// Parse blkid output line by line extracting mandatory field: path and optional
// fields: type, sec_type, uuid. Label is not extracted here because of blkid's
// default non-reversible encoding of non printable ASCII bytes.
// Example command:
// blkid /dev/sda /dev/sda1 /dev/sda2 /dev/sdb /dev/sdb1 /dev/sdb2 /dev/sdb3
// Example output:
// /dev/sda: PTUUID="5012fb1f" PTTYPE="dos"
// /dev/sda1: UUID="f828ee8c-1e16-4ca9-b234-e4949dcd4bd1" TYPE="xfs"
// /dev/sda2: UUID="p31pR5-qPLm-YICz-O09i-sB4u-mAH2-GVSNWG" TYPE="LVM2_member"
// /dev/block/8:2: UUID="p31pR5-qPLm-YICz-O09i-sB4u-mAH2-GVSNWG" TYPE="LVM2_member"
// /dev/mapper/centos-root: UUID="a195605d-22c1-422d-9213-1ed67f1eee46" TYPE="xfs"
// /dev/mapper/centos-swap: UUID="8d419cb6-c663-4db7-b91c-6bcef8418a4d" TYPE="swap"
// /dev/sdb: PTUUID="f57595e1-c0ae-40ee-be64-00851b2a9977" PTTYPE="gpt"
// /dev/sdb1: LABEL="test-ext3" UUID="f218c3b8-237e-4fbe-92c5-76623bba4062" SEC_TYPE="ext2" TYPE="ext3" PARTUUID="71b3e059-30c5-492e-a526-9251dff7bbeb"
// /dev/sdb2: SEC_TYPE="msdos" LABEL="TEST-FAT16" UUID="9F87-1061" TYPE="vfat" PARTUUID="9d07ad9a-d468-428f-9bfd-724f5efae4fb"
// /dev/sdb3: PARTUUID="bb8438e1-d9f1-45d3-9888-e990b598900d"
@ -257,8 +262,8 @@ bool FS_Info::run_blkid_load_cache( const Glib::ustring & path )
return false;
Glib::ustring cmd = "blkid";
if ( path.size() )
cmd = cmd + " " + Glib::shell_quote( path );
for (unsigned int i = 0; i < paths.size(); i++)
cmd.append(" " + Glib::shell_quote(paths[i]));
Glib::ustring output;
Glib::ustring error;

View file

@ -247,20 +247,10 @@ void GParted_Core::set_devices_thread( std::vector<Device> * pdevices )
}
}
std::cout << "DEBUG: device_paths=[";
for (unsigned int i = 0; i < device_paths.size(); i++)
std::cout << (i>0?",":"") << "\"" << device_paths[i] << "\"";
std::cout << "]" << std::endl;
// Initialise and load caches needed for content discovery.
const std::vector<Glib::ustring>& device_and_partition_paths =
Proc_Partitions_Info::get_device_and_partition_paths_for(device_paths);
std::cout << "DEBUG: device_and_partition_paths=[";
for (unsigned int i = 0; i < device_and_partition_paths.size(); i++)
std::cout << (i>0?",":"") << "\"" << device_and_partition_paths[i] << "\"";
std::cout << "]" << std::endl;
// Initialise and load caches needed for content discovery.
FS_Info::load_cache_for_paths(device_paths);
FS_Info::load_cache_for_paths(device_and_partition_paths);
Mount_Info::load_cache();
LVM2_PV_Info::clear_cache();
btrfs::clear_cache();