rename mountedon to ufs_mountedon
[unix-history] / usr / src / sys / miscfs / specfs / spec_vnops.c
index b28320d..9061958 100644 (file)
@@ -2,84 +2,79 @@
  * Copyright (c) 1989 The Regents of the University of California.
  * All rights reserved.
  *
  * Copyright (c) 1989 The Regents of the University of California.
  * All rights reserved.
  *
- * Redistribution and use in source and binary forms are permitted
- * provided that the above copyright notice and this paragraph are
- * duplicated in all such forms and that any documentation,
- * advertising materials, and other materials related to such
- * distribution and use acknowledge that the software was developed
- * by the University of California, Berkeley.  The name of the
- * University may not be used to endorse or promote products derived
- * from this software without specific prior written permission.
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ * %sccs.include.redist.c%
  *
  *
- *     @(#)spec_vnops.c        7.10 (Berkeley) %G%
+ *     @(#)spec_vnops.c        7.39 (Berkeley) %G%
  */
 
  */
 
-#include "param.h"
-#include "systm.h"
-#include "user.h"
-#include "kernel.h"
-#include "conf.h"
-#include "buf.h"
-#include "mount.h"
-#include "vnode.h"
-#include "stat.h"
-#include "errno.h"
-
-int    blk_lookup(),
-       blk_open(),
-       blk_read(),
-       blk_write(),
-       blk_strategy(),
-       blk_ioctl(),
-       blk_select(),
-       blk_lock(),
-       blk_unlock(),
-       blk_close(),
-       blk_badop(),
-       blk_nullop();
-
-struct vnodeops blk_vnodeops = {
-       blk_lookup,
-       blk_badop,
-       blk_badop,
-       blk_open,
-       blk_close,
-       blk_badop,
-       blk_badop,
-       blk_badop,
-       blk_read,
-       blk_write,
-       blk_ioctl,
-       blk_select,
-       blk_badop,
-       blk_nullop,
-       blk_badop,
-       blk_badop,
-       blk_badop,
-       blk_badop,
-       blk_badop,
-       blk_badop,
-       blk_badop,
-       blk_badop,
-       blk_badop,
-       blk_badop,
-       blk_nullop,
-       blk_nullop,
-       blk_lock,
-       blk_unlock,
-       blk_badop,
-       blk_strategy,
+#include <sys/param.h>
+#include <sys/proc.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/conf.h>
+#include <sys/buf.h>
+#include <sys/mount.h>
+#include <sys/namei.h>
+#include <sys/vnode.h>
+#include <sys/specdev.h>
+#include <sys/stat.h>
+#include <sys/errno.h>
+#include <sys/ioctl.h>
+#include <sys/file.h>
+#include <sys/disklabel.h>
+
+/* symbolic sleep message strings for devices */
+char   devopn[] = "devopn";
+char   devio[] = "devio";
+char   devwait[] = "devwait";
+char   devin[] = "devin";
+char   devout[] = "devout";
+char   devioc[] = "devioc";
+char   devcls[] = "devcls";
+
+struct vnodeops spec_vnodeops = {
+       spec_lookup,            /* lookup */
+       spec_create,            /* create */
+       spec_mknod,             /* mknod */
+       spec_open,              /* open */
+       spec_close,             /* close */
+       spec_access,            /* access */
+       spec_getattr,           /* getattr */
+       spec_setattr,           /* setattr */
+       spec_read,              /* read */
+       spec_write,             /* write */
+       spec_ioctl,             /* ioctl */
+       spec_select,            /* select */
+       spec_mmap,              /* mmap */
+       spec_fsync,             /* fsync */
+       spec_seek,              /* seek */
+       spec_remove,            /* remove */
+       spec_link,              /* link */
+       spec_rename,            /* rename */
+       spec_mkdir,             /* mkdir */
+       spec_rmdir,             /* rmdir */
+       spec_symlink,           /* symlink */
+       spec_readdir,           /* readdir */
+       spec_readlink,          /* readlink */
+       spec_abortop,           /* abortop */
+       spec_inactive,          /* inactive */
+       spec_reclaim,           /* reclaim */
+       spec_lock,              /* lock */
+       spec_unlock,            /* unlock */
+       spec_bmap,              /* bmap */
+       spec_strategy,          /* strategy */
+       spec_print,             /* print */
+       spec_islocked,          /* islocked */
+       spec_advlock,           /* advlock */
 };
 
 /*
  * Trivial lookup routine that always fails.
  */
 };
 
 /*
  * Trivial lookup routine that always fails.
  */
-blk_lookup(vp, ndp)
+spec_lookup(vp, ndp, p)
        struct vnode *vp;
        struct nameidata *ndp;
        struct vnode *vp;
        struct nameidata *ndp;
+       struct proc *p;
 {
 
        ndp->ni_dvp = vp;
 {
 
        ndp->ni_dvp = vp;
@@ -88,20 +83,22 @@ blk_lookup(vp, ndp)
 }
 
 /*
 }
 
 /*
- * Open called to allow handler
- * of special files to initialize and
- * validate before actual IO.
+ * Open a special file: Don't allow open if fs is mounted -nodev,
+ * and don't allow opens of block devices that are currently mounted.
+ * Otherwise, call device driver open function.
  */
 /* ARGSUSED */
  */
 /* ARGSUSED */
-blk_open(vp, mode, cred)
+spec_open(vp, mode, cred, p)
        register struct vnode *vp;
        int mode;
        struct ucred *cred;
        register struct vnode *vp;
        int mode;
        struct ucred *cred;
+       struct proc *p;
 {
        dev_t dev = (dev_t)vp->v_rdev;
        register int maj = major(dev);
 {
        dev_t dev = (dev_t)vp->v_rdev;
        register int maj = major(dev);
+       int error;
 
 
-       if (vp->v_mount && (vp->v_mount->m_flag & M_NODEV))
+       if (vp->v_mount && (vp->v_mount->mnt_flag & MNT_NODEV))
                return (ENXIO);
 
        switch (vp->v_type) {
                return (ENXIO);
 
        switch (vp->v_type) {
@@ -109,12 +106,17 @@ blk_open(vp, mode, cred)
        case VCHR:
                if ((u_int)maj >= nchrdev)
                        return (ENXIO);
        case VCHR:
                if ((u_int)maj >= nchrdev)
                        return (ENXIO);
-               return ((*cdevsw[maj].d_open)(dev, mode, S_IFCHR));
+               VOP_UNLOCK(vp);
+               error = (*cdevsw[maj].d_open)(dev, mode, S_IFCHR, p);
+               VOP_LOCK(vp);
+               return (error);
 
        case VBLK:
                if ((u_int)maj >= nblkdev)
                        return (ENXIO);
 
        case VBLK:
                if ((u_int)maj >= nblkdev)
                        return (ENXIO);
-               return ((*bdevsw[maj].d_open)(dev, mode, S_IFBLK));
+               if (error = ufs_mountedon(vp))
+                       return (error);
+               return ((*bdevsw[maj].d_open)(dev, mode, S_IFBLK, p));
        }
        return (0);
 }
        }
        return (0);
 }
@@ -122,81 +124,196 @@ blk_open(vp, mode, cred)
 /*
  * Vnode op for read
  */
 /*
  * Vnode op for read
  */
-blk_read(vp, uio, offp, ioflag, cred)
+/* ARGSUSED */
+spec_read(vp, uio, ioflag, cred)
        register struct vnode *vp;
        register struct vnode *vp;
-       struct uio *uio;
-       off_t *offp;
+       register struct uio *uio;
        int ioflag;
        struct ucred *cred;
 {
        int ioflag;
        struct ucred *cred;
 {
-       int count, error;
+       struct proc *p = uio->uio_procp;
+       struct buf *bp;
+       daddr_t bn;
+       long bsize, bscale;
+       struct partinfo dpart;
+       register int n, on;
+       int error = 0;
+
+#ifdef DIAGNOSTIC
+       if (uio->uio_rw != UIO_READ)
+               panic("spec_read mode");
+       if (uio->uio_segflg == UIO_USERSPACE && uio->uio_procp != curproc)
+               panic("spec_read proc");
+#endif
+       if (uio->uio_resid == 0)
+               return (0);
 
 
-       if (vp->v_type == VBLK && vp->v_data)
-               VOP_LOCK(vp);
-       uio->uio_offset = *offp;
-       count = uio->uio_resid;
-       error = readblkvp(vp, uio, cred, ioflag);
-       *offp += count - uio->uio_resid;
-       if (vp->v_type == VBLK && vp->v_data)
+       switch (vp->v_type) {
+
+       case VCHR:
                VOP_UNLOCK(vp);
                VOP_UNLOCK(vp);
-       return (error);
+               error = (*cdevsw[major(vp->v_rdev)].d_read)
+                       (vp->v_rdev, uio, ioflag);
+               VOP_LOCK(vp);
+               return (error);
+
+       case VBLK:
+               if (uio->uio_offset < 0)
+                       return (EINVAL);
+               bsize = BLKDEV_IOSIZE;
+               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 &&
+                           dpart.part->p_frag != 0 && dpart.part->p_fsize != 0)
+                               bsize = dpart.part->p_frag *
+                                   dpart.part->p_fsize;
+               }
+               bscale = bsize / DEV_BSIZE;
+               do {
+                       bn = (uio->uio_offset / DEV_BSIZE) &~ (bscale - 1);
+                       on = uio->uio_offset % bsize;
+                       n = MIN((unsigned)(bsize - on), uio->uio_resid);
+                       if (vp->v_lastr + bscale == bn)
+                               error = breada(vp, bn, (int)bsize, bn + bscale,
+                                       (int)bsize, 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);
+                       }
+                       error = uiomove(bp->b_un.b_addr + on, n, uio);
+                       if (n + on == bsize)
+                               bp->b_flags |= B_AGE;
+                       brelse(bp);
+               } while (error == 0 && uio->uio_resid > 0 && n != 0);
+               return (error);
+
+       default:
+               panic("spec_read type");
+       }
+       /* NOTREACHED */
 }
 
 /*
  * Vnode op for write
  */
 }
 
 /*
  * Vnode op for write
  */
