Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 2 Jun 2003 13:31:12 +0200
From:      Alan Robinson <alan.robinson@fujitsu-siemens.com>
To:        Marcel Moolenaar <marcel@xcllnt.net>
Cc:        freebsd-ia64@freebsd.org
Subject:   Re: /dev/kmem read return value is double requested value
Message-ID:  <20030602133112.A3892@fujitsu-siemens.com>
In-Reply-To: <20030530173029.GB568@dhcp01.pn.xcllnt.net>; from marcel@xcllnt.net on Fri, May 30, 2003 at 10:30:29AM -0700
References:  <20030530132408.A3690@fujitsu-siemens.com> <20030530173029.GB568@dhcp01.pn.xcllnt.net>

next in thread | previous in thread | raw e-mail | index | archive | help
On Fri, May 30, 2003 at 10:30:29AM -0700, Marcel Moolenaar wrote:
> 
> On Fri, May 30, 2003 at 01:24:08PM +0200, Alan Robinson wrote:
> > 
> > I was playing with a user-land program that read some data out
> > of the kernel memory and noticed that the read() return value was
> > twice what I was expecting. I think the error is in the mmrw() function
> > in file sys/ia64/ia64/mem.c, removing the following lines seems to 
> > fix the problem.
> > 
> >                 iov->iov_base = (char *)iov->iov_base + c;
> >                 iov->iov_len -= c;
> >                 uio->uio_offset += c;
> >                 uio->uio_resid -= c;
> > 
> > I had a little look at some of the other sys/ARCH/ARCH/mem.c and some others
> > seem to contain the same code so I might be wrong, then again so might the
> > ARCHs.
> 
> If you see behaviour that's not particular to ia64, it's probably better
> to post to arch@ or current@. More people hang out there, so there's a
> bigger chance you get replies.
> 
Maybe I framed my statement incorrectly:

I only have access to an i386 (4.6) and an ia64(5.0), the ia64 is the only
system that shows the problem. The i386 with 4.6 does NOT have this 
problem. While looking arround I also saw that the same code is in various 
ARCH/ARCH/mem.c files, if they really have a problem or not I cannot say.

> I don't think there's anything wrong with the lines you think we need to
> remove.
> 
I still think they are wrong, there is a uiomove() call which does exactly 
this fixup for uio several lines before and the iov gets reset at the top.

> > Note that the actual data transfered is OK, just the read() return value
> > and the /dev/kmem file offset are wrong after returning from the read().
> 
> It helps if you demonstrate the behaviour with some trivial test program
> that people can run too.
> 
You are quite correct. I didn't even say the problem only seems to show
up when trying to read info from kld loaded drivers, an example. 
(I have added the trymem.c source below)

madison# kldstat
Id Refs Address    Size     Name
 1    3 0xe000000000500000 639448   kernel
 2    1 0xa000000004768000 24000    if_fxp.ko

read some stuff from the kernel:

madison# ./trymem 0xe000000000500000 8
o=e000000000500000, sz=8
lseek xe000000000500000
read(,,x8) rc=x8
lseek(,0,SEEK_CUR) p=xe000000000500008
madison#

This seems to be OK.
read some stuff from the if_fxp.ko module:

madison# ./trymem 0xa000000004768000 8
o=a000000004768000, sz=8
lseek xa000000004768000
read(,,x8) rc=x10
read rc=x10, sz=x8 !
lseek(,0,SEEK_CUR) p=xa000000004768010
lseek(,0,SEEK_CUR) p=xa000000004768010, !=xa000000004768008 !
madison#

This is WRONG, the read returns twice the length and the
lseek offset is also wrong but consistent with the incorrect 
rc. After removing the said lines from mem.c trymem works OK
for both kernel and if_fxp.ko addresses.

Alan

-trymem.c-------trymem.c-------trymem.c--------trymem.c--------trymem.c-------

#include <stdio.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <unistd.h>
#include <stdlib.h>
#include <limits.h>


#define FN "/dev/kmem"

int
main(int argc, char *argv[])
{
        int fd, rc;
        unsigned long o,p;
        int sz;
        char buf[16 * 1024];


        if (argc < 2) {
                printf("usage: %s <address> <size>\n", argv[0]);
                exit(1);
        }

        o = strtoull(argv[1], NULL, 0);
        sz = strtol(argv[2], NULL, 0);
        printf("o=%lx, sz=%x\n",o,sz);
        if (sz > (16 *1024)) {
                printf("size to large\n");
                exit(-1);
        }

        fd = open(FN, O_RDONLY);
        if ( fd < 0) {
                perror("cannot open " FN);
                exit(-1);
        }


        printf("lseek x%lx\n",o);
        p = lseek(fd,o,SEEK_SET);
        if ( o != p ) {
                printf("lseek x%lx error\n",o);
        }

        rc = read(fd,buf,sz);
        printf("read(,,x%x) rc=x%x\n",sz,rc);
        if ( rc != sz ) {
                printf("read rc=x%x, sz=x%x !\n",rc,sz);
        }
        p = lseek(fd,(unsigned long)0,SEEK_CUR);
        printf("lseek(,0,SEEK_CUR) p=x%lx\n",p);
        if (p != (o + (unsigned long)sz)) {
                printf("lseek(,0,SEEK_CUR) p=x%lx, !=x%lx !\n",p,(o + (unsigned
long)sz));
        }
        close(fd);
        return (0);
}
-------------------------------------------------------------------------------



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20030602133112.A3892>