Package: parted / 3.2-25

fdasd-update-geometry-handling.patch Patch series | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
From 5535fb6b081322e7bde3742935d43ed0cbc848ae Mon Sep 17 00:00:00 2001
From: Viktor Mihajlovski <mihajlov@linux.vnet.ibm.com>
Date: Thu, 17 Sep 2015 15:33:28 +0200
Subject: fdasd: geometry handling updated from upstream s390-tools

Remove the necessity for DASD-specific ioctls for partition handling.
This allows to correctly handle DASD-backed virtio block devices.

Note that this is necessary because virtio is just the transport.
A DASD, even if provided via virtio, still has it's unique
characteristics, which means that only traditional DASD partition
table formats can be used (no MBR, GPT, or similar).

Use bzero for initialization to make sure all struct members are
properly cleared. Also changed partition list handling code to be
more similar to upstream s390-tools fdasd.

Further, enhanced error handling capabilities by providing a
return code by fdasd_get_geometry.

Code is largely backported from s390-tools project.

Signed-off-by: Viktor Mihajlovski <mihajlov@linux.vnet.ibm.com>
Acked-by: Stefan Haberland <stefan.haberland@de.ibm.com>
Signed-off-by: Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
Signed-off-by: Brian C. Lane <bcl@redhat.com>

Origin: upstream, http://git.savannah.gnu.org/cgit/parted.git/commit/?id=4d480d980a9b69b432b8d60df3c4397ba8cdc965
Bug-Debian: https://bugs.debian.org/803333
Last-Update: 2015-11-05

Patch-Name: fdasd-update-geometry-handling.patch
---
 include/parted/fdasd.h    |   4 +-
 include/parted/fdasd.in.h |   4 +-
 libparted/labels/fdasd.c  | 166 ++++++++++++++++++++++++++------------
 3 files changed, 122 insertions(+), 52 deletions(-)

