From: Alan Cox <alan@lxorguk.ukuu.org.uk>
To: greg@kroah.com, linux-kernel@vger.kernel.org,
linux-serial@vger.kernel.org
Subject: [PATCH 11/12] vt: fix the keyboard/led locking
Date: Fri, 22 Jun 2012 16:46:34 +0100 [thread overview]
Message-ID: <20120622154625.1405.89444.stgit@localhost.localdomain> (raw)
In-Reply-To: <20120622153600.1405.15575.stgit@localhost.localdomain>
From: Alan Cox <alan@linux.intel.com>
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 <alan@linux.intel.com>
---
drivers/tty/vt/keyboard.c | 42 ++++++++++++++++++++++--------------------
include/linux/kbd_kern.h | 1 -
2 files changed, 22 insertions(+), 21 deletions(-)
diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c
index 48cc6f2..816cbbd 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)
@@ -1053,9 +1054,9 @@ int vt_get_leds(int console, int flag)
struct kbd_struct * kbd = kbd_table + console;
int ret;
- spin_lock_irqsave(&kbd_event_lock, flags);
+ spin_lock_irqsave(&led_lock, flags);
ret = vc_kbd_led(kbd, flag);
- spin_unlock_irqrestore(&kbd_event_lock, flags);
+ spin_unlock_irqrestore(&led_lock, flags);
return ret;
}
@@ -1091,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);
}
/**
@@ -1104,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);
}
/*
@@ -1130,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,
@@ -2035,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 */
@@ -2134,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);
diff --git a/include/linux/kbd_kern.h b/include/linux/kbd_kern.h
index daf4a3a..37d5877 100644
--- a/include/linux/kbd_kern.h
+++ b/include/linux/kbd_kern.h
@@ -65,7 +65,6 @@ struct kbd_struct {
extern int kbd_init(void);
-extern unsigned char getledstate(void);
extern void setledstate(struct kbd_struct *kbd, unsigned int led);
extern int do_poke_blanked_console;
next prev parent reply other threads:[~2012-06-22 15:46 UTC|newest]
Thread overview: 23+ messages / expand[flat|nested] mbox.gz Atom feed top
2012-06-22 15:36 [PATCH 01/12] f81232: correct stubbed termios handler Alan Cox
2012-06-22 15:38 ` [PATCH 02/12] usb: fix sillies in the metro USB driver Alan Cox
2012-06-24 21:49 ` Jiri Slaby
2012-07-23 16:32 ` Alan Cox
2012-06-22 15:40 ` [PATCH 03/12] tty: note race we need to fix Alan Cox
2012-06-22 15:42 ` [PATCH 04/12] gpio-sch: Fix resource leak Alan Cox
2012-06-27 2:25 ` Greg KH
2012-06-22 15:43 ` [PATCH 05/12] kobil_sct: Fix some bogus tty handling Alan Cox
2012-06-27 2:24 ` Greg KH
2012-06-22 15:43 ` [PATCH 06/12] 8250: use the 8250 register interface not the legacy one Alan Cox
2012-06-27 2:30 ` Greg KH
2012-06-22 15:44 ` [PATCH 07/12] 8250: propogate the bugs field Alan Cox
2012-06-22 15:44 ` [PATCH 08/12] 8250: add support for ASIX devices with a FIFO bug Alan Cox
2012-06-22 15:44 ` [PATCH 09/12] commit 22126843cb3c2a782c2d52614486115f3e9db478 Alan Cox
2012-06-22 15:36 ` Greg KH
2012-06-22 17:04 ` Alan Cox
2012-08-01 0:51 ` Yinghai Lu
2012-06-22 15:46 ` [PATCH 10/12] tty: tidy up the RESET_TERMIOS case Alan Cox
2012-06-22 15:46 ` Alan Cox [this message]
2012-06-22 15:47 ` [PATCH 12/12] tty: move the handling of the tty release logic Alan Cox
2012-08-01 0:47 ` Yinghai Lu
2012-06-27 2:22 ` [PATCH 01/12] f81232: correct stubbed termios handler Greg KH
-- strict thread matches above, loose matches on Subject: below --
2012-06-27 11:21 Alan Cox
2012-06-27 11:23 ` [PATCH 11/12] vt: fix the keyboard/led locking Alan Cox
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20120622154625.1405.89444.stgit@localhost.localdomain \
--to=alan@lxorguk.ukuu.org.uk \
--cc=greg@kroah.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-serial@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).