static int exam_seq_open(struct inode *inode, struct file *file)
{
return seq_open(file, &exam_seq_ops);
};
struct proc_dir_entry *entry;
entry = create_proc_entry("exam_seq_file", 0, NULL);
if (entry)
entry->proc_fops = &exam_seq_file_ops;
|
当用户态的程序打开这个对应的proc目录时,open->sysopen->exm_seq_open->seq_open(file,&exam_seq_ops),下面我们主要来看下seq_open函数
int seq_open(struct file *file, const struct seq_operations *op)
{
struct seq_file *p = file->private_data;
if (!p) {
p = kmalloc(sizeof(*p), GFP_KERNEL);
if (!p)
return -ENOMEM;
file->private_data = p;
}
memset(p, 0, sizeof(*p));
mutex_init(&p->lock);
p->op = op;
/*
* Wrappers around seq_open(e.g. swaps_open) need to be
* aware of this. If they set f_version themselves, they
* should call seq_open first and then set f_version.
*/
file->f_version = 0;
/* SEQ files support lseek, but not pread/pwrite */
file->f_mode &= ~(FMODE_PREAD | FMODE_PWRITE);
return 0;
}
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_read函数
/**
* seq_read - ->read() method for sequential files.
* @file: the file to read from
* @buf: the buffer to read to
* @size: the maximum number of bytes to read
* @ppos: the current position in the file
*
* Ready-made ->f_op->read()
*/
ssize_t seq_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
{
struct seq_file *m = (struct seq_file *)file->private_data;
/* grab buffer if we didn't have one */
if (!m->buf) {
m->buf = kmalloc(m->size = PAGE_SIZE, GFP_KERNEL);
if (!m->buf)
goto Enomem;
}
p = m->op->start(m, &pos);
while (1) {
err = m->op->show(m, p);
p = m->op->next(m, p, &pos);
m->op->stop(m, p);
}
} //可见seq_read函数分别调用了自定义的seq_operation结构中的回调函数start,show,next,stop等函数。
这样就将vfs层的sys_read->seq_read(调用我们自己定义的seq_operation的start,show,next,stop等函数),从而可以根据我们自己选择的方式去显示我们的数据。