Device layer rollup commit.
[dragonfly.git] / sys / vfs / ufs / ffs_vfsops.c
index 61613e4..ec2711d 100644 (file)
@@ -32,7 +32,7 @@
  *
  *     @(#)ffs_vfsops.c        8.31 (Berkeley) 5/20/95
  * $FreeBSD: src/sys/ufs/ffs/ffs_vfsops.c,v 1.117.2.10 2002/06/23 22:34:52 iedowse Exp $
- * $DragonFly: src/sys/vfs/ufs/ffs_vfsops.c,v 1.10 2003/08/07 21:17:44 dillon Exp $
+ * $DragonFly: src/sys/vfs/ufs/ffs_vfsops.c,v 1.18 2004/05/19 22:53:06 dillon Exp $
  */
 
 #include "opt_quota.h"
 
 static MALLOC_DEFINE(M_FFSNODE, "FFS node", "FFS vnode private part");
 
-static int     ffs_sbupdate __P((struct ufsmount *, int));
-static int     ffs_reload __P((struct mount *,struct ucred *,struct thread *));
-static int     ffs_oldfscompat __P((struct fs *));
-static int     ffs_mount __P((struct mount *, char *, caddr_t,
-                               struct nameidata *, struct thread *));
-static int     ffs_init __P((struct vfsconf *));
+static int     ffs_sbupdate (struct ufsmount *, int);
+static int     ffs_reload (struct mount *,struct ucred *,struct thread *);
+static int     ffs_oldfscompat (struct fs *);
+static int     ffs_mount (struct mount *, char *, caddr_t,
+                               struct nameidata *, struct thread *);
+static int     ffs_init (struct vfsconf *);
 
 static struct vfsops ufs_vfsops = {
        ffs_mount,
@@ -128,12 +128,11 @@ VFS_SET(ufs_vfsops, ufs, 0);
  *             namei() if it is a genuine NULL from the user.
  */
 static int
-ffs_mount( mp, path, data, ndp, td)
-        struct mount           *mp;    /* mount struct pointer*/
-        char                   *path;  /* path to mount point*/
-        caddr_t                        data;   /* arguments to FS specific mount*/
-        struct nameidata       *ndp;   /* mount point credentials*/
-        struct thread          *td;    /* process requesting mount*/
+ffs_mount(struct mount *mp,            /* mount struct pointer */
+          char *path,                  /* path to mount point */
+          caddr_t data,                        /* arguments to FS specific mount */
+          struct nameidata *ndp,       /* mount point credentials */
+          struct thread        *td)            /* process requesting mount */
 {
        size_t          size;
        int             err = 0;
@@ -224,13 +223,13 @@ ffs_mount( mp, path, data, ndp, td)
                         * that user has necessary permissions on the device.
                         */
                        if (cred->cr_uid != 0) {
-                               vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, td);
+                               vn_lock(devvp, NULL, LK_EXCLUSIVE | LK_RETRY, td);
                                if ((error = VOP_ACCESS(devvp, VREAD | VWRITE,
                                    cred, td)) != 0) {
-                                       VOP_UNLOCK(devvp, 0, td);
+                                       VOP_UNLOCK(devvp, NULL, 0, td);
                                        return (error);
                                }
-                               VOP_UNLOCK(devvp, 0, td);
+                               VOP_UNLOCK(devvp, NULL, 0, td);
                        }
 
                        fs->fs_flags &= ~FS_UNCLEAN;
@@ -283,7 +282,7 @@ ffs_mount( mp, path, data, ndp, td)
         * Not an update, or updating the name: look up the name
         * and verify that it refers to a sensible block device.
         */
-       NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args.fspec, td);
+       NDINIT(ndp, NAMEI_LOOKUP, CNP_FOLLOW, UIO_USERSPACE, args.fspec, td);
        err = namei(ndp);
        if (err) {
                /* can't get devvp!*/
@@ -304,12 +303,12 @@ ffs_mount( mp, path, data, ndp, td)
                accessmode = VREAD;
                if ((mp->mnt_flag & MNT_RDONLY) == 0)
                        accessmode |= VWRITE;
-               vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, td);
+               vn_lock(devvp, NULL, LK_EXCLUSIVE | LK_RETRY, td);
                if ((error = VOP_ACCESS(devvp, accessmode, cred, td)) != 0) {
                        vput(devvp);
                        return (error);
                }
-               VOP_UNLOCK(devvp, 0, td);
+               VOP_UNLOCK(devvp, NULL, 0, td);
        }
 
        if (mp->mnt_flag & MNT_UPDATE) {
@@ -317,18 +316,22 @@ ffs_mount( mp, path, data, ndp, td)
                 ********************
                 * UPDATE
                 * If it's not the same vnode, or at least the same device
-                * then it's not correct.
+                * then it's not correct.  NOTE: devvp->v_rdev may be NULL
+                * since we haven't opened it, so we compare udev instead.
                 ********************
                 */
-
                if (devvp != ump->um_devvp) {
-                       if ( devvp->v_rdev == ump->um_devvp->v_rdev) {
+                       if (devvp->v_udev == ump->um_devvp->v_udev) {
                                vrele(devvp);
                        } else {
+                               printf("cannot update mount, udev does"
+                                       " not match %08x vs %08x\n",
+                                       devvp->v_udev, ump->um_devvp->v_udev);
                                err = EINVAL;   /* needs translation */
                        }
-               } else
+               } else {
                        vrele(devvp);
+               }
                /*
                 * Update device name only on success
                 */
@@ -419,19 +422,32 @@ success:
  *     5) invalidate all cached file data.
  *     6) re-read inode data for all active vnodes.
  */
