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

set_file 接口假定你在创建一个虚拟文件, 它涉及一系列的必须返回给用户空间的项. 为使用 seq_file, 你必须创建一个简单的 "iterator" 对象, 它能在序列里建立一个位 置, 向前进, 并且输出序列里的一个项. 它可能听起来复杂, 但是, 实际上, 过程非常简 单. 我们一步步来创建 /proc 文件在 scull 驱动里, 来展示它是如何做的.

第一步, 不可避免地, 是包含 <linux/seq_file.h>. 接着你必须创建 4 个 iterator 方 法, 称为 start, next, stop, 和 show.

start 方法一直是首先调用. 这个函数的原型是:

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

sfile 参数可以几乎是一直被忽略. pos 是一个整型位置值, 指示应当从哪里读. 位置的 解释完全取决于实现; 在结果文件里不需要是一个字节位置. 因为 seq_file 实现典型地 步进一系列感兴趣的项, position 常常被解释为指向序列中下一个项的指针. scull 驱 动解释每个设备作为系列中的一项, 因此进入的 pos 简单地是一个 scull_device 数组 的索引. 因此, scull 使用的 start 方法是:

static void *scull_seq_start(struct seq_file *s, loff_t *pos)

{

if (*pos >= scull_nr_devs)

return NULL;  /* No more to read */ return scull_devices + *pos;

}

返回值, 如果非 NULL, 是一个可以被 iterator 实现使用的私有值.

next 函数应当移动 iterator 到下一个位置, 如果序列里什么都没有剩下就返回 NULL. 这个方法的原型是:

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

这里, v 是从前一个对 start 或者 next 的调用返回的 iterator, pos 是文件的当前位 置. next 应当递增有 pos 指向的值; 根据你的 iterator 是如何工作的, 你可能(尽管 可能不会)需要递增 pos 不止是 1. 这是 scull 所做的:

static void *scull_seq_next(struct seq_file *s, void *v, loff_t *pos)

{

(*pos)++;

if (*pos >= scull_nr_devs) return NULL;

return scull_devices + *pos;

}

当内核处理完 iterator, 它调用 stop 来清理: void stop(struct seq_file *sfile, void *v);

scull 实现没有清理工作要做, 所以它的 stop 方法是空的.

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

在这些调用中, 内核调用 show 方法来真正输出有用的东西给用户空间. 这个方法的原型 是:

int show(struct seq_file *sfile, void *v);

这个方法应当创建序列中由 iterator v 指示的项的输出. 不应当使用 printk, 但是; 有一套特殊的用作 seq_file 输出的函数:

int seq_printf(struct seq_file *sfile, const char *fmt, ...);

这是给 seq_file 实现的 printf 对等体; 它采用常用的格式串和附加值参数. 你 必须也将给 show 函数的 set_file 结构传递给它, 然而. 如果 seq_printf 返回 非零值, 意思是缓存区已填充, 输出被丢弃. 大部分实现忽略了返回值, 但是.

int seq_putc(struct seq_file *sfile, char c);

int seq_puts(struct seq_file *sfile, const char *s); 它们是用户空间 putc 和 puts 函数的对等体.

int seq_escape(struct seq_file *m, const char *s, const char *esc);

这个函数是 seq_puts 的对等体, 除了 s 中的任何也在 esc 中出现的字符以八进 制格式打印. esc 的一个通用值是"\t\n\\", 它使内嵌的空格不会搞乱输出和可能 搞乱 shell 脚本.

int seq_path(struct seq_file *sfile, struct vfsmount *m, struct dentry *dentry, char *esc);

这个函数能够用来输出和给定命令项关联的文件名子. 它在设备驱动中不可能有用; 我们是为了完整在此包含它.

回到我们的例子; 在 scull 使用的 show 方法是:

static int scull_seq_show(struct seq_file *s, void *v)

{

struct scull_dev *dev = (struct scull_dev *) v; struct scull_qset *d;

int i;

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

seq_printf(s, "\nDevice %i: qset %i, q %i, sz %li\n", (int) (dev - scull_devices), dev->qset, dev->quantum, dev->size);

for (d = dev->data; d; d = d->next) { /* scan the list */ seq_printf(s, " item at %p, qset at %p\n", d, d->data);

if (d->data && !d->next) /* dump only the last item */

for (i = 0; i < dev->qset; i++) { if (d->data[i])

seq_printf(s, " % 4i: %8p\n",

i, d->data[i]);

}

}

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

}

这里, 我们最终解释我们的" iterator" 值, 简单地是一个 scull_dev 结构指针.

现在已有了一个完整的 iterator 操作的集合, scull 必须包装起它们, 并且连接它们到

/proc 中的一个文件. 第一步是填充一个 seq_operations 结构:

static struct seq_operations scull_seq_ops = {

.start = scull_seq_start,

.next = scull_seq_next,

.stop = scull_seq_stop,

.show = scull_seq_show

};

有那个结构在, 我们必须创建一个内核理解的文件实现. 我们不使用前面描述过的 read_proc 方法; 在使用 seq_file 时, 最好在一个稍低的级别上连接到 /proc. 那意味 着创建一个 file_operations 结构(是的, 和字符驱动使用的同样结构) 来实现所有内核 需要的操作, 来处理文件上的读和移动. 幸运的是, 这个任务是简单的. 第一步是创建一 个 open 方法连接文件到 seq_file 操作:

static int scull_proc_open(struct inode *inode, struct file *file)

{

return seq_open(file, &scull_seq_ops);

}

调用 seq_open 连接文件结构和我们上面定义的序列操作. 事实证明, open 是我们必须 自己实现的唯一文件操作, 因此我们现在可以建立我们的 file_operations 结构:

