使用seq_file,实现大文件的/proc file

下面是个用seq_file实现大文件/proc file的例子。 重要的就是那几个迭代的函数。

值得一提的是,我这个例子在cat /proc/seq_test的时候 会显示出很多东西。也就是比我想象的要多。

后来我仔细的看了log,发现输出如下

Nov 21 15:44:14 wizard-desktop kernel: [ 9354.426472] scull: position is 0
Nov 21 15:44:14 wizard-desktop kernel: [ 9354.426479] scull: next: 0
Nov 21 15:44:14 wizard-desktop kernel: [ 9354.426482] scull: next: 50
Nov 21 15:44:14 wizard-desktop kernel: [ 9354.426484] scull: next: 100
Nov 21 15:44:14 wizard-desktop kernel: [ 9354.426486] scull: next: 150
Nov 21 15:44:14 wizard-desktop kernel: [ 9354.426488] scull: next: 200
Nov 21 15:44:14 wizard-desktop kernel: [ 9354.426490] scull: next: 250
Nov 21 15:44:14 wizard-desktop kernel: [ 9354.426492] scull: next: 300
Nov 21 15:44:14 wizard-desktop kernel: [ 9354.426494] scull: next: 350
Nov 21 15:44:14 wizard-desktop kernel: [ 9354.426516] scull: position is 351
Nov 21 15:44:14 wizard-desktop kernel: [ 9354.426518] scull: next: 351
Nov 21 15:44:14 wizard-desktop kernel: [ 9354.426522] scull: position is 352
Nov 21 15:44:14 wizard-desktop kernel: [ 9354.426524] scull: next: 352
Nov 21 15:44:14 wizard-desktop kernel: [ 9354.426527] scull: position is 353
Nov 21 15:44:14 wizard-desktop kernel: [ 9354.426529] scull: next: 353
Nov 21 15:44:14 wizard-desktop kernel: [ 9354.426532] scull: position is 354
Nov 21 15:44:14 wizard-desktop kernel: [ 9354.426534] scull: next: 354
Nov 21 15:44:14 wizard-desktop kernel: [ 9354.426538] scull: position is 355
Nov 21 15:44:14 wizard-desktop kernel: [ 9354.426540] scull: next: 355
Nov 21 15:44:14 wizard-desktop kernel: [ 9354.426543] scull: position is 356
Nov 21 15:44:14 wizard-desktop kernel: [ 9354.426545] scull: next: 356
Nov 21 15:44:14 wizard-desktop kernel: [ 9354.426548] scull: position is 357
Nov 21 15:44:14 wizard-desktop kernel: [ 9354.426550] scull: next: 357
Nov 21 15:44:14 wizard-desktop kernel: [ 9354.426554] scull: position is 358
。。。。

Nov 21 15:44:14 wizard-desktop kernel: [ 9354.426774] scull: next: 399
Nov 21 15:44:14 wizard-desktop kernel: [ 9354.426778] scull: position is 400

 

可以看到前面几行输出是正常的。但是到了350后,就有问题了。每次都又调用了start,next。

然后一直到 经过next后,start得到的是400。

那这么看来,kernel会一直调用这个start,next 直到start 返回NULL。 ok,发现了问题了。

在next遇到350-400之间的pos时,加上offset,就超过了400,导致了next返回NULL,使得最后50字节无法显示。

kernel就不断调用start来往后移动这个pos。

我就交换了 赋值 和 比较的语句,修复了这个bug。

 

/*
 * =====================================================================================
 *
 *       Filename:  seq_file.c
 *
 *    Description:  This is a standalone module to show the usage of
 *                  /proc file by seq methods
 *
 *        Version:  1.0
 *        Created:  11/21/2010 01:12:35 PM
 *       Revision:  none
 *       Compiler:  gcc
 *
 *         Author:  YOUR NAME (),
 *        Company: 
 *
 * =====================================================================================
 */
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>

#include <linux/kernel.h>    /* printk() */
#include <linux/slab.h>        /* kmalloc() */
#include <linux/fs.h>        /* everything... */
#include <linux/errno.h>    /* error codes */
#include <linux/types.h>    /* size_t */
#include <linux/proc_fs.h>
#include <linux/fcntl.h>    /* O_ACCMODE */
#include <linux/seq_file.h>
#include <linux/cdev.h>

#include <asm/system.h>        /* cli(), *_flags */
#include <asm/uaccess.h>    /* copy_*_user */

#include "scull.h"        /* local definitions */

MODULE_AUTHOR("Alessandro Rubini, Jonathan Corbet");
MODULE_LICENSE("Dual BSD/GPL");

char buf[400] = "12345678901234567890";
/*
 * Here are our sequence iteration methods.  Our "position" is
 * simply the device number.
 */
/*
 *  s:     almost always ignored
 *  pos:   integer position indicateing where to start
 *         need not be a byte position
 */
static void *seq_seq_start(struct seq_file *s, loff_t *pos)
{
    PDEBUG("position is %d/n", *pos);
    if (*pos >= 400)
        return NULL;
    return  buf + *pos;
}

/*
 *  v:       is the iterator as returned from previous call to start or next
 *  return:  NULL means nothing left
 */
static void *seq_seq_next(struct seq_file *s, void *v, loff_t *pos)
{
    PDEBUG("next: %d/n", *pos);
    (*pos) = (*pos) + 50;      // 对换赋值和比较,可以修复这个bug
    if (*pos >= 400)
        return NULL;
    return  buf + *pos;
}

static void seq_seq_stop(struct seq_file *s, void *v)
{
    /* Actually, there's nothing to do here */
}

static int seq_seq_show(struct seq_file *s, void *v)
{
    char *p = (char*)v;
    char data[51] = {0};
    int i;
   
    for (i=0; (i<50) && (p<buf+400); i++)
    {
        data[i] = *(p + i);
    }

    seq_printf(s, "show: %p:%s/n", v, data);
    return 0;
}
/*
 * Tie the sequence operators up.
 */
static struct seq_operations seq_seq_ops = {
    .start = seq_seq_start,
    .next  = seq_seq_next,
    .stop  = seq_seq_stop,
    .show  = seq_seq_show
};

/*
 * Now to implement the /proc file we need only make an open
 * method which sets up the sequence operators.
 */
static int seq_proc_open(struct inode *inode, struct file *file)
{
    return seq_open(file, &seq_seq_ops);
}

/*
 * Create a set of file operations for our proc file.
 */
static struct file_operations seq_proc_ops = {
    .owner   = THIS_MODULE,
    .open    = seq_proc_open,
    .read    = seq_read,
    .llseek  = seq_lseek,
    .release = seq_release
};

int seq_init_module(void)
{
    struct proc_dir_entry *entry;
    PDEBUG("seq test/n");
    entry = create_proc_entry("seq_test", 0, NULL);
    if (entry)
        entry->proc_fops = &seq_proc_ops;
    /* create file /proc/proc_test */
    return 0;
}

void seq_cleanup_module(void)
{
    /* remove /proc/seq_test */
    remove_proc_entry("seq_test", NULL);
    return;
}
module_init(seq_init_module);
module_exit(seq_cleanup_module);

你可能感兴趣的:(struct,File,Module,null,iterator,compiler)