-blk_write(vp, uio, offp, ioflag, cred)
+/* ARGSUSED */
+spec_write(vp, uio, ioflag, cred)
        register struct vnode *vp;
        register struct vnode *vp;
-       struct uio *uio;
-       off_t *offp;
+       register struct uio *uio;
        int ioflag;
        struct ucred *cred;
 {
        int ioflag;
        struct ucred *cred;
 {
-       int count, error;
+       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;
+
+#ifdef DIAGNOSTIC
+       if (uio->uio_rw != UIO_WRITE)
+               panic("spec_write mode");
+       if (uio->uio_segflg == UIO_USERSPACE && uio->uio_procp != curproc)
+               panic("spec_write proc");
+#endif
 
 
-       if (vp->v_type == VBLK && vp->v_data)
-               VOP_LOCK(vp);
-       uio->uio_offset = *offp;
-       count = uio->uio_resid;
-       error = writeblkvp(vp, uio, cred, ioflag);
-       *offp += count - uio->uio_resid;
-       if (vp->v_type == VBLK && vp->v_data)
+       switch (vp->v_type) {
+
+       case VCHR:
                VOP_UNLOCK(vp);
                VOP_UNLOCK(vp);
-       return (error);
+               error = (*cdevsw[major(vp->v_rdev)].d_write)
+                       (vp->v_rdev, uio, ioflag);
+               VOP_LOCK(vp);
+               return (error);
+
+       case VBLK:
+               if (uio->uio_resid == 0)
+                       return (0);
+               if (uio->uio_offset < 0)
+                       return (EINVAL);
+               bsize = BLKDEV_IOSIZE;
+               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 &&
+                           dpart.part->p_frag != 0 && dpart.part->p_fsize != 0)
+                               bsize = dpart.part->p_frag *
+                                   dpart.part->p_fsize;
+               }
+               blkmask = (bsize / DEV_BSIZE) - 1;
+               do {
+                       bn = (uio->uio_offset / DEV_BSIZE) &~ blkmask;
+                       on = uio->uio_offset % bsize;
+                       n = MIN((unsigned)(bsize - on), uio->uio_resid);
+                       if (n == bsize)
+                               bp = getblk(vp, bn, bsize);
+                       else
+                               error = bread(vp, bn, bsize, NOCRED, &bp);
+                       n = MIN(n, bsize - bp->b_resid);
+                       if (error) {
+                               brelse(bp);
+                               return (error);
+                       }
+                       error = uiomove(bp->b_un.b_addr + on, n, uio);
+                       if (n + on == bsize) {
+                               bp->b_flags |= B_AGE;
+                               bawrite(bp);
+                       } else
+                               bdwrite(bp);
+               } while (error == 0 && uio->uio_resid > 0 && n != 0);
+               return (error);
+
+       default:
+               panic("spec_write type");
+       }
+       /* NOTREACHED */
 }
 
 /*
  * Device ioctl operation.
  */
 /* ARGSUSED */
 }
 
 /*
  * Device ioctl operation.
  */
 /* ARGSUSED */
