summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorbde <bde@FreeBSD.org>1998-07-29 11:15:54 +0000
committerbde <bde@FreeBSD.org>1998-07-29 11:15:54 +0000
commit57a5f9023d7ba6eb9c0fe02789312a0d6ae4e363 (patch)
tree4afbc549527fb0b6e26795be8cee174ce0d65c5a
parent4a3c46b3596a248587fc4fd2fdfe53f2443eded9 (diff)
downloadFreeBSD-src-57a5f9023d7ba6eb9c0fe02789312a0d6ae4e363.zip
FreeBSD-src-57a5f9023d7ba6eb9c0fe02789312a0d6ae4e363.tar.gz
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>.
-rw-r--r--sys/kern/subr_diskslice.c105
-rw-r--r--sys/scsi/od.c57
-rw-r--r--sys/scsi/sd.c60
-rw-r--r--sys/sys/diskslice.h5
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 */
};
OpenPOWER on IntegriCloud