seq_file接口编程浅析

linux seq_file机制学习 linux内核驱动模块经常要将一些信息通过/proc文件树暴露给用户,以方便用户直接能从文件系统中读取到驱动程序或者内核的一些状态信息,当这些信息比较短的时候编程比较容易,一旦过长并且用户有lseek相关的操作,那么在内核中编程就就会变得比较困难,需要维护很多状态。为了解决这个问题,linux内核提供了一种seq_file机制来简化编程的复杂性。 本文实验环境:Linux VM-0-13-ubuntu 5.4.0-90-generic #101-Ubuntu SMP Fri Oct 15 20:00: 阅读详情

 由于procfs的默认操作函数只使用一页的缓存,在处理较大的proc文件时就有点麻烦,并且在输出一系列结构体中的数据时也比较不灵活,需要自己在read_proc函数中实现迭代,容易出现Bug。所以内核黑客们对一些/proc代码做了研究,抽象出共性,最终形成了seq_file(Sequence file:序列文件)接口。 这个接口提供了一套简单的函数来解决以上proc接口编程时存在的问题,使得编程更加容易,降低了Bug出现的机会。

     在需要创建一个由一系列数据顺序组合而成的虚拟文件或一个较大的虚拟文件时,推荐使用seq_file接口。但是我个人认为,并不是只有procfs才可以使用这个seq_file接口,因为其实seq_file是实现的是一个操作函数集,这个函数集并不是与proc绑定的,同样可以用在其他的地方。对于一个函数接口层的学习,首先要看一个相关的数据结构struct seq_file:

include/linux/seq_file.h

  1. struct seq_file {
  2. char *buf;     //seq_file接口使用的缓存页指针
  3. size_t size;   //seq_file接口使用的缓存页大小
  4. size_t from;   //从seq_file中向用户态缓冲区拷贝时相对于buf的偏移地址
  5. size_t count;  //buf中可以拷贝到用户态的字符数目 
  6. loff_t index;  //start、next的处理的下标pos数值
  7. loff_t read_pos;  //当前已拷贝到用户态的数据量大小
  8. u64 version;
  9. struct mutex lock;  //针对此seq_file操作的互斥锁,所有seq_*的访问都会上锁
  10. const struct seq_operations *op; //操作实际底层数据的函数
  11. void *private;
  12. };
    在这个结构体中,几乎所有的成员都是由seq_file内部实现来处理的,程序员不用去关心,除非你要去研究seq_file的内部原理。对于这个结构体,程序员唯一要做的就是实现其中的 const struct seq_operations *op。 为使用 seq_file接口对于不同数据结构体进行访问,你必须创建一组简单的对象迭代操作函数。

  1. struct seq_operations {
  2. void * (*start) (struct seq_file *m, loff_t *pos);
  3. void (*stop) (struct seq_file *m, void *v);
  4. void * (*next) (struct seq_file *m, void *v, loff_t *pos);
  5. int (*show) (struct seq_file *m, void *v);
  6. };

       seq_file内部机制使用这些接口函数访问底层的实际数据结构体,并不断沿数据序列向前,同时逐个输出序列里的数据到seq_file自建的缓存(大小为一页)中。也就是说seq_file内部机制帮你实现了对序列数据的读取和放入缓存的机制,你只需要实现底层的迭代函数接口就好了,因为这些是和你要访问的底层数据相关的,而seq_file属于上层抽象。这可能看起来有点复杂,大家看了下面的图就好理解了:

 

     这里我们大致介绍下struct seq_operations中的各个函数的作用:

  void * (*start) (struct seq_file *m, loff_t *pos);

  1. start 方法会首先被调用,它的作用是在设置访问的起始点。
  2. m:指向的是本seq_file的结构体,在正常情况下无需处理。
  3. pos:是一个整型位置值,指示开始读取的位置。对于这个位置的意义完全取决于底层实现,不一定是字节为单位的位置,可能是一个元素的序列号。
  4. 返回值如果非NULL,则是一个指向迭代器实现的私有数据结构体指针。如果访问出错则返回NULL。

    

       设置好了访问起始点,seq_file内部机制可能会使用show方法获取start返回值指向的结构体中的数据到内部缓存,并适时送往用户空间。

  1. int (*show) (struct seq_file *m, void *v);

      所以show方法就是负责将v指向元素中的数据输出到seq_file的内部缓存,但是其中必须借助seq_file提供的一些类似printf的接口函数:

  1. int seq_printf(struct seq_file *sfile, const char *fmt, ...);
  2. //专为 seq_file 实现的类似 printf 的函数;用于将数据常用的格式串和附加值参数.
  3. //你必须将给 show 函数的 set_file 结构指针传递给它。如果seq_printf 返回-1,意味着缓存区已满,部分输出被丢弃。但是大部分时候都忽略了其返回值。

  4. int seq_putc(struct seq_file *sfile, char c);
  5. int seq_puts(struct seq_file *sfile, const char *s);
  6. //类似 putc 和 puts 函数的功能,sfile参数和返回值与 seq_printf相同。
  7. int seq_escape(struct seq_file *m, const char *s, const char *esc);
  8. //这个函数类似 seq_puts ,但是它会将 s 中所有在 esc 中出现的字符以八进制格式输出到缓存。
  9. //esc 的常用值是"\t\n\\", 它使内嵌的空格不会搞乱输出或迷惑 shell 脚本.

  int seq_write(struct seq_file *seq, const void *data, size_t len) 
  //直接将data指向的数据写入seq_file缓存,数据长度为len。用于非字符串数据。

  1. int seq_path(struct seq_file *sfile, struct vfsmount *m, struct dentry *dentry, char *esc);
  2. //这个函数能够用来输出给定目录项关联的文件名,驱动极少使用。  

    

 在show函数返回之后,seq_file机制可能需要移动到下一个数据元素,那就必须使用next方法。

