Skip to contentSkip to conversation

read_proc issue

DISCUSSION Laurent 8 participants 13 messages Feb 26, 2002 – Mar 1, 2002

lore
Share & tools
lore

Laurent

author
#0 lore raw

Hi everyone, hope I don't disturb too much.

I'm developping a module which uses an entry in /proc (read-only) Currently my (*read_proc) function just write a integer in my /proc entry and increments it. Here is the code:

static int number_read_procmem(char *buf, char **start, off_t offset, int count, int *eof, void *data)

{
        int len = 0;

        len = sprintf(buf, "%d\n", number_current++);
        *eof = 1;
        return len;
}

the function is registered in init_module with this:
create_proc_read_entry("number", 0, NULL, number_read_procmem, NULL);

Problem is:
when I 'cat /proc/number' multiple times, instead of getting 0
1
2
3
...

I get
0
2
4
6
...

I've searched the Net for an answer to this but in vain. I'm not sure I should post this to this list (and I'm very sorry if I indeed shouldn't have) but this list is my last hope :(

Please can you CC: me the answers to this post as I'm not on the list. Then again, sorry if I'm intruding and thanks for any help.

Regards,
Laurent Sinitambirivoutin
[email protected]

#1 lore raw

On Tue, 26 Feb 2002, Laurent wrote:

| I'm developping a module which uses an entry in /proc (read-only)
| Currently my (*read_proc) function just write a integer in my /proc entry
| and increments it. Here is the code:
|
| static int number_read_procmem(char *buf, char **start, off_t offset, int
| count, int *eof, void *data)
| {
|         int len = 0;
|
|         len = sprintf(buf, "%d\n", number_current++);
|         *eof = 1;
|         return len;
| }
|
| the function is registered in init_module with this:
| create_proc_read_entry("number", 0, NULL, number_read_procmem, NULL);
|
| Problem is:
| when I 'cat /proc/number' multiple times, instead of getting
| 0
| 1
| 2
| 3
| ...
|
| I get
| 0
| 2
| 4
| 6
| ...

I was thinking that some part(s) of the proc-fs code might call fs/proc/generic.c::proc_file_read() multiple times (internally), but no, it's just the application (or libc) doing it AFAICT.

app. calls read() [Key data: with offset=0], which calls sys_read(), which calls proc_file_read(), which returns N bytes, and then proc_file_read() and sys_read() and read() return to the app.

When the app. gets N bytes of actual data on its read(), it doesn't know whether it was at EOF or not, so it tries another read() [with offset=N], and sys_read() calls proc_file_read() again, both of which return 0, so the app. knows that there is no more data.

Signature · 1 line
~Randy
#2 lore raw
In reply to Laurent
Quoted 1 line · Randy.Dunlap

On Tue, 26 Feb 2002, Laurent wrote:

<snippety snippety>

Quoted 6 lines
| Problem is:
| when I 'cat /proc/number' multiple times, instead of getting
| 0
| 1
| 2
| 3
Quoted 8 lines
| ...
|
| I get
| 0
| 2
| 4
| 6
| ...

<more snippage>

Quoted 9 lines

app. calls read() [Key data: with offset=0], which calls sys_read(), which calls proc_file_read(), which returns N bytes, and then proc_file_read() and sys_read() and read() return to the app.

When the app. gets N bytes of actual data on its read(), it doesn't know whether it was at EOF or not, so it tries another read() [with offset=N], and sys_read() calls proc_file_read() again, both of which return 0, so the app. knows that there is no more data.

I've encountered this problem before, too. What is the "One True Way" to do this cleanly? In other words, if you want to do a calculation once every time someone runs "cat /proc/foo", what is the cleanest way to do that? The solution we came up with was to check the file offset and only do the calculation if offset == 0, which seems pretty hackish.

-VAL

#3 lore raw
Quoted 6 lines

I've encountered this problem before, too. What is the "One True Way" to do this cleanly? In other words, if you want to do a calculation once every time someone runs "cat /proc/foo", what is the cleanest way to do that? The solution we came up with was to check the file offset and only do the calculation if offset == 0, which seems pretty hackish.

Another approach is to do the calculation open and remember it in per fd private data. You can recover that and free it on release. It could even be a buffer holding the actual "content"

#4 lore raw
In reply to Val Henson

That's a good solution in the general case but doesn't work for some of the proc entries that already exist. cpuinfo, for example. There seem to be a number of niche /proc methods already. A cache-on-open method would be very useful for files like cpuinfo and a number of other files for PPC.

It sure would make accessing /proc files less whacky for user-code.

} Another approach is to do the calculation open and remember it in per } fd private data. You can recover that and free it on release. It could } even be a buffer holding the actual "content"

author
#12 lore raw
In reply to Laurent
Quoted 6 lines

I've encountered this problem before, too. What is the "One True Way" to do this cleanly? In other words, if you want to do a calculation once every time someone runs "cat /proc/foo", what is the cleanest way to do that? The solution we came up with was to check the file offset and only do the calculation if offset == 0, which seems pretty hackish.

I've tried it and... it works ! :)
Many many thanks :)

