Chapter 3. Devices(设备)

This chapter is a basic tour of the kernel-provided device infrastructure in a functioning Linux system.

本章是对Linux系统中内核提供的设备基础架构的基本介绍。

Throughout the history of Linux, there have been many changes to how the kernel presents devices to the user. We’ll begin by looking at the traditional system of device files to see how the kernel provides device configuration information through sysfs. Our goal is to be able to extract information about the devices on a system in order to understand a few rudimentary operations. Later chapters will cover interacting with specific kinds of devices in greater detail.

在Linux的历史中,内核向用户展示设备的方式经历了许多变化。

我们将看一下传统的设备文件系统,了解内核如何通过sysfs提供设备配置信息。

我们的目标是能够提取系统上设备的信息,以便理解一些基本操作。

后面的章节将更详细地介绍与特定类型设备的交互。

It’s important to understand how the kernel interacts with user space when presented with new devices. The udev system enables user-space programs to automatically configure and use new devices. You’ll see the basic workings of how the kernel sends a message to a user-space process through udev, as well as what the process does with it.

当系统接收到新设备时,了解内核与用户空间的交互方式非常重要。

udev系统使得用户空间程序能够自动配置和使用新设备。

您将会了解到内核如何通过udev向用户空间进程发送消息的基本工作原理,以及该进程如何处理这些消息。

3.1 设备文件

It is easy to manipulate most devices on a Unix system because the kernel presents many of the device I/O interfaces to user processes as files. These device files are sometimes called device nodes. Not only can a programmer use regular file operations to work with a device, but some devices are also accessible to standard programs like cat, so you don’t have to be a programmer to use a device. However, there is a limit to what you can do with a file interface, so not all devices or device capabilities are accessible with standard file I/O.

在Unix系统上,大多数设备都很容易操作,因为内核将许多设备的I/O接口呈现给用户进程作为文件。

这些设备文件有时被称为设备节点。

程序员不仅可以使用常规文件操作来处理设备,而且一些设备也可以被像cat这样的标准程序访问,所以您不必是一个程序员就可以使用设备。

然而,使用文件接口有一定的限制,因此并非所有设备或设备功能都可以通过标准文件I/O访问。

Linux uses the same design for device files as do other Unix flavors. Device files are in the /dev directory, and running ls /dev reveals more than a few files in /dev. So how do you work with devices?

Linux与其他Unix版本使用相同的设备文件设计。

设备文件位于/dev目录下,运行ls /dev命令可以看到/dev目录下的许多文件。

那么如何操作设备呢?

To get started, consider this command:

我们最先想到了以下命令:

echo blah blah > /dev/null

As does any command with redirected output, this sends some stuff from the standard output to a file. However, the file is /dev/null, a device, and the kernel decides what to do with any data written to this device. In the case of /dev/null, the kernel simply ignores the input and throws away the data.

与任何重定向输出的命令一样,这个命令将一些内容从标准输出发送到一个文件。

然而,文件是/dev/null,一个设备,内核决定如何处理写入该设备的任何数据。

在/dev/null的情况下,内核简单地忽略输入并丢弃数据。

To identify a device and view its permissions, use ls -l:

要识别设备并查看其权限,可以使用ls -l命令:

Example 3-1. Device files

示例3-1. 设备文件

$ ls -l
brw-rw---- 1 root disk 8, 1 Sep 6 08:37 sda1
crw-rw-rw- 1 root root 1, 3 Sep 6 08:37 null
prw-r--r-- 1 root root 0 Mar 3 19:17 fdata
srw-rw-rw- 1 root root 0 Dec 18 07:43 log

Note the first character of each line (the first character of the file’s mode) in Example 3-1. If this character is b, c, p, or s, the file is a device. These letters stand for block, character, pipe, and socket, respectively, as described in more detail below.

注意 示例3-1中每行的第一个字符(文件模式的第一个字符)。

如果这个字符是b、c、p或s,则该文件是一个设备。

这些字母分别代表块设备、字符设备、管道和套接字,下面将更详细地描述它们。

Block device 块设备

Programs access data from a block device in fixed chunks. The sda1 in the preceding example is a disk device, a type of block device. Disks can be easily split up into blocks of data. Because a block device’s total size is fixed and easy to index, processes have random access to any block in the device with the help of the kernel.

程序以固定的块大小从块设备中访问数据。

上述示例中的sda1是一个磁盘设备,也是一种块设备。

磁盘可以被分割成数据块。

由于块设备的总大小是固定且易于索引的,进程可以通过内核的帮助随机访问设备中的任何一个块。

Character device 字符设备

Character devices work with data streams. You can only read characters from or write characters to character devices, as previously demonstrated with /dev/null. Character devices don’t have a size; when you read from or write to one, the kernel usually performs a read or write operation on the device. Printers directly attached to your computer are represented by character devices. It’s important to note that during character device interaction, the kernel cannot back up and reexamine the data stream after it has passed data to a device or process.

字符设备用于处理数据流。

你只能从字符设备中读取字符或向其写入字符,就像之前演示的/dev/null一样。

字符设备没有大小;当你从字符设备中读取或向其写入时,内核通常会在设备上执行读取或写入操作。

直接连接到计算机的打印机由字符设备表示。

需要注意的是,在字符设备交互过程中,内核无法在将数据传递给设备或进程后备份和重新检查数据流。

Pipe device 管道设备

Named pipes are like character devices, with another process at the other end of the I/O stream instead of a kernel driver.

命名管道与字符设备类似,只是I/O流的另一端是另一个进程,而不是内核驱动程序。

套接字设备

Sockets are special-purpose interfaces that are frequently used for interprocess communication. They’re often found outside of the /dev directory. Socket files represent Unix domain sockets; you’ll learn more about those in Chapter 10.

套接字是专用接口,经常用于进程间通信。

它们通常位于/dev目录之外。

套接字文件表示Unix域套接字;你将在第10章中了解更多相关内容。

The numbers before the dates in the first two lines of Example 3-1 are the major and minor device numbers that help the kernel identify the device. Similar devices usually have the same major number, such as sda3 and sdb1 (both of which are hard disk partitions).

示例3-1的前两行中日期之前的数字是主设备号和次设备号,它们帮助内核识别设备。

类似的设备通常具有相同的主设备号,比如sda3和sdb1(它们都是硬盘分区)。

NOTE Not all devices have device files because the block and character device I/O interfaces are not appropriate in all cases. For example, network interfaces don’t have device files. It is theoretically possible to interact with a network interface using a single character device, but because it would be exceptionally difficult, the kernel uses other I/O interfaces

注意 并非所有设备都有设备文件,因为块设备和字符设备的I/O接口并不适用于所有情况。

例如,网络接口没有设备文件。

理论上可以使用单个字符设备与网络接口进行交互,但由于这将非常困难,内核使用其他I/O接口。

3.2 The sysfs Device Path(sysfs设备路径)

The traditional Unix /dev directory is a convenient way for user processes to reference and interface with devices supported by the kernel, but it’s also a very simplistic scheme. The name of the device in /dev tells you a little about the device, but not a lot. Another problem is that the kernel assigns devices in the order in which they are found, so a device may have a different name between reboots.

传统的Unix /dev目录是用户进程引用和与内核支持的设备进行交互的便捷方式,但也是一种非常简单的方案。

/dev中设备的名称对设备的了解有限。

另一个问题是内核按照找到的顺序分配设备,因此设备在重新启动后可能具有不同的名称。

To provide a uniform view for attached devices based on their actual hardware attributes, the Linux kernel offers the sysfs interface through a system of files and directories. The base path for devices is /sys/devices. For example, the SATA hard disk at /dev/sda might have the following path in sysfs:

为了根据实际硬件属性为连接的设备提供统一的视图,Linux内核通过文件和目录系统提供了sysfs接口。

设备的基本路径是/sys/devices。

例如,位于/dev/sda的SATA硬盘在sysfs中可能具有以下路径:

/sys/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda

As you can see, this path is quite long compared with the /dev/sda filename, which is also a directory. But you can’t really compare the two paths because they have different purposes. The /dev file is there so that user processes can use the device, whereas the /sys/devices path is used to view information and manage the device. If you list the contents of a device path such as the preceding one, you’ll see something like the following:

正如你所见,与/dev/sda文件名相比,这个路径相当长,而且也是一个目录。

但你不能真正比较这两个路径,因为它们有不同的目的。

/dev文件存在是为了让用户进程使用设备,而/sys/devices路径用于查看信息和管理设备。

如果列出设备路径的内容,如上述路径,你将看到类似以下的内容:

image-20231201142756885

image-20231201142748893

