自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

學(xué)習(xí)深入Linux Sysfs編程與源碼分析

運(yùn)維 系統(tǒng)運(yùn)維
從源代碼中理解 Linux Sysfs 屬性的用途更多的 Linux Sysfs 屬性的功能只能靠閱讀源代碼來理解。還是以上文提到的 scsi_host 的 scan 屬性來理解,這個(gè)功能沒有任何文檔上有描述,因此只能去讀源代碼。

Linux經(jīng)過長(zhǎng)時(shí)間的發(fā)展,很多用戶都很了解Linux Sysfs了,本人很喜歡Linux Sysfs,下面就這個(gè)問題來詳細(xì)說說吧。Linux Sysfs 源碼分析和編程實(shí)踐。Linux的發(fā)行遵守GNU(GNU is Not UNIX)的通用公共許可證,遵循公共版權(quán)許可證(GPL,General Public License),秉承“自由的思想,開放的源碼”原則。

從源代碼中理解 Linux Sysfs 屬性的用途更多的 Linux Sysfs 屬性的功能只能靠閱讀源代碼來理解。還是以上文提到的 scsi_host 的 scan 屬性來理解,這個(gè)功能沒有任何文檔上有描述,因此只能去讀源代碼。

在內(nèi)核中, Linux Sysfs屬性一般是由 __ATTR 系列的宏來聲明的,如對(duì)設(shè)備的使用 DEVICE_ATTR ,對(duì)總線使用 BUS_ATTR ,對(duì)驅(qū)動(dòng)使用 DRIVER_ATTR ,對(duì)類別(class)使用 CLASS_ATTR, 這四個(gè)高級(jí)的宏來自于 , 都是以更低層的來自 中的 __ATTR/__ATRR_RO 宏實(shí)現(xiàn); 因此我們?cè)趦?nèi)核源碼樹中相應(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ù),分別是名稱、權(quán)限位、讀函數(shù)、寫函數(shù)。這里對(duì)應(yīng)的,名稱是 scan, 權(quán)限是只有屬主可寫(S_IWUSR)、沒有讀函數(shù)、只有寫函數(shù)。因此讀寫功能與權(quán)限位是對(duì)應(yīng)的,因?yàn)?DEVICE_ATTR 把權(quán)限位聲明與真正的讀寫是否實(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ì)中多年來一直沒有人發(fā)現(xiàn)或未有人去修正這個(gè) BUG,應(yīng)該是與 /proc/scsi/ 接口的過時(shí)有關(guān),過時(shí)的功能會(huì)在未來某個(gè)內(nèi)核版本中去除。)

上面的 scan 屬性寫入功能是在 store_scan 函數(shù)中實(shí)現(xiàn)的,這個(gè)接口的四個(gè)參數(shù)中, buf/count 代表用戶寫入過來的字符串,它把 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)。

添加 Linux Sysfs 支持

如果你正在開發(fā)的設(shè)備驅(qū)動(dòng)程序中需要與用戶層的接口,一般可選的方法有:
注冊(cè)虛擬的字符設(shè)備文件,以這個(gè)虛擬設(shè)備上的 read/write/ioctl 等接口與用戶交互;但 read/write 一般只能做一件事情, ioctl 可以根據(jù) cmd 參數(shù)做多個(gè)功能,但其缺點(diǎn)是很明顯的: ioctl 接口無(wú)法直接在 Shell 腳本中使用,為了使用 ioctl 的功能,還必須編寫配套的 C語(yǔ)言的虛擬設(shè)備操作程序, ioctl 的二進(jìn)制數(shù)據(jù)接口也是造成大小端問題 (big endian與little endian)、32位/64位不可移植問題的根源;
注冊(cè) proc 接口,接受用戶的 read/write/ioctl 操作;同樣的,一個(gè) proc 項(xiàng)通常使用其 read/write/ioctl 接口,它所存在的問題與上面的虛擬字符設(shè)備的的問題相似;

注冊(cè) Linux Sysfs 屬性;

最重要的是,添加虛擬字符設(shè)備支持和注冊(cè) proc 接口支持這兩者所需要增加的代碼量都并不少,***的方法還是使用 Linux Sysfs屬性支持,一切在用戶層是可見的透明,且增加的代碼量是最少的,可維護(hù)性也***;方法就是使用 頭文件提供的這四個(gè)宏,分別應(yīng)用于總線/類別/驅(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)
 
總線(BUS)和類別(CLASS)屬性一般用于新設(shè)計(jì)的總線和新設(shè)計(jì)的類別,這兩者一般是不用的;因?yàn)槟愕脑O(shè)備一般是以PCI等成熟的常規(guī)方式連接到主機(jī),而不會(huì)去新發(fā)明一種類型;使用驅(qū)動(dòng)屬性和設(shè)備屬性的區(qū)別就在于:看你的 Linux Sysfs屬性設(shè)計(jì)是針對(duì)整個(gè)驅(qū)動(dòng)有效的還是針對(duì)這份驅(qū)動(dòng)所可能支持的每個(gè)設(shè)備分別有效。

