/proc是Linux上的一種虛擬文件系統,存儲的是當前內核運行狀態的一系列特殊文件,用戶可以通過這些文件查看有關係統硬件及當前正在運行進程的信息,甚至可以更改其中某些文件來改變內核的運行狀態。
現編寫一個內核模塊,在/proc文件系統中增加一個目錄hello,並在這個目錄中增加一個文件world,文件的內容爲hello world。
實驗環境
Ubuntu 18.04.1,源碼內核版本:Linux-4.2.6
-
獲取內核源碼
wget http://mirrors.aliyun.com/linux-kernel/v4.x/linux-4.2.6.tar.xz # 下載內核源碼
xz –d *.tar.xz # 將源碼解壓爲tar格式
tar –xvf *.tar # 將源碼解壓至當前目錄
實現proc系統的代碼主要在linux/fs/proc目錄下。該目錄下的文件如下圖所示。
創建目錄
在Linux內核網址https://www.kernel.org/doc/html/latest/查閱相關文檔可知,proc中創建目錄的函數爲proc_mkdir,該函數原型爲:
struct proc_dir_entry *proc_mkdir(const char *name, struct proc_dir_entry *parent);
該函數接受兩個參數,分別爲要創建的目錄的名稱以及一個指向該目錄的父目錄的指針,並返回指向當前目錄的指針結構體。
創建文件
考慮到在/proc目錄下有version和softirqs等文件,且源碼中有以上文件的實現,分別爲version.c和softirqs.c,則可參考這兩個文件的實現進一步實現創建world文件。以version.c爲例,部分代碼如下圖所示。
顯然,創建version文件的函數爲proc_create,查閱文檔可知,該函數原型爲:
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);
該函數接收4個參數,第一個參數爲文件名,第二個參數爲文件的讀寫權限,第三個參數爲其父目錄的結構體指針,第四個參數爲文件的讀寫操作結構體。
參照/proc/version文件的實現代碼和本實驗要求,可寫出創建world文件的主要代碼:
其中,world文件的父目錄指針即爲先前創建hello目錄所返回的指針,proc_fops定義了該文件所能執行的操作,由於本實驗只要求讀取文件內容,因此只實現了read屬性:
其中,read_proc爲實現讀取文件內容的函數指針,其實現如下:
該函數將文件內容通過msg複製給buf,以此實現文件內容的讀取。
最後,再分別定義該模塊的初始化和清理函數,其實現如下:
編寫Makefile
爲編譯該模塊,還需編寫Makefile文件,該文件內容如圖所示:
結果
結果如圖所示。由圖可見,/proc目錄下生成了hello目錄,且該目錄下的world文件的內容爲hello world。
運行與驗證
儘管本實驗的內核版本爲Linux-4.2.6,但是經測試可知,該模塊在3.10及以上版本均可使用。
爲使用該模塊,首先需要下載3.10及以上Linux內核版本並解壓,然後將proc_hello.c文件拷貝至Linux/fs/proc目錄下,由於該目錄下原本就有Makefile文件,因此要對原Makefile文件備份後再拷貝本實驗中的Makefile:
mv Makefile Makefile.bak
mv my_makefile Makefile
然後,再使用make命令編譯模塊:
編譯成功後,再使用insmod命令安裝模塊,可以看到該目錄下多了一個ko文件,該文件即爲編譯成功的模塊文件。
最後切換至/proc目錄,即可看到上述結果。
完整實現代碼已上傳至我的github。
參考資料
[1] Robert Love, Robert Love. Linux內核設計與實現(原書第3版)[M].陳莉君,譯.機械工業出版社,2011
[2] Daniel P. Bovet, Marco Cesati. 深入理解LINUX內核(第三版)[M].陳莉君,張瓊聲,張宏偉,譯.中國電力出版社,2007
[3] https://www.jianshu.com/p/a6c33bf39067 編譯安裝 Linux 內核並添加系統調用
[4] https://tuxthink.blogspot.com/2013/10/creating-read-only-proc-entry-in-kernel.html