did you miss sys/wapbl.h ?

cc ... -D_KERNEL -MD -MP  -c ../../../../kern/vfs_bio.c
../../../../kern/vfs_bio.c:59:23: error: sys/wapbl.h: No such file or
directory
../../../../kern/vfs_bio.c: In function 'bio_doread':
../../../../kern/vfs_bio.c:358: error: 'struct vnode' has no member named
'v_specmountpoint'


2015-10-23 17:19 GMT+02:00 Walter Neto <wsouz...@gmail.com>:

> Like recommended from other developers I started developing WAPBL support
> for
> OpenBSD.
>
> Looking at NetBSD and Bitrig I mage a first funcional patch.
>
> Index: sbin/mount/mntopts.h
> ===================================================================
> RCS file: /Volumes/CSP/cvs/src/sbin/mount/mntopts.h,v
> retrieving revision 1.16
> diff -u -r1.16 mntopts.h
> --- sbin/mount/mntopts.h        13 Jul 2014 12:01:30 -0000      1.16
> +++ sbin/mount/mntopts.h        23 Oct 2015 15:07:07 -0000
> @@ -66,6 +66,8 @@
>                                             | MFLAG_OPT }
>  #define MOPT_SOFTDEP   { "softdep",    MNT_SOFTDEP, MFLAG_SET }
>
> +#define MOPT_LOG       { "log",        MNT_LOG, MFLAG_SET }
> +
>  /* Control flags. */
>  #define MOPT_FORCE     { "force",      MNT_FORCE, MFLAG_SET }
>  #define MOPT_UPDATE    { "update",     MNT_UPDATE, MFLAG_SET }
> Index: sbin/mount/mount.c
> ===================================================================
> RCS file: /Volumes/CSP/cvs/src/sbin/mount/mount.c,v
> retrieving revision 1.60
> diff -u -r1.60 mount.c
> --- sbin/mount/mount.c  16 Jan 2015 06:39:59 -0000      1.60
> +++ sbin/mount/mount.c  23 Oct 2015 15:07:07 -0000
> @@ -94,6 +94,7 @@
>         { MNT_ROOTFS,           1,      "root file system",     "" },
>         { MNT_SYNCHRONOUS,      0,      "synchronous",          "sync" },
>         { MNT_SOFTDEP,          0,      "softdep",              "softdep"
> },
> +       { MNT_LOG,              0,      "log",                  "log" },
>         { 0,                    0,      "",                     "" }
>  };
>
> Index: sbin/mount_ffs/mount_ffs.c
> ===================================================================
> RCS file: /Volumes/CSP/cvs/src/sbin/mount_ffs/mount_ffs.c,v
> retrieving revision 1.21
> diff -u -r1.21 mount_ffs.c
> --- sbin/mount_ffs/mount_ffs.c  16 Jan 2015 06:39:59 -0000      1.21
> +++ sbin/mount_ffs/mount_ffs.c  23 Oct 2015 15:07:07 -0000
> @@ -53,6 +53,7 @@
>         MOPT_RELOAD,
>         MOPT_FORCE,
>         MOPT_SOFTDEP,
> +       MOPT_LOG,
>         { NULL }
>  };
>
> Index: sys/conf/GENERIC
> ===================================================================
> RCS file: /Volumes/CSP/cvs/src/sys/conf/GENERIC,v
> retrieving revision 1.220
> diff -u -r1.220 GENERIC
> --- sys/conf/GENERIC    10 Aug 2015 20:35:36 -0000      1.220
> +++ sys/conf/GENERIC    23 Oct 2015 15:07:07 -0000
> @@ -43,6 +43,7 @@
>  option         FIFO            # FIFOs; RECOMMENDED
>  option         TMPFS           # efficient memory file system
>  option         FUSE            # FUSE
> +option         WAPBL           # Write Ahead Physical Block Logging
>
>  option         SOCKET_SPLICE   # Socket Splicing for TCP and UDP
>  option         TCP_SACK        # Selective Acknowledgements for TCP
> Index: sys/conf/files
> ===================================================================
> RCS file: /Volumes/CSP/cvs/src/sys/conf/files,v
> retrieving revision 1.604
> diff -u -r1.604 files
> --- sys/conf/files      9 Oct 2015 01:17:21 -0000       1.604
> +++ sys/conf/files      23 Oct 2015 15:07:07 -0000
> @@ -732,6 +732,7 @@
>  file kern/vfs_vops.c
>  file kern/vfs_vnops.c
>  file kern/vfs_getcwd.c
> +file kern/vfs_wapbl.c                  wapbl
>  file kern/spec_vnops.c
>  file miscfs/deadfs/dead_vnops.c
>  file miscfs/fifofs/fifo_vnops.c                fifo
> @@ -887,6 +888,7 @@
>  file ufs/ffs/ffs_vfsops.c              ffs | mfs
>  file ufs/ffs/ffs_vnops.c               ffs | mfs
>  file ufs/ffs/ffs_softdep.c             ffs_softupdates
> +file ufs/ffs/ffs_wapbl.c               ffs & wapbl
>  file ufs/mfs/mfs_vfsops.c              mfs
>  file ufs/mfs/mfs_vnops.c               mfs
>  file ufs/ufs/ufs_bmap.c                        ffs | mfs | ext2fs
> @@ -898,6 +900,7 @@
>  file ufs/ufs/ufs_quota_stub.c          ffs | mfs
>  file ufs/ufs/ufs_vfsops.c              ffs | mfs | ext2fs
>  file ufs/ufs/ufs_vnops.c               ffs | mfs | ext2fs
> +file ufs/ufs/ufs_wapbl.c               ffs & wapbl
>  file ufs/ext2fs/ext2fs_alloc.c         ext2fs
>  file ufs/ext2fs/ext2fs_balloc.c                ext2fs
>  file ufs/ext2fs/ext2fs_bmap.c          ext2fs
> Index: sys/kern/spec_vnops.c
> ===================================================================
> RCS file: /Volumes/CSP/cvs/src/sys/kern/spec_vnops.c,v
> retrieving revision 1.83
> diff -u -r1.83 spec_vnops.c
> --- sys/kern/spec_vnops.c       10 Feb 2015 21:56:09 -0000      1.83
> +++ sys/kern/spec_vnops.c       23 Oct 2015 15:07:07 -0000
> @@ -408,6 +408,10 @@
>         return (EOPNOTSUPP);
>  }
>
> +#ifdef WAPBL
> +extern int ffs_wapbl_fsync_vfs(struct vnode *, int);
> +#endif
> +
>  /*
>   * Synch buffers associated with a block device
>   */
> @@ -422,6 +426,15 @@
>
>         if (vp->v_type == VCHR)
>                 return (0);
> +
> +
> +#ifdef WAPBL
> +       if (vp->v_type == VBLK &&
> +           vp->v_specmountpoint != NULL &&
> +           vp->v_specmountpoint->mnt_wapbl != NULL)
> +               return (ffs_wapbl_fsync_vfs(vp, ap->a_waitfor));
> +#endif
> +
>         /*
>          * Flush all dirty buffers associated with a block device.
>          */
> Index: sys/kern/vfs_bio.c
> ===================================================================
> RCS file: /Volumes/CSP/cvs/src/sys/kern/vfs_bio.c,v
> retrieving revision 1.170
> diff -u -r1.170 vfs_bio.c
> --- sys/kern/vfs_bio.c  19 Jul 2015 16:21:11 -0000      1.170
> +++ sys/kern/vfs_bio.c  23 Oct 2015 15:07:07 -0000
> @@ -56,7 +56,7 @@
>  #include <sys/resourcevar.h>
>  #include <sys/conf.h>
>  #include <sys/kernel.h>
> -#include <sys/specdev.h>
> +#include <sys/wapbl.h>
>  #include <uvm/uvm_extern.h>
>
>  int nobuffers;
> @@ -77,6 +77,7 @@
>  struct buf *bio_doread(struct vnode *, daddr_t, int, int);
>  struct buf *buf_get(struct vnode *, daddr_t, size_t);
>  void bread_cluster_callback(struct buf *);
> +static inline int injournal(struct buf *);
>
>  struct bcachestats bcstats;  /* counters */
>  long lodirtypages;      /* dirty page count low water mark */
> @@ -556,6 +557,16 @@
>                 mp = NULL;
>
>         /*
> +        * If using WAPBL, convert it to a delayed write
> +        */
> +       if (mp && mp->mnt_wapbl && injournal(bp)) {
> +               if (bp->b_iodone != mp->mnt_wapbl_op->wo_wapbl_biodone) {
> +                       bdwrite(bp);
> +                       return 0;
> +               }
> +       }
> +
> +       /*
>          * Remember buffer type, to switch on it later.  If the write was
>          * synchronous, but the file system was mounted with MNT_ASYNC,
>          * convert it to a delayed write.
> @@ -628,6 +639,20 @@
>         return (rv);
>  }
>
> +/*
> + * Consider a buffer for an entry in the (WAPBL) journal. We do not want
> to log
> + * regular data blocks.
> + */
> +static inline int
> +injournal(struct buf *bp)
> +{
> +       struct vnode *vp = bp->b_vp;
> +
> +       if (wapbl_vphaswapbl(vp) && (vp->v_type != VREG || bp->b_lblkno <
> 0))
> +               return (1);
> +
> +       return (0);
> +}
>
>  /*
>   * Delayed write.
> @@ -647,6 +672,20 @@
>  {
>         int s;
>
> +       /* If this is a tape block, write the block now. */
> +       if (major(bp->b_dev) < nblkdev &&
> +           bdevsw[major(bp->b_dev)].d_type == D_TAPE) {
> +               bawrite(bp);
> +               return;
> +       }
> +
> +       if (injournal(bp)) {
> +               struct mount *mp = wapbl_vptomp(bp->b_vp);
> +
> +               if (bp->b_iodone != mp->mnt_wapbl_op->wo_wapbl_biodone)
> +                       WAPBL_ADD_BUF(mp, bp);
> +       }
> +
>         /*
>          * If the block hasn't been seen before:
>          *      (1) Mark it as having been seen,
> @@ -663,13 +702,6 @@
>                 curproc->p_ru.ru_oublock++;             /* XXX */
>         }
>
> -       /* If this is a tape block, write the block now. */
> -       if (major(bp->b_dev) < nblkdev &&
> -           bdevsw[major(bp->b_dev)].d_type == D_TAPE) {
> -               bawrite(bp);
> -               return;
> -       }
> -
>         /* Otherwise, the "write" is done, so mark and release the buffer.
> */
>         CLR(bp->b_flags, B_NEEDCOMMIT);
>         SET(bp->b_flags, B_DONE);
> @@ -743,12 +775,28 @@
>          * Determine which queue the buffer should be on, then put it
> there.
>          */
>
> +       /* If it's locked, don't report an error; try again later */
> +       if (ISSET(bp->b_flags, (B_LOCKED|B_ERROR)) == (B_LOCKED|B_ERROR))
> +               CLR(bp->b_flags, B_ERROR);
> +
>         /* If it's not cacheable, or an error, mark it invalid. */
>         if (ISSET(bp->b_flags, (B_NOCACHE|B_ERROR)))
>                 SET(bp->b_flags, B_INVAL);
>
>         if (ISSET(bp->b_flags, B_INVAL)) {
>                 /*
> +                * If using WAPBL
> +                */
> +               if (ISSET(bp->b_flags, B_LOCKED)) {
> +                       if (wapbl_vphaswapbl(bp->b_vp)) {
> +                               struct mount *mp = wapbl_vptomp(bp->b_vp);
> +                               KASSERT(bp->b_iodone
> +                                   != mp->mnt_wapbl_op->wo_wapbl_biodone);
> +                               WAPBL_REMOVE_BUF(mp, bp);
> +                       }
> +               }
> +
> +               /*
>                  * If the buffer is invalid, free it now rather than
> leaving
>                  * it in a queue and wasting memory.
>                  */
> @@ -1079,6 +1127,19 @@
>                         if (!ISSET(bp->b_flags, B_DELWRI))
>                                 panic("Clean buffer on dirty queue");
>  #endif
> +
> +
> +#ifdef WAPBL
> +                       if (ISSET(bp->b_flags, B_LOCKED) &&
> +                           wapbl_vphaswapbl(bp->b_vp)) {
> +                               brelse(bp);
> +                               struct mount *mp = wapbl_vptomp(bp->b_vp);
> +                               wapbl_flush(mp->mnt_wapbl, 1);
> +                               s = splbio();
> +                               continue;
> +                       }
> +#endif /* WAPBL */
> +
>                         if (LIST_FIRST(&bp->b_dep) != NULL &&
>                             !ISSET(bp->b_flags, B_DEFERRED) &&
>                             buf_countdeps(bp, 0, 0)) {
> @@ -1206,6 +1267,17 @@
>  }
>  #endif
>
> +void
> +buf_adjcnt(struct buf *bp, long ncount)
> +{
> +       KASSERT(ncount <= bp->b_bufsize);
> +       long ocount = bp->b_bcount;
> +       bp->b_bcount = ncount;
> +       if (injournal(bp))
> +               WAPBL_RESIZE_BUF(wapbl_vptomp(bp->b_vp), bp, bp->b_bufsize,
> +                   ocount);
> +}
> +
>  /* bufcache freelist code below */
>  /*
>   * Copyright (c) 2014 Ted Unangst <t...@openbsd.org>
> Index: sys/kern/vfs_biomem.c
> ===================================================================
> RCS file: /Volumes/CSP/cvs/src/sys/kern/vfs_biomem.c,v
> retrieving revision 1.34
> diff -u -r1.34 vfs_biomem.c
> --- sys/kern/vfs_biomem.c       19 Jul 2015 21:21:14 -0000      1.34
> +++ sys/kern/vfs_biomem.c       23 Oct 2015 15:07:07 -0000
> @@ -89,7 +89,7 @@
>  {
>         splassert(IPL_BIO);
>         SET(bp->b_flags, B_BUSY);
> -       if (bp->b_data != NULL) {
> +       if (bp->b_data != NULL && !(bp->b_flags & B_LOCKED)) {
>                 TAILQ_REMOVE(&buf_valist, bp, b_valist);
>                 bcstats.kvaslots_avail--;
>                 bcstats.busymapped++;
> @@ -143,8 +143,11 @@
>                 pmap_update(pmap_kernel());
>                 bp->b_data = (caddr_t)va;
>         } else {
> -               TAILQ_REMOVE(&buf_valist, bp, b_valist);
> -               bcstats.kvaslots_avail--;
> +               if (!(bp->b_flags & B_LOCKED)) {
> +                       TAILQ_REMOVE(&buf_valist, bp, b_valist);
> +                       bcstats.kvaslots_avail--;
> +               } else
> +                       return;
>         }
>
>         bcstats.busymapped++;
> @@ -157,7 +160,7 @@
>         KASSERT(bp->b_flags & B_BUSY);
>         splassert(IPL_BIO);
>
> -       if (bp->b_data) {
> +       if (bp->b_data && !(bp->b_flags & B_LOCKED)) {
>                 bcstats.busymapped--;
>                 TAILQ_INSERT_TAIL(&buf_valist, bp, b_valist);
>                 bcstats.kvaslots_avail++;
> @@ -191,6 +194,7 @@
>         bp->b_data = NULL;
>
>         if (data) {
> +               KASSERT(!(bp->b_flags & B_LOCKED));
>                 if (bp->b_flags & B_BUSY)
>                         bcstats.busymapped--;
>                 pmap_kremove((vaddr_t)data, bp->b_bufsize);
> @@ -237,6 +241,7 @@
>                  * buffers read in by bread_cluster
>                  */
>                 bp->b_bufsize = newsize;
> +               KASSERT(!(bp->b_flags & B_LOCKED));
>         }
>  }
>
> Index: sys/kern/vfs_init.c
> ===================================================================
> RCS file: /Volumes/CSP/cvs/src/sys/kern/vfs_init.c,v
> retrieving revision 1.36
> diff -u -r1.36 vfs_init.c
> --- sys/kern/vfs_init.c 14 Mar 2015 03:38:51 -0000      1.36
> +++ sys/kern/vfs_init.c 23 Oct 2015 15:07:07 -0000
> @@ -42,6 +42,7 @@
>  #include <sys/namei.h>
>  #include <sys/vnode.h>
>  #include <sys/pool.h>
> +#include <sys/wapbl.h>
>
>  struct pool namei_pool;
>
> @@ -156,6 +157,10 @@
>         /* Initialize the vnode name cache. */
>         nchinit();
>
> +#ifdef WAPBL
> +       wapbl_init();
> +#endif
> +
>         /*
>          * Stop using vfsconf and maxvfsconf as a temporary storage,
>          * set them to their correct values now.
> Index: sys/kern/vfs_subr.c
> ===================================================================
> RCS file: /Volumes/CSP/cvs/src/sys/kern/vfs_subr.c,v
> retrieving revision 1.236
> diff -u -r1.236 vfs_subr.c
> --- sys/kern/vfs_subr.c 13 Oct 2015 09:11:48 -0000      1.236
> +++ sys/kern/vfs_subr.c 23 Oct 2015 15:07:07 -0000
> @@ -62,7 +62,7 @@
>  #include <sys/syscallargs.h>
>  #include <sys/pool.h>
>  #include <sys/tree.h>
> -#include <sys/specdev.h>
> +#include <sys/wapbl.h>
>
>  #include <netinet/in.h>
>
> @@ -921,7 +921,7 @@
>  void
>  vclean(struct vnode *vp, int flags, struct proc *p)
>  {
> -       int active;
> +       int active, error;
>
>         /*
>          * Check to see if the vnode is in use.
> @@ -955,8 +955,15 @@
>         /*
>          * Clean out any buffers associated with the vnode.
>          */
> -       if (flags & DOCLOSE)
> -               vinvalbuf(vp, V_SAVE, NOCRED, p, 0, 0);
> +       if (flags & DOCLOSE) {
> +               error = vinvalbuf(vp, V_SAVE, NOCRED, p, 0, 0);
> +               if (error != 0) {
> +                       if (wapbl_vphaswapbl(vp))
> +                               WAPBL_DISCARD(wapbl_vptomp(vp));
> +                       error = vinvalbuf(vp, 0, NOCRED, p, 0, 0);
> +               }
> +               KASSERT(error == 0);
> +       }
>         /*
>          * If purging an active vnode, it must be closed and
>          * deactivated before being reclaimed. Note that the
> @@ -1850,6 +1857,64 @@
>         return (0);
>  }
>
> +/*
> + * Destroy any in core blocks past the truncation length.
> + * Called with the underlying vnode locked, which should prevent new dirty
> + * buffers from being queued.
> + */
> +int
> +vtruncbuf(struct vnode *vp, daddr_t lbn, int slpflag, int slptimeo)
> +{
> +       struct buf *bp, *nbp;
> +       int s, error;
> +
> +       s = splbio();
> +restart:
> +       for (bp = LIST_FIRST(&vp->v_cleanblkhd); bp; bp = nbp) {
> +               nbp = LIST_NEXT(bp, b_vnbufs);
> +               if (bp->b_lblkno < lbn)
> +                       continue;
> +               if (bp->b_flags & B_BUSY) {
> +                       bp->b_flags |= B_WANTED;
> +                       error = tsleep(bp, slpflag | (PRIBIO + 1),
> +                           "vtruncbuf", slptimeo);
> +                       if (error) {
> +                               splx(s);
> +                               return (error);
> +                       }
> +                       goto restart;
> +               }
> +               bremfree(bp);
> +               buf_acquire_nomap(bp);
> +               bp->b_flags |= B_INVAL;
> +               brelse(bp);
> +       }
> +
> +       for (bp = LIST_FIRST(&vp->v_dirtyblkhd); bp; bp = nbp) {
> +               nbp = LIST_NEXT(bp, b_vnbufs);
> +               if (bp->b_lblkno < lbn)
> +                       continue;
> +               if (bp->b_flags & B_BUSY) {
> +                       bp->b_flags |= B_WANTED;
> +                       error = tsleep(bp, slpflag | (PRIBIO + 1),
> +                           "vtruncbuf", slptimeo);
> +                       if (error) {
> +                               splx(s);
> +                               return (error);
> +                       }
> +                       goto restart;
> +               }
> +               bremfree(bp);
> +               buf_acquire_nomap(bp);
> +               bp->b_flags |= B_INVAL;
> +               brelse(bp);
> +       }
> +
> +       splx(s);
> +
> +       return (0);
> +}
> +
>  void
>  vflushbuf(struct vnode *vp, int sync)
>  {
> Index: sys/kern/vfs_sync.c
> ===================================================================
> RCS file: /Volumes/CSP/cvs/src/sys/kern/vfs_sync.c,v
> retrieving revision 1.54
> diff -u -r1.54 vfs_sync.c
> --- sys/kern/vfs_sync.c 14 Mar 2015 03:38:51 -0000      1.54
> +++ sys/kern/vfs_sync.c 23 Oct 2015 15:07:07 -0000
> @@ -311,6 +311,18 @@
>  }
>
>  /*
> + * Return delay factor appropriate for the given file system.   For
> + * WAPBL we use the sync vnode to burst out metadata updates: sync
> + * those file systems more frequently.
> + */
> +static inline int
> +sync_delay(struct mount *mp)
> +{
> +
> +       return mp->mnt_wapbl != NULL ? syncdelay / 3 : syncdelay;
> +}
> +
> +/*
>   * Do a lazy sync of the filesystem.
>   */
>  int
> @@ -330,7 +342,7 @@
>         /*
>          * Move ourselves to the back of the sync list.
>          */
> -       vn_syncer_add_to_worklist(syncvp, syncdelay);
> +       vn_syncer_add_to_worklist(syncvp, sync_delay(mp));
>
>         /*
>          * Walk the list of vnodes pushing all that are dirty and
> Index: sys/kern/vfs_syscalls.c
> ===================================================================
> RCS file: /Volumes/CSP/cvs/src/sys/kern/vfs_syscalls.c,v
> retrieving revision 1.232
> diff -u -r1.232 vfs_syscalls.c
> --- sys/kern/vfs_syscalls.c     20 Oct 2015 06:40:00 -0000      1.232
> +++ sys/kern/vfs_syscalls.c     23 Oct 2015 15:07:07 -0000
> @@ -253,10 +253,10 @@
>                 mp->mnt_flag |= MNT_WANTRDWR;
>         mp->mnt_flag &=~ (MNT_NOSUID | MNT_NOEXEC | MNT_NODEV |
>             MNT_SYNCHRONOUS | MNT_ASYNC | MNT_SOFTDEP | MNT_NOATIME |
> -           MNT_FORCE);
> +           MNT_FORCE | MNT_LOG);
>         mp->mnt_flag |= flags & (MNT_NOSUID | MNT_NOEXEC |
>             MNT_NODEV | MNT_SYNCHRONOUS | MNT_ASYNC | MNT_SOFTDEP |
> -           MNT_NOATIME | MNT_FORCE);
> +           MNT_NOATIME | MNT_FORCE | MNT_LOG);
>         /*
>          * Mount the filesystem.
>          */
> Index: sys/sys/buf.h
> ===================================================================
> RCS file: /Volumes/CSP/cvs/src/sys/sys/buf.h,v
> retrieving revision 1.99
> diff -u -r1.99 buf.h
> --- sys/sys/buf.h       19 Jul 2015 16:21:11 -0000      1.99
> +++ sys/sys/buf.h       23 Oct 2015 15:07:07 -0000
> @@ -144,6 +144,7 @@
>         LIST_ENTRY(buf) b_list;         /* All allocated buffers. */
>         LIST_ENTRY(buf) b_vnbufs;       /* Buffer's associated vnode. */
>         TAILQ_ENTRY(buf) b_freelist;    /* Free list position if not
> active. */
> +       LIST_ENTRY(buf) b_wapbllist;    /* transaction buffer list */
>         int cache;                      /* which cache are we in */
>         struct  proc *b_proc;           /* Associated proc; NULL if
> kernel. */
>         volatile long   b_flags;        /* B_* flags. */
> @@ -157,6 +158,8 @@
>
>         TAILQ_ENTRY(buf) b_valist;      /* LRU of va to reuse. */
>
> +       void * b_private;               /* private data for owner */
> +
>         union   bufq_data b_bufq;
>         struct  bufq      *b_bq;        /* What bufq this buf is on */
>
> @@ -221,12 +224,14 @@
>  #define        B_COLD          0x01000000      /* buffer is on the cold
> queue
> */
>  #define        B_BC            0x02000000      /* buffer is managed by the
> cache */
>  #define        B_DMA           0x04000000      /* buffer is DMA reachable
> */
> +#define B_LOCKED       0x08000000      /* Locked in core (not reusable).
> */
>
>  #define        B_BITS  "\20\001AGE\002NEEDCOMMIT\003ASYNC\004BAD\005BUSY"
> \
>      "\006CACHE\007CALL\010DELWRI\011DONE\012EINTR\013ERROR" \
>      "\014INVAL\015NOCACHE\016PHYS\017RAW\020READ" \
>      "\021WANTED\022WRITEINPROG\023XXX(FORMAT)\024DEFERRED" \
> -    "\025SCANNED\026DAEMON\027RELEASED\030WARM\031COLD\032BC\033DMA"
> +    "\025SCANNED\026DAEMON\027RELEASED\030WARM\031COLD\032BC\033DMA" \
> +    "\034LOCKED"
>
>  /*
>   * This structure describes a clustered I/O.  It is stored in the
> b_saveaddr
> @@ -254,6 +259,8 @@
>  /* Flags to low-level allocation routines. */
>  #define B_CLRBUF       0x01    /* Request allocated buffer be cleared. */
>  #define B_SYNC         0x02    /* Do all allocations synchronously. */
> +#define        B_METAONLY      0x04    /* return indirect block buffer */
> +#define B_CONTIG       0x08    /* allocate file contiguously */
>
>  struct cluster_info {
>         daddr_t ci_lastr;       /* last read (read-ahead) */
> @@ -292,6 +299,7 @@
>  void   bufinit(void);
>  void   buf_dirty(struct buf *);
>  void    buf_undirty(struct buf *);
> +void   buf_adjcnt(struct buf *, long);
>  int    bwrite(struct buf *);
>  struct buf *getblk(struct vnode *, daddr_t, int, int, int);
>  struct buf *geteblk(int);
> Index: sys/sys/dkio.h
> ===================================================================
> RCS file: /Volumes/CSP/cvs/src/sys/sys/dkio.h,v
> retrieving revision 1.9
> diff -u -r1.9 dkio.h
> --- sys/sys/dkio.h      5 Jun 2011 18:40:33 -0000       1.9
> +++ sys/sys/dkio.h      23 Oct 2015 15:07:07 -0000
> @@ -83,4 +83,7 @@
>
>  #define        DIOCMAP         _IOWR('d', 119, struct dk_diskmap)
>
> +/* sync disk cache */
> +#define        DIOCCACHESYNC   _IOW('d', 118, int)     /* sync cache
> (force?)
> */
> +
>  #endif /* _SYS_DKIO_H_ */
> Index: sys/sys/mount.h
> ===================================================================
> RCS file: /Volumes/CSP/cvs/src/sys/sys/mount.h,v
> retrieving revision 1.121
> diff -u -r1.121 mount.h
> --- sys/sys/mount.h     8 Sep 2014 01:47:06 -0000       1.121
> +++ sys/sys/mount.h     23 Oct 2015 15:07:07 -0000
> @@ -358,6 +358,11 @@
>         int             mnt_maxsymlinklen;      /* max size of short
> symlink */
>         struct statfs   mnt_stat;               /* cache of filesystem
> stats */
>         void            *mnt_data;              /* private data */
> +       struct wapbl_ops
> +                       *mnt_wapbl_op;          /* logging ops */
> +       struct wapbl    *mnt_wapbl;             /* log info */
> +       struct wapbl_replay
> +                       *mnt_wapbl_replay;      /* replay support XXX:
> what? */
>  };
>
>  /*
> @@ -396,7 +401,7 @@
>  /*
>   * Mask of flags that are visible to statfs()
>   */
> -#define        MNT_VISFLAGMASK 0x0400ffff
> +#define        MNT_VISFLAGMASK 0x1400ffff
>
>  #define        MNT_BITS \
>      "\010\001RDONLY\002SYNCHRONOUS\003NOEXEC\004NOSUID\005NODEV" \
> @@ -413,6 +418,7 @@
>  #define MNT_WANTRDWR   0x02000000      /* want upgrade to read/write */
>  #define MNT_SOFTDEP     0x04000000      /* soft dependencies being done */
>  #define MNT_DOOMED     0x08000000      /* device behind filesystem is
> gone */
> +#define MNT_LOG                0x10000000      /* use logging */
>
>  /*
>   * Flags for various system call interfaces.
> @@ -501,6 +507,51 @@
>  extern int bufbackoff(struct uvm_constraint_range*, long);
>
>  /*
> + * This operations vector is so wapbl can be wrapped into a filesystem
> lkm.
> + * XXX Eventually, we want to move this functionality
> + * down into the filesystems themselves so that this isn't needed.
> + */
> +struct wapbl_ops {
> +       void (*wo_wapbl_discard)(struct wapbl *);
> +       int (*wo_wapbl_replay_isopen)(struct wapbl_replay *);
> +       int (*wo_wapbl_replay_can_read)(struct wapbl_replay *, daddr_t,
> long);
> +       int (*wo_wapbl_replay_read)(struct wapbl_replay *, void *, daddr_t,
> +           long);
> +       void (*wo_wapbl_add_buf)(struct wapbl *, struct buf *);
> +       void (*wo_wapbl_remove_buf)(struct wapbl *, struct buf *);
> +       void (*wo_wapbl_resize_buf)(struct wapbl *, struct buf *, long,
> long);
> +       int (*wo_wapbl_begin)(struct wapbl *, const char *, int);
> +       void (*wo_wapbl_end)(struct wapbl *);
> +       void (*wo_wapbl_junlock_assert)(struct wapbl *);
> +       void (*wo_wapbl_biodone)(struct buf *);
> +};
> +#define WAPBL_DISCARD(MP)                                              \
> +    (*(MP)->mnt_wapbl_op->wo_wapbl_discard)((MP)->mnt_wapbl)
> +#define WAPBL_REPLAY_ISOPEN(MP)
> \
> +    (*(MP)->mnt_wapbl_op->wo_wapbl_replay_isopen)((MP)->mnt_wapbl_replay)
> +#define WAPBL_REPLAY_CAN_READ(MP, BLK, LEN)                            \
> +
> (*(MP)->mnt_wapbl_op->wo_wapbl_replay_can_read)((MP)->mnt_wapbl_replay, \
> +    (BLK), (LEN))
> +#define WAPBL_REPLAY_READ(MP, DATA, BLK, LEN)                          \
> +    (*(MP)->mnt_wapbl_op->wo_wapbl_replay_read)((MP)->mnt_wapbl_replay,
> \
> +    (DATA), (BLK), (LEN))
> +#define WAPBL_ADD_BUF(MP, BP)                                          \
> +    (*(MP)->mnt_wapbl_op->wo_wapbl_add_buf)((MP)->mnt_wapbl, (BP))
> +#define WAPBL_REMOVE_BUF(MP, BP)                                       \
> +    (*(MP)->mnt_wapbl_op->wo_wapbl_remove_buf)((MP)->mnt_wapbl, (BP))
> +#define WAPBL_RESIZE_BUF(MP, BP, OLDSZ, OLDCNT)
> \
> +    (*(MP)->mnt_wapbl_op->wo_wapbl_resize_buf)((MP)->mnt_wapbl, (BP),  \
> +    (OLDSZ), (OLDCNT))
> +#define WAPBL_BEGIN(MP)
> \
> +    (*(MP)->mnt_wapbl_op->wo_wapbl_begin)((MP)->mnt_wapbl,             \
> +    __FILE__, __LINE__)
> +#define WAPBL_END(MP)                                                  \
> +    (*(MP)->mnt_wapbl_op->wo_wapbl_end)((MP)->mnt_wapbl)
> +#define WAPBL_JUNLOCK_ASSERT(MP)                                       \
> +    (*(MP)->mnt_wapbl_op->wo_wapbl_junlock_assert)((MP)->mnt_wapbl)
> +
> +
> +/*
>   * Operations supported on mounted file system.
>   */
>  struct nameidata;
> Index: sys/sys/specdev.h
> ===================================================================
> RCS file: /Volumes/CSP/cvs/src/sys/sys/specdev.h,v
> retrieving revision 1.34
> diff -u -r1.34 specdev.h
> --- sys/sys/specdev.h   2 Nov 2013 00:16:31 -0000       1.34
> +++ sys/sys/specdev.h   23 Oct 2015 15:07:07 -0000
> @@ -37,6 +37,10 @@
>   * special devices. It is allocated in checkalias and freed
>   * in vgone.
>   */
> +
> +#ifndef _SYS_SPECDEV_H_
> +#define _SYS_SPECDEV_H_
> +
>  struct specinfo {
>         struct  vnode **si_hashchain;
>         struct  vnode *si_specnext;
> @@ -108,3 +112,4 @@
>  int    spec_advlock(void *);
>
>  #endif /* _KERNEL */
> +#endif  /* _SYS_SPECDEV_H_ */
> Index: sys/sys/stat.h
> ===================================================================
> RCS file: /Volumes/CSP/cvs/src/sys/sys/stat.h,v
> retrieving revision 1.28
> diff -u -r1.28 stat.h
> --- sys/sys/stat.h      4 Apr 2015 18:06:08 -0000       1.28
> +++ sys/sys/stat.h      23 Oct 2015 15:07:07 -0000
> @@ -173,6 +173,7 @@
>  #define        SF_ARCHIVED     0x00010000      /* file is archived */
>  #define        SF_IMMUTABLE    0x00020000      /* file may not be changed
> */
>  #define        SF_APPEND       0x00040000      /* writes to file may only
> append */
> +#define SF_LOG         0x00400000      /* WAPBL log file inode */
>
>  #ifdef _KERNEL
>  /*
> Index: sys/sys/vnode.h
> ===================================================================
> RCS file: /Volumes/CSP/cvs/src/sys/sys/vnode.h,v
> retrieving revision 1.132
> diff -u -r1.132 vnode.h
> --- sys/sys/vnode.h     7 May 2015 08:53:33 -0000       1.132
> +++ sys/sys/vnode.h     23 Oct 2015 15:07:07 -0000
> @@ -185,13 +185,14 @@
>  /*
>   * Flags for ioflag.
>   */
> -#define        IO_UNIT         0x01            /* do I/O as atomic unit */
> -#define        IO_APPEND       0x02            /* append write to end */
> -#define        IO_SYNC         0x04            /* do I/O synchronously */
> -#define        IO_NODELOCKED   0x08            /* underlying node already
> locked */
> -#define        IO_NDELAY       0x10            /* FNDELAY flag set in file
> table */
> -#define        IO_NOLIMIT      0x20            /* don't enforce limits on
> i/o
> */
> -#define        IO_NOCACHE      0x40            /* don't cache result of
> this
> i/o */
> +#define        IO_UNIT                 0x01    /* I/O as atomic unit */
> +#define        IO_APPEND               0x02    /* append write to end */
> +#define        IO_SYNC                 0x04    /* do I/O synchronously */
> +#define        IO_NODELOCKED           0x08    /* underlying node already
> locked */
> +#define        IO_NDELAY               0x10    /* FNDELAY flag set in file
> table */
> +#define        IO_NOLIMIT              0x20    /* don't enforce limits on
> i/o
> */
> +#define        IO_NOCACHE              0x40    /* don't cache result of
> this
> i/o */
> +#define IO_JOURNALLOCKED       0x80    /* journal is already locked */
>
>  /*
>   *  Modes.  Some values same as Ixxx entries from inode.h for now.
> @@ -596,6 +597,7 @@
>  void   vdevgone(int, int, int, enum vtype);
>  int    vcount(struct vnode *);
>  int    vfinddev(dev_t, enum vtype, struct vnode **);
> +int    vtruncbuf(struct vnode *, daddr_t, int, int);
>  void   vflushbuf(struct vnode *, int);
>  int    vflush(struct mount *, struct vnode *, int);
>  int    vget(struct vnode *, int, struct proc *);
> Index: sys/ufs/ffs/ffs_alloc.c
> ===================================================================
> RCS file: /Volumes/CSP/cvs/src/sys/ufs/ffs/ffs_alloc.c,v
> retrieving revision 1.105
> diff -u -r1.105 ffs_alloc.c
> --- sys/ufs/ffs/ffs_alloc.c     27 Sep 2015 05:25:00 -0000      1.105
> +++ sys/ufs/ffs/ffs_alloc.c     23 Oct 2015 15:07:07 -0000
> @@ -49,11 +49,13 @@
>  #include <sys/syslog.h>
>  #include <sys/stdint.h>
>  #include <sys/time.h>
> +#include <sys/wapbl.h>
>
>  #include <ufs/ufs/quota.h>
>  #include <ufs/ufs/inode.h>
>  #include <ufs/ufs/ufsmount.h>
>  #include <ufs/ufs/ufs_extern.h>
> +#include <ufs/ufs/ufs_wapbl.h>
>
>  #include <ufs/ffs/fs.h>
>  #include <ufs/ffs/ffs_extern.h>
> @@ -63,16 +65,19 @@
>             (fs)->fs_fsmnt, (cp));                              \
>  } while (0)
>
> -daddr_t                ffs_alloccg(struct inode *, int, daddr_t, int);
> -struct buf *   ffs_cgread(struct fs *, struct inode *, int);
> -daddr_t                ffs_alloccgblk(struct inode *, struct buf *,
> daddr_t);
> -daddr_t                ffs_clusteralloc(struct inode *, int, daddr_t,
> int);
> +daddr_t                ffs_alloccg(struct inode *, int, daddr_t, int,
> int);
> +struct buf *   ffs_cgread(struct fs *, struct vnode *, int);
> +daddr_t                ffs_alloccgblk(struct inode *, struct buf *,
> daddr_t,
> int);
> +daddr_t                ffs_clusteralloc(struct inode *, int, daddr_t, int,
> int);
>  ufsino_t       ffs_dirpref(struct inode *);
>  daddr_t                ffs_fragextend(struct inode *, int, daddr_t, int,
> int);
> -daddr_t                ffs_hashalloc(struct inode *, int, daddr_t, int,
> -                   daddr_t (*)(struct inode *, int, daddr_t, int));
> -daddr_t                ffs_nodealloccg(struct inode *, int, daddr_t, int);
> +daddr_t                ffs_hashalloc(struct inode *, int, daddr_t, int,
> int,
> +                    daddr_t (*)(struct inode *, int, daddr_t, int, int));
> +daddr_t                ffs_nodealloccg(struct inode *, int, daddr_t, int,
> int);
>  daddr_t                ffs_mapsearch(struct fs *, struct cg *, daddr_t,
> int);
> +void           ffs_blkfree_subr(struct fs *, struct vnode *,
> +                   struct inode *, daddr_t bno, long size);
> +
>
>  int ffs1_reallocblks(void *);
>  #ifdef FFS2
> @@ -106,7 +111,7 @@
>   *      available block is located.
>   */
>  int
> -ffs_alloc(struct inode *ip, daddr_t lbn, daddr_t bpref, int size,
> +ffs_alloc(struct inode *ip, daddr_t lbn, daddr_t bpref, int size, int
> flags,
>      struct ucred *cred, daddr_t *bnp)
>  {
>         static struct timeval fsfull_last;
> @@ -147,7 +152,7 @@
>                 cg = dtog(fs, bpref);
>
>         /* Try allocating a block. */
> -       bno = ffs_hashalloc(ip, cg, bpref, size, ffs_alloccg);
> +       bno = ffs_hashalloc(ip, cg, bpref, size, flags, ffs_alloccg);
>         if (bno > 0) {
>                 /* allocation successful, update inode data */
>                 DIP_ADD(ip, blocks, btodb(size));
> @@ -159,6 +164,12 @@
>         /* Restore user's disk quota because allocation failed. */
>         (void) ufs_quota_free_blocks(ip, btodb(size), cred);
>
> +       if (flags & B_CONTIG) {
> +               /*
> +                * Fail silently -- it's up to our caller to report errors.
> +                */
> +               return (ENOSPC);
> +       }
>  nospace:
>         if (ratecheck(&fsfull_last, &fserr_interval)) {
>                 ffs_fserr(fs, cred->cr_uid, "file system full");
> @@ -178,7 +189,7 @@
>   */
>  int
>  ffs_realloccg(struct inode *ip, daddr_t lbprev, daddr_t bpref, int osize,
> -    int nsize, struct ucred *cred, struct buf **bpp, daddr_t *blknop)
> +    int nsize, int flags, struct ucred *cred, struct buf **bpp, daddr_t
> *blknop)
>  {
>         static struct timeval fsfull_last;
>         struct fs *fs;
> @@ -218,7 +229,7 @@
>         if (bpp != NULL) {
>                 if ((error = bread(ITOV(ip), lbprev, fs->fs_bsize, &bp))
> != 0)
>                         goto error;
> -               bp->b_bcount = osize;
> +               buf_adjcnt(bp, osize);
>         }
>
>         if ((error = ufs_quota_alloc_blocks(ip, btodb(nsize - osize),
> cred))
> @@ -241,7 +252,7 @@
>                         if (nsize > bp->b_bufsize)
>                                 panic("ffs_realloccg: small buf");
>  #endif
> -                       bp->b_bcount = nsize;
> +                       buf_adjcnt(bp, nsize);
>                         bp->b_flags |= B_DONE;
>                         memset(bp->b_data + osize, 0, nsize - osize);
>                         *bpp = bp;
> @@ -295,16 +306,29 @@
>                 panic("ffs_realloccg: bad optim");
>                 /* NOTREACHED */
>         }
> -       bno = ffs_hashalloc(ip, cg, bpref, request, ffs_alloccg);
> +       bno = ffs_hashalloc(ip, cg, bpref, request, flags, ffs_alloccg);
>         if (bno <= 0)
>                 goto nospace;
>
>         (void) uvm_vnp_uncache(ITOV(ip));
> -       if (!DOINGSOFTDEP(ITOV(ip)))
> -               ffs_blkfree(ip, bprev, (long)osize);
> -       if (nsize < request)
> -               ffs_blkfree(ip, bno + numfrags(fs, nsize),
> -                   (long)(request - nsize));
> +       if (ip->i_ump->um_mountp->mnt_wapbl && ITOV(ip)->v_type != VREG) {
> +               UFS_WAPBL_REGISTER_DEALLOCATION(ip->i_ump->um_mountp,
> +                   fsbtodb(fs, bprev), osize);
> +       } else {
> +               if (!DOINGSOFTDEP(ITOV(ip)))
> +                       ffs_blkfree(ip, bprev, (long)osize);
> +       }
> +       if (nsize < request) {
> +               if (ip->i_ump->um_mountp->mnt_wapbl &&
> +                   ITOV(ip)->v_type != VREG) {
> +
>  UFS_WAPBL_REGISTER_DEALLOCATION(ip->i_ump->um_mountp,
> +                           fsbtodb(fs, (bno + numfrags(fs, nsize))),
> +                           request - nsize);
> +               } else {
> +                       ffs_blkfree(ip, bno + numfrags(fs, nsize),
> +                           (long)(request - nsize));
> +               }
> +       }
>         DIP_ADD(ip, blocks, btodb(nsize - osize));
>         ip->i_flag |= IN_CHANGE | IN_UPDATE;
>         if (bpp != NULL) {
> @@ -313,7 +337,7 @@
>                 if (nsize > bp->b_bufsize)
>                         panic("ffs_realloccg: small buf 2");
>  #endif
> -               bp->b_bcount = nsize;
> +               buf_adjcnt(bp, nsize);
>                 bp->b_flags |= B_DONE;
>                 memset(bp->b_data + osize, 0, nsize - osize);
>                 *bpp = bp;
> @@ -434,7 +458,7 @@
>         /*
>          * Find the preferred location for the cluster.
>          */
> -       pref = ffs1_blkpref(ip, start_lbn, soff, sbap);
> +       pref = ffs1_blkpref(ip, start_lbn, soff, 0, sbap);
>         /*
>          * If the block range spans two block maps, get the second map.
>          */
> @@ -454,7 +478,7 @@
>         /*
>          * Search the block map looking for an allocation of the desired
> size.
>          */
> -       if ((newblk = ffs_hashalloc(ip, dtog(fs, pref), pref, len,
> +       if ((newblk = ffs_hashalloc(ip, dtog(fs, pref), pref, len, 0,
>             ffs_clusteralloc)) == 0)
>                 goto fail;
>         /*
> @@ -538,10 +562,17 @@
>                 printf("\n\tnew:");
>  #endif
>         for (blkno = newblk, i = 0; i < len; i++, blkno += fs->fs_frag) {
> +               if (ip->i_ump->um_mountp->mnt_wapbl &&
> +                   ITOV(ip)->v_type != VREG) {
> +
>  UFS_WAPBL_REGISTER_DEALLOCATION(ip->i_ump->um_mountp,
> +                           dbtofsb(fs, buflist->bs_children[i]->b_blkno),
> +                           fs->fs_bsize);
> +               } else {
>                 if (!DOINGSOFTDEP(vp))
>                         ffs_blkfree(ip,
> -                           dbtofsb(fs, buflist->bs_children[i]->b_blkno),
> +                           buflist->bs_children[i]->b_blkno,
>                             fs->fs_bsize);
> +               }
>                 buflist->bs_children[i]->b_blkno = fsbtodb(fs, blkno);
>  #ifdef DIAGNOSTIC
>                 if (!ffs_checkblk(ip,
> @@ -660,13 +691,13 @@
>         /*
>          * Find the preferred location for the cluster.
>          */
> -       pref = ffs2_blkpref(ip, start_lbn, soff, sbap);
> +       pref = ffs2_blkpref(ip, start_lbn, soff, 0, sbap);
>
>         /*
>          * Search the block map looking for an allocation of the desired
> size.
>          */
>         if ((newblk = ffs_hashalloc(ip, dtog(fs, pref), pref,
> -           len, ffs_clusteralloc)) == 0)
> +           len, 0, ffs_clusteralloc)) == 0)
>                 goto fail;
>
>         /*
> @@ -753,9 +784,16 @@
>                 printf("\n\tnew:");
>  #endif
>         for (blkno = newblk, i = 0; i < len; i++, blkno += fs->fs_frag) {
> -               if (!DOINGSOFTDEP(vp))
> -                       ffs_blkfree(ip, dbtofsb(fs,
> -                           buflist->bs_children[i]->b_blkno),
> fs->fs_bsize);
> +               if (ip->i_ump->um_mountp->mnt_wapbl &&
> +                   ITOV(ip)->v_type != VREG) {
> +
>  UFS_WAPBL_REGISTER_DEALLOCATION(ip->i_ump->um_mountp,
> +                           buflist->bs_children[i]->b_blkno,
> fs->fs_bsize);
> +               } else {
> +                       if (!DOINGSOFTDEP(vp))
> +                               ffs_blkfree(ip, dbtofsb(fs,
> +                                   buflist->bs_children[i]->b_blkno),
> +                                   fs->fs_bsize);
> +               }
>                 buflist->bs_children[i]->b_blkno = fsbtodb(fs, blkno);
>  #ifdef DIAGNOSTIC
>                 if (!ffs_checkblk(ip,
> @@ -831,8 +869,15 @@
>         ufsino_t ino, ipref;
>         int cg, error;
>
> +       UFS_WAPBL_JUNLOCK_ASSERT(pvp->v_mount);
> +
>         *vpp = NULL;
>         fs = pip->i_fs;
> +
> +       error = UFS_WAPBL_BEGIN(pvp->v_mount);
> +       if (error)
> +           return error;
> +
>         if (fs->fs_cstotal.cs_nifree == 0)
>                 goto noinodes;
>
> @@ -855,12 +900,18 @@
>                 if (fs->fs_contigdirs[cg] > 0)
>                         fs->fs_contigdirs[cg]--;
>         }
> -       ino = (ufsino_t)ffs_hashalloc(pip, cg, ipref, mode,
> ffs_nodealloccg);
> +       ino = (ufsino_t)ffs_hashalloc(pip, cg, ipref, mode, 0,
> ffs_nodealloccg);
>         if (ino == 0)
>                 goto noinodes;
> +       UFS_WAPBL_END(pvp->v_mount);
>         error = VFS_VGET(pvp->v_mount, ino, vpp);
>         if (error) {
> -               ffs_inode_free(pip, ino, mode);
> +               int err;
> +               err = UFS_WAPBL_BEGIN(pvp->v_mount);
> +               if (err == 0) {
> +                       ffs_inode_free(pip, ino, mode);
> +                       UFS_WAPBL_END(pvp->v_mount);
> +               }
>                 return (error);
>         }
>
> @@ -896,6 +947,7 @@
>         return (0);
>
>  noinodes:
> +       UFS_WAPBL_END(pvp->v_mount);
>         if (ratecheck(&fsnoinodes_last, &fserr_interval)) {
>                 ffs_fserr(fs, cred->cr_uid, "out of inodes");
>                 uprintf("\n%s: create/symlink failed, no inodes free\n",
> @@ -1060,7 +1112,7 @@
>   * allocated.
>   */
>  int32_t
> -ffs1_blkpref(struct inode *ip, daddr_t lbn, int indx, int32_t *bap)
> +ffs1_blkpref(struct inode *ip, daddr_t lbn, int indx, int flags, int32_t
> *bap)
>  {
>         struct fs *fs;
>         int cg, inocg, avgbfree, startcg;
> @@ -1068,6 +1120,26 @@
>
>         KASSERT(indx <= 0 || bap != NULL);
>         fs = ip->i_fs;
> +
> +       /*
> +        * If allocating a contiguous file with B_CONTIG, use the hints
> +        * in the inode extentions to return the desired block.
> +        *
> +        * For metadata (indirect blocks) return the address of where
> +        * the first indirect block resides - we'll scan for the next
> +        * available slot if we need to allocate more than one indirect
> +        * block.  For data, return the address of the actual block
> +        * relative to the address of the first data block.
> +        */
> +       if (flags & B_CONTIG) {
> +               KASSERT(ip->i_ffs_first_data_blk != 0);
> +               KASSERT(ip->i_ffs_first_indir_blk != 0);
> +               if (flags & B_METAONLY)
> +                       return ip->i_ffs_first_indir_blk;
> +               else
> +                       return ip->i_ffs_first_data_blk + blkstofrags(fs,
> lbn);
> +       }
> +
>         /*
>          * Allocation of indirect blocks is indicated by passing negative
>          * values in indx: -1 for single indirect, -2 for double indirect,
> @@ -1160,7 +1232,7 @@
>   */
>  #ifdef FFS2
>  int64_t
> -ffs2_blkpref(struct inode *ip, daddr_t lbn, int indx, int64_t *bap)
> +ffs2_blkpref(struct inode *ip, daddr_t lbn, int indx, int flags, int64_t
> *bap)
>  {
>         struct fs *fs;
>         int cg, inocg, avgbfree, startcg;
> @@ -1168,6 +1240,26 @@
>
>         KASSERT(indx <= 0 || bap != NULL);
>         fs = ip->i_fs;
> +
> +       /*
> +        * If allocating a contiguous file with B_CONTIG, use the hints
> +        * in the inode extentions to return the desired block.
> +        *
> +        * For metadata (indirect blocks) return the address of where
> +        * the first indirect block resides - we'll scan for the next
> +        * available slot if we need to allocate more than one indirect
> +        * block.  For data, return the address of the actual block
> +        * relative to the address of the first data block.
> +        */
> +       if (flags & B_CONTIG) {
> +               KASSERT(ip->i_ffs_first_data_blk != 0);
> +               KASSERT(ip->i_ffs_first_indir_blk != 0);
> +               if (flags & B_METAONLY)
> +                       return ip->i_ffs_first_indir_blk;
> +               else
> +                       return ip->i_ffs_first_data_blk + blkstofrags(fs,
> lbn);
> +       }
> +
>         /*
>          * Allocation of indirect blocks is indicated by passing negative
>          * values in indx: -1 for single indirect, -2 for double indirect,
> @@ -1267,8 +1359,8 @@
>   *   3) brute force search for a free block.
>   */
>  daddr_t
> -ffs_hashalloc(struct inode *ip, int cg, daddr_t pref, int size,
> -    daddr_t (*allocator)(struct inode *, int, daddr_t, int))
> +ffs_hashalloc(struct inode *ip, int cg, daddr_t pref, int size, int flags,
> +    daddr_t (*allocator)(struct inode *, int, daddr_t, int, int))
>  {
>         struct fs *fs;
>         daddr_t result;
> @@ -1278,9 +1370,13 @@
>         /*
>          * 1: preferred cylinder group
>          */
> -       result = (*allocator)(ip, cg, pref, size);
> +       result = (*allocator)(ip, cg, pref, size, flags);
>         if (result)
>                 return (result);
> +
> +       if (flags & B_CONTIG)
> +               return (result);
> +
>         /*
>          * 2: quadratic rehash
>          */
> @@ -1288,7 +1384,7 @@
>                 cg += i;
>                 if (cg >= fs->fs_ncg)
>                         cg -= fs->fs_ncg;
> -               result = (*allocator)(ip, cg, 0, size);
> +               result = (*allocator)(ip, cg, 0, size, flags);
>                 if (result)
>                         return (result);
>         }
> @@ -1299,7 +1395,7 @@
>          */
>         cg = (icg + 2) % fs->fs_ncg;
>         for (i = 2; i < fs->fs_ncg; i++) {
> -               result = (*allocator)(ip, cg, 0, size);
> +               result = (*allocator)(ip, cg, 0, size, flags);
>                 if (result)
>                         return (result);
>                 cg++;
> @@ -1310,11 +1406,11 @@
>  }
>
>  struct buf *
> -ffs_cgread(struct fs *fs, struct inode *ip, int cg)
> +ffs_cgread(struct fs *fs, struct vnode *devvp, int cg)
>  {
>         struct buf *bp;
>
> -       if (bread(ip->i_devvp, fsbtodb(fs, cgtod(fs, cg)),
> +       if (bread(devvp, fsbtodb(fs, cgtod(fs, cg)),
>             (int)fs->fs_cgsize, &bp)) {
>                 brelse(bp);
>                 return (NULL);
> @@ -1353,7 +1449,7 @@
>                 return (0);
>         }
>
> -       if (!(bp = ffs_cgread(fs, ip, cg)))
> +       if (!(bp = ffs_cgread(fs, ip->i_devvp, cg)))
>                 return (0);
>
>         cgp = (struct cg *)bp->b_data;
> @@ -1398,7 +1494,7 @@
>   * and if it is, allocate it.
>   */
>  daddr_t
> -ffs_alloccg(struct inode *ip, int cg, daddr_t bpref, int size)
> +ffs_alloccg(struct inode *ip, int cg, daddr_t bpref, int size, int flags)
>  {
>         struct fs *fs;
>         struct cg *cgp;
> @@ -1410,7 +1506,7 @@
>         if (fs->fs_cs(fs, cg).cs_nbfree == 0 && size == fs->fs_bsize)
>                 return (0);
>
> -       if (!(bp = ffs_cgread(fs, ip, cg)))
> +       if (!(bp = ffs_cgread(fs, ip->i_devvp, cg)))
>                 return (0);
>
>         cgp = (struct cg *)bp->b_data;
> @@ -1423,7 +1519,7 @@
>
>         if (size == fs->fs_bsize) {
>                 /* allocate and return a complete data block */
> -               bno = ffs_alloccgblk(ip, bp, bpref);
> +               bno = ffs_alloccgblk(ip, bp, bpref, flags);
>                 bdwrite(bp);
>                 return (bno);
>         }
> @@ -1445,7 +1541,7 @@
>                         brelse(bp);
>                         return (0);
>                 }
> -               bno = ffs_alloccgblk(ip, bp, bpref);
> +               bno = ffs_alloccgblk(ip, bp, bpref, flags);
>                 bpref = dtogd(fs, bno);
>                 for (i = frags; i < fs->fs_frag; i++)
>                         setbit(cg_blksfree(cgp), bpref + i);
> @@ -1487,7 +1583,7 @@
>   * blocks may be fragmented by the routine that allocates them.
>   */
>  daddr_t
> -ffs_alloccgblk(struct inode *ip, struct buf *bp, daddr_t bpref)
> +ffs_alloccgblk(struct inode *ip, struct buf *bp, daddr_t bpref, int flags)
>  {
>         struct fs *fs;
>         struct cg *cgp;
> @@ -1515,6 +1611,12 @@
>         if (ffs_isblock(fs, blksfree, fragstoblks(fs, bno)))
>                 goto gotit;
>         /*
> +        * if the requested data block isn't available and we are trying to
> +        * allocate a contiguous file,  return an error.
> +        */
> +       if ((flags & (B_CONTIG | B_METAONLY)) == B_CONTIG)
> +               return (0);
> +       /*
>          * Take the next available block in this cylinder group.
>          */
>         bno = ffs_mapsearch(fs, cgp, bpref, (int) fs->fs_frag);
> @@ -1556,7 +1658,7 @@
>   * take the first one that we find following bpref.
>   */
>  daddr_t
> -ffs_clusteralloc(struct inode *ip, int cg, daddr_t bpref, int len)
> +ffs_clusteralloc(struct inode *ip, int cg, daddr_t bpref, int len, int
> flags)
>  {
>         struct fs *fs;
>         struct cg *cgp;
> @@ -1569,7 +1671,7 @@
>         if (fs->fs_maxcluster[cg] < len)
>                 return (0);
>
> -       if (!(bp = ffs_cgread(fs, ip, cg)))
> +       if (!(bp = ffs_cgread(fs, ip->i_devvp, cg)))
>                 return (0);
>
>         cgp = (struct cg *)bp->b_data;
> @@ -1651,7 +1753,7 @@
>
>         len = blkstofrags(fs, len);
>         for (i = 0; i < len; i += fs->fs_frag)
> -               if (ffs_alloccgblk(ip, bp, bno + i) != bno + i)
> +               if (ffs_alloccgblk(ip, bp, bno + i, flags) != bno + i)
>                         panic("ffs_clusteralloc: lost block");
>         bdwrite(bp);
>         return (bno);
> @@ -1663,7 +1765,7 @@
>
>  /* inode allocation routine */
>  daddr_t
> -ffs_nodealloccg(struct inode *ip, int cg, daddr_t ipref, int mode)
> +ffs_nodealloccg(struct inode *ip, int cg, daddr_t ipref, int mode, int
> flags)
>  {
>         struct fs *fs;
>         struct cg *cgp;
> @@ -1680,10 +1782,11 @@
>          * and in the cylinder group itself.
>          */
>         fs = ip->i_fs;
> +       UFS_WAPBL_JLOCK_ASSERT(ip->i_ump->um_mountp);
>         if (fs->fs_cs(fs, cg).cs_nifree == 0)
>                 return (0);
>
> -       if (!(bp = ffs_cgread(fs, ip, cg)))
> +       if (!(bp = ffs_cgread(fs, ip->i_devvp, cg)))
>                 return (0);
>
>         cgp = (struct cg *)bp->b_data;
> @@ -1758,6 +1861,9 @@
>
>  gotit:
>
> +       UFS_WAPBL_REGISTER_INODE(ip->i_ump->um_mountp, cg * fs->fs_ipg +
> ipref,
> +           mode);
> +
>  #ifdef FFS2
>         /*
>          * For FFS2, check if all inodes in this cylinder group have been
> used
> @@ -1819,6 +1925,119 @@
>  }
>
>  /*
> + * Allocate a block or fragment.
> + *
> + * The specified block or fragment is removed from the
> + * free map, possibly fragmenting a block in the process.
> + *
> + * This implementation should mirror fs_blkfree
> + */
> +int
> +ffs_blkalloc_ump(struct ufsmount *ump, daddr_t bno, long size)
> +{
> +       struct fs *fs = ump->um_fs;
> +       struct cg *cgp;
> +       struct buf *bp;
> +       int32_t fragno, cgbno;
> +       int i, error, cg, blk, frags, bbase;
> +       u_int8_t *blksfree;
> +
> +       KASSERT((u_int)size <= fs->fs_bsize && fragoff(fs, size) == 0 &&
> +           fragnum(fs, bno) + numfrags(fs, size) <= fs->fs_frag);
> +       KASSERT(bno < fs->fs_size);
> +
> +       cg = dtog(fs, bno);
> +       error = bread(ump->um_devvp, fsbtodb(fs, cgtod(fs, cg)),
> +               (int)fs->fs_cgsize, &bp);
> +       if (error) {
> +               brelse(bp);
> +               return error;
> +       }
> +       cgp = (struct cg *)bp->b_data;
> +       if (!cg_chkmagic(cgp)) {
> +               brelse(bp);
> +               return EIO;
> +       }
> +       cgp->cg_ffs2_time = time_second;
> +       cgp->cg_time = (int32_t)cgp->cg_ffs2_time;
> +       cgbno = dtogd(fs, bno);
> +       blksfree = cg_blksfree(cgp);
> +
> +       if (size == fs->fs_bsize) {
> +               fragno = fragstoblks(fs, cgbno);
> +               if (!ffs_isblock(fs, blksfree, fragno)) {
> +                       brelse(bp);
> +                       return EBUSY;
> +               }
> +               ffs_clrblock(fs, blksfree, fragno);
> +               ffs_clusteracct(fs, cgp, fragno, -1);
> +               cgp->cg_cs.cs_nbfree--;
> +               fs->fs_cstotal.cs_nbfree--;
> +               fs->fs_cs(fs, cg).cs_nbfree--;
> +       } else {
> +               bbase = cgbno - fragnum(fs, cgbno);
> +
> +               frags = numfrags(fs, size);
> +               for (i = 0; i < frags; i++) {
> +                       if (isclr(blksfree, cgbno + i)) {
> +                               brelse(bp);
> +                               return EBUSY;
> +                       }
> +               }
> +               /*
> +                * if a complete block is being split, account for it
> +                */
> +               fragno = fragstoblks(fs, bbase);
> +               if (ffs_isblock(fs, blksfree, fragno)) {
> +                       cgp->cg_cs.cs_nffree += fs->fs_frag;
> +                       fs->fs_cstotal.cs_nffree += fs->fs_frag;
> +                       fs->fs_cs(fs, cg).cs_nffree += fs->fs_frag;
> +                       ffs_clusteracct(fs, cgp, fragno, -1);
> +                       cgp->cg_cs.cs_nbfree--;
> +                       fs->fs_cstotal.cs_nbfree--;
> +                       fs->fs_cs(fs, cg).cs_nbfree--;
> +               }
> +               /*
> +                * decrement the counts associated with the old frags
> +                */
> +               blk = blkmap(fs, blksfree, bbase);
> +               ffs_fragacct(fs, blk, cgp->cg_frsum, -1);
> +               /*
> +                * allocate the fragment
> +                */
> +               for (i = 0; i < frags; i++) {
> +                       clrbit(blksfree, cgbno + i);
> +               }
> +               cgp->cg_cs.cs_nffree -= i;
> +               fs->fs_cstotal.cs_nffree -= i;
> +               fs->fs_cs(fs, cg).cs_nffree -= i;
> +               /*
> +                * add back in counts associated with the new frags
> +                */
> +               blk = blkmap(fs, blksfree, bbase);
> +               ffs_fragacct(fs, blk, cgp->cg_frsum, 1);
> +       }
> +       fs->fs_fmod = 1;
> +       bdwrite(bp);
> +       return 0;
> +}
> +
> +#ifdef WAPBL
> +void
> +ffs_wapbl_blkfree(struct fs *fs, struct vnode *devvp, daddr_t bno,
> +    long size)
> +{
> +       ffs_blkfree_subr(fs, devvp, NULL, bno, size);
> +}
> +#endif /* WAPBL */
> +
> +void
> +ffs_blkfree(struct inode *ip, daddr_t bno, long size)
> +{
> +       ffs_blkfree_subr(NULL, NULL, ip, bno, size);
> +}
> +
> +/*
>   * Free a block or fragment.
>   *
>   * The specified block or fragment is placed back in the
> @@ -1826,29 +2045,44 @@
>   * block reassembly is checked.
>   */
>  void
> -ffs_blkfree(struct inode *ip, daddr_t bno, long size)
> +ffs_blkfree_subr(struct fs *fs, struct vnode *devvp, struct inode *ip,
> +    daddr_t bno, long size)
>  {
> -       struct fs *fs;
>         struct cg *cgp;
>         struct buf *bp;
>         daddr_t blkno;
>         int i, cg, blk, frags, bbase;
>
> -       fs = ip->i_fs;
> +       KASSERT((fs != NULL && devvp != NULL) ^ (ip != NULL));
> +
> +       if (fs == NULL) {
> +               fs = ip->i_fs;
> +               devvp = ip->i_devvp;
> +       }
> +
>         if ((u_int)size > fs->fs_bsize || fragoff(fs, size) != 0 ||
>             fragnum(fs, bno) + numfrags(fs, size) > fs->fs_frag) {
> -               printf("dev = 0x%x, bsize = %d, size = %ld, fs = %s\n",
> -                   ip->i_dev, fs->fs_bsize, size, fs->fs_fsmnt);
> +               if (ip == NULL)
> +                       printf("bsize = %d, size = %ld, fs = %s\n",
> +                           fs->fs_bsize, size, fs->fs_fsmnt);
> +               else
> +                       printf("dev = 0x%x, bsize = %d, size = %ld, fs =
> %s\n",
> +                           ip->i_dev, fs->fs_bsize, size, fs->fs_fsmnt);
>                 panic("ffs_blkfree: bad size");
>         }
>         cg = dtog(fs, bno);
>         if ((u_int)bno >= fs->fs_size) {
> -               printf("bad block %lld, ino %u\n", (long long)bno,
> -                   ip->i_number);
> -               ffs_fserr(fs, DIP(ip, uid), "bad block");
> +               if (ip == NULL) {
> +                       printf("bad block %lld\n", (long long)bno);
> +                       ffs_fserr(fs, 0, "bad block");
> +               } else {
> +                       printf("bad block %lld, ino %u\n", (long long)bno,
> +                           ip->i_number);
> +                       ffs_fserr(fs, DIP(ip, uid), "bad block");
> +               }
>                 return;
>         }
> -       if (!(bp = ffs_cgread(fs, ip, cg)))
> +       if (!(bp = ffs_cgread(fs, devvp, cg)))
>                 return;
>
>         cgp = (struct cg *)bp->b_data;
> @@ -1858,8 +2092,12 @@
>         if (size == fs->fs_bsize) {
>                 blkno = fragstoblks(fs, bno);
>                 if (!ffs_isfreeblock(fs, cg_blksfree(cgp), blkno)) {
> -                       printf("dev = 0x%x, block = %lld, fs = %s\n",
> -                           ip->i_dev, (long long)bno, fs->fs_fsmnt);
> +                       if (ip == NULL)
> +                               printf("block = %lld, fs = %s\n",
> +                                   (long long)bno, fs->fs_fsmnt);
> +                       else
> +                               printf("dev = 0x%x, block = %lld, fs =
> %s\n",
> +                                   ip->i_dev, (long long)bno,
> fs->fs_fsmnt);
>                         panic("ffs_blkfree: freeing free block");
>                 }
>                 ffs_setblock(fs, cg_blksfree(cgp), blkno);
> @@ -1887,9 +2125,13 @@
>                 frags = numfrags(fs, size);
>                 for (i = 0; i < frags; i++) {
>                         if (isset(cg_blksfree(cgp), bno + i)) {
> -                               printf("dev = 0x%x, block = %lld, fs =
> %s\n",
> -                                   ip->i_dev, (long long)(bno + i),
> -                                   fs->fs_fsmnt);
> +                               if (ip == NULL)
> +                                       printf("block = %lld, fs = %s\n",
> +                                           (long long)(bno + i),
> fs->fs_fsmnt);
> +                               else
> +                                       printf("dev = 0x%x, block = %lld, "
> +                                           "fs = %s\n", ip->i_dev,
> +                                           (long long)(bno + i),
> fs->fs_fsmnt);
>                                 panic("ffs_blkfree: freeing free frag");
>                         }
>                         setbit(cg_blksfree(cgp), bno + i);
> @@ -1957,7 +2199,7 @@
>                     pip->i_dev, ino, fs->fs_fsmnt);
>
>         cg = ino_to_cg(fs, ino);
> -       if (!(bp = ffs_cgread(fs, pip, cg)))
> +       if (!(bp = ffs_cgread(fs, pip->i_devvp, cg)))
>                 return (0);
>
>         cgp = (struct cg *)bp->b_data;
> @@ -1971,6 +2213,8 @@
>                         panic("ffs_freefile: freeing free inode");
>         }
>         clrbit(cg_inosused(cgp), ino);
> +       UFS_WAPBL_UNREGISTER_INODE(pip->i_ump->um_mountp,
> +           ino + cg * fs->fs_ipg, mode);
>         if (ino < cgp->cg_irotor)
>                 cgp->cg_irotor = ino;
>         cgp->cg_cs.cs_nifree++;
> @@ -2008,7 +2252,7 @@
>         if ((u_int)bno >= fs->fs_size)
>                 panic("ffs_checkblk: bad block %lld", (long long)bno);
>
> -       if (!(bp = ffs_cgread(fs, ip, dtog(fs, bno))))
> +       if (!(bp = ffs_cgread(fs, ip->i_devvp, dtog(fs, bno))))
>                 return (0);
>
>         cgp = (struct cg *)bp->b_data;
> Index: sys/ufs/ffs/ffs_balloc.c
> ===================================================================
> RCS file: /Volumes/CSP/cvs/src/sys/ufs/ffs/ffs_balloc.c,v
> retrieving revision 1.43
> diff -u -r1.43 ffs_balloc.c
> --- sys/ufs/ffs/ffs_balloc.c    14 Mar 2015 03:38:52 -0000      1.43
> +++ sys/ufs/ffs/ffs_balloc.c    23 Oct 2015 15:07:07 -0000
> @@ -103,8 +103,9 @@
>                 osize = blksize(fs, ip, nb);
>                 if (osize < fs->fs_bsize && osize > 0) {
>                         error = ffs_realloccg(ip, nb,
> -                           ffs1_blkpref(ip, nb, (int)nb,
> &ip->i_ffs1_db[0]),
> -                           osize, (int)fs->fs_bsize, cred, bpp, &newb);
> +                           ffs1_blkpref(ip, nb, (int)nb, flags,
> +                           &ip->i_ffs1_db[0]), osize, (int)fs->fs_bsize,
> +                           flags, cred, bpp, &newb);
>                         if (error)
>                                 return (error);
>                         if (DOINGSOFTDEP(vp))
> @@ -165,7 +166,7 @@
>                                                 brelse(*bpp);
>                                                 return (error);
>                                         }
> -                                       (*bpp)->b_bcount = osize;
> +                                       buf_adjcnt((*bpp), osize);
>                                 }
>                                 return (0);
>                         } else {
> @@ -174,9 +175,9 @@
>                                  * want, grow it.
>                                  */
>                                 error = ffs_realloccg(ip, lbn,
> -                                   ffs1_blkpref(ip, lbn, (int)lbn,
> +                                   ffs1_blkpref(ip, lbn, (int)lbn, flags,
>                                         &ip->i_ffs1_db[0]),
> -                                   osize, nsize, cred, bpp, &newb);
> +                                   osize, nsize, flags, cred, bpp, &newb);
>                                 if (error)
>                                         return (error);
>                                 if (DOINGSOFTDEP(vp))
> @@ -195,8 +196,8 @@
>                         else
>                                 nsize = fs->fs_bsize;
>                         error = ffs_alloc(ip, lbn,
> -                           ffs1_blkpref(ip, lbn, (int)lbn,
> &ip->i_ffs1_db[0]),
> -                           nsize, cred, &newb);
> +                           ffs1_blkpref(ip, lbn, (int)lbn, flags,
> +                           &ip->i_ffs1_db[0]), nsize, flags, cred, &newb);
>                         if (error)
>                                 return (error);
>                         if (bpp != NULL) {
> @@ -235,9 +236,10 @@
>         allocib = NULL;
>         allocblk = allociblk;
>         if (nb == 0) {
> -               pref = ffs1_blkpref(ip, lbn, -indirs[0].in_off - 1, NULL);
> +               pref = ffs1_blkpref(ip, lbn, -indirs[0].in_off - 1,
> +                   flags | B_METAONLY, NULL);
>                 error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize,
> -                                 cred, &newb);
> +                   flags | B_METAONLY, cred, &newb);
>                 if (error)
>                         goto fail;
>                 nb = newb;
> @@ -283,9 +285,10 @@
>                         continue;
>                 }
>                 if (pref == 0)
> -                       pref = ffs1_blkpref(ip, lbn, i - num - 1, NULL);
> -               error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, cred,
> -                                 &newb);
> +                       pref = ffs1_blkpref(ip, lbn, i - num - 1,
> +                           flags | B_METAONLY, NULL);
> +               error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize,
> +                   flags | B_METAONLY, cred, &newb);
>                 if (error) {
>                         brelse(bp);
>                         goto fail;
> @@ -323,13 +326,20 @@
>                         bdwrite(bp);
>                 }
>         }
> +
> +       if (flags & B_METAONLY) {
> +               KASSERT(bpp != NULL);
> +               *bpp = bp;
> +               return (0);
> +       }
> +
>         /*
>          * Get the data block, allocating if necessary.
>          */
>         if (nb == 0) {
> -               pref = ffs1_blkpref(ip, lbn, indirs[i].in_off, &bap[0]);
> -               error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, cred,
> -                                 &newb);
> +               pref = ffs1_blkpref(ip, lbn, indirs[i].in_off, flags,
> &bap[0]);
> +               error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, flags,
> +                   cred, &newb);
>                 if (error) {
>                         brelse(bp);
>                         goto fail;
> @@ -468,8 +478,8 @@
>                 osize = blksize(fs, ip, nb);
>                 if (osize < fs->fs_bsize && osize > 0) {
>                         error = ffs_realloccg(ip, nb, ffs2_blkpref(ip,
> -                           lastlbn, nb, &ip->i_ffs2_db[0]), osize,
> -                           (int) fs->fs_bsize, cred, bpp, &newb);
> +                           lastlbn, nb, flags, &ip->i_ffs2_db[0]), osize,
> +                           (int) fs->fs_bsize, flags, cred, bpp, &newb);
>                         if (error)
>                                 return (error);
>
> @@ -535,7 +545,7 @@
>                                                 brelse(*bpp);
>                                                 return (error);
>                                         }
> -                                       (*bpp)->b_bcount = osize;
> +                                       buf_adjcnt((*bpp), osize);
>                                 }
>
>                                 return (0);
> @@ -545,9 +555,9 @@
>                                  * grow it.
>                                  */
>                                 error = ffs_realloccg(ip, lbn,
> -                                   ffs2_blkpref(ip, lbn, (int) lbn,
> -                                   &ip->i_ffs2_db[0]), osize, nsize, cred,
> -                                   bpp, &newb);
> +                                   ffs2_blkpref(ip, lbn, (int) lbn, flags,
> +                                   &ip->i_ffs2_db[0]), osize, nsize,
> flags,
> +                                   cred, bpp, &newb);
>                                 if (error)
>                                         return (error);
>
> @@ -567,7 +577,8 @@
>                                 nsize = fs->fs_bsize;
>
>                         error = ffs_alloc(ip, lbn, ffs2_blkpref(ip, lbn,
> -                           (int) lbn, &ip->i_ffs2_db[0]), nsize, cred,
> &newb);
> +                           (int) lbn, flags, &ip->i_ffs2_db[0]), nsize,
> flags,
> +                           cred, &newb);
>                         if (error)
>                                 return (error);
>
> @@ -614,9 +625,10 @@
>         allocblk = allociblk;
>
>         if (nb == 0) {
> -               pref = ffs2_blkpref(ip, lbn, -indirs[0].in_off - 1, NULL);
> -               error = ffs_alloc(ip, lbn, pref, (int) fs->fs_bsize, cred,
> -                   &newb);
> +               pref = ffs2_blkpref(ip, lbn, -indirs[0].in_off - 1,
> +                   flags | B_METAONLY, NULL);
> +               error = ffs_alloc(ip, lbn, pref, (int) fs->fs_bsize,
> +                   flags | B_METAONLY, cred, &newb);
>                 if (error)
>                         goto fail;
>
> @@ -670,10 +682,11 @@
>                 }
>
>                 if (pref == 0)
> -                       pref = ffs2_blkpref(ip, lbn, i - num - 1, NULL);
> +                       pref = ffs2_blkpref(ip, lbn, i - num - 1,
> +                           flags | B_METAONLY, NULL);
>
> -               error = ffs_alloc(ip, lbn, pref, (int) fs->fs_bsize, cred,
> -                   &newb);
> +               error = ffs_alloc(ip, lbn, pref, (int) fs->fs_bsize,
> +                   flags | B_METAONLY, cred, &newb);
>                 if (error) {
>                         brelse(bp);
>                         goto fail;
> @@ -716,14 +729,21 @@
>                         bdwrite(bp);
>         }
>
> +       if (flags & B_METAONLY) {
> +               KASSERT(bpp != NULL);
> +               *bpp = bp;
> +               return (0);
> +       }
> +
>         /*
>          * Get the data block, allocating if necessary.
>          */
>         if (nb == 0) {
> -               pref = ffs2_blkpref(ip, lbn, indirs[num].in_off, &bap[0]);
> +               pref = ffs2_blkpref(ip, lbn, indirs[num].in_off, flags,
> +                   &bap[0]);
>
> -               error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, cred,
> -                   &newb);
> +               error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, flags,
> +                   cred, &newb);
>                 if (error) {
>                         brelse(bp);
>                         goto fail;
> Index: sys/ufs/ffs/ffs_extern.h
> ===================================================================
> RCS file: /Volumes/CSP/cvs/src/sys/ufs/ffs/ffs_extern.h,v
> retrieving revision 1.40
> diff -u -r1.40 ffs_extern.h
> --- sys/ufs/ffs/ffs_extern.h    25 Jan 2014 23:31:12 -0000      1.40
> +++ sys/ufs/ffs/ffs_extern.h    23 Oct 2015 15:07:07 -0000
> @@ -99,19 +99,20 @@
>  extern struct vops     ffs_fifovops;
>
>  /* ffs_alloc.c */
> -int ffs_alloc(struct inode *, daddr_t, daddr_t , int, struct ucred *,
> -                  daddr_t *);
> -int ffs_realloccg(struct inode *, daddr_t, daddr_t, int, int ,
> -                      struct ucred *, struct buf **, daddr_t *);
> +int ffs_alloc(struct inode *, daddr_t, daddr_t , int, int, struct ucred *,
> +           daddr_t *);
> +int ffs_realloccg(struct inode *, daddr_t, daddr_t, int, int, int,
> +           struct ucred *, struct buf **, daddr_t *);
>  int ffs_reallocblks(void *);
>  int ffs_inode_alloc(struct inode *, mode_t, struct ucred *, struct vnode
> **);
>  int ffs_inode_free(struct inode *, ufsino_t, mode_t);
>  int ffs_freefile(struct inode *, ufsino_t, mode_t);
>
> -int32_t ffs1_blkpref(struct inode *, daddr_t, int, int32_t *);
> +int32_t ffs1_blkpref(struct inode *, daddr_t, int, int, int32_t *);
>  #ifdef FFS2
> -int64_t ffs2_blkpref(struct inode *, daddr_t, int, int64_t *);
> +int64_t ffs2_blkpref(struct inode *, daddr_t, int, int, int64_t *);
>  #endif
> +int ffs_blkalloc_ump(struct ufsmount *, daddr_t, long);
>  void ffs_blkfree(struct inode *, daddr_t, long);
>  void ffs_clusteracct(struct fs *, struct cg *, daddr_t, int);
>
> @@ -160,6 +161,18 @@
>  int ffs_reclaim(void *);
>  int ffsfifo_reclaim(void *);
>
> +/* ffs_wapbl.c -- write ahead physical block logging */
> +void    ffs_wapbl_verify_inodes(struct mount *, const char *);
> +void    ffs_wapbl_replay_finish(struct mount *);
> +int     ffs_wapbl_start(struct mount *);
> +int     ffs_wapbl_stop(struct mount *, int);
> +int     ffs_wapbl_replay_start(struct mount *, struct fs *, struct vnode
> *);
> +void    ffs_wapbl_blkalloc(struct fs *, struct vnode *, daddr_t, int);
> +
> +void    ffs_wapbl_sync_metadata(struct mount *, daddr_t *, int *, int);
> +void    ffs_wapbl_abort_sync_metadata(struct mount *, daddr_t *, int *,
> int);
> +void    ffs_wapbl_blkfree(struct fs *, struct vnode *, daddr_t, long);
> +
>  /*
>   * Soft dependency function prototypes.
>   */
> Index: sys/ufs/ffs/ffs_inode.c
> ===================================================================
> RCS file: /Volumes/CSP/cvs/src/sys/ufs/ffs/ffs_inode.c,v
> retrieving revision 1.74
> diff -u -r1.74 ffs_inode.c
> --- sys/ufs/ffs/ffs_inode.c     14 Mar 2015 03:38:52 -0000      1.74
> +++ sys/ufs/ffs/ffs_inode.c     23 Oct 2015 15:07:07 -0000
> @@ -41,11 +41,13 @@
>  #include <sys/kernel.h>
>  #include <sys/malloc.h>
>  #include <sys/resourcevar.h>
> +#include <sys/wapbl.h>
>
>  #include <ufs/ufs/quota.h>
>  #include <ufs/ufs/inode.h>
>  #include <ufs/ufs/ufsmount.h>
>  #include <ufs/ufs/ufs_extern.h>
> +#include <ufs/ufs/ufs_wapbl.h>
>
>  #include <ufs/ffs/fs.h>
>  #include <ufs/ffs/ffs_extern.h>
> @@ -95,6 +97,16 @@
>                 return (error);
>         }
>
> +       if (DIP(ip, mode)) {
> +               if (DIP(ip, nlink) > 0) {
> +                       UFS_WAPBL_UNREGISTER_INODE(ip->i_ump->um_mountp,
> +                           ip->i_number, DIP(ip, mode));
> +               } else {
> +                       UFS_WAPBL_REGISTER_INODE(ip->i_ump->um_mountp,
> +                           ip->i_number, DIP(ip, mode));
> +               }
> +       }
> +
>         if (DOINGSOFTDEP(vp))
>                 softdep_update_inodeblock(ip, bp, waitfor);
>         else if (ip->i_effnlink != DIP(ip, nlink))
> @@ -135,7 +147,7 @@
>         struct fs *fs;
>         struct buf *bp;
>         int offset, size, level;
> -       long count, nblocks, vflags, blocksreleased = 0;
> +       long count, nblocks, blocksreleased = 0;
>         int i, aflags, error, allerror;
>         off_t osize;
>
> @@ -262,7 +274,7 @@
>                 (void) uvm_vnp_uncache(ovp);
>                 if (ovp->v_type != VDIR)
>                         memset(bp->b_data + offset, 0, size - offset);
> -               bp->b_bcount = size;
> +               buf_adjcnt(bp, size);
>                 if (aflags & B_SYNC)
>                         bwrite(bp);
>                 else
> @@ -321,8 +333,7 @@
>         }
>
>         DIP_ASSIGN(oip, size, osize);
> -       vflags = ((length > 0) ? V_SAVE : 0) | V_SAVEMETA;
> -       allerror = vinvalbuf(ovp, vflags, cred, curproc, 0, 0);
> +       allerror = vtruncbuf(ovp, lastblock + 1, 0, 0);
>
>         /*
>          * Indirect blocks first.
> @@ -340,7 +351,12 @@
>                         blocksreleased += count;
>                         if (lastiblock[level] < 0) {
>                                 DIP_ASSIGN(oip, ib[level], 0);
> -                               ffs_blkfree(oip, bn, fs->fs_bsize);
> +                               if (oip->i_ump->um_mountp->mnt_wapbl) {
> +                                       UFS_WAPBL_REGISTER_DEALLOCATION(
> +                                           oip->i_ump->um_mountp,
> +                                           fsbtodb(fs, bn), fs->fs_bsize);
> +                               } else
> +                                       ffs_blkfree(oip, bn, fs->fs_bsize);
>                                 blocksreleased += nblocks;
>                         }
>                 }
> @@ -360,7 +376,12 @@
>
>                 DIP_ASSIGN(oip, db[i], 0);
>                 bsize = blksize(fs, oip, i);
> -               ffs_blkfree(oip, bn, bsize);
> +               if ((oip->i_ump->um_mountp->mnt_wapbl) &&
> +                   (ovp->v_type != VREG)) {
> +
>  UFS_WAPBL_REGISTER_DEALLOCATION(oip->i_ump->um_mountp,
> +                           fsbtodb(fs, bn), bsize);
> +               } else
> +                       ffs_blkfree(oip, bn, bsize);
>                 blocksreleased += btodb(bsize);
>         }
>         if (lastblock < 0)
> @@ -390,7 +411,13 @@
>                          * required for the storage we're keeping.
>                          */
>                         bn += numfrags(fs, newspace);
> -                       ffs_blkfree(oip, bn, oldspace - newspace);
> +                       if ((oip->i_ump->um_mountp->mnt_wapbl) &&
> +                           (ovp->v_type != VREG)) {
> +                               UFS_WAPBL_REGISTER_DEALLOCATION(
> +                                   oip->i_ump->um_mountp, fsbtodb(fs, bn),
> +                                   oldspace - newspace);
> +                       } else
> +                               ffs_blkfree(oip, bn, oldspace - newspace);
>                         blocksreleased += btodb(oldspace - newspace);
>                 }
>         }
> @@ -412,6 +439,7 @@
>         else    /* sanity */
>                 DIP_ASSIGN(oip, blocks, 0);
>         oip->i_flag |= IN_CHANGE;
> +       UFS_WAPBL_UPDATE(oip, 0);
>         (void)ufs_quota_free_blocks(oip, blocksreleased, NOCRED);
>         return (allerror);
>  }
> @@ -541,7 +569,12 @@
>                                 allerror = error;
>                         blocksreleased += blkcount;
>                 }
> -               ffs_blkfree(ip, nb, fs->fs_bsize);
> +               if (ip->i_ump->um_mountp->mnt_wapbl &&
> +                   ((level > SINGLE) || ITOV(ip)->v_type != VREG)) {
> +
>  UFS_WAPBL_REGISTER_DEALLOCATION(ip->i_ump->um_mountp,
> +                           fsbtodb(fs, nb), fs->fs_bsize);
> +               } else
> +                       ffs_blkfree(ip, nb, fs->fs_bsize);
>                 blocksreleased += nblocks;
>         }
>
> Index: sys/ufs/ffs/ffs_subr.c
> ===================================================================
> RCS file: /Volumes/CSP/cvs/src/sys/ufs/ffs/ffs_subr.c,v
> retrieving revision 1.29
> diff -u -r1.29 ffs_subr.c
> --- sys/ufs/ffs/ffs_subr.c      2 Nov 2013 00:08:17 -0000       1.29
> +++ sys/ufs/ffs/ffs_subr.c      23 Oct 2015 15:07:07 -0000
> @@ -72,7 +72,7 @@
>                 brelse(bp);
>                 return (error);
>         }
> -       bp->b_bcount = bsize;
> +       buf_adjcnt(bp, bsize);
>         if (res)
>                 *res = (char *)bp->b_data + blkoff(fs, offset);
>         *bpp = bp;
> Index: sys/ufs/ffs/ffs_vfsops.c
> ===================================================================
> RCS file: /Volumes/CSP/cvs/src/sys/ufs/ffs/ffs_vfsops.c,v
> retrieving revision 1.149
> diff -u -r1.149 ffs_vfsops.c
> --- sys/ufs/ffs/ffs_vfsops.c    14 Mar 2015 03:38:52 -0000      1.149
> +++ sys/ufs/ffs/ffs_vfsops.c    23 Oct 2015 15:07:07 -0000
> @@ -50,7 +50,7 @@
>  #include <sys/pool.h>
>  #include <sys/dkio.h>
>  #include <sys/disk.h>
> -#include <sys/specdev.h>
> +#include <sys/wapbl.h>
>
>  #include <ufs/ufs/quota.h>
>  #include <ufs/ufs/ufsmount.h>
> @@ -58,6 +58,7 @@
>  #include <ufs/ufs/dir.h>
>  #include <ufs/ufs/ufs_extern.h>
>  #include <ufs/ufs/dirhash.h>
> +#include <ufs/ufs/ufs_wapbl.h>
>
>  #include <ufs/ffs/fs.h>
>  #include <ufs/ffs/ffs_extern.h>
> @@ -178,6 +179,15 @@
>         if (error)
>                 return (error);
>
> +#ifdef WAPBL
> +       /* WAPBL can only be enabled on a r/w mount. */
> +       if ((mp->mnt_flag & MNT_RDONLY) && !(mp->mnt_flag & MNT_WANTRDWR))
> {
> +               mp->mnt_flag &= ~MNT_LOG;
> +       }
> +#else /* !WAPBL */
> +       mp->mnt_flag &= ~MNT_LOG;
> +#endif /* !WAPBL */
> +
>  #ifndef FFS_SOFTUPDATES
>         if (mp->mnt_flag & MNT_SOFTDEP) {
>                 printf("WARNING: soft updates isn't compiled in\n");
> @@ -194,6 +204,16 @@
>             (MNT_SOFTDEP | MNT_ASYNC)) {
>                 return (EINVAL);
>         }
> +
> +#ifdef WAPBL
> +       /*
> +        * Likewise, WAPBL is incompatible with MNT_ASYNC and MNT_SOFTDEP.
> +        */
> +       if (mp->mnt_flag & MNT_LOG)
> +               if (mp->mnt_flag & (MNT_ASYNC|MNT_SOFTDEP))
> +                       return (EINVAL);
> +#endif /* WAPBL */
> +
>         /*
>          * If updating, check whether changing from read-only to
>          * read/write; if there is no device name, that's all we do.
> @@ -220,11 +240,30 @@
>                         if (fs->fs_flags & FS_DOSOFTDEP) {
>                                 error = softdep_flushfiles(mp, flags, p);
>                                 mp->mnt_flag &= ~MNT_SOFTDEP;
> -                       } else
> +                       } else {
>                                 error = ffs_flushfiles(mp, flags, p);
> +                               if (error == 0)
> +                                       error = UFS_WAPBL_BEGIN(mp);
> +                               if (error == 0 &&
> +                                   ffs_cgupdate(ump, MNT_WAIT) == 0 &&
> +                                   fs->fs_clean & FS_WASCLEAN) {
> +                                       fs->fs_clean = FS_ISCLEAN;
> +                                       (void) ffs_sbupdate(ump, MNT_WAIT);
> +                               }
> +                               if (error == 0)
> +                                       UFS_WAPBL_END(mp);
> +                       }
>                         ronly = 1;
>                 }
>
> +#ifdef WAPBL
> +               if (error == 0 && (mp->mnt_flag & MNT_LOG) == 0) {
> +                       error = ffs_wapbl_stop(mp, mp->mnt_flag &
> MNT_FORCE);
> +                       if (error)
> +                               return (error);
> +               }
> +#endif /* WAPBL */
> +
>                 /*
>                  * Flush soft dependencies if disabling it via an update
>                  * mount. This may leave some items to be processed,
> @@ -277,6 +316,31 @@
>                                         goto error_1;
>                         }
>
> +                       fs->fs_contigdirs = malloc((u_long)fs->fs_ncg,
> +                           M_UFSMNT, M_WAITOK|M_ZERO);
> +
> +#ifdef WAPBL
> +                       if (mp->mnt_flag & MNT_LOG) {
> +                               fs->fs_ronly = 0;
> +                               fs->fs_fmod = 1;
> +                       }
> +
> +                       if (fs->fs_flags & FS_DOWAPBL) {
> +                               printf("%s: replaying log to disk\n",
> +                                   mp->mnt_stat.f_mntonname);
> +                               KASSERT(mp->mnt_wapbl_replay);
> +                               error =
> wapbl_replay_write(mp->mnt_wapbl_replay,
> +                                   devvp);
> +                               if (error) {
> +                                       free(fs->fs_contigdirs, M_UFSMNT,
> 0);
> +                                       return (error);
> +                               }
> +                               wapbl_replay_stop(mp->mnt_wapbl_replay);
> +                               fs->fs_clean = FS_WASCLEAN;
> +                               goto logok;
> +                       }
> +#endif /* WAPBL */
> +
>                         if (fs->fs_clean == 0) {
>  #if 0
>                                 /*
> @@ -313,8 +377,18 @@
>                         fs->fs_contigdirs = malloc((u_long)fs->fs_ncg,
>                              M_UFSMNT, M_WAITOK|M_ZERO);
>
> +#ifdef WAPBL
> +logok:
> +#endif /* WAPBL */
>                         ronly = 0;
>                 }
> +
> +#ifdef WAPBL
> +               error = ffs_wapbl_start(mp);
> +               if (error)
> +                       return error;
> +#endif /* WAPBL */
> +
>                 if (args.fspec == NULL) {
>                         /*
>                          * Process export requests.
> @@ -323,8 +397,12 @@
>                             &args.export_info);
>                         if (error)
>                                 goto error_1;
> -                       else
> +                       else {
> +                               error = UFS_WAPBL_BEGIN(mp);
> +                               if (error)
> +                                       goto error_1;
>                                 goto success;
> +                       }
>                 }
>         }
>
> @@ -417,6 +495,10 @@
>         if (error)
>                 goto error_2;
>
> +       error = UFS_WAPBL_BEGIN(mp);
> +       if (error)
> +               goto error_2;
> +
>         /*
>          * Initialize FS stat information in mount struct; uses both
>          * mp->mnt_stat.f_mntonname and mp->mnt_stat.f_mntfromname
> @@ -445,6 +527,7 @@
>                 }
>                 ffs_sbupdate(ump, MNT_WAIT);
>         }
> +       UFS_WAPBL_END(mp);
>         return (0);
>
>  error_2:       /* error with devvp held */
> @@ -693,6 +776,10 @@
>         bp = NULL;
>         ump = NULL;
>
> +#ifdef WAPBL
> +sbagain:
> +#endif /* WAPBL */
> +
>         /*
>          * Try reading the super-block in each of its possible locations.
>          */
> @@ -735,6 +822,43 @@
>                 goto out;
>         }
>
> +#ifdef WAPBL
> +       if ((mp->mnt_wapbl_replay == 0) && (fs->fs_flags & FS_DOWAPBL)) {
> +               error = ffs_wapbl_replay_start(mp, fs, devvp);
> +               if (error && (mp->mnt_flag & MNT_FORCE) == 0)
> +                       goto out;
> +               if (!error) {
> +                       if (!ronly) {
> +                               /* XXX fsmnt may be stale. */
> +                               printf("%s: replaying log to disk\n",
> +                                   fs->fs_fsmnt);
> +                               error =
> wapbl_replay_write(mp->mnt_wapbl_replay,
> +                                   devvp);
> +                               if (error)
> +                                       goto out;
> +                               wapbl_replay_stop(mp->mnt_wapbl_replay);
> +                               fs->fs_clean = FS_WASCLEAN;
> +                       } else {
> +                               /* XXX fsmnt may be stale */
> +                               printf("%s: replaying log to memory\n",
> +                                   fs->fs_fsmnt);
> +                       }
> +
> +                       /* Force a re-read of the superblock */
> +                       bp->b_flags |= B_INVAL;
> +                       brelse(bp);
> +                       bp = NULL;
> +                       fs = NULL;
> +                       goto sbagain;
> +               }
> +       }
> +#else /* !WAPBL */
> +       if ((fs->fs_flags & FS_DOWAPBL) && (mp->mnt_flag & MNT_FORCE) ==
> 0) {
> +               error = EPERM;
> +               goto out;
> +       }
> +#endif /* !WAPBL */
> +
>         fs->fs_fmod = 0;
>         fs->fs_flags &= ~FS_UNCLEAN;
>         if (fs->fs_clean == 0) {
> @@ -793,6 +917,13 @@
>
>         ffs1_compat_read(fs, ump, sbloc);
>
> +       /* Don't bump fs_clean if we're replaying journal */
> +       if (!((fs->fs_flags & FS_DOWAPBL) && (fs->fs_clean & FS_WASCLEAN)))
> +               if (ronly == 0) {
> +                       fs->fs_clean <<= 1;
> +                       fs->fs_fmod = 1;
> +               }
> +
>         if (fs->fs_clean == 0)
>                 fs->fs_flags |= FS_UNCLEAN;
>         fs->fs_ronly = ronly;
> @@ -879,6 +1010,38 @@
>         if (fs->fs_maxfilesize > maxfilesize)                   /* XXX */
>                 fs->fs_maxfilesize = maxfilesize;               /* XXX */
>         if (ronly == 0) {
> +#ifdef WAPBL
> +               KASSERT(fs->fs_ronly == 0);
> +               /*
> +                * verify that we can access the last block in the fs if
> we're
> +                * mounting read/write.
> +                */
> +               error = bread(devvp, fsbtodb(fs, fs->fs_size - 1),
> +                   fs->fs_fsize, &bp);
> +               if (bp->b_bcount != fs->fs_fsize)
> +                       error = EINVAL;
> +               bp->b_flags |= B_INVAL;
> +               if (error) {
> +                       free(fs->fs_csp, M_UFSMNT, 0);
> +                       free(fs->fs_contigdirs, M_UFSMNT, 0);
> +                       goto out;
> +               }
> +               brelse(bp);
> +               bp = NULL;
> +               /*
> +                * ffs_wapbl_start() needs mp->mnt_stat initialised if it
> +                * needs to create a new log file in-filesystem.
> +                */
> +               ffs_statfs(mp, &mp->mnt_stat, curproc);
> +
> +               error = ffs_wapbl_start(mp);
> +               if (error) {
> +                       free(fs->fs_csp, M_UFSMNT, 0);
> +                       free(fs->fs_contigdirs, M_UFSMNT, 0);
> +                       goto out;
> +               }
> +#endif /* WAPBL */
> +
>                 if ((fs->fs_flags & FS_DOSOFTDEP) &&
>                     (error = softdep_mount(devvp, mp, fs, cred)) != 0) {
>                         free(fs->fs_csp, M_UFSMNT, 0);
> @@ -891,12 +1054,30 @@
>                         fs->fs_flags |= FS_DOSOFTDEP;
>                 else
>                         fs->fs_flags &= ~FS_DOSOFTDEP;
> +               error = UFS_WAPBL_BEGIN(mp);
> +               if (error) {
> +                       free(fs->fs_csp, M_UFSMNT, 0);
> +                       free(fs->fs_contigdirs, M_UFSMNT, 0);
> +                       goto out;
> +               }
>                 error = ffs_sbupdate(ump, MNT_WAIT);
> -               if (error == EROFS)
> +               UFS_WAPBL_END(mp);
> +               if (error == EROFS) {
> +                       free(fs->fs_csp, M_UFSMNT, 0);
> +                       free(fs->fs_contigdirs, M_UFSMNT, 0);
>                         goto out;
> +               }
>         }
>         return (0);
>  out:
> +#ifdef WAPBL
> +       if (mp->mnt_wapbl_replay) {
> +               wapbl_replay_stop(mp->mnt_wapbl_replay);
> +               wapbl_replay_free(mp->mnt_wapbl_replay);
> +               mp->mnt_wapbl_replay = NULL;
> +       }
> +#endif /* WAPBL */
> +
>         devvp->v_specmountpoint = NULL;
>         if (bp)
>                 brelse(bp);
> @@ -994,7 +1175,10 @@
>         struct ufsmount *ump;
>         struct fs *fs;
>         int error, flags;
> -
> +#ifdef WAPBL
> +       extern int doforce;
> +#endif /* WAPBL */
> +
>         flags = 0;
>         if (mntflags & MNT_FORCE)
>                 flags |= FORCECLOSE;
> @@ -1007,6 +1191,9 @@
>                 error = ffs_flushfiles(mp, flags, p);
>         if (error != 0)
>                 return (error);
> +       error = UFS_WAPBL_BEGIN(mp);
> +       if (error)
> +               goto logfail;
>
>         if (fs->fs_ronly == 0) {
>                 fs->fs_clean = (fs->fs_flags & FS_UNCLEAN) ? 0 : 1;
> @@ -1018,6 +1205,21 @@
>                 }
>                 free(fs->fs_contigdirs, M_UFSMNT, 0);
>         }
> +       UFS_WAPBL_END(mp);
> +logfail:
> +#ifdef WAPBL
> +       KASSERT(!(mp->mnt_wapbl_replay && mp->mnt_wapbl));
> +       if (mp->mnt_wapbl_replay) {
> +               KASSERT(fs->fs_ronly);
> +               wapbl_replay_stop(mp->mnt_wapbl_replay);
> +               wapbl_replay_free(mp->mnt_wapbl_replay);
> +               mp->mnt_wapbl_replay = NULL;
> +       }
> +       error = ffs_wapbl_stop(mp, doforce && (mntflags & MNT_FORCE));
> +       if (error) {
> +               return error;
> +       }
> +#endif /* WAPBL */
>         ump->um_devvp->v_specmountpoint = NULL;
>
>         vn_lock(ump->um_devvp, LK_EXCLUSIVE | LK_RETRY, p);
> @@ -1069,6 +1271,17 @@
>         vn_lock(ump->um_devvp, LK_EXCLUSIVE | LK_RETRY, p);
>         error = VOP_FSYNC(ump->um_devvp, p->p_ucred, MNT_WAIT, p);
>         VOP_UNLOCK(ump->um_devvp, 0, p);
> +
> +#ifdef WAPBL
> +       if (error)
> +               return error;
> +       if (mp->mnt_wapbl) {
> +               error = wapbl_flush(mp->mnt_wapbl, 1);
> +               if (flags & FORCECLOSE)
> +                       error = 0;
> +       }
> +#endif
> +
>         return (error);
>  }
>
> @@ -1202,9 +1415,26 @@
>          * Write back modified superblock.
>          */
>
> -       if (fs->fs_fmod != 0 && (error = ffs_sbupdate(ump, waitfor)) != 0)
> -               allerror = error;
> +       if (fs->fs_fmod != 0) {
> +               error = UFS_WAPBL_BEGIN(mp);
> +               if (error)
> +                       allerror = error;
> +               else {
> +                       error = ffs_cgupdate(ump, waitfor);
> +                       if (error)
> +                               allerror = error;
> +                       UFS_WAPBL_END(mp);
> +               }
> +       }
>
> +#ifdef WAPBL
> +       if (mp->mnt_wapbl) {
> +               error = wapbl_flush(mp->mnt_wapbl, waitfor != MNT_NOWAIT);
> +               if (error)
> +                       allerror = error;
> +       }
> +#endif /* WAPBL */
> +
>         return (allerror);
>  }
>
> @@ -1466,6 +1696,42 @@
>  }
>
>  int
> +ffs_cgupdate(struct ufsmount *mp, int waitfor)
> +{
> +       struct fs *fs = mp->um_fs;
> +       struct buf *bp;
> +       int blks;
> +       void *space;
> +       int i, size, error = 0, allerror = 0;
> +
> +       allerror = ffs_sbupdate(mp, waitfor);
> +       blks = howmany(fs->fs_cssize, fs->fs_fsize);
> +       space = fs->fs_csp;
> +       for (i = 0; i < blks; i += fs->fs_frag) {
> +               size = fs->fs_bsize;
> +               if (i + fs->fs_frag > blks)
> +                       size = (blks - i) * fs->fs_fsize;
> +               bp = getblk(mp->um_devvp, fsbtodb(fs, fs->fs_csaddr + i),
> size,
> +                   0, 0);
> +#ifdef FFS_EI
> +               if (mp->um_flags & UFS_NEEDSWAP)
> +                       ffs_csum_swap((struct csum*)space,
> +                           (struct csum*)bp->b_data, size);
> +               else
> +#endif
> +                       memcpy(bp->b_data, space, (u_int)size);
> +               space = (char *)space + size;
> +               if (waitfor == MNT_WAIT)
> +                       error = bwrite(bp);
> +               else
> +                       bawrite(bp);
> +       }
> +       if (!allerror && error)
> +               allerror = error;
> +       return (allerror);
> +}
> +
> +int
>  ffs_init(struct vfsconf *vfsp)
>  {
>         static int done;
> Index: sys/ufs/ffs/ffs_vnops.c
> ===================================================================
> RCS file: /Volumes/CSP/cvs/src/sys/ufs/ffs/ffs_vnops.c,v
> retrieving revision 1.80
> diff -u -r1.80 ffs_vnops.c
> --- sys/ufs/ffs/ffs_vnops.c     14 Mar 2015 03:38:52 -0000      1.80
> +++ sys/ufs/ffs/ffs_vnops.c     23 Oct 2015 15:07:07 -0000
> @@ -45,7 +45,7 @@
>  #include <sys/signalvar.h>
>  #include <sys/pool.h>
>  #include <sys/event.h>
> -#include <sys/specdev.h>
> +#include <sys/wapbl.h>
>
>  #include <miscfs/fifofs/fifo.h>
>
> @@ -54,6 +54,7 @@
>  #include <ufs/ufs/dir.h>
>  #include <ufs/ufs/ufs_extern.h>
>  #include <ufs/ufs/ufsmount.h>
> +#include <ufs/ufs/ufs_wapbl.h>
>
>  #include <ufs/ffs/fs.h>
>  #include <ufs/ffs/ffs_extern.h>
> @@ -274,6 +275,13 @@
>         if (!(vp->v_mount->mnt_flag & MNT_NOATIME) ||
>             (ip->i_flag & (IN_CHANGE | IN_UPDATE))) {
>                 ip->i_flag |= IN_ACCESS;
> +               if ((ap->a_ioflag & IO_SYNC) == IO_SYNC) {
> +                       error = UFS_WAPBL_BEGIN(vp->v_mount);
> +                       if (error)
> +                               return (error);
> +                       error = UFS_UPDATE(ip, MNT_WAIT);
> +                       UFS_WAPBL_END(vp->v_mount);
> +               }
>         }
>         return (error);
>  }
> @@ -343,6 +351,12 @@
>         osize = DIP(ip, size);
>         flags = ioflag & IO_SYNC ? B_SYNC : 0;
>
> +       if ((ioflag & IO_JOURNALLOCKED) == 0) {
> +               error = UFS_WAPBL_BEGIN(vp->v_mount);
> +               if (error)
> +                       return (error);
> +       }
> +
>         for (error = 0; uio->uio_resid > 0;) {
>                 lbn = lblkno(fs, uio->uio_offset);
>                 blkoffset = blkoff(fs, uio->uio_offset);
> @@ -410,12 +424,232 @@
>                 }
>         } else if (resid > uio->uio_resid && (ioflag & IO_SYNC)) {
>                 error = UFS_UPDATE(ip, 1);
> -       }
> +       } else
> +               UFS_WAPBL_UPDATE(ip, 0);
> +       if ((ioflag & IO_JOURNALLOCKED) == 0)
> +               UFS_WAPBL_END(vp->v_mount);
>         /* correct the result for writes clamped by vn_fsizechk() */
>         uio->uio_resid += overrun;
>         return (error);
>  }
>
> +#ifdef WAPBL
> +int ffs_wapbl_fsync_full(void *);
> +int ffs_wapbl_fsync(void *);
> +int ffs_wapbl_fsync_vfs(struct vnode *, int);
> +int ffs_wapbl_fsync_device(void *);
> +
> +int
> +ffs_wapbl_fsync_full(void *v)
> +{
> +       struct vop_fsync_args *ap = v;
> +       struct vnode *vp = ap->a_vp;
> +       struct inode *ip = VTOI(vp);
> +       struct mount *mp = vp->v_mount;
> +       int waitfor = ap->a_waitfor;
> +       int s, error = 0;
> +
> +       KASSERT(vp->v_type != VREG);
> +       KASSERT(mp->mnt_wapbl != NULL);
> +
> +#ifdef DIAGNOSTIC
> +       s = splbio();
> +       struct buf *bp, *nbp;
> +       for (bp = LIST_FIRST(&vp->v_dirtyblkhd);
> +           bp != LIST_END(&vp->v_dirtyblkhd); bp = nbp) {
> +               nbp = LIST_NEXT(bp, b_vnbufs);
> +               if ((bp->b_flags & B_LOCKED) == 0)
> +                       panic("ffs_wapbl_fsync_full: non-WAPBL buffer %p "
> +                           "on vnode %p", bp, vp);
> +       }
> +       splx(s);
> +#endif
> +
> +       /*
> +        * Don't bother writing out metadata if the syncer is making the
> +        * request. We will let the sync vnode write it out in a single
> burst
> +        * through a call to VFS_SYNC().
> +        */
> +       if (waitfor == MNT_LAZY)
> +               return (0);
> +
> +       if ((ip->i_flag &
> +           (IN_ACCESS | IN_CHANGE | IN_UPDATE | IN_MODIFIED)) != 0) {
> +               error = UFS_WAPBL_BEGIN(mp);
> +               if (error)
> +                       return (error);
> +               error = UFS_UPDATE(ip, waitfor == MNT_WAIT);
> +               UFS_WAPBL_END(mp);
> +               if (error)
> +                       return (error);
> +       }
> +
> +       /*
> +        * Don't flush the log if the vnode being flushed contains no dirty
> +        * buffers that could be in the log.
> +        */
> +       s = splbio();
> +       if (!LIST_EMPTY(&vp->v_dirtyblkhd)) {
> +               splx(s);
> +               error = wapbl_flush(mp->mnt_wapbl, 0);
> +               if (error)
> +                       return (error);
> +               s = splbio();
> +       }
> +
> +       if (waitfor == MNT_WAIT)
> +               error = vwaitforio(vp, 0, "wapblfsy", 0);
> +
> +       splx(s);
> +
> +       return (error);
> +}
> +
> +int
> +ffs_wapbl_fsync(void *v)
> +{
> +       struct vop_fsync_args *ap = v;
> +       struct vnode *vp = ap->a_vp;
> +       struct inode *ip = VTOI(vp);
> +       struct mount *mp = vp->v_mount;
> +       struct buf *bp, *nbp;
> +       int waitfor = ap->a_waitfor;
> +       int s, error;
> +
> +       KASSERT(vp->v_type == VREG);
> +       KASSERT(mp->mnt_wapbl != NULL);
> +
> +       /*
> +        * Flush all data blocks.
> +        */
> +loop:
> +       s = splbio();
> +       for (bp = LIST_FIRST(&vp->v_dirtyblkhd);
> +           bp != LIST_END(&vp->v_dirtyblkhd); bp = nbp) {
> +               nbp = LIST_NEXT(bp, b_vnbufs);
> +               if ((bp->b_flags & B_BUSY) || bp->b_lblkno < 0)
> +                       continue;
> +#ifdef DIAGNOSTIC
> +               if ((bp->b_flags & B_DELWRI) == 0)
> +                       panic("ffs_wapbl_fsync: not dirty");
> +#endif
> +               bremfree(bp);
> +               buf_acquire(bp);
> +               splx(s);
> +               bawrite(bp);
> +               goto loop;
> +       }
> +
> +       if (waitfor == MNT_WAIT) {
> +               error = vwaitforio(vp, 0, "wapblsy", 0);
> +               if (error) {
> +                       splx(s);
> +                       return (error);
> +               }
> +       }
> +
> +       splx(s);
> +
> +       /*
> +        * Don't bother writing out metadata if the syncer is making the
> +        * request. We will let the sync vnode write it out in a single
> burst
> +        * through a call to VFS_SYNC().
> +        */
> +       if (waitfor == MNT_LAZY)
> +               return (0);
> +
> +       if ((ip->i_flag &
> +           (IN_ACCESS | IN_CHANGE | IN_UPDATE | IN_MODIFIED)) != 0) {
> +               error = UFS_WAPBL_BEGIN(mp);
> +               if (error)
> +                       return (error);
> +               error = UFS_UPDATE(ip, waitfor == MNT_WAIT);
> +               UFS_WAPBL_END(mp);
> +               if (error)
> +                       return (error);
> +       }
> +
> +       return (wapbl_flush(mp->mnt_wapbl, 0));
> +}
> +
> +/*
> + * Synch vnode for a mounted file system.
> + */
> +int
> +ffs_wapbl_fsync_vfs(struct vnode *vp, int waitfor)
> +{
> +       int s, error = 0;
> +
> +       KASSERT(vp->v_type == VBLK);
> +       KASSERT(vp->v_specmountpoint != NULL);
> +       KASSERT(vp->v_specmountpoint->mnt_wapbl != NULL);
> +
> +#ifdef DIAGNOSTIC
> +       s = splbio();
> +
> +       struct buf *bp, *nbp;
> +       for (bp = LIST_FIRST(&vp->v_dirtyblkhd);
> +           bp != LIST_END(&vp->v_dirtyblkhd); bp = nbp) {
> +               nbp = LIST_NEXT(bp, b_vnbufs);
> +               if ((bp->b_flags & B_LOCKED) == 0)
> +                       panic("ffs_wapbl_fsync_vfs: non-WAPBL buffer %p "
> +                           "on vnode %p", bp, vp);
> +       }
> +       splx(s);
> +#endif
> +
> +       /*
> +        * Don't bother writing out metadata if the syncer is making the
> +        * request. We will let the sync vnode write it out in a single
> burst
> +        * through a call to VFS_SYNC().
> +        */
> +       if (waitfor == MNT_LAZY)
> +               return (0);
> +
> +       /*
> +        * Don't flush the log if the vnode being flushed contains no dirty
> +        * buffers that could be in the log.
> +        */
> +       s = splbio();
> +       if (!LIST_EMPTY(&vp->v_dirtyblkhd)) {
> +               struct mount *mp = vp->v_specmountpoint;
> +               splx(s);
> +               error = wapbl_flush(mp->mnt_wapbl, 0);
> +               if (error)
> +                       return (error);
> +               s = splbio();
> +       }
> +
> +       if (waitfor == MNT_WAIT)
> +               error = vwaitforio(vp, 0, "wapblvfs", 0);
> +
> +       splx(s);
> +
> +       return (error);
> +}
> +
> +int
> +ffs_wapbl_fsync_device(void *v)
> +{
> +       struct vop_fsync_args *ap = v;
> +       struct vnode *vp = ap->a_vp;
> +
> +       KASSERT(vp->v_mount != NULL && vp->v_mount->mnt_wapbl != NULL);
> +
> +       if (vp->v_type == VCHR)
> +               return (0);
> +
> +       /* Are we mounted somewhere with WAPBL? */
> +       if (vp->v_specmountpoint != NULL &&
> +           vp->v_specmountpoint->mnt_wapbl != NULL)
> +               return (ffs_wapbl_fsync_vfs(vp, ap->a_waitfor));
> +
> +       vflushbuf(vp, ap->a_waitfor == MNT_WAIT);
> +
> +       return (0);
> +}
> +#endif /* WAPBL */
> +
>  /*
>   * Synch an open file.
>   */
> @@ -427,6 +661,21 @@
>         struct buf *bp, *nbp;
>         int s, error, passes, skipmeta;
>
> +#if WAPBL
> +       if (vp->v_mount && vp->v_mount->mnt_wapbl) {
> +               if (vn_isdisk(vp, NULL))
> +                       return (ffs_wapbl_fsync_device(ap));
> +               if (vp->v_type != VREG)
> +                       return (ffs_wapbl_fsync_full(ap));
> +               return (ffs_wapbl_fsync(ap));
> +       }
> +
> +       if (vp->v_type == VBLK &&
> +           vp->v_specmountpoint != NULL &&
> +           vp->v_specmountpoint->mnt_wapbl != NULL)
> +               return (ffs_wapbl_fsync_vfs(vp, ap->a_waitfor));
> +#endif /* WAPBL */
> +
>         if (vp->v_type == VBLK &&
>             vp->v_specmountpoint != NULL &&
>             (vp->v_specmountpoint->mnt_flag & MNT_SOFTDEP))
> @@ -523,6 +772,7 @@
>                 }
>         }
>         splx(s);
> +
>         return (UFS_UPDATE(VTOI(vp), ap->a_waitfor == MNT_WAIT));
>  }
>
> Index: sys/ufs/ffs/fs.h
> ===================================================================
> RCS file: /Volumes/CSP/cvs/src/sys/ufs/ffs/fs.h,v
> retrieving revision 1.41
> diff -u -r1.41 fs.h
> --- sys/ufs/ffs/fs.h    20 Jan 2015 18:08:16 -0000      1.41
> +++ sys/ufs/ffs/fs.h    23 Oct 2015 15:07:07 -0000
> @@ -270,7 +270,12 @@
>         int32_t  fs_cpc;                /* cyl per cycle in postbl */
>  /* this area is only allocated if fs_ffs1_flags & FS_FLAGS_UPDATED */
>         int32_t  fs_maxbsize;           /* maximum blocking factor
> permitted */
> -       int64_t  fs_spareconf64[17];    /* old rotation block list head */
> +       uint8_t  fs_journal_version;    /* journal forma version */
> +       uint8_t  fs_journal_location;   /* journal location type */
> +       uint8_t  fs_journal_reserved[2];/* reserver for future */
> +       uint32_t fs_journal_flags;      /* journal flags */
> +       uint64_t fs_journallocs[4];     /* location info for journal */
> +       int64_t  fs_spareconf64[12];    /* old rotation block list head */
>         int64_t  fs_sblockloc;          /* offset of standard super block
> */
>         struct  csum_total fs_cstotal;  /* cylinder summary information */
>         int64_t  fs_time;               /* time last written */
> @@ -329,6 +334,7 @@
>   */
>  #define FS_UNCLEAN     0x01    /* filesystem not clean at mount */
>  #define FS_DOSOFTDEP   0x02    /* filesystem using soft dependencies */
> +#define FS_DOWAPBL     0x04    /* write-ahead physical block logging */
>  /*
>   * The following flag is used to detect a FFS1 file system that had its
> flags
>   * moved to the new (FFS2) location for compatibility.
> @@ -518,6 +524,8 @@
>         ((loc) & (fs)->fs_qbmask)
>  #define fragoff(fs, loc)       /* calculates (loc % fs->fs_fsize) */ \
>         ((loc) & (fs)->fs_qfmask)
> +#define        lfragtosize(fs, frag)   /* calculates ((off_t)frag *
> fs->fs_fsize) */ \
> +       (((off_t)(frag)) << (fs)->fs_fshift)
>  #define lblktosize(fs, blk)    /* calculates ((off_t)blk * fs->fs_bsize)
> */ \
>         ((off_t)(blk) << (fs)->fs_bshift)
>  #define lblkno(fs, loc)                /* calculates (loc / fs->fs_bsize)
> */ \
> Index: sys/ufs/ufs/inode.h
> ===================================================================
> RCS file: /Volumes/CSP/cvs/src/sys/ufs/ufs/inode.h,v
> retrieving revision 1.49
> diff -u -r1.49 inode.h
> --- sys/ufs/ufs/inode.h 14 Jul 2014 08:54:13 -0000      1.49
> +++ sys/ufs/ufs/inode.h 23 Oct 2015 15:07:07 -0000
> @@ -48,6 +48,13 @@
>  /*
>   * Per-filesystem inode extensions.
>   */
> +struct ffs_inode_ext {
> +       daddr_t *ffs_snapblklist;       /* Collect expunged snapshot
> blocks. */
> +       /* follow two fields are used by contiguous allocation code only.
> */
> +       daddr_t ffs_first_data_blk;     /* first data block on disk. */
> +       daddr_t ffs_first_indir_blk;    /* first indirect block on disk. */
> +};
> +
>  struct ext2fs_inode_ext {
>         u_int32_t       ext2fs_last_lblk;       /* last logical blk
> allocated */
>         u_int32_t       ext2fs_last_blk;        /* last blk allocated on
> disk */
> @@ -102,10 +109,13 @@
>          */
>         union {
>                 /* Other extensions could go here... */
> +               struct ffs_inode_ext ffs;
>                 struct ext2fs_inode_ext   e2fs;
>                 struct dirhash *dirhash;
>         } inode_ext;
>
> +#define i_ffs_first_data_blk   inode_ext.ffs.ffs_first_data_blk
> +#define i_ffs_first_indir_blk  inode_ext.ffs.ffs_first_indir_blk
>  #define i_e2fs_last_lblk       inode_ext.e2fs.ext2fs_last_lblk
>  #define i_e2fs_last_blk                inode_ext.e2fs.ext2fs_last_blk
>  #define i_e2fs_uid             inode_ext.e2fs.ext2fs_effective_uid
> Index: sys/ufs/ufs/ufs_extern.h
> ===================================================================
> RCS file: /Volumes/CSP/cvs/src/sys/ufs/ufs/ufs_extern.h,v
> retrieving revision 1.35
> diff -u -r1.35 ufs_extern.h
> --- sys/ufs/ufs/ufs_extern.h    25 Jan 2014 23:31:13 -0000      1.35
> +++ sys/ufs/ufs/ufs_extern.h    23 Oct 2015 15:07:07 -0000
> @@ -134,7 +134,7 @@
>  void ufs_itimes(struct vnode *);
>  int ufs_makeinode(int, struct vnode *, struct vnode **,
>                   struct componentname *);
> -
> +int ufs_gop_alloc(struct vnode *, off_t, off_t, int, struct ucred *);
>
>  /*
>   * Soft dependency function prototypes.
> Index: sys/ufs/ufs/ufs_inode.c
> ===================================================================
> RCS file: /Volumes/CSP/cvs/src/sys/ufs/ufs/ufs_inode.c,v
> retrieving revision 1.41
> diff -u -r1.41 ufs_inode.c
> --- sys/ufs/ufs/ufs_inode.c     14 Mar 2015 03:38:53 -0000      1.41
> +++ sys/ufs/ufs/ufs_inode.c     23 Oct 2015 15:07:07 -0000
> @@ -43,16 +43,20 @@
>  #include <sys/mount.h>
>  #include <sys/malloc.h>
>  #include <sys/namei.h>
> +#include <sys/wapbl.h>
>
>  #include <ufs/ufs/quota.h>
>  #include <ufs/ufs/inode.h>
>  #include <ufs/ufs/ufsmount.h>
>  #include <ufs/ufs/ufs_extern.h>
> +#include <ufs/ufs/ufs_wapbl.h>
>  #ifdef UFS_DIRHASH
>  #include <ufs/ufs/dir.h>
>  #include <ufs/ufs/dirhash.h>
>  #endif
>
> +#include <ufs/ffs/fs.h>
> +
>  /*
>   * Last reference to an inode.  If necessary, write or delete it.
>   */
> @@ -62,9 +66,10 @@
>         struct vop_inactive_args *ap = v;
>         struct vnode *vp = ap->a_vp;
>         struct inode *ip = VTOI(vp);
> +       struct fs *fs = ip->i_fs;
>         struct proc *p = ap->a_p;
>         mode_t mode;
> -       int error = 0;
> +       int error = 0, logged = 0;
>  #ifdef DIAGNOSTIC
>         extern int prtactive;
>
> @@ -72,6 +77,8 @@
>                 vprint("ufs_inactive: pushing active", vp);
>  #endif
>
> +       UFS_WAPBL_JUNLOCK_ASSERT(vp->v_mount);
> +
>         /*
>          * Ignore inodes related to stale file handles.
>          */
> @@ -79,9 +86,42 @@
>                 goto out;
>
>         if (DIP(ip, nlink) <= 0 && (vp->v_mount->mnt_flag & MNT_RDONLY) ==
> 0) {
> +               error = UFS_WAPBL_BEGIN(vp->v_mount);
> +               if (error)
> +                       goto out;
> +               logged = 1;
>                 if (getinoquota(ip) == 0)
>                         (void)ufs_quota_free_inode(ip, NOCRED);
>
> +               if (DIP(ip, size) != 0) {
> +                       /*
> +                        * When journaling, only truncate one indirect
> block
> +                        * at a time
> +                        */
> +                       if (vp->v_mount->mnt_wapbl) {
> +                               uint64_t incr = MNINDIR(ip->i_ump) <<
> +                                   fs->fs_bshift;
> +                               uint64_t base = NDADDR << fs->fs_bshift;
> +                               while (!error && DIP(ip, size) > base +
> incr) {
> +                                       /*
> +                                        * round down to next full indirect
> +                                        * block boundary.
> +                                        */
> +                                       uint64_t nsize = base +
> +                                           ((DIP(ip, size) - base - 1) &
> +                                           ~(incr - 1));
> +                                       error = UFS_TRUNCATE(ip, nsize, 0,
> +                                           NOCRED);
> +                                       if (error)
> +                                               break;
> +                                       UFS_WAPBL_END(vp->v_mount);
> +                                       error =
> UFS_WAPBL_BEGIN(vp->v_mount);
> +                                       if (error)
> +                                               goto out;
> +                               }
> +                       }
> +               }
> +
>                 error = UFS_TRUNCATE(ip, (off_t)0, 0, NOCRED);
>
>                 DIP_ASSIGN(ip, rdev, 0);
> @@ -108,8 +148,16 @@
>         }
>
>         if (ip->i_flag & (IN_ACCESS | IN_CHANGE | IN_MODIFIED |
> IN_UPDATE)) {
> +               if (!logged++) {
> +                       int err;
> +                       err = UFS_WAPBL_BEGIN(vp->v_mount);
> +                       if (err)
> +                               goto out;
> +               }
>                 UFS_UPDATE(ip, 0);
>         }
> +       if (logged)
> +               UFS_WAPBL_END(vp->v_mount);
>  out:
>         VOP_UNLOCK(vp, 0, p);
>
> @@ -143,8 +191,12 @@
>          * Stop deferring timestamp writes
>          */
>         if (ip->i_flag & IN_LAZYMOD) {
> +               int err = UFS_WAPBL_BEGIN(vp->v_mount);
> +               if (err)
> +                       return (err);
>                 ip->i_flag |= IN_MODIFIED;
>                 UFS_UPDATE(ip, 0);
> +               UFS_WAPBL_END(vp->v_mount);
>         }
>
>         /*
> Index: sys/ufs/ufs/ufs_lookup.c
> ===================================================================
> RCS file: /Volumes/CSP/cvs/src/sys/ufs/ufs/ufs_lookup.c,v
> retrieving revision 1.47
> diff -u -r1.47 ufs_lookup.c
> --- sys/ufs/ufs/ufs_lookup.c    14 Mar 2015 03:38:53 -0000      1.47
> +++ sys/ufs/ufs/ufs_lookup.c    23 Oct 2015 15:07:07 -0000
> @@ -46,6 +46,7 @@
>  #include <sys/mount.h>
>  #include <sys/proc.h>
>  #include <sys/vnode.h>
> +#include <sys/wapbl.h>
>
>  #include <ufs/ufs/quota.h>
>  #include <ufs/ufs/inode.h>
> @@ -55,6 +56,7 @@
>  #endif
>  #include <ufs/ufs/ufsmount.h>
>  #include <ufs/ufs/ufs_extern.h>
> +#include <ufs/ufs/ufs_wapbl.h>
>
>  extern struct nchstats nchstats;
>
> @@ -445,6 +447,7 @@
>                 ufs_dirbad(dp, dp->i_offset, "i_ffs_size too small");
>                 DIP_ASSIGN(dp, size, dp->i_offset + DIRSIZ(FSFMT(vdp),
> ep));
>                 dp->i_flag |= IN_CHANGE | IN_UPDATE;
> +               UFS_WAPBL_UPDATE(dp, MNT_WAIT);
>         }
>         brelse(bp);
>
> @@ -704,6 +707,8 @@
>         int error, ret, blkoff, loc, spacefree, flags;
>         char *dirbuf;
>
> +       UFS_WAPBL_JLOCK_ASSERT(dvp->v_mount);
> +
>         error = 0;
>         cr = cnp->cn_cred;
>         p = cnp->cn_proc;
> @@ -805,8 +810,11 @@
>          *
>          * N.B. - THIS IS AN ARTIFACT OF 4.2 AND SHOULD NEVER HAPPEN.
>          */
> -       if (dp->i_offset + dp->i_count > DIP(dp, size))
> +       if (dp->i_offset + dp->i_count > DIP(dp, size)) {
>                 DIP_ASSIGN(dp, size, dp->i_offset + dp->i_count);
> +               dp->i_flag |= IN_CHANGE | IN_UPDATE;
> +               UFS_WAPBL_UPDATE(dp, MNT_WAIT);
> +       }
>         /*
>          * Get the block containing the space for the new directory entry.
>          */
> @@ -925,6 +933,7 @@
>                 if (tvp != NULL)
>                         vn_lock(tvp, LK_EXCLUSIVE | LK_RETRY, p);
>         }
> +       UFS_WAPBL_UPDATE(dp, MNT_WAIT);
>         return (error);
>  }
>
> @@ -948,6 +957,8 @@
>         struct buf *bp;
>         int error;
>
> +       UFS_WAPBL_JLOCK_ASSERT(dvp->v_mount);
> +
>         dp = VTOI(dvp);
>
>         if ((error = UFS_BUFATOFF(dp,
> @@ -997,6 +1008,7 @@
>                         ip->i_effnlink--;
>                         DIP_ADD(ip, nlink, -1);
>                         ip->i_flag |= IN_CHANGE;
> +                       UFS_WAPBL_UPDATE(ip, 0);
>                 }
>                 if (DOINGASYNC(dvp) && dp->i_count != 0) {
>                         bdwrite(bp);
> @@ -1005,6 +1017,7 @@
>                         error = bwrite(bp);
>         }
>         dp->i_flag |= IN_CHANGE | IN_UPDATE;
> +       UFS_WAPBL_UPDATE(dp, 0);
>         return (error);
>  }
>
> @@ -1036,6 +1049,7 @@
>         } else {
>                 DIP_ADD(oip, nlink, -1);
>                 oip->i_flag |= IN_CHANGE;
> +               UFS_WAPBL_UPDATE(oip, MNT_WAIT);
>                 if (DOINGASYNC(vdp)) {
>                         bdwrite(bp);
>                         error = 0;
> @@ -1044,6 +1058,7 @@
>                 }
>         }
>         dp->i_flag |= IN_CHANGE | IN_UPDATE;
> +       UFS_WAPBL_UPDATE(dp, MNT_WAIT);
>         return (error);
>  }
>
> Index: sys/ufs/ufs/ufs_vnops.c
> ===================================================================
> RCS file: /Volumes/CSP/cvs/src/sys/ufs/ufs/ufs_vnops.c,v
> retrieving revision 1.122
> diff -u -r1.122 ufs_vnops.c
> --- sys/ufs/ufs/ufs_vnops.c     23 Sep 2015 15:37:26 -0000      1.122
> +++ sys/ufs/ufs/ufs_vnops.c     23 Oct 2015 15:07:07 -0000
> @@ -54,8 +54,8 @@
>  #include <sys/lockf.h>
>  #include <sys/event.h>
>  #include <sys/poll.h>
> -#include <sys/specdev.h>
>  #include <sys/unistd.h>
> +#include <sys/wapbl.h>
>
>  #include <miscfs/fifofs/fifo.h>
>
> @@ -64,6 +64,8 @@
>  #include <ufs/ufs/dir.h>
>  #include <ufs/ufs/ufsmount.h>
>  #include <ufs/ufs/ufs_extern.h>
> +#include <ufs/ufs/ufs_wapbl.h>
> +#include <ufs/ffs/fs.h>
>  #ifdef UFS_DIRHASH
>  #include <ufs/ufs/dirhash.h>
>  #endif
> @@ -165,11 +167,13 @@
>         struct vop_create_args *ap = v;
>         int error;
>
> +       /* UFS_WAPBL_BEGIN1(dvp) performed by successful ufs_makeinode() */
>         error =
>             ufs_makeinode(MAKEIMODE(ap->a_vap->va_type,
> ap->a_vap->va_mode),
>                           ap->a_dvp, ap->a_vpp, ap->a_cnp);
>         if (error)
>                 return (error);
> +       UFS_WAPBL_END1(ap->a_dvp->v_mount, ap->a_dvp);
>         VN_KNOTE(ap->a_dvp, NOTE_WRITE);
>         return (0);
>  }
> @@ -186,6 +190,10 @@
>         struct inode *ip;
>         int error;
>
> +       /*
> +        * UFS_WAPBL_BEGIN1(dvp->v_mount, dvp) performed by successful
> +        * ufs_makeinode
> +        */
>         if ((error =
>              ufs_makeinode(MAKEIMODE(vap->va_type, vap->va_mode),
>                            ap->a_dvp, vpp, ap->a_cnp)) != 0)
> @@ -200,6 +208,8 @@
>                  */
>                 DIP_ASSIGN(ip, rdev, vap->va_rdev);
>         }
> +       UFS_WAPBL_UPDATE(VTOI(*vpp), 0);
> +       UFS_WAPBL_END1(ap->a_dvp->v_mount, ap->a_dvp);
>         /*
>          * Remove inode so that it will be reloaded by VFS_VGET and
>          * checked to see if it is an alias of an existing entry in
> @@ -348,6 +358,7 @@
>         struct vattr *vap = ap->a_vap;
>         struct vnode *vp = ap->a_vp;
>         struct inode *ip = VTOI(vp);
> +       struct fs *fs = ip->i_fs;
>         struct ucred *cred = ap->a_cred;
>         struct proc *p = ap->a_p;
>         int error;
> @@ -369,19 +380,28 @@
>                 if (cred->cr_uid != DIP(ip, uid) &&
>                     (error = suser_ucred(cred)))
>                         return (error);
> +               error = UFS_WAPBL_BEGIN(vp->v_mount);
> +               if (error)
> +                       return (error);
>                 if (cred->cr_uid == 0) {
>                         if ((DIP(ip, flags) & (SF_IMMUTABLE | SF_APPEND))
> &&
> -                           securelevel > 0)
> +                           securelevel > 0) {
> +                               UFS_WAPBL_END(vp->v_mount);
>                                 return (EPERM);
> +                       }
>                         DIP_ASSIGN(ip, flags, vap->va_flags);
>                 } else {
>                         if (DIP(ip, flags) & (SF_IMMUTABLE | SF_APPEND) ||
> -                           (vap->va_flags & UF_SETTABLE) != vap->va_flags)
> +                           (vap->va_flags & UF_SETTABLE) !=
> vap->va_flags) {
> +                               UFS_WAPBL_END(vp->v_mount);
>                                 return (EPERM);
> +                       }
>                         DIP_AND(ip, flags, SF_SETTABLE);
>                         DIP_OR(ip, flags, vap->va_flags & UF_SETTABLE);
>                 }
>                 ip->i_flag |= IN_CHANGE;
> +               UFS_WAPBL_UPDATE(ip, 0);
> +               UFS_WAPBL_END(vp->v_mount);
>                 if (vap->va_flags & (IMMUTABLE | APPEND))
>                         return (0);
>         }
> @@ -393,7 +413,11 @@
>         if (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL) {
>                 if (vp->v_mount->mnt_flag & MNT_RDONLY)
>                         return (EROFS);
> +               error = UFS_WAPBL_BEGIN(vp->v_mount);
> +               if (error)
> +                       return (error);
>                 error = ufs_chown(vp, vap->va_uid, vap->va_gid, cred, p);
> +               UFS_WAPBL_END(vp->v_mount);
>                 if (error)
>                         return (error);
>         }
> @@ -415,8 +439,36 @@
>                 default:
>                         break;
>                 }
> -               if ((error = UFS_TRUNCATE(ip, vap->va_size, 0, cred)) != 0)
> -                       return (error);
> +               error = UFS_WAPBL_BEGIN(vp->v_mount);
> +               if (error)
> +                       return (error);
> +               /*
> +                * When journaling, only truncate one indirect block at a
> time.
> +                */
> +               if (vp->v_mount->mnt_wapbl) {
> +                       uint64_t incr = MNINDIR(ip->i_ump) <<
> fs->fs_bshift;
> +                       uint64_t base = NDADDR << fs->fs_bshift;
> +                       while (!error && DIP(ip, size) > base + incr &&
> +                           DIP(ip, size) > vap->va_size + incr) {
> +                               /*
> +                                * round down to next full indirect
> +                                * block boundary.
> +                                */
> +                               uint64_t nsize = base +
> +                                   ((DIP(ip, size) - base - 1) &
> +                                   ~(incr - 1));
> +                               error = UFS_TRUNCATE(ip, nsize, 0, cred);
> +                               if (error == 0) {
> +                                       UFS_WAPBL_END(vp->v_mount);
> +                                       error =
> UFS_WAPBL_BEGIN(vp->v_mount);
> +                               }
> +                       }
> +               }
> +               if (!error)
> +                       error = UFS_TRUNCATE(ip, vap->va_size, 0, cred);
> +               UFS_WAPBL_END(vp->v_mount);
> +               if (error)
> +                       return (error);
>                 if (vap->va_size < oldsize)
>                         hint |= NOTE_TRUNCATE;
>         }
> @@ -430,6 +482,9 @@
>                     ((vap->va_vaflags & VA_UTIMES_NULL) == 0 ||
>                     (error = VOP_ACCESS(vp, VWRITE, cred, p))))
>                         return (error);
> +               error = UFS_WAPBL_BEGIN(vp->v_mount);
> +               if (error)
> +                       return (error);
>                 if (vap->va_mtime.tv_nsec != VNOVAL)
>                         ip->i_flag |= IN_CHANGE | IN_UPDATE;
>                 else if (vap->va_vaflags & VA_UTIMES_CHANGE)
> @@ -449,6 +504,7 @@
>                         DIP_ASSIGN(ip, atimensec, vap->va_atime.tv_nsec);
>                 }
>                 error = UFS_UPDATE(ip, 0);
> +               UFS_WAPBL_END(vp->v_mount);
>                 if (error)
>                         return (error);
>         }
> @@ -456,7 +512,11 @@
>         if (vap->va_mode != (mode_t)VNOVAL) {
>                 if (vp->v_mount->mnt_flag & MNT_RDONLY)
>                         return (EROFS);
> +               error = UFS_WAPBL_BEGIN(vp->v_mount);
> +               if (error)
> +                       return (error);
>                 error = ufs_chmod(vp, (int)vap->va_mode, cred, p);
> +               UFS_WAPBL_END(vp->v_mount);
>         }
>         VN_KNOTE(vp, hint);
>         return (error);
> @@ -472,6 +532,8 @@
>         struct inode *ip = VTOI(vp);
>         int error;
>
> +       UFS_WAPBL_JLOCK_ASSERT(vp->v_mount);
> +
>         if (cred->cr_uid != DIP(ip, uid) &&
>             (error = suser_ucred(cred)))
>                 return (error);
> @@ -484,6 +546,7 @@
>         DIP_AND(ip, mode, ~ALLPERMS);
>         DIP_OR(ip, mode, mode & ALLPERMS);
>         ip->i_flag |= IN_CHANGE;
> +       UFS_WAPBL_UPDATE(ip, 0);
>         if ((vp->v_flag & VTEXT) && (DIP(ip, mode) & S_ISTXT) == 0)
>                 (void) uvm_vnp_uncache(vp);
>         return (0);
> @@ -553,8 +616,10 @@
>         if (getinoquota(ip))
>                 panic("chown: lost quota");
>
> -       if (ouid != uid || ogid != gid)
> +       if (ouid != uid || ogid != gid) {
>                 ip->i_flag |= IN_CHANGE;
> +               UFS_WAPBL_UPDATE(ip, 0);
> +       }
>         if (ouid != uid && cred->cr_uid != 0)
>                 DIP_AND(ip, mode, ~ISUID);
>         if (ogid != gid && cred->cr_uid != 0)
> @@ -612,12 +677,16 @@
>         if (vp->v_type == VDIR || (DIP(ip, flags) & (IMMUTABLE | APPEND))
> ||
>             (DIP(VTOI(dvp), flags) & APPEND)) {
>                 error = EPERM;
> -               goto out;
> +       } else {
> +               error = UFS_WAPBL_BEGIN(vp->v_mount);
> +               if (error == 0) {
> +                       error = ufs_dirremove(dvp, ip,
> ap->a_cnp->cn_flags, 0);
> +                       VN_KNOTE(vp, NOTE_DELETE);
> +                       VN_KNOTE(dvp, NOTE_WRITE);
> +                       UFS_WAPBL_END(vp->v_mount);
> +               }
>         }
> -       error = ufs_dirremove(dvp, ip, ap->a_cnp->cn_flags, 0);
> -       VN_KNOTE(vp, NOTE_DELETE);
> -       VN_KNOTE(dvp, NOTE_WRITE);
> - out:
> +
>         if (dvp == vp)
>                 vrele(vp);
>         else
> @@ -670,6 +739,11 @@
>                 error = EPERM;
>                 goto out1;
>         }
> +       error = UFS_WAPBL_BEGIN(vp->v_mount);
> +       if (error) {
> +               VOP_ABORTOP(dvp, cnp);
> +               goto out1;
> +       }
>         ip->i_effnlink++;
>         DIP_ADD(ip, nlink, 1);
>         ip->i_flag |= IN_CHANGE;
> @@ -683,9 +757,11 @@
>                 ip->i_effnlink--;
>                 DIP_ADD(ip, nlink, -1);
>                 ip->i_flag |= IN_CHANGE;
> +               UFS_WAPBL_UPDATE(ip, MNT_WAIT);
>                 if (DOINGSOFTDEP(vp))
>                         softdep_change_linkcnt(ip, 0);
>         }
> +       UFS_WAPBL_END(vp->v_mount);
>         pool_put(&namei_pool, cnp->cn_pnbuf);
>         VN_KNOTE(vp, NOTE_LINK);
>         VN_KNOTE(dvp, NOTE_WRITE);
> @@ -729,6 +805,7 @@
>         struct vnode *tdvp = ap->a_tdvp;
>         struct vnode *fvp = ap->a_fvp;
>         struct vnode *fdvp = ap->a_fdvp;
> +       struct mount *mp = fdvp->v_mount;
>         struct componentname *tcnp = ap->a_tcnp;
>         struct componentname *fcnp = ap->a_fcnp;
>         struct proc *p = fcnp->cn_proc;
> @@ -742,6 +819,9 @@
>             (fcnp->cn_flags & HASBUF) == 0)
>                 panic("ufs_rename: no name");
>  #endif
> +
> +       KASSERT(mp != NULL);
> +
>         /*
>          * Check for cross-device rename.
>          */
> @@ -862,6 +942,12 @@
>         if (tvp)
>                 xp = VTOI(tvp);
>
> +       error = UFS_WAPBL_BEGIN(mp);
> +       if (error) {
> +               VOP_UNLOCK(fvp, 0, p);
> +               goto bad;
> +       }
> +
>         /*
>          * 1) Bump link count while we're moving stuff
>          *    around.  If we crash somewhere before
> @@ -1037,6 +1123,7 @@
>                         if (!newparent) {
>                                 DIP_ADD(dp, nlink, -1);
>                                 dp->i_flag |= IN_CHANGE;
> +                               UFS_WAPBL_UPDATE(dp, 0);
>                         }
>
>                         DIP_ADD(xp, nlink, -1);
> @@ -1061,6 +1148,7 @@
>                 panic("ufs_rename: lost from startdir");
>         if ((error = vfs_relookup(fdvp, &fvp, fcnp)) != 0) {
>                 vrele(ap->a_fvp);
> +               UFS_WAPBL_END(mp);
>                 return (error);
>         }
>         vrele(fdvp);
> @@ -1071,6 +1159,7 @@
>                 if (doingdirectory)
>                         panic("ufs_rename: lost dir entry");
>                 vrele(ap->a_fvp);
> +               UFS_WAPBL_END(mp);
>                 return (0);
>         }
>
> @@ -1110,6 +1199,7 @@
>         if (xp)
>                 vput(fvp);
>         vrele(ap->a_fvp);
> +       UFS_WAPBL_END(mp);
>         return (error);
>
>  bad:
> @@ -1125,11 +1215,13 @@
>                 DIP_ADD(ip, nlink, -1);
>                 ip->i_flag |= IN_CHANGE;
>                 ip->i_flag &= ~IN_RENAME;
> +               UFS_WAPBL_UPDATE(ip, 0);
>                 if (DOINGSOFTDEP(fvp))
>                         softdep_change_linkcnt(ip, 0);
>                 vput(fvp);
>         } else
>                 vrele(fvp);
> +       UFS_WAPBL_END(mp);
>         return (error);
>  }
>
> @@ -1171,6 +1263,14 @@
>
>         ip = VTOI(tvp);
>
> +       error = UFS_WAPBL_BEGIN(dvp->v_mount);
> +       if (error) {
> +               UFS_INODE_FREE(ip, ip->i_number, dmode);
> +               vput(tvp);
> +               vput(dvp);
> +               return (error);
> +       }
> +
>         DIP_ASSIGN(ip, uid, cnp->cn_cred->cr_uid);
>         DIP_ASSIGN(ip, gid, DIP(dp, gid));
>
> @@ -1178,6 +1278,7 @@
>             (error = ufs_quota_alloc_inode(ip, cnp->cn_cred))) {
>                 pool_put(&namei_pool, cnp->cn_pnbuf);
>                 UFS_INODE_FREE(ip, ip->i_number, dmode);
> +               UFS_WAPBL_END(dvp->v_mount);
>                 vput(tvp);
>                 vput(dvp);
>                 return (error);
> @@ -1261,10 +1362,12 @@
>          if (error == 0) {
>                 VN_KNOTE(dvp, NOTE_WRITE | NOTE_LINK);
>                  *ap->a_vpp = tvp;
> +               UFS_WAPBL_END(dvp->v_mount);
>          } else {
>                  dp->i_effnlink--;
>                  DIP_ADD(dp, nlink, -1);
>                  dp->i_flag |= IN_CHANGE;
> +               UFS_WAPBL_UPDATE(dp, MNT_WAIT);
>                 if (DOINGSOFTDEP(dvp))
>                         softdep_change_linkcnt(dp, 0);
>                  /*
> @@ -1274,6 +1377,8 @@
>                  ip->i_effnlink = 0;
>                  DIP_ASSIGN(ip, nlink, 0);
>                  ip->i_flag |= IN_CHANGE;
> +               UFS_WAPBL_UPDATE(ip, MNT_WAIT);
> +               UFS_WAPBL_END(dvp->v_mount);
>                 if (DOINGSOFTDEP(tvp))
>                         softdep_change_linkcnt(ip, 0);
>                 vput(tvp);
> @@ -1332,21 +1437,26 @@
>                 error = EPERM;
>                 goto out;
>         }
> +       error = UFS_WAPBL_BEGIN(dvp->v_mount);
> +       if (error)
> +               goto out;
> +
>         /*
>          * Delete reference to directory before purging
>          * inode.  If we crash in between, the directory
>          * will be reattached to lost+found,
>          */
> -       dp->i_effnlink--;
> -       ip->i_effnlink--;
>         if (DOINGSOFTDEP(vp)) {
> +               dp->i_effnlink--;
> +               ip->i_effnlink--;
>                 softdep_change_linkcnt(dp, 0);
>                 softdep_change_linkcnt(ip, 0);
>         }
>         if ((error = ufs_dirremove(dvp, ip, cnp->cn_flags, 1)) != 0) {
> -               dp->i_effnlink++;
> -               ip->i_effnlink++;
> +               UFS_WAPBL_END(dvp->v_mount);
>                 if (DOINGSOFTDEP(vp)) {
> +                       dp->i_effnlink++;
> +                       ip->i_effnlink++;
>                         softdep_change_linkcnt(dp, 0);
>                         softdep_change_linkcnt(ip, 0);
>                 }
> @@ -1365,14 +1475,22 @@
>         if (!DOINGSOFTDEP(vp)) {
>                 int ioflag;
>
> +               dp->i_effnlink--;
>                 DIP_ADD(dp, nlink, -1);
>                 dp->i_flag |= IN_CHANGE;
> +               UFS_WAPBL_UPDATE(dp, MNT_WAIT);
> +               ip->i_effnlink--;
>                 DIP_ADD(ip, nlink, -1);
>                 ip->i_flag |= IN_CHANGE;
>                 ioflag = DOINGASYNC(vp) ? 0 : IO_SYNC;
>                 error = UFS_TRUNCATE(ip, (off_t)0, ioflag, cnp->cn_cred);
>         }
>         cache_purge(vp);
> +       /*
> +        * Unlock the log while we still have reference to the unlinked
> +        * directory vp so that it will not get locked for recycling
> +        */
> +       UFS_WAPBL_END(dvp->v_mount);
>  #ifdef UFS_DIRHASH
>         /* Kill any active hash; i_effnlink == 0, so it will not come
> back. */
>         if (ip->i_dirhash != NULL)
> @@ -1397,6 +1515,7 @@
>         struct inode *ip;
>         int len, error;
>
> +       /* UFS_WAPBL_BEGIN1(dvp) performed by successful ufs_makeinode() */
>         error = ufs_makeinode(IFLNK | ap->a_vap->va_mode, ap->a_dvp,
>                               vpp, ap->a_cnp);
>         if (error)
> @@ -1409,10 +1528,12 @@
>                 memcpy(SHORTLINK(ip), ap->a_target, len);
>                 DIP_ASSIGN(ip, size, len);
>                 ip->i_flag |= IN_CHANGE | IN_UPDATE;
> +               UFS_WAPBL_UPDATE(ip, 0);
>         } else
>                 error = vn_rdwr(UIO_WRITE, vp, ap->a_target, len, (off_t)0,
> -                   UIO_SYSSPACE, IO_NODELOCKED, ap->a_cnp->cn_cred, NULL,
> -                   curproc);
> +                   UIO_SYSSPACE, IO_NODELOCKED | IO_JOURNALLOCKED,
> +                   ap->a_cnp->cn_cred, NULL, curproc);
> +       UFS_WAPBL_END1(ap->a_dvp->v_mount, ap->a_dvp);
>         vput(vp);
>         return (error);
>  }
> @@ -1593,6 +1714,7 @@
>         struct buf *bp = ap->a_bp;
>         struct vnode *vp = bp->b_vp;
>         struct inode *ip;
> +       struct mount *mp;
>         int error;
>         int s;
>
> @@ -1622,7 +1744,28 @@
>         vp = ip->i_devvp;
>         bp->b_dev = vp->v_rdev;
>         (vp->v_op->vop_strategy)(ap);
> -       return (0);
> +
> +       if ((bp->b_flags & B_READ) == 0)
> +               return (0);
> +
> +       mp = wapbl_vptomp(vp);
> +       if (mp == NULL || mp->mnt_wapbl_replay == NULL ||
> +           !WAPBL_REPLAY_ISOPEN(mp) ||
> +           !WAPBL_REPLAY_CAN_READ(mp, bp->b_blkno, bp->b_bcount))
> +               return (0);
> +
> +       error = biowait(bp);
> +       if (error)
> +               return (error);
> +
> +       error = WAPBL_REPLAY_READ(mp, bp->b_data, bp->b_blkno,
> bp->b_bcount);
> +       if (error) {
> +               s = splbio();
> +               SET(bp->b_flags, B_INVAL);
> +               splx(s);
> +       }
> +
> +       return (error);
>  }
>
>  /*
> @@ -1897,6 +2040,8 @@
>         struct vnode *tvp;
>         int error;
>
> +       UFS_WAPBL_JUNLOCK_ASSERT(dvp->v_mount);
> +
>         pdir = VTOI(dvp);
>  #ifdef DIAGNOSTIC
>         if ((cnp->cn_flags & HASBUF) == 0)
> @@ -1917,10 +2062,23 @@
>         DIP_ASSIGN(ip, gid, DIP(pdir, gid));
>         DIP_ASSIGN(ip, uid, cnp->cn_cred->cr_uid);
>
> +       error = UFS_WAPBL_BEGIN1(dvp->v_mount, dvp);
> +       if (error) {
> +               /*
> +                * Note, we can't UFS_INODE_FREE() here like we should
> because
> +                * we can't write to the disk. Instead, we leave the vnode
> +                * dangling from the journal.
> +                */
> +               vput(tvp);
> +               vput(dvp);
> +               return (error);
> +       }
> +
>         if ((error = getinoquota(ip)) ||
>             (error = ufs_quota_alloc_inode(ip, cnp->cn_cred))) {
>                 pool_put(&namei_pool, cnp->cn_pnbuf);
>                 UFS_INODE_FREE(ip, ip->i_number, mode);
> +               UFS_WAPBL_END1(dvp->v_mount, dvp);
>                 vput(tvp);
>                 vput(dvp);
>                 return (error);
> @@ -1964,14 +2122,61 @@
>         ip->i_effnlink = 0;
>         DIP_ASSIGN(ip, nlink, 0);
>         ip->i_flag |= IN_CHANGE;
> +       UFS_WAPBL_UPDATE(VTOI(tvp), 0);
>         if (DOINGSOFTDEP(tvp))
>                 softdep_change_linkcnt(ip, 0);
>         tvp->v_type = VNON;
> +       UFS_WAPBL_END1(dvp->v_mount, dvp);
>         vput(tvp);
>
>         return (error);
>  }
>
> +/*
> + * Allocate len bytes at offset off.
> + */
> +int
> +ufs_gop_alloc(struct vnode *vp, off_t off, off_t len, int flags,
> +    struct ucred *cred)
> +{
> +        struct inode *ip = VTOI(vp);
> +        int error, delta, bshift, bsize;
> +
> +        error = 0;
> +        bshift = ip->i_fs->fs_bshift;
> +        bsize = 1 << bshift;
> +
> +        delta = off & (bsize - 1);
> +        off -= delta;
> +        len += delta;
> +
> +        while (len > 0) {
> +                bsize = MIN(bsize, len);
> +
> +                error = UFS_BUF_ALLOC(ip, off, bsize, cred, flags, NULL);
> +                if (error) {
> +                        goto out;
> +                }
> +
> +                /*
> +                 * increase file size now, UFS_BUF_ALLOC() requires that
> +                 * EOF be up-to-date before each call.
> +                 */
> +
> +                if (DIP(ip, size) < off + bsize) {
> +                        /* ip->i_size = off + bsize; */
> +                       DIP_ASSIGN(ip, size, off + bsize);
> +                }
> +
> +                off += bsize;
> +                len -= bsize;
> +        }
> +
> +out:
> +       UFS_WAPBL_UPDATE(ip, 0);
> +       return error;
> +}
> +
>  struct filterops ufsread_filtops =
>         { 1, NULL, filt_ufsdetach, filt_ufsread };
>  struct filterops ufswrite_filtops =
>
>


-- 
May the most significant bit of your life be positive.

Reply via email to