使用 /sys 文件系統(tǒng)訪(fǎng)問(wèn) Linux 內(nèi)核(轉(zhuǎn)載)

使用 /sys 文件系統(tǒng)訪(fǎng)問(wèn) Linux 內(nèi)核

https://www.ibm.com/developerworks/cn/linux/l-cn-sysfs/

sysfs 虛擬文件系統(tǒng)提供了一種比 proc 更為理想的訪(fǎng)問(wèn)內(nèi)核數(shù)據(jù)的途徑

程 任全

2009 年 1 月 08 日發(fā)布

sysfs 的歷史,其與 proc 的關(guān)系?

sysfs 本身并不是一項(xiàng)很新的技術(shù)振劳,但筆者發(fā)現(xiàn),雖然 sysfs 從2003年誕生至今已有5年胀滚,但人們對(duì) sysfs 依然缺乏了解;一個(gè)很重要的原因可能是缺乏文檔乱投, Linux 內(nèi)核方面最重要的理論書(shū)籍“Linux 設(shè)備驅(qū)動(dòng)第3版”和“理解 Linux 內(nèi)核第2版”都誕生于2003年前后,并且從那以后尚未有再版過(guò)顷编,其它一些重要文章則多對(duì) sysfs 與 proc 相提并論且舉例常常只有 proc戚炫,這導(dǎo)致了 sysfs 的很多重要概念至今仍鮮為人知,因此有必要對(duì) sysfs 作更多介紹媳纬,這是寫(xiě)作本文的初衷双肤。

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ū)懭胨砥恰U麄€(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)”襟企。

初識(shí) /sys

清單 1. 與 /sys 文件系統(tǒng)的一次交互(視內(nèi)核版本號(hào)和外接設(shè)備的不同,在您的系統(tǒng)上執(zhí)行這些命令的結(jié)果可能與此有所不同)

$ ls -F /sys

block/? bus/? class/? dev/? devices/? firmware/? fs/? kernel/? module/? power/

$ ls -F /sys/devices/pci0000:00/0000:00:01.0/0000:01:00.0/

broken_parity_status? enable???????? modalias? resource0???? rom?????????????? uevent

class???????????????? irq??????????? msi_bus?? resource0_wc? subsystem@??????? vendor

config??????????????? local_cpulist? power/??? resource1???? subsystem_device

device??????????????? local_cpus???? resource? resource2???? subsystem_vendor

這是在 Fedora 10 的 2.6.27.5-117.fc10.i686 的內(nèi)核上狮含,可以看到在 /sys 目錄下有 block, bus, class, dev, devices, firmware, fs, kernel, module, power 這些子目錄顽悼,本文將分別介紹這些目錄存在的含義。

第二個(gè) ls 命令展示了在一個(gè) pci 設(shè)備目錄下的文件几迄, "ls" 命令的 "-F" 命令為所列出的每個(gè)文件使用后綴來(lái)顯示文件的類(lèi)型蔚龙,后綴 "/" 表示列出的是目錄,后綴 "@" 表示列出的是符號(hào)鏈接文件映胁∧靖可以看到第二個(gè)目錄下包含有普通文件 (regular file) 和符號(hào)鏈接文件 (symbolic link file) ,本文也將以這個(gè)具體的設(shè)備為例說(shuō)明其中每一個(gè)普通文件的用途解孙。

/sys 文件系統(tǒng)下的目錄結(jié)構(gòu)

/sys 下的目錄結(jié)構(gòu)是經(jīng)過(guò)精心設(shè)計(jì)的:在?/sys/devices?下是所有設(shè)備的真實(shí)對(duì)象坑填,包括如視頻卡和以太網(wǎng)卡等真實(shí)的設(shè)備,也包括 ACPI 等不那么顯而易見(jiàn)的真實(shí)設(shè)備弛姜、還有 tty, bonding 等純粹虛擬的設(shè)備脐瑰;在其它目錄如 class, bus 等中則在分類(lèi)的目錄中含有大量對(duì) devices 中真實(shí)對(duì)象引用的符號(hào)鏈接文件; 清單 1 中在 /sys 根目錄下頂層目錄的意義如下:

表 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è)備按總線(xiàn)類(lèi)型分層放置的目錄結(jié)構(gòu)抒寂, devices 中的所有設(shè)備都是連接于某種總線(xiàn)之下,在這里的每一種具體總線(xiàn)之下可以找到每一個(gè)具體設(shè)備的符號(hào)鏈接掠剑,它也是構(gòu)成 Linux 統(tǒng)一設(shè)備模型的一部分屈芜;

/sys/class這是按照設(shè)備功能分類(lèi)的設(shè)備模型,如系統(tǒng)所有輸入設(shè)備都會(huì)出現(xiàn)在 /sys/class/input 之下朴译,而不論它們是以何種總線(xiàn)連接到系統(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ì)用戶(hù)空間的接口狡逢,關(guān)于固件有專(zhuān)用于固件加載的一套API宁舰,在附錄 LDD3 一書(shū)中有關(guān)于內(nèi)核支持固件加載機(jī)制的更詳細(xì)的介紹;

/sys/fs這里按照設(shè)計(jì)是用于描述系統(tǒng)中所有文件系統(tǒng)奢浑,包括文件系統(tǒng)本身和按文件系統(tǒng)分類(lèi)存放的已掛載點(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)中所有模塊的信息徊哑,不論這些模塊是以?xún)?nèi)聯(lián)(inlined)方式編譯到內(nèi)核映像文件(vmlinuz)中還是編譯為外部模塊(ko文件)袜刷,都可能會(huì)出現(xiàn)在?/sys/module?中:

