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