FreeBSD/Linux Kernel Cross Reference
sys/geom/geom_mbr.c
1 /*-
2 * Copyright (c) 2002 Poul-Henning Kamp
3 * Copyright (c) 2002 Networks Associates Technology, Inc.
4 * All rights reserved.
5 *
6 * This software was developed for the FreeBSD Project by Poul-Henning Kamp
7 * and NAI Labs, the Security Research Division of Network Associates, Inc.
8 * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the
9 * DARPA CHATS research program.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 *
32 * $FreeBSD: releng/5.1/sys/geom/geom_mbr.c 114517 2003-05-02 08:13:03Z phk $
33 */
34
35 #include <sys/param.h>
36 #include <sys/errno.h>
37 #include <sys/endian.h>
38 #include <sys/systm.h>
39 #include <sys/kernel.h>
40 #include <sys/malloc.h>
41 #include <sys/bio.h>
42 #include <sys/lock.h>
43 #include <sys/mutex.h>
44
45 #include <sys/diskmbr.h>
46 #include <sys/sbuf.h>
47 #include <geom/geom.h>
48 #include <geom/geom_slice.h>
49
50 #define MBR_CLASS_NAME "MBR"
51 #define MBREXT_CLASS_NAME "MBREXT"
52
53 static struct dos_partition historical_bogus_partition_table[NDOSPART] = {
54 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
55 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
56 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
57 { 0x80, 0, 1, 0, DOSPTYP_386BSD, 255, 255, 255, 0, 50000, },
58 };
59
60 static struct dos_partition historical_bogus_partition_table_fixed[NDOSPART] = {
61 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
62 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
63 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
64 { 0x80, 0, 1, 0, DOSPTYP_386BSD, 254, 255, 255, 0, 50000, },
65 };
66
67 static void
68 g_mbr_print(int i, struct dos_partition *dp)
69 {
70
71 printf("[%d] f:%02x typ:%d", i, dp->dp_flag, dp->dp_typ);
72 printf(" s(CHS):%d/%d/%d", DPCYL(dp->dp_scyl, dp->dp_ssect),
73 dp->dp_shd, DPSECT(dp->dp_ssect));
74 printf(" e(CHS):%d/%d/%d", DPCYL(dp->dp_ecyl, dp->dp_esect),
75 dp->dp_ehd, DPSECT(dp->dp_esect));
76 printf(" s:%d l:%d\n", dp->dp_start, dp->dp_size);
77 }
78
79 struct g_mbr_softc {
80 int type [NDOSPART];
81 u_int sectorsize;
82 u_char sec0[512];
83 };
84
85 static int
86 g_mbr_modify(struct g_geom *gp, struct g_mbr_softc *ms, u_char *sec0)
87 {
88 int i, error;
89 off_t l[NDOSPART];
90 struct dos_partition ndp[NDOSPART], *dp;
91
92 g_topology_assert();
93
94 if (sec0[0x1fe] != 0x55 && sec0[0x1ff] != 0xaa)
95 return (EBUSY);
96
97 dp = ndp;
98 for (i = 0; i < NDOSPART; i++) {
99 dos_partition_dec(
100 sec0 + DOSPARTOFF + i * sizeof(struct dos_partition),
101 dp + i);
102 if (bootverbose)
103 g_mbr_print(i, dp + i);
104 }
105 if ((!bcmp(dp, historical_bogus_partition_table,
106 sizeof historical_bogus_partition_table)) ||
107 (!bcmp(dp, historical_bogus_partition_table_fixed,
108 sizeof historical_bogus_partition_table_fixed))) {
109 /*
110 * We will not allow people to write these from "the inside",
111 * Since properly selfdestructing takes too much code. If
112 * people really want to do this, they cannot have any
113 * providers of this geom open, and in that case they can just
114 * as easily overwrite the MBR in the parent device.
115 */
116 return(EBUSY);
117 }
118 for (i = 0; i < NDOSPART; i++) {
119 /*
120 * A Protective MBR (PMBR) has a single partition of
121 * type 0xEE spanning the whole disk. Such a MBR
122 * protects a GPT on the disk from MBR tools that
123 * don't know anything about GPT. We're interpreting
124 * it a bit more loosely: any partition of type 0xEE
125 * is to be skipped as it doesn't contain any data
126 * that we should care about. We still allow other
127 * partitions to be present in the MBR. A PMBR will
128 * be handled correctly anyway.
129 */
130 if (dp[i].dp_typ == DOSPTYP_PMBR)
131 l[i] = 0;
132 else if (dp[i].dp_flag != 0 && dp[i].dp_flag != 0x80)
133 l[i] = 0;
134 else if (dp[i].dp_typ == 0)
135 l[i] = 0;
136 else
137 l[i] = (off_t)dp[i].dp_size * ms->sectorsize;
138 error = g_slice_config(gp, i, G_SLICE_CONFIG_CHECK,
139 (off_t)dp[i].dp_start * ms->sectorsize, l[i],
140 ms->sectorsize, "%ss%d", gp->name, 1 + i);
141 if (error)
142 return (error);
143 }
144 for (i = 0; i < NDOSPART; i++) {
145 ms->type[i] = dp[i].dp_typ;
146 g_slice_config(gp, i, G_SLICE_CONFIG_SET,
147 (off_t)dp[i].dp_start * ms->sectorsize, l[i],
148 ms->sectorsize, "%ss%d", gp->name, 1 + i);
149 }
150 bcopy(sec0, ms->sec0, 512);
151 return (0);
152 }
153
154 static void
155 g_mbr_ioctl(void *arg, int flag)
156 {
157 struct bio *bp;
158 struct g_geom *gp;
159 struct g_slicer *gsp;
160 struct g_mbr_softc *ms;
161 struct g_ioctl *gio;
162 struct g_consumer *cp;
163 u_char *sec0;
164 int error;
165
166 bp = arg;
167 if (flag == EV_CANCEL) {
168 g_io_deliver(bp, ENXIO);
169 return;
170 }
171 gp = bp->bio_to->geom;
172 gsp = gp->softc;
173 ms = gsp->softc;
174 gio = (struct g_ioctl *)bp->bio_data;
175
176 /* The disklabel to set is the ioctl argument. */
177 sec0 = gio->data;
178
179 error = g_mbr_modify(gp, ms, sec0);
180 if (error) {
181 g_io_deliver(bp, error);
182 return;
183 }
184 cp = LIST_FIRST(&gp->consumer);
185 error = g_write_data(cp, 0, sec0, 512);
186 g_io_deliver(bp, error);
187 }
188
189
190 static int
191 g_mbr_start(struct bio *bp)
192 {
193 struct g_provider *pp;
194 struct g_geom *gp;
195 struct g_mbr_softc *mp;
196 struct g_slicer *gsp;
197 struct g_ioctl *gio;
198 int idx, error;
199
200 pp = bp->bio_to;
201 idx = pp->index;
202 gp = pp->geom;
203 gsp = gp->softc;
204 mp = gsp->softc;
205 if (bp->bio_cmd == BIO_GETATTR) {
206 if (g_handleattr_int(bp, "MBR::type", mp->type[idx]))
207 return (1);
208 if (g_handleattr_off_t(bp, "MBR::offset",
209 gsp->slices[idx].offset))
210 return (1);
211 }
212
213 /* We only handle ioctl(2) requests of the right format. */
214 if (strcmp(bp->bio_attribute, "GEOM::ioctl"))
215 return (0);
216 else if (bp->bio_length != sizeof(*gio))
217 return (0);
218
219 /* Get hold of the ioctl parameters. */
220 gio = (struct g_ioctl *)bp->bio_data;
221
222 switch (gio->cmd) {
223 case DIOCSMBR:
224 /*
225 * These we cannot do without the topology lock and some
226 * some I/O requests. Ask the event-handler to schedule
227 * us in a less restricted environment.
228 */
229 error = g_post_event(g_mbr_ioctl, bp, M_NOWAIT, gp, NULL);
230 if (error)
231 g_io_deliver(bp, error);
232 /*
233 * We must return non-zero to indicate that we will deal
234 * with this bio, even though we have not done so yet.
235 */
236 return (1);
237 default:
238 return (0);
239 }
240
241 return (0);
242 }
243
244 static void
245 g_mbr_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp, struct g_consumer *cp __unused, struct g_provider *pp)
246 {
247 struct g_mbr_softc *mp;
248 struct g_slicer *gsp;
249
250 gsp = gp->softc;
251 mp = gsp->softc;
252 g_slice_dumpconf(sb, indent, gp, cp, pp);
253 if (pp != NULL) {
254 if (indent == NULL)
255 sbuf_printf(sb, " ty %d", mp->type[pp->index]);
256 else
257 sbuf_printf(sb, "%s<type>%d</type>\n", indent,
258 mp->type[pp->index]);
259 }
260 }
261
262 static struct g_geom *
263 g_mbr_taste(struct g_class *mp, struct g_provider *pp, int insist)
264 {
265 struct g_geom *gp;
266 struct g_consumer *cp;
267 int error;
268 struct g_mbr_softc *ms;
269 struct g_slicer *gsp;
270 u_int fwsectors, sectorsize;
271 u_char *buf;
272
273 g_trace(G_T_TOPOLOGY, "mbr_taste(%s,%s)", mp->name, pp->name);
274 g_topology_assert();
275 gp = g_slice_new(mp, NDOSPART, pp, &cp, &ms, sizeof *ms, g_mbr_start);
276 if (gp == NULL)
277 return (NULL);
278 gsp = gp->softc;
279 g_topology_unlock();
280 gp->dumpconf = g_mbr_dumpconf;
281 do {
282 if (gp->rank != 2 && insist == 0)
283 break;
284 error = g_getattr("GEOM::fwsectors", cp, &fwsectors);
285 if (error)
286 fwsectors = 17;
287 sectorsize = cp->provider->sectorsize;
288 if (sectorsize < 512)
289 break;
290 ms->sectorsize = sectorsize;
291 buf = g_read_data(cp, 0, sectorsize, &error);
292 if (buf == NULL || error != 0)
293 break;
294 g_topology_lock();
295 g_mbr_modify(gp, ms, buf);
296 g_topology_unlock();
297 g_free(buf);
298 break;
299 } while (0);
300 g_topology_lock();
301 g_access_rel(cp, -1, 0, 0);
302 if (LIST_EMPTY(&gp->provider)) {
303 g_slice_spoiled(cp);
304 return (NULL);
305 }
306 return (gp);
307 }
308
309 static struct g_class g_mbr_class = {
310 .name = MBR_CLASS_NAME,
311 .taste = g_mbr_taste,
312 G_CLASS_INITIALIZER
313 };
314
315 DECLARE_GEOM_CLASS(g_mbr_class, g_mbr);
316
317 #define NDOSEXTPART 32
318 struct g_mbrext_softc {
319 int type [NDOSEXTPART];
320 };
321
322 static int
323 g_mbrext_start(struct bio *bp)
324 {
325 struct g_provider *pp;
326 struct g_geom *gp;
327 struct g_mbrext_softc *mp;
328 struct g_slicer *gsp;
329 int idx;
330
331 pp = bp->bio_to;
332 idx = pp->index;
333 gp = pp->geom;
334 gsp = gp->softc;
335 mp = gsp->softc;
336 if (bp->bio_cmd == BIO_GETATTR) {
337 if (g_handleattr_int(bp, "MBR::type", mp->type[idx]))
338 return (1);
339 }
340 return (0);
341 }
342
343 static void
344 g_mbrext_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp, struct g_consumer *cp __unused, struct g_provider *pp)
345 {
346 struct g_mbrext_softc *mp;
347 struct g_slicer *gsp;
348
349 g_slice_dumpconf(sb, indent, gp, cp, pp);
350 gsp = gp->softc;
351 mp = gsp->softc;
352 if (pp != NULL) {
353 if (indent == NULL)
354 sbuf_printf(sb, " ty %d", mp->type[pp->index]);
355 else
356 sbuf_printf(sb, "%s<type>%d</type>\n", indent,
357 mp->type[pp->index]);
358 }
359 }
360
361 static struct g_geom *
362 g_mbrext_taste(struct g_class *mp, struct g_provider *pp, int insist __unused)
363 {
364 struct g_geom *gp;
365 struct g_consumer *cp;
366 int error, i, slice;
367 struct g_mbrext_softc *ms;
368 off_t off;
369 u_char *buf;
370 struct dos_partition dp[4];
371 u_int fwsectors, sectorsize;
372 struct g_slicer *gsp;
373
374 g_trace(G_T_TOPOLOGY, "g_mbrext_taste(%s,%s)", mp->name, pp->name);
375 g_topology_assert();
376 if (strcmp(pp->geom->class->name, MBR_CLASS_NAME))
377 return (NULL);
378 gp = g_slice_new(mp, NDOSEXTPART, pp, &cp, &ms, sizeof *ms,
379 g_mbrext_start);
380 if (gp == NULL)
381 return (NULL);
382 gsp = gp->softc;
383 g_topology_unlock();
384 gp->dumpconf = g_mbrext_dumpconf;
385 off = 0;
386 slice = 0;
387 do {
388 error = g_getattr("MBR::type", cp, &i);
389 if (error || (i != DOSPTYP_EXT && i != DOSPTYP_EXTLBA))
390 break;
391 error = g_getattr("GEOM::fwsectors", cp, &fwsectors);
392 if (error)
393 fwsectors = 17;
394 sectorsize = cp->provider->sectorsize;
395 if (sectorsize != 512)
396 break;
397 for (;;) {
398 buf = g_read_data(cp, off, sectorsize, &error);
399 if (buf == NULL || error != 0)
400 break;
401 if (buf[0x1fe] != 0x55 && buf[0x1ff] != 0xaa) {
402 g_free(buf);
403 break;
404 }
405 for (i = 0; i < NDOSPART; i++)
406 dos_partition_dec(
407 buf + DOSPARTOFF +
408 i * sizeof(struct dos_partition), dp + i);
409 g_free(buf);
410 if (bootverbose) {
411 printf("MBREXT Slice %d on %s:\n",
412 slice + 5, gp->name);
413 g_mbr_print(0, dp);
414 g_mbr_print(1, dp + 1);
415 }
416 if ((dp[0].dp_flag & 0x7f) == 0 &&
417 dp[0].dp_size != 0 && dp[0].dp_typ != 0) {
418 g_topology_lock();
419 g_slice_config(gp, slice, G_SLICE_CONFIG_SET,
420 (((off_t)dp[0].dp_start) << 9ULL) + off,
421 ((off_t)dp[0].dp_size) << 9ULL,
422 sectorsize,
423 "%*.*s%d",
424 strlen(gp->name) - 1,
425 strlen(gp->name) - 1,
426 gp->name,
427 slice + 5);
428 g_topology_unlock();
429 ms->type[slice] = dp[0].dp_typ;
430 slice++;
431 }
432 if (dp[1].dp_flag != 0)
433 break;
434 if (dp[1].dp_typ != DOSPTYP_EXT)
435 break;
436 if (dp[1].dp_size == 0)
437 break;
438 off = ((off_t)dp[1].dp_start) << 9ULL;
439 }
440 break;
441 } while (0);
442 g_topology_lock();
443 g_access_rel(cp, -1, 0, 0);
444 if (LIST_EMPTY(&gp->provider)) {
445 g_slice_spoiled(cp);
446 return (NULL);
447 }
448 return (gp);
449 }
450
451
452 static struct g_class g_mbrext_class = {
453 .name = MBREXT_CLASS_NAME,
454 .taste = g_mbrext_taste,
455 G_CLASS_INITIALIZER
456 };
457
458 DECLARE_GEOM_CLASS(g_mbrext_class, g_mbrext);
Cache object: cb62023fd7198c3aa9726a012dda68d8
|