編譯為外部模塊(ko文件)在加載后會(huì)出現(xiàn)對(duì)應(yīng)的 /sys/module/<module_name>/, 并且在這個(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/<modname>/parameters/<param_name>?中窒盐,

如 /sys/module/printk/parameters/time 這個(gè)可讀寫(xiě)參數(shù)控制著內(nèi)聯(lián)模塊 printk 在打印內(nèi)核消息時(shí)是否加上時(shí)間前綴;

所有內(nèi)聯(lián)模塊的參數(shù)也可以由 "<module_name>.<param_name>=<value>" 的形式寫(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/<slab_name> 接口中的各項(xiàng)信息和可調(diào)整項(xiàng)顯得更為清晰梅肤。

接下來(lái)對(duì) /sys/devices/ 下的目錄結(jié)構(gòu)作進(jìn)一步探討:

清單 2. 查看 /sys/devices/ 的目錄結(jié)構(gòu)

$ ls -F /sys/devices/

isa/? LNXSYSTM:00/? pci0000:00/? platform/? pnp0/? pnp1/? system/? virtual/

可以看到,在 /sys/devices/ 目錄下是按照設(shè)備的基本總線(xiàn)類(lèi)型分類(lèi)的目錄邑茄,再進(jìn)入進(jìn)去查看其中的 PCI 類(lèi)型的設(shè)備:

清單 3. 查看 /sys/devices/pci0000:00/ 的目錄結(jié)構(gòu)

$ ls -F /sys/devices/pci0000:00/

0000:00:00.0/? 0000:00:02.5/? 0000:00:03.1/? 0000:00:0e.0/?? power/

0000:00:01.0/? 0000:00:02.7/? 0000:00:03.2/? firmware_node@? uevent

0000:00:02.0/? 0000:00:03.0/? 0000:00:03.3/? pci_bus/

在 /sys/devices/pci0000:00/ 目錄下是按照 PCI 總線(xiàn)接入的設(shè)備號(hào)分類(lèi)存放的目錄姨蝴,再查看其中一個(gè),

清單 4. 查看 /sys/devices/pci0000:00/ 的目錄結(jié)構(gòu)

$ ls -F /sys/devices/pci0000:00/0000:00:01.0/

0000:01:00.0/???????? device???????? local_cpus? power/??????????? subsystem_vendor

broken_parity_status? enable???????? modalias??? resource????????? uevent

class???????????????? irq??????????? msi_bus???? subsystem@??????? vendor

config??????????????? local_cpulist? pci_bus/??? subsystem_device

可以看到肺缕,其中有一個(gè)目錄 0000:01:00.0/, 其它都是屬性文件和屬性組左医,而如果對(duì) 0000:01:00.0/ 子目錄中進(jìn)行再列表查看則會(huì)得到 清單 1 的目錄結(jié)構(gòu)。

繼續(xù)以上過(guò)程可以了解整個(gè)目錄樹(shù)的結(jié)構(gòu)同木,這里把它整理成 圖 1. sysfs 目錄層次圖

圖 1. sysfs 目錄層次圖

其中涉及到 ksets, kobjects, attrs 等很多術(shù)語(yǔ)浮梢,這就不得不提到 Linux 統(tǒng)一設(shè)備模型。

Linux 統(tǒng)一設(shè)備模型

在 Linux 2.5 內(nèi)核的開(kāi)發(fā)過(guò)程中泉手,人們?cè)O(shè)計(jì)了一套新的設(shè)備模型黔寇,目的是為了對(duì)計(jì)算機(jī)上的所有設(shè)備進(jìn)行統(tǒng)一地表示和操作,包括設(shè)備本身和設(shè)備之間的連接關(guān)系斩萌。這個(gè)模型是在分析了 PCI 和 USB 的總線(xiàn)驅(qū)動(dòng)過(guò)程中得到的缝裤,這兩個(gè)總線(xiàn)類(lèi)型能代表當(dāng)前系統(tǒng)中的大多數(shù)設(shè)備類(lèi)型,它們都有完善的熱挺拔機(jī)制和電源管理的支持颊郎,也都有級(jí)連機(jī)制的支持憋飞,以橋接的 PCI/USB 總線(xiàn)控制器的方式可以支持更多的 PCI/USB 設(shè)備。為了給所有設(shè)備添加統(tǒng)一的電源管理的支持姆吭,而不是讓每個(gè)設(shè)備中去獨(dú)立實(shí)現(xiàn)電源管理的支持榛做,人們考慮的是如何盡可能地重用代碼;而且在有層次模型的 PCI/USB 總線(xiàn)中内狸,必須以合理形式展示出這個(gè)層次關(guān)系检眯,這也是電源管理等所要求的必須有層次結(jié)構(gòu)。

如在一個(gè)典型的 PC 系統(tǒng)中昆淡,中央處理器(CPU)能直接控制的是 PCI 總線(xiàn)設(shè)備锰瘸,而 USB 總線(xiàn)設(shè)備是以一個(gè) PCI 設(shè)備(PCI-USB橋)的形式接入在 PCI 總線(xiàn)設(shè)備上,外部 USB 設(shè)備再接入在 USB 總線(xiàn)設(shè)備上昂灵;當(dāng)計(jì)算機(jī)執(zhí)行掛起(suspend)操作時(shí)避凝, Linux 內(nèi)核應(yīng)該以 “外部USB設(shè)備->USB總線(xiàn)設(shè)備->PCI總線(xiàn)設(shè)備” 的順序通知每一個(gè)設(shè)備將電源掛起舞萄;執(zhí)行恢復(fù)(resume)時(shí)則以相反的順序通知;反之如果不按此順序則將有設(shè)備得不到正確的電源狀態(tài)變遷的通知管削,將無(wú)法正常工作倒脓。

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è)備以用戶(hù)程序可見(jiàn)的方式表達(dá)出來(lái)含思,人們很自然想到了利用文件系統(tǒng)的目錄樹(shù)結(jié)構(gòu)(這是以 UNIX 方式思考問(wèn)題的基礎(chǔ)崎弃,一切都是文件!)在這個(gè)模型中茸俭,有幾種基本類(lèi)型吊履,它們的對(duì)應(yīng)關(guān)系見(jiàn) 表 2. Linux 統(tǒng)一設(shè)備模型的基本結(jié)構(gòu) :

表 2. Linux 統(tǒng)一設(shè)備模型的基本結(jié)構(gòu)

類(lèi)型所包含的內(nèi)容對(duì)應(yīng)內(nèi)核數(shù)據(jù)結(jié)構(gòu)對(duì)應(yīng)/sys項(xiàng)

設(shè)備(Devices)設(shè)備是此模型中最基本的類(lèi)型,以設(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/*/

總線(xiàn)類(lèi)型(Bus Types)在整個(gè)總線(xiàn)級(jí)別對(duì)此總線(xiàn)上連接的所有設(shè)備進(jìn)行管理struct bus_type/sys/bus/*/

設(shè)備類(lèi)別(Device Classes)這是按照功能進(jìn)行分類(lèi)組織的設(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è)備模型又是以?xún)煞N基本數(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)的驴娃;1


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 類(lèi)型用于引用計(jì)數(shù), parent 是單個(gè)指向父節(jié)點(diǎn)的指針循集, entry 用于父 kset 以鏈表頭結(jié)構(gòu)將 kobject 結(jié)構(gòu)維護(hù)成雙向鏈表唇敞;

kset: 它用來(lái)對(duì)同類(lèi)型對(duì)象提供一個(gè)包裝集合,在內(nèi)核數(shù)據(jù)結(jié)構(gòu)上它也是由內(nèi)嵌一個(gè) kboject 實(shí)現(xiàn)咒彤,因而它同時(shí)也是一個(gè) kobject (面向?qū)ο?OOP 概念中的繼承關(guān)系) 疆柔,具有 kobject 的全部功能;1

2

3

4

5

6

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,...)類(lèi)似歇拆, 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 等位置) 上,使用了稱(chēng)為?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)制屬性文件炼杖;其中目錄類(lèi)型可以對(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è)目錄盟劫,它們一起向用戶(hù)層提供了表示和操作這個(gè) kobject 的屬性特征的接口;

在 kobject 下還有一些符號(hào)鏈接文件与纽,指向其它的 kobject侣签,這些符號(hào)鏈接文件用于組織上面所說(shuō)的 device, driver, bus_type, class, module 之間的關(guān)系;

不同類(lèi)型如設(shè)備類(lèi)型的急迂、設(shè)備驅(qū)動(dòng)類(lèi)型的 kobject 都有不同的屬性影所,不同驅(qū)動(dòng)程序支持的 sysfs 接口也有不同的屬性文件;而相同類(lèi)型的設(shè)備上有很多相同的屬性文件僚碎;

注意猴娩,此表內(nèi)容是按照最新開(kāi)發(fā)中的 2.6.28 內(nèi)核的更新組織的,在附錄資源如 LDD3 等位置中有提到 sysfs 中曾有一種管理對(duì)象稱(chēng)為 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àn) sysfs 屬性的功能

使用 sysfs 的關(guān)鍵就是掌握這些 sysfs 屬性的用法腰吟,下面以一些常見(jiàn)的 sysfs 屬性來(lái)展示它的用法无埃;

使用設(shè)備(PCI)的 sysfs 屬性文件

以一份桌面系統(tǒng)上的視頻卡為例,列舉它對(duì)應(yīng)的 kobject 上的屬性文件的對(duì)應(yīng)用途毛雇;

一般來(lái)說(shuō)嫉称,在 Linux 桌面上都有視頻卡以支持 Xorg 軟件包作為 XWindow 服務(wù)器來(lái)運(yùn)行,因此先找到 Xorg 的進(jìn)程號(hào)灵疮,查看這個(gè)進(jìn)程所使用的所有文件(注意查看這個(gè)進(jìn)程屬性需要 root 用戶(hù)權(quán)限)织阅;


# ps xfa |grep Xorg

?2001 tty1???? Ss+??? 2:24????? \_ /usr/bin/Xorg :0 -nr -verbose -auth \

/var/run/gdm/auth-for-gdm-NPrkZK/database -nolisten tcp vt1

# lsof -nP -p 2001

Xorg??? 2001 root? mem??? REG??????? 8,3??? 617732???? 231033 \

/usr/lib/xorg/modules/drivers/sis_drv.so

[...]

Xorg??? 2001 root? mem??? REG??????? 0,0 134217728?????? 5529 \

/sys/devices/pci0000:00/0000:00:01.0/0000:01:00.0/resource0

Xorg??? 2001 root? mem??? REG??????? 0,0??? 131072?????? 5531 \

/sys/devices/pci0000:00/0000:00:01.0/0000:01:00.0/resource1

[...]

Xorg??? 2001 root??? 7u?? REG??????? 0,0?????? 256?????? 5504 \

/sys/devices/pci0000:00/0000:00:00.0/config

Xorg??? 2001 root??? 8u? unix 0xdbe66000?????? 0t0?????? 8756 socket

Xorg??? 2001 root??? 9u?? REG??????? 0,0?????? 256?????? 5528 \

/sys/devices/pci0000:00/0000:00:01.0/0000:01:00.0/config

注意到此 Xorg 服務(wù)器是以?xún)?nèi)存映射 (mem) 的形式打開(kāi)了 "/sys/devices/pci0000:00/0000:00:01.0/0000:01:00.0/resource0" 和 "/sys/devices/pci0000:00/0000:00:01.0/0000:01:00.0/resource1" ,同時(shí)以文件讀寫(xiě)形式 (7u,9u) 打開(kāi)了 "/sys/devices/pci0000:00/0000:00:00.0/config" 和 "/sys/devices/pci0000:00/0000:00:01.0/0000:01:00.0/config"

