了解 /dev

作者:Preston F. Crow

在设计任何操作系统时,必须回答的一个问题是:“程序如何与物理设备通信?” UNIX 的答案是让系统提供设备文件。当程序访问它们时,它们的行为几乎与普通文件完全相同,但内核会将对这些特殊文件的访问传递给设备驱动程序。这些文件传统上位于 /dev 目录中。

要理解设备文件,您应该首先查看 /dev 目录的内容

ls -l /dev

您会看到这些特殊文件与普通文件有一些不同之处。首先,权限的第一个字符是“b”或“c”,表示该设备是块设备还是字符设备。其次,不是文件大小,而是有两个数字。这些是主设备号和次设备号。当您访问这些文件之一时,操作系统会在块或字符驱动程序表中查找主设备号,以找到设备驱动程序(在模块的情况下,可能在 kerneld 的帮助下)。次设备号供设备驱动程序用于同一设备的多个实例或设备的不同方面等。

您可能还会注意到一些文件的第一个权限字符是“s”,表明它们是套接字。与由内核处理的设备不同,这些套接字是由守护进程在系统启动时创建的。例如,/dev/printer 是由 lpd 守护进程控制的套接字。如果您终止 lpd 进程,/dev/printer 将消失。

如果您安装了 Linux 内核源代码,您可以通过在文件 /usr/src/linux/Documentation/devices.txt 中查找其设备类型和编号来了解设备的用途。在大多数 Linux 发行版中,您会发现存在许多您不期望使用的奇怪操作的设备文件。但是,您应该非常小心删除任何设备;删除错误的文件可能会导致您无法使用您的系统,直到您从软盘重启后恢复该文件。因此,请确保您有一个启动软盘,以在您犯错时拯救您的系统。当然,除非您以 root 身份运行,否则您无法对 /dev 目录造成太大破坏。

创建设备

有两种方法可以创建设备文件。推荐的方法是使用名为 MAKEDEV 的程序。您也可以使用 mknod 程序手动创建它们。我们将在此处反向考虑它们。

要使用 mknod,您需要知道设备的名称、类型(字符或块)以及主设备号和次设备号。例如,我曾经擦除过 /dev/zero。从软盘重启并将我的普通文件系统挂载到 /mnt 后,我想创建 /mnt/dev/zero。我知道 /dev/zero 应该是一个字符设备,主设备号为 1,次设备号为 5。我用来创建设备的命令是

mknod /mnt/dev/zero c 5 1

然后我必须使用 chmodchownchgrp 来设置访问权限和所有权,就像普通文件一样。您可能需要在使用 mknod 之前阅读其手册页。

如果这听起来很麻烦,那么您是对的。幸运的是,还有更好的方法。您可以不直接调用 mknod,而是使用名为 MAKEDEV 的脚本,该脚本已经知道所有标准设备的设备类型、编号、权限和所有权。MAKEDEV 使用 mknod 来创建设备,但省去了您弄清楚详细信息的工作。例如,键入 MAKEDEV generic 将创建您希望用于典型系统的大部分(如果不是全部)设备。最好在使用 MAKEDEV 之前阅读其手册页。

特定设备

/dev/null 是众所周知的位桶。Shell 脚本经常将命令的输出重定向到 /dev/null,以避免用不需要的输出弄乱显示。当用于输入时,它充当空文件。

/dev/random 和 /dev/urandom 访问内核的随机数生成器。内核跟踪各种“随机”事件,例如磁盘和键盘活动,并使用加密哈希来生成高度随机的数字。它还会跟踪对其拥有的随机信息量的估计。如果您使用 /dev/random,它只会给您提供它拥有的信息量。如果您使用 /dev/urandom,它将为您提供无限量的随机信息,但对其不可预测性的保证不如前者强。尽管内核在内部使用此功能,但很少有程序通过设备文件访问它。

/dev/zero 生成无限的零流。每次启动使用共享库的 ELF 进程时都会使用它,使其成为 /dev 中最重要的文件之一。

IDE 硬盘驱动器和 CD-ROM 驱动器通过 /dev/hd* 访问。大多数较新的 PC 主板都包含两个 IDE 接口,每个接口都能够控制一个主设备和一个从设备。hda 和 hdb 是第一个接口上的主驱动器和从驱动器,而 hdc 和 hdd 是第二个接口上的主驱动器和从驱动器。设备名称末尾的数字指的是分区号,其中 1 到 4 是主分区,5 及以上是扩展分区。

熟悉其他 UNIX 版本的人会惊讶地发现所有 IDE 设备都是块设备。传统上,驱动器也会有字符设备,您必须小心为给定程序使用哪个设备。(例如,fsck 希望使用字符设备,但您挂载块设备——这不是一个好主意。)Linux 允许程序访问块设备,就好像它是字符设备一样,因此无需为硬盘驱动器使用字符设备。

SCSI 设备比 IDE 设备复杂一些。如果您有带多个设备的 SCSI 卡,您可能已经知道每个设备都有一个介于 0 到 7 之间的 SCSI ID 号。当 SCSI 卡初始化时,操作系统会询问它连接了哪些设备。这些设备分为几个类别。找到的第一个硬盘驱动器(ID 号最低的那个)是 sda,第一个 CD-ROM 驱动器是 sr0,第一个磁带驱动器是 sta,第一个通用设备(通常是扫描仪)是 sga。因此,在 Linux 下访问 SCSI 设备时,您不需要知道设备 ID 号(与其他版本的 UNIX 不同)。与 IDE 驱动器一样,驱动器没有字符设备,分区号附加到驱动器设备文件。

