持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第6天,点击查看活动详情
proc和sys目录为linux系统中虚拟文件系统,
sys为系统设备,驱动,总线的信息。
proc为系统将进程等信息显示到用户空间。
这两个虚拟文件系统具体不做介绍,请自行取linux下查看。
3.1 内核 seq_file 机制
普通的文件没有一定的组织结构,文件可以从任意位置开始读写。有一种文件与普通文件不同,它包含一系列的记录,而这些记录按照相同的格式来组织,这种文件称为顺序文件,sqe_file是专门用来处理顺序文件的接口。
//seq_file提供常用接口:
int seq_open(struct file *, const struct seq_operations *);
ssize_t seq_read(struct file *, char __user *, size_t, loff_t *);
loff_t seq_lseek(struct file *, loff_t, int);
int seq_release(struct inode *, struct file *);
int seq_write(struct seq_file *seq, const void *data, size_t len);
//示例:一般情况下,只需自己实现.open对应的函数,其他用标准函数seq_read,seq_lseek等。
//具体看 single_open()函数介绍。
static const struct file_operations md_seq_fops = {
.owner = THIS_MODULE,
.open = md_seq_open,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release,
.poll = mdstat_poll,
};
以上函数可以直接赋值给file_operations文件操作结构的成员。seq_file结构通常保存在file结构的private_data中。
seq_open(): 参数sqe_operations结构是seq_file机制中需要实现的操作函数,需要用户自己去实现。
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);
};
//示例:
static const struct seq_operations md_seq_ops = {
.start = md_seq_start,
.next = md_seq_next,
.stop = md_seq_stop,
.show = md_seq_show,
};
3.2 single_open
为了更进一步简化内核接口的实现,封装了该函数,这样我们不用实现整个 seq_operations 结构体,驱动开发者只需要传入 show 即可,其他回调都使用内核实现的一个简单版本,它的代码如下所示:
int single_open(struct file *file, int (*show)(struct seq_file *, void *),
void *data)
{
struct seq_operations *op = kmalloc(sizeof(*op), GFP_KERNEL_ACCOUNT);
int res = -ENOMEM;
if (op) {
op->start = single_start;
op->next = single_next;
op->stop = single_stop;
op->show = show;
res = seq_open(file, op);
if (!res)
((struct seq_file *)file->private_data)->private = data;
else
kfree(op);
}
return res;
}
//......省略
//以下为只实现show()函数的版本。
static int seq_file_demo_show(struct seq_file *seq, void *v)
{
seq_printf(seq, "Hello World\n");
return 0;
}
//file_operations 结构体的open回调。
static int seq_file_demo_open(struct inode *inode, struct file *file)
{
return single_open(file, &seq_file_demo_show, NULL);
}