The files and subdirectories here are meant to be read primarily by programs rather than humans, but you can get an idea of what they contain and represent by looking at an example such as the /dev file. Running cat dev in this directory displays the numbers 8:0, which happen to be the major and minor device numbers of /dev/sda.

这里的文件和子目录主要是供程序阅读而不是人类,但是你可以通过查看/dev文件的示例来了解它们包含和表示的内容。

在此目录中运行cat dev命令会显示数字8:0,这恰好是/dev/sda的主设备号和次设备号。

There are a few shortcuts in the /sys directory. For example, /sys/block should contain all of the block devices available on a system. However, those are just symbolic links; run ls -l /sys/block to reveal the true sysfs paths.

/sys目录中有一些快捷方式。例如,/sys/block应该包含系统上所有可用的块设备。然而,这些只是符号链接;运行ls -l /sys/block命令可以显示真正的sysfs路径。

It can be difficult to find the sysfs location of a device in /dev. Use the udevadm command to show the path and other attributes:

在/dev中找到设备的sysfs位置可能会很困难。

使用udevadm命令显示路径和其他属性:

udevadm info --query=all --name=/dev/sda
NOTE The udevadm program is in /sbin; you can put this directory at the end of your path if it’s not already there.
注意:udevadm程序位于/sbin目录下;如果路径中没有该目录,可以将其添加到路径的末尾。

You’ll find more details about udevadm and the entire udev system in 3.5 udev

关于udevadm和整个udev系统的更多详细信息,请参阅3.5 udev。

3.3 dd and Devices(dd和设备)

The program dd is extremely useful when working with block and character devices. This program’s sole function is to read from an input file or stream and write to an output file or stream, possibly doing some encoding conversion on the way.

当使用块设备和字符设备时,dd程序非常有用。

该程序的唯一功能是从输入文件或流中读取数据,并将其写入输出文件或流中,在此过程中可能进行一些编码转换。

dd copies data in blocks of a fixed size. Here’s how to use dd with a character device and some common options:

dd以固定大小的块复制数据。以下是如何使用dd与字符设备和一些常见选项的示例:

dd if=/dev/zero of=new_file bs=1024 count=1

As you can see, the dd option format differs from the option formats of most other Unix commands; it’s based on an old IBM Job Control Language (JCL) style. Rather than use the dash (-) character to signal an option, you name an option and set its value to something with the equals (=) sign. The preceding example copies a single 1024-byte block from /dev/zero (a continuous stream of zero bytes) to new_file.

正如你所见,dd的选项格式与大多数其他Unix命令的选项格式不同;它基于旧的IBM作业控制语言(JCL)风格。

你可以通过命名选项并使用等号(=)来设置其值,而不是使用破折号(-)字符来表示选项。

上面的示例将一个1024字节的块从/dev/zero(一个连续的零字节流)复制到new_file。

These are the important dd options:

以下是重要的dd选项:x

o if=file The input file. The default is the standard input.
o of=file The output file. The default is the standard output.
o bs=size The block size. dd reads and writes this many bytes of data at a time. To abbreviate large chunks of data, you can use b and k to signify 512 and 1024 bytes, respectively. Therefore, the example above could read bs=1k instead of bs=1024.
o ibs=size, obs=size The input and output block sizes. If you can use the same block size for both input and output, use the bs option; if not, use ibs and obs for input and output, respectively. o count=num The total number of blocks to copy. When working with a huge file—or with a device that supplies an endless stream of data, such as /dev/zero—you want dd to stop at a fixed point or you could waste a lot of disk space, CPU time, or both. Use count with the skip parameter to copy a small piece from a large file or device.
o skip= o num Skip past the first num blocks in the input file or stream and do not copy them to the output.

o if=file 输入文件。默认为标准输入。
o of=file 输出文件。默认为标准输出。
o bs=size 块大小。dd每次读取和写入这么多字节的数据。为了缩写大块数据,可以使用b和k分别表示512和1024字节。因此,上面的示例可以使用bs=1k来代替bs=1024。
ibs=size, obs=size 输入和输出块的大小。如果您可以同时使用相同的块大小进行输入和输出,请使用bs选项;如果不能,请分别使用ibs和obs进行输入和输出。
o count=num 要复制的总块数。当处理大文件或提供无尽数据流的设备(如/dev/zero)时,您希望dd在固定点停止,否则可能会浪费大量磁盘空间、CPU时间或两者兼而有之。使用count和skip参数从大文件或设备中复制一小部分。
o skip=num 跳过输入文件或流中的前num个块,并且不将它们复制到输出中。

警告
dd 命令非常强大,因此在运行它时务必确保自己知道自己在做什么。如果出现粗心的错误,很容易损坏设备上的文件和数据。如果不确定它会做什么,将输出写入新文件通常会有所帮助。

3.4 Device Name Summary(设备名称概述)

It can sometimes be difficult to find the name of a device (for example, when partitioning a disk). Here are a few ways to find out what it is:

有时候找到设备的名称可能会有些困难(例如,在分区磁盘时)。以下是几种找到设备名称的方法:

o Query udevd using udevadm (see 3.5 udev).
o Look for the device in the /sys directory.
o Guess the name from the output of the dmesg command (which prints the last few kernel messages) or the kernel system log file (see 7.2 System Logging). This output might contain a description of the devices on your system.
o For a disk device that is already visible to the system, you can check the output of the mount command.
o Run cat /proc/devices to see the block and character devices for which your system currently has drivers. Each line consists of a number and name. The number is the major number of the device as described in 3.1 Device Files. If you can guess the device from the name, look in /dev for the character or block devices with the corresponding major number, and you’ve found the device files.

o 使用udevadm查询udev守护进程(参见3.5 udev)。
o 在/sys目录中寻找设备。
o 根据dmesg命令的输出(打印最近的几条内核消息)或内核系统日志文件(参见7.2 系统日志)猜测设备的名称。这些输出可能包含系统上设备的描述。
o 对于已对系统可见的磁盘设备,可以检查mount命令的输出。
o 运行cat /proc/devices命令,查看系统当前具有驱动程序的块设备和字符设备。每行由一个数字和一个名称组成。数字是设备的主要编号,如3.1 设备文件中所述。如果你能从名称中猜出设备,就在/dev目录中查找具有相应主要编号的字符设备或块设备,那么你就找到了设备文件。

Among these methods, only the first is reliable, but it does require udev. If you get into a situation where udev is not available, try the other methods but keep in mind that the kernel might not have a device file for your hardware

在这些方法中,只有第一种是可靠的,但它需要udev。如果你遇到udev不可用的情况,请尝试其他方法,但要记住内核可能没有适用于你的硬件的设备文件。

The following sections list the most common Linux devices and their naming conventions.

下面的章节列出了最常见的Linux设备及其命名约定。

3.4.1 硬盘:/dev/sd*

Most hard disks attached to current Linux systems correspond to device names with an sd prefix, such as /dev/sda, /dev/sdb, and so on. These devices represent entire disks; the kernel makes separate device files, such as /dev/sda1 and /dev/sda2, for the partitions on a disk.

大多数连接到当前Linux系统的硬盘对应的设备名称都带有sd前缀,例如/dev/sda、/dev/sdb等。这些设备表示整个硬盘;内核为硬盘上的分区创建了单独的设备文件,例如/dev/sda1和/dev/sda2。

The naming convention requires a little explanation. The sd portion of the name stands for SCSI disk. Small Computer System Interface (SCSI) was originally developed as a hardware and protocol standard for communication between devices such as disks and other peripherals. Although traditional SCSI hardware isn’t used in most modern machines, the SCSI protocol is everywhere due to its adaptability. For example, USB storage devices use it to communicate. The story on SATA disks is a little more complicated, but the Linux kernel still uses SCSI commands at a certain point when talking to them.

这个命名约定需要一点解释。

名称中的sd部分代表SCSI磁盘。SCSI(Small Computer System Interface)最初是作为一种硬件和协议标准开发的,用于设备(如磁盘和其他外围设备)之间的通信。

尽管大多数现代机器中不再使用传统的SCSI硬件,但由于其适应性,SCSI协议仍然无处不在。

例如,USB存储设备使用它进行通信。关于SATA硬盘的情况稍微复杂一些,但Linux内核在与其通信时仍然使用SCSI命令。

To list the SCSI devices on your system, use a utility that walks the device paths provided by sysfs. One of the most succinct tools is lsscsi. Here is what you can expect when you run it:

要列出系统上的SCSI设备,请使用一个遍历sysfs提供的设备路径的实用工具。其中一个最简洁的工具是lsscsi。当你运行它时,你可以得到以下结果:

The first column ➊ identifies the address of the device on the system, the second ➋ describes what kind of device it is, and the last ➌ indicates where to find the device file. Everything else is vendor information.

第一列➊标识系统上设备的地址,第二列➋描述设备的类型,最后一列➌指示设备文件的位置。

其他所有信息都是供应商的信息。

Linux assigns devices to device files in the order in which its drivers encounter devices. So in the previous example, the kernel found the disk first, the optical drive second, and the flash drive last.

Linux将设备按照其驱动程序遇到设备的顺序分配给设备文件。

因此,在前面的示例中,内核首先找到磁盘,然后是光驱,最后是闪存驱动器。

Unfortunately, this device assignment scheme has traditionally caused problems when reconfiguring hardware. Say, for example, that you have a system with three disks: /dev/sda, /dev/sdb, and /dev/sdc. If /dev/sdb explodes and you must remove the disk so that the machine can work again, the former /dev/sdc moves to /dev/sdb, and there is no longer a /dev/sdc. If you were referring to the device names directly in the fstab file (see 4.2.8 The /etc/fstab Filesystem Table), you’d have to make some changes to that file in order to get things (mostly) back to normal. To solve this problem, most modern Linux systems use the Universally Unique Identifier (UUID, see 4.2.4 Filesystem UUID) for persistent disk device access.

不幸的是,这种设备分配方案在重新配置硬件时传统上会导致问题。

例如,假设您有一个带有三个磁盘的系统:/dev/sda、/dev/sdb和/dev/sdc。

如果/dev/sdb发生故障,您必须移除磁盘以使机器恢复工作,以前的/dev/sdc将移动到/dev/sdb,而/dev/sdc将不再存在。

如果您在fstab文件(参见4.2.8节的/etc/fstab文件系统表)中直接引用设备名称,则必须对该文件进行一些更改,以使事情(大部分)恢复正常。

为了解决这个问题,大多数现代Linux系统使用通用唯一标识符(UUID,参见4.2.4节的文件系统UUID)进行持久磁盘设备访问。

This discussion has barely scratched the surface of how to use disks and other storage devices on Linux systems. See Chapter 4 for more information about using disks. Later in this chapter, we’ll examine how SCSI support works in the Linux kernel.

这次讨论只是浅尝辄止地介绍了如何在Linux系统上使用磁盘和其他存储设备。

有关使用磁盘的更多信息,请参见第4章。在本章后面,我们将介绍Linux内核中SCSI支持的工作原理。