-blk_ioctl(vp, com, data, fflag, cred)
+spec_ioctl(vp, com, data, fflag, cred, p)
        struct vnode *vp;
        struct vnode *vp;
-       register int com;
+       int com;
        caddr_t data;
        int fflag;
        struct ucred *cred;
        caddr_t data;
        int fflag;
        struct ucred *cred;
+       struct proc *p;
 {
        dev_t dev = vp->v_rdev;
 
        switch (vp->v_type) {
 
        case VCHR:
 {
        dev_t dev = vp->v_rdev;
 
        switch (vp->v_type) {
 
        case VCHR:
-               return ((*cdevsw[major(dev)].d_ioctl)(dev, com, data, fflag));
+               return ((*cdevsw[major(dev)].d_ioctl)(dev, com, data,
+                   fflag, p));
 
        case VBLK:
 
        case VBLK:
-               return ((*bdevsw[major(dev)].d_ioctl)(dev, com, data, fflag));
+               if (com == 0 && (int)data == B_TAPE)
+                       if (bdevsw[major(dev)].d_flags & B_TAPE)
+                               return (0);
+                       else
+                               return (1);
+               return ((*bdevsw[major(dev)].d_ioctl)(dev, com, data,
+                  fflag, p));
 
        default:
 
        default:
-               panic("blk_ioctl");
+               panic("spec_ioctl");
                /* NOTREACHED */
        }
 }
 
 /* ARGSUSED */
                /* NOTREACHED */
        }
 }
 
 /* ARGSUSED */
