qemu block_resize(动态修改磁盘大小)实现简记

4110阅读 0评论2014-08-04 sak0
分类:虚拟化

host:
命令block_resize $block_id $size(单位MB)

virtio_blk_resize
    virtio_notify_config
        virtio_notify_vector
            virtio_pci_notify
                msix_notify
                    msg = msix_get_message(dev, vector);
                    stl_le_phys(msg.address, msg.data);
                        stl_phys_internal
                            io_mem_write(mr, addr1, val, 4);



guest:
设备初始化时注册中断,对应的处理方法是vp_config_changed
    err = request_irq(vp_dev->msix_entries[v].vector,
              vp_config_changed, 0, vp_dev->msix_names[v],
              vp_dev);


点击(此处)折叠或打开

  1. static int vp_request_msix_vectors(struct virtio_device *vdev, int nvectors,
  2.                    bool per_vq_vectors)
  3. {
  4.     struct virtio_pci_device *vp_dev = to_vp_device(vdev);
  5.     const char *name = dev_name(&vp_dev->vdev.dev);
  6.     unsigned i, v;
  7.     int err = -ENOMEM;

  8.     vp_dev->msix_entries = kmalloc(nvectors * sizeof *vp_dev->msix_entries,
  9.                        GFP_KERNEL);
  10.     if (!vp_dev->msix_entries)
  11.         goto error;
  12.     vp_dev->msix_names = kmalloc(nvectors * sizeof *vp_dev->msix_names,
  13.                      GFP_KERNEL);
  14.     if (!vp_dev->msix_names)
  15.         goto error;

  16.     for (i = 0; i < nvectors; ++i)
  17.         vp_dev->msix_entries[i].entry = i;

  18.     /* pci_enable_msix returns positive if we can't get this many. */
  19.     err = pci_enable_msix(vp_dev->pci_dev, vp_dev->msix_entries, nvectors);
  20.     if (err > 0)
  21.         err = -ENOSPC;
  22.     if (err)
  23.         goto error;
  24.     vp_dev->msix_vectors = nvectors;
  25.     vp_dev->msix_enabled = 1;

  26.     /* Set the vector used for configuration */
  27.     v = vp_dev->msix_used_vectors;
  28.     snprintf(vp_dev->msix_names[v], sizeof *vp_dev->msix_names,
  29.          "%s-config", name);
  30.     err = request_irq(vp_dev->msix_entries[v].vector,
  31.               vp_config_changed, 0, vp_dev->msix_names[v],
  32.               vp_dev);
  33.     if (err)
  34.         goto error;
  35.     ++vp_dev->msix_used_vectors;

  36.     iowrite16(v, vp_dev->ioaddr + VIRTIO_MSI_CONFIG_VECTOR);
  37.     /* Verify we had enough resources to assign the vector */
  38.     v = ioread16(vp_dev->ioaddr + VIRTIO_MSI_CONFIG_VECTOR);
  39.     if (v == VIRTIO_MSI_NO_VECTOR) {
  40.         err = -EBUSY;
  41.         goto error;
  42.     }

  43.     if (!per_vq_vectors) {
  44.         /* Shared vector for all VQs */
  45.         v = vp_dev->msix_used_vectors;
  46.         snprintf(vp_dev->msix_names[v], sizeof *vp_dev->msix_names,
  47.              "%s-virtqueues", name);
  48.         err = request_irq(vp_dev->msix_entries[v].vector,
  49.                   vp_vring_interrupt, 0, vp_dev->msix_names[v],
  50.                   vp_dev);
  51.         if (err)
  52.             goto error;
  53.         ++vp_dev->msix_used_vectors;
  54.     }
  55.     return 0;
  56. error:
  57.     vp_free_vectors(vdev);
  58.     return err;
  59. }

  60. 处理中断
  61. static irqreturn_t vp_config_changed(int irq, void *opaque)
  62. {
  63.     struct virtio_pci_device *vp_dev = opaque;
  64.     struct virtio_driver *drv;
  65.     drv = container_of(vp_dev->vdev.dev.driver,
  66.                struct virtio_driver, driver);

  67.     if (drv && drv->config_changed)
  68.         drv->config_changed(&vp_dev->vdev);
  69.     return IRQ_HANDLED;
  70. }

  71. static void virtblk_config_changed_work(struct work_struct *work)
  72. {
  73.     struct virtio_blk *vblk =
  74.         container_of(work, struct virtio_blk, config_work);
  75.     struct virtio_device *vdev = vblk->vdev;
  76.     struct request_queue *q = vblk->disk->queue;
  77.     char cap_str_2[10], cap_str_10[10];
  78.     u64 capacity, size;

  79.     mutex_lock(&vblk->config_lock);
  80.     if (!vblk->config_enable)
  81.         goto done;

  82.     /* Host must always specify the capacity. */
  83.     vdev->config->get(vdev, offsetof(struct virtio_blk_config, capacity),
  84.               &capacity, sizeof(capacity));//vm退出到host

  85.     /* If capacity is too big, truncate with warning. */
  86.     if ((sector_t)capacity != capacity) {
  87.         dev_warn(&vdev->dev, "Capacity %llu too large: truncating\n",
  88.              (unsigned long long)capacity);
  89.         capacity = (sector_t)-1;
  90.     }

  91.     size = capacity * queue_logical_block_size(q);
  92.     string_get_size(size, STRING_UNITS_2, cap_str_2, sizeof(cap_str_2));
  93.     string_get_size(size, STRING_UNITS_10, cap_str_10, sizeof(cap_str_10));

  94.     dev_notice(&vdev->dev,
  95.           "new size: %llu %d-byte logical blocks (%s/%s)\n",
  96.           (unsigned long long)capacity,
  97.           queue_logical_block_size(q),
  98.           cap_str_10, cap_str_2);

  99.     set_capacity(vblk->disk, capacity);
  100.     revalidate_disk(vblk->disk);
  101. done:
  102.     mutex_unlock(&vblk->config_lock);
  103. }

  104. host:
  105. uint32_t virtio_config_readb(VirtIODevice *vdev, uint32_t addr)
  106. {
  107.     VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
  108.     uint8_t val;

  109.     if (addr + sizeof(val) > vdev->config_len) {
  110.         return (uint32_t)-1;
  111.     }

  112.     k->get_config(vdev, vdev->config);//对应到virtio_blk_update_config

  113.     val = ldub_p(vdev->config + addr);
  114.     return val;
  115. }

  116. static void virtio_blk_update_config(VirtIODevice *vdev, uint8_t *config)
  117. {
  118.     VirtIOBlock *s = VIRTIO_BLK(vdev);
  119.     struct virtio_blk_config blkcfg;
  120.     uint64_t capacity;
  121.     int blk_size = s->conf->logical_block_size;

  122.     bdrv_get_geometry(s->bs, &capacity);
  123.     memset(&blkcfg, 0, sizeof(blkcfg));
  124.     stq_raw(&blkcfg.capacity, capacity);
  125.     stl_raw(&blkcfg.seg_max, 128 - 2);
  126.     stw_raw(&blkcfg.cylinders, s->conf->cyls);
  127.     stl_raw(&blkcfg.blk_size, blk_size);
  128.     stw_raw(&blkcfg.min_io_size, s->conf->min_io_size / blk_size);
  129.     stw_raw(&blkcfg.opt_io_size, s->conf->opt_io_size / blk_size);
  130.     blkcfg.heads = s->conf->heads;
  131.     /*
  132.      * We must ensure that the block device capacity is a multiple of
  133.      * the logical block size. If that is not the case, let's use
  134.      * sector_mask to adopt the geometry to have a correct picture.
  135.      * For those devices where the capacity is ok for the given geometry
  136.      * we don't touch the sector value of the geometry, since some devices
  137.      * (like s390 dasd) need a specific value. Here the capacity is already
  138.      * cyls*heads*secs*blk_size and the sector value is not block size
  139.      * divided by 512 - instead it is the amount of blk_size blocks
  140.      * per track (cylinder).
  141.      */
  142.     if (bdrv_getlength(s->bs) / s->conf->heads / s->conf->secs % blk_size) {
  143.         blkcfg.sectors = s->conf->secs & ~s->sector_mask;
  144.     } else {
  145.         blkcfg.sectors = s->conf->secs;
  146.     }
  147.     blkcfg.size_max = 0;
  148.     blkcfg.physical_block_exp = get_physical_block_exp(s->conf);
  149.     blkcfg.alignment_offset = 0;
  150.     blkcfg.wce = bdrv_enable_write_cache(s->bs);
  151.     memcpy(config, &blkcfg, sizeof(struct virtio_blk_config));
  152. }

上一篇:libvirt对监控虚机内存的改进
下一篇:对cinder volume live snapshot(在线快照)实现的一点疑问