proc介绍
proc文件系统是linux中的一个虚拟文件系统,内核运行时将内核中一些关键的数据结构以文件的方式呈现在/proc目录中的一些特定文件中,这样相当于将不可见的内核中的数据结构以可视化的方式呈现给开发者。我们通过观察/proc/xxx文件,可以直观的观察到一些特定的数据结构的值。
例如:
/proc/cpuinfo :处理器的相关信息的文件
/proc/cmdline:在启动时传递至内核的相关参数信息,这些信息通常由lilo或grub等启动管理工具进行传递
/proc/devices :系统已经加载的所有块设备和字符设备的信息,包含主设备号和设备组(与主设备号对应的设备类型)名
/proc/modules:标识了当前加载到内核中的模块
/proc/pci:显示当前在pci总线上能找到的设备
。。。
对proc中文件的读写操作方法
[root@admin]# cat /proc/sys/net/ipv4/ip_forward
0
[root@admin]# echo "1" > /proc/sys/net/ipv4/ip_forward
[root@admin]# cat /proc/sys/net/ipv4/ip_forward
1
[root@admin]#
/proc 文件系统并不是 GNU/Linux 系统中的惟一一个虚拟文件系统。在这种系统上,sysfs 是一个与 /proc 类似的文件系统,但是它的组织更好(从 /proc 中学习了很多教训)。不过 /proc 已经确立了自己的地位,因此即使 sysfs 与 /proc 相比有一些优点,/proc 也依然会存在。还有一个 debugfs 文件系统,不过(顾名思义)它提供的更多是调试接口。debugfs 的一个优点是它将一个值导出给用户空间非常简单(实际上这不过是一个调用而已)。
创建/proc中目录
在/proc中创建一个目录,接收要创建的目录名,父目录的结构体指针,如果为空,就在/proc目录下创建一个目录
struct proc_dir_entry *proc_mkdir( const char *name , struct proc_dir_entry *parent );
创建\删除 proc项
在/proc中创建一个虚拟文件,使用下面函数,接收一个文件名,一组权限,和这个文件在/proc文件系统中的位置。
//创建
//linux版本小于3.10.0使用该接口
struct proc_dir_entry *create_proc_entry( const char *name, mode_t mode,
struct proc_dir_entry *parent );
//linux版本大于等于3.10.0使用该接口
struct proc_dir_entry *proc_create_data(const char *name, umode_t mode, struct
proc_dir_entry *parent,
const struct file_operations *proc_fops, void * data);
//删除
void remove_proc_entry( const char *name, struct proc_dir_entry *parent );
//还有一种方法创建proc文件,还没用过,但是方法类似
struct proc_dir_entry *proc_create(const char *name, mode_t mode, struct proc_dir_entry
*parent, const struct file_operations *proc_fops)
proc_dir_entry结构体部分内容:
struct proc_dir_entry {
const char *name; // virtual file name
mode_t mode; // mode permissions
uid_t uid; // File's user id
gid_t gid; // File's group id
struct inode_operations *proc_iops; // Inode operations functions
struct file_operations *proc_fops; // File operations functions
struct proc_dir_entry *parent; // Parent directory
...
read_proc_t *read_proc; // /proc read function
write_proc_t *write_proc; // /proc write function
void *data; // Pointer to private data
atomic_t count; // use count
...
};
proc_dir_entry 快捷变量
proc_dir_entry | 在文件系统中的位置 |
---|---|
proc_root_fs | /proc |
proc_net | /proc/net |
proc_bus | /proc/bus |
proc_root_driver | /proc/driver |
其他proc创建函数
这个函数在procfs目录下创建一个从name指向dest的符号链接. 它在用户空间等效为ln -s dest name
struct proc_dir_entry *proc_symlink(const char *name, struct proc_dir_entry *parent, const char *dest)
读写回调函数
可以使用 write_proc
向 /proc 中写入数据。
也可以使用 read_proc
从一个 /proc 项中读出数据(内核空间到用户空间)
这两个函数原型如下:
int mod_write( struct file *filp, const char __user *buff,
unsigned long len, void *data );
int mod_read( char *page, char **start, off_t off,
int count, int *eof, void *data );
示例代码
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/fs.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/uaccess.h>
char str[]="this a text!";
static struct proc_dir_entry * test_entry = NULL;
static struct proc_dir_entry * test_root = NULL;
static ssize_t test_read(struct file * file,char __user *data,size_t len,loff_t *off)
{
char *ptr = PDE_DATA(file_inode(file)); //获取proc_create_data传入的私有数据。
printk("%s\n",ptr);
printk("proc read。。。\n");
return 0;
}
static ssize_t test_write(struct file * file,const char __user* data,size_t len,loff_t *off)
{
printk("proc write。。。\n");
return len;
}
static struct file_operations test_proc_ops = {
.owner = THIS_MODULE,
.read = test_read,
.write = test_write
};
static int proc_init(void)
{
proc_root = proc_mkdir("test_dir", NULL);
test_entry = proc_create_data("test_node", 0666, proc_root, &test_proc_ops, &str);
if(!test_entry){
printk(KERN_ERR"can't create proc file \n" );
return -EFAULT;
}
return 0;
}
static void proc_exit(void)
{
if(test_entry)
{
remove_proc_entry("test_node",proc_root);
}
}
module_init(proc_init);
module_exit(proc_exit);
procfs有一个缺陷,如果输出内容大于1个内存页,需要多次读,因此处理起来很难,另外,如果输出太大,速度比较慢,有时会出现一些意想不到的情况
GUN/linux系统中还有一种虚拟文件系统是sys文件系统,和proc文件系统类似,但是组织更加友好,读/sys中的文件就是获取内核中数据结构的值,而写入/sys中的文件就是设置内核中的数据结构的元素的值。后续再专门再分析一下这个文件系统。