linux驱动17:/proc文件系统(调试技术)

/proc文件系统是一种特殊的、由软件创建的文件系统,内核使用它向外界导出信息。/proc下面的每个文件都绑定于一个内核函数,用户读取其中的文件时,该函数动态地生成文件的“内容”。/proc文件支持读写,大多数情况下/proc文件是只读的。使用时包含<linux/proc_fs.h>。

seq_file接口

为大的内核虚拟文件提供一组简单的函数。使用时包含<linux/seq_file.h>,必须建立四个迭代器。

start、next、show、stop(顺序操作,四个迭代器)

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);
};

start方法始终首先调用,表明开始读取的位置;next指向下一个位置;show输出当前位置的数据;stop做清除工作。

seq_open函数

将file和定义的顺序操作seq_operations连接在一起。open是唯一需要我们实现的文件操作,file_operations结构定义如下:

static const struct file_operations hello_proc_fops = {
    .owner        = THIS_MODULE,
    .open        = hello_proc_open,
    .read        = seq_read, // seq_file.c中定义
    .llseek        = seq_lseek, // seq_file.c中定义
    .release    = seq_release, // seq_file.c中定义
};

proc_create_data函数

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);

创建/proc文件入口项,并绑定文件操作file_operations。

remove_proc_entry函数

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

删除/proc文件入口项。

例程

#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/list.h>
#include <linux/slab.h>

#define MAX_BUF_LEN 32
#define MAX_LIST_LEN 10

typedef struct 
{
	char str[MAX_BUF_LEN];
	struct list_head node;
}HELLO_NODE_S;

static struct list_head helloList;

static void *hello_seq_start(struct seq_file *s, loff_t *pos)
{
	printk("hello_seq_start\n");
	struct list_head *head = &helloList;;

	if (0 == *pos || *pos > MAX_LIST_LEN)
	{
		return head->next;
	}

	int index = *pos;
	struct list_head *list_pos = NULL; 
	struct list_head *tmp = NULL;

	list_for_each_safe(list_pos, tmp, head)
	{
		index--;
		if (0 == index)
		{
			return list_pos;
		}
	}

	return head->next;
}

static void *hello_seq_next(struct seq_file *s, void *v, loff_t *pos)
{
	printk("hello_seq_next\n");
	struct list_head *head = &helloList;

	*pos = *pos + 1;
	if (*pos > MAX_LIST_LEN)
	{
		*pos = 1;	
		return head->next;
	}

	struct list_head *tmp = (struct list_head *)v;
	return tmp->next;
}

static int hello_seq_show(struct seq_file *m, void *v)
{
	printk("hello_seq_show\n");
	struct list_head *tmp = (struct list_head *)v;
	HELLO_NODE_S *hello_node = list_entry(tmp, HELLO_NODE_S, node);
	seq_printf(m, "%s\n", hello_node->str);
	return 0;
}

static void hello_seq_stop(struct seq_file *s, void *v)
{
	printk("hello_seq_stop\n");
}

static const struct seq_operations hello_seq_ops = {
	.start = hello_seq_start,
	.next = hello_seq_next,
	.stop = hello_seq_stop,
	.show = hello_seq_show,
};

static int hello_proc_open(struct inode *inode, struct file *file)
{	
	printk("hello_proc_open\n");
	return seq_open(file, &hello_seq_ops);
}

static const struct file_operations hello_proc_fops = {
	.owner		= THIS_MODULE,
	.open		= hello_proc_open,
	.read		= seq_read,
	.llseek		= seq_lseek,
	.release	= seq_release,
};

static void create_test_data(void)
{
	struct list_head *head = &helloList;
	int i;
	for (i = 0; i < MAX_LIST_LEN; i++)
	{
		HELLO_NODE_S *new =  (HELLO_NODE_S *)kmalloc(sizeof(HELLO_NODE_S), GFP_KERNEL);
		sprintf(new->str, "hello_%d", i);
		list_add(&new->node, head);
	}
}

static void free_test_data(void)
{
	struct list_head *head = &helloList;
	struct list_head *list_pos = NULL; 
	struct list_head *tmp = NULL;
	HELLO_NODE_S *hello_node = NULL;

	list_for_each_safe(list_pos, tmp, head)
	{
		hello_node = list_entry(list_pos, HELLO_NODE_S, node);
		list_del(list_pos);
		kfree(hello_node);
	}
}

static int hello_init(void)
{
	printk("hello_init\n");
	INIT_LIST_HEAD(&helloList);
	create_test_data();
	proc_create_data("hello_proc", 0, NULL, &hello_proc_fops, NULL);
	return 0;
}

static void hello_exit(void)
{
	printk("hello_exit\n");
	free_test_data();
	remove_proc_entry("hello_proc", NULL);
}

MODULE_LICENSE("GPL");
module_init(hello_init);
module_exit(hello_exit);

insmod hello.ko 

cat /proc/hello_proc   #不断输出,ctrl+c停止

dmesg

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值