理解 Unix/Linux 設備偵測、建立 | 認識與使用 udevd | SCSI 與 Linux 核心

理解 Unix/Linux 設備偵測、建立 | 認識與使用 udevd | SCSI 與 Linux 核心

Overview of Content

在 Unix/Linux 系統中,設備節點是一個重要的概念,代表著系統中的各種硬體設備,例如硬碟驅動器、網路介面卡等等。了解設備節點的命名規範對於理解系統中設備的組織和識別十分重要。

Linux 系統通常使用 /dev 目錄來管理這些設備節點,並透過 sysfs 介面來提供更豐富的設備資訊。此外,了解如何使用 udevudevd 來管理設備,包括設定、處理設備事件以及使用 udevadm 命令來查看、監控和管理設備都是重要的技能

在設備節點的命名中,常見的設備名稱包括硬碟裝置(如 sd*hd*)、光碟裝置(如 sg*sr*)、終端設備裝置(如 tty/*ptsttyS)、連接埠裝置(如 ttyS*lp*)以及聲音設備(如 snd*)。此外,我們還可以使用 dd 指令來建立假設備,或者使用 mknod 指令手動建立 /dev 目錄下的設備節點文件。深入了解這些主題將有助於您更好地理解 Unix/Linux 系統中的設備管理和設備節點概念,並能夠有效地識別、配置和管理系統中的各種設備

寫文章分享不易,如有引用參考請詳註出處,如有指導、意見歡迎留言(如果覺得寫得好也請給我一些支持),感謝 😀

個人程式分享時比較注重「縮排」,所以可能不適合手機的排版閱讀,建議切換至「電腦版」、「平板版」視窗看


Unix 設備節點概念

Unix 系統中,核心會將 I/O 介面以 檔案的形式 型態呈現給使用者看,這些設備有為 設備節點

開發者可以使用 catlessvim、重新導向... 等等命令來存取設備

但請注意,並非 所有的設備節點都可以使用 I/O 的方式來存取

設備取名規範

● Linux 如 Unix 一樣,會將硬體設備當作檔案,儲存在 /dev 目錄下,而這個 /dev 目錄是提供 使用者程序 使用的,使用者程序可以對做讀寫

就像是直接對裝置存取一樣

以下使用 ls 查看 /dev 目錄


# 顯示前 30 筆

ls -laF /dev | head -n 30

並且這些設備顯示有一個簡易的符號可以讓我們快速了解(顯示的最前方)

檔案類型符號概述
區塊設備b固定的區塊大小
字元設備c沒有固定容量(核心不會對字元設備 備份、驗證)
管道設備p與字元類似,不過輸入的數據不一定從核心而來
Socket 設備c跨進程、遠端常用到

設備編號 是甚麽?

編號有分為,主編號、副編號;相同類型的設備會有相同的主編號(副編號則沒有硬性規定)

所有設備都有對應的檔案

NO~ 像是網路介面就沒有設備檔案

Linux 改造 /dev 目錄:sysfs 介面

● 傳統的 Unix /dev 目錄會將所有(使用者程序、核心程序)的設備檔案放至此,沒有詳細分類,而這會造成一個問題…

Unix 系統每次開機後,同樣設備儲存在 /dev 資料夾內的裝置名稱也會不同

/dev 目錄中的裝置名稱通常是由系統動態生成的,並且可能根據裝置的探測順序或其他因素而變化

● 為此 Linux 核心透過一個檔案目錄系統提供 sysfs 介面,它是 基於硬體性 統一顯示設備的相關資訊,這就讓 每次開機時,同樣設備都會顯示與上次相同的資料

sysfs 提供的是系統裝置(devices)的相關資訊,而不僅僅是硬體性質;它包括有關系統組件、裝置、驅動程式和其他資源的詳細信息

sysfs 提供的目錄為 /sys/devices,sysfs 介面會以 /sys/devices 下的路徑「作為硬體根路徑」,並呈現相對資訊,範例如下


cd /sys/devices

# 標準 PC 搜尋 sd.*
find . -name sd.*

# 嵌入式的話就要搜尋 eMMC 裝置
find . -name mmcblk0*

從下圖中,我們可以看到主硬碟在 /sys/devices 目錄下也有對應的資訊(是個目錄)

/dev 目錄跟 /sys/devices 目錄差在哪 ?

兩者都可以查看硬體訊息,但是 差異在這兩者的服務目標不同

/dev/sys/devices
提供程序使用設備用來 查找設備資訊、管理設備

A. 查找主、副設備號/sys/devies 下查找主、副設備號


# 打印 dev 檔案資訊
cat ./platform/emmc2bus/fe340000.mmc/mmc_host/mmc0/mmc0:59b4/block/mmcblk0/dev

從下圖中(最下面那行),我們可以看到當前裝置主硬碟的主設備號為 179、副設備號為 0

B. 查找區「塊」設備:在 /sys/block 目錄下的裝置都以連結的方式存在,都會連接到 ../device/virtual/block 目錄下


cd /sys

ls -laF block/

查找設備的方法

● Linux 中有多種方法可以查看當前系統所裝配的設備、裝置,常見的方式如下…

A. 使用 udevadm 命令 查看設備

B. 手動 /sys 目錄 下尋找設備


ls -laF /sys/

B. 查看系統日誌,使用 demsg 命令 輸出核心日誌

C. 使用 mount 命令 查看當前已掛載的設備


mount

D. 查看 /proc/devices 文本:該文本內容顯示系統 已經配置驅動字元、區塊 設備


cat /proc/devices

認識 udev & udevd

關鍵字簡介補充
udev(Userspace Device)Linux 設備管理工具,負責動態管理、識別設備,在找到設備後,自動加入 /dev 目錄下udev 會與內核中的 sysfsdevtmpfs 交互獲取設備訊息
udevd在背景守護 udev 進程,有(硬體)事件發生時會先通知 udevd 處理,再將處理結果傳遞給 dev通過監視 sysfsuevent 介面來獲取事件通知

udevd 注意事項

udevd 作為守護進程,系統啟動前期就需要設備檔案,也就是說 udevd 應該儘早的啟動

並且 udevd 不能依賴任何設備來建立設備檔

內核的 devtmpfs 檔案系統:通知 udevd

內核中的 devtmpfs 檔案系統 類似於舊的 devfs 系統,但它更加簡單

devtmpfs 是一種臨時的虛擬檔案系統,用於在 Linux 內核中管理和展示裝置(device)

devtmpfs 發現設備後,處理順序如下

A. devtmpfs 在發現新設時通知 udevd

當 Linux 內核發現新的裝置時,devtmpfs 會通知 udevd 進行後續處理

B. udevd 在收到消息後,它不會直接建立裝置檔案(device file),而是進行初始化和後續處理

C. 接著 udevd 會在 /dev 中建立符號連結(ln


# 可在 `/dev/disk/by-id` 發現 `udevd` 建立的連結

ls -laF /dev/disk/by-id

● udevd 會使用介面類型名稱、廠商、型號、序列號、分區… 等等的組合方式來為符號連結命名

udevd 操作、設定:uevent 事件

● 這個小節來看 udevd 的工作:它作為守護進程,當有一個新硬體後,會執行以下操作(上至下,按照順序來看)

A. 核心透過內部網路 udevd 發送 uevent 事件,以下我們來看看當前裝置的主硬碟(mmcblk0)收到的 uevent 事件

事件會紀錄在,/sys/目錄下硬體的對應資料夾中的


cat ./platform/emmc2bus/fe340000.mmc/mmc_host/mmc0/mmc0:59b4/block/mmcblk0/uevent

● 以下是一段簡單的 shell,用來判斷 /sys/devices/ 目錄下的 uevent 檔案


#!/bin/bash

list=$(find /sys/devices/ -name "uevent")

IFS=$'\n'

for tmp in $list; do

    #echo "file:$tmp"
    if [ -n "$(cat $tmp)" ] ; then
        echo "The file=($tmp) has content."
        cat $tmp
    fi

done

B. udevd 讀取 uevent 中所有屬性資訊

以下我們來看看更多 uevent 的中可能會紀錄的屬性訊息


# `udevd` 收到的事件內容
# 透過以下屬性,可以獲取 `sysfs` 的設備路徑... 等等訊息

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

C. udevd 透過 規則 解析來決定執行哪些操作udevd 的事件規則

udevd 解析這些事件則是 透過規則,這些 規則可能放置在 1. /lib/udev/rules.d2. /etc/udev/rules.d 目錄下

● 如果有重名的規則,那則以 /etc/udev/rules.d 目錄下的規則為準

● 規則有相當多,詳細規則內容則可以看 man 7 udev

以下以 60-persistent-storage.rules 規則來說明

IMPORT 導入參數:執行 ata_id 命令


# 指令
cat -n /lib/udev/rules.d/60-persistent-storage.rules

# 輸出部分內容
# ATA
KERNEL=="sd*[!0-9]|sr*",     # 配對以 sd* or sr* 開頭的硬體

    # 要求變數 `ID_SERIAL`
    ENV{ID_SERIAL}!="?*", 

    # 子系統為 scsi
    SUBSYSTEMS=="scsi",  

    ATTRS{vendor}=="ATA", 

    # 上述條件都滿足,則執行以下命令
    IMPORT{program}="ata_id --export $devnode"

ID_SERIAL 設定值

ENV{ID_SERIAL}!="?*" 是一個條件句?* 代表的是一個隨機值,加上 != 判斷後最終的意思就是

如果 ENV{ID_SERIAL} 沒有設定(空),則回傳 true 繼續往下執行,否則返回 false

true: 往下執行判斷 或 指令

false: 跳過這個規則,往下執行其他規則

其中 IMPORT{program}="ata_id --export $devnode" 最終執行的是一個 ata_id 命令;透過這個命令可以將 rules 過濾完的數據結果寫入到檔案中


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

SYMLINK 建立符號連結:建立設備符號連結的命名規則也可以在這裡找到,如下可以看出,它命名的規範


# 指令
cat -n /lib/udev/rules.d/60-persistent-storage.rules

# 輸出部分內容
#  sd* / sr* / cciss* 設備使用以下規則
KERNEL=="sd*|sr*|cciss*", 

    # 類行為 disk
    ENV{DEVTYPE}=="disk", 

    # 並且沒有 Serial id
    ENV{ID_SERIAL}=="?*",

    # 執行以下指令
    SYMLINK+="disk/by-id/$env{ID_BUS}-$env{ID_SERIAL}"

在這裡可以看到 ENV{ID_SERIAL}=="?*" 規則的改變!變成如果有設定 ID_SERIAL 則往下執行,也就是執行 SYMLINK 指令


# 執行以下指令,建立 ln 連結

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

udevadm 命令:管理 udevd

udevadm 是管理 udevd 的一個強大工具,主要用來搜尋、瀏覽、監控 udevd

查看 udevd 訊息

● 透過 udevadm 瀏覽 udevd 從核心接收到的訊息


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

其中首符號代表的意義如下表

首符號說明
P代表 sysfs 放置的路徑 (/sys/ 目錄下)
N設備節點 /dev 目錄下的設備名
S設備符號連結
Eudev 規則 中獲得的額外資訊

udevadm 監控設備

● 透過 udevadm 監控設備:以下監控所有的訊息


udevadm monitor

命令 udevadm monitor 還有其他 Option 可以過濾所需訊息

詳細訊息設定可以查看 man 8 udevadm

udevadm monitor Option功能
--kernal只查看從 Kernel 獲取的訊息
--udev只查看 udev 發送的訊息
--property只查看設備屬性

udevadm 命令:查找設備

● Udev manager tool 可以使用 udevadm 指令查看路徑 & 其他屬性


# 查找所有 name 為 /dev/sda 的設備

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

SCSI 與 Linux 核心

介紹 Linux 核心對於 SCSI 的支援方式(以下偏理論)

認識、理解 SCSI

● 傳統的 SCSI 硬體設定:由兩個大元素組成,透過 1. SCSI 匯流排 連接到 2.主機配接器;其種其種每個設備都會有 SCSI ID (主機 Adapter, 設備)

SCSI 匯流排: 可能會有 8~16 不等的 SCSI ID;匯流排中會有 硬碟、USB、光碟機... 等等硬體

而電腦並不直接與每個設備通訊,電腦只與「SCSI 主機 Adapter」通訊,而 通訊的語言則是透過 SCSI 命令集

● 新版的的 SAS (Serial Attach SCSI) 效能更加出色~

設備都是 SCSI 裝置

而現在並沒有很多的 SCSI 設備,但是卻有很多使用 SCSI 指令集通訊的設備(模擬 SCSI 設備),像是 USB, CD, DVD ... 等等

STAT 設備也可以是 SCSI 設備

透過轉換機制(使用 libata 庫),對上層表示為 SCSI 裝置(像是 USB 就可作為 SCSI 設備)

● 而高效能的 RAID 控制器,使用硬體來實現 SCSI 轉換

我們再重新檢視一次 lsscsi 命令


lsscsi

其中括號內代表的意義分別是:SCSI 主機 AdapterSCSI 匯流排編號設備 SCSI IDLUN 邏輯單元編號

Linux 核心處理 SCSI

● 按照我們對於 SCSI 的了解後,下圖表示的是從硬體到核心是如何透過 SCIS 子系統 處理 SCSI 裝置

● 接著我們區塊快來看

A. SCSI 子系統:主要分為 3 層

最頂層:按照類型設備類型做不同處理;sd 驅動(或其他驅動) 負責將來自核心區塊設備介面的請求翻譯成 SCSI 協定

中間層:調控和分流 SCSI 訊息,負責 管理系統中所有的 SCSI 匯流排和設備

最下層:該層中的驅動會向 特定主機配接器發送 SCSI 協定訊息,並擷取硬體發送的訊息

與頂層的分別:雖然 SCSI 協定對於某類設備是統一的,但不同類型的主機配接器處理 SCSI 的方式不同

● 通常下層驅動會與頂層驅動一對一配對(eg. sd 配對 ATA Bridge

B. SCSI & USB 設備:USB 也有一個子系統,當有 USB 裝置插入時,核心會通知 USB 子系統;與 SCSI 相同分為三層

最頂層:將 USB 協定翻譯成 SCSI 協定(像是一個指令 Map,幫我們做翻譯)

中間層:匯流排管理

最下層:主機控制驅動

● 其種以一個類似 lsscsi 的命令 lsusb


lsusb

C. SCSI & ATA 設備:與 USB 驅動相同,需要一個 橋接驅動將 STAT 驅動連接到 SCSI 子系統

而這裡 透過 libata 庫來達到 ATA 裝置對 SCSI 協定的翻譯工作

不然會很複雜,因為 SATA, CD/DVD 的 通訊都不同

通用設備

● 使用者空間(User space)通常是與 SCSI 子系統的最頂層 (各種區塊驅動) 來通訊,所以大多數時間是不需了解 SCSI 通訊協議

通用設備:然而我們也可以繞過 核心提供給使用者的區塊驅動,可以直接與 SCSI 設備交互

這種交互的管道就是 通用設備;可以透過以下指令查看 SCSI 設備對應的通用設備


lsscsi -g

● 通常在考慮到核心複雜度,才會使用到直接操控 通用設備

存取設備:/dev

● 通常我們使用者空間在存取設備時,並不是直接讀取驅動,而是透過 區塊設備介面 來存取(也就是我們常見的 /dev 目錄下的設備文件)


dev 常見設備名

Linux 會依照設備的類型給予一定規則的命名方式 (命名規範)

硬碟裝置:sd*hd*

sd*hd* 命名

/dev 中取名說明
/hd*PATA 硬碟,舊版本的 Linux 會將 SATA 辨認為 PATA 設備
/sd*大部分是指硬碟,現在大部分 Linux 系統中的硬碟都用 sd<順序> 開頭

● PATA 設備:

代表舊的區塊設備,這些設備有時候也會被認成 SATA 設備

sd 設備:該命名代表的是 SCSI dick

小型電腦介面 (Small Computer System Interface) 最初是作為設備之間通訊的硬體協定標準 (也就是有一個共同的抽象介面)

雖然現在已經沒有 SCSI 硬體,不過 SCSI 的規範介面卻很廣泛 !

e.g: Usb 設備就可以實作這個協定

使用 lsscsi 指令:查看當前設備中所有的 SCSI 裝置,但若是硬碟故障就必須移除,而原來對硬碟的標記也就不一定能使用


# 安裝套件
sudo apt install lsscsi

lsscsi
前到後數據說明
1[0:0:0:0]設備在系統中的位置
2dick設備描述
3/dev/sda設備檔案的路徑

光碟裝置:sg*sr*

sr*sg* 命名:光碟,Linux 會將大部分 光學儲存設備視為 SCSI 設備,但若是使用舊介面的話,可能被識別為 PATA 設備

光碟可寫不可寫 ?

不可寫設備被取名為 sr* (read),可寫設備會被取名為 sg* (generic)

終端設備裝置:tty/*ptstty

tty/*pts/*tty:終端設備,這種設備就是典型的非硬體設備,是透過記憶體模擬出來的設備

像是 shell 視窗就是偽終端

終端設備功能補充
tty1第一虛擬控制台 (X Window)-
pts/0第一虛擬終端 (純文字終端),可開 0~7 個-
pts該目錄中有一個專門的檔案系統-

連接埠裝置:ttyS*lp*

● 連接埠有分為 串列並列 連接埠

連接埠功能補充
(串)ttyS*主要在處理 Baud rateflow control,像是 Rs-232在 window 上是 COM*
(並)lp*單向並行連接埠設備在 window 上是 LPT1LPT2

● 可插拔 USB 串列 Adapter 和 ACM (Abstract control module) 模式下,就是以 串列連接埠表示

其取名是 /dev/USB* or /dev/ACM*

聲音裝置:snd*

snd*dspaudio:聲音設備,Linux 有兩組聲音設備,分別如下

A. Advanced Linux Sound Architecture (ALSA) 高級聲音架構:放置在 /dev/snd

B. Open Sorund System (OSS) 開放聲音架構:ALSA 可向後支援 OSS

eg. 可以將 WAV 檔發送給 /dev/dsp 來播放


建立設備

設備通常都需要建立一個相對的文件,而這件事通常由 Linux 設備的底層服務自動幫我們完成,但這並不代表我們不能自己建立

建立假設備:dd 指令

● 在 Linux 中,並非每個設備都是硬體元件,我們可以 透過記憶體來模擬硬體設備

使用 dd 指令

該指令可以讀取、寫入到指定檔案 (可以透過 flag 控制直接寫入 or 寫入核心分頁檔案)

dd option簡述
if=<file>輸入檔案
of=<file>輸出檔案
bs=<size>一次讀取、寫入的區塊大小(一起設定)
ibs=<size>輸入的區塊大小
obs=<size>輸出的區塊大小
count=<num>複製區塊的總數
skip=<num>跳過前面多少的區塊,不將他們複製到輸出

# 讀取 /dev/zero 區塊的資料到當前資料夾中的 testfile 檔案
# (當前是寫入核心分頁)

# 一次寫 1024
# 寫 1K 的數量,最終就是 1M 的大小
dd if=/dev/zero of=test_file bs=1024 count=1k

手動建立 dev 設備檔案:mknod 指令

● 每個外部硬體裝置通常都會在 /dev 目錄下建立自身的目錄

而我們插入硬體裝置後,這工作是通常 devtmpfsudev 自動幫我們完成

若要手動建立就要 使用 mknod 指令 (並設定設備主、次號)


# 主設備號 10
# 副設備號 20
# 建立塊設備,在 /dev/testFile 目錄下
sudo mknod /dev/testFile b 10 20

ls -laF /dev | grep testFile

mknod 也說明了,設備在 Linux 中就代表了一個節點


更多 Linux Shell 知識

探索 Debian 系統上的套件管理系統(PKMS 概念)| 套件倉庫

Linux 環境、服務:用戶、權限管理

Linux 環境、服務、管理

在這個主題中,你可以探索各種 Linux 環境、服務和管理相關的重要概念…

了解 Linux 組成:內核責任、GNU 工具、桌面環境 | 基礎版到發行版

在這裡,你將了解 Linux 系統的基本組成部分,包括內核、GNU 工具和桌面環境,並了解不同 Linux 發行版之間的差異

探索 X Window 服務與桌面環境:Linux 視窗 XWindow 服務、D-Bus 機制

這裡探討了 Linux 系統中 X Window 服務和 D-Bus 機制的工作原理,讓你深入了解桌面環境的背後運作方式

Linux 系統管理入門:安全性、用戶管理與權限設定指南

在這個指南中,你將學習如何管理 Linux 系統,包括安全性、用戶管理和權限設定,以確保系統的安全和有效運作

認識身份驗證與權限管理:UNIX UID、使用者驗證與 PAM | PAM 設定

這裡介紹了 UNIX 系統中的身份驗證機制和權限管理方式,包括 UNIX UID、使用者驗證和 PAM(Pluggable Authentication Modules)設定

Linux Shell 相關知識

Linux Shell 相關知識

這個主題涵蓋了各種與 Linux Shell 相關的知識,從基礎到進階都有…

Shell 基礎知識:包括 Shell 的基礎使用以及差異,還有變數以及計算

認識命令行:Shell 類型、命令差異 | Sub Shell 關係 | Builtin 命令

這裡介紹了命令行中不同類型的 Shell,以及各種 Shell 命令之間的區別和內建命令的用法

Shell 全局及區域變數、特殊變數及環境變數 | Shell 啟動順序 | Array 變數

學習如何在 Shell 中使用全局變數、特殊變數和環境變數,以及如何設置和管理這些變數

探索腳本與命令:Shell 腳本的必備相關知識 | 腳本的數學運算

這裡介紹了 Shell 腳本的基本知識和常用技巧,包括如何執行腳本和進行數學運算

Shell 結構化

Shell 腳本程式中的條件語句和高級特性 | Shell 結構化 & 判斷

該篇文章是介紹結構化腳本的基礎以及特殊的高級技巧,轉著於腳本中的邏輯判斷

掌握 Bash 腳本中的迴圈與循環控制技巧 | Shell 結構化 & 循環

接著是腳本中的循環與控制的技巧,它可以讓我們在 Shell 腳本中有更多的判斷與技巧

探索 Shell 函數與腳本庫 | Shell 結構化 & 函數

這裡你將會學在到結構化腳本的重要技巧「函數」,它可以讓你建立可重複利用的腳本,以節省我們之後開發的時間

Shell 掌握參數處理與用戶輸入技巧 | Shell 結構化 &輸入互動

不可互動的腳本有時候相對無趣,這篇文章有分享如何讓腳本與使用者產生交互互動,並依照使用者輸入的參數做讀取

Shell script 進階

Shell 命令輸入與輸出指南:掌握標準文件描述符與重定向 | 臨時文件

掌控 Shell、指令的輸出輸入是成為進階使用 CLI 之人必經的一課,透過這篇文章可以了解到輸出輸入、臨時文件等等資訊

探索 Linux 訊號與後台進程管理:安排定期啟動腳本 | 運行時啟動腳本

信號可以算是 Shell 腳本與 Linux 系統之間的通訊方式,透過這個文章,我們可以了解到信號與 Shell 腳本的安排時間

Linux 硬體規劃:檔案系統、分區

Linux 硬體規劃:檔案系統、分區

最後,這個主題涵蓋了 Linux 系統中硬體結構相關的重要概念…

Shell 文件和目錄操作的常用命令和技巧 | 尋找檔案

這裡介紹了 Shell 中常用的文件和目錄操作命令,包括如何尋找文件和管理文件系統

深入探索 Linux 文件系統與硬體管理 | 分區、檔案系統、邏輯卷 | inode

學習如何管理 Linux 文件系統,包括分區、文件系統和邏輯卷等相關概念,以及文件系統中的 inode 機制

理解 Unix/Linux 設備偵測、建立 | 認識與使用 udevd | SCSI 與 Linux 核心

這裡介紹了 Unix/Linux 系統中的設備偵測和管理,包括如何使用 udevd 和 SCSI 相關的 Linux 核心知識

Leave a Comment

Comments

No comments yet. Why don’t you start the discussion?

發表迴響