Skip to content

Commit

Permalink
Merge tag 'virtio-next-for-linus' of git://git.kernel.org/pub/scm/lin…
Browse files Browse the repository at this point in the history
…ux/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
  • Loading branch information
Linus Torvalds committed Mar 17, 2015
2 parents 2fc6775 + 704a0b5 commit 4d272f9
Show file tree
Hide file tree
Showing 7 changed files with 168 additions and 23 deletions.
19 changes: 18 additions & 1 deletion drivers/char/virtio_console.c
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ struct ports_device {
* notification
*/
struct work_struct control_work;
struct work_struct config_work;

struct list_head ports;

Expand Down Expand Up @@ -1837,10 +1838,21 @@ static void config_intr(struct virtio_device *vdev)

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)) {
struct virtio_device *vdev;
struct port *port;
u16 rows, cols;

vdev = portdev->vdev;
virtio_cread(vdev, struct virtio_console_config, cols, &cols);
virtio_cread(vdev, struct virtio_console_config, rows, &rows);

Expand Down Expand Up @@ -2040,12 +2052,14 @@ static int virtcons_probe(struct virtio_device *vdev)

virtio_device_ready(portdev->vdev);

INIT_WORK(&portdev->config_work, &config_work_handler);
INIT_WORK(&portdev->control_work, &control_work_handler);

if (multiport) {
unsigned int nr_added_bufs;

spin_lock_init(&portdev->c_ivq_lock);
spin_lock_init(&portdev->c_ovq_lock);
INIT_WORK(&portdev->control_work, &control_work_handler);

nr_added_bufs = fill_queue(portdev->c_ivq,
&portdev->c_ivq_lock);
Expand Down Expand Up @@ -2113,6 +2127,8 @@ static void virtcons_remove(struct virtio_device *vdev)
/* Finish up work that's lined up */
if (use_multiport(portdev))
cancel_work_sync(&portdev->control_work);
else
cancel_work_sync(&portdev->config_work);

list_for_each_entry_safe(port, port2, &portdev->ports, list)
unplug_port(port);
Expand Down Expand Up @@ -2164,6 +2180,7 @@ static int virtcons_freeze(struct virtio_device *vdev)

virtqueue_disable_cb(portdev->c_ivq);
cancel_work_sync(&portdev->control_work);
cancel_work_sync(&portdev->config_work);
/*
* Once more: if control_work_handler() was running, it would
* enable the cb as the last step.
Expand Down
17 changes: 16 additions & 1 deletion drivers/rpmsg/virtio_rpmsg_bus.c
Original file line number Diff line number Diff line change
Expand Up @@ -951,6 +951,7 @@ static int rpmsg_probe(struct virtio_device *vdev)
void *bufs_va;
int err = 0, i;
size_t total_buf_space;
bool notify;

vrp = kzalloc(sizeof(*vrp), GFP_KERNEL);
if (!vrp)
Expand Down Expand Up @@ -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 */
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");

Expand Down
21 changes: 16 additions & 5 deletions drivers/virtio/virtio_balloon.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#include <linux/module.h>
#include <linux/balloon_compaction.h>
#include <linux/oom.h>
#include <linux/wait.h>

/*
* Balloon device works in 4K page units. So each page is pointed to by
Expand Down Expand Up @@ -334,17 +335,25 @@ static int virtballoon_oom_notify(struct notifier_block *self,
static int balloon(void *_vballoon)
{
struct virtio_balloon *vb = _vballoon;
DEFINE_WAIT_FUNC(wait, woken_wake_function);

set_freezable();
while (!kthread_should_stop()) {
s64 diff;

try_to_freeze();
wait_event_interruptible(vb->config_change,
(diff = towards_target(vb)) != 0
|| vb->need_stats_update
|| kthread_should_stop()
|| freezing(current));

add_wait_queue(&vb->config_change, &wait);
for (;;) {
if ((diff = towards_target(vb)) != 0 ||
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)
stats_handle_request(vb);
if (diff > 0)
Expand Down Expand Up @@ -499,6 +508,8 @@ static int virtballoon_probe(struct virtio_device *vdev)
if (err < 0)
goto out_oom_notify;

virtio_device_ready(vdev);

vb->thread = kthread_run(balloon, vb, "vballoon");
if (IS_ERR(vb->thread)) {
err = PTR_ERR(vb->thread);
Expand Down
90 changes: 82 additions & 8 deletions drivers/virtio/virtio_mmio.c
Original file line number Diff line number Diff line change
Expand Up @@ -156,22 +156,95 @@ static void vm_get(struct virtio_device *vdev, unsigned offset,
void *buf, unsigned len)
{
struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vdev);
u8 *ptr = buf;
int i;
void __iomem *base = vm_dev->base + VIRTIO_MMIO_CONFIG;
u8 b;
__le16 w;
__le32 l;

for (i = 0; i < len; i++)
ptr[i] = readb(vm_dev->base + VIRTIO_MMIO_CONFIG + offset + i);
if (vm_dev->version == 1) {
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,
const void *buf, unsigned len)
{
struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vdev);
const u8 *ptr = buf;
int i;
void __iomem *base = vm_dev->base + VIRTIO_MMIO_CONFIG;
u8 b;
__le16 w;
__le32 l;

for (i = 0; i < len; i++)
writeb(ptr[i], vm_dev->base + VIRTIO_MMIO_CONFIG + offset + i);
if (vm_dev->version == 1) {
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)
Expand Down Expand Up @@ -440,6 +513,7 @@ static const char *vm_bus_name(struct virtio_device *vdev)
static const struct virtio_config_ops virtio_mmio_config_ops = {
.get = vm_get,
.set = vm_set,
.generation = vm_generation,
.get_status = vm_get_status,
.set_status = vm_set_status,
.reset = vm_reset,
Expand Down
8 changes: 6 additions & 2 deletions include/uapi/linux/virtio_blk.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ struct virtio_blk_config {
__u32 size_max;
/* The maximum number of segments (if VIRTIO_BLK_F_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 {
__u16 cylinders;
__u8 heads;
Expand Down Expand Up @@ -119,7 +119,11 @@ struct virtio_blk_config {
#define VIRTIO_BLK_T_BARRIER 0x80000000
#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 {
/* VIRTIO_BLK_T* */
__virtio32 type;
Expand Down
12 changes: 10 additions & 2 deletions include/uapi/linux/virtio_scsi.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,16 @@

#include <linux/virtio_types.h>

#define VIRTIO_SCSI_CDB_SIZE 32
#define VIRTIO_SCSI_SENSE_SIZE 96
/* Default values of the CDB and sense data size configuration fields */
#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 */
struct virtio_scsi_cmd_req {
Expand Down
24 changes: 20 additions & 4 deletions net/9p/trans_virtio.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
struct virtio_chan *chan = vdev->priv;

if (chan->inuse)
p9_virtio_close(chan->client);
vdev->config->del_vqs(vdev);
unsigned long warning_time;

mutex_lock(&virtio_9p_lock);

/* Remove self from list so we don't get new users. */
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);

vdev->config->del_vqs(vdev);

sysfs_remove_file(&(vdev->dev.kobj), &dev_attr_mount_tag.attr);
kobject_uevent(&(vdev->dev.kobj), KOBJ_CHANGE);
kfree(chan->tag);
Expand Down

0 comments on commit 4d272f9

Please sign in to comment.