directory ops, unmount, minor cleanup; from Margo Seltzer
authorKeith Bostic <bostic@ucbvax.Berkeley.EDU>
Tue, 23 Jun 1992 15:06:35 +0000 (07:06 -0800)
committerKeith Bostic <bostic@ucbvax.Berkeley.EDU>
Tue, 23 Jun 1992 15:06:35 +0000 (07:06 -0800)
SCCS-vsn: sys/ufs/lfs/lfs.h 7.14
SCCS-vsn: sys/ufs/lfs/lfs_alloc.c 7.46
SCCS-vsn: sys/ufs/lfs/lfs_debug.c 7.6
SCCS-vsn: sys/ufs/lfs/lfs_extern.h 7.17
SCCS-vsn: sys/ufs/lfs/lfs_inode.c 7.69
SCCS-vsn: sys/ufs/lfs/lfs_segment.c 7.20
SCCS-vsn: sys/ufs/lfs/lfs_subr.c 7.12
SCCS-vsn: sys/ufs/lfs/lfs_vfsops.c 7.75
SCCS-vsn: sys/ufs/lfs/lfs_vnops.c 7.85

usr/src/sys/ufs/lfs/lfs.h
usr/src/sys/ufs/lfs/lfs_alloc.c
usr/src/sys/ufs/lfs/lfs_debug.c
usr/src/sys/ufs/lfs/lfs_extern.h
usr/src/sys/ufs/lfs/lfs_inode.c
usr/src/sys/ufs/lfs/lfs_segment.c
usr/src/sys/ufs/lfs/lfs_subr.c
usr/src/sys/ufs/lfs/lfs_vfsops.c
usr/src/sys/ufs/lfs/lfs_vnops.c

index 6937ff2..d2981ee 100644 (file)
@@ -4,7 +4,7 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)lfs.h       7.13 (Berkeley) %G%
+ *     @(#)lfs.h       7.14 (Berkeley) %G%
  */
 
 #define        LFS_LABELPAD    8192            /* LFS label size */
  */
 
 #define        LFS_LABELPAD    8192            /* LFS label size */
@@ -19,6 +19,7 @@ struct segusage {
 #define        SEGUSE_ACTIVE           0x1     /* segment is currently being written */
 #define        SEGUSE_DIRTY            0x2     /* segment has data in it */
 #define        SEGUSE_SUPERBLOCK       0x4     /* segment contains a superblock */
 #define        SEGUSE_ACTIVE           0x1     /* segment is currently being written */
 #define        SEGUSE_DIRTY            0x2     /* segment has data in it */
 #define        SEGUSE_SUPERBLOCK       0x4     /* segment contains a superblock */
+#define        SEGUSE_LIVELOG          0x8     /* segment has not been checkpointed */
        u_long  su_flags;
 };
 
        u_long  su_flags;
 };
 
@@ -59,6 +60,7 @@ struct lfs {
        daddr_t lfs_nextseg;            /* address of next segment to write */
        daddr_t lfs_curseg;             /* current segment being written */
        daddr_t lfs_offset;             /* offset in curseg for next partial */
        daddr_t lfs_nextseg;            /* address of next segment to write */
        daddr_t lfs_curseg;             /* current segment being written */
        daddr_t lfs_offset;             /* offset in curseg for next partial */
+       daddr_t lfs_lastpseg;           /* address of last partial written */
        u_long  lfs_tstamp;             /* time stamp */
 
 /* These are configuration parameters. */
        u_long  lfs_tstamp;             /* time stamp */
 
 /* These are configuration parameters. */
@@ -95,6 +97,9 @@ struct lfs {
                                        /* XXX NOT USED */
        void    *XXXlfs_seglist;        /* list of segments being written */
        u_long  lfs_iocount;            /* number of ios pending */
                                        /* XXX NOT USED */
        void    *XXXlfs_seglist;        /* list of segments being written */
        u_long  lfs_iocount;            /* number of ios pending */
+       u_long  lfs_writer;             /* don't allow any dirops to start */
+       u_long  lfs_dirops;             /* count of active directory ops */
+       u_long  lfs_doifile;            /* Write ifile blocks on next write */
        u_char  lfs_fmod;               /* super block modified flag */
        u_char  lfs_clean;              /* file system is clean flag */
        u_char  lfs_ronly;              /* mounted read-only flag */
        u_char  lfs_fmod;               /* super block modified flag */
        u_char  lfs_clean;              /* file system is clean flag */
        u_char  lfs_ronly;              /* mounted read-only flag */
@@ -170,8 +175,12 @@ struct segsum {
        u_long  ss_datasum;             /* check sum of data */
        daddr_t ss_next;                /* next segment */
        u_long  ss_create;              /* creation time stamp */
        u_long  ss_datasum;             /* check sum of data */
        daddr_t ss_next;                /* next segment */
        u_long  ss_create;              /* creation time stamp */
-       u_long  ss_nfinfo;              /* number of file info structures */
-       u_long  ss_ninos;               /* number of inodes in summary */
+       u_short ss_nfinfo;              /* number of file info structures */
+       u_short ss_ninos;               /* number of inodes in summary */
+#define        SS_DIROP        0x01            /* segment begins a dirop */
+#define        SS_CONT         0x02            /* more partials to finish this write*/
+       u_short ss_flags;               /* used for directory operations */
+       u_short ss_pad;                 /* extra space */
        /* FINFO's and inode daddr's... */
 };
 
        /* FINFO's and inode daddr's... */
 };
 
index 8fe840f..b4afcc9 100644 (file)
@@ -4,7 +4,7 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)lfs_alloc.c 7.45 (Berkeley) %G%
+ *     @(#)lfs_alloc.c 7.46 (Berkeley) %G%
  */
 
 #include <sys/param.h>
  */
 
 #include <sys/param.h>
@@ -148,6 +148,7 @@ lfs_vcreate(mp, ino, vpp)
        /* Initialize the inode. */
        MALLOC(ip, struct inode *, sizeof(struct inode), M_LFSNODE, M_WAITOK);
        (*vpp)->v_data = ip;
        /* Initialize the inode. */
        MALLOC(ip, struct inode *, sizeof(struct inode), M_LFSNODE, M_WAITOK);
        (*vpp)->v_data = ip;
+       (*vpp)->v_flag |= VDIROP;
        ip->i_vnode = *vpp;
        ip->i_devvp = ump->um_devvp;
        ip->i_flag = 0;
        ip->i_vnode = *vpp;
        ip->i_devvp = ump->um_devvp;
        ip->i_flag = 0;
@@ -215,5 +216,3 @@ lfs_vfree (ap)
        --fs->lfs_nfiles;
        return (0);
 }
        --fs->lfs_nfiles;
        return (0);
 }
