diff options
-rw-r--r-- | sys/fs/specfs/spec_vnops.c | 65 | ||||
-rw-r--r-- | sys/kern/vfs_export.c | 36 | ||||
-rw-r--r-- | sys/kern/vfs_subr.c | 36 | ||||
-rw-r--r-- | sys/miscfs/specfs/spec_vnops.c | 65 | ||||
-rw-r--r-- | sys/miscfs/specfs/specdev.h | 7 | ||||
-rw-r--r-- | sys/sys/conf.h | 12 | ||||
-rw-r--r-- | sys/sys/linedisc.h | 12 |
7 files changed, 164 insertions, 69 deletions
diff --git a/sys/fs/specfs/spec_vnops.c b/sys/fs/specfs/spec_vnops.c index 88290e4..3f29d9362 100644 --- a/sys/fs/specfs/spec_vnops.c +++ b/sys/fs/specfs/spec_vnops.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. * * @(#)spec_vnops.c 8.14 (Berkeley) 5/21/95 - * $Id: spec_vnops.c,v 1.79 1999/01/21 08:29:07 dillon Exp $ + * $Id: spec_vnops.c,v 1.80 1999/01/27 22:42:07 dillon Exp $ */ #include <sys/param.h> @@ -286,8 +286,15 @@ spec_read(ap) case VBLK: if (uio->uio_offset < 0) return (EINVAL); - bsize = BLKDEV_IOSIZE; dev = vp->v_rdev; + + /* + * Calculate block size for block device. The block size must + * be larger then the physical minimum. + */ + + bsize = vp->v_specinfo->si_bsize_best; + if ((ioctl = bdevsw[major(dev)]->d_ioctl) != NULL && (*ioctl)(dev, DIOCGPART, (caddr_t)&dpart, FREAD, p) == 0 && dpart.part->p_fstype == FS_BSDFFS && @@ -365,7 +372,13 @@ spec_write(ap) return (0); if (uio->uio_offset < 0) return (EINVAL); - bsize = BLKDEV_IOSIZE; + + /* + * Calculate block size for block device. The block size must + * be larger then the physical minimum. + */ + bsize = vp->v_specinfo->si_bsize_best; + if ((*bdevsw[major(vp->v_rdev)]->d_ioctl)(vp->v_rdev, DIOCGPART, (caddr_t)&dpart, FREAD, p) == 0) { if (dpart.part->p_fstype == FS_BSDFFS && @@ -749,14 +762,16 @@ spec_getpages(ap) pcount = round_page(ap->a_count) / PAGE_SIZE; /* - * Calculate the offset of the transfer. + * Calculate the offset of the transfer and do sanity check. + * FreeBSD currently only supports an 8 TB range due to b_blkno + * being in DEV_BSIZE ( usually 512 ) byte chunks on call to + * VOP_STRATEGY. XXX */ offset = IDX_TO_OFF(ap->a_m[0]->pindex) + ap->a_offset; - /* XXX sanity check before we go into details. */ - /* XXX limits should be defined elsewhere. */ -#define DADDR_T_BIT 32 +#define DADDR_T_BIT (sizeof(daddr_t)*8) #define OFFSET_MAX ((1LL << (DADDR_T_BIT + DEV_BSHIFT)) - 1) + if (offset < 0 || offset > OFFSET_MAX) { /* XXX still no %q in kernel. */ printf("spec_getpages: preposterous offset 0x%x%08x\n", @@ -768,20 +783,20 @@ spec_getpages(ap) blkno = btodb(offset); /* - * Round up physical size for real devices, use the - * fundamental blocksize of the fs if possible. + * Round up physical size for real devices. We cannot round using + * v_mount's block size data because v_mount has nothing to do with + * the device. i.e. it's usually '/dev'. We need the physical block + * size for the device itself. + * + * We can't use v_specmountpoint because it only exists when the + * block device is mounted. However, we can use v_specinfo. */ - if (vp && vp->v_mount) { - if (vp->v_type != VBLK) { - vprint("Non VBLK", vp); - } - blksiz = vp->v_mount->mnt_stat.f_bsize; - if (blksiz < DEV_BSIZE) { - blksiz = DEV_BSIZE; - } - } + + if (vp->v_type == VBLK) + blksiz = vp->v_specinfo->si_bsize_phys; else blksiz = DEV_BSIZE; + size = (ap->a_count + blksiz - 1) & ~(blksiz - 1); bp = getpbuf(NULL); @@ -885,8 +900,8 @@ spec_getpages(ap) m = ap->a_m[ap->a_reqpage]; #ifndef MAX_PERF printf( - "spec_getpages: I/O read failure: (error code=%d)\n", - error); + "spec_getpages: I/O read failure: (error code=%d) bp %p vp %p\n", + error, bp, bp->b_vp); printf( " size: %d, resid: %ld, a_count: %d, valid: 0x%x\n", size, bp->b_resid, ap->a_count, m->valid); @@ -923,10 +938,14 @@ spec_getattr(ap) bzero(vap, sizeof (*vap)); - if (vp->v_type == VBLK) - vap->va_blocksize = BLKDEV_IOSIZE; - else if (vp->v_type == VCHR) + if (vp->v_type == VBLK) { + if (vp->v_specinfo) + vap->va_blocksize = vp->v_specmountpoint->mnt_stat.f_iosize; + else + vap->va_blocksize = BLKDEV_IOSIZE; + } else if (vp->v_type == VCHR) { vap->va_blocksize = MAXBSIZE; + } if ((*bdevsw[major(vp->v_rdev)]->d_ioctl)(vp->v_rdev, DIOCGPART, (caddr_t)&dpart, FREAD, ap->a_p) == 0) { diff --git a/sys/kern/vfs_export.c b/sys/kern/vfs_export.c index 8bc6935..d718a3f 100644 --- a/sys/kern/vfs_export.c +++ b/sys/kern/vfs_export.c @@ -36,7 +36,7 @@ * SUCH DAMAGE. * * @(#)vfs_subr.c 8.31 (Berkeley) 5/26/95 - * $Id: vfs_subr.c,v 1.186 1999/02/04 18:25:39 dillon Exp $ + * $Id: vfs_subr.c,v 1.187 1999/02/19 17:36:58 dillon Exp $ */ /* @@ -901,8 +901,8 @@ vn_syncer_add_to_worklist(struct vnode *vp, int delay) splx(s); } +static struct proc *updateproc; static void sched_sync __P((void)); -static struct proc *updateproc; static const struct kproc_desc up_kp = { "syncer", sched_sync, @@ -1201,6 +1201,7 @@ checkalias(nvp, nvp_rdev, mp) struct proc *p = curproc; /* XXX */ struct vnode *vp; struct vnode **vpp; + int rmaj = major(nvp_rdev); if (nvp->v_type != VBLK && nvp->v_type != VCHR) return (NULLVP); @@ -1239,16 +1240,37 @@ loop: * and the clauses had been swapped. */ if (vp == NULL || vp->v_tag != VT_NON) { + struct specinfo *sinfo; + /* * Put the new vnode into the hash chain. * and if there was an alias, connect them. */ - MALLOC(nvp->v_specinfo, struct specinfo *, + MALLOC(sinfo, struct specinfo *, sizeof(struct specinfo), M_VNODE, M_WAITOK); - nvp->v_rdev = nvp_rdev; - nvp->v_hashchain = vpp; - nvp->v_specnext = *vpp; - nvp->v_specmountpoint = NULL; + bzero(sinfo, sizeof(struct specinfo)); + nvp->v_specinfo = sinfo; + sinfo->si_rdev = nvp_rdev; + sinfo->si_hashchain = vpp; + sinfo->si_specnext = *vpp; + sinfo->si_bsize_phys = DEV_BSIZE; + sinfo->si_bsize_best = BLKDEV_IOSIZE; + sinfo->si_bsize_max = MAXBSIZE; + + /* + * Ask the device to fix up specinfo. Typically the + * si_bsize_* parameters may need fixing up. + */ + + if (nvp->v_type == VBLK && rmaj < nblkdev) { + if (bdevsw[rmaj] && bdevsw[rmaj]->d_parms) + + (*bdevsw[rmaj]->d_parms)(nvp_rdev, sinfo, DPARM_GET); + } else if (nvp->v_type == VCHR && rmaj < nchrdev) { + if (cdevsw[rmaj] && cdevsw[rmaj]->d_parms) + (*cdevsw[rmaj]->d_parms)(nvp_rdev, sinfo, DPARM_GET); + } + simple_unlock(&spechash_slock); *vpp = nvp; if (vp != NULLVP) { diff --git a/sys/kern/vfs_subr.c b/sys/kern/vfs_subr.c index 8bc6935..d718a3f 100644 --- a/sys/kern/vfs_subr.c +++ b/sys/kern/vfs_subr.c @@ -36,7 +36,7 @@ * SUCH DAMAGE. * * @(#)vfs_subr.c 8.31 (Berkeley) 5/26/95 - * $Id: vfs_subr.c,v 1.186 1999/02/04 18:25:39 dillon Exp $ + * $Id: vfs_subr.c,v 1.187 1999/02/19 17:36:58 dillon Exp $ */ /* @@ -901,8 +901,8 @@ vn_syncer_add_to_worklist(struct vnode *vp, int delay) splx(s); } +static struct proc *updateproc; static void sched_sync __P((void)); -static struct proc *updateproc; static const struct kproc_desc up_kp = { "syncer", sched_sync, @@ -1201,6 +1201,7 @@ checkalias(nvp, nvp_rdev, mp) struct proc *p = curproc; /* XXX */ struct vnode *vp; struct vnode **vpp; + int rmaj = major(nvp_rdev); if (nvp->v_type != VBLK && nvp->v_type != VCHR) return (NULLVP); @@ -1239,16 +1240,37 @@ loop: * and the clauses had been swapped. */ if (vp == NULL || vp->v_tag != VT_NON) { + struct specinfo *sinfo; + /* * Put the new vnode into the hash chain. * and if there was an alias, connect them. */ - MALLOC(nvp->v_specinfo, struct specinfo *, + MALLOC(sinfo, struct specinfo *, sizeof(struct specinfo), M_VNODE, M_WAITOK); - nvp->v_rdev = nvp_rdev; - nvp->v_hashchain = vpp; - nvp->v_specnext = *vpp; - nvp->v_specmountpoint = NULL; + bzero(sinfo, sizeof(struct specinfo)); + nvp->v_specinfo = sinfo; + sinfo->si_rdev = nvp_rdev; + sinfo->si_hashchain = vpp; + sinfo->si_specnext = *vpp; + sinfo->si_bsize_phys = DEV_BSIZE; + sinfo->si_bsize_best = BLKDEV_IOSIZE; + sinfo->si_bsize_max = MAXBSIZE; + + /* + * Ask the device to fix up specinfo. Typically the + * si_bsize_* parameters may need fixing up. + */ + + if (nvp->v_type == VBLK && rmaj < nblkdev) { + if (bdevsw[rmaj] && bdevsw[rmaj]->d_parms) + + (*bdevsw[rmaj]->d_parms)(nvp_rdev, sinfo, DPARM_GET); + } else if (nvp->v_type == VCHR && rmaj < nchrdev) { + if (cdevsw[rmaj] && cdevsw[rmaj]->d_parms) + (*cdevsw[rmaj]->d_parms)(nvp_rdev, sinfo, DPARM_GET); + } + simple_unlock(&spechash_slock); *vpp = nvp; if (vp != NULLVP) { diff --git a/sys/miscfs/specfs/spec_vnops.c b/sys/miscfs/specfs/spec_vnops.c index 88290e4..3f29d9362 100644 --- a/sys/miscfs/specfs/spec_vnops.c +++ b/sys/miscfs/specfs/spec_vnops.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. * * @(#)spec_vnops.c 8.14 (Berkeley) 5/21/95 - * $Id: spec_vnops.c,v 1.79 1999/01/21 08:29:07 dillon Exp $ + * $Id: spec_vnops.c,v 1.80 1999/01/27 22:42:07 dillon Exp $ */ #include <sys/param.h> @@ -286,8 +286,15 @@ spec_read(ap) case VBLK: if (uio->uio_offset < 0) return (EINVAL); - bsize = BLKDEV_IOSIZE; dev = vp->v_rdev; + + /* + * Calculate block size for block device. The block size must + * be larger then the physical minimum. + */ + + bsize = vp->v_specinfo->si_bsize_best; + if ((ioctl = bdevsw[major(dev)]->d_ioctl) != NULL && (*ioctl)(dev, DIOCGPART, (caddr_t)&dpart, FREAD, p) == 0 && dpart.part->p_fstype == FS_BSDFFS && @@ -365,7 +372,13 @@ spec_write(ap) return (0); if (uio->uio_offset < 0) return (EINVAL); - bsize = BLKDEV_IOSIZE; + + /* + * Calculate block size for block device. The block size must + * be larger then the physical minimum. + */ + bsize = vp->v_specinfo->si_bsize_best; + if ((*bdevsw[major(vp->v_rdev)]->d_ioctl)(vp->v_rdev, DIOCGPART, (caddr_t)&dpart, FREAD, p) == 0) { if (dpart.part->p_fstype == FS_BSDFFS && @@ -749,14 +762,16 @@ spec_getpages(ap) pcount = round_page(ap->a_count) / PAGE_SIZE; /* - * Calculate the offset of the transfer. + * Calculate the offset of the transfer and do sanity check. + * FreeBSD currently only supports an 8 TB range due to b_blkno + * being in DEV_BSIZE ( usually 512 ) byte chunks on call to + * VOP_STRATEGY. XXX */ offset = IDX_TO_OFF(ap->a_m[0]->pindex) + ap->a_offset; - /* XXX sanity check before we go into details. */ - /* XXX limits should be defined elsewhere. */ -#define DADDR_T_BIT 32 +#define DADDR_T_BIT (sizeof(daddr_t)*8) #define OFFSET_MAX ((1LL << (DADDR_T_BIT + DEV_BSHIFT)) - 1) + if (offset < 0 || offset > OFFSET_MAX) { /* XXX still no %q in kernel. */ printf("spec_getpages: preposterous offset 0x%x%08x\n", @@ -768,20 +783,20 @@ spec_getpages(ap) blkno = btodb(offset); /* - * Round up physical size for real devices, use the - * fundamental blocksize of the fs if possible. + * Round up physical size for real devices. We cannot round using + * v_mount's block size data because v_mount has nothing to do with + * the device. i.e. it's usually '/dev'. We need the physical block + * size for the device itself. + * + * We can't use v_specmountpoint because it only exists when the + * block device is mounted. However, we can use v_specinfo. */ - if (vp && vp->v_mount) { - if (vp->v_type != VBLK) { - vprint("Non VBLK", vp); - } - blksiz = vp->v_mount->mnt_stat.f_bsize; - if (blksiz < DEV_BSIZE) { - blksiz = DEV_BSIZE; - } - } + + if (vp->v_type == VBLK) + blksiz = vp->v_specinfo->si_bsize_phys; else blksiz = DEV_BSIZE; + size = (ap->a_count + blksiz - 1) & ~(blksiz - 1); bp = getpbuf(NULL); @@ -885,8 +900,8 @@ spec_getpages(ap) m = ap->a_m[ap->a_reqpage]; #ifndef MAX_PERF printf( - "spec_getpages: I/O read failure: (error code=%d)\n", - error); + "spec_getpages: I/O read failure: (error code=%d) bp %p vp %p\n", + error, bp, bp->b_vp); printf( " size: %d, resid: %ld, a_count: %d, valid: 0x%x\n", size, bp->b_resid, ap->a_count, m->valid); @@ -923,10 +938,14 @@ spec_getattr(ap) bzero(vap, sizeof (*vap)); - if (vp->v_type == VBLK) - vap->va_blocksize = BLKDEV_IOSIZE; - else if (vp->v_type == VCHR) + if (vp->v_type == VBLK) { + if (vp->v_specinfo) + vap->va_blocksize = vp->v_specmountpoint->mnt_stat.f_iosize; + else + vap->va_blocksize = BLKDEV_IOSIZE; + } else if (vp->v_type == VCHR) { vap->va_blocksize = MAXBSIZE; + } if ((*bdevsw[major(vp->v_rdev)]->d_ioctl)(vp->v_rdev, DIOCGPART, (caddr_t)&dpart, FREAD, ap->a_p) == 0) { diff --git a/sys/miscfs/specfs/specdev.h b/sys/miscfs/specfs/specdev.h index 9c225a3..a7e2bab 100644 --- a/sys/miscfs/specfs/specdev.h +++ b/sys/miscfs/specfs/specdev.h @@ -31,7 +31,7 @@ * SUCH DAMAGE. * * @(#)specdev.h 8.6 (Berkeley) 5/21/95 - * $Id: specdev.h,v 1.14 1998/03/08 09:57:40 julian Exp $ + * $Id: specdev.h,v 1.15 1998/04/19 23:32:29 julian Exp $ */ /* @@ -44,7 +44,9 @@ struct specinfo { struct vnode *si_specnext; struct mount *si_mountpoint; dev_t si_rdev; - unsigned long si_blksize; /* smallest IO unit */ + int si_bsize_phys; /* minimum physical block size */ + int si_bsize_best; /* optimal block size / VBLK */ + int si_bsize_max; /* maximum block size */ }; /* * Exported shorthand @@ -53,7 +55,6 @@ struct specinfo { #define v_hashchain v_specinfo->si_hashchain #define v_specnext v_specinfo->si_specnext #define v_specmountpoint v_specinfo->si_mountpoint -#define v_blksize v_specinfo->si_blksize /* * Special device management diff --git a/sys/sys/conf.h b/sys/sys/conf.h index 7a52186..d0d27e6 100644 --- a/sys/sys/conf.h +++ b/sys/sys/conf.h @@ -36,7 +36,7 @@ * SUCH DAMAGE. * * @(#)conf.h 8.5 (Berkeley) 1/9/95 - * $Id: conf.h,v 1.48 1998/11/14 21:58:41 wollman Exp $ + * $Id: conf.h,v 1.49 1999/01/21 16:15:53 peter Exp $ */ #ifndef _SYS_CONF_H_ @@ -48,6 +48,7 @@ struct buf; struct proc; +struct specinfo; struct tty; struct uio; struct vnode; @@ -55,6 +56,7 @@ struct vnode; typedef int d_open_t __P((dev_t dev, int oflags, int devtype, struct proc *p)); typedef int d_close_t __P((dev_t dev, int fflag, int devtype, struct proc *p)); typedef void d_strategy_t __P((struct buf *bp)); +typedef int d_parms_t __P((dev_t dev, struct specinfo *sinfo, int ctl)); typedef int d_ioctl_t __P((dev_t dev, u_long cmd, caddr_t data, int fflag, struct proc *p)); typedef int d_dump_t __P((dev_t dev)); @@ -95,6 +97,10 @@ typedef int l_modem_t __P((struct tty *tp, int flag)); #define D_NOCLUSTERRW (D_NOCLUSTERR | D_NOCLUSTERW) #define D_CANFREE 0x40000 /* can free blocks */ +/* + * Control type for d_parms() call. + */ +#define DPARM_GET 0 /* ask device to load parms in */ /* * Character device switch table @@ -111,8 +117,8 @@ struct cdevsw { d_poll_t *d_poll; d_mmap_t *d_mmap; d_strategy_t *d_strategy; - char *d_name; /* see above */ - void *d_spare; + char *d_name; /* base device name, e.g. 'vn' */ + d_parms_t *d_parms; /* populate/override specinfo */ int d_maj; d_dump_t *d_dump; d_psize_t *d_psize; diff --git a/sys/sys/linedisc.h b/sys/sys/linedisc.h index 7a52186..d0d27e6 100644 --- a/sys/sys/linedisc.h +++ b/sys/sys/linedisc.h @@ -36,7 +36,7 @@ * SUCH DAMAGE. * * @(#)conf.h 8.5 (Berkeley) 1/9/95 - * $Id: conf.h,v 1.48 1998/11/14 21:58:41 wollman Exp $ + * $Id: conf.h,v 1.49 1999/01/21 16:15:53 peter Exp $ */ #ifndef _SYS_CONF_H_ @@ -48,6 +48,7 @@ struct buf; struct proc; +struct specinfo; struct tty; struct uio; struct vnode; @@ -55,6 +56,7 @@ struct vnode; typedef int d_open_t __P((dev_t dev, int oflags, int devtype, struct proc *p)); typedef int d_close_t __P((dev_t dev, int fflag, int devtype, struct proc *p)); typedef void d_strategy_t __P((struct buf *bp)); +typedef int d_parms_t __P((dev_t dev, struct specinfo *sinfo, int ctl)); typedef int d_ioctl_t __P((dev_t dev, u_long cmd, caddr_t data, int fflag, struct proc *p)); typedef int d_dump_t __P((dev_t dev)); @@ -95,6 +97,10 @@ typedef int l_modem_t __P((struct tty *tp, int flag)); #define D_NOCLUSTERRW (D_NOCLUSTERR | D_NOCLUSTERW) #define D_CANFREE 0x40000 /* can free blocks */ +/* + * Control type for d_parms() call. + */ +#define DPARM_GET 0 /* ask device to load parms in */ /* * Character device switch table @@ -111,8 +117,8 @@ struct cdevsw { d_poll_t *d_poll; d_mmap_t *d_mmap; d_strategy_t *d_strategy; - char *d_name; /* see above */ - void *d_spare; + char *d_name; /* base device name, e.g. 'vn' */ + d_parms_t *d_parms; /* populate/override specinfo */ int d_maj; d_dump_t *d_dump; d_psize_t *d_psize; |