]> xenbits.xensource.com Git - xen.git/commitdiff
keyhandler: rework process of nonirq keyhandler
authorLan Tianyu <tianyu.lan@intel.com>
Thu, 13 Oct 2016 11:06:28 +0000 (13:06 +0200)
committerJan Beulich <jbeulich@suse.com>
Thu, 13 Oct 2016 11:06:28 +0000 (13:06 +0200)
Keyhandler may run for a long time in serial port driver's
timer handler on the large machine with a lot of physical
cpus(e,g dump_timerq()) when serial port driver works in
the poll mode(via the exception mechanism).

If a timer handler runs a long time, it will block nmi_timer_fn()
to feed NMI watchdog and cause Xen hypervisor panic. Inserting
process_pending_softirqs() in timer handler will not help. when timer
interrupt arrives, timer subsystem calls all expired timer handlers
before programming next timer interrupt. There is no timer interrupt
arriving to trigger timer softirq during run a timer handler.

This patch is to fix the issue to make nonirq keyhandler run in
tasklet when receive debug key from serial port.

Signed-off-by: Lan Tianyu <tianyu.lan@intel.com>
Reviewed-by: Jan Beulich <jbeulich@suse.com>
xen/common/keyhandler.c
xen/common/sysctl.c
xen/drivers/char/console.c
xen/include/xen/keyhandler.h

index 16de6e80904b3b7bc85224529631855cf5c615a0..2f7c364d871a197d5bfe4d4b77cc228eb2675dd6 100644 (file)
@@ -75,19 +75,22 @@ static struct keyhandler {
 
 static void keypress_action(unsigned long unused)
 {
-    handle_keypress(keypress_key, NULL);
+    console_start_log_everything();
+    key_table[keypress_key].fn(keypress_key);
+    console_end_log_everything();
 }
 
 static DECLARE_TASKLET(keypress_tasklet, keypress_action, 0);
 
-void handle_keypress(unsigned char key, struct cpu_user_regs *regs)
+void handle_keypress(unsigned char key, struct cpu_user_regs *regs,
+                     bool force_tasklet)
 {
     struct keyhandler *h;
 
     if ( key >= ARRAY_SIZE(key_table) || !(h = &key_table[key])->fn )
         return;
 
-    if ( !in_irq() || h->irq_callback )
+    if ( h->irq_callback || !force_tasklet )
     {
         console_start_log_everything();
         h->irq_callback ? h->irq_fn(key, regs) : h->fn(key);
index 8aea6efe7af8768d74993eb5f3964e0b2fdb26d3..1eb7baddc01f0631d55a33c3ee06eb577274550f 100644 (file)
@@ -136,7 +136,7 @@ long do_sysctl(XEN_GUEST_HANDLE_PARAM(xen_sysctl_t) u_sysctl)
         {
             if ( copy_from_guest_offset(&c, op->u.debug_keys.keys, i, 1) )
                 goto out;
-            handle_keypress(c, guest_cpu_user_regs());
+            handle_keypress(c, guest_cpu_user_regs(), false);
         }
         ret = 0;
         copyback = 0;
index 55ae31aaa672e4ae0e6814e135d2bde6fa39c13a..b0f74cecadfef2ab45996ca18ac84fe0779ed78f 100644 (file)
@@ -347,7 +347,7 @@ static void switch_serial_input(void)
 static void __serial_rx(char c, struct cpu_user_regs *regs)
 {
     if ( xen_rx )
-        return handle_keypress(c, regs);
+        return handle_keypress(c, regs, !in_irq());
 
     /* Deliver input to guest buffer, unless it is already full. */
     if ( (serial_rx_prod-serial_rx_cons) != SERIAL_RX_SIZE )
index 06c05c8723c598d1eaf252757590cd49b4ba1d5d..fe32d8af2689255d58cf3f02b8ba746e8c23d4d0 100644 (file)
@@ -46,7 +46,8 @@ void register_irq_keyhandler(unsigned char key,
                              bool_t diagnostic);
 
 /* Inject a keypress into the key-handling subsystem. */
-extern void handle_keypress(unsigned char key, struct cpu_user_regs *regs);
+extern void handle_keypress(unsigned char key, struct cpu_user_regs *regs,
+                            bool force_tasklet);
 
 /* Scratch space is available for use of any keyhandler. */
 extern char keyhandler_scratch[1024];