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 = 

Reply via email to