-blk_select(vp, which, cred)
+spec_select(vp, which, fflags, cred, p)
        struct vnode *vp;
        struct vnode *vp;
-       int which;
+       int which, fflags;
        struct ucred *cred;
        struct ucred *cred;
+       struct proc *p;
 {
        register dev_t dev;
 
 {
        register dev_t dev;
 
@@ -207,31 +324,51 @@ blk_select(vp, which, cred)
 
        case VCHR:
                dev = vp->v_rdev;
 
        case VCHR:
                dev = vp->v_rdev;
-               return (*cdevsw[major(dev)].d_select)(dev, which);
+               return (*cdevsw[major(dev)].d_select)(dev, which, p);
        }
 }
 
 /*
  * Just call the device strategy routine
  */
        }
 }
 
 /*
  * Just call the device strategy routine
  */
-blk_strategy(bp)
+spec_strategy(bp)
        register struct buf *bp;
 {
        register struct buf *bp;
 {
+
        (*bdevsw[major(bp->b_dev)].d_strategy)(bp);
        return (0);
 }
 
        (*bdevsw[major(bp->b_dev)].d_strategy)(bp);
        return (0);
 }
 
+/*
+ * This is a noop, simply returning what one has been given.
+ */
+spec_bmap(vp, bn, vpp, bnp)
+       struct vnode *vp;
+       daddr_t bn;
+       struct vnode **vpp;
+       daddr_t *bnp;
+{
+
+       if (vpp != NULL)
+               *vpp = vp;
+       if (bnp != NULL)
+               *bnp = bn;
+       return (0);
+}
+
 /*
  * At the moment we do not do any locking.
  */
 /*
  * At the moment we do not do any locking.
  */
