qemu-devel
[Top][All Lists]
Advanced

[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);




reply via email to

[Prev in Thread] Current Thread [Next in Thread]