章節概覽#

本章介紹 Linux kernel 提供的裝置基礎設施 (device infrastructure)。內容涵蓋傳統的裝置檔案系統 (device files)、kernel 如何透過 sysfs 提供裝置設定資訊、dd 工具的使用、常見裝置命名慣例、udev 系統的運作方式,以及 SCSI 子系統在 Linux kernel 中的角色。

目標是讓讀者能夠從系統中提取裝置資訊,並理解基本的裝置操作原理。


3.1 Device Files(裝置檔案)#

Linux kernel 將大部分裝置的 I/O 介面以檔案的形式呈現給 user-space processes,這些檔案稱為 device files(也叫 device nodes)。裝置檔案位於 /dev 目錄下。

例如,將輸出導向 /dev/null 時,kernel 會繞過一般的檔案操作,改用 device driver 處理資料:

$ echo blah blah > /dev/null

裝置類型#

使用 ls -l 可以辨識裝置,檔案模式的第一個字元代表裝置類型:

  • Block device (b):以固定大小的區塊存取資料,例如磁碟 (sda1)。因為大小固定,process 可以隨機存取任意區塊。
  • Character device (c):以資料串流方式運作,只能讀寫字元,沒有固定大小。例如 /dev/null、印表機。kernel 無法回溯已傳送的資料。
  • Pipe device (p):類似 character device,但另一端連接的是另一個 process,而非 kernel driver。也稱為 named pipe
  • Socket device (s):用於行程間通訊 (interprocess communication) 的特殊介面,常見於 /dev 目錄之外。

ls -l 的輸出中,block 和 character device 日期前的數字是 majorminor 設備號碼,kernel 用來識別裝置。相同 major number 的裝置通常屬於同一類(例如 sda3sdb1 都是硬碟分割區)。

並非所有裝置都有 device files。例如,network interface 沒有 device files,因為 block/character I/O 介面不適用於網路裝置。


3.2 The sysfs Device Path#

傳統的 /dev 目錄是一個簡化的命名方案,名稱本身提供的資訊有限,且裝置名稱可能在重新開機後改變。為了提供基於實際硬體屬性的統一檢視,Linux kernel 提供了 sysfs 介面。

  • sysfs 是一套檔案與目錄系統,掛載在 /sys/devices
  • 例如 /dev/sda 對應的 sysfs 路徑可能是:
/sys/devices/pci0000:00/0000:00:17.0/ata3/host0/target0:0:0/0:0:0:0/block/sda

/dev/sys 的差異#

路徑用途
/dev讓 user process 使用裝置
/sys/devices讓程式檢視與管理裝置資訊

常用捷徑與工具#

  • /sys/block 包含所有 block device 的 symbolic link
  • 使用 udevadm 查詢裝置的 sysfs 路徑:
$ udevadm info --query=all --name=/dev/sda

3.3 dd and Devices#

dd 是處理 block 和 character device 時非常實用的工具。它從 input file/stream 讀取資料,寫入 output file/stream,可進行編碼轉換。

dd 非常強大,操作不慎容易損壞檔案和裝置上的資料。如果不確定效果,建議先將 output 導向新檔案。

基本用法#

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

重要參數#

  • if=file:輸入檔案,預設為 standard input
  • of=file:輸出檔案,預設為 standard output
  • bs=size:每次讀寫的 block size(可用 b 表示 512、k 表示 1024)
  • ibs=size, obs=size:分別設定輸入和輸出的 block size
  • count=num:要複製的 block 數量
  • skip=num:跳過輸入檔案開頭的 block 數

dd 的選項格式源自 IBM Job Control Language (JCL),使用 = 而非 - 來設定參數值。


3.4 Device Name Summary(裝置名稱總覽)#

查找裝置名稱的方法:

  • 使用 udevadm 查詢 udev
  • 查看 /sys 目錄
  • 使用 journalctl -k 查看 kernel messages
  • 使用 mount 指令查看已掛載的磁碟裝置
  • 查看 /proc/devices 了解系統目前有哪些 driver

