Testing issues for long hypercall runs with CONFIG_PREEMPT=n is hard, the one known reported issue is triggered by creating a 50 GiB HVM guest [0], to help test this on smaller systems this creates a busy loop and sprinkles them in a few places that will not trigger when using dom0 but only when creating other guests. If you'd like to test possible issue with long hypercalls in other areas you can emulate by doing the same in other areas. [0] https://bugzilla.novell.com/show_bug.cgi?id=861093 diff --git a/xen/arch/x86/mm.c b/xen/arch/x86/mm.c index d23cb3f..0e8c041 100644 --- a/xen/arch/x86/mm.c +++ b/xen/arch/x86/mm.c @@ -4632,6 +4632,7 @@ long arch_memory_op(unsigned long cmd, XEN_GUEST_HANDLE_PARAM(void) arg) struct xen_foreign_memory_map fmap; struct domain *d; struct e820entry *e820; + dprintk(XENLOG_G_INFO, "DEBUG XENMEM_set_memory_map\n"); if ( copy_from_guest(&fmap, arg, 1) ) return -EFAULT; @@ -4685,6 +4686,7 @@ long arch_memory_op(unsigned long cmd, XEN_GUEST_HANDLE_PARAM(void) arg) struct xen_memory_map map; struct domain *d = current->domain; + dprintk(XENLOG_G_INFO, "DEBUG XENMEM_memory_map\n"); if ( copy_from_guest(&map, arg, 1) ) return -EFAULT; @@ -4716,6 +4718,8 @@ long arch_memory_op(unsigned long cmd, XEN_GUEST_HANDLE_PARAM(void) arg) XEN_GUEST_HANDLE_PARAM(e820entry_t) buffer_param; unsigned int i; + dprintk(XENLOG_G_INFO, "DEBUG XENMEM_machine_memory_map\n"); + rc = xsm_machine_memory_map(XSM_PRIV); if ( rc ) return rc; @@ -4776,6 +4780,7 @@ long arch_memory_op(unsigned long cmd, XEN_GUEST_HANDLE_PARAM(void) arg) .v_end = MACH2PHYS_VIRT_END, .max_mfn = MACH2PHYS_NR_ENTRIES - 1 }; + dprintk(XENLOG_G_INFO, "DEBUG XENMEM_machphys_mapping\n"); if ( !mem_hotplug && is_hardware_domain(current->domain) ) mapping.max_mfn = max_page - 1; @@ -4792,6 +4797,11 @@ long arch_memory_op(unsigned long cmd, XEN_GUEST_HANDLE_PARAM(void) arg) struct domain *d; struct p2m_domain *p2m; + if ( op == XENMEM_set_pod_target ) + dprintk(XENLOG_G_INFO, "DEBUG XENMEM_set_pod_target\n"); + else + dprintk(XENLOG_G_INFO, "DEBUG XENMEM_get_pod_target\n"); + if ( copy_from_guest(&target, arg, 1) ) return -EFAULT; @@ -4843,6 +4853,8 @@ long arch_memory_op(unsigned long cmd, XEN_GUEST_HANDLE_PARAM(void) arg) } default: + dprintk(XENLOG_G_INFO, "DEBUG going to call subarch_memory_op\n"); + busy_loop(400000000); return subarch_memory_op(cmd, arg); } diff --git a/xen/arch/x86/mm/p2m-pod.c b/xen/arch/x86/mm/p2m-pod.c index bd4c7c8..0d177a4 100644 --- a/xen/arch/x86/mm/p2m-pod.c +++ b/xen/arch/x86/mm/p2m-pod.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -219,6 +220,9 @@ p2m_pod_set_cache_target(struct p2m_domain *p2m, unsigned long pod_target, int p struct page_info * page; int order; + busy_loop(40000000); + dprintk(XENLOG_G_INFO, "domain: %d - p2m->pod.count: %ld\n", p2m->domain->domain_id, p2m->pod.count); + if ( (pod_target - p2m->pod.count) >= SUPERPAGE_PAGES ) order = PAGE_ORDER_2M; else diff --git a/xen/common/compat/schedule.c b/xen/common/compat/schedule.c index 812c550..0184587 100644 --- a/xen/common/compat/schedule.c +++ b/xen/common/compat/schedule.c @@ -8,6 +8,7 @@ #define COMPAT #define ret_t int +#define busy_loop compat_busy_loop #define do_sched_op compat_sched_op #define xen_sched_shutdown sched_shutdown diff --git a/xen/common/schedule.c b/xen/common/schedule.c index 73cc2ea..09f475d 100644 --- a/xen/common/schedule.c +++ b/xen/common/schedule.c @@ -921,6 +921,22 @@ typedef long ret_t; #endif /* !COMPAT */ +void busy_loop(unsigned int secs) +{ + unsigned int i; + s_time_t now = NOW(); + + for (i=0; i<=secs; i++) + { + /* In theory 1 sec -- in reality.... much less than that + * depending on where it is called, hence such big + * calls for this. + */ + while (NOW() < now + 1000000000) + cpu_relax(); + } +} + ret_t do_sched_op(int cmd, XEN_GUEST_HANDLE_PARAM(void) arg) { ret_t ret = 0; @@ -992,9 +1008,25 @@ ret_t do_sched_op(int cmd, XEN_GUEST_HANDLE_PARAM(void) arg) case SCHEDOP_remote_shutdown: { + unsigned int i; struct domain *d; struct sched_remote_shutdown sched_remote_shutdown; + /* + * N.B. This is a dangerious test, this can cause corruption on your + * filesystem, be prepared to fsck them after running: + * + * xl shutdown + * + * I don't expect any hypercalls to drag on forever here, nor are + * there any reports about but its an exterme example of an issue + * without preempted hypercalls. + */ + for (i=0; i < 3; i++) { + busy_loop(1000000000); + dprintk(XENLOG_G_INFO, "SCHEDOP_remote_shutdown iter %d\n", i); + } + ret = -EFAULT; if ( copy_from_guest(&sched_remote_shutdown, arg, 1) ) break; diff --git a/xen/include/xen/hypercall.h b/xen/include/xen/hypercall.h index a9e5229..c1f7ec2 100644 --- a/xen/include/xen/hypercall.h +++ b/xen/include/xen/hypercall.h @@ -21,6 +21,10 @@ extern long do_ni_hypercall( void); +extern void +busy_loop( + unsigned int secs); + extern long do_sched_op_compat( int cmd,