1
0
mirror of https://git.FreeBSD.org/src.git synced 2025-01-04 12:52:15 +00:00

Reviewed by: Julian Elischer <julian@whistle.com>

Add d_parms() to {c,b}devsw[].  If non-NULL this function points to
    a device routine that will properly fill in the specinfo structure.
    vfs_subr.c's checkalias() supplies appropriate defaults.  This change
    should be fully backwards compatible with existing devices.
This commit is contained in:
Matthew Dillon 1999-02-25 05:22:30 +00:00
parent 803870b48d
commit 155f87daf2
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=44247
7 changed files with 164 additions and 69 deletions

View File

@ -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) {

View File

@ -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 @@ checkalias(nvp, nvp_rdev, mp)
* 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) {

View File

@ -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 @@ checkalias(nvp, nvp_rdev, mp)
* 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) {

View File

@ -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) {

View File

@ -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

View File

@ -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;

View File

@ -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;