seq_file只是在普通的文件read中加入了内核缓冲的功能,从而实现顺序多次遍历,读取大数据量的简单接口。seq_file一般只提供只读接口,在使用seq_file操作时,主要靠下述四个操作来完成内核自定义缓冲区的遍历的输出操作,其中pos作为遍历的iterator,在seq_read函数中被多次使用,用以定位当前从内核自定义链表中读取的当前位置,当多次读取时,pos非常重要,且pos总是遵循从0,1,2...end+1遍历的次序,其即必须作为遍历内核自定义链表的下标,也可以作为返回内容的标识。但是我在使用中仅仅将其作为返回内容的标示,并没有将其作为遍历链表的下标,从而导致返回数据量大时造成莫名奇妙的错误,注意:start返回的void*v如果非0,被show输出后,在作为参数传递给next函数,next可以对其修改,也可以忽略;当next或者start返回NULL时,在seq_open中控制路径到达seq_end。

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函数应将迭代器移动到下一个位置,并在序列中没有其他项目时返回NULL;

  stop做清除工作;

  在上述调用之间,内核会调用 show 方法来将实际的数据输出到用户空间。需要使用如下一组特殊函数来处理数据:

int seq_printf(struct seq_file *sfile, const char *fmt, ...);
int seq_putc(struct seq_file *sfile, char c);
int seq_puts(struct seq_file *sfile, const char *s);

  值得注意的是,在设计上,seq_file的代码不会在 start 和 stop 的调用之间执行其他的非原子操作。我们可以确信,start调用之后马上就会有对stop的调用。因此在start方法中获取信号量或者自旋锁是安全的。

  定义了完整的操作函数,我们必须将这些函数打包并和 /proc 中的某个文件连接起来。首先要填充一个 seq_operations 结构:

static struct seq_operations seq_ops = {
.start = seq_start,
.next = seq_next,
.stop = seq_stop,
.show = seq_show
};

  有了这个结构我们可以创建一个open方法,将文件连接到seq_file操作:

static int proc_open(struct inode *inode, struct file *file){
return seq_open(file, &scull_seq_ops);
}

  对seq_open的调用将file结构和我们上面定义的顺序操作连接在一起。open是唯一一个必须由我们自己实现的文件操作,因此我们的file_operations结构可如下定义:

static struct file_operations proc_ops = {
.owner = THIS_MODULE,
.open = proc_open,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release
};

  这里,我们指定了我们自己的open方法,但对其他的file_operations成员,我们使用了已经定义好的 seq_read, seq_lseek, seq_release方法。  

  最后,我们建立实际的 /proc 文件;

  entry = create_porc_entyr("sequence", 0, NULL);

  if (entry)

    entry->proc_fops = &scull_proc_ops;

例一:现在我们使用seq_file获取0-100的数:

 #include <linux/init.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/kernel.h>
#include <asm/uaccess.h>
#include <linux/seq_file.h>
#include <linux/proc_fs.h> #define MAX_NUM 100
static void *ct_seq_start(struct seq_file *s, loff_t *pos){
loff_t *spos = kmalloc(sizeof(loff_t), GFP_KERNEL); if (*pos > MAX_NUM)
return NULL; if (!*spos){
return NULL;
}
*spos = *pos;
return spos;
}
static void *ct_seq_next(struct seq_file *s, void *v, loff_t *pos){
loff_t *spos = (loff_t *)v; *pos = ++(*spos);
if (*pos > MAX_NUM){
return NULL;
}
return spos;
} static void ct_seq_stop(struct seq_file *s, void *v){
printk("ct_seq_stop!\n");
kfree(v);
} static int ct_seq_show(struct seq_file *s, void *v){
loff_t *spos = (loff_t *)v;
seq_printf(s, "%lld\n", *spos);
return ;
}
static const struct seq_operations ct_seq_ops = {
.start = ct_seq_start,
.next = ct_seq_next,
.stop = ct_seq_stop,
.show = ct_seq_show
}; static int ct_open(struct inode *inode, struct file *file){
printk("ct_open!\n");
return seq_open(file, &ct_seq_ops);
} static const struct file_operations ct_file_ops = {
.owner = THIS_MODULE,
.open = ct_open,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release
};
static int ct_init(void){
struct proc_dir_entry *entry;
entry = create_proc_entry("sequence", , NULL);
if (entry)
entry->proc_fops = &ct_file_ops;
return ;
}
static void ct_exit(void){
remove_proc_entry("sequence", NULL);
}
module_init(ct_init);
module_exit(ct_exit); MODULE_LICENSE("GPL");

  cat /proc/sequence 遍可以获取0-100的数字;