-
-
index 36e900c..b7bb1ca 100644 (file)
@@ -4,7 +4,7 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)lfs_debug.c 7.5 (Berkeley) %G%
+ *     @(#)lfs_debug.c 7.6 (Berkeley) %G%
  */
 
 #ifdef DEBUG
  */
 
 #ifdef DEBUG
@@ -103,78 +103,4 @@ lfs_dump_dinode(dip)
                (void)printf("\t%lx", dip->di_ib[i]);
        (void)printf("\n");
 }
                (void)printf("\t%lx", dip->di_ib[i]);
        (void)printf("\n");
 }
-
-/* XXX TEMPORARY */
-#include <sys/buf.h>
-#include <sys/mount.h>
-int
-lfs_umountdebug(mp)
-       struct mount *mp;
-{
-       struct vnode *vp;
-       int dirty;
-
-       dirty = 0;
-       if ((mp->mnt_flag & MNT_MPBUSY) == 0)
-               panic("umountdebug: not busy");
-loop:
-       for (vp = mp->mnt_mounth; vp; vp = vp->v_mountf) {
-               if (vget(vp))
-                       goto loop;
-               dirty += lfs_vinvalbuf(vp);
-               vput(vp);
-               if (vp->v_mount != mp)
-                       goto loop;
-       }
-       return (dirty);
-}
-
-int
-lfs_vinvalbuf(vp)
-       register struct vnode *vp;
-{
-       register struct buf *bp;
-       struct buf *nbp, *blist;
-       int s, dirty = 0;
-
-       for (;;) {
-               if (blist = vp->v_dirtyblkhd)
-                       /* void */;
-               else if (blist = vp->v_cleanblkhd)
-                       /* void */;
-               else
-                       break;
-               for (bp = blist; bp; bp = nbp) {
-       printf("lfs_vinvalbuf: ino %d, lblkno %d, blkno %lx flags %xl\n",
-            VTOI(vp)->i_number, bp->b_lblkno, bp->b_blkno, bp->b_flags);
-                       nbp = bp->b_blockf;
-                       s = splbio();
-                       if (bp->b_flags & B_BUSY) {
-       printf("lfs_vinvalbuf: buffer busy, would normally sleep\n");
-/*
-                               bp->b_flags |= B_WANTED;
-                               sleep((caddr_t)bp, PRIBIO + 1);
-*/
-                               splx(s);
-                               break;
-                       }
-                       bremfree(bp);
-                       bp->b_flags |= B_BUSY;
-                       splx(s);
-                       if (bp->b_flags & B_DELWRI) {
-                               dirty++;                        /* XXX */
-       printf("lfs_vinvalbuf: buffer dirty (DELWRI). would normally write\n");
-                               break;
-                       }
-                       if (bp->b_vp != vp)
-                               reassignbuf(bp, bp->b_vp);
-                       else
-                               bp->b_flags |= B_INVAL;
-                       brelse(bp);
-               }
-       }
-       if (vp->v_dirtyblkhd || vp->v_cleanblkhd)
-               panic("lfs_vinvalbuf: flush failed");
-       return (dirty);
-}
 #endif /* DEBUG */
 #endif /* DEBUG */