void * (*next) (struct seq_file *m, void *v, loff_t *pos);

  1. v:是之前调用start或next返回的元素指针,可能是上一个show已经完成输出所指向的元素。
  2. pos:需要移动到的元素索引值。

      在next实现中应当递增pos指向的值,但是具体递增的数量和迭代器的实现有关,不一定是1。而next的返回值如果非NULL,则是下一个需要输出到缓存的元素指针,否则表明已经输出结束,将会调用stop方法做清理。

  1. void (*stop) (struct seq_file *m, void *v);

      在stop实现中,参数m指向本seq_file的结构体,在正常情况下无需处理。而v是指向上一个next或start返回的元素指针。在需要做退出处理的时候才需要实现具体的功能。但是许多情况下可以直接返回。


    在next和start的实现中可能需要对一个序列的函数进行遍历,而在内核中,对于一个序列数据结构体的实现一般是使用双向链表或者哈希链表,所有seq_file同时提供了一些对于内核双向链表和 哈希链表的封装接口函数,方便程序员实现对于通过链表链接的结构体序列的操作。这些函数名一般是seq_list_*或者seq_hlist_*,这些函数的实现都在 fs/seq_file.c中,有兴趣的朋友可以看看。我在后面的实验中依然使用内核通用的双向链表API。
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
编程步骤:

        在上面我们介绍了使用 seq_file 需要实现的一些函数和相关结构体,现在我们把她们组合起来,介绍以下通过 proc 来使用 seq_file 的一般步骤,而 seq_file 在其他方面的应用方法也是一样的。

(1)在注册proc文件入口的时候,注册包含seq_file操作函数的file_operations结构体到proc_fops。我的测试程序中的实例代码如下:

  1. proc_test_entry = create_proc_entry("proc_seq", 0644, NULL);
  2. if (proc_test_entry == NULL) {
  3.    ret = -ENOMEM;
  4.    cleanup_test_data();
  5.    pr_err("proc_test: Couldn't create proc entry\n");
  6. } else {
  7.    proc_test_entry->proc_fops = &proc_ops;
  8.    pr_info("proc_test: Module loaded.\n");
  9. }