例二:使用seq_file获取链表中的数据:

 #include <linux/init.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/kernel.h>
#include <asm/uaccess.h>
#include <linux/seq_file.h>
#include <linux/proc_fs.h>
#include <linux/string.h> #define MAX_NUM 5
struct node {
char buf[];
struct node *next;
};
struct node *head = NULL;
static int init_data(void){
int i;
struct node *tmp = NULL;
char ch = 'a';
for (i = ; i < MAX_NUM; i++){
tmp = (struct node *)kmalloc(sizeof(struct node), GFP_KERNEL);
if (!tmp){
return -ENOMEM;
}
memset(tmp->buf, , sizeof(tmp->buf));
memset(tmp->buf, ch + i, sizeof(tmp->buf) - );
tmp->next = NULL;
if (!head){
head = tmp;
}
else {
tmp->next = head;
head = tmp;
}
}
return ;
}
static int free_data(void){
struct node *tmp = NULL; while (head){
tmp = head;
head = head->next;
kfree(tmp);
}
return ;
} static void *ct_seq_start(struct seq_file *s, loff_t *pos){
struct node *tmp = head;
int index = *pos + ; printk("seq start!\n");
if (!*pos){
return head;
}
while (index--){
if (!tmp){
return NULL;
}
tmp = tmp->next;
} return tmp;
} static void *ct_seq_next(struct seq_file *s, void *v, loff_t *pos){
struct node *tmp = (struct node *)v; printk("seq next!\n");
*pos = *pos + ;
tmp = tmp->next;
if (!tmp){
return NULL;
} return tmp;
} static void ct_seq_stop(struct seq_file *s, void *v){
printk("ct_seq_stop!\n");
}
static int ct_seq_show(struct seq_file *s, void *v){
struct node *tmp = (struct node *)v;
printk("seq show!\n");
seq_printf(s, "%s\n", tmp->buf);
return ;
} static const struct seq_operations ct_seq_ops = {
.start = ct_seq_start,
.next = ct_seq_next,
.stop = ct_seq_stop,
.show = ct_seq_show
}; static int ct_open(struct inode *inode, struct file *file){
printk("ct_open!\n");
return seq_open(file, &ct_seq_ops);
} static const struct file_operations ct_file_ops = {
.owner = THIS_MODULE,
.open = ct_open,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release
}; static int ct_init(void){
struct proc_dir_entry *entry;
init_data();
entry = create_proc_entry("sequence", , NULL);
if (entry)
entry->proc_fops = &ct_file_ops;
return ;
}
static void ct_exit(void){
free_data();
remove_proc_entry("sequence", NULL);
}
module_init(ct_init);
module_exit(ct_exit); MODULE_LICENSE("GPL");

  cat /proc/sequence 会把链表中的数据输出,此时我们使用 dmesg 查看内核输出信息;

  现在我们把结构体中的buf数据变成1024,MAX_NUM改为10,然后执行 cat /proc/sequence 然后再 dmesg 看看;

结果为:

ct_open!
seq start!
seq show!
seq next!
seq show!
seq next!
seq show!
seq next!
seq show!
ct_seq_stop!
seq start!
seq show!
seq next!
seq show!
seq next!
seq show!
seq next!
seq show!
ct_seq_stop!
seq start!
seq show!
seq next!
seq show!
seq next!
seq show!
seq next!
ct_seq_stop!
seq start!
ct_seq_stop!

  我们发现中间执行了 stop ,而不是像上面一样执行 start->show->next->show->next->stop。原因就是某次调用 show 的时候发现 seq_file 中的buf满了【buf——4K】。

