Skip to content

Commit

Permalink
Merge tag 'to-linus' of git://github.com/rustyrussell/linux
Browse files Browse the repository at this point in the history
* tag 'to-linus' of git://github.com/rustyrussell/linux: (24 commits)
  lguest: Make sure interrupt is allocated ok by lguest_setup_irq
  lguest: move the lguest tool to the tools directory
  lguest: switch segment-voodoo-numbers to readable symbols
  virtio: balloon: Add freeze, restore handlers to support S4
  virtio: balloon: Move vq initialization into separate function
  virtio: net: Add freeze, restore handlers to support S4
  virtio: net: Move vq and vq buf removal into separate function
  virtio: net: Move vq initialization into separate function
  virtio: blk: Add freeze, restore handlers to support S4
  virtio: blk: Move vq initialization to separate function
  virtio: console: Disable callbacks for virtqueues at start of S4 freeze
  virtio: console: Add freeze and restore handlers to support S4
  virtio: console: Move vq and vq buf removal into separate functions
  virtio: pci: add PM notification handlers for restore, freeze, thaw, poweroff
  virtio: pci: switch to new PM API
  virtio_blk: fix config handler race
  virtio: add debugging if driver doesn't kick.
  virtio: expose added descriptors immediately.
  virtio: avoid modulus operation.
  virtio: support unlocked queue kick
  ...
  • Loading branch information
Linus Torvalds committed Jan 12, 2012
2 parents 61bd5e5 + b6c96c0 commit bcf8a3d
Show file tree
Hide file tree
Showing 23 changed files with 757 additions and 247 deletions.
21 changes: 13 additions & 8 deletions arch/x86/lguest/boot.c
Original file line number Diff line number Diff line change
Expand Up @@ -856,18 +856,23 @@ static void __init lguest_init_IRQ(void)
}

/*
* With CONFIG_SPARSE_IRQ, interrupt descriptors are allocated as-needed, so
* rather than set them in lguest_init_IRQ we are called here every time an
* lguest device needs an interrupt.
*
* FIXME: irq_alloc_desc_at() can fail due to lack of memory, we should
* pass that up!
* Interrupt descriptors are allocated as-needed, but low-numbered ones are
* reserved by the generic x86 code. So we ignore irq_alloc_desc_at if it
* tells us the irq is already used: other errors (ie. ENOMEM) we take
* seriously.
*/
void lguest_setup_irq(unsigned int irq)
int lguest_setup_irq(unsigned int irq)
{
irq_alloc_desc_at(irq, 0);
int err;

/* Returns -ve error or vector number. */
err = irq_alloc_desc_at(irq, 0);
if (err < 0 && err != -EEXIST)
return err;

irq_set_chip_and_handler_name(irq, &lguest_irq_controller,
handle_level_irq, "level");
return 0;
}

/*
Expand Down
87 changes: 80 additions & 7 deletions drivers/block/virtio_blk.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <linux/blkdev.h>
#include <linux/hdreg.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/virtio.h>
#include <linux/virtio_blk.h>
#include <linux/scatterlist.h>
Expand Down Expand Up @@ -36,6 +37,12 @@ struct virtio_blk
/* Process context for config space updates */
struct work_struct config_work;

/* Lock for config space updates */
struct mutex config_lock;

/* enable config space updates */
bool config_enable;

/* What host tells us, plus 2 for header & tailer. */
unsigned int sg_elems;

Expand Down Expand Up @@ -172,7 +179,7 @@ static bool do_req(struct request_queue *q, struct virtio_blk *vblk,
}
}

if (virtqueue_add_buf(vblk->vq, vblk->sg, out, in, vbr) < 0) {
if (virtqueue_add_buf(vblk->vq, vblk->sg, out, in, vbr, GFP_ATOMIC)<0) {
mempool_free(vbr, vblk->pool);
return false;
}
Expand Down Expand Up @@ -318,6 +325,10 @@ static void virtblk_config_changed_work(struct work_struct *work)
char cap_str_2[10], cap_str_10[10];
u64 capacity, size;

mutex_lock(&vblk->config_lock);
if (!vblk->config_enable)
goto done;

/* Host must always specify the capacity. */
vdev->config->get(vdev, offsetof(struct virtio_blk_config, capacity),
&capacity, sizeof(capacity));
Expand All @@ -340,6 +351,8 @@ static void virtblk_config_changed_work(struct work_struct *work)
cap_str_10, cap_str_2);

