svn commit: r252529 - in projects/virtio: share/man/man4 sys/dev/virtio/block

Bryan Venteicher bryanv at FreeBSD.org
Wed Jul 3 02:11:06 UTC 2013


Author: bryanv
Date: Wed Jul  3 02:11:05 2013
New Revision: 252529
URL: http://svnweb.freebsd.org/changeset/base/252529

Log:
  virtio_blk: Improve write cache handling
  
  Follow the exact wording of the spec and check for
  VIRTIO_BLK_F_CONFIG_WCE support before falling back
  to VIRTIO_BLK_F_WCE. Always tell GEOM we support flush
  cache even though it is a noop in writethrough mode.
  
  Add sysctl handler to change the write cache mode when
  CONFIG_WCE is supported.
  
  Add support and update man page for both global and
  per-device tunables.

Modified:
  projects/virtio/share/man/man4/virtio_blk.4
  projects/virtio/sys/dev/virtio/block/virtio_blk.c

Modified: projects/virtio/share/man/man4/virtio_blk.4
==============================================================================
--- projects/virtio/share/man/man4/virtio_blk.4	Wed Jul  3 00:19:03 2013	(r252528)
+++ projects/virtio/share/man/man4/virtio_blk.4	Wed Jul  3 02:11:05 2013	(r252529)
@@ -24,7 +24,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd January 22, 2012
+.Dd July 2, 2013
 .Dt VIRTIO_BLK 4
 .Os
 .Sh NAME
@@ -53,11 +53,33 @@ Tunables can be set at the
 .Xr loader 8
 prompt before booting the kernel or stored in
 .Xr loader.conf 5 .
-.Bl -tag -width "xxxxxx"
+.Bl -tag -width indent
 .It Va hw.vtblk.no_ident
-This tunable disables retrieving the device identification string
-from the hypervisor.
+.It Va hw.vtblk. Ns Ar X Ns Va .no_ident
+.Pp
+These tunables disable retrieving the device identification string
+from the hypervisor either globally or per-device.
 The default value is 0.
+.It Va hw.vtblk.writecache_mode
+.It Va hw.vtblk. Ns Ar X Ns Va .writecache_mode
+.Pp
+These tunables determine the write cache mode globally or per-device.
+The mode can changed only if the ConfigWCE feature is negotiated.
+Set to 0 for writethrough mode, 1 for writeback mode, and -1 to leave
+it as-is.
+The default value is to leave as-is.
+.El
+.Sh SYSCTL VARIABLES
+The following variables are available as
+.Xr sysctl 8
+variables.
+.Bl -tag -width indent
+.It Va dev.vtblk. Ns Ar X Ns Va .writecache_mode
+.Pp
+The write cache mode of the device can be either writethrough (0) or
+writeback (1).
+If the ConfigWCE feature is negotiated, the write cache mode can
+be toggled between writethrough and writeback.
 .El
 .Sh SEE ALSO
 .Xr virtio 4

Modified: projects/virtio/sys/dev/virtio/block/virtio_blk.c
==============================================================================
--- projects/virtio/sys/dev/virtio/block/virtio_blk.c	Wed Jul  3 00:19:03 2013	(r252528)
+++ projects/virtio/sys/dev/virtio/block/virtio_blk.c	Wed Jul  3 02:11:05 2013	(r252529)
@@ -36,6 +36,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/malloc.h>
 #include <sys/module.h>
 #include <sys/sglist.h>
+#include <sys/sysctl.h>
 #include <sys/lock.h>
 #include <sys/mutex.h>
 #include <sys/queue.h>
@@ -61,6 +62,12 @@ struct vtblk_request {
 	TAILQ_ENTRY(vtblk_request)	 vbr_link;
 };
 
