下面是个用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);