1?前言
內核中有三個常用的偽文件系統(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內核和用戶空間的數(shù)據(jù)交換,但是適用的場景有所差異:
procfs 歷史最早,最初就是用來跟內核交互的唯一方式,用來獲取處理器、內存、設備驅動、進程等各種信息。
sysfs 跟 kobject 框架緊密聯(lián)系,而 kobject 是為設備驅動模型而存在的,所以 sysfs 是為設備驅動服務的。
debugfs 從名字來看就是為debug而生,所以更加靈活。
它們仨的掛載方式類似,做個實驗:
$ 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/
不過,默認情況下,它們分別掛載在/proc,/sys/,/sys/kernel/debug/。
下面簡單介紹這三個文件系統(tǒ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)
參考實例
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
給接口添加多級目錄
上述接口直接創(chuàng)建在?debugfs?根目錄(/sys/kernel/debug)下,所以?debugfs_create_file的parent參數(shù)被設置成了NULL,如果要加一級目錄,則可以先用debugfs_create_dir?創(chuà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)
參考實例
在上面例子的基礎上,可以添加如下語句:
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
給接口添加多級目錄
這樣創(chuàng)建的接口用起來跟?/sys/kernel/debug/wakeup_sources?沒有任何差異,類似地,如果要加一級目錄,例如?/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?中,有另外一個常見用法,那就是在一個 kobject 對應的目錄下創(chuàng)建一個符號(屬性文件)指向另外一個 kobject 對應的目錄,通常這個是為了方便記憶和訪問。這個API是?sysfs_create_link。
這種創(chuàng)建符號鏈接方法其實有一個很特殊的實例,那就是在驅動模型里頭,有一個?class?的概念,它把掛在不同總線上,但是實現(xiàn)類似功能的設備進行歸類,比如說?input類,backlight?類等。
如果設備屬于一個現(xiàn)存的類,比如?backlight,那么可以用?backlight_device_register?創(chuàng)建,如果是?I2C?設備,會先在I2C下創(chuàng)建?sysfs?訪問節(jié)點,并創(chuàng)建一個符號鏈接到?backlight?類所屬的目錄下。
當然,如果沒有找到設備能掛的直觀的類,也可以用?class_create?創(chuàng)建類,設備類通常會有一組默認的設備操作接口,例如?backlight?類有?bl_device_attributes,如果要創(chuàng)建更多的設備特定的節(jié)點,可以用?device_create_file?或者?device_add_groups?創(chuàng)建節(jié)點或者節(jié)點群。
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)
參考實例
在?/sys/power?下創(chuàng)建一個 wakelocks 節(jié)點,用于讀/寫一個字符串。
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é)點
/sys/power/test_node
給接口添加多級目錄
咱們上面其實已經把 test_node 創(chuàng)建在?/sys/power?目錄下,而非根目錄?/sys?下,而參數(shù) power_kobj 為內核已經在?kernel/power/main.c?創(chuàng)建的kobject對象。
struct?kobject?*power_kobj;
power_kobj?=?kobject_create_and_add("power",?NULL);
if?(!power_kobj)
return?-ENOMEM;
5?小結
通過比較發(fā)現(xiàn),上述三個文件系統(tǒng)的 API 用法類似,而其中?debugfs?和?procfs?幾乎有相同的參數(shù),用的主要結構體是?struct file_operations,蠻多操作可以用?seq_*?家族的函數(shù)來實現(xiàn)。而?sysfs?則用到比較簡單一些的?struct global_attr?結構體。對于提供給用戶空間的節(jié)點,都可以輕松實現(xiàn)讀寫操作。
在創(chuàng)建目錄方面,debugfs?和?procfs?類似,且比較簡單。而?sysfs?要創(chuàng)建一級目錄,需要先創(chuàng)建一個 kobject 對象。
為了簡化設備模型依據(jù)總線創(chuàng)建的訪問節(jié)點路徑,sysfs?提供了API用于創(chuàng)建更簡易的符號鏈接,可以創(chuàng)建到自己指定的目錄下,也可以用設備類(Class)提供的API創(chuàng)建到設備類所屬的目錄下。
對于?sysfs,由于?kobject?與?device?的一對一依存關系,也可以直接用?device_create_file?來創(chuàng)建節(jié)點。
?
評論
查看更多