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. Spring中的通知(Advice)和顾问(Advisor)

    在Spring中,目前我学习了几种增强的方式,和大家分享一下 之前的话: 1.AOP  (Aspect  Oriented Programming  面向切面编程) 在软件业,AOP为Aspect O ...

  2. 开源日志记录工具log4j

    前言:当我们进行大的项目书写的时候或者我们选择维护程序的时候,想知道几点几时我们录入的数据有bug是那么我们就采用--------------------------->log4j记录日志的信息 ...

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

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

  4. reset

    html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, ...

  5. Lazyr.js – 延迟加载图片(Lazy Loading)

    Lazyr.js 是一个小的.快速的.现代的.相互间无依赖的图片延迟加载库.通过延迟加载图片,让图片出现在(或接近))视窗才加载来提高页面打开速度.这个库通过保持最少选项并最大化速度. 在线演示    ...

  6. JavaScript学习10 JS数据类型、强制类型转换和对象属性

    JavaScript学习10 JS数据类型.强制类型转换和对象属性 JavaScript数据类型 JavaScript中有五种原始数据类型:Undefined.Null.Boolean.Number以 ...

  7. JNI输出log信息

    1.修改Android.mk 如生成的库文件是“.so文件”,则在Android.mk中添加如下内容: LOCAL_LDLIBS:=-L$(SYSROOT)/usr/lib -llog 如生成的库文件 ...

  8. iOS 学习 - 10下载(3) NSURLSession 音乐 篇

    使用 NSURLSession 下载,需要注意的是文件下载文件之后会自动保存到一个临时目录,需要开发人员自己将此文件重新放到其他指定的目录中 // // ViewController.m // Web ...

  9. 编译生成IOS开发使用的FFmpeg的过程

    前言:本篇随笔纯属是参照<iOS 使用 FFmpeg>的过程,本人自己操作了一遍,但是本人记性不好,觉得这样的过程可以记录在博客中,以后需要可以快速回头翻阅细节.所以特地参考<iOS ...

  10. 数据结构--用Objective-C简单实现的数据结构:栈

    前言:最近在学习数据结构,这里用Objective-C简单实现了一下栈.用Objective-C确实好容易,因为我使用了Cocoa框架提供了NSMutableArray作为存储元素的集合,操作集合元素 ...