转载: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)接口的更多相关文章

  1. linux内核seq_file接口

    seq相关头文件linux/seq_file.h,seq相关函数的实现在fs/seq_file.c.seq函数最早是在2001年就引入了,但以前内核中一直用得不多,而到了2.6内核后,许多/proc的 ...

  2. Linux内核学习笔记之seq_file接口创建可读写proc文件

    转自:http://blog.csdn.net/mumufan05/article/details/45803219 学习笔记与个人理解,如有错误,欢迎指正. 温馨提示:建议跟着注释中的编号顺序阅读代 ...

  3. linux seq_file 接口

    如我们上面提到的, 在 /proc 下的大文件的实现有点麻烦. 一直以来, /proc 方法因为 当输出数量变大时的错误实现变得声名狼藉. 作为一种清理 /proc 代码以及使内核开发 者活得轻松些的 ...

  4. Linux内核实践之序列文件【转】

    转自:http://blog.csdn.net/bullbat/article/details/7407194 版权声明:本文为博主原创文章,未经博主允许不得转载. 作者:bullbat seq_fi ...

  5. JMeter循环读取CSV文件实现接口批量测试

    首先要理解为什么要进行批量测试,当我们在工作中进行接口测试时,项目的接口肯定不止一个,而是很多很多,而且每个接口都需要进行正确参数,错误参数,参数为空,特殊字符等方式来测试接口是否能够正确返回所需的响 ...

  6. hadoop文本转换为序列文件

    在以前使用hadoop的时候因为mahout里面很多都要求输入文件时序列文件,所以涉及到把文本文件转换为序列文件或者序列文件转为文本文件(因为当时要分析mahout的源码,所以就要看到它的输入文件是什 ...

  7. [SequenceFile_1] Hadoop 序列文件

    1. 关于 SequenceFile 对于日志文件来说,纯文本不适合记录二进制类型数据,通过 SequenceFile 为二进制键值对提供了持久的数据结构,将其作为日志文件的存储格式时,可自定义键(L ...

  8. 关于文件的INode与Java中的文件操作接口

    本文由作者周梁伟授权网易云社区发布. 近日做的项目中涉及到多进程共同读写多个文件的问题,文件名和最后修改时间都是可能会被频繁修改的,因而识别文件的唯一性会产生相当的麻烦,于是专门再学习了一下文件系统对 ...

  9. ActiveX的AssemblyInof.cs文件 IObjectSafety  接口

    ActiveX的AssemblyInof.cs文件 IObjectSafety  接口 [Guid("D4176A17-2A33-4903-8F37-9EBDD7CAFFD3"), ...

随机推荐

  1. Careercup - Microsoft面试题 - 23123665

    2014-05-12 07:44 题目链接 原题: Given an array having unique integers, each lying within the range <x&l ...

  2. 使用 SceneLoader 类在 XNA 中显示载入屏幕(十)

    平方已经开发了一些 Windows Phone 上的一些游戏,算不上什么技术大牛.在这里分享一下经验,仅为了和各位朋友交流经验.平方会逐步将自己编写的类上传到托管项目中,没有什么好名字,就叫 WPXN ...

  3. nyoj 题目19 擅长排列的小明

    擅长排列的小明 时间限制:1000 ms  |  内存限制:65535 KB 难度:4   描述 小明十分聪明,而且十分擅长排列计算.比如给小明一个数字5,他能立刻给出1-5按字典序的全排列,如果你想 ...

  4. 如何从fragment跳到activity再从activity返回(finish()方法返回)刷新fragemnt页面

    代码改变世界 如何从fragment跳到activity再从activity返回(finish()方法返回)刷新fragemnt页面 广播方法实现Fragment页面刷新 fragment中重写onA ...

  5. 【bzoj4836】[Lydsy2017年4月月赛]二元运算 分治+FFT

    题目描述 定义二元运算 opt 满足   现在给定一个长为 n 的数列 a 和一个长为 m 的数列 b ,接下来有 q 次询问.每次询问给定一个数字 c  你需要求出有多少对 (i, j) 使得 a_ ...

  6. [AGC004C] AND Grid [构造]

    题面: 传送门 思路: 一眼看上去是一道很迷的题目......直到我发现,红蓝色涂色的过程是互相独立的 而且最外围没有紫色 那么可以这样操作: 最左边一列全部红色,最右边一列全蓝 然后中间的一行红一行 ...

  7. [NOI2003][bzoj1507] 文本编辑器 editor [splay]

    其实看明白了就是一道水题 毕竟模板 splay敲一发,插入一个串的时候先把它构建成一棵平衡树,再挂到原来的splay上面去即可 没别的了,上代码 #include<iostream> #i ...

  8. 设置pycharm的python版本

    http://blog.csdn.net/github_35160620/article/details/52486986

  9. javaScript 笔记(5) --- jQuery(上)

    这节整理整理 iquery.js 相关的内容... 目录 --- jQuery 语法 --- 文档就绪事件 --- jQuery 选择器 --- jQuery 事件 --- jQuery 效果 jQu ...

  10. 在react当中巧用扩展运算符

    ...props可以把没有写到的属性补充完整 ...style 可以把style 属性在styles当中展开