Sunday, 21 July 2013

Changing UIDs of service accounts on Linux

About a month ago I was setting up a proprietary identity management solution on headless Linux servers. During the installation process I tried to keep the number of installed packages and libraries to the bare minimum, to create an as-lean-as-possible setup as opposed to the bloated 'typical' deployments.

This goal in tandem with my choice to use the most up to date version of the target Linux distribution resulted in an 'advanced' installation procedure using the command line. While it was no surprise that the graphical installshield wizard did not start due to missing libraries on the headless server, it surprise me that non-GUI installation failed each time during setting up service accounts.

Having tried various combinations, disabling SELinux, and even creating the service account manually before re-running the installer, it still kept failing. A quick search on the internet did not yield any useful hint, but looking deeper, so I investigated further. Enabled debug logging for the installshield wizard, then extracted the embedded Java installer from the blob, and found that various native binaries are unpacked and executed during the installation process.

One of these binaries was linked against an older version of a shared library (libstdc++.so.5) that was not available in any of the packages any more. As a quick and dirty workaround I quickly created a symlink with that name pointing to libstdc++.so.6, and confirmed this resolved the problem.

The installation was successful, however, it left me with a technical user and group that I did not fancy.


$ grep ldap /etc/passwd /etc/group
/etc/passwd:idsldap:x:502:501::/home/idsldap:/bin/ksh
/etc/group:idsldap:x:501:root

  • First and foremost, I prefer technical accounts to have numberic UIDs from the range reserved for system accounts, as opposed to having them created as normal users. This range varies by distribution, RedHat & SuSE based distros reserve UIDs smaller than 500 for system accounts while Debian based ones create normal users with the first available UID after 999.
  • If I have the control over the numeric values, I prefer to introduce some semantics into the naming convention, like creating the technical user for an LDAP server with UID 389. This is just a cosmetic point with no real impact, but as I had to change the UID anyway...
  • Last but not least, I very strongly dislike if the group which is the dedicated primary group of a service account, uses the same name as the service user but a different numeric ID.

This post will cover the commands I applied to fix the UID and GID of the service user and group. File ownership is automatically fixed, but only for the files under the home directory (and mail spool) of the user, so additional commands were needed to also fix file ownership or files located elsewhere.


$ find / -user idsldap | less
$ usermod -u 389 idsldap
$ find / -user idsldap | less # you see that ownership is only updated under the home directory and mail spool
$ find / -user 502 | less # the old uid is still present on other files
$ find / -user 502 -exec chown idsldap {} \;
$ find / -user 502 | less # almost done, but by default, symbolic links are dereferenced, therefore not affected.
$ find / -user 502 -exec chown -h idsldap {} \;
$ find / -user 502 # none - confirms we are done.

$ find / -group 501 | less
$ groupmod -g 389 idsldap
$ find / -group 501 -exec chgrp -h idsldap {} \;
$ find / -group 501 # confirm we are done
$ find / -group idsldap | less # this gives the same output the first group related command

While most people probably would not put any effort into changing UIDs but rather leave it that way or reinstall from scratch, I do believe that this case was worth investing a bit of extra time.

Saturday, 22 June 2013

OpenCL, Python and Ubuntu 12.10 (Part 2)

Using multiple OpenCL devices for computation intensive tasks might turn out to be a bit more challenging. Distributing load between heterogeneous GPUs is straightforward, however, ensuring that one gets the cumulative performance of all the GPUs to the same level as the sum of the individual devices is a bit tricky. At least with the drivers that ship with Ubuntu 12.10.

The current case that motivated this post is tweaking a configuration with multiple AMD GPUs of different generations. There is much controversial information available on whether an X session is required or not, whether to use crossfire cables or not, and whether dummy-plugs are required or not. It also seems to be less certain if and how cards of different generations play together.

Having searched the internet for utilities that help in debugging OpenCL related issues I decided to create my own version, that is not extremely chatty but provides a quick overview of the devices recognised along with their most important performance related parameters. The code is based on a script I found on a forum, extended and customized to match my needs.


#!/usr/bin/python

# 2013-04-03 03:35:03 

import sys
import os
import time
import platform
import imp

