Not entirely surprising: the ongoing QEMU work on virtio 1.0 has revealed

more minor issues with our virtio 1.0 drivers just introduced in the
 kernel.
 
 (I would normally use my fixes branch for this, but there were a batch of them...)
 
 Thanks,
 Rusty.
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQIcBAABAgAGBQJVB4gHAAoJENkgDmzRrbjx+BAP/0Z8TPfP5v2XQ0YlLPFpKMQ0
 DdsL9s1Se74e0RUJ6fvpVZaVgBxFq1+xi2wiSOhlOyIn0fXlO8+eYK886QX13cYO
 CUAvuwbQhGHgj+1DfQ+7pJlQe905VvHVxWIVZU1dq+PEI181kOQQE9lOHhsKsYvQ
 IxEAX3/avYALAV29FN+PvGZcmY5fgeJf58RkQb5h3XXVaBlI175HhiGm3izgqyKe
 qmZqEDuUnsdlxT5rvJnb0kg/VfRJ2MdkpIcpjpqO4DK3lY+x90LibMmnGLdLkigS
 cEfjSXPmJKNug+IoxxQuDH6zRsWqTLnwI4gU/FqbOkN12Ovt5k4F+FrFCuXD7GdW
 tCiBblkQjQ8xS+OP5slXwYKE3a4q4ih6u+9/STNlSVlG1mqZxxmK56WD00CvBpvR
 CDyTO4yHUV9rjDIhD/r8guFXsPwaaiZxKiGP1k+nnel0E9dMmZf0dE8xqHpTrl0Z
 8OAv3TgJFqhmfecFCBxj28e++dl7KvhiAGRKiZvHYkoxWZmJ5EFkw5E8FUOlJQNS
 2apGPbBEyeEQho7emzb0l9vvAu+0jJGEObxvA9wUdEcXg2kbDmGIpidZfN6xBemJ
 5WuMoGJh9UnYeImtGyXINTuQXagXdzt5bB/IkVmUYMcvsGty5lKIH1G87Q/qV4BE
 YCbKn/3J+G2TmF3+m8AH
 =8QwR
 -----END PGP SIGNATURE-----

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

Pull virtio fixes from Rusty Russell:
 "Not entirely surprising: the ongoing QEMU work on virtio 1.0 has
  revealed more minor issues with our virtio 1.0 drivers just introduced
  in the kernel.

  (I would normally use my fixes branch for this, but there were a batch
  of them...)"

* tag 'virtio-next-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rusty/linux:
  virtio_mmio: fix access width for mmio
  uapi/virtio_scsi: allow overriding CDB/SENSE size
  virtio_mmio: generation support
  virtio_rpmsg: set DRIVER_OK before using device
  9p/trans_virtio: fix hot-unplug
  virtio-balloon: do not call blocking ops when !TASK_RUNNING
  virtio_blk: fix comment for virtio 1.0
  virtio_blk: typo fix
  virtio_balloon: set DRIVER_OK before using device
  virtio_console: avoid config access from irq
  virtio_console: init work unconditionally
This commit is contained in:
Linus Torvalds 2015-03-17 10:36:01 -07:00
commit 4d272f90a7
7 changed files with 168 additions and 23 deletions

View File