(2)实现struct file_operations proc_ops,示例如下:

  1. static struct file_operations proc_ops = {
  2. .owner = THIS_MODULE,
  3. .open = proc_seq_open,
  4. .read = seq_read,
  5. .llseek = seq_lseek,
  6. .release = seq_release,
  7. };

        大家可以看到,以上的read、llseek、release都是有seq_file提供的接口函数,直接注册即可,唯有open是需要自己实现的。

(3)这个open函数的实现也是非常简单固定格式,实例如下:

  1. static int proc_seq_open(struct inode *inode, struct file *file)
  2. {
  3.      return seq_open(file, &proc_seq_ops);
  4. };

      可以看到,一般就是使用seq_file中的一个API:seq_open,目的是向seq_file结构体中注册一个struct seq_operations 。


(4)实现 seq_operations ,也就是前面我们介绍的seq_file的底层数据操作函数集,示例如下:


  1. static struct seq_operations proc_seq_ops = {
  2. .start = proc_seq_start,
  3. .next = proc_seq_next,
  4. .stop = proc_seq_stop,
  5. .show = proc_seq_show
  6. };

       这些回调函数都是需要根据你所要获取的序列数据结构来实现的。

       其实在实际编程过程应该是相反的:(4)-->(3)-->(2)-->(1),但是为了更好的理解,我就从最后的注册开始,再介绍需要实现的结构体。

       好了,基本的seq_file的使用都已经介绍过了,但是要真正的用好seq_file最好还是要去看一下她的实现源码(fs/seq_file.c),只有了解了内部原理,用起来才会得心应手。

        而对于前面所使用的测试代码以及前面的procfs的测试代码,在下一篇中将会给出,并做测试记录。

使用seq_file Linux kernel seq_file使用及编程。 阅读详情

相关推荐

Linux内核中的seq操作

  Linux内核中的seq操作 本文档的Copyleft归yfydz所有,使用GPL发布,可以自由拷贝,转载,转载时请保持文档的完整性,严禁用于任何商业用途。msn: yfydz_no1@hotmail.com来源:http://yfydz.cublog.cn1. 前言 在fs/seq_file.c中定义了关于seq

Walter的专栏 1229

Linux驱动之文件系统

module是加载的模块列表。可以看到kernfs_open_file结构体是挂在seq_file结构体的private指针下的,现在可以梳理下这三者之间的关系,file结构体的private_data指向seq_file,seq_file的private指向kernfs_open_file,这样他们就都联系起来的,当然这里是分析特定文件系统下的实现,在其他情况下可以指向其他数据结构。在这里,对seq_open()的调用采用我们之前创建的seq_operations结构,并设置为遍历虚拟文件。

Android系统攻城狮 1270

Linux中seq_file文件系统实例剖析

Linux中seq_file文件系统实例剖析 1、seq_file介绍    针对proc文件的不足而诞生了Seq_file。 Seq_file的实现基于proc文件。使用Seq_file,用户必须抽象出一个链接对象,然后可以依次遍历这个链接对象。这个链接对象可以是链表,数组,哈希表等等。 编程接口 Seq_file必须实现四个操作函数:start(), next(), show

chenglinhust的专栏 1532

内核proc文件系统与seq接口(4)---seq_file接口编程浅析

由于procfs的默认操作函数只使用一页的缓存,在处理较大的proc文件时就有点麻烦,并且在输出一系列结构体中的数据时也比较不灵活,需要自己在read_proc函数中实现迭代,容易出现Bug。所以内核黑客们对一些/proc代码做了研究,抽象出共性,最终形成了seq_file(Sequence file:序列文件)接口。 这个接口提供了一套简单的函数来解决以上proc接口编程时存在的问题,使得编

dolphin98629的专栏 1585

LDD: ch4补充,seq_file的介绍

LDD CH4补充, seq_file介绍

sky的专栏 1236

告别第三方插件:官方Fused Library如何重塑Android库的合并与发布流程

本文详细介绍了Android官方推出的Fused Library如何替代第三方fat-aar插件,优化Android库的合并与发布流程。通过原生支持、智能依赖管理等优势,Fused Library解决了版本兼容性、依赖传递等核心痛点,提供了更稳定高效的开发体验。文章还提供了迁移实操指南和工程实践建议,帮助开发者顺利过渡到官方方案。

