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
<akiyama@kme.mei.co.jp>.
This commit is contained in:
Bruce Evans 1998-07-29 11:15:54 +00:00
parent 62052b46f7
commit f9a9c96c25
4 changed files with 85 additions and 142 deletions

View File

@ -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 */)

View File

@ -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));
@ -470,63 +469,11 @@ od_strategy(struct buf *bp, struct scsi_link *sc_link)
goto bad;
}
/*
* 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();

View File

@ -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();
/*

View File

@ -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 */
};