Date: Wed, 3 Jul 2013 02:11:05 +0000 (UTC) From: Bryan Venteicher <bryanv@FreeBSD.org> To: src-committers@freebsd.org, svn-src-projects@freebsd.org Subject: svn commit: r252529 - in projects/virtio: share/man/man4 sys/dev/virtio/block Message-ID: <201307030211.r632B5qJ078256@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
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); +}
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201307030211.r632B5qJ078256>