BSD 4_4 release
[unix-history] / usr / src / sys / ufs / ffs / ffs_alloc.c
index 2e5327c..5bc3787 100644 (file)
@@ -1,10 +1,36 @@
 /*
 /*
- * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
- * All rights reserved.
+ * Copyright (c) 1982, 1986, 1989, 1993
+ *     The Regents of the University of California.  All rights reserved.
  *
  *
- * %sccs.include.redist.c%
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
  *
  *
- *     @(#)ffs_alloc.c 7.28 (Berkeley) %G%
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)ffs_alloc.c 8.1 (Berkeley) 6/11/93
  */
 
 #include <sys/param.h>
  */
 
 #include <sys/param.h>
 #include <sys/buf.h>
 #include <sys/proc.h>
 #include <sys/vnode.h>
 #include <sys/buf.h>
 #include <sys/proc.h>
 #include <sys/vnode.h>
+#include <sys/mount.h>
 #include <sys/kernel.h>
 #include <sys/syslog.h>
 
 #include <sys/kernel.h>
 #include <sys/syslog.h>
 
+#include <vm/vm.h>
+
 #include <ufs/ufs/quota.h>
 #include <ufs/ufs/inode.h>
 
 #include <ufs/ufs/quota.h>
 #include <ufs/ufs/inode.h>
 
@@ -52,25 +81,29 @@ static daddr_t      ffs_mapsearch __P((struct fs *, struct cg *, daddr_t, int));
  *   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.
  */
-ffs_alloc(ip, lbn, bpref, size, bnp)
+ffs_alloc(ip, lbn, bpref, size, cred, bnp)
        register struct inode *ip;
        daddr_t lbn, bpref;
        int size;
        register struct inode *ip;
        daddr_t lbn, bpref;
        int size;
