PREPARATION FOR MULTI-SEAT LINUX
John T. Rine
The object of this project is to set up and verify a multi-seat Linux configuration (one machine, many users).
To do this project, you will need to have successfully completed:
The materials required for this project are:
Description | Quantity |
---|---|
PC to be multiseat host | 1 |
LCDs | multiple |
keyboards | multiple |
mice | multiple |
Linux Desktop install CD | 1 |
USB docking stations | multiple |
Lately, computing has concerned itself with the idea of a single computing resource allocated to a single user. However, with this approach, computing resources are usually wasted. There are exceptions to the one resource per user rule, a multi-tasking system for example, allows for multiple logins, there can still only be one physical user at the computer's main console, however. Multi-seat Linux allows many users to simultaneously share any single Linux PC.
According to the Web page from which the pictures and instructions were taken, a multi-seat configuration “is great for education, libraries, internet cafes, etc — anywhere where you have clusters of client machines with light 3D/video app demands, and want the simplicity and savings of just one server machine with many terminals connected.”
Requirements
The instructor's requirements for this project are:
Configure and document the process of setting up a Linux machine to serve as the host machine to support multiple physical users.
Functionality
Regarding this project, once the setup and installation are complete, the instructor asks the student to explore the following functionality:
Analysis
Regarding this project, the instructor asks the student to lookout for the following things:
If possible, the instructor wants the student to try the configuration with both a 32-bit machine and a 64-bit machine (how well can the older 32-bit machine handle the load, how much more work can the newer 64-bit machine adequately handle?).
The photos both above and below and the instructions below were taken from http://plugable.com/2009/11/16/setting-up-usb-multiseat-with-displaylink-on-linux-gdm-up-to-2-20/. Please see the reference section.
1. DisplayLink framebuffer driver
udlfb is in the staging tree of Linux kernels 2.6.32 and later. We'll install the latest version here. First, make sure you have git installed with “sudo apt-get install git-core”, and create a directory which will host all the source code you download with git (e.g. ~/git/).
sudo apt-get install module-assistant sudo module-assistant prepare git clone http://git.plugable.com/webdav/udlfb/ cd udlfb make sudo make install sudo depmod -a
Now, when you plug in a DisplayLink device, you should see a “green screen” as the driver successfully loads and sets the graphics mode to match your monitor.
2. DisplayLink X server
This will get the X server installed, ready for use by later scripts.
sudo apt-get install pkg-config xorg-dev cd ~git git clone http://git.plugable.com/webdav/xf-video-udlfb/ cd xf-video-udlfb ./configure make sudo make install
We now need to create or modify a few scripts and configuration files. You'll need to use sudo to edit files in these system directories. You can cut/paste the text below, or download the files with “git clone http://git.plugable.com/webdav/misc-udlfb/” and copy each to the right location, and fix up ownership and permissions on the files.
3. udev script
Create a file called /lib/udev/rules.d/50-usbseat.rules owned by user root, with the following contents.
# set all DisplayLink devices to configuration 1 # see http://libdlo.freedesktop.org/wiki/DeviceQuirks for more info ATTR{idVendor}=="17e9", ATTR{bConfigurationValue}=="2", RUN="/bin/echo 1 > /sys%p/bConfigurationValue" # aliases for display, kbd, mouse attached to specific hubs KERNEL=="fb*",SUBSYSTEMS=="usb",PROGRAM="/bin/cat /sys/%p/../../../devnum",SYMLINK+="usbseat/%c/display",RUN+="usbseat.sh %c" KERNEL=="mouse*", SUBSYSTEMS=="usb", ATTRS{bInterfaceClass}=="03", ATTRS{bInterfaceProtocol}=="02", PROGRAM="/bin/cat /sys/%p/../../../../../devnum",SYMLINK+="usbseat/%c/mouse",RUN+="usbseat.sh %c" KERNEL=="event*", SUBSYSTEM=="input", ATTRS{bInterfaceClass}=="03", ATTRS{bInterfaceProtocol}=="01",PROGRAM="/bin/cat /sys/%p/../../../../../devnum",SYMLINK+="usbseat/%c/keyboard",RUN+="usbseat.sh %c" KERNEL=="control*", SUBSYSTEM=="sound", SUBSYSTEMS=="usb", PROGRAM="/bin/cat /sys/%p/../../../../../devnum", SYMLINK+="usbseat/%c/sound" # Handle when keyboard and mouse are one more hub downstream. Relying on pnp order to have already set up mouse, keyboard on upstream hub if we're daisy-chaining KERNEL=="event*", SUBSYSTEM=="input", ATTRS{bInterfaceClass}=="03", ATTRS{bInterfaceProtocol}=="01",PROGRAM="/bin/cat /sys/%p/../../../../../../devnum",SYMLINK+="usbseat/%c/keyboard",RUN+="usbseat.sh %c" KERNEL=="mouse*", SUBSYSTEMS=="usb", ATTRS{bInterfaceClass}=="03", ATTRS{bInterfaceProtocol}=="02", PROGRAM="/bin/cat /sys/%p/../../../../../../devnum",SYMLINK+="usbseat/%c/mouse",RUN+="usbseat.sh %c"
The udev subsystem will run this script automatically each time a USB device is attached.
4. usbseat.sh script
Create a file /lib/udev/usbseat.sh owned by user root with the following contents. Make sure to “sudo chmod a+x” to make the file executable.
#!/bin/bash # takes the "seat number" as parameter $1 # the seat number is the kernel device id of the hub the seat's devices are sitting off of # called once for every usb device that MIGHT be part of a seat, when they arrive or remove if [[ !(-n `/bin/pidof gdm`) ]]; then exit 0 fi seat_running=`/usr/bin/gdmdynamic -l | /bin/sed -n -e "/:$1,/p"` # $ACTION environment variable is set by udev subsystem case "$ACTION" in 'remove') if [[ -n "{$seat_running}" ]]; then /usr/bin/gdmdynamic -v -d $1 fi ;; *) # A device which might be part of a seat has been added # if we already have a running seat for this #, exit if [[ -n "${seat_running}" ]]; then exit 0 fi if [[ -e /dev/usbseat/$1/keyboard && -e /dev/usbseat/$1/mouse && -e /dev/usbseat/$1/display ]]; then # We have a newly complete seat. Start it. TMPFILE=`/bin/mktemp` || exit 1 /bin/sed "s/%ID_SEAT%/$1/g" < /lib/udev/usbseat-xf86.conf.sed > $TMPFILE /usr/bin/gdmdynamic -v -t 2 -s 1 -a "$1=/usr/X11R6/bin/X -br :$1 -audit 0 -nolisten tcp vt07 -config $TMPFILE" /usr/bin/gdmdynamic -v -r $1 fi ;; esac exit 0
5. X config file
Create file /lib/udev/usbseat-xf86.conf.sed with contents
Section "ServerFlags" Option "AutoEnableDevices" "false" Option "AutoAddDevices" "false" Option "DefaultLayout" "seat" Option "DontZoom" "true" Option "DontZap" "true" Option "AllowMouseOpenFail" "yes" EndSection Section "Module" Load "ddc" EndSection Section "Files" ModulePath "/usr/lib/xorg/modules" ModulePath "/usr/local/lib/xorg/modules" EndSection Section "Device" Identifier "dl" driver "displaylink" Option "fbdev" "/dev/usbseat/%ID_SEAT%/display" EndSection Section "InputDevice" Identifier "keyboard" Driver "evdev" Option "CoreKeyboard" Option "Device" "/dev/usbseat/%ID_SEAT%/keyboard" Option "XkbModel" "evdev" Option "XkbLayout" "us" EndSection Section "InputDevice" Identifier "mouse" Driver "mouse" Option "CorePointer" Option "Protocol" "ImPS/2" Option "Device" "/dev/usbseat/%ID_SEAT%/mouse" Option "Buttons" "5" Option "ZAxisMapping" "4 5" EndSection Section "Monitor" Identifier "monitor" EndSection Section "Screen" Identifier "screen" Device "dl" Monitor "monitor" EndSection Section "ServerLayout" Identifier "seat" Screen 0 "screen" 0 0 InputDevice "keyboard" "CoreKeyboard" InputDevice "mouse" "CorePointer" EndSection
6. fbcon workaround
[update: this step is no longer needed with the latest udlfb from git or in kernels 2.6.37+]
fbcon is a standard Linux kernel module, which aggressively assumes it can open any framebuffer device and take it over for use as a text terminal. Unfortunately, that's not what we want if we're going to be using that framebuffer to run its own X server. So we need to add a file /etc/modprobe.d/fbcon.conf to disable fbcon and leave our framebuffers free for other uses.
blacklist font blacklist tileblit blacklist bitblit blacklist fbcon
This file will not take effect until you run
sudo update-initramfs -u
Now, when you reboot and run “lsmod” you should not see fbcon in the loaded modules. And in /sys/class/graphics you should see fb0, instead of fbcon.
7. xrandr workaround
[update: this workaround is not needed when running xf86-video-fbdev or with recent displaylink X servers with this patch]
The DisplayLink X server currently has limited RANDR support, but later versions of GDM assume better. So for the time being, a workaround is required to get GDM applications (including gdmlogin) to display properly within the actual screen area – otherwise they tend to think the screen has a strange rotation, and display themselves completely off it.
Add these lines into /etc/gdm/Init/Default, right after the definition of gdmwhich()
XRANDR=`gdmwhich xrandr` if [ "x$XRANDR" != "x" ]; then $XRANDR -o 0 fi
8. /etc/rc.local script
Add the following lines to your /etc/rc.local script to check for attached usb terminals that were attached (at boot), and udev found them before GDM was running.
oldIFS=$IFS IFS=/ for seat in /dev/usbseat/*; do set $seat /lib/udev/usbseat.sh $4 done IFS=$oldIFS
9. /etc/init.d/gdm patch
In recent versions of X, the system largely assumes that you'll only run one X server, and it will own all devices. So to support multiseat with multiple X servers easily, we need to have two configurations: normal (using only your primary graphics), and multiseat (where your primary graphics isn't used). We do this by detecting whether you have a USB terminal attached and configured, and if so coming up with a different gdm configuration.
Add these lines to your /etc/init.d/gdm script, just after the section to “Allow cdd to override the config” (around line 35).
# Allow usbseat to override the config if [ -f /etc/gdm/gdm-usbseat.conf ]; then for usbseat in /dev/usbseat/*; do seatid=${usbseat##*/} if [ -e "/dev/usbseat/$seatid/keyboard" -a -e "/dev/usbseat/$seatid/mouse" -a -e "/dev/usbseat/$seatid/display" ]; then CONFIG_FILE="--config=/etc/gdm/gdm-usbseat.conf" fi done fi
10. Create /etc/gdm/gdm-usbseat.conf
This is the alternative gdm.conf that will be used when a USB terminal is present at boot:
[daemon] DynamicXServers=true FlexibleXServers=0 Greeter=/usr/lib/gdm/gdmgreeter [security] [xdmcp] [gui] [greeter] [chooser] [debug] [servers] 0=inactive
Now, when you boot with USB terminal(s) attached, graphical logins will come up on all of those, while your primary display will remain a text console.