-blk_lock(vp)
+/* ARGSUSED */
+spec_lock(vp)
        struct vnode *vp;
 {
 
        return (0);
 }
 
        struct vnode *vp;
 {
 
        return (0);
 }
 
-blk_unlock(vp)
+/* ARGSUSED */
+spec_unlock(vp)
        struct vnode *vp;
 {
 
        struct vnode *vp;
 {
 
@@ -242,21 +379,27 @@ blk_unlock(vp)
  * Device close routine
  */
 /* ARGSUSED */
  * Device close routine
  */
 /* ARGSUSED */
-blk_close(vp, flag, cred)
+spec_close(vp, flag, cred, p)
        register struct vnode *vp;
        int flag;
        struct ucred *cred;
        register struct vnode *vp;
        int flag;
        struct ucred *cred;
+       struct proc *p;
 {
        dev_t dev = vp->v_rdev;
 {
        dev_t dev = vp->v_rdev;
-       int (*cfunc)();
-       int error, mode;
+       int (*devclose) __P((dev_t, int, int, struct proc *));
+       int mode;
 
        switch (vp->v_type) {
 
        case VCHR:
 
        switch (vp->v_type) {
 
        case VCHR:
-               if (vp->v_count > 1)
+               /*
+                * 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 (0);
-               cfunc = cdevsw[major(dev)].d_close;
+               devclose = cdevsw[major(dev)].d_close;
                mode = S_IFCHR;
                break;
 
                mode = S_IFCHR;
                break;
 
@@ -266,53 +409,72 @@ blk_close(vp, flag, cred)
                 * we must invalidate any in core blocks, so that
                 * we can, for instance, change floppy disks.
                 */
                 * we must invalidate any in core blocks, so that
                 * we can, for instance, change floppy disks.
                 */
-               bflush(vp->v_mount);
-               if (binval(vp->v_mount))
+               vflushbuf(vp, 0);
+               if (vinvalbuf(vp, 1))
                        return (0);
                /*
                        return (0);
                /*
-                * We don't want to really close the device if it is still
-                * in use. Since every use (buffer, vnode, swap, cmap)
-                * holds a reference to the vnode, and because we ensure
-                * that there cannot be more than one vnode per device,
-                * we need only check that we are down to the last
-                * reference before closing.
+                * 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 (vp->v_count > 1)
+               if (vcount(vp) > 1 && (vp->v_flag & VXLOCK) == 0)
                        return (0);
                        return (0);
-               cfunc = bdevsw[major(dev)].d_close;
+               devclose = bdevsw[major(dev)].d_close;
                mode = S_IFBLK;
                break;
 
        default:
                mode = S_IFBLK;
                break;
 
        default:
-               panic("blk_close: not special");
+               panic("spec_close: not special");
        }
 
        }
 
-       if (setjmp(&u.u_qsave)) {
-               /*
-                * If device close routine is interrupted,
-                * must return so closef can clean up.
-                */
-               error = EINTR;
-       } else
-               error = (*cfunc)(dev, flag, mode);
-       return (error);
+       return ((*devclose)(dev, flag, mode, p));
 }
 
 /*
 }
 
 /*
- * Block device bad operation
+ * Print out the contents of a special device vnode.
  */
  */
-blk_badop()
+spec_print(vp)
+       struct vnode *vp;
 {
 
 {
 
-       panic("blk_badop called");
-       /* NOTREACHED */
+       printf("tag VT_NON, dev %d, %d\n", major(vp->v_rdev),
+               minor(vp->v_rdev));
+}
+
+/*
+ * Special device advisory byte-level locks.
+ */
+/* ARGSUSED */
+spec_advlock(vp, id, op, fl, flags)
+       struct vnode *vp;
+       caddr_t id;
+       int op;
+       struct flock *fl;
+       int flags;
+{
+
+       return (EOPNOTSUPP);
 }
 
 /*
 }
 
 /*
- * Block device null operation
+ * Special device failed operation
  */
  */
-blk_nullop()
+spec_ebadf()
 {
 
 {
 
-       return (0);
+       return (EBADF);
+}
+
+/*
+ * Special device bad operation
+ */
+spec_badop()
+{
+
+       panic("spec_badop called");
+       /* NOTREACHED */
 }
 }