proc系统使用
Posted feisonzl
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了proc系统使用相关的知识,希望对你有一定的参考价值。
1.proc系统
1.1 proc系统简介
/proc 文件系统包含了一些目录(用作组织信息的方式)和虚拟文件。虚拟文件可以向用户呈现内核中的一些信息,也可以用作一种从用户空间向内核发送信息的手段。可以通过/proc系统中的一些节点了解系统的运行状况和系统配置信息。
1.2 /proc节点的创建和使用
1.创建和删除节点
要在 /proc 文件系统中创建一个虚拟文件,请使用 create_proc_entry 函数。这个函数可以接收一个文件名、一组权限和这个文件在 /proc 文件系统中出现的位置。create_proc_entry 的返回值是一个 proc_dir_entry 指针(或者为 NULL,说明在 create 时发生了错误)。然后就可以使用这个返回的指针来配置这个虚拟文件的其他参数,例如在对该文件执行读操作时应该调用的函数。create_proc_entry 的原型和 proc_dir_entry 结构如下所示。
struct proc_dir_entry *create_proc_entry( const char *name, mode_t mode,
struct proc_dir_entry *parent );
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
...
;
void remove_proc_entry( const char *name, struct proc_dir_entry *parent );
parent 参数可以为 NULL(表示 /proc 根目录),也可以是很多其他值,这取决于我们希望将这个文件放到什么地方。下面列出了可以使用的其他一些父 proc_dir_entry,以及它们在这个文件系统中的位置。
proc_root_fs: /proc
proc_net: /proc/net
proc_bus: /proc/bus
proc_root_driver: /proc/driver
2.写回调函数
int mod_write( struct file *filp, const char __user *buff, unsigned long len, void *data );
filp:该节点文件结构
buff:用户空间传递的字符串数据,需使用copy_from_user拷贝至内核空间
len:buff的长度
data:私有数据结构
3.读回调函数
int mod_read( char *page, char **start, off_t off, int count, int *eof, void *data );
page:数据写入位置,page的缓冲区在内核空间,无需使用copy_to_user
start/off:当写入多页数据(大文件)时,使用的参数(实现大文件又更好的方法,见seq_file)
count:允许写入的最大数据长度
eof:当所有数据写入完成后,设置eof参数(文件结束符)
data:私有数据结构
4.其它常用函数
/* Create a directory in the proc filesystem */
struct proc_dir_entry *proc_mkdir( const char *name,
struct proc_dir_entry *parent );
/* Create a symlink in the proc filesystem */
struct proc_dir_entry *proc_symlink( const char *name,
struct proc_dir_entry *parent,
const char *dest );
/* Create a proc_dir_entry with a read_proc_t in one call */
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 );
1.3 测试源码
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
#include <linux/vmalloc.h>
#include <linux/proc_fs.h>// for the proc filesystem
#include <linux/seq_file.h>// for sequence files
#include <linux/jiffies.h>// for jiffies
#define MAX_COOKIE_SIZE PAGE_SIZE
static struct proc_dir_entry *proc_entry;
static char *cookie;
static int cookie_index=0;
static int read_pos=0;
ssize_t proc_write(struct file *filp,const char __user *buff,unsigned long len,void *data)
int available_space=MAX_COOKIE_SIZE-cookie_index+1;
printk("%s\\n",__func__);
if(len>available_space)
printk("no space to write!\\n");
return -ENOSPC;
if(copy_from_user(&cookie[cookie_index],buff,len))
return -EFAULT;
printk("%s\\n",&cookie[cookie_index]);
cookie_index+=len;
cookie[cookie_index-1]=0;
return len;
ssize_t proc_read(char *page,char **start,off_t off,int count,int *eof,void *data)
int len;
printk("%s\\n",__func__);
if(off>0)
*eof=1;
return 0;
if(read_pos>=cookie_index) read_pos=0;
len=sprintf(page,"%s\\n",&cookie[read_pos]);
read_pos+=len;
return len;
static int proc_init()
int ret=0;
printk(KERN_ERR "HELLO INIT!\\n");
cookie=(char *)vmalloc(MAX_COOKIE_SIZE);
if(cookie==NULL)
printk("create cookie error!\\n");
ret=-ENOMEM;
proc_entry=create_proc_entry("cookie_test",0666,NULL);
if(proc_entry==NULL)
printk("create_proc_entry error!\\n");
ret=-ENOMEM;
vfree(cookie);
else
cookie_index=0;
read_pos=0;
proc_entry->read_proc=proc_read;
proc_entry->write_proc=proc_write;
//proc_entry->owner = THIS_MODULE;
printk("proc init success!\\n");
return ret;
static void proc_exit()
remove_proc_entry(proc_entry,NULL);
vfree(cookie);
printk(KERN_ERR "HELLO EXIT!\\n");
module_init(proc_init);
module_exit(proc_exit);
MODULE_LICENSE("Dual BSD/GPL");
2.seq_file
经过第一节,我们发现完成一个proc节点有点复杂,为了方便开发者,内核提供了一组跟简单的seq_file接口。
2.1 seq_file接口
struct seq_operations
void * (*start) (struct seq_file *m, loff_t *pos);
void (*stop) (struct seq_file *m, void *v);
void * (*next) (struct seq_file *m, void *v, loff_t *pos);
int (*show) (struct seq_file *m, void *v);
;
调用流程:
1.首先调用start函数,通常为申请内存等操作,整个序列开始,如果start返回值不为NULL则进入第2步;
2.调用show函数,它将数据值写入供用户读取的缓冲区中;
3.调用next函数,该函数是一个迭代器,其目的是为了遍历所有数据,next函数返回NULL则结束调用,序列结束,进入第4步;
4.调用stop函数,一般是释放内存等操作;之后回到start函数继续下一个序列操作,直到start函数返回NULL;
执行调用的核心函数是static int traverse(struct seq_file *m, loff_t offset),该函数在seq_read和seq_lseek中被调用,以下是源码:
static int traverse(struct seq_file *m, loff_t offset)
loff_t pos = 0, index;
int error = 0;
void *p;
m->version = 0;
index = 0;
m->count = m->from = 0;
if (!offset)
m->index = index;
return 0;
if (!m->buf)
m->buf = seq_buf_alloc(m->size = PAGE_SIZE);
if (!m->buf)
return -ENOMEM;
p = m->op->start(m, &index);
while (p)
error = PTR_ERR(p);
if (IS_ERR(p))
break;
error = m->op->show(m, p);
if (error < 0)
break;
if (unlikely(error))
error = 0;
m->count = 0;
if (seq_overflow(m))
goto Eoverflow;
if (pos + m->count > offset)
m->from = offset - pos;
m->count -= m->from;
m->index = index;
break;
pos += m->count;
m->count = 0;
if (pos == offset)
index++;
m->index = index;
break;
p = m->op->next(m, p, &index);
m->op->stop(m, p);
m->index = index;
return error;
Eoverflow:
m->op->stop(m, p);
kvfree(m->buf);
m->count = 0;
m->buf = seq_buf_alloc(m->size <<= 1);
return !m->buf ? -ENOMEM : -EAGAIN;
2.2 其他常用接口
对于简单的虚拟文件(只需实现show函数),single_open是一个非常有用的接口:
int single_open(struct file *file,
int (*show)(struct seq_file *m, void *p),
void *data);
实现show函数一般可以使用seq_printf函数,等价于printf函数:
int seq_printf(struct seq_file *, const char *, ...);
以下函数均由内核实现:
int seq_open(struct file *, const struct seq_operations *);
ssize_t seq_read(struct file *, char __user *, size_t, loff_t *);
loff_t seq_lseek(struct file *, loff_t, int);
int seq_release(struct inode *, struct file *);
int seq_escape(struct seq_file *, const char *, const char *);
int seq_putc(struct seq_file *m, char c);
int seq_puts(struct seq_file *m, const char *s);
int seq_write(struct seq_file *seq, const void *data, size_t len);
2.3 测试源码
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
#include <linux/vmalloc.h>
#include <linux/proc_fs.h>// for the proc filesystem
#include <linux/seq_file.h>// for sequence files
#include <linux/jiffies.h>// for jiffies
static struct proc_dir_entry *proc_entry;
static int seq_proc_show(struct seq_file *s,void *v)
return seq_printf(s,"%s\\n","it is a test!");
static struct seq_operations seq_seq_ops=
.show=seq_proc_show,
;
static int seq_proc_open(struct inode *inode,struct file *filp)
//return seq_open(filp,&seq_seq_ops);
return single_open(filp,seq_proc_show,NULL);
static struct file_operations seq_ops=
.owner=THIS_MODULE,
.open = seq_proc_open,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release
;
static int proc_init()
int ret=0;
printk(KERN_ERR "HELLO INIT!\\n");
/* you can create proc node in one of 2 ways */
/*
* 1.
* proc_entry=create_proc_entry("proc_seq",0666,NULL);
* if(proc_entry)
* proc_entry->proc_fops=&seq_ops;
* 2.
* proc_entry=proc_create("proc_seq",0666,NULL,&seq_ops);
* */
proc_entry=proc_create("proc_seq",0666,NULL,&seq_ops);
if(proc_entry==NULL)
printk("create_proc_entry error!\\n");
ret=-ENOMEM;
else
printk("proc init success!\\n");
return ret;
static void proc_exit()
remove_proc_entry(proc_entry,NULL);
printk(KERN_ERR "HELLO EXIT!\\n");
module_init(proc_init);
module_exit(proc_exit);
MODULE_LICENSE("Dual BSD/GPL");
以上是关于proc系统使用的主要内容,如果未能解决你的问题,请参考以下文章