事實(shí)上震捣, PCI 設(shè)備對(duì)應(yīng)的 kobject 目錄下的 config 正是代表PCI設(shè)備的“配置空間”荔棉,對(duì)于普通 PCI (非PCI-E)設(shè)備而言闹炉,其配置空間大小一般是 256字節(jié),這個(gè)空間可以使用十六進(jìn)制工具 dump 出來(lái)润樱,如下渣触。(有關(guān) PCI 設(shè)備本身的三種地址空間,請(qǐng)參考附錄 LDD3)


# hexdump -C /sys/devices/pci0000:00/0000:00:01.0/0000:01:00.0/config

00000000? 39 10 30 63 03 00 30 02? 00 00 00 03 00 00 00 80? |9.0c..0.........|

00000010? 08 00 00 d8 00 00 00 e1? 01 d0 00 00 00 00 00 00? |................|

00000020? 00 00 00 00 00 00 00 00? 00 00 00 00 19 10 30 1b? |..............0.|

00000030? 00 00 00 00 40 00 00 00? 00 00 00 00 00 00 00 00? |....@...........|

00000040? 01 50 02 06 00 00 00 00? 00 00 00 00 00 00 00 00? |.P..............|

00000050? 02 00 30 00 0b 02 00 ff? 00 00 00 00 00 00 00 00? |..0.............|

00000060? 00 00 00 00 00 00 00 00? 00 00 00 00 00 00 00 00? |................|

*

00000100

這個(gè)空間正好是 256字節(jié)大小壹若,熟悉 PCI 的人們還可以知道嗅钻,從 PCI 配置空間可以讀到有關(guān)此 PCI 設(shè)備的很多有用信息,如廠(chǎng)商代碼店展,設(shè)備代碼养篓,IRQ 號(hào)碼等;前四個(gè)字節(jié) 0x39 0x10 0x30 0x63 就是按小端(little endian)存放的2個(gè)短整數(shù)赂蕴,因此其 PCI 廠(chǎng)商號(hào)碼和 PCI 設(shè)備號(hào)碼分別是 0x1039 和 0x6330


# lspci -v -d 1039:6330

01:00.0 VGA compatible controller: Silicon Integrated Systems [SiS] 661/741/760 PCI/AGP \

or 662/761Gx PCIE VGA Display Adapter (prog-if 00 [VGA controller])

????Subsystem: Elitegroup Computer Systems Device 1b30

????Flags: 66MHz, medium devsel

????BIST result: 00

????Memory at d8000000 (32-bit, prefetchable) [size=128M]

????Memory at e1000000 (32-bit, non-prefetchable) [size=128K]

????I/O ports at d000 [size=128]

????Capabilities: [40] Power Management version 2

????Capabilities: [50] AGP version 3.0

在 PCI 設(shè)備上除了有 config 是配置空間對(duì)用戶(hù)的接口以外柳弄,還有 resource{0,1,2,...} 是資源空間,對(duì)應(yīng)著 PCI 設(shè)備的可映射內(nèi)存空間睡腿;此外 PCI 設(shè)備還提供了很多接口语御,全部列表如下:

# ls -lU /sys/devices/pci0000:00/0000:00:01.0/0000:01:00.0/

總計(jì) 0

-rw-r--r-- 1 root root????? 4096 12-09 00:28 uevent

-r--r--r-- 1 root root????? 4096 12-09 00:27 resource

-r--r--r-- 1 root root????? 4096 12-09 00:27 vendor

-r--r--r-- 1 root root????? 4096 12-09 00:27 device

-r--r--r-- 1 root root????? 4096 12-09 00:28 subsystem_vendor

-r--r--r-- 1 root root????? 4096 12-09 00:28 subsystem_device

-r--r--r-- 1 root root????? 4096 12-09 00:27 class

-r--r--r-- 1 root root????? 4096 12-09 00:27 irq

-r--r--r-- 1 root root????? 4096 12-09 00:28 local_cpus

-r--r--r-- 1 root root????? 4096 12-09 00:28 local_cpulist

-r--r--r-- 1 root root????? 4096 12-09 00:28 modalias

-rw------- 1 root root????? 4096 12-09 00:28 enable

-rw-r--r-- 1 root root????? 4096 12-09 00:28 broken_parity_status

-rw-r--r-- 1 root root????? 4096 12-09 00:28 msi_bus

lrwxrwxrwx 1 root root???????? 0 12-09 00:28 subsystem -> ../../../../bus/pci

drwxr-xr-x 2 root root???????? 0 12-09 00:28 power

-rw-r--r-- 1 root root?????? 256 12-08 23:03 config

-rw------- 1 root root 134217728 12-08 23:03 resource0

-rw------- 1 root root 134217728 12-09 00:28 resource0_wc

-rw------- 1 root root??? 131072 12-08 23:03 resource1

-rw------- 1 root root?????? 128 12-09 00:28 resource2

-r-------- 1 root root???????? 0 12-09 00:28 rom

可以看到很多其它屬性文件,這些屬性文件的權(quán)限位也都是正確的席怪,有 w 權(quán)限位的才是可以寫(xiě)入应闯。其中大小為 4096字節(jié)的屬性一般是純文本描述的屬性,可以直接 cat 讀出和用 echo 字符串的方法寫(xiě)入挂捻;其它非 4096字節(jié)大小的一般是二進(jìn)制屬性碉纺,類(lèi)似于上面的 config 屬性文件;關(guān)于純文本屬性和二進(jìn)制屬性刻撒,在下文?編程實(shí)踐:添加sysfs支持?一節(jié)會(huì)進(jìn)一步說(shuō)明骨田。

從 vendor, device, subsystem_vendor, subsystem_device, class, resource 這些只讀屬性上分別可以讀到此 PCI 設(shè)備的廠(chǎng)商號(hào)、設(shè)備號(hào)声怔、子系統(tǒng)廠(chǎng)商號(hào)态贤、子系統(tǒng)設(shè)備號(hào)、PCI類(lèi)別醋火、資源表等悠汽,這些都是相應(yīng) PCI 設(shè)備的屬性,其實(shí)就是直接從 config 二進(jìn)制文件讀出來(lái)芥驳,按照配置空間的格式讀出這些號(hào)碼柿冲;

使用 enable 這個(gè)可寫(xiě)屬性可以禁用或啟用這個(gè) PCI 設(shè)備,設(shè)備的過(guò)程很直觀(guān)兆旬,寫(xiě)入1代表啟用假抄,寫(xiě)入0則代表禁用;

subsystem 和 driver 符號(hào)鏈接文件分別指向?qū)?yīng)的 sysfs 位置;(這里缺少 driver 符號(hào)鏈接說(shuō)明這個(gè)設(shè)備當(dāng)前未使用內(nèi)核級(jí)的驅(qū)動(dòng)程序)

resource0, resource0_wc, resource1, resource2 等是從"PCI 配置空間"解析出來(lái)的資源定義段落分別生成的宿饱,它們是 PCI 總線(xiàn)驅(qū)動(dòng)在 PCI 設(shè)備初始化階段加上去的熏瞄,都是二進(jìn)制屬性,但沒(méi)有實(shí)現(xiàn)讀寫(xiě)接口刑棵,只支持 mmap 內(nèi)存映射接口巴刻,嘗試進(jìn)行讀寫(xiě)會(huì)提示 IO 錯(cuò)誤,其中 _wc 后綴表示 "合并式寫(xiě)入(write combined)" 蛉签,它們用于作應(yīng)用程序的內(nèi)存映射,就可以訪(fǎng)問(wèn)對(duì)應(yīng)的 PCI 設(shè)備上相應(yīng)的內(nèi)存資源段落沥寥;

有了 PCI 核心對(duì) sysfs 的完善支持碍舍,每個(gè)設(shè)備甚至不用單獨(dú)的驅(qū)動(dòng)程序,如這里的 "0000:01:00.0" 不需要一個(gè)內(nèi)核級(jí)的驅(qū)動(dòng)程序邑雅,有了 PCI 核心對(duì)該設(shè)備的配置空間發(fā)現(xiàn)機(jī)制片橡,可以自動(dòng)發(fā)現(xiàn)它的各個(gè)不同段落的資源屬性,在 Xorg 應(yīng)用程序中可以直接以 "/usr/lib/xorg/modules/drivers/sis_drv.so" 這個(gè)用戶(hù)空間的驅(qū)動(dòng)程序?qū)ζ溥M(jìn)行映射淮野,就可以直接操作此視頻卡了捧书;

