]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/ufs/ffs/ffs_alloc.c
xnu-792.12.6.tar.gz
[apple/xnu.git] / bsd / ufs / ffs / ffs_alloc.c
index c6e4620977454d5d74fb6035ca1ed2b35c8f1b5a..e74e7423c1f07577fe08942cb6941b6d074ee7fc 100644 (file)
@@ -1,23 +1,31 @@
 /*
- * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2000-2003 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * @APPLE_LICENSE_OSREFERENCE_HEADER_START@
  * 
- * The contents of this file constitute Original Code as defined in and
- * are subject to the Apple Public Source License Version 1.1 (the
- * "License").  You may not use this file except in compliance with the
- * License.  Please obtain a copy of the License at
- * http://www.apple.com/publicsource and read it before using this file.
- * 
- * This Original Code and all software distributed under the License are
- * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
- * License for the specific language governing rights and limitations
- * under the License.
- * 
- * @APPLE_LICENSE_HEADER_END@
+ * This file contains Original Code and/or Modifications of Original Code 
+ * as defined in and that are subject to the Apple Public Source License 
+ * Version 2.0 (the 'License'). You may not use this file except in 
+ * compliance with the License.  The rights granted to you under the 
+ * License may not be used to create, or enable the creation or 
+ * redistribution of, unlawful or unlicensed copies of an Apple operating 
+ * system, or to circumvent, violate, or enable the circumvention or 
+ * violation of, any terms of an Apple operating system software license 
+ * agreement.
+ *
+ * Please obtain a copy of the License at 
+ * http://www.opensource.apple.com/apsl/ and read it before using this 
+ * file.
+ *
+ * The Original Code and all software distributed under the License are 
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 
+ * Please see the License for the specific language governing rights and 
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_OSREFERENCE_HEADER_END@
  */
 /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
 /*
 
 #include <sys/param.h>
 #include <sys/systm.h>
-#include <sys/buf.h>
+#include <sys/buf_internal.h>
 #include <sys/proc.h>
-#include <sys/vnode.h>
-#include <sys/mount.h>
+#include <sys/kauth.h>
+#include <sys/vnode_internal.h>
+#include <sys/mount_internal.h>
 #include <sys/kernel.h>
 #include <sys/syslog.h>
+#include <sys/quota.h>
 
 #include <sys/vm.h>
 
 
 extern u_long nextgennumber;
 
-static ufs_daddr_t ffs_alloccg __P((struct inode *, int, ufs_daddr_t, int));
-static ufs_daddr_t ffs_alloccgblk __P((struct fs *, struct cg *, ufs_daddr_t));
-static ufs_daddr_t ffs_clusteralloc __P((struct inode *, int, ufs_daddr_t,
-           int));
-static ino_t   ffs_dirpref __P((struct fs *));
-static ufs_daddr_t ffs_fragextend __P((struct inode *, int, long, int, int));
-static void    ffs_fserr __P((struct fs *, u_int, char *));
+static ufs_daddr_t ffs_alloccg(struct inode *, int, ufs_daddr_t, int);
+static ufs_daddr_t ffs_alloccgblk(struct fs *, struct cg *, ufs_daddr_t);
+static ufs_daddr_t ffs_clusteralloc(struct inode *, int, ufs_daddr_t, int);
+static ino_t   ffs_dirpref(struct inode *);
+static ufs_daddr_t ffs_fragextend(struct inode *, int, long, int, int);
+static void    ffs_fserr(struct fs *, u_int, char *);
 static u_long  ffs_hashalloc
-                   __P((struct inode *, int, long, int, u_int32_t (*)()));
-static ino_t   ffs_nodealloccg __P((struct inode *, int, ufs_daddr_t, int));
-static ufs_daddr_t ffs_mapsearch __P((struct fs *, struct cg *, ufs_daddr_t,
-           int));
+                  (struct inode *, int, long, int, u_int32_t (*)());
+static ino_t   ffs_nodealloccg(struct inode *, int, ufs_daddr_t, int);
+static ufs_daddr_t ffs_mapsearch(struct fs *, struct cg *, ufs_daddr_t, int);
+static void ffs_clusteracct
+               (struct fs *fs, struct cg *cgp, ufs_daddr_t blkno, int cnt);
 
 /*
  * Allocate a block in the file system.
@@ -117,7 +127,7 @@ ffs_alloc(ip, lbn, bpref, size, cred, bnp)
        register struct inode *ip;
        ufs_daddr_t lbn, bpref;
        int size;
-       struct ucred *cred;
+       kauth_cred_t cred;
        ufs_daddr_t *bnp;
 {
        register struct fs *fs;
@@ -137,11 +147,11 @@ ffs_alloc(ip, lbn, bpref, size, cred, bnp)
 #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 (suser(cred, NULL) && freespace(fs, fs->fs_minfree) <= 0)
                goto nospace;
-       VOP_DEVBLOCKSIZE(ip->i_devvp,&devBlockSize);
+       devBlockSize = vfs_devblocksize(vnode_mount(ITOV(ip)));
 #if QUOTA
-       if (error = chkdq(ip, (long)btodb(size, devBlockSize), cred, 0))
+       if (error = chkdq(ip, (int64_t)size, cred, 0))
                return (error);
 #endif /* QUOTA */
        if (bpref >= fs->fs_size)