【驱动】——seq_file使用指南的更多相关文章

  1. [译] MongoDB Java异步驱动快速指南

    导读 mongodb-java-driver是mongodb的Java驱动项目. 本文是对MongoDB-java-driver官方文档 MongoDB Async Driver Quick Tour ...

  2. 基于ABP落地领域驱动设计-00.目录和小结

    <实现领域驱动设计> -- 基于 ABP Framework 实现领域驱动设计实用指南 翻译缘由 自 ABP vNext 1.0 开始学习和使用该框架,被其优雅的设计和实现吸引,适逢 AB ...

  3. 3000本IT书籍下载地址

    http://www.shouce.ren/post/d/id/112300    黑客攻防实战入门与提高.pdfhttp://www.shouce.ren/post/d/id/112299    黑 ...

  4. ABP Framework 研习社经验总结(6.28-7.2)

    ABP Framework 研习社经验总结(6.28-7.2) 研习社初衷 在翻译 <实现领域驱动设计>-- 基于 ABP Framework 实现领域驱动设计实用指南 时,因为DDD理论 ...

  5. Redis 小白指南(一)- 简介、安装、GUI 和 C# 驱动介绍

    Redis 小白指南(一)- 简介.安装.GUI 和 C# 驱动介绍 目录 简介 安装 入门指令 GUI 工具 C# 驱动介绍 简介 ANSI C 编写,开源,基于内存,可持久化,一个键值对的数据库, ...

  6. Linux 桌面玩家指南:11. 在同一个硬盘上安装多个 Linux 发行版以及为 Linux 安装 Nvidia 显卡驱动

    特别说明:要在我的随笔后写评论的小伙伴们请注意了,我的博客开启了 MathJax 数学公式支持,MathJax 使用$标记数学公式的开始和结束.如果某条评论中出现了两个$,MathJax 会将两个$之 ...

  7. Infrastructure as Code 行为驱动开发指南 https://www.ibm.com/developerworks/cn/devops/d-bbd-guide-iac/index.html

    Infrastructure as Code 行为驱动开发指南 https://www.ibm.com/developerworks/cn/devops/d-bbd-guide-iac/index.h ...

  8. 业务驱动的全景监控体系在阿里的应用 | 阿里巴巴DevOps实践指南

    编者按:本文源自阿里云云效团队出品的<阿里巴巴DevOps实践指南>,扫描上方二维码或前往:https://developer.aliyun.com/topic/devops,下载完整版电 ...

  9. linux内核驱动学习指南

    1. 参考链接 小白的博客 ONE_Tech 你为什么看不懂Linux内核驱动源码? 求教怎么学习linux内核驱动

随机推荐

  1. 温故而知新 Vue 原来也有this.$forceUpdate();

    由于一些嵌套特别深的数据,导致数据更新了.UI没有更新(连深度监听都没有监听到),我捉摸着有没有和react一样的立即更新UI的API呢 this.forceUpdate()呢?结果还真有: this ...

  2. xpath的常见操作

    1. 获取某一个节点下所有的文本数据: data = response.xpath('//div[@id="zoomcon"]') content = ''.join(data.x ...

  3. idea搭建javaweb项目 Artifacts生成

    菜单:File - > Project Structure 图1 图2:静态资源文件 图3:java文件编译到WEB-INF/classes 图4:Inherit project compile ...

  4. Atitit jquery  1.4--v1.11  v1.12  v2.0  3.0 的新特性

    Atitit jquery  1.4--v1.11  v1.12  v2.0  3.0 的新特性 1.1. Jquery1.12  jQuery 2.2 和 1.12 新版本发布 - OPEN资讯.h ...

  5. 使用FiddlerCore来截取替换Http请求中的网页内容

    做过测试的应该都知道Fiddler,它可以很方便截取Internet上的网页替换成本地的,或者修改其中的一部分内容后呈现.简单地说就是可能监测所有HTTP连接,设置断点,胡乱修改.是测试调试的一件利器 ...

  6. AdminLTE, Color Admin

    AdminLTE, Color Adminhttps://github.com/almasaeed2010/AdminLTE/http://www.seantheme.com/color-admin- ...

  7. unzip:unzip解压文件到指定目录

    1.把文件解压到当前目录下 unzip test.zip 2.如果要把文件解压到指定的目录下,需要用到-d参数. unzip -d /temp test.zip 3.解压的时候,有时候不想覆盖已经存在 ...

  8. Fluent 18.0新功能之:其他

    ANSYS 18.0在2017年1月底发布,来看看Fluent18.0更新了哪些内容. 1 用户界面 关于用户界面方面的更新包括: (1)可以在树形菜单中同时选择多个子节点,如同时选择多个边界,点击右 ...

  9. [Windows Azure] Windows Azure Virtual Network Overview

    Windows Azure Virtual Network Overview 18 out of 33 rated this helpful - Rate this topic Updated: Ap ...

  10. [Windows Azure] Windows Azure Web Sites, Cloud Services, and VMs: When to use which?

    This document provides guidance on how to make an informed decision in choosing between Windows Azur ...