Skip to contentSkip to conversation

Linux-HVM, qemu, and xen-balloon.ko

PATCH New George Dunlap 2 participants 2 messages Dec 12, 2008 – Dec 15, 2008

lore
Share & tools
lore
#0 lore raw

There seems to be some sort of a bug when qemu interacts with the balloon driver. Stefano is trying to repro it, but I thought I'd share it for people to look at.

Host:
+ Debian 4.0 host installation
+ Vanilla -unstable xen dom0 kernel, hypervisor, and qemu-dm (all pulled this morning)
+ 4G of ram
VM:
+ Debian 4.0 Linux HVM, 2.6.18-6-i686 package
+ unmodified_drivers/ modules compiled for xen-platform-pci, and xen-balloon
+ 512M of RAM assigned
+ Disk and network are still emulated, using qemu

To repro:
* Boot the VM
* modprobe xen_balloon
* In one VM shell:

 # while true ; do rm -f zero ; dd if=/dev/zero of=zero ; done
* In another VM shell, use 'free' to see when the amount of free
memory is near zero
* In dom0:
 # xm mem-set debian-hvm 256
* In the VM shell, use 'free' to see when the amount of total memory
reaches 256 (this may take awhile, as the guest OS has to write data
out to disk.)
* In dom0:
 # xm mem-set debian-hvm 512

qemu will crash shortly.

When I install xen-vbd in the initrd, the problem goes away. So it seems almost certain that there's some mapping in qemu not getting flushed when the balloon driver hands pages back to Xen, so that when it asks Xen for pages again, and then tries to DMA into the same gpfn space, something gets lost in the translation.

Any ideas?

Peace,
-George

#1 lore raw

PATCH 1/1 Linux-HVM, qemu, and xen-balloon.ko

Quoted 3 lines · George Dunlap

There seems to be some sort of a bug when qemu interacts with the balloon driver. Stefano is trying to repro it, but I thought I'd share it for people to look at.

There is a bug in qemu_map_cache: if address_index == last_address_index we don't check that there is a valid_mapping for address_offset in the bucket.
The following patch fixes it.

---

hw/xen_machine_fv.c +4 -3
diff -r 0ea6bd53cfb6 hw/xen_machine_fv.c
@@ -135,10 +135,11 @@
     unsigned long address_index  = phys_addr >> MCACHE_BUCKET_SHIFT;
     unsigned long address_offset = phys_addr & (MCACHE_BUCKET_SIZE-1);
 
-    if (address_index == last_address_index)
+    entry = &mapcache_entry[address_index % nr_buckets];
+
+    if (address_index == last_address_index &&
+        test_bit(address_offset>>XC_PAGE_SHIFT, entry->valid_mapping))
         return last_address_vaddr + address_offset;
-
-    entry = &mapcache_entry[address_index % nr_buckets];
 
     if (entry->vaddr_base == NULL || entry->paddr_index != address_index ||
         !test_bit(address_offset>>XC_PAGE_SHIFT, entry->valid_mapping))