編寫乙個簡單的proc檔案

2021-05-27 08:31:23 字數 3956 閱讀 2144

proc檔案的實現也需要編寫出乙個核心模組並插入核心。模組的編寫過程我們已經hello,module過了,而proc檔案的實現稍微複雜一些。

在linux核心模組編寫中,常常會有一些結構體,結構體中定義了很多函式指標,核心模組的編寫常常是圍繞著實現這些函式指標而進行的。實現了這些介面便可以呼叫相應的函式把相應的功能模組插入核心(拗口),以下是proc檔案的結構體介面描述:

//linux/proc_fs.h

//讀函式原型

typedef int (read_proc_t)(char *page, char **start, off_t off,

int count, int *eof, void *data);

//寫函式原型

typedef int (write_proc_t)(struct file *file, const char __user *buffer,

unsigned long count, void *data);

struct proc_dir_entry ;

/*建立乙個proc結構體

@name: proc檔案的名字

@mode:

@parent: proc檔案被建立的目錄

*/struct proc_dir_entry *create_proc_entry(const char *name, mode_t mode,struct proc_dir_entry *parent);

/*從核心中移除乙個proc檔案

*/void remove_proc_entry(const char *name, struct proc_dir_entry *parent) ;

已經有一些預定義的proc目錄可直接作為parent使用:

proc_dir_entry

在檔案系統中的位置

proc_root_fs/proc

proc_net/proc/net

proc_bus/proc/bus

proc_root_driver/proc/driver

write_proc_t 函式(寫函式):使用者空間到核心空間

很明顯,write_proc_t函式的實現賦予proc 寫語義,它的原型如下:

int (write_proc_t)(struct file *file, const char __user *buffer, unsigned long count, void *data);

引數file可忽略,buffer為使用者空間需要寫入的資料的頭指標,count 為使用者空間需要寫入核心的資料長度,data為proc結構體得私有資料,對應於 struct  proc_dir_entry結構體中的data欄位。編碼過程中常常需要將使用者空間的資料拷貝到核心,因為使用者空間的指標不能在核心空間中使用(那不是很多拷貝,效率不是很低..),常見的拷貝函式有以下兩枚

/* copy buffer to user-space from kernel-space */

unsigned long copy_to_user( void __user *to, const void *from,unsigned long n );

/* copy buffer to kernel-space from user-space */

unsigned long copy_from_user( void *to,const void __user *from, unsigned long n );

__user巨集只是方便源**查詢而已,沒有實際語義。這兩個copy函式可能會造成阻塞,故只能在程序上下文中使用,如果在中斷上下文中使用,那恭喜你,你的核心會莫名的掛掉了。

read_proc_t 函式(讀函式):核心空間到使用者空間

typedef int (read_proc_t)(char *page, char **start, off_t off, int count, int *eof, void *data);

當某個程序讀取我們的proc檔案時,核心會分配乙個記憶體頁(即page_size大小的記憶體塊),核心模組將資料寫入到這張頁來返回資料到使用者空間。

以上引數中,page引數是為程序分配的記憶體頁,其中count定義了定義了可以寫入的最大字元數。在返回多頁資料(通常一頁是4k),我們需要使用start和off引數。當所有資料全部寫入後,就需要設定eof(檔案結束引數)。與write類似,data也是私有資料。此處提供的page緩衝區在核心空間。因此不必使用copy_to_user,而可以直接寫入。該函式返回寫入的位元組數。

start引數:start引數使用者實現返回大於一頁的資料。在read_proc_t方法被呼叫時,*start的初始值為null。如果保留*start為null,核心將家丁資料儲存在記憶體頁偏移量0的地方,並且忽略off引數。相反,如果我們將*start設為非空值,核心將認為由*start指向的資料是off引數指定的偏移量中的資料。通常返回少量資料的簡單read_proc函式可忽略start引數,複雜的read_proc函式將*start設定為頁面,並將請求偏移量處得資料放到記憶體頁。

start引數還有另一種用法,將在下文繼續討論。

以下內容實現乙個簡單的可讀寫的proc檔案例子:  

#include#include#include#include#include#includemodule_license("gpl");

module_description("fortune cookie kernel module");

#define max_cookie_length page_size

//儲存proc結構體指標

static struct proc_dir_entry *proc_entry;

//儲存緩衝區指標

static char *cookie_pot;

// cookie_index=已經寫入的資料數目-1 。

static int cookie_index;

//遍歷標

static int next_fortune;

ssize_t fortune_write(struct file *filp,const char __user *buff,

unsigned long len, void *data)

if(copy_from_user(&cookie_pot[cookie_index],buff,len ) )

return -efault;

cookie_index+=len;

cookie_pot[cookie_index-1]=0;

return len;

}//每讀一次返回乙個之前寫入的字串。

int fortune_read(char *page,char **start,off_t off,

int count ,int *eof,void *data)

if( next_fortune >= cookie_index ) next_fortune= 0 ;

len=sprintf(page,"%s\n", &cookie_pot[ next_fortune ] ) ;

next_fortune+=len;

return len; }

int init_fortune_module(void)

else

}return ret;

}void cleanup_fortune_module(void)

module_init(init_fortune_module);

module_exit(cleanup_fortune_module);

上文實現了乙個可以讀寫的proc檔案。讀者可以往/proc/fortune中寫入字串後再讀取來檢視該模組的行為。

編寫乙個簡單的shell

include include include include include include include include void getloginname void gethostname void getdir p printf s p int main char argv 32 char...

編寫乙個簡單的死鎖

public class dead lock1 class runnable1 implements runnable catch exception e class runnable2 implements runnable catch exception e obj1 和 obj2 都是屬於類的...

乙個簡單的makefile的編寫

標頭檔案 part.h cpp檔案 包含part.h part.cpp cpp檔案 包含part.h partmain.cpp makefile編寫如下 main partmain.o part.o g o main partmain.o part.o partmain.o partmain.cpp...