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

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
......@@ -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
};
/*
......
......@@ -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)
......
......@@ -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));
/*
......
......@@ -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 */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment