Exemplo n.º 1
0
static int vhost_client_migration_log(CPUPhysMemoryClient *client,
                                      int enable)
{
    struct vhost_dev *dev = container_of(client, struct vhost_dev, client);
    int r;
    if (!!enable == dev->log_enabled) {
        return 0;
    }
    if (!dev->started) {
        dev->log_enabled = enable;
        return 0;
    }
    if (!enable) {
        r = vhost_dev_set_log(dev, false);
        if (r < 0) {
            return r;
        }
        if (dev->log) {
            qemu_free(dev->log);
        }
        dev->log = NULL;
        dev->log_size = 0;
    } else {
        vhost_dev_log_resize(dev, vhost_get_log_size(dev));
        r = vhost_dev_set_log(dev, true);
        if (r < 0) {
            return r;
        }
    }
    dev->log_enabled = enable;
    return 0;
}
Exemplo n.º 2
0
static int vhost_migration_log(MemoryListener *listener, int enable)
{
    struct vhost_dev *dev = container_of(listener, struct vhost_dev,
                                         memory_listener);
    int r;
    if (!!enable == dev->log_enabled) {
        return 0;
    }
    if (!dev->started) {
        dev->log_enabled = enable;
        return 0;
    }
    if (!enable) {
        r = vhost_dev_set_log(dev, false);
        if (r < 0) {
            return r;
        }
        if (dev->log) {
            g_free(dev->log);
        }
        dev->log = NULL;
        dev->log_size = 0;
    } else {
        vhost_dev_log_resize(dev, vhost_get_log_size(dev));
        r = vhost_dev_set_log(dev, true);
        if (r < 0) {
            return r;
        }
    }
    dev->log_enabled = enable;
    return 0;
}
Exemplo n.º 3
0
static void vhost_client_set_memory(CPUPhysMemoryClient *client,
                                    target_phys_addr_t start_addr,
                                    ram_addr_t size,
                                    ram_addr_t phys_offset)
{
    struct vhost_dev *dev = container_of(client, struct vhost_dev, client);
    ram_addr_t flags = phys_offset & ~TARGET_PAGE_MASK;
    int s = offsetof(struct vhost_memory, regions) +
        (dev->mem->nregions + 1) * sizeof dev->mem->regions[0];
    uint64_t log_size;
    int r;
    dev->mem = qemu_realloc(dev->mem, s);

    assert(size);

    vhost_dev_unassign_memory(dev, start_addr, size);
    if (flags == IO_MEM_RAM) {
        /* Add given mapping, merging adjacent regions if any */
        vhost_dev_assign_memory(dev, start_addr, size,
                                (uintptr_t)qemu_get_ram_ptr(phys_offset));
    } else {
        /* Remove old mapping for this memory, if any. */
        vhost_dev_unassign_memory(dev, start_addr, size);
    }

    if (!dev->started) {
        return;
    }

    if (dev->started) {
        r = vhost_verify_ring_mappings(dev, start_addr, size);
        assert(r >= 0);
    }

    if (!dev->log_enabled) {
        r = ioctl(dev->control, VHOST_SET_MEM_TABLE, dev->mem);
        assert(r >= 0);
        return;
    }
    log_size = vhost_get_log_size(dev);
    /* We allocate an extra 4K bytes to log,
     * to reduce the * number of reallocations. */
#define VHOST_LOG_BUFFER (0x1000 / sizeof *dev->log)
    /* To log more, must increase log size before table update. */
    if (dev->log_size < log_size) {
        vhost_dev_log_resize(dev, log_size + VHOST_LOG_BUFFER);
    }
    r = ioctl(dev->control, VHOST_SET_MEM_TABLE, dev->mem);
    assert(r >= 0);
    /* To log less, can only decrease log size after table update. */
    if (dev->log_size > log_size + VHOST_LOG_BUFFER) {
        vhost_dev_log_resize(dev, log_size);
    }
}
Exemplo n.º 4
0
Arquivo: vhost.c Projeto: iggy/qemu
int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev)
{
    int i, r;

    r = vhost_dev_set_features(hdev, hdev->log_enabled);
    if (r < 0) {
        goto fail;
    }
    r = ioctl(hdev->control, VHOST_SET_MEM_TABLE, hdev->mem);
    if (r < 0) {
        r = -errno;
        goto fail;
    }
    if (hdev->log_enabled) {
        hdev->log_size = vhost_get_log_size(hdev);
        hdev->log = hdev->log_size ?
            qemu_mallocz(hdev->log_size * sizeof *hdev->log) : NULL;
        r = ioctl(hdev->control, VHOST_SET_LOG_BASE,
                  (uint64_t)(unsigned long)hdev->log);
        if (r < 0) {
            r = -errno;
            goto fail;
        }
    }

    for (i = 0; i < hdev->nvqs; ++i) {
        r = vhost_virtqueue_init(hdev,
                                 vdev,
                                 hdev->vqs + i,
                                 i);
        if (r < 0) {
            goto fail_vq;
        }
    }
    hdev->started = true;

    return 0;
fail_vq:
    while (--i >= 0) {
        vhost_virtqueue_cleanup(hdev,
                                vdev,
                                hdev->vqs + i,
                                i);
    }
fail:
    return r;
}
Exemplo n.º 5
0
int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev)
{
    int i, r;
    if (!vdev->binding->set_guest_notifiers) {
        fprintf(stderr, "binding does not support guest notifiers\n");
        r = -ENOSYS;
        goto fail;
    }

    r = vdev->binding->set_guest_notifiers(vdev->binding_opaque, true);
    if (r < 0) {
        fprintf(stderr, "Error binding guest notifier: %d\n", -r);
        goto fail_notifiers;
    }

    r = vhost_dev_set_features(hdev, hdev->log_enabled);
    if (r < 0) {
        goto fail_features;
    }
    r = ioctl(hdev->control, VHOST_SET_MEM_TABLE, hdev->mem);
    if (r < 0) {
        r = -errno;
        goto fail_mem;
    }
    for (i = 0; i < hdev->nvqs; ++i) {
        r = vhost_virtqueue_init(hdev,
                                 vdev,
                                 hdev->vqs + i,
                                 i);
        if (r < 0) {
            goto fail_vq;
        }
    }

    if (hdev->log_enabled) {
        hdev->log_size = vhost_get_log_size(hdev);
        hdev->log = hdev->log_size ?
            qemu_mallocz(hdev->log_size * sizeof *hdev->log) : NULL;
        r = ioctl(hdev->control, VHOST_SET_LOG_BASE,
                  (uint64_t)(unsigned long)hdev->log);
        if (r < 0) {
            r = -errno;
            goto fail_log;
        }
    }

    hdev->started = true;

    return 0;
fail_log:
fail_vq:
    while (--i >= 0) {
        vhost_virtqueue_cleanup(hdev,
                                vdev,
                                hdev->vqs + i,
                                i);
    }
fail_mem:
fail_features:
    vdev->binding->set_guest_notifiers(vdev->binding_opaque, false);
fail_notifiers:
fail:
    return r;
}
Exemplo n.º 6
0
static void vhost_client_set_memory(CPUPhysMemoryClient *client,
                                    target_phys_addr_t start_addr,
                                    ram_addr_t size,
                                    ram_addr_t phys_offset)
{
    struct vhost_dev *dev = container_of(client, struct vhost_dev, client);
    ram_addr_t flags = phys_offset & ~TARGET_PAGE_MASK;
    int s = offsetof(struct vhost_memory, regions) +
        (dev->mem->nregions + 1) * sizeof dev->mem->regions[0];
    uint64_t log_size;
    int r;

    /* TODO: this is a hack.
     * At least one vga card (cirrus) changes the gpa to hva 
     * memory maps on data path, which slows us down.
     * Since we should never need to DMA into VGA memory
     * anyway, lets just skip these regions. */
    if (ranges_overlap(start_addr, size, 0xa0000, 0x10000)) {
        return;
    }

    dev->mem = qemu_realloc(dev->mem, s);

    assert(size);

    vhost_mem_unassign_memory(dev->mem, start_addr, size);
    if (flags == IO_MEM_RAM) {
        /* Add given mapping, merging adjacent regions if any */
        vhost_mem_assign_memory(dev->mem, start_addr, size,
                                (uintptr_t)qemu_get_ram_ptr(phys_offset));
    } else {
        /* Remove old mapping for this memory, if any. */
        vhost_mem_unassign_memory(dev->mem, start_addr, size);
    }

    if (!dev->started) {
        return;
    }

    if (dev->started) {
        r = vhost_verify_ring_mappings(dev, start_addr, size);
        assert(r >= 0);
    }

    if (!dev->log_enabled) {
        r = ioctl(dev->control, VHOST_SET_MEM_TABLE, dev->mem);
        assert(r >= 0);
        return;
    }
    log_size = vhost_get_log_size(dev);
    /* We allocate an extra 4K bytes to log,
     * to reduce the * number of reallocations. */
#define VHOST_LOG_BUFFER (0x1000 / sizeof *dev->log)
    /* To log more, must increase log size before table update. */
    if (dev->log_size < log_size) {
        vhost_dev_log_resize(dev, log_size + VHOST_LOG_BUFFER);
    }
    r = ioctl(dev->control, VHOST_SET_MEM_TABLE, dev->mem);
    assert(r >= 0);
    /* To log less, can only decrease log size after table update. */
    if (dev->log_size > log_size + VHOST_LOG_BUFFER) {
        vhost_dev_log_resize(dev, log_size);
    }
}
Exemplo n.º 7
0
static void vhost_set_memory(MemoryListener *listener,
                             MemoryRegionSection *section,
                             bool add)
{
    struct vhost_dev *dev = container_of(listener, struct vhost_dev,
                                         memory_listener);
    target_phys_addr_t start_addr = section->offset_within_address_space;
    ram_addr_t size = section->size;
    bool log_dirty = memory_region_is_logging(section->mr);
    int s = offsetof(struct vhost_memory, regions) +
        (dev->mem->nregions + 1) * sizeof dev->mem->regions[0];
    uint64_t log_size;
    int r;
    void *ram;

    dev->mem = g_realloc(dev->mem, s);

    if (log_dirty) {
        add = false;
    }

    assert(size);

    /* Optimize no-change case. At least cirrus_vga does this a lot at this time. */
    ram = memory_region_get_ram_ptr(section->mr) + section->offset_within_region;
    if (add) {
        if (!vhost_dev_cmp_memory(dev, start_addr, size, (uintptr_t)ram)) {
            /* Region exists with same address. Nothing to do. */
            return;
        }
    } else {
        if (!vhost_dev_find_reg(dev, start_addr, size)) {
            /* Removing region that we don't access. Nothing to do. */
            return;
        }
    }

    vhost_dev_unassign_memory(dev, start_addr, size);
    if (add) {
        /* Add given mapping, merging adjacent regions if any */
        vhost_dev_assign_memory(dev, start_addr, size, (uintptr_t)ram);
    } else {
        /* Remove old mapping for this memory, if any. */
        vhost_dev_unassign_memory(dev, start_addr, size);
    }

    if (!dev->started) {
        return;
    }

    if (dev->started) {
        r = vhost_verify_ring_mappings(dev, start_addr, size);
        assert(r >= 0);
    }

    if (!dev->log_enabled) {
        r = ioctl(dev->control, VHOST_SET_MEM_TABLE, dev->mem);
        assert(r >= 0);
        return;
    }
    log_size = vhost_get_log_size(dev);
    /* We allocate an extra 4K bytes to log,
     * to reduce the * number of reallocations. */
#define VHOST_LOG_BUFFER (0x1000 / sizeof *dev->log)
    /* To log more, must increase log size before table update. */
    if (dev->log_size < log_size) {
        vhost_dev_log_resize(dev, log_size + VHOST_LOG_BUFFER);
    }
    r = ioctl(dev->control, VHOST_SET_MEM_TABLE, dev->mem);
    assert(r >= 0);
    /* To log less, can only decrease log size after table update. */
    if (dev->log_size > log_size + VHOST_LOG_BUFFER) {
        vhost_dev_log_resize(dev, log_size);
    }
}