Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > 27922b4260f65d317aabda37e42bbbff > files > 1599

kernel-2.6.18-238.el5.src.rpm

From: Jiri Pirko <jpirko@redhat.com>
Date: Thu, 25 Sep 2008 15:42:45 +0200
Subject: [input] atkbd: delay executing of LED switching request
Message-id: 20080925154245.27c95fd6@psychotron.englab.brq.redhat.com
O-Subject: [RHEL5.3 patch] BZ461233 atkbd: Delay executing of LED switching request
Bugzilla: 461233
RH-Acked-by: Rik van Riel <riel@redhat.com>
RH-Acked-by: Markus Armbruster <armbru@redhat.com>
RH-Acked-by: Brian Maly <bmaly@redhat.com>

BZ461233
https://bugzilla.redhat.com/show_bug.cgi?id=461233

Description:
On some boxes keyboard controllers are too slow to withstand continuous flow of
requests to turn keyboard LEDs on and off and start losing some keypresses or
even all of them. This causes a local denial of service situation.

Upstream status:
http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=da4249c99fd59c4e224e4f9acaf07669d205bb1d

Brew build:
https://brewweb.devel.redhat.com/taskinfo?taskID=1493452

Test status:
Booted on x86_64, i686. Tested on i686.
With -92 kernel I did reproduce this issue. All keypresses were lost.
I had to "kill -9" appropriate bash via ssh to turn it back to work.
With -116 patched by this patch I was not able to reproduce issue. Not a single
keypress lost.

What's interesting is that with -92 led blinks regularly and quite fast. With
-116 and -115 kernels (without the patch) I experienced about 3 times slower
blinking and irregular.

Jirka

diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c
index dd99588..46c96f0 100644
--- a/drivers/input/keyboard/atkbd.c
+++ b/drivers/input/keyboard/atkbd.c
@@ -223,6 +223,7 @@ struct atkbd {
 	unsigned long time;
 
 	struct work_struct event_work;
+	unsigned long event_jiffies;
 	struct mutex event_mutex;
 	unsigned long event_mask;
 };
@@ -557,12 +558,30 @@ static void atkbd_event_work(void *data)
 }
 
 /*
+ * Schedule switch for execution. We need to throttle requests,
+ * otherwise keyboard may become unresponsive.
+ */
+static void atkbd_schedule_event_work(struct atkbd *atkbd, int event_bit)
+{
+	unsigned long delay = msecs_to_jiffies(50);
+
+	if (time_after(jiffies, atkbd->event_jiffies + delay))
+		delay = 0;
+
+	atkbd->event_jiffies = jiffies;
+	set_bit(event_bit, &atkbd->event_mask);
+	wmb();
+	schedule_delayed_work(&atkbd->event_work, delay);
+}
+
+/*
  * Event callback from the input module. Events that change the state of
  * the hardware are processed here. If action can not be performed in
  * interrupt context it is offloaded to atkbd_event_work.
  */
 
-static int atkbd_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
+static int atkbd_event(struct input_dev *dev,
+			unsigned int type, unsigned int code, int value)
 {
 	struct atkbd *atkbd = dev->private;
 
@@ -572,19 +591,12 @@ static int atkbd_event(struct input_dev *dev, unsigned int type, unsigned int co
 	switch (type) {
 
 		case EV_LED:
-			set_bit(ATKBD_LED_EVENT_BIT, &atkbd->event_mask);
-			wmb();
-			schedule_work(&atkbd->event_work);
+			atkbd_schedule_event_work(atkbd, ATKBD_LED_EVENT_BIT);
 			return 0;
 
 		case EV_REP:
-
-			if (!atkbd->softrepeat) {
-				set_bit(ATKBD_REP_EVENT_BIT, &atkbd->event_mask);
-				wmb();
-				schedule_work(&atkbd->event_work);
-			}
-
+			if (!atkbd->softrepeat)
+				atkbd_schedule_event_work(atkbd, ATKBD_REP_EVENT_BIT);
 			return 0;
 	}