用户与内核空间数据交换的方式(2)-procfs

来源:互联网 发布:成都网络广播电视台 编辑:程序博客网 时间:2024/05/22 02:12

原文:http://www.embeddedlinux.org.cn/html/yingjianqudong/201304/17-2552.html


procfs是比较老的一种用户态与内核态的数据交换方式,内核的很多数据都是通过这种方式出口给用户的,内核的很多参数也是通过这种方式来让用户方便设置的。除了sysctl出口到/proc下的参数,procfs提供的大部分内核参数是只读的。实际上,很多应用严重地依赖于procfs,因此它几乎是必不可少的组件。本节将讲解如何使用procfs。
Procfs提供了如下API: 

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

该函数用于创建一个正常的proc条目,参数name给出要建立的proc条目的名称,参数mode给出了建立的该proc条目的访问权限,参数 parent指定建立的proc条目所在的目录。如果要在/proc下建立proc条目,parent应当为NULL。否则它应当为proc_mkdir 返回的struct proc_dir_entry结构的指针。 

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

该函数用于删除上面函数创建的proc条目,参数name给出要删除的proc条目的名称,参数parent指定建立的proc条目所在的目录。 

struct proc_dir_entry *proc_mkdir(const char * name, struct proc_dir_entry *parent)

该函数用于创建一个proc目录,参数name指定要创建的proc目录的名称,参数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)

该函数用于建立一个proc条目的符号链接,参数name给出要建立的符号链接proc条目的名称,参数parent指定符号连接所在的目录,参数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);

该函数用于建立一个规则的只读proc条目,参数name给出要建立的proc条目的名称,参数mode给出了建立的该proc条目的访问权限,参 数base指定建立的proc条目所在的目录,参数read_proc给出读去该proc条目的操作函数,参数data为该proc条目的专用数据,它将 保存在该proc条目对应的struct file结构的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);

该函数用于创建一个info型的proc条目,参数name给出要建立的proc条目的名称,参数mode给出了建立的该proc条目的访问权限, 参数base指定建立的proc条目所在的目录,参数get_info指定该proc条目的get_info操作函数。实际上get_info等同于 read_proc,如果proc条目没有定义个read_proc,对该proc条目的read操作将使用get_info取代,因此它在功能上非常类似于函数create_proc_read_entry。 

struct proc_dir_entry *proc_net_create(const char *name, mode_t mode, get_info_t *get_info)

该函数用于在/proc/net目录下创建一个proc条目,参数name给出要建立的proc条目的名称,参数mode给出了建立的该proc条目的访问权限,参数get_info指定该proc条目的get_info操作函数。

struct proc_dir_entry *proc_net_fops_create(const char *name, mode_t mode, struct file_operations *fops)

该函数也用于在/proc/net下创建proc条目,但是它也同时指定了对该proc条目的文件操作函数。 

void proc_net_remove(const char *name)

该函数用于删除前面两个函数在/proc/net目录下创建的proc条目。参数name指定要删除的proc名称。
除了这些函数,值得一提的是结构struct proc_dir_entry,为了创建一了可写的proc条目并指定该proc条目的写操作函数,必须设置上面的这些创建proc条目的函数返回的指针 指向的struct proc_dir_entry结构的write_proc字段,并指定该proc条目的访问权限有写权限。
为了使用这些接口函数以及结构struct proc_dir_entry,用户必须在模块中包含头文件linux/proc_fs.h。
在源代码包中给出了procfs示例程序procfs_exam.c,它定义了三个proc文件条目和一个proc目录条目,读者在插入该模块后应当看到如下结构:

$ ls /proc/myproctest
aint astring bigprocfile
$

读者可以通过cat和echo等文件操作函数来查看和设置这些proc文件。特别需要指出,bigprocfile是一个大文件(超过一个内存
页),对于这种大文件,procfs有一些限制,因为它提供的缓存,只有一个页,因此必须特别小心,并对超过页的部分做特别的考虑,处理起来比较复杂并且
很容易出错,所有procfs并不适合于大数据量的输入输出,后面一节seq_file就是因为这一缺陷而设计的,当然seq_file依赖于 procfs的一些基础功能。

//kernel module: procfs_exam.c
#include <linux/config.h>
#include
<linux/kernel.h>
#include
<linux/module.h>
#include
<linux/proc_fs.h>
#include
<linux/sched.h>
#include
<linux/types.h>
#include
<asm/uaccess.h>

#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)) //从用户空间中得到数据
 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");
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 收到的快递坏了怎么办 自寄的快递少了怎么办 邮的东西弄坏了怎么办 物流签收后发现货物损坏怎么办 发现客人损坏了酒店物品怎么办 东西坏了签收了怎么办 朋友圈贩卖三无产品你怎么办 付钱给微商没有保障怎么办 电镀锌钢带生锈怎么办 电机机油从空气滤芯里流出怎么办 把塑料皮套吃了怎么办 塑料框眼镜有点小了怎么办 出口纸箱打了钉怎么办 买房子交款单据丢了怎么办 买房子所有单据丢失怎么办 车险单据都丢了怎么办 真空包装的东西里面有空气怎么办 发货物忘记写唛头了怎么办 Word文档撤销按钮删除了怎么办 ai保存时未响应怎么办 ai还没保存卡了怎么办 ai卡住了没保存怎么办 屁股沟有硬块红肿怎么办 卧室床选太大了怎么办 画板的笔尖掉了怎么办 宜家水壶盖子有水怎么办 背滤鱼缸除油膜怎么办 书多了没地方放怎么办 学生在教室内丢手机怎么办 新车尾箱坏了怎么办 放书的箱子烂了怎么办 车钥匙锁后备箱里怎么办 布的收纳箱有味怎么办 车漆清漆层掉了怎么办 副驾驶储物箱卡子断了怎么办 玛莎拉蒂车门打不开怎么办 新买的水杯漏水怎么办 泰迪小狗掉毛怎么办 手机jlc调用接口状态异常怎么办 进门和厕所对着怎么办 p过的照片有竖条怎么办