diff --git a/s390-tools-01-zipl-src-add-basic-support-for-multiple-target-base-disks.patch b/s390-tools-01-zipl-src-add-basic-support-for-multiple-target-base-disks.patch new file mode 100644 index 0000000..aa5a861 --- /dev/null +++ b/s390-tools-01-zipl-src-add-basic-support-for-multiple-target-base-disks.patch @@ -0,0 +1,969 @@ +From d6b702d5791b47f735960ad1f6986e0a32768df6 Mon Sep 17 00:00:00 2001 +From: Eduard Shishkin +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 +Reviewed-by: Stefan Haberland +Signed-off-by: Steffen Eiden +--- + 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 */ diff --git a/s390-tools-02-zipl-src-add-basic-support-for-multiple-target-base-disks.patch b/s390-tools-02-zipl-src-add-basic-support-for-multiple-target-base-disks.patch new file mode 100644 index 0000000..bf8dfb1 --- /dev/null +++ b/s390-tools-02-zipl-src-add-basic-support-for-multiple-target-base-disks.patch @@ -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 diff --git a/s390-tools.changes b/s390-tools.changes index 5c6fc0e..2f6c8aa 100644 --- a/s390-tools.changes +++ b/s390-tools.changes @@ -1,3 +1,11 @@ +------------------------------------------------------------------- +Mon Sep 16 12:49:55 UTC 2024 - Nikolay Gueorguiev + +* 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 diff --git a/s390-tools.spec b/s390-tools.spec index c38bb48..474b690 100644 --- a/s390-tools.spec +++ b/s390-tools.spec @@ -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