static struct file_operations scull_proc_ops = {

.owner = THIS_MODULE,

.open = scull_proc_open,

.read = seq_read,

.llseek = seq_lseek,

.release = seq_release

};

这里我们指定我们自己的 open 方法, 但是使用预装好的方法 seq_read, seq_lseek, 和 seq_release 给其他.

最后的步骤是创建 /proc 中的实际文件:

entry = create_proc_entry("scullseq", 0, NULL); if (entry)

entry->proc_fops = &scull_proc_ops;

不是使用 create_proc_read_entry, 我们调用低层的 create_proc_entry, 我们有这个 原型:

struct proc_dir_entry *create_proc_entry(const char *name,mode_t mode,struct proc_dir_entry *parent);

参数和它们的在 create_proc_read_entry 中的对等体相同: 文件名子, 它的位置, 以及 父目录.

有了上面代码, scull 有一个新的 /proc 入口, 看来很象前面的一个. 但是, 它是高级 的, 因为它不管它的输出有多么大, 它正确处理移动, 并且通常它是易读和易维护的. 我 们建议使用 seq_file , 来实现包含多个非常小数目的输出行数的文件.

转载于:https://www.cnblogs.com/fanweisheng/p/11141537.html

linux 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机制学习

    linux内核驱动模块经常要将一些信息通过/proc文件树暴露给用户,以方便用户直接能从文件系统中读取到驱动程序或者内核的一些状态信息,当这些信息比较短的时候编程比较容易,一旦过长并且用户有lseek ...

  3. 【Linux 内核 内存管理】内存管理架构 ① ( 内存管理架构组成 | 用户空间 | 内核空间 | MMU 硬件 | Linux 内核架构层次 | Linux 系统调用接口 )

    文章目录 一.内存管理架构组成 ( 用户空间 | 内核空间 | MMU 硬件 ) 二.Linux 内核架构层次 三.Linux 系统调用接口 一.内存管理架构组成 ( 用户空间 | 内核空间 | MM ...

  4. Linux定时器接口

    Linux定时器接口主要分为三类: 一. sleep(), unsleep, alarm(),引用了SIGALARM信号,在多线程中使用信号又是相当麻烦的. 二. nanosleep(), clock ...

  5. Android 8.0 系统学习(6)---Linux内核接口要求

    接口要求 本页介绍了 Android 正常运行所需的一系列 Linux 内核接口.供应商测试套件 (VTS) 会测试这些接口是否存在以及是否正确无误.这些接口的数量将随时间的推移不断增加,包含越来越多 ...

  6. 基于Linux IIO接口的波形采集

    我们在<Linux IIO接口的低成本8通道AD>这篇文章中,已经介绍了如何通过程序对IIO设备进行单次读取,接下来我们就介绍波形的实现,关于IIO子系统的详细说明可以参考资料Linux ...

  7. linux上创建loopback接口,在python中的特定接口的linux loopback接口

    我试图发送一些数据到本地地址,然后使用特定的接口ppp0'转发'到外部地址.我认为我的问题与分组路由/套接字绑定问题有关,但我太多了解它的新手.在python中的特定接口的linux loopback ...

  8. linux音频设备接口,linux音频设备驱动读书笔记

    在linux系统中,先后出现了音频设备的两种框架:OSS和ALSA. 针对不同的数字音频子系统,出现了几种微处理器或DSP与音频器件间用于数字转换的接口. 音频设备的硬件接口 (1)PCM接口. (2 ...

  9. linux 雷电接口,Intel完全开放雷电技术:底层融合USB 4

    Intel官方宣布,将面向USB推广组织(USB Promoter Group)开放雷电(Thunderbolt)协议规范,厂商可以免费打造兼容雷电标准的芯片和设备. 同时,USB推广组织首次公布了即 ...

最新文章

  1. mysql索引详细介绍简书_MySql索引详解
  2. 从零开始的AI·决策树原来这么好理解(附实例代码)
  3. php递归复制文件内容,PHP实现递归复制整个文件夹的类实例_php技巧
  4. 5个杰出的商业机器学习用例
  5. 使用vs2010+WCF发布json数据,ExtJS4.0进行调用
  6. PowerDesigner16逆向工程生成PDM列注释(My Sql5.0模版)
  7. 根据文件前四个字节判断文件类型(centos 7)
  8. [转载]Badboy使用教程
  9. Unity Shader 绘制朱利亚集合 Julia 奇幻图形
  10. [小物分享] “Cap-less”——烂笔头3088
  11. [PWN][基础篇]基础理论
  12. 关于网线连内网,无线连外网,内外网同时连通的方法探究
  13. 二阶常系数齐次线性微分方程的解法
  14. FFmpeg入门详解之119:FFmpeg的SDK编程回顾总结并操练
  15. OpenCV+VS2019打开和关闭电脑摄像头
  16. 网络工程设计与实施总结
  17. 快速理解j=j++ 和 j=++j(新手入门)
  18. jpeg 照片 EXIF查看器
  19. 干干!JavaScript学习路线指南,阅读本文即可
  20. knockout简介

热门文章

  1. (收藏)Html相关网址
  2. 玩转小程序转发——小程序探索
  3. NOSQL系列-Redis精简版安装与Ruby测试
  4. 如何将visual studio 2010编辑模式改为插入???
  5. linux ed 命令的用法
  6. 《Maven官方文档》POM文件(一)
  7. MyEclipse+Tomcat web项目改名
  8. Spring 从零開始-05
  9. spring bean的初始化和销毁
  10. Object+C语法快速入门