index ed9c348..585cd41 100644 (file)
@@ -4,7 +4,7 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)lfs_extern.h        7.16 (Berkeley) %G%
+ *     @(#)lfs_extern.h        7.17 (Berkeley) %G%
  */
 
 struct fid;
  */
 
 struct fid;
@@ -24,18 +24,27 @@ int  lfs_bmap __P((struct vop_bmap_args *));
 int     lfs_bmaparray
            __P((struct vnode *, daddr_t, daddr_t *, INDIR *, int *));
 int     lfs_bwrite __P((struct vop_bwrite_args *));
 int     lfs_bmaparray
            __P((struct vnode *, daddr_t, daddr_t *, INDIR *, int *));
 int     lfs_bwrite __P((struct vop_bwrite_args *));
+int     lfs_create __P((struct vop_create_args *));
 int     lfs_fhtovp __P((struct mount *, struct fid *, int, struct vnode **));
 int     lfs_fsync __P((struct vop_fsync_args *));
 int     lfs_inactive __P((struct vop_inactive_args *));
 int     lfs_init __P((void));
 int     lfs_fhtovp __P((struct mount *, struct fid *, int, struct vnode **));
 int     lfs_fsync __P((struct vop_fsync_args *));
 int     lfs_inactive __P((struct vop_inactive_args *));
 int     lfs_init __P((void));
+int     lfs_link __P((struct vop_link_args *));
 int     lfs_makeinode __P((int, struct nameidata *, struct inode **));
 int     lfs_makeinode __P((int, struct nameidata *, struct inode **));
+int     lfs_mkdir __P((struct vop_mkdir_args *));
+int     lfs_mknod __P((struct vop_mknod_args *));
+int     lfs_mntinvalbuf __P((struct mount *));
 int     lfs_mount __P((struct mount *,
            char *, caddr_t, struct nameidata *, struct proc *));
 int     lfs_mountroot __P((void));
 int     lfs_read __P((struct vop_read_args *));
 int     lfs_mount __P((struct mount *,
            char *, caddr_t, struct nameidata *, struct proc *));
 int     lfs_mountroot __P((void));
 int     lfs_read __P((struct vop_read_args *));
+int     lfs_remove __P((struct vop_remove_args *));
+int     lfs_rmdir __P((struct vop_rmdir_args *));
+int     lfs_rename __P((struct vop_rename_args *));
 int     lfs_root __P((struct mount *, struct vnode **));
 int     lfs_segwrite __P((struct mount *, int));
 int     lfs_statfs __P((struct mount *, struct statfs *, struct proc *));
 int     lfs_root __P((struct mount *, struct vnode **));
 int     lfs_segwrite __P((struct mount *, int));
 int     lfs_statfs __P((struct mount *, struct statfs *, struct proc *));
+int     lfs_symlink __P((struct vop_symlink_args *));
 int     lfs_sync __P((struct mount *, int));
 int     lfs_truncate __P((struct vop_truncate_args *));
 int     lfs_unmount __P((struct mount *, int, struct proc *));
 int     lfs_sync __P((struct mount *, int));
 int     lfs_truncate __P((struct vop_truncate_args *));
 int     lfs_unmount __P((struct mount *, int, struct proc *));
@@ -45,13 +54,12 @@ int  lfs_vcreate __P((struct mount *, ino_t, struct vnode **));
 int     lfs_vfree __P((struct vop_vfree_args *));
 int     lfs_vflush __P((struct vnode *));
 int     lfs_vget __P((struct vop_vget_args *));
 int     lfs_vfree __P((struct vop_vfree_args *));
 int     lfs_vflush __P((struct vnode *));
 int     lfs_vget __P((struct vop_vget_args *));
+int     lfs_vinvalbuf __P((struct vnode *));
 int     lfs_vptofh __P((struct vnode *, struct fid *));
 int     lfs_write __P((struct vop_write_args *));
 #ifdef DEBUG
 void   lfs_dump_dinode __P((struct dinode *));
 void   lfs_dump_super __P((struct lfs *));
 int     lfs_vptofh __P((struct vnode *, struct fid *));
 int     lfs_write __P((struct vop_write_args *));
 #ifdef DEBUG
 void   lfs_dump_dinode __P((struct dinode *));
 void   lfs_dump_super __P((struct lfs *));
-int    lfs_umountdebug __P((struct mount *));
-int    lfs_vinvalbuf __P((struct vnode *));
 #endif
 __END_DECLS
 extern int (**lfs_vnodeop_p)();
 #endif
 __END_DECLS
 extern int (**lfs_vnodeop_p)();
index e7cfa4d..6b8ce3c 100644 (file)
@@ -4,7 +4,7 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)lfs_inode.c 7.68 (Berkeley) %G%
+ *     @(#)lfs_inode.c 7.69 (Berkeley) %G%
  */
 
 #include <sys/param.h>
  */
 
 #include <sys/param.h>
@@ -147,13 +147,14 @@ lfs_ifind(fs, ino, dip)
        register struct dinode *dip;
 {
        register int cnt;
        register struct dinode *dip;
 {
        register int cnt;
+       register struct dinode *ldip;
 
 #ifdef VERBOSE
        printf("lfs_ifind: inode %d\n", ino);
 #endif
 
 #ifdef VERBOSE
        printf("lfs_ifind: inode %d\n", ino);
 #endif
-       for (cnt = INOPB(fs); cnt--; ++dip)
-               if (dip->di_inum == ino)
-                       return (dip);
+       for (cnt = INOPB(fs), ldip = dip + (cnt - 1); cnt--; --ldip)
+               if (ldip->di_inum == ino)
+                       return (ldip);
 
        panic("lfs_ifind: dinode %u not found", ino);
        /* NOTREACHED */
 
        panic("lfs_ifind: dinode %u not found", ino);
        /* NOTREACHED */
index fed7254..10b3c8a 100644 (file)
@@ -4,7 +4,7 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)lfs_segment.c       7.19 (Berkeley) %G%
+ *     @(#)lfs_segment.c       7.20 (Berkeley) %G%
  */
 
 #include <sys/param.h>
  */
 
 #include <sys/param.h>
@@ -70,9 +70,11 @@ void  lfs_shellsort __P((struct buf **, daddr_t *, register int));
 void    lfs_updatemeta __P((struct lfs *,
            struct segment *, struct vnode *, daddr_t *, struct buf **, int));
 void    lfs_writefile __P((struct lfs *, struct segment *, struct vnode *));
 void    lfs_updatemeta __P((struct lfs *,
            struct segment *, struct vnode *, daddr_t *, struct buf **, int));
 void    lfs_writefile __P((struct lfs *, struct segment *, struct vnode *));
-void    lfs_writeinode __P((struct lfs *, struct segment *, struct inode *));
-void    lfs_writeseg __P((struct lfs *, struct segment *));
+int     lfs_writeinode __P((struct lfs *, struct segment *, struct inode *));
+int     lfs_writeseg __P((struct lfs *, struct segment *));
 void    lfs_writesuper __P((struct lfs *, struct segment *));
 void    lfs_writesuper __P((struct lfs *, struct segment *));
+void    lfs_writevnodes __P((struct lfs *fs, struct mount *mp,
+           struct segment *sp, int dirops));
 
 int    lfs_allclean_wakeup;            /* Cleaner wakeup address. */
 
 
 int    lfs_allclean_wakeup;            /* Cleaner wakeup address. */
 
@@ -131,10 +133,10 @@ lfs_vflush(vp)
        if (vp->v_dirtyblkhd != NULL)
                lfs_writefile(fs, sp, vp);
        ip = VTOI(vp);
        if (vp->v_dirtyblkhd != NULL)
                lfs_writefile(fs, sp, vp);
        ip = VTOI(vp);
-       lfs_writeinode(fs, sp, ip);
+       (void) lfs_writeinode(fs, sp, ip);
        ip->i_flags &= ~(IMOD | IACC | IUPD | ICHG);
 
        ip->i_flags &= ~(IMOD | IACC | IUPD | ICHG);
 
-       lfs_writeseg(fs, sp);
+       (void) lfs_writeseg(fs, sp);
 
        /*
         * If the I/O count is non-zero, sleep until it reaches zero.  At the
 
        /*
         * If the I/O count is non-zero, sleep until it reaches zero.  At the
@@ -160,6 +162,53 @@ lfs_vflush(vp)
        return (0);
 }
 
        return (0);
 }
 
+void
+lfs_writevnodes(fs, mp, sp, dirops)
+       struct lfs *fs;
+       struct mount *mp;
+       struct segment *sp;
+       int dirops;
+{
+       struct inode *ip;
+       struct vnode *vp;
+       int error, s;
+
+loop:  for (vp = mp->mnt_mounth; vp; vp = vp->v_mountf) {
+               /*
+                * 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;
+
+               if (dirops && !(vp->v_flag & VDIROP) ||
+                   !dirops && (vp->v_flag & VDIROP))
+                       continue;
+               /*
+                * XXX
+                * Up the ref count so we don't get tossed out of
+                * memory.
+                */
+               VREF(vp);
+
+               /*
+                * Write the inode/file if dirty and it's not the
+                * the IFILE.
+                */
+               ip = VTOI(vp);
+               if ((ip->i_flag & (IMOD | IACC | IUPD | ICHG) ||
+                   vp->v_dirtyblkhd != NULL) &&
+                   ip->i_number != LFS_IFILE_INUM) {
+                       if (vp->v_dirtyblkhd != NULL)
+                               lfs_writefile(fs, sp, vp);
+                       (void) lfs_writeinode(fs, sp, ip);
+                       ip->i_flags &= ~(IMOD | IACC | IUPD | ICHG);
+               }
+               vp->v_flag &= ~VDIROP;
+               vrele(vp);
+       }
+}
+
 int
 lfs_segwrite(mp, do_ckp)
        struct mount *mp;
 int
 lfs_segwrite(mp, do_ckp)
        struct mount *mp;
@@ -170,7 +219,7 @@ lfs_segwrite(mp, do_ckp)
        struct lfs *fs;
        struct segment *sp;
        struct vnode *vp;
        struct lfs *fs;
        struct segment *sp;
        struct vnode *vp;
-       int error, islocked, s;
+       int error, s;
 
 #ifdef VERBOSE
        printf("lfs_segwrite\n");
 
 #ifdef VERBOSE
        printf("lfs_segwrite\n");
@@ -196,61 +245,46 @@ lfs_segwrite(mp, do_ckp)
         * final decrement, avoiding the wakeup in the callback routine.
         */
        s = splbio();
         * final decrement, avoiding the wakeup in the callback routine.
         */
        s = splbio();
-       ++fs->lfs_iocount;
+       fs->lfs_iocount++;
        splx(s);
 
        splx(s);
 
-loop:  for (vp = mp->mnt_mounth; vp; vp = vp->v_mountf) {
-               /*
-                * 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;
+       lfs_writevnodes(fs, mp, sp, 0);
+       s = splbio();
+       fs->lfs_writer = 1;
+       if (fs->lfs_dirops && (error =
+           tsleep(&fs->lfs_writer, PRIBIO + 1, "lfs writer", 0))) {
+               free(sp->bpp, M_SEGMENT);
+               free(sp, M_SEGMENT); 
+               fs->lfs_writer = 0;
+               splx(s);
+               return(error);
+       }
+       splx(s);
 
 
-               islocked = VOP_ISLOCKED(vp);
+       lfs_writevnodes(fs, mp, sp, 1);
 
 
-               /*
-                * XXX
-                * This is wrong, I think -- we should just wait until we
-                * get the vnode and go on.  Probably going to reschedule
-                * all of the writes we already scheduled...
-                */
-               if (islocked)
-                       VREF(vp);
-               else if (vget(vp))
-{
-printf("lfs_segment: failed to get vnode (tell Keith)!\n");
-                       goto loop;
-}
-               /*
-                * Write the inode/file if dirty and it's not the
-                * the IFILE.
-                */
-               ip = VTOI(vp);
-               if ((ip->i_flag & (IMOD | IACC | IUPD | ICHG) ||
-                   vp->v_dirtyblkhd != NULL) &&
-                   ip->i_number != LFS_IFILE_INUM) {
-                       if (vp->v_dirtyblkhd != NULL)
-                               lfs_writefile(fs, sp, vp);
-                       lfs_writeinode(fs, sp, ip);
-                       ip->i_flags &= ~(IMOD | IACC | IUPD | ICHG);
-               }
-               if (islocked)
-                       vrele(vp);
-               else
-                       vput(vp);
-       }
-       if (do_ckp) {
+       /*
+        * If this is a checkpoint, we need to loop on both the ifile and
+        * the writeseg to make sure that we don't end up with any dirty
+        * buffers left when this is all over.
+        */
+       if (do_ckp || fs->lfs_doifile) {
+redo:
                vp = fs->lfs_ivnode;
                while (vget(vp));
                ip = VTOI(vp);
                vp = fs->lfs_ivnode;
                while (vget(vp));
                ip = VTOI(vp);
-               if (vp->v_dirtyblkhd != NULL)
-                       lfs_writefile(fs, sp, vp);
-               lfs_writeinode(fs, sp, ip);
+               do {
+                       if (vp->v_dirtyblkhd != NULL)
+                               lfs_writefile(fs, sp, vp);
+               } while (lfs_writeinode(fs, sp, ip) && do_ckp);
                ip->i_flags &= ~(IMOD | IACC | IUPD | ICHG);
                vput(vp);
                ip->i_flags &= ~(IMOD | IACC | IUPD | ICHG);
                vput(vp);
-       }
-       lfs_writeseg(fs, sp);
+               if (lfs_writeseg(fs, sp) && do_ckp) {
+                       lfs_initseg(fs, sp);
+                       goto redo;
+               }
+       } else
+               (void) lfs_writeseg(fs, sp);
 
        /*
         * If the I/O count is non-zero, sleep until it reaches zero.  At the
 
        /*
         * If the I/O count is non-zero, sleep until it reaches zero.  At the
@@ -258,6 +292,10 @@ printf("lfs_segment: failed to get vnode (tell Keith)!\n");
         */
        s = splbio();
        --fs->lfs_iocount;
         */
        s = splbio();
        --fs->lfs_iocount;
+       fs->lfs_writer = 0;
+       fs->lfs_doifile = 0;
+       wakeup(&fs->lfs_dirops);
+
        if (do_ckp) {
                if (fs->lfs_iocount && (error =
                    tsleep(&fs->lfs_iocount, PRIBIO + 1, "lfs sync", 0))) {
        if (do_ckp) {
                if (fs->lfs_iocount && (error =
                    tsleep(&fs->lfs_iocount, PRIBIO + 1, "lfs sync", 0))) {
@@ -294,7 +332,7 @@ lfs_writefile(fs, sp, vp)
 #endif
        if (sp->seg_bytes_left < fs->lfs_bsize ||
            sp->sum_bytes_left < sizeof(struct finfo)) {
 #endif
        if (sp->seg_bytes_left < fs->lfs_bsize ||
            sp->sum_bytes_left < sizeof(struct finfo)) {
-               lfs_writeseg(fs, sp);
+               (void) lfs_writeseg(fs, sp);
                lfs_initseg(fs, sp);
        }
        sp->sum_bytes_left -= sizeof(struct finfo) - sizeof(daddr_t);
                lfs_initseg(fs, sp);
        }
        sp->sum_bytes_left -= sizeof(struct finfo) - sizeof(daddr_t);
@@ -331,7 +369,7 @@ lfs_writefile(fs, sp, vp)
                sp->sum_bytes_left += sizeof(struct finfo) - sizeof(daddr_t);
 }
 
                sp->sum_bytes_left += sizeof(struct finfo) - sizeof(daddr_t);
 }
 
-void
+int
 lfs_writeinode(fs, sp, ip)
        struct lfs *fs;
        struct segment *sp;
 lfs_writeinode(fs, sp, ip)
        struct lfs *fs;
        struct segment *sp;
@@ -343,6 +381,7 @@ lfs_writeinode(fs, sp, ip)
        daddr_t daddr;
        ino_t ino;
        int ndx;
        daddr_t daddr;
        ino_t ino;
        int ndx;
+       int redo_ifile = 0;
 
 #ifdef VERBOSE
        printf("lfs_writeinode\n");
 
 #ifdef VERBOSE
        printf("lfs_writeinode\n");
@@ -352,7 +391,7 @@ lfs_writeinode(fs, sp, ip)
                /* Allocate a new segment if necessary. */
                if (sp->seg_bytes_left < fs->lfs_bsize ||
                    sp->sum_bytes_left < sizeof(daddr_t)) {
                /* Allocate a new segment if necessary. */
                if (sp->seg_bytes_left < fs->lfs_bsize ||
                    sp->sum_bytes_left < sizeof(daddr_t)) {
-                       lfs_writeseg(fs, sp);
+                       (void) lfs_writeseg(fs, sp);
                        lfs_initseg(fs, sp);
                }
 
                        lfs_initseg(fs, sp);
                }
 
@@ -394,18 +433,29 @@ lfs_writeinode(fs, sp, ip)
        daddr = ifp->if_daddr;
        ifp->if_daddr = bp->b_blkno;
        LFS_UBWRITE(ibp);
        daddr = ifp->if_daddr;
        ifp->if_daddr = bp->b_blkno;
        LFS_UBWRITE(ibp);
+       redo_ifile = (ino == LFS_IFILE_INUM && !(ibp->b_flags & B_GATHERED));
 
 
-       if (daddr != LFS_UNUSED_DADDR) {
+       /*
+        * No need to update segment usage if there was no former inode address
+        * or if the last inode address is in the current partial segment.
+        */
+       if (daddr != LFS_UNUSED_DADDR && 
+           !(daddr >= fs->lfs_curseg && daddr <= ifp->if_daddr) ) {
                LFS_SEGENTRY(sup, fs, datosn(fs, daddr), bp);
 #ifdef DIAGNOSTIC
                LFS_SEGENTRY(sup, fs, datosn(fs, daddr), bp);
 #ifdef DIAGNOSTIC
-               if (sup->su_nbytes < sizeof(struct dinode))
+               if (sup->su_nbytes < sizeof(struct dinode)) {
                        /* XXX -- Change to a panic. */
                        printf("lfs: negative bytes (segment %d)\n",
                            datosn(fs, daddr));
                        /* XXX -- Change to a panic. */
                        printf("lfs: negative bytes (segment %d)\n",
                            datosn(fs, daddr));
+                       panic("negative bytes");
+               }
 #endif
                sup->su_nbytes -= sizeof(struct dinode);
                LFS_UBWRITE(bp);
 #endif
                sup->su_nbytes -= sizeof(struct dinode);
                LFS_UBWRITE(bp);
+               redo_ifile |= 
+                   (ino == LFS_IFILE_INUM && !(bp->b_flags & B_GATHERED));
        }
        }
+       return(redo_ifile);
 }
 
 void
 }
 
 void
@@ -415,7 +465,8 @@ lfs_gather(fs, sp, vp, match)
        struct vnode *vp;
        int (*match) __P((struct lfs *, struct buf *));
 {
        struct vnode *vp;
        int (*match) __P((struct lfs *, struct buf *));
 {
-       struct buf **bpp, *bp, *nbp;
+       struct buf **bpp, *bp;
+struct buf *lastbp;
        struct finfo *fip;
        struct inode *ip;
        daddr_t *lbp, *start_lbp;
        struct finfo *fip;
        struct inode *ip;
        daddr_t *lbp, *start_lbp;
@@ -431,13 +482,10 @@ lfs_gather(fs, sp, vp, match)
        start_lbp = lbp = &fip->fi_blocks[fip->fi_nblocks];
 
 loop:  s = splbio();
        start_lbp = lbp = &fip->fi_blocks[fip->fi_nblocks];
 
 loop:  s = splbio();
-       for (bp = vp->v_dirtyblkhd; bp; bp = nbp) {
-               nbp = bp->b_blockf;
-               /*
-                * XXX
-                * Should sleep on any BUSY buffer if doing an fsync?
-                */
-               if (bp->b_flags & B_BUSY || !match(fs, bp))
+       lastbp = NULL;
+       for (bp = vp->v_dirtyblkhd; bp; lastbp = bp, bp = bp->b_blockf) {
+               if (bp->b_flags & B_BUSY || !match(fs, bp) ||
+                   bp->b_flags & B_GATHERED)
                        continue;
 #ifdef DIAGNOSTIC
                if (!(bp->b_flags & B_DELWRI))
                        continue;
 #ifdef DIAGNOSTIC
                if (!(bp->b_flags & B_DELWRI))
@@ -459,7 +507,7 @@ loop:       s = splbio();
                        ++((SEGSUM *)(sp->segsum))->ss_nfinfo;
 
                        version = fip->fi_version;
                        ++((SEGSUM *)(sp->segsum))->ss_nfinfo;
 
                        version = fip->fi_version;
-                       lfs_writeseg(fs, sp);
+                       (void) lfs_writeseg(fs, sp);
                        lfs_initseg(fs, sp);
 
                        fip = sp->fip;
                        lfs_initseg(fs, sp);
 
                        fip = sp->fip;
@@ -475,6 +523,7 @@ loop:       s = splbio();
                }
 
                /* Insert into the buffer list, update the FINFO block. */
                }
 
                /* Insert into the buffer list, update the FINFO block. */
+               bp->b_flags |= B_GATHERED;
                *sp->cbpp++ = bp;
                ++fip->fi_nblocks;
                *lbp++ = bp->b_lblkno;
                *sp->cbpp++ = bp;
                ++fip->fi_nblocks;
                *lbp++ = bp->b_lblkno;
@@ -549,10 +598,12 @@ lfs_updatemeta(fs, sp, vp, lbp, bpp, nblocks)
                if (daddr != UNASSIGNED) {
                        LFS_SEGENTRY(sup, fs, datosn(fs, daddr), bp);
 #ifdef DIAGNOSTIC
                if (daddr != UNASSIGNED) {
                        LFS_SEGENTRY(sup, fs, datosn(fs, daddr), bp);
 #ifdef DIAGNOSTIC
-                       if (sup->su_nbytes < fs->lfs_bsize)
+                       if (sup->su_nbytes < fs->lfs_bsize) {
                                /* XXX -- Change to a panic. */
                                printf("lfs: negative bytes (segment %d)\n",
                                    datosn(fs, daddr));
                                /* XXX -- Change to a panic. */
                                printf("lfs: negative bytes (segment %d)\n",
                                    datosn(fs, daddr));
+                               panic ("Negative Bytes");
+                       }
 #endif
                        sup->su_nbytes -= fs->lfs_bsize;
                        LFS_UBWRITE(bp);
 #endif
                        sup->su_nbytes -= fs->lfs_bsize;
                        LFS_UBWRITE(bp);
@@ -602,6 +653,7 @@ lfs_initseg(fs, sp)
                sp->seg_bytes_left = (fs->lfs_dbpseg -
                    (fs->lfs_offset - fs->lfs_curseg)) * DEV_BSIZE;
        }
                sp->seg_bytes_left = (fs->lfs_dbpseg -
                    (fs->lfs_offset - fs->lfs_curseg)) * DEV_BSIZE;
        }
+       fs->lfs_lastpseg = fs->lfs_offset;
 
        sp->ibp = NULL;
        sp->ninodes = 0;
 
        sp->ibp = NULL;
        sp->ninodes = 0;
@@ -652,7 +704,7 @@ lfs_newseg(fs)
        LFS_UBWRITE(bp);
 
        LFS_SEGENTRY(sup, fs, datosn(fs, fs->lfs_nextseg), bp);
        LFS_UBWRITE(bp);
 
        LFS_SEGENTRY(sup, fs, datosn(fs, fs->lfs_nextseg), bp);
-       sup->su_flags |= SEGUSE_ACTIVE | SEGUSE_DIRTY;
+       sup->su_flags |= SEGUSE_ACTIVE | SEGUSE_DIRTY | SEGUSE_LIVELOG;
        LFS_UBWRITE(bp);
 
        LFS_CLEANERINFO(cip, fs, bp);
        LFS_UBWRITE(bp);
 
        LFS_CLEANERINFO(cip, fs, bp);
@@ -675,7 +727,7 @@ lfs_newseg(fs)
        fs->lfs_nextseg = sntoda(fs, sn);
 }
 
        fs->lfs_nextseg = sntoda(fs, sn);
 }
 
-void
+int
 lfs_writeseg(fs, sp)
        struct lfs *fs;
        struct segment *sp;
 lfs_writeseg(fs, sp)
        struct lfs *fs;
        struct segment *sp;
@@ -685,15 +737,17 @@ lfs_writeseg(fs, sp)
        SEGUSE *sup;
        SEGSUM *ssp;
        dev_t i_dev;
        SEGUSE *sup;
        SEGSUM *ssp;
        dev_t i_dev;
-       u_long *datap, *dp;
        size_t size;
        size_t size;
-       int ch_per_blk, i, nblocks, num, s, (*strategy)__P((struct vop_strategy_args *));
+       u_long *datap, *dp;
+       int ch_per_blk, do_again, i, nblocks, num, s;
+       int (*strategy)__P((struct vop_strategy_args *));
        char *p;
 
 #ifdef VERBOSE
        printf("lfs_writeseg\n");
 #endif
        char *p;
 
 #ifdef VERBOSE
        printf("lfs_writeseg\n");
 #endif
-       if ((nblocks = sp->cbpp - sp->bpp) == 0)
+       /* Checkpoint always writes superblock, even if no data blocks. */
+       if ((nblocks = sp->cbpp - sp->bpp) == 0 && !(sp->seg_flags & SEGM_CKP))
                return;
 
        /*
                return;
 
        /*
@@ -714,6 +768,15 @@ lfs_writeseg(fs, sp)
            cksum(&ssp->ss_datasum, LFS_SUMMARY_SIZE - sizeof(ssp->ss_sumsum));
        free(datap, M_SEGMENT);
 
            cksum(&ssp->ss_datasum, LFS_SUMMARY_SIZE - sizeof(ssp->ss_sumsum));
        free(datap, M_SEGMENT);
 
+       /* Update the segment usage information. */
+       LFS_SEGENTRY(sup, fs, sp->seg_number, bp);
+       sup->su_nbytes += nblocks - 1 - 
+           (ssp->ss_ninos + INOPB(fs) - 1) / INOPB(fs) << fs->lfs_bshift;
+       sup->su_nbytes += ssp->ss_ninos * sizeof(struct dinode);
+       sup->su_lastmod = time.tv_sec;
+       LFS_UBWRITE(bp);
+       do_again = !(bp->b_flags & B_GATHERED);
+
        i_dev = VTOI(fs->lfs_ivnode)->i_dev;
        strategy = VTOI(fs->lfs_ivnode)->i_devvp->v_op[VOFFSET(vop_strategy)];
 
        i_dev = VTOI(fs->lfs_ivnode)->i_dev;
        strategy = VTOI(fs->lfs_ivnode)->i_devvp->v_op[VOFFSET(vop_strategy)];
 
@@ -754,9 +817,9 @@ lfs_writeseg(fs, sp)
                        bp = *bpp++;
                        bcopy(bp->b_un.b_addr, p, bp->b_bcount);
                        p += bp->b_bcount;
                        bp = *bpp++;
                        bcopy(bp->b_un.b_addr, p, bp->b_bcount);
                        p += bp->b_bcount;
-                       bp->b_flags &=
-                           ~(B_DONE | B_ERROR | B_READ | B_DELWRI | B_LOCKED);
-                       if (!(bp->b_flags & B_NOCACHE)) {
+                       bp->b_flags &= ~(B_DONE | B_ERROR | B_READ | B_DELWRI |
+                            B_LOCKED | B_GATHERED);
+                       if (!(bp->b_flags & (B_NOCACHE | B_INVAL))) {
                                bremfree(bp);
                                reassignbuf(bp, bp->b_vp);
                        }
                                bremfree(bp);
                                reassignbuf(bp, bp->b_vp);
                        }
@@ -768,14 +831,7 @@ lfs_writeseg(fs, sp)
                vop_strategy_a.a_bp = cbp;
                (strategy)(&vop_strategy_a);
        }
                vop_strategy_a.a_bp = cbp;
                (strategy)(&vop_strategy_a);
        }
