svn commit: r253132 - in stable/9/sys/dev/virtio: . balloon block network pci scsi

Bryan Venteicher bryanv at FreeBSD.org
Wed Jul 10 04:51:08 UTC 2013


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 <bryanv at daemoninthecloset.org>
+ * Copyright (c) 2011, Bryan Venteicher <bryanv at FreeBSD.org>
  * 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 <bryanv at daemoninthecloset.org>
+ * Copyright (c) 2011, Bryan Venteicher <bryanv at FreeBSD.org>
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -36,10 +36,10 @@ __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>
-#include <sys/taskqueue.h>
 
 #include <geom/geom_disk.h>
 
@@ -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 <bryanv at daemoninthecloset.org>
+ * Copyright (c) 2011, Bryan Venteicher <bryanv at FreeBSD.org>
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -42,7 +42,6 @@ __FBSDID("$FreeBSD$");
 #include <sys/module.h>
 #include <sys/socket.h>
 #include <sys/sysctl.h>
-#include <sys/taskqueue.h>
 #include <sys/random.h>
 #include <sys/sglist.h>
 #include <sys/lock.h>
@@ -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 <bryanv at daemoninthecloset.org>
+ * Copyright (c) 2011, Bryan Venteicher <bryanv at FreeBSD.org>
  * All rights reserved.

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***


More information about the svn-src-all mailing list