li {list-style-type:decimal;}ol.wiz-list-level2 > li {list-style-type:lower-latin;}ol.wiz-list-level3 > li {list-style-type:lower-roman;}blockquote {padding:0 12px;padding:0 0.75rem;}blockquote > :first-child {margin-top:0;}blockquote > :last-child {margin-bottom:0;}img {border:0;max-width:100%;height:auto !important;margin:2px 0;}table {border-collapse:collapse;border:1px solid #bbbbbb;}td, th {padding:4px 8px;border-collapse:collapse;border:1px solid #bbbbbb;min-height:28px;word-break:break-all;box-sizing: border-box;}.wiz-hide {display:none !important;}
-->
span::selection, .CodeMirror-line > span > span::selection { background: #d7d4f0; }.CodeMirror-line::-moz-selection, .CodeMirror-line > span::-moz-selection, .CodeMirror-line > span > span::-moz-selection { background: #d7d4f0; }.cm-searching {background: #ffa; background: rgba(255, 255, 0, .4);}.cm-force-border { padding-right: .1px; }@media print { .CodeMirror div.CodeMirror-cursors {visibility: hidden;}}.cm-tab-wrap-hack:after { content: ""; }span.CodeMirror-selectedtext { background: none; }.CodeMirror-activeline-background, .CodeMirror-selected {transition: visibility 0ms 100ms;}.CodeMirror-blur .CodeMirror-activeline-background, .CodeMirror-blur .CodeMirror-selected {visibility:hidden;}.CodeMirror-blur .CodeMirror-matchingbracket {color:inherit !important;outline:none !important;text-decoration:none !important;}
-->

作者

彭东林
pengdonglin137@163.com
 

平台

Linux-4.14.13
Qemu + vexpress
 

概述

前面介绍了single_open,下面结合一个简单的demo驱动,学习一下seq_file的用法。
下面是一张示意图:
 

正文

seq_demo驱动里实现了一个简单的链表,在init的时候会依次创建7个节点并加入链表,然后向用户空间导出一个seq_demo的节点,读取这个节点,就会调用seq_file相关函数对链表进行遍历,输出每个节点的相关信息。

一、seq_demo驱动

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

static struct dentry *seq_demo_dir;
static LIST_HEAD(seq_demo_list);
static DEFINE_MUTEX(seq_demo_lock);

struct seq_demo_node {
char name[10];
struct list_head list;
};

static void *seq_demo_start(struct seq_file *s, loff_t *pos)
{
mutex_lock(&seq_demo_lock);

return seq_list_start(&seq_demo_list, *pos);
}

static void *seq_demo_next(struct seq_file *s, void *v, loff_t *pos)
{
return seq_list_next(v, &seq_demo_list, pos);
}

static void seq_demo_stop(struct seq_file *s, void *v)
{
mutex_unlock(&seq_demo_lock);
}

static int seq_demo_show(struct seq_file *s, void *v)
{
struct seq_demo_node *node = list_entry(v, struct seq_demo_node, list);

seq_printf(s, "name: %s, addr: 0x%p\n", node->name, node);

return 0;
}

static const struct seq_operations seq_demo_ops = {
.start = seq_demo_start,
.next = seq_demo_next,
.stop = seq_demo_stop,
.show = seq_demo_show,
};

static int seq_demo_open(struct inode *inode, struct file *file)
{
return seq_open(file, &seq_demo_ops);
}

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

static int __init seq_demo_init(void)
{
int i;
struct seq_demo_node *node;

for (i = 0; i < 7; i++) {
node = kzalloc(sizeof(struct seq_demo_node), GFP_KERNEL);
sprintf(node->name, "node%d", i);

INIT_LIST_HEAD(&node->list);
list_add_tail(&node->list, &seq_demo_list);
}

seq_demo_dir = debugfs_create_file("seq_demo", 0444, NULL,
NULL, &seq_demo_fops);
return 0;
}

static void __exit seq_demo_exit(void)
{
struct seq_demo_node *node_pos, *node_n;

if (seq_demo_dir) {
debugfs_remove(seq_demo_dir);
list_for_each_entry_safe(node_pos, node_n, &seq_demo_list, list)
if (node_pos) {
printk("%s: release %s\n", __func__, node_pos->name);
kfree(node_pos);
}
}
}

module_init(seq_demo_init);
module_exit(seq_demo_exit);
MODULE_LICENSE("GPL");

 #include <linux/init.h>
#include <linux/module.h>
#include <linux/seq_file.h>
#include <linux/debugfs.h>
#include <linux/fs.h>
#include <linux/list.h>
#include <linux/slab.h> static struct dentry *seq_demo_dir;
static LIST_HEAD(seq_demo_list);
static DEFINE_MUTEX(seq_demo_lock); struct seq_demo_node {
char name[];
struct list_head list;
}; static void *seq_demo_start(struct seq_file *s, loff_t *pos)
{
mutex_lock(&seq_demo_lock); return seq_list_start(&seq_demo_list, *pos);
} static void *seq_demo_next(struct seq_file *s, void *v, loff_t *pos)
{
return seq_list_next(v, &seq_demo_list, pos);
} static void seq_demo_stop(struct seq_file *s, void *v)
{
mutex_unlock(&seq_demo_lock);
} static int seq_demo_show(struct seq_file *s, void *v)
{
struct seq_demo_node *node = list_entry(v, struct seq_demo_node, list); seq_printf(s, "name: %s, addr: 0x%p\n", node->name, node); return ;
} static const struct seq_operations seq_demo_ops = {
.start = seq_demo_start,
.next = seq_demo_next,
.stop = seq_demo_stop,
.show = seq_demo_show,
}; static int seq_demo_open(struct inode *inode, struct file *file)
{
return seq_open(file, &seq_demo_ops);
} static const struct file_operations seq_demo_fops = {
.owner = THIS_MODULE,
.open = seq_demo_open,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release,
}; static int __init seq_demo_init(void)
{
int i;
struct seq_demo_node *node; for (i = ; i < ; i++) {
node = kzalloc(sizeof(struct seq_demo_node), GFP_KERNEL);
sprintf(node->name, "node%d", i); INIT_LIST_HEAD(&node->list);
list_add_tail(&node->list, &seq_demo_list);
} seq_demo_dir = debugfs_create_file("seq_demo", , NULL,
NULL, &seq_demo_fops);
return ;
} static void __exit seq_demo_exit(void)
{
struct seq_demo_node *node_pos, *node_n; if (seq_demo_dir) {
debugfs_remove(seq_demo_dir);
list_for_each_entry_safe(node_pos, node_n, &seq_demo_list, list)
if (node_pos) {
printk("%s: release %s\n", __func__, node_pos->name);
kfree(node_pos);
}
}
} module_init(seq_demo_init);
module_exit(seq_demo_exit);
MODULE_LICENSE("GPL");

下面是运行结果:

[root@vexpress mnt]# cat /d/seq_demo
name: node0, addr: 0xef252000
name: node1, addr: 0xef252680
name: node2, addr: 0xef252380
name: node3, addr: 0xef252740
name: node4, addr: 0xef252b00
name: node5, addr: 0xee80e480
name: node6, addr: 0xeeb9fd40
name: node7, addr: 0xeeb9fd00

二、分析

在遍历链表的时候使用seq_file提供的通用接口函数,当然也可以自己实现,只需要遵循如下原则:
start:根据索引编号pos找到对应的node,并返回该node的地址,也就是show和next方法里的v
next:根据当前node的地址和索引编号计算下一个node的地址和索引编号pos,返回值就是下一个节点的地址
show:输出传入的node的信息
stop:如果在start里有加锁,那么在这里需要释放锁
 
结合上面的驱动分析一下:
seq_list_start:
 struct list_head *seq_list_start(struct list_head *head, loff_t pos)
{
struct list_head *lh; list_for_each(lh, head)
if (pos-- == )
return lh; return NULL;
}
遍历链表,寻找索引为pos的项,找到的话,返回地址,否则返回NULL。当返回NULL的时候, stop会被调用。
 
seq_list_next:
 struct list_head *seq_list_next(void *v, struct list_head *head, loff_t *ppos)
{
struct list_head *lh; lh = ((struct list_head *)v)->next;
++*ppos;
return lh == head ? NULL : lh;
}
计算下一项的地址和索引,如果遍历结束,即lh==head,返回NULL,否则返回下一项的地址。当返回NULL的时候,stop会被调用并把缓冲区中的内容吐给用户
 
 
未完待续

seq_file学习(2)—— seq_file的更多相关文章

  1. seq_file学习(1)—— single_open

    span::selection, .CodeMirror-line > span > span::selection { background: #d7d4f0; }.CodeMirror ...

  2. Seq_file文件系统实例剖析

    http://blog.chinaunix.net/uid-24432676-id-2607766.html 另 http://www.cnblogs.com/qq78292959/archive/2 ...

  3. linux内核seq_file接口

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

  4. 序列文件(seq_file)接口

    转载:http://blog.csdn.net/gangyanliang/article/details/7244664 内容简介: 本文主要讲述序列文件(seq_file)接口的内核实现,如何使用它 ...

  5. 设备驱动基础学习--/proc下增加节点

    在需要创建一个由一系列数据顺序组合而成的/proc虚拟文件或一个较大的/proc虚拟文件时,推荐使用seq_file接口. 数据结构struct seq_fille定义在include/linux/s ...

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

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

  7. Non Lasting Storage File System、procfs、sysfs

    catalog . 引言 . proc文件系统 . 简单的文件系统 . sysfs 0. 引言 传统上,文件系统用于在块设备上持久存储数据,但也可以使用文件系统来组织.提供.交换并不存储在块设备上的信 ...

  8. The Kernel Newbie Corner: Kernel Debugging with proc "Sequence" Files--Part 3

    转载:https://www.linux.com/learn/linux-career-center/44184-the-kernel-newbie-corner-kernel-debugging-w ...

  9. imx51-linux的cpuinfo之分析

    这两天客户提出来,我们的平板cat /proc/cpuinfo出来的信息中的serial怎么是0. 客户就是上帝啊,没办法,分析找问题贝. 我们先看一下目前的cat /proc/cpuinfo的信息: ...

随机推荐

  1. Apache Pulsar——企业级消息订阅系统介绍

    Apache Pulsar是一款由雅虎开发的类似于Kafka的企业级消息订阅系统,在2016将其开源,由Apach基金会孵化,现在已经成长为Apache基金会的顶级项目.Pulsar在雅虎内部已经运行 ...

  2. ansible基础命令实例

    参考:https://www.cnblogs.com/ilurker/p/6421624.html 1. 使用自定义的hosts 格式: ansible  组机匹配  -i  自定义的hosts  - ...

  3. Shiro笔记(六)Shiro标签的使用

    Shiro标签的使用 引入标签库 <%@taglib prefix="shiro" uri="http://shiro.apache.org/tags"% ...

  4. react学习二 生命周期

    转自:https://www.cnblogs.com/gdsblog/p/7348375.html react 中compent getDefaultProps object getDefaultPr ...

  5. Fire! -两次dfs

    题目描述: Joe works in a maze. Unfortunately, portions of the maze have caught on fire, and the owner of ...

  6. gitment Error:validation failed错误解决办法

    点击Initialize comments 突然跳转出一个错误Error:validation failed 经查阅之后发现 issue的标签label有长度限制!labels的最大长度限制是50个字 ...

  7. Git 日常工作中使用的命令记录

    前言   这篇文章主要是介绍我在使用Git中的有一些忘记了,但是很重要的命令. 20190424 Git 历史信息 username 和 email 更改 git config alias.chang ...

  8. spring mvc简单介绍xml版

    spring mvc介绍:其实spring mvc就是基于servlet实现的,只不过他讲请求处理的流程分配的更细致而已. spring mvc核心理念的4个组件: 1.DispatcherServl ...

  9. 如何基于asp.net core的Identity框架在mysql上作身份验证处理

    首先了解这个概念,我一开始也是理解和掌握基本的概念,再去做程序的开发.Identity框架是微软自己提供,基于.net core平台,可拓展.轻量 级.面向多个数据库的身份验证框架.IdentityS ...

  10. Err.number错误号和可捕获的 Microsoft access 数据库引擎和 DAO错误说明

    错误码        信息2420        数字语法错误2421        日期语法错误2422        字符串语法错误2423        ‘.’.‘!’.或 ‘()’的使用无效2 ...