linux2.6內(nèi)核引入sysfs文件系統(tǒng),sysfs可以看成與proc,devfs和devpty同類別的文件系統(tǒng),該文件系統(tǒng)是虛擬的文件系統(tǒng),可以更方便對(duì)系統(tǒng)設(shè)備進(jìn)行管理。它可以產(chǎn)生一個(gè)包含所有系統(tǒng)硬件層次視圖,與提供進(jìn)程和狀態(tài)信息的proc文件系統(tǒng)十分類似。
sysfs把連接在系統(tǒng)上的設(shè)備和總線組織成為一個(gè)分級(jí)的文件,它們可以由用戶空間存取,向用戶空間導(dǎo)出內(nèi)核的數(shù)據(jù)結(jié)構(gòu)以及它們的屬性。sysfs的一個(gè)目的就是展示設(shè)備驅(qū)動(dòng)模型中各組件的層次關(guān)系,其頂級(jí)目錄包括block,bus,drivers,class,power和firmware等.
sysfs 與 /sys
sysfs 文件系統(tǒng)總是被掛載在 /sys 掛載點(diǎn)上。雖然在較早期的2.6內(nèi)核系統(tǒng)上并沒(méi)有規(guī)定 sysfs 的標(biāo)準(zhǔn)掛載位置,可以把 sysfs 掛載在任何位置,但較近的2.6內(nèi)核修正了這一規(guī)則,要求 sysfs 總是掛載在 /sys 目錄上;針對(duì)以前的 sysfs 掛載位置不固定或沒(méi)有標(biāo)準(zhǔn)被掛載,有些程序從 /proc/mounts 中解析出 sysfs 是否被掛載以及具體的掛載點(diǎn),這個(gè)步驟現(xiàn)在已經(jīng)不需要了。請(qǐng)參考附錄給出的 sysfs-rules.txt 文件鏈接。
sysfs 與 proc
sysfs 與 proc 相比有很多優(yōu)點(diǎn),最重要的莫過(guò)于設(shè)計(jì)上的清晰。一個(gè) proc 虛擬文件可能有內(nèi)部格式,如 /proc/scsi/scsi ,它是可讀可寫(xiě)的,(其文件權(quán)限被錯(cuò)誤地標(biāo)記為了 0444 !,這是內(nèi)核的一個(gè)BUG),并且讀寫(xiě)格式不一樣,代表不同的操作,應(yīng)用程序中讀到了這個(gè)文件的內(nèi)容一般還需要進(jìn)行字符串解析,而在寫(xiě)入時(shí)需要先用字符串格式化按指定的格式寫(xiě)入字符串進(jìn)行操作;相比而言, sysfs 的設(shè)計(jì)原則是一個(gè)屬性文件只做一件事情, sysfs 屬性文件一般只有一個(gè)值,直接讀取或?qū)懭?。整個(gè) /proc/scsi 目錄在2.6內(nèi)核中已被標(biāo)記為過(guò)時(shí)(LEGACY),它的功能已經(jīng)被相應(yīng)的 /sys 屬性文件所完全取代。新設(shè)計(jì)的內(nèi)核機(jī)制應(yīng)該盡量使用 sysfs 機(jī)制,而將 proc 保留給純凈的“進(jìn)程文件系統(tǒng)”。
表 1. /sys 下的目錄結(jié)構(gòu)
/sys 下的子目錄所包含的內(nèi)容/sys/devices這是內(nèi)核對(duì)系統(tǒng)中所有設(shè)備的分層次表達(dá)模型,也是 /sys 文件系統(tǒng)管理設(shè)備的最重要的目錄結(jié)構(gòu),下文會(huì)對(duì)它的內(nèi)部結(jié)構(gòu)作進(jìn)一步分析;/sys/dev這個(gè)目錄下維護(hù)一個(gè)按字符設(shè)備和塊設(shè)備的主次號(hào)碼(major:minor)鏈接到真實(shí)的設(shè)備(/sys/devices下)的符號(hào)鏈接文件,它是在內(nèi)核 2.6.26 首次引入;/sys/bus這是內(nèi)核設(shè)備按總線類型分層放置的目錄結(jié)構(gòu), devices 中的所有設(shè)備都是連接于某種總線之下,在這里的每一種具體總線之下可以找到每一個(gè)具體設(shè)備的符號(hào)鏈接,它也是構(gòu)成 Linux 統(tǒng)一設(shè)備模型的一部分;/sys/class這是按照設(shè)備功能分類的設(shè)備模型,如系統(tǒng)所有輸入設(shè)備都會(huì)出現(xiàn)在 /sys/class/input 之下,而不論它們是以何種總線連接到系統(tǒng)。它也是構(gòu)成 Linux 統(tǒng)一設(shè)備模型的一部分;/sys/block這里是系統(tǒng)中當(dāng)前所有的塊設(shè)備所在,按照功能來(lái)說(shuō)放置在 /sys/class 之下會(huì)更合適,但只是由于歷史遺留因素而一直存在于 /sys/block, 但從 2.6.22 開(kāi)始就已標(biāo)記為過(guò)時(shí),只有在打開(kāi)了 CONFIG_SYSFS_DEPRECATED 配置下編譯才會(huì)有這個(gè)目錄的存在,并且在 2.6.26 內(nèi)核中已正式移到 /sys/class/block, 舊的接口 /sys/block 為了向后兼容保留存在,但其中的內(nèi)容已經(jīng)變?yōu)橹赶蛩鼈冊(cè)?/sys/devices/ 中真實(shí)設(shè)備的符號(hào)鏈接文件;/sys/firmware這里是系統(tǒng)加載固件機(jī)制的對(duì)用戶空間的接口,關(guān)于固件有專用于固件加載的一套API,在附錄 LDD3 一書(shū)中有關(guān)于內(nèi)核支持固件加載機(jī)制的更詳細(xì)的介紹;/sys/fs這里按照設(shè)計(jì)是用于描述系統(tǒng)中所有文件系統(tǒng),包括文件系統(tǒng)本身和按文件系統(tǒng)分類存放的已掛載點(diǎn),但目前只有 fuse,gfs2 等少數(shù)文件系統(tǒng)支持 sysfs 接口,一些傳統(tǒng)的虛擬文件系統(tǒng)(VFS)層次控制參數(shù)仍然在 sysctl (/proc/sys/fs) 接口中中;/sys/kernel這里是內(nèi)核所有可調(diào)整參數(shù)的位置,目前只有 uevent_helper, kexec_loaded, mm, 和新式的 slab 分配器等幾項(xiàng)較新的設(shè)計(jì)在使用它,其它內(nèi)核可調(diào)整參數(shù)仍然位于 sysctl (/proc/sys/kernel) 接口中 ;/sys/module這里有系統(tǒng)中所有模塊的信息,不論這些模塊是以內(nèi)聯(lián)(inlined)方式編譯到內(nèi)核映像文件(vmlinuz)中還是編譯為外部模塊(ko文件),都可能會(huì)出現(xiàn)在/sys/module?中:
編譯為外部模塊(ko文件)在加載后會(huì)出現(xiàn)對(duì)應(yīng)的 /sys/module//, 并且在這個(gè)目錄下會(huì)出現(xiàn)一些屬性文件和屬性目錄來(lái)表示此外部模塊的一些信息,如版本號(hào)、加載狀態(tài)、所提供的驅(qū)動(dòng)程序等;
編譯為內(nèi)聯(lián)方式的模塊則只在當(dāng)它有非0屬性的模塊參數(shù)時(shí)會(huì)出現(xiàn)對(duì)應(yīng)的 /sys/module/, 這些模塊的可用參數(shù)會(huì)出現(xiàn)在/sys/modules//parameters/?中,
如 /sys/module/printk/parameters/time 這個(gè)可讀寫(xiě)參數(shù)控制著內(nèi)聯(lián)模塊 printk 在打印內(nèi)核消息時(shí)是否加上時(shí)間前綴;
所有內(nèi)聯(lián)模塊的參數(shù)也可以由 ".=" 的形式寫(xiě)在內(nèi)核啟動(dòng)參數(shù)上,如啟動(dòng)內(nèi)核時(shí)加上參數(shù) "printk.time=1" 與 向 "/sys/module/printk/parameters/time" 寫(xiě)入1的效果相同;
沒(méi)有非0屬性參數(shù)的內(nèi)聯(lián)模塊不會(huì)出現(xiàn)于此。
/sys/power這里是系統(tǒng)中電源選項(xiàng),這個(gè)目錄下有幾個(gè)屬性文件可以用于控制整個(gè)機(jī)器的電源狀態(tài),如可以向其中寫(xiě)入控制命令讓機(jī)器關(guān)機(jī)、重啟等。/sys/slab (對(duì)應(yīng) 2.6.23 內(nèi)核,在 2.6.24 以后移至 /sys/kernel/slab)從2.6.23 開(kāi)始可以選擇 SLAB 內(nèi)存分配器的實(shí)現(xiàn),并且新的 SLUB(Unqueued Slab Allocator)被設(shè)置為缺省值;如果編譯了此選項(xiàng),在 /sys 下就會(huì)出現(xiàn) /sys/slab ,里面有每一個(gè) kmem_cache 結(jié)構(gòu)體的可調(diào)整參數(shù)。對(duì)應(yīng)于舊的 SLAB 內(nèi)存分配器下的 /proc/slabinfo 動(dòng)態(tài)調(diào)整接口,新式的 /sys/kernel/slab/ 接口中的各項(xiàng)信息和可調(diào)整項(xiàng)顯得更為清晰。
sysfs 是在這個(gè)?Linux?統(tǒng)一設(shè)備模型的開(kāi)發(fā)過(guò)程中的一項(xiàng)副產(chǎn)品(見(jiàn) 參考資料 中 Greg K. Hartman 寫(xiě)作的 LinuxJournal 文章)。為了將這些有層次結(jié)構(gòu)的設(shè)備以用戶程序可見(jiàn)的方式表達(dá)出來(lái),人們很自然想到了利用文件系統(tǒng)的目錄樹(shù)結(jié)構(gòu)(這是以 UNIX 方式思考問(wèn)題的基礎(chǔ),一切都是文件!)在這個(gè)模型中,有幾種基本類型,它們的對(duì)應(yīng)關(guān)系見(jiàn) 表 2.?linux?統(tǒng)一設(shè)備模型的基本結(jié)構(gòu) :
??? 表 2. Linux 統(tǒng)一設(shè)備模型的基本結(jié)構(gòu)
類型所包含的內(nèi)容對(duì)應(yīng)內(nèi)核數(shù)據(jù)結(jié)構(gòu)對(duì)應(yīng)/sys項(xiàng)設(shè)備(Devices)設(shè)備是此模型中最基本的類型,以設(shè)備本身的連接按層次組織struct device/sys/devices/*/*/.../設(shè)備驅(qū)動(dòng)(Device Drivers)在一個(gè)系統(tǒng)中安裝多個(gè)相同設(shè)備,只需要一份驅(qū)動(dòng)程序的支持struct device_driver/sys/bus/pci/drivers/*/總線類型(Bus Types)在整個(gè)總線級(jí)別對(duì)此總線上連接的所有設(shè)備進(jìn)行管理struct bus_type/sys/bus/*/設(shè)備類別(Device Classes)這是按照功能進(jìn)行分類組織的設(shè)備層次樹(shù);如 USB 接口和 PS/2 接口的鼠標(biāo)都是輸入設(shè)備,都會(huì)出現(xiàn)在 /sys/class/input/ 下struct class/sys/class/*/
從內(nèi)核在實(shí)現(xiàn)它們時(shí)所使用的數(shù)據(jù)結(jié)構(gòu)來(lái)說(shuō), Linux 統(tǒng)一設(shè)備模型又是以兩種基本數(shù)據(jù)結(jié)構(gòu)進(jìn)行樹(shù)型和鏈表型結(jié)構(gòu)組織的:
kobject: 在 Linux 設(shè)備模型中最基本的對(duì)象,它的功能是提供引用計(jì)數(shù)和維持父子(parent)結(jié)構(gòu)、平級(jí)(sibling)目錄關(guān)系,上面的 device, device_driver 等各對(duì)象都是以 kobject 基礎(chǔ)功能之上實(shí)現(xiàn)的;
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 內(nèi)含一個(gè) atomic_t 類型用于引用計(jì)數(shù), parent 是單個(gè)指向父節(jié)點(diǎn)的指針, entry 用于父 kset 以鏈表頭結(jié)構(gòu)將 kobject 結(jié)構(gòu)維護(hù)成雙向鏈表;
kset: 它用來(lái)對(duì)同類型對(duì)象提供一個(gè)包裝集合,在內(nèi)核數(shù)據(jù)結(jié)構(gòu)上它也是由內(nèi)嵌一個(gè) kboject 實(shí)現(xiàn),因而它同時(shí)也是一個(gè) kobject (面向?qū)ο?OOP 概念中的繼承關(guān)系) ,具有 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 維護(hù)成雙向鏈表;
涉及到文件系統(tǒng)實(shí)現(xiàn)來(lái)說(shuō), sysfs 是一種基于 ramfs 實(shí)現(xiàn)的內(nèi)存文件系統(tǒng),與其它同樣以 ramfs 實(shí)現(xiàn)的內(nèi)存文件系統(tǒng)(configfs,debugfs,tmpfs,...)類似, sysfs 也是直接以 VFS 中的 struct inode 和 struct dentry 等 VFS 層次的結(jié)構(gòu)體直接實(shí)現(xiàn)文件系統(tǒng)中的各種對(duì)象;同時(shí)在每個(gè)文件系統(tǒng)的私有數(shù)據(jù) (如 dentry->d_fsdata 等位置) 上,使用了稱為 struct sysfs_dirent 的結(jié)構(gòu)用于表示 /sys 中的每一個(gè)目錄項(xiàng)。
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 對(duì)象中可以看到有向 sysfs_dirent 的指針,因此在sysfs中是用同一種 struct sysfs_dirent 來(lái)統(tǒng)一設(shè)備模型中的 kset/kobject/attr/attr_group.
具體在數(shù)據(jù)結(jié)構(gòu)成員上, sysfs_dirent 上有一個(gè) union 共用體包含四種不同的結(jié)構(gòu),分別是目錄、符號(hào)鏈接文件、屬性文件、二進(jìn)制屬性文件;其中目錄類型可以對(duì)應(yīng) kobject,在相應(yīng)的 s_dir 中也有對(duì) kobject 的指針,因此在內(nèi)核數(shù)據(jù)結(jié)構(gòu), kobject 與 sysfs_dirent 是互相引用的;
有了這些概念,再來(lái)回頭看 圖 1. sysfs 目錄層次圖 所表達(dá)的 /sys 目錄結(jié)構(gòu)就是非常清晰明了:
在 /sys 根目錄之下的都是 kset,它們組織了 /sys 的頂層目錄視圖;
??? 在部分 kset 下有二級(jí)或更深層次的 kset;
??? 每個(gè) kset 目錄下再包含著一個(gè)或多個(gè) kobject,這表示一個(gè)集合所包含的 kobject 結(jié)構(gòu)體;
??? 在 kobject 下有屬性(attrs)文件和屬性組(attr_group),屬性組就是組織屬性的一個(gè)目錄,它們一起向用戶層提供了表示和操作這個(gè) kobject 的屬性特征的接口;
??? 在 kobject 下還有一些符號(hào)鏈接文件,指向其它的 kobject,這些符號(hào)鏈接文件用于組織上面所說(shuō)的 device, driver, bus_type, class, module 之間的關(guān)系;
??? 不同類型如設(shè)備類型的、設(shè)備驅(qū)動(dòng)類型的 kobject 都有不同的屬性,不同驅(qū)動(dòng)程序支持的 sysfs 接口也有不同的屬性文件;而相同類型的設(shè)備上有很多相同的屬性文件;
??? 注意,此表內(nèi)容是按照最新開(kāi)發(fā)中的 2.6.28 內(nèi)核的更新組織的,在附錄資源如 LDD3 等位置中有提到 sysfs 中曾有一種管理對(duì)象稱為 subsys (子系統(tǒng)對(duì)象),在最新的內(nèi)核中經(jīng)過(guò)重構(gòu)認(rèn)為它是不需要的,它的功能完全可以由 kset 代替,也就是說(shuō) sysfs 中只需要一種管理結(jié)構(gòu)是 kset,一種代表具體對(duì)象的結(jié)構(gòu)是 kobject,在 kobject 下再用屬性文件表示這個(gè)對(duì)象所具有的屬性;
小結(jié)
sysfs 給應(yīng)用程序提供了統(tǒng)一訪問(wèn)設(shè)備的接口,但可以看到, sysfs 僅僅是提供了一個(gè)可以統(tǒng)一訪問(wèn)設(shè)備的框架,但究竟是否支持 sysfs 還需要各設(shè)備驅(qū)動(dòng)程序的編程支持;在 2.6 內(nèi)核誕生 5年以來(lái)的發(fā)展中,很多子系統(tǒng)、設(shè)備驅(qū)動(dòng)程序逐漸轉(zhuǎn)向了 sysfs 作為與用戶空間友好的接口,但仍然也存在大量的代碼還在使用舊的 proc 或虛擬字符設(shè)備的 ioctl 方式;如果僅從最終用戶的角度來(lái)說(shuō), sysfs 與 proc 都是在提供相同或類似的功能,對(duì)于舊的 proc 代碼,沒(méi)有絕對(duì)的必要去做 proc 至 sysfs 的升級(jí);因此在可預(yù)見(jiàn)的將來(lái), sysfs 會(huì)與 proc, debugfs, configfs 等共存很長(zhǎng)一段時(shí)間。
?
評(píng)論
查看更多