gparted/src/SWRaid_Info.cc

125 lines
3.9 KiB
C++
Raw Normal View History

Detect Linux SWRaid members by querying mdadm (#756829) Detection of Linux SWRaid members currently fails in a number of cases: 1) Arrays which use metadata type 0.90 or 1.0 store the super block at the end of the partition. So file system signatures in at least linear and mirrored arrays occur at the same offsets in the underlying partitions. As libparted only recognises file systems this is what is detected, rather than an SWRaid member. # mdadm -E -s -v ARRAY /dev/md/1 level=raid1 metadata=1.0 num-devices=2 UUID=15224a42:c25bbcd9:15db6000:4e5fe53a name=chimney:1 devices=/dev/sda1,/dev/sdb1 ... # wipefs /dev/sda1 offset type ---------------------------------------------------------------- 0x438 ext4 [filesystem] LABEL: chimney-boot UUID: 10ab5f7d-7d8a-4171-8b6a-5e973b402501 0x1fffe000 linux_raid_member [raid] LABEL: chimney:1 UUID: 15224a42-c25b-bcd9-15db-60004e5fe53a # parted /dev/sda print Model: ATA VBOX HARDDISK (scsi) Disk /dev/sda: 34.4GB Sector size (logical/physical): 512B/512B Partition Table: msdos Number Start End Size Type File system Flags 1 1049kB 538MB 537MB primary ext4 boot, raid ... 2) Again with metadata type 0.90 or 1.0 arrays blkid may report the contained file system instead of an SWRaid member. Have a single example of this configuration with a mirrored array containing the /boot file system. Blkid reports one member as ext4 and the other as SWRaid! # blkid | egrep 'sd[ab]1' /dev/sda1: UUID="10ab5f7d-7d8a-4171-8b6a-5e973b402501" TYPE="ext4" LABEL="chimney-boot" /dev/sdb1: UUID="15224a42-c25b-bcd9-15db-60004e5fe53a" UUID_SUB="0a095e45-9360-1b17-0ad1-1fe369e22b98" LABEL="chimney:1" TYPE="linux_raid_member" Bypassing the blkid cache gets the correct result. # blkid -c /dev/null /dev/sda1 /dev/sda1: UUID="15224a42-c25b-bcd9-15db-60004e5fe53a" UUID_SUB="d0460f90-d11a-e80a-ee1c-3d104dae7e5d" LABEL="chimney:1" TYPE="linux_raid_member" However this can't be used because if a user has a floppy configured in the BIOS but no floppy attached, GParted will wait for minutes as the kernel tries to access non-existent hardware on behalf of the blkid query. See commit: 18f863151c82934fe0a980853cc3deb1e439bec2 Fix long scan problem when BIOS floppy setting incorrect 3) Old versions of blkid don't recognise SWRaid members at all so always report the file system when found. Occurs with blkid v1.0 on RedHat / CentOS 5. The only way I can see how to fix all these cases is to use the mdadm command to query the configured arrays. Then use this information for first choice when detecting partition content, making the order: SWRaid members, libparted, blkid and internal. GParted shell wrapper already creates temporary blank udev rules to prevent Linux Software RAID arrays being automatically started when GParted refreshes its device information[1]. However an administrator could manually stop or start arrays or change their configuration between refreshes so GParted must load this information every refresh. On my desktop with 4 internal hard drives and 3 testing Linux Software RAID arrays, running mdadm adds between 0.20 and 0.30 seconds to the device refresh time. [1] a255abf3432ad106fac9c766f0816ada20be8e42 Prevent GParted starting stopped Linux Software RAID arrays (#709640) Bug 756829 - SWRaid member detection enhancements
2015-10-20 13:52:19 -06:00
/* Copyright (C) 2015 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include "../include/SWRaid_Info.h"
#include "../include/Utils.h"
#include <glibmm/ustring.h>
namespace GParted
{
// Data model:
// mdadm_found - Is the "mdadm" command available?
// swraid_info_cache - Vector of /dev entries of members in Linux Software RAID arrays.
// E.g.
// ["/dev/sda1", "/dev/sda2", ...]
// Initialise static data elements
bool SWRaid_Info::mdadm_found = false;
std::vector<Glib::ustring> SWRaid_Info::swraid_info_cache;
void SWRaid_Info::load_cache()
{
set_command_found();
load_swraid_info_cache();
}
bool SWRaid_Info::is_member( const Glib::ustring & member_path )
{
for ( unsigned int i = 0 ; i < swraid_info_cache.size() ; i ++ )
if ( member_path == swraid_info_cache[i] )
return true;
return false;
}
// Private methods
void SWRaid_Info::set_command_found()
{
mdadm_found = ! Glib::find_program_in_path( "mdadm" ).empty();
}
void SWRaid_Info::load_swraid_info_cache()
{
Glib::ustring output, error;
swraid_info_cache.clear();
if ( ! mdadm_found )
return;
// Load SWRaid members into the cache.
Glib::ustring cmd = "mdadm --examine --scan --verbose";
if ( ! Utils::execute_command( cmd, output, error, true ) )
{
// Extract member /dev entries from Linux Software RAID arrays only,
// excluding IMSM and DDF arrays. Example output:
// ARRAY metadata=imsm UUID=...
// devices=/dev/sdd,/dev/sdc,/dev/md/imsm0
// ARRAY /dev/md/MyRaid container=...
//
// ARRAY /dev/md/1 level=raid1 metadata=1.0 num-devices=2 UUID=...
// devices=/dev/sda1,/dev/sdb1
// ARRAY /dev/md5 level=raid1 num-devices=2 UUID=...
// devices=/dev/sda6,/dev/sdb6
std::vector<Glib::ustring> lines;
Utils::split( output, lines, "\n" );
enum LINE_TYPE
{
LINE_TYPE_OTHER = 0,
LINE_TYPE_ARRAY = 1,
LINE_TYPE_DEVICES = 2
};
LINE_TYPE line_type = LINE_TYPE_OTHER;
for ( unsigned int i = 0 ; i < lines.size() ; i ++ )
{
Glib::ustring metadata_type;
if ( lines[i].substr( 0, 6 ) == "ARRAY " )
{
line_type = LINE_TYPE_ARRAY;
Glib::ustring metadata_type = Utils::regexp_label( lines[i],
"metadata=([[:graph:]]+)" );
// Mdadm with these flags doesn't seem to print the
// metadata tag for 0.90 version arrays. Accept no tag
// (or empty version) as well as "0.90".
if ( metadata_type != "" && metadata_type != "0.90" &&
metadata_type != "1.0" && metadata_type != "1.1" &&
metadata_type != "1.2" )
// Skip mdadm reported non-Linux Software RAID arrays
line_type = LINE_TYPE_OTHER;
}
else if ( line_type == LINE_TYPE_ARRAY &&
lines[i].find( "devices=" ) != Glib::ustring::npos )
{
line_type = LINE_TYPE_DEVICES;
Glib::ustring devices_str = Utils::regexp_label( lines[i],
"devices=([[:graph:]]+)" );
std::vector<Glib::ustring> devices;
Utils::split( devices_str, devices, "," );
for ( unsigned int j = 0 ; j < devices.size() ; j ++ )
swraid_info_cache.push_back( devices[j] );
}
else
line_type = LINE_TYPE_OTHER;
}
}
}
} //GParted