Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 95b18e69 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'virtio-for-linus' of...

Merge tag 'virtio-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rusty/linux-2.6-for-linus

Pull virtio update from Rusty Russell:
 "Virtio patches, mainly hotplugging fixes."

* tag 'virtio-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rusty/linux-2.6-for-linus:
  virtio-blk: return VIRTIO_BLK_F_FLUSH to header.
  virtio-blk: allow toggling host cache between writeback and writethrough
  virtio-blk: Use block layer provided spinlock
  virtio-blk: Reset device after blk_cleanup_queue()
  virtio-blk: Call del_gendisk() before disable guest kick
  virtio: rng: s3/s4 support
  virtio: rng: split out common code in probe / remove for s3/s4 ops
  virtio: rng: don't wait on host when module is going away
  virtio: rng: allow tasks to be killed that are waiting for rng input
  virtio ids: fix comment for virtio-rng
parents 6d8a97af 6a743897
Loading
Loading
Loading
Loading
+93 −22
Original line number Diff line number Diff line
@@ -21,8 +21,6 @@ struct workqueue_struct *virtblk_wq;

struct virtio_blk
{
	spinlock_t lock;

	struct virtio_device *vdev;
	struct virtqueue *vq;

@@ -65,7 +63,7 @@ static void blk_done(struct virtqueue *vq)
	unsigned int len;
	unsigned long flags;

	spin_lock_irqsave(&vblk->lock, flags);
	spin_lock_irqsave(vblk->disk->queue->queue_lock, flags);
	while ((vbr = virtqueue_get_buf(vblk->vq, &len)) != NULL) {
		int error;

@@ -99,7 +97,7 @@ static void blk_done(struct virtqueue *vq)
	}
	/* In case queue is stopped waiting for more buffers. */
	blk_start_queue(vblk->disk->queue);
	spin_unlock_irqrestore(&vblk->lock, flags);
	spin_unlock_irqrestore(vblk->disk->queue->queue_lock, flags);
}

static bool do_req(struct request_queue *q, struct virtio_blk *vblk,
@@ -397,6 +395,83 @@ static int virtblk_name_format(char *prefix, int index, char *buf, int buflen)
	return 0;
}

static int virtblk_get_cache_mode(struct virtio_device *vdev)
{
	u8 writeback;
	int err;

	err = virtio_config_val(vdev, VIRTIO_BLK_F_CONFIG_WCE,
				offsetof(struct virtio_blk_config, wce),
				&writeback);
	if (err)
		writeback = virtio_has_feature(vdev, VIRTIO_BLK_F_WCE);

	return writeback;
}

static void virtblk_update_cache_mode(struct virtio_device *vdev)
{
	u8 writeback = virtblk_get_cache_mode(vdev);
	struct virtio_blk *vblk = vdev->priv;

	if (writeback)
		blk_queue_flush(vblk->disk->queue, REQ_FLUSH);
	else
		blk_queue_flush(vblk->disk->queue, 0);

	revalidate_disk(vblk->disk);
}

static const char *const virtblk_cache_types[] = {
	"write through", "write back"
};

static ssize_t
virtblk_cache_type_store(struct device *dev, struct device_attribute *attr,
			 const char *buf, size_t count)
{
	struct gendisk *disk = dev_to_disk(dev);
	struct virtio_blk *vblk = disk->private_data;
	struct virtio_device *vdev = vblk->vdev;
	int i;
	u8 writeback;

	BUG_ON(!virtio_has_feature(vblk->vdev, VIRTIO_BLK_F_CONFIG_WCE));
	for (i = ARRAY_SIZE(virtblk_cache_types); --i >= 0; )
		if (sysfs_streq(buf, virtblk_cache_types[i]))
			break;

	if (i < 0)
		return -EINVAL;

	writeback = i;
	vdev->config->set(vdev,
			  offsetof(struct virtio_blk_config, wce),
			  &writeback, sizeof(writeback));

	virtblk_update_cache_mode(vdev);
	return count;
}

static ssize_t
virtblk_cache_type_show(struct device *dev, struct device_attribute *attr,
			 char *buf)
{
	struct gendisk *disk = dev_to_disk(dev);
	struct virtio_blk *vblk = disk->private_data;
	u8 writeback = virtblk_get_cache_mode(vblk->vdev);

	BUG_ON(writeback >= ARRAY_SIZE(virtblk_cache_types));
	return snprintf(buf, 40, "%s\n", virtblk_cache_types[writeback]);
}