有了這一個(gè) PCI 設(shè)備的示例可以知道,有了一個(gè) PCI 設(shè)備的 /sys/devices/ 設(shè)備對(duì)象骤星,去訪(fǎng)問(wèn)它的各項(xiàng)屬性和設(shè)置屬性都非常簡(jiǎn)單经瓷。

使用 uevent

在 sysfs 下的很多 kobject 下都有 uevent 屬性,它主要用于內(nèi)核與 udev (自動(dòng)設(shè)備發(fā)現(xiàn)程序)之間的一個(gè)通信接口洞难;從 udev 本身與內(nèi)核的通信接口 netlink 協(xié)議套接字來(lái)說(shuō)舆吮,它并不需要知道設(shè)備的 uevent 屬性文件,但多了 uevent 這樣一個(gè)接口队贱,可用于 udevmonitor 通過(guò)內(nèi)核向 udevd (udev 后臺(tái)程序)發(fā)送消息色冀,也可用于檢查設(shè)備本身所支持的 netlink 消息上的環(huán)境變量,這個(gè)特性一般用于開(kāi)發(fā)人員調(diào)試 udev 規(guī)則文件柱嫌, udevtrigger 這個(gè)調(diào)試工具本身就是以寫(xiě)各設(shè)備的 uevent 屬性文件實(shí)現(xiàn)的锋恬。

這些 uevent 屬性文件一般都是可寫(xiě)的,其中 /sys/devices/ 樹(shù)下的很多 uevent 屬性在較新內(nèi)核下還支持可讀:


# find /sys/ -type f -name uevent -ls

????11??? 0 -rw-r--r--?? 1 root???? root???????? 4096 12月 12 21:10 \

/sys/devices/platform/uevent

??1471??? 0 -rw-r--r--?? 1 root???? root???????? 4096 12月 12 21:10 \

/sys/devices/platform/pcspkr/uevent

??3075??? 0 -rw-r--r--?? 1 root???? root???????? 4096 12月 12 21:10 \

/sys/devices/platform/vesafb.0/uevent

??3915??? 0 -rw-r--r--?? 1 root???? root???????? 4096 12月 12 21:10 \

/sys/devices/platform/serial8250/uevent

??3941??? 0 -rw-r--r--?? 1 root???? root???????? 4096 12月 12 21:10 \

/sys/devices/platform/serial8250/tty/ttyS2/uevent

??3950??? 0 -rw-r--r--?? 1 root???? root???????? 4096 12月 12 21:10 \

/sys/devices/platform/serial8250/tty/ttyS3/uevent

??5204??? 0 -rw-r--r--?? 1 root???? root???????? 4096 12月 12 21:10 \

/sys/devices/platform/i8042/uevent

[...]

???912??? 0 -rw-r--r--?? 1 root???? root???????? 4096 12月 12 21:17 \

/sys/devices/pci0000:00/0000:00:02.5/uevent

[...]

上面截取的最后一個(gè)是 SCSI 硬盤(pán)控制器設(shè)備的 uevent 屬性文件编丘,這些 /devices/ 屬性文件都支持寫(xiě)入与学,當(dāng)前支持寫(xiě)入的參數(shù)有 "add","remove","change","move","online","offline"。如瘪吏,寫(xiě)入 "add"癣防,這樣可以向 udevd 發(fā)送一條 netlink 消息,讓它再重新一遍相關(guān)的 udev 規(guī)則文件掌眠;這個(gè)功能對(duì)開(kāi)發(fā)人員調(diào)試 udev 規(guī)則文件很有用蕾盯。

1# echo add > /sys/devices/pci0000:00/0000:00:02.5/uevent

使用驅(qū)動(dòng)(PCI)的 sysfs 屬性文件, bind, unbind 和 new_id

在設(shè)備驅(qū)動(dòng) /sys/bus/*/driver/... 下可以看到很多驅(qū)動(dòng)都有 bind, unbind, new_id 這三個(gè)屬性,

# find /sys/bus/*/drivers/ -name bind -ls

...

每一個(gè)設(shè)備驅(qū)動(dòng)程序在程序內(nèi)以某種方式注明了可用于哪些硬件级遭,如所有的 PCI 驅(qū)動(dòng)都使用 MODULE_DEVICE_TABLE 聲明了所能驅(qū)動(dòng)的 PCI 硬件的 PCI 設(shè)備號(hào)望拖。但驅(qū)動(dòng)程序不能預(yù)知未來(lái),未來(lái)生產(chǎn)的新的硬件有可能兼容現(xiàn)有硬件的工作方式挫鸽,就還可以使用現(xiàn)有硬件驅(qū)動(dòng)程序來(lái)工作说敏。在 bind 和 unbind 發(fā)明以前,這種情況除了修改 PCI 設(shè)備驅(qū)動(dòng)程序的 DEVICE_TABLE 段落丢郊,重新編譯驅(qū)動(dòng)程序盔沫,以外別無(wú)他法,在 2.6 內(nèi)核上添加了 bind 和 unbind 之后可以在不重新編譯的情況下對(duì)設(shè)備和驅(qū)動(dòng)之間進(jìn)行手工方式地綁定枫匾。

而且對(duì)于有些硬件設(shè)備可以有多份驅(qū)動(dòng)可用架诞,但任何具體時(shí)刻只能有一個(gè)驅(qū)動(dòng)程序來(lái)驅(qū)動(dòng)這個(gè)硬件,這時(shí)可以使用 bind/unbind 來(lái)強(qiáng)制使用和不使用哪一個(gè)驅(qū)動(dòng)程序干茉;(注意關(guān)于多種驅(qū)動(dòng)程序的選擇谴忧,更好的管理方法是使用 modprobe.conf 配置文件,需要重啟才生效角虫,而 bind/unbind 提供的是一種臨時(shí)的無(wú)需重啟立即生效的途徑沾谓;)

使用它們可以強(qiáng)制綁定某個(gè)設(shè)備使用或強(qiáng)制不使用某個(gè)驅(qū)動(dòng)程序,操作方法就是通過(guò) bind 和 unbind 接口戳鹅。


# find /sys/ -type f \( -name bind -or -name unbind -or -name new_id \) -ls

????69??? 0 -rw-r--r--?? 1 root???? root???????? 4096 12月 12 22:12 \

/sys/devices/virtual/vtconsole/vtcon0/bind

??3072??? 0 --w-------?? 1 root???? root???????? 4096 12月 12 22:15 \

/sys/bus/platform/drivers/vesafb/unbind

[...]

??6489??? 0 --w-------?? 1 root???? root???????? 4096 12月 12 22:09 \

/sys/bus/pci/drivers/8139too/unbind

??6490??? 0 --w-------?? 1 root???? root???????? 4096 12月 12 22:09 \

/sys/bus/pci/drivers/8139too/bind

??6491??? 0 --w-------?? 1 root???? root???????? 4096 12月 12 22:15 \

/sys/bus/pci/drivers/8139too/new_id

這個(gè)結(jié)果中特別提到了 8139too 這份驅(qū)動(dòng)程序的這三個(gè)屬性文件均驶,


# find /sys/bus/pci/drivers/8139too/ -ls

??6435??? 0 drwxr-xr-x?? 2 root???? root??????????? 0 12月 12 22:08 \

/sys/bus/pci/drivers/8139too/

??6436??? 0 lrwxrwxrwx?? 1 root???? root??????????? 0 12月 12 22:08 \

/sys/bus/pci/drivers/8139too/0000:00:0e.0 -> ../../../../devices/pci0000:00/0000:00:0e.0

??6485??? 0 lrwxrwxrwx?? 1 root???? root??????????? 0 12月 12 22:08 \

/sys/bus/pci/drivers/8139too/module -> ../../../../module/8139too

??6488??? 0 --w-------?? 1 root???? root???????? 4096 12月 12 22:08 \

/sys/bus/pci/drivers/8139too/uevent

??6489??? 0 --w-------?? 1 root???? root???????? 4096 12月 12 22:08 \

/sys/bus/pci/drivers/8139too/unbind

??6490??? 0 --w-------?? 1 root???? root???????? 4096 12月 12 22:08 \

/sys/bus/pci/drivers/8139too/bind

??6491??? 0 --w-------?? 1 root???? root???????? 4096 12月 12 22:08 \

/sys/bus/pci/drivers/8139too/new_id

# echo 0000:00:0e.0 > /sys/bus/pci/drivers/8139too/unbind

-bash: echo: write error: 沒(méi)有那個(gè)設(shè)備

# ip addr

1: lo: <LOOPBACK,UP,LOWER_UP> mtu 16436 qdisc noqueue state UNKNOWN

????link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00

????inet 127.0.0.1/8 scope host lo

2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state \

UNKNOWN qlen 1000

????link/ether 00:14:2a:d1:16:72 brd ff:ff:ff:ff:ff:ff