weixin_42561040的博客 254

内核proc文件系统与seq接口---seq_file接口编程浅析

http://blog.chinaunix.net/uid-28253945-id-3382865.html由于procfs的默认操作函数只使用一页的缓存,在处理较大的proc文件时就有点麻烦,并且在输出一系列结构体中的数据时也比较不灵活,需要自己在read_proc函数中实现迭代,容易出现Bug。所以内核黑客们对一些/proc代码做了研究,抽象出共性,最终形成了seq_file(Sequence...

Tim的嵌入式之旅 1266

Oracle EBS R12.2 安装 -- Step by Step

Oracle EBS R12.2 安装 -- Step by Step

Albert Tan DBA之路 1512

内核 seq_file 操作函数

接口API seq_file 系列函数是为了方便内核导出信息到 sysfs、debugfs、procfs 实现的。以往的内核也存在各种形式的实现,但是都无法避免个别实现会产生一些漏洞,这一套函数实现可以让内核导出信息更加简单和统一稳定,维护起来更加方便。 它包含了如下一些接口: int seq_open(struct file *file, const struct seq_operations ...

程序猿Ricky的日常干货 1万+

SAP FICO 银企直联实战:从配置到异常处理的全流程解析

本文详细解析了SAP FICO银企直联的实战配置与异常处理全流程,涵盖银行主数据搭建、支付类配置、银行接口适配等关键步骤。通过实际案例分享,帮助用户掌握实时付款、余额监控和自动对账等核心功能,提升企业财务效率与安全性。特别针对常见问题如凭证重复付款、前置机UUID冲突等提供了实用解决方案。

weixin_29215815的博客 663

避坑指南:用Adams做滚珠丝杠仿真时90%人会遇到的3个建模错误

本文针对使用Adams进行滚珠丝杠动力学仿真时常见的三大建模错误,提供了详细的避坑指南。重点解析了如何避免因直接导入CAD几何体导致的性能与精度问题,科学设置接触参数以提升计算效率与结果平滑度,以及通过规范的命名与组织管理模型,确保仿真过程高效可靠。

gin88的博客 573

序列文件(seq_file)接口

内容简介:本文主要讲述序列文件(seq_file)接口的内核实现,如何使用它将Linux内核里面常用的数据结构通过文件(主要关注proc文件)导出到用户空间,最后定义了一些宏以便于编程,减少重复代码。在分析序列文件接口实现的过程中,还连带涉及到一些应用陷阱和避免手段。序列文件接口:UNIX的世界里,文件是最普通的概念,所以用文件来作为内核和用户空间传递数据的接口也是再普通不过的事情,并且这

1102

DA14531之搭建开发环境

DA14531之搭建开发环境

hejinwu1314的博客 1777

linux seq_file 文件编程步骤

linux seq_file 文件编程步骤

一叶知秋的博客 1449

机器视觉框架源码——解读5(Dock和开源UI)

本文介绍了工业软件中Dock工具面板的使用方法,主要包括三个部分:添加avalonDock引用、修改属性配置(如显示样式和背景色),以及通过MVVM命令实现布局的加载和保存。加载布局通过XmlLayoutSerializer从XML文件恢复界面状态,保存布局则将当前DockManager的布局序列化为XML文件。文章提供了代码示例和截图说明,帮助开发者快速掌握Dock面板的核心功能。

Z's Palace 402

微信小程序 - 苹果ios无法播放视频、安卓android手机可以播放,使用video播放MP4视频时安卓正常播放视频iOS无法播放出现黑屏、加载失败或一片黑没反应等(uniapp微信小程序也能解决)

微信小程序ios无法播放视频,微信小程序 video标签 ios不能播放视频或视频黑屏,ios无法播放视频,android手机可以播放,视频格式为mp4,uniapp微信小程序安卓设备android可以播放在线网络视频 ,苹果ios设备无法播放视频,微信小程序 video标签 ios不能播放视频或视频黑屏,安卓手机正常播放iPhone手机却黑屏,如何解决这个问题,在线播放视频URL链接,iOS无法播放MP4视频文件的解决方案,在Android设备上可以正常播放,但在iOS设备上却出现黑屏、无法加载或无法播放

🏆 前端领域优质创作者 1万+

Linux Kernel 序列文件(seq_file)接口实战

@[TOC](Linux Kernel 序列文件(seq_file)接口实战) 1.PROC文件系统简介 使用 /proc 文件系统来访问 Linux 内核的内容,这个虚拟文件系统在内核空间和用户空间之间打开了一个通信窗口: /proc 文件系统是一个虚拟文件系统,通过它可以使用一种新的方法在 Linux内核空间和用户间之间进行通信。在/proc 文件系统中,我们可以将对虚拟文件的读写作为与内核中...

weixin_39280491的博客 1715

安全监控:人员行为分析_(2).人员行为分析基础理论

人员行为分析是指利用计算机视觉技术对视频中的人类行为进行实时或离线检测、识别和理解的过程。视频采集:通过摄像头等设备获取视频数据。视频预处理:对视频数据进行噪声过滤、图像增强等处理,以便后续分析。特征提取:从视频中提取出与人员行为相关的特征,如人体姿势、动作轨迹等。行为识别:利用机器学习或深度学习模型对提取的特征进行分类,识别出具体的人员行为。行为理解:对识别出的行为进行进一步分析,理解其背后的意图或状态。在人员行为分析中,常用的公开数据集包括UCF101、HMDB51、ActivityNet等。

zhubeibei168的博客 1345

The seq_file interface

The seq_file interface Copyright 2003 Jonathan Corbet <corbet@lwn.net> This file is originally from the LWN.net Driver Porting series at http://lwn.net/Articles/driver-porting/ 设备驱动程序(或其他内核组件)有...

win9 674

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

Kernel之seq_file接口

Kernel之seq_file接口 | DD'Noteshttps://notes.z-dd.online/2021/12/09/Kernel%E4%B9%8Bseq_file%E6%8E%A5%E5%8F%A3/ 最近在看/proc/cpuinfo的内核实现时,发现了一个以前没注意的东东: seq_file接口 seq_file(Sequence file:序列文件)接口 内核文档: Documentation/filesystems/seq_file.txt

DD'Notes 310

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

proc文件系统:2.seq_file接口

文章目录一、seq_file接口1.目的2.函数二、实验1.内容2.过程(1)编写内核模块.c文件(2)编写Makefile文件(3)编译(4)安装模块:(5)查看`printk`的输出在缓冲区的信息:(6)卸载模块:(7)清除`printk`输出在缓存区的信息: 一、seq_file接口 1.目的 从内核中导出信息到用户空间有很多方法,可以自己去实现file_operations的read...

sandalphon4869的博客 1028

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

linux 内核proc 文件系统与seq接口

linux 内核proc 文件系统与seq接口

一叶知秋的博客 1783

seq_file 讲得很明白

kernel module编程(八):读取proc文件之seq_file   在上次我们使用了read_proc的方式通过/proc文件读取kernel module的信息。作者给的例子他自己说是ugly。而我们在读取大量数据时发现,受到用户buffer大小的限制(page的大小),可能需要读取多次,不仅需要记录上次读取的位置,而且由于每次读取我们申请了信号量,读取完释放,那么如果多次

3489

struct seq_file

Table of Contents struct seq_file 一个例子 struct seq_file struct seq_file { char *buf; //在seq_open中分配,大小为4KB size_t size; //4096 size_t from; //struct file从seq_file中向用户态缓冲区...

RToax 1056

seq_file机制

seq_file机制 在老版本的Linux内核中,proc文件系统有一个缺陷:如果输出内容大于1个内存页,需要多次读,因此处理起来很难。另外,如果输出内容太大,速度会比较慢。在2.6内核中,由于大量使用了seq_file功能,使得内核输出大文件信息更容易。使用seq_file需要包含头文件linux/seq_file.h,并定义一个seq_operations结构: struct seq_op

harvey2008的专栏 1114
上一篇: Linux内核Crash分析
下一篇: Linux下编译、链接和装载
wdsfup
博客等级 码龄20年 31粉丝 13原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值