diff options
author | Theo de Raadt <deraadt@cvs.openbsd.org> | 2007-06-17 00:27:31 +0000 |
---|---|---|
committer | Theo de Raadt <deraadt@cvs.openbsd.org> | 2007-06-17 00:27:31 +0000 |
commit | 81f9f199b5e2a6741e5a9a68d39dd00dadaa4e18 (patch) | |
tree | aa5797e58e49aa5ab1063818eacfa236c19c2adf /sys/arch/amd64 | |
parent | 49e31b3e7fe854aae88f968da9911e2a4fd5d878 (diff) |
significantly simplified disklabel infrastructure. MBR handling becomes MI
to support hotplug media on most architectures. disklabel setup and
verification done using new helper functions. Disklabels must *always*
have a correct checksum now. Same code paths are used to learn on-disk
location disklabels, to avoid new errors sneaking in. Tested on almost all
cases, testing help from todd, kettenis, krw, otto, dlg, robert, gwk, drahn
Diffstat (limited to 'sys/arch/amd64')
-rw-r--r-- | sys/arch/amd64/amd64/disksubr.c | 280 | ||||
-rw-r--r-- | sys/arch/amd64/include/disklabel.h | 53 |
2 files changed, 19 insertions, 314 deletions
diff --git a/sys/arch/amd64/amd64/disksubr.c b/sys/arch/amd64/amd64/disksubr.c index 437f3674c2e..3dc92c8504f 100644 --- a/sys/arch/amd64/amd64/disksubr.c +++ b/sys/arch/amd64/amd64/disksubr.c @@ -1,4 +1,4 @@ -/* $OpenBSD: disksubr.c,v 1.49 2007/06/14 03:37:23 deraadt Exp $ */ +/* $OpenBSD: disksubr.c,v 1.50 2007/06/17 00:27:28 deraadt Exp $ */ /* $NetBSD: disksubr.c,v 1.21 1996/05/03 19:42:03 christos Exp $ */ /* @@ -29,16 +29,12 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. - * - * @(#)ufs_disksubr.c 7.16 (Berkeley) 5/4/91 */ #include <sys/param.h> #include <sys/systm.h> #include <sys/buf.h> -#include <sys/device.h> #include <sys/disklabel.h> -#include <sys/syslog.h> #include <sys/disk.h> #include <sys/reboot.h> #include <sys/conf.h> @@ -69,37 +65,13 @@ char * readdisklabel(dev_t dev, void (*strat)(struct buf *), struct disklabel *lp, struct cpu_disklabel *osdep, int spoofonly) { - struct dos_partition dp[NDOSPART], *dp2; - struct partition *pp; - struct disklabel *dlp; bios_diskinfo_t *pdi; - unsigned long extoff = 0; - unsigned int fattest; struct buf *bp = NULL; - daddr64_t part_blkno = DOSBBSECTOR; dev_t devno; - char *msg = NULL; - int dospartoff, cyl, i, ourpart = -1; - int wander = 1, n = 0, loop = 0; + char *msg; - /* minimal requirements for archetypal disk label */ - if (lp->d_secsize < DEV_BSIZE) - lp->d_secsize = DEV_BSIZE; - if (DL_GETDSIZE(lp) == 0) - DL_SETDSIZE(lp, MAXDISKSIZE); - if (lp->d_secpercyl == 0) { - msg = "invalid geometry"; + if ((msg = initdisklabel(lp))) goto done; - } - lp->d_npartitions = RAW_PART + 1; - for (i = 0; i < RAW_PART; i++) { - DL_SETPSIZE(&lp->d_partitions[i], 0); - DL_SETPOFFSET(&lp->d_partitions[i], 0); - } - if (DL_GETPSIZE(&lp->d_partitions[RAW_PART]) == 0) - DL_SETPSIZE(&lp->d_partitions[RAW_PART], DL_GETDSIZE(lp)); - DL_SETPOFFSET(&lp->d_partitions[RAW_PART], 0); - lp->d_version = 1; /* Look for any BIOS geometry information we should honour. */ devno = chrtoblk(dev); @@ -124,193 +96,21 @@ readdisklabel(dev_t dev, void (*strat)(struct buf *), bp = geteblk((int)lp->d_secsize); bp->b_dev = dev; - /* do dos partitions in the process of getting disklabel? */ - dospartoff = 0; - cyl = LABELSECTOR / lp->d_secpercyl; - - /* - * Read dos partition table, follow extended partitions. - * Map the partitions to disklabel entries i-p - */ - while (wander && n < 8 && loop < 8) { - loop++; - wander = 0; - if (part_blkno < extoff) - part_blkno = extoff; - - /* read boot record */ - bp->b_blkno = part_blkno; - bp->b_bcount = lp->d_secsize; - bp->b_flags = B_BUSY | B_READ; - bp->b_cylinder = part_blkno / lp->d_secpercyl; - (*strat)(bp); - - /* if successful, wander through dos partition table */ - if (biowait(bp)) { - msg = "dos partition I/O error"; - goto done; - } - bcopy(bp->b_data + DOSPARTOFF, dp, sizeof(dp)); - - if (ourpart == -1 && part_blkno == DOSBBSECTOR) { - /* Search for our MBR partition */ - for (dp2=dp, i=0; i < NDOSPART && ourpart == -1; - i++, dp2++) - if (letoh32(dp2->dp_size) && - dp2->dp_typ == DOSPTYP_OPENBSD) - ourpart = i; - if (ourpart == -1) - goto donot; - /* - * This is our MBR partition. need sector address - * for SCSI/IDE, cylinder for ESDI/ST506/RLL - */ - dp2 = &dp[ourpart]; - dospartoff = letoh32(dp2->dp_start) + part_blkno; - cyl = DPCYL(dp2->dp_scyl, dp2->dp_ssect); - - /* XXX build a temporary disklabel */ - DL_SETPSIZE(&lp->d_partitions[0], letoh32(dp2->dp_size)); - DL_SETPOFFSET(&lp->d_partitions[0], - letoh32(dp2->dp_start) + part_blkno); - if (lp->d_ntracks == 0) - lp->d_ntracks = dp2->dp_ehd + 1; - if (lp->d_nsectors == 0) - lp->d_nsectors = DPSECT(dp2->dp_esect); - if (lp->d_secpercyl == 0) - lp->d_secpercyl = lp->d_ntracks * - lp->d_nsectors; - } -donot: - /* - * In case the disklabel read below fails, we want to - * provide a fake label in i-p. - */ - for (dp2=dp, i=0; i < NDOSPART && n < 8; i++, dp2++) { - pp = &lp->d_partitions[8+n]; - - if (dp2->dp_typ == DOSPTYP_OPENBSD) - continue; - if (letoh32(dp2->dp_size) > DL_GETDSIZE(lp)) - continue; - if (letoh32(dp2->dp_start) > DL_GETDSIZE(lp)) - continue; - if (letoh32(dp2->dp_size) == 0) - continue; - if (letoh32(dp2->dp_start)) - DL_SETPOFFSET(pp, - letoh32(dp2->dp_start) + part_blkno); - - DL_SETPSIZE(pp, letoh32(dp2->dp_size)); - - switch (dp2->dp_typ) { - case DOSPTYP_UNUSED: - pp->p_fstype = FS_UNUSED; - n++; - break; - - case DOSPTYP_LINUX: - pp->p_fstype = FS_EXT2FS; - n++; - break; - - case DOSPTYP_FAT12: - case DOSPTYP_FAT16S: - case DOSPTYP_FAT16B: - case DOSPTYP_FAT16L: - case DOSPTYP_FAT32: - case DOSPTYP_FAT32L: - pp->p_fstype = FS_MSDOS; - n++; - break; - case DOSPTYP_EXTEND: - case DOSPTYP_EXTENDL: - part_blkno = letoh32(dp2->dp_start) + extoff; - if (!extoff) { - extoff = letoh32(dp2->dp_start); - part_blkno = 0; - } - wander = 1; - break; - default: - pp->p_fstype = FS_OTHER; - n++; - break; - } - } - } - lp->d_bbsize = 8192; - lp->d_sbsize = 64*1024; /* XXX ? */ - lp->d_npartitions = MAXPARTITIONS; - - if (n == 0 && part_blkno == DOSBBSECTOR) { - /* Check for a short jump instruction. */ - fattest = ((bp->b_data[0] << 8) & 0xff00) | (bp->b_data[2] & - 0xff); - if (fattest != 0xeb90 && fattest != 0xe900) - goto notfat; - - /* Check for a valid bytes per sector value. */ - fattest = ((bp->b_data[12] << 8) & 0xff00) | (bp->b_data[11] & - 0xff); - if (fattest < 512 || fattest > 4096 || (fattest % 512 != 0)) - goto notfat; - - /* Check the end of sector marker. */ - fattest = ((bp->b_data[510] << 8) & 0xff00) | (bp->b_data[511] & - 0xff); - if (fattest != 0x55aa) - goto notfat; - - /* Looks like a FAT filesystem. Spoof 'i'. */ - DL_SETPSIZE(&lp->d_partitions['i' - 'a'], - DL_GETPSIZE(&lp->d_partitions[RAW_PART])); - DL_SETPOFFSET(&lp->d_partitions['i' - 'a'], 0); - lp->d_partitions['i' - 'a'].p_fstype = FS_MSDOS; - } -notfat: - - /* don't read the on-disk label if we are in spoofed-only mode */ - if (spoofonly) - goto done; - - /* next, dig out disk label */ - bp->b_blkno = dospartoff + LABELSECTOR; - bp->b_cylinder = cyl; - bp->b_bcount = lp->d_secsize; - bp->b_flags = B_BUSY | B_READ; - (*strat)(bp); - - /* if successful, locate disk label within block and validate */ - if (biowait(bp)) { - /* XXX we return the faked label built so far */ - msg = "disk label I/O error"; + msg = readdoslabel(bp, strat, lp, osdep, NULL, NULL, spoofonly); + if (msg == NULL) goto done; - } - for (dlp = (struct disklabel *)bp->b_data; - dlp <= (struct disklabel *)(bp->b_data + lp->d_secsize - sizeof(*dlp)); - dlp = (struct disklabel *)((char *)dlp + sizeof(long))) { - if (dlp->d_magic != DISKMAGIC || dlp->d_magic2 != DISKMAGIC) { - if (msg == NULL) - msg = "no disk label"; - } else if (dlp->d_npartitions > MAXPARTITIONS || - dkcksum(dlp) != 0) - msg = "disk label corrupted"; - else { - DL_SETDSIZE(dlp, DL_GETDSIZE(lp)); - *lp = *dlp; - msg = NULL; - break; - } - } #if defined(CD9660) - if (msg && iso_disklabelspoof(dev, strat, lp) == 0) + if (iso_disklabelspoof(dev, strat, lp) == 0) { msg = NULL; + goto done; + } #endif #if defined(UDF) - if (msg && udf_disklabelspoof(dev, strat, lp) == 0) + if (udf_disklabelspoof(dev, strat, lp) == 0) { msg = NULL; + goto done; + } #endif done: @@ -318,7 +118,6 @@ done: bp->b_flags |= B_INVAL; brelse(bp); } - disklabeltokernlabel(lp); return (msg); } @@ -330,73 +129,30 @@ int writedisklabel(dev_t dev, void (*strat)(struct buf *), struct disklabel *lp, struct cpu_disklabel *osdep) { - struct dos_partition dp[NDOSPART], *dp2; + int error, partoff = -1, cyl = 0; struct disklabel *dlp; struct buf *bp = NULL; - int error, dospartoff, cyl, i; - int ourpart = -1; /* get a buffer and initialize it */ bp = geteblk((int)lp->d_secsize); bp->b_dev = dev; - /* do dos partitions in the process of getting disklabel? */ - dospartoff = 0; - cyl = LABELSECTOR / lp->d_secpercyl; - - /* read master boot record */ - bp->b_blkno = DOSBBSECTOR; - bp->b_bcount = lp->d_secsize; - bp->b_flags = B_BUSY | B_READ; - bp->b_cylinder = DOSBBSECTOR / lp->d_secpercyl; - (*strat)(bp); - - if ((error = biowait(bp)) != 0) + if (readdoslabel(bp, strat, lp, osdep, &partoff, &cyl, 1) != NULL) { + error = EIO; goto done; - - /* XXX how do we check veracity/bounds of this? */ - bcopy(bp->b_data + DOSPARTOFF, dp, sizeof(dp)); - - for (dp2=dp, i=0; i < NDOSPART && ourpart == -1; i++, dp2++) - if (letoh32(dp2->dp_size) && dp2->dp_typ == DOSPTYP_OPENBSD) - ourpart = i; - - if (ourpart != -1) { - dp2 = &dp[ourpart]; - - /* - * need sector address for SCSI/IDE, - * cylinder for ESDI/ST506/RLL - */ - dospartoff = letoh32(dp2->dp_start); - cyl = DPCYL(dp2->dp_scyl, dp2->dp_ssect); } - /* next, dig out disk label */ - bp->b_blkno = dospartoff + LABELSECTOR; + /* Read it in, slap the new label in, and write it back out */ + bp->b_blkno = partoff + LABELSECTOR; bp->b_cylinder = cyl; bp->b_bcount = lp->d_secsize; bp->b_flags = B_BUSY | B_READ; (*strat)(bp); - - /* if successful, locate disk label within block and validate */ if ((error = biowait(bp)) != 0) goto done; - for (dlp = (struct disklabel *)bp->b_data; - dlp <= (struct disklabel *)(bp->b_data + lp->d_secsize - sizeof(*dlp)); - dlp = (struct disklabel *)((char *)dlp + sizeof(long))) { - if (dlp->d_magic == DISKMAGIC && dlp->d_magic2 == DISKMAGIC && - dkcksum(dlp) == 0) { - *dlp = *lp; - bp->b_flags = B_BUSY | B_WRITE; - (*strat)(bp); - error = biowait(bp); - goto done; - } - } - /* Write it in the regular place. */ - *(struct disklabel *)bp->b_data = *lp; + dlp = (struct disklabel *)(bp->b_data + LABELOFFSET); + *dlp = *lp; bp->b_flags = B_BUSY | B_WRITE; (*strat)(bp); error = biowait(bp); diff --git a/sys/arch/amd64/include/disklabel.h b/sys/arch/amd64/include/disklabel.h index 0851f8a57b9..12c78faa294 100644 --- a/sys/arch/amd64/include/disklabel.h +++ b/sys/arch/amd64/include/disklabel.h @@ -1,5 +1,4 @@ -/* $OpenBSD: disklabel.h,v 1.8 2006/10/20 23:47:42 krw Exp $ */ -/* $NetBSD: disklabel.h,v 1.3 1996/03/09 20:52:54 ghudson Exp $ */ +/* $OpenBSD: disklabel.h,v 1.9 2007/06/17 00:27:26 deraadt Exp $ */ /* * Copyright (c) 1994 Christopher G. Demetriou @@ -37,58 +36,8 @@ #define LABELSECTOR 1 /* sector containing label */ #define LABELOFFSET 0 /* offset of label in sector */ #define MAXPARTITIONS 16 /* number of partitions */ -#define RAW_PART 2 /* raw partition: ie. rsd0c */ - -/* DOS partition table -- located in boot block */ -#define DOSBBSECTOR 0 /* DOS boot block relative sector # */ -#define DOSPARTOFF 446 -#define DOSDISKOFF 444 -#define NDOSPART 4 -#define DOSACTIVE 0x80 /* active partition */ - -struct dos_partition { - u_int8_t dp_flag; /* bootstrap flags */ - u_int8_t dp_shd; /* starting head */ - u_int8_t dp_ssect; /* starting sector */ - u_int8_t dp_scyl; /* starting cylinder */ - u_int8_t dp_typ; /* partition type (see below) */ - u_int8_t dp_ehd; /* end head */ - u_int8_t dp_esect; /* end sector */ - u_int8_t dp_ecyl; /* end cylinder */ - u_int32_t dp_start; /* absolute starting sector number */ - u_int32_t dp_size; /* partition size in sectors */ -}; - -/* Known DOS partition types. */ -#define DOSPTYP_UNUSED 0x00 /* Unused partition */ -#define DOSPTYP_FAT12 0x01 /* 12-bit FAT */ -#define DOSPTYP_FAT16S 0x04 /* 16-bit FAT, less than 32M */ -#define DOSPTYP_EXTEND 0x05 /* Extended; contains sub-partitions */ -#define DOSPTYP_FAT16B 0x06 /* 16-bit FAT, more than 32M */ -#define DOSPTYP_FAT32 0x0b /* 32-bit FAT */ -#define DOSPTYP_FAT32L 0x0c /* 32-bit FAT, LBA-mapped */ -#define DOSPTYP_FAT16L 0x0e /* 16-bit FAT, LBA-mapped */ -#define DOSPTYP_EXTENDL 0x0f /* Extended, LBA-mapped; contains sub-partitions */ -#define DOSPTYP_ONTRACK 0x54 -#define DOSPTYP_LINUX 0x83 /* That other thing */ -#define DOSPTYP_FREEBSD 0xa5 /* FreeBSD partition type */ -#define DOSPTYP_OPENBSD 0xa6 /* OpenBSD partition type */ -#define DOSPTYP_NETBSD 0xa9 /* NetBSD partition type */ - -struct dos_mbr { - u_int8_t dmbr_boot[DOSPARTOFF]; - struct dos_partition dmbr_parts[NDOSPART]; - u_int16_t dmbr_sign; -} __packed; - -#define DOSMBR_SIGNATURE (0xaa55) -#define DOSMBR_SIGNATURE_OFF (0x1fe) struct cpu_disklabel { }; -/* Isolate the relevant bits to get sector and cylinder. */ -#define DPSECT(s) ((s) & 0x3f) -#define DPCYL(c, s) ((c) + (((s) & 0xc0) << 2)) - #endif /* _MACHINE_DISKLABEL_H_ */ |