+
+static int ffs_reload_scan1(struct mount *mp, struct vnode *vp, void *data);
+static int ffs_reload_scan2(struct mount *mp, struct vnode *vp,
+                               lwkt_tokref_t vlock, void *data);
+
+struct scaninfo {
+       int rescan;
+       struct fs *fs;
+       struct vnode *devvp;
+       thread_t td;
+       int waitfor;
+       int allerror;
+};
+
 static int
 ffs_reload(struct mount *mp, struct ucred *cred, struct thread *td)
 {
-       struct vnode *vp, *nvp, *devvp;
-       struct inode *ip;
+       struct vnode *devvp;
        void *space;
        struct buf *bp;
        struct fs *fs, *newfs;
        struct partinfo dpart;
        dev_t dev;
        int i, blks, size, error;
-       int gen;
-       int vgen;
+       lwkt_tokref vlock;
+       struct scaninfo scaninfo;
        int32_t *lp;
 
        if ((mp->mnt_flag & MNT_RDONLY) == 0)
@@ -440,23 +456,22 @@ ffs_reload(struct mount *mp, struct ucred *cred, struct thread *td)
         * Step 1: invalidate all cached meta-data.
         */
        devvp = VFSTOUFS(mp)->um_devvp;
-       vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, td);
+       vn_lock(devvp, NULL, LK_EXCLUSIVE | LK_RETRY, td);
        error = vinvalbuf(devvp, 0, td, 0, 0);
-       VOP_UNLOCK(devvp, 0, td);
+       VOP_UNLOCK(devvp, NULL, 0, td);
        if (error)
                panic("ffs_reload: dirty1");
 
        dev = devvp->v_rdev;
-
        /*
         * Only VMIO the backing device if the backing device is a real
         * block device.  See ffs_mountmfs() for more details.
         */
        if (devvp->v_tag != VT_MFS && vn_isdisk(devvp, NULL)) {
-               vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, td);
+               vn_lock(devvp, NULL, LK_EXCLUSIVE | LK_RETRY, td);
                vfs_object_create(devvp, td);