set_capacity(vblk->disk, capacity);
done:
mutex_unlock(&vblk->config_lock);
}

static void virtblk_config_changed(struct virtio_device *vdev)
Expand All @@ -349,6 +362,18 @@ static void virtblk_config_changed(struct virtio_device *vdev)
queue_work(virtblk_wq, &vblk->config_work);
}

static int init_vq(struct virtio_blk *vblk)
{
int err = 0;

/* We expect one virtqueue, for output. */
vblk->vq = virtio_find_single_vq(vblk->vdev, blk_done, "requests");
if (IS_ERR(vblk->vq))
err = PTR_ERR(vblk->vq);

return err;
}

static int __devinit virtblk_probe(struct virtio_device *vdev)
{
struct virtio_blk *vblk;
Expand Down Expand Up @@ -388,14 +413,13 @@ static int __devinit virtblk_probe(struct virtio_device *vdev)
vblk->vdev = vdev;
vblk->sg_elems = sg_elems;
sg_init_table(vblk->sg, vblk->sg_elems);
mutex_init(&vblk->config_lock);
INIT_WORK(&vblk->config_work, virtblk_config_changed_work);
vblk->config_enable = true;

/* We expect one virtqueue, for output. */
vblk->vq = virtio_find_single_vq(vdev, blk_done, "requests");
if (IS_ERR(vblk->vq)) {
err = PTR_ERR(vblk->vq);
err = init_vq(vblk);
if (err)
goto out_free_vblk;
}

vblk->pool = mempool_create_kmalloc_pool(1,sizeof(struct virtblk_req));
if (!vblk->pool) {
Expand Down Expand Up @@ -542,14 +566,19 @@ static void __devexit virtblk_remove(struct virtio_device *vdev)
struct virtio_blk *vblk = vdev->priv;
int index = vblk->index;

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

/* Nothing should be pending. */
BUG_ON(!list_empty(&vblk->reqs));

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

flush_work(&vblk->config_work);

del_gendisk(vblk->disk);
blk_cleanup_queue(vblk->disk->queue);
put_disk(vblk->disk);
Expand All @@ -559,6 +588,46 @@ static void __devexit virtblk_remove(struct virtio_device *vdev)
ida_simple_remove(&vd_index_ida, index);
}

#ifdef CONFIG_PM
static int virtblk_freeze(struct virtio_device *vdev)
{
struct virtio_blk *vblk = vdev->priv;

/* Ensure we don't receive any more interrupts */
vdev->config->reset(vdev);

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

flush_work(&vblk->config_work);

spin_lock_irq(vblk->disk->queue->queue_lock);
blk_stop_queue(vblk->disk->queue);
spin_unlock_irq(vblk->disk->queue->queue_lock);
blk_sync_queue(vblk->disk->queue);

vdev->config->del_vqs(vdev);
return 0;
}

static int virtblk_restore(struct virtio_device *vdev)
{
struct virtio_blk *vblk = vdev->priv;
int ret;

vblk->config_enable = true;
ret = init_vq(vdev->priv);
if (!ret) {
spin_lock_irq(vblk->disk->queue->queue_lock);
blk_start_queue(vblk->disk->queue);
spin_unlock_irq(vblk->disk->queue->queue_lock);
}
return ret;
}
#endif

static const struct virtio_device_id id_table[] = {
{ VIRTIO_ID_BLOCK, VIRTIO_DEV_ANY_ID },
{ 0 },
Expand All @@ -584,6 +653,10 @@ static struct virtio_driver __refdata virtio_blk = {
.probe = virtblk_probe,
.remove = __devexit_p(virtblk_remove),
.config_changed = virtblk_config_changed,
#ifdef CONFIG_PM
.freeze = virtblk_freeze,
.restore = virtblk_restore,
#endif
};

static int __init init(void)
Expand Down
2 changes: 1 addition & 1 deletion drivers/char/hw_random/virtio-rng.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ static void register_buffer(u8 *buf, size_t size)
sg_init_one(&sg, buf, size);

/* There should always be room for one buffer. */
if (virtqueue_add_buf(vq, &sg, 0, 1, buf) < 0)
if (virtqueue_add_buf(vq, &sg, 0, 1, buf, GFP_KERNEL) < 0)
BUG();

virtqueue_kick(vq);
Expand Down
Loading

0 comments on commit bcf8a3d

Please sign in to comment.