http://blog.chinaunix.net/uid-24432676-id-2607766.html

http://www.cnblogs.com/qq78292959/archive/2012/06/13/2547335.html

Seq_file文件系统实例剖析的两篇文章 2011-05-07 21:51:29

分类: LINUX

文章一:
Seq_file File System
针对proc文件的不足而诞生了Seq_file。
Seq_file的实现基于proc文件。使用Seq_file,用户必须抽象出一个链接对象,然后可以依次遍历这个链接对象。这个链接对象可以是链表,数组,哈希表等等。
编程接口
Seq_file必须实现四个操作函数:start(), next(), show(), stop()。
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():
主要实现初始化工作,在遍历一个链接对象开始时,调用。返回一个链接对象的偏移或者SEQ_START_TOKEN(表征这是所有循环的开始)。出错返回ERR_PTR。
stop():
当所有链接对象遍历结束时调用。主要完成一些清理工作。
next():
用来在遍历中寻找下一个链接对象。返回下一个链接对象或者NULL(遍历结束)。
show():
对遍历对象进行操作的函数。主要是调用seq_printf(), seq_puts()之类的函数,打印出这个对象节点的信息。
下图描述了seq_file函数对一个链表的遍历。
2、重要的数据结构
除了struct seq_operations以外,另一个最重要的数据结构是struct seq_file:
struct seq_file {
        char *buf;
        size_t size;
        size_t from;
        size_t count;
        loff_t index;
        u64 version;
        struct mutex lock;
        const struct seq_operations *op;
        void *private;
};
该结构会在seq_open函数调用中分配,然后作为参数传递给每个seq_file的操作函数。Privat变量可以用来在各个操作函数之间传递参数。
3、Seq_file使用示例:
#include /* for use of init_net*/
#include /* We're doing kernel work */
#include /* Specifically, a module */
#include /* Necessary because we use proc fs */
#include /* for seq_file */
#define PROC_NAME "my_seq_proc"
MODULE_AUTHOR("Dreamice:
dreamice.jiang@mail.com
");
MODULE_LICENSE("GPL");
static void *my_seq_start(struct seq_file *s, loff_t *pos)
{
        static unsigned long counter = 0;
        printk(KERN_INFO"Invoke start\n");
        /* beginning a new sequence ? */
        if ( *pos == 0 )
        {
                /* yes => return a non null value to begin the sequence */
                printk(KERN_INFO"pos == 0\n");
                return &counter;
        }
        else
        {
                /* no => it's the end of the sequence, return end to stop reading */
                *pos = 0;
                printk(KERN_INFO"pos != 0\n");
                return NULL;
        }
}
static void *my_seq_next(struct seq_file *s, void *v, loff_t *pos)
{
        unsigned long *tmp_v = (unsigned long *)v;
        printk(KERN_INFO"Invoke next\n");
        (*tmp_v)++;
        (*pos)++;
        return NULL;
}
static void my_seq_stop(struct seq_file *s, void *v)
{
        printk(KERN_INFO"Invoke stop\n");
        /* nothing to do, we use a static value in start() */
}
static int my_seq_show(struct seq_file *s, void *v)
{
        printk(KERN_INFO"Invoke show\n");
        loff_t *spos = (loff_t *) v;
        seq_printf(s, "%Ld\n", *spos);
        return 0;
}
static struct seq_operations my_seq_ops = {
        .start = my_seq_start,
        .next = my_seq_next,
        .stop = my_seq_stop,
        .show = my_seq_show
};
static int my_open(struct inode *inode, struct file *file)
{
        return seq_open(file, &my_seq_ops);
};
static struct file_operations my_file_ops = {
        .owner = THIS_MODULE,
        .open = my_open,
        .read = seq_read,
        .llseek = seq_lseek,
        .release = seq_release
};
int init_module(void)
{
        struct proc_dir_entry *entry;
        entry = create_proc_entry(PROC_NAME, 0, init_net.proc_net);
        if (entry) {
                entry->proc_fops = &my_file_ops;
        }
        printk(KERN_INFO"Initialze my_seq_proc success!\n");
        return 0;
}
/**
* This function is called when the module is unloaded.
*
*/
void cleanup_module(void)
{
        remove_proc_entry(PROC_NAME, init_net.proc_net);
        printk(KERN_INFO"Remove my_seq_proc success!\n");
}
该程序在/proc/net下注册一个my_seq_proc文件。有兴趣的朋友可以测试一下。
总结待续
[ 本帖最后由 dreamice 于 2008-11-13 21:03 编辑 ]

seq.jpg
(10.69 KB) 2008-11-13 18:04
  执行流程图

文章二

内容简介:


文主要讲述序列文件(seq_file)接口的内核实现,如何使用它将Linux内核里面常用的数据结构通过文件(主要关注proc文件)导出到用户空
间,最后定义了一些宏以便于编程,减少重复代码。在分析序列文件接口实现的过程中,还连带涉及到一些应用陷阱和避免手段。
序列文件接口:

UNIX
的世界里,文件是最普通的概念,所以用文件来作为内核和用户空间传递数据的接口也是再普通不过的事情,并且这样的接口对于shell也是相当友好的,方便
管理员通过shell直接管理系统。由于伪文件系统proc文件系统在处理大数据结构(大于一页的数据)方面有比较大的局限性,使得在那种情况下进行编程
特别别扭,很容易导致bug,所以序列文件接口被发明出来,它提供了更加友好的接口,以方便程序员。之所以选择序列文件接口这个名字,应该是因为它主要用
来导出一条条的记录数据。

为了能给大家一个具体形象的认识,我们首先来看一段用序列文件接口通过proc文件导出内核双向循环链接表的实例代码:

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>

static struct mutex lock;
static struct list_head head;
struct my_data {
        struct list_head list;
        int value;
};

static void add_one(void)
{
        struct my_data *data;

mutex_lock(&lock);
        data = kmalloc(sizeof(*data), GFP_KERNEL);
        if (data != NULL)
                list_add(&data->list, &head);
        mutex_unlock(&lock);
}

static ssize_t _seq_write(struct file *file, const char __user * buffer,
                       size_t count, loff_t *ppos)
{
        add_one();
        return count;
}

static int _seq_show(struct seq_file *m, void *p)
{
        struct my_data *data = list_entry(p, struct my_data, list);

seq_printf(m, "value: %d\n", data->value);
        return 0;
}

static void *_seq_start(struct seq_file *m, loff_t *pos)
{
        mutex_lock(&lock);
        return seq_list_start(&head, *pos 204);">);
}

static void *_seq_next(struct seq_file *m, void *p, loff_t *pos)
{
        return seq_list_next(p, &head, pos);
}

static void _seq_stop(struct seq_file *m, void *p)
{
        mutex_unlock(&lock);
}

static struct seq_operations _seq_ops = {
        .start = _seq_start,
        .next = _seq_next,
        .stop = _seq_stop,
        .show = _seq_show
};

static int _seq_open(struct inode *inode, struct file *file)
{
        return seq_open(file, &_seq_ops);
}

static struct file_operations _seq_fops = {
        .open = _seq_open,
        .read = seq_read,
        .write = _seq_write,
        .llseek = seq_lseek,
        .release = seq_release
};

static void clean_all(struct list_head *head)
{
        struct my_data *data;

while (!list_empty(head)) {
                data = list_entry(head->next, struct my_data, list);
                list_del(&data->list);
                kfree(data);
        }
}

static int __init init(void)
{
        struct proc_dir_entry *entry;

mutex_init(&lock);
        INIT_LIST_HEAD(&head);

add_one();
        add_one();
        add_one();

entry = create_proc_entry("my_data",S_IWUSR | S_IRUGO, NULL);
        if (entry == NULL) {
                clean_all(&head);
                return -ENOMEM;
        }
        entry->proc_fops = &_seq_fops;

return 0;
}

static void __exit fini(void)
{
        remove_proc_entry("my_data", NULL);
        clean_all(&head);
}

module_init(init);
module_exit(fini);

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

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():
主要实现初始化工作,在遍历一个链接对象开始时,调用。返回一个链接对象的偏移或者SEQ_START_TOKEN(表征这是所有循环的开始)。出错返回ERR_PTR。
stop():
当所有链接对象遍历结束时调用。主要完成一些清理工作。
next():
用来在遍历中寻找下一个链接对象。返回下一个链接对象或者NULL(遍历结束)。
show():
对遍历对象进行操作的函数。主要是调用seq_printf(), seq_puts()之类的函数,打印出这个对象节点的信息。
下图描述了seq_file函数对一个链表的遍历。

2、重要的数据结构
除了struct seq_operations以外,另一个最重要的数据结构是struct seq_file:
struct seq_file {
        char *buf;
        size_t size;
        size_t from;
        size_t count;
         loff_t index;
         u64 version;
        struct mutex lock;
        const struct seq_operations *op;
        void *private;
};
该结构会在seq_open函数调用中分配,然后作为参数传递给每个seq_file的操作函数。Privat变量可以用来在各个操作函数之间传递参数。

seq_hello.c
#include <net/net_namespace.h> 
#include <linux/kernel.h> 
#include <linux/module.h> 
#include <linux/proc_fs.h> 
#include <linux/seq_file.h>

#define PROC_NAME "test_proc"
#define MAX_LINES 10

typedef struct item
{
    unsigned long key;
    unsigned char value;
}user_item;

user_item items[4];

MODULE_AUTHOR("ZHANG JIE:iptabler@mail.com");
MODULE_LICENSE("GPL");

static void *my_seq_start(struct seq_file *s, loff_t *pos)
{
        static unsigned long counter = 0;
         printk(KERN_INFO"Invoke start\n");

if ( *pos == 0 )        {                /* yes => return a non null value to begin the sequence */                return &counter;        }        else        {                /* no => it's the end of the sequence, return end to stop reading */                *pos = 0;                return NULL;        }}static void *my_seq_next(struct seq_file *s, void *v, loff_t *pos){    unsigned long *tmp_v = (unsigned long *)v;     if (*pos < MAX_LINES) {        (*tmp_v)++;        (*pos)++;         return tmp_v;        }     else     {        *pos = 0;        return NULL;    }}static void my_seq_stop(struct seq_file *s, void *v){     printk("Invoke stop\n");}static int my_seq_show(struct seq_file *s, void *v){       int i;         loff_t *spos = (loff_t *) v;    for (i = 0; i < 4; i++)    {     items[i].key = *spos;    }       items[0].value = '0';       items[1].value = '1';       items[2].value = '2';       items[3].value = '3';       seq_printf(s, "%ld=%c,%ld=%c,%ld=%c,%ld=%c;\n", items[0].key,         items[0].value, items[1].key, items[1].value, items[2].key,         items[2].value, items[3].key, items[3].value);        return 0;}static struct seq_operations my_seq_ops = {        .start = my_seq_start,        .next = my_seq_next,        .stop = my_seq_stop,        .show = my_seq_show};static int my_open(struct inode *inode, struct file *file){        return seq_open(file, &my_seq_ops);};static struct file_operations my_file_ops = {        .owner = THIS_MODULE,        .open = my_open,        .read = seq_read,        .llseek = seq_lseek,        .release = seq_release};int init_module(void){        struct proc_dir_entry *entry;         entry = create_proc_entry(PROC_NAME, 0, init_net.proc_net);        if (entry) {                 entry->proc_fops = &my_file_ops;        }         printk(KERN_INFO"Initialze /proc/net/test_proc success!\n");        return 0;}void cleanup_module(void){         remove_proc_entry(PROC_NAME, init_net.proc_net);         printk(KERN_INFO"Remove /proc/net/test_proc success!\n");}Makefileobj-m := seq_hello.oKDIR := /lib/modules/$(shell uname -r)/buildPWD := $(shell pwd)default:     $(MAKE) -C $(KDIR) M=$(PWD) modulesclean:     $(RM) *.o *.mod.c *.ko *.symvers *.markers *.order[root@zj:~/Desktop/net/seq]# cat /proc/net/test_proc

 

Seq_file文件系统实例剖析的更多相关文章

  1. Android实例剖析笔记(四)

    摘要:分析NoteEditor这个类和以及Content Provider机制 NoteEditor深入分析 首先来弄清楚“日志编辑“的状态转换,通过上篇文章的方法来做下面这样一个实验,首先进入“日志 ...

  2. 基于栈的指令集与基于寄存器的指令集详细比对及JVM执行栈指令集实例剖析

    基于栈的指令集与基于寄存器的指令集详细比对: 这次来学习一些新的概念:关于Java字节码的解释执行的一种方式,当然啦是一些纯理论的东东,但很重要,在之后会有详细的实验来对理论进行巩固滴,下面来了解一下 ...

  3. Android实例剖析笔记(一)

    摘要:用实例讲解Andriod的开发过程 开卷语 俗话说,“熟读唐诗三百首,不会作诗也会吟”.最近收集了很多Android的示例代码,从这些代码的阅读和实验中学习到很多知识,从而产生写这个系列的打算, ...

  4. python直接赋值、深浅拷贝实例剖析

    根据数据类型分为两部分进行剖析: int.str类型      list.tuple.dict类型等 1.  int.str类型 [int类型实例] >>> import copy ...

  5. JavaScript实战实例剖析——(激励倒计时日历)

    如今JavaScript在前端开发中的地位越来越高,掌握JavaScript的深度往往能决定你职业道路深远,这次通过制作 带着倒计时功能的激励日历的小实例,进一步细致的掌握JavaScript的语法与 ...

  6. Android实例剖析笔记(二)

    摘要:用实例讲解Andriod的开发过程,以NotesList为实例介绍Android的菜单机制 简介 android提供了三种菜单类型,分别为options menu,context menu,su ...

  7. Android实例剖析笔记(三)

    摘要:点介绍Activity的生命周期,通过一个简单的实验来摸索状态转换的机制 Activity的生命周期 Activity类中有许多onXXX形式的函数可以重载,比如onCreate,onStart ...

  8. Java构造方法与析构方法实例剖析

    Java构造方法 类有一个特殊的成员方法叫作构造方法,它的作用是创建对象并初始化成员变量.在创建对象时,会自动调用类的构造方法. 构造方法定义规则:Java 中的构造方法必须与该类具有相同的名字,并且 ...

  9. flv格式详解+实例剖析

    简介 FLV(Flash Video)是现在非常流行的流媒体格式,由于其视频文件体积轻巧.封装播放简单等特点,使其很适合在网络上进行应用,目前主流的视频网站无一例外地使用了FLV格式.另外由于当前浏览 ...

随机推荐

  1. Git基本使用教程

    1.创建版本库      版本库又可以称为仓库(repository),可以简单理解为一个目录,在这个目录下的所有文件都可以被git管理起来,每个文件的新增.修改.删除Git都可以跟踪,以便在任何时刻 ...

  2. 商业银行在CNAPS体系中对各种交易的处理

    简单来讲,商业银行在CNAPS体系中, 一)行内的交易 由各个银行的行内业务系统来自行解决信息流和资金流问题: 二)跨行的交易分渠道处理 柜台和网银等渠道,商业银行直接直连央行的大小额以及超级网银来解 ...

  3. iOS安全笔记

    这一篇文章, 加上里面链接的几篇文章(一个百度的, 两个阮一峰的), 全看完应该了解得差不多了 如何打造一个安全的App?这是每一个移动开发者必须面对的问题.在移动App开发领域,开发工程师对于安全方 ...

  4. Harp – 内置常用预处理器的静态 Web 服务器

    Harp 是一个基于 Node.js 平台的静态 Web 服务器,内置流行的预处理器,支持把 Jade, Markdown, EJS, Less, Stylus, Sass, and CoffeeSc ...

  5. ZedGraph饼图---傻瓜版

    GraphPane pGraphPane=this.zedGraphControl1.GraphPane;//调用饼图类 pGraphPane.Title.Text = "重金属含量分析图& ...

  6. 国内第一篇详细讲解hadoop2的automatic HA+Federation+Yarn配置的教程

    前言 hadoop是分布式系统,运行在linux之上,配置起来相对复杂.对于hadoop1,很多同学就因为不能搭建正确的运行环境,导致学习兴趣锐减.不过,我有免费的学习视频下载,请点击这里. hado ...

  7. Android NDK环境搭建及调用JNI的简单步骤

    转载请注明:http://www.cnblogs.com/tiantianbyconan/p/3396595.html Java Native Interface (JNI)标准是java平台的一部分 ...

  8. Servlet基础(二) Servlet的生命周期

    Servlet基础(二) Servlet的生命周期 Servlet的生命周期可以分为三个阶段: 1.初始化阶段 2.响应客户请求阶段 3.终止阶段 Servlet的初始化阶段 在下列时刻Servlet ...

  9. 有效解决 iOS The document “(null)” requires Xcode 8.0 or later.

    下载了一个 xocde8beta版本   运行之后   结果 在xcode7.3上再运行 就报这句错误   以下链接 是非常有效的解决办法 不信你试试 [链接]Thisversiondoesnotsu ...

  10. iOS中的小知识点

    1.tableView隐藏滚动条 self.tableView.showsVerticalScrollIndicator = NO; 2.关于属性     使用assign: 对基础数据类型 (NSI ...