[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [PATCH 1/3] x86/xen: allow for privcmd hypercalls to be preempted



From: Andrew Cooper <andrew.cooper3@xxxxxxxxxx>

Hypercalls submitted by user space tools via the privcmd driver can
take a long time (potentially many 10s of seconds) if the hypercall
has many sub-operations.

A fully preemptible kernel may deschedule such as task in any upcall
called from a hypercall continuation.

However, in a kernel with only voluntary preemption, hypercall
continuations in Xen allow event handlers to be run but the task
issuing the hypercall will not be descheduled until the hypercall is
complete and the ioctl returns to user space.  These long running
tasks may also trigger the kernel's soft lockup detection.

There needs to be a voluntary preemption point (cond_resched()) at the
end of an upcall, but only if the interrupted task had issued a
hypercall via the privcmd driver.  Add is_preemptible_hypercall()
which may be used in a upcall to determine this.

Implement is_premptible_hypercall() by adding a second hypercall page
(preemptible_hypercall_page, copied from hypercall_page).  Calls made
via the new page may be preempted.

Signed-off-by: Andrew Cooper <andrew.cooper3@xxxxxxxxxx>
Signed-off-by: David Vrabel <david.vrabel@xxxxxxxxxx>
---
 arch/x86/include/asm/xen/hypercall.h |   14 ++++++++++++++
 arch/x86/xen/enlighten.c             |    7 +++++++
 arch/x86/xen/xen-head.S              |   18 +++++++++++++++++-
 3 files changed, 38 insertions(+), 1 deletions(-)

diff --git a/arch/x86/include/asm/xen/hypercall.h 
b/arch/x86/include/asm/xen/hypercall.h
index e709884..4658a75 100644
--- a/arch/x86/include/asm/xen/hypercall.h
+++ b/arch/x86/include/asm/xen/hypercall.h
@@ -83,6 +83,16 @@
  */
 
 extern struct { char _entry[32]; } hypercall_page[];
+#ifndef CONFIG_PREEMPT
+extern struct { char _entry[32]; } preemptible_hypercall_page[];
+
+static inline bool is_preemptible_hypercall(struct pt_regs *regs)
+{
+       return !user_mode_vm(regs) &&
+               regs->ip >= (unsigned long)preemptible_hypercall_page &&
+               regs->ip < (unsigned long)preemptible_hypercall_page + 
PAGE_SIZE;
+}
+#endif
 
 #define __HYPERCALL            "call hypercall_page+%c[offset]"
 #define __HYPERCALL_ENTRY(x)                                           \
@@ -215,7 +225,11 @@ privcmd_call(unsigned call,
 
        asm volatile("call *%[call]"
                     : __HYPERCALL_5PARAM
+#ifndef CONFIG_PREEMPT
+                    : [call] "a" (&preemptible_hypercall_page[call])
+#else
                     : [call] "a" (&hypercall_page[call])
+#endif
                     : __HYPERCALL_CLOBBER5);
 
        return (long)__res;
diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c
index a4d7b64..7320fa8 100644
--- a/arch/x86/xen/enlighten.c
+++ b/arch/x86/xen/enlighten.c
@@ -84,6 +84,9 @@
 #include "multicalls.h"
 
 EXPORT_SYMBOL_GPL(hypercall_page);
+#ifndef CONFIG_PREEMPT
+EXPORT_SYMBOL_GPL(preemptible_hypercall_page);
+#endif
 
 /*
  * Pointer to the xen_vcpu_info structure or
@@ -1517,6 +1520,10 @@ asmlinkage void __init xen_start_kernel(void)
        xen_pvh_early_guest_init();
        xen_setup_machphys_mapping();
 
+#ifndef CONFIG_PREEMPT
+       copy_page(preemptible_hypercall_page, hypercall_page);
+#endif
+
        /* Install Xen paravirt ops */
        pv_info = xen_info;
        pv_init_ops = xen_init_ops;
diff --git a/arch/x86/xen/xen-head.S b/arch/x86/xen/xen-head.S
index 485b695..0407d48 100644
--- a/arch/x86/xen/xen-head.S
+++ b/arch/x86/xen/xen-head.S
@@ -50,9 +50,18 @@ ENTRY(startup_xen)
 .pushsection .text
        .balign PAGE_SIZE
 ENTRY(hypercall_page)
+
+#ifdef CONFIG_PREEMPT
+#  define PREEMPT_HYPERCALL_ENTRY(x)
+#else
+#  define PREEMPT_HYPERCALL_ENTRY(x) \
+       .global xen_hypercall_##x ## _p ASM_NL \
+       .set preemptible_xen_hypercall_##x, xen_hypercall_##x + PAGE_SIZE ASM_NL
+#endif
 #define NEXT_HYPERCALL(x) \
        ENTRY(xen_hypercall_##x) \
-       .skip 32
+       .skip 32 ASM_NL \
+       PREEMPT_HYPERCALL_ENTRY(x)
 
 NEXT_HYPERCALL(set_trap_table)
 NEXT_HYPERCALL(mmu_update)
@@ -103,6 +112,13 @@ NEXT_HYPERCALL(arch_4)
 NEXT_HYPERCALL(arch_5)
 NEXT_HYPERCALL(arch_6)
        .balign PAGE_SIZE
+
+#ifndef CONFIG_PREEMPT
+ENTRY(preemptible_hypercall_page)
+       .skip PAGE_SIZE
+#endif /* CONFIG_PREEMPT */
+
+#undef NEXT_HYPERCALL
 .popsection
 
        ELFNOTE(Xen, XEN_ELFNOTE_GUEST_OS,       .asciz "linux")
-- 
1.7.2.5


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.