Seq_file文件系统实例剖析

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:
[email protected]
");
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:[email protected]");
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[[email protected]:~/Desktop/net/seq]# cat /proc/net/test_proc

 

时间: 2024-11-07 01:44:40

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

《PNG文件格式》(三)PNG文件实例剖析

欢迎查看系列博客: <PNG文件格式>(一)PNG文件概述     <PNG文件格式>(二)PNG文件格式分析 <PNG文件格式>(三)PNG文件实例剖析(本篇) 摘自: 中文PNG格式说明:dev.gameres.com PNG文件格式白皮书:www.w3.org LZ77算法的JAVA实现:jazzlib.sourceforge.net LZ77算法的JAVA实现,包括J2ME版本:www.jcraft.com ===========================

FasterDFS分布式文件系统(实例!!!)

FasterDFS概述 ? FastDFS是一个开源的轻量级分布式文件系统,它对文件进行管理,功能包括:文件存储.文件同步.文件访问(文件上传.文件下载)等,解决了大容量存储和负载均衡的问题.特别适合以文件为载体的在线服务,如相册网站.视频网站等等. ? FastDFS为互联网量身定制,充分考虑了冗余备份.负载均衡.线性扩容等机制,并注重高可用.高性能等指标,使用FastDFS很容易搭建一套高性能的文件服务器集群提供文件上传.下载等服务. ? FastDFS服务端有两个角色:跟踪器(tracke

Android实例剖析笔记(三)

摘要:点介绍Activity的生命周期,通过一个简单的实验来摸索状态转换的机制 Activity的生命周期 Activity类中有许多onXXX形式的函数可以重载,比如onCreate,onStart,onStop,onPause,那么它们的调用顺序到底是如何的呢?下面就通过一个实验来进行分析.在做这个实验之前,我们先得知道如何在Android中进行Log输出的.我们要使用的是android.util.log类,这个类相当的简单易用,因为它提供的全是一些静态方法: Log.v(String ta

缓冲池实例剖析

在网上找了一个例子,试着运行之后,画出了他的时序图.以后便于复习 package cache; import java.util.Date; import java.util.HashMap; import java.util.Map; /** * 缓存池 * @author Administrator */ public class CachePool { // 缓存池唯一实例 private static CachePool instance; // 缓存Map private static

Shell编程之批量安装服务脚本实例剖析

今天分享一下昨天写过的一个小脚本运行的整个过程运行结果如下:   剖析如下: #!/bin/bash # Date: 4:42 2018-2-10 # Mail: [email protected]163.com # Founder: <YanKai> # Describe: This is a one - button installation service script # 提示:使用此脚本时,尽量先选择第一项配置Yum源! red_col="\e[1;31m" #定

SHELL网络爬虫实例剖析

前天简单分享了用 shell 写网络爬虫的一些见解,今天特地把代码发出来与51博友分享,还是那句话,爱技术.爱开源.爱linux. 针对脚本的注解和整体构思,我会放到脚本之后为大家详解. #!/bin/bash # # This script is used to grab the data on the specified industry websites # Written by sunsky # Mail : [email protected] # Date : 2014-09-14 3

[译]实例剖析-如何制作一个牛B的融资PPT

一些好公司明明在模式上富有创新性,但却在 pitch 时很保守,而且他们又不缺设计和开发能力.如何设计你的融资演讲稿才会吸引投资人对你投资?投资人 Daniel Eckler给大家贡献了下面这篇技术贴. 记住一个精心设计的融资演讲稿和你的产品一样重要,它有助于提高你演讲效果,让你的表述变得更加清晰.和面试相比,戴领带和系纽扣不会让你得到这份工作,但它可以为你塑造一个良好的形象. 以我为新公司Mylo设计的演讲稿为研究案例,我将向你展示如何设计一个吸引人的融资演讲稿. 快速思考:Don'ts 和

线上多服务管理工具实例剖析

公司线上对nginx.tomcat和jar包的java应用的服务管理脚本之前都是单独分离开的,这样子就造成了运维人员在跳板机上进行服务管理的时非常的不方便.特别是把这些服务管理框架纳入到自动化管理平台时,没有一个统一的服务管理接口去使用. 因此,在空的时候,我就将多个服务的管理脚本融合在了一起,将他做成一个工具,这样子就减少了服务管理的杂乱. 废话不说了,下面就是脚本内容,文章结尾我会简单介绍该脚本的思路. #!/bin/bash # # 本脚本用来对系统上的多服务进行管理操作 # 目前仅支持n

数据库设计三大范式应用实例剖析

引言 数据库的设计范式是数据库设计所需要满足的规范,满足这些规范的数据库是简洁的.结构明晰的,同时,不会发生插入(insert).删除(delete)和更新(update)操作异常.反之则是乱七八糟,不仅给数据库的编程人员制造麻烦,而且面目可憎,可能存储了大量不需要的冗余信息. 设计范式是不是很难懂呢?非也,大学教材上给我们一堆数学公式我们当然看不懂,也记不住.所以我们很多人就根本不按照范式来设计数据库. 实质上,设计范式用很形象.很简洁的话语就能说清楚,道明白.本文将对范式进行通俗地说明,并以