aboutsummaryrefslogtreecommitdiff
path: root/sys/miscfs/devfs/devfs_vnops.c
diff options
context:
space:
mode:
authorJulian Elischer <julian@FreeBSD.org>1998-07-05 23:10:22 +0000
committerJulian Elischer <julian@FreeBSD.org>1998-07-05 23:10:22 +0000
commit6312920c2029288900017977fea63cbfd4197f87 (patch)
tree7b3977f910b06c92a6c2a34aa9359efe002e01d4 /sys/miscfs/devfs/devfs_vnops.c
parent596f8506ad6a45601188efe9d7f55868df5d7c58 (diff)
downloadsrc-6312920c2029288900017977fea63cbfd4197f87.tar.gz
src-6312920c2029288900017977fea63cbfd4197f87.zip
DEVFS completely bypasses the cdevsw and bdevsw tables now.
Each devfs node has (and has had fro a while) a pointer directly to the correct cdefsw entry so just use it instead of doing the lookup. There are several other places in the kernel that still use the tables however, so they can't go away yet..
Notes
Notes: svn path=/head/; revision=37407
Diffstat (limited to 'sys/miscfs/devfs/devfs_vnops.c')
-rw-r--r--sys/miscfs/devfs/devfs_vnops.c1026
1 files changed, 799 insertions, 227 deletions
diff --git a/sys/miscfs/devfs/devfs_vnops.c b/sys/miscfs/devfs/devfs_vnops.c
index 92232aa8ed90..a916f9c8a5bd 100644
--- a/sys/miscfs/devfs/devfs_vnops.c
+++ b/sys/miscfs/devfs/devfs_vnops.c
@@ -23,7 +23,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: devfs_vnops.c,v 1.55 1998/05/07 04:58:32 msmith Exp $
+ * $Id: devfs_vnops.c,v 1.56 1998/06/10 06:34:54 peter Exp $
*/
@@ -31,14 +31,28 @@
#include <sys/systm.h>
#include <sys/namei.h>
#include <sys/kernel.h>
+#include <sys/fcntl.h>
+#include <sys/conf.h>
+#include <sys/disklabel.h>
#include <sys/lock.h>
#include <sys/stat.h>
+#include <sys/mount.h>
#include <sys/proc.h>
#include <sys/time.h>
#include <sys/vnode.h>
#include <miscfs/specfs/specdev.h>/* definitions of spec functions we use */
#include <sys/dirent.h>
#include <miscfs/devfs/devfsdefs.h>
+#include <sys/vmmeter.h>
+
+#include <vm/vm.h>
+#include <vm/vm_prot.h>
+#include <vm/vm_object.h>
+#include <vm/vm_page.h>
+#include <vm/vm_pager.h>
+#include <vm/vnode_pager.h>
+#include <vm/vm_extern.h>
+
/*
* Insert description here
@@ -299,71 +313,7 @@ DBPRINT(("GOT\n"));
}
/*
- * Create a regular file.
- * We must also free the pathname buffer pointed at
- * by ndp->ni_pnbuf, always on error, or only if the
- * SAVESTART bit in ni_nameiop is clear on success.
- * <still true in 4.4?>
- *
- * Always error... no such thing in this FS
- */
-
-#ifdef notyet
-static int
-devfs_create(struct vop_mknod_args *ap)
- /*struct vop_mknod_args {
- struct vnode *a_dvp;
- struct vnode **a_vpp;
- struct componentname *a_cnp;
- struct vattr *a_vap;
- } */
-{
-DBPRINT(("create\n"));
- return EINVAL;
-}
-
-static int
-devfs_mknod( struct vop_mknod_args *ap)
- /*struct vop_mknod_args {
- struct vnode *a_dvp;
- struct vnode **a_vpp;
- struct componentname *a_cnp;
- struct vattr *a_vap;
- } */
-{
- int error;
-
-
-DBPRINT(("mknod\n"));
- switch (ap->a_vap->va_type) {
- case VDIR:
-#ifdef VNSLEAZE
- return devfs_mkdir(ap);
- /*XXX check for WILLRELE settings (different)*/
-#else
- error = VOP_MKDIR(ap->a_dvp, ap->a_vpp, ap->a_cnp, ap->a_vap);
-#endif
- break;
-
-/*
- * devfs_create() sets ndp->ni_vp.
*/
- case VREG:
-#ifdef VNSLEAZE
- return devfs_create(ap);
- /*XXX check for WILLRELE settings (different)*/
-#else
- error = VOP_CREATE(ap->a_dvp, ap->a_vpp, ap->a_cnp, ap->a_vap);
-#endif
- break;
-
- default:
- return EINVAL;
- break;
- }
- return error;
-}
-#endif /* notyet */
static int
devfs_access(struct vop_access_args *ap)
@@ -638,7 +588,7 @@ cando:
static int
-devfs_read(struct vop_read_args *ap)
+devfs_xread(struct vop_read_args *ap)
/*struct vop_read_args {
struct vnode *a_vp;
struct uio *a_uio;
@@ -665,9 +615,7 @@ DBPRINT(("read\n"));
NULL,NULL,NULL);
case VCHR:
case VBLK:
- error = VOCALL(spec_vnodeop_p, VOFFSET(vop_read), ap);
- getnanotime(&(file_node->atime));
- return(error);
+ panic("devfs: vnode methods");
default:
panic("devfs_read(): bad file type");
@@ -679,7 +627,7 @@ DBPRINT(("read\n"));
* Write data to a file or directory.
*/
static int
-devfs_write(struct vop_write_args *ap)
+devfs_xwrite(struct vop_write_args *ap)
/*struct vop_write_args {
struct vnode *a_vp;
struct uio *a_uio;
@@ -690,14 +638,6 @@ devfs_write(struct vop_write_args *ap)
dn_p file_node;
int error;
-DBPRINT(("write\n"));
- if (error = devfs_vntodn(ap->a_vp,&file_node))
- {
- printf("devfs_vntodn returned %d ",error);
- return error;
- }
-
-
switch (ap->a_vp->v_type) {
case VREG:
return(EINVAL);
@@ -705,49 +645,12 @@ DBPRINT(("write\n"));
return(EISDIR);
case VCHR:
case VBLK:
- error = VOCALL(spec_vnodeop_p, VOFFSET(vop_write), ap);
- getnanotime(&(file_node->mtime));
- return(error);
-
+ panic("devfs: vnode methods");
default:
panic("devfs_write(): bad file type");
- break;
}
}
-/* presently not called from devices anyhow */
-#ifdef notyet
-static int
-devfs_ioctl(struct vop_ioctl_args *ap)
- /*struct vop_ioctl_args {
- struct vnode *a_vp;
- int a_command;
- caddr_t a_data;
- int a_fflag;
- struct ucred *a_cred;
- struct proc *a_p;
- } */
-{
-DBPRINT(("ioctl\n"));
- return ENOTTY;
-}
-
-static int
-devfs_select(struct vop_select_args *ap)
- /*struct vop_select_args {
- struct vnode *a_vp;
- int a_which;
- int a_fflags;
- struct ucred *a_cred;
- struct proc *a_p;
- } */
-{
-DBPRINT(("select\n"));
- return 1; /* filesystems never block? */
-}
-
-
-#endif /* notyet */
static int
devfs_remove(struct vop_remove_args *ap)
@@ -1154,34 +1057,6 @@ out:
return (error);
}
-#ifdef notyet
-static int
-devfs_mkdir(struct vop_mkdir_args *ap)
- /*struct vop_mkdir_args {
- struct vnode *a_dvp;
- struct vnode **a_vpp;
- struct componentname *a_cnp;
- struct vattr *a_vap;
- } */
-{
-DBPRINT(("mkdir\n"));
- vput(ap->a_dvp);
- return EINVAL;
-}
-
-static int
-devfs_rmdir(struct vop_rmdir_args *ap)
- /*struct vop_rmdir_args {
- struct vnode *a_dvp;
- struct vnode *a_vp;
- struct componentname *a_cnp;
- } */
-{
-DBPRINT(("rmdir\n"));
- return (0);
-}
-#endif
-
static int
devfs_symlink(struct vop_symlink_args *ap)
/*struct vop_symlink_args {
@@ -1367,70 +1242,6 @@ DBPRINT(("abortop\n"));
}
#endif /* notyet */
-static int
-devfs_inactive(struct vop_inactive_args *ap)
- /*struct vop_inactive_args {
- struct vnode *a_vp;
- } */
-{
-DBPRINT(("inactive\n"));
- return 0;
-}
-
-#ifdef notyet
-static int
-devfs_lock(struct vop_lock_args *ap)
-{
-DBPRINT(("lock\n"));
- return 0;
-}
-
-static int
-devfs_unlock( struct vop_unlock_args *ap)
-{
-DBPRINT(("unlock\n"));
- return 0;
-}
-
-static int
-devfs_islocked(struct vop_islocked_args *ap)
- /*struct vop_islocked_args {
- struct vnode *a_vp;
- } */
-{
-DBPRINT(("islocked\n"));
- return 0;
-}
-
-static int
-devfs_bmap(struct vop_bmap_args *ap)
- /*struct vop_bmap_args {
- struct vnode *a_vp;
- daddr_t a_bn;
- struct vnode **a_vpp;
- daddr_t *a_bnp;
- int *a_runp;
- int *a_runb;
- } */
-{
-DBPRINT(("bmap\n"));
- return 0;
-}
-
-static int
-devfs_advlock(struct vop_advlock_args *ap)
- /*struct vop_advlock_args {
- struct vnode *a_vp;
- caddr_t a_id;
- int a_op;
- struct flock *a_fl;
- int a_flags;
- } */
-{
-DBPRINT(("advlock\n"));
- return EINVAL; /* we don't do locking yet */
-}
-#endif /* notyet */
static int
devfs_reclaim(struct vop_reclaim_args *ap)
@@ -1484,17 +1295,6 @@ devfs_enotsupp(void *junk)
return (EOPNOTSUPP);
}
-/*
- * /devfs "should never get here" operation
- */
-static int
-devfs_badop(void *junk)
-{
-
- panic("devfs: bad op");
- /* NOTREACHED */
-}
-
/*proto*/
void
devfs_dropvnode(dn_p dnp)
@@ -1518,6 +1318,754 @@ devfs_dropvnode(dn_p dnp)
dnp->vn = NULL; /* be pedantic about this */
}
+/* struct vnode *speclisth[SPECHSZ];*/ /* till specfs goes away */
+
+/*
+ * Open a special file.
+ struct vop_open_args {
+ struct vnode *a_vp;
+ int a_mode;
+ struct ucred *a_cred;
+ struct proc *a_p;
+ } *ap;
+ */
+/* ARGSUSED */
+static int
+devfs_open( struct vop_open_args *ap)
+{
+ struct proc *p = ap->a_p;
+ struct vnode *bvp, *vp = ap->a_vp;
+ dev_t bdev, dev = (dev_t)vp->v_rdev;
+ int error;
+ dn_p dnp;
+
+ if (error = devfs_vntodn(vp,&dnp))
+ return error;
+
+ switch (vp->v_type) {
+ case VCHR:
+ VOP_UNLOCK(vp, 0, p);
+ error = (*dnp->by.Cdev.cdevsw->d_open)(
+ dnp->by.Cdev.dev,
+ ap->a_mode,
+ S_IFCHR,
+ p);
+ vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
+ return (error);
+
+ case VBLK:
+ error = (*dnp->by.Bdev.bdevsw->d_open)(
+ dnp->by.Bdev.dev,
+ ap->a_mode,
+ S_IFBLK,
+ p);
+ }
+ return (error);
+}
+
+/*
+ * Vnode op for read
+ struct vop_read_args {
+ struct vnode *a_vp;
+ struct uio *a_uio;
+ int a_ioflag;
+ struct ucred *a_cred;
+ }
+
+ */
+/* ARGSUSED */
+static int
+devfs_read( struct vop_read_args *ap)
+{
+ register struct vnode *vp = ap->a_vp;
+ register struct uio *uio = ap->a_uio;
+ struct proc *p = uio->uio_procp;
+ struct buf *bp;
+ daddr_t bn, nextbn;
+ long bsize, bscale;
+ struct partinfo dpart;
+ int n, on, majordev;
+ d_ioctl_t *ioctl;
+ int error = 0;
+ dev_t dev;
+ dn_p dnp;
+
+ if (error = devfs_vntodn(vp,&dnp))
+ return error;
+
+
+#ifdef DIAGNOSTIC
+ if (uio->uio_rw != UIO_READ)
+ panic("devfs_read mode");
+ if (uio->uio_segflg == UIO_USERSPACE && uio->uio_procp != curproc)
+ panic("devfs_read proc");
+#endif
+ if (uio->uio_resid == 0)
+ return (0);
+
+ switch (vp->v_type) {
+
+ case VCHR:
+ VOP_UNLOCK(vp, 0, p);
+ error = (*dnp->by.Cdev.cdevsw->d_read)
+ (dnp->by.Cdev.dev, uio, ap->a_ioflag);
+ vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
+ return (error);
+
+ case VBLK:
+ if (uio->uio_offset < 0)
+ return (EINVAL);
+ bsize = BLKDEV_IOSIZE;
+ dev = dnp->by.Bdev.dev;
+ /*
+ * This is a hack!
+ */
+ if ( (ioctl = dnp->by.Bdev.bdevsw->d_ioctl) != NULL &&
+ (*ioctl)(dev, DIOCGPART, (caddr_t)&dpart, FREAD, p) == 0 &&
+ 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;
+ bscale = btodb(bsize);
+ /*
+ * Get buffers with this data from the buffer cache.
+ * If it's not there the strategy() entrypoint will be called.
+ * We may do this in several chunks.
+ */
+ do {
+ bn = btodb(uio->uio_offset) & ~(bscale - 1);
+ on = uio->uio_offset % bsize;
+ n = min((unsigned)(bsize - on), uio->uio_resid);
+ if (vp->v_lastr + bscale == bn) {
+ nextbn = bn + bscale;
+ error = breadn(vp, bn, (int)bsize, &nextbn,
+ (int *)&bsize, 1, NOCRED, &bp);
+ } else
+ error = bread(vp, bn, (int)bsize, NOCRED, &bp);
+ vp->v_lastr = bn;
+ n = min(n, bsize - bp->b_resid);
+ if (error) {
+ brelse(bp);
+ return (error);
+ }
+ /*
+ * Copy it to the user's space
+ */
+ error = uiomove((char *)bp->b_data + on, n, uio);
+ brelse(bp);
+ } while (error == 0 && uio->uio_resid > 0 && n != 0);
+ return (error);
+
+ default:
+ panic("devfs_read type");
+ }
+ /* NOTREACHED */
+}
+
+/*
+ * Vnode op for write
+ struct vop_write_args {
+ struct vnode *a_vp;
+ struct uio *a_uio;
+ int a_ioflag;
+ struct ucred *a_cred;
+ }
+ */
+/* ARGSUSED */
+static int
+devfs_write( struct vop_write_args *ap)
+{
+ register struct vnode *vp = ap->a_vp;
+ register struct uio *uio = ap->a_uio;
+ struct proc *p = uio->uio_procp;
+ struct buf *bp;
+ daddr_t bn;
+ int bsize, blkmask;
+ struct partinfo dpart;
+ register int n, on;
+ int error = 0;
+ dn_p dnp;
+
+ if (error = devfs_vntodn(vp,&dnp))
+ return error;
+
+
+#ifdef DIAGNOSTIC
+ if (uio->uio_rw != UIO_WRITE)
+ panic("devfs_write mode");
+ if (uio->uio_segflg == UIO_USERSPACE && uio->uio_procp != curproc)
+ panic("devfs_write proc");
+#endif
+
+ switch (vp->v_type) {
+
+ case VCHR:
+ VOP_UNLOCK(vp, 0, p);
+ error = (*dnp->by.Cdev.cdevsw->d_write)
+ (dnp->by.Cdev.dev, uio, ap->a_ioflag);
+ vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
+ return (error);
+
+ case VBLK:
+ if (uio->uio_resid == 0)
+ return (0);
+ if (uio->uio_offset < 0)
+ return (EINVAL);
+ bsize = BLKDEV_IOSIZE;
+ if ((dnp->by.Bdev.bdevsw->d_ioctl != NULL)
+ && ((*dnp->by.Bdev.bdevsw->d_ioctl)(dnp->by.Bdev.dev, DIOCGPART,
+ (caddr_t)&dpart, FREAD, p) == 0)
+ && (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;
+ }
+ blkmask = btodb(bsize) - 1;
+ do {
+ bn = btodb(uio->uio_offset) & ~blkmask;
+ on = uio->uio_offset % bsize;
+ n = min((unsigned)(bsize - on), uio->uio_resid);
+ if (n == bsize)
+ bp = getblk(vp, bn, bsize, 0, 0);
+ else
+ error = bread(vp, bn, bsize, NOCRED, &bp);
+ n = min(n, bsize - bp->b_resid);
+ if (error) {
+ brelse(bp);
+ return (error);
+ }
+ error = uiomove((char *)bp->b_data + on, n, uio);
+ if (n + on == bsize)
+ bawrite(bp);
+ else
+ bdwrite(bp);
+ } while (error == 0 && uio->uio_resid > 0 && n != 0);
+ return (error);
+
+ default:
+ panic("devfs_write type");
+ }
+ /* NOTREACHED */
+}
+
+/*
+ * Device ioctl operation.
+ struct vop_ioctl_args {
+ struct vnode *a_vp;
+ int a_command;
+ caddr_t a_data;
+ int a_fflag;
+ struct ucred *a_cred;
+ struct proc *a_p;
+ }
+ */
+/* ARGSUSED */
+static int
+devfs_ioctl(struct vop_ioctl_args *ap)
+{
+ dn_p dnp;
+ int error;
+
+ if (error = devfs_vntodn(ap->a_vp,&dnp))
+ return error;
+
+
+ switch (ap->a_vp->v_type) {
+
+ case VCHR:
+ return ((*dnp->by.Cdev.cdevsw->d_ioctl)(dnp->by.Cdev.dev,
+ ap->a_command,
+ ap->a_data,
+ ap->a_fflag,
+ ap->a_p));
+ case VBLK:
+ return ((*dnp->by.Bdev.bdevsw->d_ioctl)(dnp->by.Bdev.dev,
+ ap->a_command,
+ ap->a_data,
+ ap->a_fflag,
+ ap->a_p));
+ default:
+ panic("devfs_ioctl");
+ /* NOTREACHED */
+ }
+}
+
+/*
+ struct vop_poll_args {
+ struct vnode *a_vp;
+ int a_events;
+ struct ucred *a_cred;
+ struct proc *a_p;
+ } *ap;
+*/
+/* ARGSUSED */
+static int
+devfs_poll(struct vop_poll_args *ap)
+{
+ dn_p dnp;
+ int error;
+
+ if (error = devfs_vntodn(ap->a_vp,&dnp))
+ return error;
+
+
+ switch (ap->a_vp->v_type) {
+
+ case VCHR:
+ return (*dnp->by.Cdev.cdevsw->d_poll)(dnp->by.Cdev.dev,
+ ap->a_events,
+ ap->a_p);
+ default:
+ return (vop_defaultop((struct vop_generic_args *)ap));
+
+ }
+}
+/*
+ * Synch buffers associated with a block device
+ struct vop_fsync_args {
+ struct vnode *a_vp;
+ struct ucred *a_cred;
+ int a_waitfor;
+ struct proc *a_p;
+ }
+ */
+/* ARGSUSED */
+static int
+devfs_fsync(struct vop_fsync_args *ap)
+{
+ register struct vnode *vp = ap->a_vp;
+ register struct buf *bp;
+ struct buf *nbp;
+ int s;
+ dn_p dnp;
+ int error;
+
+ if (error = devfs_vntodn(vp,&dnp))
+ return error;
+
+
+ if (vp->v_type == VCHR)
+ return (0);
+ /*
+ * Flush all dirty buffers associated with a block device.
+ */
+loop:
+ s = splbio();
+ for (bp = vp->v_dirtyblkhd.lh_first; bp; bp = nbp) {
+ nbp = bp->b_vnbufs.le_next;
+ if ((bp->b_flags & B_BUSY))
+ continue;
+ if ((bp->b_flags & B_DELWRI) == 0)
+ panic("devfs_fsync: not dirty");
+ if ((vp->v_flag & VOBJBUF) && (bp->b_flags & B_CLUSTEROK)) {
+ vfs_bio_awrite(bp);
+ splx(s);
+ } else {
+ bremfree(bp);
+ bp->b_flags |= B_BUSY;
+ splx(s);
+ bawrite(bp);
+ }
+ goto loop;
+ }
+ if (ap->a_waitfor == MNT_WAIT) {
+ while (vp->v_numoutput) {
+ vp->v_flag |= VBWAIT;
+ (void) tsleep((caddr_t)&vp->v_numoutput, PRIBIO + 1, "spfsyn", 0);
+ }
+#ifdef DIAGNOSTIC
+ if (vp->v_dirtyblkhd.lh_first) {
+ vprint("devfs_fsync: dirty", vp);
+ splx(s);
+ goto loop;
+ }
+#endif
+ }
+ splx(s);
+ return (0);
+}
+/*
+ *
+ * struct vop_inactive_args {
+ * struct vnode *a_vp;
+ * struct proc *a_p;
+ * }
+ */
+
+static int
+devfs_inactive(struct vop_inactive_args *ap)
+{
+
+ VOP_UNLOCK(ap->a_vp, 0, ap->a_p);
+ return (0);
+}
+
+/*
+ * Just call the device strategy routine
+ struct vop_strategy_args {
+ struct vnode *a_vp;
+ struct buf *a_bp;
+ }
+ */
+static int
+devfs_strategy(struct vop_strategy_args *ap)
+{
+ struct buf *bp = ap->a_bp;
+ dn_p dnp;
+ int error;
+
+ if ((ap->a_vp->v_type != VCHR)
+ && (ap->a_vp->v_type != VBLK))
+ panic ("devfs_strat:badvnode type");
+ if (error = devfs_vntodn(ap->a_vp,&dnp))
+ return error;
+
+
+ if (((bp->b_flags & B_READ) == 0) &&
+ (LIST_FIRST(&bp->b_dep)) != NULL && bioops.io_start)
+ (*bioops.io_start)(bp);
+ switch (ap->a_vp->v_type) {
+ case VCHR:
+ (*dnp->by.Cdev.cdevsw->d_strategy)(bp);
+ case VBLK:
+ (*dnp->by.Bdev.bdevsw->d_strategy)(bp);
+ }
+ return (0);
+}
+
+/*
+ * This is a noop, simply returning what one has been given.
+ struct vop_bmap_args {
+ struct vnode *a_vp;
+ daddr_t a_bn;
+ struct vnode **a_vpp;
+ daddr_t *a_bnp;
+ int *a_runp;
+ int *a_runb;
+ }
+ */
+static int
+devfs_bmap(struct vop_bmap_args *ap)
+{
+
+ if (ap->a_vpp != NULL)
+ *ap->a_vpp = ap->a_vp;
+ if (ap->a_bnp != NULL)
+ *ap->a_bnp = ap->a_bn;
+ if (ap->a_runp != NULL)
+ *ap->a_runp = 0;
+ if (ap->a_runb != NULL)
+ *ap->a_runb = 0;
+ return (0);
+}
+
+/*
+ * Device close routine
+ struct vop_close_args {
+ struct vnode *a_vp;
+ int a_fflag;
+ struct ucred *a_cred;
+ struct proc *a_p;
+ }
+ */
+/* ARGSUSED */
+static int
+devfs_close(struct vop_close_args *ap)
+{
+ register struct vnode *vp = ap->a_vp;
+ struct proc *p = ap->a_p;
+ dev_t dev = vp->v_rdev;
+ d_close_t *devclose;
+ int mode, error;
+ dn_p dnp;
+
+ if (error = devfs_vntodn(vp,&dnp))
+ return error;
+
+
+ switch (vp->v_type) {
+
+ case VCHR:
+ /*
+ * Hack: a tty device that is a controlling terminal
+ * has a reference from the session structure.
+ * We cannot easily tell that a character device is
+ * a controlling terminal, unless it is the closing
+ * process' controlling terminal. In that case,
+ * if the reference count is 2 (this last descriptor
+ * plus the session), release the reference from the session.
+ */
+ if (vcount(vp) == 2 && ap->a_p &&
+ (vp->v_flag & VXLOCK) == 0 &&
+ vp == ap->a_p->p_session->s_ttyvp) {
+ vrele(vp);
+ ap->a_p->p_session->s_ttyvp = NULL;
+ }
+ /*
+ * If the vnode is locked, then we are in the midst
+ * of forcably closing the device, otherwise we only
+ * close on last reference.
+ */
+ if (vcount(vp) > 1 && (vp->v_flag & VXLOCK) == 0)
+ return (0);
+ return ((*dnp->by.Cdev.cdevsw->d_close)(dnp->by.Cdev.dev,
+ ap->a_fflag,
+ S_IFCHR,
+ ap->a_p));
+ break;
+
+ case VBLK:
+ /*
+ * On last close of a block device (that isn't mounted)
+ * we must invalidate any in core blocks, so that
+ * we can, for instance, change floppy disks.
+ */
+ vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, ap->a_p);
+ error = vinvalbuf(vp, V_SAVE, ap->a_cred, ap->a_p, 0, 0);
+ VOP_UNLOCK(vp, 0, ap->a_p);
+ if (error)
+ return (error);
+
+ /*
+ * We do not want to really close the device if it
+ * is still in use unless we are trying to close it
+ * forcibly. Since every use (buffer, vnode, swap, cmap)
+ * holds a reference to the vnode, and because we mark
+ * any other vnodes that alias this device, when the
+ * sum of the reference counts on all the aliased
+ * vnodes descends to one, we are on last close.
+ */
+ if ((vcount(vp) > 1) && (vp->v_flag & VXLOCK) == 0)
+ return (0);
+
+ return ((*dnp->by.Bdev.bdevsw->d_close)(dnp->by.Bdev.dev,
+ ap->a_fflag,
+ S_IFBLK,
+ ap->a_p));
+
+ default:
+ panic("devfs_close: not special");
+ }
+}
+
+/*
+ * Print out the contents of a special device vnode.
+ struct vop_print_args {
+ struct vnode *a_vp;
+ }
+ */
+
+/*
+ * Special device advisory byte-level locks.
+ struct vop_advlock_args {
+ struct vnode *a_vp;
+ caddr_t a_id;
+ int a_op;
+ struct flock *a_fl;
+ int a_flags;
+ }
+ */
+/* ARGSUSED */
+static int
+devfs_advlock(struct vop_advlock_args *ap)
+{
+
+ return (ap->a_flags & F_FLOCK ? EOPNOTSUPP : EINVAL);
+}
+
+/*
+ * Special device bad operation
+ */
+static int
+devfs_badop(void)
+{
+
+ panic("devfs_badop called");
+ /* NOTREACHED */
+}
+
+static void
+devfs_getpages_iodone(struct buf *bp)
+{
+
+ bp->b_flags |= B_DONE;
+ wakeup(bp);
+}
+
+static int
+devfs_getpages(struct vop_getpages_args *ap)
+{
+ vm_offset_t kva;
+ int error;
+ int i, pcount, size, s;
+ daddr_t blkno;
+ struct buf *bp;
+ vm_page_t m;
+ vm_ooffset_t offset;
+ int toff, nextoff, nread;
+ struct vnode *vp = ap->a_vp;
+ int blksiz;
+ int gotreqpage;
+
+ error = 0;
+ pcount = round_page(ap->a_count) / PAGE_SIZE;
+
+ /*
+ * Calculate the offset of the transfer.
+ */
+ 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 OFFSET_MAX ((1LL << (DADDR_T_BIT + DEV_BSHIFT)) - 1)
+ if (offset < 0 || offset > OFFSET_MAX) {
+ /* XXX still no %q in kernel. */
+ printf("devfs_getpages: preposterous offset 0x%x%08x\n",
+ (u_int)((u_quad_t)offset >> 32),
+ (u_int)(offset & 0xffffffff));
+ return (VM_PAGER_ERROR);
+ }
+
+ blkno = btodb(offset);
+
+ /*
+ * Round up physical size for real devices, use the
+ * fundamental blocksize of the fs if possible.
+ */
+ 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;
+ }
+ }
+ else
+ blksiz = DEV_BSIZE;
+ size = (ap->a_count + blksiz - 1) & ~(blksiz - 1);
+
+ bp = getpbuf();
+ kva = (vm_offset_t)bp->b_data;
+
+ /*
+ * Map the pages to be read into the kva.
+ */
+ pmap_qenter(kva, ap->a_m, pcount);
+
+ /* Build a minimal buffer header. */
+ bp->b_flags = B_BUSY | B_READ | B_CALL;
+ bp->b_iodone = devfs_getpages_iodone;
+
+ /* B_PHYS is not set, but it is nice to fill this in. */
+ bp->b_proc = curproc;
+ bp->b_rcred = bp->b_wcred = bp->b_proc->p_ucred;
+ if (bp->b_rcred != NOCRED)
+ crhold(bp->b_rcred);
+ if (bp->b_wcred != NOCRED)
+ crhold(bp->b_wcred);
+ bp->b_blkno = blkno;
+ bp->b_lblkno = blkno;
+ pbgetvp(ap->a_vp, bp);
+ bp->b_bcount = size;
+ bp->b_bufsize = size;
+ bp->b_resid = 0;
+
+ cnt.v_vnodein++;
+ cnt.v_vnodepgsin += pcount;
+
+ /* Do the input. */
+ VOP_STRATEGY(bp->b_vp, bp);
+
+ s = splbio();
+
+ /* We definitely need to be at splbio here. */
+ while ((bp->b_flags & B_DONE) == 0)
+ tsleep(bp, PVM, "spread", 0);
+
+ splx(s);
+
+ if ((bp->b_flags & B_ERROR) != 0) {
+ if (bp->b_error)
+ error = bp->b_error;
+ else
+ error = EIO;
+ }
+
+ nread = size - bp->b_resid;
+
+ if (nread < ap->a_count) {
+ bzero((caddr_t)kva + nread,
+ ap->a_count - nread);
+ }
+ pmap_qremove(kva, pcount);
+
+
+ gotreqpage = 0;
+ for (i = 0, toff = 0; i < pcount; i++, toff = nextoff) {
+ nextoff = toff + PAGE_SIZE;
+ m = ap->a_m[i];
+
+ m->flags &= ~PG_ZERO;
+
+ if (nextoff <= nread) {
+ m->valid = VM_PAGE_BITS_ALL;
+ m->dirty = 0;
+ } else if (toff < nread) {
+ int nvalid = ((nread + DEV_BSIZE - 1) - toff) & ~(DEV_BSIZE - 1);
+ vm_page_set_validclean(m, 0, nvalid);
+ } else {
+ m->valid = 0;
+ m->dirty = 0;
+ }
+
+ if (i != ap->a_reqpage) {
+ /*
+ * Just in case someone was asking for this page we
+ * now tell them that it is ok to use.
+ */
+ if (!error || (m->valid == VM_PAGE_BITS_ALL)) {
+ if (m->valid) {
+ if (m->flags & PG_WANTED) {
+ vm_page_activate(m);
+ } else {
+ vm_page_deactivate(m);
+ }
+ PAGE_WAKEUP(m);
+ } else {
+ vm_page_free(m);
+ }
+ } else {
+ vm_page_free(m);
+ }
+ } else if (m->valid) {
+ gotreqpage = 1;
+ }
+ }
+ if (!gotreqpage) {
+ m = ap->a_m[ap->a_reqpage];
+#ifndef MAX_PERF
+ printf("devfs_getpages: I/O read failure: (error code=%d)\n", error);
+ printf(" size: %d, resid: %d, a_count: %d, valid: 0x%x\n",
+ size, bp->b_resid, ap->a_count, m->valid);
+ printf(" nread: %d, reqpage: %d, pindex: %d, pcount: %d\n",
+ nread, ap->a_reqpage, m->pindex, pcount);
+#endif
+ /*
+ * Free the buffer header back to the swap buffer pool.
+ */
+ relpbuf(bp);
+ return VM_PAGER_ERROR;
+ }
+ /*
+ * Free the buffer header back to the swap buffer pool.
+ */
+ relpbuf(bp);
+ return VM_PAGER_OK;
+}
+
+
+
/* These are the operations used by directories etc in a devfs */
vop_t **devfs_vnodeop_p;
@@ -1531,7 +2079,7 @@ static struct vnodeopv_entry_desc devfs_vnodeop_entries[] = {
{ &vop_lookup_desc, (vop_t *) devfs_lookup },
{ &vop_pathconf_desc, (vop_t *) vop_stdpathconf },
{ &vop_print_desc, (vop_t *) devfs_print },
- { &vop_read_desc, (vop_t *) devfs_read },
+ { &vop_read_desc, (vop_t *) devfs_xread },
{ &vop_readdir_desc, (vop_t *) devfs_readdir },
{ &vop_readlink_desc, (vop_t *) devfs_readlink },
{ &vop_reclaim_desc, (vop_t *) devfs_reclaim },
@@ -1539,7 +2087,7 @@ static struct vnodeopv_entry_desc devfs_vnodeop_entries[] = {
{ &vop_rename_desc, (vop_t *) devfs_rename },
{ &vop_setattr_desc, (vop_t *) devfs_setattr },
{ &vop_symlink_desc, (vop_t *) devfs_symlink },
- { &vop_write_desc, (vop_t *) devfs_write },
+ { &vop_write_desc, (vop_t *) devfs_xwrite },
{ NULL, NULL }
};
static struct vnodeopv_desc devfs_vnodeop_opv_desc =
@@ -1549,20 +2097,44 @@ VNODEOP_SET(devfs_vnodeop_opv_desc);
-vop_t **dev_spec_vnodeop_p;
-static struct vnodeopv_entry_desc dev_spec_vnodeop_entries[] = {
- { &vop_default_desc, (vop_t *) spec_vnoperate },
+vop_t **devfs_spec_vnodeop_p;
+static struct vnodeopv_entry_desc devfs_spec_vnodeop_entries[] = {
+ { &vop_default_desc, (vop_t *) vop_defaultop },
{ &vop_access_desc, (vop_t *) devfs_access },
+ { &vop_advlock_desc, (vop_t *) devfs_advlock },
+ { &vop_bmap_desc, (vop_t *) devfs_bmap },
+ { &vop_close_desc, (vop_t *) devfs_close },
+ { &vop_create_desc, (vop_t *) devfs_badop },
+ { &vop_fsync_desc, (vop_t *) devfs_fsync },
{ &vop_getattr_desc, (vop_t *) devfs_getattr },
+ { &vop_getpages_desc, (vop_t *) devfs_getpages },
+ { &vop_inactive_desc, (vop_t *) devfs_inactive },
+ { &vop_ioctl_desc, (vop_t *) devfs_ioctl },
+ { &vop_lease_desc, (vop_t *) vop_null },
+ { &vop_link_desc, (vop_t *) devfs_badop },
+ { &vop_lookup_desc, (vop_t *) devfs_lookup },
+ { &vop_mkdir_desc, (vop_t *) devfs_badop },
+ { &vop_mknod_desc, (vop_t *) devfs_badop },
+ { &vop_open_desc, (vop_t *) devfs_open },
+ { &vop_pathconf_desc, (vop_t *) vop_stdpathconf },
+ { &vop_poll_desc, (vop_t *) devfs_poll },
+ { &vop_print_desc, (vop_t *) devfs_print },
{ &vop_read_desc, (vop_t *) devfs_read },
+ { &vop_readdir_desc, (vop_t *) devfs_badop },
+ { &vop_readlink_desc, (vop_t *) devfs_badop },
+ { &vop_reallocblks_desc, (vop_t *) devfs_badop },
{ &vop_reclaim_desc, (vop_t *) devfs_reclaim },
+ { &vop_remove_desc, (vop_t *) devfs_badop },
+ { &vop_rename_desc, (vop_t *) devfs_badop },
+ { &vop_rmdir_desc, (vop_t *) devfs_badop },
{ &vop_setattr_desc, (vop_t *) devfs_setattr },
+ { &vop_strategy_desc, (vop_t *) devfs_strategy },
{ &vop_symlink_desc, (vop_t *) devfs_symlink },
{ &vop_write_desc, (vop_t *) devfs_write },
{ NULL, NULL }
};
-static struct vnodeopv_desc dev_spec_vnodeop_opv_desc =
- { &dev_spec_vnodeop_p, dev_spec_vnodeop_entries };
+static struct vnodeopv_desc devfs_spec_vnodeop_opv_desc =
+ { &devfs_spec_vnodeop_p, devfs_spec_vnodeop_entries };
-VNODEOP_SET(dev_spec_vnodeop_opv_desc);
+VNODEOP_SET(devfs_spec_vnodeop_opv_desc);