-               lwkt_gettoken(&devvp->v_interlock);
-               VOP_UNLOCK(devvp, LK_INTERLOCK, td);
+               lwkt_gettoken(&vlock, devvp->v_interlock);
+               VOP_UNLOCK(devvp, &vlock, LK_INTERLOCK, td);
        }
 
        /*
@@ -483,6 +498,8 @@ ffs_reload(struct mount *mp, struct ucred *cred, struct thread *td)
        newfs->fs_csp = fs->fs_csp;
        newfs->fs_maxcluster = fs->fs_maxcluster;
        newfs->fs_contigdirs = fs->fs_contigdirs;
+       /* The file system is still read-only. */
+       newfs->fs_ronly = 1;
        bcopy(newfs, fs, (u_int)fs->fs_sbsize);
        if (fs->fs_sbsize < SBSIZE)
                bp->b_flags |= B_INVAL;
@@ -520,68 +537,77 @@ ffs_reload(struct mount *mp, struct ucred *cred, struct thread *td)
                        *lp++ = fs->fs_contigsumsize;
        }
 
-       gen = lwkt_gettoken(&mntvnode_token);
-loop:
-       for (vp = TAILQ_FIRST(&mp->mnt_nvnodelist); vp != NULL; vp = nvp) {
-               if (vp->v_mount != mp) {
-                       lwkt_gentoken(&mntvnode_token, &gen);
-                       goto loop;
-               }
-               nvp = TAILQ_NEXT(vp, v_nmntvnodes);
-               /*
-                * Step 4: invalidate all inactive vnodes. 
-                */
-               if (vrecycle(vp, NULL, td)) {
-                       lwkt_gentoken(&mntvnode_token, &gen);
-                       goto loop;
-               }
-               /*
-                * Step 5: invalidate all cached file data.
-                */
-               vgen = lwkt_gettoken(&vp->v_interlock);
-               if (lwkt_gentoken(&mntvnode_token, &gen) != 0 ||
-                   lwkt_gentoken(&vp->v_interlock, &vgen) != 0) {
-                       lwkt_reltoken(&vp->v_interlock);
-                       lwkt_gentoken(&mntvnode_token, &gen);
-                       goto loop;
-               }
-               if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, td)) {
-                       lwkt_gentoken(&mntvnode_token, &gen);
-                       goto loop;
-               }
-               if (vinvalbuf(vp, 0, td, 0, 0))
-                       panic("ffs_reload: dirty2");
-               /*
-                * Step 6: re-read inode data for all active vnodes.
-                */
-               ip = VTOI(vp);
-               error =
-                   bread(devvp, fsbtodb(fs, ino_to_fsba(fs, ip->i_number)),
-                   (int)fs->fs_bsize, &bp);
-               if (error) {
-                       vput(vp);
-                       lwkt_reltoken(&mntvnode_token);
-                       return (error);
-               }
-               ip->i_din = *((struct dinode *)bp->b_data +
-                   ino_to_fsbo(fs, ip->i_number));
-               ip->i_effnlink = ip->i_nlink;
-               brelse(bp);
+       scaninfo.rescan = 0;
+       scaninfo.fs = fs;
+       scaninfo.devvp = devvp;
+       scaninfo.td = td;
+       while (error == 0 && scaninfo.rescan) {
+               scaninfo.rescan = 0;
+               error = vmntvnodescan(mp, ffs_reload_scan1, 
+                                   ffs_reload_scan2, &scaninfo);
+       }
+       return(error);
+}
+
+static 
+int
+ffs_reload_scan1(struct mount *mp, struct vnode *vp, void *data)
+{
+       struct scaninfo *info = data;
+
+       /*
+        * Step 4: invalidate all inactive vnodes. 
+        */
+       if (vrecycle(vp, NULL, info->td)) {
+               info->rescan = 1;
+               return(-1);     /* continue loop, do not call scan2 */
+       }
+       return(0);
+}
+
+static
+int
+ffs_reload_scan2(struct mount *mp, struct vnode *vp, lwkt_tokref_t vlock, void *data)
+{
+       struct scaninfo *info = data;
+       struct inode *ip;
+       struct buf *bp;
+       int error;
+
+       /*
+        * Step 5: invalidate all cached file data.
+        */
+       if (vget(vp, vlock, LK_EXCLUSIVE | LK_INTERLOCK, info->td)) {
+               info->rescan = 1;
+               return(0);
+       }
+       if (vinvalbuf(vp, 0, info->td, 0, 0))
+               panic("ffs_reload: dirty2");
+       /*
+        * Step 6: re-read inode data for all active vnodes.
+        */
+       ip = VTOI(vp);
+       error = bread(info->devvp,
+                       fsbtodb(info->fs, ino_to_fsba(info->fs, ip->i_number)),
+                       (int)info->fs->fs_bsize, &bp);
+       if (error) {
                vput(vp);
+               return (error);
        }
-       lwkt_reltoken(&mntvnode_token);
-       return (0);
+       ip->i_din = *((struct dinode *)bp->b_data +
+           ino_to_fsbo(info->fs, ip->i_number));
+       ip->i_effnlink = ip->i_nlink;
+       brelse(bp);
+       vput(vp);
+       return(0);
 }
 
 /*
  * Common code for mount and mountroot
  */
 int