????inet 192.168.1.102/24 brd 192.168.1.255 scope global eth0

3: bond0: <BROADCAST,MULTICAST,MASTER> mtu 1500 qdisc noop state DOWN

????link/ether 00:00:00:00:00:00 brd ff:ff:ff:ff:ff:ff

# echo -n 0000:00:0e.0 > /sys/bus/pci/drivers/8139too/unbind

# ip addr

1: lo: <LOOPBACK,UP,LOWER_UP> mtu 16436 qdisc noqueue state UNKNOWN

????link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00

????inet 127.0.0.1/8 scope host lo

3: bond0: <BROADCAST,MULTICAST,MASTER> mtu 1500 qdisc noop state DOWN

????link/ether 00:00:00:00:00:00 brd ff:ff:ff:ff:ff:ff

# echo -n 0000:00:0e.0 > /sys/bus/pci/drivers/8139too/bind

# ip addr

1: lo: <LOOPBACK,UP,LOWER_UP> mtu 16436 qdisc noqueue state UNKNOWN

????link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00

????inet 127.0.0.1/8 scope host lo

3: bond0: <BROADCAST,MULTICAST,MASTER> mtu 1500 qdisc noop state DOWN

????link/ether 00:00:00:00:00:00 brd ff:ff:ff:ff:ff:ff

4: eth0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN qlen 1000

????link/ether 00:14:2a:d1:16:72 brd ff:ff:ff:ff:ff:ff

這一段操作過(guò)程演示了如何對(duì) PCI 設(shè)備 "0000:00:0e.0" 強(qiáng)制取消綁定 "8139too" 驅(qū)動(dòng)和強(qiáng)制綁定 "8139too" 驅(qū)動(dòng):

對(duì) unbind 屬性寫(xiě)入總線(xiàn)號(hào)碼(bus_id)即是強(qiáng)制取消綁定;

對(duì) bind 屬性寫(xiě)入總線(xiàn)號(hào)碼(bus_id)即是強(qiáng)制綁定粉楚;

注意辣恋,它要求的寫(xiě)入的是總線(xiàn)號(hào)碼,對(duì)應(yīng)于PCI設(shè)備的總線(xiàn)號(hào)碼是按照 "domain(4位):bus(2位):slot(2位):function號(hào)(不限)" 的方式組織模软,是可以從其設(shè)備 kobject 節(jié)點(diǎn)上找到伟骨,而其它類(lèi)型的總線(xiàn)有各自不同的規(guī)則;

請(qǐng)?zhí)貏e注意: 在這一個(gè)例子中燃异, "echo 0000:00:0e.0 > /sys/bus/pci/drivers/8139too/unbind" 這第一個(gè)寫(xiě)入命令以 "No such device" 為錯(cuò)誤退出携狭,而后續(xù)的 "echo -n" 命令則可以成功。這是因?yàn)閮?nèi)核在對(duì)總線(xiàn)號(hào)碼進(jìn)行匹配時(shí)過(guò)于嚴(yán)格了回俐,通常的 "echo" 命令寫(xiě)入一個(gè)字符串會(huì)以一個(gè)換行符結(jié)束輸出逛腿,內(nèi)核所接收到的是帶有這個(gè)換行符的 bus_id 字符串,將它與內(nèi)核數(shù)據(jù)結(jié)構(gòu)中的真正的 bus_id 字符串相比較仅颇,當(dāng)然不能找到单默;所幸的是,這個(gè)問(wèn)題在最新的 2.6.28 開(kāi)發(fā)中的內(nèi)核上已已經(jīng)解決忘瓦,它將這個(gè)比較函數(shù)改為一個(gè)特殊實(shí)現(xiàn)的字符串比較搁廓,自動(dòng)忽略結(jié)尾處的換行符,在 2.6.28-rc6 內(nèi)核上測(cè)試,不帶"-n"參數(shù)的 echo 命令已經(jīng)可以寫(xiě)入成功境蜕。

而 new_id 屬性文件也可以以另一種途徑解決新的設(shè)備號(hào)問(wèn)題:它是一個(gè)只寫(xiě)的驅(qū)動(dòng)屬性蝙场,可用于向其中寫(xiě)新的設(shè)備號(hào)。它支持寫(xiě)入 2至7個(gè)十六進(jìn)制整形參數(shù)粱年,分別代表 vendor, device, subvendor, subdevice, class, class_mask, driver_data 最少為 2個(gè)是因?yàn)橐粋€(gè) PCI設(shè)備主要以廠(chǎng)商號(hào)(vendor)和設(shè)備號(hào)(device)所唯一標(biāo)定售滤,其它 5個(gè)參數(shù)如果不輸入則缺省值為 PCI_ANY_ID(0xffff)。


??5441??? 0 --w-------?? 1 root???? root???????? 4096 12月 14 18:15 \

/sys/bus/pci/drivers/8139too/new_id

從 8139too 驅(qū)動(dòng)上可以看到它當(dāng)前所靜態(tài)支持的設(shè)備號(hào)碼列表台诗,其中包括當(dāng)前系統(tǒng)中的設(shè)備 10ec:8139, 假設(shè)未來(lái)有一款 8140 設(shè)備也滿(mǎn)足 8139 設(shè)備的硬件通訊協(xié)議完箩,于是可以使用 8139too 驅(qū)動(dòng)程序來(lái)驅(qū)動(dòng)它,操作如下

1# echo '10ec 8140' > /sys/bus/pci/drivers/8139too/new_id

這在不更新驅(qū)動(dòng)程序的情況下調(diào)試設(shè)備很有用處拉队。

使用 scsi_host 的 scan 屬性

在具有使用 SCSI 總線(xiàn)連接的主機(jī)上嗜憔,與 PCI類(lèi)似的是也采用四個(gè)號(hào)碼作為一組來(lái)描述一個(gè)設(shè)備,其中位于最頂層的是 scsi_host氏仗。

我們從設(shè)備類(lèi)別 /class/為起點(diǎn)來(lái)探索:

# ls -lU /sys/class/scsi_host

總計(jì) 0

lrwxrwxrwx 1 root root 0 12-13 01:59 host0 -> \

../../devices/pci0000:00/0000:00:02.5/host0/scsi_host/host0

lrwxrwxrwx 1 root root 0 12-13 01:59 host1 -> \

../../devices/pci0000:00/0000:00:02.5/host1/scsi_host/host1

注意這是 2.6.27 內(nèi)核的最新變化,在 /sys/class/ 下的都改為符號(hào)鏈接夺鲜,真實(shí)的 kobject 都存在于 /sys/devices/ 中皆尔;我們這里探索其中的 host0 這個(gè) SCSI 控制器:


# readlink -f /sys/class/scsi_host/host0

/sys/devices/pci0000:00/0000:00:02.5/host0/scsi_host/host0

# ls -lU /sys/devices/pci0000:00/0000:00:02.5/host0/scsi_host/host0

總計(jì) 0

-rw-r--r-- 1 root root 4096 12-13 02:02 uevent

lrwxrwxrwx 1 root root??? 0 12-13 02:02 subsystem -> ../../../../../../class/scsi_host

lrwxrwxrwx 1 root root??? 0 12-13 02:02 device -> ../../../host0

-r--r--r-- 1 root root 4096 12-13 02:02 unique_id

-r--r--r-- 1 root root 4096 12-13 02:02 host_busy

-r--r--r-- 1 root root 4096 12-13 02:02 cmd_per_lun

-r--r--r-- 1 root root 4096 12-13 02:02 can_queue

-r--r--r-- 1 root root 4096 12-13 02:02 sg_tablesize

-r--r--r-- 1 root root 4096 12-13 02:02 unchecked_isa_dma

-r--r--r-- 1 root root 4096 12-13 02:02 proc_name

--w------- 1 root root 4096 12-13 02:02 scan

-rw-r--r-- 1 root root 4096 12-13 02:02 state

-rw-r--r-- 1 root root 4096 12-13 02:02 supported_mode

-rw-r--r-- 1 root root 4096 12-13 02:02 active_mode

-r--r--r-- 1 root root 4096 12-13 02:02 prot_capabilities

-r--r--r-- 1 root root 4096 12-13 02:02 prot_guard_type

drwxr-xr-x 2 root root??? 0 12-13 02:02 power

對(duì)這些屬性文件解釋如下:

有四個(gè) SCSI 特有的可寫(xiě)參數(shù): scan,state,supported_mode,active_mode;可以向其中寫(xiě)入不同的參數(shù)來(lái)控制此 SCSI 控制器的各種狀態(tài)币励;

其它一些可讀屬性用于讀取這個(gè) SCSI 控制器的一些當(dāng)前值慷蠕;

