Detect busy status of dmraid started ATARAID members (#75)

Again this is to stop GParted allowing overwrite operations being
performed on an ATARAID member while the array is actively using the
member.  This time for dmraid started arrays using the kernel DM (Device
Mapper) driver.

The DMRaid module already uses dmraid to report active array names:

    # dmraid -sa -c
    isw_ecccdhhiga_MyArray

To find active members in this array, (1) use udev to lookup the kernel
device name:

    # udevadm info --query=name /dev/mapper/isw_ecccdhhiga_MyArray
    dm-0

(2) list the member names exposed by the kernel DM driver through the
/sys file system.

    # ls /sys/block/dm-0/slaves
    sdc  sdd
    # ls -l /sys/block/dm-0/slaves
    lrwxrwxrwx 1 root root 0 Nov 24 09:52 sdc -> ../../../../pci0000:00/0000:00:0d.0/ata3/host2/target2:0:0/2:0:0:0/block/sdc
    lrwxrwxrwx 1 root root 0 Nov 24 09:52 sdc -> ../../../../pci0000:00/0000:00:0d.0/ata4/host3/target3:0:0/3:0:0:0/block/sdd

Closes #75 - Errors with GPT on RAID 0 ATARAID array
This commit is contained in:
Mike Fleetwood 2019-11-24 13:15:22 +00:00 committed by Curtis Gedak
parent 425dfa3709
commit caec22871e
3 changed files with 91 additions and 2 deletions

View File

@ -27,11 +27,14 @@
#define GPARTED_DMRAID_H
#include "Utils.h"
#include "BlockSpecial.h"
#include "Partition.h"
#include "OperationDetail.h"
#include <glibmm/ustring.h>
#include <vector>
namespace GParted
{
@ -56,17 +59,22 @@ public:
bool delete_dev_map_entry( const Partition & partition, OperationDetail & operationdetail ) ;
bool purge_dev_map_entries( const Glib::ustring & dev_path ) ;
bool update_dev_map_entry( const Partition & partition, OperationDetail & operationdetail ) ;
bool is_member_active(const Glib::ustring& member_path);
private:
void load_dmraid_cache() ;
void set_commands_found() ;
void get_dmraid_dir_entries( const Glib::ustring & dev_path, std::vector<Glib::ustring> & dir_list ) ;
void get_affected_dev_map_entries( const Partition & partition, std::vector<Glib::ustring> & affected_entries ) ;
void get_partition_dev_map_entries( const Partition & partition, std::vector<Glib::ustring> & partition_entries ) ;
static std::vector<Glib::ustring> lookup_dmraid_members(const Glib::ustring& array);
static bool dmraid_cache_initialized ;
static bool dmraid_found ;
static bool dmsetup_found ;
static bool udevadm_found ;
static std::vector<Glib::ustring> dmraid_devices ;
static std::vector<BlockSpecial> dmraid_member_cache;
};
}//GParted

View File

@ -15,7 +15,9 @@
*/
#include "DMRaid.h"
#include "BlockSpecial.h"
#include "Partition.h"
#include "Utils.h"
#include <limits.h>
#include <stdlib.h> //atoi function
@ -28,12 +30,26 @@
namespace GParted
{
// Data model:
// dmraid_cache_initialized - Has the cache been loaded?
// dmraid_found - Is the "dmraid" command available?
// dmsetup_found - Is the "dmsetup" command available?
// udevadm_found - Is the "udevadm" command available?
// dmraid_devices - Vector of active array names.
// E.g.
// ["isw_ecccdhhiga_MyArray"]
// dmraid_member_cache - Vector of members of active DMRaid arrays.
// E.g.
// [BlockSpecial("/dev/sdc"), BlockSpecial("/dev/sdd")]
//Initialize static data elements
bool DMRaid::dmraid_cache_initialized = false ;
bool DMRaid::dmraid_found = false ;
bool DMRaid::dmsetup_found = false ;
bool DMRaid::udevadm_found = false ;
std::vector<Glib::ustring> DMRaid::dmraid_devices ;
std::vector<BlockSpecial> DMRaid::dmraid_member_cache;
DMRaid::DMRaid()
{
@ -67,10 +83,11 @@ DMRaid::~DMRaid()
void DMRaid::load_dmraid_cache()
{
//Load data into dmraid structures
Glib::ustring output, error ;
dmraid_devices .clear() ;
dmraid_member_cache.clear();
// Load active DMRaid array names.
if ( dmraid_found )
{
if ( ! Utils::execute_command( "dmraid -sa -c", output, error, true ) )
@ -79,8 +96,17 @@ void DMRaid::load_dmraid_cache()
Utils::tokenize( output, dmraid_devices, "\n" ) ;
}
}
// Load members of active DMRaid arrays.
for (unsigned int i = 0; i < dmraid_devices.size(); i++)
{
std::vector<Glib::ustring> members = lookup_dmraid_members(DEV_MAPPER_PATH + dmraid_devices[i]);
for (unsigned int j = 0; j < members.size(); j++)
dmraid_member_cache.push_back(BlockSpecial(members[j]));
}
}
void DMRaid::set_commands_found()
{
//Set status of commands found
@ -492,4 +518,56 @@ bool DMRaid::update_dev_map_entry( const Partition & partition, OperationDetail
return exit_status ;
}
// Return whether the named device (e.g. "/dev/sdc") is a member of an active DMRaid array
// or not.
bool DMRaid::is_member_active(const Glib::ustring& member_path)
{
BlockSpecial bs = BlockSpecial(member_path);
for (unsigned int i = 0; i < dmraid_member_cache.size(); i++)
{
if (bs == dmraid_member_cache[i])
return true;
}
return false;
}
// Return vector of member devices of an active DMRaid array.
// E.g. lookup_dmraid_members("/dev/mapper/isw_ecccdhhiga_MyArray") -> ["/dev/sdc", "/dev/sdd"]
std::vector<Glib::ustring> DMRaid::lookup_dmraid_members(const Glib::ustring& array)
{
// Method:
// (1) Query udev for the kernel device name;
// (2) List member names from the directory /sys/block/${name}/slaves.
std::vector<Glib::ustring> members;
if (! udevadm_found)
return members; // Empty vector
Glib::ustring output;
Glib::ustring error;
Utils::execute_command("udevadm info --query=name " + Glib::shell_quote(array),
output, error, true);
// Strip terminating new line from output.
size_t len = output.length();
if (len > 0 && output[len-1] == '\n')
output.resize(len-1);
if (output.empty())
return members; // Empty vector
Glib::ustring filename;
Glib::Dir dir("/sys/block/" + output + "/slaves");
while ((filename = dir.read_name()) != "")
{
members.push_back("/dev/" + filename);
}
return members;
}
}//GParted

View File

@ -1525,13 +1525,16 @@ bool GParted_Core::is_busy( FSType fstype, const Glib::ustring & path )
}
else
{
DMRaid dmraid;
//Still search GParted internal mounted partitions map in case an
// unknown file system is mounted
busy = Mount_Info::is_dev_mounted( path );
// Custom checks for recognised but other not-supported file system types.
busy |= (fstype == FS_LINUX_SWRAID && SWRaid_Info::is_member_active(path));
busy |= (fstype == FS_ATARAID && SWRaid_Info::is_member_active(path));
busy |= (fstype == FS_ATARAID && (SWRaid_Info::is_member_active(path) ||
dmraid.is_member_active(path) ));
}
return busy ;