def getPyOpenCLPath():
    try:
        file, pathname, descr = imp.find_module('pyopencl')
    except:
        pathname = 'Not found'
    return str(pathname)

path = getPyOpenCLPath()

print 'opencl-info @ %s' % time.asctime()
print 'Operating System: %s %s' % (platform.system(), platform.dist())
print 'Python Version: %s (%s)' % (platform.python_version(), platform.architecture()[0])
print 'PyOpenCL Path: %s' % path

if path == 'Not Found':
    print 'Exiting' 
    sys.exit()

try:
    import pyopencl
    import pyopencl.version
except:
    print 'Unable to load PyOpenCL! OpenCL not supported?'
    sys.exit()
 
print 'PyOpenCL Version: %s' % pyopencl.VERSION_TEXT

try:
    platforms = pyopencl.get_platforms()
except:
    print 'Cannot get platform.'

if len(platforms) == 0:
    print 'No OpenCL platforms found!' 
    sys.exit()

count = 0

for i,p in enumerate(platforms):
    print ''
    print '[cl:%d] %s' % (i, p.name.replace('\x00','').strip())
    for k in ['vendor', 'profile', 'version']:
        print '    %s %s' % ((k + ':').ljust(16), getattr(p,k))
    print ''

    devices = platforms[i].get_devices()
    if len(devices) > 0:
        # Iterate through devices
        for j,d in enumerate(devices):
            count += 1
            print '    [cl:%d:%d] %s' % (i, j, d.name.replace('\x00','').strip())
            print '        type:                %s' % pyopencl.device_type.to_string(d.type)
            print '        memory:              %d MB' % (d.global_mem_size//1024//1024)
            print '        compute units:       %s' % d.max_compute_units
            print '        max clock:           %s MHz' % d.max_clock_frequency
            print '        max work group size: %s' % d.max_work_group_size
            print '        max work item size:  %s' % d.max_work_item_sizes
            # Iterate through device info
            #for name in filter( lambda x: not x.startswith('_'), dir(d)):
            #    try:
            #        print(name + ': '+ str(getattr(d, name)))
            #    except:
            #        print(name + ': (skipped)')

After trials and errors and a bit of tinkering I was able to set up the environment to run fine without an X session, without crossfire cables and without any dummy plug, and yield optimal performance. Documenting the configuration details are beyond the scope of this post, however the script above is provided to help others in OpenCL related debugging and optimisation.

Saturday, 18 May 2013

Tracking down TrackPoint issues (Part 2)

This post in a follow up on Tracking down TrackPoint issues. I have noticed few days ago, that hot-plugging a USB mouse "does not work". I normally do not plug a mouse into my thinkpad, so this did not come to my attention so far.

After seeing my cursor would not move after plugging in the mouse, I decided to gather more information, starting with dmesg to verify the device is connected and recognized. Then, I inspected the output of xinput list and found that the mouse is listed as a floating slave. Manually running xinput enable "HID 04b3:3107" fixed the situation, it attached the floating device as a slave to "Virtual core pointer".


⎡ Virtual core pointer                     id=2 [master pointer  (3)]
⎜   ↳ Virtual core XTEST pointer               id=4 [slave  pointer  (2)]
⎜   ↳ SynPS/2 Synaptics TouchPad               id=12 [slave  pointer  (2)]
⎜   ↳ TPPS/2 IBM TrackPoint                    id=14 [slave  pointer  (2)]
⎜   ↳ HID 04b3:3107                            id=15 [slave  pointer  (2)]
⎣ Virtual core keyboard                    id=3 [master keyboard (2)]
    ↳ Virtual core XTEST keyboard              id=5 [slave  keyboard (3)]
    ↳ Power Button                             id=6 [slave  keyboard (3)]
    ↳ Video Bus                                id=7 [slave  keyboard (3)]
    ↳ Video Bus                                id=8 [slave  keyboard (3)]
    ↳ Sleep Button                             id=9 [slave  keyboard (3)]
    ↳ Integrated Camera                        id=10 [slave  keyboard (3)]
    ↳ AT Translated Set 2 keyboard             id=11 [slave  keyboard (3)]
    ↳ ThinkPad Extra Buttons                   id=13 [slave  keyboard (3)]

After restarting my X session - logging out and back in - with the mouse already connected I found it to be enabled and working correctly.

My conclusion was that the device got connected but not enabled after hot-plugging. I revisited my custom hotplug command in .local/bin/touchpad-config (see the previous post referred to above). This script was executed whenever on startup, and then, whenever a device is added or removed. Obviously, the touchpad and trackpoint related commands do not need to be run when an external mouse is connected. They are also needless when any device is disconnected.

I was searching for a way to detect which device is being added or removed and preform different logic based on that and came across this example in the GNOME git repository on github. It clearly demonstrated how device information and action is handed over to the script and allowed me to enhance my script with logging so I could see what was happening under the hood.

Eventually, it turned out that my script was only executed a couple of times on startup, but not invoked at all after that when the mouse was hot-plugged. It boiled down to be caused by some cruft in my Xorg configuration, left over after having explored Optimus related tweaks covered in my other posts. I had to change Option "AutoEnableDevices" "false" in xorg.conf.

Although the original issue was fully resolved by the before mentioned change in to xorg.conf, the sub-optimal .local/bin/touchpad-config was still bugging me so I altered it to only execute the commands relevant for the event that triggered the script. I ended up with the following hotplug-script, which is working flawlessly in my environment:


#!/bin/sh

action=$2
shift 4
device=$@

log () {
 echo "$1" >> /tmp/hotplug-cmd.log
}

log "$action '$device'"

if [ x"$action" = xadded -o x"$action" = xpresent ]; then
 case $device in
  "SynPS/2 Synaptics TouchPad")
                 synclient PalmDetect=1 PalmMinWidth=5 \
    TapButton3=2 HorizTwoFingerScroll=1
   log "configured touchpad"
                 ;;
         "TPPS/2 IBM TrackPoint")
                 xinput disable "<default pointer>" 
                 xinput enable "TPPS/2 IBM TrackPoint"
   log "disabled <default pointer>, enabled trackpoint"
                 ;;
         *)
                 log "nop"
                 ;;
 esac
