1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
|
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE sect1 PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN" "http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd" [
<!ENTITY % general-entities SYSTEM "../general.ent">
%general-entities;
]>
<sect1 id="ch-scripts-udev">
<title>Device and Module Handling on an LFS System</title>
<?dbhtml filename="udev.html"?>
<indexterm zone="ch-scripts-udev">
<primary sortas="a-Udev">Udev</primary>
<secondary>usage</secondary></indexterm>
<para>In <xref linkend="chapter-building-system"/>, we installed the Udev
package. Before we go into the details regarding how this works,
a brief history of previous methods of handling devices is in
order.</para>
<para>Linux systems in general traditionally use a static device
creation method, whereby a great many device nodes are created under
<filename class="directory">/dev</filename> (sometimes literally
thousands of nodes), regardless of whether the corresponding hardware
devices actually exist. This is typically done via a
<command>MAKEDEV</command> script, which contains a number of
calls to the <command>mknod</command> program with the relevant major and minor device
numbers for every possible device that might exist in the world. Using
the udev method, only those devices which are detected by the kernel
get device nodes created for them. Because these device nodes will be
created each time the system boots, they will be stored on a
<systemitem class="filesystem">ramfs</systemitem> (a file system that
resides entirely in memory and does not take up any disk space).
Device nodes do not require much disk space, so the memory that is
used is negligible.</para>
<sect2>
<title>History</title>
<para>In February 2000, a new filesystem called <systemitem
class="filesystem">devfs</systemitem> was merged into the 2.3.46
kernel and was made available during the 2.4 series of
stable kernels. Although it was present in the kernel source itself,
this method of creating devices dynamically never received
overwhelming support from the core kernel developers.</para>
<para>The main problem with the approach adopted by <systemitem
class="filesystem">devfs</systemitem> was the way it handled
device detection, creation, and naming. The latter issue, that of
device node naming, was perhaps the most critical. It is generally
accepted that if device names are allowed to be configurable, then
the device naming policy should be up to a system administrator, not
imposed on them by any particular developer(s). The <systemitem
class="filesystem">devfs</systemitem> file system also suffers from race
conditions that are inherent in its design and cannot be fixed
without a substantial revision to the kernel. It has also been marked
as deprecated due to a lack of recent maintenance.</para>
<para>With the development of the unstable 2.5 kernel tree, later
released as the 2.6 series of stable kernels, a new virtual filesystem
called <systemitem class="filesystem">sysfs</systemitem> came to be.
The job of <systemitem class="filesystem">sysfs</systemitem> is to
export a view of the system's structure to userspace processes. With
this userspace visible representation, the possibility of seeing a
userspace replacement for <systemitem
class="filesystem">devfs</systemitem> became much more
realistic.</para>
</sect2>
<sect2>
<title>Udev Implementation</title>
<para>The <systemitem class="filesystem">sysfs</systemitem> filesystem
was mentioned briefly above. One may wonder how <systemitem
class="filesystem">sysfs</systemitem> knows about the devices present
on a system and what device numbers should be used. Drivers that
have been compiled into the kernel directly register their objects
with <systemitem class="filesystem">sysfs</systemitem> as they are
detected by the kernel. For drivers compiled as modules, this will
happen when the module is loaded. Once the <systemitem
class="filesystem">sysfs</systemitem> filesystem is mounted (on
<filename class="directory">/sys</filename>), the data which the
built-in drivers registered with <systemitem
class="filesystem">sysfs</systemitem> are available to userspace
processes and to <command>udev</command> for device node creation.</para>
<para>The <command>S10udev</command> initscript takes care of creating
these device nodes when Linux is booted. This script starts with
registering <command>/sbin/udevsend</command> as a hotplug event handler.
Hotplug events (discussed below) should not be generated during this
stage, but <command>udev</command> is registered just in case they do
occur. The <command>udevstart</command> program then walks through
the <systemitem class="filesystem">/sys</systemitem> filesystem and
creates devices under <filename class="directory">/dev</filename> that
match the descriptions. For example,
<filename>/sys/class/tty/vcs/dev</filename> contains the string
<quote>7:0</quote> This string is used by <command>udevstart</command>
to create <filename>/dev/vcs</filename> with major number
<emphasis>7</emphasis> and minor <emphasis>0</emphasis>. The names and
permissions of the nodes created under the
<filename class="directory">/dev</filename> directory are configured according
to the rules specified in the files within the
<filename class="directory">/etc/udev/rules.d/</filename> directory. These are
numbered in a similar fashion to the LFS bootscripts. If
<command>udev</command> can't find a rule for the device it is creating, it will
default permissions to <emphasis>660</emphasis> and ownership to
<emphasis>root:root</emphasis>.</para>
<para>Once the above stage is complete, all devices that were already
present and have compiled-in drivers will be available for use. What
about those devices that have modular drivers?</para>
<para>Earlier, we mentioned the concept of a <quote>hotplug event
handler.</quote> When a new device connection is detected by the
kernel, the kernel will generate a hotplug event and look at the file
<filename>/proc/sys/kernel/hotplug</filename> to find out the
userspace program that handles the device's connection. The
<command>udev</command> initscript registered <command>udevsend</command>
as this handler. When these hotplug events are generated, the kernel
will tell <command>udev</command> to check the <filename
class="directory">/sys</filename> filesystem for the information
pertaining to this new device and create the <filename
class="directory">/dev</filename> entry for it.</para>
<para>This brings us to one problem that exists with
<command>udev</command>, and likewise with <systemitem
class="filesystem">devfs</systemitem> before it. It is commonly
referred to as the <quote>chicken and egg</quote> problem. Most Linux
distrubtions handle loading modules via entries in
<filename>/etc/modules.conf</filename>. Access to a device node causes
the appropriate kernel module to load. With <command>udev</command>,
this method will not work because the device node does not exist until
the module is loaded. To solve this, the
<command>S05modules</command> bootscript was added to the
lfs-bootscripts package, along with the
<filename>/etc/sysconfig/modules</filename> file. By
adding module
names to the <filename>modules</filename> file, these modules will be
loaded when the computer is starting up. This allows
<command>udev</command> to detect the devices and create the
appropriate device nodes.</para>
<para>Note that on slower machines or for drivers that create a lot
of device nodes, the process of creating devices may take a few
seconds to complete. This means that some device nodes may not be
immediately accessible.</para>
</sect2>
<sect2>
<title>Handling Hotpluggable/Dynamic Devices</title>
<para>When you plug in a device, such as a Universal Serial Bus (USB) MP3 player, the kernel
recognizes that the device is now connected and generates a hotplug
event. If the driver is already loaded (either because it was compiled
into the kernel or because it was loaded via the
<command>S05modules</command> bootscript), <command>udev</command> will
be called upon to create the relevant device node(s) according to the
<systemitem class="filesystem">sysfs</systemitem> data available in
<filename class="directory">/sys</filename>.</para>
<para>If the driver for the just plugged in device is available as a module but
currently unloaded, the Hotplug package will load the appropriate module
and make this device available by creating the device node(s) for it.</para>
</sect2>
<sect2>
<title>Problems with Creating Devices</title>
<para>There are a few known problems when it comes to automatically creating
devices nodes:</para>
<para>1) A kernel driver may not export its data to <systemitem
class="filesystem">sysfs</systemitem>.</para>
<para>This is most common with third party drivers from outside the
kernel tree. These drivers will not end up having their device nodes
created. Use the
<filename>/etc/sysconfig/createfiles</filename> configuration file to
manually create the devices. Consult the
<filename>devices.txt</filename> file inside the kernel documentation
or the documentation for that driver to find the proper major/minor
numbers.</para>
<para>2) A non-hardware device is required. This is most common with
the Advanced Linux Sound Architecture (ALSA) project's Open Sound
System (OSS) compatibility module. These types of devices can be
handled in one of two ways:</para>
<itemizedlist>
<listitem><para>Adding the module names to
<filename>/etc/sysconfig/modules</filename></para></listitem>
<listitem><para>Using an
<quote>install</quote> line in
<filename>/etc/modprobe.conf</filename>. This tells the
<command>modprobe</command> command <quote>when loading this module,
also load this other module, at the same time.</quote> For example:</para>
<screen><userinput>install snd-pcm modprobe -i snd-pcm ; modprobe \
snd-pcm-oss ; true</userinput></screen>
<para>This will cause the system to load both the
<emphasis>snd-pcm</emphasis> and <emphasis>snd-pcm-oss</emphasis>
modules when any request is made to load the driver
<emphasis>snd-pcm</emphasis>.</para></listitem>
</itemizedlist>
</sect2>
<sect2>
<title>Useful Reading</title>
<para>Additional helpful documentation is available at the following
sites:</para>
<itemizedlist>
<listitem><para>A Userspace Implementation of <systemitem class="filesystem">devfs</systemitem>
<ulink url="http://www.kroah.com/linux/talks/ols_2003_udev_paper/Reprint-Kroah-Hartman-OLS2003.pdf"/></para></listitem>
<listitem><para>udev FAQ
<ulink url="http://www.kernel.org/pub/linux/utils/kernel/hotplug/udev-FAQ"/></para></listitem>
<listitem><para>The Linux Kernel Driver Model
<ulink url="http://public.planetmirror.com/pub/lca/2003/proceedings/papers/Patrick_Mochel/Patrick_Mochel.pdf"/></para></listitem>
</itemizedlist>
</sect2>
</sect1>
|