merge in vnodes
authorKirk McKusick <mckusick@ucbvax.Berkeley.EDU>
Wed, 10 May 1989 08:22:38 +0000 (00:22 -0800)
committerKirk McKusick <mckusick@ucbvax.Berkeley.EDU>
Wed, 10 May 1989 08:22:38 +0000 (00:22 -0800)
SCCS-vsn: sys/ufs/ffs/ffs_alloc.c 7.9
SCCS-vsn: sys/ufs/lfs/lfs_alloc.c 7.9
SCCS-vsn: sys/kern/vfs_bio.c 7.5
SCCS-vsn: sys/kern/vfs_cluster.c 7.5
SCCS-vsn: sys/ufs/ffs/ffs_balloc.c 7.3
SCCS-vsn: sys/ufs/lfs/lfs_balloc.c 7.3
SCCS-vsn: sys/ufs/ffs/ufs_disksubr.c 7.12
SCCS-vsn: sys/ufs/ufs/ufs_disksubr.c 7.12
SCCS-vsn: sys/ufs/ffs/ffs_inode.c 7.6
SCCS-vsn: sys/ufs/ffs/ufs_inode.c 7.6
SCCS-vsn: sys/ufs/lfs/lfs_inode.c 7.6
SCCS-vsn: sys/ufs/ufs/ufs_inode.c 7.6
SCCS-vsn: sys/ufs/ffs/ffs_subr.c 7.8
SCCS-vsn: sys/ufs/ffs/ffs_vfsops.c 7.13
SCCS-vsn: sys/ufs/ffs/ufs_vfsops.c 7.13
SCCS-vsn: sys/ufs/lfs/lfs_vfsops.c 7.13
SCCS-vsn: sys/ufs/ufs/ufs_vfsops.c 7.13
SCCS-vsn: sys/ufs/ffs/ffs_vnops.c 7.7
SCCS-vsn: sys/ufs/ffs/ufs_vnops.c 7.7
SCCS-vsn: sys/ufs/lfs/lfs_vnops.c 7.7
SCCS-vsn: sys/ufs/ufs/ufs_vnops.c 7.7

21 files changed:
usr/src/sys/kern/vfs_bio.c
usr/src/sys/kern/vfs_cluster.c
usr/src/sys/ufs/ffs/ffs_alloc.c
usr/src/sys/ufs/ffs/ffs_balloc.c
usr/src/sys/ufs/ffs/ffs_inode.c
usr/src/sys/ufs/ffs/ffs_subr.c
usr/src/sys/ufs/ffs/ffs_vfsops.c
usr/src/sys/ufs/ffs/ffs_vnops.c
usr/src/sys/ufs/ffs/ufs_disksubr.c
usr/src/sys/ufs/ffs/ufs_inode.c
usr/src/sys/ufs/ffs/ufs_vfsops.c
usr/src/sys/ufs/ffs/ufs_vnops.c
usr/src/sys/ufs/lfs/lfs_alloc.c
usr/src/sys/ufs/lfs/lfs_balloc.c
usr/src/sys/ufs/lfs/lfs_inode.c
usr/src/sys/ufs/lfs/lfs_vfsops.c
usr/src/sys/ufs/lfs/lfs_vnops.c
usr/src/sys/ufs/ufs/ufs_disksubr.c
usr/src/sys/ufs/ufs/ufs_inode.c
usr/src/sys/ufs/ufs/ufs_vfsops.c
usr/src/sys/ufs/ufs/ufs_vnops.c

index 0aef9f1..d740ae9 100644 (file)
@@ -1,36 +1,36 @@
 /*
 /*
- * Copyright (c) 1982, 1986 Regents of the University of California.
- * All rights reserved.  The Berkeley software License Agreement
- * specifies the terms and conditions for redistribution.
+ * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
+ * All rights reserved.
  *
  *
- *     @(#)vfs_bio.c   7.4 (Berkeley) %G%
+ * 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.
+ *
+ *     @(#)vfs_bio.c   7.5 (Berkeley) %G%
  */
 
 #include "param.h"
  */
 
 #include "param.h"
-#include "systm.h"
-#include "dir.h"
 #include "user.h"
 #include "buf.h"
 #include "user.h"
 #include "buf.h"
-#include "conf.h"
-#include "proc.h"
-#include "seg.h"
-#include "vm.h"
+#include "vnode.h"
 #include "trace.h"
 
 #include "trace.h"
 
-#include "machine/pte.h"
-
 /*
  * Read in (if necessary) the block and return a buffer pointer.
  */
 /*
  * Read in (if necessary) the block and return a buffer pointer.
  */
-struct buf *
-#ifdef SECSIZE
-bread(dev, blkno, size, secsize)
-#else SECSIZE
-bread(dev, blkno, size)
-#endif SECSIZE
-       dev_t dev;
+bread(vp, blkno, size, bpp)
+       struct vnode *vp;
        daddr_t blkno;
        int size;
        daddr_t blkno;
        int size;
+       struct buf **bpp;
 #ifdef SECSIZE
        long secsize;
 #endif SECSIZE
 #ifdef SECSIZE
        long secsize;
 #endif SECSIZE
@@ -42,38 +42,33 @@ bread(dev, blkno, size)
 #ifdef SECSIZE
        bp = getblk(dev, blkno, size, secsize);
 #else SECSIZE
 #ifdef SECSIZE
        bp = getblk(dev, blkno, size, secsize);
 #else SECSIZE
-       bp = getblk(dev, blkno, size);
+       *bpp = bp = getblk(vp, blkno, size);
 #endif SECSIZE
        if (bp->b_flags&(B_DONE|B_DELWRI)) {
 #endif SECSIZE
        if (bp->b_flags&(B_DONE|B_DELWRI)) {
-               trace(TR_BREADHIT, pack(dev, size), blkno);
-               return (bp);
+               trace(TR_BREADHIT, pack(vp->v_mount->m_fsid[0], size), blkno);
+               return (0);
        }
        bp->b_flags |= B_READ;
        if (bp->b_bcount > bp->b_bufsize)
                panic("bread");
        }
        bp->b_flags |= B_READ;
        if (bp->b_bcount > bp->b_bufsize)
                panic("bread");
-       (*bdevsw[major(dev)].d_strategy)(bp);
-       trace(TR_BREADMISS, pack(dev, size), blkno);
+       VOP_STRATEGY(bp);
+       trace(TR_BREADMISS, pack(vp->v_mount->m_fsid[0], size), blkno);
        u.u_ru.ru_inblock++;            /* pay for read */
        u.u_ru.ru_inblock++;            /* pay for read */
-       biowait(bp);
-       return (bp);
+       return (biowait(bp));
 }
 
 /*
  * Read in the block, like bread, but also start I/O on the
  * read-ahead block (which is not allocated to the caller)
  */
 }
 
 /*
  * Read in the block, like bread, but also start I/O on the
  * read-ahead block (which is not allocated to the caller)
  */
-struct buf *
-#ifdef SECSIZE
-breada(dev, blkno, size, secsize, rablkno, rabsize)
-#else SECSIZE
-breada(dev, blkno, size, rablkno, rabsize)
-#endif SECSIZE
-       dev_t dev;
+breada(vp, blkno, size, rablkno, rabsize, bpp)
+       struct vnode *vp;
        daddr_t blkno; int size;
 #ifdef SECSIZE
        long secsize;
 #endif SECSIZE
        daddr_t rablkno; int rabsize;
        daddr_t blkno; int size;
 #ifdef SECSIZE
        long secsize;
 #endif SECSIZE
        daddr_t rablkno; int rabsize;
+       struct buf **bpp;
 {
        register struct buf *bp, *rabp;
 
 {
        register struct buf *bp, *rabp;
 
@@ -83,42 +78,40 @@ breada(dev, blkno, size, rablkno, rabsize)
         * a buffer and initiate i/o (getblk checks
         * for a cache hit).
         */
         * a buffer and initiate i/o (getblk checks
         * for a cache hit).
         */
-       if (!incore(dev, blkno)) {
-#ifdef SECSIZE
-               bp = getblk(dev, blkno, size, secsize);
-#else SECSIZE
-               bp = getblk(dev, blkno, size);
+       if (!incore(vp, blkno)) {
+               *bpp = bp = getblk(vp, blkno, size);
 #endif SECSIZE
                if ((bp->b_flags&(B_DONE|B_DELWRI)) == 0) {
                        bp->b_flags |= B_READ;
                        if (bp->b_bcount > bp->b_bufsize)
                                panic("breada");
 #endif SECSIZE
                if ((bp->b_flags&(B_DONE|B_DELWRI)) == 0) {
                        bp->b_flags |= B_READ;
                        if (bp->b_bcount > bp->b_bufsize)
                                panic("breada");
-                       (*bdevsw[major(dev)].d_strategy)(bp);
-                       trace(TR_BREADMISS, pack(dev, size), blkno);
+                       VOP_STRATEGY(bp);
+                       trace(TR_BREADMISS, pack(vp->v_mount->m_fsid[0], size),
+                           blkno);
                        u.u_ru.ru_inblock++;            /* pay for read */
                } else
                        u.u_ru.ru_inblock++;            /* pay for read */
                } else
-                       trace(TR_BREADHIT, pack(dev, size), blkno);
+                       trace(TR_BREADHIT, pack(vp->v_mount->m_fsid[0], size),
+                           blkno);
        }
 
        /*
         * If there's a read-ahead block, start i/o
         * on it also (as above).
         */
        }
 
        /*
         * If there's a read-ahead block, start i/o
         * on it also (as above).
         */
-       if (rablkno && !incore(dev, rablkno)) {
-#ifdef SECSIZE
-               rabp = getblk(dev, rablkno, rabsize, secsize);
-#else SECSIZE
-               rabp = getblk(dev, rablkno, rabsize);
+       if (rablkno && !incore(vp, rablkno)) {
+               rabp = getblk(vp, rablkno, rabsize);
 #endif SECSIZE
                if (rabp->b_flags & (B_DONE|B_DELWRI)) {
                        brelse(rabp);
 #endif SECSIZE
                if (rabp->b_flags & (B_DONE|B_DELWRI)) {
                        brelse(rabp);
-                       trace(TR_BREADHITRA, pack(dev, rabsize), blkno);
+                       trace(TR_BREADHITRA,
+                           pack(vp->v_mount->m_fsid[0], rabsize), blkno);
                } else {
                        rabp->b_flags |= B_READ|B_ASYNC;
                        if (rabp->b_bcount > rabp->b_bufsize)
                                panic("breadrabp");
                } else {
                        rabp->b_flags |= B_READ|B_ASYNC;
                        if (rabp->b_bcount > rabp->b_bufsize)
                                panic("breadrabp");
-                       (*bdevsw[major(dev)].d_strategy)(rabp);
-                       trace(TR_BREADMISSRA, pack(dev, rabsize), rablock);
+                       VOP_STRATEGY(rabp);
+                       trace(TR_BREADMISSRA,
+                           pack(vp->v_mount->m_fsid[0], rabsize), rablock);
                        u.u_ru.ru_inblock++;            /* pay in advance */
                }
        }
                        u.u_ru.ru_inblock++;            /* pay in advance */
                }
        }
@@ -132,10 +125,8 @@ breada(dev, blkno, size, rablkno, rabsize)
 #ifdef SECSIZE
                return (bread(dev, blkno, size, secsize));
 #else SECSIZE
 #ifdef SECSIZE
                return (bread(dev, blkno, size, secsize));
 #else SECSIZE
-               return (bread(dev, blkno, size));
-#endif SECSIZE
-       biowait(bp);
-       return (bp);
+               return (bread(vp, blkno, size, bpp));
+       return (biowait(bp));
 }
 
 /*
 }
 
 /*
@@ -145,16 +136,18 @@ breada(dev, blkno, size, rablkno, rabsize)
 bwrite(bp)
        register struct buf *bp;
 {
 bwrite(bp)
        register struct buf *bp;
 {
-       register flag;
+       register int flag;
+       int error;
 
        flag = bp->b_flags;
        bp->b_flags &= ~(B_READ | B_DONE | B_ERROR | B_DELWRI);
        if ((flag&B_DELWRI) == 0)
                u.u_ru.ru_oublock++;            /* noone paid yet */
 
        flag = bp->b_flags;
        bp->b_flags &= ~(B_READ | B_DONE | B_ERROR | B_DELWRI);
        if ((flag&B_DELWRI) == 0)
                u.u_ru.ru_oublock++;            /* noone paid yet */
-       trace(TR_BWRITE, pack(bp->b_dev, bp->b_bcount), bp->b_blkno);
+       trace(TR_BWRITE,
+           pack(bp->b_vp->v_mount->m_fsid[0], bp->b_bcount), bp->b_blkno);
        if (bp->b_bcount > bp->b_bufsize)
                panic("bwrite");
        if (bp->b_bcount > bp->b_bufsize)
                panic("bwrite");
-       (*bdevsw[major(bp->b_dev)].d_strategy)(bp);
+       VOP_STRATEGY(bp);
 
        /*
         * If the write was synchronous, then await i/o completion.
 
        /*
         * If the write was synchronous, then await i/o completion.
@@ -162,10 +155,13 @@ bwrite(bp)
         * the q of blocks awaiting i/o completion status.
         */
        if ((flag&B_ASYNC) == 0) {
         * the q of blocks awaiting i/o completion status.
         */
        if ((flag&B_ASYNC) == 0) {
-               biowait(bp);
+               error = biowait(bp);
                brelse(bp);
                brelse(bp);
-       } else if (flag & B_DELWRI)
+       } else if (flag & B_DELWRI) {
                bp->b_flags |= B_AGE;
                bp->b_flags |= B_AGE;
+               error = 0;
+       }
+       return (error);
 }
 
 /*
 }
 
 /*
@@ -182,12 +178,22 @@ bdwrite(bp)
 
        if ((bp->b_flags&B_DELWRI) == 0)
                u.u_ru.ru_oublock++;            /* noone paid yet */
 
        if ((bp->b_flags&B_DELWRI) == 0)
                u.u_ru.ru_oublock++;            /* noone paid yet */
+#ifdef notdef
+       /*
+        * This does not work for buffers associated with
+        * vnodes that are remote - they have no dev.
+        * Besides, we don't use bio with tapes, so rather
+        * than develop a fix, we just ifdef this out for now.
+        */
        if (bdevsw[major(bp->b_dev)].d_flags & B_TAPE)
                bawrite(bp);
        else {
                bp->b_flags |= B_DELWRI | B_DONE;
                brelse(bp);
        }
        if (bdevsw[major(bp->b_dev)].d_flags & B_TAPE)
                bawrite(bp);
        else {
                bp->b_flags |= B_DELWRI | B_DONE;
                brelse(bp);
        }
+#endif
+       bp->b_flags |= B_DELWRI | B_DONE;
+       brelse(bp);
 }
 
 /*
 }
 
 /*
@@ -198,7 +204,7 @@ bawrite(bp)
 {
 
        bp->b_flags |= B_ASYNC;
 {
 
        bp->b_flags |= B_ASYNC;
-       bwrite(bp);
+       (void) bwrite(bp);
 }
 
 /*
 }
 
 /*
@@ -210,7 +216,8 @@ brelse(bp)
        register struct buf *flist;
        register s;
 
        register struct buf *flist;
        register s;
 
-       trace(TR_BRELSE, pack(bp->b_dev, bp->b_bufsize), bp->b_blkno);
+       trace(TR_BRELSE,
+           pack(bp->b_vp->v_mount->m_fsid[0], bp->b_bufsize), bp->b_blkno);
        /*
         * If someone's waiting for the buffer, or
         * is waiting for a buffer wake 'em up.
        /*
         * If someone's waiting for the buffer, or
         * is waiting for a buffer wake 'em up.
@@ -221,11 +228,14 @@ brelse(bp)
                bfreelist[0].b_flags &= ~B_WANTED;
                wakeup((caddr_t)bfreelist);
        }
                bfreelist[0].b_flags &= ~B_WANTED;
                wakeup((caddr_t)bfreelist);
        }
+       if (bp->b_flags & B_NOCACHE) {
+               bp->b_flags |= B_INVAL;
+       }
        if (bp->b_flags&B_ERROR)
                if (bp->b_flags & B_LOCKED)
                        bp->b_flags &= ~B_ERROR;        /* try again later */
                else
        if (bp->b_flags&B_ERROR)
                if (bp->b_flags & B_LOCKED)
                        bp->b_flags &= ~B_ERROR;        /* try again later */
                else
-                       bp->b_dev = NODEV;              /* no assoc */
+                       brelvp(bp);                     /* no assoc */
 
        /*
         * Stick the buffer back on a free list.
 
        /*
         * Stick the buffer back on a free list.
@@ -248,7 +258,7 @@ brelse(bp)
                        flist = &bfreelist[BQ_LRU];
                binstailfree(bp, flist);
        }
                        flist = &bfreelist[BQ_LRU];
                binstailfree(bp, flist);
        }
-       bp->b_flags &= ~(B_WANTED|B_BUSY|B_ASYNC|B_AGE);
+       bp->b_flags &= ~(B_WANTED|B_BUSY|B_ASYNC|B_AGE|B_NOCACHE);
        splx(s);
 }
 
        splx(s);
 }
 
@@ -256,40 +266,34 @@ brelse(bp)
  * See if the block is associated with some buffer
  * (mainly to avoid getting hung up on a wait in breada)
  */
  * See if the block is associated with some buffer
  * (mainly to avoid getting hung up on a wait in breada)
  */
-incore(dev, blkno)
-       dev_t dev;
+incore(vp, blkno)
+       struct vnode *vp;
        daddr_t blkno;
 {
        register struct buf *bp;
        register struct buf *dp;
 
        daddr_t blkno;
 {
        register struct buf *bp;
        register struct buf *dp;
 
-       dp = BUFHASH(dev, blkno);
+       dp = BUFHASH(vp->v_rdev, blkno);
        for (bp = dp->b_forw; bp != dp; bp = bp->b_forw)
        for (bp = dp->b_forw; bp != dp; bp = bp->b_forw)
-               if (bp->b_blkno == blkno && bp->b_dev == dev &&
+               if (bp->b_blkno == blkno && bp->b_vp == vp &&
                    (bp->b_flags & B_INVAL) == 0)
                        return (1);
        return (0);
 }
 
                    (bp->b_flags & B_INVAL) == 0)
                        return (1);
        return (0);
 }
 
-struct buf *
-#ifdef SECSIZE
-baddr(dev, blkno, size, secsize)
-#else SECSIZE
-baddr(dev, blkno, size)
-#endif SECSIZE
-       dev_t dev;
+baddr(vp, blkno, size, bpp)
+       struct vnode *vp;
        daddr_t blkno;
        int size;
        daddr_t blkno;
        int size;
+       struct buf **bpp;
 #ifdef SECSIZE
        long secsize;
 #endif SECSIZE
 {
 
 #ifdef SECSIZE
        long secsize;
 #endif SECSIZE
 {
 
-       if (incore(dev, blkno))
-#ifdef SECSIZE
-               return (bread(dev, blkno, size, secsize));
-#else SECSIZE
-               return (bread(dev, blkno, size));
+       if (incore(vp, blkno))
+               return (bread(vp, blkno, size, bpp));
+       *bpp = 0;
 #endif SECSIZE
        return (0);
 }
 #endif SECSIZE
        return (0);
 }
@@ -314,9 +318,8 @@ struct buf *
 #ifdef SECSIZE
 getblk(dev, blkno, size, secsize)
 #else SECSIZE
 #ifdef SECSIZE
 getblk(dev, blkno, size, secsize)
 #else SECSIZE
-getblk(dev, blkno, size)
-#endif SECSIZE
-       dev_t dev;
+getblk(vp, blkno, size)
+       register struct vnode *vp;
        daddr_t blkno;
        int size;
 #ifdef SECSIZE
        daddr_t blkno;
        int size;
 #ifdef SECSIZE
@@ -343,10 +346,10 @@ getblk(dev, blkno, size)
         * the buffer is in use for i/o, then we wait until
         * the i/o has completed.
         */
         * the buffer is in use for i/o, then we wait until
         * the i/o has completed.
         */
-       dp = BUFHASH(dev, blkno);
+       dp = BUFHASH(vp, blkno);
 loop:
        for (bp = dp->b_forw; bp != dp; bp = bp->b_forw) {
 loop:
        for (bp = dp->b_forw; bp != dp; bp = bp->b_forw) {
-               if (bp->b_blkno != blkno || bp->b_dev != dev ||
+               if (bp->b_blkno != blkno || bp->b_vp != vp ||
                    bp->b_flags&B_INVAL)
                        continue;
                s = splbio();
                    bp->b_flags&B_INVAL)
                        continue;
                s = splbio();
@@ -361,7 +364,7 @@ loop:
                if (bp->b_bcount != size) {
                        if (bp->b_bcount < size && (bp->b_flags&B_DELWRI)) {
                                bp->b_flags &= ~B_ASYNC;
                if (bp->b_bcount != size) {
                        if (bp->b_bcount < size && (bp->b_flags&B_DELWRI)) {
                                bp->b_flags &= ~B_ASYNC;
-                               bwrite(bp);
+                               (void) bwrite(bp);
                                goto loop;
                        }
                        if (brealloc(bp, size) == 0)
                                goto loop;
                        }
                        if (brealloc(bp, size) == 0)
@@ -372,18 +375,21 @@ loop:
                bp->b_flags |= B_CACHE;
                return (bp);
        }
                bp->b_flags |= B_CACHE;
                return (bp);
        }
-       if (major(dev) >= nblkdev)
-               panic("blkdev");
        bp = getnewbuf();
        bfree(bp);
        bremhash(bp);
        bp = getnewbuf();
        bfree(bp);
        bremhash(bp);
-       binshash(bp, dp);
-       bp->b_dev = dev;
+       if (bp->b_vp)
+               brelvp(bp);
+       vp->v_count++;
+       bp->b_vp = vp;
+       bp->b_dev = vp->v_rdev;
 #ifdef SECSIZE
        bp->b_blksize = secsize;
 #endif SECSIZE
        bp->b_blkno = blkno;
        bp->b_error = 0;
 #ifdef SECSIZE
        bp->b_blksize = secsize;
 #endif SECSIZE
        bp->b_blkno = blkno;
        bp->b_error = 0;
+       bp->b_resid = 0;
+       binshash(bp, dp);
        if (brealloc(bp, size) == 0)
                goto loop;
        return (bp);
        if (brealloc(bp, size) == 0)
                goto loop;
        return (bp);
@@ -407,12 +413,13 @@ loop:
        bfree(bp);
        bremhash(bp);
        flist = &bfreelist[BQ_AGE];
        bfree(bp);
        bremhash(bp);
        flist = &bfreelist[BQ_AGE];
-       binshash(bp, flist);
-       bp->b_dev = (dev_t)NODEV;
+       brelvp(bp);
 #ifdef SECSIZE
        bp->b_blksize = DEV_BSIZE;
 #endif SECSIZE
        bp->b_error = 0;
 #ifdef SECSIZE
        bp->b_blksize = DEV_BSIZE;
 #endif SECSIZE
        bp->b_error = 0;
+       bp->b_resid = 0;
+       binshash(bp, flist);
        if (brealloc(bp, size) == 0)
                goto loop;
        return (bp);
        if (brealloc(bp, size) == 0)
                goto loop;
        return (bp);
@@ -439,7 +446,7 @@ brealloc(bp, size)
                return (1);
        if (size < bp->b_bcount) { 
                if (bp->b_flags & B_DELWRI) {
                return (1);
        if (size < bp->b_bcount) { 
                if (bp->b_flags & B_DELWRI) {
-                       bwrite(bp);
+                       (void) bwrite(bp);
                        return (0);
                }
                if (bp->b_flags & B_LOCKED)
                        return (0);
                }
                if (bp->b_flags & B_LOCKED)
@@ -447,10 +454,11 @@ brealloc(bp, size)
                return (allocbuf(bp, size));
        }
        bp->b_flags &= ~B_DONE;
                return (allocbuf(bp, size));
        }
        bp->b_flags &= ~B_DONE;
-       if (bp->b_dev == NODEV)
+       if (bp->b_vp == (struct vnode *)0)
                return (allocbuf(bp, size));
 
                return (allocbuf(bp, size));
 
-       trace(TR_BREALLOC, pack(bp->b_dev, size), bp->b_blkno);
+       trace(TR_BREALLOC,
+           pack(bp->b_vp->v_mount->m_fsid[0], size), bp->b_blkno);
        /*
         * Search cache for any buffers that overlap the one that we
         * are trying to allocate. Overlapping buffers must be marked
        /*
         * Search cache for any buffers that overlap the one that we
         * are trying to allocate. Overlapping buffers must be marked
@@ -465,10 +473,11 @@ brealloc(bp, size)
 #else SECSIZE
        last = start + btodb(size) - 1;
 #endif SECSIZE
 #else SECSIZE
        last = start + btodb(size) - 1;
 #endif SECSIZE
-       dp = BUFHASH(bp->b_dev, bp->b_blkno);
+       dp = BUFHASH(bp->b_vp, bp->b_blkno);
 loop:
        for (ep = dp->b_forw; ep != dp; ep = ep->b_forw) {
 loop:
        for (ep = dp->b_forw; ep != dp; ep = ep->b_forw) {
-               if (ep == bp || ep->b_dev != bp->b_dev || (ep->b_flags&B_INVAL))
+               if (ep == bp || ep->b_vp != bp->b_vp ||
+                   (ep->b_flags & B_INVAL))
                        continue;
                /* look for overlap */
                if (ep->b_bcount == 0 || ep->b_blkno > last ||
                        continue;
                /* look for overlap */
                if (ep->b_bcount == 0 || ep->b_blkno > last ||
@@ -488,7 +497,7 @@ loop:
                splx(s);
                notavail(ep);
                if (ep->b_flags & B_DELWRI) {
                splx(s);
                notavail(ep);
                if (ep->b_flags & B_DELWRI) {
-                       bwrite(ep);
+                       (void) bwrite(ep);
                        goto loop;
                }
                ep->b_flags |= B_INVAL;
                        goto loop;
                }
                ep->b_flags |= B_INVAL;
@@ -524,10 +533,12 @@ loop:
        notavail(bp);
        if (bp->b_flags & B_DELWRI) {
                bp->b_flags |= B_ASYNC;
        notavail(bp);
        if (bp->b_flags & B_DELWRI) {
                bp->b_flags |= B_ASYNC;
-               bwrite(bp);
+               (void) bwrite(bp);
                goto loop;
        }
                goto loop;
        }
-       trace(TR_BRELSE, pack(bp->b_dev, bp->b_bufsize), bp->b_blkno);
+       trace(TR_BRELSE,
+           pack(bp->b_vp->v_mount->m_fsid[0], bp->b_bufsize), bp->b_blkno);
+       brelvp(bp);
        bp->b_flags = B_BUSY;
        return (bp);
 }
        bp->b_flags = B_BUSY;
        return (bp);
 }
@@ -545,8 +556,15 @@ biowait(bp)
        while ((bp->b_flags&B_DONE)==0)
                sleep((caddr_t)bp, PRIBIO);
        splx(s);
        while ((bp->b_flags&B_DONE)==0)
                sleep((caddr_t)bp, PRIBIO);
        splx(s);
-       if (u.u_error == 0)                     /* XXX */
-               u.u_error = geterror(bp);
+       /*
+        * Pick up the device's error number and pass it to the user;
+        * if there is an error but the number is 0 set a generalized code.
+        */
+       if ((bp->b_flags & B_ERROR) == 0)
+               return (0);
+       if (bp->b_error)
+               return (bp->b_error);
+       return (EIO);
 }
 
 /*
 }
 
 /*
@@ -576,7 +594,7 @@ biodone(bp)
 }
 
 /*
 }
 
 /*
- * Insure that no part of a specified block is in an incore buffer.
+ * Ensure that no part of a specified block is in an incore buffer.
 #ifdef SECSIZE
  * "size" is given in device blocks (the units of b_blkno).
 #endif SECSIZE
 #ifdef SECSIZE
  * "size" is given in device blocks (the units of b_blkno).
 #endif SECSIZE
@@ -584,8 +602,8 @@ biodone(bp)
  * "size" is given in device blocks (the units of b_blkno).
 #endif SECSIZE
  */
  * "size" is given in device blocks (the units of b_blkno).
 #endif SECSIZE
  */
-blkflush(dev, blkno, size)
-       dev_t dev;
+blkflush(vp, blkno, size)
+       struct vnode *vp;
        daddr_t blkno;
 #ifdef SECSIZE
        int size;
        daddr_t blkno;
 #ifdef SECSIZE
        int size;
@@ -596,7 +614,7 @@ blkflush(dev, blkno, size)
        register struct buf *ep;
        struct buf *dp;
        daddr_t start, last;
        register struct buf *ep;
        struct buf *dp;
        daddr_t start, last;
-       int s;
+       int s, error, allerrors = 0;
 
        start = blkno;
 #ifdef SECSIZE
 
        start = blkno;
 #ifdef SECSIZE
@@ -604,10 +622,10 @@ blkflush(dev, blkno, size)
 #else SECSIZE
        last = start + btodb(size) - 1;
 #endif SECSIZE
 #else SECSIZE
        last = start + btodb(size) - 1;
 #endif SECSIZE
-       dp = BUFHASH(dev, blkno);
+       dp = BUFHASH(vp, blkno);
 loop:
        for (ep = dp->b_forw; ep != dp; ep = ep->b_forw) {
 loop:
        for (ep = dp->b_forw; ep != dp; ep = ep->b_forw) {
-               if (ep->b_dev != dev || (ep->b_flags&B_INVAL))
+               if (ep->b_vp != vp || (ep->b_flags & B_INVAL))
                        continue;
                /* look for overlap */
                if (ep->b_bcount == 0 || ep->b_blkno > last ||
                        continue;
                /* look for overlap */
                if (ep->b_bcount == 0 || ep->b_blkno > last ||
@@ -627,18 +645,18 @@ loop:
                if (ep->b_flags & B_DELWRI) {
                        splx(s);
                        notavail(ep);
                if (ep->b_flags & B_DELWRI) {
                        splx(s);
                        notavail(ep);
-                       bwrite(ep);
+                       if (error = bwrite(ep))
+                               allerrors = error;
                        goto loop;
                }
                splx(s);
        }
                        goto loop;
                }
                splx(s);
        }
+       return (allerrors);
 }
 
 /*
 }
 
 /*
- * Make sure all write-behind blocks
- * on dev (or NODEV for all)
- * are flushed out.
- * (from umount and update)
+ * Make sure all write-behind blocks associated
+ * with vp are flushed out (from sync).
  */
 bflush(dev)
        dev_t dev;
  */
 bflush(dev)
        dev_t dev;
@@ -656,7 +674,7 @@ loop:
                if (dev == NODEV || dev == bp->b_dev) {
                        bp->b_flags |= B_ASYNC;
                        notavail(bp);
                if (dev == NODEV || dev == bp->b_dev) {
                        bp->b_flags |= B_ASYNC;
                        notavail(bp);
-                       bwrite(bp);
+                       (void) bwrite(bp);
                        splx(s);
                        goto loop;
                }
                        splx(s);
                        goto loop;
                }
@@ -664,20 +682,39 @@ loop:
        splx(s);
 }
 
        splx(s);
 }
 
+#ifdef unused
 /*
 /*
- * Pick up the device's error number and pass it to the user;
- * if there is an error but the number is 0 set a generalized code.
+ * Invalidate blocks associated with vp which are on the freelist.
+ * Make sure all write-behind blocks associated with vp are flushed out.
  */
  */
-geterror(bp)
-       register struct buf *bp;
+binvalfree(vp)
+       struct vnode *vp;
 {
 {
-       int error = 0;
+       register struct buf *bp;
+       register struct buf *flist;
+       int s;
 
 
-       if (bp->b_flags&B_ERROR)
-               if ((error = bp->b_error)==0)
-                       return (EIO);
-       return (error);
+loop:
+       s = splbio();
+       for (flist = bfreelist; flist < &bfreelist[BQ_EMPTY]; flist++)
+       for (bp = flist->av_forw; bp != flist; bp = bp->av_forw) {
+               if (vp == (struct vnode *) 0 || vp == bp->b_vp) {
+                       if (bp->b_flags & B_DELWRI) {
+                               bp->b_flags |= B_ASYNC;
+                               notavail(bp);
+                               (void) splx(s);
+                               (void) bwrite(bp);
+                       } else {
+                               bp->b_flags |= B_INVAL;
+                               brelvp(bp);
+                               (void) splx(s);
+                       }
+                       goto loop;
+               }
+       }
+       (void) splx(s);
 }
 }
+#endif /* unused */
 
 /*
  * Invalidate in core blocks belonging to closed or umounted filesystem
 
 /*
  * Invalidate in core blocks belonging to closed or umounted filesystem
@@ -697,8 +734,24 @@ binval(dev)
        register struct bufhd *hp;
 #define dp ((struct buf *)hp)
 
        register struct bufhd *hp;
 #define dp ((struct buf *)hp)
 
+loop:
        for (hp = bufhash; hp < &bufhash[BUFHSZ]; hp++)
                for (bp = dp->b_forw; bp != dp; bp = bp->b_forw)
        for (hp = bufhash; hp < &bufhash[BUFHSZ]; hp++)
                for (bp = dp->b_forw; bp != dp; bp = bp->b_forw)
-                       if (bp->b_dev == dev)
+                       if (bp->b_dev == dev && (bp->b_flags & B_INVAL) == 0) {
                                bp->b_flags |= B_INVAL;
                                bp->b_flags |= B_INVAL;
+                               brelvp(bp);
+                               goto loop;
+                       }
+}
+
+brelvp(bp)
+       struct buf *bp;
+{
+       struct vnode *vp;
+
+       if (bp->b_vp == (struct vnode *) 0)
+               return;
+       vp = bp->b_vp;
+       bp->b_vp = (struct vnode *) 0;
+       vrele(vp);
 }
 }
index fbaa042..5a98d13 100644 (file)
@@ -1,36 +1,36 @@
 /*
 /*
- * Copyright (c) 1982, 1986 Regents of the University of California.
- * All rights reserved.  The Berkeley software License Agreement
- * specifies the terms and conditions for redistribution.
+ * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
+ * All rights reserved.
  *
  *
- *     @(#)vfs_cluster.c       7.4 (Berkeley) %G%
+ * 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.
+ *
+ *     @(#)vfs_cluster.c       7.5 (Berkeley) %G%
  */
 
 #include "param.h"
  */
 
 #include "param.h"
-#include "systm.h"
-#include "dir.h"
 #include "user.h"
 #include "buf.h"
 #include "user.h"
 #include "buf.h"
-#include "conf.h"
-#include "proc.h"
-#include "seg.h"
-#include "vm.h"
+#include "vnode.h"
 #include "trace.h"
 
 #include "trace.h"
 
-#include "machine/pte.h"
-
 /*
  * Read in (if necessary) the block and return a buffer pointer.
  */
 /*
  * Read in (if necessary) the block and return a buffer pointer.
  */
-struct buf *
-#ifdef SECSIZE
-bread(dev, blkno, size, secsize)
-#else SECSIZE
-bread(dev, blkno, size)
-#endif SECSIZE
-       dev_t dev;
+bread(vp, blkno, size, bpp)
+       struct vnode *vp;
        daddr_t blkno;
        int size;
        daddr_t blkno;
        int size;
+       struct buf **bpp;
 #ifdef SECSIZE
        long secsize;
 #endif SECSIZE
 #ifdef SECSIZE
        long secsize;
 #endif SECSIZE
@@ -42,38 +42,33 @@ bread(dev, blkno, size)
 #ifdef SECSIZE
        bp = getblk(dev, blkno, size, secsize);
 #else SECSIZE
 #ifdef SECSIZE
        bp = getblk(dev, blkno, size, secsize);
 #else SECSIZE
-       bp = getblk(dev, blkno, size);
+       *bpp = bp = getblk(vp, blkno, size);
 #endif SECSIZE
        if (bp->b_flags&(B_DONE|B_DELWRI)) {
 #endif SECSIZE
        if (bp->b_flags&(B_DONE|B_DELWRI)) {
-               trace(TR_BREADHIT, pack(dev, size), blkno);
-               return (bp);
+               trace(TR_BREADHIT, pack(vp->v_mount->m_fsid[0], size), blkno);
+               return (0);
        }
        bp->b_flags |= B_READ;
        if (bp->b_bcount > bp->b_bufsize)
                panic("bread");
        }
        bp->b_flags |= B_READ;
        if (bp->b_bcount > bp->b_bufsize)
                panic("bread");
-       (*bdevsw[major(dev)].d_strategy)(bp);
-       trace(TR_BREADMISS, pack(dev, size), blkno);
+       VOP_STRATEGY(bp);
+       trace(TR_BREADMISS, pack(vp->v_mount->m_fsid[0], size), blkno);
        u.u_ru.ru_inblock++;            /* pay for read */
        u.u_ru.ru_inblock++;            /* pay for read */
-       biowait(bp);
-       return (bp);
+       return (biowait(bp));
 }
 
 /*
  * Read in the block, like bread, but also start I/O on the
  * read-ahead block (which is not allocated to the caller)
  */
 }
 
 /*
  * Read in the block, like bread, but also start I/O on the
  * read-ahead block (which is not allocated to the caller)
  */
-struct buf *
-#ifdef SECSIZE
-breada(dev, blkno, size, secsize, rablkno, rabsize)
-#else SECSIZE
-breada(dev, blkno, size, rablkno, rabsize)
-#endif SECSIZE
-       dev_t dev;
+breada(vp, blkno, size, rablkno, rabsize, bpp)
+       struct vnode *vp;
        daddr_t blkno; int size;
 #ifdef SECSIZE
        long secsize;
 #endif SECSIZE
        daddr_t rablkno; int rabsize;
        daddr_t blkno; int size;
 #ifdef SECSIZE
        long secsize;
 #endif SECSIZE
        daddr_t rablkno; int rabsize;
+       struct buf **bpp;
 {
        register struct buf *bp, *rabp;
 
 {
        register struct buf *bp, *rabp;
 
@@ -83,42 +78,40 @@ breada(dev, blkno, size, rablkno, rabsize)
         * a buffer and initiate i/o (getblk checks
         * for a cache hit).
         */
         * a buffer and initiate i/o (getblk checks
         * for a cache hit).
         */
-       if (!incore(dev, blkno)) {
-#ifdef SECSIZE
-               bp = getblk(dev, blkno, size, secsize);
-#else SECSIZE
-               bp = getblk(dev, blkno, size);
+       if (!incore(vp, blkno)) {
+               *bpp = bp = getblk(vp, blkno, size);
 #endif SECSIZE
                if ((bp->b_flags&(B_DONE|B_DELWRI)) == 0) {
                        bp->b_flags |= B_READ;
                        if (bp->b_bcount > bp->b_bufsize)
                                panic("breada");
 #endif SECSIZE
                if ((bp->b_flags&(B_DONE|B_DELWRI)) == 0) {
                        bp->b_flags |= B_READ;
                        if (bp->b_bcount > bp->b_bufsize)
                                panic("breada");
-                       (*bdevsw[major(dev)].d_strategy)(bp);
-                       trace(TR_BREADMISS, pack(dev, size), blkno);
+                       VOP_STRATEGY(bp);
+                       trace(TR_BREADMISS, pack(vp->v_mount->m_fsid[0], size),
+                           blkno);
                        u.u_ru.ru_inblock++;            /* pay for read */
                } else
                        u.u_ru.ru_inblock++;            /* pay for read */
                } else
-                       trace(TR_BREADHIT, pack(dev, size), blkno);
+                       trace(TR_BREADHIT, pack(vp->v_mount->m_fsid[0], size),
+                           blkno);
        }
 
        /*
         * If there's a read-ahead block, start i/o
         * on it also (as above).
         */
        }
 
        /*
         * If there's a read-ahead block, start i/o
         * on it also (as above).
         */
-       if (rablkno && !incore(dev, rablkno)) {
-#ifdef SECSIZE
-               rabp = getblk(dev, rablkno, rabsize, secsize);
-#else SECSIZE
-               rabp = getblk(dev, rablkno, rabsize);
+       if (rablkno && !incore(vp, rablkno)) {
+               rabp = getblk(vp, rablkno, rabsize);
 #endif SECSIZE
                if (rabp->b_flags & (B_DONE|B_DELWRI)) {
                        brelse(rabp);
 #endif SECSIZE
                if (rabp->b_flags & (B_DONE|B_DELWRI)) {
                        brelse(rabp);
-                       trace(TR_BREADHITRA, pack(dev, rabsize), blkno);
+                       trace(TR_BREADHITRA,
+                           pack(vp->v_mount->m_fsid[0], rabsize), blkno);
                } else {
                        rabp->b_flags |= B_READ|B_ASYNC;
                        if (rabp->b_bcount > rabp->b_bufsize)
                                panic("breadrabp");
                } else {
                        rabp->b_flags |= B_READ|B_ASYNC;
                        if (rabp->b_bcount > rabp->b_bufsize)
                                panic("breadrabp");
-                       (*bdevsw[major(dev)].d_strategy)(rabp);
-                       trace(TR_BREADMISSRA, pack(dev, rabsize), rablock);
+                       VOP_STRATEGY(rabp);
+                       trace(TR_BREADMISSRA,
+                           pack(vp->v_mount->m_fsid[0], rabsize), rablock);
                        u.u_ru.ru_inblock++;            /* pay in advance */
                }
        }
                        u.u_ru.ru_inblock++;            /* pay in advance */
                }
        }
@@ -132,10 +125,8 @@ breada(dev, blkno, size, rablkno, rabsize)
 #ifdef SECSIZE
                return (bread(dev, blkno, size, secsize));
 #else SECSIZE
 #ifdef SECSIZE
                return (bread(dev, blkno, size, secsize));
 #else SECSIZE
-               return (bread(dev, blkno, size));
-#endif SECSIZE
-       biowait(bp);
-       return (bp);
+               return (bread(vp, blkno, size, bpp));
+       return (biowait(bp));
 }
 
 /*
 }
 
 /*
@@ -145,16 +136,18 @@ breada(dev, blkno, size, rablkno, rabsize)
 bwrite(bp)
        register struct buf *bp;
 {
 bwrite(bp)
        register struct buf *bp;
 {
-       register flag;
+       register int flag;
+       int error;
 
        flag = bp->b_flags;
        bp->b_flags &= ~(B_READ | B_DONE | B_ERROR | B_DELWRI);
        if ((flag&B_DELWRI) == 0)
                u.u_ru.ru_oublock++;            /* noone paid yet */
 
        flag = bp->b_flags;
        bp->b_flags &= ~(B_READ | B_DONE | B_ERROR | B_DELWRI);
        if ((flag&B_DELWRI) == 0)
                u.u_ru.ru_oublock++;            /* noone paid yet */
-       trace(TR_BWRITE, pack(bp->b_dev, bp->b_bcount), bp->b_blkno);
+       trace(TR_BWRITE,
+           pack(bp->b_vp->v_mount->m_fsid[0], bp->b_bcount), bp->b_blkno);
        if (bp->b_bcount > bp->b_bufsize)
                panic("bwrite");
        if (bp->b_bcount > bp->b_bufsize)
                panic("bwrite");
-       (*bdevsw[major(bp->b_dev)].d_strategy)(bp);
+       VOP_STRATEGY(bp);
 
        /*
         * If the write was synchronous, then await i/o completion.
 
        /*
         * If the write was synchronous, then await i/o completion.
@@ -162,10 +155,13 @@ bwrite(bp)
         * the q of blocks awaiting i/o completion status.
         */
        if ((flag&B_ASYNC) == 0) {
         * the q of blocks awaiting i/o completion status.
         */
        if ((flag&B_ASYNC) == 0) {
-               biowait(bp);
+               error = biowait(bp);
                brelse(bp);
                brelse(bp);
-       } else if (flag & B_DELWRI)
+       } else if (flag & B_DELWRI) {
                bp->b_flags |= B_AGE;
                bp->b_flags |= B_AGE;
+               error = 0;
+       }
+       return (error);
 }
 
 /*
 }
 
 /*
@@ -182,12 +178,22 @@ bdwrite(bp)
 
        if ((bp->b_flags&B_DELWRI) == 0)
                u.u_ru.ru_oublock++;            /* noone paid yet */
 
        if ((bp->b_flags&B_DELWRI) == 0)
                u.u_ru.ru_oublock++;            /* noone paid yet */
+#ifdef notdef
+       /*
+        * This does not work for buffers associated with
+        * vnodes that are remote - they have no dev.
+        * Besides, we don't use bio with tapes, so rather
+        * than develop a fix, we just ifdef this out for now.
+        */
        if (bdevsw[major(bp->b_dev)].d_flags & B_TAPE)
                bawrite(bp);
        else {
                bp->b_flags |= B_DELWRI | B_DONE;
                brelse(bp);
        }
        if (bdevsw[major(bp->b_dev)].d_flags & B_TAPE)
                bawrite(bp);
        else {
                bp->b_flags |= B_DELWRI | B_DONE;
                brelse(bp);
        }
+#endif
+       bp->b_flags |= B_DELWRI | B_DONE;
+       brelse(bp);
 }
 
 /*
 }
 
 /*
@@ -198,7 +204,7 @@ bawrite(bp)
 {
 
        bp->b_flags |= B_ASYNC;
 {
 
        bp->b_flags |= B_ASYNC;
-       bwrite(bp);
+       (void) bwrite(bp);
 }
 
 /*
 }
 
 /*
@@ -210,7 +216,8 @@ brelse(bp)
        register struct buf *flist;
        register s;
 
        register struct buf *flist;
        register s;
 
-       trace(TR_BRELSE, pack(bp->b_dev, bp->b_bufsize), bp->b_blkno);
+       trace(TR_BRELSE,
+           pack(bp->b_vp->v_mount->m_fsid[0], bp->b_bufsize), bp->b_blkno);
        /*
         * If someone's waiting for the buffer, or
         * is waiting for a buffer wake 'em up.
        /*
         * If someone's waiting for the buffer, or
         * is waiting for a buffer wake 'em up.
@@ -221,11 +228,14 @@ brelse(bp)
                bfreelist[0].b_flags &= ~B_WANTED;
                wakeup((caddr_t)bfreelist);
        }
                bfreelist[0].b_flags &= ~B_WANTED;
                wakeup((caddr_t)bfreelist);
        }
+       if (bp->b_flags & B_NOCACHE) {
+               bp->b_flags |= B_INVAL;
+       }
        if (bp->b_flags&B_ERROR)
                if (bp->b_flags & B_LOCKED)
                        bp->b_flags &= ~B_ERROR;        /* try again later */
                else
        if (bp->b_flags&B_ERROR)
                if (bp->b_flags & B_LOCKED)
                        bp->b_flags &= ~B_ERROR;        /* try again later */
                else
-                       bp->b_dev = NODEV;              /* no assoc */
+                       brelvp(bp);                     /* no assoc */
 
        /*
         * Stick the buffer back on a free list.
 
        /*
         * Stick the buffer back on a free list.
@@ -248,7 +258,7 @@ brelse(bp)
                        flist = &bfreelist[BQ_LRU];
                binstailfree(bp, flist);
        }
                        flist = &bfreelist[BQ_LRU];
                binstailfree(bp, flist);
        }
-       bp->b_flags &= ~(B_WANTED|B_BUSY|B_ASYNC|B_AGE);
+       bp->b_flags &= ~(B_WANTED|B_BUSY|B_ASYNC|B_AGE|B_NOCACHE);
        splx(s);
 }
 
        splx(s);
 }
 
@@ -256,40 +266,34 @@ brelse(bp)
  * See if the block is associated with some buffer
  * (mainly to avoid getting hung up on a wait in breada)
  */
  * See if the block is associated with some buffer
  * (mainly to avoid getting hung up on a wait in breada)
  */
-incore(dev, blkno)
-       dev_t dev;
+incore(vp, blkno)
+       struct vnode *vp;
        daddr_t blkno;
 {
        register struct buf *bp;
        register struct buf *dp;
 
        daddr_t blkno;
 {
        register struct buf *bp;
        register struct buf *dp;
 
-       dp = BUFHASH(dev, blkno);
+       dp = BUFHASH(vp->v_rdev, blkno);
        for (bp = dp->b_forw; bp != dp; bp = bp->b_forw)
        for (bp = dp->b_forw; bp != dp; bp = bp->b_forw)
-               if (bp->b_blkno == blkno && bp->b_dev == dev &&
+               if (bp->b_blkno == blkno && bp->b_vp == vp &&
                    (bp->b_flags & B_INVAL) == 0)
                        return (1);
        return (0);
 }
 
                    (bp->b_flags & B_INVAL) == 0)
                        return (1);
        return (0);
 }
 
-struct buf *
-#ifdef SECSIZE
-baddr(dev, blkno, size, secsize)
-#else SECSIZE
-baddr(dev, blkno, size)
-#endif SECSIZE
-       dev_t dev;
+baddr(vp, blkno, size, bpp)
+       struct vnode *vp;
        daddr_t blkno;
        int size;
        daddr_t blkno;
        int size;
+       struct buf **bpp;
 #ifdef SECSIZE
        long secsize;
 #endif SECSIZE
 {
 
 #ifdef SECSIZE
        long secsize;
 #endif SECSIZE
 {
 
-       if (incore(dev, blkno))
-#ifdef SECSIZE
-               return (bread(dev, blkno, size, secsize));
-#else SECSIZE
-               return (bread(dev, blkno, size));
+       if (incore(vp, blkno))
+               return (bread(vp, blkno, size, bpp));
+       *bpp = 0;
 #endif SECSIZE
        return (0);
 }
 #endif SECSIZE
        return (0);
 }
@@ -314,9 +318,8 @@ struct buf *
 #ifdef SECSIZE
 getblk(dev, blkno, size, secsize)
 #else SECSIZE
 #ifdef SECSIZE
 getblk(dev, blkno, size, secsize)
 #else SECSIZE
-getblk(dev, blkno, size)
-#endif SECSIZE
-       dev_t dev;
+getblk(vp, blkno, size)
+       register struct vnode *vp;
        daddr_t blkno;
        int size;
 #ifdef SECSIZE
        daddr_t blkno;
        int size;
 #ifdef SECSIZE
@@ -343,10 +346,10 @@ getblk(dev, blkno, size)
         * the buffer is in use for i/o, then we wait until
         * the i/o has completed.
         */
         * the buffer is in use for i/o, then we wait until
         * the i/o has completed.
         */
-       dp = BUFHASH(dev, blkno);
+       dp = BUFHASH(vp, blkno);
 loop:
        for (bp = dp->b_forw; bp != dp; bp = bp->b_forw) {
 loop:
        for (bp = dp->b_forw; bp != dp; bp = bp->b_forw) {
-               if (bp->b_blkno != blkno || bp->b_dev != dev ||
+               if (bp->b_blkno != blkno || bp->b_vp != vp ||
                    bp->b_flags&B_INVAL)
                        continue;
                s = splbio();
                    bp->b_flags&B_INVAL)
                        continue;
                s = splbio();
@@ -361,7 +364,7 @@ loop:
                if (bp->b_bcount != size) {
                        if (bp->b_bcount < size && (bp->b_flags&B_DELWRI)) {
                                bp->b_flags &= ~B_ASYNC;
                if (bp->b_bcount != size) {
                        if (bp->b_bcount < size && (bp->b_flags&B_DELWRI)) {
                                bp->b_flags &= ~B_ASYNC;
-                               bwrite(bp);
+                               (void) bwrite(bp);
                                goto loop;
                        }
                        if (brealloc(bp, size) == 0)
                                goto loop;
                        }
                        if (brealloc(bp, size) == 0)
@@ -372,18 +375,21 @@ loop:
                bp->b_flags |= B_CACHE;
                return (bp);
        }
                bp->b_flags |= B_CACHE;
                return (bp);
        }
-       if (major(dev) >= nblkdev)
-               panic("blkdev");
        bp = getnewbuf();
        bfree(bp);
        bremhash(bp);
        bp = getnewbuf();
        bfree(bp);
        bremhash(bp);
-       binshash(bp, dp);
-       bp->b_dev = dev;
+       if (bp->b_vp)
+               brelvp(bp);
+       vp->v_count++;
+       bp->b_vp = vp;
+       bp->b_dev = vp->v_rdev;
 #ifdef SECSIZE
        bp->b_blksize = secsize;
 #endif SECSIZE
        bp->b_blkno = blkno;
        bp->b_error = 0;
 #ifdef SECSIZE
        bp->b_blksize = secsize;
 #endif SECSIZE
        bp->b_blkno = blkno;
        bp->b_error = 0;
+       bp->b_resid = 0;
+       binshash(bp, dp);
        if (brealloc(bp, size) == 0)
                goto loop;
        return (bp);
        if (brealloc(bp, size) == 0)
                goto loop;
        return (bp);
@@ -407,12 +413,13 @@ loop:
        bfree(bp);
        bremhash(bp);
        flist = &bfreelist[BQ_AGE];
        bfree(bp);
        bremhash(bp);
        flist = &bfreelist[BQ_AGE];
-       binshash(bp, flist);
-       bp->b_dev = (dev_t)NODEV;
+       brelvp(bp);
 #ifdef SECSIZE
        bp->b_blksize = DEV_BSIZE;
 #endif SECSIZE
        bp->b_error = 0;
 #ifdef SECSIZE
        bp->b_blksize = DEV_BSIZE;
 #endif SECSIZE
        bp->b_error = 0;
+       bp->b_resid = 0;
+       binshash(bp, flist);
        if (brealloc(bp, size) == 0)
                goto loop;
        return (bp);
        if (brealloc(bp, size) == 0)
                goto loop;
        return (bp);
@@ -439,7 +446,7 @@ brealloc(bp, size)
                return (1);
        if (size < bp->b_bcount) { 
                if (bp->b_flags & B_DELWRI) {
                return (1);
        if (size < bp->b_bcount) { 
                if (bp->b_flags & B_DELWRI) {
-                       bwrite(bp);
+                       (void) bwrite(bp);
                        return (0);
                }
                if (bp->b_flags & B_LOCKED)
                        return (0);
                }
                if (bp->b_flags & B_LOCKED)
@@ -447,10 +454,11 @@ brealloc(bp, size)
                return (allocbuf(bp, size));
        }
        bp->b_flags &= ~B_DONE;
                return (allocbuf(bp, size));
        }
        bp->b_flags &= ~B_DONE;
-       if (bp->b_dev == NODEV)
+       if (bp->b_vp == (struct vnode *)0)
                return (allocbuf(bp, size));
 
                return (allocbuf(bp, size));
 
-       trace(TR_BREALLOC, pack(bp->b_dev, size), bp->b_blkno);
+       trace(TR_BREALLOC,
+           pack(bp->b_vp->v_mount->m_fsid[0], size), bp->b_blkno);
        /*
         * Search cache for any buffers that overlap the one that we
         * are trying to allocate. Overlapping buffers must be marked
        /*
         * Search cache for any buffers that overlap the one that we
         * are trying to allocate. Overlapping buffers must be marked
@@ -465,10 +473,11 @@ brealloc(bp, size)
 #else SECSIZE
        last = start + btodb(size) - 1;
 #endif SECSIZE
 #else SECSIZE
        last = start + btodb(size) - 1;
 #endif SECSIZE
-       dp = BUFHASH(bp->b_dev, bp->b_blkno);
+       dp = BUFHASH(bp->b_vp, bp->b_blkno);
 loop:
        for (ep = dp->b_forw; ep != dp; ep = ep->b_forw) {
 loop:
        for (ep = dp->b_forw; ep != dp; ep = ep->b_forw) {
-               if (ep == bp || ep->b_dev != bp->b_dev || (ep->b_flags&B_INVAL))
+               if (ep == bp || ep->b_vp != bp->b_vp ||
+                   (ep->b_flags & B_INVAL))
                        continue;
                /* look for overlap */
                if (ep->b_bcount == 0 || ep->b_blkno > last ||
                        continue;
                /* look for overlap */
                if (ep->b_bcount == 0 || ep->b_blkno > last ||
@@ -488,7 +497,7 @@ loop:
                splx(s);
                notavail(ep);
                if (ep->b_flags & B_DELWRI) {
                splx(s);
                notavail(ep);
                if (ep->b_flags & B_DELWRI) {
-                       bwrite(ep);
+                       (void) bwrite(ep);
                        goto loop;
                }
                ep->b_flags |= B_INVAL;
                        goto loop;
                }
                ep->b_flags |= B_INVAL;
@@ -524,10 +533,12 @@ loop:
        notavail(bp);
        if (bp->b_flags & B_DELWRI) {
                bp->b_flags |= B_ASYNC;
        notavail(bp);
        if (bp->b_flags & B_DELWRI) {
                bp->b_flags |= B_ASYNC;
-               bwrite(bp);
+               (void) bwrite(bp);
                goto loop;
        }
                goto loop;
        }
-       trace(TR_BRELSE, pack(bp->b_dev, bp->b_bufsize), bp->b_blkno);
+       trace(TR_BRELSE,
+           pack(bp->b_vp->v_mount->m_fsid[0], bp->b_bufsize), bp->b_blkno);
+       brelvp(bp);
        bp->b_flags = B_BUSY;
        return (bp);
 }
        bp->b_flags = B_BUSY;
        return (bp);
 }
@@ -545,8 +556,15 @@ biowait(bp)
        while ((bp->b_flags&B_DONE)==0)
                sleep((caddr_t)bp, PRIBIO);
        splx(s);
        while ((bp->b_flags&B_DONE)==0)
                sleep((caddr_t)bp, PRIBIO);
        splx(s);
-       if (u.u_error == 0)                     /* XXX */
-               u.u_error = geterror(bp);
+       /*
+        * Pick up the device's error number and pass it to the user;
+        * if there is an error but the number is 0 set a generalized code.
+        */
+       if ((bp->b_flags & B_ERROR) == 0)
+               return (0);
+       if (bp->b_error)
+               return (bp->b_error);
+       return (EIO);
 }
 
 /*
 }
 
 /*
@@ -576,7 +594,7 @@ biodone(bp)
 }
 
 /*
 }
 
 /*
- * Insure that no part of a specified block is in an incore buffer.
+ * Ensure that no part of a specified block is in an incore buffer.
 #ifdef SECSIZE
  * "size" is given in device blocks (the units of b_blkno).
 #endif SECSIZE
 #ifdef SECSIZE
  * "size" is given in device blocks (the units of b_blkno).
 #endif SECSIZE
@@ -584,8 +602,8 @@ biodone(bp)
  * "size" is given in device blocks (the units of b_blkno).
 #endif SECSIZE
  */
  * "size" is given in device blocks (the units of b_blkno).
 #endif SECSIZE
  */
-blkflush(dev, blkno, size)
-       dev_t dev;
+blkflush(vp, blkno, size)
+       struct vnode *vp;
        daddr_t blkno;
 #ifdef SECSIZE
        int size;
        daddr_t blkno;
 #ifdef SECSIZE
        int size;
@@ -596,7 +614,7 @@ blkflush(dev, blkno, size)
        register struct buf *ep;
        struct buf *dp;
        daddr_t start, last;
        register struct buf *ep;
        struct buf *dp;
        daddr_t start, last;
-       int s;
+       int s, error, allerrors = 0;
 
        start = blkno;
 #ifdef SECSIZE
 
        start = blkno;
 #ifdef SECSIZE
@@ -604,10 +622,10 @@ blkflush(dev, blkno, size)
 #else SECSIZE
        last = start + btodb(size) - 1;
 #endif SECSIZE
 #else SECSIZE
        last = start + btodb(size) - 1;
 #endif SECSIZE
-       dp = BUFHASH(dev, blkno);
+       dp = BUFHASH(vp, blkno);
 loop:
        for (ep = dp->b_forw; ep != dp; ep = ep->b_forw) {
 loop:
        for (ep = dp->b_forw; ep != dp; ep = ep->b_forw) {
-               if (ep->b_dev != dev || (ep->b_flags&B_INVAL))
+               if (ep->b_vp != vp || (ep->b_flags & B_INVAL))
                        continue;
                /* look for overlap */
                if (ep->b_bcount == 0 || ep->b_blkno > last ||
                        continue;
                /* look for overlap */
                if (ep->b_bcount == 0 || ep->b_blkno > last ||
@@ -627,18 +645,18 @@ loop:
                if (ep->b_flags & B_DELWRI) {
                        splx(s);
                        notavail(ep);
                if (ep->b_flags & B_DELWRI) {
                        splx(s);
                        notavail(ep);
-                       bwrite(ep);
+                       if (error = bwrite(ep))
+                               allerrors = error;
                        goto loop;
                }
                splx(s);
        }
                        goto loop;
                }
                splx(s);
        }
+       return (allerrors);
 }
 
 /*
 }
 
 /*
- * Make sure all write-behind blocks
- * on dev (or NODEV for all)
- * are flushed out.
- * (from umount and update)
+ * Make sure all write-behind blocks associated
+ * with vp are flushed out (from sync).
  */
 bflush(dev)
        dev_t dev;
  */
 bflush(dev)
        dev_t dev;
@@ -656,7 +674,7 @@ loop:
                if (dev == NODEV || dev == bp->b_dev) {
                        bp->b_flags |= B_ASYNC;
                        notavail(bp);
                if (dev == NODEV || dev == bp->b_dev) {
                        bp->b_flags |= B_ASYNC;
                        notavail(bp);
-                       bwrite(bp);
+                       (void) bwrite(bp);
                        splx(s);
                        goto loop;
                }
                        splx(s);
                        goto loop;
                }
@@ -664,20 +682,39 @@ loop:
        splx(s);
 }
 
        splx(s);
 }
 
+#ifdef unused
 /*
 /*
- * Pick up the device's error number and pass it to the user;
- * if there is an error but the number is 0 set a generalized code.
+ * Invalidate blocks associated with vp which are on the freelist.
+ * Make sure all write-behind blocks associated with vp are flushed out.
  */
  */
-geterror(bp)
-       register struct buf *bp;
+binvalfree(vp)
+       struct vnode *vp;
 {
 {
-       int error = 0;
+       register struct buf *bp;
+       register struct buf *flist;
+       int s;
 
 
-       if (bp->b_flags&B_ERROR)
-               if ((error = bp->b_error)==0)
-                       return (EIO);
-       return (error);
+loop:
+       s = splbio();
+       for (flist = bfreelist; flist < &bfreelist[BQ_EMPTY]; flist++)
+       for (bp = flist->av_forw; bp != flist; bp = bp->av_forw) {
+               if (vp == (struct vnode *) 0 || vp == bp->b_vp) {
+                       if (bp->b_flags & B_DELWRI) {
+                               bp->b_flags |= B_ASYNC;
+                               notavail(bp);
+                               (void) splx(s);
+                               (void) bwrite(bp);
+                       } else {
+                               bp->b_flags |= B_INVAL;
+                               brelvp(bp);
+                               (void) splx(s);
+                       }
+                       goto loop;
+               }
+       }
+       (void) splx(s);
 }
 }
+#endif /* unused */
 
 /*
  * Invalidate in core blocks belonging to closed or umounted filesystem
 
 /*
  * Invalidate in core blocks belonging to closed or umounted filesystem
@@ -697,8 +734,24 @@ binval(dev)
        register struct bufhd *hp;
 #define dp ((struct buf *)hp)
 
        register struct bufhd *hp;
 #define dp ((struct buf *)hp)
 
+loop:
        for (hp = bufhash; hp < &bufhash[BUFHSZ]; hp++)
                for (bp = dp->b_forw; bp != dp; bp = bp->b_forw)
        for (hp = bufhash; hp < &bufhash[BUFHSZ]; hp++)
                for (bp = dp->b_forw; bp != dp; bp = bp->b_forw)
-                       if (bp->b_dev == dev)
+                       if (bp->b_dev == dev && (bp->b_flags & B_INVAL) == 0) {
                                bp->b_flags |= B_INVAL;
                                bp->b_flags |= B_INVAL;
+                               brelvp(bp);
+                               goto loop;
+                       }
+}
+
+brelvp(bp)
+       struct buf *bp;
+{
+       struct vnode *vp;
+
+       if (bp->b_vp == (struct vnode *) 0)
+               return;
+       vp = bp->b_vp;
+       bp->b_vp = (struct vnode *) 0;
+       vrele(vp);
 }
 }
index c6ad41c..3dbf8f9 100644 (file)
@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright (c) 1982, 1986 Regents of the University of California.
+ * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms are permitted
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms are permitted
  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  *
  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  *
- *     @(#)ffs_alloc.c 7.8 (Berkeley) %G%
+ *     @(#)ffs_alloc.c 7.9 (Berkeley) %G%
  */
 
 #include "param.h"
 #include "systm.h"
 #include "mount.h"
  */
 
 #include "param.h"
 #include "systm.h"
 #include "mount.h"
-#include "fs.h"
 #include "buf.h"
 #include "buf.h"
-#include "inode.h"
-#include "dir.h"
 #include "user.h"
 #include "user.h"
-#include "quota.h"
+#include "vnode.h"
 #include "kernel.h"
 #include "syslog.h"
 #include "cmap.h"
 #include "kernel.h"
 #include "syslog.h"
 #include "cmap.h"
+#include "../ufs/quota.h"
+#include "../ufs/inode.h"
+#include "../ufs/fs.h"
 
 extern u_long          hashalloc();
 extern ino_t           ialloccg();
 
 extern u_long          hashalloc();
 extern ino_t           ialloccg();
@@ -59,17 +59,19 @@ extern unsigned char        *fragtbl[];
  *   2) quadradically rehash into other cylinder groups, until an
  *      available block is located.
  */
  *   2) quadradically rehash into other cylinder groups, until an
  *      available block is located.
  */
-struct buf *
-alloc(ip, bpref, size)
+alloc(ip, bpref, size, bpp, flags)
        register struct inode *ip;
        daddr_t bpref;
        int size;
        register struct inode *ip;
        daddr_t bpref;
        int size;
+       struct buf **bpp;
+       int flags;
 {
        daddr_t bno;
        register struct fs *fs;
        register struct buf *bp;
 {
        daddr_t bno;
        register struct fs *fs;
        register struct buf *bp;
-       int cg;
+       int cg, error;
        
        
+       *bpp = 0;
        fs = ip->i_fs;
        if ((unsigned)size > fs->fs_bsize || fragoff(fs, size) != 0) {
                printf("dev = 0x%x, bsize = %d, size = %d, fs = %s\n",
        fs = ip->i_fs;
        if ((unsigned)size > fs->fs_bsize || fragoff(fs, size) != 0) {
                printf("dev = 0x%x, bsize = %d, size = %d, fs = %s\n",
@@ -81,9 +83,8 @@ alloc(ip, bpref, size)
        if (u.u_uid != 0 && freespace(fs, fs->fs_minfree) <= 0)
                goto nospace;
 #ifdef QUOTA
        if (u.u_uid != 0 && freespace(fs, fs->fs_minfree) <= 0)
                goto nospace;
 #ifdef QUOTA
-       u.u_error = chkdq(ip, (long)btodb(size), 0);
-       if (u.u_error)
-               return (NULL);
+       if (error = chkdq(ip, (long)btodb(size), 0))
+               return (error);
 #endif
        if (bpref >= fs->fs_size)
                bpref = 0;
 #endif
        if (bpref >= fs->fs_size)
                bpref = 0;
@@ -100,15 +101,15 @@ alloc(ip, bpref, size)
 #ifdef SECSIZE
        bp = getblk(ip->i_dev, fsbtodb(fs, bno), size, fs->fs_dbsize);
 #else SECSIZE
 #ifdef SECSIZE
        bp = getblk(ip->i_dev, fsbtodb(fs, bno), size, fs->fs_dbsize);
 #else SECSIZE
-       bp = getblk(ip->i_dev, fsbtodb(fs, bno), size);
-#endif SECSIZE
-       clrbuf(bp);
-       return (bp);
+       bp = getblk(ip->i_devvp, fsbtodb(fs, bno), size);
+       if (flags & B_CLRBUF)
+               clrbuf(bp);
+       *bpp = bp;
+       return (0);
 nospace:
        fserr(fs, "file system full");
        uprintf("\n%s: write failed, file system is full\n", fs->fs_fsmnt);
 nospace:
        fserr(fs, "file system full");
        uprintf("\n%s: write failed, file system is full\n", fs->fs_fsmnt);
-       u.u_error = ENOSPC;
-       return (NULL);
+       return (ENOSPC);
 }
 
 /*
 }
 
 /*
@@ -119,18 +120,19 @@ nospace:
  * the original block. Failing that, the regular block allocator is
  * invoked to get an appropriate block.
  */
  * the original block. Failing that, the regular block allocator is
  * invoked to get an appropriate block.
  */
-struct buf *
-realloccg(ip, bprev, bpref, osize, nsize)
+realloccg(ip, bprev, bpref, osize, nsize, bpp)
        register struct inode *ip;
        daddr_t bprev, bpref;
        int osize, nsize;
        register struct inode *ip;
        daddr_t bprev, bpref;
        int osize, nsize;
+       struct buf **bpp;
 {
        register struct fs *fs;
 {
        register struct fs *fs;
-       register struct buf *bp, *obp;
+       struct buf *bp, *obp;
        int cg, request;
        daddr_t bno, bn;
        int cg, request;
        daddr_t bno, bn;
-       int i, count;
+       int i, error, count;
        
        
+       *bpp = 0;
        fs = ip->i_fs;
        if ((unsigned)osize > fs->fs_bsize || fragoff(fs, osize) != 0 ||
            (unsigned)nsize > fs->fs_bsize || fragoff(fs, nsize) != 0) {
        fs = ip->i_fs;
        if ((unsigned)osize > fs->fs_bsize || fragoff(fs, osize) != 0 ||
            (unsigned)nsize > fs->fs_bsize || fragoff(fs, nsize) != 0) {
@@ -146,9 +148,8 @@ realloccg(ip, bprev, bpref, osize, nsize)
                panic("realloccg: bad bprev");
        }
 #ifdef QUOTA
                panic("realloccg: bad bprev");
        }
 #ifdef QUOTA
-       u.u_error = chkdq(ip, (long)btodb(nsize - osize), 0);
-       if (u.u_error)
-               return (NULL);
+       if (error = chkdq(ip, (long)btodb(nsize - osize), 0))
+               return (error);
 #endif
        cg = dtog(fs, bprev);
        bno = fragextend(ip, cg, (long)bprev, osize, nsize);
 #endif
        cg = dtog(fs, bprev);
        bno = fragextend(ip, cg, (long)bprev, osize, nsize);
@@ -158,18 +159,19 @@ realloccg(ip, bprev, bpref, osize, nsize)
                        bp = bread(ip->i_dev, fsbtodb(fs, bno), osize,
                            fs->fs_dbsize);
 #else SECSIZE
                        bp = bread(ip->i_dev, fsbtodb(fs, bno), osize,
                            fs->fs_dbsize);
 #else SECSIZE
-                       bp = bread(ip->i_dev, fsbtodb(fs, bno), osize);
-#endif SECSIZE
-                       if (bp->b_flags & B_ERROR) {
+                       error = bread(ip->i_devvp, fsbtodb(fs, bno),
+                               osize, &bp);
+                       if (error) {
                                brelse(bp);
                                brelse(bp);
-                               return (NULL);
+                               return (error);
                        }
                } while (brealloc(bp, nsize) == 0);
                bp->b_flags |= B_DONE;
                bzero(bp->b_un.b_addr + osize, (unsigned)nsize - osize);
                ip->i_blocks += btodb(nsize - osize);
                ip->i_flag |= IUPD|ICHG;
                        }
                } while (brealloc(bp, nsize) == 0);
                bp->b_flags |= B_DONE;
                bzero(bp->b_un.b_addr + osize, (unsigned)nsize - osize);
                ip->i_blocks += btodb(nsize - osize);
                ip->i_flag |= IUPD|ICHG;
-               return (bp);
+               *bpp = bp;
+               return (0);
        }
        if (bpref >= fs->fs_size)
                bpref = 0;
        }
        if (bpref >= fs->fs_size)
                bpref = 0;
@@ -223,17 +225,16 @@ realloccg(ip, bprev, bpref, osize, nsize)
                obp = bread(ip->i_dev, fsbtodb(fs, bprev), osize,
                    fs->fs_dbsize);
 #else SECSIZE
                obp = bread(ip->i_dev, fsbtodb(fs, bprev), osize,
                    fs->fs_dbsize);
 #else SECSIZE
-               obp = bread(ip->i_dev, fsbtodb(fs, bprev), osize);
-#endif SECSIZE
-               if (obp->b_flags & B_ERROR) {
+               error = bread(ip->i_devvp, fsbtodb(fs, bprev), osize, &obp);
+               if (error) {
                        brelse(obp);
                        brelse(obp);
-                       return (NULL);
+                       return (error);
                }
                bn = fsbtodb(fs, bno);
 #ifdef SECSIZE
                bp = getblk(ip->i_dev, bn, nsize, fs->fs_dbsize);
 #else SECSIZE
                }
                bn = fsbtodb(fs, bno);
 #ifdef SECSIZE
                bp = getblk(ip->i_dev, bn, nsize, fs->fs_dbsize);
 #else SECSIZE
-               bp = getblk(ip->i_dev, bn, nsize);
+               bp = getblk(ip->i_devvp, bn, nsize);
 #endif SECSIZE
                bcopy(obp->b_un.b_addr, bp->b_un.b_addr, (u_int)osize);
                count = howmany(osize, CLBYTES);
 #endif SECSIZE
                bcopy(obp->b_un.b_addr, bp->b_un.b_addr, (u_int)osize);
                count = howmany(osize, CLBYTES);
@@ -255,7 +256,8 @@ realloccg(ip, bprev, bpref, osize, nsize)
                                (off_t)(request - nsize));
                ip->i_blocks += btodb(nsize - osize);
                ip->i_flag |= IUPD|ICHG;
                                (off_t)(request - nsize));
                ip->i_blocks += btodb(nsize - osize);
                ip->i_flag |= IUPD|ICHG;
-               return (bp);
+               *bpp = bp;
+               return (0);
        }
 nospace:
        /*
        }
 nospace:
        /*
@@ -263,8 +265,7 @@ nospace:
         */
        fserr(fs, "file system full");
        uprintf("\n%s: write failed, file system is full\n", fs->fs_fsmnt);
         */
        fserr(fs, "file system full");
        uprintf("\n%s: write failed, file system is full\n", fs->fs_fsmnt);
-       u.u_error = ENOSPC;
-       return (NULL);
+       return (ENOSPC);
 }
 
 /*
 }
 
 /*
@@ -282,24 +283,24 @@ nospace:
  *   2) quadradically rehash into other cylinder groups, until an
  *      available inode is located.
  */
  *   2) quadradically rehash into other cylinder groups, until an
  *      available inode is located.
  */
-struct inode *
-ialloc(pip, ipref, mode)
+ialloc(pip, ipref, mode, ipp)
        register struct inode *pip;
        ino_t ipref;
        int mode;
        register struct inode *pip;
        ino_t ipref;
        int mode;
+       struct inode **ipp;
 {
        ino_t ino;
        register struct fs *fs;
        register struct inode *ip;
 {
        ino_t ino;
        register struct fs *fs;
        register struct inode *ip;
-       int cg;
+       int cg, error;
        
        
+       *ipp = 0;
        fs = pip->i_fs;
        if (fs->fs_cstotal.cs_nifree == 0)
                goto noinodes;
 #ifdef QUOTA
        fs = pip->i_fs;
        if (fs->fs_cstotal.cs_nifree == 0)
                goto noinodes;
 #ifdef QUOTA
-       u.u_error = chkiq(pip->i_dev, (struct inode *)NULL, u.u_uid, 0);
-       if (u.u_error)
-               return (NULL);
+       if (error = chkiq(pip->i_dev, (struct inode *)NULL, u.u_uid, 0))
+               return (error);
 #endif
        if (ipref >= fs->fs_ncg * fs->fs_ipg)
                ipref = 0;
 #endif
        if (ipref >= fs->fs_ncg * fs->fs_ipg)
                ipref = 0;
@@ -307,10 +308,11 @@ ialloc(pip, ipref, mode)
        ino = (ino_t)hashalloc(pip, cg, (long)ipref, mode, ialloccg);
        if (ino == 0)
                goto noinodes;
        ino = (ino_t)hashalloc(pip, cg, (long)ipref, mode, ialloccg);
        if (ino == 0)
                goto noinodes;
-       ip = iget(pip->i_dev, pip->i_fs, ino);
-       if (ip == NULL) {
+       error = iget(pip, ino, ipp);
+       ip = *ipp;
+       if (error) {
                ifree(pip, ino, 0);
                ifree(pip, ino, 0);
-               return (NULL);
+               return (error);
        }
        if (ip->i_mode) {
                printf("mode = 0%o, inum = %d, fs = %s\n",
        }
        if (ip->i_mode) {
                printf("mode = 0%o, inum = %d, fs = %s\n",
@@ -322,12 +324,11 @@ ialloc(pip, ipref, mode)
                    fs->fs_fsmnt, ino, ip->i_blocks);
                ip->i_blocks = 0;
        }
                    fs->fs_fsmnt, ino, ip->i_blocks);
                ip->i_blocks = 0;
        }
-       return (ip);
+       return (0);
 noinodes:
        fserr(fs, "out of inodes");
        uprintf("\n%s: create/symlink failed, no inodes free\n", fs->fs_fsmnt);
 noinodes:
        fserr(fs, "out of inodes");
        uprintf("\n%s: create/symlink failed, no inodes free\n", fs->fs_fsmnt);
-       u.u_error = ENOSPC;
-       return (NULL);
+       return (ENOSPC);
 }
 
 /*
 }
 
 /*
@@ -514,11 +515,11 @@ fragextend(ip, cg, bprev, osize, nsize)
        int osize, nsize;
 {
        register struct fs *fs;
        int osize, nsize;
 {
        register struct fs *fs;
-       register struct buf *bp;
        register struct cg *cgp;
        register struct cg *cgp;
+       struct buf *bp;
        long bno;
        int frags, bbase;
        long bno;
        int frags, bbase;
-       int i;
+       int i, error;
 
        fs = ip->i_fs;
        if (fs->fs_cs(fs, cg).cs_nffree < numfrags(fs, nsize - osize))
 
        fs = ip->i_fs;
        if (fs->fs_cs(fs, cg).cs_nffree < numfrags(fs, nsize - osize))
@@ -533,10 +534,15 @@ fragextend(ip, cg, bprev, osize, nsize)
        bp = bread(ip->i_dev, fsbtodb(fs, cgtod(fs, cg)), (int)fs->fs_cgsize,
            fs->fs_dbsize);
 #else SECSIZE
        bp = bread(ip->i_dev, fsbtodb(fs, cgtod(fs, cg)), (int)fs->fs_cgsize,
            fs->fs_dbsize);
 #else SECSIZE
-       bp = bread(ip->i_dev, fsbtodb(fs, cgtod(fs, cg)), (int)fs->fs_cgsize);
+       error = bread(ip->i_devvp, fsbtodb(fs, cgtod(fs, cg)),
+               (int)fs->fs_cgsize, &bp);
+       if (error) {
+               brelse(bp);
+               return (NULL);
+       }
 #endif SECSIZE
        cgp = bp->b_un.b_cg;
 #endif SECSIZE
        cgp = bp->b_un.b_cg;
-       if (bp->b_flags & B_ERROR || !cg_chkmagic(cgp)) {
+       if (!cg_chkmagic(cgp)) {
                brelse(bp);
                return (NULL);
        }
                brelse(bp);
                return (NULL);
        }
@@ -584,11 +590,10 @@ alloccg(ip, cg, bpref, size)
        int size;
 {
        register struct fs *fs;
        int size;
 {
        register struct fs *fs;
-       register struct buf *bp;
        register struct cg *cgp;
        register struct cg *cgp;
-       int bno, frags;
-       int allocsiz;
+       struct buf *bp;
        register int i;
        register int i;
+       int error, bno, frags, allocsiz;
 
        fs = ip->i_fs;
        if (fs->fs_cs(fs, cg).cs_nbfree == 0 && size == fs->fs_bsize)
 
        fs = ip->i_fs;
        if (fs->fs_cs(fs, cg).cs_nbfree == 0 && size == fs->fs_bsize)
@@ -597,10 +602,15 @@ alloccg(ip, cg, bpref, size)
        bp = bread(ip->i_dev, fsbtodb(fs, cgtod(fs, cg)), (int)fs->fs_cgsize,
            fs->fs_dbsize);
 #else SECSIZE
        bp = bread(ip->i_dev, fsbtodb(fs, cgtod(fs, cg)), (int)fs->fs_cgsize,
            fs->fs_dbsize);
 #else SECSIZE
-       bp = bread(ip->i_dev, fsbtodb(fs, cgtod(fs, cg)), (int)fs->fs_cgsize);
+       error = bread(ip->i_devvp, fsbtodb(fs, cgtod(fs, cg)),
+               (int)fs->fs_cgsize, &bp);
+       if (error) {
+               brelse(bp);
+               return (NULL);
+       }
 #endif SECSIZE
        cgp = bp->b_un.b_cg;
 #endif SECSIZE
        cgp = bp->b_un.b_cg;
-       if (bp->b_flags & B_ERROR || !cg_chkmagic(cgp) ||
+       if (!cg_chkmagic(cgp) ||
            (cgp->cg_cs.cs_nbfree == 0 && size == fs->fs_bsize)) {
                brelse(bp);
                return (NULL);
            (cgp->cg_cs.cs_nbfree == 0 && size == fs->fs_bsize)) {
                brelse(bp);
                return (NULL);
@@ -789,7 +799,7 @@ ialloccg(ip, cg, ipref, mode)
        register struct fs *fs;
        register struct cg *cgp;
        struct buf *bp;
        register struct fs *fs;
        register struct cg *cgp;
        struct buf *bp;
-       int start, len, loc, map, i;
+       int error, start, len, loc, map, i;
 
        fs = ip->i_fs;
        if (fs->fs_cs(fs, cg).cs_nifree == 0)
 
        fs = ip->i_fs;
        if (fs->fs_cs(fs, cg).cs_nifree == 0)
@@ -798,11 +808,15 @@ ialloccg(ip, cg, ipref, mode)
        bp = bread(ip->i_dev, fsbtodb(fs, cgtod(fs, cg)), (int)fs->fs_cgsize,
            fs->fs_dbsize);
 #else SECSIZE
        bp = bread(ip->i_dev, fsbtodb(fs, cgtod(fs, cg)), (int)fs->fs_cgsize,
            fs->fs_dbsize);
 #else SECSIZE
-       bp = bread(ip->i_dev, fsbtodb(fs, cgtod(fs, cg)), (int)fs->fs_cgsize);
+       error = bread(ip->i_devvp, fsbtodb(fs, cgtod(fs, cg)),
+               (int)fs->fs_cgsize, &bp);
+       if (error) {
+               brelse(bp);
+               return (NULL);
+       }
 #endif SECSIZE
        cgp = bp->b_un.b_cg;
 #endif SECSIZE
        cgp = bp->b_un.b_cg;
-       if (bp->b_flags & B_ERROR || !cg_chkmagic(cgp) ||
-           cgp->cg_cs.cs_nifree == 0) {
+       if (!cg_chkmagic(cgp) || cgp->cg_cs.cs_nifree == 0) {
                brelse(bp);
                return (NULL);
        }
                brelse(bp);
                return (NULL);
        }
@@ -867,8 +881,8 @@ blkfree(ip, bno, size)
 {
        register struct fs *fs;
        register struct cg *cgp;
 {
        register struct fs *fs;
        register struct cg *cgp;
-       register struct buf *bp;
-       int cg, blk, frags, bbase;
+       struct buf *bp;
+       int error, cg, blk, frags, bbase;
        register int i;
 
        fs = ip->i_fs;
        register int i;
 
        fs = ip->i_fs;
@@ -886,10 +900,15 @@ blkfree(ip, bno, size)
        bp = bread(ip->i_dev, fsbtodb(fs, cgtod(fs, cg)), (int)fs->fs_cgsize,
            fs->fs_dbsize);
 #else SECSIZE
        bp = bread(ip->i_dev, fsbtodb(fs, cgtod(fs, cg)), (int)fs->fs_cgsize,
            fs->fs_dbsize);
 #else SECSIZE
-       bp = bread(ip->i_dev, fsbtodb(fs, cgtod(fs, cg)), (int)fs->fs_cgsize);
+       error = bread(ip->i_devvp, fsbtodb(fs, cgtod(fs, cg)),
+               (int)fs->fs_cgsize, &bp);
+       if (error) {
+               brelse(bp);
+               return;
+       }
 #endif SECSIZE
        cgp = bp->b_un.b_cg;
 #endif SECSIZE
        cgp = bp->b_un.b_cg;
-       if (bp->b_flags & B_ERROR || !cg_chkmagic(cgp)) {
+       if (!cg_chkmagic(cgp)) {
                brelse(bp);
                return;
        }
                brelse(bp);
                return;
        }
@@ -967,8 +986,8 @@ ifree(ip, ino, mode)
 {
        register struct fs *fs;
        register struct cg *cgp;
 {
        register struct fs *fs;
        register struct cg *cgp;
-       register struct buf *bp;
-       int cg;
+       struct buf *bp;
+       int error, cg;
 
        fs = ip->i_fs;
        if ((unsigned)ino >= fs->fs_ipg*fs->fs_ncg) {
 
        fs = ip->i_fs;
        if ((unsigned)ino >= fs->fs_ipg*fs->fs_ncg) {
@@ -981,10 +1000,15 @@ ifree(ip, ino, mode)
        bp = bread(ip->i_dev, fsbtodb(fs, cgtod(fs, cg)), (int)fs->fs_cgsize,
            fs->fs_dbsize);
 #else SECSIZE
        bp = bread(ip->i_dev, fsbtodb(fs, cgtod(fs, cg)), (int)fs->fs_cgsize,
            fs->fs_dbsize);
 #else SECSIZE
-       bp = bread(ip->i_dev, fsbtodb(fs, cgtod(fs, cg)), (int)fs->fs_cgsize);
+       error = bread(ip->i_devvp, fsbtodb(fs, cgtod(fs, cg)),
+               (int)fs->fs_cgsize, &bp);
+       if (error) {
+               brelse(bp);
+               return;
+       }
 #endif SECSIZE
        cgp = bp->b_un.b_cg;
 #endif SECSIZE
        cgp = bp->b_un.b_cg;
-       if (bp->b_flags & B_ERROR || !cg_chkmagic(cgp)) {
+       if (!cg_chkmagic(cgp)) {
                brelse(bp);
                return;
        }
                brelse(bp);
                return;
        }
index b481675..beec1b0 100644 (file)
@@ -1,19 +1,31 @@
 /*
 /*
- * Copyright (c) 1982, 1986 Regents of the University of California.
- * All rights reserved.  The Berkeley software License Agreement
- * specifies the terms and conditions for redistribution.
+ * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
+ * All rights reserved.
  *
  *
- *     @(#)ffs_balloc.c        7.2 (Berkeley) %G%
+ * 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.
+ *
+ *     @(#)ffs_balloc.c        7.3 (Berkeley) %G%
  */
 
 #include "param.h"
 #include "systm.h"
  */
 
 #include "param.h"
 #include "systm.h"
-#include "inode.h"
-#include "dir.h"
 #include "user.h"
 #include "buf.h"
 #include "proc.h"
 #include "user.h"
 #include "buf.h"
 #include "proc.h"
-#include "fs.h"
+#include "file.h"
+#include "vnode.h"
+#include "../ufs/inode.h"
+#include "../ufs/fs.h"
 
 /*
  * Bmap defines the structure of file system storage
 
 /*
  * Bmap defines the structure of file system storage
  * block number of the next block of the file in rablock
  * for use in read-ahead.
  */
  * block number of the next block of the file in rablock
  * for use in read-ahead.
  */
-/*VARARGS3*/
-daddr_t
-bmap(ip, bn, rwflg, size)
+bmap(ip, bn, bnp, rablockp, rasizep)
        register struct inode *ip;
        register struct inode *ip;
-       daddr_t bn;
-       int rwflg;
-       int size;       /* supplied only when rwflg == B_WRITE */
+       register daddr_t bn;
+       daddr_t *bnp;
+       daddr_t *rablockp;
+       int *rasizep;
 {
 {
-       register int i;
-       int osize, nsize;
-       struct buf *bp, *nbp;
-       struct fs *fs;
-       int j, sh;
-       daddr_t nb, lbn, *bap, pref, blkpref();
+       register struct fs *fs;
+       register daddr_t nb;
+       struct buf *bp;
+       daddr_t *bap;
+       int i, j, sh;
+       int error;
+
+       if (bn < 0)
+               return (EFBIG);
+       fs = ip->i_fs;
+
+       /*
+        * The first NDADDR blocks are direct blocks
+        */
+       if (bn < NDADDR) {
+               nb = ip->i_db[bn];
+               if (nb == 0) {
+                       *bnp = (daddr_t)-1;
+                       return (0);
+               }
+               if (rablockp && rasizep) {
+                       if (bn < NDADDR - 1) {
+                               *rablockp = fsbtodb(fs, ip->i_db[bn + 1]);
+                               *rasizep = blksize(fs, ip, bn + 1);
+                       } else {
+                               *rablockp = 0;
+                               *rasizep = 0;
+                       }
+               }
+               *bnp = fsbtodb(fs, nb);
+               return (0);
+       }
+
+       /*
+        * Determine how many levels of indirection.
+        */
+       sh = 1;
+       bn -= NDADDR;
+       for (j = NIADDR; j > 0; j--) {
+               sh *= NINDIR(fs);
+               if (bn < sh)
+                       break;
+               bn -= sh;
+       }
+       if (j == 0)
+               return (EFBIG);
 
 
-       if (bn < 0) {
-               u.u_error = EFBIG;
-               return ((daddr_t)0);
+       /*
+        * fetch the first indirect block
+        */
+       nb = ip->i_ib[NIADDR - j];
+       if (nb == 0) {
+               *bnp = (daddr_t)-1;
+               return (0);
        }
        }
+
+       /*
+        * fetch through the indirect blocks
+        */
+       for (; j <= NIADDR; j++) {
+               if (error = bread(ip->i_devvp, fsbtodb(fs, nb),
+                   (int)fs->fs_bsize, &bp)) {
+                       brelse(bp);
+                       return (error);
+               }
+               bap = bp->b_un.b_daddr;
+               sh /= NINDIR(fs);
+               i = (bn / sh) % NINDIR(fs);
+               nb = bap[i];
+               if (nb == 0) {
+                       *bnp = (daddr_t)-1;
+                       brelse(bp);
+                       return (0);
+               }
+       }
+
+       /*
+        * calculate read-ahead.
+        */
+       if (rablockp && rasizep) {
+               if (i < NINDIR(fs) - 1) {
+                       *rablockp = fsbtodb(fs, bap[i + 1]);
+                       *rasizep = fs->fs_bsize;
+               } else {
+                       *rablockp = 0;
+                       *rasizep = 0;
+               }
+       }
+       *bnp = fsbtodb(fs, nb);
+       brelse(bp);
+       return (0);
+}
+
+/*
+ * Balloc defines the structure of file system storage
+ * by returning the physical block number on a device given the
+ * inode and the logical block number in a file.
+ * When unallocated entries are found, new physical blocks
+ * are allocated.
+ */
+balloc(ip, bn, size, bnp, flags)
+       register struct inode *ip;
+       register daddr_t bn;
+       int size;
+       daddr_t *bnp;
+       int flags;
+{
+       register struct fs *fs;
+       register daddr_t nb;
+       struct buf *bp, *nbp;
+       int osize, nsize, i, j, sh, error;
+       daddr_t lbn, *bap, pref, blkpref();
+
+       if (bn < 0)
+               return (EFBIG);
        fs = ip->i_fs;
        fs = ip->i_fs;
-       rablock = 0;
-       rasize = 0;             /* conservative */
 
        /*
         * If the next write will extend the file into a new block,
 
        /*
         * If the next write will extend the file into a new block,
@@ -52,14 +165,16 @@ bmap(ip, bn, rwflg, size)
         * this fragment has to be extended to be a full block.
         */
        nb = lblkno(fs, ip->i_size);
         * this fragment has to be extended to be a full block.
         */
        nb = lblkno(fs, ip->i_size);
-       if (rwflg == B_WRITE && nb < NDADDR && nb < bn) {
+       if (nb < NDADDR && nb < bn) {
                osize = blksize(fs, ip, nb);
                if (osize < fs->fs_bsize && osize > 0) {
                osize = blksize(fs, ip, nb);
                if (osize < fs->fs_bsize && osize > 0) {
-                       bp = realloccg(ip, ip->i_db[nb],
+                       error = realloccg(ip, ip->i_db[nb],
                                blkpref(ip, nb, (int)nb, &ip->i_db[0]),
                                blkpref(ip, nb, (int)nb, &ip->i_db[0]),
-                               osize, (int)fs->fs_bsize);
-                       if (bp == NULL)
-                               return ((daddr_t)-1);
+                               osize, (int)fs->fs_bsize, &bp);
+                       if (error) {
+                               *bnp = (daddr_t)-1;
+                               return (error);
+                       }
                        ip->i_size = (nb + 1) * fs->fs_bsize;
                        ip->i_db[nb] = dbtofsb(fs, bp->b_blkno);
                        ip->i_flag |= IUPD|ICHG;
                        ip->i_size = (nb + 1) * fs->fs_bsize;
                        ip->i_db[nb] = dbtofsb(fs, bp->b_blkno);
                        ip->i_flag |= IUPD|ICHG;
@@ -71,11 +186,6 @@ bmap(ip, bn, rwflg, size)
         */
        if (bn < NDADDR) {
                nb = ip->i_db[bn];
         */
        if (bn < NDADDR) {
                nb = ip->i_db[bn];
-               if (rwflg == B_READ) {
-                       if (nb == 0)
-                               return ((daddr_t)-1);
-                       goto gotit;
-               }
                if (nb == 0 || ip->i_size < (bn + 1) * fs->fs_bsize) {
                        if (nb != 0) {
                                /* consider need to reallocate a frag */
                if (nb == 0 || ip->i_size < (bn + 1) * fs->fs_bsize) {
                        if (nb != 0) {
                                /* consider need to reallocate a frag */
@@ -83,39 +193,41 @@ bmap(ip, bn, rwflg, size)
                                nsize = fragroundup(fs, size);
                                if (nsize <= osize)
                                        goto gotit;
                                nsize = fragroundup(fs, size);
                                if (nsize <= osize)
                                        goto gotit;
-                               bp = realloccg(ip, nb,
+                               error = realloccg(ip, nb,
                                        blkpref(ip, bn, (int)bn, &ip->i_db[0]),
                                        blkpref(ip, bn, (int)bn, &ip->i_db[0]),
-                                       osize, nsize);
+                                       osize, nsize, &bp);
                        } else {
                                if (ip->i_size < (bn + 1) * fs->fs_bsize)
                                        nsize = fragroundup(fs, size);
                                else
                                        nsize = fs->fs_bsize;
                        } else {
                                if (ip->i_size < (bn + 1) * fs->fs_bsize)
                                        nsize = fragroundup(fs, size);
                                else
                                        nsize = fs->fs_bsize;
-                               bp = alloc(ip,
+                               error = alloc(ip,
                                        blkpref(ip, bn, (int)bn, &ip->i_db[0]),
                                        blkpref(ip, bn, (int)bn, &ip->i_db[0]),
-                                       nsize);
+                                       nsize, &bp, flags);
+                       }
+                       if (error) {
+                               *bnp = (daddr_t)-1;
+                               return (error);
                        }
                        }
-                       if (bp == NULL)
-                               return ((daddr_t)-1);
                        nb = dbtofsb(fs, bp->b_blkno);
                        nb = dbtofsb(fs, bp->b_blkno);
-                       if ((ip->i_mode&IFMT) == IFDIR)
+                       if ((ip->i_mode & IFMT) == IFDIR)
                                /*
                                 * Write directory blocks synchronously
                                 * so they never appear with garbage in
                                 * them on the disk.
                                /*
                                 * Write directory blocks synchronously
                                 * so they never appear with garbage in
                                 * them on the disk.
+                                * 
+                                * NB: Should free space and return error
+                                * if bwrite returns an error.
                                 */
                                 */
-                               bwrite(bp);
+                               error = bwrite(bp);
                        else
                                bdwrite(bp);
                        ip->i_db[bn] = nb;
                        ip->i_flag |= IUPD|ICHG;
                }
 gotit:
                        else
                                bdwrite(bp);
                        ip->i_db[bn] = nb;
                        ip->i_flag |= IUPD|ICHG;
                }
 gotit:
-               if (bn < NDADDR - 1) {
-                       rablock = fsbtodb(fs, ip->i_db[bn + 1]);
-                       rasize = blksize(fs, ip, bn + 1);
-               }
-               return (nb);
+               *bnp = fsbtodb(fs, nb);
+               return (0);
        }
 
        /*
        }
 
        /*
@@ -125,34 +237,35 @@ gotit:
        sh = 1;
        lbn = bn;
        bn -= NDADDR;
        sh = 1;
        lbn = bn;
        bn -= NDADDR;
-       for (j = NIADDR; j>0; j--) {
+       for (j = NIADDR; j > 0; j--) {
                sh *= NINDIR(fs);
                if (bn < sh)
                        break;
                bn -= sh;
        }
                sh *= NINDIR(fs);
                if (bn < sh)
                        break;
                bn -= sh;
        }
-       if (j == 0) {
-               u.u_error = EFBIG;
-               return ((daddr_t)0);
-       }
+       if (j == 0)
+               return (EFBIG);
 
        /*
         * fetch the first indirect block
         */
        nb = ip->i_ib[NIADDR - j];
        if (nb == 0) {
 
        /*
         * fetch the first indirect block
         */
        nb = ip->i_ib[NIADDR - j];
        if (nb == 0) {
-               if (rwflg == B_READ)
-                       return ((daddr_t)-1);
                pref = blkpref(ip, lbn, 0, (daddr_t *)0);
                pref = blkpref(ip, lbn, 0, (daddr_t *)0);
-               bp = alloc(ip, pref, (int)fs->fs_bsize);
-               if (bp == NULL)
-                       return ((daddr_t)-1);
+               error = alloc(ip, pref, (int)fs->fs_bsize, &bp, B_CLRBUF);
+               if (error) {
+                       *bnp = (daddr_t)-1;
+                       return (error);
+               }
                nb = dbtofsb(fs, bp->b_blkno);
                /*
                 * Write synchronously so that indirect blocks
                 * never point at garbage.
                nb = dbtofsb(fs, bp->b_blkno);
                /*
                 * Write synchronously so that indirect blocks
                 * never point at garbage.
+                * 
+                * NB: Should free space and return error
+                * if bwrite returns an error.
                 */
                 */
-               bwrite(bp);
+               error = bwrite(bp);
                ip->i_ib[NIADDR - j] = nb;
                ip->i_flag |= IUPD|ICHG;
        }
                ip->i_ib[NIADDR - j] = nb;
                ip->i_flag |= IUPD|ICHG;
        }
@@ -165,40 +278,40 @@ gotit:
                bp = bread(ip->i_dev, fsbtodb(fs, nb), (int)fs->fs_bsize,
                    fs->fs_dbsize);
 #else SECSIZE
                bp = bread(ip->i_dev, fsbtodb(fs, nb), (int)fs->fs_bsize,
                    fs->fs_dbsize);
 #else SECSIZE
-               bp = bread(ip->i_dev, fsbtodb(fs, nb), (int)fs->fs_bsize);
-#endif SECSIZE
-               if (bp->b_flags & B_ERROR) {
+               if (error = bread(ip->i_devvp, fsbtodb(fs, nb),
+                   (int)fs->fs_bsize, &bp)) {
                        brelse(bp);
                        brelse(bp);
-                       return ((daddr_t)0);
+                       return (error);
                }
                bap = bp->b_un.b_daddr;
                sh /= NINDIR(fs);
                i = (bn / sh) % NINDIR(fs);
                nb = bap[i];
                if (nb == 0) {
                }
                bap = bp->b_un.b_daddr;
                sh /= NINDIR(fs);
                i = (bn / sh) % NINDIR(fs);
                nb = bap[i];
                if (nb == 0) {
-                       if (rwflg==B_READ) {
-                               brelse(bp);
-                               return ((daddr_t)-1);
-                       }
                        if (pref == 0)
                                if (j < NIADDR)
                                        pref = blkpref(ip, lbn, 0,
                                                (daddr_t *)0);
                                else
                                        pref = blkpref(ip, lbn, i, &bap[0]);
                        if (pref == 0)
                                if (j < NIADDR)
                                        pref = blkpref(ip, lbn, 0,
                                                (daddr_t *)0);
                                else
                                        pref = blkpref(ip, lbn, i, &bap[0]);
-                       nbp = alloc(ip, pref, (int)fs->fs_bsize);
-                       if (nbp == NULL) {
+                       error = alloc(ip, pref, (int)fs->fs_bsize, &nbp,
+                               (j < NIADDR) ? B_CLRBUF : flags);
+                       if (error) {
                                brelse(bp);
                                brelse(bp);
-                               return ((daddr_t)-1);
+                               *bnp = (daddr_t)-1;
+                               return (error);
                        }
                        nb = dbtofsb(fs, nbp->b_blkno);
                        }
                        nb = dbtofsb(fs, nbp->b_blkno);
-                       if (j < NIADDR || (ip->i_mode&IFMT) == IFDIR)
+                       if (j < NIADDR || (ip->i_mode & IFMT) == IFDIR)
                                /*
                                 * Write synchronously so indirect blocks
                                 * never point at garbage and blocks
                                 * in directories never contain garbage.
                                /*
                                 * Write synchronously so indirect blocks
                                 * never point at garbage and blocks
                                 * in directories never contain garbage.
+                                * 
+                                * NB: Should free space and return error
+                                * if bwrite returns an error.
                                 */
                                 */
-                               bwrite(nbp);
+                               error = bwrite(nbp);
                        else
                                bdwrite(nbp);
                        bap[i] = nb;
                        else
                                bdwrite(nbp);
                        bap[i] = nb;
@@ -207,12 +320,6 @@ gotit:
                        brelse(bp);
        }
 
                        brelse(bp);
        }
 
-       /*
-        * calculate read-ahead.
-        */
-       if (i < NINDIR(fs) - 1) {
-               rablock = fsbtodb(fs, bap[i+1]);
-               rasize = fs->fs_bsize;
-       }
-       return (nb);
+       *bnp = fsbtodb(fs, nb);
+       return (0);
 }
 }
index a47728f..bae874a 100644 (file)
@@ -1,22 +1,35 @@
 /*
 /*
- * Copyright (c) 1982, 1986 Regents of the University of California.
- * All rights reserved.  The Berkeley software License Agreement
- * specifies the terms and conditions for redistribution.
+ * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
+ * All rights reserved.
  *
  *
- *     @(#)ffs_inode.c 7.5 (Berkeley) %G%
+ * 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 MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ *     @(#)ffs_inode.c 7.6 (Berkeley) %G%
  */
 
 #include "param.h"
 #include "systm.h"
 #include "mount.h"
  */
 
 #include "param.h"
 #include "systm.h"
 #include "mount.h"
-#include "dir.h"
 #include "user.h"
 #include "user.h"
-#include "inode.h"
-#include "fs.h"
+#include "file.h"
 #include "buf.h"
 #include "cmap.h"
 #include "buf.h"
 #include "cmap.h"
+#include "vnode.h"
+#include "../ufs/inode.h"
+#include "../ufs/fs.h"
+#include "../ufs/ufsmount.h"
 #ifdef QUOTA
 #ifdef QUOTA
-#include "quota.h"
+#include "../ufs/quota.h"
 #endif
 #include "kernel.h"
 #include "malloc.h"
 #endif
 #include "kernel.h"
 #include "malloc.h"
 #define        INOHASH(dev,ino)        (((unsigned)((dev)+(ino)))%INOHSZ)
 #endif
 
 #define        INOHASH(dev,ino)        (((unsigned)((dev)+(ino)))%INOHSZ)
 #endif
 
+#define INSFREE(ip) {\
+       if (ifreeh) { \
+               *ifreet = (ip); \
+               (ip)->i_freeb = ifreet; \
+       } else { \
+               ifreeh = (ip); \
+               (ip)->i_freeb = &ifreeh; \
+       } \
+       (ip)->i_freef = NULL; \
+       ifreet = &(ip)->i_freef; \
+}
+
 union ihead {                          /* inode LRU cache, Chris Maltby */
        union  ihead *ih_head[2];
        struct inode *ih_chain[2];
 } ihead[INOHSZ];
 
 union ihead {                          /* inode LRU cache, Chris Maltby */
        union  ihead *ih_head[2];
        struct inode *ih_chain[2];
 } ihead[INOHSZ];
 
-struct inode *ifreeh, **ifreet;
+struct inode *ifreeh, **ifreet, *bdevlisth;
 
 /*
  * Initialize hash links for inodes
 
 /*
  * Initialize hash links for inodes
@@ -54,10 +79,12 @@ ihinit()
        ip->i_freeb = &ifreeh;
        ip->i_forw = ip;
        ip->i_back = ip;
        ip->i_freeb = &ifreeh;
        ip->i_forw = ip;
        ip->i_back = ip;
+       ITOV(ip)->v_data = (qaddr_t)ip;
        for (i = ninode; --i > 0; ) {
                ++ip;
                ip->i_forw = ip;
                ip->i_back = ip;
        for (i = ninode; --i > 0; ) {
                ++ip;
                ip->i_forw = ip;
                ip->i_back = ip;
+               ITOV(ip)->v_data = (qaddr_t)ip;
                *ifreet = ip;
                ip->i_freeb = ifreet;
                ifreet = &ip->i_freef;
                *ifreet = ip;
                ip->i_freeb = ifreet;
                ifreet = &ip->i_freef;
@@ -65,55 +92,31 @@ ihinit()
        ip->i_freef = NULL;
 }
 
        ip->i_freef = NULL;
 }
 
-#ifdef notdef
 /*
 /*
- * Find an inode if it is incore.
- * This is the equivalent, for inodes,
- * of ``incore'' in bio.c or ``pfind'' in subr.c.
- */
-struct inode *
-ifind(dev, ino)
-       dev_t dev;
-       ino_t ino;
-{
-       register struct inode *ip;
-       register union  ihead *ih;
-
-       ih = &ihead[INOHASH(dev, ino)];
-       for (ip = ih->ih_chain[0]; ip != (struct inode *)ih; ip = ip->i_forw)
-               if (ino==ip->i_number && dev==ip->i_dev)
-                       return (ip);
-       return ((struct inode *)0);
-}
-#endif notdef
-
-/*
- * Look up an inode by device,inumber.
+ * Look up an vnode/inode by device,inumber.
  * If it is in core (in the inode structure),
  * honor the locking protocol.
  * If it is not in core, read it in from the
  * specified device.
  * If it is in core (in the inode structure),
  * honor the locking protocol.
  * If it is not in core, read it in from the
  * specified device.
- * If the inode is mounted on, perform
- * the indicated indirection.
+ * Callers must check for mount points!!
  * In all cases, a pointer to a locked
  * inode structure is returned.
  * In all cases, a pointer to a locked
  * inode structure is returned.
- *
- * panic: no imt -- if the mounted file
- *     system is not in the mount table.
- *     "cannot happen"
  */
  */
-struct inode *
-iget(dev, fs, ino)
-       dev_t dev;
-       register struct fs *fs;
+iget(xp, ino, ipp)
+       struct inode *xp;
        ino_t ino;
        ino_t ino;
+       struct inode **ipp;
 {
 {
-       register struct inode *ip;
-       register union  ihead *ih;
-       register struct mount *mp;
-       register struct buf *bp;
-       register struct dinode *dp;
-       register struct inode *iq;
+       dev_t dev = xp->i_dev;
+       struct mount *mntp = ITOV(xp)->v_mount;
+       register struct fs *fs = VFSTOUFS(mntp)->um_fs;
+       register struct inode *ip, *iq;
+       register struct vnode *vp;
+       struct inode *nip;
+       struct buf *bp;
+       struct dinode tdip, *dp;
+       union  ihead *ih;
+       int error;
 
 loop:
        ih = &ihead[INOHASH(dev, ino)];
 
 loop:
        ih = &ihead[INOHASH(dev, ino)];
@@ -131,17 +134,8 @@ loop:
                                sleep((caddr_t)ip, PINOD);
                                goto loop;
                        }
                                sleep((caddr_t)ip, PINOD);
                                goto loop;
                        }
-                       if ((ip->i_flag&IMOUNT) != 0) {
-                               for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++)
-                                       if(mp->m_inodp == ip) {
-                                               dev = mp->m_dev;
-                                               fs = mp->m_fs;
-                                               ino = ROOTINO;
-                                               goto loop;
-                                       }
-                               panic("no imt");
-                       }
-                       if (ip->i_count == 0) {         /* ino on free list */
+                       vp = ITOV(ip);
+                       if (vp->v_count == 0) {         /* ino on free list */
                                if (iq = ip->i_freef)
                                        iq->i_freeb = ip->i_freeb;
                                else
                                if (iq = ip->i_freef)
                                        iq->i_freeb = ip->i_freeb;
                                else
@@ -150,17 +144,153 @@ loop:
                                ip->i_freef = NULL;
                                ip->i_freeb = NULL;
                        }
                                ip->i_freef = NULL;
                                ip->i_freeb = NULL;
                        }
-                       ip->i_count++;
                        ip->i_flag |= ILOCKED;
                        ip->i_flag |= ILOCKED;
-                       return(ip);
+                       vp->v_count++;
+                       *ipp = ip;
+                       return(0);
+               }
+       if (error = getnewino(dev, ino, &nip)) {
+               *ipp = 0;
+               return (error);
+       }
+       ip = nip;
+       /*
+        * Read in the disk contents for the inode.
+        */
+       if (error = bread(VFSTOUFS(mntp)->um_devvp, fsbtodb(fs, itod(fs, ino)),
+           (int)fs->fs_bsize, &bp)) {
+               /*
+                * The inode doesn't contain anything useful, so it would
+                * be misleading to leave it on its hash chain. Iput() will
+                * take care of putting it back on the free list. We also
+                * lose its inumber, just in case.
+                */
+               remque(ip);
+               ip->i_forw = ip;
+               ip->i_back = ip;
+               ip->i_number = 0;
+               INSFREE(ip);
+               ip->i_flag = 0;
+               brelse(bp);
+               *ipp = 0;
+               return(error);
+       }
+       /*
+        * Check to see if the new inode represents a block device
+        * for which we already have an inode (either because of
+        * bdevvp() or because of a different inode representing
+        * the same block device). If such an alias exists, put the
+        * just allocated inode back on the free list, and replace
+        * the contents of the existing inode with the contents of
+        * the new inode.
+        */
+       dp = bp->b_un.b_dino;
+       dp += itoo(fs, ino);
+       if ((dp->di_mode & IFMT) != IFBLK) {
+               ip->i_ic = dp->di_ic;
+               brelse(bp);
+       } else {
+again:
+               for (iq = bdevlisth; iq; iq = iq->i_devlst) {
+                       if (dp->di_rdev != ITOV(iq)->v_rdev)
+                               continue;
+                       igrab(iq);
+                       if (dp->di_rdev != ITOV(iq)->v_rdev) {
+                               iput(iq);
+                               goto again;
+                       }
+                       /*
+                        * Discard unneeded inode.
+                        */
+                       remque(ip);
+                       ip->i_forw = ip;
+                       ip->i_back = ip;
+                       ip->i_number = 0;
+                       INSFREE(ip);
+                       ip->i_flag = 0;
+                       /*
+                        * Reinitialize aliased inode.
+                        * We must release the buffer that we just read
+                        * before doing the iupdat() to avoid a possible
+                        * deadlock with updating an inode in the same
+                        * disk block.
+                        */
+                       ip = iq;
+                       vp = ITOV(iq);
+                       tdip.di_ic = dp->di_ic;
+                       brelse(bp);
+                       error = iupdat(ip, &time, &time, 1);
+                       ip->i_ic = tdip.di_ic;
+                       remque(ip);
+                       insque(ip, ih);
+                       ip->i_dev = dev;
+                       ip->i_number = ino;
+                       if (ip->i_devvp) {
+                               vrele(ip->i_devvp);
+                               ip->i_devvp = 0;
+                       }
+                       cache_purge(vp);
+                       break;
+               }
+               if (iq == 0) {
+                       ip->i_ic = dp->di_ic;
+                       brelse(bp);
+                       ip->i_devlst = bdevlisth;
+                       bdevlisth = ip;
                }
                }
+       }
+       /*
+        * Finish inode initialization.
+        */
+       ip->i_fs = fs;
+       ip->i_devvp = VFSTOUFS(mntp)->um_devvp;
+       ip->i_devvp->v_count++;
+       /*
+        * Initialize the associated vnode
+        */
+       vp = ITOV(ip);
+       vinit(vp, mntp, IFTOVT(ip->i_mode), &ufs_vnodeops);
+       if (vp->v_type == VCHR || vp->v_type == VBLK) {
+               vp->v_rdev = ip->i_rdev;
+               vp->v_op = &blk_vnodeops;
+       }
+       if (ino == ROOTINO)
+               vp->v_flag |= VROOT;
+#ifdef QUOTA
+       if (ip->i_mode != 0)
+               ip->i_dquot = inoquota(ip);
+#endif
+       *ipp = ip;
+       return (0);
+}
 
 
+/*
+ * Allocate a new inode.
+ *
+ * Put it onto its hash chain and lock it so that other requests for
+ * this inode will block if they arrive while we are sleeping waiting
+ * for old data structures to be purged or for the contents of the disk
+ * portion of this inode to be read.
+ */
+getnewino(dev, ino, ipp)
+       dev_t dev;
+       ino_t ino;
+       struct inode **ipp;
+{
+       union ihead *ih;
+       register struct inode *ip, *iq;
+       register struct vnode *vp;
+
+       /*
+        * Remove the next inode from the free list.
+        */
        if ((ip = ifreeh) == NULL) {
                tablefull("inode");
        if ((ip = ifreeh) == NULL) {
                tablefull("inode");
-               u.u_error = ENFILE;
-               return(NULL);
+               *ipp = 0;
+               return(ENFILE);
        }
        }
-       if (ip->i_count)
+       vp = ITOV(ip);
+       if (vp->v_count)
                panic("free inode isn't");
        if (iq = ip->i_freef)
                iq->i_freeb = &ifreeh;
                panic("free inode isn't");
        if (iq = ip->i_freef)
                iq->i_freeb = &ifreeh;
@@ -170,65 +300,47 @@ loop:
        /*
         * Now to take inode off the hash chain it was on
         * (initially, or after an iflush, it is on a "hash chain"
        /*
         * Now to take inode off the hash chain it was on
         * (initially, or after an iflush, it is on a "hash chain"
-        * consisting entirely of itself, and pointed to by no-one,
-        * but that doesn't matter), and put it on the chain for
-        * its new (ino, dev) pair
+        * consisting entirely of itself, and pointed to by no-one)
+        * and put it on the chain for its new (ino, dev) pair.
         */
        remque(ip);
         */
        remque(ip);
-       insque(ip, ih);
        ip->i_dev = dev;
        ip->i_dev = dev;
-       ip->i_fs = fs;
        ip->i_number = ino;
        ip->i_number = ino;
-       cacheinval(ip);
+       if (dev != NODEV) {
+               ih = &ihead[INOHASH(dev, ino)];
+               insque(ip, ih);
+       }
        ip->i_flag = ILOCKED;
        ip->i_flag = ILOCKED;
-       ip->i_count++;
        ip->i_lastr = 0;
        ip->i_lastr = 0;
-#ifdef QUOTA
-       dqrele(ip->i_dquot);
-#endif
-#ifdef SECSIZE
-       bp = bread(dev, fsbtodb(fs, itod(fs, ino)), (int)fs->fs_bsize,
-           fs->fs_dbsize);
-#else SECSIZE
-       bp = bread(dev, fsbtodb(fs, itod(fs, ino)), (int)fs->fs_bsize);
 #endif SECSIZE
        /*
 #endif SECSIZE
        /*
-        * Check I/O errors
+        * Purge old data structures associated with the inode.
         */
         */
-       if ((bp->b_flags&B_ERROR) != 0) {
-               brelse(bp);
-               /*
-                * the inode doesn't contain anything useful, so it would
-                * be misleading to leave it on its hash chain.
-                * 'iput' will take care of putting it back on the free list.
-                */
-               remque(ip);
-               ip->i_forw = ip;
-               ip->i_back = ip;
-               /*
-                * we also loose its inumber, just in case (as iput
-                * doesn't do that any more) - but as it isn't on its
-                * hash chain, I doubt if this is really necessary .. kre
-                * (probably the two methods are interchangable)
-                */
-               ip->i_number = 0;
-#ifdef QUOTA
-               ip->i_dquot = NODQUOT;
-#endif
-               iput(ip);
-               return(NULL);
+       cache_purge(vp);
+       if (ip->i_devvp) {
+               vrele(ip->i_devvp);
+               ip->i_devvp = 0;
        }
        }
-       dp = bp->b_un.b_dino;
-       dp += itoo(fs, ino);
-       ip->i_ic = dp->di_ic;
-       brelse(bp);
 #ifdef QUOTA
 #ifdef QUOTA
-       if (ip->i_mode == 0)
-               ip->i_dquot = NODQUOT;
-       else
-               ip->i_dquot = inoquota(ip);
+       dqrele(ip->i_dquot);
+       ip->i_dquot = NODQUOT;
 #endif
 #endif
-       return (ip);
+       if (vp->v_type == VBLK) {
+               if (bdevlisth == ip) {
+                       bdevlisth = ip->i_devlst;
+               } else {
+                       for (iq = bdevlisth; iq; iq = iq->i_devlst) {
+                               if (iq->i_devlst != ip)
+                                       continue;
+                               iq->i_devlst = ip->i_devlst;
+                               break;
+                       }
+                       if (iq == NULL)
+                               panic("missing bdev");
+               }
+       }
+       *ipp = ip;
+       return (0);
 }
 
 /*
 }
 
 /*
@@ -242,11 +354,13 @@ loop:
 igrab(ip)
        register struct inode *ip;
 {
 igrab(ip)
        register struct inode *ip;
 {
+       register struct vnode *vp = ITOV(ip);
+
        while ((ip->i_flag&ILOCKED) != 0) {
                ip->i_flag |= IWANT;
                sleep((caddr_t)ip, PINOD);
        }
        while ((ip->i_flag&ILOCKED) != 0) {
                ip->i_flag |= IWANT;
                sleep((caddr_t)ip, PINOD);
        }
-       if (ip->i_count == 0) {         /* ino on free list */
+       if (vp->v_count == 0) {         /* ino on free list */
                register struct inode *iq;
 
                if (iq = ip->i_freef)
                register struct inode *iq;
 
                if (iq = ip->i_freef)
@@ -257,10 +371,56 @@ igrab(ip)
                ip->i_freef = NULL;
                ip->i_freeb = NULL;
        }
                ip->i_freef = NULL;
                ip->i_freeb = NULL;
        }
-       ip->i_count++;
+       vp->v_count++;
        ip->i_flag |= ILOCKED;
 }
 
        ip->i_flag |= ILOCKED;
 }
 
+/*
+ * Create a vnode for a block device.
+ * Used for root filesystem, argdev, and swap areas.
+ */
+bdevvp(dev, vpp)
+       dev_t dev;
+       struct vnode **vpp;
+{
+       register struct inode *ip;
+       register struct vnode *vp;
+       struct inode *nip;
+       int error;
+
+       /*
+        * Check for the existence of an existing vnode.
+        */
+again:
+       for (ip = bdevlisth; ip; ip = ip->i_devlst) {
+               vp = ITOV(ip);
+               if (dev != vp->v_rdev)
+                       continue;
+               igrab(ip);
+               if (dev != vp->v_rdev) {
+                       iput(ip);
+                       goto again;
+               }
+               IUNLOCK(ip);
+               *vpp = vp;
+               return (0);
+       }
+       if (error = getnewino(NODEV, (ino_t)0, &nip)) {
+               *vpp = 0;
+               return (error);
+       }
+       ip = nip;
+       ip->i_fs = 0;
+       ip->i_devlst = bdevlisth;
+       bdevlisth = ip;
+       vp = ITOV(ip);
+       vinit(vp, 0, VBLK, &blk_vnodeops);
+       vp->v_rdev = dev;
+       IUNLOCK(ip);
+       *vpp = vp;
+       return (0);
+}
+
 /*
  * Decrement reference count of
  * an inode structure.
 /*
  * Decrement reference count of
  * an inode structure.
@@ -275,54 +435,43 @@ iput(ip)
        if ((ip->i_flag & ILOCKED) == 0)
                panic("iput");
        IUNLOCK(ip);
        if ((ip->i_flag & ILOCKED) == 0)
                panic("iput");
        IUNLOCK(ip);
-       irele(ip);
+       vrele(ITOV(ip));
 }
 
 }
 
-irele(ip)
-       register struct inode *ip;
+
+ufs_inactive(vp)
+       struct vnode *vp;
 {
 {
-       int mode;
-
-       if (ip->i_count == 1) {
-               ip->i_flag |= ILOCKED;
-               if (ip->i_nlink <= 0 && ip->i_fs->fs_ronly == 0) {
-                       itrunc(ip, (u_long)0);
-                       mode = ip->i_mode;
-                       ip->i_mode = 0;
-                       ip->i_rdev = 0;
-                       ip->i_flag |= IUPD|ICHG;
-                       ifree(ip, ip->i_number, mode);
+       register struct inode *ip = VTOI(vp);
+       int mode, error;
+
+       if (ITOV(ip)->v_count != 0)
+               panic("ufs_inactive: not inactive");
+       ip->i_flag |= ILOCKED;
+       if (ip->i_nlink <= 0 && (ITOV(ip)->v_mount->m_flag&M_RDONLY) == 0) {
+               error = itrunc(ip, (u_long)0);
+               mode = ip->i_mode;
+               ip->i_mode = 0;
+               ip->i_rdev = 0;
+               ip->i_flag |= IUPD|ICHG;
+               ifree(ip, ip->i_number, mode);
 #ifdef QUOTA
 #ifdef QUOTA
-                       (void) chkiq(ip->i_dev, ip, ip->i_uid, 0);
-                       dqrele(ip->i_dquot);
-                       ip->i_dquot = NODQUOT;
+               (void) chkiq(ip->i_dev, ip, ip->i_uid, 0);
+               dqrele(ip->i_dquot);
+               ip->i_dquot = NODQUOT;
 #endif
 #endif
-               }
-               IUPDAT(ip, &time, &time, 0);
-               IUNLOCK(ip);
-               ip->i_flag = 0;
-               /*
-                * Put the inode on the end of the free list.
-                * Possibly in some cases it would be better to
-                * put the inode at the head of the free list,
-                * (eg: where i_mode == 0 || i_number == 0)
-                * but I will think about that later .. kre
-                * (i_number is rarely 0 - only after an i/o error in iget,
-                * where i_mode == 0, the inode will probably be wanted
-                * again soon for an ialloc, so possibly we should keep it)
-                */
-               if (ifreeh) {
-                       *ifreet = ip;
-                       ip->i_freeb = ifreet;
-               } else {
-                       ifreeh = ip;
-                       ip->i_freeb = &ifreeh;
-               }
-               ip->i_freef = NULL;
-               ifreet = &ip->i_freef;
-       } else if (!(ip->i_flag & ILOCKED))
-               ITIMES(ip, &time, &time);
-       ip->i_count--;
+       }
+       IUPDAT(ip, &time, &time, 0);
+       IUNLOCK(ip);
+       ip->i_flag = 0;
+       /*
+        * Put the inode on the end of the free list.
+        * Possibly in some cases it would be better to
+        * put the inode at the head of the free list,
+        * (eg: where i_mode == 0 || i_number == 0).
+        */
+       INSFREE(ip);
+       return (error);
 }
 
 /*
 }
 
 /*
@@ -338,38 +487,36 @@ iupdat(ip, ta, tm, waitfor)
        struct timeval *ta, *tm;
        int waitfor;
 {
        struct timeval *ta, *tm;
        int waitfor;
 {
-       register struct buf *bp;
+       struct buf *bp;
+       struct vnode *vp = ITOV(ip);
        struct dinode *dp;
        register struct fs *fs;
 
        fs = ip->i_fs;
        struct dinode *dp;
        register struct fs *fs;
 
        fs = ip->i_fs;
-       if ((ip->i_flag & (IUPD|IACC|ICHG|IMOD)) != 0) {
-               if (fs->fs_ronly)
-                       return;
-#ifdef SECSIZE
-               bp = bread(ip->i_dev, fsbtodb(fs, itod(fs, ip->i_number)),
-                       (int)fs->fs_bsize, fs->fs_dbsize);
-#else SECSIZE
-               bp = bread(ip->i_dev, fsbtodb(fs, itod(fs, ip->i_number)),
-                       (int)fs->fs_bsize);
-#endif SECSIZE
-               if (bp->b_flags & B_ERROR) {
-                       brelse(bp);
-                       return;
-               }
-               if (ip->i_flag&IACC)
-                       ip->i_atime = ta->tv_sec;
-               if (ip->i_flag&IUPD)
-                       ip->i_mtime = tm->tv_sec;
-               if (ip->i_flag&ICHG)
-                       ip->i_ctime = time.tv_sec;
-               ip->i_flag &= ~(IUPD|IACC|ICHG|IMOD);
-               dp = bp->b_un.b_dino + itoo(fs, ip->i_number);
-               dp->di_ic = ip->i_ic;
-               if (waitfor)
-                       bwrite(bp);
-               else
-                       bdwrite(bp);
+       if ((ip->i_flag & (IUPD|IACC|ICHG|IMOD)) == 0)
+               return (0);
+       if (vp->v_mount->m_flag & M_RDONLY)
+               return (0);
+       error = bread(ip->i_devvp, fsbtodb(fs, itod(fs, ip->i_number)),
+               (int)fs->fs_bsize, &bp);
+       if (error) {
+               brelse(bp);
+               return (error);
+       }
+       if (ip->i_flag&IACC)
+               ip->i_atime = ta->tv_sec;
+       if (ip->i_flag&IUPD)
+               ip->i_mtime = tm->tv_sec;
+       if (ip->i_flag&ICHG)
+               ip->i_ctime = time.tv_sec;
+       ip->i_flag &= ~(IUPD|IACC|ICHG|IMOD);
+       dp = bp->b_un.b_dino + itoo(fs, ip->i_number);
+       dp->di_ic = ip->i_ic;
+       if (waitfor) {
+               return (bwrite(bp));
+       } else {
+               bdwrite(bp);
+               return (0);
        }
 }
 
        }
 }
 
@@ -393,17 +540,16 @@ itrunc(oip, length)
        register struct fs *fs;
        register struct inode *ip;
        struct buf *bp;
        register struct fs *fs;
        register struct inode *ip;
        struct buf *bp;
-       int offset, osize, size, count, level;
-       long nblocks, blocksreleased = 0;
+       int offset, osize, size, level;
+       long count, nblocks, blocksreleased = 0;
        register int i;
        register int i;
-       dev_t dev;
+       int error, allerror = 0;
        struct inode tip;
        struct inode tip;
-       extern long indirtrunc();
 
        if (oip->i_size <= length) {
                oip->i_flag |= ICHG|IUPD;
 
        if (oip->i_size <= length) {
                oip->i_flag |= ICHG|IUPD;
-               iupdat(oip, &time, &time, 1);
-               return;
+               error = iupdat(oip, &time, &time, 1);
+               return (error);
        }
        /*
         * Calculate index into inode's block list of
        }
        /*
         * Calculate index into inode's block list of
@@ -430,25 +576,20 @@ itrunc(oip, length)
                oip->i_size = length;
        } else {
                lbn = lblkno(fs, length);
                oip->i_size = length;
        } else {
                lbn = lblkno(fs, length);
-               bn = fsbtodb(fs, bmap(oip, lbn, B_WRITE, offset));
-               if (u.u_error || (long)bn < 0)
-                       return;
+               error = balloc(oip, lbn, offset, &bn, B_CLRBUF);
+               if (error)
+                       return (error);
+               if ((long)bn < 0)
+                       panic("itrunc: hole");
                oip->i_size = length;
                size = blksize(fs, oip, lbn);
                count = howmany(size, CLBYTES);
                oip->i_size = length;
                size = blksize(fs, oip, lbn);
                count = howmany(size, CLBYTES);
-               dev = oip->i_dev;
-               for (i = 0; i < count; i++)
-#ifdef SECSIZE
-                       munhash(dev, bn + i * CLBYTES / fs->fs_dbsize);
-#else SECSIZE
-                       munhash(dev, bn + i * CLBYTES / DEV_BSIZE);
-#endif SECSIZE
-               bp = bread(dev, bn, size);
-               if (bp->b_flags & B_ERROR) {
-                       u.u_error = EIO;
+                       munhash(oip->i_devvp, bn + i * CLBYTES / DEV_BSIZE);
+               error = bread(oip->i_devvp, bn, size, &bp);
+               if (error) {
                        oip->i_size = osize;
                        brelse(bp);
                        oip->i_size = osize;
                        brelse(bp);
-                       return;
+                       return (error);
                }
                bzero(bp->b_un.b_addr + offset, (unsigned)(size - offset));
                bdwrite(bp);
                }
                bzero(bp->b_un.b_addr + offset, (unsigned)(size - offset));
                bdwrite(bp);
@@ -471,7 +612,7 @@ itrunc(oip, length)
        for (i = NDADDR - 1; i > lastblock; i--)
                oip->i_db[i] = 0;
        oip->i_flag |= ICHG|IUPD;
        for (i = NDADDR - 1; i > lastblock; i--)
                oip->i_db[i] = 0;
        oip->i_flag |= ICHG|IUPD;
-       syncip(oip);
+       allerror = syncip(oip);
 
        /*
         * Indirect blocks first.
 
        /*
         * Indirect blocks first.
@@ -480,8 +621,11 @@ itrunc(oip, length)
        for (level = TRIPLE; level >= SINGLE; level--) {
                bn = ip->i_ib[level];
                if (bn != 0) {
        for (level = TRIPLE; level >= SINGLE; level--) {
                bn = ip->i_ib[level];
                if (bn != 0) {
-                       blocksreleased +=
-                           indirtrunc(ip, bn, lastiblock[level], level);
+                       error = indirtrunc(ip, bn, lastiblock[level], level,
+                               &count);
+                       if (error)
+                               allerror = error;
+                       blocksreleased += count;
                        if (lastiblock[level] < 0) {
                                ip->i_ib[level] = 0;
                                blkfree(ip, bn, (off_t)fs->fs_bsize);
                        if (lastiblock[level] < 0) {
                                ip->i_ib[level] = 0;
                                blkfree(ip, bn, (off_t)fs->fs_bsize);
@@ -553,6 +697,7 @@ done:
 #ifdef QUOTA
        (void) chkdq(oip, -blocksreleased, 0);
 #endif
 #ifdef QUOTA
        (void) chkdq(oip, -blocksreleased, 0);
 #endif
+       return (allerror);
 }
 
 /*
 }
 
 /*
@@ -565,19 +710,20 @@ done:
  *
  * NB: triple indirect blocks are untested.
  */
  *
  * NB: triple indirect blocks are untested.
  */
-long
-indirtrunc(ip, bn, lastbn, level)
+indirtrunc(ip, bn, lastbn, level, countp)
        register struct inode *ip;
        daddr_t bn, lastbn;
        int level;
        register struct inode *ip;
        daddr_t bn, lastbn;
        int level;
+       long *countp;
 {
        register int i;
        struct buf *bp;
        register struct fs *fs = ip->i_fs;
        register daddr_t *bap;
        daddr_t *copy, nb, last;
 {
        register int i;
        struct buf *bp;
        register struct fs *fs = ip->i_fs;
        register daddr_t *bap;
        daddr_t *copy, nb, last;
-       long factor;
-       int blocksreleased = 0, nblocks;
+       long blkcount, factor;
+       int nblocks, blocksreleased = 0;
+       int error, allerror = 0;
 
        /*
         * Calculate index in current block of last
 
        /*
         * Calculate index in current block of last
@@ -600,18 +746,20 @@ indirtrunc(ip, bn, lastbn, level)
        bp = bread(ip->i_dev, fsbtodb(fs, bn), (int)fs->fs_bsize,
            fs->fs_dbsize);
 #else SECSIZE
        bp = bread(ip->i_dev, fsbtodb(fs, bn), (int)fs->fs_bsize,
            fs->fs_dbsize);
 #else SECSIZE
-       bp = bread(ip->i_dev, fsbtodb(fs, bn), (int)fs->fs_bsize);
-#endif SECSIZE
-       if (bp->b_flags&B_ERROR) {
+       error = bread(ip->i_devvp, fsbtodb(fs, bn), (int)fs->fs_bsize, &bp);
+       if (error) {
                brelse(bp);
                brelse(bp);
-               return (0);
+               *countp = 0;
+               return (error);
        }
        bap = bp->b_un.b_daddr;
        MALLOC(copy, daddr_t *, fs->fs_bsize, M_TEMP, M_WAITOK);
        bcopy((caddr_t)bap, (caddr_t)copy, (u_int)fs->fs_bsize);
        bzero((caddr_t)&bap[last + 1],
          (u_int)(NINDIR(fs) - (last + 1)) * sizeof (daddr_t));
        }
        bap = bp->b_un.b_daddr;
        MALLOC(copy, daddr_t *, fs->fs_bsize, M_TEMP, M_WAITOK);
        bcopy((caddr_t)bap, (caddr_t)copy, (u_int)fs->fs_bsize);
        bzero((caddr_t)&bap[last + 1],
          (u_int)(NINDIR(fs) - (last + 1)) * sizeof (daddr_t));
-       bwrite(bp);
+       error = bwrite(bp);
+       if (error)
+               allerror = error;
        bap = copy;
 
        /*
        bap = copy;
 
        /*
@@ -621,9 +769,13 @@ indirtrunc(ip, bn, lastbn, level)
                nb = bap[i];
                if (nb == 0)
                        continue;
                nb = bap[i];
                if (nb == 0)
                        continue;
-               if (level > SINGLE)
-                       blocksreleased +=
-                           indirtrunc(ip, nb, (daddr_t)-1, level - 1);
+               if (level > SINGLE) {
+                       error = indirtrunc(ip, nb, (daddr_t)-1, level - 1,
+                               &blkcount);
+                       if (error)
+                               allerror = error;
+                       blocksreleased += blkcount;
+               }
                blkfree(ip, nb, (off_t)fs->fs_bsize);
                blocksreleased += nblocks;
        }
                blkfree(ip, nb, (off_t)fs->fs_bsize);
                blocksreleased += nblocks;
        }
@@ -634,11 +786,16 @@ indirtrunc(ip, bn, lastbn, level)
        if (level > SINGLE && lastbn >= 0) {
                last = lastbn % factor;
                nb = bap[i];
        if (level > SINGLE && lastbn >= 0) {
                last = lastbn % factor;
                nb = bap[i];
-               if (nb != 0)
-                       blocksreleased += indirtrunc(ip, nb, last, level - 1);
+               if (nb != 0) {
+                       error = indirtrunc(ip, nb, last, level - 1, &blkcount);
+                       if (error)
+                               allerror = error;
+                       blocksreleased += blkcount;
+               }
        }
        FREE(copy, M_TEMP);
        }
        FREE(copy, M_TEMP);
-       return (blocksreleased);
+       *countp = blocksreleased;
+       return (allerror);
 }
 
 /*
 }
 
 /*
@@ -664,14 +821,14 @@ iflush(dev)
 #else
                if (ip->i_dev == dev)
 #endif
 #else
                if (ip->i_dev == dev)
 #endif
-                       if (ip->i_count)
+                       if (ITOV(ip)->v_count)
                                return (EBUSY);
                        else {
                                remque(ip);
                                ip->i_forw = ip;
                                ip->i_back = ip;
                                /*
                                return (EBUSY);
                        else {
                                remque(ip);
                                ip->i_forw = ip;
                                ip->i_back = ip;
                                /*
-                                * as i_count == 0, the inode was on the free
+                                * as v_count == 0, the inode was on the free
                                 * list already, just leave it there, it will
                                 * fall off the bottom eventually. We could
                                 * perhaps move it to the head of the free
                                 * list already, just leave it there, it will
                                 * fall off the bottom eventually. We could
                                 * perhaps move it to the head of the free
@@ -683,6 +840,10 @@ iflush(dev)
                                dqrele(ip->i_dquot);
                                ip->i_dquot = NODQUOT;
 #endif
                                dqrele(ip->i_dquot);
                                ip->i_dquot = NODQUOT;
 #endif
+                               if (ip->i_devvp) {
+                                       vrele(ip->i_devvp);
+                                       ip->i_devvp = 0;
+                               }
                        }
        }
        return (0);
                        }
        }
        return (0);
@@ -695,7 +856,11 @@ ilock(ip)
        register struct inode *ip;
 {
 
        register struct inode *ip;
 {
 
-       ILOCK(ip);
+       while (ip->i_flag & ILOCKED) {
+               ip->i_flag |= IWANT;
+               (void) sleep((caddr_t)ip, PINOD);
+       }
+       ip->i_flag |= ILOCKED;
 }
 
 /*
 }
 
 /*
@@ -705,5 +870,55 @@ iunlock(ip)
        register struct inode *ip;
 {
 
        register struct inode *ip;
 {
 
-       IUNLOCK(ip);
+       if ((ip->i_flag & ILOCKED) == 0)
+               printf("unlocking unlocked inode %d on dev 0x%x\n",
+                       ip->i_number, ip->i_dev);
+       ip->i_flag &= ~ILOCKED;
+       if (ip->i_flag&IWANT) {
+               ip->i_flag &= ~IWANT;
+               wakeup((caddr_t)ip);
+       }
+}
+
+/*
+ * Check mode permission on inode pointer. Mode is READ, WRITE or EXEC.
+ * The mode is shifted to select the owner/group/other fields. The
+ * super user is granted all permissions.
+ *
+ * NB: Called from vnode op table. It seems this could all be done
+ * using vattr's but...
+ */
+iaccess(ip, mode, cred)
+       register struct inode *ip;
+       register int mode;
+       struct ucred *cred;
+{
+       register gid_t *gp;
+       register struct vnode *vp = ITOV(ip);
+       int i;
+
+       /*
+        * If you're the super-user,
+        * you always get access.
+        */
+       if (cred->cr_uid == 0)
+               return (0);
+       /*
+        * Access check is based on only one of owner, group, public.
+        * If not owner, then check group. If not a member of the
+        * group, then check public access.
+        */
+       if (cred->cr_uid != ip->i_uid) {
+               mode >>= 3;
+               gp = cred->cr_groups;
+               for (i = 0; i < cred->cr_ngroups; i++, gp++)
+                       if (ip->i_gid == *gp)
+                               goto found;
+               mode >>= 3;
+found:
+               ;
+       }
+       if ((ip->i_mode & mode) != 0)
+               return (0);
+       return (EACCES);
 }
 }
index 3c4f2c8..68e74dd 100644 (file)
@@ -1,93 +1,50 @@
 /*
 /*
- * Copyright (c) 1982, 1986 Regents of the University of California.
- * All rights reserved.  The Berkeley software License Agreement
- * specifies the terms and conditions for redistribution.
+ * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
+ * All rights reserved.
  *
  *
- *     @(#)ffs_subr.c  7.7 (Berkeley) %G%
+ * 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.
+ *
+ *     @(#)ffs_subr.c  7.8 (Berkeley) %G%
  */
 
 #ifdef KERNEL
 #include "param.h"
 #include "systm.h"
  */
 
 #ifdef KERNEL
 #include "param.h"
 #include "systm.h"
-#include "mount.h"
-#include "fs.h"
 #include "buf.h"
 #include "buf.h"
-#include "inode.h"
-#include "dir.h"
-#include "user.h"
-#include "quota.h"
+#include "time.h"
 #include "kernel.h"
 #include "kernel.h"
+#include "file.h"
+#include "mount.h"
+#include "vnode.h"
+#include "../ufs/inode.h"
+#include "../ufs/ufsmount.h"
+#include "../ufs/fs.h"
+#include "../ufs/quota.h"
 #else
 #include <sys/param.h>
 #include <sys/systm.h>
 #else
 #include <sys/param.h>
 #include <sys/systm.h>
-#include <sys/mount.h>
-#include <sys/fs.h>
 #include <sys/buf.h>
 #include <sys/buf.h>
-#include <sys/inode.h>
-#include <sys/dir.h>
-#include <sys/user.h>
-#include <sys/quota.h>
+#include <sys/time.h>
+#include <sys/file.h>
+#include <sys/mount.h>
+#include <sys/vnode.h>
+#include <ufs/inode.h>
+#include <ufs/ufsmount.h>
+#include <ufs/fs.h>
+#include <ufs/quota.h>
 #endif
 
 #ifdef KERNEL
 #endif
 
 #ifdef KERNEL
-int    syncprt = 0;
-
-/*
- * Update is the internal name of 'sync'.  It goes through the disk
- * queues to initiate sandbagged IO; goes through the inodes to write
- * modified nodes; and it goes through the mount table to initiate
- * the writing of the modified super blocks.
- */
-update()
-{
-       register struct inode *ip;
-       register struct mount *mp;
-       struct fs *fs;
-
-       if (syncprt)
-               bufstats();
-       if (updlock)
-               return;
-       updlock++;
-       /*
-        * Write back modified superblocks.
-        * Consistency check that the superblock
-        * of each file system is still in the buffer cache.
-        */
-       for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++) {
-               if (mp->m_fs == NULL || mp->m_fs == (struct fs *)1)   /* XXX */
-                       continue;
-               fs = mp->m_fs;
-               if (fs->fs_fmod == 0)
-                       continue;
-               if (fs->fs_ronly != 0) {                /* XXX */
-                       printf("fs = %s\n", fs->fs_fsmnt);
-                       panic("update: rofs mod");
-               }
-               fs->fs_fmod = 0;
-               fs->fs_time = time.tv_sec;
-               sbupdate(mp);
-       }
-       /*
-        * Write back each (modified) inode.
-        */
-       for (ip = inode; ip < inodeNINODE; ip++) {
-               if ((ip->i_flag & ILOCKED) != 0 || ip->i_count == 0 ||
-                   (ip->i_flag & (IMOD|IACC|IUPD|ICHG)) == 0)
-                       continue;
-               ip->i_flag |= ILOCKED;
-               ip->i_count++;
-               iupdat(ip, &time, &time, 0);
-               iput(ip);
-       }
-       updlock = 0;
-       /*
-        * Force stale buffer cache information to be flushed,
-        * for all devices.
-        */
-       bflush(NODEV);
-}
-
 /*
  * Flush all the blocks associated with an inode.
  * There are two strategies based on the size of the file;
 /*
  * Flush all the blocks associated with an inode.
  * There are two strategies based on the size of the file;
@@ -110,7 +67,7 @@ syncip(ip)
        register struct buf *bp;
        struct buf *lastbufp;
        long lbn, lastlbn;
        register struct buf *bp;
        struct buf *lastbufp;
        long lbn, lastlbn;
-       int s;
+       int s, error, allerror = 0;
        daddr_t blkno;
 
        fs = ip->i_fs;
        daddr_t blkno;
 
        fs = ip->i_fs;
@@ -120,16 +77,12 @@ syncip(ip)
                lastlbn--;
                s = fsbtodb(fs, fs->fs_frag);
                for (lbn = 0; lbn < lastlbn; lbn++) {
                lastlbn--;
                s = fsbtodb(fs, fs->fs_frag);
                for (lbn = 0; lbn < lastlbn; lbn++) {
-                       blkno = fsbtodb(fs, bmap(ip, lbn, B_READ));
-                       blkflush(ip->i_dev, blkno, s);
-               }
-               if (lastlbn >= 0)
-                       blkflush(ip->i_dev, blkno, (int)fsbtodb(fs,
-                           blksize(fs, ip, lbn) / fs->fs_fsize));
-#else SECSIZE
-               for (lbn = 0; lbn < lastlbn; lbn++) {
-                       blkno = fsbtodb(fs, bmap(ip, lbn, B_READ));
-                       blkflush(ip->i_dev, blkno, blksize(fs, ip, lbn));
+                       error = bmap(ip, lbn, &blkno, (daddr_t *)0, (int *)0);
+                       if (error)
+                               allerror = error;
+                       if (error = blkflush(ip->i_devvp, blkno,
+                           blksize(fs, ip, lbn)))
+                               allerror = error;
                }
 #endif SECSIZE
        } else {
                }
 #endif SECSIZE
        } else {
@@ -148,12 +101,15 @@ syncip(ip)
                        }
                        splx(s);
                        notavail(bp);
                        }
                        splx(s);
                        notavail(bp);
-                       bwrite(bp);
+                       if (error = bwrite(bp))
+                               allerror = error;
                }
        }
                }
        }
-       iupdat(ip, &time, &time, 1);
+       if (error = iupdat(ip, &time, &time, 1))
+               allerror = error;
+       return (allerror);
 }
 }
-#endif
+#endif KERNEL
 
 extern int around[9];
 extern int inside[9];
 
 extern int around[9];
 extern int inside[9];
@@ -311,14 +267,14 @@ struct fs *
 getfs(dev)
        dev_t dev;
 {
 getfs(dev)
        dev_t dev;
 {
-       register struct mount *mp;
+       register struct ufsmount *mp;
        register struct fs *fs;
 
        register struct fs *fs;
 
-       for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++) {
-               if (mp->m_dev != dev || mp->m_fs == NULL ||
-                   mp->m_fs == (struct fs *)1)                 /* XXX */
+       for (mp = &mounttab[0]; mp < &mounttab[NMOUNT]; mp++) {
+               if (mp->um_fs == NULL || mp->um_dev != dev ||
+                   mp->um_fs == (struct fs *)1)                /* XXX */
                        continue;
                        continue;
-               fs = mp->m_fs;
+               fs = mp->um_fs;
                if (fs->fs_magic != FS_MAGIC) {
                        printf("dev = 0x%x, fs = %s\n", dev, fs->fs_fsmnt);
                        panic("getfs: bad magic");
                if (fs->fs_magic != FS_MAGIC) {
                        printf("dev = 0x%x, fs = %s\n", dev, fs->fs_fsmnt);
                        panic("getfs: bad magic");
@@ -345,45 +301,15 @@ getfs(dev)
 getfsx(dev)
        dev_t dev;
 {
 getfsx(dev)
        dev_t dev;
 {
-       register struct mount *mp;
+       register struct ufsmount *mp;
 
        if (dev == swapdev)
                return (MSWAPX);
 
        if (dev == swapdev)
                return (MSWAPX);
-       for(mp = &mount[0]; mp < &mount[NMOUNT]; mp++)
-               if (mp->m_dev == dev)
-                       return (mp - &mount[0]);
+       for(mp = &mounttab[0]; mp < &mounttab[NMOUNT]; mp++)
+               if (mp->um_dev == dev)
+                       return (mp - &mounttab[0]);
        return (-1);
 }
        return (-1);
 }
-
-/*
- * Print out statistics on the current allocation of the buffer pool.
- * Can be enabled to print out on every ``sync'' by setting "syncprt"
- * above.
- */
-bufstats()
-{
-       int s, i, j, count;
-       register struct buf *bp, *dp;
-       int counts[MAXBSIZE/CLBYTES+1];
-       static char *bname[BQUEUES] = { "LOCKED", "LRU", "AGE", "EMPTY" };
-
-       for (bp = bfreelist, i = 0; bp < &bfreelist[BQUEUES]; bp++, i++) {
-               count = 0;
-               for (j = 0; j <= MAXBSIZE/CLBYTES; j++)
-                       counts[j] = 0;
-               s = splbio();
-               for (dp = bp->av_forw; dp != bp; dp = dp->av_forw) {
-                       counts[dp->b_bufsize/CLBYTES]++;
-                       count++;
-               }
-               splx(s);
-               printf("%s: total-%d", bname[i], count);
-               for (j = 0; j <= MAXBSIZE/CLBYTES; j++)
-                       if (counts[j] != 0)
-                               printf(", %d-%d", j * CLBYTES, counts[j]);
-               printf("\n");
-       }
-}
 #endif
 
 #if (!defined(vax) && !defined(tahoe)) || defined(VAX630) || defined(VAX650)
 #endif
 
 #if (!defined(vax) && !defined(tahoe)) || defined(VAX630) || defined(VAX650)
index 9323a13..6e2ef17 100644 (file)
 /*
 /*
- * Copyright (c) 1982, 1986 Regents of the University of California.
- * All rights reserved.  The Berkeley software License Agreement
- * specifies the terms and conditions for redistribution.
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
  *
  *
- *     @(#)ffs_vfsops.c        7.12 (Berkeley) %G%
+ * 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.
+ *
+ *     @(#)ffs_vfsops.c        7.13 (Berkeley) %G%
  */
 
  */
 
+
 #include "param.h"
 #include "systm.h"
 #include "param.h"
 #include "systm.h"
-#include "dir.h"
-#include "user.h"
-#include "inode.h"
-#include "proc.h"
-#include "fs.h"
-#include "buf.h"
+#include "time.h"
+#include "kernel.h"
+#include "namei.h"
+#include "vnode.h"
 #include "mount.h"
 #include "mount.h"
+#include "buf.h"
 #include "file.h"
 #include "file.h"
-#include "conf.h"
-#include "ioctl.h"
 #include "disklabel.h"
 #include "disklabel.h"
-#include "stat.h"
+#include "ioctl.h"
+#include "errno.h"
 #include "malloc.h"
 #include "malloc.h"
+#include "../ufs/fs.h"
+#include "../ufs/ufsmount.h"
+#include "../ufs/inode.h"
 #include "ioctl.h"
 #include "disklabel.h"
 #include "stat.h"
 
 #include "ioctl.h"
 #include "disklabel.h"
 #include "stat.h"
 
-smount()
+/*
+ * ufs vfs operations.
+ */
+int ufs_mount();
+int ufs_unmount();
+int ufs_root();
+int ufs_statfs();
+int ufs_sync();
+int ufs_fhtovp();
+int ufs_vptofh();
+
+struct vfsops ufs_vfsops = {
+       ufs_mount,
+       ufs_unmount,
+       ufs_root,
+       ufs_statfs,
+       ufs_sync,
+       ufs_fhtovp,
+       ufs_vptofh
+};
+
+/*
+ * ufs mount table.
+ */
+struct ufsmount mounttab[NMOUNT];
+
+/*
+ * Called by vfs_mountroot when ufs is going to be mounted as root
+ *
+ * XXX - Need to have a way of figuring the name of the root device
+ */
+#define ROOTNAME       "root device"
+
+ufs_mountroot()
 {
 {
-       register struct a {
-               char    *fspec;
-               char    *freg;
-               int     ronly;
-       } *uap = (struct a *)u.u_ap;
-       dev_t dev;
-       register struct inode *ip;
+       register struct mount *mp;
+       extern struct vnode *rootvp;
+       struct ufsmount *ump;
        register struct fs *fs;
        register struct fs *fs;
-       register struct nameidata *ndp = &u.u_nd;
-       u_int len;
+       u_int size;
+       int error;
 
 
-       u.u_error = getmdev(&dev, uap->fspec);
-       if (u.u_error)
-               return;
-       ndp->ni_nameiop = LOOKUP | FOLLOW;
-       ndp->ni_segflg = UIO_USERSPACE;
-       ndp->ni_dirp = (caddr_t)uap->freg;
-       ip = namei(ndp);
-       if (ip == NULL)
-               return;
-       if (ip->i_count != 1) {
-               iput(ip);
-               u.u_error = EBUSY;
-               return;
+       mp = (struct mount *)malloc((u_long)sizeof(struct mount),
+               M_MOUNT, M_WAITOK);
+       mp->m_op = &ufs_vfsops;
+       mp->m_flag = 0;
+       mp->m_exroot = 0;
+       error = mountfs(rootvp, mp);
+       if (error) {
+               free((caddr_t)mp, M_MOUNT);
+               return (error);
        }
        }
-       if ((ip->i_mode&IFMT) != IFDIR) {
-               iput(ip);
-               u.u_error = ENOTDIR;
-               return;
+       error = vfs_add((struct vnode *)0, mp, 0);
+       if (error) {
+               (void)ufs_unmount(mp, 0);
+               free((caddr_t)mp, M_MOUNT);
+               return (error);
        }
        }
-       fs = mountfs(dev, uap->ronly, ip);
-       if (fs == 0) {
-               iput(ip);
-               return;
+       ump = VFSTOUFS(mp);
+       fs = ump->um_fs;
+       fs->fs_fsmnt[0] = '/';
+       bzero(fs->fs_fsmnt + 1, sizeof(fs->fs_fsmnt) - 1);
+       (void) copystr(ROOTNAME, ump->um_mntname, MNAMELEN - 1, &size);
+       bzero(ump->um_mntname + size, MNAMELEN - size);
+       vfs_unlock(mp);
+       inittodr(fs->fs_time);
+       return (0);
+}
+
+/*
+ * VFS Operations.
+ *
+ * mount system call
+ */
+ufs_mount(mp, path, data, ndp)
+       struct mount *mp;
+       char *path;
+       caddr_t data;
+       struct nameidata *ndp;
+{
+       struct vnode *devvp;
+       struct ufs_args args;
+       struct ufsmount *ump;
+       register struct fs *fs;
+       u_int size;
+       int error;
+
+       if (error = copyin(data, (caddr_t)&args, sizeof (struct ufs_args)))
+               return (error);
+       if ((error = getmdev(&devvp, args.fspec, ndp)) != 0)
+               return (error);
+       error = mountfs(devvp, mp);
+       if (error) {
+               vrele(devvp);
+               return (error);
        }
        }
-       (void) copyinstr(uap->freg, fs->fs_fsmnt, sizeof(fs->fs_fsmnt)-1, &len);
-       bzero(fs->fs_fsmnt + len, sizeof (fs->fs_fsmnt) - len);
+       ump = VFSTOUFS(mp);
+       fs = ump->um_fs;
+       (void) copyinstr(path, fs->fs_fsmnt, sizeof(fs->fs_fsmnt) - 1, &size);
+       bzero(fs->fs_fsmnt + size, sizeof(fs->fs_fsmnt) - size);
+       (void) copyinstr(args.fspec, ump->um_mntname, MNAMELEN - 1, &size);
+       bzero(ump->um_mntname + size, MNAMELEN - size);
+       return (0);
 }
 
 }
 
-struct fs *
-mountfs(dev, ronly, ip)
-       dev_t dev;
-       int ronly;
-       struct inode *ip;
+/*
+ * Common code for mount and mountroot
+ */
+mountfs(devvp, mp)
+       struct vnode *devvp;
+       struct mount *mp;
 {
 {
-       register struct mount *mp;
-       struct mount *fmp = NULL;
-       register struct buf *bp = NULL;
+       register struct ufsmount *ump;
+       struct ufsmount *fmp = NULL;
+       struct buf *bp = NULL;
        register struct fs *fs;
        register struct fs *fs;
+       dev_t dev = devvp->v_rdev;
        struct partinfo dpart;
        int havepart = 0, blks;
        caddr_t base, space;
        struct partinfo dpart;
        int havepart = 0, blks;
        caddr_t base, space;
-       int i, size;
-       register error;
+       int havepart = 0, blks;
+       int error, i, size;
        int needclose = 0;
        int needclose = 0;
+       int ronly = (mp->m_flag & M_RDONLY) != 0;
 
 
-       for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++) {
-               if (mp->m_fs == NULL) {
+       for (ump = &mounttab[0]; ump < &mounttab[NMOUNT]; ump++) {
+               if (ump->um_fs == NULL) {
                        if (fmp == NULL)
                        if (fmp == NULL)
-                               fmp = mp;
-               } else if (dev == mp->m_dev) {
-                       u.u_error = EBUSY;              /* XXX */
-                       return ((struct fs *) NULL);
+                               fmp = ump;
+               } else if (dev == ump->um_dev) {
+                       return (EBUSY);         /* needs translation */
                }
        }
                }
        }
-       if ((mp = fmp) == NULL) {
-               u.u_error = EMFILE;             /* needs translation      XXX */
-               return ((struct fs *) NULL);
-       }
-       mp->m_fs = (struct fs *)1;      /* just to reserve this slot */
-       mp->m_dev = dev;
-       mp->m_inodp = NULL;
-       error =
            (*bdevsw[major(dev)].d_open)(dev, ronly ? FREAD : FREAD|FWRITE,
                S_IFBLK);
        if (error) {
            (*bdevsw[major(dev)].d_open)(dev, ronly ? FREAD : FREAD|FWRITE,
                S_IFBLK);
        if (error) {
-               u.u_error = error;
-               mp->m_fs = NULL;
-               return ((struct fs *) NULL);
+               ump->um_fs = NULL;
+               return (error);
        }
        needclose = 1;
        }
        needclose = 1;
-       if ((*bdevsw[major(dev)].d_ioctl)(dev, DIOCGPART,
-           (caddr_t)&dpart, FREAD) == 0) {
-               havepart = 1;
-               size = dpart.disklab->d_secsize;
-       } else
+       if (VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, FREAD,
+           (struct ucred *)0) != 0)
                size = DEV_BSIZE;
                size = DEV_BSIZE;
-#ifdef SECSIZE
-       /*
-        * If possible, determine hardware sector size
-        * and adjust fsbtodb to correspond.
-        */
-#endif SECSIZE
-       if ((*bdevsw[major(dev)].d_ioctl)(dev, DIOCGPART,
-           (caddr_t)&dpart, FREAD) == 0) {
+       else {
                havepart = 1;
                size = dpart.disklab->d_secsize;
                havepart = 1;
                size = dpart.disklab->d_secsize;
-#ifdef SECSIZE
-               if (size < MINSECSIZE) {
-                       error = EINVAL;
-                       goto out;
-               }
-#endif SECSIZE
-       } else
-               size = DEV_BSIZE;
-#ifdef SECSIZE
-       tp = bread(dev, (daddr_t)(SBOFF / size), SBSIZE, size);
-#else SECSIZE
-       bp = bread(dev, SBLOCK, SBSIZE);
-       if (bp->b_flags & B_ERROR) {
-               mp->m_fs = NULL;
+       }
+       if (error = bread(devvp, SBLOCK, SBSIZE, &bp)) {
+               ump->um_fs = NULL;
                goto out;
        }
        fs = bp->b_un.b_fs;
                goto out;
        }
        fs = bp->b_un.b_fs;
-       if (fs->fs_magic != FS_MAGIC || fs->fs_bsize > MAXBSIZE ||
-           fs->fs_bsize < sizeof(struct fs)) {
-               error = EINVAL;         /* also needs translation */
+               ump->um_fs = NULL;
+               error = EINVAL;         /* XXX also needs translation */
                goto out;
        }
                goto out;
        }
-       mp->m_fs = (struct fs *)malloc((u_long)fs->fs_sbsize, M_SUPERBLK,
+       ump->um_fs = (struct fs *)malloc((u_long)fs->fs_sbsize, M_SUPERBLK,
            M_WAITOK);
            M_WAITOK);
-       bcopy((caddr_t)bp->b_un.b_addr, (caddr_t)mp->m_fs,
+       bcopy((caddr_t)bp->b_un.b_addr, (caddr_t)ump->um_fs,
           (u_int)fs->fs_sbsize);
        brelse(bp);
        bp = NULL;
           (u_int)fs->fs_sbsize);
        brelse(bp);
        bp = NULL;
-       fs = mp->m_fs;
-       fs->fs_ronly = (ronly != 0);
+       fs = ump->um_fs;
+       fs->fs_ronly = ronly;
        if (ronly == 0)
                fs->fs_fmod = 1;
        if (havepart) {
        if (ronly == 0)
                fs->fs_fmod = 1;
        if (havepart) {
@@ -190,10 +238,6 @@ mountfs(dev, ronly, ip)
        blks = howmany(fs->fs_cssize, fs->fs_fsize);
        base = space = (caddr_t)malloc((u_long)fs->fs_cssize, M_SUPERBLK,
            M_WAITOK);
        blks = howmany(fs->fs_cssize, fs->fs_fsize);
        base = space = (caddr_t)malloc((u_long)fs->fs_cssize, M_SUPERBLK,
            M_WAITOK);
-       if (space == NULL) {
-               error = ENOMEM;
-               goto out;
-       }
        for (i = 0; i < blks; i += fs->fs_frag) {
                size = fs->fs_bsize;
                if (i + fs->fs_frag > blks)
        for (i = 0; i < blks; i += fs->fs_frag) {
                size = fs->fs_bsize;
                if (i + fs->fs_frag > blks)
@@ -202,8 +246,8 @@ mountfs(dev, ronly, ip)
                tp = bread(dev, fsbtodb(fs, fs->fs_csaddr + i), size,
                    fs->fs_dbsize);
 #else SECSIZE
                tp = bread(dev, fsbtodb(fs, fs->fs_csaddr + i), size,
                    fs->fs_dbsize);
 #else SECSIZE
-               bp = bread(dev, fsbtodb(fs, fs->fs_csaddr + i), size);
-               if (bp->b_flags&B_ERROR) {
+               error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + i), size, &bp);
+               if (error) {
                        free((caddr_t)base, M_SUPERBLK);
                        goto out;
                }
                        free((caddr_t)base, M_SUPERBLK);
                        goto out;
                }
@@ -213,64 +257,53 @@ mountfs(dev, ronly, ip)
                brelse(bp);
                bp = NULL;
        }
                brelse(bp);
                bp = NULL;
        }
-       mp->m_inodp = ip;
-       if (ip) {
-               ip->i_flag |= IMOUNT;
-               cacheinval(ip);
-               iunlock(ip);
-       }
+       mp->m_data = (qaddr_t)ump;
+       mp->m_bsize = fs->fs_bsize;
+       mp->m_fsize = fs->fs_fsize;
+       mp->m_fsid.val[0] = (long)dev;
+       mp->m_fsid.val[1] = MOUNT_UFS;
+       ump->um_mountp = mp;
+       ump->um_dev = dev;
+       ump->um_devvp = devvp;
+       ump->um_qinod = NULL;
+
        /* Sanity checks for old file systems.                     XXX */
        fs->fs_npsect = MAX(fs->fs_npsect, fs->fs_nsect);       /* XXX */
        fs->fs_interleave = MAX(fs->fs_interleave, 1);          /* XXX */
        if (fs->fs_postblformat == FS_42POSTBLFMT)              /* XXX */
                fs->fs_nrpos = 8;                               /* XXX */
 
        /* Sanity checks for old file systems.                     XXX */
        fs->fs_npsect = MAX(fs->fs_npsect, fs->fs_nsect);       /* XXX */
        fs->fs_interleave = MAX(fs->fs_interleave, 1);          /* XXX */
        if (fs->fs_postblformat == FS_42POSTBLFMT)              /* XXX */
                fs->fs_nrpos = 8;                               /* XXX */
 
-       return (fs);
+       return (0);
 out:
        if (needclose)
 out:
        if (needclose)
-               (void) closei(dev, IFBLK, ronly? FREAD : FREAD|FWRITE);
-       if (mp->m_fs) {
-               free((caddr_t)mp->m_fs, M_SUPERBLK);
-               mp->m_fs = NULL;
+               (void) VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE,
+                       (struct ucred *)0);
+       if (ump->um_fs) {
+               free((caddr_t)ump->um_fs, M_SUPERBLK);
+               ump->um_fs = NULL;
        }
        if (bp)
                brelse(bp);
        }
        if (bp)
                brelse(bp);
-       u.u_error = error ? error : EIO;                        /* XXX */
-       return ((struct fs *) NULL);
+       return (error);
 }
 
 }
 
-umount()
-{
-       struct a {
-               char    *fspec;
-       } *uap = (struct a *)u.u_ap;
 
 
-       u.u_error = unmount1(uap->fspec, 0);
-}
-
-unmount1(fname, forcibly)
-       caddr_t fname;
-       int forcibly;
+/*
+ * unmount system call
+ */
+ufs_unmount(mp, flags)
+       struct mount *mp;
+       int flags;
 {
 {
-       dev_t dev;
-       register struct mount *mp;
-       int error;
-       register struct inode *ip;
+       register struct ufsmount *ump;
        register struct fs *fs;
        register struct fs *fs;
+       dev_t dev;
+       int error, ronly;
 
 
-       forcibly = 0;                                   /* XXX */
-       forcibly = 0;                                   /* XXX */
-       error = getmdev(&dev, fname);
-       if (error)
-               return (error);
-       for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++)
-               if (mp->m_fs != NULL && dev == mp->m_dev)
-                       goto found;
-       return (EINVAL);
-found:
-       xumount(dev);   /* remove unused sticky files from text table */
-       nchinval(dev);  /* flush the name cache */
-       update();
+       if (flags & MNT_FORCE)
+               return (EINVAL);
+       ump = VFSTOUFS(mp);
+       dev = ump->um_dev;
 #ifdef QUOTA
        if ((error = iflush(dev, mp->m_qinod)) && !forcibly)
 #else
 #ifdef QUOTA
        if ((error = iflush(dev, mp->m_qinod)) && !forcibly)
 #else
@@ -278,40 +311,152 @@ found:
 #endif
                return (error);
 #ifdef QUOTA
 #endif
                return (error);
 #ifdef QUOTA
-       closedq(mp);
+       (void)closedq(ump);
        /*
         * Here we have to iflush again to get rid of the quota inode.
         * A drag, but it would be ugly to cheat, & this doesn't happen often.
         */
        (void)iflush(dev, (struct inode *)NULL);
 #endif
        /*
         * Here we have to iflush again to get rid of the quota inode.
         * A drag, but it would be ugly to cheat, & this doesn't happen often.
         */
        (void)iflush(dev, (struct inode *)NULL);
 #endif
-       ip = mp->m_inodp;
-       ip->i_flag &= ~IMOUNT;
-       fs = mp->m_fs;
+       fs = ump->um_fs;
+       ronly = !fs->fs_ronly;
        free((caddr_t)fs->fs_csp[0], M_SUPERBLK);
        free((caddr_t)fs->fs_csp[0], M_SUPERBLK);
-       free((caddr_t)mp->m_fs, M_SUPERBLK);
-       mp->m_fs = NULL;
-       mp->m_dev = NODEV;
-       mpurge(mp - &mount[0]);
        error = closei(dev, IFBLK, fs->fs_ronly? FREAD : FREAD|FWRITE);
        irele(ip);
        return (error);
 }
 
        error = closei(dev, IFBLK, fs->fs_ronly? FREAD : FREAD|FWRITE);
        irele(ip);
        return (error);
 }
 
-sbupdate(mp)
+/*
+ * Return root of a filesystem
+ */
+ufs_root(mp, vpp)
+       struct mount *mp;
+       struct vnode **vpp;
+{
+       struct inode tip, *ip;
+       int error;
+
+       tip.i_dev = VFSTOUFS(mp)->um_dev;
+       tip.i_vnode.v_mount = mp;
+       error = iget(&tip, (ino_t)ROOTINO, &ip);
+       if (error)
+               return (error);
+       *vpp = ITOV(ip);
+       return (0);
+}
+
+/*
+ * Get file system statistics.
+ */
+ufs_statfs(mp, sbp)
+       struct mount *mp;
+       register struct statfs *sbp;
+{
+       register struct ufsmount *ump;
+       register struct fs *fs;
+
+       ump = VFSTOUFS(mp);
+       fs = ump->um_fs;
+       if (fs->fs_magic != FS_MAGIC)
+               panic("ufs_statfs");
+       sbp->f_type = MOUNT_UFS;
+       sbp->f_flags = mp->m_flag &~ (M_MLOCK|M_MWAIT);
+       sbp->f_fsize = fs->fs_fsize;
+       sbp->f_bsize = fs->fs_bsize;
+       sbp->f_blocks = fs->fs_dsize;
+       sbp->f_bfree = fs->fs_cstotal.cs_nbfree * fs->fs_frag +
+               fs->fs_cstotal.cs_nffree;
+       sbp->f_bavail = (fs->fs_dsize * (100 - fs->fs_minfree) / 100) -
+               (fs->fs_dsize - sbp->f_bfree);
+       if (sbp->f_bavail < 0)
+               sbp->f_bavail = 0;
+       sbp->f_files =  fs->fs_ncg * fs->fs_ipg;
+       sbp->f_ffree = fs->fs_cstotal.cs_nifree;
+       sbp->f_fsid = mp->m_fsid;
+       bcopy((caddr_t)fs->fs_fsmnt, (caddr_t)&sbp->f_mntonname[0], MNAMELEN);
+       bcopy((caddr_t)ump->um_mntname, (caddr_t)&sbp->f_mntfromname[0],
+               MNAMELEN);
+       return (0);
+}
+
+int    syncprt = 0;
+
+/*
+ * Go through the disk queues to initiate sandbagged IO;
+ * go through the inodes to write those that have been modified;
+ * initiate the writing of the super block if it has been modified.
+ */
+ufs_sync(mp, waitfor)
        struct mount *mp;
        struct mount *mp;
+       int waitfor;
 {
 {
-       register struct fs *fs = mp->m_fs;
+       register struct inode *ip;
+       register struct ufsmount *ump = VFSTOUFS(mp);
+       register struct fs *fs;
+       int error = 0;
+       static int updlock = 0;
+
+       if (syncprt)
+               bufstats();
+       if (updlock)
+               return (EBUSY);
+       fs = ump->um_fs;
+       if (fs == (struct fs *)1)
+               return (0);
+       updlock++;
+       /*
+        * Write back modified superblock.
+        * Consistency check that the superblock
+        * is still in the buffer cache.
+        */
+       if (fs->fs_fmod != 0) {
+               if (fs->fs_ronly != 0) {                /* XXX */
+                       printf("fs = %s\n", fs->fs_fsmnt);
+                       panic("update: rofs mod");
+               }
+               fs->fs_fmod = 0;
+               fs->fs_time = time.tv_sec;
+               error = sbupdate(ump, waitfor);
+       }
+       /*
+        * Write back each (modified) inode.
+        */
+       for (ip = inode; ip < inodeNINODE; ip++) {
+               if (ip->i_devvp != ump->um_devvp ||
+                   (ip->i_flag & ILOCKED) != 0 || ITOV(ip)->v_count == 0 ||
+                   (ip->i_flag & (IMOD|IACC|IUPD|ICHG)) == 0)
+                       continue;
+               ip->i_flag |= ILOCKED;
+               ITOV(ip)->v_count++;
+               error = iupdat(ip, &time, &time, waitfor == MNT_WAIT);
+               iput(ip);
+       }
+       updlock = 0;
+       /*
+        * Force stale buffer cache information to be flushed.
+        */
+       bflush(ump->um_devvp->v_rdev);
+       return (error);
+}
+
+/*
+ * Write a superblock and associated information back to disk.
+ */
+sbupdate(mp, waitfor)
+       struct ufsmount *mp;
+       int waitfor;
+{
+       register struct fs *fs = mp->um_fs;
        register struct buf *bp;
        int blks;
        caddr_t space;
        register struct buf *bp;
        int blks;
        caddr_t space;
-       int i, size;
+       int i, size, error = 0;
 
 #ifdef SECSIZE
        bp = getblk(mp->m_dev, (daddr_t)fsbtodb(fs, SBOFF / fs->fs_fsize),
            (int)fs->fs_sbsize, fs->fs_dbsize);
 #else SECSIZE
 
 #ifdef SECSIZE
        bp = getblk(mp->m_dev, (daddr_t)fsbtodb(fs, SBOFF / fs->fs_fsize),
            (int)fs->fs_sbsize, fs->fs_dbsize);
 #else SECSIZE
-       bp = getblk(mp->m_dev, SBLOCK, (int)fs->fs_sbsize);
+       bp = getblk(mp->um_devvp, SBLOCK, (int)fs->fs_sbsize);
 #endif SECSIZE
        bcopy((caddr_t)fs, bp->b_un.b_addr, (u_int)fs->fs_sbsize);
        /* Restore compatibility to old file systems.              XXX */
 #endif SECSIZE
        bcopy((caddr_t)fs, bp->b_un.b_addr, (u_int)fs->fs_sbsize);
        /* Restore compatibility to old file systems.              XXX */
@@ -324,7 +469,10 @@ sbupdate(mp)
        bp->b_un.b_fs->fs_sparecon[0] = 0;
 #endif
 #endif SECSIZE
        bp->b_un.b_fs->fs_sparecon[0] = 0;
 #endif
 #endif SECSIZE
-       bwrite(bp);
+       if (waitfor == MNT_WAIT)
+               error = bwrite(bp);
+       else
+               bawrite(bp);
        blks = howmany(fs->fs_cssize, fs->fs_fsize);
        space = (caddr_t)fs->fs_csp[0];
        for (i = 0; i < blks; i += fs->fs_frag) {
        blks = howmany(fs->fs_cssize, fs->fs_fsize);
        space = (caddr_t)fs->fs_csp[0];
        for (i = 0; i < blks; i += fs->fs_frag) {
@@ -335,46 +483,118 @@ sbupdate(mp)
                bp = getblk(mp->m_dev, fsbtodb(fs, fs->fs_csaddr + i), size,
                    fs->fs_dbsize);
 #else SECSIZE
                bp = getblk(mp->m_dev, fsbtodb(fs, fs->fs_csaddr + i), size,
                    fs->fs_dbsize);
 #else SECSIZE
-               bp = getblk(mp->m_dev, fsbtodb(fs, fs->fs_csaddr + i), size);
+               bp = getblk(mp->um_devvp, fsbtodb(fs, fs->fs_csaddr + i), size);
 #endif SECSIZE
                bcopy(space, bp->b_un.b_addr, (u_int)size);
                space += size;
 #endif SECSIZE
                bcopy(space, bp->b_un.b_addr, (u_int)size);
                space += size;
-               bwrite(bp);
+               if (waitfor == MNT_WAIT)
+                       error = bwrite(bp);
+               else
+                       bawrite(bp);
        }
        }
+       return (error);
 }
 
 /*
 }
 
 /*
- * Common code for mount and umount.
+ * Print out statistics on the current allocation of the buffer pool.
+ * Can be enabled to print out on every ``sync'' by setting "syncprt"
+ * above.
+ */
+bufstats()
+{
+       int s, i, j, count;
+       register struct buf *bp, *dp;
+       int counts[MAXBSIZE/CLBYTES+1];
+       static char *bname[BQUEUES] = { "LOCKED", "LRU", "AGE", "EMPTY" };
+
+       for (bp = bfreelist, i = 0; bp < &bfreelist[BQUEUES]; bp++, i++) {
+               count = 0;
+               for (j = 0; j <= MAXBSIZE/CLBYTES; j++)
+                       counts[j] = 0;
+               s = splbio();
+               for (dp = bp->av_forw; dp != bp; dp = dp->av_forw) {
+                       counts[dp->b_bufsize/CLBYTES]++;
+                       count++;
+               }
+               splx(s);
+               printf("%s: total-%d", bname[i], count);
+               for (j = 0; j <= MAXBSIZE/CLBYTES; j++)
+                       if (counts[j] != 0)
+                               printf(", %d-%d", j * CLBYTES, counts[j]);
+               printf("\n");
+       }
+}
+
+/*
+ * File handle to vnode
+ */
+ufs_fhtovp(mp, fhp, vpp)
+       struct mount *mp;
+       struct fid *fhp;
+       struct vnode **vpp;
+{
+       register struct ufid *ufhp;
+       struct inode tip, *ip;
+       int error;
+
+       ufhp = (struct ufid *)fhp;
+       tip.i_dev = VFSTOUFS(mp)->um_dev;
+       tip.i_vnode.v_mount = mp;
+       if (error = iget(&tip, ufhp->ufid_ino, &ip)) {
+               *vpp = NULL;
+               return (error);
+       }
+       if (ip->i_gen != ufhp->ufid_gen) {
+               iput(ip);
+               *vpp = NULL;
+               return (EINVAL);
+       }
+       *vpp = ITOV(ip);
+       return (0);
+}
+
+/*
+ * Vnode pointer to File handle, should never happen.
+ */
+/* ARGSUSED */
+ufs_vptofh(mp, fhp, vpp)
+       struct mount *mp;
+       struct fid *fhp;
+       struct vnode **vpp;
+{
+
+       return (EINVAL);
+}
+
+/*
+ * Common code for mount and quota.
  * Check that the user's argument is a reasonable
  * thing on which to mount, and return the device number if so.
  */
  * Check that the user's argument is a reasonable
  * thing on which to mount, and return the device number if so.
  */
-getmdev(pdev, fname)
+getmdev(devvpp, fname, ndp)
+       struct vnode **devvpp;
        caddr_t fname;
        caddr_t fname;
-       dev_t *pdev;
+       register struct nameidata *ndp;
 {
 {
-       dev_t dev;
-       register struct inode *ip;
-       register struct nameidata *ndp = &u.u_nd;
+       register struct vnode *vp;
+       int error;
 
 
-       if (u.u_error = suser(u.u_cred, &u.u_acflag))
-               return (u.u_error);
-       ndp->ni_nameiop = LOOKUP | FOLLOW;
+       ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW;
        ndp->ni_segflg = UIO_USERSPACE;
        ndp->ni_dirp = fname;
        ndp->ni_segflg = UIO_USERSPACE;
        ndp->ni_dirp = fname;
-       ip = namei(ndp);
-       if (ip == NULL) {
-               if (u.u_error == ENOENT)
-                       return (ENODEV); /* needs translation */
-               return (u.u_error);
+       if (error = namei(ndp)) {
+               if (error == ENOENT)
+                       return (ENODEV);        /* needs translation */
+               return (error);
        }
        }
-       if ((ip->i_mode&IFMT) != IFBLK) {
-               iput(ip);
+       vp = ndp->ni_vp;
+       if (vp->v_type != VBLK) {
+               vput(vp);
                return (ENOTBLK);
        }
                return (ENOTBLK);
        }
-       dev = (dev_t)ip->i_rdev;
-       iput(ip);
-       if (major(dev) >= nblkdev)
+       if (major(vp->v_rdev) >= nblkdev)
                return (ENXIO);
                return (ENXIO);
-       *pdev = dev;
+       iunlock(VTOI(vp));
+       *devvpp = vp;
        return (0);
 }
        return (0);
 }
index c26614e..44547b4 100644 (file)
 /*
 /*
- * Copyright (c) 1982, 1986 Regents of the University of California.
- * All rights reserved.  The Berkeley software License Agreement
- * specifies the terms and conditions for redistribution.
+ * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
+ * All rights reserved.
  *
  *
- *     @(#)ffs_vnops.c 7.6 (Berkeley) %G%
+ * 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.
+ *
+ *     @(#)ffs_vnops.c 7.7 (Berkeley) %G%
  */
 
 #include "param.h"
 #include "systm.h"
  */
 
 #include "param.h"
 #include "systm.h"
-#include "dir.h"
 #include "user.h"
 #include "kernel.h"
 #include "file.h"
 #include "stat.h"
 #include "user.h"
 #include "kernel.h"
 #include "file.h"
 #include "stat.h"
-#include "inode.h"
-#include "fs.h"
 #include "buf.h"
 #include "proc.h"
 #include "buf.h"
 #include "proc.h"
-#include "quota.h"
 #include "uio.h"
 #include "socket.h"
 #include "socketvar.h"
 #include "uio.h"
 #include "socket.h"
 #include "socketvar.h"
+#include "conf.h"
 #include "mount.h"
 #include "mount.h"
-
-extern struct fileops inodeops;
-struct file *getinode();
+#include "vnode.h"
+#include "../ufs/inode.h"
+#include "../ufs/fs.h"
+#include "../ufs/quota.h"
 
 /*
 
 /*
- * Change current working directory (``.'').
+ * Global vfs data structures for ufs
  */
  */
-chdir()
-{
 
 
-       chdirec(&u.u_cdir);
-}
+int    ufs_lookup(),
+       ufs_create(),
+       ufs_mknod(),
+       ufs_open(),
+       ufs_close(),
+       ufs_access(),
+       ufs_getattr(),
+       ufs_setattr(),
+       ufs_read(),
+       ufs_write(),
+       ufs_ioctl(),
+       ufs_select(),
+       ufs_mmap(),
+       ufs_fsync(),
+       ufs_seek(),
+       ufs_remove(),
+       ufs_link(),
+       ufs_rename(),
+       ufs_mkdir(),
+       ufs_rmdir(),
+       ufs_symlink(),
+       ufs_readdir(),
+       ufs_readlink(),
+       ufs_abortop(),
+       ufs_inactive(),
+       ufs_lock(),
+       ufs_unlock(),
+       ufs_bmap(),
+       ufs_strategy();
+
+struct vnodeops ufs_vnodeops = {
+       ufs_lookup,
+       ufs_create,
+       ufs_mknod,
+       ufs_open,
+       ufs_close,
+       ufs_access,
+       ufs_getattr,
+       ufs_setattr,
+       ufs_read,
+       ufs_write,
+       ufs_ioctl,
+       ufs_select,
+       ufs_mmap,
+       ufs_fsync,
+       ufs_seek,
+       ufs_remove,
+       ufs_link,
+       ufs_rename,
+       ufs_mkdir,
+       ufs_rmdir,
+       ufs_symlink,
+       ufs_readdir,
+       ufs_readlink,
+       ufs_abortop,
+       ufs_inactive,
+       ufs_lock,
+       ufs_unlock,
+       ufs_bmap,
+       ufs_strategy,
+};
+
+enum vtype iftovt_tab[8] = {
+       VNON, VCHR, VDIR, VBLK, VREG, VLNK, VSOCK, VBAD,
+};
+int    vttoif_tab[8] = {
+       0, IFREG, IFDIR, IFBLK, IFCHR, IFLNK, IFSOCK, IFMT,
+};
 
 /*
 
 /*
- * Change notion of root (``/'') directory.
+ * Create a regular file
  */
  */
-chroot()
+ufs_create(ndp, vap)
+       struct nameidata *ndp;
+       struct vattr *vap;
 {
 {
+       struct inode *ip;
+       int error;
 
 
-       if (u.u_error = suser(u.u_cred, &u.u_acflag))
-               return;
-       chdirec(&u.u_rdir);
+       if (error = maknode(MAKEIMODE(vap->va_type, vap->va_mode), ndp, &ip))
+               return (error);
+       ndp->ni_vp = ITOV(ip);
+       return (0);
 }
 
 /*
 }
 
 /*
- * Common routine for chroot and chdir.
+ * Mknod vnode call
  */
  */
-chdirec(ipp)
-       register struct inode **ipp;
+/* ARGSUSED */
+ufs_mknod(ndp, vap, cred)
+       struct nameidata *ndp;
+       struct ucred *cred;
+       struct vattr *vap;
 {
 {
-       register struct inode *ip;
-       struct a {
-               char    *fname;
-       } *uap = (struct a *)u.u_ap;
-       register struct nameidata *ndp = &u.u_nd;
-
-       ndp->ni_nameiop = LOOKUP | FOLLOW;
-       ndp->ni_segflg = UIO_USERSPACE;
-       ndp->ni_dirp = uap->fname;
-       ip = namei(ndp);
-       if (ip == NULL)
-               return;
-       if ((ip->i_mode&IFMT) != IFDIR) {
-               u.u_error = ENOTDIR;
-               goto bad;
-       }
-       if (access(ip, IEXEC))
-               goto bad;
-       IUNLOCK(ip);
-       if (*ipp)
-               irele(*ipp);
-       *ipp = ip;
-       return;
+       struct inode *ip;
+       int error;
 
 
-bad:
+       if (error = maknode(MAKEIMODE(vap->va_type, vap->va_mode), ndp, &ip))
+               return (error);
+       if (vap->va_rdev) {
+               /*
+                * Want to be able to use this to make badblock
+                * inodes, so don't truncate the dev number.
+                */
+               ITOV(ip)->v_rdev = ip->i_rdev = vap->va_rdev;
+               ip->i_flag |= IACC|IUPD|ICHG;
+       }
        iput(ip);
        iput(ip);
+       /*
+        * Remove inode so that it will be reloaded by iget and
+        * checked to see if it is an alias of an existing entry
+        * in the inode cache.
+        */
+       remque(ip);
+       ip->i_forw = ip;
+       ip->i_back = ip;
+       return (0);
 }
 
 /*
 }
 
 /*
- * Open system call.
+ * Open called.
+ *
+ * Nothing to do.
  */
  */
-open()
+/* ARGSUSED */
+ufs_open(vp, mode, cred)
+       struct vnode *vp;
+       int mode;
+       struct ucred *cred;
 {
 {
-       struct a {
-               char    *fname;
-               int     mode;
-               int     crtmode;
-       } *uap = (struct a *) u.u_ap;
 
 
-       copen(uap->mode-FOPEN, uap->crtmode, uap->fname);
+       return (0);
 }
 
 /*
 }
 
 /*
- * Creat system call.
+ * Close called
+ *
+ * Update the times on the inode.
  */
  */
-creat()
+/* ARGSUSED */
+ufs_close(vp, fflag, cred)
+       struct vnode *vp;
+       int fflag;
+       struct ucred *cred;
 {
 {
-       struct a {
-               char    *fname;
-               int     fmode;
-       } *uap = (struct a *)u.u_ap;
+       register struct inode *ip = VTOI(vp);
 
 
-       copen(FWRITE|FCREAT|FTRUNC, uap->fmode, uap->fname);
-}
-
-/*
- * Common code for open and creat.
- * Check permissions, allocate an open file structure,
- * and call the device open routine if any.
- */
-copen(mode, arg, fname)
-       register int mode;
-       int arg;
-       caddr_t fname;
-{
-       register struct inode *ip;
-       register struct file *fp;
-       register struct nameidata *ndp = &u.u_nd;
-       int indx;
-
-       fp = falloc();
-       if (fp == NULL)
-               return;
-       indx = u.u_r.r_val1;
-       ndp->ni_segflg = UIO_USERSPACE;
-       ndp->ni_dirp = fname;
-       if (mode&FCREAT) {
-               if (mode & FEXCL)
-                       ndp->ni_nameiop = CREATE;
-               else
-                       ndp->ni_nameiop = CREATE | FOLLOW;
-               ip = namei(ndp);
-               if (ip == NULL) {
-                       if (u.u_error)
-                               goto bad1;
-                       ip = maknode(arg&07777&(~ISVTX), ndp);
-                       if (ip == NULL)
-                               goto bad1;
-                       mode &= ~FTRUNC;
-               } else {
-                       if (mode&FEXCL) {
-                               u.u_error = EEXIST;
-                               goto bad;
-                       }
-                       mode &= ~FCREAT;
-               }
-       } else {
-               ndp->ni_nameiop = LOOKUP | FOLLOW;
-               ip = namei(ndp);
-               if (ip == NULL)
-                       goto bad1;
-       }
-       if ((ip->i_mode & IFMT) == IFSOCK) {
-               u.u_error = EOPNOTSUPP;
-               goto bad;
-       }
-       if ((mode&FCREAT) == 0) {
-               if (mode&FREAD)
-                       if (access(ip, IREAD))
-                               goto bad;
-               if (mode&(FWRITE|FTRUNC)) {
-                       if (access(ip, IWRITE))
-                               goto bad;
-                       if ((ip->i_mode&IFMT) == IFDIR) {
-                               u.u_error = EISDIR;
-                               goto bad;
-                       }
-               }
-       }
-       if (mode&FTRUNC)
-               itrunc(ip, (u_long)0);
-       IUNLOCK(ip);
-       fp->f_flag = mode&FMASK;
-       fp->f_type = DTYPE_INODE;
-       fp->f_ops = &inodeops;
-       fp->f_data = (caddr_t)ip;
-       if (setjmp(&u.u_qsave)) {
-               if (u.u_error == 0)
-                       u.u_error = EINTR;
-               u.u_ofile[indx] = NULL;
-               closef(fp);
-               return;
-       }
-       u.u_error = openi(ip, mode);
-       if (u.u_error == 0)
-               return;
-       ILOCK(ip);
-bad:
-       iput(ip);
-bad1:
-       u.u_ofile[indx] = NULL;
-       fp->f_count--;
+       if (vp->v_count > 1 && !(ip->i_flag & ILOCKED))
+               ITIMES(ip, &time, &time);
+       return (0);
 }
 
 }
 
-/*
- * Mknod system call
- */
-mknod()
+ufs_access(vp, mode, cred)
+       struct vnode *vp;
+       int mode;
+       struct ucred *cred;
 {
 {
-       register struct inode *ip;
-       register struct a {
-               char    *fname;
-               int     fmode;
-               int     dev;
-       } *uap = (struct a *)u.u_ap;
-       register struct nameidata *ndp = &u.u_nd;
-
-       if (u.u_error = suser(u.u_cred, &u.u_acflag))
-               return;
-       ndp->ni_nameiop = CREATE;
-       ndp->ni_segflg = UIO_USERSPACE;
-       ndp->ni_dirp = uap->fname;
-       ip = namei(ndp);
-       if (ip != NULL) {
-               u.u_error = EEXIST;
-               goto out;
-       }
-       if (u.u_error)
-               return;
-       ip = maknode(uap->fmode, ndp);
-       if (ip == NULL)
-               return;
-       switch (ip->i_mode & IFMT) {
-
-       case IFMT:      /* used by badsect to flag bad sectors */
-       case IFCHR:
-       case IFBLK:
-               if (uap->dev) {
-                       /*
-                        * Want to be able to use this to make badblock
-                        * inodes, so don't truncate the dev number.
-                        */
-                       ip->i_rdev = uap->dev;
-                       ip->i_flag |= IACC|IUPD|ICHG;
-               }
-       }
 
 
-out:
-       iput(ip);
+       return (iaccess(VTOI(vp), mode, cred));
 }
 
 }
 
-/*
- * link system call
- */
-link()
+/* ARGSUSED */
+ufs_getattr(vp, vap, cred)
+       struct vnode *vp;
+       register struct vattr *vap;
+       struct ucred *cred;
 {
 {
-       register struct inode *ip, *xp;
-       register struct a {
-               char    *target;
-               char    *linkname;
-       } *uap = (struct a *)u.u_ap;
-       register struct nameidata *ndp = &u.u_nd;
-
-       ndp->ni_nameiop = LOOKUP | FOLLOW;
-       ndp->ni_segflg = UIO_USERSPACE;
-       ndp->ni_dirp = uap->target;
-       ip = namei(ndp);        /* well, this routine is doomed anyhow */
-       if (ip == NULL)
-               return;
-       if ((ip->i_mode&IFMT) == IFDIR &&
-           (u.u_error = suser(u.u_cred, &u.u_acflag))) {
-               iput(ip);
-               return;
-       }
-       if (ip->i_nlink == LINK_MAX - 1) {
-               u.u_error = EMLINK;
-               iput(ip);
-               return;
-       }
-       ip->i_nlink++;
-       ip->i_flag |= ICHG;
-       iupdat(ip, &time, &time, 1);
-       IUNLOCK(ip);
-       ndp->ni_nameiop = CREATE;
-       ndp->ni_segflg = UIO_USERSPACE;
-       ndp->ni_dirp = (caddr_t)uap->linkname;
-       xp = namei(ndp);
-       if (xp != NULL) {
-               u.u_error = EEXIST;
-               iput(xp);
-               goto out;
-       }
-       if (u.u_error)
-               goto out;
-       if (ndp->ni_pdir->i_dev != ip->i_dev) {
-               iput(ndp->ni_pdir);
-               u.u_error = EXDEV;
-               goto out;
-       }
-       u.u_error = direnter(ip, ndp);
-out:
-       if (u.u_error) {
-               ip->i_nlink--;
-               ip->i_flag |= ICHG;
-       }
-       irele(ip);
-}
-
-/*
- * symlink -- make a symbolic link
- */
-symlink()
-{
-       register struct a {
-               char    *target;
-               char    *linkname;
-       } *uap = (struct a *)u.u_ap;
-       register struct inode *ip;
-       register char *tp;
-       register c, nc;
-       register struct nameidata *ndp = &u.u_nd;
-
-       tp = uap->target;
-       nc = 0;
-       while (c = fubyte(tp)) {
-               if (c < 0) {
-                       u.u_error = EFAULT;
-                       return;
-               }
-               tp++;
-               nc++;
-       }
-       ndp->ni_nameiop = CREATE;
-       ndp->ni_segflg = UIO_USERSPACE;
-       ndp->ni_dirp = uap->linkname;
-       ip = namei(ndp);
-       if (ip) {
-               iput(ip);
-               u.u_error = EEXIST;
-               return;
-       }
-       if (u.u_error)
-               return;
-       ip = maknode(IFLNK | 0777, ndp);
-       if (ip == NULL)
-               return;
-       u.u_error = rdwri(UIO_WRITE, ip, uap->target, nc, (off_t)0, 0,
-           (int *)0);
-       /* handle u.u_error != 0 */
-       iput(ip);
-}
+       register struct inode *ip = VTOI(vp);
 
 
-/*
- * Unlink system call.
- * Hard to avoid races here, especially
- * in unlinking directories.
- */
-unlink()
-{
-       struct a {
-               char    *fname;
-       } *uap = (struct a *)u.u_ap;
-       register struct inode *ip, *dp;
-       register struct nameidata *ndp = &u.u_nd;
-
-       ndp->ni_nameiop = DELETE | LOCKPARENT;
-       ndp->ni_segflg = UIO_USERSPACE;
-       ndp->ni_dirp = uap->fname;
-       ip = namei(ndp);
-       if (ip == NULL)
-               return;
-       dp = ndp->ni_pdir;
-       if ((ip->i_mode&IFMT) == IFDIR &&
-           (u.u_error = suser(u.u_cred, &u.u_acflag)))
-               goto out;
+       ITIMES(ip, &time, &time);
        /*
        /*
-        * Don't unlink a mounted file.
+        * Copy from inode table
         */
         */
-       if (ip->i_dev != dp->i_dev) {
-               u.u_error = EBUSY;
-               goto out;
-       }
-       if (ip->i_flag&ITEXT)
-               xrele(ip);      /* try once to free text */
-       if (dirremove(ndp)) {
-               ip->i_nlink--;
-               ip->i_flag |= ICHG;
-       }
-out:
-       if (dp == ip)
-               irele(ip);
+       vap->va_fsid = ip->i_dev;
+       vap->va_fileid = ip->i_number;
+       vap->va_mode = ip->i_mode & ~IFMT;
+       vap->va_nlink = ip->i_nlink;
+       vap->va_uid = ip->i_uid;
+       vap->va_gid = ip->i_gid;
+       vap->va_rdev = (dev_t)ip->i_rdev;
+       vap->va_size = ip->i_ic.ic_size.val[0];
+       vap->va_size1 = ip->i_ic.ic_size.val[1];
+       vap->va_atime.tv_sec = ip->i_atime;
+       vap->va_mtime.tv_sec = ip->i_mtime;
+       vap->va_ctime.tv_sec = ip->i_ctime;
+       /* this doesn't belong here */
+       if (vp->v_type == VBLK)
+               vap->va_blocksize = BLKDEV_IOSIZE;
+       else if (vp->v_type == VCHR)
+               vap->va_blocksize = MAXBSIZE;
        else
        else
-               iput(ip);
-       iput(dp);
+               vap->va_blocksize = ip->i_fs->fs_bsize;
+       /*
+        * XXX THIS IS NOT CORRECT!!, but be sure to change vn_stat()
+        * if you change it.
+        */
+       vap->va_bytes = ip->i_blocks;
+       vap->va_bytes1 = -1;
+       vap->va_type = vp->v_type;
+       return (0);
 }
 
 /*
 }
 
 /*
- * Seek system call
+ * Set attribute vnode op. called from several syscalls
  */
  */
-lseek()
+ufs_setattr(vp, vap, cred)
+       register struct vnode *vp;
+       register struct vattr *vap;
+       register struct ucred *cred;
 {
 {
-       register struct file *fp;
-       register struct a {
-               int     fd;
-               off_t   off;
-               int     sbase;
-       } *uap = (struct a *)u.u_ap;
-
-       GETF(fp, uap->fd);
-       if (fp->f_type != DTYPE_INODE) {
-               u.u_error = ESPIPE;
-               return;
-       }
-       switch (uap->sbase) {
-
-       case L_INCR:
-               fp->f_offset += uap->off;
-               break;
-
-       case L_XTND:
-               fp->f_offset = uap->off + ((struct inode *)fp->f_data)->i_size;
-               break;
-
-       case L_SET:
-               fp->f_offset = uap->off;
-               break;
+       register struct inode *ip = VTOI(vp);
+       int error = 0;
 
 
-       default:
-               u.u_error = EINVAL;
-               return;
+       /*
+        * Check for unsetable attributes.
+        */
+       if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) ||
+           (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) ||
+           (vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) ||
+           ((int)vap->va_bytes != VNOVAL)) {
+               return (EINVAL);
        }
        }
-       u.u_r.r_off = fp->f_offset;
-}
-
-/*
- * Access system call
- */
-saccess()
-{
-       register svuid, svgid;
-       register struct inode *ip;
-       register struct a {
-               char    *fname;
-               int     fmode;
-       } *uap = (struct a *)u.u_ap;
-       register struct nameidata *ndp = &u.u_nd;
-
-       svuid = u.u_uid;
-       svgid = u.u_gid;
-       u.u_uid = u.u_ruid;
-       u.u_gid = u.u_rgid;
-       ndp->ni_nameiop = LOOKUP | FOLLOW;
-       ndp->ni_segflg = UIO_USERSPACE;
-       ndp->ni_dirp = uap->fname;
-       ip = namei(ndp);
-       if (ip != NULL) {
-               if ((uap->fmode&R_OK) && access(ip, IREAD))
-                       goto done;
-               if ((uap->fmode&W_OK) && access(ip, IWRITE))
-                       goto done;
-               if ((uap->fmode&X_OK) && access(ip, IEXEC))
-                       goto done;
-done:
-               iput(ip);
+       /*
+        * Go through the fields and update iff not VNOVAL.
+        */
+       if (vap->va_uid != (u_short)VNOVAL || vap->va_gid != (u_short)VNOVAL)
+               if (error = chown1(vp, vap->va_uid, vap->va_gid, cred))
+                       return (error);
+       if (vap->va_size != VNOVAL) {
+               if (vp->v_type == VDIR)
+                       return (EISDIR);
+               if (error = iaccess(ip, IWRITE, cred))
+                       return (error);
+               if (error = itrunc(ip, vap->va_size))
+                       return (error);
        }
        }
-       u.u_uid = svuid;
-       u.u_gid = svgid;
-}
-
-/*
- * Stat system call.  This version follows links.
- */
-stat()
-{
-
-       stat1(FOLLOW);
-}
-
-/*
- * Lstat system call.  This version does not follow links.
- */
-lstat()
-{
-
-       stat1(NOFOLLOW);
-}
-
-stat1(follow)
-       int follow;
-{
-       register struct inode *ip;
-       register struct a {
-               char    *fname;
-               struct stat *ub;
-       } *uap = (struct a *)u.u_ap;
-       struct stat sb;
-       register struct nameidata *ndp = &u.u_nd;
-
-       ndp->ni_nameiop = LOOKUP | follow;
-       ndp->ni_segflg = UIO_USERSPACE;
-       ndp->ni_dirp = uap->fname;
-       ip = namei(ndp);
-       if (ip == NULL)
-               return;
-       (void) ino_stat(ip, &sb);
-       iput(ip);
-       u.u_error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
-}
-
-/*
- * Return target name of a symbolic link
- */
-readlink()
-{
-       register struct inode *ip;
-       register struct a {
-               char    *name;
-               char    *buf;
-               int     count;
-       } *uap = (struct a *)u.u_ap;
-       register struct nameidata *ndp = &u.u_nd;
-       int resid;
-
-       ndp->ni_nameiop = LOOKUP;
-       ndp->ni_segflg = UIO_USERSPACE;
-       ndp->ni_dirp = uap->name;
-       ip = namei(ndp);
-       if (ip == NULL)
-               return;
-       if ((ip->i_mode&IFMT) != IFLNK) {
-               u.u_error = EINVAL;
-               goto out;
+       /*
+        * Check whether the following attributes can be changed.
+        */
+       if (cred->cr_uid != ip->i_uid &&
+           (error = suser(cred, &u.u_acflag)))
+               return (error);
+       if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) {
+               if (vap->va_atime.tv_sec != VNOVAL)
+                       ip->i_flag |= IACC;
+               if (vap->va_mtime.tv_sec != VNOVAL)
+                       ip->i_flag |= IUPD;
+               ip->i_flag |= ICHG;
+               if (error = iupdat(ip, &vap->va_atime, &vap->va_mtime, 1))
+                       return (error);
        }
        }
-       u.u_error = rdwri(UIO_READ, ip, uap->buf, uap->count, (off_t)0, 0,
-           &resid);
-out:
-       iput(ip);
-       u.u_r.r_val1 = uap->count - resid;
-}
-
-/*
- * Change mode of a file given path name.
- */
-chmod()
-{
-       struct inode *ip;
-       struct a {
-               char    *fname;
-               int     fmode;
-       } *uap = (struct a *)u.u_ap;
-
-       if ((ip = owner(uap->fname, FOLLOW)) == NULL)
-               return;
-       u.u_error = chmod1(ip, uap->fmode);
-       iput(ip);
-}
-
-/*
- * Change mode of a file given a file descriptor.
- */
-fchmod()
-{
-       struct a {
-               int     fd;
-               int     fmode;
-       } *uap = (struct a *)u.u_ap;
-       register struct inode *ip;
-       register struct file *fp;
-
-       fp = getinode(uap->fd);
-       if (fp == NULL)
-               return;
-       ip = (struct inode *)fp->f_data;
-       if (u.u_uid != ip->i_uid &&
-           (u.u_error = suser(u.u_cred, &u.u_acflag)))
-               return;
-       ILOCK(ip);
-       u.u_error = chmod1(ip, uap->fmode);
-       IUNLOCK(ip);
+       if (vap->va_mode != (u_short)VNOVAL)
+               error = chmod1(vp, (int)vap->va_mode, cred);
+       return (error);
 }
 
 /*
  * Change the mode on a file.
  * Inode must be locked before calling.
  */
 }
 
 /*
  * Change the mode on a file.
  * Inode must be locked before calling.
  */
-chmod1(ip, mode)
-       register struct inode *ip;
+chmod1(vp, mode, cred)
+       register struct vnode *vp;
        register int mode;
        register int mode;
+       struct ucred *cred;
 {
 {
+       register struct inode *ip = VTOI(vp);
 
 
-       if (ip->i_fs->fs_ronly)
-               return (EROFS);
        ip->i_mode &= ~07777;
        ip->i_mode &= ~07777;
-       if (u.u_uid) {
-               if ((ip->i_mode & IFMT) != IFDIR)
+       if (cred->cr_uid) {
+               if (vp->v_type != VDIR)
                        mode &= ~ISVTX;
                        mode &= ~ISVTX;
-               if (!groupmember(ip->i_gid))
+               if (!groupmember(ip->i_gid, cred))
                        mode &= ~ISGID;
        }
                        mode &= ~ISGID;
        }
-       ip->i_mode |= mode&07777;
+       ip->i_mode |= mode & 07777;
        ip->i_flag |= ICHG;
        ip->i_flag |= ICHG;
-       if (ip->i_flag&ITEXT && (ip->i_mode&ISVTX)==0)
-               xrele(ip);
+       if ((vp->v_flag & VTEXT) && (ip->i_mode & ISVTX) == 0)
+               xrele(vp);
        return (0);
 }
 
        return (0);
 }
 
-/*
- * Set ownership given a path name.
- */
-chown()
-{
-       struct inode *ip;
-       struct a {
-               char    *fname;
-               int     uid;
-               int     gid;
-       } *uap = (struct a *)u.u_ap;
-       register struct nameidata *ndp = &u.u_nd;
-
-       ndp->ni_nameiop = LOOKUP | NOFOLLOW;
-       ndp->ni_segflg = UIO_USERSPACE;
-       ndp->ni_dirp = uap->fname;
-       ip = namei(ndp);
-       if (ip == NULL)
-               return;
-       u.u_error = chown1(ip, uap->uid, uap->gid);
-       iput(ip);
-}
-
-/*
- * Set ownership given a file descriptor.
- */
-fchown()
-{
-       struct a {
-               int     fd;
-               int     uid;
-               int     gid;
-       } *uap = (struct a *)u.u_ap;
-       register struct inode *ip;
-       register struct file *fp;
-
-       fp = getinode(uap->fd);
-       if (fp == NULL)
-               return;
-       ip = (struct inode *)fp->f_data;
-       ILOCK(ip);
-       u.u_error = chown1(ip, uap->uid, uap->gid);
-       IUNLOCK(ip);
-}
-
 /*
  * Perform chown operation on inode ip;
  * inode must be locked prior to call.
  */
 /*
  * Perform chown operation on inode ip;
  * inode must be locked prior to call.
  */
-chown1(ip, uid, gid)
-       register struct inode *ip;
-       int uid, gid;
+chown1(vp, uid, gid, cred)
+       register struct vnode *vp;
+       uid_t uid;
+       gid_t gid;
+       struct ucred *cred;
 {
 {
+       register struct inode *ip = VTOI(vp);
 #ifdef QUOTA
        register long change;
 #endif
 #ifdef QUOTA
        register long change;
 #endif
+       int error;
 
 
-       if (ip->i_fs->fs_ronly)
-               return (EROFS);
-       if (uid == -1)
+       if (uid == (u_short)VNOVAL)
                uid = ip->i_uid;
                uid = ip->i_uid;
-       if (gid == -1)
+       if (gid == (u_short)VNOVAL)
                gid = ip->i_gid;
        /*
         * If we don't own the file, are trying to change the owner
         * of the file, or are not a member of the target group,
         * the caller must be superuser or the call fails.
         */
                gid = ip->i_gid;
        /*
         * If we don't own the file, are trying to change the owner
         * of the file, or are not a member of the target group,
         * the caller must be superuser or the call fails.
         */
-       if ((u.u_uid != ip->i_uid || uid != ip->i_uid ||
-           !groupmember((gid_t)gid)) &&
-           (u.u_error = suser(u.u_cred, &u.u_acflag)))
-               return (u.u_error);
+       if ((cred->cr_uid != ip->i_uid || uid != ip->i_uid ||
+           !groupmember((gid_t)gid, cred)) &&
+           (error = suser(cred, &u.u_acflag)))
+               return (error);
 #ifdef QUOTA
        if (ip->i_uid == uid)           /* this just speeds things a little */
                change = 0;
 #ifdef QUOTA
        if (ip->i_uid == uid)           /* this just speeds things a little */
                change = 0;
@@ -682,7 +361,7 @@ chown1(ip, uid, gid)
        ip->i_uid = uid;
        ip->i_gid = gid;
        ip->i_flag |= ICHG;
        ip->i_uid = uid;
        ip->i_gid = gid;
        ip->i_flag |= ICHG;
-       if (u.u_ruid != 0)
+       if (cred->cr_ruid != 0)
                ip->i_mode &= ~(ISUID|ISGID);
 #ifdef QUOTA
        ip->i_dquot = inoquota(ip);
                ip->i_mode &= ~(ISUID|ISGID);
 #ifdef QUOTA
        ip->i_dquot = inoquota(ip);
@@ -694,113 +373,135 @@ chown1(ip, uid, gid)
 #endif
 }
 
 #endif
 }
 
-utimes()
+/* ARGSUSED */
+ufs_ioctl(vp, com, data, fflag, cred)
+       struct vnode *vp;
+       int com;
+       caddr_t data;
+       int fflag;
+       struct ucred *cred;
 {
 {
-       register struct a {
-               char    *fname;
-               struct  timeval *tptr;
-       } *uap = (struct a *)u.u_ap;
-       register struct inode *ip;
-       struct timeval tv[2];
 
 
-       if ((ip = owner(uap->fname, FOLLOW)) == NULL)
-               return;
-       if (ip->i_fs->fs_ronly) {
-               u.u_error = EROFS;
-               iput(ip);
-               return;
-       }
-       u.u_error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv));
-       if (u.u_error == 0) {
-               ip->i_flag |= IACC|IUPD|ICHG;
-               iupdat(ip, &tv[0], &tv[1], 0);
-       }
-       iput(ip);
+       printf("ufs_ioctl called with type %d\n", vp->v_type);
+       return (ENOTTY);
+}
+
+/* ARGSUSED */
+ufs_select(vp, which, cred)
+       struct vnode *vp;
+       int which;
+       struct ucred *cred;
+{
+
+       printf("ufs_select called with type %d\n", vp->v_type);
+       return (1);             /* XXX */
 }
 
 /*
 }
 
 /*
- * Flush any pending I/O.
+ * Mmap a file
+ *
+ * NB Currently unsupported.
  */
  */
-sync()
+/* ARGSUSED */
+ufs_mmap(vp, fflags, cred)
+       struct vnode *vp;
+       int fflags;
+       struct ucred *cred;
 {
 
 {
 
-       update();
+       return (EINVAL);
 }
 
 /*
 }
 
 /*
- * Truncate a file given its path name.
+ * Synch an open file.
  */
  */
-truncate()
+/* ARGSUSED */
+ufs_fsync(vp, fflags, cred)
+       struct vnode *vp;
+       int fflags;
+       struct ucred *cred;
 {
 {
-       struct a {
-               char    *fname;
-               off_t   length;
-       } *uap = (struct a *)u.u_ap;
-       struct inode *ip;
-       register struct nameidata *ndp = &u.u_nd;
-
-       ndp->ni_nameiop = LOOKUP | FOLLOW;
-       ndp->ni_segflg = UIO_USERSPACE;
-       ndp->ni_dirp = uap->fname;
-       ip = namei(ndp);
-       if (ip == NULL)
-               return;
-       if (access(ip, IWRITE))
-               goto bad;
-       if ((ip->i_mode&IFMT) == IFDIR) {
-               u.u_error = EISDIR;
-               goto bad;
-       }
-       itrunc(ip, (u_long)uap->length);
-bad:
-       iput(ip);
+       register struct inode *ip = VTOI(vp);
+       int error;
+
+       ILOCK(ip);
+       if (fflags&FWRITE)
+               ip->i_flag |= ICHG;
+       error = syncip(ip);
+       IUNLOCK(ip);
+       return (error);
 }
 
 /*
 }
 
 /*
- * Truncate a file given a file descriptor.
+ * Seek on a file
+ *
+ * Nothing to do, so just return.
  */
  */
-ftruncate()
+/* ARGSUSED */
+ufs_seek(vp, oldoff, newoff, cred)
+       struct vnode *vp;
+       off_t oldoff, newoff;
+       struct ucred *cred;
 {
 {
-       struct a {
-               int     fd;
-               off_t   length;
-       } *uap = (struct a *)u.u_ap;
-       struct inode *ip;
-       struct file *fp;
-
-       fp = getinode(uap->fd);
-       if (fp == NULL)
-               return;
-       if ((fp->f_flag&FWRITE) == 0) {
-               u.u_error = EINVAL;
-               return;
+
+       return (0);
+}
+
+/*
+ * ufs remove
+ * Hard to avoid races here, especially
+ * in unlinking directories.
+ */
+ufs_remove(ndp)
+       struct nameidata *ndp;
+{
+       register struct inode *ip, *dp;
+       int error;
+
+       ip = VTOI(ndp->ni_vp);
+       dp = VTOI(ndp->ni_dvp);
+       error = dirremove(ndp);
+       if (!error) {
+               ip->i_nlink--;
+               ip->i_flag |= ICHG;
        }
        }
-       ip = (struct inode *)fp->f_data;
-       ILOCK(ip);
-       itrunc(ip, (u_long)uap->length);
-       IUNLOCK(ip);
+       if (dp == ip)
+               vrele(ITOV(ip));
+       else
+               iput(ip);
+       iput(dp);
+       return (error);
 }
 
 /*
 }
 
 /*
- * Synch an open file.
+ * link vnode call
  */
  */
-fsync()
+ufs_link(vp, ndp)
+       register struct vnode *vp;
+       register struct nameidata *ndp;
 {
 {
-       struct a {
-               int     fd;
-       } *uap = (struct a *)u.u_ap;
-       struct inode *ip;
-       struct file *fp;
+       register struct inode *ip = VTOI(vp);
+       int error;
 
 
-       fp = getinode(uap->fd);
-       if (fp == NULL)
-               return;
-       ip = (struct inode *)fp->f_data;
-       ILOCK(ip);
-       if (fp->f_flag&FWRITE)
+       if (ndp->ni_dvp != vp)
+               ILOCK(ip);
+       if (ip->i_nlink == LINK_MAX - 1) {
+               error = EMLINK;
+               goto out;
+       }
+       ip->i_nlink++;
+       ip->i_flag |= ICHG;
+       error = iupdat(ip, &time, &time, 1);
+       if (!error)
+               error = direnter(ip, ndp);
+out:
+       if (ndp->ni_dvp != vp)
+               IUNLOCK(ip);
+       if (error) {
+               ip->i_nlink--;
                ip->i_flag |= ICHG;
                ip->i_flag |= ICHG;
-       syncip(ip);
-       IUNLOCK(ip);
+       }
+       return (error);
 }
 
 /*
 }
 
 /*
@@ -817,7 +518,7 @@ fsync()
  * Basic algorithm is:
  *
  * 1) Bump link count on source while we're linking it to the
  * Basic algorithm is:
  *
  * 1) Bump link count on source while we're linking it to the
- *    target.  This also insure the inode won't be deleted out
+ *    target.  This also ensure the inode won't be deleted out
  *    from underneath us while we work (it may be truncated by
  *    a concurrent `trunc' or `open' for creation).
  * 2) Link source to destination.  If destination already exists,
  *    from underneath us while we work (it may be truncated by
  *    a concurrent `trunc' or `open' for creation).
  * 2) Link source to destination.  If destination already exists,
@@ -826,52 +527,36 @@ fsync()
  *    directory was moved and the parent of the destination
  *    is different from the source, patch the ".." entry in the
  *    directory.
  *    directory was moved and the parent of the destination
  *    is different from the source, patch the ".." entry in the
  *    directory.
- *
- * Source and destination must either both be directories, or both
- * not be directories.  If target is a directory, it must be empty.
  */
  */
-rename()
+ufs_rename(fndp, tndp)
+       register struct nameidata *fndp, *tndp;
 {
 {
-       struct a {
-               char    *from;
-               char    *to;
-       } *uap = (struct a *)u.u_ap;
        register struct inode *ip, *xp, *dp;
        struct dirtemplate dirbuf;
        int doingdirectory = 0, oldparent = 0, newparent = 0;
        register struct inode *ip, *xp, *dp;
        struct dirtemplate dirbuf;
        int doingdirectory = 0, oldparent = 0, newparent = 0;
-       register struct nameidata *ndp = &u.u_nd;
        int error = 0;
 
        int error = 0;
 
-       ndp->ni_nameiop = DELETE | LOCKPARENT;
-       ndp->ni_segflg = UIO_USERSPACE;
-       ndp->ni_dirp = uap->from;
-       ip = namei(ndp);
-       if (ip == NULL)
-               return;
-       dp = ndp->ni_pdir;
+       dp = VTOI(fndp->ni_dvp);
+       ip = VTOI(fndp->ni_vp);
+       ILOCK(ip);
        if ((ip->i_mode&IFMT) == IFDIR) {
        if ((ip->i_mode&IFMT) == IFDIR) {
-               register struct direct *d;
+               register struct direct *d = &fndp->ni_dent;
 
 
-               d = &ndp->ni_dent;
                /*
                 * Avoid ".", "..", and aliases of "." for obvious reasons.
                 */
                /*
                 * Avoid ".", "..", and aliases of "." for obvious reasons.
                 */
-               if ((d->d_namlen == 1 && d->d_name[0] == '.') ||
-                   (d->d_namlen == 2 && bcmp(d->d_name, "..", 2) == 0) ||
-                   (dp == ip) || (ip->i_flag & IRENAME)) {
-                       iput(dp);
-                       if (dp == ip)
-                               irele(ip);
-                       else
-                               iput(ip);
-                       u.u_error = EINVAL;
-                       return;
+               if ((d->d_namlen == 1 && d->d_name[0] == '.') || dp == ip ||
+                   fndp->ni_isdotdot || (ip->i_flag & IRENAME)) {
+                       IUNLOCK(ip);
+                       ufs_abortop(fndp);
+                       ufs_abortop(tndp);
+                       return (EINVAL);
                }
                ip->i_flag |= IRENAME;
                oldparent = dp->i_number;
                doingdirectory++;
        }
                }
                ip->i_flag |= IRENAME;
                oldparent = dp->i_number;
                doingdirectory++;
        }
-       iput(dp);
+       vrele(fndp->ni_dvp);
 
        /*
         * 1) Bump link count while we're moving stuff
 
        /*
         * 1) Bump link count while we're moving stuff
@@ -881,21 +566,17 @@ rename()
         */
        ip->i_nlink++;
        ip->i_flag |= ICHG;
         */
        ip->i_nlink++;
        ip->i_flag |= ICHG;
-       iupdat(ip, &time, &time, 1);
+       error = iupdat(ip, &time, &time, 1);
        IUNLOCK(ip);
 
        /*
         * When the target exists, both the directory
        IUNLOCK(ip);
 
        /*
         * When the target exists, both the directory
-        * and target inodes are returned locked.
+        * and target vnodes are returned locked.
         */
         */
-       ndp->ni_nameiop = CREATE | LOCKPARENT | NOCACHE;
-       ndp->ni_dirp = (caddr_t)uap->to;
-       xp = namei(ndp);
-       if (u.u_error) {
-               error = u.u_error;
-               goto out;
-       }
-       dp = ndp->ni_pdir;
+       dp = VTOI(tndp->ni_dvp);
+       xp = NULL;
+       if (tndp->ni_vp)
+               xp = VTOI(tndp->ni_vp);
        /*
         * If ".." must be changed (ie the directory gets a new
         * parent) then the source directory must not be in the
        /*
         * If ".." must be changed (ie the directory gets a new
         * parent) then the source directory must not be in the
@@ -909,21 +590,21 @@ rename()
        if (oldparent != dp->i_number)
                newparent = dp->i_number;
        if (doingdirectory && newparent) {
        if (oldparent != dp->i_number)
                newparent = dp->i_number;
        if (doingdirectory && newparent) {
-               if (access(ip, IWRITE))
+               if (error = iaccess(ip, IWRITE, tndp->ni_cred))
                        goto bad;
                        goto bad;
+               tndp->ni_nameiop = RENAME | LOCKPARENT | LOCKLEAF | NOCACHE;
                do {
                do {
-                       dp = ndp->ni_pdir;
+                       dp = VTOI(tndp->ni_dvp);
                        if (xp != NULL)
                        if (xp != NULL)
-                               iput(xp);
-                       u.u_error = checkpath(ip, dp);
-                       if (u.u_error)
+                               vput(ITOV(xp));
+                       if (error = checkpath(ip, dp, tndp->ni_cred))
                                goto out;
                                goto out;
-                       xp = namei(ndp);
-                       if (u.u_error) {
-                               error = u.u_error;
+                       if (error = namei(tndp))
                                goto out;
                                goto out;
-                       }
-               } while (dp != ndp->ni_pdir);
+                       xp = NULL;
+                       if (tndp->ni_vp)
+                               xp = VTOI(tndp->ni_vp);
+               } while (dp != VTOI(tndp->ni_dvp));
        }
        /*
         * 2) If target doesn't exist, link the target
        }
        /*
         * 2) If target doesn't exist, link the target
@@ -933,10 +614,8 @@ rename()
         *    expunge the original entry's existence.
         */
        if (xp == NULL) {
         *    expunge the original entry's existence.
         */
        if (xp == NULL) {
-               if (dp->i_dev != ip->i_dev) {
-                       error = EXDEV;
-                       goto bad;
-               }
+               if (dp->i_dev != ip->i_dev)
+                       panic("rename: EXDEV");
                /*
                 * Account for ".." in new directory.
                 * When source and destination have the same
                /*
                 * Account for ".." in new directory.
                 * When source and destination have the same
@@ -945,29 +624,27 @@ rename()
                if (doingdirectory && newparent) {
                        dp->i_nlink++;
                        dp->i_flag |= ICHG;
                if (doingdirectory && newparent) {
                        dp->i_nlink++;
                        dp->i_flag |= ICHG;
-                       iupdat(dp, &time, &time, 1);
+                       error = iupdat(dp, &time, &time, 1);
                }
                }
-               error = direnter(ip, ndp);
-               if (error)
+               if (error = direnter(ip, tndp))
                        goto out;
        } else {
                        goto out;
        } else {
-               if (xp->i_dev != dp->i_dev || xp->i_dev != ip->i_dev) {
-                       error = EXDEV;
-                       goto bad;
-               }
+               if (xp->i_dev != dp->i_dev || xp->i_dev != ip->i_dev)
+                       panic("rename: EXDEV");
                /*
                 * Short circuit rename(foo, foo).
                 */
                if (xp->i_number == ip->i_number)
                /*
                 * Short circuit rename(foo, foo).
                 */
                if (xp->i_number == ip->i_number)
-                       goto bad;
+                       panic("rename: same file");
                /*
                 * If the parent directory is "sticky", then the user must
                 * own the parent directory, or the destination of the rename,
                 * otherwise the destination may not be changed (except by
                 * root). This implements append-only directories.
                 */
                /*
                 * If the parent directory is "sticky", then the user must
                 * own the parent directory, or the destination of the rename,
                 * otherwise the destination may not be changed (except by
                 * root). This implements append-only directories.
                 */
-               if ((dp->i_mode & ISVTX) && u.u_uid != 0 &&
-                   u.u_uid != dp->i_uid && xp->i_uid != u.u_uid) {
+               if ((dp->i_mode & ISVTX) && tndp->ni_cred->cr_uid != 0 &&
+                   tndp->ni_cred->cr_uid != dp->i_uid &&
+                   xp->i_uid != tndp->ni_cred->cr_uid) {
                        error = EPERM;
                        goto bad;
                }
                        error = EPERM;
                        goto bad;
                }
@@ -979,7 +656,8 @@ rename()
                 * not directories).
                 */
                if ((xp->i_mode&IFMT) == IFDIR) {
                 * not directories).
                 */
                if ((xp->i_mode&IFMT) == IFDIR) {
-                       if (!dirempty(xp, dp->i_number) || xp->i_nlink > 2) {
+                       if (!dirempty(xp, dp->i_number, tndp->ni_cred) || 
+                           xp->i_nlink > 2) {
                                error = ENOTEMPTY;
                                goto bad;
                        }
                                error = ENOTEMPTY;
                                goto bad;
                        }
@@ -987,16 +665,14 @@ rename()
                                error = ENOTDIR;
                                goto bad;
                        }
                                error = ENOTDIR;
                                goto bad;
                        }
-                       cacheinval(dp);
+                       cache_purge(ITOV(dp));
                } else if (doingdirectory) {
                        error = EISDIR;
                        goto bad;
                }
                } else if (doingdirectory) {
                        error = EISDIR;
                        goto bad;
                }
-               dirrewrite(dp, ip, ndp);
-               if (u.u_error) {
-                       error = u.u_error;
-                       goto bad1;
-               }
+               if (error = dirrewrite(dp, ip, tndp))
+                       goto bad;
+               vput(ITOV(dp));
                /*
                 * Adjust the link count of the target to
                 * reflect the dirrewrite above.  If this is
                /*
                 * Adjust the link count of the target to
                 * reflect the dirrewrite above.  If this is
@@ -1011,32 +687,33 @@ rename()
                if (doingdirectory) {
                        if (--xp->i_nlink != 0)
                                panic("rename: linked directory");
                if (doingdirectory) {
                        if (--xp->i_nlink != 0)
                                panic("rename: linked directory");
-                       itrunc(xp, (u_long)0);
+                       error = itrunc(xp, (u_long)0);
                }
                xp->i_flag |= ICHG;
                }
                xp->i_flag |= ICHG;
-               iput(xp);
+               vput(ITOV(xp));
                xp = NULL;
        }
 
        /*
         * 3) Unlink the source.
         */
                xp = NULL;
        }
 
        /*
         * 3) Unlink the source.
         */
-       ndp->ni_nameiop = DELETE | LOCKPARENT;
-       ndp->ni_segflg = UIO_USERSPACE;
-       ndp->ni_dirp = uap->from;
-       xp = namei(ndp);
-       if (xp != NULL)
-               dp = ndp->ni_pdir;
-       else
+       fndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF;
+       (void)namei(fndp);
+       if (fndp->ni_vp != NULL) {
+               xp = VTOI(fndp->ni_vp);
+               dp = VTOI(fndp->ni_dvp);
+       } else {
+               xp = NULL;
                dp = NULL;
                dp = NULL;
+       }
        /*
        /*
-        * Insure that the directory entry still exists and has not
+        * Ensure that the directory entry still exists and has not
         * changed while the new name has been entered. If the source is
         * a file then the entry may have been unlinked or renamed. In
         * either case there is no further work to be done. If the source
         * is a directory then it cannot have been rmdir'ed; its link
         * count of three would cause a rmdir to fail with ENOTEMPTY.
         * changed while the new name has been entered. If the source is
         * a file then the entry may have been unlinked or renamed. In
         * either case there is no further work to be done. If the source
         * is a directory then it cannot have been rmdir'ed; its link
         * count of three would cause a rmdir to fail with ENOTEMPTY.
-        * The IRENAME flag insures that it cannot be moved by another
+        * The IRENAME flag ensures that it cannot be moved by another
         * rename.
         */
        if (xp != ip) {
         * rename.
         */
        if (xp != ip) {
@@ -1053,8 +730,8 @@ rename()
                        dp->i_nlink--;
                        dp->i_flag |= ICHG;
                        error = rdwri(UIO_READ, xp, (caddr_t)&dirbuf,
                        dp->i_nlink--;
                        dp->i_flag |= ICHG;
                        error = rdwri(UIO_READ, xp, (caddr_t)&dirbuf,
-                               sizeof (struct dirtemplate), (off_t)0, 1,
-                               (int *)0);
+                               sizeof (struct dirtemplate), (off_t)0,
+                               UIO_USERSPACE, tndp->ni_cred, (int *)0);
                        if (error == 0) {
                                if (dirbuf.dotdot_namlen != 2 ||
                                    dirbuf.dotdot_name[0] != '.' ||
                        if (error == 0) {
                                if (dirbuf.dotdot_namlen != 2 ||
                                    dirbuf.dotdot_name[0] != '.' ||
@@ -1065,96 +742,35 @@ rename()
                                        (void) rdwri(UIO_WRITE, xp,
                                            (caddr_t)&dirbuf,
                                            sizeof (struct dirtemplate),
                                        (void) rdwri(UIO_WRITE, xp,
                                            (caddr_t)&dirbuf,
                                            sizeof (struct dirtemplate),
-                                           (off_t)0, 1, (int *)0);
-                                       cacheinval(dp);
+                                           (off_t)0, UIO_USERSPACE,
+                                           tndp->ni_cred, (int *)0);
+                                       cache_purge(ITOV(dp));
                                }
                        }
                }
                                }
                        }
                }
-               if (dirremove(ndp)) {
+               error = dirremove(fndp);
+               if (!error) {
                        xp->i_nlink--;
                        xp->i_flag |= ICHG;
                }
                xp->i_flag &= ~IRENAME;
                        xp->i_nlink--;
                        xp->i_flag |= ICHG;
                }
                xp->i_flag &= ~IRENAME;
-               if (error == 0)         /* XXX conservative */
-                       error = u.u_error;
        }
        if (dp)
        }
        if (dp)
-               iput(dp);
+               vput(ITOV(dp));
        if (xp)
        if (xp)
-               iput(xp);
-       irele(ip);
-       if (error)
-               u.u_error = error;
-       return;
+               vput(ITOV(xp));
+       vrele(ITOV(ip));
+       return (error);
 
 bad:
 
 bad:
-       iput(dp);
-bad1:
        if (xp)
        if (xp)
-               iput(xp);
+               vput(ITOV(xp));
+       vput(ITOV(dp));
 out:
        ip->i_nlink--;
        ip->i_flag |= ICHG;
 out:
        ip->i_nlink--;
        ip->i_flag |= ICHG;
-       irele(ip);
-       if (error)
-               u.u_error = error;
-}
-
-/*
- * Make a new file.
- */
-struct inode *
-maknode(mode, ndp)
-       int mode;
-       register struct nameidata *ndp;
-{
-       register struct inode *ip;
-       register struct inode *pdir = ndp->ni_pdir;
-       ino_t ipref;
-
-       if ((mode & IFMT) == IFDIR)
-               ipref = dirpref(pdir->i_fs);
-       else
-               ipref = pdir->i_number;
-       ip = ialloc(pdir, ipref, mode);
-       if (ip == NULL) {
-               iput(pdir);
-               return (NULL);
-       }
-#ifdef QUOTA
-       if (ip->i_dquot != NODQUOT)
-               panic("maknode: dquot");
-#endif
-       ip->i_flag |= IACC|IUPD|ICHG;
-       if ((mode & IFMT) == 0)
-               mode |= IFREG;
-       ip->i_mode = mode & ~u.u_cmask;
-       ip->i_nlink = 1;
-       ip->i_uid = u.u_uid;
-       ip->i_gid = pdir->i_gid;
-       if (ip->i_mode & ISGID && !groupmember(ip->i_gid) &&
-           (u.u_error = suser(u.u_cred, &u.u_acflag)))
-               ip->i_mode &= ~ISGID;
-#ifdef QUOTA
-       ip->i_dquot = inoquota(ip);
-#endif
-
-       /*
-        * Make sure inode goes to disk before directory entry.
-        */
-       iupdat(ip, &time, &time, 1);
-       u.u_error = direnter(ip, ndp);
-       if (u.u_error) {
-               /*
-                * Write error occurred trying to update directory
-                * so must deallocate the inode.
-                */
-               ip->i_nlink = 0;
-               ip->i_flag |= ICHG;
-               iput(ip);
-               return (NULL);
-       }
-       return (ip);
+       vrele(ITOV(ip));
+       return (error);
 }
 
 /*
 }
 
 /*
@@ -1168,30 +784,21 @@ struct dirtemplate mastertemplate = {
 /*
  * Mkdir system call
  */
 /*
  * Mkdir system call
  */
-mkdir()
+ufs_mkdir(ndp, vap)
+       struct nameidata *ndp;
+       struct vattr *vap;
 {
 {
-       struct a {
-               char    *name;
-               int     dmode;
-       } *uap = (struct a *)u.u_ap;
        register struct inode *ip, *dp;
        register struct inode *ip, *dp;
+       struct inode *tip;
+       struct vnode *dvp;
        struct dirtemplate dirtemplate;
        struct dirtemplate dirtemplate;
-       register struct nameidata *ndp = &u.u_nd;
-
-       ndp->ni_nameiop = CREATE;
-       ndp->ni_segflg = UIO_USERSPACE;
-       ndp->ni_dirp = uap->name;
-       ip = namei(ndp);
-       if (u.u_error)
-               return;
-       if (ip != NULL) {
-               iput(ip);
-               u.u_error = EEXIST;
-               return;
-       }
-       dp = ndp->ni_pdir;
-       uap->dmode &= 0777;
-       uap->dmode |= IFDIR;
+       int error;
+       int dmode;
+
+       dvp = ndp->ni_dvp;
+       dp = VTOI(dvp);
+       dmode = vap->va_mode&0777;
+       dmode |= IFDIR;
        /*
         * Must simulate part of maknode here
         * in order to acquire the inode, but
        /*
         * Must simulate part of maknode here
         * in order to acquire the inode, but
@@ -1199,24 +806,26 @@ mkdir()
         * directory.  The entry is made later
         * after writing "." and ".." entries out.
         */
         * directory.  The entry is made later
         * after writing "." and ".." entries out.
         */
-       ip = ialloc(dp, dirpref(dp->i_fs), uap->dmode);
-       if (ip == NULL) {
+       error = ialloc(dp, dirpref(dp->i_fs), dmode, &tip);
+       if (error) {
                iput(dp);
                iput(dp);
-               return;
+               return (error);
        }
        }
+       ip = tip;
 #ifdef QUOTA
        if (ip->i_dquot != NODQUOT)
                panic("mkdir: dquot");
 #endif
        ip->i_flag |= IACC|IUPD|ICHG;
 #ifdef QUOTA
        if (ip->i_dquot != NODQUOT)
                panic("mkdir: dquot");
 #endif
        ip->i_flag |= IACC|IUPD|ICHG;
-       ip->i_mode = uap->dmode & ~u.u_cmask;
+       ip->i_mode = dmode;
+       ITOV(ip)->v_type = VDIR;        /* Rest init'd in iget() */
        ip->i_nlink = 2;
        ip->i_nlink = 2;
-       ip->i_uid = u.u_uid;
+       ip->i_uid = ndp->ni_cred->cr_uid;
        ip->i_gid = dp->i_gid;
 #ifdef QUOTA
        ip->i_dquot = inoquota(ip);
 #endif
        ip->i_gid = dp->i_gid;
 #ifdef QUOTA
        ip->i_dquot = inoquota(ip);
 #endif
-       iupdat(ip, &time, &time, 1);
+       error = iupdat(ip, &time, &time, 1);
 
        /*
         * Bump link count in parent directory
 
        /*
         * Bump link count in parent directory
@@ -1226,7 +835,7 @@ mkdir()
         */
        dp->i_nlink++;
        dp->i_flag |= ICHG;
         */
        dp->i_nlink++;
        dp->i_flag |= ICHG;
-       iupdat(dp, &time, &time, 1);
+       error = iupdat(dp, &time, &time, 1);
 
        /*
         * Initialize directory with "."
 
        /*
         * Initialize directory with "."
@@ -1235,15 +844,16 @@ mkdir()
        dirtemplate = mastertemplate;
        dirtemplate.dot_ino = ip->i_number;
        dirtemplate.dotdot_ino = dp->i_number;
        dirtemplate = mastertemplate;
        dirtemplate.dot_ino = ip->i_number;
        dirtemplate.dotdot_ino = dp->i_number;
-       u.u_error = rdwri(UIO_WRITE, ip, (caddr_t)&dirtemplate,
-               sizeof (dirtemplate), (off_t)0, 1, (int *)0);
-       if (u.u_error) {
+       error = rdwri(UIO_WRITE, ip, (caddr_t)&dirtemplate,
+               sizeof (dirtemplate), (off_t)0, UIO_SYSSPACE,
+               ndp->ni_cred, (int *)0);
+       if (error) {
                dp->i_nlink--;
                dp->i_flag |= ICHG;
                goto bad;
        }
                dp->i_nlink--;
                dp->i_flag |= ICHG;
                goto bad;
        }
-       if (DIRBLKSIZ > ip->i_fs->fs_fsize)
-               panic("mkdir: blksize");     /* XXX - should grow with bmap() */
+       if (DIRBLKSIZ > dp->i_fs->fs_fsize)
+               panic("mkdir: blksize");     /* XXX - should grow w/balloc() */
        else
                ip->i_size = DIRBLKSIZ;
        /*
        else
                ip->i_size = DIRBLKSIZ;
        /*
@@ -1251,14 +861,13 @@ mkdir()
         * install the entry for it in
         * the parent directory.
         */
         * install the entry for it in
         * the parent directory.
         */
-       u.u_error = direnter(ip, ndp);
+       error = direnter(ip, ndp);
        dp = NULL;
        dp = NULL;
-       if (u.u_error) {
+       if (error) {
                ndp->ni_nameiop = LOOKUP | NOCACHE;
                ndp->ni_nameiop = LOOKUP | NOCACHE;
-               ndp->ni_segflg = UIO_USERSPACE;
-               ndp->ni_dirp = uap->name;
-               dp = namei(ndp);
-               if (dp) {
+               error = namei(ndp);
+               if (!error) {
+                       dp = VTOI(ndp->ni_vp);
                        dp->i_nlink--;
                        dp->i_flag |= ICHG;
                }
                        dp->i_nlink--;
                        dp->i_flag |= ICHG;
                }
@@ -1266,55 +875,37 @@ mkdir()
 bad:
        /*
         * No need to do an explicit itrunc here,
 bad:
        /*
         * No need to do an explicit itrunc here,
-        * irele will do this for us because we set
+        * vrele will do this for us because we set
         * the link count to 0.
         */
         * the link count to 0.
         */
-       if (u.u_error) {
+       if (error) {
                ip->i_nlink = 0;
                ip->i_flag |= ICHG;
        }
                ip->i_nlink = 0;
                ip->i_flag |= ICHG;
        }
+       iput(ip);
        if (dp)
                iput(dp);
        if (dp)
                iput(dp);
-       iput(ip);
+       return (error);
 }
 
 /*
  * Rmdir system call.
  */
 }
 
 /*
  * Rmdir system call.
  */
-rmdir()
+ufs_rmdir(ndp)
+       register struct nameidata *ndp;
 {
 {
-       struct a {
-               char    *name;
-       } *uap = (struct a *)u.u_ap;
        register struct inode *ip, *dp;
        register struct inode *ip, *dp;
-       register struct nameidata *ndp = &u.u_nd;
-
-       ndp->ni_nameiop = DELETE | LOCKPARENT;
-       ndp->ni_segflg = UIO_USERSPACE;
-       ndp->ni_dirp = uap->name;
-       ip = namei(ndp);
-       if (ip == NULL)
-               return;
-       dp = ndp->ni_pdir;
+       int error = 0;
+
+       ip = VTOI(ndp->ni_vp);
+       dp = VTOI(ndp->ni_dvp);
        /*
         * No rmdir "." please.
         */
        if (dp == ip) {
        /*
         * No rmdir "." please.
         */
        if (dp == ip) {
-               irele(dp);
+               vrele(ITOV(dp));
                iput(ip);
                iput(ip);
-               u.u_error = EINVAL;
-               return;
-       }
-       if ((ip->i_mode&IFMT) != IFDIR) {
-               u.u_error = ENOTDIR;
-               goto out;
-       }
-       /*
-        * Don't remove a mounted on directory.
-        */
-       if (ip->i_dev != dp->i_dev) {
-               u.u_error = EBUSY;
-               goto out;
+               return (EINVAL);
        }
        /*
         * Verify the directory is empty (and valid).
        }
        /*
         * Verify the directory is empty (and valid).
@@ -1323,8 +914,8 @@ rmdir()
         *  the current directory and thus be
         *  non-empty.)
         */
         *  the current directory and thus be
         *  non-empty.)
         */
-       if (ip->i_nlink != 2 || !dirempty(ip, dp->i_number)) {
-               u.u_error = ENOTEMPTY;
+       if (ip->i_nlink != 2 || !dirempty(ip, dp->i_number, ndp->ni_cred)) {
+               error = ENOTEMPTY;
                goto out;
        }
        /*
                goto out;
        }
        /*
@@ -1332,13 +923,13 @@ rmdir()
         * inode.  If we crash in between, the directory
         * will be reattached to lost+found,
         */
         * inode.  If we crash in between, the directory
         * will be reattached to lost+found,
         */
-       if (dirremove(ndp) == 0)
+       if (error = dirremove(ndp))
                goto out;
        dp->i_nlink--;
        dp->i_flag |= ICHG;
                goto out;
        dp->i_nlink--;
        dp->i_flag |= ICHG;
-       cacheinval(dp);
+       cache_purge(ITOV(dp));
        iput(dp);
        iput(dp);
-       dp = NULL;
+       ndp->ni_dvp = NULL;
        /*
         * Truncate inode.  The only stuff left
         * in the directory is "." and "..".  The
        /*
         * Truncate inode.  The only stuff left
         * in the directory is "." and "..".  The
@@ -1351,40 +942,206 @@ rmdir()
         * worry about them later.
         */
        ip->i_nlink -= 2;
         * worry about them later.
         */
        ip->i_nlink -= 2;
-       itrunc(ip, (u_long)0);
-       cacheinval(ip);
+       error = itrunc(ip, (u_long)0);
+       cache_purge(ITOV(ip));
 out:
 out:
-       if (dp)
+       if (ndp->ni_dvp)
                iput(dp);
        iput(ip);
                iput(dp);
        iput(ip);
+       return (error);
 }
 
 }
 
-struct file *
-getinode(fdes)
-       int fdes;
+/*
+ * symlink -- make a symbolic link
+ */
+ufs_symlink(ndp, vap, target)
+       struct nameidata *ndp;
+       struct vattr *vap;
+       char *target;
+{
+       struct inode *ip;
+       int error;
+
+       error = maknode(IFLNK | vap->va_mode, ndp, &ip);
+       if (error)
+               return (error);
+       error = rdwri(UIO_WRITE, ip, target, strlen(target), (off_t)0,
+               UIO_SYSSPACE, ndp->ni_cred, (int *)0);
+       iput(ip);
+       return (error);
+}
+
+/*
+ * Vnode op for read and write
+ */
+ufs_readdir(vp, uio, offp, cred)
+       struct vnode *vp;
+       register struct uio *uio;
+       off_t *offp;
+       struct ucred *cred;
 {
 {
-       struct file *fp;
+       register struct inode *ip = VTOI(vp);
+       int count, error;
 
 
-       if ((unsigned)fdes >= NOFILE || (fp = u.u_ofile[fdes]) == NULL) {
-               u.u_error = EBADF;
-               return ((struct file *)0);
+       ILOCK(ip);
+       uio->uio_offset = *offp;
+       count = uio->uio_resid;
+       count &= ~(DIRBLKSIZ - 1);
+       if (vp->v_type != VDIR || uio->uio_iovcnt != 1 ||
+           (count < DIRBLKSIZ) || (uio->uio_offset & (DIRBLKSIZ -1))) {
+               IUNLOCK(ip);
+               return (EINVAL);
+       }
+       uio->uio_resid = count;
+       uio->uio_iov->iov_len = count;
+       error = readip(ip, uio, cred);
+       *offp += count - uio->uio_resid;
+       IUNLOCK(ip);
+       return (error);
+}
+
+/*
+ * Return target name of a symbolic link
+ */
+ufs_readlink(vp, uiop, cred)
+       struct vnode *vp;
+       struct uio *uiop;
+       struct ucred *cred;
+{
+
+       return (readip(VTOI(vp), uiop, cred));
+}
+
+/*
+ * Ufs abort op, called after namei() when a CREATE/DELETE isn't actually
+ * done. Iff ni_vp/ni_dvp not null and locked, unlock.
+ */
+ufs_abortop(ndp)
+       register struct nameidata *ndp;
+{
+       register struct inode *ip;
+
+       if (ndp->ni_vp) {
+               ip = VTOI(ndp->ni_vp);
+               if (ip->i_flag & ILOCKED)
+                       IUNLOCK(ip);
+               vrele(ndp->ni_vp);
        }
        }
-       if (fp->f_type != DTYPE_INODE) {
-               u.u_error = EINVAL;
-               return ((struct file *)0);
+       if (ndp->ni_dvp) {
+               ip = VTOI(ndp->ni_dvp);
+               if (ip->i_flag & ILOCKED)
+                       IUNLOCK(ip);
+               vrele(ndp->ni_dvp);
        }
        }
-       return (fp);
+       return;
+}
+
+ufs_lock(vp)
+       struct vnode *vp;
+{
+       register struct inode *ip = VTOI(vp);
+
+       ILOCK(ip);
+       return (0);
+}
+
+ufs_unlock(vp)
+       struct vnode *vp;
+{
+       register struct inode *ip = VTOI(vp);
+
+       if (!(ip->i_flag & ILOCKED))
+               panic("ufs_unlock NOT LOCKED");
+       IUNLOCK(ip);
+       return (0);
+}
+
+/*
+ * Get access to bmap
+ */
+ufs_bmap(vp, bn, vpp, bnp)
+       struct vnode *vp;
+       daddr_t bn;
+       struct vnode **vpp;
+       daddr_t *bnp;
+{
+       struct inode *ip = VTOI(vp);
+
+       if (vpp != NULL)
+               *vpp = ip->i_devvp;
+       if (bnp == NULL)
+               return (0);
+       return (bmap(ip, bn, bnp, (daddr_t *)0, (int *)0));
 }
 
 /*
 }
 
 /*
- * mode mask for creation of files
+ * Just call the device strategy routine
  */
  */
-umask()
+ufs_strategy(bp)
+       register struct buf *bp;
 {
 {
-       register struct a {
-               int     mask;
-       } *uap = (struct a *)u.u_ap;
+       (*bdevsw[major(bp->b_dev)].d_strategy)(bp);
+       return (0);
+}
 
 
-       u.u_r.r_val1 = u.u_cmask;
-       u.u_cmask = uap->mask & 07777;
+/*
+ * Make a new file.
+ */
+maknode(mode, ndp, ipp)
+       int mode;
+       register struct nameidata *ndp;
+       struct inode **ipp;
+{
+       register struct inode *ip;
+       struct inode *tip;
+       register struct inode *pdir = VTOI(ndp->ni_dvp);
+       ino_t ipref;
+       int error;
+
+       *ipp = 0;
+       if ((mode & IFMT) == IFDIR)
+               ipref = dirpref(pdir->i_fs);
+       else
+               ipref = pdir->i_number;
+       error = ialloc(pdir, ipref, mode, &tip);
+       if (error) {
+               iput(pdir);
+               return (error);
+       }
+       ip = tip;
+#ifdef QUOTA
+       if (ip->i_dquot != NODQUOT)
+               panic("maknode: dquot");
+#endif
+       ip->i_flag |= IACC|IUPD|ICHG;
+       if ((mode & IFMT) == 0)
+               mode |= IFREG;
+       ip->i_mode = mode;
+       ITOV(ip)->v_type = IFTOVT(mode);        /* Rest init'd in iget() */
+       ip->i_nlink = 1;
+       ip->i_uid = ndp->ni_cred->cr_uid;
+       ip->i_gid = pdir->i_gid;
+       if ((ip->i_mode & ISGID) && !groupmember(ip->i_gid, ndp->ni_cred) &&
+           suser(ndp->ni_cred, NULL))
+               ip->i_mode &= ~ISGID;
+#ifdef QUOTA
+       ip->i_dquot = inoquota(ip);
+#endif
+
+       /*
+        * Make sure inode goes to disk before directory entry.
+        */
+       if ((error = iupdat(ip, &time, &time, 1)) ||
+           (error = direnter(ip, ndp))) {
+               /*
+                * Write error occurred trying to update the inode
+                * or the directory so must deallocate the inode.
+                */
+               ip->i_nlink = 0;
+               ip->i_flag |= ICHG;
+               iput(ip);
+               return (error);
+       }
+       *ipp = ip;
+       return (0);
 }
 }
index c03f9cc..902d513 100644 (file)
@@ -1,9 +1,20 @@
 /*
  * Copyright (c) 1982, 1986, 1988 Regents of the University of California.
 /*
  * Copyright (c) 1982, 1986, 1988 Regents of the University of California.
- * All rights reserved.  The Berkeley software License Agreement
- * specifies the terms and conditions for redistribution.
+ * All rights reserved.
  *
  *
- *     @(#)ufs_disksubr.c      7.11 (Berkeley) %G%
+ * 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.
+ *
+ *     @(#)ufs_disksubr.c      7.12 (Berkeley) %G%
  */
 
 #include "param.h"
  */
 
 #include "param.h"
@@ -11,8 +22,6 @@
 #include "buf.h"
 #include "disklabel.h"
 #include "syslog.h"
 #include "buf.h"
 #include "disklabel.h"
 #include "syslog.h"
-
-#include "dir.h"
 #include "user.h"
 
 /*
 #include "user.h"
 
 /*
@@ -149,9 +158,7 @@ readdisklabel(dev, strat, lp)
        bp->b_flags = B_BUSY | B_READ;
        bp->b_cylin = LABELSECTOR / lp->d_secpercyl;
        (*strat)(bp);
        bp->b_flags = B_BUSY | B_READ;
        bp->b_cylin = LABELSECTOR / lp->d_secpercyl;
        (*strat)(bp);
-       biowait(bp);
-       if (bp->b_flags & B_ERROR) {
-               u.u_error = 0;          /* XXX */
+       if (biowait(bp)) {
                msg = "I/O error";
        } else for (dlp = (struct disklabel *)bp->b_un.b_addr;
            dlp <= (struct disklabel *)(bp->b_un.b_addr+DEV_BSIZE-sizeof(*dlp));
                msg = "I/O error";
        } else for (dlp = (struct disklabel *)bp->b_un.b_addr;
            dlp <= (struct disklabel *)(bp->b_un.b_addr+DEV_BSIZE-sizeof(*dlp));
@@ -244,12 +251,8 @@ writedisklabel(dev, strat, lp)
        bp->b_bcount = lp->d_secsize;
        bp->b_flags = B_READ;
        (*strat)(bp);
        bp->b_bcount = lp->d_secsize;
        bp->b_flags = B_READ;
        (*strat)(bp);
-       biowait(bp);
-       if (bp->b_flags & B_ERROR) {
-               error = u.u_error;              /* XXX */
-               u.u_error = 0;
+       if (error = biowait(bp))
                goto done;
                goto done;
-       }
        for (dlp = (struct disklabel *)bp->b_un.b_addr;
            dlp <= (struct disklabel *)
              (bp->b_un.b_addr + lp->d_secsize - sizeof(*dlp));
        for (dlp = (struct disklabel *)bp->b_un.b_addr;
            dlp <= (struct disklabel *)
              (bp->b_un.b_addr + lp->d_secsize - sizeof(*dlp));
@@ -259,11 +262,7 @@ writedisklabel(dev, strat, lp)
                        *dlp = *lp;
                        bp->b_flags = B_WRITE;
                        (*strat)(bp);
                        *dlp = *lp;
                        bp->b_flags = B_WRITE;
                        (*strat)(bp);
-                       biowait(bp);
-                       if (bp->b_flags & B_ERROR) {
-                               error = u.u_error;              /* XXX */
-                               u.u_error = 0;
-                       }
+                       error = biowait(bp);
                        goto done;
                }
        }
                        goto done;
                }
        }
index 7f3ea4f..b6a597f 100644 (file)
@@ -1,22 +1,35 @@
 /*
 /*
- * Copyright (c) 1982, 1986 Regents of the University of California.
- * All rights reserved.  The Berkeley software License Agreement
- * specifies the terms and conditions for redistribution.
+ * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
+ * All rights reserved.
  *
  *
- *     @(#)ufs_inode.c 7.5 (Berkeley) %G%
+ * 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 MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ *     @(#)ufs_inode.c 7.6 (Berkeley) %G%
  */
 
 #include "param.h"
 #include "systm.h"
 #include "mount.h"
  */
 
 #include "param.h"
 #include "systm.h"
 #include "mount.h"
-#include "dir.h"
 #include "user.h"
 #include "user.h"
-#include "inode.h"
-#include "fs.h"
+#include "file.h"
 #include "buf.h"
 #include "cmap.h"
 #include "buf.h"
 #include "cmap.h"
+#include "vnode.h"
+#include "../ufs/inode.h"
+#include "../ufs/fs.h"
+#include "../ufs/ufsmount.h"
 #ifdef QUOTA
 #ifdef QUOTA
-#include "quota.h"
+#include "../ufs/quota.h"
 #endif
 #include "kernel.h"
 #include "malloc.h"
 #endif
 #include "kernel.h"
 #include "malloc.h"
 #define        INOHASH(dev,ino)        (((unsigned)((dev)+(ino)))%INOHSZ)
 #endif
 
 #define        INOHASH(dev,ino)        (((unsigned)((dev)+(ino)))%INOHSZ)
 #endif
 
+#define INSFREE(ip) {\
+       if (ifreeh) { \
+               *ifreet = (ip); \
+               (ip)->i_freeb = ifreet; \
+       } else { \
+               ifreeh = (ip); \
+               (ip)->i_freeb = &ifreeh; \
+       } \
+       (ip)->i_freef = NULL; \
+       ifreet = &(ip)->i_freef; \
+}
+
 union ihead {                          /* inode LRU cache, Chris Maltby */
        union  ihead *ih_head[2];
        struct inode *ih_chain[2];
 } ihead[INOHSZ];
 
 union ihead {                          /* inode LRU cache, Chris Maltby */
        union  ihead *ih_head[2];
        struct inode *ih_chain[2];
 } ihead[INOHSZ];
 
-struct inode *ifreeh, **ifreet;
+struct inode *ifreeh, **ifreet, *bdevlisth;
 
 /*
  * Initialize hash links for inodes
 
 /*
  * Initialize hash links for inodes
@@ -54,10 +79,12 @@ ihinit()
        ip->i_freeb = &ifreeh;
        ip->i_forw = ip;
        ip->i_back = ip;
        ip->i_freeb = &ifreeh;
        ip->i_forw = ip;
        ip->i_back = ip;
+       ITOV(ip)->v_data = (qaddr_t)ip;
        for (i = ninode; --i > 0; ) {
                ++ip;
                ip->i_forw = ip;
                ip->i_back = ip;
        for (i = ninode; --i > 0; ) {
                ++ip;
                ip->i_forw = ip;
                ip->i_back = ip;
+               ITOV(ip)->v_data = (qaddr_t)ip;
                *ifreet = ip;
                ip->i_freeb = ifreet;
                ifreet = &ip->i_freef;
                *ifreet = ip;
                ip->i_freeb = ifreet;
                ifreet = &ip->i_freef;
@@ -65,55 +92,31 @@ ihinit()
        ip->i_freef = NULL;
 }
 
        ip->i_freef = NULL;
 }
 
-#ifdef notdef
 /*
 /*
- * Find an inode if it is incore.
- * This is the equivalent, for inodes,
- * of ``incore'' in bio.c or ``pfind'' in subr.c.
- */
-struct inode *
-ifind(dev, ino)
-       dev_t dev;
-       ino_t ino;
-{
-       register struct inode *ip;
-       register union  ihead *ih;
-
-       ih = &ihead[INOHASH(dev, ino)];
-       for (ip = ih->ih_chain[0]; ip != (struct inode *)ih; ip = ip->i_forw)
-               if (ino==ip->i_number && dev==ip->i_dev)
-                       return (ip);
-       return ((struct inode *)0);
-}
-#endif notdef
-
-/*
- * Look up an inode by device,inumber.
+ * Look up an vnode/inode by device,inumber.
  * If it is in core (in the inode structure),
  * honor the locking protocol.
  * If it is not in core, read it in from the
  * specified device.
  * If it is in core (in the inode structure),
  * honor the locking protocol.
  * If it is not in core, read it in from the
  * specified device.
- * If the inode is mounted on, perform
- * the indicated indirection.
+ * Callers must check for mount points!!
  * In all cases, a pointer to a locked
  * inode structure is returned.
  * In all cases, a pointer to a locked
  * inode structure is returned.
- *
- * panic: no imt -- if the mounted file
- *     system is not in the mount table.
- *     "cannot happen"
  */
  */
-struct inode *
-iget(dev, fs, ino)
-       dev_t dev;
-       register struct fs *fs;
+iget(xp, ino, ipp)
+       struct inode *xp;
        ino_t ino;
        ino_t ino;
+       struct inode **ipp;
 {
 {
-       register struct inode *ip;
-       register union  ihead *ih;
-       register struct mount *mp;
-       register struct buf *bp;
-       register struct dinode *dp;
-       register struct inode *iq;
+       dev_t dev = xp->i_dev;
+       struct mount *mntp = ITOV(xp)->v_mount;
+       register struct fs *fs = VFSTOUFS(mntp)->um_fs;
+       register struct inode *ip, *iq;
+       register struct vnode *vp;
+       struct inode *nip;
+       struct buf *bp;
+       struct dinode tdip, *dp;
+       union  ihead *ih;
+       int error;
 
 loop:
        ih = &ihead[INOHASH(dev, ino)];
 
 loop:
        ih = &ihead[INOHASH(dev, ino)];
@@ -131,17 +134,8 @@ loop:
                                sleep((caddr_t)ip, PINOD);
                                goto loop;
                        }
                                sleep((caddr_t)ip, PINOD);
                                goto loop;
                        }
-                       if ((ip->i_flag&IMOUNT) != 0) {
-                               for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++)
-                                       if(mp->m_inodp == ip) {
-                                               dev = mp->m_dev;
-                                               fs = mp->m_fs;
-                                               ino = ROOTINO;
-                                               goto loop;
-                                       }
-                               panic("no imt");
-                       }
-                       if (ip->i_count == 0) {         /* ino on free list */
+                       vp = ITOV(ip);
+                       if (vp->v_count == 0) {         /* ino on free list */
                                if (iq = ip->i_freef)
                                        iq->i_freeb = ip->i_freeb;
                                else
                                if (iq = ip->i_freef)
                                        iq->i_freeb = ip->i_freeb;
                                else
@@ -150,17 +144,153 @@ loop:
                                ip->i_freef = NULL;
                                ip->i_freeb = NULL;
                        }
                                ip->i_freef = NULL;
                                ip->i_freeb = NULL;
                        }
-                       ip->i_count++;
                        ip->i_flag |= ILOCKED;
                        ip->i_flag |= ILOCKED;
-                       return(ip);
+                       vp->v_count++;
+                       *ipp = ip;
+                       return(0);
+               }
+       if (error = getnewino(dev, ino, &nip)) {
+               *ipp = 0;
+               return (error);
+       }
+       ip = nip;
+       /*
+        * Read in the disk contents for the inode.
+        */
+       if (error = bread(VFSTOUFS(mntp)->um_devvp, fsbtodb(fs, itod(fs, ino)),
+           (int)fs->fs_bsize, &bp)) {
+               /*
+                * The inode doesn't contain anything useful, so it would
+                * be misleading to leave it on its hash chain. Iput() will
+                * take care of putting it back on the free list. We also
+                * lose its inumber, just in case.
+                */
+               remque(ip);
+               ip->i_forw = ip;
+               ip->i_back = ip;
+               ip->i_number = 0;
+               INSFREE(ip);
+               ip->i_flag = 0;
+               brelse(bp);
+               *ipp = 0;
+               return(error);
+       }
+       /*
+        * Check to see if the new inode represents a block device
+        * for which we already have an inode (either because of
+        * bdevvp() or because of a different inode representing
+        * the same block device). If such an alias exists, put the
+        * just allocated inode back on the free list, and replace
+        * the contents of the existing inode with the contents of
+        * the new inode.
+        */
+       dp = bp->b_un.b_dino;
+       dp += itoo(fs, ino);
+       if ((dp->di_mode & IFMT) != IFBLK) {
+               ip->i_ic = dp->di_ic;
+               brelse(bp);
+       } else {
+again:
+               for (iq = bdevlisth; iq; iq = iq->i_devlst) {
+                       if (dp->di_rdev != ITOV(iq)->v_rdev)
+                               continue;
+                       igrab(iq);
+                       if (dp->di_rdev != ITOV(iq)->v_rdev) {
+                               iput(iq);
+                               goto again;
+                       }
+                       /*
+                        * Discard unneeded inode.
+                        */
+                       remque(ip);
+                       ip->i_forw = ip;
+                       ip->i_back = ip;
+                       ip->i_number = 0;
+                       INSFREE(ip);
+                       ip->i_flag = 0;
+                       /*
+                        * Reinitialize aliased inode.
+                        * We must release the buffer that we just read
+                        * before doing the iupdat() to avoid a possible
+                        * deadlock with updating an inode in the same
+                        * disk block.
+                        */
+                       ip = iq;
+                       vp = ITOV(iq);
+                       tdip.di_ic = dp->di_ic;
+                       brelse(bp);
+                       error = iupdat(ip, &time, &time, 1);
+                       ip->i_ic = tdip.di_ic;
+                       remque(ip);
+                       insque(ip, ih);
+                       ip->i_dev = dev;
+                       ip->i_number = ino;
+                       if (ip->i_devvp) {
+                               vrele(ip->i_devvp);
+                               ip->i_devvp = 0;
+                       }
+                       cache_purge(vp);
+                       break;
+               }
+               if (iq == 0) {
+                       ip->i_ic = dp->di_ic;
+                       brelse(bp);
+                       ip->i_devlst = bdevlisth;
+                       bdevlisth = ip;
                }
                }
+       }
+       /*
+        * Finish inode initialization.
+        */
+       ip->i_fs = fs;
+       ip->i_devvp = VFSTOUFS(mntp)->um_devvp;
+       ip->i_devvp->v_count++;
+       /*
+        * Initialize the associated vnode
+        */
+       vp = ITOV(ip);
+       vinit(vp, mntp, IFTOVT(ip->i_mode), &ufs_vnodeops);
+       if (vp->v_type == VCHR || vp->v_type == VBLK) {
+               vp->v_rdev = ip->i_rdev;
+               vp->v_op = &blk_vnodeops;
+       }
+       if (ino == ROOTINO)
+               vp->v_flag |= VROOT;
+#ifdef QUOTA
+       if (ip->i_mode != 0)
+               ip->i_dquot = inoquota(ip);
+#endif
+       *ipp = ip;
+       return (0);
+}
 
 
+/*
+ * Allocate a new inode.
+ *
+ * Put it onto its hash chain and lock it so that other requests for
+ * this inode will block if they arrive while we are sleeping waiting
+ * for old data structures to be purged or for the contents of the disk
+ * portion of this inode to be read.
+ */
+getnewino(dev, ino, ipp)
+       dev_t dev;
+       ino_t ino;
+       struct inode **ipp;
+{
+       union ihead *ih;
+       register struct inode *ip, *iq;
+       register struct vnode *vp;
+
+       /*
+        * Remove the next inode from the free list.
+        */
        if ((ip = ifreeh) == NULL) {
                tablefull("inode");
        if ((ip = ifreeh) == NULL) {
                tablefull("inode");
-               u.u_error = ENFILE;
-               return(NULL);
+               *ipp = 0;
+               return(ENFILE);
        }
        }
-       if (ip->i_count)
+       vp = ITOV(ip);
+       if (vp->v_count)
                panic("free inode isn't");
        if (iq = ip->i_freef)
                iq->i_freeb = &ifreeh;
                panic("free inode isn't");
        if (iq = ip->i_freef)
                iq->i_freeb = &ifreeh;
@@ -170,65 +300,47 @@ loop:
        /*
         * Now to take inode off the hash chain it was on
         * (initially, or after an iflush, it is on a "hash chain"
        /*
         * Now to take inode off the hash chain it was on
         * (initially, or after an iflush, it is on a "hash chain"
-        * consisting entirely of itself, and pointed to by no-one,
-        * but that doesn't matter), and put it on the chain for
-        * its new (ino, dev) pair
+        * consisting entirely of itself, and pointed to by no-one)
+        * and put it on the chain for its new (ino, dev) pair.
         */
        remque(ip);
         */
        remque(ip);
-       insque(ip, ih);
        ip->i_dev = dev;
        ip->i_dev = dev;
-       ip->i_fs = fs;
        ip->i_number = ino;
        ip->i_number = ino;
-       cacheinval(ip);
+       if (dev != NODEV) {
+               ih = &ihead[INOHASH(dev, ino)];
+               insque(ip, ih);
+       }
        ip->i_flag = ILOCKED;
        ip->i_flag = ILOCKED;
-       ip->i_count++;
        ip->i_lastr = 0;
        ip->i_lastr = 0;
-#ifdef QUOTA
-       dqrele(ip->i_dquot);
-#endif
-#ifdef SECSIZE
-       bp = bread(dev, fsbtodb(fs, itod(fs, ino)), (int)fs->fs_bsize,
-           fs->fs_dbsize);
-#else SECSIZE
-       bp = bread(dev, fsbtodb(fs, itod(fs, ino)), (int)fs->fs_bsize);
 #endif SECSIZE
        /*
 #endif SECSIZE
        /*
-        * Check I/O errors
+        * Purge old data structures associated with the inode.
         */
         */
-       if ((bp->b_flags&B_ERROR) != 0) {
-               brelse(bp);
-               /*
-                * the inode doesn't contain anything useful, so it would
-                * be misleading to leave it on its hash chain.
-                * 'iput' will take care of putting it back on the free list.
-                */
-               remque(ip);
-               ip->i_forw = ip;
-               ip->i_back = ip;
-               /*
-                * we also loose its inumber, just in case (as iput
-                * doesn't do that any more) - but as it isn't on its
-                * hash chain, I doubt if this is really necessary .. kre
-                * (probably the two methods are interchangable)
-                */
-               ip->i_number = 0;
-#ifdef QUOTA
-               ip->i_dquot = NODQUOT;
-#endif
-               iput(ip);
-               return(NULL);
+       cache_purge(vp);
+       if (ip->i_devvp) {
+               vrele(ip->i_devvp);
+               ip->i_devvp = 0;
        }
        }
-       dp = bp->b_un.b_dino;
-       dp += itoo(fs, ino);
-       ip->i_ic = dp->di_ic;
-       brelse(bp);
 #ifdef QUOTA
 #ifdef QUOTA
-       if (ip->i_mode == 0)
-               ip->i_dquot = NODQUOT;
-       else
-               ip->i_dquot = inoquota(ip);
+       dqrele(ip->i_dquot);
+       ip->i_dquot = NODQUOT;
 #endif
 #endif
-       return (ip);
+       if (vp->v_type == VBLK) {
+               if (bdevlisth == ip) {
+                       bdevlisth = ip->i_devlst;
+               } else {
+                       for (iq = bdevlisth; iq; iq = iq->i_devlst) {
+                               if (iq->i_devlst != ip)
+                                       continue;
+                               iq->i_devlst = ip->i_devlst;
+                               break;
+                       }
+                       if (iq == NULL)
+                               panic("missing bdev");
+               }
+       }
+       *ipp = ip;
+       return (0);
 }
 
 /*
 }
 
 /*
@@ -242,11 +354,13 @@ loop:
 igrab(ip)
        register struct inode *ip;
 {
 igrab(ip)
        register struct inode *ip;
 {
+       register struct vnode *vp = ITOV(ip);
+
        while ((ip->i_flag&ILOCKED) != 0) {
                ip->i_flag |= IWANT;
                sleep((caddr_t)ip, PINOD);
        }
        while ((ip->i_flag&ILOCKED) != 0) {
                ip->i_flag |= IWANT;
                sleep((caddr_t)ip, PINOD);
        }
-       if (ip->i_count == 0) {         /* ino on free list */
+       if (vp->v_count == 0) {         /* ino on free list */
                register struct inode *iq;
 
                if (iq = ip->i_freef)
                register struct inode *iq;
 
                if (iq = ip->i_freef)
@@ -257,10 +371,56 @@ igrab(ip)
                ip->i_freef = NULL;
                ip->i_freeb = NULL;
        }
                ip->i_freef = NULL;
                ip->i_freeb = NULL;
        }
-       ip->i_count++;
+       vp->v_count++;
        ip->i_flag |= ILOCKED;
 }
 
        ip->i_flag |= ILOCKED;
 }
 
+/*
+ * Create a vnode for a block device.
+ * Used for root filesystem, argdev, and swap areas.
+ */
+bdevvp(dev, vpp)
+       dev_t dev;
+       struct vnode **vpp;
+{
+       register struct inode *ip;
+       register struct vnode *vp;
+       struct inode *nip;
+       int error;
+
+       /*
+        * Check for the existence of an existing vnode.
+        */
+again:
+       for (ip = bdevlisth; ip; ip = ip->i_devlst) {
+               vp = ITOV(ip);
+               if (dev != vp->v_rdev)
+                       continue;
+               igrab(ip);
+               if (dev != vp->v_rdev) {
+                       iput(ip);
+                       goto again;
+               }
+               IUNLOCK(ip);
+               *vpp = vp;
+               return (0);
+       }
+       if (error = getnewino(NODEV, (ino_t)0, &nip)) {
+               *vpp = 0;
+               return (error);
+       }
+       ip = nip;
+       ip->i_fs = 0;
+       ip->i_devlst = bdevlisth;
+       bdevlisth = ip;
+       vp = ITOV(ip);
+       vinit(vp, 0, VBLK, &blk_vnodeops);
+       vp->v_rdev = dev;
+       IUNLOCK(ip);
+       *vpp = vp;
+       return (0);
+}
+
 /*
  * Decrement reference count of
  * an inode structure.
 /*
  * Decrement reference count of
  * an inode structure.
@@ -275,54 +435,43 @@ iput(ip)
        if ((ip->i_flag & ILOCKED) == 0)
                panic("iput");
        IUNLOCK(ip);
        if ((ip->i_flag & ILOCKED) == 0)
                panic("iput");
        IUNLOCK(ip);
-       irele(ip);
+       vrele(ITOV(ip));
 }
 
 }
 
-irele(ip)
-       register struct inode *ip;
+
+ufs_inactive(vp)
+       struct vnode *vp;
 {
 {
-       int mode;
-
-       if (ip->i_count == 1) {
-               ip->i_flag |= ILOCKED;
-               if (ip->i_nlink <= 0 && ip->i_fs->fs_ronly == 0) {
-                       itrunc(ip, (u_long)0);
-                       mode = ip->i_mode;
-                       ip->i_mode = 0;
-                       ip->i_rdev = 0;
-                       ip->i_flag |= IUPD|ICHG;
-                       ifree(ip, ip->i_number, mode);
+       register struct inode *ip = VTOI(vp);
+       int mode, error;
+
+       if (ITOV(ip)->v_count != 0)
+               panic("ufs_inactive: not inactive");
+       ip->i_flag |= ILOCKED;
+       if (ip->i_nlink <= 0 && (ITOV(ip)->v_mount->m_flag&M_RDONLY) == 0) {
+               error = itrunc(ip, (u_long)0);
+               mode = ip->i_mode;
+               ip->i_mode = 0;
+               ip->i_rdev = 0;
+               ip->i_flag |= IUPD|ICHG;
+               ifree(ip, ip->i_number, mode);
 #ifdef QUOTA
 #ifdef QUOTA
-                       (void) chkiq(ip->i_dev, ip, ip->i_uid, 0);
-                       dqrele(ip->i_dquot);
-                       ip->i_dquot = NODQUOT;
+               (void) chkiq(ip->i_dev, ip, ip->i_uid, 0);
+               dqrele(ip->i_dquot);
+               ip->i_dquot = NODQUOT;
 #endif
 #endif
-               }
-               IUPDAT(ip, &time, &time, 0);
-               IUNLOCK(ip);
-               ip->i_flag = 0;
-               /*
-                * Put the inode on the end of the free list.
-                * Possibly in some cases it would be better to
-                * put the inode at the head of the free list,
-                * (eg: where i_mode == 0 || i_number == 0)
-                * but I will think about that later .. kre
-                * (i_number is rarely 0 - only after an i/o error in iget,
-                * where i_mode == 0, the inode will probably be wanted
-                * again soon for an ialloc, so possibly we should keep it)
-                */
-               if (ifreeh) {
-                       *ifreet = ip;
-                       ip->i_freeb = ifreet;
-               } else {
-                       ifreeh = ip;
-                       ip->i_freeb = &ifreeh;
-               }
-               ip->i_freef = NULL;
-               ifreet = &ip->i_freef;
-       } else if (!(ip->i_flag & ILOCKED))
-               ITIMES(ip, &time, &time);
-       ip->i_count--;
+       }
+       IUPDAT(ip, &time, &time, 0);
+       IUNLOCK(ip);
+       ip->i_flag = 0;
+       /*
+        * Put the inode on the end of the free list.
+        * Possibly in some cases it would be better to
+        * put the inode at the head of the free list,
+        * (eg: where i_mode == 0 || i_number == 0).
+        */
+       INSFREE(ip);
+       return (error);
 }
 
 /*
 }
 
 /*
@@ -338,38 +487,36 @@ iupdat(ip, ta, tm, waitfor)
        struct timeval *ta, *tm;
        int waitfor;
 {
        struct timeval *ta, *tm;
        int waitfor;
 {
-       register struct buf *bp;
+       struct buf *bp;
+       struct vnode *vp = ITOV(ip);
        struct dinode *dp;
        register struct fs *fs;
 
        fs = ip->i_fs;
        struct dinode *dp;
        register struct fs *fs;
 
        fs = ip->i_fs;
-       if ((ip->i_flag & (IUPD|IACC|ICHG|IMOD)) != 0) {
-               if (fs->fs_ronly)
-                       return;
-#ifdef SECSIZE
-               bp = bread(ip->i_dev, fsbtodb(fs, itod(fs, ip->i_number)),
-                       (int)fs->fs_bsize, fs->fs_dbsize);
-#else SECSIZE
-               bp = bread(ip->i_dev, fsbtodb(fs, itod(fs, ip->i_number)),
-                       (int)fs->fs_bsize);
-#endif SECSIZE
-               if (bp->b_flags & B_ERROR) {
-                       brelse(bp);
-                       return;
-               }
-               if (ip->i_flag&IACC)
-                       ip->i_atime = ta->tv_sec;
-               if (ip->i_flag&IUPD)
-                       ip->i_mtime = tm->tv_sec;
-               if (ip->i_flag&ICHG)
-                       ip->i_ctime = time.tv_sec;
-               ip->i_flag &= ~(IUPD|IACC|ICHG|IMOD);
-               dp = bp->b_un.b_dino + itoo(fs, ip->i_number);
-               dp->di_ic = ip->i_ic;
-               if (waitfor)
-                       bwrite(bp);
-               else
-                       bdwrite(bp);
+       if ((ip->i_flag & (IUPD|IACC|ICHG|IMOD)) == 0)
+               return (0);
+       if (vp->v_mount->m_flag & M_RDONLY)
+               return (0);
+       error = bread(ip->i_devvp, fsbtodb(fs, itod(fs, ip->i_number)),
+               (int)fs->fs_bsize, &bp);
+       if (error) {
+               brelse(bp);
+               return (error);
+       }
+       if (ip->i_flag&IACC)
+               ip->i_atime = ta->tv_sec;
+       if (ip->i_flag&IUPD)
+               ip->i_mtime = tm->tv_sec;
+       if (ip->i_flag&ICHG)
+               ip->i_ctime = time.tv_sec;
+       ip->i_flag &= ~(IUPD|IACC|ICHG|IMOD);
+       dp = bp->b_un.b_dino + itoo(fs, ip->i_number);
+       dp->di_ic = ip->i_ic;
+       if (waitfor) {
+               return (bwrite(bp));
+       } else {
+               bdwrite(bp);
+               return (0);
        }
 }
 
        }
 }
 
@@ -393,17 +540,16 @@ itrunc(oip, length)
        register struct fs *fs;
        register struct inode *ip;
        struct buf *bp;
        register struct fs *fs;
        register struct inode *ip;
        struct buf *bp;
-       int offset, osize, size, count, level;
-       long nblocks, blocksreleased = 0;
+       int offset, osize, size, level;
+       long count, nblocks, blocksreleased = 0;
        register int i;
        register int i;
-       dev_t dev;
+       int error, allerror = 0;
        struct inode tip;
        struct inode tip;
-       extern long indirtrunc();
 
        if (oip->i_size <= length) {
                oip->i_flag |= ICHG|IUPD;
 
        if (oip->i_size <= length) {
                oip->i_flag |= ICHG|IUPD;
-               iupdat(oip, &time, &time, 1);
-               return;
+               error = iupdat(oip, &time, &time, 1);
+               return (error);
        }
        /*
         * Calculate index into inode's block list of
        }
        /*
         * Calculate index into inode's block list of
@@ -430,25 +576,20 @@ itrunc(oip, length)
                oip->i_size = length;
        } else {
                lbn = lblkno(fs, length);
                oip->i_size = length;
        } else {
                lbn = lblkno(fs, length);
-               bn = fsbtodb(fs, bmap(oip, lbn, B_WRITE, offset));
-               if (u.u_error || (long)bn < 0)
-                       return;
+               error = balloc(oip, lbn, offset, &bn, B_CLRBUF);
+               if (error)
+                       return (error);
+               if ((long)bn < 0)
+                       panic("itrunc: hole");
                oip->i_size = length;
                size = blksize(fs, oip, lbn);
                count = howmany(size, CLBYTES);
                oip->i_size = length;
                size = blksize(fs, oip, lbn);
                count = howmany(size, CLBYTES);
-               dev = oip->i_dev;
-               for (i = 0; i < count; i++)
-#ifdef SECSIZE
-                       munhash(dev, bn + i * CLBYTES / fs->fs_dbsize);
-#else SECSIZE
-                       munhash(dev, bn + i * CLBYTES / DEV_BSIZE);
-#endif SECSIZE
-               bp = bread(dev, bn, size);
-               if (bp->b_flags & B_ERROR) {
-                       u.u_error = EIO;
+                       munhash(oip->i_devvp, bn + i * CLBYTES / DEV_BSIZE);
+               error = bread(oip->i_devvp, bn, size, &bp);
+               if (error) {
                        oip->i_size = osize;
                        brelse(bp);
                        oip->i_size = osize;
                        brelse(bp);
-                       return;
+                       return (error);
                }
                bzero(bp->b_un.b_addr + offset, (unsigned)(size - offset));
                bdwrite(bp);
                }
                bzero(bp->b_un.b_addr + offset, (unsigned)(size - offset));
                bdwrite(bp);
@@ -471,7 +612,7 @@ itrunc(oip, length)
        for (i = NDADDR - 1; i > lastblock; i--)
                oip->i_db[i] = 0;
        oip->i_flag |= ICHG|IUPD;
        for (i = NDADDR - 1; i > lastblock; i--)
                oip->i_db[i] = 0;
        oip->i_flag |= ICHG|IUPD;
-       syncip(oip);
+       allerror = syncip(oip);
 
        /*
         * Indirect blocks first.
 
        /*
         * Indirect blocks first.
@@ -480,8 +621,11 @@ itrunc(oip, length)
        for (level = TRIPLE; level >= SINGLE; level--) {
                bn = ip->i_ib[level];
                if (bn != 0) {
        for (level = TRIPLE; level >= SINGLE; level--) {
                bn = ip->i_ib[level];
                if (bn != 0) {
-                       blocksreleased +=
-                           indirtrunc(ip, bn, lastiblock[level], level);
+                       error = indirtrunc(ip, bn, lastiblock[level], level,
+                               &count);
+                       if (error)
+                               allerror = error;
+                       blocksreleased += count;
                        if (lastiblock[level] < 0) {
                                ip->i_ib[level] = 0;
                                blkfree(ip, bn, (off_t)fs->fs_bsize);
                        if (lastiblock[level] < 0) {
                                ip->i_ib[level] = 0;
                                blkfree(ip, bn, (off_t)fs->fs_bsize);
@@ -553,6 +697,7 @@ done:
 #ifdef QUOTA
        (void) chkdq(oip, -blocksreleased, 0);
 #endif
 #ifdef QUOTA
        (void) chkdq(oip, -blocksreleased, 0);
 #endif
+       return (allerror);
 }
 
 /*
 }
 
 /*
@@ -565,19 +710,20 @@ done:
  *
  * NB: triple indirect blocks are untested.
  */
  *
  * NB: triple indirect blocks are untested.
  */
-long
-indirtrunc(ip, bn, lastbn, level)
+indirtrunc(ip, bn, lastbn, level, countp)
        register struct inode *ip;
        daddr_t bn, lastbn;
        int level;
        register struct inode *ip;
        daddr_t bn, lastbn;
        int level;
+       long *countp;
 {
        register int i;
        struct buf *bp;
        register struct fs *fs = ip->i_fs;
        register daddr_t *bap;
        daddr_t *copy, nb, last;
 {
        register int i;
        struct buf *bp;
        register struct fs *fs = ip->i_fs;
        register daddr_t *bap;
        daddr_t *copy, nb, last;
-       long factor;
-       int blocksreleased = 0, nblocks;
+       long blkcount, factor;
+       int nblocks, blocksreleased = 0;
+       int error, allerror = 0;
 
        /*
         * Calculate index in current block of last
 
        /*
         * Calculate index in current block of last
@@ -600,18 +746,20 @@ indirtrunc(ip, bn, lastbn, level)
        bp = bread(ip->i_dev, fsbtodb(fs, bn), (int)fs->fs_bsize,
            fs->fs_dbsize);
 #else SECSIZE
        bp = bread(ip->i_dev, fsbtodb(fs, bn), (int)fs->fs_bsize,
            fs->fs_dbsize);
 #else SECSIZE
-       bp = bread(ip->i_dev, fsbtodb(fs, bn), (int)fs->fs_bsize);
-#endif SECSIZE
-       if (bp->b_flags&B_ERROR) {
+       error = bread(ip->i_devvp, fsbtodb(fs, bn), (int)fs->fs_bsize, &bp);
+       if (error) {
                brelse(bp);
                brelse(bp);
-               return (0);
+               *countp = 0;
+               return (error);
        }
        bap = bp->b_un.b_daddr;
        MALLOC(copy, daddr_t *, fs->fs_bsize, M_TEMP, M_WAITOK);
        bcopy((caddr_t)bap, (caddr_t)copy, (u_int)fs->fs_bsize);
        bzero((caddr_t)&bap[last + 1],
          (u_int)(NINDIR(fs) - (last + 1)) * sizeof (daddr_t));
        }
        bap = bp->b_un.b_daddr;
        MALLOC(copy, daddr_t *, fs->fs_bsize, M_TEMP, M_WAITOK);
        bcopy((caddr_t)bap, (caddr_t)copy, (u_int)fs->fs_bsize);
        bzero((caddr_t)&bap[last + 1],
          (u_int)(NINDIR(fs) - (last + 1)) * sizeof (daddr_t));
-       bwrite(bp);
+       error = bwrite(bp);
+       if (error)
+               allerror = error;
        bap = copy;
 
        /*
        bap = copy;
 
        /*
@@ -621,9 +769,13 @@ indirtrunc(ip, bn, lastbn, level)
                nb = bap[i];
                if (nb == 0)
                        continue;
                nb = bap[i];
                if (nb == 0)
                        continue;
-               if (level > SINGLE)
-                       blocksreleased +=
-                           indirtrunc(ip, nb, (daddr_t)-1, level - 1);
+               if (level > SINGLE) {
+                       error = indirtrunc(ip, nb, (daddr_t)-1, level - 1,
+                               &blkcount);
+                       if (error)
+                               allerror = error;
+                       blocksreleased += blkcount;
+               }
                blkfree(ip, nb, (off_t)fs->fs_bsize);
                blocksreleased += nblocks;
        }
                blkfree(ip, nb, (off_t)fs->fs_bsize);
                blocksreleased += nblocks;
        }
@@ -634,11 +786,16 @@ indirtrunc(ip, bn, lastbn, level)
        if (level > SINGLE && lastbn >= 0) {
                last = lastbn % factor;
                nb = bap[i];
        if (level > SINGLE && lastbn >= 0) {
                last = lastbn % factor;
                nb = bap[i];
-               if (nb != 0)
-                       blocksreleased += indirtrunc(ip, nb, last, level - 1);
+               if (nb != 0) {
+                       error = indirtrunc(ip, nb, last, level - 1, &blkcount);
+                       if (error)
+                               allerror = error;
+                       blocksreleased += blkcount;
+               }
        }
        FREE(copy, M_TEMP);
        }
        FREE(copy, M_TEMP);
-       return (blocksreleased);
+       *countp = blocksreleased;
+       return (allerror);
 }
 
 /*
 }
 
 /*
@@ -664,14 +821,14 @@ iflush(dev)
 #else
                if (ip->i_dev == dev)
 #endif
 #else
                if (ip->i_dev == dev)
 #endif
-                       if (ip->i_count)
+                       if (ITOV(ip)->v_count)
                                return (EBUSY);
                        else {
                                remque(ip);
                                ip->i_forw = ip;
                                ip->i_back = ip;
                                /*
                                return (EBUSY);
                        else {
                                remque(ip);
                                ip->i_forw = ip;
                                ip->i_back = ip;
                                /*
-                                * as i_count == 0, the inode was on the free
+                                * as v_count == 0, the inode was on the free
                                 * list already, just leave it there, it will
                                 * fall off the bottom eventually. We could
                                 * perhaps move it to the head of the free
                                 * list already, just leave it there, it will
                                 * fall off the bottom eventually. We could
                                 * perhaps move it to the head of the free
@@ -683,6 +840,10 @@ iflush(dev)
                                dqrele(ip->i_dquot);
                                ip->i_dquot = NODQUOT;
 #endif
                                dqrele(ip->i_dquot);
                                ip->i_dquot = NODQUOT;
 #endif
+                               if (ip->i_devvp) {
+                                       vrele(ip->i_devvp);
+                                       ip->i_devvp = 0;
+                               }
                        }
        }
        return (0);
                        }
        }
        return (0);
@@ -695,7 +856,11 @@ ilock(ip)
        register struct inode *ip;
 {
 
        register struct inode *ip;
 {
 
-       ILOCK(ip);
+       while (ip->i_flag & ILOCKED) {
+               ip->i_flag |= IWANT;
+               (void) sleep((caddr_t)ip, PINOD);
+       }
+       ip->i_flag |= ILOCKED;
 }
 
 /*
 }
 
 /*
@@ -705,5 +870,55 @@ iunlock(ip)
        register struct inode *ip;
 {
 
        register struct inode *ip;
 {
 
-       IUNLOCK(ip);
+       if ((ip->i_flag & ILOCKED) == 0)
+               printf("unlocking unlocked inode %d on dev 0x%x\n",
+                       ip->i_number, ip->i_dev);
+       ip->i_flag &= ~ILOCKED;
+       if (ip->i_flag&IWANT) {
+               ip->i_flag &= ~IWANT;
+               wakeup((caddr_t)ip);
+       }
+}
+
+/*
+ * Check mode permission on inode pointer. Mode is READ, WRITE or EXEC.
+ * The mode is shifted to select the owner/group/other fields. The
+ * super user is granted all permissions.
+ *
+ * NB: Called from vnode op table. It seems this could all be done
+ * using vattr's but...
+ */
+iaccess(ip, mode, cred)
+       register struct inode *ip;
+       register int mode;
+       struct ucred *cred;
+{
+       register gid_t *gp;
+       register struct vnode *vp = ITOV(ip);
+       int i;
+
+       /*
+        * If you're the super-user,
+        * you always get access.
+        */
+       if (cred->cr_uid == 0)
+               return (0);
+       /*
+        * Access check is based on only one of owner, group, public.
+        * If not owner, then check group. If not a member of the
+        * group, then check public access.
+        */
+       if (cred->cr_uid != ip->i_uid) {
+               mode >>= 3;
+               gp = cred->cr_groups;
+               for (i = 0; i < cred->cr_ngroups; i++, gp++)
+                       if (ip->i_gid == *gp)
+                               goto found;
+               mode >>= 3;
+found:
+               ;
+       }
+       if ((ip->i_mode & mode) != 0)
+               return (0);
+       return (EACCES);
 }
 }
index 9456b4f..3101cc1 100644 (file)
 /*
 /*
- * Copyright (c) 1982, 1986 Regents of the University of California.
- * All rights reserved.  The Berkeley software License Agreement
- * specifies the terms and conditions for redistribution.
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
  *
  *
- *     @(#)ufs_vfsops.c        7.12 (Berkeley) %G%
+ * 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.
+ *
+ *     @(#)ufs_vfsops.c        7.13 (Berkeley) %G%
  */
 
  */
 
+
 #include "param.h"
 #include "systm.h"
 #include "param.h"
 #include "systm.h"
-#include "dir.h"
-#include "user.h"
-#include "inode.h"
-#include "proc.h"
-#include "fs.h"
-#include "buf.h"
+#include "time.h"
+#include "kernel.h"
+#include "namei.h"
+#include "vnode.h"
 #include "mount.h"
 #include "mount.h"
+#include "buf.h"
 #include "file.h"
 #include "file.h"
-#include "conf.h"
-#include "ioctl.h"
 #include "disklabel.h"
 #include "disklabel.h"
-#include "stat.h"
+#include "ioctl.h"
+#include "errno.h"
 #include "malloc.h"
 #include "malloc.h"
+#include "../ufs/fs.h"
+#include "../ufs/ufsmount.h"
+#include "../ufs/inode.h"
 #include "ioctl.h"
 #include "disklabel.h"
 #include "stat.h"
 
 #include "ioctl.h"
 #include "disklabel.h"
 #include "stat.h"
 
-smount()
+/*
+ * ufs vfs operations.
+ */
+int ufs_mount();
+int ufs_unmount();
+int ufs_root();
+int ufs_statfs();
+int ufs_sync();
+int ufs_fhtovp();
+int ufs_vptofh();
+
+struct vfsops ufs_vfsops = {
+       ufs_mount,
+       ufs_unmount,
+       ufs_root,
+       ufs_statfs,
+       ufs_sync,
+       ufs_fhtovp,
+       ufs_vptofh
+};
+
+/*
+ * ufs mount table.
+ */
+struct ufsmount mounttab[NMOUNT];
+
+/*
+ * Called by vfs_mountroot when ufs is going to be mounted as root
+ *
+ * XXX - Need to have a way of figuring the name of the root device
+ */
+#define ROOTNAME       "root device"
+
+ufs_mountroot()
 {
 {
-       register struct a {
-               char    *fspec;
-               char    *freg;
-               int     ronly;
-       } *uap = (struct a *)u.u_ap;
-       dev_t dev;
-       register struct inode *ip;
+       register struct mount *mp;
+       extern struct vnode *rootvp;
+       struct ufsmount *ump;
        register struct fs *fs;
        register struct fs *fs;
-       register struct nameidata *ndp = &u.u_nd;
-       u_int len;
+       u_int size;
+       int error;
 
 
-       u.u_error = getmdev(&dev, uap->fspec);
-       if (u.u_error)
-               return;
-       ndp->ni_nameiop = LOOKUP | FOLLOW;
-       ndp->ni_segflg = UIO_USERSPACE;
-       ndp->ni_dirp = (caddr_t)uap->freg;
-       ip = namei(ndp);
-       if (ip == NULL)
-               return;
-       if (ip->i_count != 1) {
-               iput(ip);
-               u.u_error = EBUSY;
-               return;
+       mp = (struct mount *)malloc((u_long)sizeof(struct mount),
+               M_MOUNT, M_WAITOK);
+       mp->m_op = &ufs_vfsops;
+       mp->m_flag = 0;
+       mp->m_exroot = 0;
+       error = mountfs(rootvp, mp);
+       if (error) {
+               free((caddr_t)mp, M_MOUNT);
+               return (error);
        }
        }
-       if ((ip->i_mode&IFMT) != IFDIR) {
-               iput(ip);
-               u.u_error = ENOTDIR;
-               return;
+       error = vfs_add((struct vnode *)0, mp, 0);
+       if (error) {
+               (void)ufs_unmount(mp, 0);
+               free((caddr_t)mp, M_MOUNT);
+               return (error);
        }
        }
-       fs = mountfs(dev, uap->ronly, ip);
-       if (fs == 0) {
-               iput(ip);
-               return;
+       ump = VFSTOUFS(mp);
+       fs = ump->um_fs;
+       fs->fs_fsmnt[0] = '/';
+       bzero(fs->fs_fsmnt + 1, sizeof(fs->fs_fsmnt) - 1);
+       (void) copystr(ROOTNAME, ump->um_mntname, MNAMELEN - 1, &size);
+       bzero(ump->um_mntname + size, MNAMELEN - size);
+       vfs_unlock(mp);
+       inittodr(fs->fs_time);
+       return (0);
+}
+
+/*
+ * VFS Operations.
+ *
+ * mount system call
+ */
+ufs_mount(mp, path, data, ndp)
+       struct mount *mp;
+       char *path;
+       caddr_t data;
+       struct nameidata *ndp;
+{
+       struct vnode *devvp;
+       struct ufs_args args;
+       struct ufsmount *ump;
+       register struct fs *fs;
+       u_int size;
+       int error;
+
+       if (error = copyin(data, (caddr_t)&args, sizeof (struct ufs_args)))
+               return (error);
+       if ((error = getmdev(&devvp, args.fspec, ndp)) != 0)
+               return (error);
+       error = mountfs(devvp, mp);
+       if (error) {
+               vrele(devvp);
+               return (error);
        }
        }
-       (void) copyinstr(uap->freg, fs->fs_fsmnt, sizeof(fs->fs_fsmnt)-1, &len);
-       bzero(fs->fs_fsmnt + len, sizeof (fs->fs_fsmnt) - len);
+       ump = VFSTOUFS(mp);
+       fs = ump->um_fs;
+       (void) copyinstr(path, fs->fs_fsmnt, sizeof(fs->fs_fsmnt) - 1, &size);
+       bzero(fs->fs_fsmnt + size, sizeof(fs->fs_fsmnt) - size);
+       (void) copyinstr(args.fspec, ump->um_mntname, MNAMELEN - 1, &size);
+       bzero(ump->um_mntname + size, MNAMELEN - size);
+       return (0);
 }
 
 }
 
-struct fs *
-mountfs(dev, ronly, ip)
-       dev_t dev;
-       int ronly;
-       struct inode *ip;
+/*
+ * Common code for mount and mountroot
+ */
+mountfs(devvp, mp)
+       struct vnode *devvp;
+       struct mount *mp;
 {
 {
-       register struct mount *mp;
-       struct mount *fmp = NULL;
-       register struct buf *bp = NULL;
+       register struct ufsmount *ump;
+       struct ufsmount *fmp = NULL;
+       struct buf *bp = NULL;
        register struct fs *fs;
        register struct fs *fs;
+       dev_t dev = devvp->v_rdev;
        struct partinfo dpart;
        int havepart = 0, blks;
        caddr_t base, space;
        struct partinfo dpart;
        int havepart = 0, blks;
        caddr_t base, space;
-       int i, size;
-       register error;
+       int havepart = 0, blks;
+       int error, i, size;
        int needclose = 0;
        int needclose = 0;
+       int ronly = (mp->m_flag & M_RDONLY) != 0;
 
 
-       for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++) {
-               if (mp->m_fs == NULL) {
+       for (ump = &mounttab[0]; ump < &mounttab[NMOUNT]; ump++) {
+               if (ump->um_fs == NULL) {
                        if (fmp == NULL)
                        if (fmp == NULL)
-                               fmp = mp;
-               } else if (dev == mp->m_dev) {
-                       u.u_error = EBUSY;              /* XXX */
-                       return ((struct fs *) NULL);
+                               fmp = ump;
+               } else if (dev == ump->um_dev) {
+                       return (EBUSY);         /* needs translation */
                }
        }
                }
        }
-       if ((mp = fmp) == NULL) {
-               u.u_error = EMFILE;             /* needs translation      XXX */
-               return ((struct fs *) NULL);
-       }
-       mp->m_fs = (struct fs *)1;      /* just to reserve this slot */
-       mp->m_dev = dev;
-       mp->m_inodp = NULL;
-       error =
            (*bdevsw[major(dev)].d_open)(dev, ronly ? FREAD : FREAD|FWRITE,
                S_IFBLK);
        if (error) {
            (*bdevsw[major(dev)].d_open)(dev, ronly ? FREAD : FREAD|FWRITE,
                S_IFBLK);
        if (error) {
-               u.u_error = error;
-               mp->m_fs = NULL;
-               return ((struct fs *) NULL);
+               ump->um_fs = NULL;
+               return (error);
        }
        needclose = 1;
        }
        needclose = 1;
-       if ((*bdevsw[major(dev)].d_ioctl)(dev, DIOCGPART,
-           (caddr_t)&dpart, FREAD) == 0) {
-               havepart = 1;
-               size = dpart.disklab->d_secsize;
-       } else
+       if (VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, FREAD,
+           (struct ucred *)0) != 0)
                size = DEV_BSIZE;
                size = DEV_BSIZE;
-#ifdef SECSIZE
-       /*
-        * If possible, determine hardware sector size
-        * and adjust fsbtodb to correspond.
-        */
-#endif SECSIZE
-       if ((*bdevsw[major(dev)].d_ioctl)(dev, DIOCGPART,
-           (caddr_t)&dpart, FREAD) == 0) {
+       else {
                havepart = 1;
                size = dpart.disklab->d_secsize;
                havepart = 1;
                size = dpart.disklab->d_secsize;
-#ifdef SECSIZE
-               if (size < MINSECSIZE) {
-                       error = EINVAL;
-                       goto out;
-               }
-#endif SECSIZE
-       } else
-               size = DEV_BSIZE;
-#ifdef SECSIZE
-       tp = bread(dev, (daddr_t)(SBOFF / size), SBSIZE, size);
-#else SECSIZE
-       bp = bread(dev, SBLOCK, SBSIZE);
-       if (bp->b_flags & B_ERROR) {
-               mp->m_fs = NULL;
+       }
+       if (error = bread(devvp, SBLOCK, SBSIZE, &bp)) {
+               ump->um_fs = NULL;
                goto out;
        }
        fs = bp->b_un.b_fs;
                goto out;
        }
        fs = bp->b_un.b_fs;
-       if (fs->fs_magic != FS_MAGIC || fs->fs_bsize > MAXBSIZE ||
-           fs->fs_bsize < sizeof(struct fs)) {
-               error = EINVAL;         /* also needs translation */
+               ump->um_fs = NULL;
+               error = EINVAL;         /* XXX also needs translation */
                goto out;
        }
                goto out;
        }
-       mp->m_fs = (struct fs *)malloc((u_long)fs->fs_sbsize, M_SUPERBLK,
+       ump->um_fs = (struct fs *)malloc((u_long)fs->fs_sbsize, M_SUPERBLK,
            M_WAITOK);
            M_WAITOK);
-       bcopy((caddr_t)bp->b_un.b_addr, (caddr_t)mp->m_fs,
+       bcopy((caddr_t)bp->b_un.b_addr, (caddr_t)ump->um_fs,
           (u_int)fs->fs_sbsize);
        brelse(bp);
        bp = NULL;
           (u_int)fs->fs_sbsize);
        brelse(bp);
        bp = NULL;
-       fs = mp->m_fs;
-       fs->fs_ronly = (ronly != 0);
+       fs = ump->um_fs;
+       fs->fs_ronly = ronly;
        if (ronly == 0)
                fs->fs_fmod = 1;
        if (havepart) {
        if (ronly == 0)
                fs->fs_fmod = 1;
        if (havepart) {
@@ -190,10 +238,6 @@ mountfs(dev, ronly, ip)
        blks = howmany(fs->fs_cssize, fs->fs_fsize);
        base = space = (caddr_t)malloc((u_long)fs->fs_cssize, M_SUPERBLK,
            M_WAITOK);
        blks = howmany(fs->fs_cssize, fs->fs_fsize);
        base = space = (caddr_t)malloc((u_long)fs->fs_cssize, M_SUPERBLK,
            M_WAITOK);
-       if (space == NULL) {
-               error = ENOMEM;
-               goto out;
-       }
        for (i = 0; i < blks; i += fs->fs_frag) {
                size = fs->fs_bsize;
                if (i + fs->fs_frag > blks)
        for (i = 0; i < blks; i += fs->fs_frag) {
                size = fs->fs_bsize;
                if (i + fs->fs_frag > blks)
@@ -202,8 +246,8 @@ mountfs(dev, ronly, ip)
                tp = bread(dev, fsbtodb(fs, fs->fs_csaddr + i), size,
                    fs->fs_dbsize);
 #else SECSIZE
                tp = bread(dev, fsbtodb(fs, fs->fs_csaddr + i), size,
                    fs->fs_dbsize);
 #else SECSIZE
-               bp = bread(dev, fsbtodb(fs, fs->fs_csaddr + i), size);
-               if (bp->b_flags&B_ERROR) {
+               error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + i), size, &bp);
+               if (error) {
                        free((caddr_t)base, M_SUPERBLK);
                        goto out;
                }
                        free((caddr_t)base, M_SUPERBLK);
                        goto out;
                }
@@ -213,64 +257,53 @@ mountfs(dev, ronly, ip)
                brelse(bp);
                bp = NULL;
        }
                brelse(bp);
                bp = NULL;
        }
-       mp->m_inodp = ip;
-       if (ip) {
-               ip->i_flag |= IMOUNT;
-               cacheinval(ip);
-               iunlock(ip);
-       }
+       mp->m_data = (qaddr_t)ump;
+       mp->m_bsize = fs->fs_bsize;
+       mp->m_fsize = fs->fs_fsize;
+       mp->m_fsid.val[0] = (long)dev;
+       mp->m_fsid.val[1] = MOUNT_UFS;
+       ump->um_mountp = mp;
+       ump->um_dev = dev;
+       ump->um_devvp = devvp;
+       ump->um_qinod = NULL;
+
        /* Sanity checks for old file systems.                     XXX */
        fs->fs_npsect = MAX(fs->fs_npsect, fs->fs_nsect);       /* XXX */
        fs->fs_interleave = MAX(fs->fs_interleave, 1);          /* XXX */
        if (fs->fs_postblformat == FS_42POSTBLFMT)              /* XXX */
                fs->fs_nrpos = 8;                               /* XXX */
 
        /* Sanity checks for old file systems.                     XXX */
        fs->fs_npsect = MAX(fs->fs_npsect, fs->fs_nsect);       /* XXX */
        fs->fs_interleave = MAX(fs->fs_interleave, 1);          /* XXX */
        if (fs->fs_postblformat == FS_42POSTBLFMT)              /* XXX */
                fs->fs_nrpos = 8;                               /* XXX */
 
-       return (fs);
+       return (0);
 out:
        if (needclose)
 out:
        if (needclose)
-               (void) closei(dev, IFBLK, ronly? FREAD : FREAD|FWRITE);
-       if (mp->m_fs) {
-               free((caddr_t)mp->m_fs, M_SUPERBLK);
-               mp->m_fs = NULL;
+               (void) VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE,
+                       (struct ucred *)0);
+       if (ump->um_fs) {
+               free((caddr_t)ump->um_fs, M_SUPERBLK);
+               ump->um_fs = NULL;
        }
        if (bp)
                brelse(bp);
        }
        if (bp)
                brelse(bp);
-       u.u_error = error ? error : EIO;                        /* XXX */
-       return ((struct fs *) NULL);
+       return (error);
 }
 
 }
 
-umount()
-{
-       struct a {
-               char    *fspec;
-       } *uap = (struct a *)u.u_ap;
 
 
-       u.u_error = unmount1(uap->fspec, 0);
-}
-
-unmount1(fname, forcibly)
-       caddr_t fname;
-       int forcibly;
+/*
+ * unmount system call
+ */
+ufs_unmount(mp, flags)
+       struct mount *mp;
+       int flags;
 {
 {
-       dev_t dev;
-       register struct mount *mp;
-       int error;
-       register struct inode *ip;
+       register struct ufsmount *ump;
        register struct fs *fs;
        register struct fs *fs;
+       dev_t dev;
+       int error, ronly;
 
 
-       forcibly = 0;                                   /* XXX */
-       forcibly = 0;                                   /* XXX */
-       error = getmdev(&dev, fname);
-       if (error)
-               return (error);
-       for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++)
-               if (mp->m_fs != NULL && dev == mp->m_dev)
-                       goto found;
-       return (EINVAL);
-found:
-       xumount(dev);   /* remove unused sticky files from text table */
-       nchinval(dev);  /* flush the name cache */
-       update();
+       if (flags & MNT_FORCE)
+               return (EINVAL);
+       ump = VFSTOUFS(mp);
+       dev = ump->um_dev;
 #ifdef QUOTA
        if ((error = iflush(dev, mp->m_qinod)) && !forcibly)
 #else
 #ifdef QUOTA
        if ((error = iflush(dev, mp->m_qinod)) && !forcibly)
 #else
@@ -278,40 +311,152 @@ found:
 #endif
                return (error);
 #ifdef QUOTA
 #endif
                return (error);
 #ifdef QUOTA
-       closedq(mp);
+       (void)closedq(ump);
        /*
         * Here we have to iflush again to get rid of the quota inode.
         * A drag, but it would be ugly to cheat, & this doesn't happen often.
         */
        (void)iflush(dev, (struct inode *)NULL);
 #endif
        /*
         * Here we have to iflush again to get rid of the quota inode.
         * A drag, but it would be ugly to cheat, & this doesn't happen often.
         */
        (void)iflush(dev, (struct inode *)NULL);
 #endif
-       ip = mp->m_inodp;
-       ip->i_flag &= ~IMOUNT;
-       fs = mp->m_fs;
+       fs = ump->um_fs;
+       ronly = !fs->fs_ronly;
        free((caddr_t)fs->fs_csp[0], M_SUPERBLK);
        free((caddr_t)fs->fs_csp[0], M_SUPERBLK);
-       free((caddr_t)mp->m_fs, M_SUPERBLK);
-       mp->m_fs = NULL;
-       mp->m_dev = NODEV;
-       mpurge(mp - &mount[0]);
        error = closei(dev, IFBLK, fs->fs_ronly? FREAD : FREAD|FWRITE);
        irele(ip);
        return (error);
 }
 
        error = closei(dev, IFBLK, fs->fs_ronly? FREAD : FREAD|FWRITE);
        irele(ip);
        return (error);
 }
 
-sbupdate(mp)
+/*
+ * Return root of a filesystem
+ */
+ufs_root(mp, vpp)
+       struct mount *mp;
+       struct vnode **vpp;
+{
+       struct inode tip, *ip;
+       int error;
+
+       tip.i_dev = VFSTOUFS(mp)->um_dev;
+       tip.i_vnode.v_mount = mp;
+       error = iget(&tip, (ino_t)ROOTINO, &ip);
+       if (error)
+               return (error);
+       *vpp = ITOV(ip);
+       return (0);
+}
+
+/*
+ * Get file system statistics.
+ */
+ufs_statfs(mp, sbp)
+       struct mount *mp;
+       register struct statfs *sbp;
+{
+       register struct ufsmount *ump;
+       register struct fs *fs;
+
+       ump = VFSTOUFS(mp);
+       fs = ump->um_fs;
+       if (fs->fs_magic != FS_MAGIC)
+               panic("ufs_statfs");
+       sbp->f_type = MOUNT_UFS;
+       sbp->f_flags = mp->m_flag &~ (M_MLOCK|M_MWAIT);
+       sbp->f_fsize = fs->fs_fsize;
+       sbp->f_bsize = fs->fs_bsize;
+       sbp->f_blocks = fs->fs_dsize;
+       sbp->f_bfree = fs->fs_cstotal.cs_nbfree * fs->fs_frag +
+               fs->fs_cstotal.cs_nffree;
+       sbp->f_bavail = (fs->fs_dsize * (100 - fs->fs_minfree) / 100) -
+               (fs->fs_dsize - sbp->f_bfree);
+       if (sbp->f_bavail < 0)
+               sbp->f_bavail = 0;
+       sbp->f_files =  fs->fs_ncg * fs->fs_ipg;
+       sbp->f_ffree = fs->fs_cstotal.cs_nifree;
+       sbp->f_fsid = mp->m_fsid;
+       bcopy((caddr_t)fs->fs_fsmnt, (caddr_t)&sbp->f_mntonname[0], MNAMELEN);
+       bcopy((caddr_t)ump->um_mntname, (caddr_t)&sbp->f_mntfromname[0],
+               MNAMELEN);
+       return (0);
+}
+
+int    syncprt = 0;
+
+/*
+ * Go through the disk queues to initiate sandbagged IO;
+ * go through the inodes to write those that have been modified;
+ * initiate the writing of the super block if it has been modified.
+ */
+ufs_sync(mp, waitfor)
        struct mount *mp;
        struct mount *mp;
+       int waitfor;
 {
 {
-       register struct fs *fs = mp->m_fs;
+       register struct inode *ip;
+       register struct ufsmount *ump = VFSTOUFS(mp);
+       register struct fs *fs;
+       int error = 0;
+       static int updlock = 0;
+
+       if (syncprt)
+               bufstats();
+       if (updlock)
+               return (EBUSY);
+       fs = ump->um_fs;
+       if (fs == (struct fs *)1)
+               return (0);
+       updlock++;
+       /*
+        * Write back modified superblock.
+        * Consistency check that the superblock
+        * is still in the buffer cache.
+        */
+       if (fs->fs_fmod != 0) {
+               if (fs->fs_ronly != 0) {                /* XXX */
+                       printf("fs = %s\n", fs->fs_fsmnt);
+                       panic("update: rofs mod");
+               }
+               fs->fs_fmod = 0;
+               fs->fs_time = time.tv_sec;
+               error = sbupdate(ump, waitfor);
+       }
+       /*
+        * Write back each (modified) inode.
+        */
+       for (ip = inode; ip < inodeNINODE; ip++) {
+               if (ip->i_devvp != ump->um_devvp ||
+                   (ip->i_flag & ILOCKED) != 0 || ITOV(ip)->v_count == 0 ||
+                   (ip->i_flag & (IMOD|IACC|IUPD|ICHG)) == 0)
+                       continue;
+               ip->i_flag |= ILOCKED;
+               ITOV(ip)->v_count++;
+               error = iupdat(ip, &time, &time, waitfor == MNT_WAIT);
+               iput(ip);
+       }
+       updlock = 0;
+       /*
+        * Force stale buffer cache information to be flushed.
+        */
+       bflush(ump->um_devvp->v_rdev);
+       return (error);
+}
+
+/*
+ * Write a superblock and associated information back to disk.
+ */
+sbupdate(mp, waitfor)
+       struct ufsmount *mp;
+       int waitfor;
+{
+       register struct fs *fs = mp->um_fs;
        register struct buf *bp;
        int blks;
        caddr_t space;
        register struct buf *bp;
        int blks;
        caddr_t space;
-       int i, size;
+       int i, size, error = 0;
 
 #ifdef SECSIZE
        bp = getblk(mp->m_dev, (daddr_t)fsbtodb(fs, SBOFF / fs->fs_fsize),
            (int)fs->fs_sbsize, fs->fs_dbsize);
 #else SECSIZE
 
 #ifdef SECSIZE
        bp = getblk(mp->m_dev, (daddr_t)fsbtodb(fs, SBOFF / fs->fs_fsize),
            (int)fs->fs_sbsize, fs->fs_dbsize);
 #else SECSIZE
-       bp = getblk(mp->m_dev, SBLOCK, (int)fs->fs_sbsize);
+       bp = getblk(mp->um_devvp, SBLOCK, (int)fs->fs_sbsize);
 #endif SECSIZE
        bcopy((caddr_t)fs, bp->b_un.b_addr, (u_int)fs->fs_sbsize);
        /* Restore compatibility to old file systems.              XXX */
 #endif SECSIZE
        bcopy((caddr_t)fs, bp->b_un.b_addr, (u_int)fs->fs_sbsize);
        /* Restore compatibility to old file systems.              XXX */
@@ -324,7 +469,10 @@ sbupdate(mp)
        bp->b_un.b_fs->fs_sparecon[0] = 0;
 #endif
 #endif SECSIZE
        bp->b_un.b_fs->fs_sparecon[0] = 0;
 #endif
 #endif SECSIZE
-       bwrite(bp);
+       if (waitfor == MNT_WAIT)
+               error = bwrite(bp);
+       else
+               bawrite(bp);
        blks = howmany(fs->fs_cssize, fs->fs_fsize);
        space = (caddr_t)fs->fs_csp[0];
        for (i = 0; i < blks; i += fs->fs_frag) {
        blks = howmany(fs->fs_cssize, fs->fs_fsize);
        space = (caddr_t)fs->fs_csp[0];
        for (i = 0; i < blks; i += fs->fs_frag) {
@@ -335,46 +483,118 @@ sbupdate(mp)
                bp = getblk(mp->m_dev, fsbtodb(fs, fs->fs_csaddr + i), size,
                    fs->fs_dbsize);
 #else SECSIZE
                bp = getblk(mp->m_dev, fsbtodb(fs, fs->fs_csaddr + i), size,
                    fs->fs_dbsize);
 #else SECSIZE
-               bp = getblk(mp->m_dev, fsbtodb(fs, fs->fs_csaddr + i), size);
+               bp = getblk(mp->um_devvp, fsbtodb(fs, fs->fs_csaddr + i), size);
 #endif SECSIZE
                bcopy(space, bp->b_un.b_addr, (u_int)size);
                space += size;
 #endif SECSIZE
                bcopy(space, bp->b_un.b_addr, (u_int)size);
                space += size;
-               bwrite(bp);
+               if (waitfor == MNT_WAIT)
+                       error = bwrite(bp);
+               else
+                       bawrite(bp);
        }
        }
+       return (error);
 }
 
 /*
 }
 
 /*
- * Common code for mount and umount.
+ * Print out statistics on the current allocation of the buffer pool.
+ * Can be enabled to print out on every ``sync'' by setting "syncprt"
+ * above.
+ */
+bufstats()
+{
+       int s, i, j, count;
+       register struct buf *bp, *dp;
+       int counts[MAXBSIZE/CLBYTES+1];
+       static char *bname[BQUEUES] = { "LOCKED", "LRU", "AGE", "EMPTY" };
+
+       for (bp = bfreelist, i = 0; bp < &bfreelist[BQUEUES]; bp++, i++) {
+               count = 0;
+               for (j = 0; j <= MAXBSIZE/CLBYTES; j++)
+                       counts[j] = 0;
+               s = splbio();
+               for (dp = bp->av_forw; dp != bp; dp = dp->av_forw) {
+                       counts[dp->b_bufsize/CLBYTES]++;
+                       count++;
+               }
+               splx(s);
+               printf("%s: total-%d", bname[i], count);
+               for (j = 0; j <= MAXBSIZE/CLBYTES; j++)
+                       if (counts[j] != 0)
+                               printf(", %d-%d", j * CLBYTES, counts[j]);
+               printf("\n");
+       }
+}
+
+/*
+ * File handle to vnode
+ */
+ufs_fhtovp(mp, fhp, vpp)
+       struct mount *mp;
+       struct fid *fhp;
+       struct vnode **vpp;
+{
+       register struct ufid *ufhp;
+       struct inode tip, *ip;
+       int error;
+
+       ufhp = (struct ufid *)fhp;
+       tip.i_dev = VFSTOUFS(mp)->um_dev;
+       tip.i_vnode.v_mount = mp;
+       if (error = iget(&tip, ufhp->ufid_ino, &ip)) {
+               *vpp = NULL;
+               return (error);
+       }
+       if (ip->i_gen != ufhp->ufid_gen) {
+               iput(ip);
+               *vpp = NULL;
+               return (EINVAL);
+       }
+       *vpp = ITOV(ip);
+       return (0);
+}
+
+/*
+ * Vnode pointer to File handle, should never happen.
+ */
+/* ARGSUSED */
+ufs_vptofh(mp, fhp, vpp)
+       struct mount *mp;
+       struct fid *fhp;
+       struct vnode **vpp;
+{
+
+       return (EINVAL);
+}
+
+/*
+ * Common code for mount and quota.
  * Check that the user's argument is a reasonable
  * thing on which to mount, and return the device number if so.
  */
  * Check that the user's argument is a reasonable
  * thing on which to mount, and return the device number if so.
  */
-getmdev(pdev, fname)
+getmdev(devvpp, fname, ndp)
+       struct vnode **devvpp;
        caddr_t fname;
        caddr_t fname;
-       dev_t *pdev;
+       register struct nameidata *ndp;
 {
 {
-       dev_t dev;
-       register struct inode *ip;
-       register struct nameidata *ndp = &u.u_nd;
+       register struct vnode *vp;
+       int error;
 
 
-       if (u.u_error = suser(u.u_cred, &u.u_acflag))
-               return (u.u_error);
-       ndp->ni_nameiop = LOOKUP | FOLLOW;
+       ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW;
        ndp->ni_segflg = UIO_USERSPACE;
        ndp->ni_dirp = fname;
        ndp->ni_segflg = UIO_USERSPACE;
        ndp->ni_dirp = fname;
-       ip = namei(ndp);
-       if (ip == NULL) {
-               if (u.u_error == ENOENT)
-                       return (ENODEV); /* needs translation */
-               return (u.u_error);
+       if (error = namei(ndp)) {
+               if (error == ENOENT)
+                       return (ENODEV);        /* needs translation */
+               return (error);
        }
        }
-       if ((ip->i_mode&IFMT) != IFBLK) {
-               iput(ip);
+       vp = ndp->ni_vp;
+       if (vp->v_type != VBLK) {
+               vput(vp);
                return (ENOTBLK);
        }
                return (ENOTBLK);
        }
-       dev = (dev_t)ip->i_rdev;
-       iput(ip);
-       if (major(dev) >= nblkdev)
+       if (major(vp->v_rdev) >= nblkdev)
                return (ENXIO);
                return (ENXIO);
-       *pdev = dev;
+       iunlock(VTOI(vp));
+       *devvpp = vp;
        return (0);
 }
        return (0);
 }
index 9fbd717..9be11ea 100644 (file)
 /*
 /*
- * Copyright (c) 1982, 1986 Regents of the University of California.
- * All rights reserved.  The Berkeley software License Agreement
- * specifies the terms and conditions for redistribution.
+ * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
+ * All rights reserved.
  *
  *
- *     @(#)ufs_vnops.c 7.6 (Berkeley) %G%
+ * 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.
+ *
+ *     @(#)ufs_vnops.c 7.7 (Berkeley) %G%
  */
 
 #include "param.h"
 #include "systm.h"
  */
 
 #include "param.h"
 #include "systm.h"
-#include "dir.h"
 #include "user.h"
 #include "kernel.h"
 #include "file.h"
 #include "stat.h"
 #include "user.h"
 #include "kernel.h"
 #include "file.h"
 #include "stat.h"
-#include "inode.h"
-#include "fs.h"
 #include "buf.h"
 #include "proc.h"
 #include "buf.h"
 #include "proc.h"
-#include "quota.h"
 #include "uio.h"
 #include "socket.h"
 #include "socketvar.h"
 #include "uio.h"
 #include "socket.h"
 #include "socketvar.h"
+#include "conf.h"
 #include "mount.h"
 #include "mount.h"
-
-extern struct fileops inodeops;
-struct file *getinode();
+#include "vnode.h"
+#include "../ufs/inode.h"
+#include "../ufs/fs.h"
+#include "../ufs/quota.h"
 
 /*
 
 /*
- * Change current working directory (``.'').
+ * Global vfs data structures for ufs
  */
  */
-chdir()
-{
 
 
-       chdirec(&u.u_cdir);
-}
+int    ufs_lookup(),
+       ufs_create(),
+       ufs_mknod(),
+       ufs_open(),
+       ufs_close(),
+       ufs_access(),
+       ufs_getattr(),
+       ufs_setattr(),
+       ufs_read(),
+       ufs_write(),
+       ufs_ioctl(),
+       ufs_select(),
+       ufs_mmap(),
+       ufs_fsync(),
+       ufs_seek(),
+       ufs_remove(),
+       ufs_link(),
+       ufs_rename(),
+       ufs_mkdir(),
+       ufs_rmdir(),
+       ufs_symlink(),
+       ufs_readdir(),
+       ufs_readlink(),
+       ufs_abortop(),
+       ufs_inactive(),
+       ufs_lock(),
+       ufs_unlock(),
+       ufs_bmap(),
+       ufs_strategy();
+
+struct vnodeops ufs_vnodeops = {
+       ufs_lookup,
+       ufs_create,
+       ufs_mknod,
+       ufs_open,
+       ufs_close,
+       ufs_access,
+       ufs_getattr,
+       ufs_setattr,
+       ufs_read,
+       ufs_write,
+       ufs_ioctl,
+       ufs_select,
+       ufs_mmap,
+       ufs_fsync,
+       ufs_seek,
+       ufs_remove,
+       ufs_link,
+       ufs_rename,
+       ufs_mkdir,
+       ufs_rmdir,
+       ufs_symlink,
+       ufs_readdir,
+       ufs_readlink,
+       ufs_abortop,
+       ufs_inactive,
+       ufs_lock,
+       ufs_unlock,
+       ufs_bmap,
+       ufs_strategy,
+};
+
+enum vtype iftovt_tab[8] = {
+       VNON, VCHR, VDIR, VBLK, VREG, VLNK, VSOCK, VBAD,
+};
+int    vttoif_tab[8] = {
+       0, IFREG, IFDIR, IFBLK, IFCHR, IFLNK, IFSOCK, IFMT,
+};
 
 /*
 
 /*
- * Change notion of root (``/'') directory.
+ * Create a regular file
  */
  */
-chroot()
+ufs_create(ndp, vap)
+       struct nameidata *ndp;
+       struct vattr *vap;
 {
 {
+       struct inode *ip;
+       int error;
 
 
-       if (u.u_error = suser(u.u_cred, &u.u_acflag))
-               return;
-       chdirec(&u.u_rdir);
+       if (error = maknode(MAKEIMODE(vap->va_type, vap->va_mode), ndp, &ip))
+               return (error);
+       ndp->ni_vp = ITOV(ip);
+       return (0);
 }
 
 /*
 }
 
 /*
- * Common routine for chroot and chdir.
+ * Mknod vnode call
  */
  */
-chdirec(ipp)
-       register struct inode **ipp;
+/* ARGSUSED */
+ufs_mknod(ndp, vap, cred)
+       struct nameidata *ndp;
+       struct ucred *cred;
+       struct vattr *vap;
 {
 {
-       register struct inode *ip;
-       struct a {
-               char    *fname;
-       } *uap = (struct a *)u.u_ap;
-       register struct nameidata *ndp = &u.u_nd;
-
-       ndp->ni_nameiop = LOOKUP | FOLLOW;
-       ndp->ni_segflg = UIO_USERSPACE;
-       ndp->ni_dirp = uap->fname;
-       ip = namei(ndp);
-       if (ip == NULL)
-               return;
-       if ((ip->i_mode&IFMT) != IFDIR) {
-               u.u_error = ENOTDIR;
-               goto bad;
-       }
-       if (access(ip, IEXEC))
-               goto bad;
-       IUNLOCK(ip);
-       if (*ipp)
-               irele(*ipp);
-       *ipp = ip;
-       return;
+       struct inode *ip;
+       int error;
 
 
-bad:
+       if (error = maknode(MAKEIMODE(vap->va_type, vap->va_mode), ndp, &ip))
+               return (error);
+       if (vap->va_rdev) {
+               /*
+                * Want to be able to use this to make badblock
+                * inodes, so don't truncate the dev number.
+                */
+               ITOV(ip)->v_rdev = ip->i_rdev = vap->va_rdev;
+               ip->i_flag |= IACC|IUPD|ICHG;
+       }
        iput(ip);
        iput(ip);
+       /*
+        * Remove inode so that it will be reloaded by iget and
+        * checked to see if it is an alias of an existing entry
+        * in the inode cache.
+        */
+       remque(ip);
+       ip->i_forw = ip;
+       ip->i_back = ip;
+       return (0);
 }
 
 /*
 }
 
 /*
- * Open system call.
+ * Open called.
+ *
+ * Nothing to do.
  */
  */
-open()
+/* ARGSUSED */
+ufs_open(vp, mode, cred)
+       struct vnode *vp;
+       int mode;
+       struct ucred *cred;
 {
 {
-       struct a {
-               char    *fname;
-               int     mode;
-               int     crtmode;
-       } *uap = (struct a *) u.u_ap;
 
 
-       copen(uap->mode-FOPEN, uap->crtmode, uap->fname);
+       return (0);
 }
 
 /*
 }
 
 /*
- * Creat system call.
+ * Close called
+ *
+ * Update the times on the inode.
  */
  */
-creat()
+/* ARGSUSED */
+ufs_close(vp, fflag, cred)
+       struct vnode *vp;
+       int fflag;
+       struct ucred *cred;
 {
 {
-       struct a {
-               char    *fname;
-               int     fmode;
-       } *uap = (struct a *)u.u_ap;
+       register struct inode *ip = VTOI(vp);
 
 
-       copen(FWRITE|FCREAT|FTRUNC, uap->fmode, uap->fname);
-}
-
-/*
- * Common code for open and creat.
- * Check permissions, allocate an open file structure,
- * and call the device open routine if any.
- */
-copen(mode, arg, fname)
-       register int mode;
-       int arg;
-       caddr_t fname;
-{
-       register struct inode *ip;
-       register struct file *fp;
-       register struct nameidata *ndp = &u.u_nd;
-       int indx;
-
-       fp = falloc();
-       if (fp == NULL)
-               return;
-       indx = u.u_r.r_val1;
-       ndp->ni_segflg = UIO_USERSPACE;
-       ndp->ni_dirp = fname;
-       if (mode&FCREAT) {
-               if (mode & FEXCL)
-                       ndp->ni_nameiop = CREATE;
-               else
-                       ndp->ni_nameiop = CREATE | FOLLOW;
-               ip = namei(ndp);
-               if (ip == NULL) {
-                       if (u.u_error)
-                               goto bad1;
-                       ip = maknode(arg&07777&(~ISVTX), ndp);
-                       if (ip == NULL)
-                               goto bad1;
-                       mode &= ~FTRUNC;
-               } else {
-                       if (mode&FEXCL) {
-                               u.u_error = EEXIST;
-                               goto bad;
-                       }
-                       mode &= ~FCREAT;
-               }
-       } else {
-               ndp->ni_nameiop = LOOKUP | FOLLOW;
-               ip = namei(ndp);
-               if (ip == NULL)
-                       goto bad1;
-       }
-       if ((ip->i_mode & IFMT) == IFSOCK) {
-               u.u_error = EOPNOTSUPP;
-               goto bad;
-       }
-       if ((mode&FCREAT) == 0) {
-               if (mode&FREAD)
-                       if (access(ip, IREAD))
-                               goto bad;
-               if (mode&(FWRITE|FTRUNC)) {
-                       if (access(ip, IWRITE))
-                               goto bad;
-                       if ((ip->i_mode&IFMT) == IFDIR) {
-                               u.u_error = EISDIR;
-                               goto bad;
-                       }
-               }
-       }
-       if (mode&FTRUNC)
-               itrunc(ip, (u_long)0);
-       IUNLOCK(ip);
-       fp->f_flag = mode&FMASK;
-       fp->f_type = DTYPE_INODE;
-       fp->f_ops = &inodeops;
-       fp->f_data = (caddr_t)ip;
-       if (setjmp(&u.u_qsave)) {
-               if (u.u_error == 0)
-                       u.u_error = EINTR;
-               u.u_ofile[indx] = NULL;
-               closef(fp);
-               return;
-       }
-       u.u_error = openi(ip, mode);
-       if (u.u_error == 0)
-               return;
-       ILOCK(ip);
-bad:
-       iput(ip);
-bad1:
-       u.u_ofile[indx] = NULL;
-       fp->f_count--;
+       if (vp->v_count > 1 && !(ip->i_flag & ILOCKED))
+               ITIMES(ip, &time, &time);
+       return (0);
 }
 
 }
 
-/*
- * Mknod system call
- */
-mknod()
+ufs_access(vp, mode, cred)
+       struct vnode *vp;
+       int mode;
+       struct ucred *cred;
 {
 {
-       register struct inode *ip;
-       register struct a {
-               char    *fname;
-               int     fmode;
-               int     dev;
-       } *uap = (struct a *)u.u_ap;
-       register struct nameidata *ndp = &u.u_nd;
-
-       if (u.u_error = suser(u.u_cred, &u.u_acflag))
-               return;
-       ndp->ni_nameiop = CREATE;
-       ndp->ni_segflg = UIO_USERSPACE;
-       ndp->ni_dirp = uap->fname;
-       ip = namei(ndp);
-       if (ip != NULL) {
-               u.u_error = EEXIST;
-               goto out;
-       }
-       if (u.u_error)
-               return;
-       ip = maknode(uap->fmode, ndp);
-       if (ip == NULL)
-               return;
-       switch (ip->i_mode & IFMT) {
-
-       case IFMT:      /* used by badsect to flag bad sectors */
-       case IFCHR:
-       case IFBLK:
-               if (uap->dev) {
-                       /*
-                        * Want to be able to use this to make badblock
-                        * inodes, so don't truncate the dev number.
-                        */
-                       ip->i_rdev = uap->dev;
-                       ip->i_flag |= IACC|IUPD|ICHG;
-               }
-       }
 
 
-out:
-       iput(ip);
+       return (iaccess(VTOI(vp), mode, cred));
 }
 
 }
 
-/*
- * link system call
- */
-link()
+/* ARGSUSED */
+ufs_getattr(vp, vap, cred)
+       struct vnode *vp;
+       register struct vattr *vap;
+       struct ucred *cred;
 {
 {
-       register struct inode *ip, *xp;
-       register struct a {
-               char    *target;
-               char    *linkname;
-       } *uap = (struct a *)u.u_ap;
-       register struct nameidata *ndp = &u.u_nd;
-
-       ndp->ni_nameiop = LOOKUP | FOLLOW;
-       ndp->ni_segflg = UIO_USERSPACE;
-       ndp->ni_dirp = uap->target;
-       ip = namei(ndp);        /* well, this routine is doomed anyhow */
-       if (ip == NULL)
-               return;
-       if ((ip->i_mode&IFMT) == IFDIR &&
-           (u.u_error = suser(u.u_cred, &u.u_acflag))) {
-               iput(ip);
-               return;
-       }
-       if (ip->i_nlink == LINK_MAX - 1) {
-               u.u_error = EMLINK;
-               iput(ip);
-               return;
-       }
-       ip->i_nlink++;
-       ip->i_flag |= ICHG;
-       iupdat(ip, &time, &time, 1);
-       IUNLOCK(ip);
-       ndp->ni_nameiop = CREATE;
-       ndp->ni_segflg = UIO_USERSPACE;
-       ndp->ni_dirp = (caddr_t)uap->linkname;
-       xp = namei(ndp);
-       if (xp != NULL) {
-               u.u_error = EEXIST;
-               iput(xp);
-               goto out;
-       }
-       if (u.u_error)
-               goto out;
-       if (ndp->ni_pdir->i_dev != ip->i_dev) {
-               iput(ndp->ni_pdir);
-               u.u_error = EXDEV;
-               goto out;
-       }
-       u.u_error = direnter(ip, ndp);
-out:
-       if (u.u_error) {
-               ip->i_nlink--;
-               ip->i_flag |= ICHG;
-       }
-       irele(ip);
-}
-
-/*
- * symlink -- make a symbolic link
- */
-symlink()
-{
-       register struct a {
-               char    *target;
-               char    *linkname;
-       } *uap = (struct a *)u.u_ap;
-       register struct inode *ip;
-       register char *tp;
-       register c, nc;
-       register struct nameidata *ndp = &u.u_nd;
-
-       tp = uap->target;
-       nc = 0;
-       while (c = fubyte(tp)) {
-               if (c < 0) {
-                       u.u_error = EFAULT;
-                       return;
-               }
-               tp++;
-               nc++;
-       }
-       ndp->ni_nameiop = CREATE;
-       ndp->ni_segflg = UIO_USERSPACE;
-       ndp->ni_dirp = uap->linkname;
-       ip = namei(ndp);
-       if (ip) {
-               iput(ip);
-               u.u_error = EEXIST;
-               return;
-       }
-       if (u.u_error)
-               return;
-       ip = maknode(IFLNK | 0777, ndp);
-       if (ip == NULL)
-               return;
-       u.u_error = rdwri(UIO_WRITE, ip, uap->target, nc, (off_t)0, 0,
-           (int *)0);
-       /* handle u.u_error != 0 */
-       iput(ip);
-}
+       register struct inode *ip = VTOI(vp);
 
 
-/*
- * Unlink system call.
- * Hard to avoid races here, especially
- * in unlinking directories.
- */
-unlink()
-{
-       struct a {
-               char    *fname;
-       } *uap = (struct a *)u.u_ap;
-       register struct inode *ip, *dp;
-       register struct nameidata *ndp = &u.u_nd;
-
-       ndp->ni_nameiop = DELETE | LOCKPARENT;
-       ndp->ni_segflg = UIO_USERSPACE;
-       ndp->ni_dirp = uap->fname;
-       ip = namei(ndp);
-       if (ip == NULL)
-               return;
-       dp = ndp->ni_pdir;
-       if ((ip->i_mode&IFMT) == IFDIR &&
-           (u.u_error = suser(u.u_cred, &u.u_acflag)))
-               goto out;
+       ITIMES(ip, &time, &time);
        /*
        /*
-        * Don't unlink a mounted file.
+        * Copy from inode table
         */
         */
-       if (ip->i_dev != dp->i_dev) {
-               u.u_error = EBUSY;
-               goto out;
-       }
-       if (ip->i_flag&ITEXT)
-               xrele(ip);      /* try once to free text */
-       if (dirremove(ndp)) {
-               ip->i_nlink--;
-               ip->i_flag |= ICHG;
-       }
-out:
-       if (dp == ip)
-               irele(ip);
+       vap->va_fsid = ip->i_dev;
+       vap->va_fileid = ip->i_number;
+       vap->va_mode = ip->i_mode & ~IFMT;
+       vap->va_nlink = ip->i_nlink;
+       vap->va_uid = ip->i_uid;
+       vap->va_gid = ip->i_gid;
+       vap->va_rdev = (dev_t)ip->i_rdev;
+       vap->va_size = ip->i_ic.ic_size.val[0];
+       vap->va_size1 = ip->i_ic.ic_size.val[1];
+       vap->va_atime.tv_sec = ip->i_atime;
+       vap->va_mtime.tv_sec = ip->i_mtime;
+       vap->va_ctime.tv_sec = ip->i_ctime;
+       /* this doesn't belong here */
+       if (vp->v_type == VBLK)
+               vap->va_blocksize = BLKDEV_IOSIZE;
+       else if (vp->v_type == VCHR)
+               vap->va_blocksize = MAXBSIZE;
        else
        else
-               iput(ip);
-       iput(dp);
+               vap->va_blocksize = ip->i_fs->fs_bsize;
+       /*
+        * XXX THIS IS NOT CORRECT!!, but be sure to change vn_stat()
+        * if you change it.
+        */
+       vap->va_bytes = ip->i_blocks;
+       vap->va_bytes1 = -1;
+       vap->va_type = vp->v_type;
+       return (0);
 }
 
 /*
 }
 
 /*
- * Seek system call
+ * Set attribute vnode op. called from several syscalls
  */
  */
-lseek()
+ufs_setattr(vp, vap, cred)
+       register struct vnode *vp;
+       register struct vattr *vap;
+       register struct ucred *cred;
 {
 {
-       register struct file *fp;
-       register struct a {
-               int     fd;
-               off_t   off;
-               int     sbase;
-       } *uap = (struct a *)u.u_ap;
-
-       GETF(fp, uap->fd);
-       if (fp->f_type != DTYPE_INODE) {
-               u.u_error = ESPIPE;
-               return;
-       }
-       switch (uap->sbase) {
-
-       case L_INCR:
-               fp->f_offset += uap->off;
-               break;
-
-       case L_XTND:
-               fp->f_offset = uap->off + ((struct inode *)fp->f_data)->i_size;
-               break;
-
-       case L_SET:
-               fp->f_offset = uap->off;
-               break;
+       register struct inode *ip = VTOI(vp);
+       int error = 0;
 
 
-       default:
-               u.u_error = EINVAL;
-               return;
+       /*
+        * Check for unsetable attributes.
+        */
+       if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) ||
+           (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) ||
+           (vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) ||
+           ((int)vap->va_bytes != VNOVAL)) {
+               return (EINVAL);
        }
        }
-       u.u_r.r_off = fp->f_offset;
-}
-
-/*
- * Access system call
- */
-saccess()
-{
-       register svuid, svgid;
-       register struct inode *ip;
-       register struct a {
-               char    *fname;
-               int     fmode;
-       } *uap = (struct a *)u.u_ap;
-       register struct nameidata *ndp = &u.u_nd;
-
-       svuid = u.u_uid;
-       svgid = u.u_gid;
-       u.u_uid = u.u_ruid;
-       u.u_gid = u.u_rgid;
-       ndp->ni_nameiop = LOOKUP | FOLLOW;
-       ndp->ni_segflg = UIO_USERSPACE;
-       ndp->ni_dirp = uap->fname;
-       ip = namei(ndp);
-       if (ip != NULL) {
-               if ((uap->fmode&R_OK) && access(ip, IREAD))
-                       goto done;
-               if ((uap->fmode&W_OK) && access(ip, IWRITE))
-                       goto done;
-               if ((uap->fmode&X_OK) && access(ip, IEXEC))
-                       goto done;
-done:
-               iput(ip);
+       /*
+        * Go through the fields and update iff not VNOVAL.
+        */
+       if (vap->va_uid != (u_short)VNOVAL || vap->va_gid != (u_short)VNOVAL)
+               if (error = chown1(vp, vap->va_uid, vap->va_gid, cred))
+                       return (error);
+       if (vap->va_size != VNOVAL) {
+               if (vp->v_type == VDIR)
+                       return (EISDIR);
+               if (error = iaccess(ip, IWRITE, cred))
+                       return (error);
+               if (error = itrunc(ip, vap->va_size))
+                       return (error);
        }
        }
-       u.u_uid = svuid;
-       u.u_gid = svgid;
-}
-
-/*
- * Stat system call.  This version follows links.
- */
-stat()
-{
-
-       stat1(FOLLOW);
-}
-
-/*
- * Lstat system call.  This version does not follow links.
- */
-lstat()
-{
-
-       stat1(NOFOLLOW);
-}
-
-stat1(follow)
-       int follow;
-{
-       register struct inode *ip;
-       register struct a {
-               char    *fname;
-               struct stat *ub;
-       } *uap = (struct a *)u.u_ap;
-       struct stat sb;
-       register struct nameidata *ndp = &u.u_nd;
-
-       ndp->ni_nameiop = LOOKUP | follow;
-       ndp->ni_segflg = UIO_USERSPACE;
-       ndp->ni_dirp = uap->fname;
-       ip = namei(ndp);
-       if (ip == NULL)
-               return;
-       (void) ino_stat(ip, &sb);
-       iput(ip);
-       u.u_error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
-}
-
-/*
- * Return target name of a symbolic link
- */
-readlink()
-{
-       register struct inode *ip;
-       register struct a {
-               char    *name;
-               char    *buf;
-               int     count;
-       } *uap = (struct a *)u.u_ap;
-       register struct nameidata *ndp = &u.u_nd;
-       int resid;
-
-       ndp->ni_nameiop = LOOKUP;
-       ndp->ni_segflg = UIO_USERSPACE;
-       ndp->ni_dirp = uap->name;
-       ip = namei(ndp);
-       if (ip == NULL)
-               return;
-       if ((ip->i_mode&IFMT) != IFLNK) {
-               u.u_error = EINVAL;
-               goto out;
+       /*
+        * Check whether the following attributes can be changed.
+        */
+       if (cred->cr_uid != ip->i_uid &&
+           (error = suser(cred, &u.u_acflag)))
+               return (error);
+       if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) {
+               if (vap->va_atime.tv_sec != VNOVAL)
+                       ip->i_flag |= IACC;
+               if (vap->va_mtime.tv_sec != VNOVAL)
+                       ip->i_flag |= IUPD;
+               ip->i_flag |= ICHG;
+               if (error = iupdat(ip, &vap->va_atime, &vap->va_mtime, 1))
+                       return (error);
        }
        }
-       u.u_error = rdwri(UIO_READ, ip, uap->buf, uap->count, (off_t)0, 0,
-           &resid);
-out:
-       iput(ip);
-       u.u_r.r_val1 = uap->count - resid;
-}
-
-/*
- * Change mode of a file given path name.
- */
-chmod()
-{
-       struct inode *ip;
-       struct a {
-               char    *fname;
-               int     fmode;
-       } *uap = (struct a *)u.u_ap;
-
-       if ((ip = owner(uap->fname, FOLLOW)) == NULL)
-               return;
-       u.u_error = chmod1(ip, uap->fmode);
-       iput(ip);
-}
-
-/*
- * Change mode of a file given a file descriptor.
- */
-fchmod()
-{
-       struct a {
-               int     fd;
-               int     fmode;
-       } *uap = (struct a *)u.u_ap;
-       register struct inode *ip;
-       register struct file *fp;
-
-       fp = getinode(uap->fd);
-       if (fp == NULL)
-               return;
-       ip = (struct inode *)fp->f_data;
-       if (u.u_uid != ip->i_uid &&
-           (u.u_error = suser(u.u_cred, &u.u_acflag)))
-               return;
-       ILOCK(ip);
-       u.u_error = chmod1(ip, uap->fmode);
-       IUNLOCK(ip);
+       if (vap->va_mode != (u_short)VNOVAL)
+               error = chmod1(vp, (int)vap->va_mode, cred);
+       return (error);
 }
 
 /*
  * Change the mode on a file.
  * Inode must be locked before calling.
  */
 }
 
 /*
  * Change the mode on a file.
  * Inode must be locked before calling.
  */
-chmod1(ip, mode)
-       register struct inode *ip;
+chmod1(vp, mode, cred)
+       register struct vnode *vp;
        register int mode;
        register int mode;
+       struct ucred *cred;
 {
 {
+       register struct inode *ip = VTOI(vp);
 
 
-       if (ip->i_fs->fs_ronly)
-               return (EROFS);
        ip->i_mode &= ~07777;
        ip->i_mode &= ~07777;
-       if (u.u_uid) {
-               if ((ip->i_mode & IFMT) != IFDIR)
+       if (cred->cr_uid) {
+               if (vp->v_type != VDIR)
                        mode &= ~ISVTX;
                        mode &= ~ISVTX;
-               if (!groupmember(ip->i_gid))
+               if (!groupmember(ip->i_gid, cred))
                        mode &= ~ISGID;
        }
                        mode &= ~ISGID;
        }
-       ip->i_mode |= mode&07777;
+       ip->i_mode |= mode & 07777;
        ip->i_flag |= ICHG;
        ip->i_flag |= ICHG;
-       if (ip->i_flag&ITEXT && (ip->i_mode&ISVTX)==0)
-               xrele(ip);
+       if ((vp->v_flag & VTEXT) && (ip->i_mode & ISVTX) == 0)
+               xrele(vp);
        return (0);
 }
 
        return (0);
 }
 
-/*
- * Set ownership given a path name.
- */
-chown()
-{
-       struct inode *ip;
-       struct a {
-               char    *fname;
-               int     uid;
-               int     gid;
-       } *uap = (struct a *)u.u_ap;
-       register struct nameidata *ndp = &u.u_nd;
-
-       ndp->ni_nameiop = LOOKUP | NOFOLLOW;
-       ndp->ni_segflg = UIO_USERSPACE;
-       ndp->ni_dirp = uap->fname;
-       ip = namei(ndp);
-       if (ip == NULL)
-               return;
-       u.u_error = chown1(ip, uap->uid, uap->gid);
-       iput(ip);
-}
-
-/*
- * Set ownership given a file descriptor.
- */
-fchown()
-{
-       struct a {
-               int     fd;
-               int     uid;
-               int     gid;
-       } *uap = (struct a *)u.u_ap;
-       register struct inode *ip;
-       register struct file *fp;
-
-       fp = getinode(uap->fd);
-       if (fp == NULL)
-               return;
-       ip = (struct inode *)fp->f_data;
-       ILOCK(ip);
-       u.u_error = chown1(ip, uap->uid, uap->gid);
-       IUNLOCK(ip);
-}
-
 /*
  * Perform chown operation on inode ip;
  * inode must be locked prior to call.
  */
 /*
  * Perform chown operation on inode ip;
  * inode must be locked prior to call.
  */
-chown1(ip, uid, gid)
-       register struct inode *ip;
-       int uid, gid;
+chown1(vp, uid, gid, cred)
+       register struct vnode *vp;
+       uid_t uid;
+       gid_t gid;
+       struct ucred *cred;
 {
 {
+       register struct inode *ip = VTOI(vp);
 #ifdef QUOTA
        register long change;
 #endif
 #ifdef QUOTA
        register long change;
 #endif
+       int error;
 
 
-       if (ip->i_fs->fs_ronly)
-               return (EROFS);
-       if (uid == -1)
+       if (uid == (u_short)VNOVAL)
                uid = ip->i_uid;
                uid = ip->i_uid;
-       if (gid == -1)
+       if (gid == (u_short)VNOVAL)
                gid = ip->i_gid;
        /*
         * If we don't own the file, are trying to change the owner
         * of the file, or are not a member of the target group,
         * the caller must be superuser or the call fails.
         */
                gid = ip->i_gid;
        /*
         * If we don't own the file, are trying to change the owner
         * of the file, or are not a member of the target group,
         * the caller must be superuser or the call fails.
         */
-       if ((u.u_uid != ip->i_uid || uid != ip->i_uid ||
-           !groupmember((gid_t)gid)) &&
-           (u.u_error = suser(u.u_cred, &u.u_acflag)))
-               return (u.u_error);
+       if ((cred->cr_uid != ip->i_uid || uid != ip->i_uid ||
+           !groupmember((gid_t)gid, cred)) &&
+           (error = suser(cred, &u.u_acflag)))
+               return (error);
 #ifdef QUOTA
        if (ip->i_uid == uid)           /* this just speeds things a little */
                change = 0;
 #ifdef QUOTA
        if (ip->i_uid == uid)           /* this just speeds things a little */
                change = 0;
@@ -682,7 +361,7 @@ chown1(ip, uid, gid)
        ip->i_uid = uid;
        ip->i_gid = gid;
        ip->i_flag |= ICHG;
        ip->i_uid = uid;
        ip->i_gid = gid;
        ip->i_flag |= ICHG;
-       if (u.u_ruid != 0)
+       if (cred->cr_ruid != 0)
                ip->i_mode &= ~(ISUID|ISGID);
 #ifdef QUOTA
        ip->i_dquot = inoquota(ip);
                ip->i_mode &= ~(ISUID|ISGID);
 #ifdef QUOTA
        ip->i_dquot = inoquota(ip);
@@ -694,113 +373,135 @@ chown1(ip, uid, gid)
 #endif
 }
 
 #endif
 }
 
-utimes()
+/* ARGSUSED */
+ufs_ioctl(vp, com, data, fflag, cred)
+       struct vnode *vp;
+       int com;
+       caddr_t data;
+       int fflag;
+       struct ucred *cred;
 {
 {
-       register struct a {
-               char    *fname;
-               struct  timeval *tptr;
-       } *uap = (struct a *)u.u_ap;
-       register struct inode *ip;
-       struct timeval tv[2];
 
 
-       if ((ip = owner(uap->fname, FOLLOW)) == NULL)
-               return;
-       if (ip->i_fs->fs_ronly) {
-               u.u_error = EROFS;
-               iput(ip);
-               return;
-       }
-       u.u_error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv));
-       if (u.u_error == 0) {
-               ip->i_flag |= IACC|IUPD|ICHG;
-               iupdat(ip, &tv[0], &tv[1], 0);
-       }
-       iput(ip);
+       printf("ufs_ioctl called with type %d\n", vp->v_type);
+       return (ENOTTY);
+}
+
+/* ARGSUSED */
+ufs_select(vp, which, cred)
+       struct vnode *vp;
+       int which;
+       struct ucred *cred;
+{
+
+       printf("ufs_select called with type %d\n", vp->v_type);
+       return (1);             /* XXX */
 }
 
 /*
 }
 
 /*
- * Flush any pending I/O.
+ * Mmap a file
+ *
+ * NB Currently unsupported.
  */
  */
-sync()
+/* ARGSUSED */
+ufs_mmap(vp, fflags, cred)
+       struct vnode *vp;
+       int fflags;
+       struct ucred *cred;
 {
 
 {
 
-       update();
+       return (EINVAL);
 }
 
 /*
 }
 
 /*
- * Truncate a file given its path name.
+ * Synch an open file.
  */
  */
-truncate()
+/* ARGSUSED */
+ufs_fsync(vp, fflags, cred)
+       struct vnode *vp;
+       int fflags;
+       struct ucred *cred;
 {
 {
-       struct a {
-               char    *fname;
-               off_t   length;
-       } *uap = (struct a *)u.u_ap;
-       struct inode *ip;
-       register struct nameidata *ndp = &u.u_nd;
-
-       ndp->ni_nameiop = LOOKUP | FOLLOW;
-       ndp->ni_segflg = UIO_USERSPACE;
-       ndp->ni_dirp = uap->fname;
-       ip = namei(ndp);
-       if (ip == NULL)
-               return;
-       if (access(ip, IWRITE))
-               goto bad;
-       if ((ip->i_mode&IFMT) == IFDIR) {
-               u.u_error = EISDIR;
-               goto bad;
-       }
-       itrunc(ip, (u_long)uap->length);
-bad:
-       iput(ip);
+       register struct inode *ip = VTOI(vp);
+       int error;
+
+       ILOCK(ip);
+       if (fflags&FWRITE)
+               ip->i_flag |= ICHG;
+       error = syncip(ip);
+       IUNLOCK(ip);
+       return (error);
 }
 
 /*
 }
 
 /*
- * Truncate a file given a file descriptor.
+ * Seek on a file
+ *
+ * Nothing to do, so just return.
  */
  */
-ftruncate()
+/* ARGSUSED */
+ufs_seek(vp, oldoff, newoff, cred)
+       struct vnode *vp;
+       off_t oldoff, newoff;
+       struct ucred *cred;
 {
 {
-       struct a {
-               int     fd;
-               off_t   length;
-       } *uap = (struct a *)u.u_ap;
-       struct inode *ip;
-       struct file *fp;
-
-       fp = getinode(uap->fd);
-       if (fp == NULL)
-               return;
-       if ((fp->f_flag&FWRITE) == 0) {
-               u.u_error = EINVAL;
-               return;
+
+       return (0);
+}
+
+/*
+ * ufs remove
+ * Hard to avoid races here, especially
+ * in unlinking directories.
+ */
+ufs_remove(ndp)
+       struct nameidata *ndp;
+{
+       register struct inode *ip, *dp;
+       int error;
+
+       ip = VTOI(ndp->ni_vp);
+       dp = VTOI(ndp->ni_dvp);
+       error = dirremove(ndp);
+       if (!error) {
+               ip->i_nlink--;
+               ip->i_flag |= ICHG;
        }
        }
-       ip = (struct inode *)fp->f_data;
-       ILOCK(ip);
-       itrunc(ip, (u_long)uap->length);
-       IUNLOCK(ip);
+       if (dp == ip)
+               vrele(ITOV(ip));
+       else
+               iput(ip);
+       iput(dp);
+       return (error);
 }
 
 /*
 }
 
 /*
- * Synch an open file.
+ * link vnode call
  */
  */
-fsync()
+ufs_link(vp, ndp)
+       register struct vnode *vp;
+       register struct nameidata *ndp;
 {
 {
-       struct a {
-               int     fd;
-       } *uap = (struct a *)u.u_ap;
-       struct inode *ip;
-       struct file *fp;
+       register struct inode *ip = VTOI(vp);
+       int error;
 
 
-       fp = getinode(uap->fd);
-       if (fp == NULL)
-               return;
-       ip = (struct inode *)fp->f_data;
-       ILOCK(ip);
-       if (fp->f_flag&FWRITE)
+       if (ndp->ni_dvp != vp)
+               ILOCK(ip);
+       if (ip->i_nlink == LINK_MAX - 1) {
+               error = EMLINK;
+               goto out;
+       }
+       ip->i_nlink++;
+       ip->i_flag |= ICHG;
+       error = iupdat(ip, &time, &time, 1);
+       if (!error)
+               error = direnter(ip, ndp);
+out:
+       if (ndp->ni_dvp != vp)
+               IUNLOCK(ip);
+       if (error) {
+               ip->i_nlink--;
                ip->i_flag |= ICHG;
                ip->i_flag |= ICHG;
-       syncip(ip);
-       IUNLOCK(ip);
+       }
+       return (error);
 }
 
 /*
 }
 
 /*
@@ -817,7 +518,7 @@ fsync()
  * Basic algorithm is:
  *
  * 1) Bump link count on source while we're linking it to the
  * Basic algorithm is:
  *
  * 1) Bump link count on source while we're linking it to the
- *    target.  This also insure the inode won't be deleted out
+ *    target.  This also ensure the inode won't be deleted out
  *    from underneath us while we work (it may be truncated by
  *    a concurrent `trunc' or `open' for creation).
  * 2) Link source to destination.  If destination already exists,
  *    from underneath us while we work (it may be truncated by
  *    a concurrent `trunc' or `open' for creation).
  * 2) Link source to destination.  If destination already exists,
@@ -826,52 +527,36 @@ fsync()
  *    directory was moved and the parent of the destination
  *    is different from the source, patch the ".." entry in the
  *    directory.
  *    directory was moved and the parent of the destination
  *    is different from the source, patch the ".." entry in the
  *    directory.
- *
- * Source and destination must either both be directories, or both
- * not be directories.  If target is a directory, it must be empty.
  */
  */
-rename()
+ufs_rename(fndp, tndp)
+       register struct nameidata *fndp, *tndp;
 {
 {
-       struct a {
-               char    *from;
-               char    *to;
-       } *uap = (struct a *)u.u_ap;
        register struct inode *ip, *xp, *dp;
        struct dirtemplate dirbuf;
        int doingdirectory = 0, oldparent = 0, newparent = 0;
        register struct inode *ip, *xp, *dp;
        struct dirtemplate dirbuf;
        int doingdirectory = 0, oldparent = 0, newparent = 0;
-       register struct nameidata *ndp = &u.u_nd;
        int error = 0;
 
        int error = 0;
 
-       ndp->ni_nameiop = DELETE | LOCKPARENT;
-       ndp->ni_segflg = UIO_USERSPACE;
-       ndp->ni_dirp = uap->from;
-       ip = namei(ndp);
-       if (ip == NULL)
-               return;
-       dp = ndp->ni_pdir;
+       dp = VTOI(fndp->ni_dvp);
+       ip = VTOI(fndp->ni_vp);
+       ILOCK(ip);
        if ((ip->i_mode&IFMT) == IFDIR) {
        if ((ip->i_mode&IFMT) == IFDIR) {
-               register struct direct *d;
+               register struct direct *d = &fndp->ni_dent;
 
 
-               d = &ndp->ni_dent;
                /*
                 * Avoid ".", "..", and aliases of "." for obvious reasons.
                 */
                /*
                 * Avoid ".", "..", and aliases of "." for obvious reasons.
                 */
-               if ((d->d_namlen == 1 && d->d_name[0] == '.') ||
-                   (d->d_namlen == 2 && bcmp(d->d_name, "..", 2) == 0) ||
-                   (dp == ip) || (ip->i_flag & IRENAME)) {
-                       iput(dp);
-                       if (dp == ip)
-                               irele(ip);
-                       else
-                               iput(ip);
-                       u.u_error = EINVAL;
-                       return;
+               if ((d->d_namlen == 1 && d->d_name[0] == '.') || dp == ip ||
+                   fndp->ni_isdotdot || (ip->i_flag & IRENAME)) {
+                       IUNLOCK(ip);
+                       ufs_abortop(fndp);
+                       ufs_abortop(tndp);
+                       return (EINVAL);
                }
                ip->i_flag |= IRENAME;
                oldparent = dp->i_number;
                doingdirectory++;
        }
                }
                ip->i_flag |= IRENAME;
                oldparent = dp->i_number;
                doingdirectory++;
        }
-       iput(dp);
+       vrele(fndp->ni_dvp);
 
        /*
         * 1) Bump link count while we're moving stuff
 
        /*
         * 1) Bump link count while we're moving stuff
@@ -881,21 +566,17 @@ rename()
         */
        ip->i_nlink++;
        ip->i_flag |= ICHG;
         */
        ip->i_nlink++;
        ip->i_flag |= ICHG;
-       iupdat(ip, &time, &time, 1);
+       error = iupdat(ip, &time, &time, 1);
        IUNLOCK(ip);
 
        /*
         * When the target exists, both the directory
        IUNLOCK(ip);
 
        /*
         * When the target exists, both the directory
-        * and target inodes are returned locked.
+        * and target vnodes are returned locked.
         */
         */
-       ndp->ni_nameiop = CREATE | LOCKPARENT | NOCACHE;
-       ndp->ni_dirp = (caddr_t)uap->to;
-       xp = namei(ndp);
-       if (u.u_error) {
-               error = u.u_error;
-               goto out;
-       }
-       dp = ndp->ni_pdir;
+       dp = VTOI(tndp->ni_dvp);
+       xp = NULL;
+       if (tndp->ni_vp)
+               xp = VTOI(tndp->ni_vp);
        /*
         * If ".." must be changed (ie the directory gets a new
         * parent) then the source directory must not be in the
        /*
         * If ".." must be changed (ie the directory gets a new
         * parent) then the source directory must not be in the
@@ -909,21 +590,21 @@ rename()
        if (oldparent != dp->i_number)
                newparent = dp->i_number;
        if (doingdirectory && newparent) {
        if (oldparent != dp->i_number)
                newparent = dp->i_number;
        if (doingdirectory && newparent) {
-               if (access(ip, IWRITE))
+               if (error = iaccess(ip, IWRITE, tndp->ni_cred))
                        goto bad;
                        goto bad;
+               tndp->ni_nameiop = RENAME | LOCKPARENT | LOCKLEAF | NOCACHE;
                do {
                do {
-                       dp = ndp->ni_pdir;
+                       dp = VTOI(tndp->ni_dvp);
                        if (xp != NULL)
                        if (xp != NULL)
-                               iput(xp);
-                       u.u_error = checkpath(ip, dp);
-                       if (u.u_error)
+                               vput(ITOV(xp));
+                       if (error = checkpath(ip, dp, tndp->ni_cred))
                                goto out;
                                goto out;
-                       xp = namei(ndp);
-                       if (u.u_error) {
-                               error = u.u_error;
+                       if (error = namei(tndp))
                                goto out;
                                goto out;
-                       }
-               } while (dp != ndp->ni_pdir);
+                       xp = NULL;
+                       if (tndp->ni_vp)
+                               xp = VTOI(tndp->ni_vp);
+               } while (dp != VTOI(tndp->ni_dvp));
        }
        /*
         * 2) If target doesn't exist, link the target
        }
        /*
         * 2) If target doesn't exist, link the target
@@ -933,10 +614,8 @@ rename()
         *    expunge the original entry's existence.
         */
        if (xp == NULL) {
         *    expunge the original entry's existence.
         */
        if (xp == NULL) {
-               if (dp->i_dev != ip->i_dev) {
-                       error = EXDEV;
-                       goto bad;
-               }
+               if (dp->i_dev != ip->i_dev)
+                       panic("rename: EXDEV");
                /*
                 * Account for ".." in new directory.
                 * When source and destination have the same
                /*
                 * Account for ".." in new directory.
                 * When source and destination have the same
@@ -945,29 +624,27 @@ rename()
                if (doingdirectory && newparent) {
                        dp->i_nlink++;
                        dp->i_flag |= ICHG;
                if (doingdirectory && newparent) {
                        dp->i_nlink++;
                        dp->i_flag |= ICHG;
-                       iupdat(dp, &time, &time, 1);
+                       error = iupdat(dp, &time, &time, 1);
                }
                }
-               error = direnter(ip, ndp);
-               if (error)
+               if (error = direnter(ip, tndp))
                        goto out;
        } else {
                        goto out;
        } else {
-               if (xp->i_dev != dp->i_dev || xp->i_dev != ip->i_dev) {
-                       error = EXDEV;
-                       goto bad;
-               }
+               if (xp->i_dev != dp->i_dev || xp->i_dev != ip->i_dev)
+                       panic("rename: EXDEV");
                /*
                 * Short circuit rename(foo, foo).
                 */
                if (xp->i_number == ip->i_number)
                /*
                 * Short circuit rename(foo, foo).
                 */
                if (xp->i_number == ip->i_number)
-                       goto bad;
+                       panic("rename: same file");
                /*
                 * If the parent directory is "sticky", then the user must
                 * own the parent directory, or the destination of the rename,
                 * otherwise the destination may not be changed (except by
                 * root). This implements append-only directories.
                 */
                /*
                 * If the parent directory is "sticky", then the user must
                 * own the parent directory, or the destination of the rename,
                 * otherwise the destination may not be changed (except by
                 * root). This implements append-only directories.
                 */
-               if ((dp->i_mode & ISVTX) && u.u_uid != 0 &&
-                   u.u_uid != dp->i_uid && xp->i_uid != u.u_uid) {
+               if ((dp->i_mode & ISVTX) && tndp->ni_cred->cr_uid != 0 &&
+                   tndp->ni_cred->cr_uid != dp->i_uid &&
+                   xp->i_uid != tndp->ni_cred->cr_uid) {
                        error = EPERM;
                        goto bad;
                }
                        error = EPERM;
                        goto bad;
                }
@@ -979,7 +656,8 @@ rename()
                 * not directories).
                 */
                if ((xp->i_mode&IFMT) == IFDIR) {
                 * not directories).
                 */
                if ((xp->i_mode&IFMT) == IFDIR) {
-                       if (!dirempty(xp, dp->i_number) || xp->i_nlink > 2) {
+                       if (!dirempty(xp, dp->i_number, tndp->ni_cred) || 
+                           xp->i_nlink > 2) {
                                error = ENOTEMPTY;
                                goto bad;
                        }
                                error = ENOTEMPTY;
                                goto bad;
                        }
@@ -987,16 +665,14 @@ rename()
                                error = ENOTDIR;
                                goto bad;
                        }
                                error = ENOTDIR;
                                goto bad;
                        }
-                       cacheinval(dp);
+                       cache_purge(ITOV(dp));
                } else if (doingdirectory) {
                        error = EISDIR;
                        goto bad;
                }
                } else if (doingdirectory) {
                        error = EISDIR;
                        goto bad;
                }
-               dirrewrite(dp, ip, ndp);
-               if (u.u_error) {
-                       error = u.u_error;
-                       goto bad1;
-               }
+               if (error = dirrewrite(dp, ip, tndp))
+                       goto bad;
+               vput(ITOV(dp));
                /*
                 * Adjust the link count of the target to
                 * reflect the dirrewrite above.  If this is
                /*
                 * Adjust the link count of the target to
                 * reflect the dirrewrite above.  If this is
@@ -1011,32 +687,33 @@ rename()
                if (doingdirectory) {
                        if (--xp->i_nlink != 0)
                                panic("rename: linked directory");
                if (doingdirectory) {
                        if (--xp->i_nlink != 0)
                                panic("rename: linked directory");
-                       itrunc(xp, (u_long)0);
+                       error = itrunc(xp, (u_long)0);
                }
                xp->i_flag |= ICHG;
                }
                xp->i_flag |= ICHG;
-               iput(xp);
+               vput(ITOV(xp));
                xp = NULL;
        }
 
        /*
         * 3) Unlink the source.
         */
                xp = NULL;
        }
 
        /*
         * 3) Unlink the source.
         */
-       ndp->ni_nameiop = DELETE | LOCKPARENT;
-       ndp->ni_segflg = UIO_USERSPACE;
-       ndp->ni_dirp = uap->from;
-       xp = namei(ndp);
-       if (xp != NULL)
-               dp = ndp->ni_pdir;
-       else
+       fndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF;
+       (void)namei(fndp);
+       if (fndp->ni_vp != NULL) {
+               xp = VTOI(fndp->ni_vp);
+               dp = VTOI(fndp->ni_dvp);
+       } else {
+               xp = NULL;
                dp = NULL;
                dp = NULL;
+       }
        /*
        /*
-        * Insure that the directory entry still exists and has not
+        * Ensure that the directory entry still exists and has not
         * changed while the new name has been entered. If the source is
         * a file then the entry may have been unlinked or renamed. In
         * either case there is no further work to be done. If the source
         * is a directory then it cannot have been rmdir'ed; its link
         * count of three would cause a rmdir to fail with ENOTEMPTY.
         * changed while the new name has been entered. If the source is
         * a file then the entry may have been unlinked or renamed. In
         * either case there is no further work to be done. If the source
         * is a directory then it cannot have been rmdir'ed; its link
         * count of three would cause a rmdir to fail with ENOTEMPTY.
-        * The IRENAME flag insures that it cannot be moved by another
+        * The IRENAME flag ensures that it cannot be moved by another
         * rename.
         */
        if (xp != ip) {
         * rename.
         */
        if (xp != ip) {
@@ -1053,8 +730,8 @@ rename()
                        dp->i_nlink--;
                        dp->i_flag |= ICHG;
                        error = rdwri(UIO_READ, xp, (caddr_t)&dirbuf,
                        dp->i_nlink--;
                        dp->i_flag |= ICHG;
                        error = rdwri(UIO_READ, xp, (caddr_t)&dirbuf,
-                               sizeof (struct dirtemplate), (off_t)0, 1,
-                               (int *)0);
+                               sizeof (struct dirtemplate), (off_t)0,
+                               UIO_USERSPACE, tndp->ni_cred, (int *)0);
                        if (error == 0) {
                                if (dirbuf.dotdot_namlen != 2 ||
                                    dirbuf.dotdot_name[0] != '.' ||
                        if (error == 0) {
                                if (dirbuf.dotdot_namlen != 2 ||
                                    dirbuf.dotdot_name[0] != '.' ||
@@ -1065,96 +742,35 @@ rename()
                                        (void) rdwri(UIO_WRITE, xp,
                                            (caddr_t)&dirbuf,
                                            sizeof (struct dirtemplate),
                                        (void) rdwri(UIO_WRITE, xp,
                                            (caddr_t)&dirbuf,
                                            sizeof (struct dirtemplate),
-                                           (off_t)0, 1, (int *)0);
-                                       cacheinval(dp);
+                                           (off_t)0, UIO_USERSPACE,
+                                           tndp->ni_cred, (int *)0);
+                                       cache_purge(ITOV(dp));
                                }
                        }
                }
                                }
                        }
                }
-               if (dirremove(ndp)) {
+               error = dirremove(fndp);
+               if (!error) {
                        xp->i_nlink--;
                        xp->i_flag |= ICHG;
                }
                xp->i_flag &= ~IRENAME;
                        xp->i_nlink--;
                        xp->i_flag |= ICHG;
                }
                xp->i_flag &= ~IRENAME;
-               if (error == 0)         /* XXX conservative */
-                       error = u.u_error;
        }
        if (dp)
        }
        if (dp)
-               iput(dp);
+               vput(ITOV(dp));
        if (xp)
        if (xp)
-               iput(xp);
-       irele(ip);
-       if (error)
-               u.u_error = error;
-       return;
+               vput(ITOV(xp));
+       vrele(ITOV(ip));
+       return (error);
 
 bad:
 
 bad:
-       iput(dp);
-bad1:
        if (xp)
        if (xp)
-               iput(xp);
+               vput(ITOV(xp));
+       vput(ITOV(dp));
 out:
        ip->i_nlink--;
        ip->i_flag |= ICHG;
 out:
        ip->i_nlink--;
        ip->i_flag |= ICHG;
-       irele(ip);
-       if (error)
-               u.u_error = error;
-}
-
-/*
- * Make a new file.
- */
-struct inode *
-maknode(mode, ndp)
-       int mode;
-       register struct nameidata *ndp;
-{
-       register struct inode *ip;
-       register struct inode *pdir = ndp->ni_pdir;
-       ino_t ipref;
-
-       if ((mode & IFMT) == IFDIR)
-               ipref = dirpref(pdir->i_fs);
-       else
-               ipref = pdir->i_number;
-       ip = ialloc(pdir, ipref, mode);
-       if (ip == NULL) {
-               iput(pdir);
-               return (NULL);
-       }
-#ifdef QUOTA
-       if (ip->i_dquot != NODQUOT)
-               panic("maknode: dquot");
-#endif
-       ip->i_flag |= IACC|IUPD|ICHG;
-       if ((mode & IFMT) == 0)
-               mode |= IFREG;
-       ip->i_mode = mode & ~u.u_cmask;
-       ip->i_nlink = 1;
-       ip->i_uid = u.u_uid;
-       ip->i_gid = pdir->i_gid;
-       if (ip->i_mode & ISGID && !groupmember(ip->i_gid) &&
-           (u.u_error = suser(u.u_cred, &u.u_acflag)))
-               ip->i_mode &= ~ISGID;
-#ifdef QUOTA
-       ip->i_dquot = inoquota(ip);
-#endif
-
-       /*
-        * Make sure inode goes to disk before directory entry.
-        */
-       iupdat(ip, &time, &time, 1);
-       u.u_error = direnter(ip, ndp);
-       if (u.u_error) {
-               /*
-                * Write error occurred trying to update directory
-                * so must deallocate the inode.
-                */
-               ip->i_nlink = 0;
-               ip->i_flag |= ICHG;
-               iput(ip);
-               return (NULL);
-       }
-       return (ip);
+       vrele(ITOV(ip));
+       return (error);
 }
 
 /*
 }
 
 /*
@@ -1168,30 +784,21 @@ struct dirtemplate mastertemplate = {
 /*
  * Mkdir system call
  */
 /*
  * Mkdir system call
  */
-mkdir()
+ufs_mkdir(ndp, vap)
+       struct nameidata *ndp;
+       struct vattr *vap;
 {
 {
-       struct a {
-               char    *name;
-               int     dmode;
-       } *uap = (struct a *)u.u_ap;
        register struct inode *ip, *dp;
        register struct inode *ip, *dp;
+       struct inode *tip;
+       struct vnode *dvp;
        struct dirtemplate dirtemplate;
        struct dirtemplate dirtemplate;
-       register struct nameidata *ndp = &u.u_nd;
-
-       ndp->ni_nameiop = CREATE;
-       ndp->ni_segflg = UIO_USERSPACE;
-       ndp->ni_dirp = uap->name;
-       ip = namei(ndp);
-       if (u.u_error)
-               return;
-       if (ip != NULL) {
-               iput(ip);
-               u.u_error = EEXIST;
-               return;
-       }
-       dp = ndp->ni_pdir;
-       uap->dmode &= 0777;
-       uap->dmode |= IFDIR;
+       int error;
+       int dmode;
+
+       dvp = ndp->ni_dvp;
+       dp = VTOI(dvp);
+       dmode = vap->va_mode&0777;
+       dmode |= IFDIR;
        /*
         * Must simulate part of maknode here
         * in order to acquire the inode, but
        /*
         * Must simulate part of maknode here
         * in order to acquire the inode, but
@@ -1199,24 +806,26 @@ mkdir()
         * directory.  The entry is made later
         * after writing "." and ".." entries out.
         */
         * directory.  The entry is made later
         * after writing "." and ".." entries out.
         */
-       ip = ialloc(dp, dirpref(dp->i_fs), uap->dmode);
-       if (ip == NULL) {
+       error = ialloc(dp, dirpref(dp->i_fs), dmode, &tip);
+       if (error) {
                iput(dp);
                iput(dp);
-               return;
+               return (error);
        }
        }
+       ip = tip;
 #ifdef QUOTA
        if (ip->i_dquot != NODQUOT)
                panic("mkdir: dquot");
 #endif
        ip->i_flag |= IACC|IUPD|ICHG;
 #ifdef QUOTA
        if (ip->i_dquot != NODQUOT)
                panic("mkdir: dquot");
 #endif
        ip->i_flag |= IACC|IUPD|ICHG;
-       ip->i_mode = uap->dmode & ~u.u_cmask;
+       ip->i_mode = dmode;
+       ITOV(ip)->v_type = VDIR;        /* Rest init'd in iget() */
        ip->i_nlink = 2;
        ip->i_nlink = 2;
-       ip->i_uid = u.u_uid;
+       ip->i_uid = ndp->ni_cred->cr_uid;
        ip->i_gid = dp->i_gid;
 #ifdef QUOTA
        ip->i_dquot = inoquota(ip);
 #endif
        ip->i_gid = dp->i_gid;
 #ifdef QUOTA
        ip->i_dquot = inoquota(ip);
 #endif
-       iupdat(ip, &time, &time, 1);
+       error = iupdat(ip, &time, &time, 1);
 
        /*
         * Bump link count in parent directory
 
        /*
         * Bump link count in parent directory
@@ -1226,7 +835,7 @@ mkdir()
         */
        dp->i_nlink++;
        dp->i_flag |= ICHG;
         */
        dp->i_nlink++;
        dp->i_flag |= ICHG;
-       iupdat(dp, &time, &time, 1);
+       error = iupdat(dp, &time, &time, 1);
 
        /*
         * Initialize directory with "."
 
        /*
         * Initialize directory with "."
@@ -1235,15 +844,16 @@ mkdir()
        dirtemplate = mastertemplate;
        dirtemplate.dot_ino = ip->i_number;
        dirtemplate.dotdot_ino = dp->i_number;
        dirtemplate = mastertemplate;
        dirtemplate.dot_ino = ip->i_number;
        dirtemplate.dotdot_ino = dp->i_number;
-       u.u_error = rdwri(UIO_WRITE, ip, (caddr_t)&dirtemplate,
-               sizeof (dirtemplate), (off_t)0, 1, (int *)0);
-       if (u.u_error) {
+       error = rdwri(UIO_WRITE, ip, (caddr_t)&dirtemplate,
+               sizeof (dirtemplate), (off_t)0, UIO_SYSSPACE,
+               ndp->ni_cred, (int *)0);
+       if (error) {
                dp->i_nlink--;
                dp->i_flag |= ICHG;
                goto bad;
        }
                dp->i_nlink--;
                dp->i_flag |= ICHG;
                goto bad;
        }
-       if (DIRBLKSIZ > ip->i_fs->fs_fsize)
-               panic("mkdir: blksize");     /* XXX - should grow with bmap() */
+       if (DIRBLKSIZ > dp->i_fs->fs_fsize)
+               panic("mkdir: blksize");     /* XXX - should grow w/balloc() */
        else
                ip->i_size = DIRBLKSIZ;
        /*
        else
                ip->i_size = DIRBLKSIZ;
        /*
@@ -1251,14 +861,13 @@ mkdir()
         * install the entry for it in
         * the parent directory.
         */
         * install the entry for it in
         * the parent directory.
         */
-       u.u_error = direnter(ip, ndp);
+       error = direnter(ip, ndp);
        dp = NULL;
        dp = NULL;
-       if (u.u_error) {
+       if (error) {
                ndp->ni_nameiop = LOOKUP | NOCACHE;
                ndp->ni_nameiop = LOOKUP | NOCACHE;
-               ndp->ni_segflg = UIO_USERSPACE;
-               ndp->ni_dirp = uap->name;
-               dp = namei(ndp);
-               if (dp) {
+               error = namei(ndp);
+               if (!error) {
+                       dp = VTOI(ndp->ni_vp);
                        dp->i_nlink--;
                        dp->i_flag |= ICHG;
                }
                        dp->i_nlink--;
                        dp->i_flag |= ICHG;
                }
@@ -1266,55 +875,37 @@ mkdir()
 bad:
        /*
         * No need to do an explicit itrunc here,
 bad:
        /*
         * No need to do an explicit itrunc here,
-        * irele will do this for us because we set
+        * vrele will do this for us because we set
         * the link count to 0.
         */
         * the link count to 0.
         */
-       if (u.u_error) {
+       if (error) {
                ip->i_nlink = 0;
                ip->i_flag |= ICHG;
        }
                ip->i_nlink = 0;
                ip->i_flag |= ICHG;
        }
+       iput(ip);
        if (dp)
                iput(dp);
        if (dp)
                iput(dp);
-       iput(ip);
+       return (error);
 }
 
 /*
  * Rmdir system call.
  */
 }
 
 /*
  * Rmdir system call.
  */
-rmdir()
+ufs_rmdir(ndp)
+       register struct nameidata *ndp;
 {
 {
-       struct a {
-               char    *name;
-       } *uap = (struct a *)u.u_ap;
        register struct inode *ip, *dp;
        register struct inode *ip, *dp;
-       register struct nameidata *ndp = &u.u_nd;
-
-       ndp->ni_nameiop = DELETE | LOCKPARENT;
-       ndp->ni_segflg = UIO_USERSPACE;
-       ndp->ni_dirp = uap->name;
-       ip = namei(ndp);
-       if (ip == NULL)
-               return;
-       dp = ndp->ni_pdir;
+       int error = 0;
+
+       ip = VTOI(ndp->ni_vp);
+       dp = VTOI(ndp->ni_dvp);
        /*
         * No rmdir "." please.
         */
        if (dp == ip) {
        /*
         * No rmdir "." please.
         */
        if (dp == ip) {
-               irele(dp);
+               vrele(ITOV(dp));
                iput(ip);
                iput(ip);
-               u.u_error = EINVAL;
-               return;
-       }
-       if ((ip->i_mode&IFMT) != IFDIR) {
-               u.u_error = ENOTDIR;
-               goto out;
-       }
-       /*
-        * Don't remove a mounted on directory.
-        */
-       if (ip->i_dev != dp->i_dev) {
-               u.u_error = EBUSY;
-               goto out;
+               return (EINVAL);
        }
        /*
         * Verify the directory is empty (and valid).
        }
        /*
         * Verify the directory is empty (and valid).
@@ -1323,8 +914,8 @@ rmdir()
         *  the current directory and thus be
         *  non-empty.)
         */
         *  the current directory and thus be
         *  non-empty.)
         */
-       if (ip->i_nlink != 2 || !dirempty(ip, dp->i_number)) {
-               u.u_error = ENOTEMPTY;
+       if (ip->i_nlink != 2 || !dirempty(ip, dp->i_number, ndp->ni_cred)) {
+               error = ENOTEMPTY;
                goto out;
        }
        /*
                goto out;
        }
        /*
@@ -1332,13 +923,13 @@ rmdir()
         * inode.  If we crash in between, the directory
         * will be reattached to lost+found,
         */
         * inode.  If we crash in between, the directory
         * will be reattached to lost+found,
         */
-       if (dirremove(ndp) == 0)
+       if (error = dirremove(ndp))
                goto out;
        dp->i_nlink--;
        dp->i_flag |= ICHG;
                goto out;
        dp->i_nlink--;
        dp->i_flag |= ICHG;
-       cacheinval(dp);
+       cache_purge(ITOV(dp));
        iput(dp);
        iput(dp);
-       dp = NULL;
+       ndp->ni_dvp = NULL;
        /*
         * Truncate inode.  The only stuff left
         * in the directory is "." and "..".  The
        /*
         * Truncate inode.  The only stuff left
         * in the directory is "." and "..".  The
@@ -1351,40 +942,206 @@ rmdir()
         * worry about them later.
         */
        ip->i_nlink -= 2;
         * worry about them later.
         */
        ip->i_nlink -= 2;
-       itrunc(ip, (u_long)0);
-       cacheinval(ip);
+       error = itrunc(ip, (u_long)0);
+       cache_purge(ITOV(ip));
 out:
 out:
-       if (dp)
+       if (ndp->ni_dvp)
                iput(dp);
        iput(ip);
                iput(dp);
        iput(ip);
+       return (error);
 }
 
 }
 
-struct file *
-getinode(fdes)
-       int fdes;
+/*
+ * symlink -- make a symbolic link
+ */
+ufs_symlink(ndp, vap, target)
+       struct nameidata *ndp;
+       struct vattr *vap;
+       char *target;
+{
+       struct inode *ip;
+       int error;
+
+       error = maknode(IFLNK | vap->va_mode, ndp, &ip);
+       if (error)
+               return (error);
+       error = rdwri(UIO_WRITE, ip, target, strlen(target), (off_t)0,
+               UIO_SYSSPACE, ndp->ni_cred, (int *)0);
+       iput(ip);
+       return (error);
+}
+
+/*
+ * Vnode op for read and write
+ */
+ufs_readdir(vp, uio, offp, cred)
+       struct vnode *vp;
+       register struct uio *uio;
+       off_t *offp;
+       struct ucred *cred;
 {
 {
-       struct file *fp;
+       register struct inode *ip = VTOI(vp);
+       int count, error;
 
 
-       if ((unsigned)fdes >= NOFILE || (fp = u.u_ofile[fdes]) == NULL) {
-               u.u_error = EBADF;
-               return ((struct file *)0);
+       ILOCK(ip);
+       uio->uio_offset = *offp;
+       count = uio->uio_resid;
+       count &= ~(DIRBLKSIZ - 1);
+       if (vp->v_type != VDIR || uio->uio_iovcnt != 1 ||
+           (count < DIRBLKSIZ) || (uio->uio_offset & (DIRBLKSIZ -1))) {
+               IUNLOCK(ip);
+               return (EINVAL);
+       }
+       uio->uio_resid = count;
+       uio->uio_iov->iov_len = count;
+       error = readip(ip, uio, cred);
+       *offp += count - uio->uio_resid;
+       IUNLOCK(ip);
+       return (error);
+}
+
+/*
+ * Return target name of a symbolic link
+ */
+ufs_readlink(vp, uiop, cred)
+       struct vnode *vp;
+       struct uio *uiop;
+       struct ucred *cred;
+{
+
+       return (readip(VTOI(vp), uiop, cred));
+}
+
+/*
+ * Ufs abort op, called after namei() when a CREATE/DELETE isn't actually
+ * done. Iff ni_vp/ni_dvp not null and locked, unlock.
+ */
+ufs_abortop(ndp)
+       register struct nameidata *ndp;
+{
+       register struct inode *ip;
+
+       if (ndp->ni_vp) {
+               ip = VTOI(ndp->ni_vp);
+               if (ip->i_flag & ILOCKED)
+                       IUNLOCK(ip);
+               vrele(ndp->ni_vp);
        }
        }
-       if (fp->f_type != DTYPE_INODE) {
-               u.u_error = EINVAL;
-               return ((struct file *)0);
+       if (ndp->ni_dvp) {
+               ip = VTOI(ndp->ni_dvp);
+               if (ip->i_flag & ILOCKED)
+                       IUNLOCK(ip);
+               vrele(ndp->ni_dvp);
        }
        }
-       return (fp);
+       return;
+}
+
+ufs_lock(vp)
+       struct vnode *vp;
+{
+       register struct inode *ip = VTOI(vp);
+
+       ILOCK(ip);
+       return (0);
+}
+
+ufs_unlock(vp)
+       struct vnode *vp;
+{
+       register struct inode *ip = VTOI(vp);
+
+       if (!(ip->i_flag & ILOCKED))
+               panic("ufs_unlock NOT LOCKED");
+       IUNLOCK(ip);
+       return (0);
+}
+
+/*
+ * Get access to bmap
+ */
+ufs_bmap(vp, bn, vpp, bnp)
+       struct vnode *vp;
+       daddr_t bn;
+       struct vnode **vpp;
+       daddr_t *bnp;
+{
+       struct inode *ip = VTOI(vp);
+
+       if (vpp != NULL)
+               *vpp = ip->i_devvp;
+       if (bnp == NULL)
+               return (0);
+       return (bmap(ip, bn, bnp, (daddr_t *)0, (int *)0));
 }
 
 /*
 }
 
 /*
- * mode mask for creation of files
+ * Just call the device strategy routine
  */
  */
-umask()
+ufs_strategy(bp)
+       register struct buf *bp;
 {
 {
-       register struct a {
-               int     mask;
-       } *uap = (struct a *)u.u_ap;
+       (*bdevsw[major(bp->b_dev)].d_strategy)(bp);
+       return (0);
+}
 
 
-       u.u_r.r_val1 = u.u_cmask;
-       u.u_cmask = uap->mask & 07777;
+/*
+ * Make a new file.
+ */
+maknode(mode, ndp, ipp)
+       int mode;
+       register struct nameidata *ndp;
+       struct inode **ipp;
+{
+       register struct inode *ip;
+       struct inode *tip;
+       register struct inode *pdir = VTOI(ndp->ni_dvp);
+       ino_t ipref;
+       int error;
+
+       *ipp = 0;
+       if ((mode & IFMT) == IFDIR)
+               ipref = dirpref(pdir->i_fs);
+       else
+               ipref = pdir->i_number;
+       error = ialloc(pdir, ipref, mode, &tip);
+       if (error) {
+               iput(pdir);
+               return (error);
+       }
+       ip = tip;
+#ifdef QUOTA
+       if (ip->i_dquot != NODQUOT)
+               panic("maknode: dquot");
+#endif
+       ip->i_flag |= IACC|IUPD|ICHG;
+       if ((mode & IFMT) == 0)
+               mode |= IFREG;
+       ip->i_mode = mode;
+       ITOV(ip)->v_type = IFTOVT(mode);        /* Rest init'd in iget() */
+       ip->i_nlink = 1;
+       ip->i_uid = ndp->ni_cred->cr_uid;
+       ip->i_gid = pdir->i_gid;
+       if ((ip->i_mode & ISGID) && !groupmember(ip->i_gid, ndp->ni_cred) &&
+           suser(ndp->ni_cred, NULL))
+               ip->i_mode &= ~ISGID;
+#ifdef QUOTA
+       ip->i_dquot = inoquota(ip);
+#endif
+
+       /*
+        * Make sure inode goes to disk before directory entry.
+        */
+       if ((error = iupdat(ip, &time, &time, 1)) ||
+           (error = direnter(ip, ndp))) {
+               /*
+                * Write error occurred trying to update the inode
+                * or the directory so must deallocate the inode.
+                */
+               ip->i_nlink = 0;
+               ip->i_flag |= ICHG;
+               iput(ip);
+               return (error);
+       }
+       *ipp = ip;
+       return (0);
 }
 }
index 15ca5db..5d2399b 100644 (file)
@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright (c) 1982, 1986 Regents of the University of California.
+ * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms are permitted
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms are permitted
  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  *
  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  *
- *     @(#)lfs_alloc.c 7.8 (Berkeley) %G%
+ *     @(#)lfs_alloc.c 7.9 (Berkeley) %G%
  */
 
 #include "param.h"
 #include "systm.h"
 #include "mount.h"
  */
 
 #include "param.h"
 #include "systm.h"
 #include "mount.h"
-#include "fs.h"
 #include "buf.h"
 #include "buf.h"
-#include "inode.h"
-#include "dir.h"
 #include "user.h"
 #include "user.h"
-#include "quota.h"
+#include "vnode.h"
 #include "kernel.h"
 #include "syslog.h"
 #include "cmap.h"
 #include "kernel.h"
 #include "syslog.h"
 #include "cmap.h"
+#include "../ufs/quota.h"
+#include "../ufs/inode.h"
+#include "../ufs/fs.h"
 
 extern u_long          hashalloc();
 extern ino_t           ialloccg();
 
 extern u_long          hashalloc();
 extern ino_t           ialloccg();
@@ -59,17 +59,19 @@ extern unsigned char        *fragtbl[];
  *   2) quadradically rehash into other cylinder groups, until an
  *      available block is located.
  */
  *   2) quadradically rehash into other cylinder groups, until an
  *      available block is located.
  */
-struct buf *
-alloc(ip, bpref, size)
+alloc(ip, bpref, size, bpp, flags)
        register struct inode *ip;
        daddr_t bpref;
        int size;
        register struct inode *ip;
        daddr_t bpref;
        int size;
+       struct buf **bpp;
+       int flags;
 {
        daddr_t bno;
        register struct fs *fs;
        register struct buf *bp;
 {
        daddr_t bno;
        register struct fs *fs;
        register struct buf *bp;
-       int cg;
+       int cg, error;
        
        
+       *bpp = 0;
        fs = ip->i_fs;
        if ((unsigned)size > fs->fs_bsize || fragoff(fs, size) != 0) {
                printf("dev = 0x%x, bsize = %d, size = %d, fs = %s\n",
        fs = ip->i_fs;
        if ((unsigned)size > fs->fs_bsize || fragoff(fs, size) != 0) {
                printf("dev = 0x%x, bsize = %d, size = %d, fs = %s\n",
@@ -81,9 +83,8 @@ alloc(ip, bpref, size)
        if (u.u_uid != 0 && freespace(fs, fs->fs_minfree) <= 0)
                goto nospace;
 #ifdef QUOTA
        if (u.u_uid != 0 && freespace(fs, fs->fs_minfree) <= 0)
                goto nospace;
 #ifdef QUOTA
-       u.u_error = chkdq(ip, (long)btodb(size), 0);
-       if (u.u_error)
-               return (NULL);
+       if (error = chkdq(ip, (long)btodb(size), 0))
+               return (error);
 #endif
        if (bpref >= fs->fs_size)
                bpref = 0;
 #endif
        if (bpref >= fs->fs_size)
                bpref = 0;
@@ -100,15 +101,15 @@ alloc(ip, bpref, size)
 #ifdef SECSIZE
        bp = getblk(ip->i_dev, fsbtodb(fs, bno), size, fs->fs_dbsize);
 #else SECSIZE
 #ifdef SECSIZE
        bp = getblk(ip->i_dev, fsbtodb(fs, bno), size, fs->fs_dbsize);
 #else SECSIZE
-       bp = getblk(ip->i_dev, fsbtodb(fs, bno), size);
-#endif SECSIZE
-       clrbuf(bp);
-       return (bp);
+       bp = getblk(ip->i_devvp, fsbtodb(fs, bno), size);
+       if (flags & B_CLRBUF)
+               clrbuf(bp);
+       *bpp = bp;
+       return (0);
 nospace:
        fserr(fs, "file system full");
        uprintf("\n%s: write failed, file system is full\n", fs->fs_fsmnt);
 nospace:
        fserr(fs, "file system full");
        uprintf("\n%s: write failed, file system is full\n", fs->fs_fsmnt);
-       u.u_error = ENOSPC;
-       return (NULL);
+       return (ENOSPC);
 }
 
 /*
 }
 
 /*
@@ -119,18 +120,19 @@ nospace:
  * the original block. Failing that, the regular block allocator is
  * invoked to get an appropriate block.
  */
  * the original block. Failing that, the regular block allocator is
  * invoked to get an appropriate block.
  */
-struct buf *
-realloccg(ip, bprev, bpref, osize, nsize)
+realloccg(ip, bprev, bpref, osize, nsize, bpp)
        register struct inode *ip;
        daddr_t bprev, bpref;
        int osize, nsize;
        register struct inode *ip;
        daddr_t bprev, bpref;
        int osize, nsize;
+       struct buf **bpp;
 {
        register struct fs *fs;
 {
        register struct fs *fs;
-       register struct buf *bp, *obp;
+       struct buf *bp, *obp;
        int cg, request;
        daddr_t bno, bn;
        int cg, request;
        daddr_t bno, bn;
-       int i, count;
+       int i, error, count;
        
        
+       *bpp = 0;
        fs = ip->i_fs;
        if ((unsigned)osize > fs->fs_bsize || fragoff(fs, osize) != 0 ||
            (unsigned)nsize > fs->fs_bsize || fragoff(fs, nsize) != 0) {
        fs = ip->i_fs;
        if ((unsigned)osize > fs->fs_bsize || fragoff(fs, osize) != 0 ||
            (unsigned)nsize > fs->fs_bsize || fragoff(fs, nsize) != 0) {
@@ -146,9 +148,8 @@ realloccg(ip, bprev, bpref, osize, nsize)
                panic("realloccg: bad bprev");
        }
 #ifdef QUOTA
                panic("realloccg: bad bprev");
        }
 #ifdef QUOTA
-       u.u_error = chkdq(ip, (long)btodb(nsize - osize), 0);
-       if (u.u_error)
-               return (NULL);
+       if (error = chkdq(ip, (long)btodb(nsize - osize), 0))
+               return (error);
 #endif
        cg = dtog(fs, bprev);
        bno = fragextend(ip, cg, (long)bprev, osize, nsize);
 #endif
        cg = dtog(fs, bprev);
        bno = fragextend(ip, cg, (long)bprev, osize, nsize);
@@ -158,18 +159,19 @@ realloccg(ip, bprev, bpref, osize, nsize)
                        bp = bread(ip->i_dev, fsbtodb(fs, bno), osize,
                            fs->fs_dbsize);
 #else SECSIZE
                        bp = bread(ip->i_dev, fsbtodb(fs, bno), osize,
                            fs->fs_dbsize);
 #else SECSIZE
-                       bp = bread(ip->i_dev, fsbtodb(fs, bno), osize);
-#endif SECSIZE
-                       if (bp->b_flags & B_ERROR) {
+                       error = bread(ip->i_devvp, fsbtodb(fs, bno),
+                               osize, &bp);
+                       if (error) {
                                brelse(bp);
                                brelse(bp);
-                               return (NULL);
+                               return (error);
                        }
                } while (brealloc(bp, nsize) == 0);
                bp->b_flags |= B_DONE;
                bzero(bp->b_un.b_addr + osize, (unsigned)nsize - osize);
                ip->i_blocks += btodb(nsize - osize);
                ip->i_flag |= IUPD|ICHG;
                        }
                } while (brealloc(bp, nsize) == 0);
                bp->b_flags |= B_DONE;
                bzero(bp->b_un.b_addr + osize, (unsigned)nsize - osize);
                ip->i_blocks += btodb(nsize - osize);
                ip->i_flag |= IUPD|ICHG;
-               return (bp);
+               *bpp = bp;
+               return (0);
        }
        if (bpref >= fs->fs_size)
                bpref = 0;
        }
        if (bpref >= fs->fs_size)
                bpref = 0;
@@ -223,17 +225,16 @@ realloccg(ip, bprev, bpref, osize, nsize)
                obp = bread(ip->i_dev, fsbtodb(fs, bprev), osize,
                    fs->fs_dbsize);
 #else SECSIZE
                obp = bread(ip->i_dev, fsbtodb(fs, bprev), osize,
                    fs->fs_dbsize);
 #else SECSIZE
-               obp = bread(ip->i_dev, fsbtodb(fs, bprev), osize);
-#endif SECSIZE
-               if (obp->b_flags & B_ERROR) {
+               error = bread(ip->i_devvp, fsbtodb(fs, bprev), osize, &obp);
+               if (error) {
                        brelse(obp);
                        brelse(obp);
-                       return (NULL);
+                       return (error);
                }
                bn = fsbtodb(fs, bno);
 #ifdef SECSIZE
                bp = getblk(ip->i_dev, bn, nsize, fs->fs_dbsize);
 #else SECSIZE
                }
                bn = fsbtodb(fs, bno);
 #ifdef SECSIZE
                bp = getblk(ip->i_dev, bn, nsize, fs->fs_dbsize);
 #else SECSIZE
-               bp = getblk(ip->i_dev, bn, nsize);
+               bp = getblk(ip->i_devvp, bn, nsize);
 #endif SECSIZE
                bcopy(obp->b_un.b_addr, bp->b_un.b_addr, (u_int)osize);
                count = howmany(osize, CLBYTES);
 #endif SECSIZE
                bcopy(obp->b_un.b_addr, bp->b_un.b_addr, (u_int)osize);
                count = howmany(osize, CLBYTES);
@@ -255,7 +256,8 @@ realloccg(ip, bprev, bpref, osize, nsize)
                                (off_t)(request - nsize));
                ip->i_blocks += btodb(nsize - osize);
                ip->i_flag |= IUPD|ICHG;
                                (off_t)(request - nsize));
                ip->i_blocks += btodb(nsize - osize);
                ip->i_flag |= IUPD|ICHG;
-               return (bp);
+               *bpp = bp;
+               return (0);
        }
 nospace:
        /*
        }
 nospace:
        /*
@@ -263,8 +265,7 @@ nospace:
         */
        fserr(fs, "file system full");
        uprintf("\n%s: write failed, file system is full\n", fs->fs_fsmnt);
         */
        fserr(fs, "file system full");
        uprintf("\n%s: write failed, file system is full\n", fs->fs_fsmnt);
-       u.u_error = ENOSPC;
-       return (NULL);
+       return (ENOSPC);
 }
 
 /*
 }
 
 /*
@@ -282,24 +283,24 @@ nospace:
  *   2) quadradically rehash into other cylinder groups, until an
  *      available inode is located.
  */
  *   2) quadradically rehash into other cylinder groups, until an
  *      available inode is located.
  */
-struct inode *
-ialloc(pip, ipref, mode)
+ialloc(pip, ipref, mode, ipp)
        register struct inode *pip;
        ino_t ipref;
        int mode;
        register struct inode *pip;
        ino_t ipref;
        int mode;
+       struct inode **ipp;
 {
        ino_t ino;
        register struct fs *fs;
        register struct inode *ip;
 {
        ino_t ino;
        register struct fs *fs;
        register struct inode *ip;
-       int cg;
+       int cg, error;
        
        
+       *ipp = 0;
        fs = pip->i_fs;
        if (fs->fs_cstotal.cs_nifree == 0)
                goto noinodes;
 #ifdef QUOTA
        fs = pip->i_fs;
        if (fs->fs_cstotal.cs_nifree == 0)
                goto noinodes;
 #ifdef QUOTA
-       u.u_error = chkiq(pip->i_dev, (struct inode *)NULL, u.u_uid, 0);
-       if (u.u_error)
-               return (NULL);
+       if (error = chkiq(pip->i_dev, (struct inode *)NULL, u.u_uid, 0))
+               return (error);
 #endif
        if (ipref >= fs->fs_ncg * fs->fs_ipg)
                ipref = 0;
 #endif
        if (ipref >= fs->fs_ncg * fs->fs_ipg)
                ipref = 0;
@@ -307,10 +308,11 @@ ialloc(pip, ipref, mode)
        ino = (ino_t)hashalloc(pip, cg, (long)ipref, mode, ialloccg);
        if (ino == 0)
                goto noinodes;
        ino = (ino_t)hashalloc(pip, cg, (long)ipref, mode, ialloccg);
        if (ino == 0)
                goto noinodes;
-       ip = iget(pip->i_dev, pip->i_fs, ino);
-       if (ip == NULL) {
+       error = iget(pip, ino, ipp);
+       ip = *ipp;
+       if (error) {
                ifree(pip, ino, 0);
                ifree(pip, ino, 0);
-               return (NULL);
+               return (error);
        }
        if (ip->i_mode) {
                printf("mode = 0%o, inum = %d, fs = %s\n",
        }
        if (ip->i_mode) {
                printf("mode = 0%o, inum = %d, fs = %s\n",
@@ -322,12 +324,11 @@ ialloc(pip, ipref, mode)
                    fs->fs_fsmnt, ino, ip->i_blocks);
                ip->i_blocks = 0;
        }
                    fs->fs_fsmnt, ino, ip->i_blocks);
                ip->i_blocks = 0;
        }
-       return (ip);
+       return (0);
 noinodes:
        fserr(fs, "out of inodes");
        uprintf("\n%s: create/symlink failed, no inodes free\n", fs->fs_fsmnt);
 noinodes:
        fserr(fs, "out of inodes");
        uprintf("\n%s: create/symlink failed, no inodes free\n", fs->fs_fsmnt);
-       u.u_error = ENOSPC;
-       return (NULL);
+       return (ENOSPC);
 }
 
 /*
 }
 
 /*
@@ -514,11 +515,11 @@ fragextend(ip, cg, bprev, osize, nsize)
        int osize, nsize;
 {
        register struct fs *fs;
        int osize, nsize;
 {
        register struct fs *fs;
-       register struct buf *bp;
        register struct cg *cgp;
        register struct cg *cgp;
+       struct buf *bp;
        long bno;
        int frags, bbase;
        long bno;
        int frags, bbase;
-       int i;
+       int i, error;
 
        fs = ip->i_fs;
        if (fs->fs_cs(fs, cg).cs_nffree < numfrags(fs, nsize - osize))
 
        fs = ip->i_fs;
        if (fs->fs_cs(fs, cg).cs_nffree < numfrags(fs, nsize - osize))
@@ -533,10 +534,15 @@ fragextend(ip, cg, bprev, osize, nsize)
        bp = bread(ip->i_dev, fsbtodb(fs, cgtod(fs, cg)), (int)fs->fs_cgsize,
            fs->fs_dbsize);
 #else SECSIZE
        bp = bread(ip->i_dev, fsbtodb(fs, cgtod(fs, cg)), (int)fs->fs_cgsize,
            fs->fs_dbsize);
 #else SECSIZE
-       bp = bread(ip->i_dev, fsbtodb(fs, cgtod(fs, cg)), (int)fs->fs_cgsize);
+       error = bread(ip->i_devvp, fsbtodb(fs, cgtod(fs, cg)),
+               (int)fs->fs_cgsize, &bp);
+       if (error) {
+               brelse(bp);
+               return (NULL);
+       }
 #endif SECSIZE
        cgp = bp->b_un.b_cg;
 #endif SECSIZE
        cgp = bp->b_un.b_cg;
-       if (bp->b_flags & B_ERROR || !cg_chkmagic(cgp)) {
+       if (!cg_chkmagic(cgp)) {
                brelse(bp);
                return (NULL);
        }
                brelse(bp);
                return (NULL);
        }
@@ -584,11 +590,10 @@ alloccg(ip, cg, bpref, size)
        int size;
 {
        register struct fs *fs;
        int size;
 {
        register struct fs *fs;
-       register struct buf *bp;
        register struct cg *cgp;
        register struct cg *cgp;
-       int bno, frags;
-       int allocsiz;
+       struct buf *bp;
        register int i;
        register int i;
+       int error, bno, frags, allocsiz;
 
        fs = ip->i_fs;
        if (fs->fs_cs(fs, cg).cs_nbfree == 0 && size == fs->fs_bsize)
 
        fs = ip->i_fs;
        if (fs->fs_cs(fs, cg).cs_nbfree == 0 && size == fs->fs_bsize)
@@ -597,10 +602,15 @@ alloccg(ip, cg, bpref, size)
        bp = bread(ip->i_dev, fsbtodb(fs, cgtod(fs, cg)), (int)fs->fs_cgsize,
            fs->fs_dbsize);
 #else SECSIZE
        bp = bread(ip->i_dev, fsbtodb(fs, cgtod(fs, cg)), (int)fs->fs_cgsize,
            fs->fs_dbsize);
 #else SECSIZE
-       bp = bread(ip->i_dev, fsbtodb(fs, cgtod(fs, cg)), (int)fs->fs_cgsize);
+       error = bread(ip->i_devvp, fsbtodb(fs, cgtod(fs, cg)),
+               (int)fs->fs_cgsize, &bp);
+       if (error) {
+               brelse(bp);
+               return (NULL);
+       }
 #endif SECSIZE
        cgp = bp->b_un.b_cg;
 #endif SECSIZE
        cgp = bp->b_un.b_cg;
-       if (bp->b_flags & B_ERROR || !cg_chkmagic(cgp) ||
+       if (!cg_chkmagic(cgp) ||
            (cgp->cg_cs.cs_nbfree == 0 && size == fs->fs_bsize)) {
                brelse(bp);
                return (NULL);
            (cgp->cg_cs.cs_nbfree == 0 && size == fs->fs_bsize)) {
                brelse(bp);
                return (NULL);
@@ -789,7 +799,7 @@ ialloccg(ip, cg, ipref, mode)
        register struct fs *fs;
        register struct cg *cgp;
        struct buf *bp;
        register struct fs *fs;
        register struct cg *cgp;
        struct buf *bp;
-       int start, len, loc, map, i;
+       int error, start, len, loc, map, i;
 
        fs = ip->i_fs;
        if (fs->fs_cs(fs, cg).cs_nifree == 0)
 
        fs = ip->i_fs;
        if (fs->fs_cs(fs, cg).cs_nifree == 0)
@@ -798,11 +808,15 @@ ialloccg(ip, cg, ipref, mode)
        bp = bread(ip->i_dev, fsbtodb(fs, cgtod(fs, cg)), (int)fs->fs_cgsize,
            fs->fs_dbsize);
 #else SECSIZE
        bp = bread(ip->i_dev, fsbtodb(fs, cgtod(fs, cg)), (int)fs->fs_cgsize,
            fs->fs_dbsize);
 #else SECSIZE
-       bp = bread(ip->i_dev, fsbtodb(fs, cgtod(fs, cg)), (int)fs->fs_cgsize);
+       error = bread(ip->i_devvp, fsbtodb(fs, cgtod(fs, cg)),
+               (int)fs->fs_cgsize, &bp);
+       if (error) {
+               brelse(bp);
+               return (NULL);
+       }
 #endif SECSIZE
        cgp = bp->b_un.b_cg;
 #endif SECSIZE
        cgp = bp->b_un.b_cg;
-       if (bp->b_flags & B_ERROR || !cg_chkmagic(cgp) ||
-           cgp->cg_cs.cs_nifree == 0) {
+       if (!cg_chkmagic(cgp) || cgp->cg_cs.cs_nifree == 0) {
                brelse(bp);
                return (NULL);
        }
                brelse(bp);
                return (NULL);
        }
@@ -867,8 +881,8 @@ blkfree(ip, bno, size)
 {
        register struct fs *fs;
        register struct cg *cgp;
 {
        register struct fs *fs;
        register struct cg *cgp;
-       register struct buf *bp;
-       int cg, blk, frags, bbase;
+       struct buf *bp;
+       int error, cg, blk, frags, bbase;
        register int i;
 
        fs = ip->i_fs;
        register int i;
 
        fs = ip->i_fs;
@@ -886,10 +900,15 @@ blkfree(ip, bno, size)
        bp = bread(ip->i_dev, fsbtodb(fs, cgtod(fs, cg)), (int)fs->fs_cgsize,
            fs->fs_dbsize);
 #else SECSIZE
        bp = bread(ip->i_dev, fsbtodb(fs, cgtod(fs, cg)), (int)fs->fs_cgsize,
            fs->fs_dbsize);
 #else SECSIZE
-       bp = bread(ip->i_dev, fsbtodb(fs, cgtod(fs, cg)), (int)fs->fs_cgsize);
+       error = bread(ip->i_devvp, fsbtodb(fs, cgtod(fs, cg)),
+               (int)fs->fs_cgsize, &bp);
+       if (error) {
+               brelse(bp);
+               return;
+       }
 #endif SECSIZE
        cgp = bp->b_un.b_cg;
 #endif SECSIZE
        cgp = bp->b_un.b_cg;
-       if (bp->b_flags & B_ERROR || !cg_chkmagic(cgp)) {
+       if (!cg_chkmagic(cgp)) {
                brelse(bp);
                return;
        }
                brelse(bp);
                return;
        }
@@ -967,8 +986,8 @@ ifree(ip, ino, mode)
 {
        register struct fs *fs;
        register struct cg *cgp;
 {
        register struct fs *fs;
        register struct cg *cgp;
-       register struct buf *bp;
-       int cg;
+       struct buf *bp;
+       int error, cg;
 
        fs = ip->i_fs;
        if ((unsigned)ino >= fs->fs_ipg*fs->fs_ncg) {
 
        fs = ip->i_fs;
        if ((unsigned)ino >= fs->fs_ipg*fs->fs_ncg) {
@@ -981,10 +1000,15 @@ ifree(ip, ino, mode)
        bp = bread(ip->i_dev, fsbtodb(fs, cgtod(fs, cg)), (int)fs->fs_cgsize,
            fs->fs_dbsize);
 #else SECSIZE
        bp = bread(ip->i_dev, fsbtodb(fs, cgtod(fs, cg)), (int)fs->fs_cgsize,
            fs->fs_dbsize);
 #else SECSIZE
-       bp = bread(ip->i_dev, fsbtodb(fs, cgtod(fs, cg)), (int)fs->fs_cgsize);
+       error = bread(ip->i_devvp, fsbtodb(fs, cgtod(fs, cg)),
+               (int)fs->fs_cgsize, &bp);
+       if (error) {
+               brelse(bp);
+               return;
+       }
 #endif SECSIZE
        cgp = bp->b_un.b_cg;
 #endif SECSIZE
        cgp = bp->b_un.b_cg;
-       if (bp->b_flags & B_ERROR || !cg_chkmagic(cgp)) {
+       if (!cg_chkmagic(cgp)) {
                brelse(bp);
                return;
        }
                brelse(bp);
                return;
        }
index a6bb42b..8b1c23f 100644 (file)
@@ -1,19 +1,31 @@
 /*
 /*
- * Copyright (c) 1982, 1986 Regents of the University of California.
- * All rights reserved.  The Berkeley software License Agreement
- * specifies the terms and conditions for redistribution.
+ * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
+ * All rights reserved.
  *
  *
- *     @(#)lfs_balloc.c        7.2 (Berkeley) %G%
+ * 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.
+ *
+ *     @(#)lfs_balloc.c        7.3 (Berkeley) %G%
  */
 
 #include "param.h"
 #include "systm.h"
  */
 
 #include "param.h"
 #include "systm.h"
-#include "inode.h"
-#include "dir.h"
 #include "user.h"
 #include "buf.h"
 #include "proc.h"
 #include "user.h"
 #include "buf.h"
 #include "proc.h"
-#include "fs.h"
+#include "file.h"
+#include "vnode.h"
+#include "../ufs/inode.h"
+#include "../ufs/fs.h"
 
 /*
  * Bmap defines the structure of file system storage
 
 /*
  * Bmap defines the structure of file system storage
  * block number of the next block of the file in rablock
  * for use in read-ahead.
  */
  * block number of the next block of the file in rablock
  * for use in read-ahead.
  */
-/*VARARGS3*/
-daddr_t
-bmap(ip, bn, rwflg, size)
+bmap(ip, bn, bnp, rablockp, rasizep)
        register struct inode *ip;
        register struct inode *ip;
-       daddr_t bn;
-       int rwflg;
-       int size;       /* supplied only when rwflg == B_WRITE */
+       register daddr_t bn;
+       daddr_t *bnp;
+       daddr_t *rablockp;
+       int *rasizep;
 {
 {
-       register int i;
-       int osize, nsize;
-       struct buf *bp, *nbp;
-       struct fs *fs;
-       int j, sh;
-       daddr_t nb, lbn, *bap, pref, blkpref();
+       register struct fs *fs;
+       register daddr_t nb;
+       struct buf *bp;
+       daddr_t *bap;
+       int i, j, sh;
+       int error;
+
+       if (bn < 0)
+               return (EFBIG);
+       fs = ip->i_fs;
+
+       /*
+        * The first NDADDR blocks are direct blocks
+        */
+       if (bn < NDADDR) {
+               nb = ip->i_db[bn];
+               if (nb == 0) {
+                       *bnp = (daddr_t)-1;
+                       return (0);
+               }
+               if (rablockp && rasizep) {
+                       if (bn < NDADDR - 1) {
+                               *rablockp = fsbtodb(fs, ip->i_db[bn + 1]);
+                               *rasizep = blksize(fs, ip, bn + 1);
+                       } else {
+                               *rablockp = 0;
+                               *rasizep = 0;
+                       }
+               }
+               *bnp = fsbtodb(fs, nb);
+               return (0);
+       }
+
+       /*
+        * Determine how many levels of indirection.
+        */
+       sh = 1;
+       bn -= NDADDR;
+       for (j = NIADDR; j > 0; j--) {
+               sh *= NINDIR(fs);
+               if (bn < sh)
+                       break;
+               bn -= sh;
+       }
+       if (j == 0)
+               return (EFBIG);
 
 
-       if (bn < 0) {
-               u.u_error = EFBIG;
-               return ((daddr_t)0);
+       /*
+        * fetch the first indirect block
+        */
+       nb = ip->i_ib[NIADDR - j];
+       if (nb == 0) {
+               *bnp = (daddr_t)-1;
+               return (0);
        }
        }
+
+       /*
+        * fetch through the indirect blocks
+        */
+       for (; j <= NIADDR; j++) {
+               if (error = bread(ip->i_devvp, fsbtodb(fs, nb),
+                   (int)fs->fs_bsize, &bp)) {
+                       brelse(bp);
+                       return (error);
+               }
+               bap = bp->b_un.b_daddr;
+               sh /= NINDIR(fs);
+               i = (bn / sh) % NINDIR(fs);
+               nb = bap[i];
+               if (nb == 0) {
+                       *bnp = (daddr_t)-1;
+                       brelse(bp);
+                       return (0);
+               }
+       }
+
+       /*
+        * calculate read-ahead.
+        */
+       if (rablockp && rasizep) {
+               if (i < NINDIR(fs) - 1) {
+                       *rablockp = fsbtodb(fs, bap[i + 1]);
+                       *rasizep = fs->fs_bsize;
+               } else {
+                       *rablockp = 0;
+                       *rasizep = 0;
+               }
+       }
+       *bnp = fsbtodb(fs, nb);
+       brelse(bp);
+       return (0);
+}
+
+/*
+ * Balloc defines the structure of file system storage
+ * by returning the physical block number on a device given the
+ * inode and the logical block number in a file.
+ * When unallocated entries are found, new physical blocks
+ * are allocated.
+ */
+balloc(ip, bn, size, bnp, flags)
+       register struct inode *ip;
+       register daddr_t bn;
+       int size;
+       daddr_t *bnp;
+       int flags;
+{
+       register struct fs *fs;
+       register daddr_t nb;
+       struct buf *bp, *nbp;
+       int osize, nsize, i, j, sh, error;
+       daddr_t lbn, *bap, pref, blkpref();
+
+       if (bn < 0)
+               return (EFBIG);
        fs = ip->i_fs;
        fs = ip->i_fs;
-       rablock = 0;
-       rasize = 0;             /* conservative */
 
        /*
         * If the next write will extend the file into a new block,
 
        /*
         * If the next write will extend the file into a new block,
@@ -52,14 +165,16 @@ bmap(ip, bn, rwflg, size)
         * this fragment has to be extended to be a full block.
         */
        nb = lblkno(fs, ip->i_size);
         * this fragment has to be extended to be a full block.
         */
        nb = lblkno(fs, ip->i_size);
-       if (rwflg == B_WRITE && nb < NDADDR && nb < bn) {
+       if (nb < NDADDR && nb < bn) {
                osize = blksize(fs, ip, nb);
                if (osize < fs->fs_bsize && osize > 0) {
                osize = blksize(fs, ip, nb);
                if (osize < fs->fs_bsize && osize > 0) {
-                       bp = realloccg(ip, ip->i_db[nb],
+                       error = realloccg(ip, ip->i_db[nb],
                                blkpref(ip, nb, (int)nb, &ip->i_db[0]),
                                blkpref(ip, nb, (int)nb, &ip->i_db[0]),
-                               osize, (int)fs->fs_bsize);
-                       if (bp == NULL)
-                               return ((daddr_t)-1);
+                               osize, (int)fs->fs_bsize, &bp);
+                       if (error) {
+                               *bnp = (daddr_t)-1;
+                               return (error);
+                       }
                        ip->i_size = (nb + 1) * fs->fs_bsize;
                        ip->i_db[nb] = dbtofsb(fs, bp->b_blkno);
                        ip->i_flag |= IUPD|ICHG;
                        ip->i_size = (nb + 1) * fs->fs_bsize;
                        ip->i_db[nb] = dbtofsb(fs, bp->b_blkno);
                        ip->i_flag |= IUPD|ICHG;
@@ -71,11 +186,6 @@ bmap(ip, bn, rwflg, size)
         */
        if (bn < NDADDR) {
                nb = ip->i_db[bn];
         */
        if (bn < NDADDR) {
                nb = ip->i_db[bn];
-               if (rwflg == B_READ) {
-                       if (nb == 0)
-                               return ((daddr_t)-1);
-                       goto gotit;
-               }
                if (nb == 0 || ip->i_size < (bn + 1) * fs->fs_bsize) {
                        if (nb != 0) {
                                /* consider need to reallocate a frag */
                if (nb == 0 || ip->i_size < (bn + 1) * fs->fs_bsize) {
                        if (nb != 0) {
                                /* consider need to reallocate a frag */
@@ -83,39 +193,41 @@ bmap(ip, bn, rwflg, size)
                                nsize = fragroundup(fs, size);
                                if (nsize <= osize)
                                        goto gotit;
                                nsize = fragroundup(fs, size);
                                if (nsize <= osize)
                                        goto gotit;
-                               bp = realloccg(ip, nb,
+                               error = realloccg(ip, nb,
                                        blkpref(ip, bn, (int)bn, &ip->i_db[0]),
                                        blkpref(ip, bn, (int)bn, &ip->i_db[0]),
-                                       osize, nsize);
+                                       osize, nsize, &bp);
                        } else {
                                if (ip->i_size < (bn + 1) * fs->fs_bsize)
                                        nsize = fragroundup(fs, size);
                                else
                                        nsize = fs->fs_bsize;
                        } else {
                                if (ip->i_size < (bn + 1) * fs->fs_bsize)
                                        nsize = fragroundup(fs, size);
                                else
                                        nsize = fs->fs_bsize;
-                               bp = alloc(ip,
+                               error = alloc(ip,
                                        blkpref(ip, bn, (int)bn, &ip->i_db[0]),
                                        blkpref(ip, bn, (int)bn, &ip->i_db[0]),
-                                       nsize);
+                                       nsize, &bp, flags);
+                       }
+                       if (error) {
+                               *bnp = (daddr_t)-1;
+                               return (error);
                        }
                        }
-                       if (bp == NULL)
-                               return ((daddr_t)-1);
                        nb = dbtofsb(fs, bp->b_blkno);
                        nb = dbtofsb(fs, bp->b_blkno);
-                       if ((ip->i_mode&IFMT) == IFDIR)
+                       if ((ip->i_mode & IFMT) == IFDIR)
                                /*
                                 * Write directory blocks synchronously
                                 * so they never appear with garbage in
                                 * them on the disk.
                                /*
                                 * Write directory blocks synchronously
                                 * so they never appear with garbage in
                                 * them on the disk.
+                                * 
+                                * NB: Should free space and return error
+                                * if bwrite returns an error.
                                 */
                                 */
-                               bwrite(bp);
+                               error = bwrite(bp);
                        else
                                bdwrite(bp);
                        ip->i_db[bn] = nb;
                        ip->i_flag |= IUPD|ICHG;
                }
 gotit:
                        else
                                bdwrite(bp);
                        ip->i_db[bn] = nb;
                        ip->i_flag |= IUPD|ICHG;
                }
 gotit:
-               if (bn < NDADDR - 1) {
-                       rablock = fsbtodb(fs, ip->i_db[bn + 1]);
-                       rasize = blksize(fs, ip, bn + 1);
-               }
-               return (nb);
+               *bnp = fsbtodb(fs, nb);
+               return (0);
        }
 
        /*
        }
 
        /*
@@ -125,34 +237,35 @@ gotit:
        sh = 1;
        lbn = bn;
        bn -= NDADDR;
        sh = 1;
        lbn = bn;
        bn -= NDADDR;
-       for (j = NIADDR; j>0; j--) {
+       for (j = NIADDR; j > 0; j--) {
                sh *= NINDIR(fs);
                if (bn < sh)
                        break;
                bn -= sh;
        }
                sh *= NINDIR(fs);
                if (bn < sh)
                        break;
                bn -= sh;
        }
-       if (j == 0) {
-               u.u_error = EFBIG;
-               return ((daddr_t)0);
-       }
+       if (j == 0)
+               return (EFBIG);
 
        /*
         * fetch the first indirect block
         */
        nb = ip->i_ib[NIADDR - j];
        if (nb == 0) {
 
        /*
         * fetch the first indirect block
         */
        nb = ip->i_ib[NIADDR - j];
        if (nb == 0) {
-               if (rwflg == B_READ)
-                       return ((daddr_t)-1);
                pref = blkpref(ip, lbn, 0, (daddr_t *)0);
                pref = blkpref(ip, lbn, 0, (daddr_t *)0);
-               bp = alloc(ip, pref, (int)fs->fs_bsize);
-               if (bp == NULL)
-                       return ((daddr_t)-1);
+               error = alloc(ip, pref, (int)fs->fs_bsize, &bp, B_CLRBUF);
+               if (error) {
+                       *bnp = (daddr_t)-1;
+                       return (error);
+               }
                nb = dbtofsb(fs, bp->b_blkno);
                /*
                 * Write synchronously so that indirect blocks
                 * never point at garbage.
                nb = dbtofsb(fs, bp->b_blkno);
                /*
                 * Write synchronously so that indirect blocks
                 * never point at garbage.
+                * 
+                * NB: Should free space and return error
+                * if bwrite returns an error.
                 */
                 */
-               bwrite(bp);
+               error = bwrite(bp);
                ip->i_ib[NIADDR - j] = nb;
                ip->i_flag |= IUPD|ICHG;
        }
                ip->i_ib[NIADDR - j] = nb;
                ip->i_flag |= IUPD|ICHG;
        }
@@ -165,40 +278,40 @@ gotit:
                bp = bread(ip->i_dev, fsbtodb(fs, nb), (int)fs->fs_bsize,
                    fs->fs_dbsize);
 #else SECSIZE
                bp = bread(ip->i_dev, fsbtodb(fs, nb), (int)fs->fs_bsize,
                    fs->fs_dbsize);
 #else SECSIZE
-               bp = bread(ip->i_dev, fsbtodb(fs, nb), (int)fs->fs_bsize);
-#endif SECSIZE
-               if (bp->b_flags & B_ERROR) {
+               if (error = bread(ip->i_devvp, fsbtodb(fs, nb),
+                   (int)fs->fs_bsize, &bp)) {
                        brelse(bp);
                        brelse(bp);
-                       return ((daddr_t)0);
+                       return (error);
                }
                bap = bp->b_un.b_daddr;
                sh /= NINDIR(fs);
                i = (bn / sh) % NINDIR(fs);
                nb = bap[i];
                if (nb == 0) {
                }
                bap = bp->b_un.b_daddr;
                sh /= NINDIR(fs);
                i = (bn / sh) % NINDIR(fs);
                nb = bap[i];
                if (nb == 0) {
-                       if (rwflg==B_READ) {
-                               brelse(bp);
-                               return ((daddr_t)-1);
-                       }
                        if (pref == 0)
                                if (j < NIADDR)
                                        pref = blkpref(ip, lbn, 0,
                                                (daddr_t *)0);
                                else
                                        pref = blkpref(ip, lbn, i, &bap[0]);
                        if (pref == 0)
                                if (j < NIADDR)
                                        pref = blkpref(ip, lbn, 0,
                                                (daddr_t *)0);
                                else
                                        pref = blkpref(ip, lbn, i, &bap[0]);
-                       nbp = alloc(ip, pref, (int)fs->fs_bsize);
-                       if (nbp == NULL) {
+                       error = alloc(ip, pref, (int)fs->fs_bsize, &nbp,
+                               (j < NIADDR) ? B_CLRBUF : flags);
+                       if (error) {
                                brelse(bp);
                                brelse(bp);
-                               return ((daddr_t)-1);
+                               *bnp = (daddr_t)-1;
+                               return (error);
                        }
                        nb = dbtofsb(fs, nbp->b_blkno);
                        }
                        nb = dbtofsb(fs, nbp->b_blkno);
-                       if (j < NIADDR || (ip->i_mode&IFMT) == IFDIR)
+                       if (j < NIADDR || (ip->i_mode & IFMT) == IFDIR)
                                /*
                                 * Write synchronously so indirect blocks
                                 * never point at garbage and blocks
                                 * in directories never contain garbage.
                                /*
                                 * Write synchronously so indirect blocks
                                 * never point at garbage and blocks
                                 * in directories never contain garbage.
+                                * 
+                                * NB: Should free space and return error
+                                * if bwrite returns an error.
                                 */
                                 */
-                               bwrite(nbp);
+                               error = bwrite(nbp);
                        else
                                bdwrite(nbp);
                        bap[i] = nb;
                        else
                                bdwrite(nbp);
                        bap[i] = nb;
@@ -207,12 +320,6 @@ gotit:
                        brelse(bp);
        }
 
                        brelse(bp);
        }
 
-       /*
-        * calculate read-ahead.
-        */
-       if (i < NINDIR(fs) - 1) {
-               rablock = fsbtodb(fs, bap[i+1]);
-               rasize = fs->fs_bsize;
-       }
-       return (nb);
+       *bnp = fsbtodb(fs, nb);
+       return (0);
 }
 }
index 5d81a96..980b726 100644 (file)
@@ -1,22 +1,35 @@
 /*
 /*
- * Copyright (c) 1982, 1986 Regents of the University of California.
- * All rights reserved.  The Berkeley software License Agreement
- * specifies the terms and conditions for redistribution.
+ * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
+ * All rights reserved.
  *
  *
- *     @(#)lfs_inode.c 7.5 (Berkeley) %G%
+ * 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 MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ *     @(#)lfs_inode.c 7.6 (Berkeley) %G%
  */
 
 #include "param.h"
 #include "systm.h"
 #include "mount.h"
  */
 
 #include "param.h"
 #include "systm.h"
 #include "mount.h"
-#include "dir.h"
 #include "user.h"
 #include "user.h"
-#include "inode.h"
-#include "fs.h"
+#include "file.h"
 #include "buf.h"
 #include "cmap.h"
 #include "buf.h"
 #include "cmap.h"
+#include "vnode.h"
+#include "../ufs/inode.h"
+#include "../ufs/fs.h"
+#include "../ufs/ufsmount.h"
 #ifdef QUOTA
 #ifdef QUOTA
-#include "quota.h"
+#include "../ufs/quota.h"
 #endif
 #include "kernel.h"
 #include "malloc.h"
 #endif
 #include "kernel.h"
 #include "malloc.h"
 #define        INOHASH(dev,ino)        (((unsigned)((dev)+(ino)))%INOHSZ)
 #endif
 
 #define        INOHASH(dev,ino)        (((unsigned)((dev)+(ino)))%INOHSZ)
 #endif
 
+#define INSFREE(ip) {\
+       if (ifreeh) { \
+               *ifreet = (ip); \
+               (ip)->i_freeb = ifreet; \
+       } else { \
+               ifreeh = (ip); \
+               (ip)->i_freeb = &ifreeh; \
+       } \
+       (ip)->i_freef = NULL; \
+       ifreet = &(ip)->i_freef; \
+}
+
 union ihead {                          /* inode LRU cache, Chris Maltby */
        union  ihead *ih_head[2];
        struct inode *ih_chain[2];
 } ihead[INOHSZ];
 
 union ihead {                          /* inode LRU cache, Chris Maltby */
        union  ihead *ih_head[2];
        struct inode *ih_chain[2];
 } ihead[INOHSZ];
 
-struct inode *ifreeh, **ifreet;
+struct inode *ifreeh, **ifreet, *bdevlisth;
 
 /*
  * Initialize hash links for inodes
 
 /*
  * Initialize hash links for inodes
@@ -54,10 +79,12 @@ ihinit()
        ip->i_freeb = &ifreeh;
        ip->i_forw = ip;
        ip->i_back = ip;
        ip->i_freeb = &ifreeh;
        ip->i_forw = ip;
        ip->i_back = ip;
+       ITOV(ip)->v_data = (qaddr_t)ip;
        for (i = ninode; --i > 0; ) {
                ++ip;
                ip->i_forw = ip;
                ip->i_back = ip;
        for (i = ninode; --i > 0; ) {
                ++ip;
                ip->i_forw = ip;
                ip->i_back = ip;
+               ITOV(ip)->v_data = (qaddr_t)ip;
                *ifreet = ip;
                ip->i_freeb = ifreet;
                ifreet = &ip->i_freef;
                *ifreet = ip;
                ip->i_freeb = ifreet;
                ifreet = &ip->i_freef;
@@ -65,55 +92,31 @@ ihinit()
        ip->i_freef = NULL;
 }
 
        ip->i_freef = NULL;
 }
 
-#ifdef notdef
 /*
 /*
- * Find an inode if it is incore.
- * This is the equivalent, for inodes,
- * of ``incore'' in bio.c or ``pfind'' in subr.c.
- */
-struct inode *
-ifind(dev, ino)
-       dev_t dev;
-       ino_t ino;
-{
-       register struct inode *ip;
-       register union  ihead *ih;
-
-       ih = &ihead[INOHASH(dev, ino)];
-       for (ip = ih->ih_chain[0]; ip != (struct inode *)ih; ip = ip->i_forw)
-               if (ino==ip->i_number && dev==ip->i_dev)
-                       return (ip);
-       return ((struct inode *)0);
-}
-#endif notdef
-
-/*
- * Look up an inode by device,inumber.
+ * Look up an vnode/inode by device,inumber.
  * If it is in core (in the inode structure),
  * honor the locking protocol.
  * If it is not in core, read it in from the
  * specified device.
  * If it is in core (in the inode structure),
  * honor the locking protocol.
  * If it is not in core, read it in from the
  * specified device.
- * If the inode is mounted on, perform
- * the indicated indirection.
+ * Callers must check for mount points!!
  * In all cases, a pointer to a locked
  * inode structure is returned.
  * In all cases, a pointer to a locked
  * inode structure is returned.
- *
- * panic: no imt -- if the mounted file
- *     system is not in the mount table.
- *     "cannot happen"
  */
  */
-struct inode *
-iget(dev, fs, ino)
-       dev_t dev;
-       register struct fs *fs;
+iget(xp, ino, ipp)
+       struct inode *xp;
        ino_t ino;
        ino_t ino;
+       struct inode **ipp;
 {
 {
-       register struct inode *ip;
-       register union  ihead *ih;
-       register struct mount *mp;
-       register struct buf *bp;
-       register struct dinode *dp;
-       register struct inode *iq;
+       dev_t dev = xp->i_dev;
+       struct mount *mntp = ITOV(xp)->v_mount;
+       register struct fs *fs = VFSTOUFS(mntp)->um_fs;
+       register struct inode *ip, *iq;
+       register struct vnode *vp;
+       struct inode *nip;
+       struct buf *bp;
+       struct dinode tdip, *dp;
+       union  ihead *ih;
+       int error;
 
 loop:
        ih = &ihead[INOHASH(dev, ino)];
 
 loop:
        ih = &ihead[INOHASH(dev, ino)];
@@ -131,17 +134,8 @@ loop:
                                sleep((caddr_t)ip, PINOD);
                                goto loop;
                        }
                                sleep((caddr_t)ip, PINOD);
                                goto loop;
                        }
-                       if ((ip->i_flag&IMOUNT) != 0) {
-                               for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++)
-                                       if(mp->m_inodp == ip) {
-                                               dev = mp->m_dev;
-                                               fs = mp->m_fs;
-                                               ino = ROOTINO;
-                                               goto loop;
-                                       }
-                               panic("no imt");
-                       }
-                       if (ip->i_count == 0) {         /* ino on free list */
+                       vp = ITOV(ip);
+                       if (vp->v_count == 0) {         /* ino on free list */
                                if (iq = ip->i_freef)
                                        iq->i_freeb = ip->i_freeb;
                                else
                                if (iq = ip->i_freef)
                                        iq->i_freeb = ip->i_freeb;
                                else
@@ -150,17 +144,153 @@ loop:
                                ip->i_freef = NULL;
                                ip->i_freeb = NULL;
                        }
                                ip->i_freef = NULL;
                                ip->i_freeb = NULL;
                        }
-                       ip->i_count++;
                        ip->i_flag |= ILOCKED;
                        ip->i_flag |= ILOCKED;
-                       return(ip);
+                       vp->v_count++;
+                       *ipp = ip;
+                       return(0);
+               }
+       if (error = getnewino(dev, ino, &nip)) {
+               *ipp = 0;
+               return (error);
+       }
+       ip = nip;
+       /*
+        * Read in the disk contents for the inode.
+        */
+       if (error = bread(VFSTOUFS(mntp)->um_devvp, fsbtodb(fs, itod(fs, ino)),
+           (int)fs->fs_bsize, &bp)) {
+               /*
+                * The inode doesn't contain anything useful, so it would
+                * be misleading to leave it on its hash chain. Iput() will
+                * take care of putting it back on the free list. We also
+                * lose its inumber, just in case.
+                */
+               remque(ip);
+               ip->i_forw = ip;
+               ip->i_back = ip;
+               ip->i_number = 0;
+               INSFREE(ip);
+               ip->i_flag = 0;
+               brelse(bp);
+               *ipp = 0;
+               return(error);
+       }
+       /*
+        * Check to see if the new inode represents a block device
+        * for which we already have an inode (either because of
+        * bdevvp() or because of a different inode representing
+        * the same block device). If such an alias exists, put the
+        * just allocated inode back on the free list, and replace
+        * the contents of the existing inode with the contents of
+        * the new inode.
+        */
+       dp = bp->b_un.b_dino;
+       dp += itoo(fs, ino);
+       if ((dp->di_mode & IFMT) != IFBLK) {
+               ip->i_ic = dp->di_ic;
+               brelse(bp);
+       } else {
+again:
+               for (iq = bdevlisth; iq; iq = iq->i_devlst) {
+                       if (dp->di_rdev != ITOV(iq)->v_rdev)
+                               continue;
+                       igrab(iq);
+                       if (dp->di_rdev != ITOV(iq)->v_rdev) {
+                               iput(iq);
+                               goto again;
+                       }
+                       /*
+                        * Discard unneeded inode.
+                        */
+                       remque(ip);
+                       ip->i_forw = ip;
+                       ip->i_back = ip;
+                       ip->i_number = 0;
+                       INSFREE(ip);
+                       ip->i_flag = 0;
+                       /*
+                        * Reinitialize aliased inode.
+                        * We must release the buffer that we just read
+                        * before doing the iupdat() to avoid a possible
+                        * deadlock with updating an inode in the same
+                        * disk block.
+                        */
+                       ip = iq;
+                       vp = ITOV(iq);
+                       tdip.di_ic = dp->di_ic;
+                       brelse(bp);
+                       error = iupdat(ip, &time, &time, 1);
+                       ip->i_ic = tdip.di_ic;
+                       remque(ip);
+                       insque(ip, ih);
+                       ip->i_dev = dev;
+                       ip->i_number = ino;
+                       if (ip->i_devvp) {
+                               vrele(ip->i_devvp);
+                               ip->i_devvp = 0;
+                       }
+                       cache_purge(vp);
+                       break;
+               }
+               if (iq == 0) {
+                       ip->i_ic = dp->di_ic;
+                       brelse(bp);
+                       ip->i_devlst = bdevlisth;
+                       bdevlisth = ip;
                }
                }
+       }
+       /*
+        * Finish inode initialization.
+        */
+       ip->i_fs = fs;
+       ip->i_devvp = VFSTOUFS(mntp)->um_devvp;
+       ip->i_devvp->v_count++;
+       /*
+        * Initialize the associated vnode
+        */
+       vp = ITOV(ip);
+       vinit(vp, mntp, IFTOVT(ip->i_mode), &ufs_vnodeops);
+       if (vp->v_type == VCHR || vp->v_type == VBLK) {
+               vp->v_rdev = ip->i_rdev;
+               vp->v_op = &blk_vnodeops;
+       }
+       if (ino == ROOTINO)
+               vp->v_flag |= VROOT;
+#ifdef QUOTA
+       if (ip->i_mode != 0)
+               ip->i_dquot = inoquota(ip);
+#endif
+       *ipp = ip;
+       return (0);
+}
 
 
+/*
+ * Allocate a new inode.
+ *
+ * Put it onto its hash chain and lock it so that other requests for
+ * this inode will block if they arrive while we are sleeping waiting
+ * for old data structures to be purged or for the contents of the disk
+ * portion of this inode to be read.
+ */
+getnewino(dev, ino, ipp)
+       dev_t dev;
+       ino_t ino;
+       struct inode **ipp;
+{
+       union ihead *ih;
+       register struct inode *ip, *iq;
+       register struct vnode *vp;
+
+       /*
+        * Remove the next inode from the free list.
+        */
        if ((ip = ifreeh) == NULL) {
                tablefull("inode");
        if ((ip = ifreeh) == NULL) {
                tablefull("inode");
-               u.u_error = ENFILE;
-               return(NULL);
+               *ipp = 0;
+               return(ENFILE);
        }
        }
-       if (ip->i_count)
+       vp = ITOV(ip);
+       if (vp->v_count)
                panic("free inode isn't");
        if (iq = ip->i_freef)
                iq->i_freeb = &ifreeh;
                panic("free inode isn't");
        if (iq = ip->i_freef)
                iq->i_freeb = &ifreeh;
@@ -170,65 +300,47 @@ loop:
        /*
         * Now to take inode off the hash chain it was on
         * (initially, or after an iflush, it is on a "hash chain"
        /*
         * Now to take inode off the hash chain it was on
         * (initially, or after an iflush, it is on a "hash chain"
-        * consisting entirely of itself, and pointed to by no-one,
-        * but that doesn't matter), and put it on the chain for
-        * its new (ino, dev) pair
+        * consisting entirely of itself, and pointed to by no-one)
+        * and put it on the chain for its new (ino, dev) pair.
         */
        remque(ip);
         */
        remque(ip);
-       insque(ip, ih);
        ip->i_dev = dev;
        ip->i_dev = dev;
-       ip->i_fs = fs;
        ip->i_number = ino;
        ip->i_number = ino;
-       cacheinval(ip);
+       if (dev != NODEV) {
+               ih = &ihead[INOHASH(dev, ino)];
+               insque(ip, ih);
+       }
        ip->i_flag = ILOCKED;
        ip->i_flag = ILOCKED;
-       ip->i_count++;
        ip->i_lastr = 0;
        ip->i_lastr = 0;
-#ifdef QUOTA
-       dqrele(ip->i_dquot);
-#endif
-#ifdef SECSIZE
-       bp = bread(dev, fsbtodb(fs, itod(fs, ino)), (int)fs->fs_bsize,
-           fs->fs_dbsize);
-#else SECSIZE
-       bp = bread(dev, fsbtodb(fs, itod(fs, ino)), (int)fs->fs_bsize);
 #endif SECSIZE
        /*
 #endif SECSIZE
        /*
-        * Check I/O errors
+        * Purge old data structures associated with the inode.
         */
         */
-       if ((bp->b_flags&B_ERROR) != 0) {
-               brelse(bp);
-               /*
-                * the inode doesn't contain anything useful, so it would
-                * be misleading to leave it on its hash chain.
-                * 'iput' will take care of putting it back on the free list.
-                */
-               remque(ip);
-               ip->i_forw = ip;
-               ip->i_back = ip;
-               /*
-                * we also loose its inumber, just in case (as iput
-                * doesn't do that any more) - but as it isn't on its
-                * hash chain, I doubt if this is really necessary .. kre
-                * (probably the two methods are interchangable)
-                */
-               ip->i_number = 0;
-#ifdef QUOTA
-               ip->i_dquot = NODQUOT;
-#endif
-               iput(ip);
-               return(NULL);
+       cache_purge(vp);
+       if (ip->i_devvp) {
+               vrele(ip->i_devvp);
+               ip->i_devvp = 0;
        }
        }
-       dp = bp->b_un.b_dino;
-       dp += itoo(fs, ino);
-       ip->i_ic = dp->di_ic;
-       brelse(bp);
 #ifdef QUOTA
 #ifdef QUOTA
-       if (ip->i_mode == 0)
-               ip->i_dquot = NODQUOT;
-       else
-               ip->i_dquot = inoquota(ip);
+       dqrele(ip->i_dquot);
+       ip->i_dquot = NODQUOT;
 #endif
 #endif
-       return (ip);
+       if (vp->v_type == VBLK) {
+               if (bdevlisth == ip) {
+                       bdevlisth = ip->i_devlst;
+               } else {
+                       for (iq = bdevlisth; iq; iq = iq->i_devlst) {
+                               if (iq->i_devlst != ip)
+                                       continue;
+                               iq->i_devlst = ip->i_devlst;
+                               break;
+                       }
+                       if (iq == NULL)
+                               panic("missing bdev");
+               }
+       }
+       *ipp = ip;
+       return (0);
 }
 
 /*
 }
 
 /*
@@ -242,11 +354,13 @@ loop:
 igrab(ip)
        register struct inode *ip;
 {
 igrab(ip)
        register struct inode *ip;
 {
+       register struct vnode *vp = ITOV(ip);
+
        while ((ip->i_flag&ILOCKED) != 0) {
                ip->i_flag |= IWANT;
                sleep((caddr_t)ip, PINOD);
        }
        while ((ip->i_flag&ILOCKED) != 0) {
                ip->i_flag |= IWANT;
                sleep((caddr_t)ip, PINOD);
        }
-       if (ip->i_count == 0) {         /* ino on free list */
+       if (vp->v_count == 0) {         /* ino on free list */
                register struct inode *iq;
 
                if (iq = ip->i_freef)
                register struct inode *iq;
 
                if (iq = ip->i_freef)
@@ -257,10 +371,56 @@ igrab(ip)
                ip->i_freef = NULL;
                ip->i_freeb = NULL;
        }
                ip->i_freef = NULL;
                ip->i_freeb = NULL;
        }
-       ip->i_count++;
+       vp->v_count++;
        ip->i_flag |= ILOCKED;
 }
 
        ip->i_flag |= ILOCKED;
 }
 
+/*
+ * Create a vnode for a block device.
+ * Used for root filesystem, argdev, and swap areas.
+ */
+bdevvp(dev, vpp)
+       dev_t dev;
+       struct vnode **vpp;
+{
+       register struct inode *ip;
+       register struct vnode *vp;
+       struct inode *nip;
+       int error;
+
+       /*
+        * Check for the existence of an existing vnode.
+        */
+again:
+       for (ip = bdevlisth; ip; ip = ip->i_devlst) {
+               vp = ITOV(ip);
+               if (dev != vp->v_rdev)
+                       continue;
+               igrab(ip);
+               if (dev != vp->v_rdev) {
+                       iput(ip);
+                       goto again;
+               }
+               IUNLOCK(ip);
+               *vpp = vp;
+               return (0);
+       }
+       if (error = getnewino(NODEV, (ino_t)0, &nip)) {
+               *vpp = 0;
+               return (error);
+       }
+       ip = nip;
+       ip->i_fs = 0;
+       ip->i_devlst = bdevlisth;
+       bdevlisth = ip;
+       vp = ITOV(ip);
+       vinit(vp, 0, VBLK, &blk_vnodeops);
+       vp->v_rdev = dev;
+       IUNLOCK(ip);
+       *vpp = vp;
+       return (0);
+}
+
 /*
  * Decrement reference count of
  * an inode structure.
 /*
  * Decrement reference count of
  * an inode structure.
@@ -275,54 +435,43 @@ iput(ip)
        if ((ip->i_flag & ILOCKED) == 0)
                panic("iput");
        IUNLOCK(ip);
        if ((ip->i_flag & ILOCKED) == 0)
                panic("iput");
        IUNLOCK(ip);
-       irele(ip);
+       vrele(ITOV(ip));
 }
 
 }
 
-irele(ip)
-       register struct inode *ip;
+
+ufs_inactive(vp)
+       struct vnode *vp;
 {
 {
-       int mode;
-
-       if (ip->i_count == 1) {
-               ip->i_flag |= ILOCKED;
-               if (ip->i_nlink <= 0 && ip->i_fs->fs_ronly == 0) {
-                       itrunc(ip, (u_long)0);
-                       mode = ip->i_mode;
-                       ip->i_mode = 0;
-                       ip->i_rdev = 0;
-                       ip->i_flag |= IUPD|ICHG;
-                       ifree(ip, ip->i_number, mode);
+       register struct inode *ip = VTOI(vp);
+       int mode, error;
+
+       if (ITOV(ip)->v_count != 0)
+               panic("ufs_inactive: not inactive");
+       ip->i_flag |= ILOCKED;
+       if (ip->i_nlink <= 0 && (ITOV(ip)->v_mount->m_flag&M_RDONLY) == 0) {
+               error = itrunc(ip, (u_long)0);
+               mode = ip->i_mode;
+               ip->i_mode = 0;
+               ip->i_rdev = 0;
+               ip->i_flag |= IUPD|ICHG;
+               ifree(ip, ip->i_number, mode);
 #ifdef QUOTA
 #ifdef QUOTA
-                       (void) chkiq(ip->i_dev, ip, ip->i_uid, 0);
-                       dqrele(ip->i_dquot);
-                       ip->i_dquot = NODQUOT;
+               (void) chkiq(ip->i_dev, ip, ip->i_uid, 0);
+               dqrele(ip->i_dquot);
+               ip->i_dquot = NODQUOT;
 #endif
 #endif
-               }
-               IUPDAT(ip, &time, &time, 0);
-               IUNLOCK(ip);
-               ip->i_flag = 0;
-               /*
-                * Put the inode on the end of the free list.
-                * Possibly in some cases it would be better to
-                * put the inode at the head of the free list,
-                * (eg: where i_mode == 0 || i_number == 0)
-                * but I will think about that later .. kre
-                * (i_number is rarely 0 - only after an i/o error in iget,
-                * where i_mode == 0, the inode will probably be wanted
-                * again soon for an ialloc, so possibly we should keep it)
-                */
-               if (ifreeh) {
-                       *ifreet = ip;
-                       ip->i_freeb = ifreet;
-               } else {
-                       ifreeh = ip;
-                       ip->i_freeb = &ifreeh;
-               }
-               ip->i_freef = NULL;
-               ifreet = &ip->i_freef;
-       } else if (!(ip->i_flag & ILOCKED))
-               ITIMES(ip, &time, &time);
-       ip->i_count--;
+       }
+       IUPDAT(ip, &time, &time, 0);
+       IUNLOCK(ip);
+       ip->i_flag = 0;
+       /*
+        * Put the inode on the end of the free list.
+        * Possibly in some cases it would be better to
+        * put the inode at the head of the free list,
+        * (eg: where i_mode == 0 || i_number == 0).
+        */
+       INSFREE(ip);
+       return (error);
 }
 
 /*
 }
 
 /*
@@ -338,38 +487,36 @@ iupdat(ip, ta, tm, waitfor)
        struct timeval *ta, *tm;
        int waitfor;
 {
        struct timeval *ta, *tm;
        int waitfor;
 {
-       register struct buf *bp;
+       struct buf *bp;
+       struct vnode *vp = ITOV(ip);
        struct dinode *dp;
        register struct fs *fs;
 
        fs = ip->i_fs;
        struct dinode *dp;
        register struct fs *fs;
 
        fs = ip->i_fs;
-       if ((ip->i_flag & (IUPD|IACC|ICHG|IMOD)) != 0) {
-               if (fs->fs_ronly)
-                       return;
-#ifdef SECSIZE
-               bp = bread(ip->i_dev, fsbtodb(fs, itod(fs, ip->i_number)),
-                       (int)fs->fs_bsize, fs->fs_dbsize);
-#else SECSIZE
-               bp = bread(ip->i_dev, fsbtodb(fs, itod(fs, ip->i_number)),
-                       (int)fs->fs_bsize);
-#endif SECSIZE
-               if (bp->b_flags & B_ERROR) {
-                       brelse(bp);
-                       return;
-               }
-               if (ip->i_flag&IACC)
-                       ip->i_atime = ta->tv_sec;
-               if (ip->i_flag&IUPD)
-                       ip->i_mtime = tm->tv_sec;
-               if (ip->i_flag&ICHG)
-                       ip->i_ctime = time.tv_sec;
-               ip->i_flag &= ~(IUPD|IACC|ICHG|IMOD);
-               dp = bp->b_un.b_dino + itoo(fs, ip->i_number);
-               dp->di_ic = ip->i_ic;
-               if (waitfor)
-                       bwrite(bp);
-               else
-                       bdwrite(bp);
+       if ((ip->i_flag & (IUPD|IACC|ICHG|IMOD)) == 0)
+               return (0);
+       if (vp->v_mount->m_flag & M_RDONLY)
+               return (0);
+       error = bread(ip->i_devvp, fsbtodb(fs, itod(fs, ip->i_number)),
+               (int)fs->fs_bsize, &bp);
+       if (error) {
+               brelse(bp);
+               return (error);
+       }
+       if (ip->i_flag&IACC)
+               ip->i_atime = ta->tv_sec;
+       if (ip->i_flag&IUPD)
+               ip->i_mtime = tm->tv_sec;
+       if (ip->i_flag&ICHG)
+               ip->i_ctime = time.tv_sec;
+       ip->i_flag &= ~(IUPD|IACC|ICHG|IMOD);
+       dp = bp->b_un.b_dino + itoo(fs, ip->i_number);
+       dp->di_ic = ip->i_ic;
+       if (waitfor) {
+               return (bwrite(bp));
+       } else {
+               bdwrite(bp);
+               return (0);
        }
 }
 
        }
 }
 
@@ -393,17 +540,16 @@ itrunc(oip, length)
        register struct fs *fs;
        register struct inode *ip;
        struct buf *bp;
        register struct fs *fs;
        register struct inode *ip;
        struct buf *bp;
-       int offset, osize, size, count, level;
-       long nblocks, blocksreleased = 0;
+       int offset, osize, size, level;
+       long count, nblocks, blocksreleased = 0;
        register int i;
        register int i;
-       dev_t dev;
+       int error, allerror = 0;
        struct inode tip;
        struct inode tip;
-       extern long indirtrunc();
 
        if (oip->i_size <= length) {
                oip->i_flag |= ICHG|IUPD;
 
        if (oip->i_size <= length) {
                oip->i_flag |= ICHG|IUPD;
-               iupdat(oip, &time, &time, 1);
-               return;
+               error = iupdat(oip, &time, &time, 1);
+               return (error);
        }
        /*
         * Calculate index into inode's block list of
        }
        /*
         * Calculate index into inode's block list of
@@ -430,25 +576,20 @@ itrunc(oip, length)
                oip->i_size = length;
        } else {
                lbn = lblkno(fs, length);
                oip->i_size = length;
        } else {
                lbn = lblkno(fs, length);
-               bn = fsbtodb(fs, bmap(oip, lbn, B_WRITE, offset));
-               if (u.u_error || (long)bn < 0)
-                       return;
+               error = balloc(oip, lbn, offset, &bn, B_CLRBUF);
+               if (error)
+                       return (error);
+               if ((long)bn < 0)
+                       panic("itrunc: hole");
                oip->i_size = length;
                size = blksize(fs, oip, lbn);
                count = howmany(size, CLBYTES);
                oip->i_size = length;
                size = blksize(fs, oip, lbn);
                count = howmany(size, CLBYTES);
-               dev = oip->i_dev;
-               for (i = 0; i < count; i++)
-#ifdef SECSIZE
-                       munhash(dev, bn + i * CLBYTES / fs->fs_dbsize);
-#else SECSIZE
-                       munhash(dev, bn + i * CLBYTES / DEV_BSIZE);
-#endif SECSIZE
-               bp = bread(dev, bn, size);
-               if (bp->b_flags & B_ERROR) {
-                       u.u_error = EIO;
+                       munhash(oip->i_devvp, bn + i * CLBYTES / DEV_BSIZE);
+               error = bread(oip->i_devvp, bn, size, &bp);
+               if (error) {
                        oip->i_size = osize;
                        brelse(bp);
                        oip->i_size = osize;
                        brelse(bp);
-                       return;
+                       return (error);
                }
                bzero(bp->b_un.b_addr + offset, (unsigned)(size - offset));
                bdwrite(bp);
                }
                bzero(bp->b_un.b_addr + offset, (unsigned)(size - offset));
                bdwrite(bp);
@@ -471,7 +612,7 @@ itrunc(oip, length)
        for (i = NDADDR - 1; i > lastblock; i--)
                oip->i_db[i] = 0;
        oip->i_flag |= ICHG|IUPD;
        for (i = NDADDR - 1; i > lastblock; i--)
                oip->i_db[i] = 0;
        oip->i_flag |= ICHG|IUPD;
-       syncip(oip);
+       allerror = syncip(oip);
 
        /*
         * Indirect blocks first.
 
        /*
         * Indirect blocks first.
@@ -480,8 +621,11 @@ itrunc(oip, length)
        for (level = TRIPLE; level >= SINGLE; level--) {
                bn = ip->i_ib[level];
                if (bn != 0) {
        for (level = TRIPLE; level >= SINGLE; level--) {
                bn = ip->i_ib[level];
                if (bn != 0) {
-                       blocksreleased +=
-                           indirtrunc(ip, bn, lastiblock[level], level);
+                       error = indirtrunc(ip, bn, lastiblock[level], level,
+                               &count);
+                       if (error)
+                               allerror = error;
+                       blocksreleased += count;
                        if (lastiblock[level] < 0) {
                                ip->i_ib[level] = 0;
                                blkfree(ip, bn, (off_t)fs->fs_bsize);
                        if (lastiblock[level] < 0) {
                                ip->i_ib[level] = 0;
                                blkfree(ip, bn, (off_t)fs->fs_bsize);
@@ -553,6 +697,7 @@ done:
 #ifdef QUOTA
        (void) chkdq(oip, -blocksreleased, 0);
 #endif
 #ifdef QUOTA
        (void) chkdq(oip, -blocksreleased, 0);
 #endif
+       return (allerror);
 }
 
 /*
 }
 
 /*
@@ -565,19 +710,20 @@ done:
  *
  * NB: triple indirect blocks are untested.
  */
  *
  * NB: triple indirect blocks are untested.
  */
-long
-indirtrunc(ip, bn, lastbn, level)
+indirtrunc(ip, bn, lastbn, level, countp)
        register struct inode *ip;
        daddr_t bn, lastbn;
        int level;
        register struct inode *ip;
        daddr_t bn, lastbn;
        int level;
+       long *countp;
 {
        register int i;
        struct buf *bp;
        register struct fs *fs = ip->i_fs;
        register daddr_t *bap;
        daddr_t *copy, nb, last;
 {
        register int i;
        struct buf *bp;
        register struct fs *fs = ip->i_fs;
        register daddr_t *bap;
        daddr_t *copy, nb, last;
-       long factor;
-       int blocksreleased = 0, nblocks;
+       long blkcount, factor;
+       int nblocks, blocksreleased = 0;
+       int error, allerror = 0;
 
        /*
         * Calculate index in current block of last
 
        /*
         * Calculate index in current block of last
@@ -600,18 +746,20 @@ indirtrunc(ip, bn, lastbn, level)
        bp = bread(ip->i_dev, fsbtodb(fs, bn), (int)fs->fs_bsize,
            fs->fs_dbsize);
 #else SECSIZE
        bp = bread(ip->i_dev, fsbtodb(fs, bn), (int)fs->fs_bsize,
            fs->fs_dbsize);
 #else SECSIZE
-       bp = bread(ip->i_dev, fsbtodb(fs, bn), (int)fs->fs_bsize);
-#endif SECSIZE
-       if (bp->b_flags&B_ERROR) {
+       error = bread(ip->i_devvp, fsbtodb(fs, bn), (int)fs->fs_bsize, &bp);
+       if (error) {
                brelse(bp);
                brelse(bp);
-               return (0);
+               *countp = 0;
+               return (error);
        }
        bap = bp->b_un.b_daddr;
        MALLOC(copy, daddr_t *, fs->fs_bsize, M_TEMP, M_WAITOK);
        bcopy((caddr_t)bap, (caddr_t)copy, (u_int)fs->fs_bsize);
        bzero((caddr_t)&bap[last + 1],
          (u_int)(NINDIR(fs) - (last + 1)) * sizeof (daddr_t));
        }
        bap = bp->b_un.b_daddr;
        MALLOC(copy, daddr_t *, fs->fs_bsize, M_TEMP, M_WAITOK);
        bcopy((caddr_t)bap, (caddr_t)copy, (u_int)fs->fs_bsize);
        bzero((caddr_t)&bap[last + 1],
          (u_int)(NINDIR(fs) - (last + 1)) * sizeof (daddr_t));
-       bwrite(bp);
+       error = bwrite(bp);
+       if (error)
+               allerror = error;
        bap = copy;
 
        /*
        bap = copy;
 
        /*
@@ -621,9 +769,13 @@ indirtrunc(ip, bn, lastbn, level)
                nb = bap[i];
                if (nb == 0)
                        continue;
                nb = bap[i];
                if (nb == 0)
                        continue;
-               if (level > SINGLE)
-                       blocksreleased +=
-                           indirtrunc(ip, nb, (daddr_t)-1, level - 1);
+               if (level > SINGLE) {
+                       error = indirtrunc(ip, nb, (daddr_t)-1, level - 1,
+                               &blkcount);
+                       if (error)
+                               allerror = error;
+                       blocksreleased += blkcount;
+               }
                blkfree(ip, nb, (off_t)fs->fs_bsize);
                blocksreleased += nblocks;
        }
                blkfree(ip, nb, (off_t)fs->fs_bsize);
                blocksreleased += nblocks;
        }
@@ -634,11 +786,16 @@ indirtrunc(ip, bn, lastbn, level)
        if (level > SINGLE && lastbn >= 0) {
                last = lastbn % factor;
                nb = bap[i];
        if (level > SINGLE && lastbn >= 0) {
                last = lastbn % factor;
                nb = bap[i];
-               if (nb != 0)
-                       blocksreleased += indirtrunc(ip, nb, last, level - 1);
+               if (nb != 0) {
+                       error = indirtrunc(ip, nb, last, level - 1, &blkcount);
+                       if (error)
+                               allerror = error;
+                       blocksreleased += blkcount;
+               }
        }
        FREE(copy, M_TEMP);
        }
        FREE(copy, M_TEMP);
-       return (blocksreleased);
+       *countp = blocksreleased;
+       return (allerror);
 }
 
 /*
 }
 
 /*
@@ -664,14 +821,14 @@ iflush(dev)
 #else
                if (ip->i_dev == dev)
 #endif
 #else
                if (ip->i_dev == dev)
 #endif
-                       if (ip->i_count)
+                       if (ITOV(ip)->v_count)
                                return (EBUSY);
                        else {
                                remque(ip);
                                ip->i_forw = ip;
                                ip->i_back = ip;
                                /*
                                return (EBUSY);
                        else {
                                remque(ip);
                                ip->i_forw = ip;
                                ip->i_back = ip;
                                /*
-                                * as i_count == 0, the inode was on the free
+                                * as v_count == 0, the inode was on the free
                                 * list already, just leave it there, it will
                                 * fall off the bottom eventually. We could
                                 * perhaps move it to the head of the free
                                 * list already, just leave it there, it will
                                 * fall off the bottom eventually. We could
                                 * perhaps move it to the head of the free
@@ -683,6 +840,10 @@ iflush(dev)
                                dqrele(ip->i_dquot);
                                ip->i_dquot = NODQUOT;
 #endif
                                dqrele(ip->i_dquot);
                                ip->i_dquot = NODQUOT;
 #endif
+                               if (ip->i_devvp) {
+                                       vrele(ip->i_devvp);
+                                       ip->i_devvp = 0;
+                               }
                        }
        }
        return (0);
                        }
        }
        return (0);
@@ -695,7 +856,11 @@ ilock(ip)
        register struct inode *ip;
 {
 
        register struct inode *ip;
 {
 
-       ILOCK(ip);
+       while (ip->i_flag & ILOCKED) {
+               ip->i_flag |= IWANT;
+               (void) sleep((caddr_t)ip, PINOD);
+       }
+       ip->i_flag |= ILOCKED;
 }
 
 /*
 }
 
 /*
@@ -705,5 +870,55 @@ iunlock(ip)
        register struct inode *ip;
 {
 
        register struct inode *ip;
 {
 
-       IUNLOCK(ip);
+       if ((ip->i_flag & ILOCKED) == 0)
+               printf("unlocking unlocked inode %d on dev 0x%x\n",
+                       ip->i_number, ip->i_dev);
+       ip->i_flag &= ~ILOCKED;
+       if (ip->i_flag&IWANT) {
+               ip->i_flag &= ~IWANT;
+               wakeup((caddr_t)ip);
+       }
+}
+
+/*
+ * Check mode permission on inode pointer. Mode is READ, WRITE or EXEC.
+ * The mode is shifted to select the owner/group/other fields. The
+ * super user is granted all permissions.
+ *
+ * NB: Called from vnode op table. It seems this could all be done
+ * using vattr's but...
+ */
+iaccess(ip, mode, cred)
+       register struct inode *ip;
+       register int mode;
+       struct ucred *cred;
+{
+       register gid_t *gp;
+       register struct vnode *vp = ITOV(ip);
+       int i;
+
+       /*
+        * If you're the super-user,
+        * you always get access.
+        */
+       if (cred->cr_uid == 0)
+               return (0);
+       /*
+        * Access check is based on only one of owner, group, public.
+        * If not owner, then check group. If not a member of the
+        * group, then check public access.
+        */
+       if (cred->cr_uid != ip->i_uid) {
+               mode >>= 3;
+               gp = cred->cr_groups;
+               for (i = 0; i < cred->cr_ngroups; i++, gp++)
+                       if (ip->i_gid == *gp)
+                               goto found;
+               mode >>= 3;
+found:
+               ;
+       }
+       if ((ip->i_mode & mode) != 0)
+               return (0);
+       return (EACCES);
 }
 }
index 9f20ea1..4e7bfe4 100644 (file)
 /*
 /*
- * Copyright (c) 1982, 1986 Regents of the University of California.
- * All rights reserved.  The Berkeley software License Agreement
- * specifies the terms and conditions for redistribution.
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
  *
  *
- *     @(#)lfs_vfsops.c        7.12 (Berkeley) %G%
+ * 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.
+ *
+ *     @(#)lfs_vfsops.c        7.13 (Berkeley) %G%
  */
 
  */
 
+
 #include "param.h"
 #include "systm.h"
 #include "param.h"
 #include "systm.h"
-#include "dir.h"
-#include "user.h"
-#include "inode.h"
-#include "proc.h"
-#include "fs.h"
-#include "buf.h"
+#include "time.h"
+#include "kernel.h"
+#include "namei.h"
+#include "vnode.h"
 #include "mount.h"
 #include "mount.h"
+#include "buf.h"
 #include "file.h"
 #include "file.h"
-#include "conf.h"
-#include "ioctl.h"
 #include "disklabel.h"
 #include "disklabel.h"
-#include "stat.h"
+#include "ioctl.h"
+#include "errno.h"
 #include "malloc.h"
 #include "malloc.h"
+#include "../ufs/fs.h"
+#include "../ufs/ufsmount.h"
+#include "../ufs/inode.h"
 #include "ioctl.h"
 #include "disklabel.h"
 #include "stat.h"
 
 #include "ioctl.h"
 #include "disklabel.h"
 #include "stat.h"
 
-smount()
+/*
+ * ufs vfs operations.
+ */
+int ufs_mount();
+int ufs_unmount();
+int ufs_root();
+int ufs_statfs();
+int ufs_sync();
+int ufs_fhtovp();
+int ufs_vptofh();
+
+struct vfsops ufs_vfsops = {
+       ufs_mount,
+       ufs_unmount,
+       ufs_root,
+       ufs_statfs,
+       ufs_sync,
+       ufs_fhtovp,
+       ufs_vptofh
+};
+
+/*
+ * ufs mount table.
+ */
+struct ufsmount mounttab[NMOUNT];
+
+/*
+ * Called by vfs_mountroot when ufs is going to be mounted as root
+ *
+ * XXX - Need to have a way of figuring the name of the root device
+ */
+#define ROOTNAME       "root device"
+
+ufs_mountroot()
 {
 {
-       register struct a {
-               char    *fspec;
-               char    *freg;
-               int     ronly;
-       } *uap = (struct a *)u.u_ap;
-       dev_t dev;
-       register struct inode *ip;
+       register struct mount *mp;
+       extern struct vnode *rootvp;
+       struct ufsmount *ump;
        register struct fs *fs;
        register struct fs *fs;
-       register struct nameidata *ndp = &u.u_nd;
-       u_int len;
+       u_int size;
+       int error;
 
 
-       u.u_error = getmdev(&dev, uap->fspec);
-       if (u.u_error)
-               return;
-       ndp->ni_nameiop = LOOKUP | FOLLOW;
-       ndp->ni_segflg = UIO_USERSPACE;
-       ndp->ni_dirp = (caddr_t)uap->freg;
-       ip = namei(ndp);
-       if (ip == NULL)
-               return;
-       if (ip->i_count != 1) {
-               iput(ip);
-               u.u_error = EBUSY;
-               return;
+       mp = (struct mount *)malloc((u_long)sizeof(struct mount),
+               M_MOUNT, M_WAITOK);
+       mp->m_op = &ufs_vfsops;
+       mp->m_flag = 0;
+       mp->m_exroot = 0;
+       error = mountfs(rootvp, mp);
+       if (error) {
+               free((caddr_t)mp, M_MOUNT);
+               return (error);
        }
        }
-       if ((ip->i_mode&IFMT) != IFDIR) {
-               iput(ip);
-               u.u_error = ENOTDIR;
-               return;
+       error = vfs_add((struct vnode *)0, mp, 0);
+       if (error) {
+               (void)ufs_unmount(mp, 0);
+               free((caddr_t)mp, M_MOUNT);
+               return (error);
        }
        }
-       fs = mountfs(dev, uap->ronly, ip);
-       if (fs == 0) {
-               iput(ip);
-               return;
+       ump = VFSTOUFS(mp);
+       fs = ump->um_fs;
+       fs->fs_fsmnt[0] = '/';
+       bzero(fs->fs_fsmnt + 1, sizeof(fs->fs_fsmnt) - 1);
+       (void) copystr(ROOTNAME, ump->um_mntname, MNAMELEN - 1, &size);
+       bzero(ump->um_mntname + size, MNAMELEN - size);
+       vfs_unlock(mp);
+       inittodr(fs->fs_time);
+       return (0);
+}
+
+/*
+ * VFS Operations.
+ *
+ * mount system call
+ */
+ufs_mount(mp, path, data, ndp)
+       struct mount *mp;
+       char *path;
+       caddr_t data;
+       struct nameidata *ndp;
+{
+       struct vnode *devvp;
+       struct ufs_args args;
+       struct ufsmount *ump;
+       register struct fs *fs;
+       u_int size;
+       int error;
+
+       if (error = copyin(data, (caddr_t)&args, sizeof (struct ufs_args)))
+               return (error);
+       if ((error = getmdev(&devvp, args.fspec, ndp)) != 0)
+               return (error);
+       error = mountfs(devvp, mp);
+       if (error) {
+               vrele(devvp);
+               return (error);
        }
        }
-       (void) copyinstr(uap->freg, fs->fs_fsmnt, sizeof(fs->fs_fsmnt)-1, &len);
-       bzero(fs->fs_fsmnt + len, sizeof (fs->fs_fsmnt) - len);
+       ump = VFSTOUFS(mp);
+       fs = ump->um_fs;
+       (void) copyinstr(path, fs->fs_fsmnt, sizeof(fs->fs_fsmnt) - 1, &size);
+       bzero(fs->fs_fsmnt + size, sizeof(fs->fs_fsmnt) - size);
+       (void) copyinstr(args.fspec, ump->um_mntname, MNAMELEN - 1, &size);
+       bzero(ump->um_mntname + size, MNAMELEN - size);
+       return (0);
 }
 
 }
 
-struct fs *
-mountfs(dev, ronly, ip)
-       dev_t dev;
-       int ronly;
-       struct inode *ip;
+/*
+ * Common code for mount and mountroot
+ */
+mountfs(devvp, mp)
+       struct vnode *devvp;
+       struct mount *mp;
 {
 {
-       register struct mount *mp;
-       struct mount *fmp = NULL;
-       register struct buf *bp = NULL;
+       register struct ufsmount *ump;
+       struct ufsmount *fmp = NULL;
+       struct buf *bp = NULL;
        register struct fs *fs;
        register struct fs *fs;
+       dev_t dev = devvp->v_rdev;
        struct partinfo dpart;
        int havepart = 0, blks;
        caddr_t base, space;
        struct partinfo dpart;
        int havepart = 0, blks;
        caddr_t base, space;
-       int i, size;
-       register error;
+       int havepart = 0, blks;
+       int error, i, size;
        int needclose = 0;
        int needclose = 0;
+       int ronly = (mp->m_flag & M_RDONLY) != 0;
 
 
-       for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++) {
-               if (mp->m_fs == NULL) {
+       for (ump = &mounttab[0]; ump < &mounttab[NMOUNT]; ump++) {
+               if (ump->um_fs == NULL) {
                        if (fmp == NULL)
                        if (fmp == NULL)
-                               fmp = mp;
-               } else if (dev == mp->m_dev) {
-                       u.u_error = EBUSY;              /* XXX */
-                       return ((struct fs *) NULL);
+                               fmp = ump;
+               } else if (dev == ump->um_dev) {
+                       return (EBUSY);         /* needs translation */
                }
        }
                }
        }
-       if ((mp = fmp) == NULL) {
-               u.u_error = EMFILE;             /* needs translation      XXX */
-               return ((struct fs *) NULL);
-       }
-       mp->m_fs = (struct fs *)1;      /* just to reserve this slot */
-       mp->m_dev = dev;
-       mp->m_inodp = NULL;
-       error =
            (*bdevsw[major(dev)].d_open)(dev, ronly ? FREAD : FREAD|FWRITE,
                S_IFBLK);
        if (error) {
            (*bdevsw[major(dev)].d_open)(dev, ronly ? FREAD : FREAD|FWRITE,
                S_IFBLK);
        if (error) {
-               u.u_error = error;
-               mp->m_fs = NULL;
-               return ((struct fs *) NULL);
+               ump->um_fs = NULL;
+               return (error);
        }
        needclose = 1;
        }
        needclose = 1;
-       if ((*bdevsw[major(dev)].d_ioctl)(dev, DIOCGPART,
-           (caddr_t)&dpart, FREAD) == 0) {
-               havepart = 1;
-               size = dpart.disklab->d_secsize;
-       } else
+       if (VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, FREAD,
+           (struct ucred *)0) != 0)
                size = DEV_BSIZE;
                size = DEV_BSIZE;
-#ifdef SECSIZE
-       /*
-        * If possible, determine hardware sector size
-        * and adjust fsbtodb to correspond.
-        */
-#endif SECSIZE
-       if ((*bdevsw[major(dev)].d_ioctl)(dev, DIOCGPART,
-           (caddr_t)&dpart, FREAD) == 0) {
+       else {
                havepart = 1;
                size = dpart.disklab->d_secsize;
                havepart = 1;
                size = dpart.disklab->d_secsize;
-#ifdef SECSIZE
-               if (size < MINSECSIZE) {
-                       error = EINVAL;
-                       goto out;
-               }
-#endif SECSIZE
-       } else
-               size = DEV_BSIZE;
-#ifdef SECSIZE
-       tp = bread(dev, (daddr_t)(SBOFF / size), SBSIZE, size);
-#else SECSIZE
-       bp = bread(dev, SBLOCK, SBSIZE);
-       if (bp->b_flags & B_ERROR) {
-               mp->m_fs = NULL;
+       }
+       if (error = bread(devvp, SBLOCK, SBSIZE, &bp)) {
+               ump->um_fs = NULL;
                goto out;
        }
        fs = bp->b_un.b_fs;
                goto out;
        }
        fs = bp->b_un.b_fs;
-       if (fs->fs_magic != FS_MAGIC || fs->fs_bsize > MAXBSIZE ||
-           fs->fs_bsize < sizeof(struct fs)) {
-               error = EINVAL;         /* also needs translation */
+               ump->um_fs = NULL;
+               error = EINVAL;         /* XXX also needs translation */
                goto out;
        }
                goto out;
        }
-       mp->m_fs = (struct fs *)malloc((u_long)fs->fs_sbsize, M_SUPERBLK,
+       ump->um_fs = (struct fs *)malloc((u_long)fs->fs_sbsize, M_SUPERBLK,
            M_WAITOK);
            M_WAITOK);
-       bcopy((caddr_t)bp->b_un.b_addr, (caddr_t)mp->m_fs,
+       bcopy((caddr_t)bp->b_un.b_addr, (caddr_t)ump->um_fs,
           (u_int)fs->fs_sbsize);
        brelse(bp);
        bp = NULL;
           (u_int)fs->fs_sbsize);
        brelse(bp);
        bp = NULL;
-       fs = mp->m_fs;
-       fs->fs_ronly = (ronly != 0);
+       fs = ump->um_fs;
+       fs->fs_ronly = ronly;
        if (ronly == 0)
                fs->fs_fmod = 1;
        if (havepart) {
        if (ronly == 0)
                fs->fs_fmod = 1;
        if (havepart) {
@@ -190,10 +238,6 @@ mountfs(dev, ronly, ip)
        blks = howmany(fs->fs_cssize, fs->fs_fsize);
        base = space = (caddr_t)malloc((u_long)fs->fs_cssize, M_SUPERBLK,
            M_WAITOK);
        blks = howmany(fs->fs_cssize, fs->fs_fsize);
        base = space = (caddr_t)malloc((u_long)fs->fs_cssize, M_SUPERBLK,
            M_WAITOK);
-       if (space == NULL) {
-               error = ENOMEM;
-               goto out;
-       }
        for (i = 0; i < blks; i += fs->fs_frag) {
                size = fs->fs_bsize;
                if (i + fs->fs_frag > blks)
        for (i = 0; i < blks; i += fs->fs_frag) {
                size = fs->fs_bsize;
                if (i + fs->fs_frag > blks)
@@ -202,8 +246,8 @@ mountfs(dev, ronly, ip)
                tp = bread(dev, fsbtodb(fs, fs->fs_csaddr + i), size,
                    fs->fs_dbsize);
 #else SECSIZE
                tp = bread(dev, fsbtodb(fs, fs->fs_csaddr + i), size,
                    fs->fs_dbsize);
 #else SECSIZE
-               bp = bread(dev, fsbtodb(fs, fs->fs_csaddr + i), size);
-               if (bp->b_flags&B_ERROR) {
+               error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + i), size, &bp);
+               if (error) {
                        free((caddr_t)base, M_SUPERBLK);
                        goto out;
                }
                        free((caddr_t)base, M_SUPERBLK);
                        goto out;
                }
@@ -213,64 +257,53 @@ mountfs(dev, ronly, ip)
                brelse(bp);
                bp = NULL;
        }
                brelse(bp);
                bp = NULL;
        }
-       mp->m_inodp = ip;
-       if (ip) {
-               ip->i_flag |= IMOUNT;
-               cacheinval(ip);
-               iunlock(ip);
-       }
+       mp->m_data = (qaddr_t)ump;
+       mp->m_bsize = fs->fs_bsize;
+       mp->m_fsize = fs->fs_fsize;
+       mp->m_fsid.val[0] = (long)dev;
+       mp->m_fsid.val[1] = MOUNT_UFS;
+       ump->um_mountp = mp;
+       ump->um_dev = dev;
+       ump->um_devvp = devvp;
+       ump->um_qinod = NULL;
+
        /* Sanity checks for old file systems.                     XXX */
        fs->fs_npsect = MAX(fs->fs_npsect, fs->fs_nsect);       /* XXX */
        fs->fs_interleave = MAX(fs->fs_interleave, 1);          /* XXX */
        if (fs->fs_postblformat == FS_42POSTBLFMT)              /* XXX */
                fs->fs_nrpos = 8;                               /* XXX */
 
        /* Sanity checks for old file systems.                     XXX */
        fs->fs_npsect = MAX(fs->fs_npsect, fs->fs_nsect);       /* XXX */
        fs->fs_interleave = MAX(fs->fs_interleave, 1);          /* XXX */
        if (fs->fs_postblformat == FS_42POSTBLFMT)              /* XXX */
                fs->fs_nrpos = 8;                               /* XXX */
 
-       return (fs);
+       return (0);
 out:
        if (needclose)
 out:
        if (needclose)
-               (void) closei(dev, IFBLK, ronly? FREAD : FREAD|FWRITE);
-       if (mp->m_fs) {
-               free((caddr_t)mp->m_fs, M_SUPERBLK);
-               mp->m_fs = NULL;
+               (void) VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE,
+                       (struct ucred *)0);
+       if (ump->um_fs) {
+               free((caddr_t)ump->um_fs, M_SUPERBLK);
+               ump->um_fs = NULL;
        }
        if (bp)
                brelse(bp);
        }
        if (bp)
                brelse(bp);
-       u.u_error = error ? error : EIO;                        /* XXX */
-       return ((struct fs *) NULL);
+       return (error);
 }
 
 }
 
-umount()
-{
-       struct a {
-               char    *fspec;
-       } *uap = (struct a *)u.u_ap;
 
 
-       u.u_error = unmount1(uap->fspec, 0);
-}
-
-unmount1(fname, forcibly)
-       caddr_t fname;
-       int forcibly;
+/*
+ * unmount system call
+ */
+ufs_unmount(mp, flags)
+       struct mount *mp;
+       int flags;
 {
 {
-       dev_t dev;
-       register struct mount *mp;
-       int error;
-       register struct inode *ip;
+       register struct ufsmount *ump;
        register struct fs *fs;
        register struct fs *fs;
+       dev_t dev;
+       int error, ronly;
 
 
-       forcibly = 0;                                   /* XXX */
-       forcibly = 0;                                   /* XXX */
-       error = getmdev(&dev, fname);
-       if (error)
-               return (error);
-       for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++)
-               if (mp->m_fs != NULL && dev == mp->m_dev)
-                       goto found;
-       return (EINVAL);
-found:
-       xumount(dev);   /* remove unused sticky files from text table */
-       nchinval(dev);  /* flush the name cache */
-       update();
+       if (flags & MNT_FORCE)
+               return (EINVAL);
+       ump = VFSTOUFS(mp);
+       dev = ump->um_dev;
 #ifdef QUOTA
        if ((error = iflush(dev, mp->m_qinod)) && !forcibly)
 #else
 #ifdef QUOTA
        if ((error = iflush(dev, mp->m_qinod)) && !forcibly)
 #else
@@ -278,40 +311,152 @@ found:
 #endif
                return (error);
 #ifdef QUOTA
 #endif
                return (error);
 #ifdef QUOTA
-       closedq(mp);
+       (void)closedq(ump);
        /*
         * Here we have to iflush again to get rid of the quota inode.
         * A drag, but it would be ugly to cheat, & this doesn't happen often.
         */
        (void)iflush(dev, (struct inode *)NULL);
 #endif
        /*
         * Here we have to iflush again to get rid of the quota inode.
         * A drag, but it would be ugly to cheat, & this doesn't happen often.
         */
        (void)iflush(dev, (struct inode *)NULL);
 #endif
-       ip = mp->m_inodp;
-       ip->i_flag &= ~IMOUNT;
-       fs = mp->m_fs;
+       fs = ump->um_fs;
+       ronly = !fs->fs_ronly;
        free((caddr_t)fs->fs_csp[0], M_SUPERBLK);
        free((caddr_t)fs->fs_csp[0], M_SUPERBLK);
-       free((caddr_t)mp->m_fs, M_SUPERBLK);
-       mp->m_fs = NULL;
-       mp->m_dev = NODEV;
-       mpurge(mp - &mount[0]);
        error = closei(dev, IFBLK, fs->fs_ronly? FREAD : FREAD|FWRITE);
        irele(ip);
        return (error);
 }
 
        error = closei(dev, IFBLK, fs->fs_ronly? FREAD : FREAD|FWRITE);
        irele(ip);
        return (error);
 }
 
-sbupdate(mp)
+/*
+ * Return root of a filesystem
+ */
+ufs_root(mp, vpp)
+       struct mount *mp;
+       struct vnode **vpp;
+{
+       struct inode tip, *ip;
+       int error;
+
+       tip.i_dev = VFSTOUFS(mp)->um_dev;
+       tip.i_vnode.v_mount = mp;
+       error = iget(&tip, (ino_t)ROOTINO, &ip);
+       if (error)
+               return (error);
+       *vpp = ITOV(ip);
+       return (0);
+}
+
+/*
+ * Get file system statistics.
+ */
+ufs_statfs(mp, sbp)
+       struct mount *mp;
+       register struct statfs *sbp;
+{
+       register struct ufsmount *ump;
+       register struct fs *fs;
+
+       ump = VFSTOUFS(mp);
+       fs = ump->um_fs;
+       if (fs->fs_magic != FS_MAGIC)
+               panic("ufs_statfs");
+       sbp->f_type = MOUNT_UFS;
+       sbp->f_flags = mp->m_flag &~ (M_MLOCK|M_MWAIT);
+       sbp->f_fsize = fs->fs_fsize;
+       sbp->f_bsize = fs->fs_bsize;
+       sbp->f_blocks = fs->fs_dsize;
+       sbp->f_bfree = fs->fs_cstotal.cs_nbfree * fs->fs_frag +
+               fs->fs_cstotal.cs_nffree;
+       sbp->f_bavail = (fs->fs_dsize * (100 - fs->fs_minfree) / 100) -
+               (fs->fs_dsize - sbp->f_bfree);
+       if (sbp->f_bavail < 0)
+               sbp->f_bavail = 0;
+       sbp->f_files =  fs->fs_ncg * fs->fs_ipg;
+       sbp->f_ffree = fs->fs_cstotal.cs_nifree;
+       sbp->f_fsid = mp->m_fsid;
+       bcopy((caddr_t)fs->fs_fsmnt, (caddr_t)&sbp->f_mntonname[0], MNAMELEN);
+       bcopy((caddr_t)ump->um_mntname, (caddr_t)&sbp->f_mntfromname[0],
+               MNAMELEN);
+       return (0);
+}
+
+int    syncprt = 0;
+
+/*
+ * Go through the disk queues to initiate sandbagged IO;
+ * go through the inodes to write those that have been modified;
+ * initiate the writing of the super block if it has been modified.
+ */
+ufs_sync(mp, waitfor)
        struct mount *mp;
        struct mount *mp;
+       int waitfor;
 {
 {
-       register struct fs *fs = mp->m_fs;
+       register struct inode *ip;
+       register struct ufsmount *ump = VFSTOUFS(mp);
+       register struct fs *fs;
+       int error = 0;
+       static int updlock = 0;
+
+       if (syncprt)
+               bufstats();
+       if (updlock)
+               return (EBUSY);
+       fs = ump->um_fs;
+       if (fs == (struct fs *)1)
+               return (0);
+       updlock++;
+       /*
+        * Write back modified superblock.
+        * Consistency check that the superblock
+        * is still in the buffer cache.
+        */
+       if (fs->fs_fmod != 0) {
+               if (fs->fs_ronly != 0) {                /* XXX */
+                       printf("fs = %s\n", fs->fs_fsmnt);
+                       panic("update: rofs mod");
+               }
+               fs->fs_fmod = 0;
+               fs->fs_time = time.tv_sec;
+               error = sbupdate(ump, waitfor);
+       }
+       /*
+        * Write back each (modified) inode.
+        */
+       for (ip = inode; ip < inodeNINODE; ip++) {
+               if (ip->i_devvp != ump->um_devvp ||
+                   (ip->i_flag & ILOCKED) != 0 || ITOV(ip)->v_count == 0 ||
+                   (ip->i_flag & (IMOD|IACC|IUPD|ICHG)) == 0)
+                       continue;
+               ip->i_flag |= ILOCKED;
+               ITOV(ip)->v_count++;
+               error = iupdat(ip, &time, &time, waitfor == MNT_WAIT);
+               iput(ip);
+       }
+       updlock = 0;
+       /*
+        * Force stale buffer cache information to be flushed.
+        */
+       bflush(ump->um_devvp->v_rdev);
+       return (error);
+}
+
+/*
+ * Write a superblock and associated information back to disk.
+ */
+sbupdate(mp, waitfor)
+       struct ufsmount *mp;
+       int waitfor;
+{
+       register struct fs *fs = mp->um_fs;
        register struct buf *bp;
        int blks;
        caddr_t space;
        register struct buf *bp;
        int blks;
        caddr_t space;
-       int i, size;
+       int i, size, error = 0;
 
 #ifdef SECSIZE
        bp = getblk(mp->m_dev, (daddr_t)fsbtodb(fs, SBOFF / fs->fs_fsize),
            (int)fs->fs_sbsize, fs->fs_dbsize);
 #else SECSIZE
 
 #ifdef SECSIZE
        bp = getblk(mp->m_dev, (daddr_t)fsbtodb(fs, SBOFF / fs->fs_fsize),
            (int)fs->fs_sbsize, fs->fs_dbsize);
 #else SECSIZE
-       bp = getblk(mp->m_dev, SBLOCK, (int)fs->fs_sbsize);
+       bp = getblk(mp->um_devvp, SBLOCK, (int)fs->fs_sbsize);
 #endif SECSIZE
        bcopy((caddr_t)fs, bp->b_un.b_addr, (u_int)fs->fs_sbsize);
        /* Restore compatibility to old file systems.              XXX */
 #endif SECSIZE
        bcopy((caddr_t)fs, bp->b_un.b_addr, (u_int)fs->fs_sbsize);
        /* Restore compatibility to old file systems.              XXX */
@@ -324,7 +469,10 @@ sbupdate(mp)
        bp->b_un.b_fs->fs_sparecon[0] = 0;
 #endif
 #endif SECSIZE
        bp->b_un.b_fs->fs_sparecon[0] = 0;
 #endif
 #endif SECSIZE
-       bwrite(bp);
+       if (waitfor == MNT_WAIT)
+               error = bwrite(bp);
+       else
+               bawrite(bp);
        blks = howmany(fs->fs_cssize, fs->fs_fsize);
        space = (caddr_t)fs->fs_csp[0];
        for (i = 0; i < blks; i += fs->fs_frag) {
        blks = howmany(fs->fs_cssize, fs->fs_fsize);
        space = (caddr_t)fs->fs_csp[0];
        for (i = 0; i < blks; i += fs->fs_frag) {
@@ -335,46 +483,118 @@ sbupdate(mp)
                bp = getblk(mp->m_dev, fsbtodb(fs, fs->fs_csaddr + i), size,
                    fs->fs_dbsize);
 #else SECSIZE
                bp = getblk(mp->m_dev, fsbtodb(fs, fs->fs_csaddr + i), size,
                    fs->fs_dbsize);
 #else SECSIZE
-               bp = getblk(mp->m_dev, fsbtodb(fs, fs->fs_csaddr + i), size);
+               bp = getblk(mp->um_devvp, fsbtodb(fs, fs->fs_csaddr + i), size);
 #endif SECSIZE
                bcopy(space, bp->b_un.b_addr, (u_int)size);
                space += size;
 #endif SECSIZE
                bcopy(space, bp->b_un.b_addr, (u_int)size);
                space += size;
-               bwrite(bp);
+               if (waitfor == MNT_WAIT)
+                       error = bwrite(bp);
+               else
+                       bawrite(bp);
        }
        }
+       return (error);
 }
 
 /*
 }
 
 /*
- * Common code for mount and umount.
+ * Print out statistics on the current allocation of the buffer pool.
+ * Can be enabled to print out on every ``sync'' by setting "syncprt"
+ * above.
+ */
+bufstats()
+{
+       int s, i, j, count;
+       register struct buf *bp, *dp;
+       int counts[MAXBSIZE/CLBYTES+1];
+       static char *bname[BQUEUES] = { "LOCKED", "LRU", "AGE", "EMPTY" };
+
+       for (bp = bfreelist, i = 0; bp < &bfreelist[BQUEUES]; bp++, i++) {
+               count = 0;
+               for (j = 0; j <= MAXBSIZE/CLBYTES; j++)
+                       counts[j] = 0;
+               s = splbio();
+               for (dp = bp->av_forw; dp != bp; dp = dp->av_forw) {
+                       counts[dp->b_bufsize/CLBYTES]++;
+                       count++;
+               }
+               splx(s);
+               printf("%s: total-%d", bname[i], count);
+               for (j = 0; j <= MAXBSIZE/CLBYTES; j++)
+                       if (counts[j] != 0)
+                               printf(", %d-%d", j * CLBYTES, counts[j]);
+               printf("\n");
+       }
+}
+
+/*
+ * File handle to vnode
+ */
+ufs_fhtovp(mp, fhp, vpp)
+       struct mount *mp;
+       struct fid *fhp;
+       struct vnode **vpp;
+{
+       register struct ufid *ufhp;
+       struct inode tip, *ip;
+       int error;
+
+       ufhp = (struct ufid *)fhp;
+       tip.i_dev = VFSTOUFS(mp)->um_dev;
+       tip.i_vnode.v_mount = mp;
+       if (error = iget(&tip, ufhp->ufid_ino, &ip)) {
+               *vpp = NULL;
+               return (error);
+       }
+       if (ip->i_gen != ufhp->ufid_gen) {
+               iput(ip);
+               *vpp = NULL;
+               return (EINVAL);
+       }
+       *vpp = ITOV(ip);
+       return (0);
+}
+
+/*
+ * Vnode pointer to File handle, should never happen.
+ */
+/* ARGSUSED */
+ufs_vptofh(mp, fhp, vpp)
+       struct mount *mp;
+       struct fid *fhp;
+       struct vnode **vpp;
+{
+
+       return (EINVAL);
+}
+
+/*
+ * Common code for mount and quota.
  * Check that the user's argument is a reasonable
  * thing on which to mount, and return the device number if so.
  */
  * Check that the user's argument is a reasonable
  * thing on which to mount, and return the device number if so.
  */
-getmdev(pdev, fname)
+getmdev(devvpp, fname, ndp)
+       struct vnode **devvpp;
        caddr_t fname;
        caddr_t fname;
-       dev_t *pdev;
+       register struct nameidata *ndp;
 {
 {
-       dev_t dev;
-       register struct inode *ip;
-       register struct nameidata *ndp = &u.u_nd;
+       register struct vnode *vp;
+       int error;
 
 
-       if (u.u_error = suser(u.u_cred, &u.u_acflag))
-               return (u.u_error);
-       ndp->ni_nameiop = LOOKUP | FOLLOW;
+       ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW;
        ndp->ni_segflg = UIO_USERSPACE;
        ndp->ni_dirp = fname;
        ndp->ni_segflg = UIO_USERSPACE;
        ndp->ni_dirp = fname;
-       ip = namei(ndp);
-       if (ip == NULL) {
-               if (u.u_error == ENOENT)
-                       return (ENODEV); /* needs translation */
-               return (u.u_error);
+       if (error = namei(ndp)) {
+               if (error == ENOENT)
+                       return (ENODEV);        /* needs translation */
+               return (error);
        }
        }
-       if ((ip->i_mode&IFMT) != IFBLK) {
-               iput(ip);
+       vp = ndp->ni_vp;
+       if (vp->v_type != VBLK) {
+               vput(vp);
                return (ENOTBLK);
        }
                return (ENOTBLK);
        }
-       dev = (dev_t)ip->i_rdev;
-       iput(ip);
-       if (major(dev) >= nblkdev)
+       if (major(vp->v_rdev) >= nblkdev)
                return (ENXIO);
                return (ENXIO);
-       *pdev = dev;
+       iunlock(VTOI(vp));
+       *devvpp = vp;
        return (0);
 }
        return (0);
 }
index 77b4d7f..9cbabfb 100644 (file)
 /*
 /*
- * Copyright (c) 1982, 1986 Regents of the University of California.
- * All rights reserved.  The Berkeley software License Agreement
- * specifies the terms and conditions for redistribution.
+ * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
+ * All rights reserved.
  *
  *
- *     @(#)lfs_vnops.c 7.6 (Berkeley) %G%
+ * 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.
+ *
+ *     @(#)lfs_vnops.c 7.7 (Berkeley) %G%
  */
 
 #include "param.h"
 #include "systm.h"
  */
 
 #include "param.h"
 #include "systm.h"
-#include "dir.h"
 #include "user.h"
 #include "kernel.h"
 #include "file.h"
 #include "stat.h"
 #include "user.h"
 #include "kernel.h"
 #include "file.h"
 #include "stat.h"
-#include "inode.h"
-#include "fs.h"
 #include "buf.h"
 #include "proc.h"
 #include "buf.h"
 #include "proc.h"
-#include "quota.h"
 #include "uio.h"
 #include "socket.h"
 #include "socketvar.h"
 #include "uio.h"
 #include "socket.h"
 #include "socketvar.h"
+#include "conf.h"
 #include "mount.h"
 #include "mount.h"
-
-extern struct fileops inodeops;
-struct file *getinode();
+#include "vnode.h"
+#include "../ufs/inode.h"
+#include "../ufs/fs.h"
+#include "../ufs/quota.h"
 
 /*
 
 /*
- * Change current working directory (``.'').
+ * Global vfs data structures for ufs
  */
  */
-chdir()
-{
 
 
-       chdirec(&u.u_cdir);
-}
+int    ufs_lookup(),
+       ufs_create(),
+       ufs_mknod(),
+       ufs_open(),
+       ufs_close(),
+       ufs_access(),
+       ufs_getattr(),
+       ufs_setattr(),
+       ufs_read(),
+       ufs_write(),
+       ufs_ioctl(),
+       ufs_select(),
+       ufs_mmap(),
+       ufs_fsync(),
+       ufs_seek(),
+       ufs_remove(),
+       ufs_link(),
+       ufs_rename(),
+       ufs_mkdir(),
+       ufs_rmdir(),
+       ufs_symlink(),
+       ufs_readdir(),
+       ufs_readlink(),
+       ufs_abortop(),
+       ufs_inactive(),
+       ufs_lock(),
+       ufs_unlock(),
+       ufs_bmap(),
+       ufs_strategy();
+
+struct vnodeops ufs_vnodeops = {
+       ufs_lookup,
+       ufs_create,
+       ufs_mknod,
+       ufs_open,
+       ufs_close,
+       ufs_access,
+       ufs_getattr,
+       ufs_setattr,
+       ufs_read,
+       ufs_write,
+       ufs_ioctl,
+       ufs_select,
+       ufs_mmap,
+       ufs_fsync,
+       ufs_seek,
+       ufs_remove,
+       ufs_link,
+       ufs_rename,
+       ufs_mkdir,
+       ufs_rmdir,
+       ufs_symlink,
+       ufs_readdir,
+       ufs_readlink,
+       ufs_abortop,
+       ufs_inactive,
+       ufs_lock,
+       ufs_unlock,
+       ufs_bmap,
+       ufs_strategy,
+};
+
+enum vtype iftovt_tab[8] = {
+       VNON, VCHR, VDIR, VBLK, VREG, VLNK, VSOCK, VBAD,
+};
+int    vttoif_tab[8] = {
+       0, IFREG, IFDIR, IFBLK, IFCHR, IFLNK, IFSOCK, IFMT,
+};
 
 /*
 
 /*
- * Change notion of root (``/'') directory.
+ * Create a regular file
  */
  */
-chroot()
+ufs_create(ndp, vap)
+       struct nameidata *ndp;
+       struct vattr *vap;
 {
 {
+       struct inode *ip;
+       int error;
 
 
-       if (u.u_error = suser(u.u_cred, &u.u_acflag))
-               return;
-       chdirec(&u.u_rdir);
+       if (error = maknode(MAKEIMODE(vap->va_type, vap->va_mode), ndp, &ip))
+               return (error);
+       ndp->ni_vp = ITOV(ip);
+       return (0);
 }
 
 /*
 }
 
 /*
- * Common routine for chroot and chdir.
+ * Mknod vnode call
  */
  */
-chdirec(ipp)
-       register struct inode **ipp;
+/* ARGSUSED */
+ufs_mknod(ndp, vap, cred)
+       struct nameidata *ndp;
+       struct ucred *cred;
+       struct vattr *vap;
 {
 {
-       register struct inode *ip;
-       struct a {
-               char    *fname;
-       } *uap = (struct a *)u.u_ap;
-       register struct nameidata *ndp = &u.u_nd;
-
-       ndp->ni_nameiop = LOOKUP | FOLLOW;
-       ndp->ni_segflg = UIO_USERSPACE;
-       ndp->ni_dirp = uap->fname;
-       ip = namei(ndp);
-       if (ip == NULL)
-               return;
-       if ((ip->i_mode&IFMT) != IFDIR) {
-               u.u_error = ENOTDIR;
-               goto bad;
-       }
-       if (access(ip, IEXEC))
-               goto bad;
-       IUNLOCK(ip);
-       if (*ipp)
-               irele(*ipp);
-       *ipp = ip;
-       return;
+       struct inode *ip;
+       int error;
 
 
-bad:
+       if (error = maknode(MAKEIMODE(vap->va_type, vap->va_mode), ndp, &ip))
+               return (error);
+       if (vap->va_rdev) {
+               /*
+                * Want to be able to use this to make badblock
+                * inodes, so don't truncate the dev number.
+                */
+               ITOV(ip)->v_rdev = ip->i_rdev = vap->va_rdev;
+               ip->i_flag |= IACC|IUPD|ICHG;
+       }
        iput(ip);
        iput(ip);
+       /*
+        * Remove inode so that it will be reloaded by iget and
+        * checked to see if it is an alias of an existing entry
+        * in the inode cache.
+        */
+       remque(ip);
+       ip->i_forw = ip;
+       ip->i_back = ip;
+       return (0);
 }
 
 /*
 }
 
 /*
- * Open system call.
+ * Open called.
+ *
+ * Nothing to do.
  */
  */
-open()
+/* ARGSUSED */
+ufs_open(vp, mode, cred)
+       struct vnode *vp;
+       int mode;
+       struct ucred *cred;
 {
 {
-       struct a {
-               char    *fname;
-               int     mode;
-               int     crtmode;
-       } *uap = (struct a *) u.u_ap;
 
 
-       copen(uap->mode-FOPEN, uap->crtmode, uap->fname);
+       return (0);
 }
 
 /*
 }
 
 /*
- * Creat system call.
+ * Close called
+ *
+ * Update the times on the inode.
  */
  */
-creat()
+/* ARGSUSED */
+ufs_close(vp, fflag, cred)
+       struct vnode *vp;
+       int fflag;
+       struct ucred *cred;
 {
 {
-       struct a {
-               char    *fname;
-               int     fmode;
-       } *uap = (struct a *)u.u_ap;
+       register struct inode *ip = VTOI(vp);
 
 
-       copen(FWRITE|FCREAT|FTRUNC, uap->fmode, uap->fname);
-}
-
-/*
- * Common code for open and creat.
- * Check permissions, allocate an open file structure,
- * and call the device open routine if any.
- */
-copen(mode, arg, fname)
-       register int mode;
-       int arg;
-       caddr_t fname;
-{
-       register struct inode *ip;
-       register struct file *fp;
-       register struct nameidata *ndp = &u.u_nd;
-       int indx;
-
-       fp = falloc();
-       if (fp == NULL)
-               return;
-       indx = u.u_r.r_val1;
-       ndp->ni_segflg = UIO_USERSPACE;
-       ndp->ni_dirp = fname;
-       if (mode&FCREAT) {
-               if (mode & FEXCL)
-                       ndp->ni_nameiop = CREATE;
-               else
-                       ndp->ni_nameiop = CREATE | FOLLOW;
-               ip = namei(ndp);
-               if (ip == NULL) {
-                       if (u.u_error)
-                               goto bad1;
-                       ip = maknode(arg&07777&(~ISVTX), ndp);
-                       if (ip == NULL)
-                               goto bad1;
-                       mode &= ~FTRUNC;
-               } else {
-                       if (mode&FEXCL) {
-                               u.u_error = EEXIST;
-                               goto bad;
-                       }
-                       mode &= ~FCREAT;
-               }
-       } else {
-               ndp->ni_nameiop = LOOKUP | FOLLOW;
-               ip = namei(ndp);
-               if (ip == NULL)
-                       goto bad1;
-       }
-       if ((ip->i_mode & IFMT) == IFSOCK) {
-               u.u_error = EOPNOTSUPP;
-               goto bad;
-       }
-       if ((mode&FCREAT) == 0) {
-               if (mode&FREAD)
-                       if (access(ip, IREAD))
-                               goto bad;
-               if (mode&(FWRITE|FTRUNC)) {
-                       if (access(ip, IWRITE))
-                               goto bad;
-                       if ((ip->i_mode&IFMT) == IFDIR) {
-                               u.u_error = EISDIR;
-                               goto bad;
-                       }
-               }
-       }
-       if (mode&FTRUNC)
-               itrunc(ip, (u_long)0);
-       IUNLOCK(ip);
-       fp->f_flag = mode&FMASK;
-       fp->f_type = DTYPE_INODE;
-       fp->f_ops = &inodeops;
-       fp->f_data = (caddr_t)ip;
-       if (setjmp(&u.u_qsave)) {
-               if (u.u_error == 0)
-                       u.u_error = EINTR;
-               u.u_ofile[indx] = NULL;
-               closef(fp);
-               return;
-       }
-       u.u_error = openi(ip, mode);
-       if (u.u_error == 0)
-               return;
-       ILOCK(ip);
-bad:
-       iput(ip);
-bad1:
-       u.u_ofile[indx] = NULL;
-       fp->f_count--;
+       if (vp->v_count > 1 && !(ip->i_flag & ILOCKED))
+               ITIMES(ip, &time, &time);
+       return (0);
 }
 
 }
 
-/*
- * Mknod system call
- */
-mknod()
+ufs_access(vp, mode, cred)
+       struct vnode *vp;
+       int mode;
+       struct ucred *cred;
 {
 {
-       register struct inode *ip;
-       register struct a {
-               char    *fname;
-               int     fmode;
-               int     dev;
-       } *uap = (struct a *)u.u_ap;
-       register struct nameidata *ndp = &u.u_nd;
-
-       if (u.u_error = suser(u.u_cred, &u.u_acflag))
-               return;
-       ndp->ni_nameiop = CREATE;
-       ndp->ni_segflg = UIO_USERSPACE;
-       ndp->ni_dirp = uap->fname;
-       ip = namei(ndp);
-       if (ip != NULL) {
-               u.u_error = EEXIST;
-               goto out;
-       }
-       if (u.u_error)
-               return;
-       ip = maknode(uap->fmode, ndp);
-       if (ip == NULL)
-               return;
-       switch (ip->i_mode & IFMT) {
-
-       case IFMT:      /* used by badsect to flag bad sectors */
-       case IFCHR:
-       case IFBLK:
-               if (uap->dev) {
-                       /*
-                        * Want to be able to use this to make badblock
-                        * inodes, so don't truncate the dev number.
-                        */
-                       ip->i_rdev = uap->dev;
-                       ip->i_flag |= IACC|IUPD|ICHG;
-               }
-       }
 
 
-out:
-       iput(ip);
+       return (iaccess(VTOI(vp), mode, cred));
 }
 
 }
 
-/*
- * link system call
- */
-link()
+/* ARGSUSED */
+ufs_getattr(vp, vap, cred)
+       struct vnode *vp;
+       register struct vattr *vap;
+       struct ucred *cred;
 {
 {
-       register struct inode *ip, *xp;
-       register struct a {
-               char    *target;
-               char    *linkname;
-       } *uap = (struct a *)u.u_ap;
-       register struct nameidata *ndp = &u.u_nd;
-
-       ndp->ni_nameiop = LOOKUP | FOLLOW;
-       ndp->ni_segflg = UIO_USERSPACE;
-       ndp->ni_dirp = uap->target;
-       ip = namei(ndp);        /* well, this routine is doomed anyhow */
-       if (ip == NULL)
-               return;
-       if ((ip->i_mode&IFMT) == IFDIR &&
-           (u.u_error = suser(u.u_cred, &u.u_acflag))) {
-               iput(ip);
-               return;
-       }
-       if (ip->i_nlink == LINK_MAX - 1) {
-               u.u_error = EMLINK;
-               iput(ip);
-               return;
-       }
-       ip->i_nlink++;
-       ip->i_flag |= ICHG;
-       iupdat(ip, &time, &time, 1);
-       IUNLOCK(ip);
-       ndp->ni_nameiop = CREATE;
-       ndp->ni_segflg = UIO_USERSPACE;
-       ndp->ni_dirp = (caddr_t)uap->linkname;
-       xp = namei(ndp);
-       if (xp != NULL) {
-               u.u_error = EEXIST;
-               iput(xp);
-               goto out;
-       }
-       if (u.u_error)
-               goto out;
-       if (ndp->ni_pdir->i_dev != ip->i_dev) {
-               iput(ndp->ni_pdir);
-               u.u_error = EXDEV;
-               goto out;
-       }
-       u.u_error = direnter(ip, ndp);
-out:
-       if (u.u_error) {
-               ip->i_nlink--;
-               ip->i_flag |= ICHG;
-       }
-       irele(ip);
-}
-
-/*
- * symlink -- make a symbolic link
- */
-symlink()
-{
-       register struct a {
-               char    *target;
-               char    *linkname;
-       } *uap = (struct a *)u.u_ap;
-       register struct inode *ip;
-       register char *tp;
-       register c, nc;
-       register struct nameidata *ndp = &u.u_nd;
-
-       tp = uap->target;
-       nc = 0;
-       while (c = fubyte(tp)) {
-               if (c < 0) {
-                       u.u_error = EFAULT;
-                       return;
-               }
-               tp++;
-               nc++;
-       }
-       ndp->ni_nameiop = CREATE;
-       ndp->ni_segflg = UIO_USERSPACE;
-       ndp->ni_dirp = uap->linkname;
-       ip = namei(ndp);
-       if (ip) {
-               iput(ip);
-               u.u_error = EEXIST;
-               return;
-       }
-       if (u.u_error)
-               return;
-       ip = maknode(IFLNK | 0777, ndp);
-       if (ip == NULL)
-               return;
-       u.u_error = rdwri(UIO_WRITE, ip, uap->target, nc, (off_t)0, 0,
-           (int *)0);
-       /* handle u.u_error != 0 */
-       iput(ip);
-}
+       register struct inode *ip = VTOI(vp);
 
 
-/*
- * Unlink system call.
- * Hard to avoid races here, especially
- * in unlinking directories.
- */
-unlink()
-{
-       struct a {
-               char    *fname;
-       } *uap = (struct a *)u.u_ap;
-       register struct inode *ip, *dp;
-       register struct nameidata *ndp = &u.u_nd;
-
-       ndp->ni_nameiop = DELETE | LOCKPARENT;
-       ndp->ni_segflg = UIO_USERSPACE;
-       ndp->ni_dirp = uap->fname;
-       ip = namei(ndp);
-       if (ip == NULL)
-               return;
-       dp = ndp->ni_pdir;
-       if ((ip->i_mode&IFMT) == IFDIR &&
-           (u.u_error = suser(u.u_cred, &u.u_acflag)))
-               goto out;
+       ITIMES(ip, &time, &time);
        /*
        /*
-        * Don't unlink a mounted file.
+        * Copy from inode table
         */
         */
-       if (ip->i_dev != dp->i_dev) {
-               u.u_error = EBUSY;
-               goto out;
-       }
-       if (ip->i_flag&ITEXT)
-               xrele(ip);      /* try once to free text */
-       if (dirremove(ndp)) {
-               ip->i_nlink--;
-               ip->i_flag |= ICHG;
-       }
-out:
-       if (dp == ip)
-               irele(ip);
+       vap->va_fsid = ip->i_dev;
+       vap->va_fileid = ip->i_number;
+       vap->va_mode = ip->i_mode & ~IFMT;
+       vap->va_nlink = ip->i_nlink;
+       vap->va_uid = ip->i_uid;
+       vap->va_gid = ip->i_gid;
+       vap->va_rdev = (dev_t)ip->i_rdev;
+       vap->va_size = ip->i_ic.ic_size.val[0];
+       vap->va_size1 = ip->i_ic.ic_size.val[1];
+       vap->va_atime.tv_sec = ip->i_atime;
+       vap->va_mtime.tv_sec = ip->i_mtime;
+       vap->va_ctime.tv_sec = ip->i_ctime;
+       /* this doesn't belong here */
+       if (vp->v_type == VBLK)
+               vap->va_blocksize = BLKDEV_IOSIZE;
+       else if (vp->v_type == VCHR)
+               vap->va_blocksize = MAXBSIZE;
        else
        else
-               iput(ip);
-       iput(dp);
+               vap->va_blocksize = ip->i_fs->fs_bsize;
+       /*
+        * XXX THIS IS NOT CORRECT!!, but be sure to change vn_stat()
+        * if you change it.
+        */
+       vap->va_bytes = ip->i_blocks;
+       vap->va_bytes1 = -1;
+       vap->va_type = vp->v_type;
+       return (0);
 }
 
 /*
 }
 
 /*
- * Seek system call
+ * Set attribute vnode op. called from several syscalls
  */
  */
-lseek()
+ufs_setattr(vp, vap, cred)
+       register struct vnode *vp;
+       register struct vattr *vap;
+       register struct ucred *cred;
 {
 {
-       register struct file *fp;
-       register struct a {
-               int     fd;
-               off_t   off;
-               int     sbase;
-       } *uap = (struct a *)u.u_ap;
-
-       GETF(fp, uap->fd);
-       if (fp->f_type != DTYPE_INODE) {
-               u.u_error = ESPIPE;
-               return;
-       }
-       switch (uap->sbase) {
-
-       case L_INCR:
-               fp->f_offset += uap->off;
-               break;
-
-       case L_XTND:
-               fp->f_offset = uap->off + ((struct inode *)fp->f_data)->i_size;
-               break;
-
-       case L_SET:
-               fp->f_offset = uap->off;
-               break;
+       register struct inode *ip = VTOI(vp);
+       int error = 0;
 
 
-       default:
-               u.u_error = EINVAL;
-               return;
+       /*
+        * Check for unsetable attributes.
+        */
+       if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) ||
+           (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) ||
+           (vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) ||
+           ((int)vap->va_bytes != VNOVAL)) {
+               return (EINVAL);
        }
        }
-       u.u_r.r_off = fp->f_offset;
-}
-
-/*
- * Access system call
- */
-saccess()
-{
-       register svuid, svgid;
-       register struct inode *ip;
-       register struct a {
-               char    *fname;
-               int     fmode;
-       } *uap = (struct a *)u.u_ap;
-       register struct nameidata *ndp = &u.u_nd;
-
-       svuid = u.u_uid;
-       svgid = u.u_gid;
-       u.u_uid = u.u_ruid;
-       u.u_gid = u.u_rgid;
-       ndp->ni_nameiop = LOOKUP | FOLLOW;
-       ndp->ni_segflg = UIO_USERSPACE;
-       ndp->ni_dirp = uap->fname;
-       ip = namei(ndp);
-       if (ip != NULL) {
-               if ((uap->fmode&R_OK) && access(ip, IREAD))
-                       goto done;
-               if ((uap->fmode&W_OK) && access(ip, IWRITE))
-                       goto done;
-               if ((uap->fmode&X_OK) && access(ip, IEXEC))
-                       goto done;
-done:
-               iput(ip);
+       /*
+        * Go through the fields and update iff not VNOVAL.
+        */
+       if (vap->va_uid != (u_short)VNOVAL || vap->va_gid != (u_short)VNOVAL)
+               if (error = chown1(vp, vap->va_uid, vap->va_gid, cred))
+                       return (error);
+       if (vap->va_size != VNOVAL) {
+               if (vp->v_type == VDIR)
+                       return (EISDIR);
+               if (error = iaccess(ip, IWRITE, cred))
+                       return (error);
+               if (error = itrunc(ip, vap->va_size))
+                       return (error);
        }
        }
-       u.u_uid = svuid;
-       u.u_gid = svgid;
-}
-
-/*
- * Stat system call.  This version follows links.
- */
-stat()
-{
-
-       stat1(FOLLOW);
-}
-
-/*
- * Lstat system call.  This version does not follow links.
- */
-lstat()
-{
-
-       stat1(NOFOLLOW);
-}
-
-stat1(follow)
-       int follow;
-{
-       register struct inode *ip;
-       register struct a {
-               char    *fname;
-               struct stat *ub;
-       } *uap = (struct a *)u.u_ap;
-       struct stat sb;
-       register struct nameidata *ndp = &u.u_nd;
-
-       ndp->ni_nameiop = LOOKUP | follow;
-       ndp->ni_segflg = UIO_USERSPACE;
-       ndp->ni_dirp = uap->fname;
-       ip = namei(ndp);
-       if (ip == NULL)
-               return;
-       (void) ino_stat(ip, &sb);
-       iput(ip);
-       u.u_error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
-}
-
-/*
- * Return target name of a symbolic link
- */
-readlink()
-{
-       register struct inode *ip;
-       register struct a {
-               char    *name;
-               char    *buf;
-               int     count;
-       } *uap = (struct a *)u.u_ap;
-       register struct nameidata *ndp = &u.u_nd;
-       int resid;
-
-       ndp->ni_nameiop = LOOKUP;
-       ndp->ni_segflg = UIO_USERSPACE;
-       ndp->ni_dirp = uap->name;
-       ip = namei(ndp);
-       if (ip == NULL)
-               return;
-       if ((ip->i_mode&IFMT) != IFLNK) {
-               u.u_error = EINVAL;
-               goto out;
+       /*
+        * Check whether the following attributes can be changed.
+        */
+       if (cred->cr_uid != ip->i_uid &&
+           (error = suser(cred, &u.u_acflag)))
+               return (error);
+       if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) {
+               if (vap->va_atime.tv_sec != VNOVAL)
+                       ip->i_flag |= IACC;
+               if (vap->va_mtime.tv_sec != VNOVAL)
+                       ip->i_flag |= IUPD;
+               ip->i_flag |= ICHG;
+               if (error = iupdat(ip, &vap->va_atime, &vap->va_mtime, 1))
+                       return (error);
        }
        }
-       u.u_error = rdwri(UIO_READ, ip, uap->buf, uap->count, (off_t)0, 0,
-           &resid);
-out:
-       iput(ip);
-       u.u_r.r_val1 = uap->count - resid;
-}
-
-/*
- * Change mode of a file given path name.
- */
-chmod()
-{
-       struct inode *ip;
-       struct a {
-               char    *fname;
-               int     fmode;
-       } *uap = (struct a *)u.u_ap;
-
-       if ((ip = owner(uap->fname, FOLLOW)) == NULL)
-               return;
-       u.u_error = chmod1(ip, uap->fmode);
-       iput(ip);
-}
-
-/*
- * Change mode of a file given a file descriptor.
- */
-fchmod()
-{
-       struct a {
-               int     fd;
-               int     fmode;
-       } *uap = (struct a *)u.u_ap;
-       register struct inode *ip;
-       register struct file *fp;
-
-       fp = getinode(uap->fd);
-       if (fp == NULL)
-               return;
-       ip = (struct inode *)fp->f_data;
-       if (u.u_uid != ip->i_uid &&
-           (u.u_error = suser(u.u_cred, &u.u_acflag)))
-               return;
-       ILOCK(ip);
-       u.u_error = chmod1(ip, uap->fmode);
-       IUNLOCK(ip);
+       if (vap->va_mode != (u_short)VNOVAL)
+               error = chmod1(vp, (int)vap->va_mode, cred);
+       return (error);
 }
 
 /*
  * Change the mode on a file.
  * Inode must be locked before calling.
  */
 }
 
 /*
  * Change the mode on a file.
  * Inode must be locked before calling.
  */
-chmod1(ip, mode)
-       register struct inode *ip;
+chmod1(vp, mode, cred)
+       register struct vnode *vp;
        register int mode;
        register int mode;
+       struct ucred *cred;
 {
 {
+       register struct inode *ip = VTOI(vp);
 
 
-       if (ip->i_fs->fs_ronly)
-               return (EROFS);
        ip->i_mode &= ~07777;
        ip->i_mode &= ~07777;
-       if (u.u_uid) {
-               if ((ip->i_mode & IFMT) != IFDIR)
+       if (cred->cr_uid) {
+               if (vp->v_type != VDIR)
                        mode &= ~ISVTX;
                        mode &= ~ISVTX;
-               if (!groupmember(ip->i_gid))
+               if (!groupmember(ip->i_gid, cred))
                        mode &= ~ISGID;
        }
                        mode &= ~ISGID;
        }
-       ip->i_mode |= mode&07777;
+       ip->i_mode |= mode & 07777;
        ip->i_flag |= ICHG;
        ip->i_flag |= ICHG;
-       if (ip->i_flag&ITEXT && (ip->i_mode&ISVTX)==0)
-               xrele(ip);
+       if ((vp->v_flag & VTEXT) && (ip->i_mode & ISVTX) == 0)
+               xrele(vp);
        return (0);
 }
 
        return (0);
 }
 
-/*
- * Set ownership given a path name.
- */
-chown()
-{
-       struct inode *ip;
-       struct a {
-               char    *fname;
-               int     uid;
-               int     gid;
-       } *uap = (struct a *)u.u_ap;
-       register struct nameidata *ndp = &u.u_nd;
-
-       ndp->ni_nameiop = LOOKUP | NOFOLLOW;
-       ndp->ni_segflg = UIO_USERSPACE;
-       ndp->ni_dirp = uap->fname;
-       ip = namei(ndp);
-       if (ip == NULL)
-               return;
-       u.u_error = chown1(ip, uap->uid, uap->gid);
-       iput(ip);
-}
-
-/*
- * Set ownership given a file descriptor.
- */
-fchown()
-{
-       struct a {
-               int     fd;
-               int     uid;
-               int     gid;
-       } *uap = (struct a *)u.u_ap;
-       register struct inode *ip;
-       register struct file *fp;
-
-       fp = getinode(uap->fd);
-       if (fp == NULL)
-               return;
-       ip = (struct inode *)fp->f_data;
-       ILOCK(ip);
-       u.u_error = chown1(ip, uap->uid, uap->gid);
-       IUNLOCK(ip);
-}
-
 /*
  * Perform chown operation on inode ip;
  * inode must be locked prior to call.
  */
 /*
  * Perform chown operation on inode ip;
  * inode must be locked prior to call.
  */
-chown1(ip, uid, gid)
-       register struct inode *ip;
-       int uid, gid;
+chown1(vp, uid, gid, cred)
+       register struct vnode *vp;
+       uid_t uid;
+       gid_t gid;
+       struct ucred *cred;
 {
 {
+       register struct inode *ip = VTOI(vp);
 #ifdef QUOTA
        register long change;
 #endif
 #ifdef QUOTA
        register long change;
 #endif
+       int error;
 
 
-       if (ip->i_fs->fs_ronly)
-               return (EROFS);
-       if (uid == -1)
+       if (uid == (u_short)VNOVAL)
                uid = ip->i_uid;
                uid = ip->i_uid;
-       if (gid == -1)
+       if (gid == (u_short)VNOVAL)
                gid = ip->i_gid;
        /*
         * If we don't own the file, are trying to change the owner
         * of the file, or are not a member of the target group,
         * the caller must be superuser or the call fails.
         */
                gid = ip->i_gid;
        /*
         * If we don't own the file, are trying to change the owner
         * of the file, or are not a member of the target group,
         * the caller must be superuser or the call fails.
         */
-       if ((u.u_uid != ip->i_uid || uid != ip->i_uid ||
-           !groupmember((gid_t)gid)) &&
-           (u.u_error = suser(u.u_cred, &u.u_acflag)))
-               return (u.u_error);
+       if ((cred->cr_uid != ip->i_uid || uid != ip->i_uid ||
+           !groupmember((gid_t)gid, cred)) &&
+           (error = suser(cred, &u.u_acflag)))
+               return (error);
 #ifdef QUOTA
        if (ip->i_uid == uid)           /* this just speeds things a little */
                change = 0;
 #ifdef QUOTA
        if (ip->i_uid == uid)           /* this just speeds things a little */
                change = 0;
@@ -682,7 +361,7 @@ chown1(ip, uid, gid)
        ip->i_uid = uid;
        ip->i_gid = gid;
        ip->i_flag |= ICHG;
        ip->i_uid = uid;
        ip->i_gid = gid;
        ip->i_flag |= ICHG;
-       if (u.u_ruid != 0)
+       if (cred->cr_ruid != 0)
                ip->i_mode &= ~(ISUID|ISGID);
 #ifdef QUOTA
        ip->i_dquot = inoquota(ip);
                ip->i_mode &= ~(ISUID|ISGID);
 #ifdef QUOTA
        ip->i_dquot = inoquota(ip);
@@ -694,113 +373,135 @@ chown1(ip, uid, gid)
 #endif
 }
 
 #endif
 }
 
-utimes()
+/* ARGSUSED */
+ufs_ioctl(vp, com, data, fflag, cred)
+       struct vnode *vp;
+       int com;
+       caddr_t data;
+       int fflag;
+       struct ucred *cred;
 {
 {
-       register struct a {
-               char    *fname;
-               struct  timeval *tptr;
-       } *uap = (struct a *)u.u_ap;
-       register struct inode *ip;
-       struct timeval tv[2];
 
 
-       if ((ip = owner(uap->fname, FOLLOW)) == NULL)
-               return;
-       if (ip->i_fs->fs_ronly) {
-               u.u_error = EROFS;
-               iput(ip);
-               return;
-       }
-       u.u_error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv));
-       if (u.u_error == 0) {
-               ip->i_flag |= IACC|IUPD|ICHG;
-               iupdat(ip, &tv[0], &tv[1], 0);
-       }
-       iput(ip);
+       printf("ufs_ioctl called with type %d\n", vp->v_type);
+       return (ENOTTY);
+}
+
+/* ARGSUSED */
+ufs_select(vp, which, cred)
+       struct vnode *vp;
+       int which;
+       struct ucred *cred;
+{
+
+       printf("ufs_select called with type %d\n", vp->v_type);
+       return (1);             /* XXX */
 }
 
 /*
 }
 
 /*
- * Flush any pending I/O.
+ * Mmap a file
+ *
+ * NB Currently unsupported.
  */
  */
-sync()
+/* ARGSUSED */
+ufs_mmap(vp, fflags, cred)
+       struct vnode *vp;
+       int fflags;
+       struct ucred *cred;
 {
 
 {
 
-       update();
+       return (EINVAL);
 }
 
 /*
 }
 
 /*
- * Truncate a file given its path name.
+ * Synch an open file.
  */
  */
-truncate()
+/* ARGSUSED */
+ufs_fsync(vp, fflags, cred)
+       struct vnode *vp;
+       int fflags;
+       struct ucred *cred;
 {
 {
-       struct a {
-               char    *fname;
-               off_t   length;
-       } *uap = (struct a *)u.u_ap;
-       struct inode *ip;
-       register struct nameidata *ndp = &u.u_nd;
-
-       ndp->ni_nameiop = LOOKUP | FOLLOW;
-       ndp->ni_segflg = UIO_USERSPACE;
-       ndp->ni_dirp = uap->fname;
-       ip = namei(ndp);
-       if (ip == NULL)
-               return;
-       if (access(ip, IWRITE))
-               goto bad;
-       if ((ip->i_mode&IFMT) == IFDIR) {
-               u.u_error = EISDIR;
-               goto bad;
-       }
-       itrunc(ip, (u_long)uap->length);
-bad:
-       iput(ip);
+       register struct inode *ip = VTOI(vp);
+       int error;
+
+       ILOCK(ip);
+       if (fflags&FWRITE)
+               ip->i_flag |= ICHG;
+       error = syncip(ip);
+       IUNLOCK(ip);
+       return (error);
 }
 
 /*
 }
 
 /*
- * Truncate a file given a file descriptor.
+ * Seek on a file
+ *
+ * Nothing to do, so just return.
  */
  */
-ftruncate()
+/* ARGSUSED */
+ufs_seek(vp, oldoff, newoff, cred)
+       struct vnode *vp;
+       off_t oldoff, newoff;
+       struct ucred *cred;
 {
 {
-       struct a {
-               int     fd;
-               off_t   length;
-       } *uap = (struct a *)u.u_ap;
-       struct inode *ip;
-       struct file *fp;
-
-       fp = getinode(uap->fd);
-       if (fp == NULL)
-               return;
-       if ((fp->f_flag&FWRITE) == 0) {
-               u.u_error = EINVAL;
-               return;
+
+       return (0);
+}
+
+/*
+ * ufs remove
+ * Hard to avoid races here, especially
+ * in unlinking directories.
+ */
+ufs_remove(ndp)
+       struct nameidata *ndp;
+{
+       register struct inode *ip, *dp;
+       int error;
+
+       ip = VTOI(ndp->ni_vp);
+       dp = VTOI(ndp->ni_dvp);
+       error = dirremove(ndp);
+       if (!error) {
+               ip->i_nlink--;
+               ip->i_flag |= ICHG;
        }
        }
-       ip = (struct inode *)fp->f_data;
-       ILOCK(ip);
-       itrunc(ip, (u_long)uap->length);
-       IUNLOCK(ip);
+       if (dp == ip)
+               vrele(ITOV(ip));
+       else
+               iput(ip);
+       iput(dp);
+       return (error);
 }
 
 /*
 }
 
 /*
- * Synch an open file.
+ * link vnode call
  */
  */
-fsync()
+ufs_link(vp, ndp)
+       register struct vnode *vp;
+       register struct nameidata *ndp;
 {
 {
-       struct a {
-               int     fd;
-       } *uap = (struct a *)u.u_ap;
-       struct inode *ip;
-       struct file *fp;
+       register struct inode *ip = VTOI(vp);
+       int error;
 
 
-       fp = getinode(uap->fd);
-       if (fp == NULL)
-               return;
-       ip = (struct inode *)fp->f_data;
-       ILOCK(ip);
-       if (fp->f_flag&FWRITE)
+       if (ndp->ni_dvp != vp)
+               ILOCK(ip);
+       if (ip->i_nlink == LINK_MAX - 1) {
+               error = EMLINK;
+               goto out;
+       }
+       ip->i_nlink++;
+       ip->i_flag |= ICHG;
+       error = iupdat(ip, &time, &time, 1);
+       if (!error)
+               error = direnter(ip, ndp);
+out:
+       if (ndp->ni_dvp != vp)
+               IUNLOCK(ip);
+       if (error) {
+               ip->i_nlink--;
                ip->i_flag |= ICHG;
                ip->i_flag |= ICHG;
-       syncip(ip);
-       IUNLOCK(ip);
+       }
+       return (error);
 }
 
 /*
 }
 
 /*
@@ -817,7 +518,7 @@ fsync()
  * Basic algorithm is:
  *
  * 1) Bump link count on source while we're linking it to the
  * Basic algorithm is:
  *
  * 1) Bump link count on source while we're linking it to the
- *    target.  This also insure the inode won't be deleted out
+ *    target.  This also ensure the inode won't be deleted out
  *    from underneath us while we work (it may be truncated by
  *    a concurrent `trunc' or `open' for creation).
  * 2) Link source to destination.  If destination already exists,
  *    from underneath us while we work (it may be truncated by
  *    a concurrent `trunc' or `open' for creation).
  * 2) Link source to destination.  If destination already exists,
@@ -826,52 +527,36 @@ fsync()
  *    directory was moved and the parent of the destination
  *    is different from the source, patch the ".." entry in the
  *    directory.
  *    directory was moved and the parent of the destination
  *    is different from the source, patch the ".." entry in the
  *    directory.
- *
- * Source and destination must either both be directories, or both
- * not be directories.  If target is a directory, it must be empty.
  */
  */
-rename()
+ufs_rename(fndp, tndp)
+       register struct nameidata *fndp, *tndp;
 {
 {
-       struct a {
-               char    *from;
-               char    *to;
-       } *uap = (struct a *)u.u_ap;
        register struct inode *ip, *xp, *dp;
        struct dirtemplate dirbuf;
        int doingdirectory = 0, oldparent = 0, newparent = 0;
        register struct inode *ip, *xp, *dp;
        struct dirtemplate dirbuf;
        int doingdirectory = 0, oldparent = 0, newparent = 0;
-       register struct nameidata *ndp = &u.u_nd;
        int error = 0;
 
        int error = 0;
 
-       ndp->ni_nameiop = DELETE | LOCKPARENT;
-       ndp->ni_segflg = UIO_USERSPACE;
-       ndp->ni_dirp = uap->from;
-       ip = namei(ndp);
-       if (ip == NULL)
-               return;
-       dp = ndp->ni_pdir;
+       dp = VTOI(fndp->ni_dvp);
+       ip = VTOI(fndp->ni_vp);
+       ILOCK(ip);
        if ((ip->i_mode&IFMT) == IFDIR) {
        if ((ip->i_mode&IFMT) == IFDIR) {
-               register struct direct *d;
+               register struct direct *d = &fndp->ni_dent;
 
 
-               d = &ndp->ni_dent;
                /*
                 * Avoid ".", "..", and aliases of "." for obvious reasons.
                 */
                /*
                 * Avoid ".", "..", and aliases of "." for obvious reasons.
                 */
-               if ((d->d_namlen == 1 && d->d_name[0] == '.') ||
-                   (d->d_namlen == 2 && bcmp(d->d_name, "..", 2) == 0) ||
-                   (dp == ip) || (ip->i_flag & IRENAME)) {
-                       iput(dp);
-                       if (dp == ip)
-                               irele(ip);
-                       else
-                               iput(ip);
-                       u.u_error = EINVAL;
-                       return;
+               if ((d->d_namlen == 1 && d->d_name[0] == '.') || dp == ip ||
+                   fndp->ni_isdotdot || (ip->i_flag & IRENAME)) {
+                       IUNLOCK(ip);
+                       ufs_abortop(fndp);
+                       ufs_abortop(tndp);
+                       return (EINVAL);
                }
                ip->i_flag |= IRENAME;
                oldparent = dp->i_number;
                doingdirectory++;
        }
                }
                ip->i_flag |= IRENAME;
                oldparent = dp->i_number;
                doingdirectory++;
        }
-       iput(dp);
+       vrele(fndp->ni_dvp);
 
        /*
         * 1) Bump link count while we're moving stuff
 
        /*
         * 1) Bump link count while we're moving stuff
@@ -881,21 +566,17 @@ rename()
         */
        ip->i_nlink++;
        ip->i_flag |= ICHG;
         */
        ip->i_nlink++;
        ip->i_flag |= ICHG;
-       iupdat(ip, &time, &time, 1);
+       error = iupdat(ip, &time, &time, 1);
        IUNLOCK(ip);
 
        /*
         * When the target exists, both the directory
        IUNLOCK(ip);
 
        /*
         * When the target exists, both the directory
-        * and target inodes are returned locked.
+        * and target vnodes are returned locked.
         */
         */
-       ndp->ni_nameiop = CREATE | LOCKPARENT | NOCACHE;
-       ndp->ni_dirp = (caddr_t)uap->to;
-       xp = namei(ndp);
-       if (u.u_error) {
-               error = u.u_error;
-               goto out;
-       }
-       dp = ndp->ni_pdir;
+       dp = VTOI(tndp->ni_dvp);
+       xp = NULL;
+       if (tndp->ni_vp)
+               xp = VTOI(tndp->ni_vp);
        /*
         * If ".." must be changed (ie the directory gets a new
         * parent) then the source directory must not be in the
        /*
         * If ".." must be changed (ie the directory gets a new
         * parent) then the source directory must not be in the
@@ -909,21 +590,21 @@ rename()
        if (oldparent != dp->i_number)
                newparent = dp->i_number;
        if (doingdirectory && newparent) {
        if (oldparent != dp->i_number)
                newparent = dp->i_number;
        if (doingdirectory && newparent) {
-               if (access(ip, IWRITE))
+               if (error = iaccess(ip, IWRITE, tndp->ni_cred))
                        goto bad;
                        goto bad;
+               tndp->ni_nameiop = RENAME | LOCKPARENT | LOCKLEAF | NOCACHE;
                do {
                do {
-                       dp = ndp->ni_pdir;
+                       dp = VTOI(tndp->ni_dvp);
                        if (xp != NULL)
                        if (xp != NULL)
-                               iput(xp);
-                       u.u_error = checkpath(ip, dp);
-                       if (u.u_error)
+                               vput(ITOV(xp));
+                       if (error = checkpath(ip, dp, tndp->ni_cred))
                                goto out;
                                goto out;
-                       xp = namei(ndp);
-                       if (u.u_error) {
-                               error = u.u_error;
+                       if (error = namei(tndp))
                                goto out;
                                goto out;
-                       }
-               } while (dp != ndp->ni_pdir);
+                       xp = NULL;
+                       if (tndp->ni_vp)
+                               xp = VTOI(tndp->ni_vp);
+               } while (dp != VTOI(tndp->ni_dvp));
        }
        /*
         * 2) If target doesn't exist, link the target
        }
        /*
         * 2) If target doesn't exist, link the target
@@ -933,10 +614,8 @@ rename()
         *    expunge the original entry's existence.
         */
        if (xp == NULL) {
         *    expunge the original entry's existence.
         */
        if (xp == NULL) {
-               if (dp->i_dev != ip->i_dev) {
-                       error = EXDEV;
-                       goto bad;
-               }
+               if (dp->i_dev != ip->i_dev)
+                       panic("rename: EXDEV");
                /*
                 * Account for ".." in new directory.
                 * When source and destination have the same
                /*
                 * Account for ".." in new directory.
                 * When source and destination have the same
@@ -945,29 +624,27 @@ rename()
                if (doingdirectory && newparent) {
                        dp->i_nlink++;
                        dp->i_flag |= ICHG;
                if (doingdirectory && newparent) {
                        dp->i_nlink++;
                        dp->i_flag |= ICHG;
-                       iupdat(dp, &time, &time, 1);
+                       error = iupdat(dp, &time, &time, 1);
                }
                }
-               error = direnter(ip, ndp);
-               if (error)
+               if (error = direnter(ip, tndp))
                        goto out;
        } else {
                        goto out;
        } else {
-               if (xp->i_dev != dp->i_dev || xp->i_dev != ip->i_dev) {
-                       error = EXDEV;
-                       goto bad;
-               }
+               if (xp->i_dev != dp->i_dev || xp->i_dev != ip->i_dev)
+                       panic("rename: EXDEV");
                /*
                 * Short circuit rename(foo, foo).
                 */
                if (xp->i_number == ip->i_number)
                /*
                 * Short circuit rename(foo, foo).
                 */
                if (xp->i_number == ip->i_number)
-                       goto bad;
+                       panic("rename: same file");
                /*
                 * If the parent directory is "sticky", then the user must
                 * own the parent directory, or the destination of the rename,
                 * otherwise the destination may not be changed (except by
                 * root). This implements append-only directories.
                 */
                /*
                 * If the parent directory is "sticky", then the user must
                 * own the parent directory, or the destination of the rename,
                 * otherwise the destination may not be changed (except by
                 * root). This implements append-only directories.
                 */
-               if ((dp->i_mode & ISVTX) && u.u_uid != 0 &&
-                   u.u_uid != dp->i_uid && xp->i_uid != u.u_uid) {
+               if ((dp->i_mode & ISVTX) && tndp->ni_cred->cr_uid != 0 &&
+                   tndp->ni_cred->cr_uid != dp->i_uid &&
+                   xp->i_uid != tndp->ni_cred->cr_uid) {
                        error = EPERM;
                        goto bad;
                }
                        error = EPERM;
                        goto bad;
                }
@@ -979,7 +656,8 @@ rename()
                 * not directories).
                 */
                if ((xp->i_mode&IFMT) == IFDIR) {
                 * not directories).
                 */
                if ((xp->i_mode&IFMT) == IFDIR) {
-                       if (!dirempty(xp, dp->i_number) || xp->i_nlink > 2) {
+                       if (!dirempty(xp, dp->i_number, tndp->ni_cred) || 
+                           xp->i_nlink > 2) {
                                error = ENOTEMPTY;
                                goto bad;
                        }
                                error = ENOTEMPTY;
                                goto bad;
                        }
@@ -987,16 +665,14 @@ rename()
                                error = ENOTDIR;
                                goto bad;
                        }
                                error = ENOTDIR;
                                goto bad;
                        }
-                       cacheinval(dp);
+                       cache_purge(ITOV(dp));
                } else if (doingdirectory) {
                        error = EISDIR;
                        goto bad;
                }
                } else if (doingdirectory) {
                        error = EISDIR;
                        goto bad;
                }
-               dirrewrite(dp, ip, ndp);
-               if (u.u_error) {
-                       error = u.u_error;
-                       goto bad1;
-               }
+               if (error = dirrewrite(dp, ip, tndp))
+                       goto bad;
+               vput(ITOV(dp));
                /*
                 * Adjust the link count of the target to
                 * reflect the dirrewrite above.  If this is
                /*
                 * Adjust the link count of the target to
                 * reflect the dirrewrite above.  If this is
@@ -1011,32 +687,33 @@ rename()
                if (doingdirectory) {
                        if (--xp->i_nlink != 0)
                                panic("rename: linked directory");
                if (doingdirectory) {
                        if (--xp->i_nlink != 0)
                                panic("rename: linked directory");
-                       itrunc(xp, (u_long)0);
+                       error = itrunc(xp, (u_long)0);
                }
                xp->i_flag |= ICHG;
                }
                xp->i_flag |= ICHG;
-               iput(xp);
+               vput(ITOV(xp));
                xp = NULL;
        }
 
        /*
         * 3) Unlink the source.
         */
                xp = NULL;
        }
 
        /*
         * 3) Unlink the source.
         */
-       ndp->ni_nameiop = DELETE | LOCKPARENT;
-       ndp->ni_segflg = UIO_USERSPACE;
-       ndp->ni_dirp = uap->from;
-       xp = namei(ndp);
-       if (xp != NULL)
-               dp = ndp->ni_pdir;
-       else
+       fndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF;
+       (void)namei(fndp);
+       if (fndp->ni_vp != NULL) {
+               xp = VTOI(fndp->ni_vp);
+               dp = VTOI(fndp->ni_dvp);
+       } else {
+               xp = NULL;
                dp = NULL;
                dp = NULL;
+       }
        /*
        /*
-        * Insure that the directory entry still exists and has not
+        * Ensure that the directory entry still exists and has not
         * changed while the new name has been entered. If the source is
         * a file then the entry may have been unlinked or renamed. In
         * either case there is no further work to be done. If the source
         * is a directory then it cannot have been rmdir'ed; its link
         * count of three would cause a rmdir to fail with ENOTEMPTY.
         * changed while the new name has been entered. If the source is
         * a file then the entry may have been unlinked or renamed. In
         * either case there is no further work to be done. If the source
         * is a directory then it cannot have been rmdir'ed; its link
         * count of three would cause a rmdir to fail with ENOTEMPTY.
-        * The IRENAME flag insures that it cannot be moved by another
+        * The IRENAME flag ensures that it cannot be moved by another
         * rename.
         */
        if (xp != ip) {
         * rename.
         */
        if (xp != ip) {
@@ -1053,8 +730,8 @@ rename()
                        dp->i_nlink--;
                        dp->i_flag |= ICHG;
                        error = rdwri(UIO_READ, xp, (caddr_t)&dirbuf,
                        dp->i_nlink--;
                        dp->i_flag |= ICHG;
                        error = rdwri(UIO_READ, xp, (caddr_t)&dirbuf,
-                               sizeof (struct dirtemplate), (off_t)0, 1,
-                               (int *)0);
+                               sizeof (struct dirtemplate), (off_t)0,
+                               UIO_USERSPACE, tndp->ni_cred, (int *)0);
                        if (error == 0) {
                                if (dirbuf.dotdot_namlen != 2 ||
                                    dirbuf.dotdot_name[0] != '.' ||
                        if (error == 0) {
                                if (dirbuf.dotdot_namlen != 2 ||
                                    dirbuf.dotdot_name[0] != '.' ||
@@ -1065,96 +742,35 @@ rename()
                                        (void) rdwri(UIO_WRITE, xp,
                                            (caddr_t)&dirbuf,
                                            sizeof (struct dirtemplate),
                                        (void) rdwri(UIO_WRITE, xp,
                                            (caddr_t)&dirbuf,
                                            sizeof (struct dirtemplate),
-                                           (off_t)0, 1, (int *)0);
-                                       cacheinval(dp);
+                                           (off_t)0, UIO_USERSPACE,
+                                           tndp->ni_cred, (int *)0);
+                                       cache_purge(ITOV(dp));
                                }
                        }
                }
                                }
                        }
                }
-               if (dirremove(ndp)) {
+               error = dirremove(fndp);
+               if (!error) {
                        xp->i_nlink--;
                        xp->i_flag |= ICHG;
                }
                xp->i_flag &= ~IRENAME;
                        xp->i_nlink--;
                        xp->i_flag |= ICHG;
                }
                xp->i_flag &= ~IRENAME;
-               if (error == 0)         /* XXX conservative */
-                       error = u.u_error;
        }
        if (dp)
        }
        if (dp)
-               iput(dp);
+               vput(ITOV(dp));
        if (xp)
        if (xp)
-               iput(xp);
-       irele(ip);
-       if (error)
-               u.u_error = error;
-       return;
+               vput(ITOV(xp));
+       vrele(ITOV(ip));
+       return (error);
 
 bad:
 
 bad:
-       iput(dp);
-bad1:
        if (xp)
        if (xp)
-               iput(xp);
+               vput(ITOV(xp));
+       vput(ITOV(dp));
 out:
        ip->i_nlink--;
        ip->i_flag |= ICHG;
 out:
        ip->i_nlink--;
        ip->i_flag |= ICHG;
-       irele(ip);
-       if (error)
-               u.u_error = error;
-}
-
-/*
- * Make a new file.
- */
-struct inode *
-maknode(mode, ndp)
-       int mode;
-       register struct nameidata *ndp;
-{
-       register struct inode *ip;
-       register struct inode *pdir = ndp->ni_pdir;
-       ino_t ipref;
-
-       if ((mode & IFMT) == IFDIR)
-               ipref = dirpref(pdir->i_fs);
-       else
-               ipref = pdir->i_number;
-       ip = ialloc(pdir, ipref, mode);
-       if (ip == NULL) {
-               iput(pdir);
-               return (NULL);
-       }
-#ifdef QUOTA
-       if (ip->i_dquot != NODQUOT)
-               panic("maknode: dquot");
-#endif
-       ip->i_flag |= IACC|IUPD|ICHG;
-       if ((mode & IFMT) == 0)
-               mode |= IFREG;
-       ip->i_mode = mode & ~u.u_cmask;
-       ip->i_nlink = 1;
-       ip->i_uid = u.u_uid;
-       ip->i_gid = pdir->i_gid;
-       if (ip->i_mode & ISGID && !groupmember(ip->i_gid) &&
-           (u.u_error = suser(u.u_cred, &u.u_acflag)))
-               ip->i_mode &= ~ISGID;
-#ifdef QUOTA
-       ip->i_dquot = inoquota(ip);
-#endif
-
-       /*
-        * Make sure inode goes to disk before directory entry.
-        */
-       iupdat(ip, &time, &time, 1);
-       u.u_error = direnter(ip, ndp);
-       if (u.u_error) {
-               /*
-                * Write error occurred trying to update directory
-                * so must deallocate the inode.
-                */
-               ip->i_nlink = 0;
-               ip->i_flag |= ICHG;
-               iput(ip);
-               return (NULL);
-       }
-       return (ip);
+       vrele(ITOV(ip));
+       return (error);
 }
 
 /*
 }
 
 /*
@@ -1168,30 +784,21 @@ struct dirtemplate mastertemplate = {
 /*
  * Mkdir system call
  */
 /*
  * Mkdir system call
  */
-mkdir()
+ufs_mkdir(ndp, vap)
+       struct nameidata *ndp;
+       struct vattr *vap;
 {
 {
-       struct a {
-               char    *name;
-               int     dmode;
-       } *uap = (struct a *)u.u_ap;
        register struct inode *ip, *dp;
        register struct inode *ip, *dp;
+       struct inode *tip;
+       struct vnode *dvp;
        struct dirtemplate dirtemplate;
        struct dirtemplate dirtemplate;
-       register struct nameidata *ndp = &u.u_nd;
-
-       ndp->ni_nameiop = CREATE;
-       ndp->ni_segflg = UIO_USERSPACE;
-       ndp->ni_dirp = uap->name;
-       ip = namei(ndp);
-       if (u.u_error)
-               return;
-       if (ip != NULL) {
-               iput(ip);
-               u.u_error = EEXIST;
-               return;
-       }
-       dp = ndp->ni_pdir;
-       uap->dmode &= 0777;
-       uap->dmode |= IFDIR;
+       int error;
+       int dmode;
+
+       dvp = ndp->ni_dvp;
+       dp = VTOI(dvp);
+       dmode = vap->va_mode&0777;
+       dmode |= IFDIR;
        /*
         * Must simulate part of maknode here
         * in order to acquire the inode, but
        /*
         * Must simulate part of maknode here
         * in order to acquire the inode, but
@@ -1199,24 +806,26 @@ mkdir()
         * directory.  The entry is made later
         * after writing "." and ".." entries out.
         */
         * directory.  The entry is made later
         * after writing "." and ".." entries out.
         */
-       ip = ialloc(dp, dirpref(dp->i_fs), uap->dmode);
-       if (ip == NULL) {
+       error = ialloc(dp, dirpref(dp->i_fs), dmode, &tip);
+       if (error) {
                iput(dp);
                iput(dp);
-               return;
+               return (error);
        }
        }
+       ip = tip;
 #ifdef QUOTA
        if (ip->i_dquot != NODQUOT)
                panic("mkdir: dquot");
 #endif
        ip->i_flag |= IACC|IUPD|ICHG;
 #ifdef QUOTA
        if (ip->i_dquot != NODQUOT)
                panic("mkdir: dquot");
 #endif
        ip->i_flag |= IACC|IUPD|ICHG;
-       ip->i_mode = uap->dmode & ~u.u_cmask;
+       ip->i_mode = dmode;
+       ITOV(ip)->v_type = VDIR;        /* Rest init'd in iget() */
        ip->i_nlink = 2;
        ip->i_nlink = 2;
-       ip->i_uid = u.u_uid;
+       ip->i_uid = ndp->ni_cred->cr_uid;
        ip->i_gid = dp->i_gid;
 #ifdef QUOTA
        ip->i_dquot = inoquota(ip);
 #endif
        ip->i_gid = dp->i_gid;
 #ifdef QUOTA
        ip->i_dquot = inoquota(ip);
 #endif
-       iupdat(ip, &time, &time, 1);
+       error = iupdat(ip, &time, &time, 1);
 
        /*
         * Bump link count in parent directory
 
        /*
         * Bump link count in parent directory
@@ -1226,7 +835,7 @@ mkdir()
         */
        dp->i_nlink++;
        dp->i_flag |= ICHG;
         */
        dp->i_nlink++;
        dp->i_flag |= ICHG;
-       iupdat(dp, &time, &time, 1);
+       error = iupdat(dp, &time, &time, 1);
 
        /*
         * Initialize directory with "."
 
        /*
         * Initialize directory with "."
@@ -1235,15 +844,16 @@ mkdir()
        dirtemplate = mastertemplate;
        dirtemplate.dot_ino = ip->i_number;
        dirtemplate.dotdot_ino = dp->i_number;
        dirtemplate = mastertemplate;
        dirtemplate.dot_ino = ip->i_number;
        dirtemplate.dotdot_ino = dp->i_number;
-       u.u_error = rdwri(UIO_WRITE, ip, (caddr_t)&dirtemplate,
-               sizeof (dirtemplate), (off_t)0, 1, (int *)0);
-       if (u.u_error) {
+       error = rdwri(UIO_WRITE, ip, (caddr_t)&dirtemplate,
+               sizeof (dirtemplate), (off_t)0, UIO_SYSSPACE,
+               ndp->ni_cred, (int *)0);
+       if (error) {
                dp->i_nlink--;
                dp->i_flag |= ICHG;
                goto bad;
        }
                dp->i_nlink--;
                dp->i_flag |= ICHG;
                goto bad;
        }
-       if (DIRBLKSIZ > ip->i_fs->fs_fsize)
-               panic("mkdir: blksize");     /* XXX - should grow with bmap() */
+       if (DIRBLKSIZ > dp->i_fs->fs_fsize)
+               panic("mkdir: blksize");     /* XXX - should grow w/balloc() */
        else
                ip->i_size = DIRBLKSIZ;
        /*
        else
                ip->i_size = DIRBLKSIZ;
        /*
@@ -1251,14 +861,13 @@ mkdir()
         * install the entry for it in
         * the parent directory.
         */
         * install the entry for it in
         * the parent directory.
         */
-       u.u_error = direnter(ip, ndp);
+       error = direnter(ip, ndp);
        dp = NULL;
        dp = NULL;
-       if (u.u_error) {
+       if (error) {
                ndp->ni_nameiop = LOOKUP | NOCACHE;
                ndp->ni_nameiop = LOOKUP | NOCACHE;
-               ndp->ni_segflg = UIO_USERSPACE;
-               ndp->ni_dirp = uap->name;
-               dp = namei(ndp);
-               if (dp) {
+               error = namei(ndp);
+               if (!error) {
+                       dp = VTOI(ndp->ni_vp);
                        dp->i_nlink--;
                        dp->i_flag |= ICHG;
                }
                        dp->i_nlink--;
                        dp->i_flag |= ICHG;
                }
@@ -1266,55 +875,37 @@ mkdir()
 bad:
        /*
         * No need to do an explicit itrunc here,
 bad:
        /*
         * No need to do an explicit itrunc here,
-        * irele will do this for us because we set
+        * vrele will do this for us because we set
         * the link count to 0.
         */
         * the link count to 0.
         */
-       if (u.u_error) {
+       if (error) {
                ip->i_nlink = 0;
                ip->i_flag |= ICHG;
        }
                ip->i_nlink = 0;
                ip->i_flag |= ICHG;
        }
+       iput(ip);
        if (dp)
                iput(dp);
        if (dp)
                iput(dp);
-       iput(ip);
+       return (error);
 }
 
 /*
  * Rmdir system call.
  */
 }
 
 /*
  * Rmdir system call.
  */
-rmdir()
+ufs_rmdir(ndp)
+       register struct nameidata *ndp;
 {
 {
-       struct a {
-               char    *name;
-       } *uap = (struct a *)u.u_ap;
        register struct inode *ip, *dp;
        register struct inode *ip, *dp;
-       register struct nameidata *ndp = &u.u_nd;
-
-       ndp->ni_nameiop = DELETE | LOCKPARENT;
-       ndp->ni_segflg = UIO_USERSPACE;
-       ndp->ni_dirp = uap->name;
-       ip = namei(ndp);
-       if (ip == NULL)
-               return;
-       dp = ndp->ni_pdir;
+       int error = 0;
+
+       ip = VTOI(ndp->ni_vp);
+       dp = VTOI(ndp->ni_dvp);
        /*
         * No rmdir "." please.
         */
        if (dp == ip) {
        /*
         * No rmdir "." please.
         */
        if (dp == ip) {
-               irele(dp);
+               vrele(ITOV(dp));
                iput(ip);
                iput(ip);
-               u.u_error = EINVAL;
-               return;
-       }
-       if ((ip->i_mode&IFMT) != IFDIR) {
-               u.u_error = ENOTDIR;
-               goto out;
-       }
-       /*
-        * Don't remove a mounted on directory.
-        */
-       if (ip->i_dev != dp->i_dev) {
-               u.u_error = EBUSY;
-               goto out;
+               return (EINVAL);
        }
        /*
         * Verify the directory is empty (and valid).
        }
        /*
         * Verify the directory is empty (and valid).
@@ -1323,8 +914,8 @@ rmdir()
         *  the current directory and thus be
         *  non-empty.)
         */
         *  the current directory and thus be
         *  non-empty.)
         */
-       if (ip->i_nlink != 2 || !dirempty(ip, dp->i_number)) {
-               u.u_error = ENOTEMPTY;
+       if (ip->i_nlink != 2 || !dirempty(ip, dp->i_number, ndp->ni_cred)) {
+               error = ENOTEMPTY;
                goto out;
        }
        /*
                goto out;
        }
        /*
@@ -1332,13 +923,13 @@ rmdir()
         * inode.  If we crash in between, the directory
         * will be reattached to lost+found,
         */
         * inode.  If we crash in between, the directory
         * will be reattached to lost+found,
         */
-       if (dirremove(ndp) == 0)
+       if (error = dirremove(ndp))
                goto out;
        dp->i_nlink--;
        dp->i_flag |= ICHG;
                goto out;
        dp->i_nlink--;
        dp->i_flag |= ICHG;
-       cacheinval(dp);
+       cache_purge(ITOV(dp));
        iput(dp);
        iput(dp);
-       dp = NULL;
+       ndp->ni_dvp = NULL;
        /*
         * Truncate inode.  The only stuff left
         * in the directory is "." and "..".  The
        /*
         * Truncate inode.  The only stuff left
         * in the directory is "." and "..".  The
@@ -1351,40 +942,206 @@ rmdir()
         * worry about them later.
         */
        ip->i_nlink -= 2;
         * worry about them later.
         */
        ip->i_nlink -= 2;
-       itrunc(ip, (u_long)0);
-       cacheinval(ip);
+       error = itrunc(ip, (u_long)0);
+       cache_purge(ITOV(ip));
 out:
 out:
-       if (dp)
+       if (ndp->ni_dvp)
                iput(dp);
        iput(ip);
                iput(dp);
        iput(ip);
+       return (error);
 }
 
 }
 
-struct file *
-getinode(fdes)
-       int fdes;
+/*
+ * symlink -- make a symbolic link
+ */
+ufs_symlink(ndp, vap, target)
+       struct nameidata *ndp;
+       struct vattr *vap;
+       char *target;
+{
+       struct inode *ip;
+       int error;
+
+       error = maknode(IFLNK | vap->va_mode, ndp, &ip);
+       if (error)
+               return (error);
+       error = rdwri(UIO_WRITE, ip, target, strlen(target), (off_t)0,
+               UIO_SYSSPACE, ndp->ni_cred, (int *)0);
+       iput(ip);
+       return (error);
+}
+
+/*
+ * Vnode op for read and write
+ */
+ufs_readdir(vp, uio, offp, cred)
+       struct vnode *vp;
+       register struct uio *uio;
+       off_t *offp;
+       struct ucred *cred;
 {
 {
-       struct file *fp;
+       register struct inode *ip = VTOI(vp);
+       int count, error;
 
 
-       if ((unsigned)fdes >= NOFILE || (fp = u.u_ofile[fdes]) == NULL) {
-               u.u_error = EBADF;
-               return ((struct file *)0);
+       ILOCK(ip);
+       uio->uio_offset = *offp;
+       count = uio->uio_resid;
+       count &= ~(DIRBLKSIZ - 1);
+       if (vp->v_type != VDIR || uio->uio_iovcnt != 1 ||
+           (count < DIRBLKSIZ) || (uio->uio_offset & (DIRBLKSIZ -1))) {
+               IUNLOCK(ip);
+               return (EINVAL);
+       }
+       uio->uio_resid = count;
+       uio->uio_iov->iov_len = count;
+       error = readip(ip, uio, cred);
+       *offp += count - uio->uio_resid;
+       IUNLOCK(ip);
+       return (error);
+}
+
+/*
+ * Return target name of a symbolic link
+ */
+ufs_readlink(vp, uiop, cred)
+       struct vnode *vp;
+       struct uio *uiop;
+       struct ucred *cred;
+{
+
+       return (readip(VTOI(vp), uiop, cred));
+}
+
+/*
+ * Ufs abort op, called after namei() when a CREATE/DELETE isn't actually
+ * done. Iff ni_vp/ni_dvp not null and locked, unlock.
+ */
+ufs_abortop(ndp)
+       register struct nameidata *ndp;
+{
+       register struct inode *ip;
+
+       if (ndp->ni_vp) {
+               ip = VTOI(ndp->ni_vp);
+               if (ip->i_flag & ILOCKED)
+                       IUNLOCK(ip);
+               vrele(ndp->ni_vp);
        }
        }
-       if (fp->f_type != DTYPE_INODE) {
-               u.u_error = EINVAL;
-               return ((struct file *)0);
+       if (ndp->ni_dvp) {
+               ip = VTOI(ndp->ni_dvp);
+               if (ip->i_flag & ILOCKED)
+                       IUNLOCK(ip);
+               vrele(ndp->ni_dvp);
        }
        }
-       return (fp);
+       return;
+}
+
+ufs_lock(vp)
+       struct vnode *vp;
+{
+       register struct inode *ip = VTOI(vp);
+
+       ILOCK(ip);
+       return (0);
+}
+
+ufs_unlock(vp)
+       struct vnode *vp;
+{
+       register struct inode *ip = VTOI(vp);
+
+       if (!(ip->i_flag & ILOCKED))
+               panic("ufs_unlock NOT LOCKED");
+       IUNLOCK(ip);
+       return (0);
+}
+
+/*
+ * Get access to bmap
+ */
+ufs_bmap(vp, bn, vpp, bnp)
+       struct vnode *vp;
+       daddr_t bn;
+       struct vnode **vpp;
+       daddr_t *bnp;
+{
+       struct inode *ip = VTOI(vp);
+
+       if (vpp != NULL)
+               *vpp = ip->i_devvp;
+       if (bnp == NULL)
+               return (0);
+       return (bmap(ip, bn, bnp, (daddr_t *)0, (int *)0));
 }
 
 /*
 }
 
 /*
- * mode mask for creation of files
+ * Just call the device strategy routine
  */
  */
-umask()
+ufs_strategy(bp)
+       register struct buf *bp;
 {
 {
-       register struct a {
-               int     mask;
-       } *uap = (struct a *)u.u_ap;
+       (*bdevsw[major(bp->b_dev)].d_strategy)(bp);
+       return (0);
+}
 
 
-       u.u_r.r_val1 = u.u_cmask;
-       u.u_cmask = uap->mask & 07777;
+/*
+ * Make a new file.
+ */
+maknode(mode, ndp, ipp)
+       int mode;
+       register struct nameidata *ndp;
+       struct inode **ipp;
+{
+       register struct inode *ip;
+       struct inode *tip;
+       register struct inode *pdir = VTOI(ndp->ni_dvp);
+       ino_t ipref;
+       int error;
+
+       *ipp = 0;
+       if ((mode & IFMT) == IFDIR)
+               ipref = dirpref(pdir->i_fs);
+       else
+               ipref = pdir->i_number;
+       error = ialloc(pdir, ipref, mode, &tip);
+       if (error) {
+               iput(pdir);
+               return (error);
+       }
+       ip = tip;
+#ifdef QUOTA
+       if (ip->i_dquot != NODQUOT)
+               panic("maknode: dquot");
+#endif
+       ip->i_flag |= IACC|IUPD|ICHG;
+       if ((mode & IFMT) == 0)
+               mode |= IFREG;
+       ip->i_mode = mode;
+       ITOV(ip)->v_type = IFTOVT(mode);        /* Rest init'd in iget() */
+       ip->i_nlink = 1;
+       ip->i_uid = ndp->ni_cred->cr_uid;
+       ip->i_gid = pdir->i_gid;
+       if ((ip->i_mode & ISGID) && !groupmember(ip->i_gid, ndp->ni_cred) &&
+           suser(ndp->ni_cred, NULL))
+               ip->i_mode &= ~ISGID;
+#ifdef QUOTA
+       ip->i_dquot = inoquota(ip);
+#endif
+
+       /*
+        * Make sure inode goes to disk before directory entry.
+        */
+       if ((error = iupdat(ip, &time, &time, 1)) ||
+           (error = direnter(ip, ndp))) {
+               /*
+                * Write error occurred trying to update the inode
+                * or the directory so must deallocate the inode.
+                */
+               ip->i_nlink = 0;
+               ip->i_flag |= ICHG;
+               iput(ip);
+               return (error);
+       }
+       *ipp = ip;
+       return (0);
 }
 }
index c03f9cc..902d513 100644 (file)
@@ -1,9 +1,20 @@
 /*
  * Copyright (c) 1982, 1986, 1988 Regents of the University of California.
 /*
  * Copyright (c) 1982, 1986, 1988 Regents of the University of California.
- * All rights reserved.  The Berkeley software License Agreement
- * specifies the terms and conditions for redistribution.
+ * All rights reserved.
  *
  *
- *     @(#)ufs_disksubr.c      7.11 (Berkeley) %G%
+ * 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.
+ *
+ *     @(#)ufs_disksubr.c      7.12 (Berkeley) %G%
  */
 
 #include "param.h"
  */
 
 #include "param.h"
@@ -11,8 +22,6 @@
 #include "buf.h"
 #include "disklabel.h"
 #include "syslog.h"
 #include "buf.h"
 #include "disklabel.h"
 #include "syslog.h"
-
-#include "dir.h"
 #include "user.h"
 
 /*
 #include "user.h"
 
 /*
@@ -149,9 +158,7 @@ readdisklabel(dev, strat, lp)
        bp->b_flags = B_BUSY | B_READ;
        bp->b_cylin = LABELSECTOR / lp->d_secpercyl;
        (*strat)(bp);
        bp->b_flags = B_BUSY | B_READ;
        bp->b_cylin = LABELSECTOR / lp->d_secpercyl;
        (*strat)(bp);
-       biowait(bp);
-       if (bp->b_flags & B_ERROR) {
-               u.u_error = 0;          /* XXX */
+       if (biowait(bp)) {
                msg = "I/O error";
        } else for (dlp = (struct disklabel *)bp->b_un.b_addr;
            dlp <= (struct disklabel *)(bp->b_un.b_addr+DEV_BSIZE-sizeof(*dlp));
                msg = "I/O error";
        } else for (dlp = (struct disklabel *)bp->b_un.b_addr;
            dlp <= (struct disklabel *)(bp->b_un.b_addr+DEV_BSIZE-sizeof(*dlp));
@@ -244,12 +251,8 @@ writedisklabel(dev, strat, lp)
        bp->b_bcount = lp->d_secsize;
        bp->b_flags = B_READ;
        (*strat)(bp);
        bp->b_bcount = lp->d_secsize;
        bp->b_flags = B_READ;
        (*strat)(bp);
-       biowait(bp);
-       if (bp->b_flags & B_ERROR) {
-               error = u.u_error;              /* XXX */
-               u.u_error = 0;
+       if (error = biowait(bp))
                goto done;
                goto done;
-       }
        for (dlp = (struct disklabel *)bp->b_un.b_addr;
            dlp <= (struct disklabel *)
              (bp->b_un.b_addr + lp->d_secsize - sizeof(*dlp));
        for (dlp = (struct disklabel *)bp->b_un.b_addr;
            dlp <= (struct disklabel *)
              (bp->b_un.b_addr + lp->d_secsize - sizeof(*dlp));
@@ -259,11 +262,7 @@ writedisklabel(dev, strat, lp)
                        *dlp = *lp;
                        bp->b_flags = B_WRITE;
                        (*strat)(bp);
                        *dlp = *lp;
                        bp->b_flags = B_WRITE;
                        (*strat)(bp);
-                       biowait(bp);
-                       if (bp->b_flags & B_ERROR) {
-                               error = u.u_error;              /* XXX */
-                               u.u_error = 0;
-                       }
+                       error = biowait(bp);
                        goto done;
                }
        }
                        goto done;
                }
        }
index 7f3ea4f..b6a597f 100644 (file)
@@ -1,22 +1,35 @@
 /*
 /*
- * Copyright (c) 1982, 1986 Regents of the University of California.
- * All rights reserved.  The Berkeley software License Agreement
- * specifies the terms and conditions for redistribution.
+ * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
+ * All rights reserved.
  *
  *
- *     @(#)ufs_inode.c 7.5 (Berkeley) %G%
+ * 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 MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ *     @(#)ufs_inode.c 7.6 (Berkeley) %G%
  */
 
 #include "param.h"
 #include "systm.h"
 #include "mount.h"
  */
 
 #include "param.h"
 #include "systm.h"
 #include "mount.h"
-#include "dir.h"
 #include "user.h"
 #include "user.h"
-#include "inode.h"
-#include "fs.h"
+#include "file.h"
 #include "buf.h"
 #include "cmap.h"
 #include "buf.h"
 #include "cmap.h"
+#include "vnode.h"
+#include "../ufs/inode.h"
+#include "../ufs/fs.h"
+#include "../ufs/ufsmount.h"
 #ifdef QUOTA
 #ifdef QUOTA
-#include "quota.h"
+#include "../ufs/quota.h"
 #endif
 #include "kernel.h"
 #include "malloc.h"
 #endif
 #include "kernel.h"
 #include "malloc.h"
 #define        INOHASH(dev,ino)        (((unsigned)((dev)+(ino)))%INOHSZ)
 #endif
 
 #define        INOHASH(dev,ino)        (((unsigned)((dev)+(ino)))%INOHSZ)
 #endif
 
+#define INSFREE(ip) {\
+       if (ifreeh) { \
+               *ifreet = (ip); \
+               (ip)->i_freeb = ifreet; \
+       } else { \
+               ifreeh = (ip); \
+               (ip)->i_freeb = &ifreeh; \
+       } \
+       (ip)->i_freef = NULL; \
+       ifreet = &(ip)->i_freef; \
+}
+
 union ihead {                          /* inode LRU cache, Chris Maltby */
        union  ihead *ih_head[2];
        struct inode *ih_chain[2];
 } ihead[INOHSZ];
 
 union ihead {                          /* inode LRU cache, Chris Maltby */
        union  ihead *ih_head[2];
        struct inode *ih_chain[2];
 } ihead[INOHSZ];
 
-struct inode *ifreeh, **ifreet;
+struct inode *ifreeh, **ifreet, *bdevlisth;
 
 /*
  * Initialize hash links for inodes
 
 /*
  * Initialize hash links for inodes
@@ -54,10 +79,12 @@ ihinit()
        ip->i_freeb = &ifreeh;
        ip->i_forw = ip;
        ip->i_back = ip;
        ip->i_freeb = &ifreeh;
        ip->i_forw = ip;
        ip->i_back = ip;
+       ITOV(ip)->v_data = (qaddr_t)ip;
        for (i = ninode; --i > 0; ) {
                ++ip;
                ip->i_forw = ip;
                ip->i_back = ip;
        for (i = ninode; --i > 0; ) {
                ++ip;
                ip->i_forw = ip;
                ip->i_back = ip;
+               ITOV(ip)->v_data = (qaddr_t)ip;
                *ifreet = ip;
                ip->i_freeb = ifreet;
                ifreet = &ip->i_freef;
                *ifreet = ip;
                ip->i_freeb = ifreet;
                ifreet = &ip->i_freef;
@@ -65,55 +92,31 @@ ihinit()
        ip->i_freef = NULL;
 }
 
        ip->i_freef = NULL;
 }
 
-#ifdef notdef
 /*
 /*
- * Find an inode if it is incore.
- * This is the equivalent, for inodes,
- * of ``incore'' in bio.c or ``pfind'' in subr.c.
- */
-struct inode *
-ifind(dev, ino)
-       dev_t dev;
-       ino_t ino;
-{
-       register struct inode *ip;
-       register union  ihead *ih;
-
-       ih = &ihead[INOHASH(dev, ino)];
-       for (ip = ih->ih_chain[0]; ip != (struct inode *)ih; ip = ip->i_forw)
-               if (ino==ip->i_number && dev==ip->i_dev)
-                       return (ip);
-       return ((struct inode *)0);
-}
-#endif notdef
-
-/*
- * Look up an inode by device,inumber.
+ * Look up an vnode/inode by device,inumber.
  * If it is in core (in the inode structure),
  * honor the locking protocol.
  * If it is not in core, read it in from the
  * specified device.
  * If it is in core (in the inode structure),
  * honor the locking protocol.
  * If it is not in core, read it in from the
  * specified device.
- * If the inode is mounted on, perform
- * the indicated indirection.
+ * Callers must check for mount points!!
  * In all cases, a pointer to a locked
  * inode structure is returned.
  * In all cases, a pointer to a locked
  * inode structure is returned.
- *
- * panic: no imt -- if the mounted file
- *     system is not in the mount table.
- *     "cannot happen"
  */
  */
-struct inode *
-iget(dev, fs, ino)
-       dev_t dev;
-       register struct fs *fs;
+iget(xp, ino, ipp)
+       struct inode *xp;
        ino_t ino;
        ino_t ino;
+       struct inode **ipp;
 {
 {
-       register struct inode *ip;
-       register union  ihead *ih;
-       register struct mount *mp;
-       register struct buf *bp;
-       register struct dinode *dp;
-       register struct inode *iq;
+       dev_t dev = xp->i_dev;
+       struct mount *mntp = ITOV(xp)->v_mount;
+       register struct fs *fs = VFSTOUFS(mntp)->um_fs;
+       register struct inode *ip, *iq;
+       register struct vnode *vp;
+       struct inode *nip;
+       struct buf *bp;
+       struct dinode tdip, *dp;
+       union  ihead *ih;
+       int error;
 
 loop:
        ih = &ihead[INOHASH(dev, ino)];
 
 loop:
        ih = &ihead[INOHASH(dev, ino)];
@@ -131,17 +134,8 @@ loop:
                                sleep((caddr_t)ip, PINOD);
                                goto loop;
                        }
                                sleep((caddr_t)ip, PINOD);
                                goto loop;
                        }
-                       if ((ip->i_flag&IMOUNT) != 0) {
-                               for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++)
-                                       if(mp->m_inodp == ip) {
-                                               dev = mp->m_dev;
-                                               fs = mp->m_fs;
-                                               ino = ROOTINO;
-                                               goto loop;
-                                       }
-                               panic("no imt");
-                       }
-                       if (ip->i_count == 0) {         /* ino on free list */
+                       vp = ITOV(ip);
+                       if (vp->v_count == 0) {         /* ino on free list */
                                if (iq = ip->i_freef)
                                        iq->i_freeb = ip->i_freeb;
                                else
                                if (iq = ip->i_freef)
                                        iq->i_freeb = ip->i_freeb;
                                else
@@ -150,17 +144,153 @@ loop:
                                ip->i_freef = NULL;
                                ip->i_freeb = NULL;
                        }
                                ip->i_freef = NULL;
                                ip->i_freeb = NULL;
                        }
-                       ip->i_count++;
                        ip->i_flag |= ILOCKED;
                        ip->i_flag |= ILOCKED;
-                       return(ip);
+                       vp->v_count++;
+                       *ipp = ip;
+                       return(0);
+               }
+       if (error = getnewino(dev, ino, &nip)) {
+               *ipp = 0;
+               return (error);
+       }
+       ip = nip;
+       /*
+        * Read in the disk contents for the inode.
+        */
+       if (error = bread(VFSTOUFS(mntp)->um_devvp, fsbtodb(fs, itod(fs, ino)),
+           (int)fs->fs_bsize, &bp)) {
+               /*
+                * The inode doesn't contain anything useful, so it would
+                * be misleading to leave it on its hash chain. Iput() will
+                * take care of putting it back on the free list. We also
+                * lose its inumber, just in case.
+                */
+               remque(ip);
+               ip->i_forw = ip;
+               ip->i_back = ip;
+               ip->i_number = 0;
+               INSFREE(ip);
+               ip->i_flag = 0;
+               brelse(bp);
+               *ipp = 0;
+               return(error);
+       }
+       /*
+        * Check to see if the new inode represents a block device
+        * for which we already have an inode (either because of
+        * bdevvp() or because of a different inode representing
+        * the same block device). If such an alias exists, put the
+        * just allocated inode back on the free list, and replace
+        * the contents of the existing inode with the contents of
+        * the new inode.
+        */
+       dp = bp->b_un.b_dino;
+       dp += itoo(fs, ino);
+       if ((dp->di_mode & IFMT) != IFBLK) {
+               ip->i_ic = dp->di_ic;
+               brelse(bp);
+       } else {
+again:
+               for (iq = bdevlisth; iq; iq = iq->i_devlst) {
+                       if (dp->di_rdev != ITOV(iq)->v_rdev)
+                               continue;
+                       igrab(iq);
+                       if (dp->di_rdev != ITOV(iq)->v_rdev) {
+                               iput(iq);
+                               goto again;
+                       }
+                       /*
+                        * Discard unneeded inode.
+                        */
+                       remque(ip);
+                       ip->i_forw = ip;
+                       ip->i_back = ip;
+                       ip->i_number = 0;
+                       INSFREE(ip);
+                       ip->i_flag = 0;
+                       /*
+                        * Reinitialize aliased inode.
+                        * We must release the buffer that we just read
+                        * before doing the iupdat() to avoid a possible
+                        * deadlock with updating an inode in the same
+                        * disk block.
+                        */
+                       ip = iq;
+                       vp = ITOV(iq);
+                       tdip.di_ic = dp->di_ic;
+                       brelse(bp);
+                       error = iupdat(ip, &time, &time, 1);
+                       ip->i_ic = tdip.di_ic;
+                       remque(ip);
+                       insque(ip, ih);
+                       ip->i_dev = dev;
+                       ip->i_number = ino;
+                       if (ip->i_devvp) {
+                               vrele(ip->i_devvp);
+                               ip->i_devvp = 0;
+                       }
+                       cache_purge(vp);
+                       break;
+               }
+               if (iq == 0) {
+                       ip->i_ic = dp->di_ic;
+                       brelse(bp);
+                       ip->i_devlst = bdevlisth;
+                       bdevlisth = ip;
                }
                }
+       }
+       /*
+        * Finish inode initialization.
+        */
+       ip->i_fs = fs;
+       ip->i_devvp = VFSTOUFS(mntp)->um_devvp;
+       ip->i_devvp->v_count++;
+       /*
+        * Initialize the associated vnode
+        */
+       vp = ITOV(ip);
+       vinit(vp, mntp, IFTOVT(ip->i_mode), &ufs_vnodeops);
+       if (vp->v_type == VCHR || vp->v_type == VBLK) {
+               vp->v_rdev = ip->i_rdev;
+               vp->v_op = &blk_vnodeops;
+       }
+       if (ino == ROOTINO)
+               vp->v_flag |= VROOT;
+#ifdef QUOTA
+       if (ip->i_mode != 0)
+               ip->i_dquot = inoquota(ip);
+#endif
+       *ipp = ip;
+       return (0);
+}
 
 
+/*
+ * Allocate a new inode.
+ *
+ * Put it onto its hash chain and lock it so that other requests for
+ * this inode will block if they arrive while we are sleeping waiting
+ * for old data structures to be purged or for the contents of the disk
+ * portion of this inode to be read.
+ */
+getnewino(dev, ino, ipp)
+       dev_t dev;
+       ino_t ino;
+       struct inode **ipp;
+{
+       union ihead *ih;
+       register struct inode *ip, *iq;
+       register struct vnode *vp;
+
+       /*
+        * Remove the next inode from the free list.
+        */
        if ((ip = ifreeh) == NULL) {
                tablefull("inode");
        if ((ip = ifreeh) == NULL) {
                tablefull("inode");
-               u.u_error = ENFILE;
-               return(NULL);
+               *ipp = 0;
+               return(ENFILE);
        }
        }
-       if (ip->i_count)
+       vp = ITOV(ip);
+       if (vp->v_count)
                panic("free inode isn't");
        if (iq = ip->i_freef)
                iq->i_freeb = &ifreeh;
                panic("free inode isn't");
        if (iq = ip->i_freef)
                iq->i_freeb = &ifreeh;
@@ -170,65 +300,47 @@ loop:
        /*
         * Now to take inode off the hash chain it was on
         * (initially, or after an iflush, it is on a "hash chain"
        /*
         * Now to take inode off the hash chain it was on
         * (initially, or after an iflush, it is on a "hash chain"
-        * consisting entirely of itself, and pointed to by no-one,
-        * but that doesn't matter), and put it on the chain for
-        * its new (ino, dev) pair
+        * consisting entirely of itself, and pointed to by no-one)
+        * and put it on the chain for its new (ino, dev) pair.
         */
        remque(ip);
         */
        remque(ip);
-       insque(ip, ih);
        ip->i_dev = dev;
        ip->i_dev = dev;
-       ip->i_fs = fs;
        ip->i_number = ino;
        ip->i_number = ino;
-       cacheinval(ip);
+       if (dev != NODEV) {
+               ih = &ihead[INOHASH(dev, ino)];
+               insque(ip, ih);
+       }
        ip->i_flag = ILOCKED;
        ip->i_flag = ILOCKED;
-       ip->i_count++;
        ip->i_lastr = 0;
        ip->i_lastr = 0;
-#ifdef QUOTA
-       dqrele(ip->i_dquot);
-#endif
-#ifdef SECSIZE
-       bp = bread(dev, fsbtodb(fs, itod(fs, ino)), (int)fs->fs_bsize,
-           fs->fs_dbsize);
-#else SECSIZE
-       bp = bread(dev, fsbtodb(fs, itod(fs, ino)), (int)fs->fs_bsize);
 #endif SECSIZE
        /*
 #endif SECSIZE
        /*
-        * Check I/O errors
+        * Purge old data structures associated with the inode.
         */
         */
-       if ((bp->b_flags&B_ERROR) != 0) {
-               brelse(bp);
-               /*
-                * the inode doesn't contain anything useful, so it would
-                * be misleading to leave it on its hash chain.
-                * 'iput' will take care of putting it back on the free list.
-                */
-               remque(ip);
-               ip->i_forw = ip;
-               ip->i_back = ip;
-               /*
-                * we also loose its inumber, just in case (as iput
-                * doesn't do that any more) - but as it isn't on its
-                * hash chain, I doubt if this is really necessary .. kre
-                * (probably the two methods are interchangable)
-                */
-               ip->i_number = 0;
-#ifdef QUOTA
-               ip->i_dquot = NODQUOT;
-#endif
-               iput(ip);
-               return(NULL);
+       cache_purge(vp);
+       if (ip->i_devvp) {
+               vrele(ip->i_devvp);
+               ip->i_devvp = 0;
        }
        }
-       dp = bp->b_un.b_dino;
-       dp += itoo(fs, ino);
-       ip->i_ic = dp->di_ic;
-       brelse(bp);
 #ifdef QUOTA
 #ifdef QUOTA
-       if (ip->i_mode == 0)
-               ip->i_dquot = NODQUOT;
-       else
-               ip->i_dquot = inoquota(ip);
+       dqrele(ip->i_dquot);
+       ip->i_dquot = NODQUOT;
 #endif
 #endif
-       return (ip);
+       if (vp->v_type == VBLK) {
+               if (bdevlisth == ip) {
+                       bdevlisth = ip->i_devlst;
+               } else {
+                       for (iq = bdevlisth; iq; iq = iq->i_devlst) {
+                               if (iq->i_devlst != ip)
+                                       continue;
+                               iq->i_devlst = ip->i_devlst;
+                               break;
+                       }
+                       if (iq == NULL)
+                               panic("missing bdev");
+               }
+       }
+       *ipp = ip;
+       return (0);
 }
 
 /*
 }
 
 /*
@@ -242,11 +354,13 @@ loop:
 igrab(ip)
        register struct inode *ip;
 {
 igrab(ip)
        register struct inode *ip;
 {
+       register struct vnode *vp = ITOV(ip);
+
        while ((ip->i_flag&ILOCKED) != 0) {
                ip->i_flag |= IWANT;
                sleep((caddr_t)ip, PINOD);
        }
        while ((ip->i_flag&ILOCKED) != 0) {
                ip->i_flag |= IWANT;
                sleep((caddr_t)ip, PINOD);
        }
-       if (ip->i_count == 0) {         /* ino on free list */
+       if (vp->v_count == 0) {         /* ino on free list */
                register struct inode *iq;
 
                if (iq = ip->i_freef)
                register struct inode *iq;
 
                if (iq = ip->i_freef)
@@ -257,10 +371,56 @@ igrab(ip)
                ip->i_freef = NULL;
                ip->i_freeb = NULL;
        }
                ip->i_freef = NULL;
                ip->i_freeb = NULL;
        }
-       ip->i_count++;
+       vp->v_count++;
        ip->i_flag |= ILOCKED;
 }
 
        ip->i_flag |= ILOCKED;
 }
 
+/*
+ * Create a vnode for a block device.
+ * Used for root filesystem, argdev, and swap areas.
+ */
+bdevvp(dev, vpp)
+       dev_t dev;
+       struct vnode **vpp;
+{
+       register struct inode *ip;
+       register struct vnode *vp;
+       struct inode *nip;
+       int error;
+
+       /*
+        * Check for the existence of an existing vnode.
+        */
+again:
+       for (ip = bdevlisth; ip; ip = ip->i_devlst) {
+               vp = ITOV(ip);
+               if (dev != vp->v_rdev)
+                       continue;
+               igrab(ip);
+               if (dev != vp->v_rdev) {
+                       iput(ip);
+                       goto again;
+               }
+               IUNLOCK(ip);
+               *vpp = vp;
+               return (0);
+       }
+       if (error = getnewino(NODEV, (ino_t)0, &nip)) {
+               *vpp = 0;
+               return (error);
+       }
+       ip = nip;
+       ip->i_fs = 0;
+       ip->i_devlst = bdevlisth;
+       bdevlisth = ip;
+       vp = ITOV(ip);
+       vinit(vp, 0, VBLK, &blk_vnodeops);
+       vp->v_rdev = dev;
+       IUNLOCK(ip);
+       *vpp = vp;
+       return (0);
+}
+
 /*
  * Decrement reference count of
  * an inode structure.
 /*
  * Decrement reference count of
  * an inode structure.
@@ -275,54 +435,43 @@ iput(ip)
        if ((ip->i_flag & ILOCKED) == 0)
                panic("iput");
        IUNLOCK(ip);
        if ((ip->i_flag & ILOCKED) == 0)
                panic("iput");
        IUNLOCK(ip);
-       irele(ip);
+       vrele(ITOV(ip));
 }
 
 }
 
-irele(ip)
-       register struct inode *ip;
+
+ufs_inactive(vp)
+       struct vnode *vp;
 {
 {
-       int mode;
-
-       if (ip->i_count == 1) {
-               ip->i_flag |= ILOCKED;
-               if (ip->i_nlink <= 0 && ip->i_fs->fs_ronly == 0) {
-                       itrunc(ip, (u_long)0);
-                       mode = ip->i_mode;
-                       ip->i_mode = 0;
-                       ip->i_rdev = 0;
-                       ip->i_flag |= IUPD|ICHG;
-                       ifree(ip, ip->i_number, mode);
+       register struct inode *ip = VTOI(vp);
+       int mode, error;
+
+       if (ITOV(ip)->v_count != 0)
+               panic("ufs_inactive: not inactive");
+       ip->i_flag |= ILOCKED;
+       if (ip->i_nlink <= 0 && (ITOV(ip)->v_mount->m_flag&M_RDONLY) == 0) {
+               error = itrunc(ip, (u_long)0);
+               mode = ip->i_mode;
+               ip->i_mode = 0;
+               ip->i_rdev = 0;
+               ip->i_flag |= IUPD|ICHG;
+               ifree(ip, ip->i_number, mode);
 #ifdef QUOTA
 #ifdef QUOTA
-                       (void) chkiq(ip->i_dev, ip, ip->i_uid, 0);
-                       dqrele(ip->i_dquot);
-                       ip->i_dquot = NODQUOT;
+               (void) chkiq(ip->i_dev, ip, ip->i_uid, 0);
+               dqrele(ip->i_dquot);
+               ip->i_dquot = NODQUOT;
 #endif
 #endif
-               }
-               IUPDAT(ip, &time, &time, 0);
-               IUNLOCK(ip);
-               ip->i_flag = 0;
-               /*
-                * Put the inode on the end of the free list.
-                * Possibly in some cases it would be better to
-                * put the inode at the head of the free list,
-                * (eg: where i_mode == 0 || i_number == 0)
-                * but I will think about that later .. kre
-                * (i_number is rarely 0 - only after an i/o error in iget,
-                * where i_mode == 0, the inode will probably be wanted
-                * again soon for an ialloc, so possibly we should keep it)
-                */
-               if (ifreeh) {
-                       *ifreet = ip;
-                       ip->i_freeb = ifreet;
-               } else {
-                       ifreeh = ip;
-                       ip->i_freeb = &ifreeh;
-               }
-               ip->i_freef = NULL;
-               ifreet = &ip->i_freef;
-       } else if (!(ip->i_flag & ILOCKED))
-               ITIMES(ip, &time, &time);
-       ip->i_count--;
+       }
+       IUPDAT(ip, &time, &time, 0);
+       IUNLOCK(ip);
+       ip->i_flag = 0;
+       /*
+        * Put the inode on the end of the free list.
+        * Possibly in some cases it would be better to
+        * put the inode at the head of the free list,
+        * (eg: where i_mode == 0 || i_number == 0).
+        */
+       INSFREE(ip);
+       return (error);
 }
 
 /*
 }
 
 /*
@@ -338,38 +487,36 @@ iupdat(ip, ta, tm, waitfor)
        struct timeval *ta, *tm;
        int waitfor;
 {
        struct timeval *ta, *tm;
        int waitfor;
 {
-       register struct buf *bp;
+       struct buf *bp;
+       struct vnode *vp = ITOV(ip);
        struct dinode *dp;
        register struct fs *fs;
 
        fs = ip->i_fs;
        struct dinode *dp;
        register struct fs *fs;
 
        fs = ip->i_fs;
-       if ((ip->i_flag & (IUPD|IACC|ICHG|IMOD)) != 0) {
-               if (fs->fs_ronly)
-                       return;
-#ifdef SECSIZE
-               bp = bread(ip->i_dev, fsbtodb(fs, itod(fs, ip->i_number)),
-                       (int)fs->fs_bsize, fs->fs_dbsize);
-#else SECSIZE
-               bp = bread(ip->i_dev, fsbtodb(fs, itod(fs, ip->i_number)),
-                       (int)fs->fs_bsize);
-#endif SECSIZE
-               if (bp->b_flags & B_ERROR) {
-                       brelse(bp);
-                       return;
-               }
-               if (ip->i_flag&IACC)
-                       ip->i_atime = ta->tv_sec;
-               if (ip->i_flag&IUPD)
-                       ip->i_mtime = tm->tv_sec;
-               if (ip->i_flag&ICHG)
-                       ip->i_ctime = time.tv_sec;
-               ip->i_flag &= ~(IUPD|IACC|ICHG|IMOD);
-               dp = bp->b_un.b_dino + itoo(fs, ip->i_number);
-               dp->di_ic = ip->i_ic;
-               if (waitfor)
-                       bwrite(bp);
-               else
-                       bdwrite(bp);
+       if ((ip->i_flag & (IUPD|IACC|ICHG|IMOD)) == 0)
+               return (0);
+       if (vp->v_mount->m_flag & M_RDONLY)
+               return (0);
+       error = bread(ip->i_devvp, fsbtodb(fs, itod(fs, ip->i_number)),
+               (int)fs->fs_bsize, &bp);
+       if (error) {
+               brelse(bp);
+               return (error);
+       }
+       if (ip->i_flag&IACC)
+               ip->i_atime = ta->tv_sec;
+       if (ip->i_flag&IUPD)
+               ip->i_mtime = tm->tv_sec;
+       if (ip->i_flag&ICHG)
+               ip->i_ctime = time.tv_sec;
+       ip->i_flag &= ~(IUPD|IACC|ICHG|IMOD);
+       dp = bp->b_un.b_dino + itoo(fs, ip->i_number);
+       dp->di_ic = ip->i_ic;
+       if (waitfor) {
+               return (bwrite(bp));
+       } else {
+               bdwrite(bp);
+               return (0);
        }
 }
 
        }
 }
 
@@ -393,17 +540,16 @@ itrunc(oip, length)
        register struct fs *fs;
        register struct inode *ip;
        struct buf *bp;
        register struct fs *fs;
        register struct inode *ip;
        struct buf *bp;
-       int offset, osize, size, count, level;
-       long nblocks, blocksreleased = 0;
+       int offset, osize, size, level;
+       long count, nblocks, blocksreleased = 0;
        register int i;
        register int i;
-       dev_t dev;
+       int error, allerror = 0;
        struct inode tip;
        struct inode tip;
-       extern long indirtrunc();
 
        if (oip->i_size <= length) {
                oip->i_flag |= ICHG|IUPD;
 
        if (oip->i_size <= length) {
                oip->i_flag |= ICHG|IUPD;
-               iupdat(oip, &time, &time, 1);
-               return;
+               error = iupdat(oip, &time, &time, 1);
+               return (error);
        }
        /*
         * Calculate index into inode's block list of
        }
        /*
         * Calculate index into inode's block list of
@@ -430,25 +576,20 @@ itrunc(oip, length)
                oip->i_size = length;
        } else {
                lbn = lblkno(fs, length);
                oip->i_size = length;
        } else {
                lbn = lblkno(fs, length);
-               bn = fsbtodb(fs, bmap(oip, lbn, B_WRITE, offset));
-               if (u.u_error || (long)bn < 0)
-                       return;
+               error = balloc(oip, lbn, offset, &bn, B_CLRBUF);
+               if (error)
+                       return (error);
+               if ((long)bn < 0)
+                       panic("itrunc: hole");
                oip->i_size = length;
                size = blksize(fs, oip, lbn);
                count = howmany(size, CLBYTES);
                oip->i_size = length;
                size = blksize(fs, oip, lbn);
                count = howmany(size, CLBYTES);
-               dev = oip->i_dev;
-               for (i = 0; i < count; i++)
-#ifdef SECSIZE
-                       munhash(dev, bn + i * CLBYTES / fs->fs_dbsize);
-#else SECSIZE
-                       munhash(dev, bn + i * CLBYTES / DEV_BSIZE);
-#endif SECSIZE
-               bp = bread(dev, bn, size);
-               if (bp->b_flags & B_ERROR) {
-                       u.u_error = EIO;
+                       munhash(oip->i_devvp, bn + i * CLBYTES / DEV_BSIZE);
+               error = bread(oip->i_devvp, bn, size, &bp);
+               if (error) {
                        oip->i_size = osize;
                        brelse(bp);
                        oip->i_size = osize;
                        brelse(bp);
-                       return;
+                       return (error);
                }
                bzero(bp->b_un.b_addr + offset, (unsigned)(size - offset));
                bdwrite(bp);
                }
                bzero(bp->b_un.b_addr + offset, (unsigned)(size - offset));
                bdwrite(bp);
@@ -471,7 +612,7 @@ itrunc(oip, length)
        for (i = NDADDR - 1; i > lastblock; i--)
                oip->i_db[i] = 0;
        oip->i_flag |= ICHG|IUPD;
        for (i = NDADDR - 1; i > lastblock; i--)
                oip->i_db[i] = 0;
        oip->i_flag |= ICHG|IUPD;
-       syncip(oip);
+       allerror = syncip(oip);
 
        /*
         * Indirect blocks first.
 
        /*
         * Indirect blocks first.
@@ -480,8 +621,11 @@ itrunc(oip, length)
        for (level = TRIPLE; level >= SINGLE; level--) {
                bn = ip->i_ib[level];
                if (bn != 0) {
        for (level = TRIPLE; level >= SINGLE; level--) {
                bn = ip->i_ib[level];
                if (bn != 0) {
-                       blocksreleased +=
-                           indirtrunc(ip, bn, lastiblock[level], level);
+                       error = indirtrunc(ip, bn, lastiblock[level], level,
+                               &count);
+                       if (error)
+                               allerror = error;
+                       blocksreleased += count;
                        if (lastiblock[level] < 0) {
                                ip->i_ib[level] = 0;
                                blkfree(ip, bn, (off_t)fs->fs_bsize);
                        if (lastiblock[level] < 0) {
                                ip->i_ib[level] = 0;
                                blkfree(ip, bn, (off_t)fs->fs_bsize);
@@ -553,6 +697,7 @@ done:
 #ifdef QUOTA
        (void) chkdq(oip, -blocksreleased, 0);
 #endif
 #ifdef QUOTA
        (void) chkdq(oip, -blocksreleased, 0);
 #endif
+       return (allerror);
 }
 
 /*
 }
 
 /*
@@ -565,19 +710,20 @@ done:
  *
  * NB: triple indirect blocks are untested.
  */
  *
  * NB: triple indirect blocks are untested.
  */
-long
-indirtrunc(ip, bn, lastbn, level)
+indirtrunc(ip, bn, lastbn, level, countp)
        register struct inode *ip;
        daddr_t bn, lastbn;
        int level;
        register struct inode *ip;
        daddr_t bn, lastbn;
        int level;
+       long *countp;
 {
        register int i;
        struct buf *bp;
        register struct fs *fs = ip->i_fs;
        register daddr_t *bap;
        daddr_t *copy, nb, last;
 {
        register int i;
        struct buf *bp;
        register struct fs *fs = ip->i_fs;
        register daddr_t *bap;
        daddr_t *copy, nb, last;
-       long factor;
-       int blocksreleased = 0, nblocks;
+       long blkcount, factor;
+       int nblocks, blocksreleased = 0;
+       int error, allerror = 0;
 
        /*
         * Calculate index in current block of last
 
        /*
         * Calculate index in current block of last
@@ -600,18 +746,20 @@ indirtrunc(ip, bn, lastbn, level)
        bp = bread(ip->i_dev, fsbtodb(fs, bn), (int)fs->fs_bsize,
            fs->fs_dbsize);
 #else SECSIZE
        bp = bread(ip->i_dev, fsbtodb(fs, bn), (int)fs->fs_bsize,
            fs->fs_dbsize);
 #else SECSIZE
-       bp = bread(ip->i_dev, fsbtodb(fs, bn), (int)fs->fs_bsize);
-#endif SECSIZE
-       if (bp->b_flags&B_ERROR) {
+       error = bread(ip->i_devvp, fsbtodb(fs, bn), (int)fs->fs_bsize, &bp);
+       if (error) {
                brelse(bp);
                brelse(bp);
-               return (0);
+               *countp = 0;
+               return (error);
        }
        bap = bp->b_un.b_daddr;
        MALLOC(copy, daddr_t *, fs->fs_bsize, M_TEMP, M_WAITOK);
        bcopy((caddr_t)bap, (caddr_t)copy, (u_int)fs->fs_bsize);
        bzero((caddr_t)&bap[last + 1],
          (u_int)(NINDIR(fs) - (last + 1)) * sizeof (daddr_t));
        }
        bap = bp->b_un.b_daddr;
        MALLOC(copy, daddr_t *, fs->fs_bsize, M_TEMP, M_WAITOK);
        bcopy((caddr_t)bap, (caddr_t)copy, (u_int)fs->fs_bsize);
        bzero((caddr_t)&bap[last + 1],
          (u_int)(NINDIR(fs) - (last + 1)) * sizeof (daddr_t));
-       bwrite(bp);
+       error = bwrite(bp);
+       if (error)
+               allerror = error;
        bap = copy;
 
        /*
        bap = copy;
 
        /*
@@ -621,9 +769,13 @@ indirtrunc(ip, bn, lastbn, level)
                nb = bap[i];
                if (nb == 0)
                        continue;
                nb = bap[i];
                if (nb == 0)
                        continue;
-               if (level > SINGLE)
-                       blocksreleased +=
-                           indirtrunc(ip, nb, (daddr_t)-1, level - 1);
+               if (level > SINGLE) {
+                       error = indirtrunc(ip, nb, (daddr_t)-1, level - 1,
+                               &blkcount);
+                       if (error)
+                               allerror = error;
+                       blocksreleased += blkcount;
+               }
                blkfree(ip, nb, (off_t)fs->fs_bsize);
                blocksreleased += nblocks;
        }
                blkfree(ip, nb, (off_t)fs->fs_bsize);
                blocksreleased += nblocks;
        }
@@ -634,11 +786,16 @@ indirtrunc(ip, bn, lastbn, level)
        if (level > SINGLE && lastbn >= 0) {
                last = lastbn % factor;
                nb = bap[i];
        if (level > SINGLE && lastbn >= 0) {
                last = lastbn % factor;
                nb = bap[i];
-               if (nb != 0)
-                       blocksreleased += indirtrunc(ip, nb, last, level - 1);
+               if (nb != 0) {
+                       error = indirtrunc(ip, nb, last, level - 1, &blkcount);
+                       if (error)
+                               allerror = error;
+                       blocksreleased += blkcount;
+               }
        }
        FREE(copy, M_TEMP);
        }
        FREE(copy, M_TEMP);
-       return (blocksreleased);
+       *countp = blocksreleased;
+       return (allerror);
 }
 
 /*
 }
 
 /*
@@ -664,14 +821,14 @@ iflush(dev)
 #else
                if (ip->i_dev == dev)
 #endif
 #else
                if (ip->i_dev == dev)
 #endif
-                       if (ip->i_count)
+                       if (ITOV(ip)->v_count)
                                return (EBUSY);
                        else {
                                remque(ip);
                                ip->i_forw = ip;
                                ip->i_back = ip;
                                /*
                                return (EBUSY);
                        else {
                                remque(ip);
                                ip->i_forw = ip;
                                ip->i_back = ip;
                                /*
-                                * as i_count == 0, the inode was on the free
+                                * as v_count == 0, the inode was on the free
                                 * list already, just leave it there, it will
                                 * fall off the bottom eventually. We could
                                 * perhaps move it to the head of the free
                                 * list already, just leave it there, it will
                                 * fall off the bottom eventually. We could
                                 * perhaps move it to the head of the free
@@ -683,6 +840,10 @@ iflush(dev)
                                dqrele(ip->i_dquot);
                                ip->i_dquot = NODQUOT;
 #endif
                                dqrele(ip->i_dquot);
                                ip->i_dquot = NODQUOT;
 #endif
+                               if (ip->i_devvp) {
+                                       vrele(ip->i_devvp);
+                                       ip->i_devvp = 0;
+                               }
                        }
        }
        return (0);
                        }
        }
        return (0);
@@ -695,7 +856,11 @@ ilock(ip)
        register struct inode *ip;
 {
 
        register struct inode *ip;
 {
 
-       ILOCK(ip);
+       while (ip->i_flag & ILOCKED) {
+               ip->i_flag |= IWANT;
+               (void) sleep((caddr_t)ip, PINOD);
+       }
+       ip->i_flag |= ILOCKED;
 }
 
 /*
 }
 
 /*
@@ -705,5 +870,55 @@ iunlock(ip)
        register struct inode *ip;
 {
 
        register struct inode *ip;
 {
 
-       IUNLOCK(ip);
+       if ((ip->i_flag & ILOCKED) == 0)
+               printf("unlocking unlocked inode %d on dev 0x%x\n",
+                       ip->i_number, ip->i_dev);
+       ip->i_flag &= ~ILOCKED;
+       if (ip->i_flag&IWANT) {
+               ip->i_flag &= ~IWANT;
+               wakeup((caddr_t)ip);
+       }
+}
+
+/*
+ * Check mode permission on inode pointer. Mode is READ, WRITE or EXEC.
+ * The mode is shifted to select the owner/group/other fields. The
+ * super user is granted all permissions.
+ *
+ * NB: Called from vnode op table. It seems this could all be done
+ * using vattr's but...
+ */
+iaccess(ip, mode, cred)
+       register struct inode *ip;
+       register int mode;
+       struct ucred *cred;
+{
+       register gid_t *gp;
+       register struct vnode *vp = ITOV(ip);
+       int i;
+
+       /*
+        * If you're the super-user,
+        * you always get access.
+        */
+       if (cred->cr_uid == 0)
+               return (0);
+       /*
+        * Access check is based on only one of owner, group, public.
+        * If not owner, then check group. If not a member of the
+        * group, then check public access.
+        */
+       if (cred->cr_uid != ip->i_uid) {
+               mode >>= 3;
+               gp = cred->cr_groups;
+               for (i = 0; i < cred->cr_ngroups; i++, gp++)
+                       if (ip->i_gid == *gp)
+                               goto found;
+               mode >>= 3;
+found:
+               ;
+       }
+       if ((ip->i_mode & mode) != 0)
+               return (0);
+       return (EACCES);
 }
 }
index 9456b4f..3101cc1 100644 (file)
 /*
 /*
- * Copyright (c) 1982, 1986 Regents of the University of California.
- * All rights reserved.  The Berkeley software License Agreement
- * specifies the terms and conditions for redistribution.
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
  *
  *
- *     @(#)ufs_vfsops.c        7.12 (Berkeley) %G%
+ * 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.
+ *
+ *     @(#)ufs_vfsops.c        7.13 (Berkeley) %G%
  */
 
  */
 
+
 #include "param.h"
 #include "systm.h"
 #include "param.h"
 #include "systm.h"
-#include "dir.h"
-#include "user.h"
-#include "inode.h"
-#include "proc.h"
-#include "fs.h"
-#include "buf.h"
+#include "time.h"
+#include "kernel.h"
+#include "namei.h"
+#include "vnode.h"
 #include "mount.h"
 #include "mount.h"
+#include "buf.h"
 #include "file.h"
 #include "file.h"
-#include "conf.h"
-#include "ioctl.h"
 #include "disklabel.h"
 #include "disklabel.h"
-#include "stat.h"
+#include "ioctl.h"
+#include "errno.h"
 #include "malloc.h"
 #include "malloc.h"
+#include "../ufs/fs.h"
+#include "../ufs/ufsmount.h"
+#include "../ufs/inode.h"
 #include "ioctl.h"
 #include "disklabel.h"
 #include "stat.h"
 
 #include "ioctl.h"
 #include "disklabel.h"
 #include "stat.h"
 
-smount()
+/*
+ * ufs vfs operations.
+ */
+int ufs_mount();
+int ufs_unmount();
+int ufs_root();
+int ufs_statfs();
+int ufs_sync();
+int ufs_fhtovp();
+int ufs_vptofh();
+
+struct vfsops ufs_vfsops = {
+       ufs_mount,
+       ufs_unmount,
+       ufs_root,
+       ufs_statfs,
+       ufs_sync,
+       ufs_fhtovp,
+       ufs_vptofh
+};
+
+/*
+ * ufs mount table.
+ */
+struct ufsmount mounttab[NMOUNT];
+
+/*
+ * Called by vfs_mountroot when ufs is going to be mounted as root
+ *
+ * XXX - Need to have a way of figuring the name of the root device
+ */
+#define ROOTNAME       "root device"
+
+ufs_mountroot()
 {
 {
-       register struct a {
-               char    *fspec;
-               char    *freg;
-               int     ronly;
-       } *uap = (struct a *)u.u_ap;
-       dev_t dev;
-       register struct inode *ip;
+       register struct mount *mp;
+       extern struct vnode *rootvp;
+       struct ufsmount *ump;
        register struct fs *fs;
        register struct fs *fs;
-       register struct nameidata *ndp = &u.u_nd;
-       u_int len;
+       u_int size;
+       int error;
 
 
-       u.u_error = getmdev(&dev, uap->fspec);
-       if (u.u_error)
-               return;
-       ndp->ni_nameiop = LOOKUP | FOLLOW;
-       ndp->ni_segflg = UIO_USERSPACE;
-       ndp->ni_dirp = (caddr_t)uap->freg;
-       ip = namei(ndp);
-       if (ip == NULL)
-               return;
-       if (ip->i_count != 1) {
-               iput(ip);
-               u.u_error = EBUSY;
-               return;
+       mp = (struct mount *)malloc((u_long)sizeof(struct mount),
+               M_MOUNT, M_WAITOK);
+       mp->m_op = &ufs_vfsops;
+       mp->m_flag = 0;
+       mp->m_exroot = 0;
+       error = mountfs(rootvp, mp);
+       if (error) {
+               free((caddr_t)mp, M_MOUNT);
+               return (error);
        }
        }
-       if ((ip->i_mode&IFMT) != IFDIR) {
-               iput(ip);
-               u.u_error = ENOTDIR;
-               return;
+       error = vfs_add((struct vnode *)0, mp, 0);
+       if (error) {
+               (void)ufs_unmount(mp, 0);
+               free((caddr_t)mp, M_MOUNT);
+               return (error);
        }
        }
-       fs = mountfs(dev, uap->ronly, ip);
-       if (fs == 0) {
-               iput(ip);
-               return;
+       ump = VFSTOUFS(mp);
+       fs = ump->um_fs;
+       fs->fs_fsmnt[0] = '/';
+       bzero(fs->fs_fsmnt + 1, sizeof(fs->fs_fsmnt) - 1);
+       (void) copystr(ROOTNAME, ump->um_mntname, MNAMELEN - 1, &size);
+       bzero(ump->um_mntname + size, MNAMELEN - size);
+       vfs_unlock(mp);
+       inittodr(fs->fs_time);
+       return (0);
+}
+
+/*
+ * VFS Operations.
+ *
+ * mount system call
+ */
+ufs_mount(mp, path, data, ndp)
+       struct mount *mp;
+       char *path;
+       caddr_t data;
+       struct nameidata *ndp;
+{
+       struct vnode *devvp;
+       struct ufs_args args;
+       struct ufsmount *ump;
+       register struct fs *fs;
+       u_int size;
+       int error;
+
+       if (error = copyin(data, (caddr_t)&args, sizeof (struct ufs_args)))
+               return (error);
+       if ((error = getmdev(&devvp, args.fspec, ndp)) != 0)
+               return (error);
+       error = mountfs(devvp, mp);
+       if (error) {
+               vrele(devvp);
+               return (error);
        }
        }
-       (void) copyinstr(uap->freg, fs->fs_fsmnt, sizeof(fs->fs_fsmnt)-1, &len);
-       bzero(fs->fs_fsmnt + len, sizeof (fs->fs_fsmnt) - len);
+       ump = VFSTOUFS(mp);
+       fs = ump->um_fs;
+       (void) copyinstr(path, fs->fs_fsmnt, sizeof(fs->fs_fsmnt) - 1, &size);
+       bzero(fs->fs_fsmnt + size, sizeof(fs->fs_fsmnt) - size);
+       (void) copyinstr(args.fspec, ump->um_mntname, MNAMELEN - 1, &size);
+       bzero(ump->um_mntname + size, MNAMELEN - size);
+       return (0);
 }
 
 }
 
-struct fs *
-mountfs(dev, ronly, ip)
-       dev_t dev;
-       int ronly;
-       struct inode *ip;
+/*
+ * Common code for mount and mountroot
+ */
+mountfs(devvp, mp)
+       struct vnode *devvp;
+       struct mount *mp;
 {
 {
-       register struct mount *mp;
-       struct mount *fmp = NULL;
-       register struct buf *bp = NULL;
+       register struct ufsmount *ump;
+       struct ufsmount *fmp = NULL;
+       struct buf *bp = NULL;
        register struct fs *fs;
        register struct fs *fs;
+       dev_t dev = devvp->v_rdev;
        struct partinfo dpart;
        int havepart = 0, blks;
        caddr_t base, space;
        struct partinfo dpart;
        int havepart = 0, blks;
        caddr_t base, space;
-       int i, size;
-       register error;
+       int havepart = 0, blks;
+       int error, i, size;
        int needclose = 0;
        int needclose = 0;
+       int ronly = (mp->m_flag & M_RDONLY) != 0;
 
 
-       for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++) {
-               if (mp->m_fs == NULL) {
+       for (ump = &mounttab[0]; ump < &mounttab[NMOUNT]; ump++) {
+               if (ump->um_fs == NULL) {
                        if (fmp == NULL)
                        if (fmp == NULL)
-                               fmp = mp;
-               } else if (dev == mp->m_dev) {
-                       u.u_error = EBUSY;              /* XXX */
-                       return ((struct fs *) NULL);
+                               fmp = ump;
+               } else if (dev == ump->um_dev) {
+                       return (EBUSY);         /* needs translation */
                }
        }
                }
        }
-       if ((mp = fmp) == NULL) {
-               u.u_error = EMFILE;             /* needs translation      XXX */
-               return ((struct fs *) NULL);
-       }
-       mp->m_fs = (struct fs *)1;      /* just to reserve this slot */
-       mp->m_dev = dev;
-       mp->m_inodp = NULL;
-       error =
            (*bdevsw[major(dev)].d_open)(dev, ronly ? FREAD : FREAD|FWRITE,
                S_IFBLK);
        if (error) {
            (*bdevsw[major(dev)].d_open)(dev, ronly ? FREAD : FREAD|FWRITE,
                S_IFBLK);
        if (error) {
-               u.u_error = error;
-               mp->m_fs = NULL;
-               return ((struct fs *) NULL);
+               ump->um_fs = NULL;
+               return (error);
        }
        needclose = 1;
        }
        needclose = 1;
-       if ((*bdevsw[major(dev)].d_ioctl)(dev, DIOCGPART,
-           (caddr_t)&dpart, FREAD) == 0) {
-               havepart = 1;
-               size = dpart.disklab->d_secsize;
-       } else
+       if (VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, FREAD,
+           (struct ucred *)0) != 0)
                size = DEV_BSIZE;
                size = DEV_BSIZE;
-#ifdef SECSIZE
-       /*
-        * If possible, determine hardware sector size
-        * and adjust fsbtodb to correspond.
-        */
-#endif SECSIZE
-       if ((*bdevsw[major(dev)].d_ioctl)(dev, DIOCGPART,
-           (caddr_t)&dpart, FREAD) == 0) {
+       else {
                havepart = 1;
                size = dpart.disklab->d_secsize;
                havepart = 1;
                size = dpart.disklab->d_secsize;
-#ifdef SECSIZE
-               if (size < MINSECSIZE) {
-                       error = EINVAL;
-                       goto out;
-               }
-#endif SECSIZE
-       } else
-               size = DEV_BSIZE;
-#ifdef SECSIZE
-       tp = bread(dev, (daddr_t)(SBOFF / size), SBSIZE, size);
-#else SECSIZE
-       bp = bread(dev, SBLOCK, SBSIZE);
-       if (bp->b_flags & B_ERROR) {
-               mp->m_fs = NULL;
+       }
+       if (error = bread(devvp, SBLOCK, SBSIZE, &bp)) {
+               ump->um_fs = NULL;
                goto out;
        }
        fs = bp->b_un.b_fs;
                goto out;
        }
        fs = bp->b_un.b_fs;
-       if (fs->fs_magic != FS_MAGIC || fs->fs_bsize > MAXBSIZE ||
-           fs->fs_bsize < sizeof(struct fs)) {
-               error = EINVAL;         /* also needs translation */
+               ump->um_fs = NULL;
+               error = EINVAL;         /* XXX also needs translation */
                goto out;
        }
                goto out;
        }
-       mp->m_fs = (struct fs *)malloc((u_long)fs->fs_sbsize, M_SUPERBLK,
+       ump->um_fs = (struct fs *)malloc((u_long)fs->fs_sbsize, M_SUPERBLK,
            M_WAITOK);
            M_WAITOK);
-       bcopy((caddr_t)bp->b_un.b_addr, (caddr_t)mp->m_fs,
+       bcopy((caddr_t)bp->b_un.b_addr, (caddr_t)ump->um_fs,
           (u_int)fs->fs_sbsize);
        brelse(bp);
        bp = NULL;
           (u_int)fs->fs_sbsize);
        brelse(bp);
        bp = NULL;
-       fs = mp->m_fs;
-       fs->fs_ronly = (ronly != 0);
+       fs = ump->um_fs;
+       fs->fs_ronly = ronly;
        if (ronly == 0)
                fs->fs_fmod = 1;
        if (havepart) {
        if (ronly == 0)
                fs->fs_fmod = 1;
        if (havepart) {
@@ -190,10 +238,6 @@ mountfs(dev, ronly, ip)
        blks = howmany(fs->fs_cssize, fs->fs_fsize);
        base = space = (caddr_t)malloc((u_long)fs->fs_cssize, M_SUPERBLK,
            M_WAITOK);
        blks = howmany(fs->fs_cssize, fs->fs_fsize);
        base = space = (caddr_t)malloc((u_long)fs->fs_cssize, M_SUPERBLK,
            M_WAITOK);
-       if (space == NULL) {
-               error = ENOMEM;
-               goto out;
-       }
        for (i = 0; i < blks; i += fs->fs_frag) {
                size = fs->fs_bsize;
                if (i + fs->fs_frag > blks)
        for (i = 0; i < blks; i += fs->fs_frag) {
                size = fs->fs_bsize;
                if (i + fs->fs_frag > blks)
@@ -202,8 +246,8 @@ mountfs(dev, ronly, ip)
                tp = bread(dev, fsbtodb(fs, fs->fs_csaddr + i), size,
                    fs->fs_dbsize);
 #else SECSIZE
                tp = bread(dev, fsbtodb(fs, fs->fs_csaddr + i), size,
                    fs->fs_dbsize);
 #else SECSIZE
-               bp = bread(dev, fsbtodb(fs, fs->fs_csaddr + i), size);
-               if (bp->b_flags&B_ERROR) {
+               error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + i), size, &bp);
+               if (error) {
                        free((caddr_t)base, M_SUPERBLK);
                        goto out;
                }
                        free((caddr_t)base, M_SUPERBLK);
                        goto out;
                }
@@ -213,64 +257,53 @@ mountfs(dev, ronly, ip)
                brelse(bp);
                bp = NULL;
        }
                brelse(bp);
                bp = NULL;
        }
-       mp->m_inodp = ip;
-       if (ip) {
-               ip->i_flag |= IMOUNT;
-               cacheinval(ip);
-               iunlock(ip);
-       }
+       mp->m_data = (qaddr_t)ump;
+       mp->m_bsize = fs->fs_bsize;
+       mp->m_fsize = fs->fs_fsize;
+       mp->m_fsid.val[0] = (long)dev;
+       mp->m_fsid.val[1] = MOUNT_UFS;
+       ump->um_mountp = mp;
+       ump->um_dev = dev;
+       ump->um_devvp = devvp;
+       ump->um_qinod = NULL;
+
        /* Sanity checks for old file systems.                     XXX */
        fs->fs_npsect = MAX(fs->fs_npsect, fs->fs_nsect);       /* XXX */
        fs->fs_interleave = MAX(fs->fs_interleave, 1);          /* XXX */
        if (fs->fs_postblformat == FS_42POSTBLFMT)              /* XXX */
                fs->fs_nrpos = 8;                               /* XXX */
 
        /* Sanity checks for old file systems.                     XXX */
        fs->fs_npsect = MAX(fs->fs_npsect, fs->fs_nsect);       /* XXX */
        fs->fs_interleave = MAX(fs->fs_interleave, 1);          /* XXX */
        if (fs->fs_postblformat == FS_42POSTBLFMT)              /* XXX */
                fs->fs_nrpos = 8;                               /* XXX */
 
-       return (fs);
+       return (0);
 out:
        if (needclose)
 out:
        if (needclose)
-               (void) closei(dev, IFBLK, ronly? FREAD : FREAD|FWRITE);
-       if (mp->m_fs) {
-               free((caddr_t)mp->m_fs, M_SUPERBLK);
-               mp->m_fs = NULL;
+               (void) VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE,
+                       (struct ucred *)0);
+       if (ump->um_fs) {
+               free((caddr_t)ump->um_fs, M_SUPERBLK);
+               ump->um_fs = NULL;
        }
        if (bp)
                brelse(bp);
        }
        if (bp)
                brelse(bp);
-       u.u_error = error ? error : EIO;                        /* XXX */
-       return ((struct fs *) NULL);
+       return (error);
 }
 
 }
 
-umount()
-{
-       struct a {
-               char    *fspec;
-       } *uap = (struct a *)u.u_ap;
 
 
-       u.u_error = unmount1(uap->fspec, 0);
-}
-
-unmount1(fname, forcibly)
-       caddr_t fname;
-       int forcibly;
+/*
+ * unmount system call
+ */
+ufs_unmount(mp, flags)
+       struct mount *mp;
+       int flags;
 {
 {
-       dev_t dev;
-       register struct mount *mp;
-       int error;
-       register struct inode *ip;
+       register struct ufsmount *ump;
        register struct fs *fs;
        register struct fs *fs;
+       dev_t dev;
+       int error, ronly;
 
 
-       forcibly = 0;                                   /* XXX */
-       forcibly = 0;                                   /* XXX */
-       error = getmdev(&dev, fname);
-       if (error)
-               return (error);
-       for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++)
-               if (mp->m_fs != NULL && dev == mp->m_dev)
-                       goto found;
-       return (EINVAL);
-found:
-       xumount(dev);   /* remove unused sticky files from text table */
-       nchinval(dev);  /* flush the name cache */
-       update();
+       if (flags & MNT_FORCE)
+               return (EINVAL);
+       ump = VFSTOUFS(mp);
+       dev = ump->um_dev;
 #ifdef QUOTA
        if ((error = iflush(dev, mp->m_qinod)) && !forcibly)
 #else
 #ifdef QUOTA
        if ((error = iflush(dev, mp->m_qinod)) && !forcibly)
 #else
@@ -278,40 +311,152 @@ found:
 #endif
                return (error);
 #ifdef QUOTA
 #endif
                return (error);
 #ifdef QUOTA
-       closedq(mp);
+       (void)closedq(ump);
        /*
         * Here we have to iflush again to get rid of the quota inode.
         * A drag, but it would be ugly to cheat, & this doesn't happen often.
         */
        (void)iflush(dev, (struct inode *)NULL);
 #endif
        /*
         * Here we have to iflush again to get rid of the quota inode.
         * A drag, but it would be ugly to cheat, & this doesn't happen often.
         */
        (void)iflush(dev, (struct inode *)NULL);
 #endif
-       ip = mp->m_inodp;
-       ip->i_flag &= ~IMOUNT;
-       fs = mp->m_fs;
+       fs = ump->um_fs;
+       ronly = !fs->fs_ronly;
        free((caddr_t)fs->fs_csp[0], M_SUPERBLK);
        free((caddr_t)fs->fs_csp[0], M_SUPERBLK);
-       free((caddr_t)mp->m_fs, M_SUPERBLK);
-       mp->m_fs = NULL;
-       mp->m_dev = NODEV;
-       mpurge(mp - &mount[0]);
        error = closei(dev, IFBLK, fs->fs_ronly? FREAD : FREAD|FWRITE);
        irele(ip);
        return (error);
 }
 
        error = closei(dev, IFBLK, fs->fs_ronly? FREAD : FREAD|FWRITE);
        irele(ip);
        return (error);
 }
 
-sbupdate(mp)
+/*
+ * Return root of a filesystem
+ */
+ufs_root(mp, vpp)
+       struct mount *mp;
+       struct vnode **vpp;
+{
+       struct inode tip, *ip;
+       int error;
+
+       tip.i_dev = VFSTOUFS(mp)->um_dev;
+       tip.i_vnode.v_mount = mp;
+       error = iget(&tip, (ino_t)ROOTINO, &ip);
+       if (error)
+               return (error);
+       *vpp = ITOV(ip);
+       return (0);
+}
+
+/*
+ * Get file system statistics.
+ */
+ufs_statfs(mp, sbp)
+       struct mount *mp;
+       register struct statfs *sbp;
+{
+       register struct ufsmount *ump;
+       register struct fs *fs;
+
+       ump = VFSTOUFS(mp);
+       fs = ump->um_fs;
+       if (fs->fs_magic != FS_MAGIC)
+               panic("ufs_statfs");
+       sbp->f_type = MOUNT_UFS;
+       sbp->f_flags = mp->m_flag &~ (M_MLOCK|M_MWAIT);
+       sbp->f_fsize = fs->fs_fsize;
+       sbp->f_bsize = fs->fs_bsize;
+       sbp->f_blocks = fs->fs_dsize;
+       sbp->f_bfree = fs->fs_cstotal.cs_nbfree * fs->fs_frag +
+               fs->fs_cstotal.cs_nffree;
+       sbp->f_bavail = (fs->fs_dsize * (100 - fs->fs_minfree) / 100) -
+               (fs->fs_dsize - sbp->f_bfree);
+       if (sbp->f_bavail < 0)
+               sbp->f_bavail = 0;
+       sbp->f_files =  fs->fs_ncg * fs->fs_ipg;
+       sbp->f_ffree = fs->fs_cstotal.cs_nifree;
+       sbp->f_fsid = mp->m_fsid;
+       bcopy((caddr_t)fs->fs_fsmnt, (caddr_t)&sbp->f_mntonname[0], MNAMELEN);
+       bcopy((caddr_t)ump->um_mntname, (caddr_t)&sbp->f_mntfromname[0],
+               MNAMELEN);
+       return (0);
+}
+
+int    syncprt = 0;
+
+/*
+ * Go through the disk queues to initiate sandbagged IO;
+ * go through the inodes to write those that have been modified;
+ * initiate the writing of the super block if it has been modified.
+ */
+ufs_sync(mp, waitfor)
        struct mount *mp;
        struct mount *mp;
+       int waitfor;
 {
 {
-       register struct fs *fs = mp->m_fs;
+       register struct inode *ip;
+       register struct ufsmount *ump = VFSTOUFS(mp);
+       register struct fs *fs;
+       int error = 0;
+       static int updlock = 0;
+
+       if (syncprt)
+               bufstats();
+       if (updlock)
+               return (EBUSY);
+       fs = ump->um_fs;
+       if (fs == (struct fs *)1)
+               return (0);
+       updlock++;
+       /*
+        * Write back modified superblock.
+        * Consistency check that the superblock
+        * is still in the buffer cache.
+        */
+       if (fs->fs_fmod != 0) {
+               if (fs->fs_ronly != 0) {                /* XXX */
+                       printf("fs = %s\n", fs->fs_fsmnt);
+                       panic("update: rofs mod");
+               }
+               fs->fs_fmod = 0;
+               fs->fs_time = time.tv_sec;
+               error = sbupdate(ump, waitfor);
+       }
+       /*
+        * Write back each (modified) inode.
+        */
+       for (ip = inode; ip < inodeNINODE; ip++) {
+               if (ip->i_devvp != ump->um_devvp ||
+                   (ip->i_flag & ILOCKED) != 0 || ITOV(ip)->v_count == 0 ||
+                   (ip->i_flag & (IMOD|IACC|IUPD|ICHG)) == 0)
+                       continue;
+               ip->i_flag |= ILOCKED;
+               ITOV(ip)->v_count++;
+               error = iupdat(ip, &time, &time, waitfor == MNT_WAIT);
+               iput(ip);
+       }
+       updlock = 0;
+       /*
+        * Force stale buffer cache information to be flushed.
+        */
+       bflush(ump->um_devvp->v_rdev);
+       return (error);
+}
+
+/*
+ * Write a superblock and associated information back to disk.
+ */
+sbupdate(mp, waitfor)
+       struct ufsmount *mp;
+       int waitfor;
+{
+       register struct fs *fs = mp->um_fs;
        register struct buf *bp;
        int blks;
        caddr_t space;
        register struct buf *bp;
        int blks;
        caddr_t space;
-       int i, size;
+       int i, size, error = 0;
 
 #ifdef SECSIZE
        bp = getblk(mp->m_dev, (daddr_t)fsbtodb(fs, SBOFF / fs->fs_fsize),
            (int)fs->fs_sbsize, fs->fs_dbsize);
 #else SECSIZE
 
 #ifdef SECSIZE
        bp = getblk(mp->m_dev, (daddr_t)fsbtodb(fs, SBOFF / fs->fs_fsize),
            (int)fs->fs_sbsize, fs->fs_dbsize);
 #else SECSIZE
-       bp = getblk(mp->m_dev, SBLOCK, (int)fs->fs_sbsize);
+       bp = getblk(mp->um_devvp, SBLOCK, (int)fs->fs_sbsize);
 #endif SECSIZE
        bcopy((caddr_t)fs, bp->b_un.b_addr, (u_int)fs->fs_sbsize);
        /* Restore compatibility to old file systems.              XXX */
 #endif SECSIZE
        bcopy((caddr_t)fs, bp->b_un.b_addr, (u_int)fs->fs_sbsize);
        /* Restore compatibility to old file systems.              XXX */
@@ -324,7 +469,10 @@ sbupdate(mp)
        bp->b_un.b_fs->fs_sparecon[0] = 0;
 #endif
 #endif SECSIZE
        bp->b_un.b_fs->fs_sparecon[0] = 0;
 #endif
 #endif SECSIZE
-       bwrite(bp);
+       if (waitfor == MNT_WAIT)
+               error = bwrite(bp);
+       else
+               bawrite(bp);
        blks = howmany(fs->fs_cssize, fs->fs_fsize);
        space = (caddr_t)fs->fs_csp[0];
        for (i = 0; i < blks; i += fs->fs_frag) {
        blks = howmany(fs->fs_cssize, fs->fs_fsize);
        space = (caddr_t)fs->fs_csp[0];
        for (i = 0; i < blks; i += fs->fs_frag) {
@@ -335,46 +483,118 @@ sbupdate(mp)
                bp = getblk(mp->m_dev, fsbtodb(fs, fs->fs_csaddr + i), size,
                    fs->fs_dbsize);
 #else SECSIZE
                bp = getblk(mp->m_dev, fsbtodb(fs, fs->fs_csaddr + i), size,
                    fs->fs_dbsize);
 #else SECSIZE
-               bp = getblk(mp->m_dev, fsbtodb(fs, fs->fs_csaddr + i), size);
+               bp = getblk(mp->um_devvp, fsbtodb(fs, fs->fs_csaddr + i), size);
 #endif SECSIZE
                bcopy(space, bp->b_un.b_addr, (u_int)size);
                space += size;
 #endif SECSIZE
                bcopy(space, bp->b_un.b_addr, (u_int)size);
                space += size;
-               bwrite(bp);
+               if (waitfor == MNT_WAIT)
+                       error = bwrite(bp);
+               else
+                       bawrite(bp);
        }
        }
+       return (error);
 }
 
 /*
 }
 
 /*
- * Common code for mount and umount.
+ * Print out statistics on the current allocation of the buffer pool.
+ * Can be enabled to print out on every ``sync'' by setting "syncprt"
+ * above.
+ */
+bufstats()
+{
+       int s, i, j, count;
+       register struct buf *bp, *dp;
+       int counts[MAXBSIZE/CLBYTES+1];
+       static char *bname[BQUEUES] = { "LOCKED", "LRU", "AGE", "EMPTY" };
+
+       for (bp = bfreelist, i = 0; bp < &bfreelist[BQUEUES]; bp++, i++) {
+               count = 0;
+               for (j = 0; j <= MAXBSIZE/CLBYTES; j++)
+                       counts[j] = 0;
+               s = splbio();
+               for (dp = bp->av_forw; dp != bp; dp = dp->av_forw) {
+                       counts[dp->b_bufsize/CLBYTES]++;
+                       count++;
+               }
+               splx(s);
+               printf("%s: total-%d", bname[i], count);
+               for (j = 0; j <= MAXBSIZE/CLBYTES; j++)
+                       if (counts[j] != 0)
+                               printf(", %d-%d", j * CLBYTES, counts[j]);
+               printf("\n");
+       }
+}
+
+/*
+ * File handle to vnode
+ */
+ufs_fhtovp(mp, fhp, vpp)
+       struct mount *mp;
+       struct fid *fhp;
+       struct vnode **vpp;
+{
+       register struct ufid *ufhp;
+       struct inode tip, *ip;
+       int error;
+
+       ufhp = (struct ufid *)fhp;
+       tip.i_dev = VFSTOUFS(mp)->um_dev;
+       tip.i_vnode.v_mount = mp;
+       if (error = iget(&tip, ufhp->ufid_ino, &ip)) {
+               *vpp = NULL;
+               return (error);
+       }
+       if (ip->i_gen != ufhp->ufid_gen) {
+               iput(ip);
+               *vpp = NULL;
+               return (EINVAL);
+       }
+       *vpp = ITOV(ip);
+       return (0);
+}
+
+/*
+ * Vnode pointer to File handle, should never happen.
+ */
+/* ARGSUSED */
+ufs_vptofh(mp, fhp, vpp)
+       struct mount *mp;
+       struct fid *fhp;
+       struct vnode **vpp;
+{
+
+       return (EINVAL);
+}
+
+/*
+ * Common code for mount and quota.
  * Check that the user's argument is a reasonable
  * thing on which to mount, and return the device number if so.
  */
  * Check that the user's argument is a reasonable
  * thing on which to mount, and return the device number if so.
  */
-getmdev(pdev, fname)
+getmdev(devvpp, fname, ndp)
+       struct vnode **devvpp;
        caddr_t fname;
        caddr_t fname;
-       dev_t *pdev;
+       register struct nameidata *ndp;
 {
 {
-       dev_t dev;
-       register struct inode *ip;
-       register struct nameidata *ndp = &u.u_nd;
+       register struct vnode *vp;
+       int error;
 
 
-       if (u.u_error = suser(u.u_cred, &u.u_acflag))
-               return (u.u_error);
-       ndp->ni_nameiop = LOOKUP | FOLLOW;
+       ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW;
        ndp->ni_segflg = UIO_USERSPACE;
        ndp->ni_dirp = fname;
        ndp->ni_segflg = UIO_USERSPACE;
        ndp->ni_dirp = fname;
-       ip = namei(ndp);
-       if (ip == NULL) {
-               if (u.u_error == ENOENT)
-                       return (ENODEV); /* needs translation */
-               return (u.u_error);
+       if (error = namei(ndp)) {
+               if (error == ENOENT)
+                       return (ENODEV);        /* needs translation */
+               return (error);
        }
        }
-       if ((ip->i_mode&IFMT) != IFBLK) {
-               iput(ip);
+       vp = ndp->ni_vp;
+       if (vp->v_type != VBLK) {
+               vput(vp);
                return (ENOTBLK);
        }
                return (ENOTBLK);
        }
-       dev = (dev_t)ip->i_rdev;
-       iput(ip);
-       if (major(dev) >= nblkdev)
+       if (major(vp->v_rdev) >= nblkdev)
                return (ENXIO);
                return (ENXIO);
-       *pdev = dev;
+       iunlock(VTOI(vp));
+       *devvpp = vp;
        return (0);
 }
        return (0);
 }
index 9fbd717..9be11ea 100644 (file)
 /*
 /*
- * Copyright (c) 1982, 1986 Regents of the University of California.
- * All rights reserved.  The Berkeley software License Agreement
- * specifies the terms and conditions for redistribution.
+ * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
+ * All rights reserved.
  *
  *
- *     @(#)ufs_vnops.c 7.6 (Berkeley) %G%
+ * 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.
+ *
+ *     @(#)ufs_vnops.c 7.7 (Berkeley) %G%
  */
 
 #include "param.h"
 #include "systm.h"
  */
 
 #include "param.h"
 #include "systm.h"
-#include "dir.h"
 #include "user.h"
 #include "kernel.h"
 #include "file.h"
 #include "stat.h"
 #include "user.h"
 #include "kernel.h"
 #include "file.h"
 #include "stat.h"
-#include "inode.h"
-#include "fs.h"
 #include "buf.h"
 #include "proc.h"
 #include "buf.h"
 #include "proc.h"
-#include "quota.h"
 #include "uio.h"
 #include "socket.h"
 #include "socketvar.h"
 #include "uio.h"
 #include "socket.h"
 #include "socketvar.h"
+#include "conf.h"
 #include "mount.h"
 #include "mount.h"
-
-extern struct fileops inodeops;
-struct file *getinode();
+#include "vnode.h"
+#include "../ufs/inode.h"
+#include "../ufs/fs.h"
+#include "../ufs/quota.h"
 
 /*
 
 /*
- * Change current working directory (``.'').
+ * Global vfs data structures for ufs
  */
  */
-chdir()
-{
 
 
-       chdirec(&u.u_cdir);
-}
+int    ufs_lookup(),
+       ufs_create(),
+       ufs_mknod(),
+       ufs_open(),
+       ufs_close(),
+       ufs_access(),
+       ufs_getattr(),
+       ufs_setattr(),
+       ufs_read(),
+       ufs_write(),
+       ufs_ioctl(),
+       ufs_select(),
+       ufs_mmap(),
+       ufs_fsync(),
+       ufs_seek(),
+       ufs_remove(),
+       ufs_link(),
+       ufs_rename(),
+       ufs_mkdir(),
+       ufs_rmdir(),
+       ufs_symlink(),
+       ufs_readdir(),
+       ufs_readlink(),
+       ufs_abortop(),
+       ufs_inactive(),
+       ufs_lock(),
+       ufs_unlock(),
+       ufs_bmap(),
+       ufs_strategy();
+
+struct vnodeops ufs_vnodeops = {
+       ufs_lookup,
+       ufs_create,
+       ufs_mknod,
+       ufs_open,
+       ufs_close,
+       ufs_access,
+       ufs_getattr,
+       ufs_setattr,
+       ufs_read,
+       ufs_write,
+       ufs_ioctl,
+       ufs_select,
+       ufs_mmap,
+       ufs_fsync,
+       ufs_seek,
+       ufs_remove,
+       ufs_link,
+       ufs_rename,
+       ufs_mkdir,
+       ufs_rmdir,
+       ufs_symlink,
+       ufs_readdir,
+       ufs_readlink,
+       ufs_abortop,
+       ufs_inactive,
+       ufs_lock,
+       ufs_unlock,
+       ufs_bmap,
+       ufs_strategy,
+};
+
+enum vtype iftovt_tab[8] = {
+       VNON, VCHR, VDIR, VBLK, VREG, VLNK, VSOCK, VBAD,
+};
+int    vttoif_tab[8] = {
+       0, IFREG, IFDIR, IFBLK, IFCHR, IFLNK, IFSOCK, IFMT,
+};
 
 /*
 
 /*
- * Change notion of root (``/'') directory.
+ * Create a regular file
  */
  */
-chroot()
+ufs_create(ndp, vap)
+       struct nameidata *ndp;
+       struct vattr *vap;
 {
 {
+       struct inode *ip;
+       int error;
 
 
-       if (u.u_error = suser(u.u_cred, &u.u_acflag))
-               return;
-       chdirec(&u.u_rdir);
+       if (error = maknode(MAKEIMODE(vap->va_type, vap->va_mode), ndp, &ip))
+               return (error);
+       ndp->ni_vp = ITOV(ip);
+       return (0);
 }
 
 /*
 }
 
 /*
- * Common routine for chroot and chdir.
+ * Mknod vnode call
  */
  */
-chdirec(ipp)
-       register struct inode **ipp;
+/* ARGSUSED */
+ufs_mknod(ndp, vap, cred)
+       struct nameidata *ndp;
+       struct ucred *cred;
+       struct vattr *vap;
 {
 {
-       register struct inode *ip;
-       struct a {
-               char    *fname;
-       } *uap = (struct a *)u.u_ap;
-       register struct nameidata *ndp = &u.u_nd;
-
-       ndp->ni_nameiop = LOOKUP | FOLLOW;
-       ndp->ni_segflg = UIO_USERSPACE;
-       ndp->ni_dirp = uap->fname;
-       ip = namei(ndp);
-       if (ip == NULL)
-               return;
-       if ((ip->i_mode&IFMT) != IFDIR) {
-               u.u_error = ENOTDIR;
-               goto bad;
-       }
-       if (access(ip, IEXEC))
-               goto bad;
-       IUNLOCK(ip);
-       if (*ipp)
-               irele(*ipp);
-       *ipp = ip;
-       return;
+       struct inode *ip;
+       int error;
 
 
-bad:
+       if (error = maknode(MAKEIMODE(vap->va_type, vap->va_mode), ndp, &ip))
+               return (error);
+       if (vap->va_rdev) {
+               /*
+                * Want to be able to use this to make badblock
+                * inodes, so don't truncate the dev number.
+                */
+               ITOV(ip)->v_rdev = ip->i_rdev = vap->va_rdev;
+               ip->i_flag |= IACC|IUPD|ICHG;
+       }
        iput(ip);
        iput(ip);
+       /*
+        * Remove inode so that it will be reloaded by iget and
+        * checked to see if it is an alias of an existing entry
+        * in the inode cache.
+        */
+       remque(ip);
+       ip->i_forw = ip;
+       ip->i_back = ip;
+       return (0);
 }
 
 /*
 }
 
 /*
- * Open system call.
+ * Open called.
+ *
+ * Nothing to do.
  */
  */
-open()
+/* ARGSUSED */
+ufs_open(vp, mode, cred)
+       struct vnode *vp;
+       int mode;
+       struct ucred *cred;
 {
 {
-       struct a {
-               char    *fname;
-               int     mode;
-               int     crtmode;
-       } *uap = (struct a *) u.u_ap;
 
 
-       copen(uap->mode-FOPEN, uap->crtmode, uap->fname);
+       return (0);
 }
 
 /*
 }
 
 /*
- * Creat system call.
+ * Close called
+ *
+ * Update the times on the inode.
  */
  */
-creat()
+/* ARGSUSED */
+ufs_close(vp, fflag, cred)
+       struct vnode *vp;
+       int fflag;
+       struct ucred *cred;
 {
 {
-       struct a {
-               char    *fname;
-               int     fmode;
-       } *uap = (struct a *)u.u_ap;
+       register struct inode *ip = VTOI(vp);
 
 
-       copen(FWRITE|FCREAT|FTRUNC, uap->fmode, uap->fname);
-}
-
-/*
- * Common code for open and creat.
- * Check permissions, allocate an open file structure,
- * and call the device open routine if any.
- */
-copen(mode, arg, fname)
-       register int mode;
-       int arg;
-       caddr_t fname;
-{
-       register struct inode *ip;
-       register struct file *fp;
-       register struct nameidata *ndp = &u.u_nd;
-       int indx;
-
-       fp = falloc();
-       if (fp == NULL)
-               return;
-       indx = u.u_r.r_val1;
-       ndp->ni_segflg = UIO_USERSPACE;
-       ndp->ni_dirp = fname;
-       if (mode&FCREAT) {
-               if (mode & FEXCL)
-                       ndp->ni_nameiop = CREATE;
-               else
-                       ndp->ni_nameiop = CREATE | FOLLOW;
-               ip = namei(ndp);
-               if (ip == NULL) {
-                       if (u.u_error)
-                               goto bad1;
-                       ip = maknode(arg&07777&(~ISVTX), ndp);
-                       if (ip == NULL)
-                               goto bad1;
-                       mode &= ~FTRUNC;
-               } else {
-                       if (mode&FEXCL) {
-                               u.u_error = EEXIST;
-                               goto bad;
-                       }
-                       mode &= ~FCREAT;
-               }
-       } else {
-               ndp->ni_nameiop = LOOKUP | FOLLOW;
-               ip = namei(ndp);
-               if (ip == NULL)
-                       goto bad1;
-       }
-       if ((ip->i_mode & IFMT) == IFSOCK) {
-               u.u_error = EOPNOTSUPP;
-               goto bad;
-       }
-       if ((mode&FCREAT) == 0) {
-               if (mode&FREAD)
-                       if (access(ip, IREAD))
-                               goto bad;
-               if (mode&(FWRITE|FTRUNC)) {
-                       if (access(ip, IWRITE))
-                               goto bad;
-                       if ((ip->i_mode&IFMT) == IFDIR) {
-                               u.u_error = EISDIR;
-                               goto bad;
-                       }
-               }
-       }
-       if (mode&FTRUNC)
-               itrunc(ip, (u_long)0);
-       IUNLOCK(ip);
-       fp->f_flag = mode&FMASK;
-       fp->f_type = DTYPE_INODE;
-       fp->f_ops = &inodeops;
-       fp->f_data = (caddr_t)ip;
-       if (setjmp(&u.u_qsave)) {
-               if (u.u_error == 0)
-                       u.u_error = EINTR;
-               u.u_ofile[indx] = NULL;
-               closef(fp);
-               return;
-       }
-       u.u_error = openi(ip, mode);
-       if (u.u_error == 0)
-               return;
-       ILOCK(ip);
-bad:
-       iput(ip);
-bad1:
-       u.u_ofile[indx] = NULL;
-       fp->f_count--;
+       if (vp->v_count > 1 && !(ip->i_flag & ILOCKED))
+               ITIMES(ip, &time, &time);
+       return (0);
 }
 
 }
 
-/*
- * Mknod system call
- */
-mknod()
+ufs_access(vp, mode, cred)
+       struct vnode *vp;
+       int mode;
+       struct ucred *cred;
 {
 {
-       register struct inode *ip;
-       register struct a {
-               char    *fname;
-               int     fmode;
-               int     dev;
-       } *uap = (struct a *)u.u_ap;
-       register struct nameidata *ndp = &u.u_nd;
-
-       if (u.u_error = suser(u.u_cred, &u.u_acflag))
-               return;
-       ndp->ni_nameiop = CREATE;
-       ndp->ni_segflg = UIO_USERSPACE;
-       ndp->ni_dirp = uap->fname;
-       ip = namei(ndp);
-       if (ip != NULL) {
-               u.u_error = EEXIST;
-               goto out;
-       }
-       if (u.u_error)
-               return;
-       ip = maknode(uap->fmode, ndp);
-       if (ip == NULL)
-               return;
-       switch (ip->i_mode & IFMT) {
-
-       case IFMT:      /* used by badsect to flag bad sectors */
-       case IFCHR:
-       case IFBLK:
-               if (uap->dev) {
-                       /*
-                        * Want to be able to use this to make badblock
-                        * inodes, so don't truncate the dev number.
-                        */
-                       ip->i_rdev = uap->dev;
-                       ip->i_flag |= IACC|IUPD|ICHG;
-               }
-       }
 
 
-out:
-       iput(ip);
+       return (iaccess(VTOI(vp), mode, cred));
 }
 
 }
 
-/*
- * link system call
- */
-link()
+/* ARGSUSED */
+ufs_getattr(vp, vap, cred)
+       struct vnode *vp;
+       register struct vattr *vap;
+       struct ucred *cred;
 {
 {
-       register struct inode *ip, *xp;
-       register struct a {
-               char    *target;
-               char    *linkname;
-       } *uap = (struct a *)u.u_ap;
-       register struct nameidata *ndp = &u.u_nd;
-
-       ndp->ni_nameiop = LOOKUP | FOLLOW;
-       ndp->ni_segflg = UIO_USERSPACE;
-       ndp->ni_dirp = uap->target;
-       ip = namei(ndp);        /* well, this routine is doomed anyhow */
-       if (ip == NULL)
-               return;
-       if ((ip->i_mode&IFMT) == IFDIR &&
-           (u.u_error = suser(u.u_cred, &u.u_acflag))) {
-               iput(ip);
-               return;
-       }
-       if (ip->i_nlink == LINK_MAX - 1) {
-               u.u_error = EMLINK;
-               iput(ip);
-               return;
-       }
-       ip->i_nlink++;
-       ip->i_flag |= ICHG;
-       iupdat(ip, &time, &time, 1);
-       IUNLOCK(ip);
-       ndp->ni_nameiop = CREATE;
-       ndp->ni_segflg = UIO_USERSPACE;
-       ndp->ni_dirp = (caddr_t)uap->linkname;
-       xp = namei(ndp);
-       if (xp != NULL) {
-               u.u_error = EEXIST;
-               iput(xp);
-               goto out;
-       }
-       if (u.u_error)
-               goto out;
-       if (ndp->ni_pdir->i_dev != ip->i_dev) {
-               iput(ndp->ni_pdir);
-               u.u_error = EXDEV;
-               goto out;
-       }
-       u.u_error = direnter(ip, ndp);
-out:
-       if (u.u_error) {
-               ip->i_nlink--;
-               ip->i_flag |= ICHG;
-       }
-       irele(ip);
-}
-
-/*
- * symlink -- make a symbolic link
- */
-symlink()
-{
-       register struct a {
-               char    *target;
-               char    *linkname;
-       } *uap = (struct a *)u.u_ap;
-       register struct inode *ip;
-       register char *tp;
-       register c, nc;
-       register struct nameidata *ndp = &u.u_nd;
-
-       tp = uap->target;
-       nc = 0;
-       while (c = fubyte(tp)) {
-               if (c < 0) {
-                       u.u_error = EFAULT;
-                       return;
-               }
-               tp++;
-               nc++;
-       }
-       ndp->ni_nameiop = CREATE;
-       ndp->ni_segflg = UIO_USERSPACE;
-       ndp->ni_dirp = uap->linkname;
-       ip = namei(ndp);
-       if (ip) {
-               iput(ip);
-               u.u_error = EEXIST;
-               return;
-       }
-       if (u.u_error)
-               return;
-       ip = maknode(IFLNK | 0777, ndp);
-       if (ip == NULL)
-               return;
-       u.u_error = rdwri(UIO_WRITE, ip, uap->target, nc, (off_t)0, 0,
-           (int *)0);
-       /* handle u.u_error != 0 */
-       iput(ip);
-}
+       register struct inode *ip = VTOI(vp);
 
 
-/*
- * Unlink system call.
- * Hard to avoid races here, especially
- * in unlinking directories.
- */
-unlink()
-{
-       struct a {
-               char    *fname;
-       } *uap = (struct a *)u.u_ap;
-       register struct inode *ip, *dp;
-       register struct nameidata *ndp = &u.u_nd;
-
-       ndp->ni_nameiop = DELETE | LOCKPARENT;
-       ndp->ni_segflg = UIO_USERSPACE;
-       ndp->ni_dirp = uap->fname;
-       ip = namei(ndp);
-       if (ip == NULL)
-               return;
-       dp = ndp->ni_pdir;
-       if ((ip->i_mode&IFMT) == IFDIR &&
-           (u.u_error = suser(u.u_cred, &u.u_acflag)))
-               goto out;
+       ITIMES(ip, &time, &time);
        /*
        /*
-        * Don't unlink a mounted file.
+        * Copy from inode table
         */
         */
-       if (ip->i_dev != dp->i_dev) {
-               u.u_error = EBUSY;
-               goto out;
-       }
-       if (ip->i_flag&ITEXT)
-               xrele(ip);      /* try once to free text */
-       if (dirremove(ndp)) {
-               ip->i_nlink--;
-               ip->i_flag |= ICHG;
-       }
-out:
-       if (dp == ip)
-               irele(ip);
+       vap->va_fsid = ip->i_dev;
+       vap->va_fileid = ip->i_number;
+       vap->va_mode = ip->i_mode & ~IFMT;
+       vap->va_nlink = ip->i_nlink;
+       vap->va_uid = ip->i_uid;
+       vap->va_gid = ip->i_gid;
+       vap->va_rdev = (dev_t)ip->i_rdev;
+       vap->va_size = ip->i_ic.ic_size.val[0];
+       vap->va_size1 = ip->i_ic.ic_size.val[1];
+       vap->va_atime.tv_sec = ip->i_atime;
+       vap->va_mtime.tv_sec = ip->i_mtime;
+       vap->va_ctime.tv_sec = ip->i_ctime;
+       /* this doesn't belong here */
+       if (vp->v_type == VBLK)
+               vap->va_blocksize = BLKDEV_IOSIZE;
+       else if (vp->v_type == VCHR)
+               vap->va_blocksize = MAXBSIZE;
        else
        else
-               iput(ip);
-       iput(dp);
+               vap->va_blocksize = ip->i_fs->fs_bsize;
+       /*
+        * XXX THIS IS NOT CORRECT!!, but be sure to change vn_stat()
+        * if you change it.
+        */
+       vap->va_bytes = ip->i_blocks;
+       vap->va_bytes1 = -1;
+       vap->va_type = vp->v_type;
+       return (0);
 }
 
 /*
 }
 
 /*
- * Seek system call
+ * Set attribute vnode op. called from several syscalls
  */
  */
-lseek()
+ufs_setattr(vp, vap, cred)
+       register struct vnode *vp;
+       register struct vattr *vap;
+       register struct ucred *cred;
 {
 {
-       register struct file *fp;
-       register struct a {
-               int     fd;
-               off_t   off;
-               int     sbase;
-       } *uap = (struct a *)u.u_ap;
-
-       GETF(fp, uap->fd);
-       if (fp->f_type != DTYPE_INODE) {
-               u.u_error = ESPIPE;
-               return;
-       }
-       switch (uap->sbase) {
-
-       case L_INCR:
-               fp->f_offset += uap->off;
-               break;
-
-       case L_XTND:
-               fp->f_offset = uap->off + ((struct inode *)fp->f_data)->i_size;
-               break;
-
-       case L_SET:
-               fp->f_offset = uap->off;
-               break;
+       register struct inode *ip = VTOI(vp);
+       int error = 0;
 
 
-       default:
-               u.u_error = EINVAL;
-               return;
+       /*
+        * Check for unsetable attributes.
+        */
+       if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) ||
+           (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) ||
+           (vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) ||
+           ((int)vap->va_bytes != VNOVAL)) {
+               return (EINVAL);
        }
        }
-       u.u_r.r_off = fp->f_offset;
-}
-
-/*
- * Access system call
- */
-saccess()
-{
-       register svuid, svgid;
-       register struct inode *ip;
-       register struct a {
-               char    *fname;
-               int     fmode;
-       } *uap = (struct a *)u.u_ap;
-       register struct nameidata *ndp = &u.u_nd;
-
-       svuid = u.u_uid;
-       svgid = u.u_gid;
-       u.u_uid = u.u_ruid;
-       u.u_gid = u.u_rgid;
-       ndp->ni_nameiop = LOOKUP | FOLLOW;
-       ndp->ni_segflg = UIO_USERSPACE;
-       ndp->ni_dirp = uap->fname;
-       ip = namei(ndp);
-       if (ip != NULL) {
-               if ((uap->fmode&R_OK) && access(ip, IREAD))
-                       goto done;
-               if ((uap->fmode&W_OK) && access(ip, IWRITE))
-                       goto done;
-               if ((uap->fmode&X_OK) && access(ip, IEXEC))
-                       goto done;
-done:
-               iput(ip);
+       /*
+        * Go through the fields and update iff not VNOVAL.
+        */
+       if (vap->va_uid != (u_short)VNOVAL || vap->va_gid != (u_short)VNOVAL)
+               if (error = chown1(vp, vap->va_uid, vap->va_gid, cred))
+                       return (error);
+       if (vap->va_size != VNOVAL) {
+               if (vp->v_type == VDIR)
+                       return (EISDIR);
+               if (error = iaccess(ip, IWRITE, cred))
+                       return (error);
+               if (error = itrunc(ip, vap->va_size))
+                       return (error);
        }
        }
-       u.u_uid = svuid;
-       u.u_gid = svgid;
-}
-
-/*
- * Stat system call.  This version follows links.
- */
-stat()
-{
-
-       stat1(FOLLOW);
-}
-
-/*
- * Lstat system call.  This version does not follow links.
- */
-lstat()
-{
-
-       stat1(NOFOLLOW);
-}
-
-stat1(follow)
-       int follow;
-{
-       register struct inode *ip;
-       register struct a {
-               char    *fname;
-               struct stat *ub;
-       } *uap = (struct a *)u.u_ap;
-       struct stat sb;
-       register struct nameidata *ndp = &u.u_nd;
-
-       ndp->ni_nameiop = LOOKUP | follow;
-       ndp->ni_segflg = UIO_USERSPACE;
-       ndp->ni_dirp = uap->fname;
-       ip = namei(ndp);
-       if (ip == NULL)
-               return;
-       (void) ino_stat(ip, &sb);
-       iput(ip);
-       u.u_error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
-}
-
-/*
- * Return target name of a symbolic link
- */
-readlink()
-{
-       register struct inode *ip;
-       register struct a {
-               char    *name;
-               char    *buf;
-               int     count;
-       } *uap = (struct a *)u.u_ap;
-       register struct nameidata *ndp = &u.u_nd;
-       int resid;
-
-       ndp->ni_nameiop = LOOKUP;
-       ndp->ni_segflg = UIO_USERSPACE;
-       ndp->ni_dirp = uap->name;
-       ip = namei(ndp);
-       if (ip == NULL)
-               return;
-       if ((ip->i_mode&IFMT) != IFLNK) {
-               u.u_error = EINVAL;
-               goto out;
+       /*
+        * Check whether the following attributes can be changed.
+        */
+       if (cred->cr_uid != ip->i_uid &&
+           (error = suser(cred, &u.u_acflag)))
+               return (error);
+       if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) {
+               if (vap->va_atime.tv_sec != VNOVAL)
+                       ip->i_flag |= IACC;
+               if (vap->va_mtime.tv_sec != VNOVAL)
+                       ip->i_flag |= IUPD;
+               ip->i_flag |= ICHG;
+               if (error = iupdat(ip, &vap->va_atime, &vap->va_mtime, 1))
+                       return (error);
        }
        }
-       u.u_error = rdwri(UIO_READ, ip, uap->buf, uap->count, (off_t)0, 0,
-           &resid);
-out:
-       iput(ip);
-       u.u_r.r_val1 = uap->count - resid;
-}
-
-/*
- * Change mode of a file given path name.
- */
-chmod()
-{
-       struct inode *ip;
-       struct a {
-               char    *fname;
-               int     fmode;
-       } *uap = (struct a *)u.u_ap;
-
-       if ((ip = owner(uap->fname, FOLLOW)) == NULL)
-               return;
-       u.u_error = chmod1(ip, uap->fmode);
-       iput(ip);
-}
-
-/*
- * Change mode of a file given a file descriptor.
- */
-fchmod()
-{
-       struct a {
-               int     fd;
-               int     fmode;
-       } *uap = (struct a *)u.u_ap;
-       register struct inode *ip;
-       register struct file *fp;
-
-       fp = getinode(uap->fd);
-       if (fp == NULL)
-               return;
-       ip = (struct inode *)fp->f_data;
-       if (u.u_uid != ip->i_uid &&
-           (u.u_error = suser(u.u_cred, &u.u_acflag)))
-               return;
-       ILOCK(ip);
-       u.u_error = chmod1(ip, uap->fmode);
-       IUNLOCK(ip);
+       if (vap->va_mode != (u_short)VNOVAL)
+               error = chmod1(vp, (int)vap->va_mode, cred);
+       return (error);
 }
 
 /*
  * Change the mode on a file.
  * Inode must be locked before calling.
  */
 }
 
 /*
  * Change the mode on a file.
  * Inode must be locked before calling.
  */
-chmod1(ip, mode)
-       register struct inode *ip;
+chmod1(vp, mode, cred)
+       register struct vnode *vp;
        register int mode;
        register int mode;
+       struct ucred *cred;
 {
 {
+       register struct inode *ip = VTOI(vp);
 
 
-       if (ip->i_fs->fs_ronly)
-               return (EROFS);
        ip->i_mode &= ~07777;
        ip->i_mode &= ~07777;
-       if (u.u_uid) {
-               if ((ip->i_mode & IFMT) != IFDIR)
+       if (cred->cr_uid) {
+               if (vp->v_type != VDIR)
                        mode &= ~ISVTX;
                        mode &= ~ISVTX;
-               if (!groupmember(ip->i_gid))
+               if (!groupmember(ip->i_gid, cred))
                        mode &= ~ISGID;
        }
                        mode &= ~ISGID;
        }
-       ip->i_mode |= mode&07777;
+       ip->i_mode |= mode & 07777;
        ip->i_flag |= ICHG;
        ip->i_flag |= ICHG;
-       if (ip->i_flag&ITEXT && (ip->i_mode&ISVTX)==0)
-               xrele(ip);
+       if ((vp->v_flag & VTEXT) && (ip->i_mode & ISVTX) == 0)
+               xrele(vp);
        return (0);
 }
 
        return (0);
 }
 
-/*
- * Set ownership given a path name.
- */
-chown()
-{
-       struct inode *ip;
-       struct a {
-               char    *fname;
-               int     uid;
-               int     gid;
-       } *uap = (struct a *)u.u_ap;
-       register struct nameidata *ndp = &u.u_nd;
-
-       ndp->ni_nameiop = LOOKUP | NOFOLLOW;
-       ndp->ni_segflg = UIO_USERSPACE;
-       ndp->ni_dirp = uap->fname;
-       ip = namei(ndp);
-       if (ip == NULL)
-               return;
-       u.u_error = chown1(ip, uap->uid, uap->gid);
-       iput(ip);
-}
-
-/*
- * Set ownership given a file descriptor.
- */
-fchown()
-{
-       struct a {
-               int     fd;
-               int     uid;
-               int     gid;
-       } *uap = (struct a *)u.u_ap;
-       register struct inode *ip;
-       register struct file *fp;
-
-       fp = getinode(uap->fd);
-       if (fp == NULL)
-               return;
-       ip = (struct inode *)fp->f_data;
-       ILOCK(ip);
-       u.u_error = chown1(ip, uap->uid, uap->gid);
-       IUNLOCK(ip);
-}
-
 /*
  * Perform chown operation on inode ip;
  * inode must be locked prior to call.
  */
 /*
  * Perform chown operation on inode ip;
  * inode must be locked prior to call.
  */
-chown1(ip, uid, gid)
-       register struct inode *ip;
-       int uid, gid;
+chown1(vp, uid, gid, cred)
+       register struct vnode *vp;
+       uid_t uid;
+       gid_t gid;
+       struct ucred *cred;
 {
 {
+       register struct inode *ip = VTOI(vp);
 #ifdef QUOTA
        register long change;
 #endif
 #ifdef QUOTA
        register long change;
 #endif
+       int error;
 
 
-       if (ip->i_fs->fs_ronly)
-               return (EROFS);
-       if (uid == -1)
+       if (uid == (u_short)VNOVAL)
                uid = ip->i_uid;
                uid = ip->i_uid;
-       if (gid == -1)
+       if (gid == (u_short)VNOVAL)
                gid = ip->i_gid;
        /*
         * If we don't own the file, are trying to change the owner
         * of the file, or are not a member of the target group,
         * the caller must be superuser or the call fails.
         */
                gid = ip->i_gid;
        /*
         * If we don't own the file, are trying to change the owner
         * of the file, or are not a member of the target group,
         * the caller must be superuser or the call fails.
         */
-       if ((u.u_uid != ip->i_uid || uid != ip->i_uid ||
-           !groupmember((gid_t)gid)) &&
-           (u.u_error = suser(u.u_cred, &u.u_acflag)))
-               return (u.u_error);
+       if ((cred->cr_uid != ip->i_uid || uid != ip->i_uid ||
+           !groupmember((gid_t)gid, cred)) &&
+           (error = suser(cred, &u.u_acflag)))
+               return (error);
 #ifdef QUOTA
        if (ip->i_uid == uid)           /* this just speeds things a little */
                change = 0;
 #ifdef QUOTA
        if (ip->i_uid == uid)           /* this just speeds things a little */
                change = 0;
@@ -682,7 +361,7 @@ chown1(ip, uid, gid)
        ip->i_uid = uid;
        ip->i_gid = gid;
        ip->i_flag |= ICHG;
        ip->i_uid = uid;
        ip->i_gid = gid;
        ip->i_flag |= ICHG;
-       if (u.u_ruid != 0)
+       if (cred->cr_ruid != 0)
                ip->i_mode &= ~(ISUID|ISGID);
 #ifdef QUOTA
        ip->i_dquot = inoquota(ip);
                ip->i_mode &= ~(ISUID|ISGID);
 #ifdef QUOTA
        ip->i_dquot = inoquota(ip);
@@ -694,113 +373,135 @@ chown1(ip, uid, gid)
 #endif
 }
 
 #endif
 }
 
-utimes()
+/* ARGSUSED */
+ufs_ioctl(vp, com, data, fflag, cred)
+       struct vnode *vp;
+       int com;
+       caddr_t data;
+       int fflag;
+       struct ucred *cred;
 {
 {
-       register struct a {
-               char    *fname;
-               struct  timeval *tptr;
-       } *uap = (struct a *)u.u_ap;
-       register struct inode *ip;
-       struct timeval tv[2];
 
 
-       if ((ip = owner(uap->fname, FOLLOW)) == NULL)
-               return;
-       if (ip->i_fs->fs_ronly) {
-               u.u_error = EROFS;
-               iput(ip);
-               return;
-       }
-       u.u_error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv));
-       if (u.u_error == 0) {
-               ip->i_flag |= IACC|IUPD|ICHG;
-               iupdat(ip, &tv[0], &tv[1], 0);
-       }
-       iput(ip);
+       printf("ufs_ioctl called with type %d\n", vp->v_type);
+       return (ENOTTY);
+}
+
+/* ARGSUSED */
+ufs_select(vp, which, cred)
+       struct vnode *vp;
+       int which;
+       struct ucred *cred;
+{
+
+       printf("ufs_select called with type %d\n", vp->v_type);
+       return (1);             /* XXX */
 }
 
 /*
 }
 
 /*
- * Flush any pending I/O.
+ * Mmap a file
+ *
+ * NB Currently unsupported.
  */
  */
-sync()
+/* ARGSUSED */
+ufs_mmap(vp, fflags, cred)
+       struct vnode *vp;
+       int fflags;
+       struct ucred *cred;
 {
 
 {
 
-       update();
+       return (EINVAL);
 }
 
 /*
 }
 
 /*
- * Truncate a file given its path name.
+ * Synch an open file.
  */
  */
-truncate()
+/* ARGSUSED */
+ufs_fsync(vp, fflags, cred)
+       struct vnode *vp;
+       int fflags;
+       struct ucred *cred;
 {
 {
-       struct a {
-               char    *fname;
-               off_t   length;
-       } *uap = (struct a *)u.u_ap;
-       struct inode *ip;
-       register struct nameidata *ndp = &u.u_nd;
-
-       ndp->ni_nameiop = LOOKUP | FOLLOW;
-       ndp->ni_segflg = UIO_USERSPACE;
-       ndp->ni_dirp = uap->fname;
-       ip = namei(ndp);
-       if (ip == NULL)
-               return;
-       if (access(ip, IWRITE))
-               goto bad;
-       if ((ip->i_mode&IFMT) == IFDIR) {
-               u.u_error = EISDIR;
-               goto bad;
-       }
-       itrunc(ip, (u_long)uap->length);
-bad:
-       iput(ip);
+       register struct inode *ip = VTOI(vp);
+       int error;
+
+       ILOCK(ip);
+       if (fflags&FWRITE)
+               ip->i_flag |= ICHG;
+       error = syncip(ip);
+       IUNLOCK(ip);
+       return (error);
 }
 
 /*
 }
 
 /*
- * Truncate a file given a file descriptor.
+ * Seek on a file
+ *
+ * Nothing to do, so just return.
  */
  */
-ftruncate()
+/* ARGSUSED */
+ufs_seek(vp, oldoff, newoff, cred)
+       struct vnode *vp;
+       off_t oldoff, newoff;
+       struct ucred *cred;
 {
 {
-       struct a {
-               int     fd;
-               off_t   length;
-       } *uap = (struct a *)u.u_ap;
-       struct inode *ip;
-       struct file *fp;
-
-       fp = getinode(uap->fd);
-       if (fp == NULL)
-               return;
-       if ((fp->f_flag&FWRITE) == 0) {
-               u.u_error = EINVAL;
-               return;
+
+       return (0);
+}
+
+/*
+ * ufs remove
+ * Hard to avoid races here, especially
+ * in unlinking directories.
+ */
+ufs_remove(ndp)
+       struct nameidata *ndp;
+{
+       register struct inode *ip, *dp;
+       int error;
+
+       ip = VTOI(ndp->ni_vp);
+       dp = VTOI(ndp->ni_dvp);
+       error = dirremove(ndp);
+       if (!error) {
+               ip->i_nlink--;
+               ip->i_flag |= ICHG;
        }
        }
-       ip = (struct inode *)fp->f_data;
-       ILOCK(ip);
-       itrunc(ip, (u_long)uap->length);
-       IUNLOCK(ip);
+       if (dp == ip)
+               vrele(ITOV(ip));
+       else
+               iput(ip);
+       iput(dp);
+       return (error);
 }
 
 /*
 }
 
 /*
- * Synch an open file.
+ * link vnode call
  */
  */
-fsync()
+ufs_link(vp, ndp)
+       register struct vnode *vp;
+       register struct nameidata *ndp;
 {
 {
-       struct a {
-               int     fd;
-       } *uap = (struct a *)u.u_ap;
-       struct inode *ip;
-       struct file *fp;
+       register struct inode *ip = VTOI(vp);
+       int error;
 
 
-       fp = getinode(uap->fd);
-       if (fp == NULL)
-               return;
-       ip = (struct inode *)fp->f_data;
-       ILOCK(ip);
-       if (fp->f_flag&FWRITE)
+       if (ndp->ni_dvp != vp)
+               ILOCK(ip);
+       if (ip->i_nlink == LINK_MAX - 1) {
+               error = EMLINK;
+               goto out;
+       }
+       ip->i_nlink++;
+       ip->i_flag |= ICHG;
+       error = iupdat(ip, &time, &time, 1);
+       if (!error)
+               error = direnter(ip, ndp);
+out:
+       if (ndp->ni_dvp != vp)
+               IUNLOCK(ip);
+       if (error) {
+               ip->i_nlink--;
                ip->i_flag |= ICHG;
                ip->i_flag |= ICHG;
-       syncip(ip);
-       IUNLOCK(ip);
+       }
+       return (error);
 }
 
 /*
 }
 
 /*
@@ -817,7 +518,7 @@ fsync()
  * Basic algorithm is:
  *
  * 1) Bump link count on source while we're linking it to the
  * Basic algorithm is:
  *
  * 1) Bump link count on source while we're linking it to the
- *    target.  This also insure the inode won't be deleted out
+ *    target.  This also ensure the inode won't be deleted out
  *    from underneath us while we work (it may be truncated by
  *    a concurrent `trunc' or `open' for creation).
  * 2) Link source to destination.  If destination already exists,
  *    from underneath us while we work (it may be truncated by
  *    a concurrent `trunc' or `open' for creation).
  * 2) Link source to destination.  If destination already exists,
@@ -826,52 +527,36 @@ fsync()
  *    directory was moved and the parent of the destination
  *    is different from the source, patch the ".." entry in the
  *    directory.
  *    directory was moved and the parent of the destination
  *    is different from the source, patch the ".." entry in the
  *    directory.
- *
- * Source and destination must either both be directories, or both
- * not be directories.  If target is a directory, it must be empty.
  */
  */
-rename()
+ufs_rename(fndp, tndp)
+       register struct nameidata *fndp, *tndp;
 {
 {
-       struct a {
-               char    *from;
-               char    *to;
-       } *uap = (struct a *)u.u_ap;
        register struct inode *ip, *xp, *dp;
        struct dirtemplate dirbuf;
        int doingdirectory = 0, oldparent = 0, newparent = 0;
        register struct inode *ip, *xp, *dp;
        struct dirtemplate dirbuf;
        int doingdirectory = 0, oldparent = 0, newparent = 0;
-       register struct nameidata *ndp = &u.u_nd;
        int error = 0;
 
        int error = 0;
 
-       ndp->ni_nameiop = DELETE | LOCKPARENT;
-       ndp->ni_segflg = UIO_USERSPACE;
-       ndp->ni_dirp = uap->from;
-       ip = namei(ndp);
-       if (ip == NULL)
-               return;
-       dp = ndp->ni_pdir;
+       dp = VTOI(fndp->ni_dvp);
+       ip = VTOI(fndp->ni_vp);
+       ILOCK(ip);
        if ((ip->i_mode&IFMT) == IFDIR) {
        if ((ip->i_mode&IFMT) == IFDIR) {
-               register struct direct *d;
+               register struct direct *d = &fndp->ni_dent;
 
 
-               d = &ndp->ni_dent;
                /*
                 * Avoid ".", "..", and aliases of "." for obvious reasons.
                 */
                /*
                 * Avoid ".", "..", and aliases of "." for obvious reasons.
                 */
-               if ((d->d_namlen == 1 && d->d_name[0] == '.') ||
-                   (d->d_namlen == 2 && bcmp(d->d_name, "..", 2) == 0) ||
-                   (dp == ip) || (ip->i_flag & IRENAME)) {
-                       iput(dp);
-                       if (dp == ip)
-                               irele(ip);
-                       else
-                               iput(ip);
-                       u.u_error = EINVAL;
-                       return;
+               if ((d->d_namlen == 1 && d->d_name[0] == '.') || dp == ip ||
+                   fndp->ni_isdotdot || (ip->i_flag & IRENAME)) {
+                       IUNLOCK(ip);
+                       ufs_abortop(fndp);
+                       ufs_abortop(tndp);
+                       return (EINVAL);
                }
                ip->i_flag |= IRENAME;
                oldparent = dp->i_number;
                doingdirectory++;
        }
                }
                ip->i_flag |= IRENAME;
                oldparent = dp->i_number;
                doingdirectory++;
        }
-       iput(dp);
+       vrele(fndp->ni_dvp);
 
        /*
         * 1) Bump link count while we're moving stuff
 
        /*
         * 1) Bump link count while we're moving stuff
@@ -881,21 +566,17 @@ rename()
         */
        ip->i_nlink++;
        ip->i_flag |= ICHG;
         */
        ip->i_nlink++;
        ip->i_flag |= ICHG;
-       iupdat(ip, &time, &time, 1);
+       error = iupdat(ip, &time, &time, 1);
        IUNLOCK(ip);
 
        /*
         * When the target exists, both the directory
        IUNLOCK(ip);
 
        /*
         * When the target exists, both the directory
-        * and target inodes are returned locked.
+        * and target vnodes are returned locked.
         */
         */
-       ndp->ni_nameiop = CREATE | LOCKPARENT | NOCACHE;
-       ndp->ni_dirp = (caddr_t)uap->to;
-       xp = namei(ndp);
-       if (u.u_error) {
-               error = u.u_error;
-               goto out;
-       }
-       dp = ndp->ni_pdir;
+       dp = VTOI(tndp->ni_dvp);
+       xp = NULL;
+       if (tndp->ni_vp)
+               xp = VTOI(tndp->ni_vp);
        /*
         * If ".." must be changed (ie the directory gets a new
         * parent) then the source directory must not be in the
        /*
         * If ".." must be changed (ie the directory gets a new
         * parent) then the source directory must not be in the
@@ -909,21 +590,21 @@ rename()
        if (oldparent != dp->i_number)
                newparent = dp->i_number;
        if (doingdirectory && newparent) {
        if (oldparent != dp->i_number)
                newparent = dp->i_number;
        if (doingdirectory && newparent) {
-               if (access(ip, IWRITE))
+               if (error = iaccess(ip, IWRITE, tndp->ni_cred))
                        goto bad;
                        goto bad;
+               tndp->ni_nameiop = RENAME | LOCKPARENT | LOCKLEAF | NOCACHE;
                do {
                do {
-                       dp = ndp->ni_pdir;
+                       dp = VTOI(tndp->ni_dvp);
                        if (xp != NULL)
                        if (xp != NULL)
-                               iput(xp);
-                       u.u_error = checkpath(ip, dp);
-                       if (u.u_error)
+                               vput(ITOV(xp));
+                       if (error = checkpath(ip, dp, tndp->ni_cred))
                                goto out;
                                goto out;
-                       xp = namei(ndp);
-                       if (u.u_error) {
-                               error = u.u_error;
+                       if (error = namei(tndp))
                                goto out;
                                goto out;
-                       }
-               } while (dp != ndp->ni_pdir);
+                       xp = NULL;
+                       if (tndp->ni_vp)
+                               xp = VTOI(tndp->ni_vp);
+               } while (dp != VTOI(tndp->ni_dvp));
        }
        /*
         * 2) If target doesn't exist, link the target
        }
        /*
         * 2) If target doesn't exist, link the target
@@ -933,10 +614,8 @@ rename()
         *    expunge the original entry's existence.
         */
        if (xp == NULL) {
         *    expunge the original entry's existence.
         */
        if (xp == NULL) {
-               if (dp->i_dev != ip->i_dev) {
-                       error = EXDEV;
-                       goto bad;
-               }
+               if (dp->i_dev != ip->i_dev)
+                       panic("rename: EXDEV");
                /*
                 * Account for ".." in new directory.
                 * When source and destination have the same
                /*
                 * Account for ".." in new directory.
                 * When source and destination have the same
@@ -945,29 +624,27 @@ rename()
                if (doingdirectory && newparent) {
                        dp->i_nlink++;
                        dp->i_flag |= ICHG;
                if (doingdirectory && newparent) {
                        dp->i_nlink++;
                        dp->i_flag |= ICHG;
-                       iupdat(dp, &time, &time, 1);
+                       error = iupdat(dp, &time, &time, 1);
                }
                }
-               error = direnter(ip, ndp);
-               if (error)
+               if (error = direnter(ip, tndp))
                        goto out;
        } else {
                        goto out;
        } else {
-               if (xp->i_dev != dp->i_dev || xp->i_dev != ip->i_dev) {
-                       error = EXDEV;
-                       goto bad;
-               }
+               if (xp->i_dev != dp->i_dev || xp->i_dev != ip->i_dev)
+                       panic("rename: EXDEV");
                /*
                 * Short circuit rename(foo, foo).
                 */
                if (xp->i_number == ip->i_number)
                /*
                 * Short circuit rename(foo, foo).
                 */
                if (xp->i_number == ip->i_number)
-                       goto bad;
+                       panic("rename: same file");
                /*
                 * If the parent directory is "sticky", then the user must
                 * own the parent directory, or the destination of the rename,
                 * otherwise the destination may not be changed (except by
                 * root). This implements append-only directories.
                 */
                /*
                 * If the parent directory is "sticky", then the user must
                 * own the parent directory, or the destination of the rename,
                 * otherwise the destination may not be changed (except by
                 * root). This implements append-only directories.
                 */
-               if ((dp->i_mode & ISVTX) && u.u_uid != 0 &&
-                   u.u_uid != dp->i_uid && xp->i_uid != u.u_uid) {
+               if ((dp->i_mode & ISVTX) && tndp->ni_cred->cr_uid != 0 &&
+                   tndp->ni_cred->cr_uid != dp->i_uid &&
+                   xp->i_uid != tndp->ni_cred->cr_uid) {
                        error = EPERM;
                        goto bad;
                }
                        error = EPERM;
                        goto bad;
                }
@@ -979,7 +656,8 @@ rename()
                 * not directories).
                 */
                if ((xp->i_mode&IFMT) == IFDIR) {
                 * not directories).
                 */
                if ((xp->i_mode&IFMT) == IFDIR) {
-                       if (!dirempty(xp, dp->i_number) || xp->i_nlink > 2) {
+                       if (!dirempty(xp, dp->i_number, tndp->ni_cred) || 
+                           xp->i_nlink > 2) {
                                error = ENOTEMPTY;
                                goto bad;
                        }
                                error = ENOTEMPTY;
                                goto bad;
                        }
@@ -987,16 +665,14 @@ rename()
                                error = ENOTDIR;
                                goto bad;
                        }
                                error = ENOTDIR;
                                goto bad;
                        }
-                       cacheinval(dp);
+                       cache_purge(ITOV(dp));
                } else if (doingdirectory) {
                        error = EISDIR;
                        goto bad;
                }
                } else if (doingdirectory) {
                        error = EISDIR;
                        goto bad;
                }
-               dirrewrite(dp, ip, ndp);
-               if (u.u_error) {
-                       error = u.u_error;
-                       goto bad1;
-               }
+               if (error = dirrewrite(dp, ip, tndp))
+                       goto bad;
+               vput(ITOV(dp));
                /*
                 * Adjust the link count of the target to
                 * reflect the dirrewrite above.  If this is
                /*
                 * Adjust the link count of the target to
                 * reflect the dirrewrite above.  If this is
@@ -1011,32 +687,33 @@ rename()
                if (doingdirectory) {
                        if (--xp->i_nlink != 0)
                                panic("rename: linked directory");
                if (doingdirectory) {
                        if (--xp->i_nlink != 0)
                                panic("rename: linked directory");
-                       itrunc(xp, (u_long)0);
+                       error = itrunc(xp, (u_long)0);
                }
                xp->i_flag |= ICHG;
                }
                xp->i_flag |= ICHG;
-               iput(xp);
+               vput(ITOV(xp));
                xp = NULL;
        }
 
        /*
         * 3) Unlink the source.
         */
                xp = NULL;
        }
 
        /*
         * 3) Unlink the source.
         */
-       ndp->ni_nameiop = DELETE | LOCKPARENT;
-       ndp->ni_segflg = UIO_USERSPACE;
-       ndp->ni_dirp = uap->from;
-       xp = namei(ndp);
-       if (xp != NULL)
-               dp = ndp->ni_pdir;
-       else
+       fndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF;
+       (void)namei(fndp);
+       if (fndp->ni_vp != NULL) {
+               xp = VTOI(fndp->ni_vp);
+               dp = VTOI(fndp->ni_dvp);
+       } else {
+               xp = NULL;
                dp = NULL;
                dp = NULL;
+       }
        /*
        /*
-        * Insure that the directory entry still exists and has not
+        * Ensure that the directory entry still exists and has not
         * changed while the new name has been entered. If the source is
         * a file then the entry may have been unlinked or renamed. In
         * either case there is no further work to be done. If the source
         * is a directory then it cannot have been rmdir'ed; its link
         * count of three would cause a rmdir to fail with ENOTEMPTY.
         * changed while the new name has been entered. If the source is
         * a file then the entry may have been unlinked or renamed. In
         * either case there is no further work to be done. If the source
         * is a directory then it cannot have been rmdir'ed; its link
         * count of three would cause a rmdir to fail with ENOTEMPTY.
-        * The IRENAME flag insures that it cannot be moved by another
+        * The IRENAME flag ensures that it cannot be moved by another
         * rename.
         */
        if (xp != ip) {
         * rename.
         */
        if (xp != ip) {
@@ -1053,8 +730,8 @@ rename()
                        dp->i_nlink--;
                        dp->i_flag |= ICHG;
                        error = rdwri(UIO_READ, xp, (caddr_t)&dirbuf,
                        dp->i_nlink--;
                        dp->i_flag |= ICHG;
                        error = rdwri(UIO_READ, xp, (caddr_t)&dirbuf,
-                               sizeof (struct dirtemplate), (off_t)0, 1,
-                               (int *)0);
+                               sizeof (struct dirtemplate), (off_t)0,
+                               UIO_USERSPACE, tndp->ni_cred, (int *)0);
                        if (error == 0) {
                                if (dirbuf.dotdot_namlen != 2 ||
                                    dirbuf.dotdot_name[0] != '.' ||
                        if (error == 0) {
                                if (dirbuf.dotdot_namlen != 2 ||
                                    dirbuf.dotdot_name[0] != '.' ||
@@ -1065,96 +742,35 @@ rename()
                                        (void) rdwri(UIO_WRITE, xp,
                                            (caddr_t)&dirbuf,
                                            sizeof (struct dirtemplate),
                                        (void) rdwri(UIO_WRITE, xp,
                                            (caddr_t)&dirbuf,
                                            sizeof (struct dirtemplate),
-                                           (off_t)0, 1, (int *)0);
-                                       cacheinval(dp);
+                                           (off_t)0, UIO_USERSPACE,
+                                           tndp->ni_cred, (int *)0);
+                                       cache_purge(ITOV(dp));
                                }
                        }
                }
                                }
                        }
                }
-               if (dirremove(ndp)) {
+               error = dirremove(fndp);
+               if (!error) {
                        xp->i_nlink--;
                        xp->i_flag |= ICHG;
                }
                xp->i_flag &= ~IRENAME;
                        xp->i_nlink--;
                        xp->i_flag |= ICHG;
                }
                xp->i_flag &= ~IRENAME;
-               if (error == 0)         /* XXX conservative */
-                       error = u.u_error;
        }
        if (dp)
        }
        if (dp)
-               iput(dp);
+               vput(ITOV(dp));
        if (xp)
        if (xp)
-               iput(xp);
-       irele(ip);
-       if (error)
-               u.u_error = error;
-       return;
+               vput(ITOV(xp));
+       vrele(ITOV(ip));
+       return (error);
 
 bad:
 
 bad:
-       iput(dp);
-bad1:
        if (xp)
        if (xp)
-               iput(xp);
+               vput(ITOV(xp));
+       vput(ITOV(dp));
 out:
        ip->i_nlink--;
        ip->i_flag |= ICHG;
 out:
        ip->i_nlink--;
        ip->i_flag |= ICHG;
-       irele(ip);
-       if (error)
-               u.u_error = error;
-}
-
-/*
- * Make a new file.
- */
-struct inode *
-maknode(mode, ndp)
-       int mode;
-       register struct nameidata *ndp;
-{
-       register struct inode *ip;
-       register struct inode *pdir = ndp->ni_pdir;
-       ino_t ipref;
-
-       if ((mode & IFMT) == IFDIR)
-               ipref = dirpref(pdir->i_fs);
-       else
-               ipref = pdir->i_number;
-       ip = ialloc(pdir, ipref, mode);
-       if (ip == NULL) {
-               iput(pdir);
-               return (NULL);
-       }
-#ifdef QUOTA
-       if (ip->i_dquot != NODQUOT)
-               panic("maknode: dquot");
-#endif
-       ip->i_flag |= IACC|IUPD|ICHG;
-       if ((mode & IFMT) == 0)
-               mode |= IFREG;
-       ip->i_mode = mode & ~u.u_cmask;
-       ip->i_nlink = 1;
-       ip->i_uid = u.u_uid;
-       ip->i_gid = pdir->i_gid;
-       if (ip->i_mode & ISGID && !groupmember(ip->i_gid) &&
-           (u.u_error = suser(u.u_cred, &u.u_acflag)))
-               ip->i_mode &= ~ISGID;
-#ifdef QUOTA
-       ip->i_dquot = inoquota(ip);
-#endif
-
-       /*
-        * Make sure inode goes to disk before directory entry.
-        */
-       iupdat(ip, &time, &time, 1);
-       u.u_error = direnter(ip, ndp);
-       if (u.u_error) {
-               /*
-                * Write error occurred trying to update directory
-                * so must deallocate the inode.
-                */
-               ip->i_nlink = 0;
-               ip->i_flag |= ICHG;
-               iput(ip);
-               return (NULL);
-       }
-       return (ip);
+       vrele(ITOV(ip));
+       return (error);
 }
 
 /*
 }
 
 /*
@@ -1168,30 +784,21 @@ struct dirtemplate mastertemplate = {
 /*
  * Mkdir system call
  */
 /*
  * Mkdir system call
  */
-mkdir()
+ufs_mkdir(ndp, vap)
+       struct nameidata *ndp;
+       struct vattr *vap;
 {
 {
-       struct a {
-               char    *name;
-               int     dmode;
-       } *uap = (struct a *)u.u_ap;
        register struct inode *ip, *dp;
        register struct inode *ip, *dp;
+       struct inode *tip;
+       struct vnode *dvp;
        struct dirtemplate dirtemplate;
        struct dirtemplate dirtemplate;
-       register struct nameidata *ndp = &u.u_nd;
-
-       ndp->ni_nameiop = CREATE;
-       ndp->ni_segflg = UIO_USERSPACE;
-       ndp->ni_dirp = uap->name;
-       ip = namei(ndp);
-       if (u.u_error)
-               return;
-       if (ip != NULL) {
-               iput(ip);
-               u.u_error = EEXIST;
-               return;
-       }
-       dp = ndp->ni_pdir;
-       uap->dmode &= 0777;
-       uap->dmode |= IFDIR;
+       int error;
+       int dmode;
+
+       dvp = ndp->ni_dvp;
+       dp = VTOI(dvp);
+       dmode = vap->va_mode&0777;
+       dmode |= IFDIR;
        /*
         * Must simulate part of maknode here
         * in order to acquire the inode, but
        /*
         * Must simulate part of maknode here
         * in order to acquire the inode, but
@@ -1199,24 +806,26 @@ mkdir()
         * directory.  The entry is made later
         * after writing "." and ".." entries out.
         */
         * directory.  The entry is made later
         * after writing "." and ".." entries out.
         */
-       ip = ialloc(dp, dirpref(dp->i_fs), uap->dmode);
-       if (ip == NULL) {
+       error = ialloc(dp, dirpref(dp->i_fs), dmode, &tip);
+       if (error) {
                iput(dp);
                iput(dp);
-               return;
+               return (error);
        }
        }
+       ip = tip;
 #ifdef QUOTA
        if (ip->i_dquot != NODQUOT)
                panic("mkdir: dquot");
 #endif
        ip->i_flag |= IACC|IUPD|ICHG;
 #ifdef QUOTA
        if (ip->i_dquot != NODQUOT)
                panic("mkdir: dquot");
 #endif
        ip->i_flag |= IACC|IUPD|ICHG;
-       ip->i_mode = uap->dmode & ~u.u_cmask;
+       ip->i_mode = dmode;
+       ITOV(ip)->v_type = VDIR;        /* Rest init'd in iget() */
        ip->i_nlink = 2;
        ip->i_nlink = 2;
-       ip->i_uid = u.u_uid;
+       ip->i_uid = ndp->ni_cred->cr_uid;
        ip->i_gid = dp->i_gid;
 #ifdef QUOTA
        ip->i_dquot = inoquota(ip);
 #endif
        ip->i_gid = dp->i_gid;
 #ifdef QUOTA
        ip->i_dquot = inoquota(ip);
 #endif
-       iupdat(ip, &time, &time, 1);
+       error = iupdat(ip, &time, &time, 1);
 
        /*
         * Bump link count in parent directory
 
        /*
         * Bump link count in parent directory
@@ -1226,7 +835,7 @@ mkdir()
         */
        dp->i_nlink++;
        dp->i_flag |= ICHG;
         */
        dp->i_nlink++;
        dp->i_flag |= ICHG;
-       iupdat(dp, &time, &time, 1);
+       error = iupdat(dp, &time, &time, 1);
 
        /*
         * Initialize directory with "."
 
        /*
         * Initialize directory with "."
@@ -1235,15 +844,16 @@ mkdir()
        dirtemplate = mastertemplate;
        dirtemplate.dot_ino = ip->i_number;
        dirtemplate.dotdot_ino = dp->i_number;
        dirtemplate = mastertemplate;
        dirtemplate.dot_ino = ip->i_number;
        dirtemplate.dotdot_ino = dp->i_number;
-       u.u_error = rdwri(UIO_WRITE, ip, (caddr_t)&dirtemplate,
-               sizeof (dirtemplate), (off_t)0, 1, (int *)0);
-       if (u.u_error) {
+       error = rdwri(UIO_WRITE, ip, (caddr_t)&dirtemplate,
+               sizeof (dirtemplate), (off_t)0, UIO_SYSSPACE,
+               ndp->ni_cred, (int *)0);
+       if (error) {
                dp->i_nlink--;
                dp->i_flag |= ICHG;
                goto bad;
        }
                dp->i_nlink--;
                dp->i_flag |= ICHG;
                goto bad;
        }
-       if (DIRBLKSIZ > ip->i_fs->fs_fsize)
-               panic("mkdir: blksize");     /* XXX - should grow with bmap() */
+       if (DIRBLKSIZ > dp->i_fs->fs_fsize)
+               panic("mkdir: blksize");     /* XXX - should grow w/balloc() */
        else
                ip->i_size = DIRBLKSIZ;
        /*
        else
                ip->i_size = DIRBLKSIZ;
        /*
@@ -1251,14 +861,13 @@ mkdir()
         * install the entry for it in
         * the parent directory.
         */
         * install the entry for it in
         * the parent directory.
         */
-       u.u_error = direnter(ip, ndp);
+       error = direnter(ip, ndp);
        dp = NULL;
        dp = NULL;
-       if (u.u_error) {
+       if (error) {
                ndp->ni_nameiop = LOOKUP | NOCACHE;
                ndp->ni_nameiop = LOOKUP | NOCACHE;
-               ndp->ni_segflg = UIO_USERSPACE;
-               ndp->ni_dirp = uap->name;
-               dp = namei(ndp);
-               if (dp) {
+               error = namei(ndp);
+               if (!error) {
+                       dp = VTOI(ndp->ni_vp);
                        dp->i_nlink--;
                        dp->i_flag |= ICHG;
                }
                        dp->i_nlink--;
                        dp->i_flag |= ICHG;
                }
@@ -1266,55 +875,37 @@ mkdir()
 bad:
        /*
         * No need to do an explicit itrunc here,
 bad:
        /*
         * No need to do an explicit itrunc here,
-        * irele will do this for us because we set
+        * vrele will do this for us because we set
         * the link count to 0.
         */
         * the link count to 0.
         */
-       if (u.u_error) {
+       if (error) {
                ip->i_nlink = 0;
                ip->i_flag |= ICHG;
        }
                ip->i_nlink = 0;
                ip->i_flag |= ICHG;
        }
+       iput(ip);
        if (dp)
                iput(dp);
        if (dp)
                iput(dp);
-       iput(ip);
+       return (error);
 }
 
 /*
  * Rmdir system call.
  */
 }
 
 /*
  * Rmdir system call.
  */
-rmdir()
+ufs_rmdir(ndp)
+       register struct nameidata *ndp;
 {
 {
-       struct a {
-               char    *name;
-       } *uap = (struct a *)u.u_ap;
        register struct inode *ip, *dp;
        register struct inode *ip, *dp;
-       register struct nameidata *ndp = &u.u_nd;
-
-       ndp->ni_nameiop = DELETE | LOCKPARENT;
-       ndp->ni_segflg = UIO_USERSPACE;
-       ndp->ni_dirp = uap->name;
-       ip = namei(ndp);
-       if (ip == NULL)
-               return;
-       dp = ndp->ni_pdir;
+       int error = 0;
+
+       ip = VTOI(ndp->ni_vp);
+       dp = VTOI(ndp->ni_dvp);
        /*
         * No rmdir "." please.
         */
        if (dp == ip) {
        /*
         * No rmdir "." please.
         */
        if (dp == ip) {
-               irele(dp);
+               vrele(ITOV(dp));
                iput(ip);
                iput(ip);
-               u.u_error = EINVAL;
-               return;
-       }
-       if ((ip->i_mode&IFMT) != IFDIR) {
-               u.u_error = ENOTDIR;
-               goto out;
-       }
-       /*
-        * Don't remove a mounted on directory.
-        */
-       if (ip->i_dev != dp->i_dev) {
-               u.u_error = EBUSY;
-               goto out;
+               return (EINVAL);
        }
        /*
         * Verify the directory is empty (and valid).
        }
        /*
         * Verify the directory is empty (and valid).
@@ -1323,8 +914,8 @@ rmdir()
         *  the current directory and thus be
         *  non-empty.)
         */
         *  the current directory and thus be
         *  non-empty.)
         */
-       if (ip->i_nlink != 2 || !dirempty(ip, dp->i_number)) {
-               u.u_error = ENOTEMPTY;
+       if (ip->i_nlink != 2 || !dirempty(ip, dp->i_number, ndp->ni_cred)) {
+               error = ENOTEMPTY;
                goto out;
        }
        /*
                goto out;
        }
        /*
@@ -1332,13 +923,13 @@ rmdir()
         * inode.  If we crash in between, the directory
         * will be reattached to lost+found,
         */
         * inode.  If we crash in between, the directory
         * will be reattached to lost+found,
         */
-       if (dirremove(ndp) == 0)
+       if (error = dirremove(ndp))
                goto out;
        dp->i_nlink--;
        dp->i_flag |= ICHG;
                goto out;
        dp->i_nlink--;
        dp->i_flag |= ICHG;
-       cacheinval(dp);
+       cache_purge(ITOV(dp));
        iput(dp);
        iput(dp);
-       dp = NULL;
+       ndp->ni_dvp = NULL;
        /*
         * Truncate inode.  The only stuff left
         * in the directory is "." and "..".  The
        /*
         * Truncate inode.  The only stuff left
         * in the directory is "." and "..".  The
@@ -1351,40 +942,206 @@ rmdir()
         * worry about them later.
         */
        ip->i_nlink -= 2;
         * worry about them later.
         */
        ip->i_nlink -= 2;
-       itrunc(ip, (u_long)0);
-       cacheinval(ip);
+       error = itrunc(ip, (u_long)0);
+       cache_purge(ITOV(ip));
 out:
 out:
-       if (dp)
+       if (ndp->ni_dvp)
                iput(dp);
        iput(ip);
                iput(dp);
        iput(ip);
+       return (error);
 }
 
 }
 
-struct file *
-getinode(fdes)
-       int fdes;
+/*
+ * symlink -- make a symbolic link
+ */
+ufs_symlink(ndp, vap, target)
+       struct nameidata *ndp;
+       struct vattr *vap;
+       char *target;
+{
+       struct inode *ip;
+       int error;
+
+       error = maknode(IFLNK | vap->va_mode, ndp, &ip);
+       if (error)
+               return (error);
+       error = rdwri(UIO_WRITE, ip, target, strlen(target), (off_t)0,
+               UIO_SYSSPACE, ndp->ni_cred, (int *)0);
+       iput(ip);
+       return (error);
+}
+
+/*
+ * Vnode op for read and write
+ */
+ufs_readdir(vp, uio, offp, cred)
+       struct vnode *vp;
+       register struct uio *uio;
+       off_t *offp;
+       struct ucred *cred;
 {
 {
-       struct file *fp;
+       register struct inode *ip = VTOI(vp);
+       int count, error;
 
 
-       if ((unsigned)fdes >= NOFILE || (fp = u.u_ofile[fdes]) == NULL) {
-               u.u_error = EBADF;
-               return ((struct file *)0);
+       ILOCK(ip);
+       uio->uio_offset = *offp;
+       count = uio->uio_resid;
+       count &= ~(DIRBLKSIZ - 1);
+       if (vp->v_type != VDIR || uio->uio_iovcnt != 1 ||
+           (count < DIRBLKSIZ) || (uio->uio_offset & (DIRBLKSIZ -1))) {
+               IUNLOCK(ip);
+               return (EINVAL);
+       }
+       uio->uio_resid = count;
+       uio->uio_iov->iov_len = count;
+       error = readip(ip, uio, cred);
+       *offp += count - uio->uio_resid;
+       IUNLOCK(ip);
+       return (error);
+}
+
+/*
+ * Return target name of a symbolic link
+ */
+ufs_readlink(vp, uiop, cred)
+       struct vnode *vp;
+       struct uio *uiop;
+       struct ucred *cred;
+{
+
+       return (readip(VTOI(vp), uiop, cred));
+}
+
+/*
+ * Ufs abort op, called after namei() when a CREATE/DELETE isn't actually
+ * done. Iff ni_vp/ni_dvp not null and locked, unlock.
+ */
+ufs_abortop(ndp)
+       register struct nameidata *ndp;
+{
+       register struct inode *ip;
+
+       if (ndp->ni_vp) {
+               ip = VTOI(ndp->ni_vp);
+               if (ip->i_flag & ILOCKED)
+                       IUNLOCK(ip);
+               vrele(ndp->ni_vp);
        }
        }
-       if (fp->f_type != DTYPE_INODE) {
-               u.u_error = EINVAL;
-               return ((struct file *)0);
+       if (ndp->ni_dvp) {
+               ip = VTOI(ndp->ni_dvp);
+               if (ip->i_flag & ILOCKED)
+                       IUNLOCK(ip);
+               vrele(ndp->ni_dvp);
        }
        }
-       return (fp);
+       return;
+}
+
+ufs_lock(vp)
+       struct vnode *vp;
+{
+       register struct inode *ip = VTOI(vp);
+
+       ILOCK(ip);
+       return (0);
+}
+
+ufs_unlock(vp)
+       struct vnode *vp;
+{
+       register struct inode *ip = VTOI(vp);
+
+       if (!(ip->i_flag & ILOCKED))
+               panic("ufs_unlock NOT LOCKED");
+       IUNLOCK(ip);
+       return (0);
+}
+
+/*
+ * Get access to bmap
+ */
+ufs_bmap(vp, bn, vpp, bnp)
+       struct vnode *vp;
+       daddr_t bn;
+       struct vnode **vpp;
+       daddr_t *bnp;
+{
+       struct inode *ip = VTOI(vp);
+
+       if (vpp != NULL)
+               *vpp = ip->i_devvp;
+       if (bnp == NULL)
+               return (0);
+       return (bmap(ip, bn, bnp, (daddr_t *)0, (int *)0));
 }
 
 /*
 }
 
 /*
- * mode mask for creation of files
+ * Just call the device strategy routine
  */
  */
-umask()
+ufs_strategy(bp)
+       register struct buf *bp;
 {
 {
-       register struct a {
-               int     mask;
-       } *uap = (struct a *)u.u_ap;
+       (*bdevsw[major(bp->b_dev)].d_strategy)(bp);
+       return (0);
+}
 
 
-       u.u_r.r_val1 = u.u_cmask;
-       u.u_cmask = uap->mask & 07777;
+/*
+ * Make a new file.
+ */
+maknode(mode, ndp, ipp)
+       int mode;
+       register struct nameidata *ndp;
+       struct inode **ipp;
+{
+       register struct inode *ip;
+       struct inode *tip;
+       register struct inode *pdir = VTOI(ndp->ni_dvp);
+       ino_t ipref;
+       int error;
+
+       *ipp = 0;
+       if ((mode & IFMT) == IFDIR)
+               ipref = dirpref(pdir->i_fs);
+       else
+               ipref = pdir->i_number;
+       error = ialloc(pdir, ipref, mode, &tip);
+       if (error) {
+               iput(pdir);
+               return (error);
+       }
+       ip = tip;
+#ifdef QUOTA
+       if (ip->i_dquot != NODQUOT)
+               panic("maknode: dquot");
+#endif
+       ip->i_flag |= IACC|IUPD|ICHG;
+       if ((mode & IFMT) == 0)
+               mode |= IFREG;
+       ip->i_mode = mode;
+       ITOV(ip)->v_type = IFTOVT(mode);        /* Rest init'd in iget() */
+       ip->i_nlink = 1;
+       ip->i_uid = ndp->ni_cred->cr_uid;
+       ip->i_gid = pdir->i_gid;
+       if ((ip->i_mode & ISGID) && !groupmember(ip->i_gid, ndp->ni_cred) &&
+           suser(ndp->ni_cred, NULL))
+               ip->i_mode &= ~ISGID;
+#ifdef QUOTA
+       ip->i_dquot = inoquota(ip);
+#endif
+
+       /*
+        * Make sure inode goes to disk before directory entry.
+        */
+       if ((error = iupdat(ip, &time, &time, 1)) ||
+           (error = direnter(ip, ndp))) {
+               /*
+                * Write error occurred trying to update the inode
+                * or the directory so must deallocate the inode.
+                */
+               ip->i_nlink = 0;
+               ip->i_flag |= ICHG;
+               iput(ip);
+               return (error);
+       }
+       *ipp = ip;
+       return (0);
 }
 }