On Fri, Oct 23, 2015 at 01:19:15PM -0200, Walter Neto wrote:
> Like recommended from other developers I started developing WAPBL support for
> OpenBSD.
>
> Looking at NetBSD and Bitrig I mage a first funcional patch.
Wow... that is a big diff :)
Care to elaborate in some more words what "functional" means here?
Thanks,
Regards,
Joerg
> 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 <[email protected]>
> 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 =
>