-ffs_mountfs(devvp, mp, td, malloctype)
-       struct vnode *devvp;
-       struct mount *mp;
-       struct thread *td;
-       struct malloc_type *malloctype;
+ffs_mountfs(struct vnode *devvp, struct mount *mp, struct thread *td,
+           struct malloc_type *malloctype)
 {
        struct ufsmount *ump;
        struct buf *bp;
@@ -590,12 +616,11 @@ ffs_mountfs(devvp, mp, td, malloctype)
        struct partinfo dpart;
        void *space;
        int error, i, blks, size, ronly;
+       lwkt_tokref vlock;
        int32_t *lp;
        u_int64_t maxfilesize;                                  /* XXX */
        size_t strsize;
-       int ncount;
 
-       dev = devvp->v_rdev;
        /*
         * Disallow multiple mounts of the same device.
         * Disallow mounting of a device that is currently in use
@@ -605,13 +630,11 @@ ffs_mountfs(devvp, mp, td, malloctype)
        error = vfs_mountedon(devvp);
        if (error)
                return (error);
-       ncount = vcount(devvp);
-
-       if (ncount > 1 && devvp != rootvp)
+       if (count_udev(devvp->v_udev) > 0 && devvp != rootvp)
                return (EBUSY);
-       vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, td);
+       vn_lock(devvp, NULL, LK_EXCLUSIVE | LK_RETRY, td);
        error = vinvalbuf(devvp, V_SAVE, td, 0, 0);
-       VOP_UNLOCK(devvp, 0, td);
+       VOP_UNLOCK(devvp, NULL, 0, td);
        if (error)
                return (error);
 
@@ -622,20 +645,21 @@ ffs_mountfs(devvp, mp, td, malloctype)
         * increases the opportunity for metadata caching.
         */
        if (devvp->v_tag != VT_MFS && vn_isdisk(devvp, NULL)) {
-               vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, td);
+               vn_lock(devvp, NULL, LK_EXCLUSIVE | LK_RETRY, td);
                vfs_object_create(devvp, td);
-               lwkt_gettoken(&devvp->v_interlock);
-               VOP_UNLOCK(devvp, LK_INTERLOCK, td);
+               lwkt_gettoken(&vlock, devvp->v_interlock);
+               VOP_UNLOCK(devvp, &vlock, LK_INTERLOCK, td);
        }
 
        ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
-       vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, td);
+       vn_lock(devvp, NULL, LK_EXCLUSIVE | LK_RETRY, td);
        error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, td);
-       VOP_UNLOCK(devvp, 0, td);
+       VOP_UNLOCK(devvp, NULL, 0, td);
        if (error)
                return (error);
-       if (devvp->v_rdev->si_iosize_max != 0)
-               mp->mnt_iosize_max = devvp->v_rdev->si_iosize_max;
+       dev = devvp->v_rdev;
+       if (dev->si_iosize_max != 0)
+               mp->mnt_iosize_max = dev->si_iosize_max;
        if (mp->mnt_iosize_max > MAXPHYS)
                mp->mnt_iosize_max = MAXPHYS;
 
