From patchwork Tue Feb 26 10:11:31 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Michael S. Tsirkin" X-Patchwork-Id: 223166 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 79FC12C0294 for ; Tue, 26 Feb 2013 21:11:35 +1100 (EST) Received: from localhost ([::1]:58850 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1UAHVV-0000Az-Kg for incoming@patchwork.ozlabs.org; Tue, 26 Feb 2013 05:11:33 -0500 Received: from eggs.gnu.org ([208.118.235.92]:37703) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1UAHVL-0000AV-OL for qemu-devel@nongnu.org; Tue, 26 Feb 2013 05:11:26 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1UAHVI-0008R1-T2 for qemu-devel@nongnu.org; Tue, 26 Feb 2013 05:11:23 -0500 Received: from mx1.redhat.com ([209.132.183.28]:53451) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1UAHVI-0008Qj-Li for qemu-devel@nongnu.org; Tue, 26 Feb 2013 05:11:20 -0500 Received: from int-mx10.intmail.prod.int.phx2.redhat.com (int-mx10.intmail.prod.int.phx2.redhat.com [10.5.11.23]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id r1QABI7R019965 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Tue, 26 Feb 2013 05:11:18 -0500 Received: from redhat.com (vpn1-4-143.ams2.redhat.com [10.36.4.143]) by int-mx10.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with SMTP id r1QABFmA007898; Tue, 26 Feb 2013 05:11:16 -0500 Date: Tue, 26 Feb 2013 12:11:31 +0200 From: "Michael S. Tsirkin" To: qemu-devel@nongnu.org Message-ID: <20130226101053.GA22129@redhat.com> MIME-Version: 1.0 Content-Disposition: inline X-Scanned-By: MIMEDefang 2.68 on 10.5.11.23 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x X-Received-From: 209.132.183.28 Cc: Jason Wang , Paolo Bonzini , Anthony Liguori , avi.kivity@gmail.com, Stefan Hajnoczi Subject: [Qemu-devel] [PATCHv2 for-1.4] vhost: memory sync fixes X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org 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 Tested-by: Jason Wang Acked-by: Jason Wang --- 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);