+enum vtblk_cache_mode {
+	VTBLK_CACHE_WRITETHROUGH,
+	VTBLK_CACHE_WRITEBACK,
+	VTBLK_CACHE_MAX
+};
+
 struct vtblk_softc {
 	device_t		 vtblk_dev;
 	struct mtx		 vtblk_mtx;
@@ -72,6 +79,7 @@ struct vtblk_softc {
 #define VTBLK_FLAG_SUSPEND	0x0008
 #define VTBLK_FLAG_DUMPING	0x0010
 #define VTBLK_FLAG_BARRIER	0x0020
+#define VTBLK_FLAG_WC_CONFIG	0x0040
 
 	struct virtqueue	*vtblk_vq;
 	struct sglist		*vtblk_sglist;
@@ -86,6 +94,7 @@ struct vtblk_softc {
 
 	int			 vtblk_max_nsegs;
 	int			 vtblk_request_count;
+	enum vtblk_cache_mode	 vtblk_write_cache;
 
 	struct vtblk_request	 vtblk_dump_request;
 };
@@ -127,8 +136,10 @@ static int	vtblk_maximum_segments(struct
 		    struct virtio_blk_config *);
 static int	vtblk_alloc_virtqueue(struct vtblk_softc *);
 static void	vtblk_resize_disk(struct vtblk_softc *, uint64_t);
+static void	vtblk_set_write_cache(struct vtblk_softc *, int);
 static int	vtblk_write_cache_enabled(struct vtblk_softc *sc,
 		    struct virtio_blk_config *);
+static int	vtblk_write_cache_sysctl(SYSCTL_HANDLER_ARGS);
 static void	vtblk_alloc_disk(struct vtblk_softc *,
 		    struct virtio_blk_config *);
 static void	vtblk_create_disk(struct vtblk_softc *);
@@ -169,11 +180,14 @@ static void	vtblk_enqueue_ready(struct v
 static int	vtblk_request_error(struct vtblk_request *);
 static void	vtblk_finish_bio(struct bio *, int);
 
+static void	vtblk_setup_sysctl(struct vtblk_softc *);
+static int	vtblk_tunable_int(struct vtblk_softc *, const char *, int);
+
 /* Tunables. */
 static int vtblk_no_ident = 0;
 TUNABLE_INT("hw.vtblk.no_ident", &vtblk_no_ident);
-static int vtblk_write_cache = 1;
-TUNABLE_INT("hw.vtblk.write_cache", &vtblk_write_cache);
+static int vtblk_writecache_mode = -1;
+TUNABLE_INT("hw.vtblk.writecache_mode", &vtblk_writecache_mode);
 
 /* Features desired/implemented by this driver. */
 #define VTBLK_FEATURES \
@@ -292,6 +306,10 @@ vtblk_attach(device_t dev)
 		sc->vtblk_flags |= VTBLK_FLAG_READONLY;
 	if (virtio_with_feature(dev, VIRTIO_BLK_F_BARRIER))
 		sc->vtblk_flags |= VTBLK_FLAG_BARRIER;
+	if (virtio_with_feature(dev, VIRTIO_BLK_F_CONFIG_WCE))
+		sc->vtblk_flags |= VTBLK_FLAG_WC_CONFIG;
+
+	vtblk_setup_sysctl(sc);
 
 	/* Get local copy of config. */
 	vtblk_read_config(sc, &blkcfg);
@@ -639,35 +657,57 @@ vtblk_resize_disk(struct vtblk_softc *sc
 	}
 }
 
+static void
+vtblk_set_write_cache(struct vtblk_softc *sc, int wc)
+{
+
+	/* Set either writeback (1) or writethrough (0) mode. */
+	virtio_write_dev_config_1(sc->vtblk_dev,
+	    offsetof(struct virtio_blk_config, writeback), wc);
+}
+
 static int
 vtblk_write_cache_enabled(struct vtblk_softc *sc,
     struct virtio_blk_config *blkcfg)
 {
-	device_t dev;
-	char buf[32];
 	int wc;
 
-	dev = sc->vtblk_dev;
+	if (sc->vtblk_flags & VTBLK_FLAG_WC_CONFIG) {
+		wc = vtblk_tunable_int(sc, "writecache_mode",
+		    vtblk_writecache_mode);
+		if (wc >= 0 && wc < VTBLK_CACHE_MAX) {
+			vtblk_set_write_cache(sc, wc);
+		} else
+			wc = blkcfg->writeback;
+	} else
+		wc = virtio_with_feature(sc->vtblk_dev, VIRTIO_BLK_F_WCE);
 
-	if (!virtio_with_feature(dev, VIRTIO_BLK_F_WCE))
-		return (0);
-	if (!virtio_with_feature(dev, VIRTIO_BLK_F_CONFIG_WCE))
-		return (1);
-
-	wc = vtblk_write_cache;
-	snprintf(buf, sizeof(buf), "hw.vtblk.%d.write_cache",
-	    device_get_unit(dev));
-	TUNABLE_INT_FETCH(buf, &wc);
-
-	if (wc != -1) {
-		/* Set either writeback (1) or writethrough (0) mode. */
-		blkcfg->writeback = !!wc;
-		virtio_write_dev_config_1(dev,
-		    offsetof(struct virtio_blk_config, writeback),
-		    blkcfg->writeback);
-	}
+	return (wc);
+}
+
+static int
+vtblk_write_cache_sysctl(SYSCTL_HANDLER_ARGS)
+{
+	struct vtblk_softc *sc;
+	int wc, error;
 
-	return (blkcfg->writeback);
+	sc = oidp->oid_arg1;
+	wc = sc->vtblk_write_cache;;
+
+	error = sysctl_handle_int(oidp, &wc, 0, req);
+	if (error || req->newptr == NULL)
+		return (error);
+	if ((sc->vtblk_flags & VTBLK_FLAG_WC_CONFIG) == 0)
+		return (EPERM);
+	if (wc < 0 || wc >= VTBLK_CACHE_MAX)
+		return (EINVAL);
+
+	VTBLK_LOCK(sc);
+	sc->vtblk_write_cache = wc;
+	vtblk_set_write_cache(sc, sc->vtblk_write_cache);
+	VTBLK_UNLOCK(sc);
+
+	return (0);
 }
 
 static void
@@ -686,6 +726,7 @@ vtblk_alloc_disk(struct vtblk_softc *sc,
 	dp->d_name = VTBLK_DISK_NAME;
 	dp->d_unit = device_get_unit(dev);
 	dp->d_drv1 = sc;
+	dp->d_flags = DISKFLAG_CANFLUSHCACHE;
 	dp->d_hba_vendor = virtio_get_vendor(dev);
 	dp->d_hba_device = virtio_get_device(dev);
 	dp->d_hba_subvendor = virtio_get_subvendor(dev);
@@ -734,7 +775,9 @@ vtblk_alloc_disk(struct vtblk_softc *sc,
 	}
 
 	if (vtblk_write_cache_enabled(sc, blkcfg) != 0)
-		dp->d_flags |= DISKFLAG_CANFLUSHCACHE;
+		sc->vtblk_write_cache = VTBLK_CACHE_WRITEBACK;
+	else
+		sc->vtblk_write_cache = VTBLK_CACHE_WRITETHROUGH;
 }
 
 static void
@@ -952,7 +995,7 @@ vtblk_stop(struct vtblk_softc *sc)
 #define VTBLK_GET_CONFIG(_dev, _feature, _field, _cfg)			\
 	if (virtio_with_feature(_dev, _feature)) {			\
 		virtio_read_device_config(_dev,				\
-		    offsetof(struct virtio_blk_config, _field), 	\
+		    offsetof(struct virtio_blk_config, _field),		\
 		    &(_cfg)->_field, sizeof((_cfg)->_field));		\
 	}
 
@@ -991,7 +1034,7 @@ vtblk_get_ident(struct vtblk_softc *sc)
 	dp = sc->vtblk_disk;
 	len = MIN(VIRTIO_BLK_ID_BYTES, DISK_IDENT_SIZE);
 
-	if (vtblk_no_ident != 0)
+	if (vtblk_tunable_int(sc, "no_ident", vtblk_no_ident) != 0)
 		return;
 
 	req = vtblk_dequeue_request(sc);
@@ -1327,3 +1370,33 @@ vtblk_finish_bio(struct bio *bp, int err
 
 	biodone(bp);
 }
+
+static void
+vtblk_setup_sysctl(struct vtblk_softc *sc)
+{
+	device_t dev;
+	struct sysctl_ctx_list *ctx;
+	struct sysctl_oid *tree;
+	struct sysctl_oid_list *child;
+
+	dev = sc->vtblk_dev;
+	ctx = device_get_sysctl_ctx(dev);
+	tree = device_get_sysctl_tree(dev);
+	child = SYSCTL_CHILDREN(tree);
+
+	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "writecache_mode",
+	    CTLTYPE_INT | CTLFLAG_RW, sc, 0, vtblk_write_cache_sysctl,
+	    "I", "Write cache mode (writethrough (0) or writeback (1))");
+}
+
+static int
+vtblk_tunable_int(struct vtblk_softc *sc, const char *knob, int def)
+{
+	char path[64];
+
+	snprintf(path, sizeof(path),
+	    "hw.vtblk.%d.%s", device_get_unit(sc->vtblk_dev), knob);
+	TUNABLE_INT_FETCH(path, &def);
+
+	return (def);
+}


More information about the svn-src-projects mailing list