mirror of
https://github.com/ibm-s390-linux/s390-tools.git
synced 2026-08-05 02:14:52 +00:00
zipl/src: add support of md-mirrors
Add a script to process mirrored zipl targets managed by Linux "md"
driver (AKA "software mirrors")
. In the file zipl_helper.device-mapper.c implement two handlers
identified by pairs (ZIPL_UTIL_ID, MD_DRIVER_ID) and
(CHREIPL_UTIL_ID, MD_DRIVER_ID) for the helpers zipl_helper.md
and chreipl_helper.md respectively
. zipl_helper.md: prints sets of target parameters (one such set
per mirror) for a specified logical zipl target managed by linux
"md" driver.
. chreipl_helper.md: for a specified logical zipl target managed
by linux "md" driver prints a random disk from the set of disks
participating in the mirrored setup.
. Add zipl_helper.md and chreipl_helper.md as symbolic links to
zipl_helper.device-mapper
Signed-off-by: Eduard Shishkin <edward6@linux.ibm.com>
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
This commit is contained in:
committed by
Steffen Eiden
parent
0eeab96f0d
commit
3296d85e35
@@ -13,21 +13,25 @@ objects = misc.o error.o scan.o job.o boot.o bootmap.o fs-map.o disk.o \
|
|||||||
bootmap_header.o envblk.o install.o zipl.o
|
bootmap_header.o envblk.o install.o zipl.o
|
||||||
|
|
||||||
zipl_helpers = $(basename $(wildcard zipl_helper.*.c))
|
zipl_helpers = $(basename $(wildcard zipl_helper.*.c))
|
||||||
|
zipl_helpers += zipl_helper.md
|
||||||
chreipl_helpers = $(subst zipl_,chreipl_, $(zipl_helpers))
|
chreipl_helpers = $(subst zipl_,chreipl_, $(zipl_helpers))
|
||||||
|
|
||||||
all: zipl zipl-editenv $(chreipl_helpers)
|
all: zipl zipl-editenv zipl_helper.md $(chreipl_helpers)
|
||||||
|
|
||||||
boot.o: ../boot/.loaders
|
boot.o: ../boot/.loaders
|
||||||
zipl: $(objects) $(libs)
|
zipl: $(objects) $(libs)
|
||||||
|
|
||||||
zipl_helper.device-mapper: $(rootdir)/libdasd/libdasd.a \
|
zipl_helper.device-mapper: $(rootdir)/libdasd/libdasd.a \
|
||||||
$(rootdir)/libvtoc/libvtoc.a \
|
$(rootdir)/libvtoc/libvtoc.a \
|
||||||
$(libs) zipl_helper.device-mapper.o
|
$(libs) misc.o error.o zipl_helper.device-mapper.o
|
||||||
|
|
||||||
zipl-editenv: $(libs) misc.o error.o fs-map.o bootmap_header.o \
|
zipl-editenv: $(libs) misc.o error.o fs-map.o bootmap_header.o \
|
||||||
envblk.o zipl-editenv.o
|
envblk.o zipl-editenv.o
|
||||||
|
|
||||||
chreipl_helper.%: zipl_helper.%
|
zipl_helper.md: zipl_helper.device-mapper
|
||||||
|
ln -f -s $< $@
|
||||||
|
|
||||||
|
chreipl_helper.%: zipl_helper.device-mapper
|
||||||
ln -f -s $< $@
|
ln -f -s $< $@
|
||||||
|
|
||||||
install: all
|
install: all
|
||||||
|
|||||||
@@ -32,11 +32,27 @@
|
|||||||
* major:minor parameters are printed. Otherwise, the script exits with an
|
* major:minor parameters are printed. Otherwise, the script exits with an
|
||||||
* error message and a non-zero return code.
|
* error message and a non-zero return code.
|
||||||
*
|
*
|
||||||
|
* 3. Usage: zipl_helper.md <target directory> or
|
||||||
|
* <major:minor of target md device>
|
||||||
|
*
|
||||||
|
* This tool identifies the set of all physical devices that the specified
|
||||||
|
* logical target md-device is composed of and for each such component
|
||||||
|
* prints target parameters needed to install a boot record on respective
|
||||||
|
* disk. Only RAID1 md-setups are supported. All physical devices in the md
|
||||||
|
* RAID1 setup must have identical type and geometry and equal file system
|
||||||
|
* offsets from the beginning of the disk.
|
||||||
|
*
|
||||||
|
* 4. Usage: chreipl_helper.md <major:minor of target md device>
|
||||||
|
*
|
||||||
|
* This tool identifies single (random) physical device from the set of
|
||||||
|
* raid devices that the specified target md-device is composed of and
|
||||||
|
* prints the pair major:minor of respective physical disk.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <linux/limits.h>
|
#include <linux/limits.h>
|
||||||
|
#include <linux/raid/md_u.h>
|
||||||
#include <locale.h>
|
#include <locale.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
@@ -46,9 +62,11 @@
|
|||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/sysmacros.h>
|
#include <sys/sysmacros.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
#include <fcntl.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include "misc.h"
|
||||||
#include "lib/dasd_base.h"
|
#include "lib/dasd_base.h"
|
||||||
#include "lib/util_base.h"
|
#include "lib/util_base.h"
|
||||||
#include "lib/util_file.h"
|
#include "lib/util_file.h"
|
||||||
@@ -112,8 +130,21 @@ struct physical_device {
|
|||||||
struct dmpath_entry *mirror;
|
struct dmpath_entry *mirror;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct mdstat {
|
||||||
|
char *version;
|
||||||
|
char *raid_level;
|
||||||
|
char *state;
|
||||||
|
unsigned long raid_devices;
|
||||||
|
unsigned long total_devices;
|
||||||
|
unsigned long active_devices;
|
||||||
|
unsigned long working_devices;
|
||||||
|
unsigned long failed_devices;
|
||||||
|
unsigned long spare_devices;
|
||||||
|
};
|
||||||
|
|
||||||
enum driver_id {
|
enum driver_id {
|
||||||
DM_DRIVER_ID,
|
DM_DRIVER_ID,
|
||||||
|
MD_DRIVER_ID,
|
||||||
LAST_DRIVER_ID
|
LAST_DRIVER_ID
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -139,6 +170,9 @@ struct helper {
|
|||||||
#define DASD_PARTN_MASK 0x03
|
#define DASD_PARTN_MASK 0x03
|
||||||
#define SCSI_PARTN_MASK 0x0f
|
#define SCSI_PARTN_MASK 0x0f
|
||||||
|
|
||||||
|
#define MD_MAJOR 9
|
||||||
|
#define DEVICE_MAPPER_MAJOR 253
|
||||||
|
|
||||||
/* Internal constants */
|
/* Internal constants */
|
||||||
enum dev_type {
|
enum dev_type {
|
||||||
DEV_TYPE_CDL = 0,
|
DEV_TYPE_CDL = 0,
|
||||||
@@ -161,6 +195,11 @@ enum lookup_result {
|
|||||||
DM_MULTIPLE_TARGETS
|
DM_MULTIPLE_TARGETS
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static int is_device_mapper(unsigned int major)
|
||||||
|
{
|
||||||
|
return major == DEVICE_MAPPER_MAJOR;
|
||||||
|
}
|
||||||
|
|
||||||
static void get_type_name(char *name, unsigned short type)
|
static void get_type_name(char *name, unsigned short type)
|
||||||
{
|
{
|
||||||
switch (type) {
|
switch (type) {
|
||||||
@@ -1234,6 +1273,399 @@ static int handle_device_mapper(dev_t dev, int util_id, char *name)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* In the file stream FP find the first line formatted as
|
||||||
|
* 'W : STRVAL' and coincided in W with the specified keyword KW.
|
||||||
|
* Store the string value in STR
|
||||||
|
*/
|
||||||
|
static int kw_to_str(char **line, size_t *n, FILE *fp,
|
||||||
|
const char *kw, char **str)
|
||||||
|
{
|
||||||
|
char *w = NULL;
|
||||||
|
int ret = -1;
|
||||||
|
|
||||||
|
while (getline(line, n, fp) != -1) {
|
||||||
|
if (sscanf(*line, "%ms : %m[a-zA-Z,0-9. ]",
|
||||||
|
&w, str) >= 2 &&
|
||||||
|
strcmp(w, kw) == 0) {
|
||||||
|
ret = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(w);
|
||||||
|
if (ret)
|
||||||
|
ERR("Unrecognized %s\n", kw);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* In the file stream FP find the first line formatted as
|
||||||
|
* 'W1 W2 : STRVAL' and coincided in W1 and W2 with the specified
|
||||||
|
* keywords KW1 and KW2. Store the string value in STR.
|
||||||
|
*/
|
||||||
|
static int kw_pair_to_str(char **line, size_t *n, FILE *fp,
|
||||||
|
const char *kw1, const char *kw2,
|
||||||
|
char **str)
|
||||||
|
{
|
||||||
|
char *w1 = NULL;
|
||||||
|
char *w2 = NULL;
|
||||||
|
int ret = -1;
|
||||||
|
|
||||||
|
while (getline(line, n, fp) != -1) {
|
||||||
|
if (sscanf(*line, "%ms %ms : %m[a-zA-Z,0-9. ]",
|
||||||
|
&w1, &w2, str) >= 3 &&
|
||||||
|
strcmp(w1, kw1) == 0 &&
|
||||||
|
strcmp(w2, kw2) == 0) {
|
||||||
|
ret = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(w1);
|
||||||
|
free(w2);
|
||||||
|
if (ret)
|
||||||
|
ERR("Unrecognized %s %s\n", kw1, kw1);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* In the file stream FP find the first line formatted as
|
||||||
|
* 'W1 W2 : NUMVAL' and coincided in W1 and W2 with the specified
|
||||||
|
* keywords KW1 and KW2. Store the numerical value in VAL.
|
||||||
|
*/
|
||||||
|
static int kw_pair_to_ulong_silent(char **line, size_t *n, FILE *fp,
|
||||||
|
const char *kw1, const char *kw2,
|
||||||
|
unsigned long *val)
|
||||||
|
{
|
||||||
|
char *w1 = NULL;
|
||||||
|
char *w2 = NULL;
|
||||||
|
int ret = -1;
|
||||||
|
|
||||||
|
while (getline(line, n, fp) != -1) {
|
||||||
|
if (sscanf(*line, "%ms %ms : %lu", &w1, &w2, val) >= 3 &&
|
||||||
|
strcmp(w1, kw1) == 0 &&
|
||||||
|
strcmp(w2, kw2) == 0) {
|
||||||
|
ret = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(w1);
|
||||||
|
free(w2);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int kw_pair_to_ulong(char **line, size_t *n, FILE *fp,
|
||||||
|
const char *kw1, const char *kw2,
|
||||||
|
unsigned long *value)
|
||||||
|
{
|
||||||
|
if (kw_pair_to_ulong_silent(line, n, fp, kw1, kw2, value)) {
|
||||||
|
ERR("Unrecognized %s %s\n", kw1, kw2);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int get_components_header(char **line, size_t *n, FILE *fp)
|
||||||
|
{
|
||||||
|
while (getline(line, n, fp) != -1) {
|
||||||
|
if (strstr(*line, "Number") &&
|
||||||
|
strstr(*line, "Major") &&
|
||||||
|
strstr(*line, "Minor") &&
|
||||||
|
strstr(*line, "RaidDevice") &&
|
||||||
|
strstr(*line, "State")) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int md_get_component(char **line, size_t *n, FILE *fp, int nr_expected,
|
||||||
|
unsigned int *major, unsigned int *minor)
|
||||||
|
{
|
||||||
|
int nr_found, raid_dev;
|
||||||
|
|
||||||
|
while (getline(line, n, fp) != -1) {
|
||||||
|
if (sscanf(*line, "%d %u %u %d",
|
||||||
|
&nr_found, major, minor, &raid_dev) >= 4 &&
|
||||||
|
nr_expected == raid_dev) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ERR("Unrecognized %d component\n", nr_expected);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse the output of "mdadm --examine MAJOR:MINOR" command, where
|
||||||
|
* MAJOR and MINOR specify a physical component of some logical md device.
|
||||||
|
* Find out how much space (in sectors) is reserved for md-metadata
|
||||||
|
* (typically superblock and bitmap) at the beginning of that component.
|
||||||
|
*/
|
||||||
|
static int md_get_data_offset(unsigned long major, unsigned long minor,
|
||||||
|
unsigned long *data_offset)
|
||||||
|
{
|
||||||
|
char *line = NULL;
|
||||||
|
size_t n = 0;
|
||||||
|
FILE *fp;
|
||||||
|
|
||||||
|
fp = exec_cmd_and_get_out_stream("mdadm --examine %lu:%lu",
|
||||||
|
major, minor);
|
||||||
|
if (fp == NULL)
|
||||||
|
return -1;
|
||||||
|
if (kw_pair_to_ulong_silent(&line, &n, fp,
|
||||||
|
"Data", "Offset", data_offset))
|
||||||
|
*data_offset = 0;
|
||||||
|
free(line);
|
||||||
|
pclose(fp);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void md_print_bad_status(struct mdstat *md, const char *devname)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Raid Devices: %lu\n", md->raid_devices);
|
||||||
|
fprintf(stderr, "Active Devices: %lu\n", md->active_devices);
|
||||||
|
fprintf(stderr, "Working Devices: %lu\n", md->working_devices);
|
||||||
|
fprintf(stderr, "%s: RAID inconsistent (some its components are not active or working).\n",
|
||||||
|
devname);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int devname_by_device(dev_t device, char **devname)
|
||||||
|
{
|
||||||
|
struct util_proc_part_entry entry;
|
||||||
|
|
||||||
|
if (util_proc_part_get_entry(device, &entry))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
*devname = misc_make_path("/dev", entry.name);
|
||||||
|
util_proc_part_free_entry(&entry);
|
||||||
|
return *devname ? 0 : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int check_md(dev_t dev, int *is_md_device)
|
||||||
|
{
|
||||||
|
mdu_array_info_t array;
|
||||||
|
char *devname = NULL;
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
if (major(dev) == MD_MAJOR) {
|
||||||
|
*is_md_device = 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (devname_by_device(dev, &devname))
|
||||||
|
return -1;
|
||||||
|
fd = open(devname, O_RDONLY);
|
||||||
|
free(devname);
|
||||||
|
if (fd == -1)
|
||||||
|
return -1;
|
||||||
|
if (ioctl(fd, GET_ARRAY_INFO, &array) >= 0)
|
||||||
|
*is_md_device = 1;
|
||||||
|
else
|
||||||
|
*is_md_device = 0;
|
||||||
|
close(fd);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Print one set of zipl parameters for a raid component specified
|
||||||
|
* by MAJOR and MINOR.
|
||||||
|
*
|
||||||
|
* FS_START_MD: file system start on the md-device in sector units
|
||||||
|
*/
|
||||||
|
static int md_mirror_to_params(unsigned int major, unsigned int minor,
|
||||||
|
unsigned long partstart_md, int util_id)
|
||||||
|
{
|
||||||
|
struct device_characteristics dc;
|
||||||
|
unsigned long data_start_md;
|
||||||
|
unsigned long partstart_phy;
|
||||||
|
unsigned long fs_start_base;
|
||||||
|
int is_md_device;
|
||||||
|
dev_t base;
|
||||||
|
dev_t dev;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
dev = makedev(major, minor);
|
||||||
|
|
||||||
|
if (check_md(dev, &is_md_device)) {
|
||||||
|
ERR("Failed to get md-status for (%d:%d)\n",
|
||||||
|
major, minor);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (is_md_device) {
|
||||||
|
ERR("Unsupported configuration: nested md devices\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (is_device_mapper(major)) {
|
||||||
|
char *name;
|
||||||
|
|
||||||
|
misc_asprintf(&name, "%d:%d", major, minor);
|
||||||
|
|
||||||
|
fail_on_dm_mirrors = 1;
|
||||||
|
ret = handle_device_mapper(dev, util_id, name);
|
||||||
|
free(name);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* find space reserved for md-metadata at the beginning
|
||||||
|
* of the physical device
|
||||||
|
*/
|
||||||
|
if (md_get_data_offset(major, minor, &data_start_md))
|
||||||
|
return -1;
|
||||||
|
/*
|
||||||
|
* find parameters of the physical device
|
||||||
|
*/
|
||||||
|
if (get_dev_characteristics(&dc, dev))
|
||||||
|
return -1;
|
||||||
|
partstart_phy = dc.partstart * (dc.blocksize / SECTOR_SIZE);
|
||||||
|
|
||||||
|
if (data_start_md && partstart_phy < dc.bootsectors) {
|
||||||
|
ERR("Unsupported configuration: md metadata locate at boot area\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (partstart_phy > 0) {
|
||||||
|
base = get_partition_base(dc.type, dev);
|
||||||
|
/* Update device geometry */
|
||||||
|
get_dev_characteristics(&dc, base);
|
||||||
|
} else {
|
||||||
|
base = dev;
|
||||||
|
}
|
||||||
|
if (util_id == CHREIPL_UTIL_ID) {
|
||||||
|
printf("%u:%u\n", major(base), minor(base));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
fs_start_base = partstart_md + data_start_md + partstart_phy;
|
||||||
|
if (fs_start_base % (dc.blocksize / SECTOR_SIZE)) {
|
||||||
|
ERR("File system is not aligned on physical block size\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
base_dev_to_params(base, &dc, fs_start_base);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If STATE contains THIS property, then issue an error message
|
||||||
|
* with the proposed FIXUP
|
||||||
|
*/
|
||||||
|
static int error_on(const char *state, const char *this, const char *fixup,
|
||||||
|
const char *devname)
|
||||||
|
{
|
||||||
|
if (strstr(state, this)) {
|
||||||
|
fprintf(stderr, "%s: Inconsistent RAID state ('%s'). %s.\n",
|
||||||
|
devname, this, fixup);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int check_md_state(struct mdstat *md, const char *devname)
|
||||||
|
{
|
||||||
|
if (error_on(md->state, "recovering", "Complete its recovery", devname))
|
||||||
|
return -1;
|
||||||
|
if (error_on(md->state, "degraded", "Restore its redundancy", devname))
|
||||||
|
return -1;
|
||||||
|
if (error_on(md->state, "dirty", "Bring it into clean state\n", devname))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (md->raid_devices != md->active_devices ||
|
||||||
|
md->raid_devices > md->working_devices) {
|
||||||
|
md_print_bad_status(md, devname);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse the output of "mdadm --detail" command issued for logical
|
||||||
|
* device DEV.
|
||||||
|
*
|
||||||
|
* Identify the set of physical devices that DEVNAME is composed of.
|
||||||
|
*
|
||||||
|
* If util_id is ZIPL_UTIL_ID:
|
||||||
|
* Calculate and print (to the standerd output) target parameters
|
||||||
|
* for each identified component.
|
||||||
|
*
|
||||||
|
* If util_id is CHREIPL_UTIL_ID:
|
||||||
|
* Print the pair major:minor of one (random) identified component.
|
||||||
|
*/
|
||||||
|
static int md_dev_to_params(dev_t dev, const char *devname, int util_id)
|
||||||
|
{
|
||||||
|
struct mdstat md = {0};
|
||||||
|
char *line = NULL;
|
||||||
|
long partstart_md;
|
||||||
|
unsigned long i;
|
||||||
|
int ret = -1;
|
||||||
|
size_t n = 0;
|
||||||
|
FILE *fp;
|
||||||
|
|
||||||
|
fp = exec_cmd_and_get_out_stream("mdadm --detail %s", devname);
|
||||||
|
if (fp == NULL)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
if (kw_to_str(&line, &n, fp, "Version", &md.version) ||
|
||||||
|
kw_pair_to_str(&line, &n, fp, "Raid", "Level", &md.raid_level) ||
|
||||||
|
kw_pair_to_ulong(&line, &n, fp, "Raid", "Devices",
|
||||||
|
&md.raid_devices) ||
|
||||||
|
kw_pair_to_ulong(&line, &n, fp, "Total", "Devices",
|
||||||
|
&md.total_devices) ||
|
||||||
|
kw_to_str(&line, &n, fp, "State", &md.state) ||
|
||||||
|
kw_pair_to_ulong(&line, &n, fp, "Active", "Devices",
|
||||||
|
&md.active_devices) ||
|
||||||
|
kw_pair_to_ulong(&line, &n, fp, "Working", "Devices",
|
||||||
|
&md.working_devices) ||
|
||||||
|
kw_pair_to_ulong(&line, &n, fp, "Failed", "Devices",
|
||||||
|
&md.failed_devices) ||
|
||||||
|
kw_pair_to_ulong(&line, &n, fp, "Spare", "Devices",
|
||||||
|
&md.spare_devices))
|
||||||
|
goto out;
|
||||||
|
/* check raid level */
|
||||||
|
if (strcmp(md.raid_level, "raid1") != 0) {
|
||||||
|
ERR("%s: Unsupported raid level %s\n", devname, md.raid_level);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
/* check that raid is healthy */
|
||||||
|
if (check_md_state(&md, devname))
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
/* Handle the case when DEV is a partition */
|
||||||
|
|
||||||
|
partstart_md = get_partition_start(major(dev), minor(dev));
|
||||||
|
if (partstart_md < 0) {
|
||||||
|
fprintf(stderr, "Could not determine partition start for '%s'\n",
|
||||||
|
devname);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
/* get information about raid components */
|
||||||
|
|
||||||
|
if (get_components_header(&line, &n, fp)) {
|
||||||
|
fprintf(stderr, "Could not get raid components info for %s\n",
|
||||||
|
devname);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
for (i = 0; i < md.raid_devices; i++) {
|
||||||
|
unsigned int major, minor;
|
||||||
|
|
||||||
|
if (md_get_component(&line, &n, fp, i, &major, &minor))
|
||||||
|
goto out;
|
||||||
|
if (md_mirror_to_params(major, minor, partstart_md, util_id))
|
||||||
|
goto out;
|
||||||
|
if (util_id == CHREIPL_UTIL_ID)
|
||||||
|
/* chreipl accepts only one base disk */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ret = 0;
|
||||||
|
out:
|
||||||
|
free(md.raid_level);
|
||||||
|
free(md.version);
|
||||||
|
free(md.state);
|
||||||
|
free(line);
|
||||||
|
pclose(fp);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int devname_by_major_minor(unsigned int major, unsigned int minor,
|
||||||
|
char **devname)
|
||||||
|
{
|
||||||
|
return devname_by_device(makedev(major, minor), devname);
|
||||||
|
}
|
||||||
|
|
||||||
static int print_params_device_mapper(char *argv[], struct helper *h)
|
static int print_params_device_mapper(char *argv[], struct helper *h)
|
||||||
{
|
{
|
||||||
unsigned int major, minor;
|
unsigned int major, minor;
|
||||||
@@ -1247,6 +1679,38 @@ static int print_params_device_mapper(char *argv[], struct helper *h)
|
|||||||
return handle_device_mapper(dev, h->util_id, name);
|
return handle_device_mapper(dev, h->util_id, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int print_params_md(char *argv[], struct helper *h)
|
||||||
|
{
|
||||||
|
unsigned int major, minor;
|
||||||
|
char *devname;
|
||||||
|
dev_t dev;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (h->util_id != CHREIPL_UTIL_ID && h->util_id != ZIPL_UTIL_ID) {
|
||||||
|
fprintf(stderr, "Unsupported utility %d\n", h->util_id);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (extract_major_minor_from_cmdline(argv, &major, &minor) == 0) {
|
||||||
|
if (devname_by_major_minor(major, minor, &devname)) {
|
||||||
|
fprintf(stderr, "Could not resolve %u:%u to device name\n",
|
||||||
|
major, minor);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
dev = makedev(major, minor);
|
||||||
|
} else {
|
||||||
|
if (device_by_filename(&dev, argv[1]))
|
||||||
|
return -1;
|
||||||
|
if (devname_by_device(dev, &devname)) {
|
||||||
|
fprintf(stderr, "Directory %s is not over any block device\n",
|
||||||
|
argv[1]);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ret = md_dev_to_params(dev, devname, h->util_id);
|
||||||
|
free(devname);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static int check_usage_zipl_helper(int argc, char *argv[])
|
static int check_usage_zipl_helper(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
if (argc <= 1) {
|
if (argc <= 1) {
|
||||||
@@ -1276,6 +1740,13 @@ static struct helper helpers[LAST_DRIVER_ID][LAST_UTIL_ID] = {
|
|||||||
. check_usage = check_usage_zipl_helper,
|
. check_usage = check_usage_zipl_helper,
|
||||||
. print_params = print_params_device_mapper
|
. print_params = print_params_device_mapper
|
||||||
},
|
},
|
||||||
|
[MD_DRIVER_ID][ZIPL_UTIL_ID] = {
|
||||||
|
. util_id = ZIPL_UTIL_ID,
|
||||||
|
. driver_id = MD_DRIVER_ID,
|
||||||
|
. name = "zipl_helper.md",
|
||||||
|
. check_usage = check_usage_zipl_helper,
|
||||||
|
. print_params = print_params_md
|
||||||
|
},
|
||||||
[DM_DRIVER_ID][CHREIPL_UTIL_ID] = {
|
[DM_DRIVER_ID][CHREIPL_UTIL_ID] = {
|
||||||
. util_id = CHREIPL_UTIL_ID,
|
. util_id = CHREIPL_UTIL_ID,
|
||||||
. driver_id = DM_DRIVER_ID,
|
. driver_id = DM_DRIVER_ID,
|
||||||
@@ -1283,6 +1754,13 @@ static struct helper helpers[LAST_DRIVER_ID][LAST_UTIL_ID] = {
|
|||||||
. check_usage = check_usage_chreipl_helper,
|
. check_usage = check_usage_chreipl_helper,
|
||||||
. print_params = print_params_device_mapper
|
. print_params = print_params_device_mapper
|
||||||
},
|
},
|
||||||
|
[MD_DRIVER_ID][CHREIPL_UTIL_ID] = {
|
||||||
|
. util_id = CHREIPL_UTIL_ID,
|
||||||
|
. driver_id = MD_DRIVER_ID,
|
||||||
|
. name = "chreipl_helper.md",
|
||||||
|
. check_usage = check_usage_chreipl_helper,
|
||||||
|
. print_params = print_params_md
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct helper *helper_by_toolname(const char *toolname)
|
static struct helper *helper_by_toolname(const char *toolname)
|
||||||
@@ -1307,7 +1785,7 @@ int main(int argc, char *argv[])
|
|||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
|
|
||||||
if (setlocale(LC_ALL, "C") == NULL) {
|
if (setlocale(LC_ALL, "C") == NULL) {
|
||||||
ERR("Could not use standard locale\n");
|
fprintf(stderr, "Could not use standard locale\n");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
if (h->print_params(argv, h))
|
if (h->print_params(argv, h))
|
||||||
|
|||||||
Reference in New Issue
Block a user