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>