@@ -162,10 +172,10 @@ ffs_alloc(ip, lbn, bpref, size, cred, bnp)
        /*
         * Restore user's disk quota because allocation failed.
         */
-       (void) chkdq(ip, (long)-btodb(size, devBlockSize), cred, FORCE);
+       (void) chkdq(ip, (int64_t)-size, cred, FORCE);
 #endif /* QUOTA */
 nospace:
-       ffs_fserr(fs, cred->cr_uid, "file system full");
+       ffs_fserr(fs, kauth_cred_getuid(cred), "file system full");
        uprintf("\n%s: write failed, file system is full\n", fs->fs_fsmnt);
        return (ENOSPC);
 }
@@ -183,7 +193,7 @@ ffs_realloccg(ip, lbprev, bpref, osize, nsize, cred, bpp)
        ufs_daddr_t lbprev;
        ufs_daddr_t bpref;
        int osize, nsize;
-       struct ucred *cred;
+       kauth_cred_t cred;
        struct buf **bpp;
 {
        register struct fs *fs;
@@ -205,7 +215,7 @@ ffs_realloccg(ip, lbprev, bpref, osize, nsize, cred, bpp)
        if (cred == NOCRED)
                panic("ffs_realloccg: missing credential\n");
 #endif /* DIAGNOSTIC */
-       if (cred->cr_uid != 0 && freespace(fs, fs->fs_minfree) <= 0)
+       if (suser(cred, NULL) != 0 && freespace(fs, fs->fs_minfree) <= 0)
                goto nospace;
        if ((bprev = ip->i_db[lbprev]) == 0) {
                printf("dev = 0x%x, bsize = %d, bprev = %d, fs = %s\n",
@@ -215,16 +225,16 @@ ffs_realloccg(ip, lbprev, bpref, osize, nsize, cred, bpp)
        /*
         * Allocate the extra space in the buffer.
         */
-       if (error = bread(ITOV(ip), lbprev, osize, NOCRED, &bp)) {
-               brelse(bp);
+       if (error = (int)buf_bread(ITOV(ip), (daddr64_t)((unsigned)lbprev), osize, NOCRED, &bp)) {
+               buf_brelse(bp);
                return (error);
        }
-       VOP_DEVBLOCKSIZE(ip->i_devvp,&devBlockSize);
+       devBlockSize = vfs_devblocksize(vnode_mount(ITOV(ip)));
 
 #if QUOTA
-       if (error = chkdq(ip, (long)btodb(nsize - osize, devBlockSize), cred, 0))
+       if (error = chkdq(ip, (int64_t)(nsize - osize), cred, 0))
        {
-               brelse(bp);
+               buf_brelse(bp);
                return (error);
        }
 #endif /* QUOTA */
@@ -233,13 +243,13 @@ ffs_realloccg(ip, lbprev, bpref, osize, nsize, cred, bpp)
         */
        cg = dtog(fs, bprev);
        if (bno = ffs_fragextend(ip, cg, (long)bprev, osize, nsize)) {
-               if (bp->b_blkno != fsbtodb(fs, bno))
+               if ((ufs_daddr_t)buf_blkno(bp) != fsbtodb(fs, bno))
                        panic("bad blockno");
                ip->i_blocks += btodb(nsize - osize, devBlockSize);
                ip->i_flag |= IN_CHANGE | IN_UPDATE;
                allocbuf(bp, nsize);
-               bp->b_flags |= B_DONE;
-               bzero((char *)bp->b_data + osize, (u_int)nsize - osize);
+               buf_setflags(bp, B_DONE);
+               bzero((char *)buf_dataptr(bp) + osize, (u_int)buf_size(bp) - osize);
                *bpp = bp;
                return (0);
        }
@@ -294,7 +304,7 @@ ffs_realloccg(ip, lbprev, bpref, osize, nsize, cred, bpp)
        bno = (ufs_daddr_t)ffs_hashalloc(ip, cg, (long)bpref, request,
            (u_int32_t (*)())ffs_alloccg);
        if (bno > 0) {
-               bp->b_blkno = fsbtodb(fs, bno);
+               buf_setblkno(bp, (daddr64_t)((unsigned)fsbtodb(fs, bno)));
                ffs_blkfree(ip, bprev, (long)osize);
                if (nsize < request)
                        ffs_blkfree(ip, bno + numfrags(fs, nsize),
@@ -302,8 +312,8 @@ ffs_realloccg(ip, lbprev, bpref, osize, nsize, cred, bpp)
                ip->i_blocks += btodb(nsize - osize, devBlockSize);
                ip->i_flag |= IN_CHANGE | IN_UPDATE;
                allocbuf(bp, nsize);
-               bp->b_flags |= B_DONE;
-               bzero((char *)bp->b_data + osize, (u_int)nsize - osize);
+               buf_setflags(bp, B_DONE);
+               bzero((char *)buf_dataptr(bp) + osize, (u_int)buf_size(bp) - osize);
                *bpp = bp;
                return (0);
        }
@@ -311,14 +321,14 @@ ffs_realloccg(ip, lbprev, bpref, osize, nsize, cred, bpp)
        /*
         * Restore user's disk quota because allocation failed.
         */
-       (void) chkdq(ip, (long)-btodb(nsize - osize, devBlockSize), cred, FORCE);
+       (void) chkdq(ip, (int64_t)-(nsize - osize), cred, FORCE);
 #endif /* QUOTA */
-       brelse(bp);
+       buf_brelse(bp);
 nospace:
        /*
         * no space available
         */
-       ffs_fserr(fs, cred->cr_uid, "file system full");
+       ffs_fserr(fs, kauth_cred_getuid(cred), "file system full");
        uprintf("\n%s: write failed, file system is full\n", fs->fs_fsmnt);
        return (ENOSPC);
 }
@@ -342,12 +352,6 @@ nospace:
 int doasyncfree = 1;
 int doreallocblks = 1;
 
-int
-ffs_reallocblks(ap)
-       struct vop_reallocblks_args *ap;
-{
-       return (ENOSPC);
-}
 
 /*
  * Allocate an inode in the file system.
@@ -365,44 +369,55 @@ ffs_reallocblks(ap)
  *      available inode is located.
  */
 int
-ffs_valloc(ap)
-       struct vop_valloc_args /* {
-               struct vnode *a_pvp;
-               int a_mode;
-               struct ucred *a_cred;
-               struct vnode **a_vpp;
-       } */ *ap;
+ffs_valloc(
+               struct vnode *pvp,
+               mode_t mode,
+               kauth_cred_t cred,
+               struct vnode **vpp)
+
 {
-       register struct vnode *pvp = ap->a_pvp;
        register struct inode *pip;
        register struct fs *fs;
        register struct inode *ip;
-       mode_t mode = ap->a_mode;
+       struct timeval tv;
        ino_t ino, ipref;
        int cg, error;
        
-       *ap->a_vpp = NULL;
+       *vpp = NULL;
        pip = VTOI(pvp);
        fs = pip->i_fs;
        if (fs->fs_cstotal.cs_nifree == 0)
                goto noinodes;
 
        if ((mode & IFMT) == IFDIR)
-               ipref = ffs_dirpref(fs);
+               ipref = ffs_dirpref(pip);
        else
                ipref = pip->i_number;
        if (ipref >= fs->fs_ncg * fs->fs_ipg)
                ipref = 0;
        cg = ino_to_cg(fs, ipref);
+       /*
+        * Track the number of dirs created one after another
+        * in a cg without intervening files.
+        */
+       if ((mode & IFMT) == IFDIR) {
+               if (fs->fs_contigdirs[cg] < 255)
+                       fs->fs_contigdirs[cg]++;
+       } else {
+               if (fs->fs_contigdirs[cg] > 0)
+                       fs->fs_contigdirs[cg]--;
+       }
        ino = (ino_t)ffs_hashalloc(pip, cg, (long)ipref, mode, ffs_nodealloccg);
        if (ino == 0)
                goto noinodes;
-       error = VFS_VGET(pvp->v_mount, ino, ap->a_vpp);
+
+        error = ffs_vget_internal(pvp->v_mount, ino, vpp, NULL, NULL, mode, 0);
        if (error) {
-               VOP_VFREE(pvp, ino, mode);
+               ffs_vfree(pvp, ino, mode);
                return (error);
        }
-       ip = VTOI(*ap->a_vpp);
+       ip = VTOI(*vpp);
+
        if (ip->i_mode) {
                printf("mode = 0%o, inum = %d, fs = %s\n",
                    ip->i_mode, ip->i_number, fs->fs_fsmnt);
@@ -417,39 +432,124 @@ ffs_valloc(ap)
        /*
         * Set up a new generation number for this inode.
         */
-       if (++nextgennumber < (u_long)time.tv_sec)
-               nextgennumber = time.tv_sec;
+       microtime(&tv);
+       if (++nextgennumber < (u_long)tv.tv_sec)
+               nextgennumber = tv.tv_sec;
        ip->i_gen = nextgennumber;
        return (0);
 noinodes:
-       ffs_fserr(fs, ap->a_cred->cr_uid, "out of inodes");
+       ffs_fserr(fs, kauth_cred_getuid(cred), "out of inodes");
        uprintf("\n%s: create/symlink failed, no inodes free\n", fs->fs_fsmnt);
        return (ENOSPC);
 }
 
 /*
- * Find a cylinder to place a directory.
+ * Find a cylinder group to place a directory.
  *
- * The policy implemented by this algorithm is to select from
- * among those cylinder groups with above the average number of
- * free inodes, the one with the smallest number of directories.
+ * The policy implemented by this algorithm is to allocate a
+ * directory inode in the same cylinder group as its parent
+ * directory, but also to reserve space for its files inodes
+ * and data. Restrict the number of directories which may be
+ * allocated one after another in the same cylinder group
+ * without intervening allocation of files.
  */
 static ino_t
-ffs_dirpref(fs)
-       register struct fs *fs;
+ffs_dirpref(pip)
+       struct inode *pip;
 {
-       int cg, minndir, mincg, avgifree;
+       register struct fs *fs;
+       int cg, prefcg, dirsize, cgsize;
+       int avgifree, avgbfree, avgndir, curdirsize;
+       int minifree, minbfree, maxndir;
+       int mincg, minndir;
+       int maxcontigdirs;
 
+       fs = pip->i_fs;
        avgifree = fs->fs_cstotal.cs_nifree / fs->fs_ncg;
-       minndir = fs->fs_ipg;
-       mincg = 0;
-       for (cg = 0; cg < fs->fs_ncg; cg++)
-               if (fs->fs_cs(fs, cg).cs_ndir < minndir &&
-                   fs->fs_cs(fs, cg).cs_nifree >= avgifree) {
-                       mincg = cg;
-                       minndir = fs->fs_cs(fs, cg).cs_ndir;
+       avgbfree = fs->fs_cstotal.cs_nbfree / fs->fs_ncg;
+       avgndir = fs->fs_cstotal.cs_ndir / fs->fs_ncg;
+
+       /*
+        * Force allocation in another cg if creating a first level dir.
+        */
+       if (ITOV(pip)->v_flag & VROOT) {
+#ifdef __APPLE__
+               prefcg = random() % fs->fs_ncg;
+#else
+               prefcg = arc4random() % fs->fs_ncg;
+#endif
+               mincg = prefcg;
+               minndir = fs->fs_ipg;
+               for (cg = prefcg; cg < fs->fs_ncg; cg++)
+                       if (fs->fs_cs(fs, cg).cs_ndir < minndir &&
+                           fs->fs_cs(fs, cg).cs_nifree >= avgifree &&
+                           fs->fs_cs(fs, cg).cs_nbfree >= avgbfree) {
+                               mincg = cg;
+                               minndir = fs->fs_cs(fs, cg).cs_ndir;
+                       }
+               for (cg = 0; cg < prefcg; cg++)
+                       if (fs->fs_cs(fs, cg).cs_ndir < minndir &&
+                           fs->fs_cs(fs, cg).cs_nifree >= avgifree &&
+                           fs->fs_cs(fs, cg).cs_nbfree >= avgbfree) {
+                               mincg = cg;
+                               minndir = fs->fs_cs(fs, cg).cs_ndir;
+                       }
+               return ((ino_t)(fs->fs_ipg * mincg));
+       }
+
+       /*
+        * Count various limits which used for
+        * optimal allocation of a directory inode.
+        */
+       maxndir = min(avgndir + fs->fs_ipg / 16, fs->fs_ipg);
+       minifree = avgifree - fs->fs_ipg / 4;
+       if (minifree < 0)
+               minifree = 0;
+       minbfree = avgbfree - fs->fs_fpg / fs->fs_frag / 4;
+       if (minbfree < 0)
+               minbfree = 0;
+       cgsize = fs->fs_fsize * fs->fs_fpg;
+       dirsize = fs->fs_avgfilesize * fs->fs_avgfpdir;
+       curdirsize = avgndir ? (cgsize - avgbfree * fs->fs_bsize) / avgndir : 0;
+       if (dirsize < curdirsize)
+               dirsize = curdirsize;
+       maxcontigdirs = min(cgsize / dirsize, 255);
+       if (fs->fs_avgfpdir > 0)
+               maxcontigdirs = min(maxcontigdirs,
+                   fs->fs_ipg / fs->fs_avgfpdir);
+       if (maxcontigdirs == 0)
+               maxcontigdirs = 1;
+
+       /*
+        * Limit number of dirs in one cg and reserve space for
+        * regular files, but only if we have no deficit in
+        * inodes or space.
+        */
+       prefcg = ino_to_cg(fs, pip->i_number);
+       for (cg = prefcg; cg < fs->fs_ncg; cg++)
+               if (fs->fs_cs(fs, cg).cs_ndir < maxndir &&
+                   fs->fs_cs(fs, cg).cs_nifree >= minifree &&
+                   fs->fs_cs(fs, cg).cs_nbfree >= minbfree) {
+                       if (fs->fs_contigdirs[cg] < maxcontigdirs)
+                               return ((ino_t)(fs->fs_ipg * cg));
                }
-       return ((ino_t)(fs->fs_ipg * mincg));
+       for (cg = 0; cg < prefcg; cg++)
+               if (fs->fs_cs(fs, cg).cs_ndir < maxndir &&
+                   fs->fs_cs(fs, cg).cs_nifree >= minifree &&
+                   fs->fs_cs(fs, cg).cs_nbfree >= minbfree) {
+                       if (fs->fs_contigdirs[cg] < maxcontigdirs)
+                               return ((ino_t)(fs->fs_ipg * cg));
+               }
+       /*
+        * This is a backstop when we have deficit in space.
+        */
+       for (cg = prefcg; cg < fs->fs_ncg; cg++)
+               if (fs->fs_cs(fs, cg).cs_nifree >= avgifree)
+                       return ((ino_t)(fs->fs_ipg * cg));
+       for (cg = 0; cg < prefcg; cg++)
+               if (fs->fs_cs(fs, cg).cs_nifree >= avgifree)
+                       break;
+       return ((ino_t)(fs->fs_ipg * cg));
 }
 
 /*
@@ -657,6 +757,7 @@ ffs_fragextend(ip, cg, bprev, osize, nsize)
        register struct fs *fs;
        register struct cg *cgp;
        struct buf *bp;
+       struct timeval tv;
        long bno;
        int frags, bbase;
        int i, error;
@@ -676,13 +777,13 @@ ffs_fragextend(ip, cg, bprev, osize, nsize)
                return (NULL);
        }
        /* read corresponding cylinder group info */
-       error = bread(ip->i_devvp, fsbtodb(fs, cgtod(fs, cg)),
-               (int)fs->fs_cgsize, NOCRED, &bp);
+       error = (int)buf_bread(ip->i_devvp, (daddr64_t)((unsigned)fsbtodb(fs, cgtod(fs, cg))),
+                              (int)fs->fs_cgsize, NOCRED, &bp);
        if (error) {
-               brelse(bp);
+               buf_brelse(bp);
                return (NULL);
        }
-       cgp = (struct cg *)bp->b_data;
+       cgp = (struct cg *)buf_dataptr(bp);
 #if REV_ENDIAN_FS
        if (rev_endian) {
                byte_swap_cgin(cgp, fs);
@@ -694,10 +795,11 @@ ffs_fragextend(ip, cg, bprev, osize, nsize)
                if (rev_endian)
                        byte_swap_cgout(cgp,fs);
 #endif /* REV_ENDIAN_FS */
-               brelse(bp);
+               buf_brelse(bp);
                return (NULL);
        }
-       cgp->cg_time = time.tv_sec;
+       microtime(&tv);
+       cgp->cg_time = tv.tv_sec;
        bno = dtogd(fs, bprev);
        for (i = numfrags(fs, osize); i < frags; i++)
                if (isclr(cg_blksfree(cgp), bno + i)) {
@@ -705,7 +807,7 @@ ffs_fragextend(ip, cg, bprev, osize, nsize)
                        if (rev_endian)
                                byte_swap_cgout(cgp,fs);
 #endif /* REV_ENDIAN_FS */
-                       brelse(bp);
+                       buf_brelse(bp);
                        return (NULL);
                }
        /*
@@ -731,7 +833,7 @@ ffs_fragextend(ip, cg, bprev, osize, nsize)
        if (rev_endian)
                byte_swap_cgout(cgp,fs);
 #endif /* REV_ENDIAN_FS */
-       bdwrite(bp);
+       buf_bdwrite(bp);
        return (bprev);
 }
 
@@ -751,6 +853,7 @@ ffs_alloccg(ip, cg, bpref, size)
        register struct fs *fs;
        register struct cg *cgp;
        struct buf *bp;
+       struct timeval tv;
        register int i;
        int error, bno, frags, allocsiz;
 #if REV_ENDIAN_FS
@@ -762,13 +865,13 @@ 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);
-       error = bread(ip->i_devvp, fsbtodb(fs, cgtod(fs, cg)),
-               (int)fs->fs_cgsize, NOCRED, &bp);
+       error = (int)buf_bread(ip->i_devvp, (daddr64_t)((unsigned)fsbtodb(fs, cgtod(fs, cg))),
+                              (int)fs->fs_cgsize, NOCRED, &bp);
        if (error) {
-               brelse(bp);
+               buf_brelse(bp);
                return (NULL);
        }
-       cgp = (struct cg *)bp->b_data;
+       cgp = (struct cg *)buf_dataptr(bp);
 #if REV_ENDIAN_FS
        if (rev_endian)
                byte_swap_cgin(cgp,fs);
@@ -779,17 +882,18 @@ ffs_alloccg(ip, cg, bpref, size)
                if (rev_endian)
                        byte_swap_cgout(cgp,fs);
 #endif /* REV_ENDIAN_FS */
-               brelse(bp);
+               buf_brelse(bp);
                return (NULL);
        }
-       cgp->cg_time = time.tv_sec;
+       microtime(&tv);
+       cgp->cg_time = tv.tv_sec;
        if (size == fs->fs_bsize) {
                bno = ffs_alloccgblk(fs, cgp, bpref);
 #if REV_ENDIAN_FS
                if (rev_endian)
                        byte_swap_cgout(cgp,fs);
 #endif /* REV_ENDIAN_FS */
-               bdwrite(bp);
+               buf_bdwrite(bp);
                return (bno);
        }
        /*
@@ -811,7 +915,7 @@ ffs_alloccg(ip, cg, bpref, size)
                        if (rev_endian)
                                byte_swap_cgout(cgp,fs);
 #endif /* REV_ENDIAN_FS */
-                       brelse(bp);
+                       buf_brelse(bp);
                        return (NULL);
                }
                bno = ffs_alloccgblk(fs, cgp, bpref);
@@ -828,7 +932,7 @@ ffs_alloccg(ip, cg, bpref, size)
                if (rev_endian)
                        byte_swap_cgout(cgp,fs);
 #endif /* REV_ENDIAN_FS */
-               bdwrite(bp);
+               buf_bdwrite(bp);
                return (bno);
        }
        bno = ffs_mapsearch(fs, cgp, bpref, allocsiz);
@@ -837,7 +941,7 @@ ffs_alloccg(ip, cg, bpref, size)
                if (rev_endian)
                        byte_swap_cgout(cgp,fs);
 #endif /* REV_ENDIAN_FS */
-               brelse(bp);
+               buf_brelse(bp);
                return (NULL);
        }
        for (i = 0; i < frags; i++)
