From 57a5f9023d7ba6eb9c0fe02789312a0d6ae4e363 Mon Sep 17 00:00:00 2001 From: bde Date: Wed, 29 Jul 1998 11:15:54 +0000 Subject: Centralized and optimized handling of large sectors. Centralized checking of transfer sizes and alignments. Old version tested with 2K-sectors on od disks by: Shunsuke Akiyama . --- sys/kern/subr_diskslice.c | 105 ++++++++++++++++++++++++++++++++-------------- sys/scsi/od.c | 57 +------------------------ sys/scsi/sd.c | 60 +++----------------------- sys/sys/diskslice.h | 5 ++- 4 files changed, 85 insertions(+), 142 deletions(-) diff --git a/sys/kern/subr_diskslice.c b/sys/kern/subr_diskslice.c index 164ed29..0b2e13d 100644 --- a/sys/kern/subr_diskslice.c +++ b/sys/kern/subr_diskslice.c @@ -43,7 +43,7 @@ * from: wd.c,v 1.55 1994/10/22 01:57:12 phk Exp $ * 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: subr_diskslice.c,v 1.53 1998/07/28 19:39:09 bde Exp $ + * $Id: subr_diskslice.c,v 1.54 1998/07/29 08:24:23 bde Exp $ */ #include "opt_devfs.h" @@ -156,48 +156,69 @@ dscheck(bp, ssp) struct diskslices *ssp; { daddr_t blkno; + u_long endsecno; daddr_t labelsect; struct disklabel *lp; - u_long maxsz; char *msg; + long nsec; struct partition *pp; + daddr_t secno; + daddr_t slicerel_secno; struct diskslice *sp; - long sz; - if (bp->b_blkno < 0) { - Debugger("Slice code got negative blocknumber"); + blkno = bp->b_blkno; + if (blkno < 0) { + printf("dscheck: negative b_blkno %ld\n", (long)blkno); bp->b_error = EINVAL; goto bad; } - sp = &ssp->dss_slices[dkslice(bp->b_dev)]; lp = sp->ds_label; - sz = (bp->b_bcount + DEV_BSIZE - 1) >> DEV_BSHIFT; + if (ssp->dss_secmult == 1) { + if (bp->b_bcount % (u_long)DEV_BSIZE) + goto bad_bcount; + secno = blkno; + nsec = bp->b_bcount >> DEV_BSHIFT; + } else if (ssp->dss_secshift != -1) { + if (bp->b_bcount & (ssp->dss_secsize - 1)) + goto bad_bcount; + if (blkno & (ssp->dss_secmult - 1)) + goto bad_blkno; + secno = blkno >> ssp->dss_secshift; + nsec = bp->b_bcount >> (DEV_BSHIFT + ssp->dss_secshift); + } else { + if (bp->b_bcount % ssp->dss_secsize) + goto bad_bcount; + if (blkno % ssp->dss_secmult) + goto bad_blkno; + secno = blkno / ssp->dss_secmult; + nsec = bp->b_bcount / ssp->dss_secsize; + } if (lp == NULL) { - blkno = bp->b_blkno; labelsect = -LABELSECTOR - 1; - maxsz = sp->ds_size; + endsecno = sp->ds_size; + slicerel_secno = secno; } else { labelsect = lp->d_partitions[LABEL_PART].p_offset; if (labelsect != 0) Debugger("labelsect != 0 in dscheck()"); pp = &lp->d_partitions[dkpart(bp->b_dev)]; - blkno = pp->p_offset + bp->b_blkno; - maxsz = pp->p_size; + endsecno = pp->p_size; + slicerel_secno = pp->p_offset + secno; if (sp->ds_bad != NULL && ds_debug) { - daddr_t newblkno; + daddr_t newsecno; - newblkno = transbad144(sp->ds_bad, blkno); - if (newblkno != blkno) - printf("should map bad block %ld -> %ld\n", - (long)blkno, (long)newblkno); + newsecno = transbad144(sp->ds_bad, slicerel_secno); + if (newsecno != slicerel_secno) + printf("should map bad sector %ld -> %ld\n", + (long)slicerel_secno, (long)newsecno); } } /* overwriting disk label ? */ /* XXX should also protect bootstrap in first 8K */ - if (blkno <= LABELSECTOR + labelsect && + if (slicerel_secno <= LABELSECTOR + labelsect && #if LABELSECTOR != 0 - blkno + sz > LABELSECTOR + labelsect && + slicerel_secno + nsec > LABELSECTOR + labelsect && #endif (bp->b_flags & B_READ) == 0 && sp->ds_wlabel == 0) { bp->b_error = EROFS; @@ -206,7 +227,7 @@ if (labelsect != 0) Debugger("labelsect != 0 in dscheck()"); #if defined(DOSBBSECTOR) && defined(notyet) /* overwriting master boot record? */ - if (blkno <= DOSBBSECTOR && (bp->b_flags & B_READ) == 0 && + if (slicerel_secno <= DOSBBSECTOR && (bp->b_flags & B_READ) == 0 && sp->ds_wlabel == 0) { bp->b_error = EROFS; goto bad; @@ -214,31 +235,31 @@ if (labelsect != 0) Debugger("labelsect != 0 in dscheck()"); #endif /* beyond partition? */ - if (bp->b_blkno < 0 || bp->b_blkno + sz > maxsz) { + if (secno + nsec > endsecno) { /* if exactly at end of disk, return an EOF */ - if (bp->b_blkno == maxsz) { + if (secno == endsecno) { bp->b_resid = bp->b_bcount; return (0); } /* or truncate if part of it fits */ - sz = maxsz - bp->b_blkno; - if (sz <= 0) { + nsec = endsecno - secno; + if (nsec <= 0) { bp->b_error = EINVAL; goto bad; } - bp->b_bcount = sz << DEV_BSHIFT; + bp->b_bcount = nsec * ssp->dss_secsize; } - bp->b_pblkno = blkno + sp->ds_offset; + bp->b_pblkno = sp->ds_offset + slicerel_secno; /* * Snoop on label accesses if the slice offset is nonzero. Fudge * offsets in the label to keep the in-core label coherent with * the on-disk one. */ - if (blkno <= LABELSECTOR + labelsect + if (slicerel_secno <= LABELSECTOR + labelsect #if LABELSECTOR != 0 - && blkno + sz > LABELSECTOR + labelsect + && slicerel_secno + nsec > LABELSECTOR + labelsect #endif && sp->ds_offset != 0) { struct iodone_chain *ic; @@ -247,10 +268,8 @@ if (labelsect != 0) Debugger("labelsect != 0 in dscheck()"); ic->ic_prev_flags = bp->b_flags; ic->ic_prev_iodone = bp->b_iodone; ic->ic_prev_iodone_chain = bp->b_iodone_chain; - ic->ic_args[0].ia_long = (LABELSECTOR + labelsect - blkno) - << DEV_BSHIFT; - if (lp) - ic->ic_args[0].ia_long *= lp->d_secsize / DEV_BSIZE; + ic->ic_args[0].ia_long = (LABELSECTOR + labelsect - + slicerel_secno) * ssp->dss_secsize; ic->ic_args[1].ia_ptr = sp; bp->b_flags |= B_CALL; bp->b_iodone = dsiodone; @@ -267,6 +286,7 @@ if (labelsect != 0) Debugger("labelsect != 0 in dscheck()"); */ if (bp->b_vp != NULL) bp->b_vp->v_numoutput++; + /* XXX need name here. */ msg = fixlabel((char *)NULL, sp, (struct disklabel *) (bp->b_data + ic->ic_args[0].ia_long), @@ -280,6 +300,18 @@ if (labelsect != 0) Debugger("labelsect != 0 in dscheck()"); } return (1); +bad_bcount: + printf("dscheck: b_bcount %ld is not on a sector boundary (ssize %d)\n", + bp->b_bcount, ssp->dss_secsize); + bp->b_error = EINVAL; + goto bad; + +bad_blkno: + printf("dscheck: b_blkno %ld is not on a sector boundary (ssize %d)\n", + (long)blkno, ssp->dss_secsize); + bp->b_error = EINVAL; + goto bad; + bad: bp->b_resid = bp->b_bcount; bp->b_flags |= B_ERROR; @@ -620,6 +652,12 @@ dsmakeslicestruct(nslices, lp) ssp->dss_cdevsw = NULL; ssp->dss_first_bsd_slice = COMPATIBILITY_SLICE; ssp->dss_nslices = nslices; + ssp->dss_secmult = lp->d_secsize / DEV_BSIZE; + if (ssp->dss_secmult & (ssp->dss_secmult - 1)) + ssp->dss_secshift = -1; + else + ssp->dss_secshift = ffs(ssp->dss_secmult) - 1; + ssp->dss_secsize = lp->d_secsize; sp = &ssp->dss_slices[0]; bzero(sp, nslices * sizeof *sp); sp[WHOLE_DISK_SLICE].ds_size = lp->d_secperunit; @@ -684,6 +722,9 @@ dsopen(dname, dev, mode, sspp, lp, strat, setgeom, bdevsw, cdevsw) struct diskslices *ssp; int unit; + if (lp->d_secsize % DEV_BSIZE) + return (EINVAL); + /* * XXX reinitialize the slice table unless there is an open device * on the unit. This should only be done if the media has changed. @@ -786,6 +827,8 @@ dsopen(dname, dev, mode, sspp, lp, strat, setgeom, bdevsw, cdevsw) #endif if (msg == NULL) msg = fixlabel(sname, sp, lp1, FALSE); + if (msg == NULL && lp1->d_secsize != ssp->dss_secsize) + msg = "inconsistent sector size"; if (msg != NULL) { free(lp1, M_DEVBUF); if (sp->ds_type == DOSPTYP_386BSD /* XXX */) diff --git a/sys/scsi/od.c b/sys/scsi/od.c index 1dc817e..4769406 100644 --- a/sys/scsi/od.c +++ b/sys/scsi/od.c @@ -28,7 +28,7 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * - * $Id: od.c,v 1.42 1998/07/13 09:53:11 bde Exp $ + * $Id: od.c,v 1.43 1998/07/28 18:59:49 bde Exp $ */ /* @@ -456,7 +456,6 @@ od_strategy(struct buf *bp, struct scsi_link *sc_link) u_int32_t opri; struct scsi_data *od; u_int32_t unit; - int secsize; odstrats++; unit = ODUNIT((bp->b_dev)); @@ -471,62 +470,10 @@ od_strategy(struct buf *bp, struct scsi_link *sc_link) } /* - * Odd number of bytes or negative offset - */ - if (bp->b_blkno < 0 ) { - bp->b_error = EINVAL; - printf("od_strategy: Negative block number: 0x%x\n", bp->b_blkno); - goto bad; - } - - - secsize = od->params.secsiz; - - /* make sure the blkno is scalable */ - if( (bp->b_blkno % (secsize/DEV_BSIZE)) != 0 ) { - bp->b_error = EINVAL; - printf("od_strategy: Block number is not multiple of sector size (2): 0x%x\n", bp->b_blkno); - goto bad; - } - - /* make sure that the transfer size is a multiple of the sector size */ - if( (bp->b_bcount % secsize) != 0 ) { - bp->b_error = EINVAL; - printf( - "od_strategy: Invalid b_bcount %ld at block number: 0x%lx\n", - bp->b_bcount, (long)bp->b_blkno); - goto bad; - } - - /* * Do bounds checking, adjust transfer, and set b_pblkno. */ - { - int status; - int sec_blk_ratio = secsize/DEV_BSIZE; - /* save original block number and size */ - int b_blkno = bp->b_blkno; - int b_bcount = bp->b_bcount; - - /* replace with scaled values */ - bp->b_blkno /= sec_blk_ratio; - bp->b_bcount /= sec_blk_ratio; - - /* have dscheck enforce limits and map to physical block number */ - status = dscheck(bp, od->dk_slices); - - /* restore original values to prevent bad side effects in block system */ - bp->b_blkno = b_blkno; - bp->b_bcount = b_bcount; - /* scale resid */ - bp->b_resid *= sec_blk_ratio; - - /* see if the mapping failed */ - if (status <= 0) - { + if (dscheck(bp, od->dk_slices) <= 0) goto done; /* XXX check b_resid */ - } - } opri = SPLOD(); diff --git a/sys/scsi/sd.c b/sys/scsi/sd.c index c7e191b..8043704 100644 --- a/sys/scsi/sd.c +++ b/sys/scsi/sd.c @@ -14,7 +14,7 @@ * * Ported to run under 386BSD by Julian Elischer (julian@dialix.oz.au) Sept 1992 * - * $Id: sd.c,v 1.135 1998/07/14 11:34:22 bde Exp $ + * $Id: sd.c,v 1.136 1998/07/28 18:59:49 bde Exp $ */ #include "opt_bounce.h" @@ -559,7 +559,7 @@ sd_strategy(struct buf *bp, struct scsi_link *sc_link) { u_int32_t opri; struct scsi_data *sd; - u_int32_t unit, secsize; + u_int32_t unit; sdstrats++; unit = SDUNIT((bp->b_dev)); @@ -578,60 +578,10 @@ sd_strategy(struct buf *bp, struct scsi_link *sc_link) scsi_minphys(bp,&sd_switch); /* - * Odd number of bytes or negative offset + * Do bounds checking, adjust transfer, and set b_pbklno. */ - if (bp->b_blkno < 0 ) { - bp->b_error = EINVAL; - printf("sd_strategy: Negative block number: 0x%x\n", - bp->b_blkno); - goto bad; - } - - secsize = sd->params.secsiz; - - /* make sure the blkno is scalable */ - if( (bp->b_blkno % (secsize/DEV_BSIZE)) != 0 ) { - bp->b_error = EINVAL; - printf("sd_strategy: Block number is not multiple of sector size (2): 0x%x\n", bp->b_blkno); - goto bad; - } - - /* make sure that the transfer size is a multiple of the sector size */ - if( (bp->b_bcount % secsize) != 0 ) { - bp->b_error = EINVAL; - printf( - "sd_strategy: Invalid b_bcount %ld at block number: 0x%lx\n", - bp->b_bcount, (long)bp->b_blkno); - goto bad; - } - - /* - * Do bounds checking, adjust transfer, set b_cylin and b_pbklno. - */ - { - int status; - int sec_blk_ratio = secsize/DEV_BSIZE; - int b_blkno = bp->b_blkno; - - /* Replace blkno and count with scaled values. */ - bp->b_blkno /= sec_blk_ratio; - bp->b_bcount /= sec_blk_ratio; - - /* enforce limits and map to physical block number */ - status = dscheck(bp, sd->dk_slices); - - /* - * Restore blkno and unscale the values set by dscheck(), - * except for b_pblkno. - */ - bp->b_blkno = b_blkno; - bp->b_bcount *= sec_blk_ratio; - bp->b_resid *= sec_blk_ratio; - - /* see if the mapping failed */ - if (status <= 0) - goto done; /* XXX check b_resid */ - } + if (dscheck(bp, sd->dk_slices) <= 0) + goto done; /* XXX check b_resid */ opri = SPLSD(); /* diff --git a/sys/sys/diskslice.h b/sys/sys/diskslice.h index 31b1219..e6aca57 100644 --- a/sys/sys/diskslice.h +++ b/sys/sys/diskslice.h @@ -23,7 +23,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: diskslice.h,v 1.23 1998/07/04 22:30:26 julian Exp $ + * $Id: diskslice.h,v 1.24 1998/07/20 13:39:45 bde Exp $ */ #ifndef _SYS_DISKSLICE_H_ @@ -73,6 +73,9 @@ struct diskslices { struct cdevsw *dss_cdevsw; /* for containing device */ int dss_first_bsd_slice; /* COMPATIBILITY_SLICE is mapped here */ u_int dss_nslices; /* actual dimension of dss_slices[] */ + int dss_secmult; /* block to sector multiplier */ + int dss_secshift; /* block to sector shift (or -1) */ + int dss_secsize; /* sector size */ struct diskslice dss_slices[MAX_SLICES]; /* actually usually less */ }; -- cgit v1.1