@ -142,6 +142,7 @@ struct ports_device {
* notification * notification
*/ */
struct work_struct control_work; struct work_struct control_work;
struct work_struct config_work;
struct list_head ports; struct list_head ports;
@ -1837,10 +1838,21 @@ static void config_intr(struct virtio_device *vdev)
portdev = vdev->priv; portdev = vdev->priv;
if (!use_multiport(portdev))
schedule_work(&portdev->config_work);
}
static void config_work_handler(struct work_struct *work)
{
struct ports_device *portdev;
portdev = container_of(work, struct ports_device, control_work);
if (!use_multiport(portdev)) { if (!use_multiport(portdev)) {
struct virtio_device *vdev;
struct port *port; struct port *port;
u16 rows, cols; u16 rows, cols;
vdev = portdev->vdev;
virtio_cread(vdev, struct virtio_console_config, cols, &cols); virtio_cread(vdev, struct virtio_console_config, cols, &cols);
virtio_cread(vdev, struct virtio_console_config, rows, &rows); virtio_cread(vdev, struct virtio_console_config, rows, &rows);
@ -2040,12 +2052,14 @@ static int virtcons_probe(struct virtio_device *vdev)
virtio_device_ready(portdev->vdev); virtio_device_ready(portdev->vdev);
INIT_WORK(&portdev->config_work, &config_work_handler);
INIT_WORK(&portdev->control_work, &control_work_handler);
if (multiport) { if (multiport) {
unsigned int nr_added_bufs; unsigned int nr_added_bufs;
spin_lock_init(&portdev->c_ivq_lock); spin_lock_init(&portdev->c_ivq_lock);
spin_lock_init(&portdev->c_ovq_lock); spin_lock_init(&portdev->c_ovq_lock);
INIT_WORK(&portdev->control_work, &control_work_handler);
nr_added_bufs = fill_queue(portdev->c_ivq, nr_added_bufs = fill_queue(portdev->c_ivq,
&portdev->c_ivq_lock); &portdev->c_ivq_lock);
@ -2113,6 +2127,8 @@ static void virtcons_remove(struct virtio_device *vdev)
/* Finish up work that's lined up */ /* Finish up work that's lined up */
if (use_multiport(portdev)) if (use_multiport(portdev))
cancel_work_sync(&portdev->control_work); cancel_work_sync(&portdev->control_work);
else
cancel_work_sync(&portdev->config_work);
list_for_each_entry_safe(port, port2, &portdev->ports, list) list_for_each_entry_safe(port, port2, &portdev->ports, list)
unplug_port(port); unplug_port(port);
@ -2164,6 +2180,7 @@ static int virtcons_freeze(struct virtio_device *vdev)
virtqueue_disable_cb(portdev->c_ivq); virtqueue_disable_cb(portdev->c_ivq);
cancel_work_sync(&portdev->control_work); cancel_work_sync(&portdev->control_work);
cancel_work_sync(&portdev->config_work);
/* /*
* Once more: if control_work_handler() was running, it would * Once more: if control_work_handler() was running, it would
* enable the cb as the last step. * enable the cb as the last step.

View File

@ -951,6 +951,7 @@ static int rpmsg_probe(struct virtio_device *vdev)
void *bufs_va; void *bufs_va;
int err = 0, i; int err = 0, i;
size_t total_buf_space; size_t total_buf_space;
bool notify;
vrp = kzalloc(sizeof(*vrp), GFP_KERNEL); vrp = kzalloc(sizeof(*vrp), GFP_KERNEL);
if (!vrp) if (!vrp)
@ -1030,8 +1031,22 @@ static int rpmsg_probe(struct virtio_device *vdev)
} }
} }
/*
* Prepare to kick but don't notify yet - we can't do this before
* device is ready.
*/
notify = virtqueue_kick_prepare(vrp->rvq);
/* From this point on, we can notify and get callbacks. */
virtio_device_ready(vdev);
/* tell the remote processor it can start sending messages */ /* tell the remote processor it can start sending messages */
virtqueue_kick(vrp->rvq); /*
* this might be concurrent with callbacks, but we are only
* doing notify, not a full kick here, so that's ok.
*/
if (notify)
virtqueue_notify(vrp->rvq);
dev_info(&vdev->dev, "rpmsg host is online\n"); dev_info(&vdev->dev, "rpmsg host is online\n");

View File

@ -29,6 +29,7 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/balloon_compaction.h> #include <linux/balloon_compaction.h>
#include <linux/oom.h> #include <linux/oom.h>
#include <linux/wait.h>
/* /*
* Balloon device works in 4K page units. So each page is pointed to by * Balloon device works in 4K page units. So each page is pointed to by
@ -334,17 +335,25 @@ static int virtballoon_oom_notify(struct notifier_block *self,
static int balloon(void *_vballoon) static int balloon(void *_vballoon)
{ {
struct virtio_balloon *vb = _vballoon; struct virtio_balloon *vb = _vballoon;
DEFINE_WAIT_FUNC(wait, woken_wake_function);
set_freezable(); set_freezable();
while (!kthread_should_stop()) { while (!kthread_should_stop()) {
s64 diff; s64 diff;
try_to_freeze(); try_to_freeze();
wait_event_interruptible(vb->config_change,
(diff = towards_target(vb)) != 0 add_wait_queue(&vb->config_change, &wait);
|| vb->need_stats_update for (;;) {
|| kthread_should_stop() if ((diff = towards_target(vb)) != 0 ||
|| freezing(current)); vb->need_stats_update ||
kthread_should_stop() ||
freezing(current))
break;
wait_woken(&wait, TASK_INTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT);
}
remove_wait_queue(&vb->config_change, &wait);
if (vb->need_stats_update) if (vb->need_stats_update)
stats_handle_request(vb); stats_handle_request(vb);
if (diff > 0) if (diff > 0)
@ -499,6 +508,8 @@ static int virtballoon_probe(struct virtio_device *vdev)
if (err < 0) if (err < 0)
goto out_oom_notify; goto out_oom_notify;
virtio_device_ready(vdev);
vb->thread = kthread_run(balloon, vb, "vballoon"); vb->thread = kthread_run(balloon, vb, "vballoon");
if (IS_ERR(vb->thread)) { if (IS_ERR(vb->thread)) {
err = PTR_ERR(vb->thread); err = PTR_ERR(vb->thread);

View File

@ -156,22 +156,95 @@ static void vm_get(struct virtio_device *vdev, unsigned offset,
void *buf, unsigned len) void *buf, unsigned len)
{ {
struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vdev); struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vdev);
u8 *ptr = buf; void __iomem *base = vm_dev->base + VIRTIO_MMIO_CONFIG;
int i; u8 b;
__le16 w;
__le32 l;
for (i = 0; i < len; i++) if (vm_dev->version == 1) {
ptr[i] = readb(vm_dev->base + VIRTIO_MMIO_CONFIG + offset + i); u8 *ptr = buf;
int i;
for (i = 0; i < len; i++)
ptr[i] = readb(base + offset + i);
return;
}
switch (len) {
case 1:
b = readb(base + offset);
memcpy(buf, &b, sizeof b);
break;
case 2:
w = cpu_to_le16(readw(base + offset));
memcpy(buf, &w, sizeof w);
break;
case 4:
l = cpu_to_le32(readl(base + offset));
memcpy(buf, &l, sizeof l);
break;
case 8:
l = cpu_to_le32(readl(base + offset));
memcpy(buf, &l, sizeof l);
l = cpu_to_le32(ioread32(base + offset + sizeof l));
memcpy(buf + sizeof l, &l, sizeof l);
break;
default:
BUG();
}
} }
static void vm_set(struct virtio_device *vdev, unsigned offset, static void vm_set(struct virtio_device *vdev, unsigned offset,
const void *buf, unsigned len) const void *buf, unsigned len)
{ {
struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vdev); struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vdev);
const u8 *ptr = buf; void __iomem *base = vm_dev->base + VIRTIO_MMIO_CONFIG;
int i; u8 b;
__le16 w;
__le32 l;
for (i = 0; i < len; i++) if (vm_dev->version == 1) {
writeb(ptr[i], vm_dev->base + VIRTIO_MMIO_CONFIG + offset + i); const u8 *ptr = buf;
int i;
for (i = 0; i < len; i++)
writeb(ptr[i], base + offset + i);
return;
}
switch (len) {
case 1:
memcpy(&b, buf, sizeof b);
writeb(b, base + offset);
break;
case 2:
memcpy(&w, buf, sizeof w);
writew(le16_to_cpu(w), base + offset);
break;
case 4:
memcpy(&l, buf, sizeof l);
writel(le32_to_cpu(l), base + offset);
break;
case 8:
memcpy(&l, buf, sizeof l);
writel(le32_to_cpu(l), base + offset);
memcpy(&l, buf + sizeof l, sizeof l);
writel(le32_to_cpu(l), base + offset + sizeof l);
break;
default:
BUG();
}
}
static u32 vm_generation(struct virtio_device *vdev)
{
struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vdev);
if (vm_dev->version == 1)
return 0;
else
return readl(vm_dev->base + VIRTIO_MMIO_CONFIG_GENERATION);
} }
static u8 vm_get_status(struct virtio_device *vdev) static u8 vm_get_status(struct virtio_device *vdev)
@ -440,6 +513,7 @@ static const char *vm_bus_name(struct virtio_device *vdev)
static const struct virtio_config_ops virtio_mmio_config_ops = { static const struct virtio_config_ops virtio_mmio_config_ops = {
.get = vm_get, .get = vm_get,
.set = vm_set, .set = vm_set,
.generation = vm_generation,
.get_status = vm_get_status, .get_status = vm_get_status,
.set_status = vm_set_status, .set_status = vm_set_status,
.reset = vm_reset, .reset = vm_reset,

View File

@ -60,7 +60,7 @@ struct virtio_blk_config {
__u32 size_max; __u32 size_max;
/* The maximum number of segments (if VIRTIO_BLK_F_SEG_MAX) */ /* The maximum number of segments (if VIRTIO_BLK_F_SEG_MAX) */
__u32 seg_max; __u32 seg_max;
/* geometry the device (if VIRTIO_BLK_F_GEOMETRY) */ /* geometry of the device (if VIRTIO_BLK_F_GEOMETRY) */
struct virtio_blk_geometry { struct virtio_blk_geometry {
__u16 cylinders; __u16 cylinders;
__u8 heads; __u8 heads;
@ -119,7 +119,11 @@ struct virtio_blk_config {
#define VIRTIO_BLK_T_BARRIER 0x80000000 #define VIRTIO_BLK_T_BARRIER 0x80000000
#endif /* !VIRTIO_BLK_NO_LEGACY */ #endif /* !VIRTIO_BLK_NO_LEGACY */
/* This is the first element of the read scatter-gather list. */ /*
* This comes first in the read scatter-gather list.
* For legacy virtio, if VIRTIO_F_ANY_LAYOUT is not negotiated,
* this is the first element of the read scatter-gather list.
*/
struct virtio_blk_outhdr { struct virtio_blk_outhdr {
/* VIRTIO_BLK_T* */ /* VIRTIO_BLK_T* */
__virtio32 type; __virtio32 type;

View File

@ -29,8 +29,16 @@
#include <linux/virtio_types.h> #include <linux/virtio_types.h>
#define VIRTIO_SCSI_CDB_SIZE 32 /* Default values of the CDB and sense data size configuration fields */
#define VIRTIO_SCSI_SENSE_SIZE 96 #define VIRTIO_SCSI_CDB_DEFAULT_SIZE 32
#define VIRTIO_SCSI_SENSE_DEFAULT_SIZE 96
#ifndef VIRTIO_SCSI_CDB_SIZE
#define VIRTIO_SCSI_CDB_SIZE VIRTIO_SCSI_CDB_DEFAULT_SIZE
#endif
#ifndef VIRTIO_SCSI_SENSE_SIZE
#define VIRTIO_SCSI_SENSE_SIZE VIRTIO_SCSI_SENSE_DEFAULT_SIZE
#endif
/* SCSI command request, followed by data-out */ /* SCSI command request, followed by data-out */
struct virtio_scsi_cmd_req { struct virtio_scsi_cmd_req {

View File

@ -658,14 +658,30 @@ p9_virtio_create(struct p9_client *client, const char *devname, char *args)
static void p9_virtio_remove(struct virtio_device *vdev) static void p9_virtio_remove(struct virtio_device *vdev)
{ {
struct virtio_chan *chan = vdev->priv; struct virtio_chan *chan = vdev->priv;
unsigned long warning_time;
if (chan->inuse)
p9_virtio_close(chan->client);
vdev->config->del_vqs(vdev);
mutex_lock(&virtio_9p_lock); mutex_lock(&virtio_9p_lock);
/* Remove self from list so we don't get new users. */
list_del(&chan->chan_list); list_del(&chan->chan_list);
warning_time = jiffies;
/* Wait for existing users to close. */
while (chan->inuse) {
mutex_unlock(&virtio_9p_lock);
msleep(250);
if (time_after(jiffies, warning_time + 10 * HZ)) {
dev_emerg(&vdev->dev,
"p9_virtio_remove: waiting for device in use.\n");
warning_time = jiffies;
}
mutex_lock(&virtio_9p_lock);
}
mutex_unlock(&virtio_9p_lock); mutex_unlock(&virtio_9p_lock);
vdev->config->del_vqs(vdev);
sysfs_remove_file(&(vdev->dev.kobj), &dev_attr_mount_tag.attr); sysfs_remove_file(&(vdev->dev.kobj), &dev_attr_mount_tag.attr);
kobject_uevent(&(vdev->dev.kobj), KOBJ_CHANGE); kobject_uevent(&(vdev->dev.kobj), KOBJ_CHANGE);
kfree(chan->tag); kfree(chan->tag);