fi

Note that the script above still includes logging which may be safely removed.

Monday, 1 April 2013

OpenCL, Python and Ubuntu 12.10

Installing PyOpenCL, the python OpenCL wrapper on Ubuntu 12.10 could have been just as easy as installing the according package python-pyopencl but this is currently not possible because of a packaging bug that was reported and confirmed before the release of 12.10 but not fixed since. I am not going to comment on this but document my work around instead.

What is OpenCL?

OpenCL is the short name for Open Computing Language - an open standard that specifies a vendor agnostic language and cross-platform framework for developing code that is can be executed on parallel computing enabled platforms, such as GPUs (graphics cards), FPGAs (field programmable gate arrays) or newer generation multicore CPUs.

The most typical use-case is using the graphics device for non-graphics computation tasks. Typical computation intensive tasks can be broken down into multiple sub-tasks that can be executed independent of each other, in parallel. The many pourpose built processing pipelines, special shift register circuits, shaders and vertext processors inegrated into modern graphics devices are equipped with a multitiude of 256bit registers, and excel at high volume calculation of matrix operations, interpolations and special tranformations (e.g. fourier, laplace). OpenCL enables one to unleash this raw parallel/stream processing power to be used for generic purposes, other than gaming.

Currently, OpenCL support is provided by proprietary drivers for Nvidia GPUs, AMD GPUs and CPUs and Intel CPUs. Although these drivers are not open source components, OpenCL, being an open standard, enables one to avoid coding against vendor specific APIs and create software mostly portable across computing platforms. (One well known example of such vendor specific APIs is provided by Nvidia's Compute Unified Device Architecture - CUDA - but recent CUDA versions expose OpenCL interfaces as well.)

As of the time of this writing, OpenCL is my preferred platform for computation intensive, time critical applications. It is worth to be aware of, and tinker around with it for fun and profit.

What is the bug?

In a nutshell, the package cannot installed, the bug is a package dependency on a non-existent package, namely opencl-icd that is not available in any of the official or partner repositories and also not provided by other package. As the but was reported and confirmed one month before the final release of 12.10 I am rather surprised it has not been fixed yet, especially as fixing the problematic dependency boils down require merely one line to be changed in the package metadata.

I have quickly read up on the format of debian packages to make sure I understand the issue correctly and found the following alternatives for solving the current problem:

  • Modify the package python-pyopencl by removing the dependency on opencl-icd. This is a low hanging fruit but would leads to broken packages in the long run as any update to the package would overwrite my local changes. This issue can be dodged by putting the package on hold.
  • The strategic solution would be to alter the metadata of packages nvidia-current and fglrx so these packages would provide opencl-icd as a virtual package. This is not my preferred approach for a local workaround, as leads to maintenance issues on package updates. The concerns and workarounds of the previous alternative apply here as well.
  • My preferred approach was creating a dummy package python-pyopencl that merely depends on the appropriate drivers but does not contain any real file itself, only metadata. This approach will shield me from package update issues.

Creating and installing the dummy package


$ mkdir /tmp/dummy && cd /tmp/dummy
$ tar czf data.tar.gz * # creating an empty archive, will output some errors
$ tar tzf data.tar.gz   # this verifies the archive is empty and can be read without errors
$ touch md5sums
$ cat <<EOF>> control
Package: opencl-icd
Source: opencl-icd
Version: 1.0.0-1
Architecture: amd64
Maintainer: Tibor Bősze <tibor.boesze@gmail.com>
Installed-Size: 4
Depends: fglrx | nvidia-current | intel-ocl-sdk
Section: universe/libs
Priority: optional
Homepage: http://tuxicate.blogspot.com/
Description: Dummy package
 This is a dummy package to workaround bug 1048036
EOF
$ tar czf control.tar.gz md5sums control
$ echo "2.0" > debian-binary
$ ar rcs opencl-icd_1.0.0-1_amd64.deb debian-binary control.tar.gz data.tar.gz
$ dpkg-deb --verbose --info opencl-icd_1.0.0-1_amd64.deb # verify
$ sudo dpkg -i opencl-icd_1.0.0-1_amd64.deb # install

The package, once installed, will appear under Obsolete and Locally Created Packages in aptitude, so it is easy to track and uninstall if needed. Now, python-pyopencl can be installed and used without issues.

One could modify the dependencies (the line starting with Depends:) as required, I have added Nvidia or AMD Radeon/FireGL graphics drivers, or the Intel OpelCL SDK. The Intel SDK can be downloaded in rpm for Intel, and converted to a deb package with alien.

Tuesday, 12 February 2013

Optimus and Ubuntu 12.10 (Part 5)

This post is the fifth of a series of posts on tweaking Ubuntu 12.10 to exploit Optimus technology on my Lenovo W530 to the extent I need. Make sure you are familiar with the context and objectives.

As described in Part 1, plymouth issues when Optimus is enabled on the W530 in EFI mode. The issue around missing usplash/plymouth turned out to be connected to the random order in which the kernel initialized the graphics devices.

Part 3 captures the root cause of the symthom: Usplash is hardcoded to render to /dev/fb0 which is fine if the IGD is initialized first by the kernel, but not good if /dev/fb0 is associated with the DIS framebuffer.

One workaround already explained is blacklisting nouveau, and loading it later, after usplash is started on the IGD framebuffer. I seeked more elegant approaches and tinkered with initram to explore the alternatives:

  • Forcing proper module load order in initrd:/etc/modules - I found that this file is only processed after the kernel finished autoloading, and cannot load blacklisted modules.
  • Crafting custom initram scripts to take care of module loading early in the book process - this approach did not prove effective either.
  • Creating an initram script to disable DIS proved to be impossible as debugfs was not mounted at the time of initram script execution.
  • Packaging custom udev rules into the initial ramdisk to ensure the desired framebuffer numbering. I settled with this option.

Ensuring consistent framebuffer numbering via udev rules

Traditionally, Unix systems exposed a static set of device files under /dev but current versions of Linux ship with a device manager that can dynamically populate the /dev directory with nodes for the devices present. It allows persistent naming insensitive to the order of hardware initialization or hotplug. This is achieved by udev rules, which match the devices based on their attributes and perform actions such as creating device nodes, symlinks, changing permissions and ownership, or if fact, running arbitrary logic.

This section provides a very brief walk-through on how the rules for the current use-case can be created. First, information about the framebuffer devices had to be gathered, and the properties and attributes for the matching part had to be identified.


$ udevadm info -a -n /dev/fb0 | head -n 24

Udevadm info starts with the device specified by the devpath and then
walks up the chain of parent devices. It prints for every device
found, all possible attributes in the udev rules key format.
A rule to match, can be composed by the attributes of the device
and the attributes from one single parent device.

  looking at device '/devices/pci0000:00/0000:00:01.0/0000:01:00.0/graphics/fb0':
    KERNEL=="fb0"
    SUBSYSTEM=="graphics"
    DRIVER==""
    ATTR{pan}=="0,0"
    ATTR{name}=="nouveaufb"
    ATTR{mode}==""
    ATTR{console}==""
    ATTR{blank}==""
    ATTR{modes}=="U:1024x768p-0"
    ATTR{state}=="0"
    ATTR{bits_per_pixel}=="32"
    ATTR{cursor}==""
    ATTR{rotate}=="0"
    ATTR{stride}=="4096"
    ATTR{virtual_size}=="1024,768"

$ udevadm info -a -n /dev/fb1 | sed -n '8,24p'
  looking at device '/devices/pci0000:00/0000:00:02.0/graphics/fb1':
    KERNEL=="fb1"
    SUBSYSTEM=="graphics"
    DRIVER==""
    ATTR{pan}=="0,0"
    ATTR{name}=="inteldrmfb"
    ATTR{mode}==""
    ATTR{console}==""
    ATTR{blank}==""
    ATTR{modes}=="U:1920x1080p-0"
    ATTR{state}=="0"
    ATTR{bits_per_pixel}=="32"
    ATTR{cursor}==""
    ATTR{rotate}=="0"
    ATTR{stride}=="7680"
    ATTR{virtual_size}=="1920,1080"

As it can be seen from the listing above, is is sufficient to match devices of the graphics subsystem named by the kernel as "fd0" and "fb1". The attribute "name" can be used to discriminate between the two framebuffers. The goal is create device node /dev/fb0 for the intel framebuffer /dev/fb1 for the nouveau framebuffer respectively. This can be achieved by the following udev rule:


KERNEL=="fb?", SUBSYSTEM=="graphics", ATTR{name}=="nouveaufb", NAME="fb1"
KERNEL=="fb?", SUBSYSTEM=="graphics", ATTR{name}=="inteldrmfb", NAME="fb0"

Normally, one would save these lines to a file in the appropriate folder, say /etc/udev/rules.d/82-explicit-fb-assignment.rules. (The numbering is used to ensure the rule is not overridden, as rules are parsed in lexicographical order.)

In this very case, however, the rule will not yield the desired results. One would see usplash on shutdown, but not on boot. The rule file is located on disk, in the root partition to be precise. It gets mounted after usplash initializes during boot...

Packaging custom udev rules into initrd

As implied by the nature of the use case, it would not suffice to drop the custom udev rule into /etc/udev/rules.d/, it needs to be included in the initial ramdisk. Customization of initial ramdisk content is best done via custom hook scripts - they provide a clean, modular way of achieving the current goal while being minimally intrusive to other parts of the system. The hook scripts will run whenever the a new initrd is created and can contribute files to the ramdisk. They do not become part of the ramdisk themselves.


$ cat <<EOX | sudo tee /etc/initramfs-tools/hooks/explicit-fb-assignment
#!/bin/sh -e

PREREQ="udev"

# Output pre-requisites
prereqs()
{
   echo "$PREREQ"
}

case "$1" in
    prereqs)
   prereqs
   exit 0
   ;;
