概括介紹Linux統一設備基本結構
經過長時間學習Linux統一設備,于是和大家分享一下,看完本文你肯定有不少收獲,希望本文能教會你更多東西。在 Linux 2.5 內核的開發過程中,人們設計了一套新的設備模型,目的是為了對計算機上的所有Linux統一設備進行統一地表示和操作,包括Linux統一設備本身和設備之間的連接關系。
這個模型是在分析了 PCI 和 USB 的總線驅動過程中得到的,這兩個總線類型能代表當前系統中的大多數設備類型,它們都有完善的熱挺拔機制和電源管理的支持,也都有級連機制的支持,以橋接的 PCI/USB 總線控制器的方式可以支持更多的 PCI/USB 設備。為了給所有設備添加統一的電源管理的支持,而不是讓每個Linux統一設備中去獨立實現電源管理的支持,人們考慮的是如何盡可能地重用代碼;而且在有層次模型的 PCI/USB 總線中,必須以合理形式展示出這個層次關系,這也是電源管理等所要求的必須有層次結構。
如在一個典型的 PC 系統中,中央處理器(CPU)能直接控制的是 PCI 總線設備,而 USB 總線設備是以一個 PCI 設備(PCI-USB橋)的形式接入在 PCI 總線設備上,外部 USB 設備再接入在 USB 總線設備上;當計算機執行掛起(suspend)操作時, Linux 內核應該以 “外部USB設備->USB總線設備->PCI總線設備” 的順序通知每一個設備將電源掛起;執行恢復(resume)時則以相反的順序通知;反之如果不按此順序則將有設備得不到正確的電源狀態變遷的通知,將無法正常工作。
sysfs 是在這個 Linux統一設備模型的開發過程中的一項副產品(見 參考資料 中 Greg K. Hartman 寫作的 LinuxJournal 文章)。為了將這些有層次結構的設備以用戶程序可見的方式表達出來,人們很自然想到了利用文件系統的目錄樹結構(這是以 UNIX 方式思考問題的基礎,一切都是文件!)在這個模型中,有幾種基本類型它們的對應關系。
Linux統一設備模型的基本結構
類型 所包含的內容 對應內核數據結構 對應/sys項
設備(Devices) 設備是此模型中最基本的類型,以設備本身的連接按層次組織 struct device /sys/devices/*/*/.../
設備驅動(Device Drivers) 在一個系統中安裝多個相同設備,只需要一份驅動程序的支持 struct device_driver /sys/bus/pci/drivers/*/
總線類型(Bus Types) 在整個總線級別對此總線上連接的所有設備進行管理 struct bus_type /sys/bus/*/
設備類別(Device Classes) 這是按照功能進行分類組織的設備層次樹;如 USB 接口和 PS/2 接口的鼠標都是輸入設備,都會出現在 /sys/class/input/ 下 struct class /sys/class/*/
從內核在實現它們時所使用的數據結構來說, Linux統一設備模型又是以兩種基本數據結構進行樹型和鏈表型結構組織的:
kobject: 在 Linux統一設備模型中最基本的對象,它的功能是提供引用計數和維持父子(parent)結構、平級(sibling)目錄關系,上面的 device, device_driver 等各對象都是以 kobject 基礎功能之上實現的; struct kobject {
const char *name;
struct list_headentry;
struct kobject *parent;
struct kset *kset;
struct kobj_type*ktype;
struct sysfs_dirent *sd;
struct kref kref;
unsigned int state_initialized:1;
unsigned int state_in_sysfs:1;
unsigned int state_add_uevent_sent:1;
unsigned int state_remove_uevent_sent:1;
其中 struct kref 內含一個 atomic_t 類型用于引用計數, parent 是單個指向父節點的指針, entry 用于父 kset 以鏈表頭結構將 kobject 結構維護成雙向鏈表;
kset: 它用來對同類型對象提供一個包裝集合,在內核數據結構上它也是由內嵌一個 kboject 實現,因而它同時也是一個 kobject (面向對象 OOP 概念中的繼承關系) ,具有 kobject 的全部功能; struct kset {
struct list_head list;
spinlock_t list_lock;
struct kobject kobj;
struct kset_uevent_ops *uevent_ops;
其中的 struct list_head list 用于將集合中的 kobject 按 struct list_head entry 維護成雙向鏈表;
涉及到文件系統實現來說, sysfs 是一種基于 ramfs 實現的內存文件系統,與其它同樣以 ramfs 實現的內存文件系統(configfs,debugfs,tmpfs,...)類似, sysfs 也是直接以 VFS 中的 struct inode 和 struct dentry 等 VFS 層次的結構體直接實現文件系統中的各種對象;同時在每個文件系統的私有數據 (如 dentry->d_fsdata 等位置) 上,使用了稱為 struct sysfs_dirent 的結構用于表示 /sys 中的每一個目錄項。
struct sysfs_dirent {
atomic_ts_count;
atomic_ts_active;
struct sysfs_dirent *s_parent;
struct sysfs_dirent *s_sibling;
const char *s_name;
union {
struct sysfs_elem_dir s_dir;
struct sysfs_elem_symlink s_symlink;
struct sysfs_elem_attr s_attr;
struct sysfs_elem_bin_attr s_bin_attr;
unsigned int s_flags;
ino_t s_ino;
umode_t s_mode;
struct iattr *s_iattr;
在上面的 kobject 對象中可以看到有向 sysfs_dirent 的指針,因此在sysfs中是用同一種 struct sysfs_dirent 來Linux統一設備模型中的 kset/kobject/attr/attr_group.
具體在數據結構成員上, sysfs_dirent 上有一個 union 共用體包含四種不同的結構,分別是目錄、符號鏈接文件、屬性文件、二進制屬性文件;其中目錄類型可以對應 kobject,在相應的 s_dir 中也有對 kobject 的指針,因此在內核數據結構, kobject 與 sysfs_dirent 是互相引用的;
sysfs 所表達的 /sys 目錄結構就是非常清晰明了:
在 /sys 根目錄之下的都是 kset,它們組織了 /sys 的頂層目錄視圖;
在部分 kset 下有二級或更深層次的 kset;
每個 kset 目錄下再包含著一個或多個 kobject,這表示一個集合所包含的 kobject 結構體;
在 kobject 下有屬性(attrs)文件和屬性組(attr_group),屬性組就是組織屬性的一個目錄,它們一起向用戶層提供了表示和操作這個 kobject 的屬性特征的接口;
在 kobject 下還有一些符號鏈接文件,指向其它的 kobject,這些符號鏈接文件用于組織上面所說的 device, driver, bus_type, class, module 之間的關系;
不同類型如設備類型的、設備驅動類型的 kobject 都有不同的屬性,不同驅動程序支持的 sysfs 接口也有不同的屬性文件;而相同類型的設備上有很多相同的屬性文件;
注意,此表內容是按照***開發中的 2.6.28 內核的更新組織的,在附錄資源如 LDD3 等位置中有提到 sysfs 中曾有一種管理對象稱為 subsys (子系統對象),在***的內核中經過重構認為它是不需要的,它的功能完全可以由 kset 代替,也就是說 sysfs 中只需要一種管理結構是 kset,一種代表具體對象的結構是 kobject,在 kobject 下再用屬性文件表示這個對象所具有的屬性。以上是介紹Linux統一設備。
【編輯推薦】