more-or-less working with new proc & user structs
[unix-history] / usr / src / sys / miscfs / specfs / spec_vnops.c
index 2eb67bd..c1f2520 100644 (file)
  * 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.1 (Berkeley) %G%
+ *     @(#)spec_vnops.c        7.31 (Berkeley) %G%
  */
 
 #include "param.h"
 #include "systm.h"
  */
 
 #include "param.h"
 #include "systm.h"
-#include "time.h"
+#include "user.h"
+#include "kernel.h"
 #include "conf.h"
 #include "buf.h"
 #include "conf.h"
 #include "buf.h"
+#include "mount.h"
 #include "vnode.h"
 #include "vnode.h"
-#include "../ufs/inode.h"
+#include "specdev.h"
 #include "stat.h"
 #include "stat.h"
-#include "uio.h"
 #include "errno.h"
 #include "errno.h"
-#include "malloc.h"
-
-int    blk_open(),
-       blk_access(),
-       blk_read(),
-       blk_write(),
-       blk_strategy(),
-       blk_ioctl(),
-       blk_select(),
-       blk_inactive(),
-       blk_lock(),
-       blk_unlock(),
-       blk_close(),
-       blk_badop(),
-       blk_nullop();
-
-int    ufs_getattr(),
-       ufs_setattr();
-
-struct vnodeops blk_vnodeops = {
-       blk_badop,
-       blk_badop,
-       blk_badop,
-       blk_open,
-       blk_close,
-       blk_access,
-       ufs_getattr,
-       ufs_setattr,
-       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_inactive,
-       blk_lock,
-       blk_unlock,
-       blk_badop,
-       blk_strategy,
+#include "ioctl.h"
+#include "file.h"
+#include "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";
+
+int    spec_lookup(),
+       spec_open(),
+       spec_read(),
+       spec_write(),
+       spec_strategy(),
+       spec_bmap(),
+       spec_ioctl(),
+       spec_select(),
+       spec_lock(),
+       spec_unlock(),
+       spec_close(),
+       spec_print(),
+       spec_advlock(),
+       spec_ebadf(),
+       spec_badop();
+
+int    nullop();
+
+struct vnodeops spec_vnodeops = {
+       spec_lookup,            /* lookup */
+       spec_badop,             /* create */
+       spec_badop,             /* mknod */
+       spec_open,              /* open */
+       spec_close,             /* close */
+       spec_ebadf,             /* access */
+       spec_ebadf,             /* getattr */
+       spec_ebadf,             /* setattr */
+       spec_read,              /* read */
+       spec_write,             /* write */
+       spec_ioctl,             /* ioctl */
+       spec_select,            /* select */
+       spec_badop,             /* mmap */
+       nullop,                 /* fsync */
+       spec_badop,             /* seek */
+       spec_badop,             /* remove */
+       spec_badop,             /* link */
+       spec_badop,             /* rename */
+       spec_badop,             /* mkdir */
+       spec_badop,             /* rmdir */
+       spec_badop,             /* symlink */
+       spec_badop,             /* readdir */
+       spec_badop,             /* readlink */
+       spec_badop,             /* abortop */
+       nullop,                 /* inactive */
+       nullop,                 /* reclaim */
+       spec_lock,              /* lock */
+       spec_unlock,            /* unlock */
+       spec_bmap,              /* bmap */
+       spec_strategy,          /* strategy */
+       spec_print,             /* print */
+       nullop,                 /* islocked */
+       spec_advlock,           /* advlock */
 };
 
 };
 
+/*
+ * Trivial lookup routine that always fails.
+ */
+spec_lookup(vp, ndp)
+       struct vnode *vp;
+       struct nameidata *ndp;
+{
+
+       ndp->ni_dvp = vp;
+       ndp->ni_vp = NULL;
+       return (ENOTDIR);
+}
+
 /*
  * Open called to allow handler
  * of special files to initialize and
  * validate before actual IO.
  */
 /*
  * Open called to allow handler
  * of special files to initialize and
  * validate before actual IO.
  */
-blk_open(vp, mode, cred)
+/* ARGSUSED */
+spec_open(vp, mode, cred)
        register struct vnode *vp;
        int mode;
        struct ucred *cred;
 {
        register struct vnode *vp;
        int mode;
        struct ucred *cred;
 {
+       struct proc *p = curproc;               /* XXX */
        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->mnt_flag & MNT_NODEV))
+               return (ENXIO);
 
        switch (vp->v_type) {
 
        case VCHR:
                if ((u_int)maj >= nchrdev)
                        return (ENXIO);
 
        switch (vp->v_type) {
 
        case VCHR:
                if ((u_int)maj >= nchrdev)
                        return (ENXIO);
-               return ((*cdevsw[maj].d_open)(dev, mode, S_IFCHR));
+               return ((*cdevsw[maj].d_open)(dev, mode, S_IFCHR, p));
 
        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 = mountedon(vp))
+                       return (error);
+               return ((*bdevsw[maj].d_open)(dev, mode, S_IFBLK, p));
        }
        return (0);
 }
 
        }
        return (0);
 }
 