diff --git a/include/parted/fdasd.h b/include/parted/fdasd.h
index 6f6a7e0a..4e351c4e 100644
--- a/include/parted/fdasd.h
+++ b/include/parted/fdasd.h
@@ -190,6 +190,8 @@ typedef struct format_data_t {
 #define BLKRRPART  _IO(0x12,95)
 /* get block device sector size */
 #define BLKSSZGET  _IO(0x12,104)
+/* device size in bytes (u64 *arg)*/
+#define BLKGETSIZE64 _IOR(0x12,114,size_t)
 /* get device geometry */
 #define HDIO_GETGEO		0x0301
 
@@ -285,7 +287,7 @@ enum fdasd_failure {
 
 void fdasd_cleanup (fdasd_anchor_t *anchor);
 void fdasd_initialize_anchor (fdasd_anchor_t * anc);
-void fdasd_get_geometry (const PedDevice *dev, fdasd_anchor_t *anc, int fd);
+int fdasd_get_geometry (const PedDevice *dev, fdasd_anchor_t *anc, int fd);
 void fdasd_check_api_version (fdasd_anchor_t *anc, int fd);
 int fdasd_check_volume (fdasd_anchor_t *anc, int fd);
 int fdasd_write_labels (fdasd_anchor_t *anc, int fd);
diff --git a/include/parted/fdasd.in.h b/include/parted/fdasd.in.h
index 6f6a7e0a..4e351c4e 100644
--- a/include/parted/fdasd.in.h
+++ b/include/parted/fdasd.in.h
@@ -190,6 +190,8 @@ typedef struct format_data_t {
 #define BLKRRPART  _IO(0x12,95)
 /* get block device sector size */
 #define BLKSSZGET  _IO(0x12,104)
+/* device size in bytes (u64 *arg)*/
+#define BLKGETSIZE64 _IOR(0x12,114,size_t)
 /* get device geometry */
 #define HDIO_GETGEO		0x0301
 
@@ -285,7 +287,7 @@ enum fdasd_failure {
 
 void fdasd_cleanup (fdasd_anchor_t *anchor);
 void fdasd_initialize_anchor (fdasd_anchor_t * anc);
-void fdasd_get_geometry (const PedDevice *dev, fdasd_anchor_t *anc, int fd);
+int fdasd_get_geometry (const PedDevice *dev, fdasd_anchor_t *anc, int fd);
 void fdasd_check_api_version (fdasd_anchor_t *anc, int fd);
 int fdasd_check_volume (fdasd_anchor_t *anc, int fd);
 int fdasd_write_labels (fdasd_anchor_t *anc, int fd);
diff --git a/libparted/labels/fdasd.c b/libparted/labels/fdasd.c
index 1f879373..7e6a77a2 100644
--- a/libparted/labels/fdasd.c
+++ b/libparted/labels/fdasd.c
@@ -210,27 +210,7 @@ fdasd_initialize_anchor (fdasd_anchor_t * anc)
 	partition_info_t *p = NULL;
 	partition_info_t *q = NULL;
 
-	anc->devno             = 0;
-	anc->dev_type          = 0;
-	anc->used_partitions   = 0;
-
-	anc->silent            = 0;
-	anc->verbose           = 0;
-	anc->big_disk          = 0;
-	anc->volid_specified   = 0;
-	anc->config_specified  = 0;
-	anc->auto_partition    = 0;
-	anc->devname_specified = 0;
-	anc->print_table       = 0;
-
-	anc->option_reuse      = 0;
-	anc->option_recreate   = 0;
-
-	anc->vlabel_changed    = 0;
-	anc->vtoc_changed      = 0;
-	anc->blksize           = 0;
-	anc->fspace_trk        = 0;
-	anc->label_pos         = 0;
+	bzero(anc, sizeof(fdasd_anchor_t));
 
 	for (i=0; i<USABLE_PARTITIONS; i++)
 		setpos(anc, i, -1);
@@ -272,24 +252,18 @@ fdasd_initialize_anchor (fdasd_anchor_t * anc)
 		if (p == NULL)
 			fdasd_error(anc, malloc_failed,
 				    _("No room for partition info."));
-		p->used       = 0x00;
-		p->len_trk    = 0;
-		p->start_trk  = 0;
-		p->fspace_trk = 0;
-		p->type       = 0;
+		bzero(p, sizeof(partition_info_t));
 
 		/* add p to double pointered list */
 		if (i == 1) {
-	        anc->first = p;
-			p->prev = NULL;
+		        anc->first = p;
 		} else if (i == USABLE_PARTITIONS) {
-	        anc->last = p;
-	        p->next = NULL;
+		        anc->last = p;
 			p->prev = q;
 			q->next = p;
 		} else {
-	        p->prev = q;
-	        q->next = p;
+	                p->prev = q;
+	                q->next = p;
 		}
 
 		p->f1 = malloc(sizeof(format1_label_t));
@@ -946,16 +920,78 @@ fdasd_check_api_version (fdasd_anchor_t *anc, int f)
 	}
 }
 
+/*
+ * The following two functions match those in the DASD ECKD device driver.
+ * They are used to compute how many records of a given size can be stored
+ * in one track.
+ */
+static unsigned int ceil_quot(unsigned int d1, unsigned int d2)
+{
+	return (d1 + (d2 - 1)) / d2;
+}
+
+/* kl: key length, dl: data length */
+static unsigned int recs_per_track(unsigned short dev_type, unsigned int kl,
+				   unsigned int dl)
+{
+	unsigned int dn, kn;
+
+	switch (dev_type) {
+	case DASD_3380_TYPE:
+		if (kl)
+			return 1499 / (15 + 7 + ceil_quot(kl + 12, 32) +
+				       ceil_quot(dl + 12, 32));
+		else
+			return 1499 / (15 + ceil_quot(dl + 12, 32));
+	case DASD_3390_TYPE:
+		dn = ceil_quot(dl + 6, 232) + 1;
+		if (kl) {
+			kn = ceil_quot(kl + 6, 232) + 1;
+			return 1729 / (10 + 9 + ceil_quot(kl + 6 * kn, 34) +
+				       9 + ceil_quot(dl + 6 * dn, 34));
+		} else
+			return 1729 / (10 + 9 + ceil_quot(dl + 6 * dn, 34));
+	case DASD_9345_TYPE:
+		dn = ceil_quot(dl + 6, 232) + 1;
+		if (kl) {
+			kn = ceil_quot(kl + 6, 232) + 1;
+			return 1420 / (18 + 7 + ceil_quot(kl + 6 * kn, 34) +
+				       ceil_quot(dl + 6 * dn, 34));
+		} else
+			return 1420 / (18 + 7 + ceil_quot(dl + 6 * dn, 34));
+	}
+	return 0;
+}
+
+/*
+ * Verify that number of tracks (heads) per cylinder and number of
+ * sectors per track match the expected values for a given device type
+ * and block size.
+ * Returns 1 for a valid match and 0 otherwise.
+ */
+static int fdasd_verify_geometry(unsigned short dev_type, int blksize,
+				 struct fdasd_hd_geometry *geometry)
+{
+	unsigned int expected_sectors;
+	if (geometry->heads != 15)
+		return 0;
+	expected_sectors = recs_per_track(dev_type, 0, blksize);
+	if (geometry->sectors == expected_sectors)
+		return 1;
+	return 0;
+}
+
 /*
  * reads dasd geometry data
  */
-void
+int
 fdasd_get_geometry (const PedDevice *dev, fdasd_anchor_t *anc, int f)
 {
 	PDEBUG
 	int blksize = 0;
 	dasd_information_t dasd_info;
 	struct dasd_eckd_characteristics *characteristics;
+	unsigned long long size_in_bytes;
 
 	/* We can't get geometry from a regular file,
 	   so simulate something usable, for the sake of testing.  */
@@ -979,6 +1015,12 @@ fdasd_get_geometry (const PedDevice *dev, fdasd_anchor_t *anc, int f)
 				anc->geo.heads;
 	    anc->is_file = 1;
 	} else {
+	        if (ioctl(f, BLKGETSIZE64, &size_in_bytes) != 0) {
+		        fdasd_error(anc, unable_to_ioctl,
+				    _("Could not retrieve disk size."));
+			goto error;
+		}
+
 		if (ioctl(f, HDIO_GETGEO, &anc->geo) != 0)
 			fdasd_error(anc, unable_to_ioctl,
 			    _("Could not retrieve disk geometry information."));
@@ -988,27 +1030,51 @@ fdasd_get_geometry (const PedDevice *dev, fdasd_anchor_t *anc, int f)
 			    _("Could not retrieve blocksize information."));
 
 		/* get disk type */
-		if (ioctl(f, BIODASDINFO, &dasd_info) != 0)
-			fdasd_error(anc, unable_to_ioctl,
-				    _("Could not retrieve disk information."));
-
-		characteristics = (struct dasd_eckd_characteristics *)
-					&dasd_info.characteristics;
-		if (characteristics->no_cyl == LV_COMPAT_CYL &&
-		    characteristics->long_no_cyl)
-			anc->hw_cylinders = characteristics->long_no_cyl;
-		else
-			anc->hw_cylinders = characteristics->no_cyl;
+		if (ioctl(f, BIODASDINFO, &dasd_info) != 0) {
+		        /* verify that the geometry matches a 3390 DASD */
+		        if (!fdasd_verify_geometry(DASD_3390_TYPE, blksize,
+						   &anc->geo)) {
+			        fdasd_error(anc, wrong_disk_type,
+					    _("Disk geometry does not match a " \
+					      "DASD device of type 3390."));
+				goto error;
+			}
+			anc->dev_type = DASD_3390_TYPE;
+			anc->hw_cylinders =
+			        size_in_bytes / (blksize * anc->geo.heads * anc->geo.sectors);
+			/* The VOL1 label on a CDL formatted ECKD DASD is in block 2
+			 * It will be verified later, if this position actually holds a
+			 * valid label record.
+			 */
+			anc->label_pos = 2 * blksize;
+			/* A devno 0 is actually a valid devno, which could exist
+			 * in the system. Since we use this number only to create
+			 * a default volume serial, there is no serious conflict.
+			 */
+			anc->devno = 0;
+		} else {
+		        characteristics = (struct dasd_eckd_characteristics *)
+			        &dasd_info.characteristics;
+			if (characteristics->no_cyl == LV_COMPAT_CYL &&
+			        characteristics->long_no_cyl)
+		                anc->hw_cylinders = characteristics->long_no_cyl;
+			else
+		                anc->hw_cylinders = characteristics->no_cyl;
+			anc->dev_type = dasd_info.dev_type;
+			anc->label_pos = dasd_info.label_block * blksize;
+			anc->devno = dasd_info.devno;
+			anc->label_block = dasd_info.label_block;
+			anc->FBA_layout = dasd_info.FBA_layout;
+		}
 
 		anc->is_file = 0;
 	}
 
-	anc->dev_type   = dasd_info.dev_type;
-	anc->blksize    = blksize;
-	anc->label_pos  = dasd_info.label_block * blksize;
-	anc->devno      = dasd_info.devno;
-	anc->label_block = dasd_info.label_block;
-	anc->FBA_layout = dasd_info.FBA_layout;
+	anc->blksize = blksize;
+	return 1;
+
+ error:
+	return 0;
 }
 
 /*