其中的 scan 屬性文件在調(diào)試一些 SCSI 硬件驅(qū)動(dòng)時(shí)很有用,它是只寫(xiě)的食呻,可以寫(xiě)入三個(gè)至四個(gè)以空格分開(kāi)的整數(shù)流炕,用于分別指定對(duì)應(yīng)的 host, channel, id, lun 進(jìn)行重新搜索。且這個(gè) scan 屬性支持以"-"作為通配符仅胞,如以下命令可以執(zhí)行讓整個(gè) scsi_host 進(jìn)行重新搜索每辟,這個(gè)功能用于調(diào)試某些對(duì)熱挺拔實(shí)現(xiàn)不完善的 SCSI 驅(qū)動(dòng)程序很有用:

1# echo '- - -' >/sys/devices/pci0000:00/0000:00:02.5/host0/scsi_host/host0/scan

內(nèi)核模塊中的 sysfs 屬性文件

以一個(gè) 8139too 模塊為例解釋在這個(gè) kboject 下每一個(gè)屬性的用途;


# find /sys/module/8139too/ -ls

??6408??? 0 -r--r--r--?? 1 root???? root???????? 4096 12月 13 02:17 \

/sys/module/8139too/version

??6412??? 0 drwxr-xr-x?? 2 root???? root??????????? 0 12月 13 02:17 \

/sys/module/8139too/sections

??6433??? 0 drwxr-xr-x?? 2 root???? root??????????? 0 12月 13 02:17 \

/sys/module/8139too/notes

??6434??? 0 -r--r--r--?? 1 root???? root?????????? 36 12月 13 02:17 \

/sys/module/8139too/notes/.note.gnu.build-id

??6486??? 0 drwxr-xr-x?? 2 root???? root??????????? 0 12月 13 02:17 \

/sys/module/8139too/drivers

??6487??? 0 lrwxrwxrwx?? 1 root???? root??????????? 0 12月 13 02:17 \

/sys/module/8139too/drivers/pci:8139too -> ../../../bus/pci/drivers/8139too

其中的屬性文件都是只讀的干旧,用于提供信息渠欺。從 version, srcversion 上可以了解到這個(gè)模塊所聲明的版本號(hào),源碼版本號(hào)椎眯, refcnt 是模塊引用計(jì)數(shù)挠将, sections 屬性組中有一些模塊加載至內(nèi)存的相應(yīng)節(jié)信息, drivers/ 目錄中是對(duì)所提供的驅(qū)動(dòng)的鏈接编整;

因?yàn)槟K是內(nèi)核驅(qū)動(dòng)編程的最佳選擇舔稀,而一個(gè)模塊有可能提供多個(gè)驅(qū)動(dòng)程序,因而在未知一個(gè)設(shè)備在用哪一個(gè)驅(qū)動(dòng)的情況下可以先從 /sys/module/ 查找相應(yīng)模塊的情況掌测,再?gòu)?drivers/ 發(fā)現(xiàn)出真正的驅(qū)動(dòng)程序内贮。或者也可以完全反過(guò)來(lái)利用這些信息,先用 lspci/lshw 等工具找到 /sys/devices/ 下的設(shè)備節(jié)點(diǎn)贺归,再?gòu)钠湓O(shè)備的 driver 鏈接找到 /sys/bus/*/drivers/ 下的 device_driver, 再?gòu)?device_driver 下的 module 鏈接找到 /sys/module/*/淆两,這樣就可以得到已加載模塊中空間是哪一個(gè)模塊在給一個(gè)設(shè)備提供驅(qū)動(dòng)程序。

更多 sysfs 屬性文件

以上所舉的例子僅僅是一些常見(jiàn)的 sysfs 屬性用法拂酣,實(shí)際的系統(tǒng)中還常常有很多其它的從未見(jiàn)過(guò)的 sysfs 屬性秋冰,因此只有舉例是不夠的,即使維護(hù)了一份 sysfs 屬性用法參考大全也不夠婶熬,未來(lái)的內(nèi)核版本還會(huì)出現(xiàn)新的 sysfs 屬性剑勾,因此還必須了解 Linux 內(nèi)核代碼以找到實(shí)現(xiàn)這些屬性的代碼位置,以學(xué)會(huì)在沒(méi)有相應(yīng)屬性文檔的情況從內(nèi)核源代碼來(lái)分析其 sysfs 屬性功能赵颅。

Sysfs 源碼分析和編程實(shí)踐

從源代碼中理解 sysfs 屬性的用途

更多的 sysfs 屬性的功能只能靠閱讀源代碼來(lái)理解虽另。還是以上文提到的 scsi_host 的 scan 屬性來(lái)理解,這個(gè)功能沒(méi)有任何文檔上有描述饺谬,因此只能去讀源代碼捂刺。

在內(nèi)核中, sysfs 屬性一般是由 __ATTR 系列的宏來(lái)聲明的募寨,如對(duì)設(shè)備的使用 DEVICE_ATTR 族展,對(duì)總線(xiàn)使用 BUS_ATTR ,對(duì)驅(qū)動(dòng)使用 DRIVER_ATTR 拔鹰,對(duì)類(lèi)別(class)使用 CLASS_ATTR, 這四個(gè)高級(jí)的宏來(lái)自于 , 都是以更低層的來(lái)自 中的 __ATTR/__ATRR_RO 宏實(shí)現(xiàn)仪缸; 因此我們?cè)趦?nèi)核源碼樹(shù)中相應(yīng)位置 drivers/scsi/ 找到這幾個(gè)宏的使用情況,可以得到在?drivers/scsi/scsi_sysfs.c?中:


static ssize_t

store_scan(struct device *dev, struct device_attribute *attr,

???????????const char *buf, size_t count)

{

????????struct Scsi_Host *shost = class_to_shost(dev);

????????int res;


????????res = scsi_scan(shost, buf);

????????if (res == 0)

????????????????res = count;

????????return res;

};

static DEVICE_ATTR(scan, S_IWUSR, NULL, store_scan);

DEVICE_ATTR 宏聲明有四個(gè)參數(shù)列肢,分別是名稱(chēng)恰画、權(quán)限位、讀函數(shù)瓷马、寫(xiě)函數(shù)拴还。這里對(duì)應(yīng)的,名稱(chēng)是 scan, 權(quán)限是只有屬主可寫(xiě)(S_IWUSR)决采、沒(méi)有讀函數(shù)抗果、只有寫(xiě)函數(shù)捏膨。因此讀寫(xiě)功能與權(quán)限位是對(duì)應(yīng)的鸯绿,因?yàn)?DEVICE_ATTR 把權(quán)限位聲明與真正的讀寫(xiě)是否實(shí)現(xiàn)放在了一起满粗,減少了出現(xiàn)不一致的可能。(上文提到 /proc/scsi/scsi 接口的權(quán)限位聲明與其功能不對(duì)應(yīng)晒喷,這與注冊(cè) proc 接口的函數(shù)設(shè)計(jì)中的不一致是有關(guān)系的孝偎,權(quán)限位聲明與功能實(shí)現(xiàn)不在代碼中同一個(gè)位置,因此易出錯(cuò)凉敲。雖然修復(fù) /proc/scsi/scsi 的權(quán)限位錯(cuò)誤很容易衣盾,但內(nèi)核團(tuán)隊(duì)中多年來(lái)一直沒(méi)有人發(fā)現(xiàn)或未有人去修正這個(gè) BUG寺旺,應(yīng)該是與 /proc/scsi/ 接口的過(guò)時(shí)有關(guān),過(guò)時(shí)的功能會(huì)在未來(lái)某個(gè)內(nèi)核版本中去除势决。)

上面的 scan 屬性寫(xiě)入功能是在 store_scan 函數(shù)中實(shí)現(xiàn)的阻塑,這個(gè)接口的四個(gè)參數(shù)中, buf/count 代表用戶(hù)寫(xiě)入過(guò)來(lái)的字符串果复,它把 buf 進(jìn)一步傳給了 scsi_scan 函數(shù)陈莽;如果進(jìn)一步分析 scsi_scan 函數(shù)實(shí)現(xiàn)可以知道,它期望從 buf 中接受三個(gè)或四個(gè)整型值(也接受"-"作為通配符)虽抄,分別代表 host, channel, id 三個(gè)值走搁,(第四個(gè)整數(shù)在早期內(nèi)核中曾代表 lun 號(hào)碼,但在較新內(nèi)核中第四個(gè)數(shù)字被忽略迈窟,僅作為向后兼容保留接受四個(gè)整數(shù))私植,然后對(duì)具體的 (host, channel, id) 進(jìn)行重新掃描以發(fā)現(xiàn)這個(gè) SCSI 控制器上的設(shè)備變動(dòng)。

