读取proc文件之seq_file

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

读取proc文件之seq_file

本文也即《Linux Device Drivers》,LDD3的第四章Debuging Techniques的读书笔记之三,但我们不限于此内容。

  在上次我们使用了read_proc的方式通过/proc文件读取kernel module的信息。作者给的例子他自己说是ugly。而我们在读取大量数据时发现,受到用户buffer大小的限制(page的大小),可能需要读取多次,不仅需要记录上次读取的位置,而且由于每次读取我们申请了信号量,读取完释放,那么如果多次读取的间隔中,如果信号量被写所获取就好出现混乱。linux kernel提供seq_file更好的方式来解决这个问题,除非我们确定读取的信息量非常少,能够在page中返回,我们应使用seq_file的方式而不是read_proc 。

  LDD3中介绍的方式,我觉得是典型的西方人和中国人思维方式的不同。在seq_file的介绍中,LDD3先从每个操作具体将其,然后到如何和proc文件联系,最后到如何创建proc文件,我喜欢反过来的方式,先创建proc,在一步步细化。老外是日月年,我们是年月日,嘿嘿。seq_file的处理方式开看有点发展,步骤有些多,但是安全,是规范的处理方式。

步骤一:建立proc文件。

  通过一个struct proc_dir_entry的元素,在/proc中建立文件,如下:

struct proc_dir_entry * entry = create_proc_entry(“scullseq”,0,NULL)。参数的内容和read_proc,第一个参数表示文件名,第二个参数表示文件属性,对于只读方式为0,第三个参数表示文件路径,NULL表示缺省路径,即/proc。

步骤二:关联proc的操作。

   需要对文件进行操作,见过文件和struct file_operations相关联,我们注意到这个数据结构也用于模块操作关联中。具体操作如下:

#ifdef SCULL_SEQ_FILE 
/* 步骤二:2、定义proc文件所关联的文件操作数据 */ 
static struct file_operations scull_proc_ops = {  
        .owner  = THIS_MODULE,   
        .open    = scull_proc_open,  //open通常这是我们唯一需要重新定义的函数,需要和特定的seq_file关联起来。 
        .read     = seq_read,               //采用系统的处理方式 
        .llseek   = seq_lseek,              //采用系统的处理方式 
        .release = seq_release,         //采用系统的处理方式 
};

/* 步骤二:4、在前面的步骤二1~3中我们创建了proc文件,关联了proc文件和file_operations,并进一步关联了seq_file,这里我们具体定义被关联的seq_file */ 
static struct seq_operations scull_seq_ops = { 
        .start          = scull_seq_start, 
        .next          = scull_seq_next, 
        .stop          = scull_seq_stop, 
        .show         = scull_seq_show, 
};

static struct proc_dir_entry * entry; 
#endif 
… … 
static int __init scull_init(void) 
{ 
… … 
#ifdef SCULL_SEQ_FILE 
        /* 步骤一:创建proc文件*/ 
        entry = create_proc_entry ("scullseq", 0 ,NULL); 
        /* 步骤二:1、将proc文件和对应的文件操作关联起来*/ 
        if(entry) 
                entry -> proc_fops = & scull_proc_ops ; 
#endif 
} 
... ...  

static void __exit scull_exit(void) 
{ 
#ifdef SCULL_SEQ_FILE
 
/* 我们在模块中创建的proc文件,都应该模块cleanup模块的时候删除,以防影响系统,另外,我们应该在删除模块函数的开始执行这个操作,防止相关联的数据已经删除或者注销后再来处理,避免异常出现。 */ 
        remove_proc_entry("scullseq",NULL ); 
#endif 
        if(is_get_dev < 0){ 
                return ; 
        }else{ 
                int i = 0; 
                for(i = 0; i < SCULL_DEV_NUM; i ++){ 
                        scull_trim(&mydev[i]); 
                        cdev_del( & mydev[i].cdev ); 
                } 
                unregister_chrdev_region(dev,SCULL_DEV_NUM); 
                WDEBUG(WEI_KERN_NOTICE,"Scull module exit/n"); 
        } 
}

/* 步骤二:3、具体实现proc文件的open操作,目的与seq_file相关联。*/ 
int scull_proc_open(struct inode * inode , struct file * file) 
{ 
        return seq_open(file, & scull_seq_ops ); 
}

 

