Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 16 Feb 2013 14:51:31 +0000 (UTC)
From:      Kirk McKusick <mckusick@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r246876 - in head/sys: geom kern sys
Message-ID:  <201302161451.r1GEpVOL022665@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: mckusick
Date: Sat Feb 16 14:51:30 2013
New Revision: 246876
URL: http://svnweb.freebsd.org/changeset/base/246876

Log:
  Add barrier write capability to the VFS buffer interface. A barrier
  write is a disk write request that tells the disk that the buffer
  being written must be committed to the media along with any writes
  that preceeded it before any future blocks may be written to the drive.
  
  Barrier writes are provided by adding the functions bbarrierwrite
  (bwrite with barrier) and babarrierwrite (bawrite with barrier).
  
  Following a bbarrierwrite the client knows that the requested buffer
  is on the media. It does not ensure that buffers written before that
  buffer are on the media. It only ensure that buffers written before
  that buffer will get to the media before any buffers written after
  that buffer. A flush command must be sent to the disk to ensure that
  all earlier written buffers are on the media.
  
  Reviewed by: kib
  Tested by:   Peter Holm

Modified:
  head/sys/geom/geom_vfs.c
  head/sys/kern/vfs_bio.c
  head/sys/kern/vfs_cluster.c
  head/sys/sys/buf.h

Modified: head/sys/geom/geom_vfs.c
==============================================================================
--- head/sys/geom/geom_vfs.c	Sat Feb 16 12:52:40 2013	(r246875)
+++ head/sys/geom/geom_vfs.c	Sat Feb 16 14:51:30 2013	(r246876)
@@ -192,6 +192,10 @@ g_vfs_strategy(struct bufobj *bo, struct
 	bip->bio_done = g_vfs_done;
 	bip->bio_caller2 = bp;
 	bip->bio_length = bp->b_bcount;
+	if (bp->b_flags & B_BARRIER) {
+		bip->bio_flags |= BIO_ORDERED;
+		bp->b_flags &= ~B_BARRIER;
+	}
 	g_io_request(bip, cp);
 }
 

