Differences between revisions 1 and 16 (spanning 15 versions)
Revision 1 as of 2007-04-05 16:17:54
Size: 1711
Editor: ?Eduard Bloch
Comment:
Revision 16 as of 2007-04-06 08:49:16
Size: 10198
Comment:
Deletions are marked like this. Additions are marked like this.
Line 1: Line 1:
= On Locking schemes on device files and device drivers = = On Locking Schemes on Linux Device Drivers =
Line 5: Line 5:
recently we (cdrkit and cdrskin developers) came accross increasing recently we (cdrkit and libburnia developers) came accross increasing
Line 17: Line 17:
either willingly (e.g. liblkid) or unwillingly (e.g. hald, opening with either willingly (e.g. liblkid) or accidentally (e.g. hald, opening with
Line 24: Line 24:
which shall cope with the particular requirements and which may be
implemented in a library shared by our applications later
.
which shall cope with the particular requirements.
Line 27: Line 26:
State of the practice
---------------------
== State of the practice ==
Line 30: Line 28:
Currently, following mechanisms can be considered: There are various locking techniques used in other areas which are more or less applicable in our case.
Line 32: Line 30:
1: O_EXCL locking === General inter-process locking mechanisms ===

In general, all the mechanisms listed below are not optimally appropriate for our purpose. They lack on two places which make then not reliable when used alone:

 * they do not cope with multiple device file which imply the access to the same driver through different files
 * they do not automatically cope with multiple device '''drivers''' accessible through '''different''' user space interfaces, like with sg vs. sr drivers on Linux. No matter how many excuses some kernel developers do present to paper over this obvious shortcomings. Automatic use of /dev/sr instead of /dev/sg is not always possible or may not be wanted by the user.

Finally, they may be sufficient to lower the risk on inappropriate operation. Which exactly are available in the wild?

 * System V Semaphores

 Principle: a magic integer, "key" or "semid", identifies a set of state objects on which the atomic operations can be performed which are necessary for implementing a proper locking algorithm. See man semget(2), semop(2) SEM_UNDO.

 Pros: semaphores are originally designed for our purpose and they are very traditional Unix requisites.

 Cons:
  * the semaphore key must be systemwide unique for the set of lockable drives and all participating programs have to use the same key. This situation is prone to collisions with locking mechanisms for other system resources. Function ftok(3) is not a secure solution.
  * each device needs a fixely defined index number in the set of semaphores which are allocated system resources. So we can hardly span up a giant index space where we can map different device file classes to disjoint index intervals.

 * Lock files associated with target file

 Principle: an additional file is created during the action on the real target file.

 Pros: regular filesystem operation, no additional infrastructure required
   
 Cons:
  * Possible races unless OS mechanisms are used for exclusive operation on the lock file, see below
  * The location and name of the lock file need to be known and discussed upfront among all application developers, or be documented excessively
  * Permission problems may disallow the creation of lock files (security issues), especially for self-compiled applications and having no root permissions to install them in a required way
  * Special precautions are necessary against stale locks

 * fcntl(2) exclusive file locking

 Principle: lock applied on open file handles. Internally associated with a path, see fcntl(2) for details.
 
 Pros:

  * known (POSIX.1-2001), usually reliable mechanism

 Cons:

  * diverges from flock() implementation on Linux, see below. Results in independent locking.
  * possible problems on network file systems

 * flock(2) exclusive file locking

 Principle: similar to fcntl locks, applied with a different system function.

 Pros: see fcntl(2) locking above

 Cons: like flock(2), but less portable, not working over network file systems
  
==== Advanced Linux-specific locking mechanisms ====

 * O_EXCL locking
Line 36: Line 89:
   Pros:
    - reliable for a device accessible through one driver
   Cons:

 Pros:
  * reliable for a device accessible through one driver
 
 Cons:
  * requires kernel 2.6.x (x>=7 or so)
  * does not automagicaly make the device inaccessible, only applications using O_EXCL will know about the locked state when getting negative result with EBUSY errno value.

=== Applicability on CD/(HD)DVD/BD drives ===

As explained in the introduction, the locking is important on optical media recording due to the delicate operation mode during the recording. Ideally, no application should touch them, even reading from the media is an evil task. But how does the state of the practice look like?

 * mount: the block device is mounted with the O_EXCL flag '''BUT''' the mount executable also uses '''libblkid''' which opens the devices without locking and read magic data from it. This also provides no solution for operation through the sg driver.
 
 * hald (HAL daemon): periodically opens the cdrom block devices with O_EXCL flag. Clashes with operation on sg is possible.

 * wodim: opens the devices with O_EXCL flag. Opening /dev/sg is possible and happens more likely with versions prior to 1.1.4.

 * growisofs: opens the block devices with O_EXCL flag. Opening /dev/sg was never encouraged and does not work on kernel 2.4 (not tested yet on 2.6).

 * cdrskin (via libburn): opens the devices with O_EXCL flag. It uses a unique device file path for serious operations on the drive. This is /dev/sg* on kernel 2.4, and recently has become /dev/sr* on kernel 2.6. Operations on other path representations of the same device are restricted to open(2) O_RDONLY and to obtaining SCSI parameters host,channel,id,lun.

 * cdrecord: no locking. Author recommends to get rid of applications which may touch the device somehow.

=== Proposed general locking algorithms ===

=== What can be done within the CD/DVD tool community ===

The following method is proposed to create a midway between the limitations of kernel and the requirements of others, also unifying the way of dealing with the device locks.

The locking methods with additional lock files are identified as very cumbersome because of inconsistent security settings on different applications, see above. Instead, this proposal relies on a two-step locking method and does not yet solve the ambiguity problem of sr-scd-sg paths:

 1. Open the device. For applications that operate in a delicate way (burning tools), O_EXCL shall be set. For others, it may be omited.
 2. Set or check the additional fcntl lock on the device file. It must be exclusive! Sample code (by Thomas Schmitt)
{{{
        struct flock lockthing;
        ...
        f = open(device, mode|O_EXCL);
        if (f != -1) {
             memset(&lockthing, 0, sizeof(lockthing));
             lockthing.l_type = F_WRLCK;
             lockthing.l_whence = SEEK_SET;
             lockthing.l_start = 0;
             lockthing.l_len = 0;
             if (fcntl(f, F_SETLK, &lockthing)) {
                close(f);
                /* user feedback, report error, etc... */
                f = -1;
             }
        }
}}}
Normally, fcntl(2) imposes advisory locking. But the sysadmin can make this mandatory locking by a mount option. (But is /dev/ mount(8)ed at all ?)

Unique path resolution is necessary so all interested processes come together at the same inode where this locking is guaranteed to collide. (Does F_SETLK work with all the implementations of directory /dev/ ?)

Links or additional device paths created by mknod(1) can be translated into /dev/sg* resp. /dev/sr* by help of call stat(2) and its result element .st_rdev. But the jump from /dev/sg* to /dev/sr* is not possible via stat(2). For that we need open(2) O_RDONLY, ioctl(SCSI_IOCTL_GET_IDLUN), close(2).

The translation is done by obtaining info from the given path, by iterating over the desired device paths /dev/hd%c , /dev/sg%d , /dev/sr%d, and by comparing their info with the one we look for. Kernel 2.6: If the result is a /dev/sg%d then it has to be translated into a /dev/sr%d in another step.

NOTE: there are sysfs symlinks that set up a path usable to map exactly. However, this depends on a mounted sysfs and the required symlinks have also been declared deprecated in the recent Linux kernel versions.


Kernel 2.4 imposes the problem that ioctl(SG_IO) is not possible with sr, so most of the programs have to use sg. Only growisofs uses sr via ioctl(CDROM_SEND_PACKET). We will possibly not come to a completely sufficient agreement under these circumstances. Well, we 2.4ers are used to suffer neglect. (sob, hehe)


== Obstacles for a better solution ==

Why not FHS compliant /var/lock/ files?

First: races, stale locks.

Second: unclear or unreliable cleanup technique, dangling bad lockfiles possible

Third: The most obvious problem is the usual permission setting of /var/lock :
{{{
SuSE 9.0 (kernel 2.4):
  drwxrwxr-x 3 root uucp 4096 Apr 4 05:07 /var/lock
SuSE 9.3 (kernel 2.6):
  drwxrwxr-t 4 root uucp 4096 2007-04-04 17:50 /var/lock
| Fedora Core 3.x:
| drwxrwxr-x 5 root lock 4096 Apr 4 04:03 /var/lock
| Debian gives rw-permission to anybody and thus would be no problem.
}}}
This system may work with the plain old UUCP program and few others programs with low device opening activity AND administrated by root but is a real PITA nowadays.

=== The better solution would be ... ===

(to come after breakfast :)

On Locking Schemes on Linux Device Drivers

Hello fellow application developer or maintainer,

recently we (cdrkit and libburnia developers) came accross increasing problems with reliable and safe device locking. This paper enlightens the issues behind the scenes and presents possible future solutions.

Introduction

Our original concern is the influence of even read-only operations on optical media drives (recorders) during their duty as recorders -- depending on the device model such read-only work may interrupt the process badly practically destroying the medium.

Since many programs already do act on such devices in an unsafe manner, either willingly (e.g. liblkid) or accidentally (e.g. hald, opening with O_EXCL but still clashing with cdr applications working on the competing sg driver), we see the need for reliable communication in order to ensure proper device locking where appropriate, in a way which is appropriate for the particular application. In the following document, first the currently possible mechanisms are itemized with their advantages and their problems, followed by a draft of a locking scheme which shall cope with the particular requirements.

State of the practice

There are various locking techniques used in other areas which are more or less applicable in our case.

General inter-process locking mechanisms

In general, all the mechanisms listed below are not optimally appropriate for our purpose. They lack on two places which make then not reliable when used alone:

  • they do not cope with multiple device file which imply the access to the same driver through different files
  • they do not automatically cope with multiple device drivers accessible through different user space interfaces, like with sg vs. sr drivers on Linux. No matter how many excuses some kernel developers do present to paper over this obvious shortcomings. Automatic use of /dev/sr instead of /dev/sg is not always possible or may not be wanted by the user.

Finally, they may be sufficient to lower the risk on inappropriate operation. Which exactly are available in the wild?

  • System V Semaphores Principle: a magic integer, "key" or "semid", identifies a set of state objects on which the atomic operations can be performed which are necessary for implementing a proper locking algorithm. See man semget(2), semop(2) SEM_UNDO. Pros: semaphores are originally designed for our purpose and they are very traditional Unix requisites. Cons:
    • the semaphore key must be systemwide unique for the set of lockable drives and all participating programs have to use the same key. This situation is prone to collisions with locking mechanisms for other system resources. Function ftok(3) is not a secure solution.
    • each device needs a fixely defined index number in the set of semaphores which are allocated system resources. So we can hardly span up a giant index space where we can map different device file classes to disjoint index intervals.
  • Lock files associated with target file Principle: an additional file is created during the action on the real target file. Pros: regular filesystem operation, no additional infrastructure required Cons:
    • Possible races unless OS mechanisms are used for exclusive operation on the lock file, see below
    • The location and name of the lock file need to be known and discussed upfront among all application developers, or be documented excessively
    • Permission problems may disallow the creation of lock files (security issues), especially for self-compiled applications and having no root permissions to install them in a required way
    • Special precautions are necessary against stale locks
  • fcntl(2) exclusive file locking Principle: lock applied on open file handles. Internally associated with a path, see fcntl(2) for details. Pros:
    • known (POSIX.1-2001), usually reliable mechanism
    Cons:
    • diverges from flock() implementation on Linux, see below. Results in independent locking.
    • possible problems on network file systems
  • flock(2) exclusive file locking Principle: similar to fcntl locks, applied with a different system function. Pros: see fcntl(2) locking above Cons: like flock(2), but less portable, not working over network file systems

Advanced Linux-specific locking mechanisms

  • O_EXCL locking
    • Principle: passing of the O_EXCL flag to the open call. The device is locked exclusively for the calling PID, the lock is maintained in the device driver to the particular major/minor combination.
    Pros:
    • reliable for a device accessible through one driver
    Cons:
    • requires kernel 2.6.x (x>=7 or so)

    • does not automagicaly make the device inaccessible, only applications using O_EXCL will know about the locked state when getting negative result with EBUSY errno value.

Applicability on CD/(HD)DVD/BD drives

As explained in the introduction, the locking is important on optical media recording due to the delicate operation mode during the recording. Ideally, no application should touch them, even reading from the media is an evil task. But how does the state of the practice look like?

  • mount: the block device is mounted with the O_EXCL flag BUT the mount executable also uses libblkid which opens the devices without locking and read magic data from it. This also provides no solution for operation through the sg driver.

  • hald (HAL daemon): periodically opens the cdrom block devices with O_EXCL flag. Clashes with operation on sg is possible.
  • wodim: opens the devices with O_EXCL flag. Opening /dev/sg is possible and happens more likely with versions prior to 1.1.4.
  • growisofs: opens the block devices with O_EXCL flag. Opening /dev/sg was never encouraged and does not work on kernel 2.4 (not tested yet on 2.6).
  • cdrskin (via libburn): opens the devices with O_EXCL flag. It uses a unique device file path for serious operations on the drive. This is /dev/sg* on kernel 2.4, and recently has become /dev/sr* on kernel 2.6. Operations on other path representations of the same device are restricted to open(2) O_RDONLY and to obtaining SCSI parameters host,channel,id,lun.
  • cdrecord: no locking. Author recommends to get rid of applications which may touch the device somehow.

Proposed general locking algorithms

What can be done within the CD/DVD tool community

The following method is proposed to create a midway between the limitations of kernel and the requirements of others, also unifying the way of dealing with the device locks.

The locking methods with additional lock files are identified as very cumbersome because of inconsistent security settings on different applications, see above. Instead, this proposal relies on a two-step locking method and does not yet solve the ambiguity problem of sr-scd-sg paths:

  1. Open the device. For applications that operate in a delicate way (burning tools), O_EXCL shall be set. For others, it may be omited.
  2. Set or check the additional fcntl lock on the device file. It must be exclusive! Sample code (by Thomas Schmitt)

        struct flock lockthing;
        ...
        f = open(device, mode|O_EXCL);
        if (f != -1) {
             memset(&lockthing, 0, sizeof(lockthing));
             lockthing.l_type = F_WRLCK;
             lockthing.l_whence = SEEK_SET;
             lockthing.l_start = 0;
             lockthing.l_len = 0;
             if (fcntl(f, F_SETLK, &lockthing)) {
                close(f);
                /* user feedback, report error, etc... */
                f = -1;
             }
        }

Normally, fcntl(2) imposes advisory locking. But the sysadmin can make this mandatory locking by a mount option. (But is /dev/ mount(8)ed at all ?)

Unique path resolution is necessary so all interested processes come together at the same inode where this locking is guaranteed to collide. (Does F_SETLK work with all the implementations of directory /dev/ ?)

Links or additional device paths created by mknod(1) can be translated into /dev/sg* resp. /dev/sr* by help of call stat(2) and its result element .st_rdev. But the jump from /dev/sg* to /dev/sr* is not possible via stat(2). For that we need open(2) O_RDONLY, ioctl(SCSI_IOCTL_GET_IDLUN), close(2).

The translation is done by obtaining info from the given path, by iterating over the desired device paths /dev/hd%c , /dev/sg%d , /dev/sr%d, and by comparing their info with the one we look for. Kernel 2.6: If the result is a /dev/sg%d then it has to be translated into a /dev/sr%d in another step.

NOTE: there are sysfs symlinks that set up a path usable to map exactly. However, this depends on a mounted sysfs and the required symlinks have also been declared deprecated in the recent Linux kernel versions.

Kernel 2.4 imposes the problem that ioctl(SG_IO) is not possible with sr, so most of the programs have to use sg. Only growisofs uses sr via ioctl(CDROM_SEND_PACKET). We will possibly not come to a completely sufficient agreement under these circumstances. Well, we 2.4ers are used to suffer neglect. (sob, hehe)

Obstacles for a better solution

Why not FHS compliant /var/lock/ files?

First: races, stale locks.

Second: unclear or unreliable cleanup technique, dangling bad lockfiles possible

Third: The most obvious problem is the usual permission setting of /var/lock :

SuSE 9.0 (kernel 2.4):
  drwxrwxr-x    3 root     uucp         4096 Apr  4     05:07 /var/lock
SuSE 9.3 (kernel 2.6):
  drwxrwxr-t    4 root     uucp         4096 2007-04-04 17:50 /var/lock
| Fedora Core 3.x:
|   drwxrwxr-x    5 root     lock         4096 Apr  4     04:03 /var/lock
| Debian gives rw-permission to anybody and thus would be no problem.

This system may work with the plain old UUCP program and few others programs with low device opening activity AND administrated by root but is a real PITA nowadays.

The better solution would be ...

(to come after breakfast :)