esac


. /usr/share/initramfs-tools/hook-functions

# Create udev rules to control fb1/fb0 assignment
cat > ${DESTDIR}/lib/udev/rules.d/82-explicit-fb-assignment.rules <<EOF
KERNEL=="fb?", SUBSYSTEM=="graphics", ATTR{name}=="nouveaufb", NAME="fb1"
KERNEL=="fb?", SUBSYSTEM=="graphics", ATTR{name}=="inteldrmfb", NAME="fb0"
EOF

EOX

$ sudo chmod +x /etc/initramfs-tools/hooks/fb_order
# create new initrd for the current kernel
$ sudo update-initramfs -c -k $(uname -r)
# verify on next reboot

The listing above provides the commands for creating the hook and generating a new initrd. Having applied this tweak, usplash/plymouth is fully functional and reliable, as /dev/fb0 always refers to the intel framebuffer device.

Troubleshooting

One has to remember that there are 2 udev daemons launched at different parts of the boot process. One runs off initrd, while the other is spawned after the root filesystem has been mounted. The former uses the rules included in ramdisk, while the later one reads the rules from /{lib|etc}/udev/ruled.d of the root partition, and does not use any rule from the initrd.

Friday, 1 February 2013

Tracking down TrackPoint issues

I occasionally experience strange, inconsistent behavior of the TrackPoint on my Lenovo w530. Sometimes, middle button scroll was not working at all, other times it kind of worked, however, after having scrolled and released the middle button, the clipboard's content was pasted into the current caret position. Also, scrolling pdf documents in evince with the TrackPoint simply resulting into up and down shaking and vibrating pages. I also noticed that in this cases, the cursor moved during middle button scroll which was very weird.