-
-       /* Update the segment usage information. */
-       LFS_SEGENTRY(sup, fs, sp->seg_number, bp);
-       sup->su_nbytes += nblocks - 1 - 
-           (ssp->ss_ninos + INOPB(fs) - 1) / INOPB(fs) << fs->lfs_bshift;
-       sup->su_nbytes += ssp->ss_ninos * sizeof(struct dinode);
-       sup->su_lastmod = time.tv_sec;
-       LFS_UBWRITE(bp);
+       return(do_again);
 }
 
 void
 }
 
 void
index 44b0c8f..71d1498 100644 (file)
@@ -4,17 +4,17 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)lfs_subr.c  7.11 (Berkeley) %G%
+ *     @(#)lfs_subr.c  7.12 (Berkeley) %G%
  */
 
 #include <sys/param.h>
 #include <sys/namei.h>
 #include <sys/vnode.h>
 #include <sys/buf.h>
  */
 
 #include <sys/param.h>
 #include <sys/namei.h>
 #include <sys/vnode.h>
 #include <sys/buf.h>
+#include <sys/mount.h>
 
 #include <ufs/ufs/quota.h>
 #include <ufs/ufs/inode.h>
 
 #include <ufs/ufs/quota.h>
 #include <ufs/ufs/inode.h>
-
 #include <ufs/lfs/lfs.h>
 #include <ufs/lfs/lfs_extern.h>
 
 #include <ufs/lfs/lfs.h>
 #include <ufs/lfs/lfs_extern.h>
 
@@ -48,3 +48,71 @@ lfs_blkatoff (ap)
        *ap->a_bpp = bp;
        return (0);
 }
        *ap->a_bpp = bp;
        return (0);
 }