-/*
- * Check access permissions for a block device.
- */
-blk_access(vp, mode, cred)
-       struct vnode *vp;
-       int mode;
-       struct ucred *cred;
-{
-       register struct inode *ip = VTOI(vp);
-       int error;
-
-       if ((ip->i_flag & ILOCKED) == 0)
-               printf("access called with %d not locked\n", ip->i_number);
-       error = iaccess(ip, mode, cred);
-       return (error);
-}
-
 /*
  * 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;
 {
-       register struct inode *ip = VTOI(vp);
-       int count, error;
-
-       if (vp->v_type == VBLK && ip)
-               ILOCK(ip);
-       uio->uio_offset = *offp;
-       count = uio->uio_resid;
-       error = readblkvp(vp, uio, cred);
-       *offp += count - uio->uio_resid;
-       if (vp->v_type == VBLK && ip)
-               IUNLOCK(ip);
-       return (error);
+       struct proc *p = curproc;               /* XXX */
+       struct buf *bp;
+       daddr_t bn;
+       long bsize, bscale;
+       struct partinfo dpart;
+       register int n, on;
+       int error = 0;
+       extern int mem_no;
+
+       if (uio->uio_rw != UIO_READ)
+               panic("spec_read mode");
+       if (uio->uio_resid == 0)
+               return (0);
+
+       switch (vp->v_type) {
+
+       case VCHR:
+               /*
+                * Negative offsets allowed only for /dev/kmem
+                */
+               if (uio->uio_offset < 0 && major(vp->v_rdev) != mem_no)
+                       return (EINVAL);
+               VOP_UNLOCK(vp);
+               error = (*cdevsw[major(vp->v_rdev)].d_read)
+                       (vp->v_rdev, uio, ioflag, p);
+               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;
 {
-       register struct inode *ip = VTOI(vp);
-       int count, error;
-
-       if (vp->v_type == VBLK && ip)
-               ILOCK(ip);
-       uio->uio_offset = *offp;
-       count = uio->uio_resid;
-       error = writeblkvp(vp, uio, cred);
-       *offp += count - uio->uio_resid;
-       if (vp->v_type == VBLK && ip)
-               IUNLOCK(ip);
-       return (error);
+       struct proc *p = curproc;               /* XXX */
+       struct buf *bp;
+       daddr_t bn;
+       int bsize, blkmask;
+       struct partinfo dpart;
+       register int n, on;
+       int error = 0;
+       extern int mem_no;
+
+       if (uio->uio_rw != UIO_WRITE)
+               panic("spec_write mode");
+
+       switch (vp->v_type) {
+
+       case VCHR:
+               /*
+                * Negative offsets allowed only for /dev/kmem
+                */
+               if (uio->uio_offset < 0 && major(vp->v_rdev) != mem_no)
+                       return (EINVAL);
+               VOP_UNLOCK(vp);
+               error = (*cdevsw[major(vp->v_rdev)].d_write)
+                       (vp->v_rdev, uio, ioflag, p);
+               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.
  */
 }
 
 /*
  * Device ioctl operation.
  */
-blk_ioctl(vp, com, data, fflag, cred)
+/* ARGSUSED */
+spec_ioctl(vp, com, data, fflag, cred)
        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;
 {
-       register struct inode *ip = VTOI(vp);
-       dev_t dev = ip->i_rdev;
+       struct proc *p = curproc;               /* XXX */
+       dev_t dev = vp->v_rdev;
 
        switch (vp->v_type) {
 
        case VCHR:
 
        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 */
        }
 }
 
                /* NOTREACHED */
        }
 }
 
