proc_create的使用方法
proc文件系統是個有用的東東。
創建一個proc虛擬文件,應用層通過讀寫該文件,即可實現與內核的交互。
proc虛擬文件是如何創建的呢?
先看看比較簡單的,創建proc文件夾。
調用以下函數,即可實現proc文件夾的創建:
struct proc_dir_entry *proc_mkdir(const char *name, struct proc_dir_entry *parent);
name就是要創建的文件夾名稱。
parent是要創建節點的父節點。也就是要在哪個文件夾之下創建新文件夾,需要將那個文件夾的proc_dir_entry傳入。
如果是在/proc目錄下創建文件夾,parent為NULL。
例如:
struct proc_dir_entry *mytest_dir = proc_mkdir("mytest", NULL);
然后來看看proc文件的創建。
創建方法是調用以下函數:
static inline struct proc_dir_entry *proc_create(const char *name, mode_t mode, struct proc_dir_entry *parent, const struct file_operations *proc_fops);
name就是要創建的文件名。
mode是文件的訪問權限,以UGO的模式表示。
parent與proc_mkdir中的parent類似。也是父文件夾的proc_dir_entry對象。
proc_fops就是該文件的操作函數了。
例如:
struct proc_dir_entry *mytest_file = proc_create("mytest", 0x0644, mytest_dir, mytest_proc_fops);
還有一種方式:
struct proc_dir_entry *mytest_file = proc_create("mytest/mytest", 0x0644, NULL, mytest_proc_fops);
如果文件夾名稱和文件名定義為常量:
#define MYTEST_PROC_DIR "mytest" #define MYTEST_PROC_FILE "mytest"
第二種方式為:
struct proc_dir_entry *mytest_file = proc_create(MYTEST_PROC_DIR"/"MYTEST_PROC_FILE, 0x0644, NULL, mytest_proc_fops);
接下來看看mytest_proc_fops的定義。
static const struct file_operations mytest_proc_fops = { .open = mytest_proc_open, .read = seq_read, .write = mytest_proc_write, .llseek = seq_lseek, .release = single_release, };
以seq_和single_為前綴的函數都是kernel中現成的。
可以參考文檔:Documentation\filesystems\seq_file.txt
關於single_開頭的函數,有以下說明:
The extra-simple version
For extremely simple virtual files, there is an even easier interface. A
module can define only the show() function, which should create all the
output that the virtual file will contain. The file's open() method then
calls:
int single_open(struct file *file, int (*show)(struct seq_file *m, void *p), void *data);
When output time comes, the show() function will be called once. The data
value given to single_open() can be found in the private field of the
seq_file structure. When using single_open(), the programmer should use
single_release() instead of seq_release() in the file_operations structure
to avoid a memory leak.
根據以上這段說明,在mytest_proc_open函數中,只需要調用single_open函數,並傳入一個show函數即可。
例如:
static int mytest_proc_open(struct inode *inode, struct file *file) { return single_open(file, mytest_proc_show, inode->i_private); }
其中第三個參數,也就是single_open的data參數,內核中有些地方傳入的NULL,有些地方傳入的inode->i_private,也有傳入其他值的。
來看看data在single_open函數中如何被使用的:
if (!res)
((struct seq_file *)file->private_data)->private = data;
這與前面的英文說明一致,data是seq_file結構體的private成員。
那么data如何真正被使用的呢?
發現show函數的第一個參數為seq_file類型,在show函數中,可以將seq_file的private成員轉換成對應的類型進行使用。
下面來看看mytest_proc_show函數如何實現。
傳遞給single_open的show函數指針,將在proc file輸出時被調用。
例如,cat /proc/mytest/mytest時,mytest_proc_show函數將會被調用。
假設我們的mytest只是記錄了一個標志,內核中會根據該標准執行不同的操作。
來看看mytest_proc_show的實現:
static int task_lifecycle_proc_show(struct seq_file *seq, void *v) { seq_puts(seq, mytest_flag ? "true\n" : "false\n"); return 0; }
接下來再看看mytest_proc_write函數的實現。
顧名思義,mytest_proc_write函數會在寫mytest文件時被調用。
功能就是記錄寫入數據到mytest文件。
實現也不麻煩:
static ssize_t task_lifecycle_proc_write(struct file *file, const char __user *buffer, size_t count, loff_t *pos) { char mode; if (count > 0) { if (get_user(mode, buffer)) return -EFAULT; mytest_flag = (mode != '0'); } return count; }
至此,proc文件創建完畢。
通過讀寫mytest文件,即可實現對mytest_flag的控制。
更深層次的原理,即proc文件系統是如何實現的,就先不討論了。
不然又成懶婆娘的裹腳了