+
+int
+lfs_mntinvalbuf(mp)
+       struct mount *mp;
+{
+       struct vnode *vp;
+       int dirty;
+
+       dirty = 0;
+       if ((mp->mnt_flag & MNT_MPBUSY) == 0)
+               panic("lfs_mntinvalbuf: not busy");
+loop:
+       for (vp = mp->mnt_mounth; vp; vp = vp->v_mountf) {
+               if (VTOI(vp)->i_number == LFS_IFILE_INUM)
+                       continue;
+               if (vget(vp))
+                       goto loop;
+               dirty += lfs_vinvalbuf(vp);
+               vput(vp);
+               if (vp->v_mount != mp)
+                       goto loop;
+       }
+       return (dirty);
+}
+
+/*
+ * For LFS, we need to do two passes.  First we need to wait on any dirty and
+ * busy buffers.  Once we've guaranteed that all the buffers are unbusy, we
+ * can do the segment write.  Then we need to go through and invalidate all
+ * the buffers on the clean list.
+ */
+int
+lfs_vinvalbuf(vp)
+       register struct vnode *vp;
+{
+       register struct buf *bp;
+       struct buf *nbp, *blist;
+       int s, dirty = 0;
+
+loop:  for (bp = vp->v_dirtyblkhd; bp; bp = nbp) {
+               nbp = bp->b_blockf;
+               s = splbio();
+               if (bp->b_flags & B_BUSY) {
+                       bp->b_flags |= B_WANTED;
+                       sleep((caddr_t)bp, PRIBIO + 1);
+                       splx(s);
+                       goto loop;
+               }
+               bremfree(bp);
+               splx(s);
+               dirty++;
+               brelse(bp);
+       }
+       if (dirty)
+               lfs_segwrite(vp->v_mount, 0);
+
+       /* Remove blocks from the clean list. */
+       for (bp = vp->v_cleanblkhd; bp; bp = nbp) {
+               nbp = bp->b_blockf;
+               bremfree(bp);
+               bp->b_flags |= B_INVAL;
+               brelse(bp);
+       }
+
+       if (vp->v_dirtyblkhd || vp->v_cleanblkhd)
+               panic("lfs_vinvalbuf: flush failed");
+       return (dirty);
+}
index 026e02e..09aa628 100644 (file)
@@ -4,7 +4,7 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)lfs_vfsops.c        7.74 (Berkeley) %G%
+ *     @(#)lfs_vfsops.c        7.75 (Berkeley) %G%
  */
 
 #include <sys/param.h>
  */
 
 #include <sys/param.h>
@@ -227,6 +227,11 @@ lfs_mountfs(devvp, mp, p)
        /* Set up the I/O information */
        fs->lfs_iocount = 0;
 
        /* Set up the I/O information */
        fs->lfs_iocount = 0;
 
+       /* Set up the ifile flags */
+       fs->lfs_doifile = 0;
+       fs->lfs_writer = 0;
+       fs->lfs_dirops = 0;
+
        /* Set the file system readonly/modify bits. */
        fs = ump->um_lfs;
        fs->lfs_ronly = ronly;
        /* Set the file system readonly/modify bits. */
        fs = ump->um_lfs;
        fs->lfs_ronly = ronly;
@@ -295,19 +300,28 @@ lfs_unmount(mp, mntflags, p)
                        return (EINVAL);
                flags |= FORCECLOSE;
        }
                        return (EINVAL);
                flags |= FORCECLOSE;
        }