@@ -853,7 +957,7 @@ ffs_alloccg(ip, cg, bpref, size)
        if (rev_endian)
                byte_swap_cgout(cgp,fs);
 #endif /* REV_ENDIAN_FS */
-       bdwrite(bp);
+       buf_bdwrite(bp);
        return (cg * fs->fs_fpg + bno);
 }
 
@@ -1001,10 +1105,10 @@ ffs_clusteralloc(ip, cg, bpref, len)
        fs = ip->i_fs;
        if (fs->fs_maxcluster[cg] < len)
                return (NULL);
-       if (bread(ip->i_devvp, fsbtodb(fs, cgtod(fs, cg)), (int)fs->fs_cgsize,
-           NOCRED, &bp))
+       if (buf_bread(ip->i_devvp, (daddr64_t)((unsigned)fsbtodb(fs, cgtod(fs, cg))), (int)fs->fs_cgsize,
+                     NOCRED, &bp))
                goto fail;
-       cgp = (struct cg *)bp->b_data;
+       cgp = (struct cg *)buf_dataptr(bp);
 #if    REV_ENDIAN_FS
        if (rev_endian)
                byte_swap_cgin(cgp,fs);
@@ -1100,11 +1204,11 @@ ffs_clusteralloc(ip, cg, bpref, len)
        if (rev_endian)
                byte_swap_cgout(cgp,fs);
 #endif /* REV_ENDIAN_FS */