步骤三:处理seq_file操作过程。

  seq_file操作定义了四个操作,格式如下:

void * start(struct seq_file * s, loff_t * v); 
void * next (struct seq_file * s, void * v, loff_t * pos); 
void   stop (struct seq_file * s, void * v); 
int    show (struct seq_file * s, void * v);

  其中loff_t表示位置,这是由我们自己程序控制的,初始为0,在scull中我们依次读取scull0-3,因此使用该偏移量来表示我们所读取的设备的序号。

  我们利用void * v来记录设备的入口位置。start根据编译量,即我们的设备的序号,返回scullx的入口位置,无论下一操作是next,stop,还是show,这个返回值会作为参数void *v输入。next表示下一查询,和start相似,只是多了void * v的输入,同样它的返回值也作为下一操作的参数void *v输入。show用于通过/proc文件输出。stop表示一次读取的结束。虽然在seq_file中和read_proc不一样,不需要考虑每次可以输出的buff的大小,但是实际读取不会连续一片很大的数据输出,在例子后面,我们将讨论这些操作的执行。

  输出方式非常简单,一般可以使用seq_printf,另外还有seq_putc,seq_puts,seq_escape。例子如下:

#ifdef SCULL_SEQ_FILE 
void * scull_seq_start (struct seq_file * s, loff_t * pos) 
{ 
        printk("==scull_seq_start() enter %p %p %lli/n", s , pos , * pos); 
        if( * pos >= SCULL_DEV_NUM) 
                return NULL; 
        else 
                return mydev + * pos; 
}

void * scull_seq_next (struct seq_file * s, void * v, loff_t * pos) 
{ 
        printk("==scull_seq_next() enter %p %p %p %lli/n", s , v, pos , * pos); 
        (* pos ) ++; 
        return scull_seq_start(s, pos); 
}

void scull_seq_stop (struct seq_file * s, void * v) 
{ 
       printk("==scull_seq_stop() enter/n"); 
        return ; 
}

int scull_seq_show (struct seq_file * s, void * v) 
{ 
        struct scull_dev * dev = (struct scull_dev *) v; 
        struct scull_qset * qs = NULL; 
        int j = 0; 
       printk("==scull_seq_show() enter/n");

        if(down_interruptible(&dev->sem)) 
                return -ERESTARTSYS; 

        seq_printf (s, "/n Device Scull%d: qset %i, q %i sz %li/n", (int) (dev - mydev),dev->qset, dev->quantum, dev->size); 
        printk("/n Device Scull%d: qset %i, q %i sz %li/n", (int) (dev - mydev),dev->qset, dev->quantum, dev->size);

        for(qs = dev->data ; qs ; qs=qs->next){ 
                seq_printf ( s,"  item at %p, qset at %p/n", qs,  qs->data); 
                printk("  item at %p, qset at %p/n", qs,  qs->data); 
                if(qs->data ){ 
                        for(; j < dev->qset /* && qs->data[ j ] */ ;j++){ 
                               seq_printf (s ,"/t%4i:%8p/n",  j,qs->data[ j ]); 
                                printk("/t%4i:%8p/n",  j,qs->data[ j ]); 
                        } 
                } 
        } 

        up(&dev->sem); 
        return 0; 
}

  我们描述一下处理的过程:当我们读取proc文件,例如cat /proc/scullseq时,我们假设scull0和scull1都有较多信息输入。

  一开始调用start,偏移量为0,返回scull0的入口,接着调用show,scull0的入口作为参数输入,在show中,我们可以遍历scull0的数据结构,通过seq_printf输出。完成show后,由于输出信息多,进入stop,在例子中stop没有实际操作,我们只是用来跟踪处理的流程。

   再次调用start,偏移量步进1,即1,返回scull0的入口,接着调用show,scull1的入口作为参数输入,在show中,我们可以遍历scull1的数据结构,通过seq_printf输出。完成show后,由于输出信息多,进入stop。

  再次调用start,偏移量步进1,即2,返回scull2的入口,接着调用show,scull2的入口作为参数输入,在show中,我们可以遍历scull2的数据结构,通过seq_printf输出。完成show后,由于输出信息非常少,kernel认为可以继续进行操作,而不需要stop,调用next(),在next参数中输入的参数loff_t为2,next将其加一,为3,返回scull3的入口。接着调用show,scull3的入口作为参数输入,在show中,我们可以遍历scull3的数据结构,通过seq_printf输出。完成show后,由于输出信息非常少,kernel认为可以继续进行操作,而不需要stop,调用next()。由于已经全部信息返回,在next中发现没有数据,返回NULL。系统再次调用start,返回NULL,系统调用stop,结束这次输出。

  再次调用start,返回NULL,表示已经没有数据输出,调用stop,结束所有的输出。

  值得注意 seq_file 代码在调用 start 和 stop 之间不睡眠或者进行其他非原子性任务. 你也肯定会看到在调用 start 后马上有一个 stop 调用. 因此, 对你的 start 方法来说请求信号量或自旋锁是安全的. 只要你的其他 seq_file 方法是原子的, 调用的整个序列是原子的.

 

 原文地址 http://www.deansys.com/doc/ldd3/ch04s03.html

