Linux編寫內核模塊及文件讀寫

sysfs是什麼

sysfs是一個基於內存的文件系統,它的作用是將內核信息以文件的方式提供給用戶程序使用。該文件系統的目錄層次結構嚴格按照內核的數據結構組織。除了二進制文件外(只有特殊場合才使用),sysfs文件內容均以ASCII格式保存,且一個文件只保存一個數據,另外,一個文件不可大於一個內存頁(通常爲4096字節)。

項目要求將char數組保存到屬性文件,下面將介紹如何完成。

Linux內核模塊是什麼

內核模塊是Linux內核向外部提供的一個插口,其全稱爲動態可加載內核模塊(LoadableKernel Module,LKM),我們簡稱爲模塊。Linux內核之所以提供模塊機制,是因爲它本身是一個單內核(monolithic kernel)。單內核的最大優點是效率高,因爲所有的內容都集成在一起,但其缺點是可擴展性和可維護性相對較差,模塊機制就是爲了彌補這一缺陷。

模塊是具有獨立功能的程序,它可以被單獨編譯,但不能獨立運行。它在運行時被鏈接到內核作爲內核的一部分在內核空間運行,這與運行在用戶空間的進程是不同的。模塊通常由一組函數和數據結構組成,用來實現一種文件系統、一個驅動程序或其他內核上層的功能。

總之,模塊是一個爲內核(從某種意義上來說,內核也是一個模塊)或其他內核模塊提供使用功能的代碼塊。

 

Linux內核模塊編寫

首先得包含內核模塊編程所需的頭文件,一般以下三種需要包含:

linux/module.h,該頭文件作用是動態的將模塊加載到內核中

linux/kernel.h,該頭文件包含了常用的內核函數

linux/init.h,該頭文件包含了宏_init和_exit,它們允許釋放內核佔用的內存

接下來就是模塊加載函數和模塊卸載函數。

加載函數需要添加_init標識,如

static int __init ***_init(void)

    返回0表示加載成功,失敗則返回一些錯誤代碼,參考<linux/errno.h>,在加載函數中一般用於初始化硬件,申請資源。

卸載函數需要添加_exit標識,如

static void __exit ***_exit(void)

一般在該函數完成以下幾件事情,        

若模塊加載函數中註冊了***,則在模塊卸載函數中需註銷;

    若在模塊加載函數中動態申請了內存,則在此亦需要釋放;

 

若在模塊加載中申請了一些硬件資源(如:IRQ, DMA channel,I/O ,memory),則在此需釋放。

然後通過module_init(***_init)函數告訴內核編寫的模塊從哪裏開始執行,參數就是註冊函數的函數名;通過module_exit(***_exit)函數告訴內核編寫的模塊從哪裏推出,參數就是卸載函數的函數名。

gcc編譯的時候需要加上 modules 參數,表示編譯爲內核模塊,如下圖所示


    下面介紹如何在初始化的時候從用戶空間讀文件內容並寫入該內核模塊的屬性文件中。

 

 

內核模塊讀寫文件

首先簡單瞭解下linux文件讀寫的工作流程

 

所以,在內核中打開文件,需要通過filp_open 函數,其參數與open函數一樣, 原形如下

strcut file* filp_open(const char* filename, int open_mode, intmode);

然後通過get_fs()取得當前的設置,並通過set_fs()改變kernel對內存地址檢查的處理方式,其原形如下:

void set_fs(mm_segment_t fs);

然後才能使用vfs_read 和vfs_write這兩個函數對文件進行讀寫。原形如下

ssize_t vfs_read(struct file* filp, char __user* buffer, size_t len,loff_t* pos);

ssize_t vfs_write(struct file* filp, const char __user* buffer,size_t len, loff_t* pos);

最後通過filp_close關閉文件。

具體實現過程如下:

 

內核模塊創建屬性文件

首先調用kobject_create_and_add函數,動態創建一個kobject結構並註冊到sysfs,函數原形如下

struct kobject *kobject_create_and_add(const char *name, structkobject *parent)

接下來屬性文件通過函數sysfs_create_file建立。這個也同時建立了文件與操作之間的聯繫和對應。函數原形如下

int sysfs_create_file(helloworld_kobj, &hello_value_attribute)

當完成前面調用後之後. 調用kobject_put,這樣kobject結構在不再使用時將會動態的釋放。函數原形如下

void kobject_put(struct kobject *kobj)

具體實現過程如下


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章