[systemd-devel] systemd should not call KDSKBMODE on a VT with X

Arthur Taylor art at ified.ca
Sat Feb 2 14:17:48 PST 2013

Hello systemd developers

TL;DR: On a VT which X is running, messing with KDSKBMODE on
underneath X at best has no affect and at worst breaks keyboard input
badly. In the short term, systemd should stop calling this ioctl
because it has no benefit and makes no sense.


There is a bit of back story about the KDSKBMODE ioctl and the way in
which X11 uses it, what it does, and what it is mistaken to do. I
researched and contributed patches to both Xorg and the kernel to fix
an issue related to KDSKBMODE a year and a bit ago. I don't claim to
know it all or be right though ;-)

KDSKBMODE is a virtual console ioctl which changes the current "mode"
of the virtual console keyboard for that particular virtual terminal.
That is, the virtual console keyboard mode, like the keymap, is a
per-virtual terminal setting which is saved and restored when
switching virtual terminals.

KDSKBMODE currently accepts the values K_XLATE, K_UNICODE,

K_XLATE and K_UNICODE are identical in operation, both translating key
events, other than that the latter is in unicode. A better name for it
would have been K_UNICODEXLATE.

In both K_XLATE and K_UNICODE the kernel takes key up/down events,
does repeat-rate calculations, maps them to characters (with
modifiers) if applicable and buffers them in a line descriptor. The
line supports editing (backspace, delete). The line descriptor is
flushed when a return key is pressed. Special keys (CTRL-C, ALT-Fn)
are also interpreted. In other words, the kernel is doing everything
we expect from a keyboard input.

In K_RAW things are completely different. Every key event (keyup/down)
is written to the line descriptor and then the line descriptor is
flushed. No keymaps are used, no special keys are interpreted, and no
modifier states are maintained. K_RAW is the old way of doing X11
input (by the xfree86-input-kbd driver) and this makes sense. When in
an X session, the X server manages the key map, modifier state,
special keys, etc.

Now a days we have the Linux input subsystem. The virtual console
keyboard now gets its events by registering as an event handler with
the input subsystem. X11 now also gets its input from the input event
devices, which are also an input event handler (xfree86-input-evdev).

Thus, X11 keyboard input is *independent* of the virtual console keyboard.

Moreover, with X using event devices directly, there is the new
problem of keeping the virtual console keyboard from getting in the
way. There are two possible things the virtual console keyboard can do
to ruin things.

The first is to continue to interpret special keys. When this happens,
hitting Alt-F4 in an X session takes you to vt4 and CTRL-C sends
SIGTERM to the X server. X fixed this by after initializing a VT
calling KDSKBMODE to set the input to K_RAW. (If X uses the old
xf86-input-kbd driver, it makes the same call again anyways.)

The second way the virtual console keyboard can ruin things is to keep
buffering input nobody wants, eventually overflowing the line
descriptor causing a kworker to spin forever and eat power. X fixed
this by creating a handler which dumps the unneeded input. This worker
solution has some annoying corner cases so K_OFF was introduced. K_OFF
behaves the same as K_RAW, except no input is buffered in the line
descriptor, so nothing overflows and nothing needs flushing.

Currently, through an interesting series of calls, systemd will call
KDSKBMODE on a virtual terminal. This is bad when X is running on said
virtual terminal. Specifically, Gnome-Control-Center calls some
methods which resulted in systemd calling the ioctl. This caused
issues which were noticed back in September and are document in
https://bugzilla.redhat.com/show_bug.cgi?id=859485 .

This seems to be because of a misinterpretation of what K_UNICODE
means. systemd is told to change the system (or just the console?) to
some keymap, that keymap uses unicode, so systemd is told to make the
current console use unicode, so systemd calls KDSKBMODE with
K_UNICODE, because hey, it says unicode right there in the name, what
could go wrong? Comment 25
https://bugzilla.redhat.com/show_bug.cgi?id=859485#c25 shows the
series of calls which results in this.

This is a bad idea.

Firstly, X input will be either broken or messed up. The virtual
console keyboard mode on the VT which X is running is now in (unicode)
translate mode, which it should never be when running X. If X is using
the virtual console keyboard, X looses its keyboard input. If X is
using evdev, keyboard input keep working, but the kernel is now
interpreting special keys and causing shenanigans (the issue which
resulting in the aforementioned bug report being opened.)

Second, there is *no affect* to the system but messing up X. The
virtual console keyboard mode is a per-VT setting. X opens a new
virtual terminal for itself and closes it on exit. This means that no
program other than X will use the virtual terminal, so setting the
virtual console keyboard mode affects nothing other than X, which will
now be borked.

It is possible to get X to use an already allocated virtual terminal
using command line parameters, but in such a case there is still no
benefit changing the virtual console keyboard mode as X stores the
original mode on startup and restores it on exit, so changing it in
the middle of an X session won't do anything as X will change it back
on exit.

Third, systemd already changes whether K_XLATE or K_UNICODE is the
default for new virtual terminals by the vt module parameter

Fedora resolved this issue by patching the kernel to have a new ioctl
KDSKBMUTE to "mute" key events, stopping special key handling too. The
changes are currently in Xorg head, but are not yet in the kernel.

I think this is a fix to a problem which shouldn't exist, but hey, I'm
biased for working on K_OFF ;-). If KDSKBMODE is changed under X and
then the keyboard is messed, should anyone be surprised?

KDSKBMODE is overloaded. I think it would make more sense to split the
unicode/not unicode behaviour out into its own ioctl rather than the
enqueue events / don't enqueue events behaviour.

Another fix would be in vconsole-setup.c:enable_utf8(int fd) to first
check whether the virtual console keyboard mode is K_XLATE before
changing it to K_UNICODE, as if it is anything else, changing it will
cause troubles.

I hope this sheds light on what is going on.


Arthur Taylor
art at ified.ca
taylora at csc.uvic.ca

More information about the systemd-devel mailing list