Difference between revisions of "Common Problem: namespace race conditions"

From MythTV Official Wiki
Jump to: navigation, search
m (The Problem: Mention of some specific failure cases)
m (The Solution: Probing an HD-PVR (for example))
Line 17: Line 17:
  
 
==The Solution==
 
==The Solution==
 +
The solution is relatively simple.  If your MythTV box is to host more than one sufficiently different type of tuner or video input, we'll need to add a custom udev rule that gives these devices separate and unique namespaces by which MythTV can access them.  To do this you'll need to find a unique bit of information that udev can reliably recognize about each device, and the name of a new symlink for it to create.
 +
 +
=== Identifying the device ===
 +
In order for udev to be able to handle rules which match our device, we need to first find out something relatively unique about what udev will know about the device the next time it is initialized.  The first step to doing this is to find out the sysfs path to the device.  Assuming for the moment your device is currently connected and functioning properly as '''/dev/video0''', run the following command to query udev about the sysfs path used by the device at /dev/video0.
 +
 +
udevinfo -q path -n '''/dev/video0'''
 +
 +
You will get an answer like '''/class/video4linux/video0'''.  Next, using the sysfs path you just discovered, you'll run the udevinfo command again to tell it to show you practically everything it knows about the device, what it's connected to, and what ''that's'' connected to.  The output from this can be relatively long and winding, so you'll probably want to pipe it through less.
 +
 +
user@mythtv:~$ '''udevinfo -a -p /class/video4linux/video0 | less'''
 +
 +
Udevinfo 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 '/class/video4linux/video0':
 +
    KERNEL=="video0"
 +
    SUBSYSTEM=="video4linux"
 +
    DRIVER==""
 +
    ATTR{dev}=="81:0"
 +
    ATTR{name}=="Hauppauge HD PVR"
 +
    ATTR{index}=="0"
 +
 +
  looking at parent device '/devices/pci0000:00/0000:00:04.1/usb3/3-1/3-1:1.0':
 +
    KERNELS=="3-1:1.0"
 +
    SUBSYSTEMS=="usb"
 +
    DRIVERS=="hdpvr"
 +
    ATTRS{bInterfaceNumber}=="00"
 +
    ATTRS{bAlternateSetting}==" 0"
 +
    ATTRS{bNumEndpoints}=="02"
 +
    ATTRS{bInterfaceClass}=="ff"
 +
    ATTRS{bInterfaceSubClass}=="02"
 +
    ATTRS{bInterfaceProtocol}=="00"
 +
    ATTRS{modalias}=="usb:v2040p4902d0000dc00dsc00dp00icFFisc02ip00"
 +
    ATTRS{supports_autosuspend}=="0"
 +
 +
  looking at parent device '/devices/pci0000:00/0000:00:04.1/usb3/3-1':
 +
    KERNELS=="3-1"
 +
    SUBSYSTEMS=="usb"
 +
    DRIVERS=="usb"
 +
    ATTRS{dev}=="189:263"
 +
    ATTRS{configuration}==""
 +
    ATTRS{bNumInterfaces}==" 1"
 +
    ATTRS{bConfigurationValue}=="1"
 +
    ATTRS{bmAttributes}=="c0"
 +
    ATTRS{bMaxPower}=="  4mA"
 +
    ATTRS{urbnum}=="1403294"
 +
    ATTRS{idVendor}=="2040"
 +
    ATTRS{idProduct}=="4902"
 +
    ATTRS{bcdDevice}=="0000"
 +
    ATTRS{bDeviceClass}=="00"
 +
    ATTRS{bDeviceSubClass}=="00"
 +
    ATTRS{bDeviceProtocol}=="00"
 +
    ATTRS{bNumConfigurations}=="1"
 +
    ATTRS{bMaxPacketSize0}=="64"
 +
    ATTRS{speed}=="480"
 +
    ATTRS{busnum}=="3"
 +
    ATTRS{devnum}=="8"
 +
    ATTRS{version}==" 2.00"
 +
    ATTRS{maxchild}=="0"
 +
    ATTRS{quirks}=="0x0"
 +
    ATTRS{authorized}=="1"
 +
    ATTRS{manufacturer}=="AMBA"
 +
    ATTRS{product}=="Hauppauge HD PVR"
 +
    ATTRS{serial}=="FEEBDAED"
 +
 +
Almost all of those attributes can be matched against later by udev while it's initializing the device, and any one of them may be unique enough for our purposes.  The first one that we'll want to match is ''definitely'' the broad category of SUBSYSTEM.  The string "Hauppauge HD PVR" appears as both ATTRS{product} and ATTRS{name} and appears to be relatively unique, but for the sake of simplicity in our example, we'll use just ATTRS{name}.
 +
 +
=== Creating a custom udev rule ===
 +
 +
=== Renaming the device ===
 +
A strong suggestion would be to create new device symlink names which closely follow the hardware's ''actual'' name, so that they may be accessed by MythTV through more descriptively-named symbolic links instead of as generic video4linux devices named /dev/video[0-9].
 +
 +
* Hauppauge PVR-''nnn'' units may be named /dev/pvr''nnn''_[0-9].
 +
* Hauppauge HD-PVR units may be named /dev/hdpvr[0-9].

Revision as of 05:04, 24 January 2010

The Symptom

If you're here it's because you're experiencing a problem where your various tuners don't always seem to wind up with the same device name each time the machine boots and it's causing your backend to fail to use the correct tuner (or any tuner at all) to record with.

This is most likely to occur if you have multiple tuner devices on separate buses (meaning one or more USB devices and/or one or more PCI devices), although it can potentially happen under rarer circumstances like the cards being moved around inside the machine, or the USB devices being plugged into a different hub or different ports.

