序列文件(seq_file)接口
转载:http://blog.csdn.net/gangyanliang/article/details/7244664
内容简介:
本文主要讲述序列文件(seq_file)接口的内核实现,如何使用它将Linux内核里面常用的数据结构通过文件(主要关注proc文件)导出到 用户空间,最后定义了一些宏以便于编程,减少重复代码。在分析序列文件接口实现的过程中,还连带涉及到一些应用陷阱和避免手段。
序列文件接口:
UNIX的世界里,文件是最普通的概念,所以用文件来作为内核和用户空间传递数据的接口也是再普通不过的事情,并且这样的接口对于shell也是相
当友好的,方便管理员通过shell直接管理系统。由于伪文件系统proc文件系统在处理大数据结构(大于一页的数据)方面有比较大的局限性,使得在那种
情况下进行编程特别别扭,很容易导致bug,所以序列文件接口被发明出来,它提供了更加友好的接口,以方便程序员。之所以选择序列文件接口这个名字,应该
是因为它主要用来导出一条条的记录数据。
为了能给大家一个具体形象的认识,我们首先来看一段用序列文件接口通过proc文件导出内核双向循环链接表的实例代码:
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h> static struct mutex lock;
static struct list_head head;
struct my_data {
struct list_head list;
int value;
}; static void add_one(void)
{
struct my_data *data; mutex_lock(&lock);
data = kmalloc(sizeof(*data), GFP_KERNEL);
if (data != NULL)
list_add(&data->list, &head);
mutex_unlock(&lock);
} static ssize_t _seq_write(struct file *file, const char __user * buffer,
size_t count, loff_t *ppos)
{
add_one();
return count;
} static int _seq_show(struct seq_file *m, void *p)
{
struct my_data *data = list_entry(p, struct my_data, list); seq_printf(m, "value: %d/n", data->value);
return ;
} static void *_seq_start(struct seq_file *m, loff_t *pos)
{
mutex_lock(&lock);
return seq_list_start(&head, *pos);
} static void *_seq_next(struct seq_file *m, void *p, loff_t *pos)
{
return seq_list_next(p, &head, pos);
} static void _seq_stop(struct seq_file *m, void *p)
{
mutex_unlock(&lock);
} static struct seq_operations _seq_ops = {
.start = _seq_start,
.next = _seq_next,
.stop = _seq_stop,
.show = _seq_show
}; static int _seq_open(struct inode *inode, struct file *file)
{
return seq_open(file, &_seq_ops);
} static struct file_operations _seq_fops = {
.open = _seq_open,
.read = seq_read,
.write = _seq_write,
.llseek = seq_lseek,
.release = seq_release
}; static void clean_all(struct list_head *head)
{
struct my_data *data; while (!list_empty(head)) {
data = list_entry(head->next, struct my_data, list);
list_del(&data->list);
kfree(data);
}
} static int __init init(void)
{
struct proc_dir_entry *entry; mutex_init(&lock);
INIT_LIST_HEAD(&head); add_one();
add_one();
add_one(); entry = create_proc_entry("my_data",S_IWUSR | S_IRUGO, NULL);
if (entry == NULL) {
clean_all(&head);
return -ENOMEM;
}
entry->proc_fops = &_seq_fops; return ;
} static void __exit fini(void)
{
remove_proc_entry("my_data", NULL);
clean_all(&head);
} module_init(init);
module_exit(fini);
Seq_file File System
针对proc文件的不足而诞生了Seq_file。
Seq_file的实现基于proc文件。使用Seq_file,用户必须抽象出一个链接对象,然后可以依次遍历这个链接对象。这个链接对象可以是链表,数组,哈希表等等。
1.编程接口
Seq_file必须实现四个操作函数: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():
主要实现初始化工作,在遍历一个链接对象开始时,调用。返回一个链接对象的偏移或者SEQ_START_TOKEN(表征这是所有循环的开始)。出错返回ERR_PTR。
stop():
当所有链接对象遍历结束时调用。主要完成一些清理工作。
next():
用来在遍历中寻找下一个链接对象。返回下一个链接对象或者NULL(遍历结束)。
show():
对遍历对象进行操作的函数。主要是调用seq_printf(), seq_puts()之类的函数,打印出这个对象节点的信息。
下图描述了seq_file函数对一个链表的遍历。
2、重要的数据结构
除了struct seq_operations以外,另一个最重要的数据结构是struct seq_file:
struct seq_file {
char *buf;
size_t size;
size_t from;
size_t count;
loff_t index;
u64 version;
struct mutex lock;
const struct seq_operations *op;
void *private;
};
该结构会在seq_open函数调用中分配,然后作为参数传递给每个seq_file的操作函数。Privat变量可以用来在各个操作函数之间传递参数。
seq_hello.c
#include <net/net_namespace.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h> #define PROC_NAME "test_proc"
#define MAX_LINES 10 typedef struct item
{
unsigned long key;
unsigned char value;
}user_item; user_item items[]; MODULE_AUTHOR("ZHANG JIE:iptabler@mail.com");
MODULE_LICENSE("GPL"); static void *my_seq_start(struct seq_file *s, loff_t *pos)
{
static unsigned long counter = ;
printk(KERN_INFO"Invoke start/n"); if ( *pos == )
{
/* 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 = ;
return NULL;
}
} static void *my_seq_next(struct seq_file *s, void *v, loff_t *pos)
{
unsigned long *tmp_v = (unsigned long *)v;
if (*pos < MAX_LINES) {
(*tmp_v)++;
(*pos)++;
return tmp_v;
}
else
{
*pos = ;
return NULL;
}
} static void my_seq_stop(struct seq_file *s, void *v)
{
printk("Invoke stop/n");
} static int my_seq_show(struct seq_file *s, void *v)
{
int i;
loff_t *spos = (loff_t *) v;
for (i = ; i < ; i++)
{
items[i].key = *spos;
}
items[].value = '';
items[].value = '';
items[].value = '';
items[].value = '';
seq_printf(s, "%ld=%c,%ld=%c,%ld=%c,%ld=%c;/n", items[].key,
items[].value, items[].key, items[].value, items[].key,
items[].value, items[].key, items[].value);
return ;
} static struct seq_operations my_seq_ops = {
.start = my_seq_start,
.next = my_seq_next,
.stop = my_seq_stop,
.show = my_seq_show
}; static int my_open(struct inode *inode, struct file *file)
{
return seq_open(file, &my_seq_ops);
}; static struct file_operations my_file_ops = {
.owner = THIS_MODULE,
.open = my_open,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release
}; int init_module(void)
{
struct proc_dir_entry *entry;
entry = create_proc_entry(PROC_NAME, , init_net.proc_net);
if (entry) {
entry->proc_fops = &my_file_ops;
}
printk(KERN_INFO"Initialze /proc/net/test_proc success!/n");
return ;
} void cleanup_module(void)
{
remove_proc_entry(PROC_NAME, init_net.proc_net);
printk(KERN_INFO"Remove /proc/net/test_proc success!/n");
}
Makefile
obj-m := seq_hello.o
KDIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd) default:
$(MAKE) -C $(KDIR) M=$(PWD) modules
clean:
$(RM) *.o *.mod.c *.ko *.symvers *.markers *.order
测试
[root@zj:~/Desktop/net/seq]# cat /proc/net/test_proc
完。
序列文件(seq_file)接口的更多相关文章
- linux内核seq_file接口
seq相关头文件linux/seq_file.h,seq相关函数的实现在fs/seq_file.c.seq函数最早是在2001年就引入了,但以前内核中一直用得不多,而到了2.6内核后,许多/proc的 ...
- Linux内核学习笔记之seq_file接口创建可读写proc文件
转自:http://blog.csdn.net/mumufan05/article/details/45803219 学习笔记与个人理解,如有错误,欢迎指正. 温馨提示:建议跟着注释中的编号顺序阅读代 ...
- linux seq_file 接口
如我们上面提到的, 在 /proc 下的大文件的实现有点麻烦. 一直以来, /proc 方法因为 当输出数量变大时的错误实现变得声名狼藉. 作为一种清理 /proc 代码以及使内核开发 者活得轻松些的 ...
- Linux内核实践之序列文件【转】
转自:http://blog.csdn.net/bullbat/article/details/7407194 版权声明:本文为博主原创文章,未经博主允许不得转载. 作者:bullbat seq_fi ...
- JMeter循环读取CSV文件实现接口批量测试
首先要理解为什么要进行批量测试,当我们在工作中进行接口测试时,项目的接口肯定不止一个,而是很多很多,而且每个接口都需要进行正确参数,错误参数,参数为空,特殊字符等方式来测试接口是否能够正确返回所需的响 ...
- hadoop文本转换为序列文件
在以前使用hadoop的时候因为mahout里面很多都要求输入文件时序列文件,所以涉及到把文本文件转换为序列文件或者序列文件转为文本文件(因为当时要分析mahout的源码,所以就要看到它的输入文件是什 ...
- [SequenceFile_1] Hadoop 序列文件
1. 关于 SequenceFile 对于日志文件来说,纯文本不适合记录二进制类型数据,通过 SequenceFile 为二进制键值对提供了持久的数据结构,将其作为日志文件的存储格式时,可自定义键(L ...
- 关于文件的INode与Java中的文件操作接口
本文由作者周梁伟授权网易云社区发布. 近日做的项目中涉及到多进程共同读写多个文件的问题,文件名和最后修改时间都是可能会被频繁修改的,因而识别文件的唯一性会产生相当的麻烦,于是专门再学习了一下文件系统对 ...
- ActiveX的AssemblyInof.cs文件 IObjectSafety 接口
ActiveX的AssemblyInof.cs文件 IObjectSafety 接口 [Guid("D4176A17-2A33-4903-8F37-9EBDD7CAFFD3"), ...
随机推荐
- python 二——函数、装饰器、生成器、面向对象编程(初级)
本节内容 1.函数 2.装饰器 3.生成器 4.类 一.函数 函数式:将某功能代码封装到函数中,日后便无需重复编写,仅调用函数即可 面向对象:对函数进行分类和封装,让开发“更快更好更强...” 函数式 ...
- 【LoadRunner】场景执行报错“failed: WSA_IO_PENDING”
问题:性能测试场景执行报“failed: WSA_IO_PENDING”错误 解决方法: 添加web_set_sockets_option("OVERLAPPED_SEND", & ...
- Python+Selenium练习篇之5-利用partial link text定位元素
本文介绍如何通过partial link text来定位页面元素.看到这个,有点和前一篇文字link text有点类似.字面意思,确实和link text相类似,partial link text就是 ...
- 菜鸟之路——机器学习之SVM分类器学习理解以及Python实现
SVM分类器里面的东西好多呀,碾压前两个.怪不得称之为深度学习出现之前表现最好的算法. 今天学到的也应该只是冰山一角,懂了SVM的一些原理.还得继续深入学习理解呢. 一些关键词: 超平面(hyper ...
- [python][django学习篇][2]创建django app
推荐学校django博客:http://pythonzh.cn/post/8/ django app 可以理解为一个文件夹: 里面包含了相关功能的代码.通过manage.py来创建 web app 激 ...
- python中 in, any 和 all用法
in if x == 1 or y == 1 or z == 1: print('passed') if 1 in (x, y, z): print('passed') any if x or y o ...
- PAT1021
给定一个k位整数N = dk-1*10k-1 + ... + d1*101 + d0 (0<=di<=9, i=0,...,k-1, dk-1>0),请编写程序统计每种不同的个位数字 ...
- 【转】ugui自制摇杆
http://www.cnblogs.com/duyushuang/p/4457691.html 珍爱生命,远离插件. 以上8个字,好好理解. 反正我是这么觉得. 我说的是unity,不是魔兽世界. ...
- redis应用场景及实例
Redis在很多方面与其他数据库解决方案不同:它使用内存提供主存储支持,而仅使用硬盘做持久性的存储;它的数据模型非常独特,用的是单线程.另一个大区别在于,你可以在开发环境中使用Redis的功能,但却不 ...
- [HAOI2010][bzoj2424] 订货 [费用流]
题面 传送门 思路 这题其实挺水的......做过餐巾计划问题就能明白,是同一个道理 首先,显然刚刚好满足每一个月的需求,会得到最优解(废话-_-||) 然后我们发现,货物在不同的月之间的转移,可以比 ...