-       bdwrite(bp);
+       buf_bdwrite(bp);
        return (bno);
 
 fail:
-       brelse(bp);
+       buf_brelse(bp);
        return (0);
 }
 
@@ -1127,6 +1231,7 @@ ffs_nodealloccg(ip, cg, ipref, mode)
        register struct fs *fs;
        register struct cg *cgp;
        struct buf *bp;
+       struct timeval tv;
        int error, start, len, loc, map, i;
 #if REV_ENDIAN_FS
        struct vnode *vp=ITOV(ip);
@@ -1137,13 +1242,13 @@ ffs_nodealloccg(ip, cg, ipref, mode)
        fs = ip->i_fs;
        if (fs->fs_cs(fs, cg).cs_nifree == 0)
                return (NULL);
-       error = bread(ip->i_devvp, fsbtodb(fs, cgtod(fs, cg)),
-               (int)fs->fs_cgsize, NOCRED, &bp);
+       error = (int)buf_bread(ip->i_devvp, (daddr64_t)((unsigned)fsbtodb(fs, cgtod(fs, cg))),
+                              (int)fs->fs_cgsize, NOCRED, &bp);
        if (error) {
-               brelse(bp);
+               buf_brelse(bp);
                return (NULL);
        }
-       cgp = (struct cg *)bp->b_data;
+       cgp = (struct cg *)buf_dataptr(bp);
 #if REV_ENDIAN_FS
        if (rev_endian)
                byte_swap_cgin(cgp,fs);