從頭文件中還可以找到 show/store 函數(shù)的原型,注意到它和虛擬字符設(shè)備或 proc 項(xiàng)的 read/write 的作用很類似,但有一點(diǎn)不同是 show/store 函數(shù)上的 buf/count 參數(shù)是在Linux Sysfs 層已作了用戶區(qū)/內(nèi)核區(qū)的內(nèi)存復(fù)制,虛擬字符設(shè)備上常見的 __user 屬性在這里并不需要,因而也不需要多一次 copy_from_user/copy_to_user, 在 show/store 函數(shù)參數(shù)上的 buf/count 參數(shù)已經(jīng)是內(nèi)核區(qū)的地址,可以直接操作。
上面四種都是 Linux Sysfs 統(tǒng)一設(shè)備模型所添加的高級(jí)接口,如果使用 Linux Sysfs所提供的底層接口的話,則還有下面兩個(gè),定義來自 :(上面的總線/類別/驅(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è)總線/類別/驅(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)添加上。
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 用來描述此二進(jìn)制文件的大小,而普通屬性文件的大小總是 4096, 準(zhǔn)確地說,應(yīng)該是一個(gè)內(nèi)存頁(yè)的大小,因?yàn)閺漠?dāng)前 Linux Sysfs 內(nèi)核實(shí)現(xiàn)來說,它分配一個(gè)內(nèi)存頁(yè)面來作為 (buf/count) 的緩沖區(qū);二進(jìn)制屬性比普通屬性多內(nèi)存映射(mmap)接口的支持;

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

首先,這個(gè)程序本身是針對(duì)當(dāng)時(shí)作者寫書的年代的內(nèi)核(2.6.11)而編寫的,在當(dāng)前的 Fedora10 系統(tǒng) (2.6.27.5-117.fc10.i686) 上甚至無(wú)法編譯編譯通過;因此首先需要將它移植過來至少達(dá)到可運(yùn)行狀態(tài);附件的壓縮包中含有修改過的 lddbus, sculld 的源代碼和修改過程的四個(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)成為 Linux Sysfs 屬性接口的,從這個(gè) patch 中可以看到刪除的代碼多而新增加的代碼少,這說明對(duì)于相同的功能,使用 Linux Sysfs 編程接口的代碼量更少,而且 sysfs 代碼看起來也比 proc 更為整潔:打印每個(gè)設(shè)備的調(diào)試信息可以做成每個(gè)設(shè)備上分別有自己的接口,而不是統(tǒng)一的一個(gè) proc 接口;設(shè)備屬性文件最終出現(xiàn)的位置如 "/sys/devices/ldd0/sculld0/dmem"; 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)成為基于 Linux Sysfs 接口,由于原來的 ioctl 接口設(shè)置和獲取 qset 信息是表示整個(gè)驅(qū)動(dòng)模塊級(jí)的變量,它用來控制整個(gè)驅(qū)動(dòng)程序而非驅(qū)動(dòng)所支持的單個(gè)的設(shè)備,因此這個(gè) qset 屬性使用 DRIVER_ATTR 來添加更為合適; 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í)讀寫的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í)可讀寫的,權(quán)限位 0644 與其保持一致。 6446 0 -rw-r--r-- 1 root root 4096 12月 14 07:44 /sys/bus/ldd/drivers/sculld/qset

【編輯推薦】

  1. 為你分析Linux操作系統(tǒng)和Windows系統(tǒng)
  2. 闡述Linux操作系統(tǒng)安裝與認(rèn)識(shí)支援的硬體
  3. 詳解Linux操作系統(tǒng)中使用Windows分區(qū)
  4. Linux技術(shù)受風(fēng)河與NEC垂青
  5. 多樣性的Linux桌面
責(zé)任編輯:佚名 來源: CSDN
相關(guān)推薦

2009-12-22 13:26:03

Linux sysfs

2009-12-11 09:42:54

Linux內(nèi)核源碼進(jìn)程調(diào)度

2009-12-11 09:47:23

Linux內(nèi)核源碼進(jìn)程調(diào)度

2016-10-26 20:49:24

ReactJavascript前端

2024-04-29 09:06:46

線程初始化源碼

2010-01-12 17:55:03

C++程序

2011-06-28 14:11:33

JavaScript

2009-12-22 13:05:15

Linux sysfs

2023-12-13 10:01:15

數(shù)據(jù)結(jié)構(gòu)c++編程

2017-02-28 18:26:09

Linuxinput子系統(tǒng)編程

2009-06-16 10:51:14

Java源碼

2024-10-14 13:30:20

2010-03-08 14:53:48

Linux分區(qū)

2023-03-15 21:46:17

中間件Java網(wǎng)絡(luò)編程

2018-10-31 15:54:47

Java線程池源碼

2009-07-03 11:14:57

2016-10-21 13:03:18

androidhandlerlooper

2021-09-08 10:47:33

Flink執(zhí)行流程

2019-07-08 20:00:35

Linux內(nèi)核模塊

2009-11-30 16:46:29

學(xué)習(xí)Linux
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)