svn commit: r340518 - in stable/12/sys/dev: atkbdc evdev kbdmux usb/input

Vladimir Kondratyev wulf at FreeBSD.org
Sat Nov 17 20:18:17 UTC 2018


Author: wulf
Date: Sat Nov 17 20:18:15 2018
New Revision: 340518
URL: https://svnweb.freebsd.org/changeset/base/340518

Log:
  MFC r339823:
  
  evdev: Use console lock as evdev lock for all supported keyboard drivers.
  
  Now evdev part of keyboard drivers does not take any locks if corresponding
  input/eventN device node is not opened by userland consumers.
  
  Do not assert console lock inside evdev to handle the cases when keyboard
  driver is called from some special single-threaded context like shutdown
  thread.
  
  MFC r339824:
  
  evdev: disable evdev if it is invoked from KDB or panic context
  
  This allow to prevent deadlock on entering KDB if one of evdev locks is
  already taken by userspace process.
  
  Also this change discards all but LED console events produced by KDB as
  unrelated to userspace.

Modified:
  stable/12/sys/dev/atkbdc/atkbd.c
  stable/12/sys/dev/evdev/cdev.c
  stable/12/sys/dev/evdev/evdev.c
  stable/12/sys/dev/evdev/evdev_private.h
  stable/12/sys/dev/kbdmux/kbdmux.c
  stable/12/sys/dev/usb/input/ukbd.c
Directory Properties:
  stable/12/   (props changed)

