Blame SOURCES/0051-fdasd-geometry-handling-updated-from-upstream-s390-t.patch

fc4a62
From 42944dd6be000d49d5e1178a576e269aac6f6335 Mon Sep 17 00:00:00 2001
fc4a62
From: Viktor Mihajlovski <mihajlov@linux.vnet.ibm.com>
fc4a62
Date: Thu, 17 Sep 2015 15:33:28 +0200
fc4a62
Subject: [PATCH 51/54] fdasd: geometry handling updated from upstream
fc4a62
 s390-tools
fc4a62
fc4a62
Remove the necessity for DASD-specific ioctls for partition handling.
fc4a62
This allows to correctly handle DASD-backed virtio block devices.
fc4a62
fc4a62
Note that this is necessary because virtio is just the transport.
fc4a62
A DASD, even if provided via virtio, still has it's unique
fc4a62
characteristics, which means that only traditional DASD partition
fc4a62
table formats can be used (no MBR, GPT, or similar).
fc4a62
fc4a62
Use bzero for initialization to make sure all struct members are
fc4a62
properly cleared. Also changed partition list handling code to be
fc4a62
more similar to upstream s390-tools fdasd.
fc4a62
fc4a62
Further, enhanced error handling capabilities by providing a
fc4a62
return code by fdasd_get_geometry.
fc4a62
fc4a62
Code is largely backported from s390-tools project.
fc4a62
fc4a62
Signed-off-by: Viktor Mihajlovski <mihajlov@linux.vnet.ibm.com>
fc4a62
Acked-by: Stefan Haberland <stefan.haberland@de.ibm.com>
fc4a62
Signed-off-by: Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
fc4a62
Signed-off-by: Brian C. Lane <bcl@redhat.com>
fc4a62
fc4a62
(cherry picked from commit 4d480d980a9b69b432b8d60df3c4397ba8cdc965)
fc4a62
fc4a62
Resolves: rhbz#1676604
fc4a62
---
fc4a62
 include/parted/fdasd.h   |   4 +-
fc4a62
 libparted/labels/fdasd.c | 166 +++++++++++++++++++++++++++------------
fc4a62
 2 files changed, 119 insertions(+), 51 deletions(-)