Solving this problem can be done semi-permanently with little risk to the rest of your configuration but will require a small amount a reading, a few shell commands, and the ability to cut and paste short strings without making mistakes.

The Problem

An old problem that originally occurred when udev/HAL were first being deployed has come back to haunt you.

Prior to the developments of udev/HAL, if you had two of the same piece of hardware in your machine, it was up to you to find a way to be certain that either they couldn't swap places between reboots or that it didn't matter if it did. At that time, the kernel searched for these devices in a specific order which avoided many potential problems.

The change to having udev enumerate (in short, identify them, load their respective driver, and give them their /dev node if applicable) devices on USB and PCI buses brought this problem back with a vengeance. Initially udev loaded driver modules based on whichever devices on the bus identified themselves first, but this is not guaranteed to happen in the same order very time. The changes to udev to ensure that devices are enumerated consistently in the same order applies to each individual bus and under certain circumstances may still fail to do what you expect if these devices are on different buses. This may be the case if you have both PCI and USB tuner devices.

During one boot, a USB device may be assigned /dev/video0 while a PCI device be given /dev/video1. During the the next boot, this situation can actually reverse itself. Particularly pressing is the issue of a Hauppauge PVR-500, which while having two tuners on the same card can actually wind up with it's second /dev/video[1-9] node not immediately following the first, should a USB tuner device announce itself at the right time.

The Solution

The solution is relatively simple. If your MythTV box is to host more than one sufficiently different type of tuner or video input, we'll need to add a custom udev rule that gives these devices separate and unique namespaces by which MythTV can access them. To do this you'll need to find a unique bit of information that udev can reliably recognize about each device, and the name of a new symlink for it to create.

Identifying the device

In order for udev to be able to handle rules which match our device, we need to first find out something relatively unique about what udev will know about the device the next time it is initialized. The first step to doing this is to find out the sysfs path to the device. Assuming for the moment your device is currently connected and functioning properly as /dev/video0, run the following command to query udev about the sysfs path used by the device at /dev/video0.

udevinfo -q path -n /dev/video0

You will get an answer like /class/video4linux/video0. Next, using the sysfs path you just discovered, you'll run the udevinfo command again to tell it to show you practically everything it knows about the device, what it's connected to, and what that's connected to. The output from this can be relatively long and winding, so you'll probably want to pipe it through less.

user@mythtv:~$ udevinfo -a -p /class/video4linux/video0 | less

Udevinfo 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 '/class/video4linux/video0':
   KERNEL=="video0"
   SUBSYSTEM=="video4linux"
   DRIVER==""
   ATTR{dev}=="81:0"
   ATTR{name}=="Hauppauge HD PVR"
   ATTR{index}=="0"

 looking at parent device '/devices/pci0000:00/0000:00:04.1/usb3/3-1/3-1:1.0':
   KERNELS=="3-1:1.0"
   SUBSYSTEMS=="usb"
   DRIVERS=="hdpvr"
   ATTRS{bInterfaceNumber}=="00"
   ATTRS{bAlternateSetting}==" 0"
   ATTRS{bNumEndpoints}=="02"
   ATTRS{bInterfaceClass}=="ff"
   ATTRS{bInterfaceSubClass}=="02"
   ATTRS{bInterfaceProtocol}=="00"
   ATTRS{modalias}=="usb:v2040p4902d0000dc00dsc00dp00icFFisc02ip00"
   ATTRS{supports_autosuspend}=="0"

 looking at parent device '/devices/pci0000:00/0000:00:04.1/usb3/3-1':
   KERNELS=="3-1"
   SUBSYSTEMS=="usb"
   DRIVERS=="usb"
   ATTRS{dev}=="189:263"
   ATTRS{configuration}==""
   ATTRS{bNumInterfaces}==" 1"
   ATTRS{bConfigurationValue}=="1"
   ATTRS{bmAttributes}=="c0"
   ATTRS{bMaxPower}=="  4mA"
   ATTRS{urbnum}=="1403294"
   ATTRS{idVendor}=="2040"
   ATTRS{idProduct}=="4902"
   ATTRS{bcdDevice}=="0000"
   ATTRS{bDeviceClass}=="00"
   ATTRS{bDeviceSubClass}=="00"
   ATTRS{bDeviceProtocol}=="00"
   ATTRS{bNumConfigurations}=="1"
   ATTRS{bMaxPacketSize0}=="64"
   ATTRS{speed}=="480"
   ATTRS{busnum}=="3"
   ATTRS{devnum}=="8"
   ATTRS{version}==" 2.00"
   ATTRS{maxchild}=="0"
   ATTRS{quirks}=="0x0"
   ATTRS{authorized}=="1"
   ATTRS{manufacturer}=="AMBA"
   ATTRS{product}=="Hauppauge HD PVR"
   ATTRS{serial}=="FEEBDAED"

Almost all of those attributes can be matched against later by udev while it's initializing the device, and any one of them may be unique enough for our purposes. The first one that we'll want to match is definitely the broad category of SUBSYSTEM. The string "Hauppauge HD PVR" appears as both ATTRS{product} and ATTRS{name} and appears to be relatively unique, but for the sake of simplicity in our example, we'll use just ATTRS{name}.

Creating a custom udev rule

Renaming the device

A strong suggestion would be to create new device symlink names which closely follow the hardware's actual name, so that they may be accessed by MythTV through more descriptively-named symbolic links instead of as generic video4linux devices named /dev/video[0-9].

  • Hauppauge PVR-nnn units may be named /dev/pvrnnn_[0-9].
  • Hauppauge HD-PVR units may be named /dev/hdpvr[0-9].