@@ -1153,11 +1258,12 @@ ffs_nodealloccg(ip, cg, ipref, mode)
                if (rev_endian)
                        byte_swap_cgout(cgp,fs);
 #endif /* REV_ENDIAN_FS */
-               brelse(bp);
+               buf_brelse(bp);
                return (NULL);
        }
 
-       cgp->cg_time = time.tv_sec;
+       microtime(&tv);
+       cgp->cg_time = tv.tv_sec;
        if (ipref) {
                ipref %= fs->fs_ipg;
                if (isclr(cg_inosused(cgp), ipref))
@@ -1204,7 +1310,7 @@ gotit:
        if (rev_endian)
                byte_swap_cgout(cgp,fs);
 #endif /* REV_ENDIAN_FS */
-       bdwrite(bp);
+       buf_bdwrite(bp);
        return (cg * fs->fs_ipg + ipref);
 }
 
@@ -1215,6 +1321,7 @@ gotit:
  * free map. If a fragment is deallocated, a possible 
  * block reassembly is checked.
  */
+void
 ffs_blkfree(ip, bno, size)
        register struct inode *ip;
        ufs_daddr_t bno;
@@ -1223,6 +1330,7 @@ ffs_blkfree(ip, bno, size)
        register struct fs *fs;
        register struct cg *cgp;
        struct buf *bp;
