mirror of
https://github.com/ibm-s390-linux/s390-tools.git
synced 2026-08-05 02:14:52 +00:00
zipl/src: add basic support for multiple target base disks
. Modify disk_get_info() to process multiple sets of target parameters
provided by the helper script and store it in the array of "targets"
of the structure job_target_data;
. Besides the logical device, maintain an array of physical base disks
in the disk_info structure;
. Use the logical target device only to create bootmap (it is
automatically mirrored by the respective linux driver (dm, or md)
managing the mirrored target). In contrast, install bootstrap blocks
to each physical base disk individually, bypassing that driver;
. Report in verbose mode on which base disks the bootstrap
installation was performed;
. Use the following logic of setting @info->device (which is printed
as "Device...:" in verbose mode):
. source_auto - the target base disk is set;
. source_script - the target (logical) device is set;
. source_user - the device specified by user (via --targetbase
option), or config file is set.
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
d9a9bd8dcf
commit
d6b702d579
@@ -56,13 +56,14 @@ typedef enum {
|
||||
/* targetbase definition */
|
||||
typedef enum {
|
||||
defined_as_device,
|
||||
defined_as_name
|
||||
defined_as_name,
|
||||
undefined
|
||||
} definition_t;
|
||||
|
||||
/* Disk information type */
|
||||
struct disk_info {
|
||||
disk_type_t type;
|
||||
dev_t device;
|
||||
dev_t device; /* logical device for bootmap creation */
|
||||
dev_t partition;
|
||||
int devno;
|
||||
int partnum;
|
||||
@@ -72,8 +73,11 @@ struct disk_info {
|
||||
struct hd_geometry geo;
|
||||
char* name;
|
||||
char* drv_name;
|
||||
definition_t targetbase;
|
||||
definition_t targetbase_def;
|
||||
int is_nvme;
|
||||
dev_t basedisks[MAX_TARGETS]; /* array of physical disks for
|
||||
* bootstrap blocks recording
|
||||
*/
|
||||
};
|
||||
|
||||
struct file_range {
|
||||
@@ -113,6 +117,9 @@ blocknum_t disk_write_block_buffer_align(int fd, int fd_is_basedisk,
|
||||
struct disk_info *info, int align,
|
||||
off_t *offset);
|
||||
void disk_print_devt(dev_t d);
|
||||
void disk_print_devname(dev_t d);
|
||||
void prepare_footnote_ptr(int source, char *ptr);
|
||||
void print_footnote_ref(int source, const char *prefix);
|
||||
void disk_print_info(struct disk_info *info, int source);
|
||||
int disk_is_zero_block(disk_blockptr_t* block, struct disk_info* info);
|
||||
blocknum_t disk_compact_blocklist(disk_blockptr_t* list, blocknum_t count,
|
||||
@@ -122,7 +129,6 @@ blocknum_t disk_get_blocklist_from_file(const char* filename,
|
||||
disk_blockptr_t** blocklist,
|
||||
struct disk_info* pinfo);
|
||||
int disk_check_subchannel_set(int devno, dev_t device, char* dev_name);
|
||||
void disk_print_geo(struct disk_info *data);
|
||||
int fs_map(int fd, uint64_t offset, blocknum_t *mapped, int fs_block_size);
|
||||
|
||||
#endif /* not DISK_H */
|
||||
|
||||
@@ -71,7 +71,7 @@ struct install_set {
|
||||
struct program_component *components[NR_PROGRAM_COMPONENTS];
|
||||
int nr_menu_entries;
|
||||
int fd;
|
||||
char *device;
|
||||
char *basetmp[MAX_TARGETS];
|
||||
char *filename;
|
||||
unsigned int tmp_filename_created:1;
|
||||
unsigned int skip_prepare:1;
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
#include "disk.h"
|
||||
#include "zipl.h"
|
||||
|
||||
|
||||
enum job_id {
|
||||
job_print_usage = 1,
|
||||
job_print_version = 2,
|
||||
@@ -30,6 +29,21 @@ enum job_id {
|
||||
job_mvdump = 8,
|
||||
};
|
||||
|
||||
/*
|
||||
* Set of parameters per physical disk, which are provided
|
||||
* either by user, or by helper script
|
||||
*/
|
||||
struct target {
|
||||
char *targetbase;
|
||||
disk_type_t targettype;
|
||||
int targetcylinders;
|
||||
int targetheads;
|
||||
int targetsectors;
|
||||
int targetblocksize;
|
||||
blocknum_t targetoffset;
|
||||
int check_params;
|
||||
};
|
||||
|
||||
/* target information source */
|
||||
typedef enum {
|
||||
source_unknown = 0,
|
||||
@@ -39,17 +53,21 @@ typedef enum {
|
||||
} source_t;
|
||||
|
||||
struct job_target_data {
|
||||
char* bootmap_dir;
|
||||
char* targetbase;
|
||||
disk_type_t targettype;
|
||||
int targetcylinders;
|
||||
int targetheads;
|
||||
int targetsectors;
|
||||
int targetblocksize;
|
||||
blocknum_t targetoffset;
|
||||
char *bootmap_dir;
|
||||
int nr_targets;
|
||||
struct target targets[MAX_TARGETS];
|
||||
source_t source;
|
||||
};
|
||||
|
||||
enum target_params {
|
||||
TARGET_BASE,
|
||||
TARGET_TYPE,
|
||||
TARGET_GEOMETRY,
|
||||
TARGET_BLOCKSIZE,
|
||||
TARGET_OFFSET,
|
||||
LAST_TARGET_PARAM
|
||||
};
|
||||
|
||||
struct job_common_ipl_data {
|
||||
char* image;
|
||||
char* parmline;
|
||||
@@ -142,12 +160,94 @@ struct job_data {
|
||||
int is_ldipl_dump;
|
||||
};
|
||||
|
||||
static inline struct target *target_at(struct job_target_data *data,
|
||||
int index)
|
||||
{
|
||||
return index >= MAX_TARGETS ? NULL : &data->targets[index];
|
||||
}
|
||||
|
||||
static inline char *get_targetbase(struct job_target_data *data, int index)
|
||||
{
|
||||
return target_at(data, index)->targetbase;
|
||||
}
|
||||
|
||||
static inline void set_targetbase(struct job_target_data *data, int index,
|
||||
char *value)
|
||||
{
|
||||
target_at(data, index)->targetbase = value;
|
||||
}
|
||||
|
||||
static inline disk_type_t get_targettype(struct job_target_data *data,
|
||||
int index)
|
||||
{
|
||||
return target_at(data, index)->targettype;
|
||||
}
|
||||
|
||||
int set_targettype(struct job_target_data *data, int index, char *value);
|
||||
|
||||
static inline char *job_get_targetbase(struct job_data *job)
|
||||
{
|
||||
return get_targetbase(&job->target, 0);
|
||||
}
|
||||
|
||||
static inline void job_set_targetbase(struct job_data *job, char *value)
|
||||
{
|
||||
set_targetbase(&job->target, 0, value);
|
||||
}
|
||||
|
||||
static inline int job_get_nr_targets(struct job_data *job)
|
||||
{
|
||||
return job->target.nr_targets;
|
||||
}
|
||||
|
||||
static inline void job_set_nr_targets(struct job_data *job, int value)
|
||||
{
|
||||
job->target.nr_targets = value;
|
||||
}
|
||||
|
||||
static inline disk_type_t job_get_targettype(struct job_data *job)
|
||||
{
|
||||
return get_targettype(&job->target, 0);
|
||||
}
|
||||
|
||||
int job_set_targettype(struct job_data *job, char *value);
|
||||
|
||||
#define define_target_param_ops(_TYPE_, _PARAM_) \
|
||||
static inline _TYPE_ get_target##_PARAM_(struct job_target_data *data, \
|
||||
int index) \
|
||||
{ \
|
||||
return target_at(data, index)->target##_PARAM_; \
|
||||
} \
|
||||
\
|
||||
static inline void set_target##_PARAM_(struct job_target_data *data, \
|
||||
int index, _TYPE_ value) \
|
||||
{ \
|
||||
target_at(data, index)->target##_PARAM_ = value; \
|
||||
} \
|
||||
\
|
||||
static inline _TYPE_ job_get_target##_PARAM_(struct job_data *job) \
|
||||
{ \
|
||||
return get_target##_PARAM_(&job->target, 0); \
|
||||
} \
|
||||
\
|
||||
static inline void job_set_target##_PARAM_(struct job_data *job, \
|
||||
_TYPE_ value) \
|
||||
{ \
|
||||
set_target##_PARAM_(&job->target, 0, value); \
|
||||
}
|
||||
|
||||
define_target_param_ops(int, cylinders)
|
||||
define_target_param_ops(int, heads)
|
||||
define_target_param_ops(int, sectors)
|
||||
define_target_param_ops(int, blocksize)
|
||||
define_target_param_ops(blocknum_t, offset)
|
||||
|
||||
/**
|
||||
* Return true, if target parameters for the base disk are set
|
||||
* Return true, if target parameters are set at least for one target base disk
|
||||
*/
|
||||
static inline int target_parameters_are_set(struct job_target_data *td)
|
||||
{
|
||||
return td->targetbase != NULL;
|
||||
return get_targetbase(td, 0) != NULL;
|
||||
}
|
||||
|
||||
int job_get(int argc, char* argv[], struct job_data** data);
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
#define MENU_DEFAULT_TIMEOUT 0
|
||||
|
||||
#define MAX_DUMP_VOLUMES 32
|
||||
#define MAX_TARGETS 32
|
||||
|
||||
#define SECURE_BOOT_UNDEFINED -1
|
||||
#define SECURE_BOOT_DISABLED 0
|
||||
|
||||
@@ -1489,9 +1489,9 @@ static int prepare_build_program_table_device(struct job_data *job,
|
||||
printf("Target device information\n");
|
||||
disk_print_info(bis->info, job->target.source);
|
||||
}
|
||||
if (misc_temp_dev(bis->info->device, 1, &bis->device))
|
||||
if (misc_temp_dev(bis->info->device, 1, &bis->basetmp[0]))
|
||||
return -1;
|
||||
if (check_dump_device(job, bis->info, bis->device))
|
||||
if (check_dump_device(job, bis->info, bis->basetmp[0]))
|
||||
return -1;
|
||||
printf("Building bootmap directly on partition '%s'%s\n",
|
||||
bis->filename,
|
||||
@@ -1555,6 +1555,8 @@ static int prepare_bootloader_device(struct job_data *job,
|
||||
static int prepare_build_program_table_file(struct job_data *job,
|
||||
struct install_set *bis)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (bis->skip_prepare)
|
||||
/* skip the preparation work */
|
||||
return 0;
|
||||
@@ -1588,8 +1590,12 @@ static int prepare_build_program_table_file(struct job_data *job,
|
||||
printf("Target device information\n");
|
||||
disk_print_info(bis->info, job->target.source);
|
||||
}
|
||||
if (misc_temp_dev(bis->info->device, 1, &bis->device))
|
||||
return -1;
|
||||
for (i = 0; i < job_get_nr_targets(job); i++) {
|
||||
if (misc_temp_dev(bis->info->basedisks[i],
|
||||
1,
|
||||
&bis->basetmp[i]))
|
||||
return -1;
|
||||
}
|
||||
/* Check configuration number limits */
|
||||
if (job->id == job_menu) {
|
||||
if (check_menu_positions(&job->data.menu, job->name,
|
||||
@@ -1704,9 +1710,9 @@ static int prepare_bootloader_ngdump(struct job_data *job,
|
||||
/* Retrieve target device information */
|
||||
if (disk_get_info(job->data.dump.device, &job->target, &info))
|
||||
return -1;
|
||||
if (misc_temp_dev(info->device, 1, &bis->device))
|
||||
if (misc_temp_dev(info->device, 1, &bis->basetmp[0]))
|
||||
return -1;
|
||||
if (check_dump_device(job, info, bis->device))
|
||||
if (check_dump_device(job, info, bis->basetmp[0]))
|
||||
return -1;
|
||||
|
||||
assert(!job->target.bootmap_dir);
|
||||
@@ -1856,6 +1862,9 @@ void free_bootloader(struct install_set *bis)
|
||||
if (bis->tmp_filename_created)
|
||||
misc_free_temp_file(bis->filename);
|
||||
free(bis->filename);
|
||||
misc_free_temp_dev(bis->device);
|
||||
for (i = 0; i < MAX_TARGETS; i++) {
|
||||
if (bis->basetmp[i])
|
||||
misc_free_temp_dev(bis->basetmp[i]);
|
||||
}
|
||||
disk_free_info(bis->info);
|
||||
}
|
||||
|
||||
293
zipl/src/disk.c
293
zipl/src/disk.c
@@ -187,43 +187,134 @@ out_err:
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a script output represented by FH and consisting
|
||||
* of pairs 'key=value' (each such pair is on a separate line).
|
||||
* Check its consistency and set the extracted target parameters
|
||||
* to the array of "targets" at TD.
|
||||
*
|
||||
* NOTE: this function defines specifications on valid output of
|
||||
* zipl helper scripts. See zipl-support-for-mirrored-devices.txt
|
||||
* for details. Before modifying this function, make sure that it
|
||||
* won't lead to format change.
|
||||
*/
|
||||
static int set_target_parameters(FILE *fh, struct job_target_data *td)
|
||||
{
|
||||
int checkparm = 0;
|
||||
int idx[LAST_TARGET_PARAM] = {0};
|
||||
struct target *t;
|
||||
char buffer[80];
|
||||
char value[40];
|
||||
char *error;
|
||||
int i;
|
||||
|
||||
/**
|
||||
* Process a stream of 'key=value' pairs and distribute
|
||||
* them into groups.
|
||||
* The i-th occurrence of some "key" in the stream means
|
||||
* that the respective pair belongs to the group #i
|
||||
*/
|
||||
error = "Exceeded the maximum number of base disks";
|
||||
while (fgets(buffer, 80, fh)) {
|
||||
if (sscanf(buffer, "targetbase=%s", value) == 1) {
|
||||
td->targetbase = misc_strdup(value);
|
||||
checkparm++;
|
||||
t = target_at(td, idx[TARGET_BASE]++);
|
||||
if (!t)
|
||||
goto error;
|
||||
t->targetbase = misc_strdup(value);
|
||||
goto found;
|
||||
}
|
||||
if (sscanf(buffer, "targettype=%s", value) == 1) {
|
||||
type_from_target(value, &td->targettype);
|
||||
checkparm++;
|
||||
t = target_at(td, idx[TARGET_TYPE]++);
|
||||
if (!t)
|
||||
goto error;
|
||||
type_from_target(value, &t->targettype);
|
||||
goto found;
|
||||
}
|
||||
if (sscanf(buffer, "targetgeometry=%s", value) == 1) {
|
||||
td->targetcylinders =
|
||||
atoi(strtok(value, ","));
|
||||
td->targetheads = atoi(strtok(NULL, ","));
|
||||
td->targetsectors = atoi(strtok(NULL, ","));
|
||||
checkparm++;
|
||||
t = target_at(td, idx[TARGET_GEOMETRY]++);
|
||||
if (!t)
|
||||
goto error;
|
||||
t->targetcylinders = atoi(strtok(value, ","));
|
||||
t->targetheads = atoi(strtok(NULL, ","));
|
||||
t->targetsectors = atoi(strtok(NULL, ","));
|
||||
goto found;
|
||||
}
|
||||
if (sscanf(buffer, "targetblocksize=%s", value) == 1) {
|
||||
td->targetblocksize = atoi(value);
|
||||
checkparm++;
|
||||
t = target_at(td, idx[TARGET_BLOCKSIZE]++);
|
||||
if (!t)
|
||||
goto error;
|
||||
t->targetblocksize = atoi(value);
|
||||
goto found;
|
||||
}
|
||||
if (sscanf(buffer, "targetoffset=%s", value) == 1) {
|
||||
td->targetoffset = atol(value);
|
||||
checkparm++;
|
||||
t = target_at(td, idx[TARGET_OFFSET]++);
|
||||
if (!t)
|
||||
goto error;
|
||||
t->targetoffset = atol(value);
|
||||
goto found;
|
||||
}
|
||||
continue;
|
||||
found:
|
||||
t->check_params++;
|
||||
}
|
||||
if ((!disk_is_eckd(td->targettype) && checkparm < 4) ||
|
||||
(disk_is_eckd(td->targettype) && checkparm != 5)) {
|
||||
error_reason("Target parameters missing from script");
|
||||
return -1;
|
||||
/* Check for consistency */
|
||||
error = "Inconsistent script output";
|
||||
/*
|
||||
* First, calculate total number of groups
|
||||
*/
|
||||
td->nr_targets = 0;
|
||||
for (i = 0; i < MAX_TARGETS; i++) {
|
||||
t = target_at(td, i);
|
||||
if (t->check_params == 0)
|
||||
break;
|
||||
td->nr_targets++;
|
||||
}
|
||||
if (!td->nr_targets)
|
||||
/* No keywords found in the stream */
|
||||
goto error;
|
||||
/*
|
||||
* Each group has to include targetbase, targettype,
|
||||
* targetblocksize and targetoffset.
|
||||
*/
|
||||
if (td->nr_targets != idx[TARGET_BASE] ||
|
||||
td->nr_targets != idx[TARGET_TYPE] ||
|
||||
td->nr_targets != idx[TARGET_BLOCKSIZE] ||
|
||||
td->nr_targets != idx[TARGET_OFFSET])
|
||||
goto error;
|
||||
/*
|
||||
* In addition, any group of "ECKD" type has to include
|
||||
* targetgeometry
|
||||
*/
|
||||
for (i = 0; i < td->nr_targets; i++) {
|
||||
t = target_at(td, i);
|
||||
assert(t->check_params >= 4);
|
||||
if (disk_is_eckd(t->targettype) && t->check_params != 5)
|
||||
goto error;
|
||||
}
|
||||
return 0;
|
||||
error:
|
||||
error_reason("%s", error);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void print_base_disk_params(struct job_target_data *td, int index)
|
||||
{
|
||||
disk_type_t type = get_targettype(td, index);
|
||||
|
||||
if (!verbose)
|
||||
return;
|
||||
{
|
||||
fprintf(stderr, "Base disk '%s':\n", get_targetbase(td, index));
|
||||
fprintf(stderr, " layout........: %s\n", disk_get_type_name(type));
|
||||
}
|
||||
if (disk_is_eckd(type)) {
|
||||
fprintf(stderr, " heads.........: %u\n", get_targetheads(td, index));
|
||||
fprintf(stderr, " sectors.......: %u\n", get_targetsectors(td, index));
|
||||
fprintf(stderr, " cylinders.....: %u\n", get_targetcylinders(td, index));
|
||||
}
|
||||
{
|
||||
fprintf(stderr, " start.........: %lu\n", get_targetoffset(td, index));
|
||||
fprintf(stderr, " blksize.......: %u\n", get_targetblocksize(td, index));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -235,31 +326,57 @@ static int disk_set_info_by_hint(struct job_target_data *td,
|
||||
{
|
||||
int majnum, minnum;
|
||||
struct stat stats;
|
||||
|
||||
int i;
|
||||
/*
|
||||
* Currently multiple base disks with different parameters
|
||||
* are not supported
|
||||
*/
|
||||
data->devno = -1;
|
||||
data->phy_block_size = td->targetblocksize;
|
||||
data->type = td->targettype;
|
||||
data->partnum = 0;
|
||||
data->phy_block_size = get_targetblocksize(td, 0);
|
||||
data->type = get_targettype(td, 0);
|
||||
|
||||
if (sscanf(td->targetbase, "%d:%d", &majnum, &minnum) == 2) {
|
||||
data->device = makedev(majnum, minnum);
|
||||
data->targetbase = defined_as_device;
|
||||
data->partnum = minor(stats.st_rdev) - minnum;
|
||||
} else {
|
||||
if (stat(td->targetbase, &stats)) {
|
||||
error_reason(strerror(errno));
|
||||
error_text("Could not get information for "
|
||||
"file '%s'", td->targetbase);
|
||||
assert(td->nr_targets != 0);
|
||||
for (i = 1; i < td->nr_targets; i++) {
|
||||
if (data->type != get_targettype(td, i) ||
|
||||
data->phy_block_size != get_targetblocksize(td, i)) {
|
||||
print_base_disk_params(td, 0);
|
||||
print_base_disk_params(td, i);
|
||||
error_reason("Inconsistent base disk geometry in target device");
|
||||
return -1;
|
||||
}
|
||||
if (!S_ISBLK(stats.st_mode)) {
|
||||
error_reason("Target base device '%s' is not "
|
||||
"a block device",
|
||||
td->targetbase);
|
||||
}
|
||||
data->partnum = 0;
|
||||
data->targetbase_def = undefined;
|
||||
|
||||
for (i = 0; i < td->nr_targets; i++) {
|
||||
definition_t defined_as;
|
||||
|
||||
if (sscanf(get_targetbase(td, i),
|
||||
"%d:%d", &majnum, &minnum) == 2) {
|
||||
data->basedisks[i] = makedev(majnum, minnum);
|
||||
defined_as = defined_as_device;
|
||||
} else {
|
||||
if (stat(get_targetbase(td, i), &stats)) {
|
||||
error_reason(strerror(errno));
|
||||
error_text("Could not get information for "
|
||||
"file '%s'", get_targetbase(td, i));
|
||||
return -1;
|
||||
}
|
||||
if (!S_ISBLK(stats.st_mode)) {
|
||||
error_reason("Target base device '%s' is not "
|
||||
"a block device",
|
||||
get_targetbase(td, i));
|
||||
return -1;
|
||||
}
|
||||
data->basedisks[i] = stats.st_rdev;
|
||||
defined_as = defined_as_name;
|
||||
}
|
||||
if (data->targetbase_def != undefined &&
|
||||
data->targetbase_def != defined_as) {
|
||||
error_reason("Target base disks are defined by different ways");
|
||||
return -1;
|
||||
}
|
||||
data->device = stats.st_rdev;
|
||||
data->targetbase = defined_as_name;
|
||||
data->targetbase_def = defined_as;
|
||||
}
|
||||
if (data->type == disk_type_scsi && ioctl(fd, NVME_IOCTL_ID) >= 0)
|
||||
data->is_nvme = 1;
|
||||
@@ -446,11 +563,28 @@ static int run_targetbase_script(struct job_target_data *td,
|
||||
static int disk_set_geometry_by_hint(struct job_target_data *td,
|
||||
struct disk_info *data)
|
||||
{
|
||||
data->geo.heads = td->targetheads;
|
||||
data->geo.sectors = td->targetsectors;
|
||||
data->geo.cylinders = td->targetcylinders;
|
||||
data->geo.start = td->targetoffset;
|
||||
int i;
|
||||
/*
|
||||
* Currently multiple base disks with different parameters
|
||||
* are not supported
|
||||
*/
|
||||
data->geo.heads = get_targetheads(td, 0);
|
||||
data->geo.sectors = get_targetsectors(td, 0);
|
||||
data->geo.cylinders = get_targetcylinders(td, 0);
|
||||
data->geo.start = get_targetoffset(td, 0);
|
||||
|
||||
assert(td->nr_targets != 0);
|
||||
for (i = 1; i < td->nr_targets; i++) {
|
||||
if (data->geo.heads != get_targetheads(td, i) ||
|
||||
data->geo.sectors != get_targetsectors(td, i) ||
|
||||
data->geo.cylinders != get_targetcylinders(td, i) ||
|
||||
data->geo.start != get_targetoffset(td, i)) {
|
||||
print_base_disk_params(td, 0);
|
||||
print_base_disk_params(td, i);
|
||||
error_reason("Inconsistent base disk geometry in target device");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -515,14 +649,16 @@ static int disk_set_info_complete(struct job_target_data *td,
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare INFO required to perform IPL installation on the physical
|
||||
* disk where the logical DEVICE is located.
|
||||
* Prepare INFO required to perform IPL installation on physical disks
|
||||
* participating in the logical DEVICE.
|
||||
* Preparation is performed in 2 steps:
|
||||
*
|
||||
* 1. Find out a physical "base" disk where the logical DEVICE is
|
||||
* located. Calculate "target" parameters (type, geometry, physical
|
||||
* block size, data offset, etc);
|
||||
* 2. Complete INFO by the found base disk and target parameters.
|
||||
* 1. Find out a set of physical "base" disks participating in the
|
||||
* logical DEVICE. For each found disk calculate "target" parameters
|
||||
* (type, geometry, physical block size, data offset, etc) and store
|
||||
* it in the array of "targets" of TD;
|
||||
* 2. Complete INFO using the found base disks and calculated target
|
||||
* parameters.
|
||||
*
|
||||
* TD: optionally contains target parameters specified by user via
|
||||
* config file, or special "target options" of zipl tool.
|
||||
@@ -569,6 +705,7 @@ int disk_get_info(const char *device, struct job_target_data *td,
|
||||
goto error;
|
||||
if (disk_set_info_by_hint(td, data, fd))
|
||||
goto error;
|
||||
data->device = stats.st_rdev;
|
||||
break;
|
||||
case source_user:
|
||||
/*
|
||||
@@ -581,6 +718,12 @@ int disk_get_info(const char *device, struct job_target_data *td,
|
||||
goto error;
|
||||
if (disk_set_info_by_hint(td, data, fd))
|
||||
goto error;
|
||||
/*
|
||||
* multiple base disks are not supported
|
||||
* with this source type
|
||||
*/
|
||||
assert(td->nr_targets == 1);
|
||||
data->device = data->basedisks[0];
|
||||
break;
|
||||
case source_auto:
|
||||
/* no ready target parameters are available */
|
||||
@@ -588,6 +731,12 @@ int disk_get_info(const char *device, struct job_target_data *td,
|
||||
goto error;
|
||||
if (disk_set_info_auto(data, &stats, fd))
|
||||
goto error;
|
||||
/*
|
||||
* multiple base disks are not supported
|
||||
* with this source type
|
||||
*/
|
||||
data->basedisks[0] = data->device;
|
||||
td->nr_targets = 1;
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
@@ -943,6 +1092,33 @@ disk_print_devt(dev_t d)
|
||||
printf("%02x:%02x", major(d), minor(d));
|
||||
}
|
||||
|
||||
void disk_print_devname(dev_t dev)
|
||||
{
|
||||
struct util_proc_part_entry part_entry;
|
||||
|
||||
if (!util_proc_part_get_entry(dev, &part_entry)) {
|
||||
printf("%s", part_entry.name);
|
||||
util_proc_part_free_entry(&part_entry);
|
||||
} else {
|
||||
disk_print_devt(dev);
|
||||
}
|
||||
}
|
||||
|
||||
void prepare_footnote_ptr(int source, char *ptr)
|
||||
{
|
||||
if (source == source_user || source == source_script)
|
||||
strcpy(ptr, " *)");
|
||||
else
|
||||
strcpy(ptr, "");
|
||||
}
|
||||
|
||||
void print_footnote_ref(int source, const char *prefix)
|
||||
{
|
||||
if (source == source_user)
|
||||
printf("%s*) Data provided by user.\n", prefix);
|
||||
else if (source == source_script)
|
||||
printf("%s*) Data provided by script.\n", prefix);
|
||||
}
|
||||
|
||||
/* Return a name for a given disk TYPE. */
|
||||
char *
|
||||
@@ -994,12 +1170,11 @@ disk_is_large_volume(struct disk_info* info)
|
||||
void disk_print_info(struct disk_info *info, int source)
|
||||
{
|
||||
char footnote[4] = "";
|
||||
if (source == source_user || source == source_script)
|
||||
strcpy(footnote, " *)");
|
||||
|
||||
prepare_footnote_ptr(source, footnote);
|
||||
printf(" Device..........................: ");
|
||||
disk_print_devt(info->device);
|
||||
if (info->targetbase == defined_as_device)
|
||||
if (info->targetbase_def == defined_as_device)
|
||||
printf("%s", footnote);
|
||||
printf("\n");
|
||||
if (info->partnum != 0) {
|
||||
@@ -1010,7 +1185,7 @@ void disk_print_info(struct disk_info *info, int source)
|
||||
if (info->name) {
|
||||
printf(" Device name.....................: %s",
|
||||
info->name);
|
||||
if (info->targetbase == defined_as_name)
|
||||
if (info->targetbase_def == defined_as_name)
|
||||
printf("%s", footnote);
|
||||
printf("\n");
|
||||
}
|
||||
@@ -1053,21 +1228,7 @@ void disk_print_info(struct disk_info *info, int source)
|
||||
info->phy_block_size, footnote);
|
||||
printf(" Device size in physical blocks..: %ld\n",
|
||||
(long) info->phy_blocks);
|
||||
if (source == source_user)
|
||||
printf(" *) Data provided by user.\n");
|
||||
if (source == source_script)
|
||||
printf(" *) Data provided by script.\n");
|
||||
}
|
||||
|
||||
/* Print textual representation of geo structure. */
|
||||
void
|
||||
disk_print_geo(struct disk_info *data)
|
||||
{
|
||||
printf(" geo.heads.........:%u\n", data->geo.heads);
|
||||
printf(" geo.sectors.......:%u\n", data->geo.sectors);
|
||||
printf(" geo.cylinders.....:%u\n", data->geo.cylinders);
|
||||
printf(" geo.start.........:%lu\n", data->geo.start);
|
||||
printf(" blksize...........:%u\n", data->phy_block_size);
|
||||
print_footnote_ref(source, " ");
|
||||
}
|
||||
|
||||
/* Check whether a block is a zero block which identifies a hole in a file.
|
||||
|
||||
@@ -434,11 +434,14 @@ int install_bootloader(struct job_data *job, struct install_set *bis)
|
||||
{
|
||||
disk_blockptr_t *scsi_dump_sb_blockptr = &bis->scsi_dump_sb_blockptr;
|
||||
struct disk_info *info = bis->info;
|
||||
char *device = bis->device;
|
||||
int fd, rc;
|
||||
char footnote[4];
|
||||
int rc;
|
||||
int i;
|
||||
|
||||
if (!info)
|
||||
return 0;
|
||||
|
||||
prepare_footnote_ptr(job->target.source, footnote);
|
||||
/* Inform user about what we're up to */
|
||||
printf("Preparing boot device for %s%s: ",
|
||||
disk_get_ipl_type(info->type,
|
||||
@@ -455,40 +458,58 @@ int install_bootloader(struct job_data *job, struct install_set *bis)
|
||||
disk_print_devt(info->device);
|
||||
printf(".\n");
|
||||
}
|
||||
/* Open device file */
|
||||
fd = open(device, O_RDWR);
|
||||
if (fd == -1) {
|
||||
error_reason(strerror(errno));
|
||||
error_text("Could not open temporary device file '%s'",
|
||||
device);
|
||||
return -1;
|
||||
}
|
||||
/* Ensure that potential cache inconsistencies between disk and
|
||||
* partition are resolved by flushing the corresponding buffers. */
|
||||
if (!dry_run) {
|
||||
if (ioctl(fd, BLKFLSBUF)) {
|
||||
fprintf(stderr, "Warning: Could not flush disk "
|
||||
"caches.\n");
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Depending on disk type, install one or two program tables
|
||||
* for CCW-type IPL and (or) for List-Directed IPL (see the
|
||||
* picture in comments above)
|
||||
*/
|
||||
if (job->id == job_dump_partition) {
|
||||
rc = install_bootloader_dump(bis->tables, info,
|
||||
scsi_dump_sb_blockptr,
|
||||
is_ngdump_enabled(job),
|
||||
fd);
|
||||
} else {
|
||||
rc = install_bootloader_ipl(bis->tables, info, fd);
|
||||
}
|
||||
/* Install independently on each physical target base */
|
||||
|
||||
if (fsync(fd))
|
||||
error_text("Could not sync device file '%s'", device);
|
||||
if (close(fd))
|
||||
error_text("Could not close device file '%s'", device);
|
||||
for (i = 0; i < job_get_nr_targets(job); i++) {
|
||||
int fd;
|
||||
|
||||
if (verbose) {
|
||||
printf("Installing on base disk: ");
|
||||
disk_print_devname(info->basedisks[i]);
|
||||
printf("%s.\n", footnote);
|
||||
}
|
||||
/* Open device file */
|
||||
fd = open(bis->basetmp[i], O_RDWR);
|
||||
if (fd == -1) {
|
||||
error_reason(strerror(errno));
|
||||
error_text("Could not open temporary device file '%s'",
|
||||
bis->basetmp[i]);
|
||||
return -1;
|
||||
}
|
||||
/* Ensure that potential cache inconsistencies between disk and
|
||||
* partition are resolved by flushing the corresponding buffers.
|
||||
*/
|
||||
if (!dry_run) {
|
||||
if (ioctl(fd, BLKFLSBUF)) {
|
||||
fprintf(stderr, "Warning: Could not flush disk "
|
||||
"caches.\n");
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Depending on disk type, install one or two program tables
|
||||
* for CCW-type IPL and (or) for List-Directed IPL (see the
|
||||
* picture in comments above)
|
||||
*/
|
||||
if (job->id == job_dump_partition) {
|
||||
rc = install_bootloader_dump(bis->tables, info,
|
||||
scsi_dump_sb_blockptr,
|
||||
is_ngdump_enabled(job),
|
||||
fd);
|
||||
} else {
|
||||
rc = install_bootloader_ipl(bis->tables, info,
|
||||
fd);
|
||||
}
|
||||
if (fsync(fd))
|
||||
error_text("Could not sync device file '%s'",
|
||||
bis->basetmp[i]);
|
||||
if (close(fd))
|
||||
error_text("Could not close device file '%s'",
|
||||
bis->basetmp[i]);
|
||||
if (rc)
|
||||
break;
|
||||
}
|
||||
if (verbose)
|
||||
print_footnote_ref(job->target.source, "");
|
||||
|
||||
if (!dry_run && rc == 0) {
|
||||
if (info->devno >= 0)
|
||||
|
||||
@@ -369,11 +369,13 @@ get_command_line(int argc, char* argv[], struct command_line* line)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void free_target_data(struct job_target_data *data)
|
||||
{
|
||||
int i;
|
||||
|
||||
free(data->bootmap_dir);
|
||||
free(data->targetbase);
|
||||
for (i = 0; i < data->nr_targets; i++)
|
||||
free(get_targetbase(data, i));
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -1345,6 +1347,27 @@ type_from_target(char *target, disk_type_t *type)
|
||||
}
|
||||
}
|
||||
|
||||
int set_targettype(struct job_target_data *data, int index, char *value)
|
||||
{
|
||||
return type_from_target(value,
|
||||
&target_at(data, index)->targettype);
|
||||
}
|
||||
|
||||
int job_set_targettype(struct job_data *job, char *value)
|
||||
{
|
||||
return set_targettype(&job->target, 0, value);
|
||||
}
|
||||
|
||||
static int job_set_target(struct job_data *job, char *value)
|
||||
{
|
||||
job_set_targetbase(job, value);
|
||||
if (!job_get_targetbase(job))
|
||||
return -1;
|
||||
job_set_nr_targets(job, 1);
|
||||
job->target.source = source_user;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
get_job_from_section_data(char* data[], struct job_data* job, char* section)
|
||||
{
|
||||
@@ -1361,32 +1384,28 @@ get_job_from_section_data(char* data[], struct job_data* job, char* section)
|
||||
return -1;
|
||||
/* Fill in target */
|
||||
if (data[(int) scan_keyword_targetbase] != NULL) {
|
||||
job->target.targetbase =
|
||||
misc_strdup(data[(int)
|
||||
scan_keyword_targetbase]);
|
||||
if (job->target.targetbase == NULL)
|
||||
if (job_set_target(job, misc_strdup(data[(int)
|
||||
scan_keyword_targetbase])))
|
||||
return -1;
|
||||
job->target.source = source_user;
|
||||
}
|
||||
if (data[(int) scan_keyword_targettype] != NULL) {
|
||||
if (type_from_target(
|
||||
data[(int) scan_keyword_targettype],
|
||||
&job->target.targettype))
|
||||
if (job_set_targettype(job,
|
||||
data[(int) scan_keyword_targettype]))
|
||||
return -1;
|
||||
}
|
||||
if (data[(int) scan_keyword_targetgeometry] != NULL) {
|
||||
job->target.targetcylinders =
|
||||
job_set_targetcylinders(job,
|
||||
atoi(strtok(data[(int)
|
||||
scan_keyword_targetgeometry], ","));
|
||||
job->target.targetheads = atoi(strtok(NULL, ","));
|
||||
job->target.targetsectors = atoi(strtok(NULL, ","));
|
||||
scan_keyword_targetgeometry], ",")));
|
||||
job_set_targetheads(job, atoi(strtok(NULL, ",")));
|
||||
job_set_targetsectors(job, atoi(strtok(NULL, ",")));
|
||||
}
|
||||
if (data[(int) scan_keyword_targetblocksize] != NULL)
|
||||
job->target.targetblocksize =
|
||||
atoi(data[(int) scan_keyword_targetblocksize]);
|
||||
job_set_targetblocksize(job,
|
||||
atoi(data[(int) scan_keyword_targetblocksize]));
|
||||
if (data[(int) scan_keyword_targetoffset] != NULL)
|
||||
job->target.targetoffset =
|
||||
atol(data[(int) scan_keyword_targetoffset]);
|
||||
job_set_targetoffset(job,
|
||||
atol(data[(int) scan_keyword_targetoffset]));
|
||||
/* Fill in name and address of image file */
|
||||
|
||||
job->data.ipl.common.image = misc_strdup(
|
||||
@@ -1614,37 +1633,32 @@ get_menu_job(struct scan_token* scan, char* menu, struct job_data* job)
|
||||
return -1;
|
||||
break;
|
||||
case scan_keyword_targetbase:
|
||||
job->target.targetbase = misc_strdup(
|
||||
scan[i].content.keyword.value);
|
||||
if (job->target.targetbase == NULL)
|
||||
if (job_set_target(job, misc_strdup(
|
||||
scan[i].content.keyword.value)))
|
||||
return -1;
|
||||
job->target.source = source_user;
|
||||
break;
|
||||
case scan_keyword_targettype:
|
||||
if (type_from_target(
|
||||
scan[i].content.keyword.value,
|
||||
&job->target.targettype))
|
||||
if (job_set_targettype(job,
|
||||
scan[i].content.keyword.value))
|
||||
return -1;
|
||||
break;
|
||||
case scan_keyword_targetgeometry:
|
||||
job->target.targetcylinders =
|
||||
job_set_targetcylinders(job,
|
||||
atoi(strtok(
|
||||
scan[i].content.keyword.value,
|
||||
","));
|
||||
job->target.targetheads =
|
||||
atoi(strtok(NULL, ","));
|
||||
job->target.targetsectors =
|
||||
atoi(strtok(NULL, ","));
|
||||
",")));
|
||||
job_set_targetheads(job,
|
||||
atoi(strtok(NULL, ",")));
|
||||
job_set_targetsectors(job,
|
||||
atoi(strtok(NULL, ",")));
|
||||
break;
|
||||
case scan_keyword_targetblocksize:
|
||||
job->target.targetblocksize =
|
||||
atoi(
|
||||
scan[i].content.keyword.value);
|
||||
job_set_targetblocksize(job, atoi(
|
||||
scan[i].content.keyword.value));
|
||||
break;
|
||||
case scan_keyword_targetoffset:
|
||||
job->target.targetoffset =
|
||||
atol(
|
||||
scan[i].content.keyword.value);
|
||||
job_set_targetoffset(job, atol(
|
||||
scan[i].content.keyword.value));
|
||||
break;
|
||||
default:
|
||||
/* Should not happen */
|
||||
|
||||
Reference in New Issue
Block a user