3.4.1 Hard Disks: /dev/sd*#

  • 大部分硬碟使用 sd 前綴(代表 SCSI disk
  • 整顆磁碟:/dev/sda/dev/sdb
  • 分割區:/dev/sda1/dev/sda2
  • 使用 lsscsi 列出 SCSI 裝置:
$ lsscsi
[0:0:0:0]  disk  ATA   WDC WD3200AAJS-2  01.0  /dev/sda
[2:0:0:0]  disk  FLASH Drive UT_USB20    0.00  /dev/sdb
  • Linux 按照 driver 偵測順序分配裝置名稱,重新開機後名稱可能改變
  • 為解決此問題,現代系統使用 UUID (Universally Unique Identifier)LVM 穩定映射

3.4.2 Virtual Disks: /dev/xvd*, /dev/vd*#

用於虛擬機器(如 AWS、VirtualBox),Xen 使用 /dev/xvd 前綴。

3.4.3 Non-Volatile Memory Devices: /dev/nvme*#

NVMe (Non-Volatile Memory Express) 介面用於 SSD,使用 nvme list 查看。

3.4.4 Device Mapper: /dev/dm-*, /dev/mapper/*#

LVM (Logical Volume Manager) 使用的 kernel 系統,稱為 device mapper

3.4.5 CD and DVD Drives: /dev/sr*#

光碟機顯示為 SCSI 裝置 /dev/sr0/dev/sr1,為唯讀。寫入需使用 generic SCSI device(如 /dev/sg0)。

3.4.6 PATA Hard Disks: /dev/hd*#

較舊的 PATA (Parallel ATA) 裝置使用 /dev/hda/dev/hdb 等,基於介面固定分配。

3.4.7 Terminals: /dev/tty*, /dev/pts/*, /dev/tty#

  • Terminal 是在 user process 與 I/O 裝置之間傳遞字元的裝置
  • 大部分 terminal 是 pseudoterminal(模擬終端機),kernel 將 I/O 介面呈現給軟體而非硬體
  • 常見裝置:/dev/tty1(第一個 virtual console)、/dev/pts/0(第一個 pseudoterminal)
  • /dev/tty 是目前 process 的 controlling terminal 的同義詞

Virtual Consoles:Linux 支援以 ALT+Function Key 在多個虛擬控制台間切換。在圖形模式下需使用 CTRL+ALT+Function Key。

3.4.8 Serial Ports: /dev/ttyS*, /dev/ttyUSB*, /dev/ttyACM*#

  • RS-232 序列埠:/dev/ttyS0(COM1)、/dev/ttyS1(COM2)
  • USB 轉序列埠:/dev/ttyUSB0/dev/ttyACM0
  • 可用於連接 microcontroller 開發板(如 CircuitPython)

3.4.9 Parallel Ports: /dev/lp0 and /dev/lp1#

單向平行埠 /dev/lp0/dev/lp1(對應 Windows 的 LPT1、LPT2),雙向為 /dev/parport0/dev/parport1

3.4.10 Audio Devices: /dev/snd/*, /dev/dsp, /dev/audio#

  • ALSA (Advanced Linux Sound Architecture) 裝置位於 /dev/snd
  • 較舊的 OSS (Open Sound System) 裝置為 /dev/dsp/dev/audio

Linux 音效涉及多層架構。kernel 層級之上通常有 user-space 音效伺服器(如 PulseAudio)作為中介。

3.4.11 Device File Creation#

在現代系統中,device files 由 devtmpfsudev 自動建立。手動建立裝置使用 mknod

# mknod /dev/sda1 b 8 1

其中 b 8 1 表示 block device、major number 8、minor number 1。Character 和 pipe device 使用 cp


3.5 udev#

udev 系統負責在 user space 中管理裝置檔案。kernel 偵測到新裝置時,會發送通知給 user-space process udevd,由其建立 device file 並執行裝置初始化。

3.5.1 devtmpfs#

devtmpfs 解決了開機時裝置可用性的問題:

  • kernel 在開機時建立必要的 device files
  • 當新裝置出現時,通知 udevd
  • udevd 不建立 device files,而是負責:
    • 設定權限
    • 通知其他 process
    • /dev/disk/by-id 等目錄建立 symbolic links 以便識別
$ ls -l /dev/disk/by-id

devtmpfs 中的 “tmp” 表示檔案系統存在於主記憶體中,具有 read/write 能力,讓 udevd 能建立 symbolic links。

3.5.2 udevd Operation and Configuration#

udevd daemon 的運作流程:

  1. kernel 透過內部網路連結發送 uevent 通知給 udevd
  2. udevd 載入 uevent 中的所有屬性
  3. udevd 根據 rules 解析、過濾並更新 uevent,執行對應動作

Rules 檔案位於:

  • /lib/udev/rules.d/ — 預設規則
  • /etc/udev/rules.d/ — 自訂覆蓋規則

udev rules 語法重點#

  • 條件式 (conditional):使用 ==(等於)或 !=(不等於)
  • 指令 (directive):使用 =(設定)、+=(新增)、:=(強制設定)
  • Rules 從頭到尾逐行讀取,可使用 GOTO 跳過不相關的區段
  • IMPORT{program} 可執行外部程式匯入變數
  • SYMLINK+= 為裝置建立 symbolic link

3.5.3 udevadm#

udevadm 是 udev 的管理工具,主要功能:

  • 查詢裝置資訊:
$ udevadm info --query=all --name=/dev/sda

輸出中的前綴含義:

前綴意義
P:sysfs device path
N:device node 名稱(/dev 中的名稱)
S:udev 根據 rules 建立的 symbolic link
E:從 udev rules 取得的額外裝置資訊

3.5.4 Device Monitoring#

使用 udevadm monitor 即時監控 uevent:

$ udevadm monitor
  • 預設同時顯示 kernel 和 udevd 的訊息
  • --kernel:只顯示 kernel 事件
  • --udev:只顯示 udevd 處理事件
  • --property:顯示完整 uevent 屬性
  • --subsystem-match=scsi:過濾特定子系統

3.6 In-Depth: SCSI and the Linux Kernel#

本節深入探討 SCSI (Small Computer System Interface) 在 Linux kernel 中的支援。此為進階內容,非使用磁碟所必需。

SCSI 基本架構#

  • 傳統 SCSI 硬體:host adapter 透過 SCSI bus 連接一串裝置
  • 每個裝置有一個 SCSI ID,每條 bus 可有 8 或 16 個 ID
  • 裝置間可透過 SCSI command 以 peer-to-peer 方式通訊
  • 現代系統中,USB storage 和 ATAPI(CD/DVD)裝置也使用 SCSI 指令集
  • SATA 磁碟透過 libata 轉譯層接入 SCSI 子系統

Figure 3-1: SCSI bus with host adapter and devices

使用 lsscsi 查看裝置,輸出中的四個數字分別代表:SCSI host adapter numberSCSI bus numberdevice SCSI IDLUN (Logical Unit Number)

SCSI 子系統的三層架構#

Linux kernel 的 SCSI 子系統分為三層 driver:

  • 上層 (Top layer):處理裝置類別的操作。例如 sd driver 將 block device 請求轉譯為 SCSI disk 指令。
  • 中層 (Middle layer):協調與路由上下層之間的 SCSI 訊息,追蹤所有 SCSI bus 與裝置。
  • 下層 (Bottom layer):處理硬體特定的動作,將 SCSI 協定訊息發送到特定的 host adapter 或硬體。

Figure 3-2: Linux SCSI subsystem schematic

對於任何一個 device file,kernel 幾乎總是使用一個上層 driver 和一個下層 driver。例如 /dev/sda 使用 sd 上層 driver 和 ATA bridge 下層 driver。

3.6.1 USB Storage and SCSI#

  • Linux kernel 的 USB 子系統與 SCSI 子系統結構類似(三層架構)
  • USB storage driver 作為轉譯器:一端說 SCSI,另一端說 USB
  • 因為 USB 訊息內就包含 SCSI 指令,轉譯工作相對簡單
  • 最終由一個 SCSI bridge driver 連接兩個子系統

3.6.2 SCSI and ATA#

  • SATA 硬碟和光碟機共用相同的 SATA 介面
  • 光碟機使用 ATAPI(ATA 協定中編碼的 SCSI 指令版本),轉譯較簡單
  • 硬碟不使用 ATAPI,也不編碼任何 SCSI 指令,需要 libata 進行完整轉譯
  • libata 負責將 ATA/SATA 介面和裝置連接到 SCSI 子系統

3.6.3 Generic SCSI Devices#

  • 一般情況下,user process 透過 block device layer 和 SCSI device class driver(如 sdsr)與裝置互動
  • Generic SCSI device/dev/sg*)允許 user process 繞過 device class driver,直接向裝置發送 SCSI 指令

Figure 3-3: Optical device driver schematic

  • 使用 lsscsi -g 可查看每個裝置對應的 generic device
$ 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

Generic SCSI device 的典型使用場景是 CD/DVD 寫入。讀取光碟由專用 kernel driver 處理,但寫入因為複雜度高且非系統關鍵操作,改由 user-space 程式透過 /dev/sg* 進行,減少 kernel 的複雜度。