添加 sysfs 支持

如果你正在開(kāi)發(fā)的設(shè)備驅(qū)動(dòng)程序中需要與用戶(hù)層的接口车酣,一般可選的方法有:

注冊(cè)虛擬的字符設(shè)備文件曲稼,以這個(gè)虛擬設(shè)備上的 read/write/ioctl 等接口與用戶(hù)交互;但 read/write 一般只能做一件事情湖员, ioctl 可以根據(jù) cmd 參數(shù)做多個(gè)功能躯肌,但其缺點(diǎn)是很明顯的: ioctl 接口無(wú)法直接在 Shell 腳本中使用,為了使用 ioctl 的功能破衔,還必須編寫(xiě)配套的 C語(yǔ)言的虛擬設(shè)備操作程序, ioctl 的二進(jìn)制數(shù)據(jù)接口也是造成大小端問(wèn)題 (big endian與little endian)钱烟、32位/64位不可移植問(wèn)題的根源晰筛;

注冊(cè) proc 接口,接受用戶(hù)的 read/write/ioctl 操作拴袭;同樣的读第,一個(gè) proc 項(xiàng)通常使用其 read/write/ioctl 接口,它所存在的問(wèn)題與上面的虛擬字符設(shè)備的的問(wèn)題相似拥刻;

注冊(cè) sysfs 屬性怜瞒;

最重要的是,添加虛擬字符設(shè)備支持和注冊(cè) proc 接口支持這兩者所需要增加的代碼量都并不少般哼,最好的方法還是使用 sysfs 屬性支持吴汪,一切在用戶(hù)層是可見(jiàn)的透明,且增加的代碼量是最少的蒸眠,可維護(hù)性也最好漾橙;方法就是使用 <include/linux/device.h> 頭文件提供的這四個(gè)宏,分別應(yīng)用于總線(xiàn)/類(lèi)別/驅(qū)動(dòng)/設(shè)備四種內(nèi)核數(shù)據(jù)結(jié)構(gòu)對(duì)象上:


#define BUS_ATTR(_name, _mode, _show, _store)?? \

struct bus_attribute bus_attr_##_name = __ATTR(_name, _mode, _show, _store)


#define CLASS_ATTR(_name, _mode, _show, _store)???????????????? \

struct class_attribute class_attr_##_name = __ATTR(_name, _mode, _show, _store)


#define DRIVER_ATTR(_name, _mode, _show, _store)??????? \

struct driver_attribute driver_attr_##_name =?????????? \

????????__ATTR(_name, _mode, _show, _store)


#define DEVICE_ATTR(_name, _mode, _show, _store) \

struct device_attribute dev_attr_##_name = __ATTR(_name, _mode, _show, _store)

總線(xiàn)(BUS)和類(lèi)別(CLASS)屬性一般用于新設(shè)計(jì)的總線(xiàn)和新設(shè)計(jì)的類(lèi)別楞卡,這兩者一般是不用的霜运;因?yàn)槟愕脑O(shè)備一般是以PCI等成熟的常規(guī)方式連接到主機(jī)脾歇,而不會(huì)去新發(fā)明一種類(lèi)型;使用驅(qū)動(dòng)屬性和設(shè)備屬性的區(qū)別就在于:看你的 sysfs 屬性設(shè)計(jì)是針對(duì)整個(gè)驅(qū)動(dòng)有效的還是針對(duì)這份驅(qū)動(dòng)所可能支持的每個(gè)設(shè)備分別有效淘捡。

從頭文件中還可以找到 show/store 函數(shù)的原型藕各,注意到它和虛擬字符設(shè)備或 proc 項(xiàng)的 read/write 的作用很類(lèi)似,但有一點(diǎn)不同是 show/store 函數(shù)上的 buf/count 參數(shù)是在 sysfs 層已作了用戶(hù)區(qū)/內(nèi)核區(qū)的內(nèi)存復(fù)制焦除,虛擬字符設(shè)備上常見(jiàn)的 __user 屬性在這里并不需要激况,因而也不需要多一次 copy_from_user/copy_to_user, 在 show/store 函數(shù)參數(shù)上的 buf/count 參數(shù)已經(jīng)是內(nèi)核區(qū)的地址,可以直接操作踢京。

上面四種都是 Linux 統(tǒng)一設(shè)備模型所添加的高級(jí)接口誉碴,如果使用 sysfs 所提供的底層接口的話(huà),則還有下面兩個(gè)瓣距,定義來(lái)自 <include/linux/sysfs.h> :(上面的總線(xiàn)/類(lèi)別/驅(qū)動(dòng)/設(shè)備四個(gè)接口都是以這里的__ATTR實(shí)現(xiàn)的)


#define __ATTR(_name,_mode,_show,_store) { \

????????.attr = {.name = __stringify(_name), .mode = _mode },?? \

????????.show?? = _show,??????????????????????????????????????? \

????.store? = _store,?????????????????????????????????????? \

}


#define __ATTR_RO(_name) { \

????????.attr?? = { .name = __stringify(_name), .mode = 0444 }, \

????????.show?? = _name##_show,???????????????????????????????? \

}

上面這些宏都是在注冊(cè)總線(xiàn)/類(lèi)別/驅(qū)動(dòng)/設(shè)備時(shí)作為缺省屬性而使用的黔帕,在實(shí)際應(yīng)用中還有一種情況是根據(jù)條件動(dòng)態(tài)添加屬性,如 PCI 設(shè)備上的 resource{0,1,2,...} 屬性文件蹈丸,因?yàn)橐粋€(gè) PCI 設(shè)備上的可映射資源究竟有多少無(wú)法預(yù)知成黄,也只能以條件判斷的方式動(dòng)態(tài)添加上。

1

2

3

4

int __must_check sysfs_create_file(struct kobject *kobj,

???????????????????????????????????const struct attribute *attr);

int __must_check sysfs_create_bin_file(struct kobject *kobj,

???????????????????????????????????????struct bin_attribute *attr);

這兩個(gè)函數(shù)可以對(duì)一個(gè) kobject 動(dòng)態(tài)添加上文本屬性或二進(jìn)制屬性逻杖,這也是唯一可以添加二進(jìn)制屬性的方法奋岁。

二進(jìn)制屬性與普通文本屬性的區(qū)別在于:

二進(jìn)制屬性?struct bin_attribute?中內(nèi)嵌一個(gè)?struct attribute?結(jié)構(gòu)體對(duì)象,因此具有普通屬性的所有功能特征荸百;

二進(jìn)制屬性上多一個(gè) size 用來(lái)描述此二進(jìn)制文件的大小闻伶,而普通屬性文件的大小總是 4096, 準(zhǔn)確地說(shuō),應(yīng)該是一個(gè)內(nèi)存頁(yè)的大小够话,因?yàn)閺漠?dāng)前 sysfs 內(nèi)核實(shí)現(xiàn)來(lái)說(shuō)蓝翰,它分配一個(gè)內(nèi)存頁(yè)面來(lái)作為 (buf/count) 的緩沖區(qū);

二進(jìn)制屬性比普通屬性多內(nèi)存映射(mmap)接口的支持女嘲;

編程示例畜份,對(duì) LDD3 一書(shū)中的 lddbus 驅(qū)動(dòng)程序的 sysfs 改進(jìn)

首先,這個(gè)程序本身是針對(duì)當(dāng)時(shí)作者寫(xiě)書(shū)的年代的內(nèi)核(2.6.11)而編寫(xiě)的欣尼,在當(dāng)前的 Fedora10 系統(tǒng) (2.6.27.5-117.fc10.i686) 上甚至無(wú)法編譯編譯通過(guò)爆雹;因此首先需要將它移植過(guò)來(lái)至少達(dá)到可運(yùn)行狀態(tài);

附件的壓縮包中含有修改過(guò)的 lddbus, sculld 的源代碼和修改過(guò)程的四個(gè)patch:

第一個(gè) 0001-ldd3-examples-build-on-fedora-10-2.6.27.5-117.fc10.i.patch 是將 lddbus 和 sculld 移植到 Fedora10 內(nèi)核上可運(yùn)行愕鼓,這其中主要是一此內(nèi)核 API 的變化钙态;

第二個(gè) 0002-port-dmem-proc-entry-to-use-sysfs-entry.patch 演示了怎樣將原有的 proc 接口改進(jìn)成為 sysfs 屬性接口的,從這個(gè) patch 中可以看到刪除的代碼多而新增加的代碼少菇晃,這說(shuō)明對(duì)于相同的功能驯绎,使用 sysfs 編程接口的代碼量更少,而且 sysfs 代碼看起來(lái)也比 proc 更為整潔:打印每個(gè)設(shè)備的調(diào)試信息可以做成每個(gè)設(shè)備上分別有自己的接口谋旦,而不是統(tǒng)一的一個(gè) proc 接口剩失;設(shè)備屬性文件最終出現(xiàn)的位置如 "/sys/devices/ldd0/sculld0/dmem"屈尼;1

