Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files. =================================================================== RCS file: /ftp/cvs/cvsroot/src/sys/miscfs/specfs/spec_vnops.c,v rcsdiff: /ftp/cvs/cvsroot/src/sys/miscfs/specfs/spec_vnops.c,v: warning: Unknown phrases like `commitid ...;' are present. retrieving revision 1.145 retrieving revision 1.145.4.8 diff -u -p -r1.145 -r1.145.4.8 --- src/sys/miscfs/specfs/spec_vnops.c 2014/07/25 08:20:53 1.145 +++ src/sys/miscfs/specfs/spec_vnops.c 2017/02/05 13:40:57 1.145.4.8 @@ -1,4 +1,4 @@ -/* $NetBSD: spec_vnops.c,v 1.145 2014/07/25 08:20:53 dholland Exp $ */ +/* $NetBSD: spec_vnops.c,v 1.145.4.8 2017/02/05 13:40:57 skrll Exp $ */ /*- * Copyright (c) 2008 The NetBSD Foundation, Inc. @@ -58,7 +58,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: spec_vnops.c,v 1.145 2014/07/25 08:20:53 dholland Exp $"); +__KERNEL_RCSID(0, "$NetBSD: spec_vnops.c,v 1.145.4.8 2017/02/05 13:40:57 skrll Exp $"); #include #include @@ -68,7 +68,7 @@ __KERNEL_RCSID(0, "$NetBSD: spec_vnops.c #include #include #include -#include +#include #include #include #include @@ -101,6 +101,7 @@ const char devcls[] = "devcls"; #endif static vnode_t *specfs_hash[SPECHSZ]; +extern struct mount *dead_rootmount; /* * This vnode operations vector is used for special device nodes @@ -309,7 +310,7 @@ spec_node_lookup_by_dev(enum vtype type, mutex_enter(vp->v_interlock); } mutex_exit(&device_lock); - error = vget(vp, 0); + error = vcache_vget(vp); if (error != 0) return error; *vpp = vp; @@ -344,7 +345,7 @@ spec_node_lookup_by_mount(struct mount * } mutex_enter(vq->v_interlock); mutex_exit(&device_lock); - error = vget(vq, 0); + error = vcache_vget(vq); if (error != 0) return error; *vpp = vq; @@ -479,6 +480,8 @@ spec_lookup(void *v) return (ENOTDIR); } +typedef int (*spec_ioctl_t)(dev_t, u_long, void *, int, struct lwp *); + /* * Open a special file. */ @@ -495,14 +498,14 @@ spec_open(void *v) struct vnode *vp; dev_t dev; int error; - struct partinfo pi; enum kauth_device_req req; specnode_t *sn; specdev_t *sd; - + spec_ioctl_t ioctl; u_int gen; const char *name; - + struct partinfo pi; + l = curlwp; vp = ap->a_vp; dev = vp->v_rdev; @@ -510,7 +513,7 @@ spec_open(void *v) sd = sn->sn_dev; name = NULL; gen = 0; - + /* * Don't allow open if fs is mounted -nodev. */ @@ -557,7 +560,7 @@ spec_open(void *v) error = cdev_open(dev, ap->a_mode, S_IFCHR, l); if (error != ENXIO) break; - + /* Check if we already have a valid driver */ mutex_enter(&device_lock); cdev = cdevsw_lookup(dev); @@ -568,7 +571,7 @@ spec_open(void *v) /* Get device name from devsw_conv array */ if ((name = cdevsw_getname(major(dev))) == NULL) break; - + /* Try to autoload device module */ (void) module_autoload(name, MODULE_CLASS_DRIVER); } while (gen != module_gen); @@ -622,7 +625,7 @@ spec_open(void *v) /* Try to autoload device module */ (void) module_autoload(name, MODULE_CLASS_DRIVER); - + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); } while (gen != module_gen); @@ -655,13 +658,12 @@ spec_open(void *v) if (cdev_type(dev) != D_DISK || error != 0) return error; - if (vp->v_type == VCHR) - error = cdev_ioctl(vp->v_rdev, DIOCGPART, &pi, FREAD, curlwp); - else - error = bdev_ioctl(vp->v_rdev, DIOCGPART, &pi, FREAD, curlwp); + + ioctl = vp->v_type == VCHR ? cdev_ioctl : bdev_ioctl; + error = (*ioctl)(vp->v_rdev, DIOCGPARTINFO, &pi, FREAD, curlwp); if (error == 0) - uvm_vnp_setsize(vp, - (voff_t)pi.disklab->d_secsize * pi.part->p_size); + uvm_vnp_setsize(vp, (voff_t)pi.pi_secsize * pi.pi_size); + return 0; } @@ -684,17 +686,15 @@ spec_read(void *v) struct buf *bp; daddr_t bn; int bsize, bscale; - struct partinfo dpart; + struct partinfo pi; int n, on; int error = 0; -#ifdef DIAGNOSTIC - if (uio->uio_rw != UIO_READ) - panic("spec_read mode"); - if (&uio->uio_vmspace->vm_map != kernel_map && - uio->uio_vmspace != curproc->p_vmspace) - panic("spec_read proc"); -#endif + KASSERT(uio->uio_rw == UIO_READ); + KASSERTMSG(VMSPACE_IS_KERNEL_P(uio->uio_vmspace) || + uio->uio_vmspace == curproc->p_vmspace, + "vmspace belongs to neither kernel nor curproc"); + if (uio->uio_resid == 0) return (0); @@ -710,35 +710,18 @@ spec_read(void *v) KASSERT(vp == vp->v_specnode->sn_dev->sd_bdevvp); if (uio->uio_offset < 0) return (EINVAL); - bsize = BLKDEV_IOSIZE; - /* - * dholland 20130616: XXX this logic should not be - * here. It is here because the old buffer cache - * demands that all accesses to the same blocks need - * to be the same size; but it only works for FFS and - * nowadays I think it'll fail silently if the size - * info in the disklabel is wrong. (Or missing.) The - * buffer cache needs to be smarter; or failing that - * we need a reliable way here to get the right block - * size; or a reliable way to guarantee that (a) the - * fs is not mounted when we get here and (b) any - * buffers generated here will get purged when the fs - * does get mounted. - */ - if (bdev_ioctl(vp->v_rdev, DIOCGPART, &dpart, FREAD, l) == 0) { - if (dpart.part->p_fstype == FS_BSDFFS && - dpart.part->p_frag != 0 && dpart.part->p_fsize != 0) - bsize = dpart.part->p_frag * - dpart.part->p_fsize; - } + if (bdev_ioctl(vp->v_rdev, DIOCGPARTINFO, &pi, FREAD, l) == 0) + bsize = pi.pi_bsize; + else + bsize = BLKDEV_IOSIZE; bscale = bsize >> DEV_BSHIFT; do { bn = (uio->uio_offset >> DEV_BSHIFT) &~ (bscale - 1); on = uio->uio_offset % bsize; n = min((unsigned)(bsize - on), uio->uio_resid); - error = bread(vp, bn, bsize, NOCRED, 0, &bp); + error = bread(vp, bn, bsize, 0, &bp); if (error) { return (error); } @@ -773,17 +756,14 @@ spec_write(void *v) struct buf *bp; daddr_t bn; int bsize, bscale; - struct partinfo dpart; + struct partinfo pi; int n, on; int error = 0; -#ifdef DIAGNOSTIC - if (uio->uio_rw != UIO_WRITE) - panic("spec_write mode"); - if (&uio->uio_vmspace->vm_map != kernel_map && - uio->uio_vmspace != curproc->p_vmspace) - panic("spec_write proc"); -#endif + KASSERT(uio->uio_rw == UIO_WRITE); + KASSERTMSG(VMSPACE_IS_KERNEL_P(uio->uio_vmspace) || + uio->uio_vmspace == curproc->p_vmspace, + "vmspace belongs to neither kernel nor curproc"); switch (vp->v_type) { @@ -799,13 +779,12 @@ spec_write(void *v) return (0); if (uio->uio_offset < 0) return (EINVAL); - bsize = BLKDEV_IOSIZE; - if (bdev_ioctl(vp->v_rdev, DIOCGPART, &dpart, FREAD, l) == 0) { - if (dpart.part->p_fstype == FS_BSDFFS && - dpart.part->p_frag != 0 && dpart.part->p_fsize != 0) - bsize = dpart.part->p_frag * - dpart.part->p_fsize; - } + + if (bdev_ioctl(vp->v_rdev, DIOCGPARTINFO, &pi, FREAD, l) == 0) + bsize = pi.pi_bsize; + else + bsize = BLKDEV_IOSIZE; + bscale = bsize >> DEV_BSHIFT; do { bn = (uio->uio_offset >> DEV_BSHIFT) &~ (bscale - 1); @@ -814,8 +793,7 @@ spec_write(void *v) if (n == bsize) bp = getblk(vp, bn, bsize, 0, 0); else - error = bread(vp, bn, bsize, NOCRED, - B_MODIFY, &bp); + error = bread(vp, bn, bsize, B_MODIFY, &bp); if (error) { return (error); } @@ -1051,26 +1029,44 @@ spec_strategy(void *v) } */ *ap = v; struct vnode *vp = ap->a_vp; struct buf *bp = ap->a_bp; + dev_t dev; int error; - KASSERT(vp == vp->v_specnode->sn_dev->sd_bdevvp); + dev = NODEV; - error = 0; - bp->b_dev = vp->v_rdev; + /* + * Extract all the info we need from the vnode, taking care to + * avoid a race with VOP_REVOKE(). + */ - if (!(bp->b_flags & B_READ)) - error = fscow_run(bp, false); + mutex_enter(vp->v_interlock); + if (vdead_check(vp, VDEAD_NOWAIT) == 0 && vp->v_specnode != NULL) { + KASSERT(vp == vp->v_specnode->sn_dev->sd_bdevvp); + dev = vp->v_rdev; + } + mutex_exit(vp->v_interlock); - if (error) { - bp->b_error = error; - bp->b_resid = bp->b_bcount; - biodone(bp); - return (error); + if (dev == NODEV) { + error = ENXIO; + goto out; } + bp->b_dev = dev; + if (!(bp->b_flags & B_READ)) { + error = fscow_run(bp, false); + if (error) + goto out; + } bdev_strategy(bp); - return (0); + return 0; + +out: + bp->b_error = error; + bp->b_resid = bp->b_bcount; + biodone(bp); + + return error; } int @@ -1078,11 +1074,26 @@ spec_inactive(void *v) { struct vop_inactive_args /* { struct vnode *a_vp; - struct proc *a_l; + struct bool *a_recycle; } */ *ap = v; + struct vnode *vp = ap->a_vp; - VOP_UNLOCK(ap->a_vp); - return (0); + KASSERT(vp->v_mount == dead_rootmount); + *ap->a_recycle = true; + VOP_UNLOCK(vp); + return 0; +} + +int +spec_reclaim(void *v) +{ + struct vop_reclaim_args /* { + struct vnode *a_vp; + } */ *ap = v; + struct vnode *vp __diagused = ap->a_vp; + + KASSERT(vp->v_mount == dead_rootmount); + return 0; } /* @@ -1216,7 +1227,7 @@ spec_close(void *v) sd->sd_bdevvp = NULL; mutex_exit(&device_lock); - if (count != 0) + if (count != 0 && (vp->v_type != VCHR || !(cdev_flags(dev) & D_MCLOSE))) return 0; /*