手把手复现金蝶云星空V8.1文件上传漏洞(附完整POC与修复方案) 本文深度解析金蝶云星空V8.1文件上传漏洞,提供详细的漏洞复现步骤与完整POC,涵盖技术原理、测试环境搭建及验证流程。同时给出多维防护方案,包括官方补丁部署、临时缓解措施和长期安全加固建议,帮助企业有效防范任意文件上传风险。 阅读详情

相关推荐

Palantir Vertex:数字孪生模拟与决策系统深度指南

Palantir Vertex是Foundry系统中的核心数字孪生模块,本质上是一个决策模拟器而非简单的数据可视化工具。它基于本体层构建,通过对象关系网络模拟现实世界实体,填补数据模型与业务决策间的鸿沟。核心功能包括:创建隔离的沙盒场景进行假设测试、修改参数模拟不同干预方案、对比虚实数据发现异常,并最终将最优决策回传至业务系统。典型应用场景涵盖供应链韧性评估、资产维护优化和应急方案制定等,帮助用户在复杂环境中做出更优决策。

轩哥的个人研究和成长记录 891

kernel module编程(七):通过读取proc文件进行debug

  本文也即《Linux Device Drivers》,LDD3的第四章Debuging Techniques的读书笔记之二,但我们不限于此内容。  在linux中,例如读取CPU,可以使用cat /proc/cpuinfo,通过这个我们可以在程序中采用读文件的方式获取CPU,这种大容量高性能的服务中非常常用,例如在cpu大于60%的时候,我们将拒绝所有的业务请求,直至cpu恢复到40%

愷风(Wei)的专栏 4782

matlab物元可拓模型程序,熵权可拓物元模型

1 概述物元分析方法是中国学者蔡文于20世纪80年代提出的用于解决矛盾问题的技术方法,是研究物元及其变化规律,解决现实世界中不相容问题的有效方法,可应用于生态环境,水资源承载力,农用地分级和土地生态水平等综合评价研究中.本文主要介绍了熵权可拓物元模型的相关概念与该模型的建立过程.2 概念2.1 物元物元分析法的主要思想是把事物用"事物,特征,量值"(分别用N,C,V表示)3个要素以有序三元组的形式...

weixin_33823399的博客 4110

seq文件传输

