[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Qemu-devel] [PATCHv2 for-1.4] vhost: memory sync fixes
From: |
Jason Wang |
Subject: |
Re: [Qemu-devel] [PATCHv2 for-1.4] vhost: memory sync fixes |
Date: |
Wed, 27 Feb 2013 10:53:58 +0800 |
User-agent: |
Mozilla/5.0 (X11; Linux x86_64; rv:17.0) Gecko/20130106 Thunderbird/17.0.2 |
On 02/26/2013 06:11 PM, Michael S. Tsirkin wrote:
> This fixes two bugs related to memory sync during
> migration:
> - ram address calculation was missing the chunk
> address, so the wrong page was dirtied
> - one after last was used instead of the
> end address of a region, which might overflow to 0
> and cause us to skip the region when the region ends at
> ~0x0ull.
>
> Signed-off-by: Michael S. Tsirkin <address@hidden>
> Tested-by: Jason Wang <address@hidden>
Also need for 1.3
Acked-by: Jason Wang <address@hidden>
> ---
> hw/vhost.c | 49 ++++++++++++++++++++++++++++++++-----------------
> 1 file changed, 32 insertions(+), 17 deletions(-)
>
> diff --git a/hw/vhost.c b/hw/vhost.c
> index 8d41fdb..37777c2 100644
> --- a/hw/vhost.c
> +++ b/hw/vhost.c
> @@ -53,10 +53,14 @@ static void vhost_dev_sync_region(struct vhost_dev *dev,
> log = __sync_fetch_and_and(from, 0);
> while ((bit = sizeof(log) > sizeof(int) ?
> ffsll(log) : ffs(log))) {
> - ram_addr_t ram_addr;
> + hwaddr page_addr;
> + hwaddr section_offset;
> + hwaddr mr_offset;
> bit -= 1;
> - ram_addr = section->offset_within_region + bit * VHOST_LOG_PAGE;
> - memory_region_set_dirty(section->mr, ram_addr, VHOST_LOG_PAGE);
> + page_addr = addr + bit * VHOST_LOG_PAGE;
> + section_offset = page_addr -
> section->offset_within_address_space;
> + mr_offset = section_offset + section->offset_within_region;
> + memory_region_set_dirty(section->mr, mr_offset, VHOST_LOG_PAGE);
> log &= ~(0x1ull << bit);
> }
> addr += VHOST_LOG_CHUNK;
> @@ -65,14 +69,21 @@ static void vhost_dev_sync_region(struct vhost_dev *dev,
>
> static int vhost_sync_dirty_bitmap(struct vhost_dev *dev,
> MemoryRegionSection *section,
> - hwaddr start_addr,
> - hwaddr end_addr)
> + hwaddr first,
> + hwaddr last)
> {
> int i;
> + hwaddr start_addr;
> + hwaddr end_addr;
>
> if (!dev->log_enabled || !dev->started) {
> return 0;
> }
> + start_addr = section->offset_within_address_space;
> + end_addr = range_get_last(start_addr, section->size);
> + start_addr = MAX(first, start_addr);
> + end_addr = MIN(last, end_addr);
> +
> for (i = 0; i < dev->mem->nregions; ++i) {
> struct vhost_memory_region *reg = dev->mem->regions + i;
> vhost_dev_sync_region(dev, section, start_addr, end_addr,
> @@ -93,10 +104,18 @@ static void vhost_log_sync(MemoryListener *listener,
> {
> struct vhost_dev *dev = container_of(listener, struct vhost_dev,
> memory_listener);
> - hwaddr start_addr = section->offset_within_address_space;
> - hwaddr end_addr = start_addr + section->size;
> + vhost_sync_dirty_bitmap(dev, section, 0x0, ~0x0ULL);
> +}
>
> - vhost_sync_dirty_bitmap(dev, section, start_addr, end_addr);
> +static void vhost_log_sync_range(struct vhost_dev *dev,
> + hwaddr first, hwaddr last)
> +{
> + int i;
> + /* FIXME: this is N^2 in number of sections */
> + for (i = 0; i < dev->n_mem_sections; ++i) {
> + MemoryRegionSection *section = &dev->mem_sections[i];
> + vhost_sync_dirty_bitmap(dev, section, first, last);
> + }
> }
>
> /* Assign/unassign. Keep an unsorted array of non-overlapping
> @@ -268,16 +287,15 @@ static inline void vhost_dev_log_resize(struct
> vhost_dev* dev, uint64_t size)
> {
> vhost_log_chunk_t *log;
> uint64_t log_base;
> - int r, i;
> + int r;
>
> log = g_malloc0(size * sizeof *log);
> log_base = (uint64_t)(unsigned long)log;
> r = ioctl(dev->control, VHOST_SET_LOG_BASE, &log_base);
> assert(r >= 0);
> - for (i = 0; i < dev->n_mem_sections; ++i) {
> - /* Sync only the range covered by the old log */
> - vhost_sync_dirty_bitmap(dev, &dev->mem_sections[i], 0,
> - dev->log_size * VHOST_LOG_CHUNK - 1);
> + /* Sync only the range covered by the old log */
> + if (dev->log_size) {
> + vhost_log_sync_range(dev, 0, dev->log_size * VHOST_LOG_CHUNK - 1);
> }
> if (dev->log) {
> g_free(dev->log);
> @@ -1014,10 +1032,7 @@ void vhost_dev_stop(struct vhost_dev *hdev,
> VirtIODevice *vdev)
> hdev->vqs + i,
> hdev->vq_index + i);
> }
> - for (i = 0; i < hdev->n_mem_sections; ++i) {
> - vhost_sync_dirty_bitmap(hdev, &hdev->mem_sections[i],
> - 0, (hwaddr)~0x0ull);
> - }
> + vhost_log_sync_range(hdev, 0, ~0x0ull);
>
> hdev->started = false;
> g_free(hdev->log);