summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/fs/specfs/spec_vnops.c65
-rw-r--r--sys/kern/vfs_export.c36
-rw-r--r--sys/kern/vfs_subr.c36
-rw-r--r--sys/miscfs/specfs/spec_vnops.c65
-rw-r--r--sys/miscfs/specfs/specdev.h7
-rw-r--r--sys/sys/conf.h12
-rw-r--r--sys/sys/linedisc.h12
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;
OpenPOWER on IntegriCloud