最近在看/proc/cpuinfo的内核实现时,发现了一个以前没注意的东东: seq_file接口

seq_file(Sequence file:序列文件)接口
内核文档: Documentation/filesystems/seq_file.txt

There are numerous ways for a device driver (or other kernel component) to
provide information to the user or system administrator. One useful
technique is the creation of virtual files, in debugfs, /proc or elsewhere.
Virtual files can provide human-readable output that is easy to get at
without any special utility programs; they can also make life easier for
script writers. It is not surprising that the use of virtual files has
grown over the years.

Creating those files correctly has always been a bit of a challenge,
however. It is not that hard to make a virtual file which returns a
string. But life gets trickier if the output is long - anything greater
than an application is likely to read in a single operation. Handling
multiple reads (and seeks) requires careful attention to the reader’s
position within the virtual file - that position is, likely as not, in the
middle of a line of output. The kernel has traditionally had a number of
implementations that got this wrong.



#include <linux/init.h>  
#include <linux/kernel.h>  
#include <linux/module.h>  

#include <linux/fs.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>

#define VERSION "0.1"
#define MODULE_NAME ""

//#define USE_SEQ_OPEN
#define TEST_NODE_NAME "seq_test"

static int c_show(struct seq_file *m, void *v)
	seq_puts(m, "test start...\n");
	seq_printf(m, "test: %d\n", 0);
	seq_puts(m, "\n");
	return 0;
static void *c_start(struct seq_file *m, loff_t *pos)
	return *pos < 1 ? (void *)1 : NULL;

static void *c_next(struct seq_file *m, void *v, loff_t *pos)
	return NULL;

static void c_stop(struct seq_file *m, void *v)

const struct seq_operations seq_ops = {
	.start	= c_start,
	.next	= c_next,
	.stop	= c_stop,
	.show	= c_show

static int test_open(struct inode *inode, struct file *file)
	printk("test_open:  seq_open()\n");
	return seq_open(file, &seq_ops);

static int test_open(struct inode *inode, struct file *file)
	printk("test_open:  single_open()\n");
	return single_open(file, c_show, inode->i_private);

static ssize_t test_write(struct file *file, const char __user *buffer,
                size_t count, loff_t *pos)
	printk("test_write: count=%d\n",count);
	return count;

static const struct file_operations proc_seq_test_ops = {
	.open	= test_open,
	.read	= seq_read,
    .write = test_write,
	.llseek	= seq_lseek,
	.release = seq_release, 
	.release = single_release, 

static int __init seq_test_init(void)   
	printk("init module...  \n");
	proc_create(TEST_NODE_NAME, 0, NULL, &proc_seq_test_ops);

	return 0;  

static void __exit seq_test_exit(void)   
	printk("exit modules... \n");  
	remove_proc_entry(TEST_NODE_NAME, NULL); 

module_init(seq_test_init);   /*声明初始化函数*/
module_exit(seq_test_exit);    /*声明卸载函数*/

MODULE_AUTHOR("zdd <>");           /*模块作者,可选*/
MODULE_LICENSE("GPL");     /*模块许可,描述内核模块的许可权限,必须*/