From 4c2ef53d3bfb36659c47ba589f35bcab24f425c7 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 4 Jun 2012 13:35:31 +0200 Subject: TTY: vt, remove con_schedule_flip This is identical to tty_schedule_flip. So let us use that instead. Signed-off-by: Jiri Slaby Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/keyboard.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/tty/vt/keyboard.c') diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c index 48cc6f25cfd3..0b6217c93036 100644 --- a/drivers/tty/vt/keyboard.c +++ b/drivers/tty/vt/keyboard.c @@ -310,7 +310,7 @@ static void put_queue(struct vc_data *vc, int ch) if (tty) { tty_insert_flip_char(tty, ch, 0); - con_schedule_flip(tty); + tty_schedule_flip(tty); } } @@ -325,7 +325,7 @@ static void puts_queue(struct vc_data *vc, char *cp) tty_insert_flip_char(tty, *cp, 0); cp++; } - con_schedule_flip(tty); + tty_schedule_flip(tty); } static void applkey(struct vc_data *vc, int key, char mode) @@ -586,7 +586,7 @@ static void fn_send_intr(struct vc_data *vc) if (!tty) return; tty_insert_flip_char(tty, 0, TTY_BREAK); - con_schedule_flip(tty); + tty_schedule_flip(tty); } static void fn_scroll_forw(struct vc_data *vc) -- cgit From 157a4b311c45c9aba75a990464d9680867dc8805 Mon Sep 17 00:00:00 2001 From: Christopher Brannon Date: Fri, 22 Jun 2012 08:16:34 -0500 Subject: tty: keyboard.c: Remove locking from vt_get_leds. There are three call sites for this function, and all three are called within a keyboard handler. kbd_event_lock is already held within keyboard handlers, so attempting to lock it in vt_get_leds causes deadlock. Signed-off-by: Christopher Brannon Acked-by: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/keyboard.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers/tty/vt/keyboard.c') diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c index 0b6217c93036..9b4f60a6ab0e 100644 --- a/drivers/tty/vt/keyboard.c +++ b/drivers/tty/vt/keyboard.c @@ -1049,13 +1049,10 @@ static int kbd_update_leds_helper(struct input_handle *handle, void *data) */ int vt_get_leds(int console, int flag) { - unsigned long flags; struct kbd_struct * kbd = kbd_table + console; int ret; - spin_lock_irqsave(&kbd_event_lock, flags); ret = vc_kbd_led(kbd, flag); - spin_unlock_irqrestore(&kbd_event_lock, flags); return ret; } -- cgit From 3db1ddb725dcd9a2bb32be2b64d0688c3e1c4579 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Tue, 17 Jul 2012 17:06:41 +0100 Subject: vt: fix the keyboard/led locking We touch the LED from both keyboard callback and direct paths. In one case we've got the lock held way up the call chain and in the other we haven't. This leads to complete insanity so fix it by giving the LED bits their own lock. Signed-off-by: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/keyboard.c | 41 +++++++++++++++++++++++------------------ 1 file changed, 23 insertions(+), 18 deletions(-) (limited to 'drivers/tty/vt/keyboard.c') diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c index 9b4f60a6ab0e..681765baef69 100644 --- a/drivers/tty/vt/keyboard.c +++ b/drivers/tty/vt/keyboard.c @@ -119,6 +119,7 @@ static const int NR_TYPES = ARRAY_SIZE(max_vals); static struct input_handler kbd_handler; static DEFINE_SPINLOCK(kbd_event_lock); +static DEFINE_SPINLOCK(led_lock); static unsigned long key_down[BITS_TO_LONGS(KEY_CNT)]; /* keyboard key bitmap */ static unsigned char shift_down[NR_SHIFT]; /* shift state counters.. */ static bool dead_key_next; @@ -984,7 +985,7 @@ static void k_brl(struct vc_data *vc, unsigned char value, char up_flag) * or (ii) whatever pattern of lights people want to show using KDSETLED, * or (iii) specified bits of specified words in kernel memory. */ -unsigned char getledstate(void) +static unsigned char getledstate(void) { return ledstate; } @@ -992,7 +993,7 @@ unsigned char getledstate(void) void setledstate(struct kbd_struct *kbd, unsigned int led) { unsigned long flags; - spin_lock_irqsave(&kbd_event_lock, flags); + spin_lock_irqsave(&led_lock, flags); if (!(led & ~7)) { ledioctl = led; kbd->ledmode = LED_SHOW_IOCTL; @@ -1000,7 +1001,7 @@ void setledstate(struct kbd_struct *kbd, unsigned int led) kbd->ledmode = LED_SHOW_FLAGS; set_leds(); - spin_unlock_irqrestore(&kbd_event_lock, flags); + spin_unlock_irqrestore(&led_lock, flags); } static inline unsigned char getleds(void) @@ -1051,8 +1052,11 @@ int vt_get_leds(int console, int flag) { struct kbd_struct * kbd = kbd_table + console; int ret; + unsigned long flags; + spin_lock_irqsave(&led_lock, flags); ret = vc_kbd_led(kbd, flag); + spin_unlock_irqrestore(&led_lock, flags); return ret; } @@ -1088,11 +1092,11 @@ void vt_set_led_state(int console, int leds) void vt_kbd_con_start(int console) { struct kbd_struct * kbd = kbd_table + console; -/* unsigned long flags; */ -/* spin_lock_irqsave(&kbd_event_lock, flags); */ + unsigned long flags; + spin_lock_irqsave(&led_lock, flags); clr_vc_kbd_led(kbd, VC_SCROLLOCK); set_leds(); -/* spin_unlock_irqrestore(&kbd_event_lock, flags); */ + spin_unlock_irqrestore(&led_lock, flags); } /** @@ -1101,21 +1105,15 @@ void vt_kbd_con_start(int console) * * Handle console stop. This is a wrapper for the VT layer * so that we can keep kbd knowledge internal - * - * FIXME: We eventually need to hold the kbd lock here to protect - * the LED updating. We can't do it yet because fn_hold calls stop_tty - * and start_tty under the kbd_event_lock, while normal tty paths - * don't hold the lock. We probably need to split out an LED lock - * but not during an -rc release! */ void vt_kbd_con_stop(int console) { struct kbd_struct * kbd = kbd_table + console; -/* unsigned long flags; */ -/* spin_lock_irqsave(&kbd_event_lock, flags); */ + unsigned long flags; + spin_lock_irqsave(&led_lock, flags); set_vc_kbd_led(kbd, VC_SCROLLOCK); set_leds(); -/* spin_unlock_irqrestore(&kbd_event_lock, flags); */ + spin_unlock_irqrestore(&led_lock, flags); } /* @@ -1127,7 +1125,12 @@ void vt_kbd_con_stop(int console) */ static void kbd_bh(unsigned long dummy) { - unsigned char leds = getleds(); + unsigned char leds; + unsigned long flags; + + spin_lock_irqsave(&led_lock, flags); + leds = getleds(); + spin_unlock_irqrestore(&led_lock, flags); if (leds != ledstate) { input_handler_for_each_handle(&kbd_handler, &leds, @@ -2032,11 +2035,11 @@ int vt_do_kdskled(int console, int cmd, unsigned long arg, int perm) return -EPERM; if (arg & ~0x77) return -EINVAL; - spin_lock_irqsave(&kbd_event_lock, flags); + spin_lock_irqsave(&led_lock, flags); kbd->ledflagstate = (arg & 7); kbd->default_ledflagstate = ((arg >> 4) & 7); set_leds(); - spin_unlock_irqrestore(&kbd_event_lock, flags); + spin_unlock_irqrestore(&led_lock, flags); return 0; /* the ioctls below only set the lights, not the functions */ @@ -2131,8 +2134,10 @@ void vt_reset_keyboard(int console) clr_vc_kbd_mode(kbd, VC_CRLF); kbd->lockstate = 0; kbd->slockstate = 0; + spin_lock(&led_lock); kbd->ledmode = LED_SHOW_FLAGS; kbd->ledflagstate = kbd->default_ledflagstate; + spin_unlock(&led_lock); /* do not do set_leds here because this causes an endless tasklet loop when the keyboard hasn't been initialized yet */ spin_unlock_irqrestore(&kbd_event_lock, flags); -- cgit