seq文件传输 一、PROC读写 在进行proc接口创建的时候,我们需要制定对应的文件操作函数,即创建的proc文件被读、写的时候要调用的函数,也就是我们的回调函数。其结构体定义如下: struct file_operations { loff_t (*llseek) (struct file *, loff_t, int); ssize_t (*read) (struct file *, char __user *, size_t, loff_t *); ssize_t (*write) (stru

qq_17045267的博客 2190

属性基加密(Attribute-based Encryption, ABE)

KP-ABE中,用户的密钥定义了访问策略,密文的属性与策略进行匹配。CP-ABE中,密文定义了访问策略,用户的属性与策略进行匹配。

2201_75392924的博客 1830

IAR9.X半主模式异常解析:为何硬件复位后仍陷调试状态?

本文深入解析了IAR 9.X半主模式异常问题,探讨了硬件复位后MCU仍陷调试状态的原因及解决方案。通过分析半主模式工作机制,提供了禁用半主功能、重写低级IO函数等具体方法,并给出了版本兼容性处理和调试与量产配置分离的优化建议,帮助开发者有效解决复位异常问题。

oo7890的博客 605

kernel module编程(八):读取proc文件之seq_file

  本文也即《Linux Device Drivers》,LDD3的第四章Debuging Techniques的读书笔记之三,但我们不限于此内容。  在上次我们使用了read_proc的方式通过/proc文件读取kernel module的信息。作者给的例子他自己说是ugly。而我们在读取大量数据时发现,受到用户buffer大小的限制(page的大小),可能需要读取多次,不仅需要记录上次

愷风(Wei)的专栏 7637

Flutter连接蓝牙打印机打印(含中文、双排打印)

Flutter连接蓝牙打印机打印(含中文、双排打印)

Session_W的博客 701

内核管理与系统启动

启动过程,systemd,netstat

weixin_43332972的博客 1000

PCIe 6.0 – 关于 PCI Express Gen6 您需要知道的一切

幸运的是,PCIe 6.0 FEC 足够轻,对延迟的影响最小。在电气层上,PCIe 6.0 使用 PAM4 信号(“四级脉冲幅度调制”),每个时钟周期将 2 位组合为 4 个幅度级别(00、01、10、11),与 PCIe 5.0 和前几代相比,它使用 NRZ 调制,每个时钟周期 1 位和两个幅度级别 (0, 1)。虽然 PAM4 信号更容易出错,但由于调制技术的性质,与 PCIe 5.0 相比,通道损耗不受影响,因此 PCB 上 PCIe 6.0 信号的范围将与 PCIe 5.0 相同。

qq_43416206的博客 3432

038、OIS 光学防抖原理与调试:陀螺仪数据融合、Lens Shift OIS 的闭环控制

本文分享了OIS光学防抖系统的调试经验和关键技术要点。作者通过一个"呼吸感"Bug案例,揭示了陀螺仪数据融合和闭环控制的重要性。系统介绍了OIS的三个关键层次:传感器层(陀螺仪特性)、控制层(复合算法)和执行层(闭环控制)。重点讲解了陀螺仪数据融合的互补滤波实现、Lens Shift闭环控制的PID优化策略(包括积分抗饱和和微分滤波),以及前馈补偿的应用。最后总结了调试中的关键问题:数据同步、霍尔校准、温度补偿和性能评估方法,并给出实用建议:平衡算法复杂度与性能、预留带宽余量、重视产线校准等。文章强调OIS

sundong_81的博客 262

Linux内核通信seq_file详解

Linux内核通信seq_file详解

Linux内核研究者 1322

AgentScope Java 2.0 最佳实践:9 个完整示例手把手带你开发 Java‑Agent

本文基于9 个完整示例,深入剖析从基础对话(BasicChatExample)、工具调用(@Tool 注解)、结构化输出(POJO Schema)、ToolGroup 自主管理、MCP 外部工具集成、Hook 生命周期监控、Spring Boot SSE 流式 Web、JsonSession 会话持久化到中断恢复的全链路实战教程。

program哲学 1642

kernel module编程(八) 读取proc文件之seq file

kernel module编程(八) 读取proc文件之seq file

skdhfdfc的博客 313

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

linux 读取proc文件之seq_file浅析1

在linux中通过proc文件系统

zhanshenwu的专栏 4809

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

seq_file 讲得很明白

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

3489

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

linux下proc文件系统下创建文件

proc.c /************************* * 使用seq_file接口实现可读写的proc文件 * 适用于3.10以后的内核 *************************/ #include <linux/module.h> #include <linux/sched.h> #include <linux/fs.h> #include <linux/proc_fs.h> #include <linux/seq_file

kuangzuxiaoN的博客 1615

linux seq_file 机制

和device_attr proc什么区别呢?seq_file 是 proc 的改进版本,device_attr 也可以认为是 proc 的改进吧 在老版本的Linux内核中,proc文件系统有一个缺陷:如果输出内容大于1个内存页(4096 Bytes),需要多次读,因此处理起来很难。另外,...

chenglinpan1548的博客 501
上一篇: unistd.h有什么用
dkbrain
博客等级 码龄18年 7粉丝 4原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值