Modified: stable/12/sys/dev/atkbdc/atkbd.c
==============================================================================
--- stable/12/sys/dev/atkbdc/atkbd.c	Sat Nov 17 20:14:02 2018	(r340517)
+++ stable/12/sys/dev/atkbdc/atkbd.c	Sat Nov 17 20:18:15 2018	(r340518)
@@ -484,7 +484,7 @@ atkbd_init(int unit, keyboard_t **kbdp, void *arg, int
 			evdev_support_led(evdev, LED_CAPSL);
 			evdev_support_led(evdev, LED_SCROLLL);
 
-			if (evdev_register(evdev))
+			if (evdev_register_mtx(evdev, &Giant))
 				evdev_free(evdev);
 			else
 				state->ks_evdev = evdev;

Modified: stable/12/sys/dev/evdev/cdev.c
==============================================================================
--- stable/12/sys/dev/evdev/cdev.c	Sat Nov 17 20:14:02 2018	(r340517)
+++ stable/12/sys/dev/evdev/cdev.c	Sat Nov 17 20:18:15 2018	(r340518)
@@ -349,6 +349,19 @@ evdev_ioctl(struct cdev *dev, u_long cmd, caddr_t data
 	if (client->ec_revoked || evdev == NULL)
 		return (ENODEV);
 
+	/*
+	 * Fix evdev state corrupted with discarding of kdb events.
+	 * EVIOCGKEY and EVIOCGLED ioctls can suffer from this.
+	 */
+	if (evdev->ev_kdb_active) {
+		EVDEV_LOCK(evdev);
+		if (evdev->ev_kdb_active) {
+			evdev->ev_kdb_active = false;
+			evdev_restore_after_kdb(evdev);
+		}
+		EVDEV_UNLOCK(evdev);
+	}
+
 	/* file I/O ioctl handling */
 	switch (cmd) {
 	case FIOSETOWN:

Modified: stable/12/sys/dev/evdev/evdev.c
==============================================================================
--- stable/12/sys/dev/evdev/evdev.c	Sat Nov 17 20:14:02 2018	(r340517)
+++ stable/12/sys/dev/evdev/evdev.c	Sat Nov 17 20:18:15 2018	(r340518)
@@ -32,9 +32,11 @@
 #include <sys/param.h>
 #include <sys/bitstring.h>
 #include <sys/conf.h>
+#include <sys/kdb.h>
 #include <sys/kernel.h>
 #include <sys/malloc.h>
 #include <sys/module.h>
+#include <sys/proc.h>
 #include <sys/sysctl.h>
 #include <sys/systm.h>
 
@@ -763,6 +765,30 @@ evdev_send_event(struct evdev_dev *evdev, uint16_t typ
 	}
 }
 
+void
+evdev_restore_after_kdb(struct evdev_dev *evdev)
+{
+	int code;
+
+	EVDEV_LOCK_ASSERT(evdev);
+
+	/* Report postponed leds */
+	for (code = 0; code < LED_CNT; code++)
+		if (bit_test(evdev->ev_kdb_led_states, code))
+			evdev_send_event(evdev, EV_LED, code,
+			    !bit_test(evdev->ev_led_states, code));
+	bit_nclear(evdev->ev_kdb_led_states, 0, LED_MAX);
+
+	/* Release stuck keys (CTRL + ALT + ESC) */
+	evdev_stop_repeat(evdev);
+	for (code = 0; code < KEY_CNT; code++) {
+		if (bit_test(evdev->ev_key_states, code)) {
+			evdev_send_event(evdev, EV_KEY, code, KEY_EVENT_UP);
+			evdev_send_event(evdev, EV_SYN, SYN_REPORT, 1);
+		}
+	}
+}
+
 int
 evdev_push_event(struct evdev_dev *evdev, uint16_t type, uint16_t code,
     int32_t value)
@@ -771,7 +797,25 @@ evdev_push_event(struct evdev_dev *evdev, uint16_t typ
 	if (evdev_check_event(evdev, type, code, value) != 0)
 		return (EINVAL);
 
+	/*
+	 * Discard all but LEDs kdb events as unrelated to userspace.
+	 * Aggregate LED updates and postpone reporting until kdb deactivation.
+	 */
+	if (kdb_active || SCHEDULER_STOPPED()) {
+		evdev->ev_kdb_active = true;
+		if (type == EV_LED)
+			bit_set(evdev->ev_kdb_led_states,
+			    bit_test(evdev->ev_led_states, code) != value);
+		return (0);
+	}
+
 	EVDEV_ENTER(evdev);
+
+	/* Fix evdev state corrupted with discarding of kdb events */
+	if (evdev->ev_kdb_active) {
+		evdev->ev_kdb_active = false;
+		evdev_restore_after_kdb(evdev);
+	}
 
 	evdev_modify_event(evdev, type, code, &value);
 	if (type == EV_SYN && code == SYN_REPORT &&

Modified: stable/12/sys/dev/evdev/evdev_private.h
==============================================================================
--- stable/12/sys/dev/evdev/evdev_private.h	Sat Nov 17 20:14:02 2018	(r340517)
+++ stable/12/sys/dev/evdev/evdev_private.h	Sat Nov 17 20:18:15 2018	(r340518)
@@ -117,6 +117,10 @@ struct evdev_dev
 	bitstr_t		bit_decl(ev_sw_states, SW_CNT);
 	bool			ev_report_opened;
 
+	/* KDB state: */
+	bool			ev_kdb_active;
+	bitstr_t		bit_decl(ev_kdb_led_states, LED_CNT);
+
 	/* Multitouch protocol type B state: */
 	struct evdev_mt *	ev_mt;
 
@@ -132,9 +136,14 @@ struct evdev_dev
 	LIST_HEAD(, evdev_client) ev_clients;
 };
 
+#define	SYSTEM_CONSOLE_LOCK	&Giant
+
 #define	EVDEV_LOCK(evdev)		mtx_lock((evdev)->ev_lock)
 #define	EVDEV_UNLOCK(evdev)		mtx_unlock((evdev)->ev_lock)
-#define	EVDEV_LOCK_ASSERT(evdev)	mtx_assert((evdev)->ev_lock, MA_OWNED)
+#define	EVDEV_LOCK_ASSERT(evdev)	do {				\
+	if ((evdev)->ev_lock != SYSTEM_CONSOLE_LOCK)			\
+		mtx_assert((evdev)->ev_lock, MA_OWNED);			\
+} while (0)
 #define	EVDEV_ENTER(evdev)	do {					\
 	if ((evdev)->ev_lock_type == EV_LOCK_INTERNAL)			\
 		EVDEV_LOCK(evdev);					\
@@ -185,6 +194,7 @@ int evdev_cdev_destroy(struct evdev_dev *);
 bool evdev_event_supported(struct evdev_dev *, uint16_t);
 void evdev_set_abs_bit(struct evdev_dev *, uint16_t);
 void evdev_set_absinfo(struct evdev_dev *, uint16_t, struct input_absinfo *);
+void evdev_restore_after_kdb(struct evdev_dev *);
 
 /* Client interface: */
 int evdev_register_client(struct evdev_dev *, struct evdev_client *);

Modified: stable/12/sys/dev/kbdmux/kbdmux.c
==============================================================================
--- stable/12/sys/dev/kbdmux/kbdmux.c	Sat Nov 17 20:14:02 2018	(r340517)
+++ stable/12/sys/dev/kbdmux/kbdmux.c	Sat Nov 17 20:18:15 2018	(r340518)
@@ -505,7 +505,7 @@ kbdmux_init(int unit, keyboard_t **kbdp, void *arg, in
 		evdev_support_led(evdev, LED_CAPSL);
 		evdev_support_led(evdev, LED_SCROLLL);
 
-		if (evdev_register(evdev))
+		if (evdev_register_mtx(evdev, &Giant))
 			evdev_free(evdev);
 		else
 			state->ks_evdev = evdev;

Modified: stable/12/sys/dev/usb/input/ukbd.c
==============================================================================
--- stable/12/sys/dev/usb/input/ukbd.c	Sat Nov 17 20:14:02 2018	(r340517)
+++ stable/12/sys/dev/usb/input/ukbd.c	Sat Nov 17 20:18:15 2018	(r340518)
@@ -1361,7 +1361,7 @@ ukbd_attach(device_t dev)
 	if (sc->sc_flags & UKBD_FLAG_SCROLLLOCK)
 		evdev_support_led(evdev, LED_SCROLLL);
 
-	if (evdev_register(evdev))
+	if (evdev_register_mtx(evdev, &Giant))
 		evdev_free(evdev);
 	else
 		sc->sc_evdev = evdev;


More information about the svn-src-stable-12 mailing list