+       struct ucred *cred;
        daddr_t *bnp;
 {
        daddr_t bno;
        register struct fs *fs;
        register struct buf *bp;
        int cg, error;
        daddr_t *bnp;
 {
        daddr_t bno;
        register struct fs *fs;
        register struct buf *bp;
        int cg, error;
-       struct ucred *cred = curproc->p_ucred;          /* XXX */
        
        *bnp = 0;
        fs = ip->i_fs;
        
        *bnp = 0;
        fs = ip->i_fs;
+#ifdef DIAGNOSTIC
        if ((unsigned)size > fs->fs_bsize || fragoff(fs, size) != 0) {
                printf("dev = 0x%x, bsize = %d, size = %d, fs = %s\n",
                    ip->i_dev, fs->fs_bsize, size, fs->fs_fsmnt);
                panic("ffs_alloc: bad size");
        }
        if ((unsigned)size > fs->fs_bsize || fragoff(fs, size) != 0) {
                printf("dev = 0x%x, bsize = %d, size = %d, fs = %s\n",
                    ip->i_dev, fs->fs_bsize, size, fs->fs_fsmnt);
                panic("ffs_alloc: bad size");
        }
+       if (cred == NOCRED)
+               panic("ffs_alloc: missing credential\n");
+#endif /* DIAGNOSTIC */
        if (size == fs->fs_bsize && fs->fs_cstotal.cs_nbfree == 0)
                goto nospace;
        if (cred->cr_uid != 0 && freespace(fs, fs->fs_minfree) <= 0)
        if (size == fs->fs_bsize && fs->fs_cstotal.cs_nbfree == 0)
                goto nospace;
        if (cred->cr_uid != 0 && freespace(fs, fs->fs_minfree) <= 0)
@@ -113,21 +146,22 @@ 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.
  */
-ffs_realloccg(ip, lbprev, bpref, osize, nsize, bpp)
+ffs_realloccg(ip, lbprev, bpref, osize, nsize, cred, bpp)
        register struct inode *ip;
        register struct inode *ip;
-       off_t lbprev;
+       daddr_t lbprev;
        daddr_t bpref;
        int osize, nsize;
        daddr_t bpref;
        int osize, nsize;
+       struct ucred *cred;
        struct buf **bpp;
 {
        register struct fs *fs;
        struct buf *bp, *obp;
        int cg, request, error;
        daddr_t bprev, bno;
        struct buf **bpp;
 {
        register struct fs *fs;
        struct buf *bp, *obp;
        int cg, request, error;
        daddr_t bprev, bno;
-       struct ucred *cred = curproc->p_ucred;          /* XXX */
        
        *bpp = 0;
        fs = ip->i_fs;
        
        *bpp = 0;
        fs = ip->i_fs;
+#ifdef DIAGNOSTIC
        if ((unsigned)osize > fs->fs_bsize || fragoff(fs, osize) != 0 ||
            (unsigned)nsize > fs->fs_bsize || fragoff(fs, nsize) != 0) {
                printf(
        if ((unsigned)osize > fs->fs_bsize || fragoff(fs, osize) != 0 ||
            (unsigned)nsize > fs->fs_bsize || fragoff(fs, nsize) != 0) {
                printf(
@@ -135,6 +169,9 @@ ffs_realloccg(ip, lbprev, bpref, osize, nsize, bpp)
                    ip->i_dev, fs->fs_bsize, osize, nsize, fs->fs_fsmnt);
                panic("ffs_realloccg: bad size");
        }
                    ip->i_dev, fs->fs_bsize, osize, nsize, fs->fs_fsmnt);
                panic("ffs_realloccg: bad size");
        }
+       if (cred == NOCRED)
+               panic("ffs_realloccg: missing credential\n");
+#endif /* DIAGNOSTIC */
        if (cred->cr_uid != 0 && freespace(fs, fs->fs_minfree) <= 0)
                goto nospace;
        if ((bprev = ip->i_db[lbprev]) == 0) {
        if (cred->cr_uid != 0 && freespace(fs, fs->fs_minfree) <= 0)
                goto nospace;
        if ((bprev = ip->i_db[lbprev]) == 0) {
@@ -221,21 +258,12 @@ ffs_realloccg(ip, lbprev, bpref, osize, nsize, bpp)
        bno = (daddr_t)ffs_hashalloc(ip, cg, (long)bpref, request,
            (u_long (*)())ffs_alloccg);
        if (bno > 0) {
        bno = (daddr_t)ffs_hashalloc(ip, cg, (long)bpref, request,
            (u_long (*)())ffs_alloccg);
        if (bno > 0) {
-#ifdef SECSIZE
-               obp = bread(ip->i_dev, fsbtodb(fs, bprev), osize,
-                   fs->fs_dbsize);
-#else SECSIZE
-               count = howmany(osize, CLBYTES);
-               for (i = 0; i < count; i++)
-#ifdef SECSIZE
-                       munhash(ip->i_dev, bn + i * CLBYTES / fs->fs_dbsize);
-#else SECSIZE
-                       munhash(ip->i_dev, bn + i * CLBYTES / DEV_BSIZE);
-#endif SECSIZE
-               ffs_blkfree(ip, bprev, (off_t)osize);
+               bp->b_blkno = fsbtodb(fs, bno);
+               (void) vnode_pager_uncache(ITOV(ip));
+               ffs_blkfree(ip, bprev, (long)osize);
                if (nsize < request)
                        ffs_blkfree(ip, bno + numfrags(fs, nsize),
                if (nsize < request)
                        ffs_blkfree(ip, bno + numfrags(fs, nsize),
-                           (off_t)(request - nsize));
+                           (long)(request - nsize));
                ip->i_blocks += btodb(nsize - osize);
                ip->i_flag |= IUPD|ICHG;
                allocbuf(bp, nsize);
                ip->i_blocks += btodb(nsize - osize);
                ip->i_flag |= IUPD|ICHG;
                allocbuf(bp, nsize);
@@ -275,24 +303,30 @@ 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.
  */
-ffs_ialloc(pip, mode, cred, ipp)
-       register struct inode *pip;
-       int mode;
-       struct ucred *cred;
-       struct inode **ipp;
+ffs_valloc(ap)
+       struct vop_valloc_args /* {
+               struct vnode *a_pvp;
+               int a_mode;
+               struct ucred *a_cred;
+               struct vnode **a_vpp;
+       } */ *ap;
 {
 {
+       register struct vnode *pvp = ap->a_pvp;
+       register struct inode *pip;
        register struct fs *fs;
        register struct inode *ip;
        register struct fs *fs;
        register struct inode *ip;
+       mode_t mode = ap->a_mode;
        ino_t ino, ipref;
        int cg, error;
        
        ino_t ino, ipref;
        int cg, error;
        
-       *ipp = NULL;
+       *ap->a_vpp = NULL;
+       pip = VTOI(pvp);
        fs = pip->i_fs;
        if (fs->fs_cstotal.cs_nifree == 0)
                goto noinodes;
 
        if ((mode & IFMT) == IFDIR)
        fs = pip->i_fs;
        if (fs->fs_cstotal.cs_nifree == 0)
                goto noinodes;
 
        if ((mode & IFMT) == IFDIR)
-               ipref = ffs_dirpref(pip->i_fs);
+               ipref = ffs_dirpref(fs);
        else
                ipref = pip->i_number;
        if (ipref >= fs->fs_ncg * fs->fs_ipg)
        else
                ipref = pip->i_number;
        if (ipref >= fs->fs_ncg * fs->fs_ipg)
@@ -301,16 +335,16 @@ ffs_ialloc(pip, mode, cred, ipp)
        ino = (ino_t)ffs_hashalloc(pip, cg, (long)ipref, mode, ffs_ialloccg);
        if (ino == 0)
                goto noinodes;
        ino = (ino_t)ffs_hashalloc(pip, cg, (long)ipref, mode, ffs_ialloccg);
        if (ino == 0)
                goto noinodes;
-       error = ffs_iget(pip, ino, ipp);
+       error = VFS_VGET(pvp->v_mount, ino, ap->a_vpp);
        if (error) {
        if (error) {
-               ffs_ifree(pip, ino, mode);      /* XXX already freed? */
+               VOP_VFREE(pvp, ino, mode);
                return (error);
        }
                return (error);
        }
-       ip = *ipp;
+       ip = VTOI(*ap->a_vpp);
        if (ip->i_mode) {
                printf("mode = 0%o, inum = %d, fs = %s\n",
                    ip->i_mode, ip->i_number, fs->fs_fsmnt);
        if (ip->i_mode) {
                printf("mode = 0%o, inum = %d, fs = %s\n",
                    ip->i_mode, ip->i_number, fs->fs_fsmnt);
-               panic("ffs_ialloc: dup alloc");
+               panic("ffs_valloc: dup alloc");
        }
        if (ip->i_blocks) {                             /* XXX */
                printf("free inode %s/%d had %d blocks\n",
        }
        if (ip->i_blocks) {                             /* XXX */
                printf("free inode %s/%d had %d blocks\n",
@@ -326,7 +360,7 @@ ffs_ialloc(pip, mode, cred, ipp)
        ip->i_gen = nextgennumber;
        return (0);
 noinodes:
        ip->i_gen = nextgennumber;
        return (0);
 noinodes:
-       ffs_fserr(fs, cred->cr_uid, "out of inodes");
+       ffs_fserr(fs, ap->a_cred->cr_uid, "out of inodes");
        uprintf("\n%s: create/symlink failed, no inodes free\n", fs->fs_fsmnt);
        return (ENOSPC);
 }
        uprintf("\n%s: create/symlink failed, no inodes free\n", fs->fs_fsmnt);
        return (ENOSPC);
 }
@@ -429,9 +463,8 @@ ffs_blkpref(ip, lbn, indx, bap)
         * requested rotationally delayed by fs_rotdelay milliseconds.
         */
        nextblk = bap[indx - 1] + fs->fs_frag;
         * requested rotationally delayed by fs_rotdelay milliseconds.
         */
        nextblk = bap[indx - 1] + fs->fs_frag;
-       if (indx > fs->fs_maxcontig &&
-           bap[indx - fs->fs_maxcontig] + blkstofrags(fs, fs->fs_maxcontig)
-           != nextblk)
+       if (indx < fs->fs_maxcontig || bap[indx - fs->fs_maxcontig] +
+           blkstofrags(fs, fs->fs_maxcontig) != nextblk)
                return (nextblk);
        if (fs->fs_rotdelay != 0)
                /*
                return (nextblk);
        if (fs->fs_rotdelay != 0)
                /*
@@ -530,17 +563,12 @@ ffs_fragextend(ip, cg, bprev, osize, nsize)
                /* cannot extend across a block boundary */
                return (NULL);
        }
                /* cannot extend across a block boundary */
                return (NULL);
        }
-#ifdef SECSIZE
-       bp = bread(ip->i_dev, fsbtodb(fs, cgtod(fs, cg)), (int)fs->fs_cgsize,
-           fs->fs_dbsize);
-#else SECSIZE
        error = bread(ip->i_devvp, fsbtodb(fs, cgtod(fs, cg)),
                (int)fs->fs_cgsize, NOCRED, &bp);
        if (error) {
                brelse(bp);
                return (NULL);
        }
        error = bread(ip->i_devvp, fsbtodb(fs, cgtod(fs, cg)),
                (int)fs->fs_cgsize, NOCRED, &bp);
        if (error) {
                brelse(bp);
                return (NULL);
        }
-#endif SECSIZE
        cgp = bp->b_un.b_cg;
        if (!cg_chkmagic(cgp)) {
                brelse(bp);
        cgp = bp->b_un.b_cg;
        if (!cg_chkmagic(cgp)) {
                brelse(bp);
@@ -582,7 +610,7 @@ ffs_fragextend(ip, cg, bprev, osize, nsize)
  * Check to see if a block of the apprpriate size is available,
  * and if it is, allocate it.
  */
  * Check to see if a block of the apprpriate size is available,
  * and if it is, allocate it.
  */
-daddr_t
+static daddr_t
 ffs_alloccg(ip, cg, bpref, size)
        struct inode *ip;
        int cg;
 ffs_alloccg(ip, cg, bpref, size)
        struct inode *ip;
        int cg;
@@ -598,17 +626,12 @@ ffs_alloccg(ip, cg, bpref, size)
        fs = ip->i_fs;
        if (fs->fs_cs(fs, cg).cs_nbfree == 0 && size == fs->fs_bsize)
                return (NULL);
        fs = ip->i_fs;
        if (fs->fs_cs(fs, cg).cs_nbfree == 0 && size == fs->fs_bsize)
                return (NULL);
-#ifdef SECSIZE
-       bp = bread(ip->i_dev, fsbtodb(fs, cgtod(fs, cg)), (int)fs->fs_cgsize,
-           fs->fs_dbsize);
-#else SECSIZE
        error = bread(ip->i_devvp, fsbtodb(fs, cgtod(fs, cg)),
                (int)fs->fs_cgsize, NOCRED, &bp);
        if (error) {
                brelse(bp);
                return (NULL);
        }
        error = bread(ip->i_devvp, fsbtodb(fs, cgtod(fs, cg)),
                (int)fs->fs_cgsize, NOCRED, &bp);
        if (error) {
                brelse(bp);
                return (NULL);
        }
-#endif SECSIZE
        cgp = bp->b_un.b_cg;
        if (!cg_chkmagic(cgp) ||
            (cgp->cg_cs.cs_nbfree == 0 && size == fs->fs_bsize)) {
        cgp = bp->b_un.b_cg;
        if (!cg_chkmagic(cgp) ||
            (cgp->cg_cs.cs_nbfree == 0 && size == fs->fs_bsize)) {
@@ -713,10 +736,13 @@ ffs_alloccgblk(fs, cgp, bpref)
                goto norot;
        if (fs->fs_cpc == 0) {
                /*
                goto norot;
        if (fs->fs_cpc == 0) {
                /*
-                * block layout info is not available, so just have
-                * to take any block in this cylinder.
+                * Block layout information is not available.
+                * Leaving bpref unchanged means we take the
+                * next available free block following the one 
+                * we just allocated. Hopefully this will at
+                * least hit a track cache on drives of unknown
+                * geometry (e.g. SCSI).
                 */
                 */
-               bpref = howmany(fs->fs_spc * cylno, NSPF(fs));
                goto norot;
        }
        /*
                goto norot;
        }
        /*
@@ -804,17 +830,12 @@ ffs_ialloccg(ip, cg, ipref, mode)
        fs = ip->i_fs;
        if (fs->fs_cs(fs, cg).cs_nifree == 0)
                return (NULL);
        fs = ip->i_fs;
        if (fs->fs_cs(fs, cg).cs_nifree == 0)
                return (NULL);
-#ifdef SECSIZE
-       bp = bread(ip->i_dev, fsbtodb(fs, cgtod(fs, cg)), (int)fs->fs_cgsize,
-           fs->fs_dbsize);
-#else SECSIZE
        error = bread(ip->i_devvp, fsbtodb(fs, cgtod(fs, cg)),
                (int)fs->fs_cgsize, NOCRED, &bp);
        if (error) {
                brelse(bp);
                return (NULL);
        }
        error = bread(ip->i_devvp, fsbtodb(fs, cgtod(fs, cg)),
                (int)fs->fs_cgsize, NOCRED, &bp);
        if (error) {
                brelse(bp);
                return (NULL);
        }
-#endif SECSIZE
        cgp = bp->b_un.b_cg;
        if (!cg_chkmagic(cgp) || cgp->cg_cs.cs_nifree == 0) {
                brelse(bp);
        cgp = bp->b_un.b_cg;
        if (!cg_chkmagic(cgp) || cgp->cg_cs.cs_nifree == 0) {
                brelse(bp);
@@ -877,14 +898,13 @@ gotit:
 ffs_blkfree(ip, bno, size)
        register struct inode *ip;
        daddr_t bno;
 ffs_blkfree(ip, bno, size)
        register struct inode *ip;
        daddr_t bno;
-       off_t size;
+       long size;
 {
        register struct fs *fs;
        register struct cg *cgp;
        struct buf *bp;
        int error, cg, blk, frags, bbase;
        register int i;
 {
        register struct fs *fs;
        register struct cg *cgp;
        struct buf *bp;
        int error, cg, blk, frags, bbase;
        register int i;
-       struct ucred *cred = curproc->p_ucred;  /* XXX */
 
        fs = ip->i_fs;
        if ((unsigned)size > fs->fs_bsize || fragoff(fs, size) != 0) {
 
        fs = ip->i_fs;
        if ((unsigned)size > fs->fs_bsize || fragoff(fs, size) != 0) {
@@ -895,20 +915,15 @@ ffs_blkfree(ip, bno, size)
        cg = dtog(fs, bno);
        if ((unsigned)bno >= fs->fs_size) {
                printf("bad block %d, ino %d\n", bno, ip->i_number);
        cg = dtog(fs, bno);
        if ((unsigned)bno >= fs->fs_size) {
                printf("bad block %d, ino %d\n", bno, ip->i_number);
-               ffs_fserr(fs, cred->cr_uid, "bad block");
+               ffs_fserr(fs, ip->i_uid, "bad block");
                return;
        }
                return;
        }
-#ifdef SECSIZE
-       bp = bread(ip->i_dev, fsbtodb(fs, cgtod(fs, cg)), (int)fs->fs_cgsize,
-           fs->fs_dbsize);
-#else SECSIZE
        error = bread(ip->i_devvp, fsbtodb(fs, cgtod(fs, cg)),
                (int)fs->fs_cgsize, NOCRED, &bp);
        if (error) {
                brelse(bp);
                return;
        }
        error = bread(ip->i_devvp, fsbtodb(fs, cgtod(fs, cg)),
                (int)fs->fs_cgsize, NOCRED, &bp);
        if (error) {
                brelse(bp);
                return;
        }
-#endif SECSIZE
        cgp = bp->b_un.b_cg;
        if (!cg_chkmagic(cgp)) {
                brelse(bp);
        cgp = bp->b_un.b_cg;
        if (!cg_chkmagic(cgp)) {
                brelse(bp);
@@ -981,37 +996,37 @@ ffs_blkfree(ip, bno, size)
  *
  * The specified inode is placed back in the free map.
  */
  *
  * The specified inode is placed back in the free map.
  */
-void
-ffs_ifree(pip, ino, mode)
-       struct inode *pip;
-       ino_t ino;
-       int mode;
+int
+ffs_vfree(ap)
+       struct vop_vfree_args /* {
+               struct vnode *a_pvp;
+               ino_t a_ino;
+               int a_mode;
+       } */ *ap;
 {
        register struct fs *fs;
        register struct cg *cgp;
 {
        register struct fs *fs;
        register struct cg *cgp;
+       register struct inode *pip;
+       ino_t ino = ap->a_ino;
        struct buf *bp;
        int error, cg;
 
        struct buf *bp;
        int error, cg;
 
+       pip = VTOI(ap->a_pvp);
        fs = pip->i_fs;
        if ((u_int)ino >= fs->fs_ipg * fs->fs_ncg)
                panic("ifree: range: dev = 0x%x, ino = %d, fs = %s\n",
                    pip->i_dev, ino, fs->fs_fsmnt);
        cg = itog(fs, ino);
        fs = pip->i_fs;
        if ((u_int)ino >= fs->fs_ipg * fs->fs_ncg)
                panic("ifree: range: dev = 0x%x, ino = %d, fs = %s\n",
                    pip->i_dev, ino, fs->fs_fsmnt);
        cg = itog(fs, ino);
-#ifdef SECSIZE
-       bp = bread(ip->i_dev, fsbtodb(fs, cgtod(fs, cg)), (int)fs->fs_cgsize,
-           fs->fs_dbsize);
-#else SECSIZE
        error = bread(pip->i_devvp, fsbtodb(fs, cgtod(fs, cg)),
                (int)fs->fs_cgsize, NOCRED, &bp);
        if (error) {
                brelse(bp);
        error = bread(pip->i_devvp, fsbtodb(fs, cgtod(fs, cg)),
                (int)fs->fs_cgsize, NOCRED, &bp);
        if (error) {
                brelse(bp);
-               return;
+               return (0);
        }
        }
-#endif SECSIZE
        cgp = bp->b_un.b_cg;
        if (!cg_chkmagic(cgp)) {
                brelse(bp);
        cgp = bp->b_un.b_cg;
        if (!cg_chkmagic(cgp)) {
                brelse(bp);
-               return;
+               return (0);
        }
        cgp->cg_time = time.tv_sec;
        ino %= fs->fs_ipg;
        }
        cgp->cg_time = time.tv_sec;
        ino %= fs->fs_ipg;
@@ -1027,13 +1042,14 @@ ffs_ifree(pip, ino, mode)
        cgp->cg_cs.cs_nifree++;
        fs->fs_cstotal.cs_nifree++;
        fs->fs_cs(fs, cg).cs_nifree++;
        cgp->cg_cs.cs_nifree++;
        fs->fs_cstotal.cs_nifree++;
        fs->fs_cs(fs, cg).cs_nifree++;
-       if ((mode & IFMT) == IFDIR) {
+       if ((ap->a_mode & IFMT) == IFDIR) {
                cgp->cg_cs.cs_ndir--;
                fs->fs_cstotal.cs_ndir--;
                fs->fs_cs(fs, cg).cs_ndir--;
        }
        fs->fs_fmod = 1;
        bdwrite(bp);
                cgp->cg_cs.cs_ndir--;
                fs->fs_cstotal.cs_ndir--;
                fs->fs_cs(fs, cg).cs_ndir--;
        }
        fs->fs_fmod = 1;
        bdwrite(bp);
+       return (0);
 }
 
 /*
 }
 
 /*