我写了一个简单的代码片段来了解/proc
文件系统的用法。当我完成时,一切都很好,除了从这个文件读取导致无限循环。
下面显示了一些代码:
static struct seq_operations proc_seq_ops = {
.start = proc_seq_start,
.next = proc_seq_next,
.stop = proc_seq_stop,
.show = proc_seq_show,
};
int proc_seq_open(struct inode *inode, struct file *filp)
{
return seq_open(filp, &proc_seq_ops);
}
static void *proc_seq_start(struct seq_file *s_file, loff_t *pos)
{
PDEBUG("seq file start\n");
if (list_empty(&store_list_head))
return NULL;
return list_first_entry(&store_list_head, struct store_node, list);
}
static void *proc_seq_next(struct seq_file *s_file, void *v, loff_t *pos)
{
void *tmp = NULL;
PDEBUG("seq file next\n");
tmp = list_next_entry((struct store_node *)v, list);
if (&((struct store_node *)tmp)->list == &store_list_head) {
PDEBUG("seq next return NULL\n");
return NULL;
}
PDEBUG("seq file now is returning %p\n", tmp);
return tmp;
}
static void proc_seq_stop(struct seq_file *s_file, void *v)
{
PDEBUG("seq stop\n");
}
static int proc_seq_show(struct seq_file *s_file, void *v)
{
PDEBUG("%p -> %s\n", v, ((struct store_node *)v)->buf);
seq_printf(s_file, "%p -> %s\n", v, ((struct store_node *)v)->buf);
return 0;
}
将要打印的数据放在列表中。在每次调用seq_next
时,我们都会前往下一个节点。
节点的结构非常简单:
struct store_node {
list_head list;
char *buf;
};
当我使用cat
命令读取此proc文件,然后通过dmesg
检查输出时,我得到了这个:
[ 893.111027] proc-fs-iterator: seq file next
[ 893.111028] proc-fs-iterator: seq next return NULL
[ 893.111028] proc-fs-iterator: seq stop
[ 893.111036] proc-fs-iterator: seq file start
[ 893.111037] proc-fs-iterator: ffff88002f863dc0 -> 1234
[ 893.111038] proc-fs-iterator: seq file next
[ 893.111039] proc-fs-iterator: seq next return NULL
[ 893.111040] proc-fs-iterator: seq stop
[ 893.111062] proc-fs-iterator: seq file start
[ 893.111064] proc-fs-iterator: ffff88002f863dc0 -> 1234
[ 893.111065] proc-fs-iterator: seq file next
[ 893.111066] proc-fs-iterator: seq next return NULL
[ 893.111067] proc-fs-iterator: seq stop
为什么无限打印?实际执行了seq_stop
!
答案 0 :(得分:1)
您忘记更新*pos
处理程序中的_next
参数。通常,每_next
次呼叫增加1。
更新:您的_start
处理程序也应该导航到给定的位置。
无限循环实际上是cat
实现的结果:它调用 read(2)直到它返回0或-1。由于您的实现不更新位置,每个 read(2)调用从开头读取并返回正值(已读取非零字节)。
在内核中使用的BTW,C标准允许void*
和其他指针类型之间的隐式转换。因此,您可以安全地在tmp
处理程序中将_next
变量声明为struct store_node *tmp;
。例如,请参阅seq_list_*
内核源代码中的fs/seq_file.c
个处理程序。