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
This commit is contained in:
@@ -21,8 +21,6 @@ struct workqueue_struct *virtblk_wq;
|
|||||||
|
|
||||||
struct virtio_blk
|
struct virtio_blk
|
||||||
{
|
{
|
||||||
spinlock_t lock;
|
|
||||||
|
|
||||||
struct virtio_device *vdev;
|
struct virtio_device *vdev;
|
||||||
struct virtqueue *vq;
|
struct virtqueue *vq;
|
||||||
|
|
||||||
@@ -65,7 +63,7 @@ static void blk_done(struct virtqueue *vq)
|
|||||||
unsigned int len;
|
unsigned int len;
|
||||||
unsigned long flags;
|
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) {
|
while ((vbr = virtqueue_get_buf(vblk->vq, &len)) != NULL) {
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
@@ -99,7 +97,7 @@ static void blk_done(struct virtqueue *vq)
|
|||||||
}
|
}
|
||||||
/* In case queue is stopped waiting for more buffers. */
|
/* In case queue is stopped waiting for more buffers. */
|
||||||
blk_start_queue(vblk->disk->queue);
|
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,
|
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;
|
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)
|
static int __devinit virtblk_probe(struct virtio_device *vdev)
|
||||||
{
|
{
|
||||||
struct virtio_blk *vblk;
|
struct virtio_blk *vblk;
|
||||||
@@ -431,7 +506,6 @@ static int __devinit virtblk_probe(struct virtio_device *vdev)
|
|||||||
goto out_free_index;
|
goto out_free_index;
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_lock_init(&vblk->lock);
|
|
||||||
vblk->vdev = vdev;
|
vblk->vdev = vdev;
|
||||||
vblk->sg_elems = sg_elems;
|
vblk->sg_elems = sg_elems;
|
||||||
sg_init_table(vblk->sg, vblk->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;
|
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) {
|
if (!q) {
|
||||||
err = -ENOMEM;
|
err = -ENOMEM;
|
||||||
goto out_put_disk;
|
goto out_put_disk;
|
||||||
@@ -474,8 +548,7 @@ static int __devinit virtblk_probe(struct virtio_device *vdev)
|
|||||||
vblk->index = index;
|
vblk->index = index;
|
||||||
|
|
||||||
/* configure queue flush support */
|
/* configure queue flush support */
|
||||||
if (virtio_has_feature(vdev, VIRTIO_BLK_F_FLUSH))
|
virtblk_update_cache_mode(vdev);
|
||||||
blk_queue_flush(q, REQ_FLUSH);
|
|
||||||
|
|
||||||
/* If disk is read-only in the host, the guest should obey */
|
/* If disk is read-only in the host, the guest should obey */
|
||||||
if (virtio_has_feature(vdev, VIRTIO_BLK_F_RO))
|
if (virtio_has_feature(vdev, VIRTIO_BLK_F_RO))
|
||||||
@@ -553,6 +626,14 @@ static int __devinit virtblk_probe(struct virtio_device *vdev)
|
|||||||
if (err)
|
if (err)
|
||||||
goto out_del_disk;
|
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;
|
return 0;
|
||||||
|
|
||||||
out_del_disk:
|
out_del_disk:
|
||||||
@@ -576,30 +657,20 @@ static void __devexit virtblk_remove(struct virtio_device *vdev)
|
|||||||
{
|
{
|
||||||
struct virtio_blk *vblk = vdev->priv;
|
struct virtio_blk *vblk = vdev->priv;
|
||||||
int index = vblk->index;
|
int index = vblk->index;
|
||||||
struct virtblk_req *vbr;
|
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
/* Prevent config work handler from accessing the device. */
|
/* Prevent config work handler from accessing the device. */
|
||||||
mutex_lock(&vblk->config_lock);
|
mutex_lock(&vblk->config_lock);
|
||||||
vblk->config_enable = false;
|
vblk->config_enable = false;
|
||||||
mutex_unlock(&vblk->config_lock);
|
mutex_unlock(&vblk->config_lock);
|
||||||
|
|
||||||
|
del_gendisk(vblk->disk);
|
||||||
|
blk_cleanup_queue(vblk->disk->queue);
|
||||||
|
|
||||||
/* Stop all the virtqueues. */
|
/* Stop all the virtqueues. */
|
||||||
vdev->config->reset(vdev);
|
vdev->config->reset(vdev);
|
||||||
|
|
||||||
flush_work(&vblk->config_work);
|
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);
|
put_disk(vblk->disk);
|
||||||
mempool_destroy(vblk->pool);
|
mempool_destroy(vblk->pool);
|
||||||
vdev->config->del_vqs(vdev);
|
vdev->config->del_vqs(vdev);
|
||||||
@@ -655,7 +726,7 @@ static const struct virtio_device_id id_table[] = {
|
|||||||
static unsigned int features[] = {
|
static unsigned int features[] = {
|
||||||
VIRTIO_BLK_F_SEG_MAX, VIRTIO_BLK_F_SIZE_MAX, VIRTIO_BLK_F_GEOMETRY,
|
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_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)
|
static int virtio_read(struct hwrng *rng, void *buf, size_t size, bool wait)
|
||||||
{
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
if (!busy) {
|
if (!busy) {
|
||||||
busy = true;
|
busy = true;
|
||||||
@@ -65,7 +66,9 @@ static int virtio_read(struct hwrng *rng, void *buf, size_t size, bool wait)
|
|||||||
if (!wait)
|
if (!wait)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
wait_for_completion(&have_data);
|
ret = wait_for_completion_killable(&have_data);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
busy = false;
|
busy = false;
|
||||||
|
|
||||||
@@ -85,7 +88,7 @@ static struct hwrng virtio_hwrng = {
|
|||||||
.read = virtio_read,
|
.read = virtio_read,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int virtrng_probe(struct virtio_device *vdev)
|
static int probe_common(struct virtio_device *vdev)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
@@ -103,13 +106,37 @@ static int virtrng_probe(struct virtio_device *vdev)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __devexit virtrng_remove(struct virtio_device *vdev)
|
static void remove_common(struct virtio_device *vdev)
|
||||||
{
|
{
|
||||||
vdev->config->reset(vdev);
|
vdev->config->reset(vdev);
|
||||||
|
busy = false;
|
||||||
hwrng_unregister(&virtio_hwrng);
|
hwrng_unregister(&virtio_hwrng);
|
||||||
vdev->config->del_vqs(vdev);
|
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[] = {
|
static struct virtio_device_id id_table[] = {
|
||||||
{ VIRTIO_ID_RNG, VIRTIO_DEV_ANY_ID },
|
{ VIRTIO_ID_RNG, VIRTIO_DEV_ANY_ID },
|
||||||
{ 0 },
|
{ 0 },
|
||||||
@@ -121,6 +148,10 @@ static struct virtio_driver virtio_rng_driver = {
|
|||||||
.id_table = id_table,
|
.id_table = id_table,
|
||||||
.probe = virtrng_probe,
|
.probe = virtrng_probe,
|
||||||
.remove = __devexit_p(virtrng_remove),
|
.remove = __devexit_p(virtrng_remove),
|
||||||
|
#ifdef CONFIG_PM
|
||||||
|
.freeze = virtrng_freeze,
|
||||||
|
.restore = virtrng_restore,
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
static int __init init(void)
|
static int __init init(void)
|
||||||
|
@@ -37,8 +37,14 @@
|
|||||||
#define VIRTIO_BLK_F_RO 5 /* Disk is read-only */
|
#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_BLK_SIZE 6 /* Block size of disk is available*/
|
||||||
#define VIRTIO_BLK_F_SCSI 7 /* Supports scsi command passthru */
|
#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_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 */
|
#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. */
|
/* optimal sustained I/O size in logical blocks. */
|
||||||
__u32 opt_io_size;
|
__u32 opt_io_size;
|
||||||
|
|
||||||
|
/* writeback mode (if VIRTIO_BLK_F_CONFIG_WCE) */
|
||||||
|
__u8 wce;
|
||||||
} __attribute__((packed));
|
} __attribute__((packed));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@@ -32,7 +32,7 @@
|
|||||||
#define VIRTIO_ID_NET 1 /* virtio net */
|
#define VIRTIO_ID_NET 1 /* virtio net */
|
||||||
#define VIRTIO_ID_BLOCK 2 /* virtio block */
|
#define VIRTIO_ID_BLOCK 2 /* virtio block */
|
||||||
#define VIRTIO_ID_CONSOLE 3 /* virtio console */
|
#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_BALLOON 5 /* virtio balloon */
|
||||||
#define VIRTIO_ID_RPMSG 7 /* virtio remote processor messaging */
|
#define VIRTIO_ID_RPMSG 7 /* virtio remote processor messaging */
|
||||||
#define VIRTIO_ID_SCSI 8 /* virtio scsi */
|
#define VIRTIO_ID_SCSI 8 /* virtio scsi */
|
||||||
|
Reference in New Issue
Block a user