1?前言
內(nèi)核中有三個(gè)常用的偽文件系統(tǒng):procfs,debugfs和sysfs。
procfs — The proc filesystem is a pseudo-filesystem which provides an interface to kernel data structures.
sysfs —?The?filesystem for exporting kernel objects.
debugfs — Debugfs exists as a simple way for kernel developers to make information available to user space.
它們都用于Linux內(nèi)核和用戶空間的數(shù)據(jù)交換,但是適用的場(chǎng)景有所差異:
procfs 歷史最早,最初就是用來跟內(nèi)核交互的唯一方式,用來獲取處理器、內(nèi)存、設(shè)備驅(qū)動(dòng)、進(jìn)程等各種信息。
sysfs 跟 kobject 框架緊密聯(lián)系,而 kobject 是為設(shè)備驅(qū)動(dòng)模型而存在的,所以 sysfs 是為設(shè)備驅(qū)動(dòng)服務(wù)的。
debugfs 從名字來看就是為debug而生,所以更加靈活。
它們仨的掛載方式類似,做個(gè)實(shí)驗(yàn):
$ sudo mkdir?/tmp/{proc,sys,debug}
$ sudo mount?-t proc nondev?/tmp/proc/
$ sudo mount?-t sys nondev?/tmp/sys/
$ sudo mount?-t debugfs nondev?/tmp/debug/
不過,默認(rèn)情況下,它們分別掛載在/proc,/sys/,/sys/kernel/debug/。
下面簡(jiǎn)單介紹這三個(gè)文件系統(tǒng)的用法。在介紹之前,請(qǐng)記下他們的官方文檔:
procfs — Documentation/filesystems/proc.txt
sysfs — Documentation/filesystems/sysfs.txt
debugfs — Documentation/filesystems/debugfs.txt
2?debugfs
API說明
struct?dentry?*debugfs_create_dir(const?char?*name,?struct?dentry?*parent)
struct?dentry?*debugfs_create_file(const?char?*name,?umode_t?mode,
struct?dentry?*parent,?void?*data,
const?struct?file_operations?*fops)
參考實(shí)例
drivers/base/power/wakeup.c:
/**
* wakeup_sources_stats_show - Print wakeup sources statistics information.
* @m: seq_file to print the statistics into.
*/
static?int?wakeup_sources_stats_show(struct?seq_file?*m,?void?*unused)
{
struct?wakeup_source?*ws;
seq_puts(m,?"name active_count event_count wakeup_count "
"expire_count active_since total_time max_time "
"last_change prevent_suspend_time ");
rcu_read_lock();
list_for_each_entry_rcu(ws,?&wakeup_sources,?entry)
print_wakeup_source_stats(m,?ws);
rcu_read_unlock();
return?0;
}
static?int?wakeup_sources_stats_open(struct?inode?*inode,?struct?file?*file)
{
return?single_open(file,?wakeup_sources_stats_show,?NULL);
}
static?const?struct?file_operations wakeup_sources_stats_fops?=?{
.owner?=?THIS_MODULE,
.open?=?wakeup_sources_stats_open,
.read?=?seq_read,
.llseek?=?seq_lseek,
.release?=?single_release,
};
static?int?__init wakeup_sources_debugfs_init(void)
{
wakeup_sources_stats_dentry?=?debugfs_create_file("wakeup_sources",
S_IRUGO,?NULL,?NULL,?&wakeup_sources_stats_fops);
return?0;
}
創(chuàng)建完的接口
/sys/kernel/debug/wakup_sources
給接口添加多級(jí)目錄
上述接口直接創(chuàng)建在?debugfs?根目錄(/sys/kernel/debug)下,所以?debugfs_create_file的parent參數(shù)被設(shè)置成了NULL,如果要加一級(jí)目錄,則可以先用debugfs_create_dir?創(chuàng)建一級(jí)目錄,例如,要?jiǎng)?chuàng)建:/sys/kernel/debug/power/wakeup_sources?的話,則需要:
struct?dentry?*power;
int?err?=?-ENOMEM;
power?=?debugfs_create_dir("clock",?NULL);
if?(!power)
return?err;
wakeup_sources_stats_dentry?=?debugfs_create_file("wakeup_sources",
S_IRUGO,?power,?NULL,?&wakeup_sources_stats_fops);
3?procfs
proc_mkdir?用法跟?debugfs_create_dir?幾無差異。
API說明
static?inline?struct?proc_dir_entry?*proc_mkdir(const?char?*name,?struct?proc_dir_entry?*parent)
static?inline?struct?proc_dir_entry?*proc_create(const?char?*name,?umode_t?mode,
struct?proc_dir_entry?*parent,?const?struct?file_operations?*proc_fops)
參考實(shí)例
在上面例子的基礎(chǔ)上,可以添加如下語句:
static?int?__init wakeup_sources_debugfs_init(void)
{
proc_create("wakelocks",?S_IFREG?|?S_IRUGO,?NULL,?&wakeup_sources_stats_fops);
return?0;
}
創(chuàng)建后的接口
/proc/wakelocks
給接口添加多級(jí)目錄
這樣創(chuàng)建的接口用起來跟?/sys/kernel/debug/wakeup_sources?沒有任何差異,類似地,如果要加一級(jí)目錄,例如?/proc/power/wakelocks,則可以:
struct?proc_dir_entry?*power;
int?err?=?-ENOMEM;
power?=?proc_mkdir("power",?NULL);
if?(!power)
return?err;
proc_create("wakelocks",?S_IFREG?|?S_IRUGO,?power,?&wakeup_sources_stats_fops);
4?sysfs
在?sysfs?中,有另外一個(gè)常見用法,那就是在一個(gè) kobject 對(duì)應(yīng)的目錄下創(chuàng)建一個(gè)符號(hào)(屬性文件)指向另外一個(gè) kobject 對(duì)應(yīng)的目錄,通常這個(gè)是為了方便記憶和訪問。這個(gè)API是?sysfs_create_link。
這種創(chuàng)建符號(hào)鏈接方法其實(shí)有一個(gè)很特殊的實(shí)例,那就是在驅(qū)動(dòng)模型里頭,有一個(gè)?class?的概念,它把掛在不同總線上,但是實(shí)現(xiàn)類似功能的設(shè)備進(jìn)行歸類,比如說?input類,backlight?類等。
如果設(shè)備屬于一個(gè)現(xiàn)存的類,比如?backlight,那么可以用?backlight_device_register?創(chuàng)建,如果是?I2C?設(shè)備,會(huì)先在I2C下創(chuàng)建?sysfs?訪問節(jié)點(diǎn),并創(chuàng)建一個(gè)符號(hào)鏈接到?backlight?類所屬的目錄下。
當(dāng)然,如果沒有找到設(shè)備能掛的直觀的類,也可以用?class_create?創(chuàng)建類,設(shè)備類通常會(huì)有一組默認(rèn)的設(shè)備操作接口,例如?backlight?類有?bl_device_attributes,如果要?jiǎng)?chuàng)建更多的設(shè)備特定的節(jié)點(diǎn),可以用?device_create_file?或者?device_add_groups?創(chuàng)建節(jié)點(diǎn)或者節(jié)點(diǎn)群。
API說明
struct?kobject?*kobject_create_and_add(const?char?*name,?struct?kobject?*parent)
int?sysfs_create_file(struct?kobject?*?kobj,?const?struct?attribute?*?attr)
static?inline?int?sysfs_create_link(struct?kobject?*kobj,?struct?kobject?*target,?const?char?*name)
int?device_create_file(struct?device?*dev,?const?struct?device_attribute?*attr)
參考實(shí)例
在?/sys/power?下創(chuàng)建一個(gè) wakelocks 節(jié)點(diǎn),用于讀/寫一個(gè)字符串。
static?char?test_str[11];
static?ssize_t?show_wakelocks(struct?kobject?*kobj,?struct?attribute?*attr,?char?*buf)
{
int?ret;
ret?=?snprintf(buf,?10,?"%s ",?test_str);
return?ret;
}
static?ssize_t?store_wakelocks(struct?kobject?*kobj,?struct?attribute?*attr,
const?char?*buf,?size_t?count)
{
int?tmp;
ret?=?sscanf(buf,?"%10s",?test_str);
if?(ret?!=?1)
return?-EINVAL;
return?count;
}
define_one_global_rw(wakelocks);
static?int?__init wakelocks_init(void)
{
int?ret;
ret?=?sysfs_create_file(power_kobj,?&wakelocks.attr);
}
創(chuàng)建后的節(jié)點(diǎn)
/sys/power/test_node
給接口添加多級(jí)目錄
咱們上面其實(shí)已經(jīng)把 test_node 創(chuàng)建在?/sys/power?目錄下,而非根目錄?/sys?下,而參數(shù) power_kobj 為內(nèi)核已經(jīng)在?kernel/power/main.c?創(chuàng)建的kobject對(duì)象。
struct?kobject?*power_kobj;
power_kobj?=?kobject_create_and_add("power",?NULL);
if?(!power_kobj)
return?-ENOMEM;
5?小結(jié)
通過比較發(fā)現(xiàn),上述三個(gè)文件系統(tǒng)的 API 用法類似,而其中?debugfs?和?procfs?幾乎有相同的參數(shù),用的主要結(jié)構(gòu)體是?struct file_operations,蠻多操作可以用?seq_*?家族的函數(shù)來實(shí)現(xiàn)。而?sysfs?則用到比較簡(jiǎn)單一些的?struct global_attr?結(jié)構(gòu)體。對(duì)于提供給用戶空間的節(jié)點(diǎn),都可以輕松實(shí)現(xiàn)讀寫操作。
在創(chuàng)建目錄方面,debugfs?和?procfs?類似,且比較簡(jiǎn)單。而?sysfs?要?jiǎng)?chuàng)建一級(jí)目錄,需要先創(chuàng)建一個(gè) kobject 對(duì)象。
為了簡(jiǎn)化設(shè)備模型依據(jù)總線創(chuàng)建的訪問節(jié)點(diǎn)路徑,sysfs?提供了API用于創(chuàng)建更簡(jiǎn)易的符號(hào)鏈接,可以創(chuàng)建到自己指定的目錄下,也可以用設(shè)備類(Class)提供的API創(chuàng)建到設(shè)備類所屬的目錄下。
對(duì)于?sysfs,由于?kobject?與?device?的一對(duì)一依存關(guān)系,也可以直接用?device_create_file?來創(chuàng)建節(jié)點(diǎn)。
?
評(píng)論
查看更多