procfs是比較老的一種用戶態(tài)與內(nèi)核態(tài)的數(shù)據(jù)交換方式,內(nèi)核的很多數(shù)據(jù)都是通過這種方式出口給用戶的,內(nèi)核的很多參數(shù)也是通過這種方式來讓用戶方便設(shè)置的。除了sysctl出口到/proc下的參數(shù),procfs提供的大部分內(nèi)核參數(shù)是只讀的。實際上,很多應(yīng)用嚴重地依賴于procfs,因此它幾乎是必不可少的組件。本節(jié)將講解如何使用procfs。
Procfs提供了如下API:?
struct proc_dir_entry *create_proc_entry(const char *name, mode_t mode, struct proc_dir_entry *parent)
該函數(shù)用于創(chuàng)建一個正常的proc條目,參數(shù)name給出要建立的proc條目的名稱,參數(shù)mode給出了建立的該proc條目的訪問權(quán)限,參數(shù) parent指定建立的proc條目所在的目錄。如果要在/proc下建立proc條目,parent應(yīng)當為NULL。否則它應(yīng)當為proc_mkdir 返回的struct proc_dir_entry結(jié)構(gòu)的指針。?
extern void remove_proc_entry(const char *name, struct proc_dir_entry *parent)
該函數(shù)用于刪除上面函數(shù)創(chuàng)建的proc條目,參數(shù)name給出要刪除的proc條目的名稱,參數(shù)parent指定建立的proc條目所在的目錄。?
struct proc_dir_entry *proc_mkdir(const char * name, struct proc_dir_entry *parent)
該函數(shù)用于創(chuàng)建一個proc目錄,參數(shù)name指定要創(chuàng)建的proc目錄的名稱,參數(shù)parent為該proc目錄所在的目錄。?
extern struct proc_dir_entry *proc_mkdir_mode(const char *name, mode_t mode, struct proc_dir_entry *parent)
struct proc_dir_entry *proc_symlink(const char * name, struct proc_dir_entry* parent, const char *dest)
該函數(shù)用于建立一個proc條目的符號鏈接,參數(shù)name給出要建立的符號鏈接proc條目的名稱,參數(shù)parent指定符號連接所在的目錄,參數(shù)dest指定鏈接到的proc條目名稱。
struct proc_dir_entry *create_proc_read_entry(const char *name, mode_t mode, struct proc_dir_entry *base,
read_proc_t *read_proc, void * data);
該函數(shù)用于建立一個規(guī)則的只讀proc條目,參數(shù)name給出要建立的proc條目的名稱,參數(shù)mode給出了建立的該proc條目的訪問權(quán)限,參 數(shù)base指定建立的proc條目所在的目錄,參數(shù)read_proc給出讀去該proc條目的操作函數(shù),參數(shù)data為該proc條目的專用數(shù)據(jù),它將 保存在該proc條目對應(yīng)的struct file結(jié)構(gòu)的private_data字段中。
struct proc_dir_entry *create_proc_info_entry(const char *name, mode_t mode, struct proc_dir_entry *base,
get_info_t *get_info);
該函數(shù)用于創(chuàng)建一個info型的proc條目,參數(shù)name給出要建立的proc條目的名稱,參數(shù)mode給出了建立的該proc條目的訪問權(quán)限, 參數(shù)base指定建立的proc條目所在的目錄,參數(shù)get_info指定該proc條目的get_info操作函數(shù)。實際上get_info等同于 read_proc,如果proc條目沒有定義個read_proc,對該proc條目的read操作將使用get_info取代,因此它在功能上非常類似于函數(shù)create_proc_read_entry。?
struct proc_dir_entry *proc_net_create(const char *name, mode_t mode, get_info_t *get_info)
該函數(shù)用于在/proc/net目錄下創(chuàng)建一個proc條目,參數(shù)name給出要建立的proc條目的名稱,參數(shù)mode給出了建立的該proc條目的訪問權(quán)限,參數(shù)get_info指定該proc條目的get_info操作函數(shù)。
struct proc_dir_entry *proc_net_fops_create(const char *name, mode_t mode, struct file_operations *fops)
該函數(shù)也用于在/proc/net下創(chuàng)建proc條目,但是它也同時指定了對該proc條目的文件操作函數(shù)。?
void proc_net_remove(const char *name)
該函數(shù)用于刪除前面兩個函數(shù)在/proc/net目錄下創(chuàng)建的proc條目。參數(shù)name指定要刪除的proc名稱。
除了這些函數(shù),值得一提的是結(jié)構(gòu)struct proc_dir_entry,為了創(chuàng)建一了可寫的proc條目并指定該proc條目的寫操作函數(shù),必須設(shè)置上面的這些創(chuàng)建proc條目的函數(shù)返回的指針 指向的struct proc_dir_entry結(jié)構(gòu)的write_proc字段,并指定該proc條目的訪問權(quán)限有寫權(quán)限。
為了使用這些接口函數(shù)以及結(jié)構(gòu)struct proc_dir_entry,用戶必須在模塊中包含頭文件linux/proc_fs.h。
在源代碼包中給出了procfs示例程序procfs_exam.c,它定義了三個proc文件條目和一個proc目錄條目,讀者在插入該模塊后應(yīng)當看到如下結(jié)構(gòu):
$ ls /proc/myproctest
aint astring bigprocfile
$
讀者可以通過cat和echo等文件操作函數(shù)來查看和設(shè)置這些proc文件。特別需要指出,bigprocfile是一個大文件(超過一個內(nèi)存
頁),對于這種大文件,procfs有一些限制,因為它提供的緩存,只有一個頁,因此必須特別小心,并對超過頁的部分做特別的考慮,處理起來比較復雜并且
很容易出錯,所有procfs并不適合于大數(shù)據(jù)量的輸入輸出,后面一節(jié)seq_file就是因為這一缺陷而設(shè)計的,當然seq_file依賴于 procfs的一些基礎(chǔ)功能。
//kernel module: procfs_exam.c
#include
#include
#include
#include
#include
#include
#include
#define STR_MAX_SIZE 255
static int int_var;
static char string_var[256];
static char big_buffer[65536];
static int big_buffer_len = 0;
static struct proc_dir_entry * myprocroot;
static int first_write_flag = 1;
int int_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data)
{
count = sprintf(page, "%d", *(int *)data);
return count;
}
int int_write_proc(struct file *file, const char __user *buffer,unsigned long count, void *data)
{
unsigned int c = 0, len = 0, val, sum = 0;
int * temp = (int *)data;
while (count) {
if (get_user(c, buffer)) //從用戶空間中得到數(shù)據(jù)
?return -EFAULT;
len++;
buffer++;
count--;
if (c == 10 || c == 0)
break;
val = c - '0';
if (val > 9)
return -EINVAL;
sum *= 10;
sum += val;
}
* temp = sum;
return len;
}
int string_read_proc(char *page, char **start, off_t off,int count, int *eof, void *data)
{
count = sprintf(page, "%s", (char *)data);
return count;
}
int string_write_proc(struct file *file, const char __user *buffer, unsigned long count, void *data)
{
if (count > STR_MAX_SIZE) {
count = 255;
}
copy_from_user(data, buffer, count);
return count;
}
int bigfile_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data)
{
if (off > big_buffer_len) {
* eof = 1;
return 0;
}
if (count > PAGE_SIZE) {
count = PAGE_SIZE;
}
if (big_buffer_len - off < count) {
count = big_buffer_len - off;
}
memcpy(page, data, count);
*start = page;
return count;
}
int bigfile_write_proc(struct file *file, const char __user *buffer, unsigned long count, void *data)
{
char * p = (char *)data;
if (first_write_flag) {
big_buffer_len = 0;
first_write_flag = 0;
}
if (65536 - big_buffer_len < count) {
count = 65536 - big_buffer_len;
first_write_flag = 1;
}
copy_from_user(p + big_buffer_len, buffer, count);
big_buffer_len += count;
return count;
}
static int __init procfs_exam_init(void)
{
#ifdef CONFIG_PROC_FS
struct proc_dir_entry * entry;
myprocroot = proc_mkdir("myproctest", NULL);
entry = create_proc_entry("aint", 0644, myprocroot);
if (entry) {
entry->data = &int_var;
entry->read_proc = &int_read_proc;
entry->write_proc = &int_write_proc;
}
entry = create_proc_entry("astring", 0644, myprocroot);
if (entry) {
entry->data = &string_var;
entry->read_proc = &string_read_proc;
entry->write_proc = &string_write_proc;
}
entry = create_proc_entry("bigprocfile", 0644, myprocroot);
if (entry) {
entry->data = &big_buffer;
entry->read_proc = &bigfile_read_proc;
entry->write_proc = &bigfile_write_proc;
}
#else
printk("This module requires the kernel to support procfs,\n");
#endif
return 0;
}
static void __exit procfs_exam_exit(void)
{
#ifdef CONFIG_PROC_FS
remove_proc_entry("aint", myprocroot);
remove_proc_entry("astring", myprocroot);
remove_proc_entry("bigprocfile", myprocroot);
remove_proc_entry("myproctest", NULL);
#endif
}
module_init(procfs_exam_init);
module_exit(procfs_exam_exit);
MODULE_LICENSE("GPL");
?
評論
查看更多