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:
parent
62052b46f7
commit
f9a9c96c25
@ -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 */)
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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();
|
||||
/*
|
||||
|
@ -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 */
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user