In the meantime, I've also followed Tommy Reynolds' advice to not modify global state variables within read_procmem. I've intercepted a syscall which does the calculation (I've used the open syscall since it allowed me to increase the counter by just running vi on any file ;) ) and put it into a buffer which is dumped when the /proc entry is read. Works great that way too. By the way, as the final module will intercept syscalls like open, creat, close, link, unlink, mkdir, etc. , I'm wondering if there'll be a dramatic negative impact on file operations performance. Is there any efficient method to measure this ?
In any case, thanks for all the help you gave me :)

Regards,
Laurent Sinitambirivoutin
[email protected]

#5 lore raw
In reply to Val Henson
Quoted 10 lines · Alan Cox
Quoted 6 lines

I've encountered this problem before, too. What is the "One True Way" to do this cleanly? In other words, if you want to do a calculation once every time someone runs "cat /proc/foo", what is the cleanest way to do that? The solution we came up with was to check the file offset and only do the calculation if offset == 0, which seems pretty hackish.

Another approach is to do the calculation open and remember it in per fd private data. You can recover that and free it on release. It could even be a buffer holding the actual "content"

It might also be an idea to export proc_calc_metrics() from fs/proc/proc_misc.c because quite a lot of code actually tries to do exactly the same.

Erik

Signature · 5 lines
J.A.K. (Erik) Mouw, Information and Communication Theory Group, Faculty
of Information Technology and Systems, Delft University of Technology,
PO BOX 5031, 2600 GA Delft, The Netherlands  Phone: +31-15-2783635
Fax: +31-15-2781843  Email: [email protected]
WWW: http://www-ict.its.tudelft.nl/~erik/
#6 lore raw
In reply to Val Henson
Quoted 8 lines · Erik Mouw
Quoted 7 lines · Alan Cox
Quoted 6 lines

I've encountered this problem before, too. What is the "One True Way" to do this cleanly? In other words, if you want to do a calculation once every time someone runs "cat /proc/foo", what is the cleanest way to do that? The solution we came up with was to check the file offset and only do the calculation if offset == 0, which seems pretty hackish.

Quoted 7 lines
Quoted 3 lines

Another approach is to do the calculation open and remember it in per fd private data. You can recover that and free it on release. It could even be a buffer holding the actual "content"

It might also be an idea to export proc_calc_metrics() from fs/proc/proc_misc.c because quite a lot of code actually tries to do exactly the same.

Look at all the parameters, they're trying to be a struct. How about cleaning it up before exporting?

Signature · 1 line
Daniel
#7 lore raw
In reply to Val Henson
Quoted 7 lines · Daniel Phillips
Quoted 3 lines · Erik Mouw

It might also be an idea to export proc_calc_metrics() from fs/proc/proc_misc.c because quite a lot of code actually tries to do exactly the same.

Look at all the parameters, they're trying to be a struct. How about cleaning it up before exporting?

Look at all the parameters of a procfs read() function and compare them with the parameters of proc_calc_metrics(). See why cleaning up would make things only more complicated?

Erik

Signature · 5 lines
J.A.K. (Erik) Mouw, Information and Communication Theory Group, Faculty
of Information Technology and Systems, Delft University of Technology,
PO BOX 5031, 2600 GA Delft, The Netherlands  Phone: +31-15-2783635
Fax: +31-15-2781843  Email: [email protected]
WWW: http://www-ict.its.tudelft.nl/~erik/
#8 lore raw
Quoted 6 lines · Erik Mouw
Quoted 5 lines · Daniel Phillips
Quoted 3 lines · Erik Mouw

It might also be an idea to export proc_calc_metrics() from fs/proc/proc_misc.c because quite a lot of code actually tries to do exactly the same.

Quoted 6 lines
Quoted 2 lines

Look at all the parameters, they're trying to be a struct. How about cleaning it up before exporting?

Look at all the parameters of a procfs read() function and compare them with the parameters of proc_calc_metrics(). See why cleaning up would make things only more complicated?

Oh, for fsck sake...

We already have better mechanism. Let ->proc_read() die, it's an ugly kludge, breeding overcomplicated code and buffer overflows.

#10 lore raw
In reply to Laurent
Quoted 4 lines · Laurent
Quoted 2 lines

We already have better mechanism. Let ->proc_read() die, it's an ugly kludge, breeding overcomplicated code and buffer overflows.

What better mechanism ??

seq_file.c and seq_file.h. Grep around for stuff using it.

author
#9 lore raw
In reply to Alexander Viro
Quoted 2 lines

We already have better mechanism. Let ->proc_read() die, it's an ugly kludge, breeding overcomplicated code and buffer overflows.

What better mechanism ??

Signature · 2 lines
Laurent Sinitambirivoutin
[email protected]
#11 lore raw
In reply to Erik Mouw

Yes, please kill it! seq files are much better and don't give people as much of a chance to do things the wrong way. Fewer interfaces to /proc would be vast improvement.

} Oh, for fsck sake...
}
} We already have better mechanism. Let ->proc_read() die, it's an ugly } kludge, breeding overcomplicated code and buffer overflows.
}
} -
} To unsubscribe from this list: send the line "unsubscribe linux-kernel" in } the body of a message to [email protected]
} More majordomo info at http://vger.kernel.org/majordomo-info.html
} Please read the FAQ at http://www.tux.org/lkml/