static const struct device_attribute dev_attr_cache_type_ro =
	__ATTR(cache_type, S_IRUGO,
	       virtblk_cache_type_show, NULL);
static const struct device_attribute dev_attr_cache_type_rw =
	__ATTR(cache_type, S_IRUGO|S_IWUSR,
	       virtblk_cache_type_show, virtblk_cache_type_store);

static int __devinit virtblk_probe(struct virtio_device *vdev)
{
	struct virtio_blk *vblk;
@@ -431,7 +506,6 @@ static int __devinit virtblk_probe(struct virtio_device *vdev)
		goto out_free_index;
	}

	spin_lock_init(&vblk->lock);
	vblk->vdev = vdev;
	vblk->sg_elems = sg_elems;
	sg_init_table(vblk->sg, vblk->sg_elems);
@@ -456,7 +530,7 @@ static int __devinit virtblk_probe(struct virtio_device *vdev)
		goto out_mempool;
	}

	q = vblk->disk->queue = blk_init_queue(do_virtblk_request, &vblk->lock);
	q = vblk->disk->queue = blk_init_queue(do_virtblk_request, NULL);
	if (!q) {
		err = -ENOMEM;
		goto out_put_disk;
@@ -474,8 +548,7 @@ static int __devinit virtblk_probe(struct virtio_device *vdev)
	vblk->index = index;

	/* configure queue flush support */
	if (virtio_has_feature(vdev, VIRTIO_BLK_F_FLUSH))
		blk_queue_flush(q, REQ_FLUSH);
	virtblk_update_cache_mode(vdev);

	/* If disk is read-only in the host, the guest should obey */
	if (virtio_has_feature(vdev, VIRTIO_BLK_F_RO))
@@ -553,6 +626,14 @@ static int __devinit virtblk_probe(struct virtio_device *vdev)
	if (err)
		goto out_del_disk;

	if (virtio_has_feature(vdev, VIRTIO_BLK_F_CONFIG_WCE))
		err = device_create_file(disk_to_dev(vblk->disk),
					 &dev_attr_cache_type_rw);
	else
		err = device_create_file(disk_to_dev(vblk->disk),
					 &dev_attr_cache_type_ro);
	if (err)
		goto out_del_disk;
	return 0;

out_del_disk:
@@ -576,30 +657,20 @@ static void __devexit virtblk_remove(struct virtio_device *vdev)
{
	struct virtio_blk *vblk = vdev->priv;
	int index = vblk->index;
	struct virtblk_req *vbr;
	unsigned long flags;

	/* Prevent config work handler from accessing the device. */
	mutex_lock(&vblk->config_lock);
	vblk->config_enable = false;
	mutex_unlock(&vblk->config_lock);

	del_gendisk(vblk->disk);
	blk_cleanup_queue(vblk->disk->queue);

	/* Stop all the virtqueues. */
	vdev->config->reset(vdev);

	flush_work(&vblk->config_work);

	del_gendisk(vblk->disk);

	/* Abort requests dispatched to driver. */
	spin_lock_irqsave(&vblk->lock, flags);
	while ((vbr = virtqueue_detach_unused_buf(vblk->vq))) {
		__blk_end_request_all(vbr->req, -EIO);
		mempool_free(vbr, vblk->pool);
	}
	spin_unlock_irqrestore(&vblk->lock, flags);

	blk_cleanup_queue(vblk->disk->queue);
	put_disk(vblk->disk);
	mempool_destroy(vblk->pool);
	vdev->config->del_vqs(vdev);
@@ -655,7 +726,7 @@ static const struct virtio_device_id id_table[] = {
static unsigned int features[] = {
	VIRTIO_BLK_F_SEG_MAX, VIRTIO_BLK_F_SIZE_MAX, VIRTIO_BLK_F_GEOMETRY,
	VIRTIO_BLK_F_RO, VIRTIO_BLK_F_BLK_SIZE, VIRTIO_BLK_F_SCSI,
	VIRTIO_BLK_F_FLUSH, VIRTIO_BLK_F_TOPOLOGY
	VIRTIO_BLK_F_WCE, VIRTIO_BLK_F_TOPOLOGY, VIRTIO_BLK_F_CONFIG_WCE
};

/*
+34 −3
Original line number Diff line number Diff line
@@ -55,6 +55,7 @@ static void register_buffer(u8 *buf, size_t size)

static int virtio_read(struct hwrng *rng, void *buf, size_t size, bool wait)
{
	int ret;

	if (!busy) {
		busy = true;
@@ -65,7 +66,9 @@ static int virtio_read(struct hwrng *rng, void *buf, size_t size, bool wait)
	if (!wait)
		return 0;

	wait_for_completion(&have_data);
	ret = wait_for_completion_killable(&have_data);
	if (ret < 0)
		return ret;

	busy = false;

@@ -85,7 +88,7 @@ static struct hwrng virtio_hwrng = {
	.read		= virtio_read,
};

static int virtrng_probe(struct virtio_device *vdev)
static int probe_common(struct virtio_device *vdev)
{
	int err;

@@ -103,13 +106,37 @@ static int virtrng_probe(struct virtio_device *vdev)
	return 0;
}

static void __devexit virtrng_remove(struct virtio_device *vdev)
static void remove_common(struct virtio_device *vdev)
{
	vdev->config->reset(vdev);
	busy = false;
	hwrng_unregister(&virtio_hwrng);
	vdev->config->del_vqs(vdev);
}

static int virtrng_probe(struct virtio_device *vdev)
{
	return probe_common(vdev);
}

static void __devexit virtrng_remove(struct virtio_device *vdev)
{
	remove_common(vdev);
}

#ifdef CONFIG_PM
static int virtrng_freeze(struct virtio_device *vdev)
{
	remove_common(vdev);
	return 0;
}

static int virtrng_restore(struct virtio_device *vdev)
{
	return probe_common(vdev);
}
#endif

static struct virtio_device_id id_table[] = {
	{ VIRTIO_ID_RNG, VIRTIO_DEV_ANY_ID },
	{ 0 },
@@ -121,6 +148,10 @@ static struct virtio_driver virtio_rng_driver = {
	.id_table =	id_table,
	.probe =	virtrng_probe,
	.remove =	__devexit_p(virtrng_remove),
#ifdef CONFIG_PM
	.freeze =	virtrng_freeze,
	.restore =	virtrng_restore,
#endif
};

static int __init init(void)
+9 −1
Original line number Diff line number Diff line
@@ -37,8 +37,14 @@
#define VIRTIO_BLK_F_RO		5	/* Disk is read-only */
#define VIRTIO_BLK_F_BLK_SIZE	6	/* Block size of disk is available*/
#define VIRTIO_BLK_F_SCSI	7	/* Supports scsi command passthru */
#define VIRTIO_BLK_F_FLUSH	9	/* Cache flush command support */
#define VIRTIO_BLK_F_WCE	9	/* Writeback mode enabled after reset */
#define VIRTIO_BLK_F_TOPOLOGY	10	/* Topology information is available */
#define VIRTIO_BLK_F_CONFIG_WCE	11	/* Writeback mode available in config */

#ifndef __KERNEL__
/* Old (deprecated) name for VIRTIO_BLK_F_WCE. */
#define VIRTIO_BLK_F_FLUSH VIRTIO_BLK_F_WCE
#endif

#define VIRTIO_BLK_ID_BYTES	20	/* ID string length */

@@ -69,6 +75,8 @@ struct virtio_blk_config {
	/* optimal sustained I/O size in logical blocks. */
	__u32 opt_io_size;

	/* writeback mode (if VIRTIO_BLK_F_CONFIG_WCE) */
	__u8 wce;
} __attribute__((packed));

/*
+1 −1
Original line number Diff line number Diff line
@@ -32,7 +32,7 @@
#define VIRTIO_ID_NET		1 /* virtio net */
#define VIRTIO_ID_BLOCK		2 /* virtio block */
#define VIRTIO_ID_CONSOLE	3 /* virtio console */
#define VIRTIO_ID_RNG		4 /* virtio ring */
#define VIRTIO_ID_RNG		4 /* virtio rng */
#define VIRTIO_ID_BALLOON	5 /* virtio balloon */
#define VIRTIO_ID_RPMSG		7 /* virtio remote processor messaging */
#define VIRTIO_ID_SCSI		8 /* virtio scsi */