Locating the root cause

The symptoms above were not persistent across reboot - occasionally they were present. Further, restarting the X server typically improved the situation. After a bit of experimenting it turned out, that the strange behaviour occurs more frequently when running of a fast SSD, however, even with a rotating disk the symptoms appeared from time to time.

After a bit of googling I used the command xinput to enumerate X input devices and view their settings. I confirmed that wheel emulation was enabled, and configured for button 2. With xev I also confirmed that the middle TrackPoint button indeed fired button 2 events.


$ xinput --list
⎡ Virtual core pointer                        id=2    [master pointer  (3)]
⎜   ↳ Virtual core XTEST pointer              id=4    [slave  pointer  (2)]
⎜   ↳ SynPS/2 Synaptics TouchPad              id=13   [slave  pointer  (2)]
⎜   ↳ <default pointer>                       id=6    [slave  pointer  (2)]
⎣ Virtual core keyboard                       id=3    [master keyboard (2)]
    ↳ Virtual core XTEST keyboard             id=5    [slave  keyboard (3)]
    ↳ Power Button                            id=7    [slave  keyboard (3)]
    ↳ Video Bus                               id=8    [slave  keyboard (3)]
    ↳ Video Bus                               id=9    [slave  keyboard (3)]
    ↳ Sleep Button                            id=10   [slave  keyboard (3)]
    ↳ Integrated Camera                       id=11   [slave  keyboard (3)]
    ↳ AT Translated Set 2 keyboard            id=12   [slave  keyboard (3)]
    ↳ ThinkPad Extra Buttons                  id=14   [slave  keyboard (3)]