磁带驱动器通常至少有两个不同的设备文件。主设备在您完成读取或写入磁带后会自动倒带。名称前带有“n”的设备不会为您倒带磁带。通常,您会使用它在磁带上写入多个存档。

tty 设备是 /dev 中所有文件中数量最多且最令人困惑的设备之一。每次您登录或启动新的 xterm 时,都会为 shell 分配一个 tty 设备。此设备负责显示 shell 的输出并提供其输入。它被称为该 shell 及其子进程的控制 tty。设备 /dev/tty 是一个神奇的设备,它引用的是哪个 tty 设备是该进程的控制 tty。

除了 /dev/tty 之外,tty 设备还有三种类型:控制台、串行端口和伪设备。

当键盘和显示器直接连接到系统而不运行 X Window 系统时,会使用控制台 tty。由于您可以有多个虚拟控制台,因此设备是 tty0 到 tty63。理论上,您可以有 64 个虚拟控制台,但大多数人只使用几个。设备 /dev/console 与 tty0 相同,并且出于历史原因需要它。如果您的系统允许您在控制台 1 到 6 上登录,那么当您运行 X Windows System 时,X 使用控制台 7,因此您的系统上将需要 /dev/tty1 到 /dev/tty7。我建议拥有 /dev/tty12 及以下的文件。有关使用虚拟控制台的更多信息,请参阅 John Fisk 在 1996 年 11 月号的《Linux Journal》中发表的文章 键盘、控制台和 VT 巡航

如果您有终端连接到串行端口,或者您使用调制解调器拨入,您将使用串行 tty 设备。如果您有带有许多串行端口的特殊卡(ttyC*、ttyD*、ttyX* 和 ttyR*),则会使用许多不同的串行设备,但大多数人只使用 ttyS* 用于普通串行端口(DOS 下的 COM1 到 COM4)。

这开始变得令人困惑,因为每个串行端口也有呼叫设备。对于每个 ttyS 设备,都有一个对应的 cua 设备。如果您仅将串行端口用于一个目的,那么使用哪个设备可能并不重要。为了能够远程拨入您的机器并在您在家时拨出,请务必使用该设备的 tty 版本来侦听传入的呼叫,并使用呼叫版本来发出呼叫。通过这样做,您不会因为尝试在同一条线路上拨出而打断已拨入的人。(请参阅“串行端口设备”。)

当通过启动新的 xterm 或通过 TELNET 连接到您的机器来启动登录时,会使用伪 tty 设备。由于您可以打开许多窗口并且同时进行许多 TELNET 会话,因此您可能需要很多这些设备。因此,您应该有很多 /dev/pty* 形式的文件。最初,Linux 将您限制为 64 个伪终端,但有些人发现这太受限制了,因此您现在最多可以拥有 256 个伪终端,使用不同的主设备号和次设备号。更复杂的是,实际上每个伪 tty 都有两个设备:主设备和从设备。因此,对于每个 /dev/pty* 文件,都有一个匹配的 /dev/tty* 文件。幸运的是,您不必担心这种区别,只需小心成对创建或删除它们即可。

优化 /dev

如果您希望从您的系统中获得每一毫秒的性能提升,那么您应该了解一些关于 UNIX 文件系统中目录的知识。(虽然从技术上讲,我谈论的是 EXT2 文件系统的实现,但这些要点几乎适用于所有 UNIX 文件系统。)

首先请注意,虽然命令 ls 始终以排序的顺序显示目录,但目录的条目并非以排序的方式存储。相反,每个新条目都尽可能靠近目录的开头放置。

要在目录中查找文件,文件名会与目录中的第一个文件进行比较。如果不匹配,则检查第二个名称,依此类推,直到找到匹配项或到达目录末尾。因此,如果目录中有大量文件,并且您经常打开目录中的最后一个文件,则您的 CPU 会进行大量比较。但是,如果您可以控制条目的顺序,以便将最常用的条目放在目录的开头,那么这就不成问题了。

如果您想重做 /dev 中条目的内部排序,请从软盘启动,然后挂载您的主文件系统。如果您的常规文件系统挂载为 /mnt,则您的常规设备目录为 /mnt/dev。创建一个名为 /mnt/dev2 的新目录。现在您可以将设备文件从 /mnt/dev 移动到 /mnt/dev2。您可能需要从 /mnt/dev/zero 和 /mnt/dev/null 开始,因为这两个设备的打开频率远高于任何其他设备。

如果这听起来很麻烦,那就不要为此烦恼。除非您在旧的 386 上运行,否则您可能不会注意到任何差异。此外,在 2.1.x 内核系列中开发的新目录缓存很可能会使这不再是问题。

串行端口设备

Preston Crow 在爱达荷州博伊西长大。他拥有达特茅斯学院计算机科学硕士学位,并希望很快升级为博士学位。他现在在马萨诸塞州剑桥市的 Open Group 工作,与他杰出的妻子住在一起。可以通过电子邮件 Preston.F.Crow@Dartmouth.edu 与他联系。

加载 Disqus 评论