+       struct timeval tv;
        ufs_daddr_t blkno;
        int i, error, cg, blk, frags, bbase;
 #if REV_ENDIAN_FS
@@ -1230,6 +1338,7 @@ ffs_blkfree(ip, bno, size)
        struct mount *mp=vp->v_mount;
        int rev_endian=(mp->mnt_flag & MNT_REVEND);
 #endif /* REV_ENDIAN_FS */
+
        fs = ip->i_fs;
        if ((u_int)size > fs->fs_bsize || fragoff(fs, size) != 0) {
                printf("dev = 0x%x, bsize = %d, size = %d, fs = %s\n",
@@ -1242,13 +1351,13 @@ ffs_blkfree(ip, bno, size)
                ffs_fserr(fs, ip->i_uid, "bad block");
                return;
        }
-       error = bread(ip->i_devvp, fsbtodb(fs, cgtod(fs, cg)),
-               (int)fs->fs_cgsize, NOCRED, &bp);
+       error = (int)buf_bread(ip->i_devvp, (daddr64_t)((unsigned)fsbtodb(fs, cgtod(fs, cg))),
+                              (int)fs->fs_cgsize, NOCRED, &bp);
        if (error) {
-               brelse(bp);
+               buf_brelse(bp);
                return;
        }
-       cgp = (struct cg *)bp->b_data;
+       cgp = (struct cg *)buf_dataptr(bp);
 #if REV_ENDIAN_FS
        if (rev_endian)
                byte_swap_cgin(cgp,fs);
@@ -1258,10 +1367,11 @@ ffs_blkfree(ip, bno, size)
                if (rev_endian)
                        byte_swap_cgout(cgp,fs);
 #endif /* REV_ENDIAN_FS */
-               brelse(bp);
+               buf_brelse(bp);
                return;
        }