+       /*
+        * FFS does a mntflushbuf here.  Our analagous operation
+        * would be a segment write, but that has already been
+        * done in the vfs code.
+        */
+       if (lfs_mntinvalbuf(mp))
+               return(EBUSY);
+
+       /* Need to checkpoint again to pick up any new ifile changes */
        if (error = lfs_segwrite(mp, 1))
                return(error);
        if (error = lfs_segwrite(mp, 1))
                return(error);
-
-ndirty = lfs_umountdebug(mp);
-printf("lfs_umountdebug: returned %d dirty\n", ndirty);
-return(0);
-       if (mntinvalbuf(mp))
-               return (EBUSY);
        ump = VFSTOUFS(mp);
        ump = VFSTOUFS(mp);
+       fs = ump->um_lfs;
+       if (fs->lfs_ivnode->v_dirtyblkhd)
+               panic("Still have dirty blocks on ifile vnode\n");
+       if (lfs_vinvalbuf(fs->lfs_ivnode))
+               panic("lfs_vinvalbuf failed on ifile\n");
+
                return (error);
 #ifdef QUOTA
        if (mp->mnt_flag & MNT_QUOTA) {
                return (error);
 #ifdef QUOTA
        if (mp->mnt_flag & MNT_QUOTA) {
-               if (error = vflush(mp, NULLVP, SKIPSYSTEM|flags))
+               if (error = vflush(mp, fs->lfs_ivnode, SKIPSYSTEM|flags))
                        return (error);
                for (i = 0; i < MAXQUOTAS; i++) {
                        if (ump->um_quotas[i] == NULLVP)
                        return (error);
                for (i = 0; i < MAXQUOTAS; i++) {
                        if (ump->um_quotas[i] == NULLVP)
@@ -320,11 +334,10 @@ return(0);
                 */
        }
 #endif
                 */
        }
 #endif
+       vrele(fs->lfs_ivnode);
        if (error = vflush(mp, NULLVP, flags))
                return (error);
        if (error = vflush(mp, NULLVP, flags))
                return (error);
-       fs = ump->um_lfs;
        ronly = !fs->lfs_ronly;
        ronly = !fs->lfs_ronly;
-       vrele(fs->lfs_ivnode);
  * Get file system statistics.
  */
 lfs_statfs(mp, sbp, p)
  * Get file system statistics.
  */
 lfs_statfs(mp, sbp, p)
index c0fde92..1f0d2bb 100644 (file)
@@ -4,7 +4,7 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)lfs_vnops.c 7.84 (Berkeley) %G%
+ *     @(#)lfs_vnops.c 7.85 (Berkeley) %G%
  */
 
 #include <sys/param.h>
  */
 
 #include <sys/param.h>
@@ -38,8 +38,8 @@ int (**lfs_vnodeop_p)();
 struct vnodeopv_entry_desc lfs_vnodeop_entries[] = {
        { &vop_default_desc, vn_default_error },
        { &vop_lookup_desc, ufs_lookup },               /* lookup */
 struct vnodeopv_entry_desc lfs_vnodeop_entries[] = {
        { &vop_default_desc, vn_default_error },
        { &vop_lookup_desc, ufs_lookup },               /* lookup */
-       { &vop_create_desc, ufs_create },               /* create */
-       { &vop_mknod_desc, ufs_mknod },                 /* mknod */
+       { &vop_create_desc, lfs_create },               /* create */
+       { &vop_mknod_desc, lfs_mknod },                 /* mknod */
        { &vop_open_desc, ufs_open },                   /* open */
        { &vop_close_desc, ufs_close },                 /* close */
        { &vop_access_desc, ufs_access },               /* access */
        { &vop_open_desc, ufs_open },                   /* open */
        { &vop_close_desc, ufs_close },                 /* close */
        { &vop_access_desc, ufs_access },               /* access */
@@ -52,12 +52,12 @@ struct vnodeopv_entry_desc lfs_vnodeop_entries[] = {
        { &vop_mmap_desc, ufs_mmap },                   /* mmap */
        { &vop_fsync_desc, lfs_fsync },                 /* fsync */
        { &vop_seek_desc, ufs_seek },                   /* seek */
        { &vop_mmap_desc, ufs_mmap },                   /* mmap */
        { &vop_fsync_desc, lfs_fsync },                 /* fsync */
        { &vop_seek_desc, ufs_seek },                   /* seek */
-       { &vop_remove_desc, ufs_remove },               /* remove */
-       { &vop_link_desc, ufs_link },                   /* link */
-       { &vop_rename_desc, ufs_rename },               /* rename */
-       { &vop_mkdir_desc, ufs_mkdir },                 /* mkdir */
-       { &vop_rmdir_desc, ufs_rmdir },                 /* rmdir */
-       { &vop_symlink_desc, ufs_symlink },             /* symlink */
+       { &vop_remove_desc, lfs_remove },               /* remove */
+       { &vop_link_desc, lfs_link },                   /* link */
+       { &vop_rename_desc, lfs_rename },               /* rename */
+       { &vop_mkdir_desc, lfs_mkdir },                 /* mkdir */
+       { &vop_rmdir_desc, lfs_rmdir },                 /* rmdir */
+       { &vop_symlink_desc, lfs_symlink },             /* symlink */
        { &vop_readdir_desc, ufs_readdir },             /* readdir */
        { &vop_readlink_desc, ufs_readlink },           /* readlink */
        { &vop_abortop_desc, ufs_abortop },             /* abortop */
        { &vop_readdir_desc, ufs_readdir },             /* readdir */
        { &vop_readlink_desc, ufs_readlink },           /* readlink */
        { &vop_abortop_desc, ufs_abortop },             /* abortop */
@@ -425,3 +425,136 @@ lfs_inactive(ap)
                vgone(vp);
        return (error);
 }
                vgone(vp);
        return (error);
 }
+
+/*
+ * These macros are used to bracket UFS directory ops, so that we can
+ * identify all the pages touched during directory ops which need to
+ * be ordered and flushed atomically, so that they may be recovered.
+ */
+#define        SET_DIROP(fs) {                                                 \
+       int __s;                                                        \
+       __s = splbio();                                                 \
+       if ((fs)->lfs_writer)                                           \
+               tsleep(&(fs)->lfs_dirops, PRIBIO + 1, "lfs dirop", 0);  \
+       ++(fs)->lfs_dirops;                                             \
+       (fs)->lfs_doifile = 1;                                          \
+       splx(__s);                                                      \
+}
+
+#define        SET_ENDOP(fs) {                                                 \
+       int __s;                                                        \
+       __s = splbio();                                                 \
+       --(fs)->lfs_dirops;                                             \
+       if (!(fs)->lfs_dirops)                                          \
+               wakeup(&(fs)->lfs_writer);                              \
+       splx(__s);                                                      \
+}
+
+#define        MARK_VNODE(dvp) (dvp)->v_flag |= VDIROP
+
+int
+lfs_symlink(ap)
+       struct vop_symlink_args *ap;
+{
+       int ret;
+
+       SET_DIROP(VTOI(ap->a_dvp)->i_lfs);
+       MARK_VNODE(ap->a_dvp);
+       ret = ufs_symlink(ap);
+       SET_ENDOP(VTOI(ap->a_dvp)->i_lfs);
+       return (ret);
+}
+
+int
+lfs_mknod(ap)
+       struct vop_mknod_args *ap;
+{
+       int ret;
+
+       SET_DIROP(VTOI(ap->a_dvp)->i_lfs);
+       MARK_VNODE(ap->a_dvp);
+       ret = ufs_mknod(ap);
+       SET_ENDOP(VTOI(ap->a_dvp)->i_lfs);
+       return (ret);
+}
+
+int
+lfs_create(ap)
+       struct vop_create_args *ap;
+{
+       int ret;
+
+       SET_DIROP(VTOI(ap->a_dvp)->i_lfs);
+       MARK_VNODE(ap->a_dvp);
+       ret = ufs_create(ap);
+       SET_ENDOP(VTOI(ap->a_dvp)->i_lfs);
+       return (ret);
+}
+
+int
+lfs_mkdir(ap)
+       struct vop_mkdir_args *ap;
+{
+       int ret;
+
+       SET_DIROP(VTOI(ap->a_dvp)->i_lfs);
+       MARK_VNODE(ap->a_dvp);
+       ret = ufs_mkdir(ap);
+       SET_ENDOP(VTOI(ap->a_dvp)->i_lfs);
+       return (ret);
+}
+
+int
+lfs_remove(ap)
+       struct vop_remove_args *ap;
+{
+       int ret;
+
+       SET_DIROP(VTOI(ap->a_dvp)->i_lfs);
+       MARK_VNODE(ap->a_dvp);
+       MARK_VNODE(ap->a_vp);
+       ret = ufs_remove(ap);
+       SET_ENDOP(VTOI(ap->a_dvp)->i_lfs);
+       return (ret);
+}
+
+int
+lfs_rmdir(ap)
+       struct vop_rmdir_args *ap;
+{
+       int ret;
+
+       SET_DIROP(VTOI(ap->a_dvp)->i_lfs);
+       MARK_VNODE(ap->a_dvp);
+       MARK_VNODE(ap->a_vp);
+       ret = ufs_rmdir(ap);
+       SET_ENDOP(VTOI(ap->a_dvp)->i_lfs);
+       return (ret);
+}
+
+int
+lfs_link(ap)
+       struct vop_link_args *ap;
+{
+       int ret;
+
+       SET_DIROP(VTOI(ap->a_vp)->i_lfs);
+       MARK_VNODE(ap->a_vp);
+       ret = ufs_link(ap);
+       SET_ENDOP(VTOI(ap->a_vp)->i_lfs);
+       return (ret);
+}
+
+int
+lfs_rename(ap)
+       struct vop_rename_args *ap;
+{
+       int ret;
+
+       SET_DIROP(VTOI(ap->a_fdvp)->i_lfs);
+       MARK_VNODE(ap->a_fdvp);
+       MARK_VNODE(ap->a_tdvp);
+       ret = ufs_rename(ap);
+       SET_ENDOP(VTOI(ap->a_fdvp)->i_lfs);
+       return (ret);
+}