@@ -744,7 +768,7 @@ ffs_mountfs(devvp, mp, td, malloctype)
        ump->um_seqinc = fs->fs_frag;
        for (i = 0; i < MAXQUOTAS; i++)
                ump->um_quotas[i] = NULLVP;
-       devvp->v_specmountpoint = mp;
+       dev->si_mountpoint = mp;
        ffs_oldfscompat(fs);
 
        /*
@@ -784,10 +808,10 @@ ffs_mountfs(devvp, mp, td, malloctype)
        }
        return (0);
 out:
-       devvp->v_specmountpoint = NULL;
+       dev->si_mountpoint = NULL;
        if (bp)
                brelse(bp);
-       (void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, td);
+       VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, td);
        if (ump) {
                free(ump->um_fs, M_UFSMNT);
                free(ump, M_UFSMNT);
@@ -802,10 +826,8 @@ out:
  * XXX - goes away some day.
  */
 static int
-ffs_oldfscompat(fs)
-       struct fs *fs;
+ffs_oldfscompat(struct fs *fs)
 {
-
        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 */
@@ -859,7 +881,7 @@ ffs_unmount(struct mount *mp, int mntflags, struct thread *td)
                        return (error);
                }
        }
-       ump->um_devvp->v_specmountpoint = NULL;
+       ump->um_devvp->v_rdev->si_mountpoint = NULL;
 
        vinvalbuf(ump->um_devvp, V_SAVE, td, 0, 0);
        error = VOP_CLOSE(ump->um_devvp, fs->fs_ronly ? FREAD : FREAD|FWRITE, td);
@@ -909,9 +931,9 @@ ffs_flushfiles(struct mount *mp, int flags, struct thread *td)
        /*
         * Flush filesystem metadata.
         */
-       vn_lock(ump->um_devvp, LK_EXCLUSIVE | LK_RETRY, td);
+       vn_lock(ump->um_devvp, NULL, LK_EXCLUSIVE | LK_RETRY, td);
        error = VOP_FSYNC(ump->um_devvp, MNT_WAIT, td);
-       VOP_UNLOCK(ump->um_devvp, 0, td);
+       VOP_UNLOCK(ump->um_devvp, NULL, 0, td);
        return (error);
 }
 
