Douglas Su
Douglas Su

Reputation: 3364

Infinite loop when I read from /proc which is implemented with seq_file

I wrote a simple code snippet to learn the usage of /proc file system. When I finished, everything is ok except the reading from this file causes an infinite loop.

Some codes show below:

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;
}

The data which will be printed is put in a list. In each invoking of seq_next, we travel to next node.

The structure of nodes is fairly simple:

struct store_node {
    list_head list;
    char *buf;
};

When I use cat command to read this proc file and then check the output by dmesg, I get this:

[  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

Why it print infinitely? The seq_stop is actually executed!

Upvotes: 1

Views: 1634

Answers (1)

Tsyvarev
Tsyvarev

Reputation: 65870

Your forget to update *pos parameter in your _next handler. Usually, it is incremented by 1 every _next call. UPDATE: Also your _start handler should navigate to given position.

Infinite loop is actually a consequence of cat implementation: it call read(2) until it returns 0 or -1. Because of your implementation do not update position, every read(2) call reads from the beginning and return positive value(non-zero bytes has been read).

BTW, C standard, used in the kernel, allows implicit conversion between void* and other pointer types. So you can safetly declare tmp variable in your _next handler as struct store_node *tmp;. For example, see seq_list_* handlers in fs/seq_file.c kernel source.

Upvotes: 2

Related Questions