∼ TPPS/2 IBM TrackPoint                       id=15   [floating slave]
$ xinput --list-props "TPPS/2 IBM TrackPoint" | grep "Wheel Emulation"
 Evdev Wheel Emulation (425): 1
 Evdev Wheel Emulation Axes (426): 6, 7, 4, 5
 Evdev Wheel Emulation Inertia (427): 10
 Evdev Wheel Emulation Timeout (428): 200
 Evdev Wheel Emulation Button (429): 2
$ xev

First I thought I should just disable the paste action on middle button click, by remapping the buttons. The middle button click actions can be completely disabled by the following command:


$ # disable normal middle button action (like paste)
$ xinput set-button-map "TPPS/2 IBM TrackPoint" 1 0 3 4 5 6 7 

This command eliminated the annoying text-pasting behavior whenever the middle button was released, but it did not solve the occasional inability to use middle button close, neither the shaking/vibrating pages in evince, so I continued investigating the issue...

I drew the conclusion that the error is caused by race conditions on around X server start, resulting an improper start up sequence of input device initialization. The W530 has 8 logical CPU cores, and my thinkpad is also equipped with a fast SSD - I already encountered similar issues in other areas which I recorded in previous posts.

My theory

I revisited the symptoms and tried to find a plausible explanation for the behavior. It seemed like 2 xinput devices were concurrently handling the TrackPoint, to a degree that varied across X restarts.

  • Ability to move the cursor, but inability to use middle mouse scroll - in cases the 'other' devices actively handling the TrackPoint.
  • Button click events when finishing middle wheel scroll - in case both X input devices are actively interpreting raw button press and release events.
  • Moving cursor during middle button scroll - when both X input devices are interpreting pointer motion with the middle button pressed.
  • Shaking pdf pages - I believe evince has some software level 'page dragging' capability built in, where the drag directions are the opposite of the scroll direction, resulting the strange vibrating effect. To clarify this assumption, let us imagine what happened if both X input devices were indeed actively handling the raw TrackPoint events: the pointer is moving upwards while the middle button is in a pressed state.
    • The TrackPoint X input device, as wheel emulation is enabled, sends wheel events scrolling the page up.
    • The other X input device, without wheel emulation, simply forwards the cursor movements and the pressed state of the middle button to the application, which activated page dragging. Dragging the current page upwards is equivalent to scrolling down.
    It sound plausible that this situation could result a conflict between scrolling up and down at the same time, yielding vertically vibrating pages...

