您的位置:首页 > 其它

proc文件系统

2016-03-08 15:12 459 查看

1.proc文件系统

proc文件系统是由内核实现的文件系统。当用户态访问/proc下文件时,实际上是调用内核中和该文件对应的特定函数。
一般用proc文件来实现内核/驱动的调用。

大部分proc文件是只读的,用于获取内核信息;

还有一些proc文件是可写的,当用户态改变了proc文件的内容时,会调用内核的函数,从而改变内核的对应行为。这些可写的文件,一般集中在/proc/sys下

proc文件系统和sysfs文件系统类似,是虚拟文件系统,存在于内存中,用于内核和用户程序交互等,查看内核信息。

基于/proc文件系统如上所述的特殊性,其内的文件也常被称作虚拟文件,并具有一些独特的特点。例如,其中有些文件虽然使用查看命令查看时会返回大量信息,但文件本身的大小却会显示为0字节。此外,这些特殊文件中大多数文件的时间及日期属性通常为当前系统时间和日期,这跟它们随时会被刷新(存储于RAM中)有关。为了查看及使用上的方便,这些文件通常会按照相关性进行分类存储于不同的目录甚至子目录中,如/proc/scsi目录中存储的就是当前系统上所有SCSI设备的相关信息,/proc/N中存储的则是系统当前正在运行的进程的相关信息,其中N为正在运行的进程(可以想象得到,在某进程结束后其相关目录则会消失)。

/proc 文件系统是由软件创建,被内核用来向外界报告信息的一个文件系统。/proc 下面的每一个文件都和一个内核函数相关联,当文件的被读取时,与之对应的内核函数用于产生文件的内容。我们已经见到了很多这样的文件,例如,/proc/modules 总是返回当前内核中加载的模块。

2.proc相关函数

(1)创建一个 proc 文件

structproc_dir_entry*create_proc_entry(const char *name, mode_t mode, structproc_dir_entry*parent)

这是最直接,包装最少的创建方法。

参数 name 是要创建的 proc 文件名。

mode 是该文件权限值,例如 S_IRUGO,可传入0表示采用系统默认值。

parent 指定该文件的上层 proc 目录项,如果为 NULL,表示创建在 /proc 根目录下。create_proc_entry()完成的任务主要包括:检测 mode 值,分配 proc_dir_entry 结构,注册 proc_dir_entry。

(2)读 proc 文件

proc 文件的读需要自己提供一个read_proc_t类型的函数放在proc_dir_entry 结构中供proc_file_read() 函数调用。

下面是read_proc_t 类型函数的定义:typedef int (read_proc_t)(char *page, char **start, off_t off, intcount, int*eof, void *data);

这个函数的定义很复杂,不过当proc 文件返回的数据量总是小于一个PAGE_SIZE 时可以简化使用。关于这个函数以及它的那一大串参数我觉得再怎么解释都解释不全,所以还是留给自己去看 proc_file_read() 的代码就明白了。

(3)写 proc 文件

proc 文件的写很简单。如果是使用proc_fs 默认提供的file_operations的话,要自己实现一个write_proc_t 类型的函数放在proc_dir_entry 结构中供proc_file_write() 函数调用。write_proc_t 类型函数的定义如下:

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

(4)删除一个 proc 项

要删除一个 proc 文件或目录就调用 voidremove_proc_entry(const char *name, struct proc_dir_entry*parent)

3.创建自己的proc文件

(1)proc_rw.c
#include <linux/module.h>
#include <linux/proc_fs.h>
#include <linux/sched.h>
#include <linux/uaccess.h>  //copy_to|from_user

//在str中存储用户态write到文件的字符串
static char *str;

//proc文件的读函数
static int my_proc_read(char *page, char **start, off_t off, int count, int *eof, void *data)
{
int ret = 0,val = 0;

//先输出时间,后输出从外部写入的内容
ret = sprintf(page, "kernel time: %ld\n", jiffies);
ret += sprintf(page+ret, "str is %s\n", str);

return ret;
}

//proc文件的写函数
static int my_proc_write(struct file *filp, const char __user *buf, unsigned long count, void *data)
{
//为从用户态拷贝字符串分配空间
char *tmp = kzalloc(count, GFP_KERNEL);
if (!tmp)
return -ENOMEM;

//将字符串从用户态拷贝到内核态
if (copy_from_user(tmp, buf, count)) {
kfree(tmp);
return -EFAULT;
}

//释放旧的字符串,可以是null,为了清空之前存在的内容,每次都是覆盖
kfree(str);
str = tmp;

return count;
}

static int __init my_init(void)
{
struct proc_dir_entry *file;

//1.创建文件/proc/abc_rw
file = create_proc_entry("abc_rw", 0644, NULL);
if (!file) {
printk("Cannot create /proc/abc_rw\n");
return -EPERM;
}

//2.关联读写函数
file->read_proc = my_proc_read;
file->write_proc = my_proc_write;

return 0;
}

static void __exit my_exit(void)
{
//删除proc文件并释放str的空间
remove_proc_entry("abc_rw", NULL);
kfree(str);
}

module_init(my_init);
module_exit(my_exit);
MODULE_AUTHOR("JX");
MODULE_LICENSE("GPL");


(2)Makefile
obj-m:=proc_rw.o
KERNEL := /lib/modules/`uname -r`/build

all:
make -C $(KERNEL) M=`pwd` modules
install:
make -C $(KERNEL) M=`pwd` modules_install
depmod -A
clean:
make -C $(KERNEL) M=`pwd` clean

创建的是一个可以读写proc文件,下面是操作过程

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: