Oracle bug 7556514 32-bit PVHVM guest running under 64-bit hypervisor will crash if "xm mem-set" attempts to change its memory reservation. Change the 32-bit PVHVM balloon driver to check if memory reservation changes are supported. This is done by issuing a zero page XENMEM_decrease_reservation hypervisor call to see if it returns -ENOSYS. Also fix two compiler warnings by changing: "#ifdef CONFIG_PROC_FS" to: "#if defined(CONFIG_PROC_FS) && defined(CONFIG_XEN)" for the definitions of balloon_pde, balloon_read() and balloon_write() to match the conditional wrapper around their reference. --- linux-2.6.9/drivers/xen/balloon/balloon.c.orig 2009-01-22 15:42:00.000000000 -0800 +++ linux-2.6.9/drivers/xen/balloon/balloon.c 2009-03-13 21:03:55.000000000 -0700 @@ -70,9 +70,9 @@ #define PAGES2KB(_p) ((_p)<<(PAGE_SHIFT-10)) -#ifdef CONFIG_PROC_FS +#if defined(CONFIG_PROC_FS) && defined(CONFIG_XEN) static struct proc_dir_entry *balloon_pde; -#endif +#endif /* defined(CONFIG_PROC_FS) && defined(CONFIG_XEN) */ static DECLARE_MUTEX(balloon_mutex); @@ -130,6 +130,15 @@ #define WPRINTK(fmt, args...) \ printk(KERN_WARNING "xen_mem: " fmt, ##args) +/* + * Oracle bug 7556514 + * if PVHVM and guest is X86-32bit, need to check if mem reservation changes + * are supported by the hypervisor. + */ +#if CONFIG_XEN_PV_ON_HVM && (CONFIG_X86 && !CONFIG_X86_64) +static int mem_reservation_change_supported(void); +#endif /* CONFIG_XEN_PV_ON_HVM && (CONFIG_X86 && !CONFIG_X86_64) */ + /* balloon_append: add the given page to the balloon. */ static void balloon_append(struct page *page) { @@ -353,6 +362,14 @@ down(&balloon_mutex); + /* Oracle bug 7556514 */ +#if CONFIG_XEN_PV_ON_HVM && (CONFIG_X86 && !CONFIG_X86_64) + if (mem_reservation_change_supported() == 0) { + up(&balloon_mutex); + return; + } +#endif /* CONFIG_XEN_PV_ON_HVM && (CONFIG_X86 && !CONFIG_X86_64) */ + do { credit = current_target() - current_pages; if (credit > 0) @@ -419,7 +436,7 @@ return NOTIFY_DONE; } -#ifdef CONFIG_PROC_FS +#if defined CONFIG_PROC_FS && defined(CONFIG_XEN) static int balloon_write(struct file *file, const char __user *buffer, unsigned long count, void *data) { @@ -438,6 +455,14 @@ return -EFAULT; memstring[sizeof(memstring)-1] = '\0'; + /* Oracle bug 7556514 */ +#if CONFIG_XEN_PV_ON_HVM && (CONFIG_X86 && !CONFIG_X86_64) + if (mem_reservation_change_supported() == 0) { + /* memory reservation changes are not supported */ + return -ENOSYS; + } +#endif /* CONFIG_XEN_PV_ON_HVM && (CONFIG_X86 && !CONFIG_X86_64) */ + target_bytes = memparse(memstring, &endchar); set_new_target(target_bytes >> PAGE_SHIFT); @@ -469,7 +494,7 @@ *eof = 1; return len; } -#endif +#endif /* CONFIG_PROC_FS && defined(CONFIG_XEN) */ static struct notifier_block xenstore_notifier; @@ -662,6 +687,77 @@ schedule_work(&balloon_worker); } +/* Oracle bug 7556514 */ +#if CONFIG_XEN_PV_ON_HVM && (CONFIG_X86 && !CONFIG_X86_64) +/* + * mem_reservation_change_supported() + * Check to see if the hypervisor call XENMEM_decrease_reservation is supported + * for this guest. OVM xen (so far) has not supported it + * (or XENMEM_increase_reservation) from a 32-bit PVHVM guest running under a + * 64-bit hypervisor. + * We assume that XENMEM_increase_reservation support is the same as support + * for XENMEM_decrease_reservation. + * + * We issue a XENMEM_decrease_reservation hv call specifying a change + * of zero pages. We want to see if -ENOSYS is returned, indicating that + * the hv call is not supported for this guest. + * We assume that any other return value indicates the call is supported. + * + * Locking: + * No locks need to be held on entry. + * No locks acquired or released. + * OK if "set change_supported" path is taken more than once. + * If CPUs race to set change_supported, they presumably will + * write the same value. + * + * Return values: + * 0 - XENMEM_decrease_reservation is not supported + * 1 - XENMEM_decrease_reservation is supported + */ +static int mem_reservation_change_supported(void) { + int ret; + static unsigned int msg_issued = 0; + /* -1 == we have not checked if change is supported */ + static int change_supported = -1; + struct xen_memory_reservation reservation = { + .nr_extents = 0, + .extent_order = 0, + .domid = DOMID_SELF + }; + + if (change_supported == 1) { + /* we have checked and changes are supported */ + return 1; + } + else if (change_supported == 0) { + /* we have checked and changes not supported */ + return 0; + } + + /* + * We have not checked if mem reservation changes are supported. + * Attempt zero sized XENMEM_decrease_reservation to see if we + * get -ENOSYS. + */ + ret = HYPERVISOR_memory_op(XENMEM_decrease_reservation, &reservation); + if (ret == -ENOSYS) { + /* memory reservation changes are not supported */ + change_supported = 0; + if (!msg_issued) { + msg_issued = 1; + printk(KERN_WARNING + "Balloon driver: Changing memory reservation is not supported on this guest.\n"); + printk(KERN_WARNING + "Balloon driver: 'xm mem-set' will have no effect.\n"); + } + return 0; + } + /* memory reservation changes are supported */ + change_supported = 1; + return 1; +} +#endif /* CONFIG_XEN_PV_ON_HVM && (CONFIG_X86 && !CONFIG_X86_64) */ + EXPORT_SYMBOL_GPL(balloon_update_driver_allowance); EXPORT_SYMBOL_GPL(alloc_empty_pages_and_pagevec); EXPORT_SYMBOL_GPL(free_empty_pages_and_pagevec);