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. Android 手机卫士2--home页面

    1,自定义获取焦点的TextView FocusTextView.java package com.itheima.mobilesafe74.view; import android.content. ...

  2. linux TCP: time wait bucket table overflow

    早上一台rabbitmq和Java所在的服务器,客户端反馈超级卡,看io和cpu都不高.发现六七万消息挤压,临时性问题解决之后,看/var/log/messages,发现很多TCP: time wai ...

  3. 一:【nopcommerce系列】Nop整体架构的简单介绍,在看nop代码之前,你需要懂哪些东西

    首先,我看的是Nop 3.80,最新版 百度资料很多,Nop用到的主要的技术有: 1.Mvc,最新版用的是 5.2.3.0 2.entity framework 3.autofac 4.插件化 5.( ...

  4. SQL Server数据类型转换

    在SQL Server日常的函数.存储过程和SQL语句中,经常会用到不同数据类型的转换.在SQL Server有两种数据转换类型:一种是显性数据转换:另一种是隐性数据转换.下面分别对这两种数据类型转换 ...

  5. JavaScript for循环 闭包 【转】

    个网友问了个问题,如下的html,为什么每次输出都是5,而不是点击每个p,就alert出对应的1,2,3,4,5. <html > <head> <meta http-e ...

  6. Kickoff - 创造可扩展的,响应式的网站

    Kickoff 是一个轻量级的前端框架,用于创建可扩展的,响应式的网站.作为前端开发人员,我们工作的类型越来越多样化.Kickoff 旨在帮助您在所有项目保持一致的结构和风格,无需添加其他框架. 在线 ...

  7. JavaScript学习笔记3之 数组 & arguments(参数对象)& 数字和字符串转换 & innerText/innerHTML & 鼠标事件

    一.Array数组 1.数组初始化(Array属于对象类型) /*关于数组的初始化*/ //1.创建 Array 对象--方法1: var arr1=[]; arr1[0]='aa';//给数组元素赋 ...

  8. 马旭飞:共探H3 BPM社区发展战略

    近日,以"让天下没有难用的流程"为主题,H3 BPM10.0在北京金隅喜来登酒店正式发布. H3 BPM全新的业务流程管理系统是颠覆BPM行业的巨作,拥有众多独创技术,近200个业 ...

  9. Android上传图片到PHP服务器并且支持浏览器上传文件(word、图片、音乐等)

    暑假已经过了一半了,这才完成计划当中的第二个任务.虽然进度是慢了点.但也算是暑假的收获吧.下面我就把我学习当中的收获记录在此. 还是跟以往一样,先上图片. 操作的步骤:打开程序---->选择上传 ...

  10. Android 内容提供者的实现

    接着上文<Android 内容提供者简介>进一步实现内容提供者. 每个Content Provider类都使用URI(Universal Resource Identifier,通用资源标 ...