Modified: head/sys/kern/vfs_bio.c
==============================================================================
--- head/sys/kern/vfs_bio.c	Sat Feb 16 12:52:40 2013	(r246875)
+++ head/sys/kern/vfs_bio.c	Sat Feb 16 14:51:30 2013	(r246876)
@@ -206,6 +206,9 @@ SYSCTL_INT(_vfs, OID_AUTO, flushbufqtarg
 static long notbufdflashes;
 SYSCTL_LONG(_vfs, OID_AUTO, notbufdflashes, CTLFLAG_RD, &notbufdflashes, 0,
     "Number of dirty buffer flushes done by the bufdaemon helpers");
+static long barrierwrites;
+SYSCTL_LONG(_vfs, OID_AUTO, barrierwrites, CTLFLAG_RW, &barrierwrites, 0,
+    "Number of barrier writes");
 
 /*
  * Wakeup point for bufdaemon, as well as indicator of whether it is already
@@ -888,6 +891,9 @@ bufwrite(struct buf *bp)
 		return (0);
 	}
 
+	if (bp->b_flags & B_BARRIER)
+		barrierwrites++;
+
 	oldflags = bp->b_flags;
 
 	BUF_ASSERT_HELD(bp);
@@ -1007,6 +1013,8 @@ bdwrite(struct buf *bp)
 
 	CTR3(KTR_BUF, "bdwrite(%p) vp %p flags %X", bp, bp->b_vp, bp->b_flags);
 	KASSERT(bp->b_bufobj != NULL, ("No b_bufobj %p", bp));
+	KASSERT((bp->b_flags & B_BARRIER) == 0,
+	    ("Barrier request in delayed write %p", bp));
 	BUF_ASSERT_HELD(bp);
 
 	if (bp->b_flags & B_INVAL) {
@@ -1167,6 +1175,40 @@ bawrite(struct buf *bp)
 }
 
 /*
+ *	babarrierwrite:
+ *
+ *	Asynchronous barrier write.  Start output on a buffer, but do not
+ *	wait for it to complete.  Place a write barrier after this write so
+ *	that this buffer and all buffers written before it are committed to
+ *	the disk before any buffers written after this write are committed
+ *	to the disk.  The buffer is released when the output completes.
+ */
+void
+babarrierwrite(struct buf *bp)
+{
+
+	bp->b_flags |= B_ASYNC | B_BARRIER;
+	(void) bwrite(bp);
+}
+
+/*
+ *	bbarrierwrite:
+ *
+ *	Synchronous barrier write.  Start output on a buffer and wait for
+ *	it to complete.  Place a write barrier after this write so that
+ *	this buffer and all buffers written before it are committed to 
+ *	the disk before any buffers written after this write are committed
+ *	to the disk.  The buffer is released when the output completes.
+ */
+int
+bbarrierwrite(struct buf *bp)
+{
+
+	bp->b_flags |= B_BARRIER;
+	return (bwrite(bp));
+}
+
+/*
  *	bwillwrite:
  *
  *	Called prior to the locking of any vnodes when we are expecting to

Modified: head/sys/kern/vfs_cluster.c
==============================================================================
--- head/sys/kern/vfs_cluster.c	Sat Feb 16 12:52:40 2013	(r246875)
+++ head/sys/kern/vfs_cluster.c	Sat Feb 16 14:51:30 2013	(r246876)
@@ -944,11 +944,17 @@ cluster_wbuild(vp, size, start_lbn, len)
 			}
 			bp->b_bcount += size;
 			bp->b_bufsize += size;
-			bundirty(tbp);
-			tbp->b_flags &= ~B_DONE;
-			tbp->b_ioflags &= ~BIO_ERROR;
+			/*
+			 * If any of the clustered buffers have their
+			 * B_BARRIER flag set, transfer that request to
+			 * the cluster.
+			 */
+			bp->b_flags |= (tbp->b_flags & B_BARRIER);
+			tbp->b_flags &= ~(B_DONE | B_BARRIER);
 			tbp->b_flags |= B_ASYNC;
+			tbp->b_ioflags &= ~BIO_ERROR;
 			tbp->b_iocmd = BIO_WRITE;
+			bundirty(tbp);
 			reassignbuf(tbp);		/* put on clean list */
 			bufobj_wref(tbp->b_bufobj);
 			BUF_KERNPROC(tbp);

Modified: head/sys/sys/buf.h
==============================================================================
--- head/sys/sys/buf.h	Sat Feb 16 12:52:40 2013	(r246875)
+++ head/sys/sys/buf.h	Sat Feb 16 14:51:30 2013	(r246876)
@@ -205,7 +205,7 @@ struct buf {
 #define	B_00000800	0x00000800	/* Available flag. */
 #define	B_00001000	0x00001000	/* Available flag. */
 #define	B_INVAL		0x00002000	/* Does not contain valid info. */
-#define	B_00004000	0x00004000	/* Available flag. */
+#define	B_BARRIER	0x00004000	/* Write this and all preceeding first. */
 #define	B_NOCACHE	0x00008000	/* Do not cache block after use. */
 #define	B_MALLOC	0x00010000	/* malloced b_data */
 #define	B_CLUSTEROK	0x00020000	/* Pagein op, so swap() can count it. */
@@ -488,6 +488,8 @@ int	breadn_flags(struct vnode *, daddr_t
 void	breada(struct vnode *, daddr_t *, int *, int, struct ucred *);
 void	bdwrite(struct buf *);
 void	bawrite(struct buf *);
+void	babarrierwrite(struct buf *);
+int	bbarrierwrite(struct buf *);
 void	bdirty(struct buf *);
 void	bundirty(struct buf *);
 void	bufstrategy(struct bufobj *, struct buf *);



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201302161451.r1GEpVOL022665>