According to an old email thread the X server automatically ads the input device <default pointer> if there are no configured pointing devices, and it is well possible that in my case TrackPoint initialization is done after, or in parallel to the X server checking for configured devices.

Steps to fix it

Looking at the output of xinput --list again, as shown above, made me wonder what a floating slave could mean - according to the GDK3 reference manual this indicates that the device is not attached to any virtual device (master). In the case when middle button scroll was not working at all, I could simply enable the TrackPoint device from the command line, which restored my ability to use middle button scroll but also reproduced the phenomenon of pasting-when-scrolling and vibrating pdf pages. To me this seemed to prove the theory described above. I experimented with various xinput calls and eventually fixed the situation by disabling the default pointer pointer.

After having minimized the list of commands needed to resolve the middle button scroll issue, I decided to restore normal button mapping and re-enable middle button paste. Actually, it does not conflict with middle button scroll at all. Just tapping/clicking the middle button triggers the paste action (or normal middle button action as defined for the actual application) while keeping it pressed enters wheel emulation mode - and releasing it does not fire the normal click event. The timout for a normal middle button click is configured to 200 ms which seems to work fine for me.


$ xinput enable "TPPS/2 IBM TrackPoint"
$ xinput disable "<default pointer>"
$ # quickly click on middle button to paste, hold it down to start scrolling

These are the minimal commands I use to fix the TrackPoint behavior whenever it occurs.

Friday, 18 January 2013

Optimus and Ubuntu 12.10 (Part 4)

This post is the fourth of a series of posts on tweaking Ubuntu 12.10 to exploit Optimus technology on my Lenovo W530 to the extent I need. Make sure you are familiar with the context, especially the objectives and constraints as described in Part 1, Part 2 and Part 3.

Moving windows from the primary screen to the external VGA screen

As it has been explained before, windows cannot cross screen boundaries, and the GNOME desktop cannot span multiple X screens even in the case when the these screens belong to the same display (X instance). It should be obvious that this is also the case with screens that belong to different X servers.

The objectives defined in the previous parts require the ability to extend the GNOME desktop to the monitor attached to the external VGA port, to run presentations using two monitors and to clone the primary monitors content to the external monitor.

In order to meet one of the objectives, one could mirror, or better said clone the content of one screen to another screen. To be even more precise, only a given portion of the screen has to be cloned to other viewport, the area of the other screen that is displayed by the external monitor. There is a userspace tool called hybrid screenclone to perform exactly this task - find more on this tool below.

Extending the desktop to a screen of the other X server

Thinking further, in order to be able to extend the desktop and thereby meet other objectives, one could set up a mock monitor in the first X server, and then, clone the content to the screen of the other X server so it would show up on the external monitor.

My first approach was to examine the video outputs of the integrated graphics device, and found VGA[12] that is wired to /dev/null (see Part 2). With various xrandr commands I could force the unused, thus always disconnected output to be configured with a fixed resolution, right of the primary monitor. A screenshot confirmed I was half way through: it contained a black are next to the primary desktop. I could even drag windows onto this black area, however, the desktop would not extend to this portion of the X screen. Also, libreoffice refused to start the slideshow in multi-monitor mode, as it only detected one connected monitor. While the idea was not completely useless, this approach did turn out not to be usable in production.