2

3

4

5

6

7

8

9

10

11

static ssize_t sculld_show_dmem(struct device *ddev,

????????struct device_attribute *attr, char *buf)

{

????/* 其中打印每個(gè)設(shè)備調(diào)試信息的代碼復(fù)制自原proc接口 */

}

static DEVICE_ATTR(dmem, S_IRUGO, sculld_show_dmem, NULL);

static int __init sculld_register_dev(struct sculld_dev *dev, int index)

{

????/* 創(chuàng)建此device屬性文件 */

????ret |= device_create_file(&dev->ldev.dev, &dev_attr_dmem);

}

第三個(gè) 0003-add-.gitignore.patch 是增加了 .gitignore 文件,屏蔽一些編譯生成的臨時(shí)文件拴孤;

第四個(gè) 0004-port-qset-get-set-ioctl-to-use-sysfs-entry.patch 演示了怎樣把基于 ioctl 的操作接口改進(jìn)成為基于 sysfs 接口脾歧,由于原來(lái)的 ioctl 接口設(shè)置和獲取 qset 信息是表示整個(gè)驅(qū)動(dòng)模塊級(jí)的變量,它用來(lái)控制整個(gè)驅(qū)動(dòng)程序而非驅(qū)動(dòng)所支持的單個(gè)的設(shè)備演熟,因此這個(gè) qset 屬性使用 DRIVER_ATTR 來(lái)添加更為合適鞭执;1

2

3

4

5

6

7

8

9

10

11

12

13

14

ssize_t sculld_show_qset(struct device_driver *driver, char *buf)

{

????return snprintf(buf, PAGE_SIZE, "%d\n", sculld_qset);

}

ssize_t sculld_store_qset(struct device_driver *driver, const char *buf,

????????size_t count)

{

????sculld_qset = simple_strtol(buf, NULL, 0);

????return count;

}

????/* 聲明一個(gè)權(quán)限為0644的可同時(shí)讀寫(xiě)的driver屬性 */

static DRIVER_ATTR(qset, S_IRUGO | S_IWUSR, sculld_show_qset, sculld_store_qset);

????/* 創(chuàng)建此driver屬性文件 */

????result = driver_create_file(&sculld_driver.driver, &driver_attr_qset);

驅(qū)動(dòng)屬性最終出現(xiàn)如 "/sys/bus/ldd/drivers/sculld/qset" ,這里聲明的是同時(shí)可讀寫(xiě)的芒粹,權(quán)限位 0644 與其保持一致兄纺。

6446 0 -rw-r--r-- 1 root root 4096 12月 14 07:44 /sys/bus/ldd/drivers/sculld/qset

小結(jié)

sysfs 給應(yīng)用程序提供了統(tǒng)一訪(fǎng)問(wèn)設(shè)備的接口,但可以看到化漆, sysfs 僅僅是提供了一個(gè)可以統(tǒng)一訪(fǎ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 作為與用戶(hù)空間友好的接口,但仍然也存在大量的代碼還在使用舊的 proc 或虛擬字符設(shè)備的 ioctl 方式朦拖;如果僅從最終用戶(hù)的角度來(lái)說(shuō)圃阳, sysfs 與 proc 都是在提供相同或類(lèi)似的功能,對(duì)于舊的 proc 代碼璧帝,沒(méi)有絕對(duì)的必要去做 proc 至 sysfs 的升級(jí)捍岳;因此在可預(yù)見(jiàn)的將來(lái), sysfs 會(huì)與 proc, debugfs, configfs 等共存很長(zhǎng)一段時(shí)間睬隶。

下載資源

本文用到的 Sysfs 模塊編程示例?(sysfs-examples.tar.gz | 58KB): 這是針對(duì) Fedora10 內(nèi)核(2.6.27.5-117.fc10.i686)改進(jìn)后的代碼祟同,而 LDD3-examples 原始代碼下載位置在?examples.oreilly.com?站點(diǎn)。

相關(guān)主題

使用 /proc 文件系統(tǒng)來(lái)訪(fǎng)問(wèn) Linux 內(nèi)核的內(nèi)容”(developerWorks 中國(guó)理疙,2006 年 4 月)介紹了通過(guò) /proc 來(lái)訪(fǎng)問(wèn)Linux內(nèi)核的方法,包括怎樣在自己編寫(xiě)的內(nèi)核模塊中泞坦,給用戶(hù)提供/proc訪(fǎng)問(wèn)接口的方法窖贤。

The Driver Model Core, Part I”(LinuxJournal文章, June 1st, 2003 by Greg Kroah-Hartman in Software)。

Linux設(shè)備驅(qū)動(dòng)第3版”(LnuxWeeklyNews, 由Jonathan Corbet, Alessandro Rubini, 和 Greg Kroah-Hartman 共同完成于2003年)其中第14章(Chapter 14: The Linux Device Model)系統(tǒng)地闡述了Linux設(shè)備模型贰锁,其中包括Linux設(shè)備模型與sysfs文件系統(tǒng)的關(guān)系赃梧。

Linux設(shè)備模型”(2003年 Linux Conference Australia)。

The sysfs Filesystem, OLS'05”(2005年 Ottawa Linux Symposium)豌熄,論文下載自?kernel.org授嘀。

Sysfs, From Wikipedia”。

kobjects and sysfs, From Linux Weekly News, 2003”锣险。

The zen of kobjects, From Linux Weekly News, 2003”蹄皱。

請(qǐng)參考閱讀 Linux 內(nèi)核代碼览闰, Linux 設(shè)備模型代碼位于?drivers/base/,而 sysfs 代碼位于?fs/sysfs/巷折。

在?developerWorks 中國(guó)網(wǎng)站 Linux 專(zhuān)區(qū)?中學(xué)習(xí)更多 Linux 方面的知識(shí)压鉴。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市锻拘,隨后出現(xiàn)的幾起案子油吭,更是在濱河造成了極大的恐慌,老刑警劉巖署拟,帶你破解...
    沈念sama閱讀 206,214評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件婉宰,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡推穷,警方通過(guò)查閱死者的電腦和手機(jī)心包,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)缨恒,“玉大人谴咸,你說(shuō)我怎么就攤上這事∑叮” “怎么了岭佳?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,543評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵,是天一觀(guān)的道長(zhǎng)萧锉。 經(jīng)常有香客問(wèn)我珊随,道長(zhǎng),這世上最難降的妖魔是什么柿隙? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,221評(píng)論 1 279
  • 正文 為了忘掉前任叶洞,我火速辦了婚禮,結(jié)果婚禮上禀崖,老公的妹妹穿的比我還像新娘衩辟。我一直安慰自己,他們只是感情好波附,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,224評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布艺晴。 她就那樣靜靜地躺著,像睡著了一般掸屡。 火紅的嫁衣襯著肌膚如雪封寞。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,007評(píng)論 1 284
  • 那天仅财,我揣著相機(jī)與錄音狈究,去河邊找鬼。 笑死盏求,一個(gè)胖子當(dāng)著我的面吹牛抖锥,可吹牛的內(nèi)容都是我干的亿眠。 我是一名探鬼主播,決...
    沈念sama閱讀 38,313評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼宁改,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼缕探!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起还蹲,我...
    開(kāi)封第一講書(shū)人閱讀 36,956評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤爹耗,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后谜喊,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體潭兽,經(jīng)...
    沈念sama閱讀 43,441評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,925評(píng)論 2 323
  • 正文 我和宋清朗相戀三年斗遏,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了山卦。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,018評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡诵次,死狀恐怖账蓉,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情逾一,我是刑警寧澤铸本,帶...
    沈念sama閱讀 33,685評(píng)論 4 322
  • 正文 年R本政府宣布,位于F島的核電站遵堵,受9級(jí)特大地震影響箱玷,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜陌宿,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,234評(píng)論 3 307
  • 文/蒙蒙 一锡足、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧壳坪,春花似錦舶得、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,240評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至霜瘪,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間惧磺,已是汗流浹背颖对。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,464評(píng)論 1 261
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留磨隘,地道東北人缤底。 一個(gè)月前我還...
    沈念sama閱讀 45,467評(píng)論 2 352
  • 正文 我出身青樓顾患,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親个唧。 傳聞我的和親對(duì)象是個(gè)殘疾皇子江解,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,762評(píng)論 2 345