sysfs文件系統
sysfs,全稱為System Filesystem,是一個由Linux內核實現的虛擬文件系統。它扮演著一個橋梁的角色,將內核中的設備和驅動程序信息以文件的形式呈現給用戶空間。與/proc文件系統相似,sysfs專注于展示設備和驅動程序的細節,而/proc則主要反映進程信息。
在sysfs中,信息被組織成層次化的文件系統結構。每個設備或內核對象在文件系統中都有其對應的表示,通常是以文件或目錄的形式存在。這些文件不僅存儲了設備的屬性和狀態信息,而且很多文件還允許用戶通過讀寫操作來對設備進行配置或控制。
sysfs默認掛載在文件系統的/sys路徑下。通過這個虛擬文件系統,用戶空間的應用程序能夠以一種直觀和動態的方式訪問和管理系統設備,無需進行復雜的內核空間交互。這種設計提供了一種高效且用戶友好的接口,使得設備管理變得更加簡單和靈活。
kernel Object
在Linux內核架構中,kobject扮演著一個核心角色,它是一個用于抽象化內核對象的框架。kobject不僅構成了內核中各種子系統的基礎構件,而且能夠代表設備、驅動程序、總線等多樣化的內核實體。
kobject架構提供了一種靈活且統一的模型,用以維護和管理內核對象。每個Kobject實例都擁有一個獨一無二的標識符和指向其上層Kobject的鏈接,這樣的設計允許它們形成一個有序的層級網絡。更進一步,Kobject可以附加多種屬性,這些屬性反映了對象的特征或狀態,并且可以通過sysfs這一虛擬文件系統對外公布,使得用戶空間程序能夠訪問和操作這些屬性。
Sysfs作為Kobject信息呈現的媒介,將內核內部的設備和驅動程序等對象的狀態和信息以文件的形式展現給用戶空間。每當內核中新增設備或驅動程序時,相應的Kobject實例也會被動態創建,并通過Sysfs將這些信息映射到用戶空間可訪問的路徑下。
在Linux內核的源碼樹中,struct kobject這一數據結構在"linux/kobject.h"頭文件里定義。它經常作為其他結構體的成員出現,使得這些結構體所代表的內核對象能夠整合進Kobject的管理體系中。通過這種方式,內核開發者可以輕松地為各種內核對象實現統一的管理和訪問接口。
structkobject{ constchar*name; structlist_headentry; structkobject*parent; structkset*kset; structkobj_type*ktype; structkernfs_node*sd;/*sysfsdirectoryentry*/ structkrefkref; ... };
其中:- kref:提供kobject的引用技術。- ktype:kobject關聯的類型。- kset:指向同一類kobject集合的指針。- sd:當前kobject在/sys下的目錄條目。
sysfs使用方式
Linux內核中使用sysfs的步驟比較簡單:(1)在sys路徑下創建目錄;(2)創建sysfs文件。下面將詳細展開這兩步涉及的內核API。
在sys下創建目錄
structkobject*kobject_create_and_add(constchar*name,structkobject*parent);
Linux內核預定義了幾個常用的parent參數:- kernel_kobj:在/sys/kernel下創建目錄;- firmware_kobj:在/sys/firmware下創建目錄;- fs_kobj:在/sys/fs下創建目錄。- 如果parent取值為NULL,則在/sys下面創建目錄。
相應地,如果需要刪除對應的sysfs目錄,可以用:
voidkobject_put(structkobject*kobj);
創建sysfs文件
sysfs文件可以通過sysfs屬性來創建,它定義在頭文件"sysfs.h"中:
structkobj_attribute{ structattributeattr; ssize_t(*show)(structkobject*kobj,structkobj_attribute*attr,char*buf); ssize_t(*store)(structkobject*kobj,structkobj_attribute*attr,constchar*buf,size_tcount); };
attr表示將要創建的文件(屬性),而show和store分別表示對應的sysfs文件在讀和寫操作時的回調函數。
struct kobj_attribute可以通過__ATTR宏來創建:
__ATTR(name,permission,show_ptr,store_ptr);
準備好attr之后,可以通過sysfs_create_file來創建出sysfs文件:
intsysfs_create_file(structkobject*kobj,conststructattribute*attr);
如果需要刪除對應的sysfs文件,可以用:
voidsysfs_remove_file(structkobject*kobj,conststructattribute*attr);
sysfs創建設備節點
前面描述了如何創建一個基本的sysfs,接下載描述的是如何創建設備節點的sysfs。
實際創建設備節點的sysf跟基本的sysfs是一樣的,只是結構體換了一個名字。它使用DEVICE_ATTR宏,可以定義一個struct device_attribute設備屬性,使用sysfs_create_file便可以在設備目錄下創建具有show和store方法的節點。
DEVICE_ATTR宏定義
DEVICE_ATTR宏定義如下:
#defineDEVICE_ATTR(_name,_mode,_show,_store) structdevice_attributedev_attr_##_name=__ATTR(_name,_mode,_show,_store)
__ATTR宏定義,宏定義在include/linux/sysfs.h文件中,如下:
#define__ATTR(_name,_mode,_show,_store){ .attr={.name=__stringify(_name), .mode=VERIFY_OCTAL_PERMISSIONS(_mode)}, .show=_show, .store=_store, }
struct device_attribute結構體,該結構體的定義在include /linux/device.h,其定義如下:
structdevice_attribute{ structattributeattr; ssize_t(*show)(structdevice*dev,structdevice_attribute*attr, char*buf); ssize_t(*store)(structdevice*dev,structdevice_attribute*attr, constchar*buf,size_tcount); };
struct attribute結構體, 該結構體的定義在include /linux/device.h,其定義如下:
structattribute{ constchar*name; umode_tmode; #ifdefCONFIG_DEBUG_LOCK_ALLOC boolignore_lockdep:1; structlock_class_key*key; structlock_class_keyskey; #endif };
DEVICE_ATTR宏定義等價說明
我們頂一個文件的范式如下
DEVICE_ATTR(_name,_mode,_show,_store)
等價于:
structdevice_attributedev_attr_##_name={ .attr={.name=__stringify(_name), .mode=VERIFY_OCTAL_PERMISSIONS(_mode)}, .show=_show, .store=_store, }
show函數的詳細描述:
ssize_t(*show)(structdevice*dev,structdevice_attribute*attr,char*buf);
參數說明:
入參buf是需要我們填充的string即我們cat屬性節點時要顯示的內容;-函數的返回值是我們填充buf的長度,且長度應當小于一個頁面的大小(4096字節);
其他參數一般不用關心。
實例說明,當我們使用cat命令的時候,將調用該函數
staticssize_tshow_youyeetoo_device(structdevice*dev, structdevice_attribute*attr,char*buf) { returnsprintf(buf,"%sn",mybuf); }
store函數的詳細描述:
ssize_t(*store)(structdevice*dev,structdevice_attribute*attr,constchar*buf,size_tcount);
參數說明:
入參buf是用戶傳入的字符串,即echo到屬性節點的內容;
入參count是buf中字符串的長度。
函數的返回值通常返回count即可。
其他參數一般不用關心。
實例說明,當我們使用echo命令的時候,將調用該函數:
staticssize_tstore_youyeetoo_device(structdevice*dev, structdevice_attribute*attr, constchar*buf,size_tcount) { sprintf(mybuf,"%s",buf); returncount; }
mode的權限定義,在kernel/include/uapi/linux/stat.h中:
#defineS_IRWXU00700//用戶可讀寫和執行 #defineS_IRUSR00400//用戶可讀 #defineS_IWUSR00200//用戶可寫 #defineS_IXUSR00100//用戶可執行 #defineS_IRWXG00070//用戶組可讀寫和執行 #defineS_IRGRP00040//用戶組可讀 #defineS_IWGRP00020//用戶組可寫 #defineS_IXGRP00010//用戶組可執行 #defineS_IRWXO00007//其他可讀寫和執行 #defineS_IROTH00004//其他可讀 #defineS_IWOTH00002//其他可寫 #defineS_IXOTH00001//其他可執行
至此,我們已經定義好了.show和.store函數,那么就可以使用DEVICE_ATTR了。
staticDEVICE_ATTR(youyeetoo_device,S_IWUSR|S_IRUSR,show_youyeetoo_device,store_youyeetoo_device);
device attribute添加到sysfs
上面描述的是sysfs的讀寫接口的定義方式,他還需要注冊到sysfs中。才會在對應驅動中顯示我們的文件,其中:
注冊函數:sysfs_create_file();
注銷函數:sysfs_remove_file();
樣例代碼代碼:
注冊樣例:
sysfs_create_file(&(youyeetoo_dev->kobj),&dev_attr_youyeetoo.attr);
注銷樣例:
sysfs_remove_file(&(youyeetoo_dev->kobj),&dev_attr_youyeetoo.attr);
sysfs樣例測試
完整的測試代碼,在sysfs的驅動節點里面生成一個youyeetoo文件,文件支持讀寫功能。
#include #include #include #include #include staticintmajor; staticstructclass*youyeetoo_class; structdevice*youyeetoo_dev; staticcharyouyeetoo_buff[100]="youyeetoo"; staticssize_tshow_youyeetoo_device(structdevice*dev, structdevice_attribute*attr,char*buf) { returnsprintf(buf,"%sn",youyeetoo_buff); } staticssize_tstore_youyeetoo_device(structdevice*dev, structdevice_attribute*attr, constchar*buf,size_tcount) { sprintf(youyeetoo_buff,"%s",buf); returncount; } staticDEVICE_ATTR(youyeetoo,S_IWUSR|S_IRUSR,show_youyeetoo_device,store_youyeetoo_device); structfile_operationsyouyeetoo_ops={ .owner=THIS_MODULE, }; staticintyouyeetoo_init(void) { major=register_chrdev(0,"youyeetoo",&youyeetoo_ops); youyeetoo_class=class_create(THIS_MODULE,"youyeetoo"); youyeetoo_dev=device_create(youyeetoo_class,0,MKDEV(major,0),NULL,"youyeetoo"); if(sysfs_create_file(&(youyeetoo_dev->kobj),&dev_attr_youyeetoo.attr)) {//在mytest_device設備目錄下創建一個sys_device_file屬性文件 return-1; } return0; } staticvoidyouyeetoo_exit(void) { device_destroy(youyeetoo_class,MKDEV(major,0)); class_destroy(youyeetoo_class); unregister_chrdev(major,"youyeetoo"); sysfs_remove_file(&(youyeetoo_dev->kobj),&dev_attr_youyeetoo.attr); } module_init(youyeetoo_init); module_exit(youyeetoo_exit); MODULE_AUTHOR("youyeetoo"); MODULE_LICENSE("GPL");
將上面驅動編譯燒錄之后,就可以sysfs下看到我們創建的文件:
測試我們創建的sysfs
審核編輯 黃宇
-
Linux
+關注
關注
87文章
11292瀏覽量
209328 -
Sysfs
+關注
關注
0文章
15瀏覽量
6236
發布評論請先 登錄
相關推薦
評論