linux2.6內核引入sysfs文件系統,sysfs可以看成與proc,devfs和devpty同類別的文件系統,該文件系統是虛擬的文件系統,可以更方便對系統設備進行管理。它可以產生一個包含所有系統硬件層次視圖,與提供進程和狀態信息的proc文件系統十分類似。
sysfs把連接在系統上的設備和總線組織成為一個分級的文件,它們可以由用戶空間存取,向用戶空間導出內核的數據結構以及它們的屬性。sysfs的一個目的就是展示設備驅動模型中各組件的層次關系,其頂級目錄包括block,bus,drivers,class,power和firmware等.
sysfs 與 /sys
sysfs 文件系統總是被掛載在 /sys 掛載點上。雖然在較早期的2.6內核系統上并沒有規定 sysfs 的標準掛載位置,可以把 sysfs 掛載在任何位置,但較近的2.6內核修正了這一規則,要求 sysfs 總是掛載在 /sys 目錄上;針對以前的 sysfs 掛載位置不固定或沒有標準被掛載,有些程序從 /proc/mounts 中解析出 sysfs 是否被掛載以及具體的掛載點,這個步驟現在已經不需要了。請參考附錄給出的 sysfs-rules.txt 文件鏈接。
sysfs 與 proc
sysfs 與 proc 相比有很多優點,最重要的莫過于設計上的清晰。一個 proc 虛擬文件可能有內部格式,如 /proc/scsi/scsi ,它是可讀可寫的,(其文件權限被錯誤地標記為了 0444 !,這是內核的一個BUG),并且讀寫格式不一樣,代表不同的操作,應用程序中讀到了這個文件的內容一般還需要進行字符串解析,而在寫入時需要先用字符串格式化按指定的格式寫入字符串進行操作;相比而言, sysfs 的設計原則是一個屬性文件只做一件事情, sysfs 屬性文件一般只有一個值,直接讀取或寫入。整個 /proc/scsi 目錄在2.6內核中已被標記為過時(LEGACY),它的功能已經被相應的 /sys 屬性文件所完全取代。新設計的內核機制應該盡量使用 sysfs 機制,而將 proc 保留給純凈的“進程文件系統”。
表 1. /sys 下的目錄結構
/sys 下的子目錄所包含的內容/sys/devices這是內核對系統中所有設備的分層次表達模型,也是 /sys 文件系統管理設備的最重要的目錄結構,下文會對它的內部結構作進一步分析;/sys/dev這個目錄下維護一個按字符設備和塊設備的主次號碼(major:minor)鏈接到真實的設備(/sys/devices下)的符號鏈接文件,它是在內核 2.6.26 首次引入;/sys/bus這是內核設備按總線類型分層放置的目錄結構, devices 中的所有設備都是連接于某種總線之下,在這里的每一種具體總線之下可以找到每一個具體設備的符號鏈接,它也是構成 Linux 統一設備模型的一部分;/sys/class這是按照設備功能分類的設備模型,如系統所有輸入設備都會出現在 /sys/class/input 之下,而不論它們是以何種總線連接到系統。它也是構成 Linux 統一設備模型的一部分;/sys/block這里是系統中當前所有的塊設備所在,按照功能來說放置在 /sys/class 之下會更合適,但只是由于歷史遺留因素而一直存在于 /sys/block, 但從 2.6.22 開始就已標記為過時,只有在打開了 CONFIG_SYSFS_DEPRECATED 配置下編譯才會有這個目錄的存在,并且在 2.6.26 內核中已正式移到 /sys/class/block, 舊的接口 /sys/block 為了向后兼容保留存在,但其中的內容已經變為指向它們在 /sys/devices/ 中真實設備的符號鏈接文件;/sys/firmware這里是系統加載固件機制的對用戶空間的接口,關于固件有專用于固件加載的一套API,在附錄 LDD3 一書中有關于內核支持固件加載機制的更詳細的介紹;/sys/fs這里按照設計是用于描述系統中所有文件系統,包括文件系統本身和按文件系統分類存放的已掛載點,但目前只有 fuse,gfs2 等少數文件系統支持 sysfs 接口,一些傳統的虛擬文件系統(VFS)層次控制參數仍然在 sysctl (/proc/sys/fs) 接口中中;/sys/kernel這里是內核所有可調整參數的位置,目前只有 uevent_helper, kexec_loaded, mm, 和新式的 slab 分配器等幾項較新的設計在使用它,其它內核可調整參數仍然位于 sysctl (/proc/sys/kernel) 接口中 ;/sys/module這里有系統中所有模塊的信息,不論這些模塊是以內聯(inlined)方式編譯到內核映像文件(vmlinuz)中還是編譯為外部模塊(ko文件),都可能會出現在/sys/module?中:
編譯為外部模塊(ko文件)在加載后會出現對應的 /sys/module//, 并且在這個目錄下會出現一些屬性文件和屬性目錄來表示此外部模塊的一些信息,如版本號、加載狀態、所提供的驅動程序等;
編譯為內聯方式的模塊則只在當它有非0屬性的模塊參數時會出現對應的 /sys/module/, 這些模塊的可用參數會出現在/sys/modules//parameters/?中,
如 /sys/module/printk/parameters/time 這個可讀寫參數控制著內聯模塊 printk 在打印內核消息時是否加上時間前綴;
所有內聯模塊的參數也可以由 ".=" 的形式寫在內核啟動參數上,如啟動內核時加上參數 "printk.time=1" 與 向 "/sys/module/printk/parameters/time" 寫入1的效果相同;
沒有非0屬性參數的內聯模塊不會出現于此。
/sys/power這里是系統中電源選項,這個目錄下有幾個屬性文件可以用于控制整個機器的電源狀態,如可以向其中寫入控制命令讓機器關機、重啟等。/sys/slab (對應 2.6.23 內核,在 2.6.24 以后移至 /sys/kernel/slab)從2.6.23 開始可以選擇 SLAB 內存分配器的實現,并且新的 SLUB(Unqueued Slab Allocator)被設置為缺省值;如果編譯了此選項,在 /sys 下就會出現 /sys/slab ,里面有每一個 kmem_cache 結構體的可調整參數。對應于舊的 SLAB 內存分配器下的 /proc/slabinfo 動態調整接口,新式的 /sys/kernel/slab/ 接口中的各項信息和可調整項顯得更為清晰。
sysfs 是在這個?Linux?統一設備模型的開發過程中的一項副產品(見 參考資料 中 Greg K. Hartman 寫作的 LinuxJournal 文章)。為了將這些有層次結構的設備以用戶程序可見的方式表達出來,人們很自然想到了利用文件系統的目錄樹結構(這是以 UNIX 方式思考問題的基礎,一切都是文件!)在這個模型中,有幾種基本類型,它們的對應關系見 表 2.?linux?統一設備模型的基本結構 :
??? 表 2. 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_head entry; 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_t s_count; atomic_t s_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 來統一設備模型中的 kset/kobject/attr/attr_group.
具體在數據結構成員上, sysfs_dirent 上有一個 union 共用體包含四種不同的結構,分別是目錄、符號鏈接文件、屬性文件、二進制屬性文件;其中目錄類型可以對應 kobject,在相應的 s_dir 中也有對 kobject 的指針,因此在內核數據結構, kobject 與 sysfs_dirent 是互相引用的;
有了這些概念,再來回頭看 圖 1. 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 下再用屬性文件表示這個對象所具有的屬性;
小結
sysfs 給應用程序提供了統一訪問設備的接口,但可以看到, sysfs 僅僅是提供了一個可以統一訪問設備的框架,但究竟是否支持 sysfs 還需要各設備驅動程序的編程支持;在 2.6 內核誕生 5年以來的發展中,很多子系統、設備驅動程序逐漸轉向了 sysfs 作為與用戶空間友好的接口,但仍然也存在大量的代碼還在使用舊的 proc 或虛擬字符設備的 ioctl 方式;如果僅從最終用戶的角度來說, sysfs 與 proc 都是在提供相同或類似的功能,對于舊的 proc 代碼,沒有絕對的必要去做 proc 至 sysfs 的升級;因此在可預見的將來, sysfs 會與 proc, debugfs, configfs 等共存很長一段時間。
?
評論
查看更多