From 7262c5ee2c4f82a922411ebd64381463e2cc4269 Mon Sep 17 00:00:00 2001 From: Bruce Evans Date: Sat, 4 Mar 1995 11:44:05 +0000 Subject: [PATCH] Support extended DOSpartitions. Accept even suspicious partitions. Moved most handling of the compatibility slice to dsopen(). Report i/o errors. --- sys/i386/isa/diskslice_machdep.c | 232 ++++++++++++++++++++++++------- sys/kern/subr_diskmbr.c | 232 ++++++++++++++++++++++++------- 2 files changed, 362 insertions(+), 102 deletions(-) diff --git a/sys/i386/isa/diskslice_machdep.c b/sys/i386/isa/diskslice_machdep.c index 91641f670272..6b2af2b6a0e8 100644 --- a/sys/i386/isa/diskslice_machdep.c +++ b/sys/i386/isa/diskslice_machdep.c @@ -35,17 +35,64 @@ * * from: @(#)ufs_disksubr.c 7.16 (Berkeley) 5/4/91 * from: ufs_disksubr.c,v 1.8 1994/06/07 01:21:39 phk Exp $ - * $Id: diskslice_machdep.c,v 1.5 1995/02/21 08:37:09 bde Exp $ + * $Id: diskslice_machdep.c,v 1.6 1995/02/22 22:46:36 bde Exp $ */ #include #include #include #include +#define DOSPTYP_EXTENDED 5 #include #include +#include #include +#define TRACE(str) do { if (dsi_debug) printf str; } while (0) + +static volatile u_char dsi_debug; + +static int check_part __P((char *sname, struct dos_partition *dp, + u_long offset, int nsectors, int ntracks)); +static void extended __P((char *dname, dev_t dev, d_strategy_t *strat, + struct disklabel *lp, struct diskslices *ssp, + u_long ext_offset, u_long ext_size, + u_long base_ext_offset, int nsectors, int ntracks)); + +static int +check_part(sname, dp, offset, nsectors, ntracks) + char *sname; + struct dos_partition *dp; + u_long offset; + int nsectors; + int ntracks; +{ + int error; + u_long esector; + u_long esector1; + u_long secpercyl; + u_long ssector; + u_long ssector1; + + secpercyl = (u_long)nsectors * ntracks; + ssector = DPSECT(dp->dp_ssect) - 1 + dp->dp_shd * nsectors + + DPCYL(dp->dp_scyl, dp->dp_ssect) * secpercyl; + ssector1 = offset + dp->dp_start; + esector = DPSECT(dp->dp_esect) - 1 + dp->dp_ehd * nsectors + + DPCYL(dp->dp_ecyl, dp->dp_esect) * secpercyl; + esector1 = ssector1 + dp->dp_size - 1; + error = ssector == ssector1 && esector == esector1 ? 0 : EINVAL; + printf("%s: start %lu, end = %lu, size %lu%s\n", + sname, ssector, esector, dp->dp_size, error ? "" : ": OK"); + if (ssector != ssector1) + printf("%s: C/H/S start %lu != start %lu: invalid\n", + sname, ssector, ssector1); + if (esector != esector1) + printf("%s: C/H/S end %lu != end %lu: invalid\n", + sname, esector, esector1); + return (error); +} + int dsinit(dname, dev, strat, lp, sspp) char *dname; @@ -56,6 +103,7 @@ dsinit(dname, dev, strat, lp, sspp) { struct buf *bp; u_char *cp; + int dospart; struct dos_partition *dp; struct dos_partition *dp0; int error; @@ -92,6 +140,9 @@ dsinit(dname, dev, strat, lp, sspp) bp->b_flags = B_BUSY | B_READ; (*strat)(bp); if (biowait(bp) != 0) { + diskerr(bp, dname, "error reading partition table", + LOG_PRINTF, 0, lp); + printf("\n"); error = EIO; goto done; } @@ -99,6 +150,9 @@ dsinit(dname, dev, strat, lp, sspp) /* Weakly verify it. */ cp = bp->b_un.b_addr; if (cp[0x1FE] != 0x55 || cp[0x1FF] != 0xAA) { + diskerr(bp, dname, "invalid partition table", + LOG_PRINTF, 0, lp); + printf("\n"); error = EINVAL; goto done; } @@ -113,10 +167,9 @@ dsinit(dname, dev, strat, lp, sspp) max_nsectors = 0; max_ntracks = 0; dp0 = (struct dos_partition *)(cp + DOSPARTOFF); - for (dp = dp0, slice = BASE_SLICE; slice < BASE_SLICE + NDOSPART; - dp++, slice++) { - int nsectors; - int ntracks; + for (dospart = 0, dp = dp0; dospart < NDOSPART; dospart++, dp++) { + int nsectors; + int ntracks; max_ncyls = DPCYL(dp->dp_ecyl, dp->dp_esect); if (max_ncyls < max_ncyls) @@ -137,35 +190,22 @@ dsinit(dname, dev, strat, lp, sspp) * Check against d_secperunit if the latter is reliable. */ error = 0; - secpercyl = max_nsectors * max_ntracks; - for (dp = dp0, slice = BASE_SLICE; slice < BASE_SLICE + NDOSPART; - dp++, slice++) { - u_long esector; - u_long esector1; - u_long ssector; - + secpercyl = (u_long)max_nsectors * max_ntracks; + for (dospart = 0, dp = dp0; dospart < NDOSPART; dospart++, dp++) { if (dp->dp_scyl == 0 && dp->dp_shd == 0 && dp->dp_ssect == 0 && dp->dp_start == 0 && dp->dp_size == 0) continue; - ssector = DPSECT(dp->dp_ssect) - 1 + dp->dp_shd * max_nsectors - + DPCYL(dp->dp_scyl, dp->dp_ssect) * secpercyl; - esector = DPSECT(dp->dp_esect) - 1 + dp->dp_ehd * max_nsectors - + DPCYL(dp->dp_ecyl, dp->dp_esect) * secpercyl; - esector1 = dp->dp_start + dp->dp_size - 1; - sname = dsname(dname, dkunit(dev), slice, RAW_PART, partname); - if (ssector != dp->dp_start || esector != esector1) - error = EINVAL; -#if 1 - else - printf("%s: start %lu, end = %lu, size %lu: OK\n", - sname, ssector, esector, dp->dp_size); - if (ssector != dp->dp_start) - printf("%s: C/H/S start %lu != start %lu: invalid\n", - sname, ssector, dp->dp_start); - if (esector != esector1) - printf("%s: C/H/S end %lu != end %lu: invalid\n", - sname, esector, esector1); -#endif + sname = dsname(dname, dkunit(dev), BASE_SLICE + dospart, + RAW_PART, partname); + + /* + * Temporarily ignore errors from this check. We could + * simplify things by accepting the table eariler if we + * always ignore errors here. Perhaps we should always + * accept the table if the magic is right but not let + * bad entries affect the geometry. + */ + check_part(sname, dp, (u_long)0, max_nsectors, max_ntracks); } if (error != 0) goto done; @@ -192,40 +232,35 @@ dsinit(dname, dev, strat, lp, sspp) */ free(ssp, M_DEVBUF); ssp = malloc(offsetof(struct diskslices, dss_slices) - + (BASE_SLICE + NDOSPART) * sizeof *sp, - M_DEVBUF, M_WAITOK); +#define MAX_SLICES_SUPPORTED MAX_SLICES /* was (BASE_SLICE + NDOSPART) */ + + MAX_SLICES_SUPPORTED * sizeof *sp, M_DEVBUF, M_WAITOK); *sspp = ssp; ssp->dss_first_bsd_slice = COMPATIBILITY_SLICE; sp = &ssp->dss_slices[0]; - bzero(sp, (BASE_SLICE + NDOSPART) * sizeof *sp); + bzero(sp, MAX_SLICES_SUPPORTED * sizeof *sp); sp[WHOLE_DISK_SLICE].ds_size = lp->d_secperunit; /* Initialize normal slices. */ sp += BASE_SLICE; - for (dp = dp0, slice = BASE_SLICE; slice < BASE_SLICE + NDOSPART; - dp++, slice++, sp++) { - if (dp->dp_typ == DOSPTYP_386BSD - && ssp->dss_first_bsd_slice == COMPATIBILITY_SLICE) { - ssp->dss_first_bsd_slice = slice; - ssp->dss_slices[COMPATIBILITY_SLICE].ds_offset - = dp->dp_start; - ssp->dss_slices[COMPATIBILITY_SLICE].ds_size - = dp->dp_size; - } + for (dospart = 0, dp = dp0; dospart < NDOSPART; dospart++, dp++, sp++) { sp->ds_offset = dp->dp_start; sp->ds_size = dp->dp_size; + sp->ds_type = dp->dp_typ; #if 0 - lp->d_subtype |= (lp->d_subtype & 3) - | (slice - BASE_SLICE) | DSTYPE_INDOSPART; + lp->d_subtype |= (lp->d_subtype & 3) | dospart + | DSTYPE_INDOSPART; #endif } - - /* - * We're not handling extended partitions yet, so there are always - * BASE_SLICE + NDOSPART slices altogether. - */ ssp->dss_nslices = BASE_SLICE + NDOSPART; + /* Handle extended partitions. */ + sp -= NDOSPART; + for (dospart = 0; dospart < NDOSPART; dospart++, sp++) + if (sp->ds_type == DOSPTYP_EXTENDED) + extended(dname, bp->b_dev, strat, lp, ssp, + sp->ds_offset, sp->ds_size, sp->ds_offset, + max_nsectors, max_ntracks); + done: bp->b_flags = B_INVAL | B_AGE; brelse(bp); @@ -233,3 +268,98 @@ dsinit(dname, dev, strat, lp, sspp) error = 0; return (error); } + +void +extended(dname, dev, strat, lp, ssp, ext_offset, ext_size, base_ext_offset, + nsectors, ntracks) + char *dname; + dev_t dev; + struct disklabel *lp; + d_strategy_t *strat; + struct diskslices *ssp; + u_long ext_offset; + u_long ext_size; + u_long base_ext_offset; + int nsectors; + int ntracks; +{ + struct buf *bp; + u_char *cp; + int dospart; + struct dos_partition *dp; + int end_slice; + u_long ext_offsets[NDOSPART]; + u_long ext_sizes[NDOSPART]; + char partname[2]; + int slice; + char *sname; + struct diskslice *sp; + + /* Read extended boot record. */ + bp = geteblk((int)lp->d_secsize); + bp->b_dev = dev; + bp->b_blkno = ext_offset; + bp->b_bcount = lp->d_secsize; + bp->b_flags = B_BUSY | B_READ; + (*strat)(bp); + if (biowait(bp) != 0) { + diskerr(bp, dname, "error reading extended partition table", + LOG_PRINTF, 0, lp); + printf("\n"); + return; + } + + /* Weakly verify it. */ + cp = bp->b_un.b_addr; + if (cp[0x1FE] != 0x55 || cp[0x1FF] != 0xAA) { + diskerr(bp, dname, "invalid extended partition table", + LOG_PRINTF, 0, lp); + printf("\n"); + return; + } + + for (dospart = 0, + dp = (struct dos_partition *)(bp->b_un.b_addr + DOSPARTOFF), + slice = ssp->dss_nslices, sp = &ssp->dss_slices[slice]; + dospart < NDOSPART; dospart++, dp++) { + ext_sizes[dospart] = 0; + if (dp->dp_scyl == 0 && dp->dp_shd == 0 && dp->dp_ssect == 0 + && dp->dp_start == 0 && dp->dp_size == 0) + continue; + if (dp->dp_typ == DOSPTYP_EXTENDED) { + char buf[32]; + + sname = dsname(dname, dkunit(dev), WHOLE_DISK_SLICE, + RAW_PART, partname); + strcpy(buf, sname); + if (strlen(buf) < sizeof buf - 11) + strcat(buf, ""); + check_part(buf, dp, base_ext_offset, nsectors, + ntracks); + ext_offsets[dospart] = base_ext_offset + dp->dp_start; + ext_sizes[dospart] = dp->dp_size; + } else { + sname = dsname(dname, dkunit(dev), slice, RAW_PART, + partname); + check_part(sname, dp, ext_offset, nsectors, ntracks); + if (slice >= MAX_SLICES) { + printf("%s: too many slices\n", sname); + slice++; + continue; + } + sp->ds_offset = ext_offset + dp->dp_start; + sp->ds_size = dp->dp_size; + sp->ds_type = dp->dp_typ; + ssp->dss_nslices++; + slice++; + sp++; + } + } + + /* If we found any more slices, recursively find all the subslices. */ + for (dospart = 0; dospart < NDOSPART; dospart++) + if (ext_sizes[dospart] != 0) + extended(dname, dev, strat, lp, ssp, + ext_offsets[dospart], ext_sizes[dospart], + base_ext_offset, nsectors, ntracks); +} diff --git a/sys/kern/subr_diskmbr.c b/sys/kern/subr_diskmbr.c index 91641f670272..6b2af2b6a0e8 100644 --- a/sys/kern/subr_diskmbr.c +++ b/sys/kern/subr_diskmbr.c @@ -35,17 +35,64 @@ * * from: @(#)ufs_disksubr.c 7.16 (Berkeley) 5/4/91 * from: ufs_disksubr.c,v 1.8 1994/06/07 01:21:39 phk Exp $ - * $Id: diskslice_machdep.c,v 1.5 1995/02/21 08:37:09 bde Exp $ + * $Id: diskslice_machdep.c,v 1.6 1995/02/22 22:46:36 bde Exp $ */ #include #include #include #include +#define DOSPTYP_EXTENDED 5 #include #include +#include #include +#define TRACE(str) do { if (dsi_debug) printf str; } while (0) + +static volatile u_char dsi_debug; + +static int check_part __P((char *sname, struct dos_partition *dp, + u_long offset, int nsectors, int ntracks)); +static void extended __P((char *dname, dev_t dev, d_strategy_t *strat, + struct disklabel *lp, struct diskslices *ssp, + u_long ext_offset, u_long ext_size, + u_long base_ext_offset, int nsectors, int ntracks)); + +static int +check_part(sname, dp, offset, nsectors, ntracks) + char *sname; + struct dos_partition *dp; + u_long offset; + int nsectors; + int ntracks; +{ + int error; + u_long esector; + u_long esector1; + u_long secpercyl; + u_long ssector; + u_long ssector1; + + secpercyl = (u_long)nsectors * ntracks; + ssector = DPSECT(dp->dp_ssect) - 1 + dp->dp_shd * nsectors + + DPCYL(dp->dp_scyl, dp->dp_ssect) * secpercyl; + ssector1 = offset + dp->dp_start; + esector = DPSECT(dp->dp_esect) - 1 + dp->dp_ehd * nsectors + + DPCYL(dp->dp_ecyl, dp->dp_esect) * secpercyl; + esector1 = ssector1 + dp->dp_size - 1; + error = ssector == ssector1 && esector == esector1 ? 0 : EINVAL; + printf("%s: start %lu, end = %lu, size %lu%s\n", + sname, ssector, esector, dp->dp_size, error ? "" : ": OK"); + if (ssector != ssector1) + printf("%s: C/H/S start %lu != start %lu: invalid\n", + sname, ssector, ssector1); + if (esector != esector1) + printf("%s: C/H/S end %lu != end %lu: invalid\n", + sname, esector, esector1); + return (error); +} + int dsinit(dname, dev, strat, lp, sspp) char *dname; @@ -56,6 +103,7 @@ dsinit(dname, dev, strat, lp, sspp) { struct buf *bp; u_char *cp; + int dospart; struct dos_partition *dp; struct dos_partition *dp0; int error; @@ -92,6 +140,9 @@ dsinit(dname, dev, strat, lp, sspp) bp->b_flags = B_BUSY | B_READ; (*strat)(bp); if (biowait(bp) != 0) { + diskerr(bp, dname, "error reading partition table", + LOG_PRINTF, 0, lp); + printf("\n"); error = EIO; goto done; } @@ -99,6 +150,9 @@ dsinit(dname, dev, strat, lp, sspp) /* Weakly verify it. */ cp = bp->b_un.b_addr; if (cp[0x1FE] != 0x55 || cp[0x1FF] != 0xAA) { + diskerr(bp, dname, "invalid partition table", + LOG_PRINTF, 0, lp); + printf("\n"); error = EINVAL; goto done; } @@ -113,10 +167,9 @@ dsinit(dname, dev, strat, lp, sspp) max_nsectors = 0; max_ntracks = 0; dp0 = (struct dos_partition *)(cp + DOSPARTOFF); - for (dp = dp0, slice = BASE_SLICE; slice < BASE_SLICE + NDOSPART; - dp++, slice++) { - int nsectors; - int ntracks; + for (dospart = 0, dp = dp0; dospart < NDOSPART; dospart++, dp++) { + int nsectors; + int ntracks; max_ncyls = DPCYL(dp->dp_ecyl, dp->dp_esect); if (max_ncyls < max_ncyls) @@ -137,35 +190,22 @@ dsinit(dname, dev, strat, lp, sspp) * Check against d_secperunit if the latter is reliable. */ error = 0; - secpercyl = max_nsectors * max_ntracks; - for (dp = dp0, slice = BASE_SLICE; slice < BASE_SLICE + NDOSPART; - dp++, slice++) { - u_long esector; - u_long esector1; - u_long ssector; - + secpercyl = (u_long)max_nsectors * max_ntracks; + for (dospart = 0, dp = dp0; dospart < NDOSPART; dospart++, dp++) { if (dp->dp_scyl == 0 && dp->dp_shd == 0 && dp->dp_ssect == 0 && dp->dp_start == 0 && dp->dp_size == 0) continue; - ssector = DPSECT(dp->dp_ssect) - 1 + dp->dp_shd * max_nsectors - + DPCYL(dp->dp_scyl, dp->dp_ssect) * secpercyl; - esector = DPSECT(dp->dp_esect) - 1 + dp->dp_ehd * max_nsectors - + DPCYL(dp->dp_ecyl, dp->dp_esect) * secpercyl; - esector1 = dp->dp_start + dp->dp_size - 1; - sname = dsname(dname, dkunit(dev), slice, RAW_PART, partname); - if (ssector != dp->dp_start || esector != esector1) - error = EINVAL; -#if 1 - else - printf("%s: start %lu, end = %lu, size %lu: OK\n", - sname, ssector, esector, dp->dp_size); - if (ssector != dp->dp_start) - printf("%s: C/H/S start %lu != start %lu: invalid\n", - sname, ssector, dp->dp_start); - if (esector != esector1) - printf("%s: C/H/S end %lu != end %lu: invalid\n", - sname, esector, esector1); -#endif + sname = dsname(dname, dkunit(dev), BASE_SLICE + dospart, + RAW_PART, partname); + + /* + * Temporarily ignore errors from this check. We could + * simplify things by accepting the table eariler if we + * always ignore errors here. Perhaps we should always + * accept the table if the magic is right but not let + * bad entries affect the geometry. + */ + check_part(sname, dp, (u_long)0, max_nsectors, max_ntracks); } if (error != 0) goto done; @@ -192,40 +232,35 @@ dsinit(dname, dev, strat, lp, sspp) */ free(ssp, M_DEVBUF); ssp = malloc(offsetof(struct diskslices, dss_slices) - + (BASE_SLICE + NDOSPART) * sizeof *sp, - M_DEVBUF, M_WAITOK); +#define MAX_SLICES_SUPPORTED MAX_SLICES /* was (BASE_SLICE + NDOSPART) */ + + MAX_SLICES_SUPPORTED * sizeof *sp, M_DEVBUF, M_WAITOK); *sspp = ssp; ssp->dss_first_bsd_slice = COMPATIBILITY_SLICE; sp = &ssp->dss_slices[0]; - bzero(sp, (BASE_SLICE + NDOSPART) * sizeof *sp); + bzero(sp, MAX_SLICES_SUPPORTED * sizeof *sp); sp[WHOLE_DISK_SLICE].ds_size = lp->d_secperunit; /* Initialize normal slices. */ sp += BASE_SLICE; - for (dp = dp0, slice = BASE_SLICE; slice < BASE_SLICE + NDOSPART; - dp++, slice++, sp++) { - if (dp->dp_typ == DOSPTYP_386BSD - && ssp->dss_first_bsd_slice == COMPATIBILITY_SLICE) { - ssp->dss_first_bsd_slice = slice; - ssp->dss_slices[COMPATIBILITY_SLICE].ds_offset - = dp->dp_start; - ssp->dss_slices[COMPATIBILITY_SLICE].ds_size - = dp->dp_size; - } + for (dospart = 0, dp = dp0; dospart < NDOSPART; dospart++, dp++, sp++) { sp->ds_offset = dp->dp_start; sp->ds_size = dp->dp_size; + sp->ds_type = dp->dp_typ; #if 0 - lp->d_subtype |= (lp->d_subtype & 3) - | (slice - BASE_SLICE) | DSTYPE_INDOSPART; + lp->d_subtype |= (lp->d_subtype & 3) | dospart + | DSTYPE_INDOSPART; #endif } - - /* - * We're not handling extended partitions yet, so there are always - * BASE_SLICE + NDOSPART slices altogether. - */ ssp->dss_nslices = BASE_SLICE + NDOSPART; + /* Handle extended partitions. */ + sp -= NDOSPART; + for (dospart = 0; dospart < NDOSPART; dospart++, sp++) + if (sp->ds_type == DOSPTYP_EXTENDED) + extended(dname, bp->b_dev, strat, lp, ssp, + sp->ds_offset, sp->ds_size, sp->ds_offset, + max_nsectors, max_ntracks); + done: bp->b_flags = B_INVAL | B_AGE; brelse(bp); @@ -233,3 +268,98 @@ dsinit(dname, dev, strat, lp, sspp) error = 0; return (error); } + +void +extended(dname, dev, strat, lp, ssp, ext_offset, ext_size, base_ext_offset, + nsectors, ntracks) + char *dname; + dev_t dev; + struct disklabel *lp; + d_strategy_t *strat; + struct diskslices *ssp; + u_long ext_offset; + u_long ext_size; + u_long base_ext_offset; + int nsectors; + int ntracks; +{ + struct buf *bp; + u_char *cp; + int dospart; + struct dos_partition *dp; + int end_slice; + u_long ext_offsets[NDOSPART]; + u_long ext_sizes[NDOSPART]; + char partname[2]; + int slice; + char *sname; + struct diskslice *sp; + + /* Read extended boot record. */ + bp = geteblk((int)lp->d_secsize); + bp->b_dev = dev; + bp->b_blkno = ext_offset; + bp->b_bcount = lp->d_secsize; + bp->b_flags = B_BUSY | B_READ; + (*strat)(bp); + if (biowait(bp) != 0) { + diskerr(bp, dname, "error reading extended partition table", + LOG_PRINTF, 0, lp); + printf("\n"); + return; + } + + /* Weakly verify it. */ + cp = bp->b_un.b_addr; + if (cp[0x1FE] != 0x55 || cp[0x1FF] != 0xAA) { + diskerr(bp, dname, "invalid extended partition table", + LOG_PRINTF, 0, lp); + printf("\n"); + return; + } + + for (dospart = 0, + dp = (struct dos_partition *)(bp->b_un.b_addr + DOSPARTOFF), + slice = ssp->dss_nslices, sp = &ssp->dss_slices[slice]; + dospart < NDOSPART; dospart++, dp++) { + ext_sizes[dospart] = 0; + if (dp->dp_scyl == 0 && dp->dp_shd == 0 && dp->dp_ssect == 0 + && dp->dp_start == 0 && dp->dp_size == 0) + continue; + if (dp->dp_typ == DOSPTYP_EXTENDED) { + char buf[32]; + + sname = dsname(dname, dkunit(dev), WHOLE_DISK_SLICE, + RAW_PART, partname); + strcpy(buf, sname); + if (strlen(buf) < sizeof buf - 11) + strcat(buf, ""); + check_part(buf, dp, base_ext_offset, nsectors, + ntracks); + ext_offsets[dospart] = base_ext_offset + dp->dp_start; + ext_sizes[dospart] = dp->dp_size; + } else { + sname = dsname(dname, dkunit(dev), slice, RAW_PART, + partname); + check_part(sname, dp, ext_offset, nsectors, ntracks); + if (slice >= MAX_SLICES) { + printf("%s: too many slices\n", sname); + slice++; + continue; + } + sp->ds_offset = ext_offset + dp->dp_start; + sp->ds_size = dp->dp_size; + sp->ds_type = dp->dp_typ; + ssp->dss_nslices++; + slice++; + sp++; + } + } + + /* If we found any more slices, recursively find all the subslices. */ + for (dospart = 0; dospart < NDOSPART; dospart++) + if (ext_sizes[dospart] != 0) + extended(dname, dev, strat, lp, ssp, + ext_offsets[dospart], ext_sizes[dospart], + base_ext_offset, nsectors, ntracks); +}