A bit of googling revealed, that the author of hybrid screenclone also maintains a patch against the intel video driver which adds a dynamically configurable virtual output - enabling exactly the scenario I was targeting.

Intel driver hack

The listing below takes the reader through the process of creating and installing a package containing the patched version of the intel video driver.


$ mkdir /tmp/foo && cd /tmp/foo # we are going to compile in tmpfs/RAM
$ sudo aptitude build-dep --schedule-only  xserver-xorg-video-intel
$ sudo aptitude # review interactively what is going to be installed
$ apt-get source xserver-xorg-video-intel
$ cd xserver-xorg-video-intel-2.20.9/
$ wget https://raw.github.com/liskin/patches/master/hacks/xserver-xorg-video-intel-2.20.2_virtual_crtc.patch
$ # the newer patch did not match.
$ patch -p1 < xserver-xorg-video-intel-2.20.2_virtual_crtc.patch
$ # now update the version to show this is a patched package
$ # NEVER alter packages without making it clear in the package version!
$ # I prepend this to debian/changelog:
$ mv debian/changelog debian/changelog.old && cat <<EOF > debian/changelog
xserver-xorg-video-intel (2:2.20.9-0ubuntu2+virtual-crtc) quantal; urgency=low

  [ Tibor Bősze ]
  * Add xserver-xorg-video-intel-2.20.2_virtual_crtc.patch

 -- Tibor Bősze <tibor.boesze@gmail.com>  Sun, 13 Jan 2013 03:15:00 +0200

EOF
$ cat debian/changelog.old >> debian/changelog && rm debian/changelog.old
$ # now build and install the package
$ dpkg-buildpackage -b
$ sudo dpkg -i ../xserver-xorg-video-intel_2.20.9-0ubuntu2+virtual-crtc_amd64.deb
$ # as you see, the package version will clearly show that this is a patched package
$ # prevent the package to be automatically updated
$ sudo aptitude hold xserver-xorg-video-intel

After a reboot, the command below will active the virtual monitor. The graphical display manager will not show any second display, however, creating a screenshot quickly confirms that the second virtual monitor is active, and the desktop correctly extends to it. Also, libreoffice impress can finely use it for running the slideshow in dual monitor mode.


$ xrandr --output LVDS2 --auto --output VIRTUAL --mode 800x600 --right-of LVDS2

Screenclone

To render this post complete, below are listed the commands to download and compile the tool.


$ # we are still doing stuff in tmpfs/RAM
$ aptitude install git-core
$ git clone git://github.com/liskin/hybrid-screenclone.git
$ cd hybrid-screenclone && make
g++ -std=c++0x -g -Wall    screenclone.cc  -lpthread -lX11 -lXdamage -lXtst -lXinerama -lXcursor -o screenclone
screenclone.cc:18:33: fatal error: X11/Xcursor/Xcursor.h: No such file or directory
compilation terminated.
make: *** [screenclone] Error 1
$ apt-file search Xcursor.h
libxcursor-dev: /usr/include/X11/Xcursor/Xcursor.h
$ aptitude install libxcursor-dev
$ make
g++ -std=c++0x -g -Wall    screenclone.cc  -lpthread -lX11 -lXdamage -lXtst -lXinerama -lXcursor -o screenclone
screenclone.cc:24:37: fatal error: X11/extensions/Xinerama.h: No such file or directory
compilation terminated.
make: *** [screenclone] Error 1
$ aptitude install libxinerama-dev libxdamage-dev libxtst-dev
$ make
$ mv screenclone ~/optimus/

By default the tool will clone the first screen of the first display to the first screen of the second one, that is, :0.0 to :1.0. This almost completely fits my use case, I added the parameter -x 1 which limits the content to be copied to the area of the screen that is displayed by the second monitor, the VIRTUAL output in my case.


$ # clone the viewport of the VIRTUAL output from :0.0 to the top left corner of :1.0
$ ~/optimus/screenclone -x 1 

Part 5 will revisit the issue of changing framebuffer number assignment and provide a more elegant solution to fixing usplash.