2006-02-22 19:04:56

by Martin Schlemmer

[permalink] [raw]
Subject: Problems with read() on /proc/devices with x86_64 system

Hi,

Not sure when it started, but 2.6.16-rc[1234] at least have problems
with unbuffered read() and /proc/devices on my x86_64 box. I first
picked it up with dmsetup that did not want to work properly built
against klibc (glibc with fread() worked fine though, as it mmap()'d the
file).

Following code (from HPA and klibc mailing lists), when compiled and run
with /proc/devices only reads the first two lines and then exits
normally, where with any other file works as expected.

-----
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/stat.h>

int main(int argc, char *argv[])
{
char c;
int i, fd, rv;

for ( i = 1 ; i < argc ; i++ ) {
fd = open(argv[i], O_RDONLY);
if ( fd < 0 ) {
perror(argv[i]);
exit(1);
}

while ( (rv = read(fd, &c, 1)) ) {
if ( rv == -1 ) {
if ( errno == EINTR || errno == EAGAIN )
continue;

perror(argv[i]);
exit(1);
}
putchar(c);
}

close(fd);
}

return 0;
}
-----

Output over here:

-----
# ./readbychar.klibc /proc/devices
Character devices:
1 mem
#
-----


Thanks,

--
Martin Schlemmer


Attachments:
signature.asc (191.00 B)
This is a digitally signed message part

2006-02-22 20:44:05

by linux-os (Dick Johnson)

[permalink] [raw]
Subject: Re: Problems with read() on /proc/devices with x86_64 system


On Wed, 22 Feb 2006, Martin Schlemmer wrote:

> Hi,
>
> Not sure when it started, but 2.6.16-rc[1234] at least have problems
> with unbuffered read() and /proc/devices on my x86_64 box. I first
> picked it up with dmsetup that did not want to work properly built
> against klibc (glibc with fread() worked fine though, as it mmap()'d the
> file).
>
> Following code (from HPA and klibc mailing lists), when compiled and run
> with /proc/devices only reads the first two lines and then exits
> normally, where with any other file works as expected.
>
> -----
> #include <stdlib.h>
> #include <stdio.h>
> #include <unistd.h>
> #include <fcntl.h>
> #include <errno.h>
> #include <sys/stat.h>
>
> int main(int argc, char *argv[])
> {
> char c;
> int i, fd, rv;
>
> for ( i = 1 ; i < argc ; i++ ) {
> fd = open(argv[i], O_RDONLY);
> if ( fd < 0 ) {
> perror(argv[i]);
> exit(1);
> }
>
> while ( (rv = read(fd, &c, 1)) ) {
> if ( rv == -1 ) {
> if ( errno == EINTR || errno == EAGAIN )
> continue;
>
> perror(argv[i]);
> exit(1);
> }
> putchar(c);
> }
>
> close(fd);
> }
> return 0;
> }
> -----
>
> Output over here:
>
> -----
> # ./readbychar.klibc /proc/devices
> Character devices:
> 1 mem
> #
> -----
> Thanks,
> Martin Schlemmer

If your code ever worked, it's probably because of some
fortuitous buffering in the 'C' runtime library. Most
of the 'read' code in drivers that have a /proc interface
is not designed for 1-character-at-a-time I/O. It's expected
that it will be accessed like `cat` or `more` or other
such tools access it, -- one read with 4096-byte buffer --

read(3, "MemTotal: 773860 kB\nMemFre"..., 4096) = 670
write(1, "MemTotal: 773860 kB\nMemFre"..., 670) = 670

The read code uses sprintf to write all the parameters to
a buffer, then it copies the parameters to the user. The
next read will return 0 for EOF and reset the interface
for the next access.

If your code read /proc without any help from the 'C' runtime
library, you would read the same first character, every time
you attempted to read a character. Don't do that! Your code
should do (with some error-checking):

fd = open(argv[1], O_RDONLY);
buffer = malloc(LEN);
read(fd, buffer, len);
puts(buffer);

Also, something seems somewhat strange because it is not
commonplace to provide a mmap() interface to /proc file-system
capability in drivers and the /proc base code doesn't
provide memory-map capability at least on 2.6.15.4. So,
your reference to memory-mapping the file seems to be
incorrect.


Cheers,
Dick Johnson
Penguin : Linux version 2.6.15.4 on an i686 machine (5589.54 BogoMips).
Warning : 98.36% of all statistics are fiction.
_


****************************************************************
The information transmitted in this message is confidential and may be privileged. Any review, retransmission, dissemination, or other use of this information by persons or entities other than the intended recipient is prohibited. If you are not the intended recipient, please notify Analogic Corporation immediately - by replying to this message or by sending an email to [email protected] - and destroy all copies of this information, including any attachments, without reading or disclosing them.

