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