3.4.2 CD and DVD Drives: /dev/sr (CD和DVD驱动器:/dev/sr

Linux recognizes most optical storage drives as the SCSI devices /dev/sr0, /dev/sr1, and so on. However, if the drive uses an older interface, it might show up as a PATA device, as discussed below. The /dev/sr* devices are read only, and they are used only for reading from discs. For the write and rewrite capabilities of optical devices, you’ll use the “generic” SCSI devices such as /dev/sg0.

Linux将大多数光学存储驱动器识别为SCSI设备/dev/sr0、/dev/sr1等。

但是,如果驱动器使用较旧的接口,则可能显示为PATA设备,如下所述。/dev/sr* 设备只能用于从光盘中读取数据,是只读的。

对于光学设备的写入和重写功能,您将使用“通用”SCSI设备,如/dev/sg0。

3.4.3 PATA硬盘:/dev/hd*

The Linux block devices /dev/hda, /dev/hdb, /dev/hdc, and /dev/hdd are common on older versions of the Linux kernel and with older hardware. These are fixed assignments based on the master and slave devices on interfaces 0 and 1. At times, you might find a SATA drive recognized as one of these disks. This means that the SATA drive is running in a compatibility mode, which hinders performance. Check your BIOS settings to see if you can switch the SATA controller to its native mode.

Linux块设备/dev/hda、/dev/hdb、/dev/hdc和/dev/hdd在较旧版本的Linux内核和较旧的硬件上很常见。

这些是基于接口0和1上的主设备和从设备的固定分配。

有时,您可能会发现SATA驱动器被识别为其中一个磁盘。

这意味着SATA驱动器正在以兼容模式运行,这会影响性能。

请检查您的BIOS设置,看看是否可以将SATA控制器切换到其本机模式。

3.4.4 终端:/dev/tty*、/dev/pts/*和/dev/tty

Terminals are devices for moving characters between a user process and an I/O device, usually for text output to a terminal screen. The terminal device interface goes back a long way, to the days when terminals were typewriter-based devices.

终端是用于在用户进程和I/O设备之间传输字符的设备,通常用于文本输出到终端屏幕。

终端设备接口可以追溯到很久以前,当时终端是基于打字机的设备。

Pseudoterminal devices are emulated terminals that understand the I/O features of real terminals. But rather than talk to a real piece of hardware, the kernel presents the I/O interface to a piece of software, such as the shell terminal window that you probably type most of your commands into.

伪终端设备是模拟终端,它们了解真实终端的I/O特性。但是,内核不是与真实的硬件交互,而是将I/O接口呈现给软件,例如您可能大部分输入命令的shell终端窗口。

Two common terminal devices are /dev/tty1 (the first virtual console) and /dev/pts/0 (the first pseudoterminal device). The /dev/pts directory itself is a dedicated filesystem

两个常见的终端设备是/dev/tty1(第一个虚拟控制台)和/dev/pts/0(第一个伪终端设备)。/dev/pts目录本身是一个专用的文件系统。

The /dev/tty device is the controlling terminal of the current process. If a program is currently reading from and writing to a terminal, this device is a synonym for that terminal. A process does not need to be attached to a terminal.

/dev/tty设备是当前进程的控制终端。如果程序当前正在从终端读取和写入数据,则该设备是该终端的同义词。进程不需要连接到终端。

Display Modes and Virtual Consoles显示模式和虚拟控制台

Linux has two primary display modes: text mode and an X Window System server (graphics mode, usually via a display manager). Although Linux systems traditionally booted in text mode, most distributions now use kernel parameters and interim graphical display mechanisms (bootsplashes such as plymouth) to completely hide text mode as the system is booting. In such cases, the system switches over to full graphics mode near the end of the boot process.

Linux有两种主要的显示模式:文本模式和X Window系统服务器(图形模式,通常通过显示管理器实现)。

尽管Linux系统传统上是以文本模式启动的,但现在大多数发行版都使用内核参数和临时图形显示机制(如plymouth引导屏幕)来完全隐藏系统启动时的文本模式。

在这种情况下,系统在启动过程的最后阶段切换到完全的图形模式。

Linux supports virtual consoles to multiplex the display. Each virtual console may run in graphics or text mode. When in text mode, you can switch between consoles with an ALT-Function key combination—for example, ALT-F1 takes you to /dev/tty1, ALT-F2 goes to /dev/tty2, and so on. Many of these may be occupied by a getty process running a login prompt, as described in 7.4 getty and login.

Linux支持虚拟控制台来复用显示。每个虚拟控制台可以运行在图形模式或文本模式下。

在文本模式下,你可以使用ALT-Fn键组合在不同的控制台之间切换——例如,ALT-F1带你到/dev/tty1,ALT-F2带你到/dev/tty2,依此类推。其中许多虚拟控制台可能被运行登录提示符的getty进程占用,如7.4小节中所描述的getty和login。

A virtual console used by the X server in graphics mode is slightly different. Rather than getting a virtual console assignment from the init configuration, an X server takes over a free virtual console unless directed to use a specific virtual console. For example, if you have getty processes running on tty1 and tty2, a new X server takes over tty3. In addition, after the X server puts a virtual console into graphics mode, you must normally press a CTRL-ALT-Function key combination to switch to another virtual console instead of the simpler ALT-Function key combination.

图形模式下由X服务器使用的虚拟控制台稍有不同。

X服务器不像在init配置中获取虚拟控制台分配,而是占用一个空闲的虚拟控制台,除非指定使用特定的虚拟控制台。

例如,如果在tty1和tty2上有getty进程运行,新的X服务器将占用tty3。此外,在X服务器将虚拟控制台切换到图形模式后,你通常需要按下CTRL-ALT-Fn键组合来切换到另一个虚拟控制台,而不是简单的ALT-Fn键组合。

The upshot of all of this is that if you want to see your text console after your system boots, press CTRL-ALTF1. To return to the X11 session, press ALT-F2, ALT-F3, and so on, until you get to the X session

总之,如果你想在系统启动后看到文本控制台,请按下CTRL-ALT-F1。

要返回X11会话,请按下ALT-F2、ALT-F3等,直到进入X会话。

If you run into trouble switching consoles due to a malfunctioning input mechanism or some other circumstance, you can try to force the system to change consoles with the chvt command. For example, to switch to tty1, run the following as root:

如果由于输入机制故障或其他情况导致切换控制台出现问题,你可以尝试使用chvt命令强制系统切换控制台。

例如,要切换到tty1,请以root身份运行以下命令:

chvt 1

3.4.5串行端口:/dev/ttyS*

Older RS-232 type and similar serial ports are special terminal devices. You can’t do much on the command line with serial port devices because there are too many settings to worry about, such as baud rate and flow control.

旧的RS-232类型和类似的串行端口是特殊的终端设备。

你无法在命令行上对串口设备进行太多操作,因为有太多的设置需要考虑,如波特率和流控制。

The port known as COM1 on Windows is /dev/ttyS0; COM2 is /dev/ttyS1; and so on. Plug-in USB serial adapters show up with USB and ACM with the names /dev/ttyUSB0, /dev/ttyACM0, /dev/ttyUSB1, /dev/ttyACM1, and so on.

Windows上的COM1端口对应/dev/ttyS0;COM2对应/dev/ttyS1;依此类推。插入的USB串行适配器会显示为/dev/ttyUSB0、/dev/ttyACM0、/dev/ttyUSB1、/dev/ttyACM1等名称。

3.4.6 Parallel Ports: /dev/lp0 and /dev/lp1 (并行端口:/dev/lp0和/dev/lp1)

Representing an interface type that has largely been replaced by USB, the unidirectional parallel port devices /dev/lp0 and /dev/lp1 correspond to LPT1: and LPT2: in Windows. You can send files (such as a file to be printed) directly to a parallel port with the cat command, but you might need to give the printer an extra form feed or reset afterward. A print server such as CUPS is much better at handling interaction with a printer. The bidirectional parallel ports are /dev/parport0 and /dev/parport1.

代表着已经被USB取代的接口类型,单向并行端口设备/dev/lp0和/dev/lp1对应Windows中的LPT1:和LPT2:。

你可以使用cat命令直接将文件(如打印文件)发送到并行端口,但之后可能需要给打印机添加额外的换页符或进行复位操作。

像CUPS这样的打印服务器更擅长处理与打印机的交互。
双向并行端口是/dev/parport0和/dev/parport1。

3.4.7 Audio Devices: /dev/snd/*, /dev/dsp, /dev/audio, and More (音频设备:/dev/snd/*、/dev/dsp、/dev/audio等)

Linux has two sets of audio devices. There are separate devices for the Advanced Linux Sound Architecture (ALSA) system interface and the older Open Sound System (OSS). The ALSA devices are in the /dev/snd directory, but it’s difficult to work with them directly. Linux systems that use ALSA support OSS backwardcompatible devices if the OSS kernel support is currently loaded.

Linux有两套音频设备。ALSA(Advanced Linux Sound Architecture)系统接口和旧的Open Sound System(OSS)各自有独立的设备。

ALSA设备位于/dev/snd目录下,但直接使用它们比较困难。

使用ALSA的Linux系统如果当前加载了OSS内核支持,就支持OSS向后兼容的设备。

Some rudimentary operations are possible with the OSS dsp and audio devices. For example, the computer plays any WAV file that you send to /dev/dsp. However, the hardware may not do what you expect due to frequency mismatches. Furthermore, on most systems, the device is often busy as soon as you log in.

使用OSS的dsp和audio设备可以进行一些基本操作。例如,计算机会播放你发送到/dev/dsp的任何WAV文件。

然而,由于频率不匹配,硬件可能不会按预期工作。

此外,在大多数系统上,一旦你登录,该设备通常会处于忙碌状态。

NOTE
Linux sound is a messy subject due to the many layers involved. We’ve just talked about the kernel-level devices, but typically there are user-space servers such as pulse-audio that manage audio from different sources and act as intermediaries between the sound devices and other userspace processes.

注意
由于涉及到多个层次的复杂性,Linux音频是一个混乱的主题。

我们刚刚讨论了内核级设备,但通常还有用户空间服务器(如pulse-audio)来管理来自不同来源的音频,并充当音频设备和其他用户空间进程之间的中间人。

3.4.8 Creating Device Files 创建设备文件

In modern Linux systems, you do not create your own device files; this is done with devtmpfs and udev (see 3.5 udev). However, it is instructive to see how it was once done, and on a rare occasion, you might need to create a named pipe.

在现代Linux系统中,您不需要自己创建设备文件;这是通过devtmpfs和udev完成的(参见3.5 udev)。然而,了解一下以前是如何完成的,而且在极少数情况下,您可能需要创建一个命名管道。

The mknod command creates one device. You must know the device name as well as its major and minor numbers. For example, creating /dev/sda1 is a matter of using the following command:

mknod命令用于创建一个设备。您必须知道设备名称以及其主要和次要编号。例如,创建/dev/sda1只需使用以下命令:

mknod /dev/sda1 b 8 2

The b 8 2 specifies a block device with a major number 8 and a minor number 2. For character or named pipe devices, use c or p instead of b (omit the major and minor numbers for named pipes).

b 8 2指定了一个主要编号为8,次要编号为2的块设备。

对于字符设备或命名管道设备,使用c或p而不是b(对于命名管道设备,省略主要和次要编号)。

As mentioned earlier, the mknod command is useful only for creating the occasional named pipe. At one time, it was also sometimes useful for creating missing devices in single-user mode during system recovery

正如前面提到的,mknod命令只用于创建偶尔需要的命名管道。

曾经,在系统恢复期间的单用户模式下,它有时也用于创建丢失的设备。

In older versions of Unix and Linux, maintaining the /dev directory was a challenge. With every significant kernel upgrade or driver addition, the kernel could support more kinds of devices, meaning that there would be a new set of major and minor numbers to be assigned to device filenames. Maintaining this was difficult, so each system had a MAKEDEV program in /dev to create groups of devices. When you upgraded your system, you would try to find an update to MAKEDEV and then run it in order to create new devices.

在旧版本的Unix和Linux中,维护/dev目录是一项挑战。

随着每次重要的内核升级或驱动程序添加,内核可以支持更多类型的设备,这意味着将有一组新的主要和次要编号分配给设备文件名。

维护这一点很困难,因此每个系统都有一个位于/dev中的MAKEDEV程序来创建设备组。

当您升级系统时,您会尝试找到一个更新的MAKEDEV并运行它以创建新设备。

This static system became ungainly, so a replacement was in order. The first attempt to fix it was devfs, a kernel-space implementation of /dev that contained all of the devices that the current kernel supported. However, there were a number of limitations, which led to the development of udev and devtmpfs.

这个静态系统变得笨重,所以需要一个替代品。首次尝试修复它的是devfs,它是一个包含当前内核支持的所有设备的内核空间实现的/dev。

然而,存在一些限制,这导致了udev和devtmpfs的开发。

3.5 udev

We’ve already talked about how unnecessary complexity in the kernel is dangerous because you can too easily introduce system instability. Device file management is an example: You can create device files in user space, so why would you do this in the kernel? The Linux kernel can send notifications to a user-space process (called udevd) upon detecting a new device on the system (for example, when someone attaches a USB flash drive). The user-space process on the other end examines the new device’s characteristics, creates a device file, and then performs any device initialization.

我们已经谈过内核中不必要的复杂性是危险的,因为这样很容易引入系统不稳定性。

设备文件管理就是一个例子:你可以在用户空间创建设备文件,那为什么要在内核中这样做呢?

Linux内核可以在检测到系统上有新设备时(例如,当有人插入USB闪存驱动器时),向用户空间进程(称为udevd)发送通知。

另一端的用户空间进程会检查新设备的特性,创建设备文件,然后执行任何设备初始化工作。

这是理论。

不幸的是,在实践中,这种方法存在一个问题——设备文件在引导过程的早期是必需的,所以udevd必须尽早启动。

为了创建设备文件,udevd不能依赖于它应该创建的任何设备,并且它需要非常快速地进行初始启动,以便系统的其余部分不会因为等待udevd启动而被阻塞。

3.5.1 devtmpfs

The devtmpfs filesystem was developed in response to the problem of device availability during boot (see 4.2 Filesystems for more details on filesystems). This filesystem is similar to the older devfs support, but it’s simplified. The kernel creates device files as necessary, but it also notifies udevd that a new device is available. Upon receiving this signal, udevd does not create the device files, but it does perform device initialization and process notification. Additionally, it creates a number of symbolic links in /dev to further identify devices. You can find examples in the directory /dev/disk/by-id, where each attached disk has one or more entries.

devtmpfs文件系统是为了解决引导过程中设备可用性的问题而开发的(有关文件系统的更多细节,请参见4.2)。

这个文件系统类似于较旧的devfs支持,但更简化。

内核根据需要创建设备文件,但同时也通知udevd有新设备可用。

在接收到此信号后,udevd不会创建设备文件,但会执行设备初始化和进程通知。

此外,它还在/dev目录下创建了一些符号链接,以进一步标识设备。

你可以在目录/dev/disk/by-id中找到示例,其中每个连接的磁盘都有一个或多个条目。

For example, consider this typical disk:

例如,考虑以下典型的磁盘:

lrwxrwxrwx 1 root root 9 Jul 26 10:23 scsi-SATA_WDC_WD3200AAJS-_WDWMAV2FU80671 -> ../../sda
lrwxrwxrwx 1 root root 10 Jul 26 10:23 scsi-SATA_WDC_WD3200AAJS-_WDWMAV2FU80671-part1 ->
 ../../sda1
lrwxrwxrwx 1 root root 10 Jul 26 10:23 scsi-SATA_WDC_WD3200AAJS-_WDWMAV2FU80671-part2 ->
 ../../sda2
lrwxrwxrwx 1 root root 10 Jul 26 10:23 scsi-SATA_WDC_WD3200AAJS-_WDWMAV2FU80671-part5 ->
 ../../sda5

udevd names the links by interface type, and then by manufacturer and model information, serial number, and partition (if applicable).

udevd根据接口类型、制造商和型号信息、序列号以及分区(如果适用)来命名链接。

But how does udevd know which symbolic links to create, and how does it create them? The next section describes how udevd does its work. However, you don’t need to know that to continue on with the book. In fact, if this is your first time looking at Linux devices, you’re encouraged to move to the next chapter to start learning about how to use disks.

但是,udevd如何知道要创建哪些符号链接,以及它如何创建它们?下一节将介绍udevd的工作原理。

但是,您不需要了解这一点就可以继续阅读本书。

实际上,如果这是您第一次接触Linux设备,我们鼓励您转到下一章开始学习如何使用磁盘。

3.5.2 udevd Operation and Configuration(udevd操作和配置)

The udevd daemon operates as follows:

udev守护进程的操作如下:

  1. The kernel sends udevd a notification event, called a uevent, through an internal network link.
  2. udevd loads all of the attributes in the uevent.
  3. udevd parses its rules, and it takes actions or sets more attributes based on those rules.
  4. 内核通过内部网络链接向udev发送一个名为uevent的通知事件。
  5. udev加载uevent中的所有属性。
  6. udev解析其规则,并根据这些规则执行操作或设置更多属性。

An incoming uevent that udevd receives from the kernel might look like this:

udev从内核接收到的一个传入的uevent可能如下所示:

ACTION=change
DEVNAME=sde
DEVPATH=/devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.2/1-
1.2:1.0/host4/
 target4:0:0/4:0:0:3/block/sde
DEVTYPE=disk
DISK_MEDIA_CHANGE=1
MAJOR=8
MINOR=64
SEQNUM=2752
SUBSYSTEM=block
UDEV_LOG=3

You can see here that there is a change to a device. After receiving the uevent, udevd knows the sysfs device path and a number of other attributes associated with the properties, and it is now ready to start processing rules.

您可以在这里看到设备的更改。在接收到uevent后,udev已经知道了sysfs设备路径以及与属性相关的其他属性,现在准备开始处理规则。

The rules files are in the /lib/udev/rules.d and /etc/udev/rules.d directories. The rules in /lib are the defaults, and the rules in /etc are overrides. A full explanation of the rules would be tedious, and you can learn much more from the udev(7) manual page, but let’s look at the symbolic links from the /dev/sda example in 3.5.1 devtmpfs. Those links were defined by rules in /lib/udev/rules.d/60-persistent-storage.rules. Inside, you’ll see the following lines:

规则文件位于/lib/udev/rules.d和/etc/udev/rules.d目录中。

/lib中的规则是默认规则,而/etc中的规则是覆盖规则。

对规则的完整解释会很冗长,您可以从udev(7)手册页中了解更多信息,但让我们来看看3.5.1 devtmpfs中/dev/sda示例中的符号链接。

这些链接是由/lib/udev/rules.d/60-persistent-storage.rules中的规则定义的。在其中,您会看到以下行:

# ATA devices using the "scsi" subsystem
KERNEL=="sd*[!0-9]|sr*", ENV{ID_SERIAL}!="?*", SUBSYSTEMS=="scsi", 
ATTRS{vendor}=="ATA",
 IMPORT{program}="ata_id --export $tempnode"
 
# ATA/ATAPI devices (SPC-3 or later) using the "scsi" subsystem
KERNEL=="sd*[!0-9]|sr*", ENV{ID_SERIAL}!="?*", SUBSYSTEMS=="scsi",
 ATTRS{type}=="5", ATTRS{scsi_level}=="[6-9]*", 
IMPORT{program}="ata_id --export $tempnode"

These rules match ATA disks presented through the kernel’s SCSI subsystem (see 3.6 In-Depth: SCSI and the Linux Kernel). You can see that there are a few rules to catch different ways that the devices may be represented, but the idea is that udevd will try to match a device starting with sd or sr but without a number (with the KERNEL=="sd[!0-9]|sr" expression), as well as a subsystem (SUBSYSTEMS=="scsi"), and finally, some other attributes. If all of those conditional expressions are true, udevd moves to the next expression:

这些规则适用于通过内核的SCSI子系统(参见3.6深入解析:SCSI和Linux内核)呈现的ATA硬盘。

你可以看到,有一些规则可以捕捉设备可能被表示的不同方式,但是思路是udev将尝试匹配以sd或sr开头但没有数字(使用KERNEL=="sd[!0-9]|sr"表达式),以及一个子系统(SUBSYSTEMS=="scsi"),最后是一些其他属性。

如果所有这些条件表达式都为真,udev将移至下一个表达式:

IMPORT{program}="ata_id --export $tempnode"

This is not a conditional, but rather, a directive to import variables from the /lib/udev/ata_id command. If you have such a disk, try it yourself on the command line:

这不是一个条件语句,而是一个指令,用于从/lib/udev/ata_id命令中导入变量。

如果你有这样的磁盘,请在命令行上自行尝试。

sudo /lib/udev/ata_id --export /dev/sda

ID_ATA=1
ID_TYPE=disk
ID_BUS=ata
ID_MODEL=WDC_WD3200AAJS-22L7A0
ID_MODEL_ENC=WDC\x20WD3200AAJS22L7A0\x20\x20\x20\x20\x20\x20\x20\x20\x
20\x20
 \x20\x20\x20\x20\x20\x20\x20\x20\x20
ID_REVISION=01.03E10
ID_SERIAL=WDC_WD3200AAJS-22L7A0_WD-WMAV2FU80671
--snip--

The import now sets the environment so that all of the variable names in this output are set to the values shown. For example, any rule that follows will now recognize ENV{ID_TYPE} as disk.

现在导入设置环境,以便此输出中的所有变量名称都设置为所示的值。

例如,任何随后的规则现在都将识别ENV{ID_TYPE}为disk。

Of particular note is ID_SERIAL. In each of the rules, this conditional appears second:

特别需要注意的是ID_SERIAL。

在每个规则中,此条件出现在第二位:

ENV{ID_SERIAL}!="?*"

This means that ID_SERIAL is true only if is not set. Therefore, if it is set, the conditional is false, the entire current rule is false, and udevd moves to the next rule.

这意味着只有在ID_SERIAL未设置时才为真。

因此,如果它被设置了,条件就为假,整个当前规则也为假,udev进程就会转到下一个规则。

So what’s the point? The object of these two rules (and many around them in the file) is to find the serial number of the disk device. With ENV{ID_SERIAL} set, udevd can now evaluate this rule:

那么,这有什么意义呢?这两个规则(以及文件中的其他许多规则)的目的是找到磁盘设备的序列号。

当ENV{ID_SERIAL}被设置后,udev进程现在可以评估这个规则了。

KERNEL=="sd*|sr*|cciss*", ENV{DEVTYPE}=="disk", ENV{ID_SERIAL}=="?*",
 SYMLINK+="disk/by-id/$env{ID_BUS}-$env{ID_SERIAL}"

You can see that this rule requires ENV{ID_SERIAL} to be set, and it has one directive:

您可以看到,该规则要求设置 ENV{ID_SERIAL},并且有一条指令:

SYMLINK+="disk/by-id/$env{ID_BUS}-$env{ID_SERIAL}"

Upon encountering this directive, udevd adds a symbolic link for the incoming device. So now you know where the device symbolic links came from!

在遇到这个指令时,udev会为即将到来的设备添加一个符号链接。

现在你知道设备符号链接是从哪里来的了!

You may be wondering how to tell a conditional expression from a directive. Conditionals are denoted by two equal signs (\=\=) or a bang equal (!=), and directives by a single equal sign (=), a plus equal (+=), or a colon equal (:=).

你可能会想知道如何区分条件表达式和指令。条件表达式用两个等号(\=\=)或一个不等号(!=)表示,而指令用一个等号(=)、一个加等号(+=)或一个冒号等号(:=)表示。

3.5.3 udevadm

The udevadm program is an administration tool for udevd. You can reload udevd rules and trigger events, but perhaps the most powerful features of udevadm are the ability to search for and explore system devices and the ability to monitor uevents as udevd receives them from the kernel. The only trick is that the command syntax can get a bit involved.

udevadm程序是udev的管理工具。

您可以重新加载udev规则和触发事件,但是udevadm最强大的功能可能是搜索和探索系统设备以及监视udev从内核接收到的uevents。

唯一的问题是命令语法可能会有些复杂。

Let’s start by examining a system device. Returning to the example in 3.5.2 udevd Operation and Configuration, in order to look at all of the udev attributes used and generated in conjunction with the rules for a device such as /dev/sda, run the following command:

让我们从检查一个系统设备开始。

回到3.5.2 udevd操作和配置中的示例,为了查看与设备(如/dev/sda)的规则相关的所有udev属性的使用和生成情况,请运行以下命令:

$ udevadm info --query=all –-name=/dev/sda

The output looks like this:

输出结果如下

P: 
/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda
N: sda
S: disk/by-id/ata-WDC_WD3200AAJS-22L7A0_WD-WMAV2FU80671
S: disk/by-id/scsi-SATA_WDC_WD3200AAJS-_WD-WMAV2FU80671
S: disk/by-id/wwn-0x50014ee057faef84 S: disk/by-path/pci-0000:00:1f.2-
scsi-0:0:0:0
E: DEVLINKS=/dev/disk/by-id/ata-WDC_WD3200AAJS-22L7A0_WD-WMAV2FU80671 
/dev/disk/by-id/scsi
 -SATA_WDC_WD3200AAJS-_WD-WMAV2FU80671 /dev/disk/by-id/wwn-
0x50014ee057faef84 /dev/disk/by
 -path/pci-0000:00:1f.2-scsi-0:0:0:0
E: DEVNAME=/dev/sda
E: 
DEVPATH=/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/blo
ck/sda
E: DEVTYPE=disk
E: ID_ATA=1
E: ID_ATA_DOWNLOAD_MICROCODE=1
E: ID_ATA_FEATURE_SET_AAM=1
--snip--

The prefix in each line indicates an attribute or other characteristic of the device. In this case, the P: at the top is the sysfs device path, the N: is the device node (that is, the name given to the /dev file), S: indicates a symbolic link to the device node that udevd placed in /dev according to its rules, and E: is additional device information extracted in the udevd rules. (There was far more output in this example than was necessary to show here; try the command for yourself to get a feel for what it does.)

每行的前缀表示设备的属性或其他特征。在本例中,顶部的P:是sysfs设备路径,N:是设备节点(即给定的/dev文件的名称),S:表示udev根据其规则放置在/dev中的设备节点的符号链接,而E:是udev规则中提取的附加设备信息。(这个示例中的输出远远超过了需要展示的内容;请自行尝试该命令,以了解其功能。)

3.5.4 Monitoring Devices(监控设备)

To monitor uevents with udevadm, use the monitor command:

要使用 udevadm 监控 uevents,请使用 monitor 命令:

$ udevadm monitor

Output (for example, when you insert a flash media device) looks like this abbreviated sample:

输出(例如,当您插入闪存媒体设备时)看起来像下面这个简短的示例:

KERNEL[658299.569485] add /devices/pci0000:00/0000:00:1d.0/usb2/2-
1/2-1.2 (usb)
KERNEL[658299.569667] add /devices/pci0000:00/0000:00:1d.0/usb2/2-
1/2-1.2/2-1.2:1.0 (usb)
KERNEL[658299.570614] add /devices/pci0000:00/0000:00:1d.0/usb2/2-
1/2-1.2/2-1.2:1.0/host15
 (scsi)
KERNEL[658299.570645] add /devices/pci0000:00/0000:00:1d.0/usb2/2-
1/2-1.2/2-1.2:1.0/
 host15/scsi_host/host15 (scsi_host)
UDEV [658299.622579] add /devices/pci0000:00/0000:00:1d.0/usb2/2-
1/2-1.2 (usb)
UDEV [658299.623014] add /devices/pci0000:00/0000:00:1d.0/usb2/2-
1/2-1.2/2-1.2:1.0 (usb)
UDEV [658299.623673] add /devices/pci0000:00/0000:00:1d.0/usb2/2-
1/2-1.2/2-1.2:1.0/host15
 (scsi)
UDEV [658299.623690] add /devices/pci0000:00/0000:00:1d.0/usb2/2-
1/2-1.2/2-1.2:1.0/
 host15/scsi_host/host15 (scsi_host)
--snip--

There are two copies of each message in this output because the default behavior is to print both the incoming message from the kernel (marked with KERNEL) and the message that udevd sends out to other programs when it’s finished processing and filtering the event. To see only kernel events, add the --kernel option, and to see only outgoing events, use --udev. To see the whole incoming uevent, including the attributes as shown in 3.5.2 udevd Operation and Configuration, use the --property option.

这个输出中每条消息都有两份副本,因为默认行为是同时打印内核发出的消息(标记为KERNEL)和udev完成处理和过滤事件后发送给其他程序的消息。

如果只想看到内核事件,可以添加--kernel选项;

如果只想看到输出事件,可以使用--udev选项;

如果想要看到完整的入站uevent,包括3.5.2节udev操作和配置中所示的属性,请使用--property选项。

You can also filter events by subsystem. For example, to see only kernel messages pertaining to changes in the SCSI subsystem, use this command:

还可以按子系统筛选事件。例如,要只看到与SCSI子系统更改相关的内核消息,请使用以下命令:


$ udevadm monitor --kernel --subsystem-match=scsi

For more on udevadm, see the udevadm(8) manual page.

有关udevadm的更多信息,请参阅udevadm(8)手册页。

There’s much more to udev. For example, the D-Bus system for interprocess communication has a daemon called udisks-daemon that listens to the outgoing udevd events in order to automatically attach disks and to further notify other desktop software that a new disk is now available.

udev还有更多功能。

例如,用于进程间通信的D-Bus系统有一个名为udisks-daemon的守护进程,它监听出站的udev事件,以自动挂载磁盘并进一步通知其他桌面软件新磁盘已可用。

3.6 In-Depth: SCSI and the Linux Kernel(深入解析:SCSI和Linux内核)

In this section, we’ll take a look at the SCSI support in the Linux kernel as a way to explore part of the Linux kernel architecture. You don’t need to know any of this information in order to use disks, so if you’re in a hurry to use one, move on to Chapter 4. In addition, the material here is more advanced and theoretical in nature that what you’ve seen so far, so if you want to stay hands-on, you should definitely skip to the next chapter.

在本节中,我们将以Linux内核中的SCSI支持为例,探索Linux内核架构的一部分。

您不需要了解这些信息就能使用磁盘,所以如果您急于使用磁盘,请继续阅读第4章。

此外,这里的内容更加高级和理论化,如果您想保持实践操作,请务必跳到下一章节。

Let’s begin with a little background. The traditional SCSI hardware setup is a host adapter linked with a chain of devices over an SCSI bus, as shown in Figure 3-1. The host adapter is attached to a computer. The host adapter and devices each have an SCSI ID, and there can be 8 or 16 IDs per bus, depending on the SCSI version. You might hear the term SCSI target used to refer to a device and its SCSI ID.

让我们从一些背景知识开始。

传统的SCSI硬件设置是一个与SCSI总线上的设备链路相连的主机适配器,如图3-1所示。

主机适配器连接到计算机。

主机适配器和设备都有一个SCSI ID,每个总线上可以有8个或16个ID,具体取决于SCSI版本。

您可能会听到SCSI目标这个术语,用于指代设备及其SCSI ID。

Figure 3-1. SCSI Bus with host adapter and devices

Figure 3-1. SCSI Bus with host adapter and devices

The host adapter communicates with the devices through the SCSI command set in a peer-to-peer relationship; the devices send responses back to the host adapter. The computer is not directly attached to the device chain, so it must go through the host adapter in order to communicate with disks and other devices. Typically, the computer sends SCSI commands to the host adapter to relay to the devices, and the devices relay responses back through the host adapter.

主机适配器通过SCSI命令集与设备进行点对点的通信;设备将响应发送回主机适配器。

计算机并没有直接连接到设备链上,因此必须通过主机适配器与磁盘和其他设备进行通信。

通常情况下,计算机会将SCSI命令发送给主机适配器,再由主机适配器转发给设备,并将设备的响应通过主机适配器传回。

Newer versions of SCSI, such as Serial Attached SCSI (SAS), offer exceptional performance, but you probably won’t find true SCSI devices in most machines. You’ll more often encounter USB storage devices that use SCSI commands. In addition, devices supporting ATAPI (such as CD/DVD-ROM drives) use a version of the SCSI command set

较新版本的SCSI,如串行连接SCSI(SAS),提供了出色的性能,但在大多数机器上你可能找不到真正的SCSI设备。你更常见的是遇到使用SCSI命令的USB存储设备。

此外,支持ATAPI的设备(如CD/DVD-ROM驱动器)使用了SCSI命令集的一个版本。

SATA disks also appear on your system as SCSI devices by means of a translation layer in libata (see 3.6.2 SCSI and ATA). Some SATA controllers (especially high-performance RAID controllers) perform this translation in hardware.

通过libata中的翻译层,SATA硬盘也会以SCSI设备的形式显示在系统中(参见3.6.2节SCSI和ATA)。

一些SATA控制器(尤其是高性能RAID控制器)会在硬件中执行这种翻译。

How does this all fit together? Consider the devices shown on the following system:

这一切是如何组合在一起的呢?请考虑以下系统上显示的设备:

$ lsscsi
[0:0:0:0] disk ATA WDC WD3200AAJS-2 01.0 /dev/sda
[1:0:0:0] cd/dvd Slimtype DVD A DS8A5SH XA15 /dev/sr0
[2:0:0:0] disk USB2.0 CardReader CF 0100 /dev/sdb
[2:0:0:1] disk USB2.0 CardReader SM XD 0100 /dev/sdc
[2:0:0:2] disk USB2.0 CardReader MS 0100 /dev/sdd
[2:0:0:3] disk USB2.0 CardReader SD 0100 /dev/sde
[3:0:0:0] disk FLASH Drive UT_USB20 0.00 /dev/sdf

The numbers in brackets are, from left to right, the SCSI host adapter number, the SCSI bus number, the device SCSI ID, and the LUN (logical unit number, a further subdivision of a device). In this example, there are four attached adapters (scsi0, scsi1, scsi2, and scsi3), each of which has a single bus (all with bus number 0), and just one device on each bus (all with target 0). The USB card reader at 2:0:0 has four logical units, though— one for each kind of flash card that can be inserted. The kernel has assigned a different device file to each logical unit.

方括号中的数字,从左到右依次表示SCSI主机适配器编号、SCSI总线编号、设备SCSI ID和LUN(逻辑单元号,设备的进一步细分)。

在这个例子中,有四个连接的适配器(scsi0、scsi1、scsi2和scsi3),每个适配器都有一个总线(都是总线编号0),每个总线上只有一个设备(都是目标0)。

然而,2:0:0的USB读卡器有四个逻辑单元,分别对应可以插入的四种闪存卡。内核为每个逻辑单元分配了不同的设备文件。

Figure 3-2 illustrates the driver and interface hierarchy inside the kernel for this particular system configuration, from the individual device drivers up to the block drivers. It does not include the SCSI generic (sg) drivers.

图3-2展示了内核中该特定系统配置的驱动程序和接口层次结构,从个别设备驱动程序到块驱动程序。

其中不包括SCSI通用(sg)驱动程序。

Figure 3-2. Linux SCSI subsystem schematic

Figure 3-2. Linux SCSI subsystem schematic

Although this is a large structure and may look overwhelming at first, the data flow in the figure is very linear. Let’s begin dissecting it by looking at the SCSI subsystem and its three layers of drivers:

虽然这是一个庞大的结构,初看可能让人不知所措,但图中的数据流是非常线性的。

让我们从 SCSI 子系统及其三层驱动程序开始剖析:

让我们开始解析它,首先看一下SCSI子系统及其三层驱动程序:

o The top layer handles operations for a class of device. For example, the sd (SCSI disk) driver is at this layer; it knows how to translate requests from the kernel block device interface into disk-specific commands in the SCSI protocol, and vice versa.
o The middle layer moderates and routes the SCSI messages between the top and bottom layers, and keeps track of all of the SCSI buses and devices attached to the system.
o The bottom layer handles hardware-specific actions. The drivers here send outgoing SCSI protocol messages to specific host adapters or hardware, and they extract incoming messages from the hardware. The reason for this separation from the top layer is that although SCSI messages are uniform for a device class (such as the disk class), different kinds of host adapters have varying procedures for sending the same messages.

  • 顶层处理一类设备的操作。例如,sd(SCSI磁盘)驱动程序位于此层;它知道如何将内核块设备接口的请求转换为SCSI协议中特定于磁盘的命令,反之亦然。
  • 中间层在顶层和底层之间进行调节和路由SCSI消息,并跟踪连接到系统的所有SCSI总线和设备。
  • 底层处理硬件特定的操作。这里的驱动程序将传出的SCSI协议消息发送到特定的主机适配器或硬件,并从硬件中提取传入的消息。之所以将其与顶层分开,是因为尽管SCSI消息对于设备类别(例如磁盘类别)是统一的,但不同类型的主机适配器在发送相同消息时有不同的过程。

The top and bottom layers contain many different drivers, but it’s important to remember that, for any given device file on your system, the kernel uses one top-layer driver and one lower-layer driver. For the disk at /dev/sda in our example, the kernel uses the sd top-layer driver and the ATA bridge lower-layer driver

顶层和底层包含许多不同的驱动程序,但重要的是要记住,在系统中的任何给定设备文件上,内核使用一个顶层驱动程序和一个底层驱动程序。

例如,在我们的示例中,对于/dev/sda上的磁盘,内核使用sd顶层驱动程序和ATA桥底层驱动程序。

There are times when you might use more than one upper-layer driver for one hardware device (see 3.6.3 Generic SCSI Devices). For true hardware SCSI devices, such as a disk attached to an SCSI host adapter or a hardware RAID controller, the lower-layer drivers talk directly to the hardware below. However, for most hardware that you find attached to the SCSI subsystem, it’s a different story.

有时,您可能会为一个硬件设备使用多个上层驱动程序(请参见3.6.3通用SCSI设备)。

对于真正的硬件SCSI设备,例如连接到SCSI主机适配器或硬件RAID控制器的磁盘,底层驱动程序直接与底层硬件通信。

然而,对于大多数连接到SCSI子系统的硬件而言,情况有所不同。

3.6.1 USB Storage and SCSI(USB存储和SCSI)

In order for the SCSI subsystem to talk to common USB storage hardware, as shown in Figure 3-2, the kernel needs more than just a lower-layer SCSI driver. The USB flash drive represented by /dev/sdf understands SCSI commands, but to actually communicate with the drive, the kernel needs to know how to talk through the USB system.

为了使SCSI子系统能够与常见的USB存储硬件进行通信(如图3-2所示),内核需要的不仅仅是一个底层SCSI驱动程序。

由/dev/sdf表示的USB闪存驱动器理解SCSI命令,但为了实际与驱动器通信,内核需要知道如何通过USB系统进行通信。

In the abstract, USB is quite similar to SCSI—it has device classes, buses, and host controllers. Therefore, it should be no surprise that the Linux kernel includes a three-layer USB subsystem that closely resembles the SCSI subsystem, with device-class drivers at the top, a bus management core in the middle, and host controller drivers at the bottom. Much as the SCSI subsystem passes SCSI commands between its components, the USB subsystem passes USB messages between its components. There’s even an lsusb command that is similar to lsscsi.

从抽象的角度来看,USB与SCSI非常相似——它有设备类、总线和主机控制器。

因此,Linux内核包括一个与SCSI子系统非常相似的三层USB子系统,顶部是设备类驱动程序,中间是总线管理核心,底部是主机控制器驱动程序。

与SCSI子系统在其组件之间传递SCSI命令类似,USB子系统在其组件之间传递USB消息。

甚至有一个类似于lsscsi的lsusb命令。

The part we’re really interested in here is the USB storage driver at the top. This driver acts as a translator. On one side, the driver speaks SCSI, and on the other, it speaks USB. Because the storage hardware includes SCSI commands inside its USB messages, the driver has a relatively easy job: It mostly repackages data.

我们在这里真正感兴趣的部分是顶部的USB存储驱动程序。

该驱动程序充当一个翻译器。

在一侧,驱动程序使用SCSI,而在另一侧,它使用USB。

由于存储硬件在其USB消息中包含SCSI命令,所以驱动程序的工作相对容易:它主要是重新包装数据。

With both the SCSI and USB subsystems in place, you have almost everything you need to talk to the flash drive. The final missing link is the lower-layer driver in the SCSI subsystem because the USB storage driver is a part of the USB subsystem, not the SCSI subsystem. (For organizational reasons, the two subsystems should not share a driver.) To get the subsystems to talk to one another, a simple, lower-layer SCSI bridge driver connects to the USB subsystem’s storage driver.

安装了SCSI和USB子系统后,你几乎拥有与闪存驱动器进行通信所需的一切。

最后缺失的环节是SCSI子系统中的底层驱动程序,因为USB存储驱动程序属于USB子系统,而不属于SCSI子系统。

(出于组织原因,这两个子系统不应共享一个驱动程序。)

为了使这两个子系统进行通信,一个简单的底层SCSI桥接驱动程序连接到USB子系统的存储驱动程序上。

3.6.2 SCSI and ATA(SCSI和ATA)

The SATA hard disk and optical drive shown in Figure 3-2 both use the same SATA interface. To connect the SATA-specific drivers of the kernel to the SCSI subsystem, the kernel employs a bridge driver, as with the USB drives, but with a different mechanism and additional complications. The optical drive speaks ATAPI, a version of SCSI commands encoded in the ATA protocol. However, the hard disk does not use ATAPI and does not encode any SCSI commands!

图3-2中显示的SATA硬盘和光驱都使用相同的SATA接口。

为了将内核的SATA特定驱动程序连接到SCSI子系统,内核使用了一个桥接驱动程序,与USB驱动器类似,但机制不同且有额外的复杂性。

光驱使用ATAPI,这是一种编码在ATA协议中的SCSI命令版本。

然而,硬盘不使用ATAPI,也不编码任何SCSI命令!

The Linux kernel uses part of a library called libata to reconcile SATA (and ATA) drives with the SCSI subsystem. For the ATAPI-speaking optical drives, this is a relatively simple task of packaging and extracting SCSI commands into and from the ATA protocol. But for the hard disk, the task is much more complicated because the library must do a full command translation.

Linux内核使用名为libata的库的一部分来将SATA(和ATA)驱动器与SCSI子系统协调。

对于使用ATAPI的光驱来说,这是一个相对简单的任务,将SCSI命令打包并从ATA协议中提取出来。

但对于硬盘来说,任务要复杂得多,因为库必须进行完整的命令转换。

The job of the optical drive is similar to typing an English book into a computer. You don’t need to understand what the book is about in order to do this job, nor do you even need to understand English. But the task for the hard disk is more like reading a German book and typing it into the computer as an English translation. In this case, you need to understand both languages as well as the book’s content.

光驱的工作类似于将一本英文书打字输入到计算机中。

你不需要理解这本书的内容来完成这项工作,甚至不需要理解英语。

但对于硬盘来说,任务更像是阅读一本德文书并将其作为英文翻译输入到计算机中。

在这种情况下,你需要理解两种语言以及书的内容。

Despite this difficulty, libata performs this task and makes it possible to attach the SCSI subsystem to ATA/SATA interfaces and devices. (There are typically more drivers involved than just the one SATA host driver shown in Figure 3-2, but they’re not shown for the sake of simplicity.)

尽管存在这个困难,libata完成了这个任务,并使得将SCSI子系统连接到ATA/SATA接口和设备成为可能。(通常涉及的驱动程序不仅仅是图3-2中显示的一个SATA主机驱动程序,但出于简单起见,它们没有显示出来。)

3.6.3 Generic SCSI Devices(通用SCSI设备)

When a user-space process communicates with the SCSI subsystem, it normally does so through the block device layer and/or another other kernel service that sits on top of an SCSI device class driver (like sd or sr). In other words, most user processes never need to know anything about SCSI devices or their commands.

当用户空间进程与SCSI子系统通信时,通常通过块设备层和/或其他在SCSI设备类驱动程序(如sd或sr)之上的内核服务来进行。

换句话说,大多数用户进程不需要了解SCSI设备或其命令。

However, user processes can bypass device class drivers and give SCSI protocol commands directly to devices through their generic devices. For example, consider the system described in 3.6 In-Depth: SCSI and the Linux Kernel, but this time, take a look at what happens when you add the -g option to lsscsi in order to show the generic devices:

然而,用户进程可以绕过设备类驱动程序,通过它们的通用设备直接向设备发送SCSI协议命令。

例如,考虑3.6节中深入解析:SCSI和Linux内核中描述的系统,但这次,在使用lsscsi命令时添加-g选项以显示通用设备时,看看会发生什么:

$ lsscsi -g
[0:0:0:0] disk ATA WDC WD3200AAJS-2 01.0 /dev/sda ➊/dev/sg0
[1:0:0:0] cd/dvd Slimtype DVD A DS8A5SH XA15 /dev/sr0 /dev/sg1
[2:0:0:0] disk USB2.0 CardReader CF 0100 /dev/sdb /dev/sg2
[2:0:0:1] disk USB2.0 CardReader SM XD 0100 /dev/sdc /dev/sg3
[2:0:0:2] disk USB2.0 CardReader MS 0100 /dev/sdd /dev/sg4
[2:0:0:3] disk USB2.0 CardReader SD 0100 /dev/sde /dev/sg5
[3:0:0:0] disk FLASH Drive UT_USB20 0.00 /dev/sdf /dev/sg6

In addition to the usual block device file, each entry lists an SCSI generic device file in the last column at ➊.
For example, the generic device for the optical drive at /dev/sr0 is /dev/sg1.

除了常规的块设备文件外,每个条目还在➊ 的最后一列列出 SCSI 通用设备文件。

例如,位于 /dev/sr0 的光驱的通用设备是 /dev/sg1。

Why would you want to use an SCSI generic device? The answer has to do with the complexity of code in the kernel. As tasks get more complicated, it’s better to leave them out of the kernel. Consider CD/DVD writing and reading. Not only is writing significantly more difficult than reading, but no critical system services depend on the action of writing. A user-space program might do the writing a little more inefficiently than a kernel service, but that program will be far easier to build and maintain than a kernel service, and bugs will not threaten kernel space. Therefore, to write to an optical disc in Linux, you run a program that talks to a generic SCSI device, such as /dev/sg1. Due to the relative simplicity of reading compared to writing, however, you still read from the device using the specialized sr optical device driver in the kernel.

为什么要使用SCSI通用设备呢?答案与内核中的代码复杂性有关。

随着任务变得更加复杂,最好将它们从内核中排除。

以CD/DVD的写入和读取为例。写入不仅比读取困难得多,而且没有任何关键的系统服务依赖于写入操作。

用户空间程序可能比内核服务稍微低效地进行写入,但该程序构建和维护起来要比内核服务简单得多,并且不会威胁到内核空间的稳定性。

因此,在Linux中写入光盘时,您需要运行一个与通用SCSI设备(例如/dev/sg1)通信的程序。然而,由于相对于写入而言读取相对简单,因此仍然需要使用内核中的专用sr光学设备驱动程序从设备中读取。

3.6.4 Multiple Access Methods for a Single Device(单个设备的多重访问方法)

The two points of access (sr and sg) for an optical drive from user space are illustrated for the Linux SCSI subsystem in Figure 3-3 (any drivers below the SCSI lower layer have been omitted). Process A reads from the drive using the sr driver, and process B writes to the drive with the sg driver. However, processes such as these two would not normally run simultaneously to access the same device.

图3-3展示了Linux SCSI子系统中用户空间对光驱的两个访问点(sr和sg)。

图中省略了SCSI下层的任何驱动程序。

进程A使用sr驱动程序从驱动器中读取数据,而进程B使用sg驱动程序向驱动器中写入数据。然而,这两个进程通常不会同时运行以访问同一设备。

Figure 3-3. Optical device driver schematic

Figure 3-3. Optical device driver schematic

In Figure 3-3, process A reads from the block device. But do user processes really read data this way? Normally, the answer is no, not directly. There are more layers on top of the block devices and even more points of access for hard disks, as you’ll learn in the next chapter.

在图3-3中,进程A从块设备中读取数据。

但是用户进程真的是以这种方式读取数据吗?通常情况下,答案是否定的,不是直接地。

在块设备之上还有更多的层次,甚至硬盘的访问点也更多,这些你将在下一章中学到。


Xander
195 声望50 粉丝