Thank you.

2006-02-22 21:23:08

by Martin Schlemmer

[permalink] [raw]
Subject: Re: Problems with read() on /proc/devices with x86_64 system

On Wed, 2006-02-22 at 15:43 -0500, linux-os (Dick Johnson) wrote:
> On Wed, 22 Feb 2006, Martin Schlemmer wrote:
>
> > Hi,
> >
> > Not sure when it started, but 2.6.16-rc[1234] at least have problems
> > with unbuffered read() and /proc/devices on my x86_64 box. I first
> > picked it up with dmsetup that did not want to work properly built
> > against klibc (glibc with fread() worked fine though, as it mmap()'d the
> > file).
> >
> > Following code (from HPA and klibc mailing lists), when compiled and run
> > with /proc/devices only reads the first two lines and then exits
> > normally, where with any other file works as expected.
> >
> > -----
> > #include <stdlib.h>
> > #include <stdio.h>
> > #include <unistd.h>
> > #include <fcntl.h>
> > #include <errno.h>
> > #include <sys/stat.h>
> >
> > int main(int argc, char *argv[])
> > {
> > char c;
> > int i, fd, rv;
> >
> > for ( i = 1 ; i < argc ; i++ ) {
> > fd = open(argv[i], O_RDONLY);
> > if ( fd < 0 ) {
> > perror(argv[i]);
> > exit(1);
> > }
> >
> > while ( (rv = read(fd, &c, 1)) ) {
> > if ( rv == -1 ) {
> > if ( errno == EINTR || errno == EAGAIN )
> > continue;
> >
> > perror(argv[i]);
> > exit(1);
> > }
> > putchar(c);
> > }
> >
> > close(fd);
> > }
> > return 0;
> > }
> > -----
> >
> > Output over here:
> >
> > -----
> > # ./readbychar.klibc /proc/devices
> > Character devices:
> > 1 mem
> > #
> > -----
> > Thanks,
> > Martin Schlemmer
>
> If your code ever worked, it's probably because of some
> fortuitous buffering in the 'C' runtime library.

Not my code .. I just did a minimal hack to get it to build with klibc
(klibc do not support fscanf(), so used fread() and sscanf() ..).

> Most
> of the 'read' code in drivers that have a /proc interface
> is not designed for 1-character-at-a-time I/O. It's expected
> that it will be accessed like `cat` or `more` or other
> such tools access it, -- one read with 4096-byte buffer --
>
> read(3, "MemTotal: 773860 kB\nMemFre"..., 4096) = 670
> write(1, "MemTotal: 773860 kB\nMemFre"..., 670) = 670
>

Maybe, but the same code I posted works fine with any other file
in /proc, and works fine on my small p3 server with 2.6.14.

> The read code uses sprintf to write all the parameters to
> a buffer, then it copies the parameters to the user. The
> next read will return 0 for EOF and reset the interface
> for the next access.
>
> If your code read /proc without any help from the 'C' runtime
> library, you would read the same first character, every time
> you attempted to read a character. Don't do that! Your code
> should do (with some error-checking):
>
> fd = open(argv[1], O_RDONLY);
> buffer = malloc(LEN);
> read(fd, buffer, len);
> puts(buffer);
>
> Also, something seems somewhat strange because it is not
> commonplace to provide a mmap() interface to /proc file-system
> capability in drivers and the /proc base code doesn't
> provide memory-map capability at least on 2.6.15.4. So,
> your reference to memory-mapping the file seems to be
> incorrect.
>

Might have misread the strace there.



Thanks,

--
Martin Schlemmer


Attachments:
signature.asc (191.00 B)
This is a digitally signed message part

2006-02-24 07:42:48

by Jan Engelhardt

[permalink] [raw]
Subject: Re: Problems with read() on /proc/devices with x86_64 system

>> If your code ever worked, it's probably because of some
>> fortuitous buffering in the 'C' runtime library.
>
>Not my code .. I just did a minimal hack to get it to build with klibc
>(klibc do not support fscanf(), so used fread() and sscanf() ..).
>
Ah, you can't do fread(ptr, 4096, 1, fp), because it would probably never
return 1 if the file was smaller than 4096. Bad luck with stdio, I'd say.
Back to read(2).

>> Most
>> of the 'read' code in drivers that have a /proc interface
>> is not designed for 1-character-at-a-time I/O. It's expected
>> that it will be accessed like `cat` or `more` or other
>> such tools access it, -- one read with 4096-byte buffer --
>>
>> read(3, "MemTotal: 773860 kB\nMemFre"..., 4096) = 670
>> write(1, "MemTotal: 773860 kB\nMemFre"..., 670) = 670

Jan Engelhardt
--