zoukankan      html  css  js  c++  java
  • 【驱动】——seq_file使用指南

      seq_file只是在普通的文件read中加入了内核缓冲的功能,从而实现顺序多次遍历,读取大数据量的简单接口。seq_file一般只提供只读接口,在使用seq_file操作时,主要靠下述四个操作来完成内核自定义缓冲区的遍历的输出操作,其中pos作为遍历的iterator,在seq_read函数中被多次使用,用以定位当前从内核自定义链表中读取的当前位置,当多次读取时,pos非常重要,且pos总是遵循从0,1,2...end+1遍历的次序,其即必须作为遍历内核自定义链表的下标,也可以作为返回内容的标识。但是我在使用中仅仅将其作为返回内容的标示,并没有将其作为遍历链表的下标,从而导致返回数据量大时造成莫名奇妙的错误,注意:start返回的void*v如果非0,被show输出后,在作为参数传递给next函数,next可以对其修改,也可以忽略;当next或者start返回NULL时,在seq_open中控制路径到达seq_end。

    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方法始终会首先调用;

      next函数应将迭代器移动到下一个位置,并在序列中没有其他项目时返回NULL;

      stop做清除工作;

      在上述调用之间,内核会调用 show 方法来将实际的数据输出到用户空间。需要使用如下一组特殊函数来处理数据:

    int seq_printf(struct seq_file *sfile, const char *fmt, ...);
    int seq_putc(struct seq_file *sfile, char c);
    int seq_puts(struct seq_file *sfile, const char *s);

      值得注意的是,在设计上,seq_file的代码不会在 start 和 stop 的调用之间执行其他的非原子操作。我们可以确信,start调用之后马上就会有对stop的调用。因此在start方法中获取信号量或者自旋锁是安全的。

      定义了完整的操作函数,我们必须将这些函数打包并和 /proc 中的某个文件连接起来。首先要填充一个 seq_operations 结构:

    static struct seq_operations seq_ops = {
        .start = seq_start,
        .next = seq_next,
        .stop = seq_stop,
        .show = seq_show 
    };

      有了这个结构我们可以创建一个open方法,将文件连接到seq_file操作:

    static int proc_open(struct inode *inode, struct file *file){
        return seq_open(file, &scull_seq_ops);
    }

      对seq_open的调用将file结构和我们上面定义的顺序操作连接在一起。open是唯一一个必须由我们自己实现的文件操作,因此我们的file_operations结构可如下定义:

    static struct file_operations proc_ops = {
        .owner = THIS_MODULE,
        .open = proc_open,
        .read = seq_read,
        .llseek = seq_lseek,
        .release = seq_release
    };

      这里,我们指定了我们自己的open方法,但对其他的file_operations成员,我们使用了已经定义好的 seq_read, seq_lseek, seq_release方法。  

      最后,我们建立实际的 /proc 文件;

      entry = create_porc_entyr("sequence", 0, NULL);

      if (entry)

        entry->proc_fops = &scull_proc_ops;

    例一:现在我们使用seq_file获取0-100的数:

     1 #include <linux/init.h>
     2 #include <linux/module.h>
     3 #include <linux/types.h>
     4 #include <linux/fs.h>
     5 #include <linux/cdev.h>
     6 #include <linux/kernel.h>
     7 #include <asm/uaccess.h>
     8 #include <linux/seq_file.h>
     9 #include <linux/proc_fs.h>
    10 
    11 #define MAX_NUM     100
    12 static void *ct_seq_start(struct seq_file *s, loff_t *pos){ 
    13     loff_t *spos = kmalloc(sizeof(loff_t), GFP_KERNEL);
    14 
    15     if (*pos > MAX_NUM)
    16         return NULL;
    17 
    18     if (!*spos){
    19         return NULL;
    20     }   
    21     *spos = *pos;
    22     return spos;
    23 }  
    24 static void *ct_seq_next(struct seq_file *s, void *v, loff_t *pos){
    25     loff_t *spos = (loff_t *)v;
    26 
    27     *pos = ++(*spos);
    28     if (*pos > MAX_NUM){
    29         return NULL;
    30     }
    31     return spos;
    32 }
    33 
    34 static void ct_seq_stop(struct seq_file *s, void *v){
    35     printk("ct_seq_stop!
    ");
    36     kfree(v);
    37 }
    38 
    39 static int ct_seq_show(struct seq_file *s, void *v){
    40     loff_t *spos = (loff_t *)v;
    41     seq_printf(s, "%lld
    ", *spos);
    42     return 0;
    43 }
    44 static const struct seq_operations ct_seq_ops = {
    45     .start = ct_seq_start,
    46     .next  = ct_seq_next,
    47     .stop  = ct_seq_stop,
    48     .show  = ct_seq_show
    49 };
    50 
    51 static int ct_open(struct inode *inode, struct file *file){
    52     printk("ct_open!
    ");
    53     return seq_open(file, &ct_seq_ops);
    54 }
    55 
    56 static const struct file_operations ct_file_ops = {
    57     .owner   = THIS_MODULE,
    58     .open    = ct_open,
    59     .read    = seq_read,
    60     .llseek  = seq_lseek,
    61     .release = seq_release
    62 };
    63 static int ct_init(void){
    64     struct proc_dir_entry *entry;
    65     entry = create_proc_entry("sequence", 0, NULL);
    66     if (entry)
    67         entry->proc_fops = &ct_file_ops;
    68     return 0;
    69 }
    70 static void ct_exit(void){
    71     remove_proc_entry("sequence", NULL);
    72 }
    73 module_init(ct_init);
    74 module_exit(ct_exit);
    75 
    76 MODULE_LICENSE("GPL");

      cat /proc/sequence 遍可以获取0-100的数字;

    例二:使用seq_file获取链表中的数据:

      1 #include <linux/init.h>
      2 #include <linux/module.h>
      3 #include <linux/types.h>
      4 #include <linux/fs.h>
      5 #include <linux/cdev.h>
      6 #include <linux/kernel.h>
      7 #include <asm/uaccess.h>
      8 #include <linux/seq_file.h>
      9 #include <linux/proc_fs.h>
     10 #include <linux/string.h>
     11 
     12 #define MAX_NUM     5
     13 struct node {
     14     char buf[10];
     15     struct node *next;
     16 };
     17 struct node *head = NULL;
     18 static int init_data(void){
     19     int i;
     20     struct node *tmp = NULL;
     21     char ch = 'a';
     22     for (i = 0; i < MAX_NUM; i++){
     23         tmp = (struct node *)kmalloc(sizeof(struct node), GFP_KERNEL);
     24         if (!tmp){
     25             return -ENOMEM;
     26         }
     27         memset(tmp->buf, 0, sizeof(tmp->buf));
     28         memset(tmp->buf, ch + i, sizeof(tmp->buf) - 1);
     29         tmp->next = NULL;
     30         if (!head){
     31             head = tmp;
     32         }
     33         else {
     34             tmp->next = head;
     35             head = tmp;
     36         }
     37     }
     38     return 0;
     39 }
     40 static int free_data(void){
     41     struct node *tmp = NULL;
     42 
     43     while (head){
     44         tmp = head;
     45         head = head->next;
     46         kfree(tmp);
     47     }
     48     return 0;
     49 }
     50 
     51 static void *ct_seq_start(struct seq_file *s, loff_t *pos){
     52     struct node *tmp = head;
     53     int index = *pos + 1;
     54 
     55     printk("seq start!
    ");
     56     if (!*pos){
     57         return head;
     58     }
     59     while (index--){
     60         if (!tmp){
     61             return NULL;
     62         }
     63         tmp = tmp->next;
     64     }
     65 
     66     return tmp;
     67 }
     68 
     69 static void *ct_seq_next(struct seq_file *s, void *v, loff_t *pos){
     70     struct node *tmp = (struct node *)v;
     71 
     72     printk("seq next!
    ");
     73     *pos = *pos + 1;
     74     tmp = tmp->next;
     75     if (!tmp){
     76         return NULL;
     77     }
     78 
     79     return tmp;
     80 }
     81 
     82 static void ct_seq_stop(struct seq_file *s, void *v){
     83     printk("ct_seq_stop!
    ");
     84 }
     85 static int ct_seq_show(struct seq_file *s, void *v){
     86     struct node *tmp = (struct node *)v;
     87     printk("seq show!
    ");
     88     seq_printf(s, "%s
    ", tmp->buf);
     89     return 0;
     90 }
     91 
     92 static const struct seq_operations ct_seq_ops = {
     93     .start = ct_seq_start,
     94     .next  = ct_seq_next,
     95     .stop  = ct_seq_stop,
     96     .show  = ct_seq_show
     97 };
     98 
     99 static int ct_open(struct inode *inode, struct file *file){
    100     printk("ct_open!
    ");
    101     return seq_open(file, &ct_seq_ops);
    102 }
    103 
    104 static const struct file_operations ct_file_ops = {
    105     .owner   = THIS_MODULE,
    106     .open    = ct_open,
    107     .read    = seq_read,
    108     .llseek  = seq_lseek,
    109     .release = seq_release
    110 };
    111 
    112 static int ct_init(void){
    113     struct proc_dir_entry *entry;
    114     init_data();
    115     entry = create_proc_entry("sequence", 0, NULL);
    116     if (entry)
    117         entry->proc_fops = &ct_file_ops;
    118     return 0;
    119 }
    120 static void ct_exit(void){
    121     free_data();
    122     remove_proc_entry("sequence", NULL);
    123 }
    124 module_init(ct_init);
    125 module_exit(ct_exit);
    126 
    127 MODULE_LICENSE("GPL");

      cat /proc/sequence 会把链表中的数据输出,此时我们使用 dmesg 查看内核输出信息;

      现在我们把结构体中的buf数据变成1024,MAX_NUM改为10,然后执行 cat /proc/sequence 然后再 dmesg 看看;

    结果为:

    ct_open!
    seq start!
    seq show!
    seq next!
    seq show!
    seq next!
    seq show!
    seq next!
    seq show!
    ct_seq_stop!
    seq start!
    seq show!
    seq next!
    seq show!
    seq next!
    seq show!
    seq next!
    seq show!
    ct_seq_stop!
    seq start!
    seq show!
    seq next!
    seq show!
    seq next!
    seq show!
    seq next!
    ct_seq_stop!
    seq start!
    ct_seq_stop!

      我们发现中间执行了 stop ,而不是像上面一样执行 start->show->next->show->next->stop。原因就是某次调用 show 的时候发现 seq_file 中的buf满了【buf——4K】。

  • 相关阅读:
    oracle11g静默安装
    pv vg lv
    oracle日志表
    oracle常用sql
    vulnhub~muzzybox
    vulnhub~sunset:dusk1
    vulnhub~MyExpense
    vulnhub~DC-9
    汇编学习一
    贪心算法和动态规划
  • 原文地址:https://www.cnblogs.com/ngnetboy/p/4617369.html
Copyright © 2011-2022 走看看