From 8d46affabf1d3f64b26a6f423a89d48f2fadcb5f Mon Sep 17 00:00:00 2001 From: "Jason J. Herne" Date: Tue, 17 Nov 2020 15:59:34 -0500 Subject: [PATCH] s390-tools: zipl: Fix NVMe partition and base device detection Copying the SCSI scheme wasn't good enough due to how major/minor numbers are assigned by the blkext driver. We now query the relevant information via sysfs. Signed-off-by: Jason J. Herne Reviewed-by: Peter Oberparleiter --- zipl/src/disk.c | 95 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 93 insertions(+), 2 deletions(-) diff --git a/zipl/src/disk.c b/zipl/src/disk.c index 8abf668..5baeaeb 100644 --- a/zipl/src/disk.c +++ b/zipl/src/disk.c @@ -89,6 +89,88 @@ disk_determine_dasd_type(struct disk_info *data, return 0; } +static int blkext_get_partnum(dev_t dev) +{ + char path[PATH_MAX], *buf; + int dev_major, dev_minor, partnum = -1; + + dev_major = major(dev); + dev_minor = minor(dev); + snprintf(path, PATH_MAX, "/sys/dev/block/%d:%d/partition", + dev_major, dev_minor); + + if (misc_read_special_file(path, &buf, NULL, 1)) { + error_text("Could not read from path '%s'", path); + return -1; + } + + partnum = atoi(buf); + free(buf); + if (partnum < 0) { + error_text("Bad partition number in '%s'", path); + return -1; + } + + return partnum; +} + +static int blkext_is_base_device(dev_t dev) +{ + int dev_major, dev_minor; + char path[PATH_MAX]; + struct stat stats; + + dev_major = major(dev); + dev_minor = minor(dev); + + snprintf(path, PATH_MAX, "/sys/dev/block/%d:%d/partition", + dev_major, dev_minor); + return (stat(path, &stats)); +} + +static int blkext_get_base_dev(dev_t dev, dev_t *base_dev) +{ + int base_major, base_minor; + char dev_path[PATH_MAX], base_path[PATH_MAX]; + char *temp_path, *buf; + + misc_asprintf(&temp_path, "/sys/dev/block/%d:%d", major(dev), minor(dev)); + if (!realpath(temp_path, dev_path)) { + error_reason(strerror(errno)); + error_text("Could not resolve link %s", temp_path); + free(temp_path); + return -1; + } + free(temp_path); + + misc_asprintf(&temp_path, "%s/..", dev_path); + if (!realpath(temp_path, base_path)) { + error_reason(strerror(errno)); + error_text("Could not resolve path %s", temp_path); + free(temp_path); + return -1; + } + free(temp_path); + + misc_asprintf(&temp_path, "%s/dev", base_path); + if (misc_read_special_file(temp_path, &buf, NULL, 1)) { + error_text("Could not read from path '%s'", temp_path); + free(temp_path); + return -1; + } + free(temp_path); + + if (sscanf(buf, "%i:%i", &base_major, &base_minor) != 2) { + error_text("Could not parse major:minor from string '%s'", buf); + free(buf); + return -1; + } + + free(buf); + *base_dev = makedev(base_major, base_minor); + return 0; +} + /* Return non-zero for ECKD type. */ int disk_is_eckd(disk_type_t type) @@ -409,8 +491,17 @@ disk_get_info(const char* device, struct job_target_data* target, } else if (strcmp(data->drv_name, "blkext") == 0) { data->devno = -1; data->type = disk_type_scsi; - data->partnum = stats.st_rdev & SCSI_PARTN_MASK; - data->device = stats.st_rdev & ~SCSI_PARTN_MASK; + + if (blkext_is_base_device(stats.st_rdev)) { + data->device = stats.st_rdev; + data->partnum = 0; + } else { + if (blkext_get_base_dev(stats.st_rdev, &data->device)) + goto out_close; + data->partnum = blkext_get_partnum(stats.st_rdev); + if (data->partnum == -1) + goto out_close; + } } else { /* Driver name is unknown */ error_reason("Unsupported device driver '%s'", data->drv_name); -- 2.21.1