From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([2001:4830:134:3::10]:39763) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Xq4J6-0004w4-7W for qemu-devel@nongnu.org; Sun, 16 Nov 2014 13:12:22 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1Xq4J0-00008b-3N for qemu-devel@nongnu.org; Sun, 16 Nov 2014 13:12:16 -0500 Received: from mail-lb0-f177.google.com ([209.85.217.177]:53029) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Xq4Iz-00008X-Sx for qemu-devel@nongnu.org; Sun, 16 Nov 2014 13:12:10 -0500 Received: by mail-lb0-f177.google.com with SMTP id z12so8040232lbi.22 for ; Sun, 16 Nov 2014 10:12:08 -0800 (PST) MIME-Version: 1.0 From: Peter Maydell Date: Sun, 16 Nov 2014 18:11:48 +0000 Message-ID: Content-Type: text/plain; charset=UTF-8 Subject: [Qemu-devel] exec.c:invalidate_and_set_dirty() only checks whether first page in its range is dirty... List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: QEMU Developers Cc: Paolo Bonzini , Stefan Hajnoczi I'm trying to track down a bug in ARM TCG where we: * boot a guest * run 'shutdown -r now' to trigger a reboot * on reboot, crash when running userspace because the contents of physical RAM have changed but the translated code from before the shutdown was never invalidated This is with a virtio-mmio block device as the disk. Debugging indicates that when the post-reboot guest reloads binaries from disk into ram we fail to invalidate the cached translations. For the specific case I looked at, we have a translation of code at ramaddr_t 0x806e000. The disk load pulls 0x16000 bytes of data off disk to address 0x806a000. Virtio correctly calls address_space_unmap(), which is supposed to be what marks the ram range as dirty. It in turn calls invalidate_and_set_clean(). However invalidate_and_set_clean() just does this: if (cpu_physical_memory_is_clean(addr)) { /* invalidate code */ tb_invalidate_phys_page_range(addr, addr + length, 0); /* set dirty bit */ cpu_physical_memory_set_dirty_range_nocode(addr, length); } So if the first page in the range (here 0x806a000) happens to be dirty then we won't do anything, even if later pages in the range do need to be invalidated. Also, we'll call tb_invalidate_phys_page_range() with a start/end which may be in different physical pages, which is forbidden by that function's API. I guess invalidate_and_set_clean() really needs to be fixed to loop through each page in the range; does anybody know how this is supposed to work (or why nobody's noticed this bug before :-)) ? thanks -- PMM