fc4a62
fc4a62
diff --git a/include/parted/fdasd.h b/include/parted/fdasd.h
fc4a62
index 6f6a7e0..4e351c4 100644
fc4a62
--- a/include/parted/fdasd.h
fc4a62
+++ b/include/parted/fdasd.h
fc4a62
@@ -190,6 +190,8 @@ typedef struct format_data_t {
fc4a62
 #define BLKRRPART  _IO(0x12,95)
fc4a62
 /* get block device sector size */
fc4a62
 #define BLKSSZGET  _IO(0x12,104)
fc4a62
+/* device size in bytes (u64 *arg)*/
fc4a62
+#define BLKGETSIZE64 _IOR(0x12,114,size_t)
fc4a62
 /* get device geometry */
fc4a62
 #define HDIO_GETGEO		0x0301
fc4a62
 
fc4a62
@@ -285,7 +287,7 @@ enum fdasd_failure {
fc4a62
 
fc4a62
 void fdasd_cleanup (fdasd_anchor_t *anchor);
fc4a62
 void fdasd_initialize_anchor (fdasd_anchor_t * anc);
fc4a62
-void fdasd_get_geometry (const PedDevice *dev, fdasd_anchor_t *anc, int fd);
fc4a62
+int fdasd_get_geometry (const PedDevice *dev, fdasd_anchor_t *anc, int fd);
fc4a62
 void fdasd_check_api_version (fdasd_anchor_t *anc, int fd);
fc4a62
 int fdasd_check_volume (fdasd_anchor_t *anc, int fd);
fc4a62
 int fdasd_write_labels (fdasd_anchor_t *anc, int fd);
fc4a62
diff --git a/libparted/labels/fdasd.c b/libparted/labels/fdasd.c
fc4a62
index 1f87937..7e6a77a 100644
fc4a62
--- a/libparted/labels/fdasd.c
fc4a62
+++ b/libparted/labels/fdasd.c
fc4a62
@@ -210,27 +210,7 @@ fdasd_initialize_anchor (fdasd_anchor_t * anc)
fc4a62
 	partition_info_t *p = NULL;
fc4a62
 	partition_info_t *q = NULL;
fc4a62
 
fc4a62
-	anc->devno             = 0;
fc4a62
-	anc->dev_type          = 0;
fc4a62
-	anc->used_partitions   = 0;
fc4a62
-
fc4a62
-	anc->silent            = 0;
fc4a62
-	anc->verbose           = 0;
fc4a62
-	anc->big_disk          = 0;
fc4a62
-	anc->volid_specified   = 0;
fc4a62
-	anc->config_specified  = 0;
fc4a62
-	anc->auto_partition    = 0;
fc4a62
-	anc->devname_specified = 0;
fc4a62
-	anc->print_table       = 0;
fc4a62
-
fc4a62
-	anc->option_reuse      = 0;
fc4a62
-	anc->option_recreate   = 0;
fc4a62
-
fc4a62
-	anc->vlabel_changed    = 0;
fc4a62
-	anc->vtoc_changed      = 0;
fc4a62
-	anc->blksize           = 0;
fc4a62
-	anc->fspace_trk        = 0;
fc4a62
-	anc->label_pos         = 0;
fc4a62
+	bzero(anc, sizeof(fdasd_anchor_t));
fc4a62
 
fc4a62
 	for (i=0; i
fc4a62
 		setpos(anc, i, -1);
fc4a62
@@ -272,24 +252,18 @@ fdasd_initialize_anchor (fdasd_anchor_t * anc)
fc4a62
 		if (p == NULL)
fc4a62
 			fdasd_error(anc, malloc_failed,
fc4a62
 				    _("No room for partition info."));
fc4a62
-		p->used       = 0x00;
fc4a62
-		p->len_trk    = 0;
fc4a62
-		p->start_trk  = 0;
fc4a62
-		p->fspace_trk = 0;
fc4a62
-		p->type       = 0;
fc4a62
+		bzero(p, sizeof(partition_info_t));
fc4a62
 
fc4a62
 		/* add p to double pointered list */
fc4a62
 		if (i == 1) {
fc4a62
-	        anc->first = p;
fc4a62
-			p->prev = NULL;
fc4a62
+		        anc->first = p;
fc4a62
 		} else if (i == USABLE_PARTITIONS) {
fc4a62
-	        anc->last = p;
fc4a62
-	        p->next = NULL;
fc4a62
+		        anc->last = p;
fc4a62
 			p->prev = q;
fc4a62
 			q->next = p;
fc4a62
 		} else {
fc4a62
-	        p->prev = q;
fc4a62
-	        q->next = p;
fc4a62
+	                p->prev = q;
fc4a62
+	                q->next = p;
fc4a62
 		}
fc4a62
 
fc4a62
 		p->f1 = malloc(sizeof(format1_label_t));
fc4a62
@@ -946,16 +920,78 @@ fdasd_check_api_version (fdasd_anchor_t *anc, int f)
fc4a62
 	}
fc4a62
 }
fc4a62
 
fc4a62
+/*
fc4a62
+ * The following two functions match those in the DASD ECKD device driver.
fc4a62
+ * They are used to compute how many records of a given size can be stored
fc4a62
+ * in one track.
fc4a62
+ */
fc4a62
+static unsigned int ceil_quot(unsigned int d1, unsigned int d2)
fc4a62
+{
fc4a62
+	return (d1 + (d2 - 1)) / d2;
fc4a62
+}
fc4a62
+
fc4a62
+/* kl: key length, dl: data length */
fc4a62
+static unsigned int recs_per_track(unsigned short dev_type, unsigned int kl,
fc4a62
+				   unsigned int dl)
fc4a62
+{
fc4a62
+	unsigned int dn, kn;
fc4a62
+
fc4a62
+	switch (dev_type) {
fc4a62
+	case DASD_3380_TYPE:
fc4a62
+		if (kl)
fc4a62
+			return 1499 / (15 + 7 + ceil_quot(kl + 12, 32) +
fc4a62
+				       ceil_quot(dl + 12, 32));
fc4a62
+		else
fc4a62
+			return 1499 / (15 + ceil_quot(dl + 12, 32));
fc4a62
+	case DASD_3390_TYPE:
fc4a62
+		dn = ceil_quot(dl + 6, 232) + 1;
fc4a62
+		if (kl) {
fc4a62
+			kn = ceil_quot(kl + 6, 232) + 1;
fc4a62
+			return 1729 / (10 + 9 + ceil_quot(kl + 6 * kn, 34) +
fc4a62
+				       9 + ceil_quot(dl + 6 * dn, 34));
fc4a62
+		} else
fc4a62
+			return 1729 / (10 + 9 + ceil_quot(dl + 6 * dn, 34));
fc4a62
+	case DASD_9345_TYPE:
fc4a62
+		dn = ceil_quot(dl + 6, 232) + 1;
fc4a62
+		if (kl) {
fc4a62
+			kn = ceil_quot(kl + 6, 232) + 1;
fc4a62
+			return 1420 / (18 + 7 + ceil_quot(kl + 6 * kn, 34) +
fc4a62
+				       ceil_quot(dl + 6 * dn, 34));
fc4a62
+		} else
fc4a62
+			return 1420 / (18 + 7 + ceil_quot(dl + 6 * dn, 34));
fc4a62
+	}
fc4a62
+	return 0;
fc4a62
+}
fc4a62
+
fc4a62
+/*
fc4a62
+ * Verify that number of tracks (heads) per cylinder and number of
fc4a62
+ * sectors per track match the expected values for a given device type
fc4a62
+ * and block size.
fc4a62
+ * Returns 1 for a valid match and 0 otherwise.
fc4a62
+ */
fc4a62
+static int fdasd_verify_geometry(unsigned short dev_type, int blksize,
fc4a62
+				 struct fdasd_hd_geometry *geometry)
fc4a62
+{
fc4a62
+	unsigned int expected_sectors;
fc4a62
+	if (geometry->heads != 15)
fc4a62
+		return 0;
fc4a62
+	expected_sectors = recs_per_track(dev_type, 0, blksize);
fc4a62
+	if (geometry->sectors == expected_sectors)
fc4a62
+		return 1;
fc4a62
+	return 0;
fc4a62
+}
fc4a62
+
fc4a62
 /*
fc4a62
  * reads dasd geometry data
fc4a62
  */
fc4a62
-void
fc4a62
+int
fc4a62
 fdasd_get_geometry (const PedDevice *dev, fdasd_anchor_t *anc, int f)
fc4a62
 {
fc4a62
 	PDEBUG
fc4a62
 	int blksize = 0;
fc4a62
 	dasd_information_t dasd_info;
fc4a62
 	struct dasd_eckd_characteristics *characteristics;
fc4a62
+	unsigned long long size_in_bytes;
fc4a62
 
fc4a62
 	/* We can't get geometry from a regular file,
fc4a62
 	   so simulate something usable, for the sake of testing.  */
fc4a62
@@ -979,6 +1015,12 @@ fdasd_get_geometry (const PedDevice *dev, fdasd_anchor_t *anc, int f)
fc4a62
 				anc->geo.heads;
fc4a62
 	    anc->is_file = 1;
fc4a62
 	} else {
fc4a62
+	        if (ioctl(f, BLKGETSIZE64, &size_in_bytes) != 0) {
fc4a62
+		        fdasd_error(anc, unable_to_ioctl,
fc4a62
+				    _("Could not retrieve disk size."));
fc4a62
+			goto error;
fc4a62
+		}
fc4a62
+
fc4a62
 		if (ioctl(f, HDIO_GETGEO, &anc->geo) != 0)
fc4a62
 			fdasd_error(anc, unable_to_ioctl,
fc4a62
 			    _("Could not retrieve disk geometry information."));
fc4a62
@@ -988,27 +1030,51 @@ fdasd_get_geometry (const PedDevice *dev, fdasd_anchor_t *anc, int f)
fc4a62
 			    _("Could not retrieve blocksize information."));
fc4a62
 
fc4a62
 		/* get disk type */
fc4a62
-		if (ioctl(f, BIODASDINFO, &dasd_info) != 0)
fc4a62
-			fdasd_error(anc, unable_to_ioctl,
fc4a62
-				    _("Could not retrieve disk information."));
fc4a62
-
fc4a62
-		characteristics = (struct dasd_eckd_characteristics *)
fc4a62
-					&dasd_info.characteristics;
fc4a62
-		if (characteristics->no_cyl == LV_COMPAT_CYL &&
fc4a62
-		    characteristics->long_no_cyl)
fc4a62
-			anc->hw_cylinders = characteristics->long_no_cyl;
fc4a62
-		else
fc4a62
-			anc->hw_cylinders = characteristics->no_cyl;
fc4a62
+		if (ioctl(f, BIODASDINFO, &dasd_info) != 0) {
fc4a62
+		        /* verify that the geometry matches a 3390 DASD */
fc4a62
+		        if (!fdasd_verify_geometry(DASD_3390_TYPE, blksize,
fc4a62
+						   &anc->geo)) {
fc4a62
+			        fdasd_error(anc, wrong_disk_type,
fc4a62
+					    _("Disk geometry does not match a " \
fc4a62
+					      "DASD device of type 3390."));
fc4a62
+				goto error;
fc4a62
+			}
fc4a62
+			anc->dev_type = DASD_3390_TYPE;
fc4a62
+			anc->hw_cylinders =
fc4a62
+			        size_in_bytes / (blksize * anc->geo.heads * anc->geo.sectors);
fc4a62
+			/* The VOL1 label on a CDL formatted ECKD DASD is in block 2
fc4a62
+			 * It will be verified later, if this position actually holds a
fc4a62
+			 * valid label record.
fc4a62
+			 */
fc4a62
+			anc->label_pos = 2 * blksize;
fc4a62
+			/* A devno 0 is actually a valid devno, which could exist
fc4a62
+			 * in the system. Since we use this number only to create
fc4a62
+			 * a default volume serial, there is no serious conflict.
fc4a62
+			 */
fc4a62
+			anc->devno = 0;
fc4a62
+		} else {
fc4a62
+		        characteristics = (struct dasd_eckd_characteristics *)
fc4a62
+			        &dasd_info.characteristics;
fc4a62
+			if (characteristics->no_cyl == LV_COMPAT_CYL &&
fc4a62
+			        characteristics->long_no_cyl)
fc4a62
+		                anc->hw_cylinders = characteristics->long_no_cyl;
fc4a62
+			else
fc4a62
+		                anc->hw_cylinders = characteristics->no_cyl;
fc4a62
+			anc->dev_type = dasd_info.dev_type;
fc4a62
+			anc->label_pos = dasd_info.label_block * blksize;
fc4a62
+			anc->devno = dasd_info.devno;
fc4a62
+			anc->label_block = dasd_info.label_block;
fc4a62
+			anc->FBA_layout = dasd_info.FBA_layout;
fc4a62
+		}
fc4a62
 
fc4a62
 		anc->is_file = 0;
fc4a62
 	}
fc4a62
 
fc4a62
-	anc->dev_type   = dasd_info.dev_type;
fc4a62
-	anc->blksize    = blksize;
fc4a62
-	anc->label_pos  = dasd_info.label_block * blksize;
fc4a62
-	anc->devno      = dasd_info.devno;
fc4a62
-	anc->label_block = dasd_info.label_block;
fc4a62
-	anc->FBA_layout = dasd_info.FBA_layout;
fc4a62
+	anc->blksize = blksize;
fc4a62
+	return 1;
fc4a62
+
fc4a62
+ error:
fc4a62
+	return 0;
fc4a62
 }
fc4a62
 
fc4a62
 /*
fc4a62
-- 
fc4a62
2.20.1
fc4a62