-       cgp->cg_time = time.tv_sec;
+       microtime(&tv);
+       cgp->cg_time = tv.tv_sec;
        bno = dtogd(fs, bno);
        if (size == fs->fs_bsize) {
                blkno = fragstoblks(fs, bno);
@@ -1327,7 +1437,7 @@ ffs_blkfree(ip, bno, size)
        if (rev_endian)
                byte_swap_cgout(cgp,fs);
 #endif /* REV_ENDIAN_FS */
-       bdwrite(bp);
+       buf_bdwrite(bp);
 }
 
 #if DIAGNOSTIC
@@ -1358,13 +1468,13 @@ ffs_checkblk(ip, bno, size)
        }
        if ((u_int)bno >= fs->fs_size)
                panic("checkblk: bad block %d", bno);
-       error = bread(ip->i_devvp, fsbtodb(fs, cgtod(fs, dtog(fs, bno))),
-               (int)fs->fs_cgsize, NOCRED, &bp);
+       error = (int)buf_bread(ip->i_devvp, (daddr64_t)((unsigned)fsbtodb(fs, cgtod(fs, dtog(fs, bno)))),
+                              (int)fs->fs_cgsize, NOCRED, &bp);
        if (error) {
-               brelse(bp);
+               buf_brelse(bp);
                return;
        }
