当我从使用 seq_file 实现的 /proc 读取时无限循环
Infinite loop when I read from /proc which is implemented with seq_file
我写了一个简单的代码片段来学习 /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
实际执行!
您忘记更新 _next
处理程序中的 *pos
参数。通常,它在每 _next
次调用时递增 1。
更新:您的 _start
处理程序也应导航到给定位置。
无限循环实际上是 cat
实现的结果:它调用 read(2) 直到它 returns 0 或 -1。由于您的实现不更新位置,每个 read(2) 调用从头开始读取 return 正值(已读取非零字节)。
BTW,内核中使用的C标准,允许void*
和其他指针类型之间的隐式转换。因此,您可以在 _next
处理程序中安全地将 tmp
变量声明为 struct store_node *tmp;
。例如,请参阅 fs/seq_file.c
内核源代码中的 seq_list_*
处理程序。
我写了一个简单的代码片段来学习 /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
实际执行!
您忘记更新 _next
处理程序中的 *pos
参数。通常,它在每 _next
次调用时递增 1。
更新:您的 _start
处理程序也应导航到给定位置。
无限循环实际上是 cat
实现的结果:它调用 read(2) 直到它 returns 0 或 -1。由于您的实现不更新位置,每个 read(2) 调用从头开始读取 return 正值(已读取非零字节)。
BTW,内核中使用的C标准,允许void*
和其他指针类型之间的隐式转换。因此,您可以在 _next
处理程序中安全地将 tmp
变量声明为 struct store_node *tmp;
。例如,请参阅 fs/seq_file.c
内核源代码中的 seq_list_*
处理程序。