Accepting request 1201422 from Base:System
* Applied patches (bsc#1230345) - zipl/src: add basic support for multiple target base disks - s390-tools-01-zipl-src-add-basic-support-for-multiple-target-base-disks.patch - s390-tools-02-zipl-src-add-basic-support-for-multiple-target-base-disks.patch OBS-URL: https://build.opensuse.org/request/show/1201422 OBS-URL: https://build.opensuse.org/package/show/openSUSE:Factory/s390-tools?expand=0&rev=81
This commit is contained in:
commit
f85aac9036
@ -0,0 +1,969 @@
|
||||
From d6b702d5791b47f735960ad1f6986e0a32768df6 Mon Sep 17 00:00:00 2001
|
||||
From: Eduard Shishkin <edward6@linux.ibm.com>
|
||||
Date: Thu, 11 Jul 2024 10:43:37 +0200
|
||||
Subject: [PATCH] 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>
|
||||
---
|
||||
zipl/include/disk.h | 14 +-
|
||||
zipl/include/install.h | 2
|
||||
zipl/include/job.h | 122 ++++++++++++++++++--
|
||||
zipl/include/zipl.h | 1
|
||||
zipl/src/bootmap.c | 23 ++-
|
||||
zipl/src/disk.c | 295 +++++++++++++++++++++++++++++++++++++------------
|
||||
zipl/src/install.c | 89 +++++++++-----
|
||||
zipl/src/job.c | 82 +++++++------
|
||||
8 files changed, 469 insertions(+), 159 deletions(-)
|
||||
|
||||
--- a/zipl/include/disk.h
|
||||
+++ b/zipl/include/disk.h
|
||||
@@ -56,13 +56,14 @@
|
||||
/* 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 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 @@
|
||||
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 @@
|
||||
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 */
|
||||
--- a/zipl/include/install.h
|
||||
+++ b/zipl/include/install.h
|
||||
@@ -71,7 +71,7 @@
|
||||
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;
|
||||
--- a/zipl/include/job.h
|
||||
+++ b/zipl/include/job.h
|
||||
@@ -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 @@
|
||||
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 @@
|
||||
} 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 @@
|
||||
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);
|
||||
--- a/zipl/include/zipl.h
|
||||
+++ b/zipl/include/zipl.h
|
||||
@@ -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
|
||||
--- a/zipl/src/bootmap.c
|
||||
+++ b/zipl/src/bootmap.c
|
||||
@@ -1477,9 +1477,9 @@
|
||||
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,
|
||||
@@ -1543,6 +1543,8 @@
|
||||
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;
|
||||
@@ -1576,8 +1578,12 @@
|
||||
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,
|
||||
@@ -1692,9 +1698,9 @@
|
||||
/* 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);
|
||||
@@ -1844,6 +1850,9 @@
|
||||
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);
|
||||
}
|
||||
--- a/zipl/src/disk.c
|
||||
+++ b/zipl/src/disk.c
|
||||
@@ -187,43 +187,134 @@
|
||||
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 @@
|
||||
{
|
||||
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 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 @@
|
||||
}
|
||||
|
||||
/**
|
||||
- * 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.
|
||||
@@ -566,6 +702,7 @@
|
||||
goto error;
|
||||
if (disk_set_info_by_hint(td, data, fd))
|
||||
goto error;
|
||||
+ data->device = stats.st_rdev;
|
||||
break;
|
||||
case source_user:
|
||||
/*
|
||||
@@ -578,6 +715,12 @@
|
||||
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 */
|
||||
@@ -585,6 +728,12 @@
|
||||
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);
|
||||
@@ -940,6 +1089,33 @@
|
||||
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 *
|
||||
@@ -991,12 +1167,11 @@
|
||||
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) {
|
||||
@@ -1007,7 +1182,7 @@
|
||||
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");
|
||||
}
|
||||
@@ -1050,21 +1225,7 @@
|
||||
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.
|
||||
--- a/zipl/src/install.c
|
||||
+++ b/zipl/src/install.c
|
||||
@@ -434,11 +434,14 @@
|
||||
{
|
||||
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 @@
|
||||
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");
|
||||
+ /* Install independently on each physical target base */
|
||||
+
|
||||
+ 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;
|
||||
}
|
||||
- /*
|
||||
- * 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'", device);
|
||||
- if (close(fd))
|
||||
- error_text("Could not close device file '%s'", device);
|
||||
+ if (verbose)
|
||||
+ print_footnote_ref(job->target.source, "");
|
||||
|
||||
if (!dry_run && rc == 0) {
|
||||
if (info->devno >= 0)
|
||||
--- a/zipl/src/job.c
|
||||
+++ b/zipl/src/job.c
|
||||
@@ -1346,6 +1346,27 @@
|
||||
}
|
||||
}
|
||||
|
||||
+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)
|
||||
{
|
||||
@@ -1362,32 +1383,28 @@
|
||||
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(
|
||||
@@ -1615,37 +1632,32 @@
|
||||
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 */
|
@ -0,0 +1,15 @@
|
||||
--- a/zipl/src/job.c 2024-09-16 14:20:09.321762661 +0200
|
||||
+++ b/zipl/src/job.c 2024-09-16 14:29:28.601846724 +0200
|
||||
@@ -373,8 +373,11 @@
|
||||
static 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
|
@ -1,3 +1,11 @@
|
||||
-------------------------------------------------------------------
|
||||
Mon Sep 16 12:49:55 UTC 2024 - Nikolay Gueorguiev <nikolay.gueorguiev@suse.com>
|
||||
|
||||
* Applied patches (bsc#1230345)
|
||||
- zipl/src: add basic support for multiple target base disks
|
||||
- s390-tools-01-zipl-src-add-basic-support-for-multiple-target-base-disks.patch
|
||||
- s390-tools-02-zipl-src-add-basic-support-for-multiple-target-base-disks.patch
|
||||
|
||||
-------------------------------------------------------------------
|
||||
Mon Aug 26 09:17:17 UTC 2024 - Nikolay Gueorguiev <nikolay.gueorguiev@suse.com>
|
||||
|
||||
|
@ -155,6 +155,8 @@ Patch912: s390-tools-ALP-zdev-live.patch
|
||||
Patch913: s390-tools-sles15sp6-kdump-initrd-59-zfcp-compat-rules.patch
|
||||
Patch914: s390-tools-slfo-01-parse-ipl-device-for-activation.patch
|
||||
Patch915: s390-tools-2.34-Fix-Rust-compilation-errors.patch
|
||||
Patch916: s390-tools-01-zipl-src-add-basic-support-for-multiple-target-base-disks.patch
|
||||
Patch917: s390-tools-02-zipl-src-add-basic-support-for-multiple-target-base-disks.patch
|
||||
###
|
||||
|
||||
BuildRequires: curl-devel
|
||||
|
Loading…
Reference in New Issue
Block a user