From owner-svn-src-stable@FreeBSD.ORG Wed Jul 10 04:51:08 2013 Return-Path: Delivered-To: svn-src-stable@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [8.8.178.115]) by hub.freebsd.org (Postfix) with ESMTP id A65741DB; Wed, 10 Jul 2013 04:51:08 +0000 (UTC) (envelope-from bryanv@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) by mx1.freebsd.org (Postfix) with ESMTP id 89ACF1275; Wed, 10 Jul 2013 04:51:08 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.7/8.14.7) with ESMTP id r6A4p8pp087662; Wed, 10 Jul 2013 04:51:08 GMT (envelope-from bryanv@svn.freebsd.org) Received: (from bryanv@localhost) by svn.freebsd.org (8.14.7/8.14.5/Submit) id r6A4p74F087655; Wed, 10 Jul 2013 04:51:07 GMT (envelope-from bryanv@svn.freebsd.org) Message-Id: <201307100451.r6A4p74F087655@svn.freebsd.org> From: Bryan Venteicher Date: Wed, 10 Jul 2013 04:51:07 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-9@freebsd.org Subject: svn commit: r253132 - in stable/9/sys/dev/virtio: . balloon block network pci scsi X-SVN-Group: stable-9 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-stable@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: SVN commit messages for all the -stable branches of the src tree List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 10 Jul 2013 04:51:08 -0000 Author: bryanv Date: Wed Jul 10 04:51:07 2013 New Revision: 253132 URL: http://svnweb.freebsd.org/changeset/base/253132 Log: MFC VirtIO r252702,r252703,r252704,r252706,r252707,r252708,r252709 This brings in several bug fixes and better conformance with various aspects of the spec that have changed. r252702: Convert VirtIO to use ithreads instead of taskqueues r252703: Block driver bug fixes and spec changes r252704: Balloon driver improvements r252706: Minor network driver improvements r252707: Minor misc VirtIO changes r252708: PCI driver bug fixes and cleanup r252709: Fix SCSI driver lock not owned panic Modified: stable/9/sys/dev/virtio/balloon/virtio_balloon.c stable/9/sys/dev/virtio/block/virtio_blk.c stable/9/sys/dev/virtio/block/virtio_blk.h stable/9/sys/dev/virtio/network/if_vtnet.c stable/9/sys/dev/virtio/network/if_vtnetvar.h stable/9/sys/dev/virtio/pci/virtio_pci.c stable/9/sys/dev/virtio/scsi/virtio_scsi.c stable/9/sys/dev/virtio/scsi/virtio_scsivar.h stable/9/sys/dev/virtio/virtio.c stable/9/sys/dev/virtio/virtio.h stable/9/sys/dev/virtio/virtio_bus_if.m stable/9/sys/dev/virtio/virtio_if.m stable/9/sys/dev/virtio/virtqueue.c stable/9/sys/dev/virtio/virtqueue.h Directory Properties: stable/9/sys/ (props changed) stable/9/sys/dev/ (props changed) Modified: stable/9/sys/dev/virtio/balloon/virtio_balloon.c ============================================================================== --- stable/9/sys/dev/virtio/balloon/virtio_balloon.c Wed Jul 10 01:33:49 2013 (r253131) +++ stable/9/sys/dev/virtio/balloon/virtio_balloon.c Wed Jul 10 04:51:07 2013 (r253132) @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2011, Bryan Venteicher + * Copyright (c) 2011, Bryan Venteicher * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -70,7 +70,7 @@ struct vtballoon_softc { uint32_t vtballoon_current_npages; TAILQ_HEAD(,vm_page) vtballoon_pages; - struct proc *vtballoon_kproc; + struct thread *vtballoon_td; uint32_t *vtballoon_page_frames; int vtballoon_timeout; }; @@ -90,7 +90,7 @@ static int vtballoon_config_change(devic static void vtballoon_negotiate_features(struct vtballoon_softc *); static int vtballoon_alloc_virtqueues(struct vtballoon_softc *); -static int vtballoon_vq_intr(void *); +static void vtballoon_vq_intr(void *); static void vtballoon_inflate(struct vtballoon_softc *, int); static void vtballoon_deflate(struct vtballoon_softc *, int); @@ -127,9 +127,9 @@ CTASSERT(VTBALLOON_PAGES_PER_REQUEST * s #define VTBALLOON_MTX(_sc) &(_sc)->vtballoon_mtx #define VTBALLOON_LOCK_INIT(_sc, _name) mtx_init(VTBALLOON_MTX((_sc)), _name, \ - "VirtIO Balloon Lock", MTX_SPIN) -#define VTBALLOON_LOCK(_sc) mtx_lock_spin(VTBALLOON_MTX((_sc))) -#define VTBALLOON_UNLOCK(_sc) mtx_unlock_spin(VTBALLOON_MTX((_sc))) + "VirtIO Balloon Lock", MTX_DEF) +#define VTBALLOON_LOCK(_sc) mtx_lock(VTBALLOON_MTX((_sc))) +#define VTBALLOON_UNLOCK(_sc) mtx_unlock(VTBALLOON_MTX((_sc))) #define VTBALLOON_LOCK_DESTROY(_sc) mtx_destroy(VTBALLOON_MTX((_sc))) static device_method_t vtballoon_methods[] = { @@ -206,10 +206,10 @@ vtballoon_attach(device_t dev) goto fail; } - error = kproc_create(vtballoon_thread, sc, &sc->vtballoon_kproc, + error = kthread_add(vtballoon_thread, sc, NULL, &sc->vtballoon_td, 0, 0, "virtio_balloon"); if (error) { - device_printf(dev, "cannot create balloon kproc\n"); + device_printf(dev, "cannot create balloon kthread\n"); goto fail; } @@ -230,15 +230,14 @@ vtballoon_detach(device_t dev) sc = device_get_softc(dev); - if (sc->vtballoon_kproc != NULL) { + if (sc->vtballoon_td != NULL) { VTBALLOON_LOCK(sc); sc->vtballoon_flags |= VTBALLOON_FLAG_DETACH; wakeup_one(sc); - msleep_spin(sc->vtballoon_kproc, VTBALLOON_MTX(sc), - "vtbdth", 0); + msleep(sc->vtballoon_td, VTBALLOON_MTX(sc), 0, "vtbdth", 0); VTBALLOON_UNLOCK(sc); - sc->vtballoon_kproc = NULL; + sc->vtballoon_td = NULL; } if (device_is_attached(dev)) { @@ -300,7 +299,7 @@ vtballoon_alloc_virtqueues(struct vtball return (virtio_alloc_virtqueues(dev, 0, nvqs, vq_info)); } -static int +static void vtballoon_vq_intr(void *xsc) { struct vtballoon_softc *sc; @@ -310,8 +309,6 @@ vtballoon_vq_intr(void *xsc) VTBALLOON_LOCK(sc); wakeup_one(sc); VTBALLOON_UNLOCK(sc); - - return (1); } static void @@ -322,28 +319,26 @@ vtballoon_inflate(struct vtballoon_softc int i; vq = sc->vtballoon_inflate_vq; - m = NULL; if (npages > VTBALLOON_PAGES_PER_REQUEST) npages = VTBALLOON_PAGES_PER_REQUEST; - KASSERT(npages > 0, ("balloon doesn't need inflating?")); for (i = 0; i < npages; i++) { - if ((m = vtballoon_alloc_page(sc)) == NULL) + if ((m = vtballoon_alloc_page(sc)) == NULL) { + sc->vtballoon_timeout = VTBALLOON_LOWMEM_TIMEOUT; break; + } sc->vtballoon_page_frames[i] = VM_PAGE_TO_PHYS(m) >> VIRTIO_BALLOON_PFN_SHIFT; - KASSERT(m->queue == PQ_NONE, ("allocated page on queue")); + KASSERT(m->queue == PQ_NONE, + ("%s: allocated page %p on queue", __func__, m)); TAILQ_INSERT_TAIL(&sc->vtballoon_pages, m, pageq); } if (i > 0) vtballoon_send_page_frames(sc, vq, i); - - if (m == NULL) - sc->vtballoon_timeout = VTBALLOON_LOWMEM_TIMEOUT; } static void @@ -359,11 +354,10 @@ vtballoon_deflate(struct vtballoon_softc if (npages > VTBALLOON_PAGES_PER_REQUEST) npages = VTBALLOON_PAGES_PER_REQUEST; - KASSERT(npages > 0, ("balloon doesn't need deflating?")); for (i = 0; i < npages; i++) { m = TAILQ_FIRST(&sc->vtballoon_pages); - KASSERT(m != NULL, ("no more pages to deflate")); + KASSERT(m != NULL, ("%s: no more pages to deflate", __func__)); sc->vtballoon_page_frames[i] = VM_PAGE_TO_PHYS(m) >> VIRTIO_BALLOON_PFN_SHIFT; @@ -385,7 +379,9 @@ vtballoon_deflate(struct vtballoon_softc KASSERT((TAILQ_EMPTY(&sc->vtballoon_pages) && sc->vtballoon_current_npages == 0) || (!TAILQ_EMPTY(&sc->vtballoon_pages) && - sc->vtballoon_current_npages != 0), ("balloon empty?")); + sc->vtballoon_current_npages != 0), + ("%s: bogus page count %d", __func__, + sc->vtballoon_current_npages)); } static void @@ -413,7 +409,7 @@ vtballoon_send_page_frames(struct vtball */ VTBALLOON_LOCK(sc); while ((c = virtqueue_dequeue(vq, NULL)) == NULL) - msleep_spin(sc, VTBALLOON_MTX(sc), "vtbspf", 0); + msleep(sc, VTBALLOON_MTX(sc), 0, "vtbspf", 0); VTBALLOON_UNLOCK(sc); KASSERT(c == vq, ("unexpected balloon operation response")); @@ -512,7 +508,7 @@ vtballoon_sleep(struct vtballoon_softc * if (current < desired && timeout == 0) break; - msleep_spin(sc, VTBALLOON_MTX(sc), "vtbslp", timeout); + msleep(sc, VTBALLOON_MTX(sc), 0, "vtbslp", timeout); } VTBALLOON_UNLOCK(sc); @@ -544,7 +540,7 @@ vtballoon_thread(void *xsc) } } - kproc_exit(0); + kthread_exit(); } static void Modified: stable/9/sys/dev/virtio/block/virtio_blk.c ============================================================================== --- stable/9/sys/dev/virtio/block/virtio_blk.c Wed Jul 10 01:33:49 2013 (r253131) +++ stable/9/sys/dev/virtio/block/virtio_blk.c Wed Jul 10 04:51:07 2013 (r253132) @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2011, Bryan Venteicher + * Copyright (c) 2011, Bryan Venteicher * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -36,10 +36,10 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include -#include #include @@ -62,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; @@ -73,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; @@ -85,11 +92,9 @@ struct vtblk_softc { vtblk_req_ready; struct vtblk_request *vtblk_req_ordered; - struct taskqueue *vtblk_tq; - struct task vtblk_intr_task; - int vtblk_max_nsegs; int vtblk_request_count; + enum vtblk_cache_mode vtblk_write_cache; struct vtblk_request vtblk_dump_request; }; @@ -102,8 +107,9 @@ static struct virtio_feature_desc vtblk_ { VIRTIO_BLK_F_RO, "ReadOnly" }, { VIRTIO_BLK_F_BLK_SIZE, "BlockSize" }, { VIRTIO_BLK_F_SCSI, "SCSICmds" }, - { VIRTIO_BLK_F_FLUSH, "FlushCmd" }, + { VIRTIO_BLK_F_WCE, "WriteCache" }, { VIRTIO_BLK_F_TOPOLOGY, "Topology" }, + { VIRTIO_BLK_F_CONFIG_WCE, "ConfigWCE" }, { 0, NULL } }; @@ -116,6 +122,7 @@ static int vtblk_detach(device_t); static int vtblk_suspend(device_t); static int vtblk_resume(device_t); static int vtblk_shutdown(device_t); +static int vtblk_config_change(device_t); static int vtblk_open(struct disk *); static int vtblk_close(struct disk *); @@ -128,6 +135,10 @@ static void vtblk_negotiate_features(str static int vtblk_maximum_segments(struct vtblk_softc *, struct virtio_blk_config *); static int vtblk_alloc_virtqueue(struct vtblk_softc *); +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 *); @@ -138,11 +149,12 @@ static struct vtblk_request * vtblk_bio_ static int vtblk_execute_request(struct vtblk_softc *, struct vtblk_request *); -static int vtblk_vq_intr(void *); -static void vtblk_intr_task(void *, int); +static void vtblk_vq_intr(void *); static void vtblk_stop(struct vtblk_softc *); +static void vtblk_read_config(struct vtblk_softc *, + struct virtio_blk_config *); static void vtblk_get_ident(struct vtblk_softc *); static void vtblk_prepare_dump(struct vtblk_softc *); static int vtblk_write_dump(struct vtblk_softc *, void *, off_t, size_t); @@ -167,9 +179,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_writecache_mode = -1; +TUNABLE_INT("hw.vtblk.writecache_mode", &vtblk_writecache_mode); /* Features desired/implemented by this driver. */ #define VTBLK_FEATURES \ @@ -179,13 +196,14 @@ TUNABLE_INT("hw.vtblk.no_ident", &vtblk_ VIRTIO_BLK_F_GEOMETRY | \ VIRTIO_BLK_F_RO | \ VIRTIO_BLK_F_BLK_SIZE | \ - VIRTIO_BLK_F_FLUSH | \ + VIRTIO_BLK_F_WCE | \ + VIRTIO_BLK_F_CONFIG_WCE | \ VIRTIO_RING_F_INDIRECT_DESC) #define VTBLK_MTX(_sc) &(_sc)->vtblk_mtx #define VTBLK_LOCK_INIT(_sc, _name) \ mtx_init(VTBLK_MTX((_sc)), (_name), \ - "VTBLK Lock", MTX_DEF) + "VirtIO Block Lock", MTX_DEF) #define VTBLK_LOCK(_sc) mtx_lock(VTBLK_MTX((_sc))) #define VTBLK_UNLOCK(_sc) mtx_unlock(VTBLK_MTX((_sc))) #define VTBLK_LOCK_DESTROY(_sc) mtx_destroy(VTBLK_MTX((_sc))) @@ -211,6 +229,9 @@ static device_method_t vtblk_methods[] = DEVMETHOD(device_resume, vtblk_resume), DEVMETHOD(device_shutdown, vtblk_shutdown), + /* VirtIO methods. */ + DEVMETHOD(virtio_config_change, vtblk_config_change), + DEVMETHOD_END }; @@ -284,10 +305,13 @@ 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. */ - virtio_read_device_config(dev, 0, &blkcfg, - sizeof(struct virtio_blk_config)); + vtblk_read_config(sc, &blkcfg); /* * With the current sglist(9) implementation, it is not easy @@ -333,24 +357,12 @@ vtblk_attach(device_t dev) vtblk_alloc_disk(sc, &blkcfg); - TASK_INIT(&sc->vtblk_intr_task, 0, vtblk_intr_task, sc); - sc->vtblk_tq = taskqueue_create_fast("vtblk_taskq", M_NOWAIT, - taskqueue_thread_enqueue, &sc->vtblk_tq); - if (sc->vtblk_tq == NULL) { - error = ENOMEM; - device_printf(dev, "cannot allocate taskqueue\n"); - goto fail; - } - error = virtio_setup_intr(dev, INTR_TYPE_BIO | INTR_ENTROPY); if (error) { device_printf(dev, "cannot setup virtqueue interrupt\n"); goto fail; } - taskqueue_start_threads(&sc->vtblk_tq, 1, PI_DISK, "%s taskq", - device_get_nameunit(dev)); - vtblk_create_disk(sc); virtqueue_enable_intr(sc->vtblk_vq); @@ -375,12 +387,6 @@ vtblk_detach(device_t dev) vtblk_stop(sc); VTBLK_UNLOCK(sc); - if (sc->vtblk_tq != NULL) { - taskqueue_drain(sc->vtblk_tq, &sc->vtblk_intr_task); - taskqueue_free(sc->vtblk_tq); - sc->vtblk_tq = NULL; - } - vtblk_drain(sc); if (sc->vtblk_disk != NULL) { @@ -441,6 +447,13 @@ vtblk_shutdown(device_t dev) } static int +vtblk_config_change(device_t dev) +{ + + return (0); +} + +static int vtblk_open(struct disk *dp) { struct vtblk_softc *sc; @@ -541,8 +554,8 @@ vtblk_strategy(struct bio *bp) max_nsegs = sc->vtblk_max_nsegs - VTBLK_MIN_SEGMENTS; KASSERT(nsegs <= max_nsegs, - ("bio %p spanned too many segments: %d, max: %d", - bp, nsegs, max_nsegs)); + ("%s: bio %p spanned too many segments: %d, max: %d", + __func__, bp, nsegs, max_nsegs)); } #endif @@ -606,6 +619,59 @@ vtblk_alloc_virtqueue(struct vtblk_softc } 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) +{ + int wc; + + 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); + + return (wc); +} + +static int +vtblk_write_cache_sysctl(SYSCTL_HANDLER_ARGS) +{ + struct vtblk_softc *sc; + int wc, error; + + 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 vtblk_alloc_disk(struct vtblk_softc *sc, struct virtio_blk_config *blkcfg) { device_t dev; @@ -621,6 +687,11 @@ 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); + dp->d_hba_subdevice = virtio_get_subdevice(dev); if ((sc->vtblk_flags & VTBLK_FLAG_READONLY) == 0) dp->d_dump = vtblk_dump; @@ -656,8 +727,18 @@ vtblk_alloc_disk(struct vtblk_softc *sc, dp->d_fwheads = blkcfg->geometry.heads; } - if (virtio_with_feature(dev, VIRTIO_BLK_F_FLUSH)) - dp->d_flags |= DISKFLAG_CANFLUSHCACHE; + if (virtio_with_feature(dev, VIRTIO_BLK_F_TOPOLOGY)) { + dp->d_stripesize = dp->d_sectorsize * + (1 << blkcfg->topology.physical_block_exp); + dp->d_stripeoffset = (dp->d_stripesize - + blkcfg->topology.alignment_offset * dp->d_sectorsize) % + dp->d_stripesize; + } + + if (vtblk_write_cache_enabled(sc, blkcfg) != 0) + sc->vtblk_write_cache = VTBLK_CACHE_WRITEBACK; + else + sc->vtblk_write_cache = VTBLK_CACHE_WRITETHROUGH; } static void @@ -765,8 +846,7 @@ vtblk_bio_request(struct vtblk_softc *sc req->vbr_hdr.sector = bp->bio_offset / 512; break; default: - panic("%s: bio with unhandled cmd: %d", __FUNCTION__, - bp->bio_cmd); + panic("%s: bio with unhandled cmd: %d", __func__, bp->bio_cmd); } return (req); @@ -809,14 +889,13 @@ vtblk_execute_request(struct vtblk_softc } sglist_reset(sg); - sglist_append(sg, &req->vbr_hdr, sizeof(struct virtio_blk_outhdr)); if (bp->bio_cmd == BIO_READ || bp->bio_cmd == BIO_WRITE) { error = sglist_append(sg, bp->bio_data, bp->bio_bcount); if (error || sg->sg_nseg == sg->sg_maxseg) panic("%s: data buffer too big bio:%p error:%d", - __FUNCTION__, bp, error); + __func__, bp, error); /* BIO_READ means the host writes into our buffer. */ if (bp->bio_cmd == BIO_READ) @@ -834,28 +913,16 @@ vtblk_execute_request(struct vtblk_softc return (error); } -static int -vtblk_vq_intr(void *xsc) -{ - struct vtblk_softc *sc; - - sc = xsc; - - virtqueue_disable_intr(sc->vtblk_vq); - taskqueue_enqueue_fast(sc->vtblk_tq, &sc->vtblk_intr_task); - - return (1); -} - static void -vtblk_intr_task(void *arg, int pending) +vtblk_vq_intr(void *xsc) { struct vtblk_softc *sc; struct virtqueue *vq; - sc = arg; + sc = xsc; vq = sc->vtblk_vq; +again: VTBLK_LOCK(sc); if (sc->vtblk_flags & VTBLK_FLAG_DETACH) { VTBLK_UNLOCK(sc); @@ -872,9 +939,7 @@ vtblk_intr_task(void *arg, int pending) if (virtqueue_enable_intr(vq) != 0) { virtqueue_disable_intr(vq); VTBLK_UNLOCK(sc); - taskqueue_enqueue_fast(sc->vtblk_tq, - &sc->vtblk_intr_task); - return; + goto again; } VTBLK_UNLOCK(sc); @@ -888,6 +953,37 @@ vtblk_stop(struct vtblk_softc *sc) virtio_stop(sc->vtblk_dev); } +#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), \ + &(_cfg)->_field, sizeof((_cfg)->_field)); \ + } + +static void +vtblk_read_config(struct vtblk_softc *sc, struct virtio_blk_config *blkcfg) +{ + device_t dev; + + dev = sc->vtblk_dev; + + bzero(blkcfg, sizeof(struct virtio_blk_config)); + + /* The capacity is always available. */ + virtio_read_device_config(dev, offsetof(struct virtio_blk_config, + capacity), &blkcfg->capacity, sizeof(blkcfg->capacity)); + + /* Read the configuration if the feature was negotiated. */ + VTBLK_GET_CONFIG(dev, VIRTIO_BLK_F_SIZE_MAX, size_max, blkcfg); + VTBLK_GET_CONFIG(dev, VIRTIO_BLK_F_SEG_MAX, seg_max, blkcfg); + VTBLK_GET_CONFIG(dev, VIRTIO_BLK_F_GEOMETRY, geometry, blkcfg); + VTBLK_GET_CONFIG(dev, VIRTIO_BLK_F_BLK_SIZE, blk_size, blkcfg); + VTBLK_GET_CONFIG(dev, VIRTIO_BLK_F_TOPOLOGY, topology, blkcfg); + VTBLK_GET_CONFIG(dev, VIRTIO_BLK_F_CONFIG_WCE, writeback, blkcfg); +} + +#undef VTBLK_GET_CONFIG + static void vtblk_get_ident(struct vtblk_softc *sc) { @@ -899,7 +995,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); @@ -949,8 +1045,10 @@ vtblk_prepare_dump(struct vtblk_softc *s */ vtblk_drain_vq(sc, 1); - if (virtio_reinit(dev, sc->vtblk_features) != 0) - panic("cannot reinit VirtIO block device during dump"); + if (virtio_reinit(dev, sc->vtblk_features) != 0) { + panic("%s: cannot reinit VirtIO block device during dump", + device_get_nameunit(dev)); + } virtqueue_disable_intr(vq); virtio_reinit_complete(dev); @@ -1003,7 +1101,6 @@ static int vtblk_poll_request(struct vtblk_softc *sc, struct vtblk_request *req) { struct virtqueue *vq; - struct vtblk_request *r; int error; vq = sc->vtblk_vq; @@ -1016,14 +1113,12 @@ vtblk_poll_request(struct vtblk_softc *s return (error); virtqueue_notify(vq); - - r = virtqueue_poll(vq, NULL); - KASSERT(r == req, ("unexpected request response: %p/%p", r, req)); + virtqueue_poll(vq, NULL); error = vtblk_request_error(req); if (error && bootverbose) { device_printf(sc->vtblk_dev, - "%s: IO error: %d\n", __FUNCTION__, error); + "%s: IO error: %d\n", __func__, error); } return (error); @@ -1154,7 +1249,7 @@ vtblk_free_requests(struct vtblk_softc * struct vtblk_request *req; KASSERT(TAILQ_EMPTY(&sc->vtblk_req_ready), - ("ready requests left on queue")); + ("%s: ready requests left on queue", __func__)); while ((req = vtblk_dequeue_request(sc)) != NULL) { sc->vtblk_request_count--; @@ -1162,7 +1257,7 @@ vtblk_free_requests(struct vtblk_softc * } KASSERT(sc->vtblk_request_count == 0, - ("leaked requests: %d", sc->vtblk_request_count)); + ("%s: leaked %d requests", __func__, sc->vtblk_request_count)); } static struct vtblk_request * @@ -1236,3 +1331,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); +} Modified: stable/9/sys/dev/virtio/block/virtio_blk.h ============================================================================== --- stable/9/sys/dev/virtio/block/virtio_blk.h Wed Jul 10 01:33:49 2013 (r253131) +++ stable/9/sys/dev/virtio/block/virtio_blk.h Wed Jul 10 04:51:07 2013 (r253132) @@ -39,8 +39,9 @@ #define VIRTIO_BLK_F_RO 0x0020 /* Disk is read-only */ #define VIRTIO_BLK_F_BLK_SIZE 0x0040 /* Block size of disk is available*/ #define VIRTIO_BLK_F_SCSI 0x0080 /* Supports scsi command passthru */ -#define VIRTIO_BLK_F_FLUSH 0x0200 /* Cache flush command support */ +#define VIRTIO_BLK_F_WCE 0x0200 /* Writeback mode enabled after reset */ #define VIRTIO_BLK_F_TOPOLOGY 0x0400 /* Topology information is available */ +#define VIRTIO_BLK_F_CONFIG_WCE 0x0800 /* Writeback mode available in config */ #define VIRTIO_BLK_ID_BYTES 20 /* ID string length */ @@ -51,15 +52,27 @@ struct virtio_blk_config { uint32_t size_max; /* The maximum number of segments (if VIRTIO_BLK_F_SEG_MAX) */ uint32_t seg_max; - /* geometry the device (if VIRTIO_BLK_F_GEOMETRY) */ + /* Geometry of the device (if VIRTIO_BLK_F_GEOMETRY) */ struct virtio_blk_geometry { uint16_t cylinders; uint8_t heads; uint8_t sectors; } geometry; - /* block size of device (if VIRTIO_BLK_F_BLK_SIZE) */ + /* Block size of device (if VIRTIO_BLK_F_BLK_SIZE) */ uint32_t blk_size; + + /* Topology of the device (if VIRTIO_BLK_F_TOPOLOGY) */ + struct virtio_blk_topology { + uint8_t physical_block_exp; + uint8_t alignment_offset; + uint16_t min_io_size; + uint16_t opt_io_size; + } topology; + + /* Writeback mode (if VIRTIO_BLK_F_CONFIG_WCE) */ + uint8_t writeback; + } __packed; /* Modified: stable/9/sys/dev/virtio/network/if_vtnet.c ============================================================================== --- stable/9/sys/dev/virtio/network/if_vtnet.c Wed Jul 10 01:33:49 2013 (r253131) +++ stable/9/sys/dev/virtio/network/if_vtnet.c Wed Jul 10 04:51:07 2013 (r253132) @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2011, Bryan Venteicher + * Copyright (c) 2011, Bryan Venteicher * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -42,7 +42,6 @@ __FBSDID("$FreeBSD$"); #include #include #include -#include #include #include #include @@ -97,7 +96,6 @@ static void vtnet_set_hwaddr(struct vtne static int vtnet_is_link_up(struct vtnet_softc *); static void vtnet_update_link_status(struct vtnet_softc *); static void vtnet_watchdog(struct vtnet_softc *); -static void vtnet_config_change_task(void *, int); static int vtnet_change_mtu(struct vtnet_softc *, int); static int vtnet_ioctl(struct ifnet *, u_long, caddr_t); @@ -123,8 +121,7 @@ static int vtnet_rx_csum(struct vtnet_so struct virtio_net_hdr *); static int vtnet_rxeof_merged(struct vtnet_softc *, struct mbuf *, int); static int vtnet_rxeof(struct vtnet_softc *, int, int *); -static void vtnet_rx_intr_task(void *, int); -static int vtnet_rx_vq_intr(void *); +static void vtnet_rx_vq_intr(void *); static void vtnet_txeof(struct vtnet_softc *); static struct mbuf * vtnet_tx_offload(struct vtnet_softc *, struct mbuf *, @@ -135,8 +132,7 @@ static int vtnet_encap(struct vtnet_soft static void vtnet_start_locked(struct ifnet *); static void vtnet_start(struct ifnet *); static void vtnet_tick(void *); -static void vtnet_tx_intr_task(void *, int); -static int vtnet_tx_vq_intr(void *); +static void vtnet_tx_vq_intr(void *); static void vtnet_stop(struct vtnet_softc *); static int vtnet_reinit(struct vtnet_softc *); @@ -427,19 +423,6 @@ vtnet_attach(device_t dev) ifp->if_capabilities |= IFCAP_POLLING; #endif - TASK_INIT(&sc->vtnet_rx_intr_task, 0, vtnet_rx_intr_task, sc); - TASK_INIT(&sc->vtnet_tx_intr_task, 0, vtnet_tx_intr_task, sc); - TASK_INIT(&sc->vtnet_cfgchg_task, 0, vtnet_config_change_task, sc); - - sc->vtnet_tq = taskqueue_create_fast("vtnet_taskq", M_NOWAIT, - taskqueue_thread_enqueue, &sc->vtnet_tq); - if (sc->vtnet_tq == NULL) { - error = ENOMEM; - device_printf(dev, "cannot allocate taskqueue\n"); - ether_ifdetach(ifp); - goto fail; - } - error = virtio_setup_intr(dev, INTR_TYPE_NET); if (error) { device_printf(dev, "cannot setup virtqueue interrupts\n"); @@ -447,9 +430,6 @@ vtnet_attach(device_t dev) goto fail; } - taskqueue_start_threads(&sc->vtnet_tq, 1, PI_NET, "%s taskq", - device_get_nameunit(dev)); - /* * Device defaults to promiscuous mode for backwards * compatibility. Turn it off if possible. @@ -495,18 +475,10 @@ vtnet_detach(device_t dev) VTNET_UNLOCK(sc); callout_drain(&sc->vtnet_tick_ch); - taskqueue_drain(taskqueue_fast, &sc->vtnet_cfgchg_task); ether_ifdetach(ifp); } - if (sc->vtnet_tq != NULL) { - taskqueue_drain(sc->vtnet_tq, &sc->vtnet_rx_intr_task); - taskqueue_drain(sc->vtnet_tq, &sc->vtnet_tx_intr_task); - taskqueue_free(sc->vtnet_tq); - sc->vtnet_tq = NULL; - } - if (sc->vtnet_vlan_attach != NULL) { EVENTHANDLER_DEREGISTER(vlan_config, sc->vtnet_vlan_attach); sc->vtnet_vlan_attach = NULL; @@ -590,9 +562,11 @@ vtnet_config_change(device_t dev) sc = device_get_softc(dev); - taskqueue_enqueue_fast(taskqueue_fast, &sc->vtnet_cfgchg_task); + VTNET_LOCK(sc); + vtnet_update_link_status(sc); + VTNET_UNLOCK(sc); - return (1); + return (0); } static void @@ -788,18 +762,6 @@ vtnet_watchdog(struct vtnet_softc *sc) vtnet_init_locked(sc); } -static void -vtnet_config_change_task(void *arg, int pending) -{ - struct vtnet_softc *sc; - - sc = arg; - - VTNET_LOCK(sc); - vtnet_update_link_status(sc); - VTNET_UNLOCK(sc); -} - static int vtnet_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) { @@ -1705,15 +1667,16 @@ vtnet_rxeof(struct vtnet_softc *sc, int } static void -vtnet_rx_intr_task(void *arg, int pending) +vtnet_rx_vq_intr(void *xsc) { struct vtnet_softc *sc; struct ifnet *ifp; int more; - sc = arg; + sc = xsc; ifp = sc->vtnet_ifp; +again: VTNET_LOCK(sc); #ifdef DEVICE_POLLING @@ -1730,31 +1693,15 @@ vtnet_rx_intr_task(void *arg, int pendin } more = vtnet_rxeof(sc, sc->vtnet_rx_process_limit, NULL); - if (!more && vtnet_enable_rx_intr(sc) != 0) { - vtnet_disable_rx_intr(sc); - more = 1; - } - - VTNET_UNLOCK(sc); - - if (more) { + if (more || vtnet_enable_rx_intr(sc) != 0) { + if (!more) + vtnet_disable_rx_intr(sc); sc->vtnet_stats.rx_task_rescheduled++; - taskqueue_enqueue_fast(sc->vtnet_tq, - &sc->vtnet_rx_intr_task); + VTNET_UNLOCK(sc); + goto again; } -} - -static int -vtnet_rx_vq_intr(void *xsc) -{ - struct vtnet_softc *sc; - - sc = xsc; - vtnet_disable_rx_intr(sc); - taskqueue_enqueue_fast(sc->vtnet_tq, &sc->vtnet_rx_intr_task); - - return (1); + VTNET_UNLOCK(sc); } static void @@ -1800,7 +1747,6 @@ vtnet_tx_offload(struct vtnet_softc *sc, uint8_t ip_proto, gso_type; ifp = sc->vtnet_ifp; - M_ASSERTPKTHDR(m); ip_offset = sizeof(struct ether_header); if (m->m_len < ip_offset) { @@ -1918,7 +1864,7 @@ vtnet_enqueue_txbuf(struct vtnet_softc * sglist_init(&sg, VTNET_MAX_TX_SEGS, segs); error = sglist_append(&sg, &txhdr->vth_uhdr, sc->vtnet_hdr_size); KASSERT(error == 0 && sg.sg_nseg == 1, - ("cannot add header to sglist")); + ("%s: cannot add header to sglist error %d", __func__, error)); again: error = sglist_append_mbuf(&sg, m); @@ -1955,6 +1901,7 @@ vtnet_encap(struct vtnet_softc *sc, stru int error; m = *m_head; + M_ASSERTPKTHDR(m); txhdr = uma_zalloc(vtnet_tx_header_zone, M_NOWAIT | M_ZERO); if (txhdr == NULL) { @@ -2077,14 +2024,15 @@ vtnet_tick(void *xsc) } static void -vtnet_tx_intr_task(void *arg, int pending) +vtnet_tx_vq_intr(void *xsc) { struct vtnet_softc *sc; struct ifnet *ifp; - sc = arg; + sc = xsc; ifp = sc->vtnet_ifp; +again: VTNET_LOCK(sc); #ifdef DEVICE_POLLING @@ -2109,26 +2057,12 @@ vtnet_tx_intr_task(void *arg, int pendin vtnet_disable_tx_intr(sc); sc->vtnet_stats.tx_task_rescheduled++; VTNET_UNLOCK(sc); - taskqueue_enqueue_fast(sc->vtnet_tq, &sc->vtnet_tx_intr_task); - return; + goto again; } VTNET_UNLOCK(sc); } -static int -vtnet_tx_vq_intr(void *xsc) -{ - struct vtnet_softc *sc; - - sc = xsc; - - vtnet_disable_tx_intr(sc); - taskqueue_enqueue_fast(sc->vtnet_tq, &sc->vtnet_tx_intr_task); - - return (1); -} - static void vtnet_stop(struct vtnet_softc *sc) { Modified: stable/9/sys/dev/virtio/network/if_vtnetvar.h ============================================================================== --- stable/9/sys/dev/virtio/network/if_vtnetvar.h Wed Jul 10 01:33:49 2013 (r253131) +++ stable/9/sys/dev/virtio/network/if_vtnetvar.h Wed Jul 10 04:51:07 2013 (r253132) @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2011, Bryan Venteicher + * Copyright (c) 2011, Bryan Venteicher * All rights reserved. *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***