-       cgp = (struct cg *)bp->b_data;
+       cgp = (struct cg *)buf_dataptr(bp);
 #if REV_ENDIAN_FS
        if (rev_endian)
                byte_swap_cgin(cgp,fs);
@@ -1374,7 +1484,7 @@ ffs_checkblk(ip, bno, size)
                if (rev_endian)
                        byte_swap_cgout(cgp,fs);
 #endif /* REV_ENDIAN_FS */
-               brelse(bp);
+               buf_brelse(bp);
                return;
        }
        bno = dtogd(fs, bno);
@@ -1392,7 +1502,7 @@ ffs_checkblk(ip, bno, size)
        if (rev_endian)
                byte_swap_cgout(cgp,fs);
 #endif /* REV_ENDIAN_FS */
-       brelse(bp);
+       buf_brelse(bp);
        return (!free);
 }
 #endif /* DIAGNOSTIC */
@@ -1403,38 +1513,32 @@ ffs_checkblk(ip, bno, size)
  * The specified inode is placed back in the free map.
  */
 int
-ffs_vfree(ap)
-       struct vop_vfree_args /* {
-               struct vnode *a_pvp;
-               ino_t a_ino;
-               int a_mode;
-       } */ *ap;
+ffs_vfree(struct vnode *vp, ino_t ino, int mode)
 {
        register struct fs *fs;
        register struct cg *cgp;
        register struct inode *pip;
-       ino_t ino = ap->a_ino;
        struct buf *bp;
+       struct timeval tv;
        int error, cg;
 #if REV_ENDIAN_FS
-       struct vnode *vp=ap->a_pvp;
        struct mount *mp=vp->v_mount;
        int rev_endian=(mp->mnt_flag & MNT_REVEND);
 #endif /* REV_ENDIAN_FS */
 
-       pip = VTOI(ap->a_pvp);
+       pip = VTOI(vp);
        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 = ino_to_cg(fs, ino);
-       error = bread(pip->i_devvp, fsbtodb(fs, cgtod(fs, cg)),
-               (int)fs->fs_cgsize, NOCRED, &bp);
+       error = (int)buf_bread(pip->i_devvp, (daddr64_t)((unsigned)fsbtodb(fs, cgtod(fs, cg))),
+                              (int)fs->fs_cgsize, NOCRED, &bp);
        if (error) {
-               brelse(bp);
+               buf_brelse(bp);
                return (0);
        }
-       cgp = (struct cg *)bp->b_data;
+       cgp = (struct cg *)buf_dataptr(bp);
 #if REV_ENDIAN_FS
        if (rev_endian)
                byte_swap_cgin(cgp,fs);
@@ -1444,10 +1548,11 @@ ffs_vfree(ap)
                if (rev_endian)
                        byte_swap_cgout(cgp,fs);
 #endif /* REV_ENDIAN_FS */
-               brelse(bp);
+               buf_brelse(bp);
                return (0);
        }
-       cgp->cg_time = time.tv_sec;
+       microtime(&tv);
+       cgp->cg_time = tv.tv_sec;
        ino %= fs->fs_ipg;
        if (isclr(cg_inosused(cgp), ino)) {
                printf("dev = 0x%x, ino = %d, fs = %s\n",
@@ -1461,7 +1566,7 @@ ffs_vfree(ap)
        cgp->cg_cs.cs_nifree++;
        fs->fs_cstotal.cs_nifree++;
        fs->fs_cs(fs, cg).cs_nifree++;
-       if ((ap->a_mode & IFMT) == IFDIR) {
+       if ((mode & IFMT) == IFDIR) {
                cgp->cg_cs.cs_ndir--;
                fs->fs_cstotal.cs_ndir--;
                fs->fs_cs(fs, cg).cs_ndir--;
@@ -1471,7 +1576,7 @@ ffs_vfree(ap)
        if (rev_endian)
                byte_swap_cgout(cgp,fs);
 #endif /* REV_ENDIAN_FS */
-       bdwrite(bp);
+       buf_bdwrite(bp);
        return (0);
 }
 
@@ -1545,11 +1650,8 @@ ffs_mapsearch(fs, cgp, bpref, allocsiz)
  *
  * Cnt == 1 means free; cnt == -1 means allocating.
  */
-ffs_clusteracct(fs, cgp, blkno, cnt)
-       struct fs *fs;
-       struct cg *cgp;
-       ufs_daddr_t blkno;
-       int cnt;
+static void
+ffs_clusteracct(struct fs *fs, struct cg *cgp, ufs_daddr_t blkno, int cnt)
 {
        int32_t *sump;
        int32_t *lp;