@@ -953,88 +975,47 @@ ffs_statfs(struct mount *mp, struct statfs *sbp, struct thread *td)
  *
  * Note: we are always called with the filesystem marked `MPBUSY'.
  */
+
+
+static int ffs_sync_scan1(struct mount *mp, struct vnode *vp, void *data);
+static int ffs_sync_scan2(struct mount *mp, struct vnode *vp,
+                lwkt_tokref_t vlock, void *data);
+
 int
 ffs_sync(struct mount *mp, int waitfor, struct thread *td)
 {
-       struct vnode *nvp, *vp;
-       struct inode *ip;
        struct ufsmount *ump = VFSTOUFS(mp);
        struct fs *fs;
-       int error, allerror = 0;
+       int error;
+       struct scaninfo scaninfo;
 
        fs = ump->um_fs;
        if (fs->fs_fmod != 0 && fs->fs_ronly != 0) {            /* XXX */
                printf("fs = %s\n", fs->fs_fsmnt);
                panic("ffs_sync: rofs mod");
        }
+
        /*
         * Write back each (modified) inode.
         */
-       lwkt_gettoken(&mntvnode_token);
-loop:
-       for (vp = TAILQ_FIRST(&mp->mnt_nvnodelist); vp != NULL; vp = nvp) {
-               /*
-                * If the vnode that we are about to sync is no longer
-                * associated with this mount point, start over.
-                */
-               if (vp->v_mount != mp)
-                       goto loop;
-
-               /*
-                * Depend on the mntvnode_token to keep things stable enough
-                * for a quick test.  Since there might be hundreds of 
-                * thousands of vnodes, we cannot afford even a subroutine
-                * call unless there's a good chance that we have work to do.
-                */
-               nvp = TAILQ_NEXT(vp, v_nmntvnodes);
-               ip = VTOI(vp);
-               if (vp->v_type == VNON || ((ip->i_flag &
-                    (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) == 0 &&
-                    TAILQ_EMPTY(&vp->v_dirtyblkhd))) {
-                       continue;
-               }
-               if (vp->v_type != VCHR) {
-                       lwkt_reltoken(&mntvnode_token);
-                       error = vget(vp, LK_EXCLUSIVE | LK_NOWAIT, td);
-                       if (error) {
-                               lwkt_gettoken(&mntvnode_token);
-                               if (error == ENOENT)
-                                       goto loop;
-                       } else {
-                               if ((error = VOP_FSYNC(vp, waitfor, td)) != 0)
-                                       allerror = error;
-                               VOP_UNLOCK(vp, 0, td);
-                               vrele(vp);
-                               lwkt_gettoken(&mntvnode_token);
-                       }
-               } else {
-                       /*
-                        * We must reference the vp to prevent it from
-                        * getting ripped out from under UFS_UPDATE, since
-                        * we are not holding a vnode lock.  XXX why aren't
-                        * we holding a vnode lock?
-                        */
-                       VREF(vp);
-                       lwkt_reltoken(&mntvnode_token);
-                       /* UFS_UPDATE(vp, waitfor == MNT_WAIT); */
-                       UFS_UPDATE(vp, 0);
-                       vrele(vp);
-                       lwkt_gettoken(&mntvnode_token);
-               }
-               if (TAILQ_NEXT(vp, v_nmntvnodes) != nvp)
-                       goto loop;
+       scaninfo.allerror = 0;
+       scaninfo.rescan = 1;
+       scaninfo.waitfor = waitfor;
+       while (scaninfo.rescan) {
+               scaninfo.rescan = 0;
+               vmntvnodescan(mp, ffs_sync_scan1, ffs_sync_scan2, &scaninfo);
        }
-       lwkt_reltoken(&mntvnode_token);
+
        /*
         * Force stale file system control information to be flushed.
         */
        if (waitfor != MNT_LAZY) {
                if (ump->um_mountp->mnt_flag & MNT_SOFTDEP)
                        waitfor = MNT_NOWAIT;
-               vn_lock(ump->um_devvp, LK_EXCLUSIVE | LK_RETRY, td);
+               vn_lock(ump->um_devvp, NULL, LK_EXCLUSIVE | LK_RETRY, td);
                if ((error = VOP_FSYNC(ump->um_devvp, waitfor, td)) != 0)
-                       allerror = error;
-               VOP_UNLOCK(ump->um_devvp, 0, td);
+                       scaninfo.allerror = error;
+               VOP_UNLOCK(ump->um_devvp, NULL, 0, td);
        }
 #ifdef QUOTA
        qsync(mp);
@@ -1043,8 +1024,75 @@ loop:
         * Write back modified superblock.
         */
        if (fs->fs_fmod != 0 && (error = ffs_sbupdate(ump, waitfor)) != 0)
-               allerror = error;
-       return (allerror);
+               scaninfo.allerror = error;
+       return (scaninfo.allerror);
+}
+
+static
+int
+ffs_sync_scan1(struct mount *mp, struct vnode *vp, void *data)
+{
+       struct inode *ip;
+
+       /*
+        * Depend on the mount list's vnode lock to keep things stable 
+        * enough for a quick test.  Since there might be hundreds of 
+        * thousands of vnodes, we cannot afford even a subroutine
+        * call unless there's a good chance that we have work to do.
+        */
+       ip = VTOI(vp);
+       if (vp->v_type == VNON || ((ip->i_flag &
+            (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) == 0 &&
+            TAILQ_EMPTY(&vp->v_dirtyblkhd))) {
+               return(-1);
+       }
+       return(0);
+}
+
+static
+int 
+ffs_sync_scan2(struct mount *mp, struct vnode *vp,
+              lwkt_tokref_t vlock, void *data)
+{
+       struct scaninfo *info = data;
+       thread_t td = curthread;        /* XXX */
+       struct inode *ip;
+       int error;
+
+       /*
+        * We have to recheck after having obtained the vnode interlock.
+        */
+       ip = VTOI(vp);
+       if (vp->v_type == VNON || ((ip->i_flag &
+            (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) == 0 &&
+            TAILQ_EMPTY(&vp->v_dirtyblkhd))) {
+               lwkt_reltoken(vlock);
+               return(0);
+       }
+       if (vp->v_type != VCHR) {
+               error = vget(vp, vlock, LK_INTERLOCK|LK_EXCLUSIVE|LK_NOWAIT, td);
+               if (error) {
+                       if (error == ENOENT)
+                               info->rescan = 1;
+               } else {
+                       if ((error = VOP_FSYNC(vp, info->waitfor, td)) != 0)
+                               info->allerror = error;
+                       VOP_UNLOCK(vp, NULL, 0, td);
+                       vrele(vp);
+               }
+       } else {
+               /*
+                * We must reference the vp to prevent it from
+                * getting ripped out from under UFS_UPDATE, since
+                * we are not holding a vnode lock.
+                */
+               vref(vp);
+               lwkt_reltoken(vlock);
+               /* UFS_UPDATE(vp, waitfor == MNT_WAIT); */
+               UFS_UPDATE(vp, 0);
+               vrele(vp);
+       }
+       return(0);
 }
 
 /*
@@ -1056,10 +1104,7 @@ loop:
 static int ffs_inode_hash_lock;
 
 int
-ffs_vget(mp, ino, vpp)
-       struct mount *mp;
-       ino_t ino;
-       struct vnode **vpp;
+ffs_vget(struct mount *mp, ino_t ino, struct vnode **vpp)
 {
        struct fs *fs;
        struct inode *ip;
@@ -1176,7 +1221,7 @@ restart:
         * Finish inode initialization now that aliasing has been resolved.
         */
        ip->i_devvp = ump->um_devvp;
-       VREF(ip->i_devvp);
+       vref(ip->i_devvp);
        /*
         * Set up a generation number for this inode if it does not
         * already have one. This should only happen on old filesystems.
@@ -1210,10 +1255,7 @@ restart:
  *   those rights via. exflagsp and credanonp
  */
 int
-ffs_fhtovp(mp, fhp, vpp)
-       struct mount *mp;
-       struct fid *fhp;
-       struct vnode **vpp;
+ffs_fhtovp(struct mount *mp, struct fid *fhp, struct vnode **vpp)
 {
        struct ufid *ufhp;
        struct fs *fs;
@@ -1231,9 +1273,7 @@ ffs_fhtovp(mp, fhp, vpp)
  */
 /* ARGSUSED */
 int
-ffs_vptofh(vp, fhp)
-       struct vnode *vp;
-       struct fid *fhp;
+ffs_vptofh(struct vnode *vp, struct fid *fhp)
 {
        struct inode *ip;
        struct ufid *ufhp;
@@ -1250,10 +1290,8 @@ ffs_vptofh(vp, fhp)
  * Initialize the filesystem; just use ufs_init.
  */
 static int
-ffs_init(vfsp)
-       struct vfsconf *vfsp;
+ffs_init(struct vfsconf *vfsp)
 {
-
        softdep_initialize();
        return (ufs_init(vfsp));
 }
@@ -1262,9 +1300,7 @@ ffs_init(vfsp)
  * Write a superblock and associated information back to disk.
  */
 static int
-ffs_sbupdate(mp, waitfor)
-       struct ufsmount *mp;
-       int waitfor;
+ffs_sbupdate(struct ufsmount *mp, int waitfor)
 {
        struct fs *dfs, *fs = mp->um_fs;
        struct buf *bp;