-blk_select(vp, which, cred)
+/* ARGSUSED */
+spec_select(vp, which, fflags, cred)
        struct vnode *vp;
        struct vnode *vp;
-       int which;
+       int which, fflags;
        struct ucred *cred;
 {
        struct ucred *cred;
 {
-       register struct inode *ip = VTOI(vp);
+       struct proc *p = curproc;               /* XXX */
        register dev_t dev;
 
        switch (vp->v_type) {
        register dev_t dev;
 
        switch (vp->v_type) {
@@ -212,83 +340,157 @@ blk_select(vp, which, cred)
                return (1);             /* XXX */
 
        case VCHR:
                return (1);             /* XXX */
 
        case VCHR:
-               dev = ip->i_rdev;
-               return (*cdevsw[major(dev)].d_select)(dev, which);
+               dev = vp->v_rdev;
+               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);
 }
 
-blk_lock(vp)
+/*
+ * This is a noop, simply returning what one has been given.
+ */
+spec_bmap(vp, bn, vpp, bnp)
        struct vnode *vp;
        struct vnode *vp;
+       daddr_t bn;
+       struct vnode **vpp;
+       daddr_t *bnp;
 {
 {
-       register struct inode *ip = VTOI(vp);
 
 
-       if (ip)
-               ILOCK(ip);
+       if (vpp != NULL)
+               *vpp = vp;
+       if (bnp != NULL)
+               *bnp = bn;
        return (0);
 }
 
        return (0);
 }
 
-blk_unlock(vp)
+/*
+ * At the moment we do not do any locking.
+ */
+/* ARGSUSED */
+spec_lock(vp)
        struct vnode *vp;
 {
        struct vnode *vp;
 {
-       register struct inode *ip = VTOI(vp);
 
 
-       if (ip)
-               IUNLOCK(ip);
        return (0);
 }
 
        return (0);
 }
 
-blk_inactive(vp)
+/* ARGSUSED */
+spec_unlock(vp)
        struct vnode *vp;
 {
        struct vnode *vp;
 {
-       struct inode *ip = VTOI(vp);
-       struct vnode *devvp = 0;
-       int error;
 
 
-       if (vp->v_count > 0)
-               return (0);
-printf("blk_inactive: free dev 0x%x\n", vp->v_rdev);
-       return (ufs_inactive(vp));
+       return (0);
 }
 
 /*
  * Device close routine
  */
 }
 
 /*
  * Device close routine
  */
-blk_close(vp, flag, cred)
-       struct vnode *vp;
+/* ARGSUSED */
+spec_close(vp, flag, cred)
+       register struct vnode *vp;
        int flag;
        struct ucred *cred;
 {
        int flag;
        struct ucred *cred;
 {
+       struct proc *p = curproc;               /* XXX */
        dev_t dev = vp->v_rdev;
        dev_t dev = vp->v_rdev;
-       int type = vp->v_type;
+       int (*cfunc)();
+       int mode;
+
+       switch (vp->v_type) {
+
+       case VCHR:
+               /*
+                * 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);
+               cfunc = cdevsw[major(dev)].d_close;
+               mode = S_IFCHR;
+               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.
+                */
+               vflushbuf(vp, 0);
+               if (vinvalbuf(vp, 1))
+                       return (0);
+               /*
+                * 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);
+               cfunc = bdevsw[major(dev)].d_close;
+               mode = S_IFBLK;
+               break;
 
 
-       return (closei(dev, type, flag));
+       default:
+               panic("spec_close: not special");
+       }
+
+       return ((*cfunc)(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;
 {
 
 {
 
-       printf("blk_badop called\n");
-       return (ENXIO);
+       printf("tag VT_NON, dev %d, %d\n", major(vp->v_rdev),
+               minor(vp->v_rdev));
 }
 
 /*
 }
 
 /*
- * Block device null operation
+ * Special device advisory byte-level locks.
  */
  */
-blk_nullop()
+spec_advlock(vp, id, op, fl, flags)
+       struct vnode *vp;
+       caddr_t id;
+       int op;
+       struct flock *fl;
+       int flags;
 {
 
 {
 
-       return (0);
+       return (EOPNOTSUPP);
+}
+
+/*
+ * Special device failed operation
+ */
+spec_ebadf()
+{
+
+       return (EBADF);
+}
+
+/*
+ * Special device bad operation
+ */
+spec_badop()
+{
+
+       panic("spec_badop called");
+       /* NOTREACHED */
 }
 }