linux 内核调试技术之proc文件系统的应用
1, proc文件系统初步
1.1, /proc文件系统
/proc文件系统是一种特殊的,由软件创建的文件系统,内核使用它向外界导出信息。 /proc下面的每个文件都绑定一个内核函数,用户读取其中的文件时,该函数动态的生成文件的“内容”。
由于/proc文件系统已经被添加了大量的信息。因此,最好的办法是用sysfs而不是/proc文件系统来向外导出信息。
/proc文件不仅可以用于读数据,也可以用于写数据,不过写数据比较麻烦一些,这里只描述读数据的用法.写数据的用法可以在看完读数据的过程后参考kernel源码.
1.2,创建/proc文件的函数
前面介绍过/proc下的文件都是在访问时实时生成文件内容的,那么为了创建/proc下的一个只读的文件,我们必须实现一个函数用于在读取文件时生成数据,幸运的是,该函数接口已经设计好了,我们只需要按照函数接口实现自己需要的功能就可以了.该函数的原型如下:
*向用户层导出数据的读取函数
int (*read_proc)(char *page, char **start, off_t offset, int count,
int *eof, void *data);
参数说明:
page : 用来写入数据的缓冲区;也就是说从/proc文件中读到的数据都写入到page指向的缓冲区中.
start: 用于指定实际的数据写入到page指向的内存页的具体的那个位置.
offset : 和read参数中的相同
count : 和read函数中的参数意义相同
eof : 当没有数据返回时,必须设置该参数为一个整数,例如: *eof = 1;
data : 该参数是内核提供给驱动程序的专用指针,可以用于内部记录
*创建只读/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)
参数说明:
name : 要创建的/proc下的文件名
mode : 创建的文件权限的掩码,若为0,则使用系统默认的权限
base : 该文件所在的父目录,若该参数为null,则该文件将会被创建在/proc的根目录下
read_proc : 读取/proc下的文件时调用的函数,也就是前面讲解的那个函数
data : 内核会忽略data,但会把该参数传递给read_proc函数
删除/proc系统文件的函数
void remove_proc_entry(const char *name, struct proc_dir_entry *parent)
参数说明:
name : 在/proc文件系统中创建的文件名
parent : 父目录名
1.3, 使用/proc文件系统的缺点
(1) 删除调用可能在/proc文件系统的文件正在被使用时发生
(2) 同一个文件名可能注册两次,这将会发生错误
2, 创建简单的proc文件(一)
/*
* simple /proc file
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/mm.h>
#include <linux/errno.h>
#include <linux/proc_fs.h>
#include <linux/fs.h>
static char dev_name[] = "helloproc";
/*
* do proc file
*/
static int do_proc_mem(char *buf, char **start, off_t offset,
int count, int *eof, void *data)
{
int len = 0;
len += sprintf(buf+len, "hello world!\n");
*eof = 1;
return len;
}
static int __init do_proc_init(void) { create_proc_read_entry(dev_name, 0, NULL, do_proc_mem, NULL);
printk("%s proc file created successfully!\n", dev_name); return 0; }
static void __exit do_proc_exit(void)
{
remove_proc_entry(dev_name, NULL);
printk("goodbye %s!\n", dev_name);
}
module_init(do_proc_init);
module_exit(do_proc_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("hover");
|
2.1, 创建简单的proc文件(二)
/*
* simple_proc-2.c - create a "file" in /proc
*/
#include <linux/module.h> /* Specifically, a module */
#include <linux/kernel.h> /* We're doing kernel work */
#include <linux/proc_fs.h> /* Necessary because we use the proc fs */
#define procfs_name "helloworld"
/*
* This structure hold information about the /proc file
*/
struct proc_dir_entry *Our_Proc_File;
/* Put data into the proc fs file.
*
* Usage and Return Value
* ======================
* A return value of zero means you have no further
* information at this time (end of file). A negative
* return value is an error condition.
*/
int
procfile_read(char *buffer,
char **buffer_location,
off_t offset, int buffer_length, int *eof, void *data)
{
int ret;
printk(KERN_INFO "procfile_read (/proc/%s) called\n", procfs_name);
if (offset > 0) {
/* we have finished to read, return 0 */
ret = 0;
} else {
/* fill the buffer, return the buffer size */
ret = sprintf(buffer, "HelloWorld!\n");
}
return ret;
}
static __init int proc_init(void)
{
Our_Proc_File = create_proc_entry(procfs_name, 0644, NULL);
if (Our_Proc_File == NULL) {
remove_proc_entry(procfs_name, NULL);
printk(KERN_ALERT "Error: Could not initialize /proc/%s\n",
procfs_name);
return -ENOMEM;
}
Our_Proc_File->read_proc = procfile_read;
Our_Proc_File->owner = THIS_MODULE;
Our_Proc_File->mode = S_IFREG | S_IRUGO;
Our_Proc_File->uid = 0;
Our_Proc_File->gid = 0;
Our_Proc_File->size = 37;
printk(KERN_ALERT "/proc/%s created\n", procfs_name);
return 0; /* everything is ok */
}
static __exit void proc_cleanup(void)
{
remove_proc_entry(procfs_name, NULL);
printk(KERN_ALERT "/proc/%s removed\n", procfs_name);
}
MODULE_LICENSE("GPL");
MODULE_AUTHOR("tree");
module_init(proc_init);
module_exit(proc_cleanup);
|
2.3 利用seq_file管理大容量的/proc文件
seq_file提供了一套接口函数和方案可以用来安全的访问/proc文件系统。因为它可以容易的管理输出的缓冲区溢出和大于一页大小的文件。
seq_file接口建设我们正在创建的虚拟文件要遍历一个项目序列,而这些项目正是必须返回给用户空间的。为使用seq_file我们必须创建一个简单的“迭代器iterator”对象,该对象用来表示项目序列中的位置,每前进一步,该对象输出序列中的一个项目。
所以第一个就是建立4个迭代对象,分别为start,next,stop和show
void *start(struct seq_file *sfile, loff_t *pos);
这里pos是一个整数的位置值。
void *next(struct seq_file *sfile, void *v, loff_t *pos);
这里v是先前对start或next的调用所返回的迭代器,pos是文件的当前位置。next方法应增加pos指向的值。这当然依赖于迭代器的工作方式。
void *stop(struct seq_file *sfile, void *v);
int show(struct seq_file *sfile, void *v);
/*
* seqproc.c - create a "file" in /proc
* This program uses the seq_file library to manage the /proc file.
*/
#include <linux/kernel.h> /* We're doing kernel work */
#include <linux/module.h> /* Specifically, a module */
#include <linux/proc_fs.h> /* Necessary because we use proc fs */
#include <linux/seq_file.h> /* for seq_file */
#define PROC_NAME "hover_iter"
MODULE_AUTHOR("PR");
MODULE_LICENSE("GPL");
/*
* This function is called at the beginning of a sequence.
* ie, when:
* - the /proc file is read (first time)
* - after the function stop (end of sequence)
*/
static void *my_seq_start(struct seq_file *s, loff_t *pos)
{
static unsigned long counter = 0;
/* beginning a new sequence ? */
if (*pos == 0) {
/* yes => return a non null value to begin the sequence */
return &counter;
} else {
/* no => it's the end of the sequence, return end to stop reading */
*pos = 0;
return NULL;
}
}
/*
* This function is called after the beginning of a sequence.
* It's called untill the return is NULL (this ends the sequence).
*/
static void *my_seq_next(struct seq_file *s, void *v, loff_t *pos)
{
unsigned long *tmp_v = (unsigned long *)v;
(*tmp_v)++;
(*pos)++;
return NULL;
}
/*
* This function is called at the end of a sequence
*/
static void my_seq_stop(struct seq_file *s, void *v)
{
/* nothing to do, we use a static value in start() */
}
/*
* This function is called for each "step" of a sequence
*/
static int my_seq_show(struct seq_file *s, void *v)
{
loff_t *spos = (loff_t *) v;
seq_printf(s, "%Ld\n", *spos);
return 0;
}
/*
* This structure gather "function" to manage the sequence
*/
static struct seq_operations my_seq_ops = {
.start = my_seq_start,
.next = my_seq_next,
.stop = my_seq_stop,
.show = my_seq_show
};
/*
* This function is called when the /proc file is open.
*/
static int my_open(struct inode *inode, struct file *file)
{
return seq_open(file, &my_seq_ops);
};
/*
* This structure gather "function" that manage the /proc file
*/
static struct file_operations my_file_ops = {
.owner = THIS_MODULE,
.open = my_open,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release
};
/*
* This function is called when the module is loaded
*/
static __init int seq_proc_init(void)
{
struct proc_dir_entry *entry;
entry = create_proc_entry(PROC_NAME, 0, NULL);
if (entry) {
entry->proc_fops = &my_file_ops;
}
return 0
|
阅读(1016) | 评论(0) | 转发(0) |