Subject: Re: help w/ shmat() [followup; problem found]
To: Frederick Bruckman <fredb@immanent.net>
From: Dave B <spam@dberg.net>
List: netbsd-help
Date: 12/27/2004 20:59:30
On Thu, Dec 02, 2004 at 06:44:13PM -0600, Frederick Bruckman wrote:
> On Thu, 2 Dec 2004, Dave B wrote:
> 
> >On Thu, Dec 02, 2004 at 03:40:35PM -0600, Frederick Bruckman wrote:
> >>
> >>There's no reason to think things would be any different in current...
> >>MAXDSIZ on atari is still only 64Mb, while it's 1Gb on alpha and i386.
> >>How much memory are you trying to mmap()? There might be a reason why
> >>atari's limit is so low, but if you want to find out for yourself,
> >>try building a kernel with "options MAXDSIZ (1*1024*1024*1024)".
> >...
> >
> > I'd already upped MAXDSIZ to 128*1024*1024 four years ago.  Do you
> >suspect that this still isn't enough? I've tried the shmget call in my
> >test case with a size arg as low as 0x100.  No good.  I don't know how
> >that relates to the calls to mmap(), though (I'm not calling mmap()
> >explicitly).
> 
> I see. It might well be a bug, then.

  I finally figured this out: idealistically, I'd say it was neither
NetBSD's bug nor my configuration error--more like a pathological
case.  In practice, though, the problem was that I had set MAXTSIZ too
high (128*1024*1024--same as I'd set MAXDSIZ), because the default
seemed way too low (6*1024*1024).  The consequence (if I'm grasping
this right) was that in leaving room for text, data and other segments,
uvm_map_findspace() would always try to attach the shared-mem segment
at a point way higher in virtual memory than it would with a stock
NetBSD/atari system.  This, in turn, was an issue because NetBSD/atari
only expects a small portion of the 32bit range to be used for virtual
memory address space (nothing above 0x0E000000, it seems, but with my
kernel, shmat() was always getting placed above there, thus always
failing).  0x0E000000 is also the value of the macro VM_MAX_ADDRESS,
which I suppose isn't a coincidence?

  How much sense am I making here?  Should VM_MAX_ADDRESS be this low
for the full 32-bit architecture trimlines in the m68k family?  Any-
way, my thanks to the person who included the UVMHIST tracing feature
in the kernel code--without it, I would probably still be stumped.
I've enclosed the program I used to turn uvmhist_print() on and off
just for my invocation of shmat(), in case someone can use it in the
future.

  Anyway, lowering MAXTSIZ to 32*1024*1024 seems to have solved my
troubles for now.  Frederick, many thanks for your attention.

Cheers,  --Dave

======================================================================
/* kernset.c, by Dave Berger; based on dkstats.c by John M. Vinopal */

/* required in kernel config for this program to do anything useful:
 *   options UVMHIST
 *   options UVMHIST_PRINT
 */

/*	$NetBSD: dkstats.c,v 1.8 2000/06/04 16:10:17 thorpej Exp $	*/

/*
 * Copyright (c) 1996 John M. Vinopal
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *      This product includes software developed for the NetBSD Project
 *      by John M. Vinopal.
 * 4. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

#include <fcntl.h>
#include <kvm.h>
#include <limits.h>
#include <nlist.h>
#include <sys/shm.h>

#define KEY 9182

static struct nlist namelist[]
 = {
	{ "_uvmhist_print_enabled" },		/* ticks per second */
	{ NULL },
};

/* Kernel pointers: nlistf and memf defined in calling program. */
static kvm_t	*kd = NULL;
const char	*const nlistf = "/netbsd" ;
const char	*const memf = "/dev/mem" ;

#define	KVM_ERROR(_string) {						\
	warnx("%s", (_string));						\
	errx(1, "%s", kvm_geterr(kd));					\
}

/*
 * Dereference the namelist pointer `v' and fill in the local copy 
 * 'p' which is of size 's'.
 */
#define deref_nl(v, p, s) deref_kptr((void *)namelist[(v)].n_value, (p), (s));

static void deref_kptr __P((void *, void *, size_t));

/*
 * Perform all of the initialization and memory allocation needed to
 * track disk statistics.
 */
int
main(int argc, char *argv[])
{
	int iRetVal;
	int iShmId;
	void *pvAddr;
        char		errbuf[_POSIX2_LINE_MAX];

	/* Open the kernel. */
        if ((kd = kvm_openfiles(nlistf, memf, NULL, O_RDWR, errbuf)) == NULL)
		errx(1, "kvm_openfiles: %s", errbuf);

	/* Obtain the namelist symbols from the kernel. */
	if (kvm_nlist(kd, namelist))
		KVM_ERROR("kvm_nlist failed to read symbols.");

	/* Get the value of the symbol */
	deref_nl(0, &iRetVal, sizeof(iRetVal));

	(void) printf( "Existing value: %d\n", iRetVal );

/* TEST-CASE SETUP CODE (pre-uvm-tracing) HERE -> */

	iShmId = shmget(KEY, 0x0100, 0x780);

/* <- END TEST-CASE SETUP CODE */

	iRetVal = 1;
		if (kvm_write(	kd,
				(u_long)namelist[0].n_value,
				(char *) &iRetVal,
				sizeof(iRetVal))
			!= sizeof(iRetVal))
		{
			err(2, "kvm_write");
		}

/* TEST CODE to be uvm traced HERE -> */

	pvAddr = shmat(iShmId, 0, 0);

/* <- END TEST CODE */

	iRetVal = 0;
		if (kvm_write(	kd,
				(u_long)namelist[0].n_value,
				(char *) &iRetVal,
				sizeof(iRetVal))
			!= sizeof(iRetVal))
		{
			err(2, "kvm_write");
		}

	return(1);
}

/*
 * Dereference the kernel pointer `kptr' and fill in the local copy 
 * pointed to by `ptr'.  The storage space must be pre-allocated,
 * and the size of the copy passed in `len'.
 */
static void
deref_kptr(kptr, ptr, len)
	void *kptr, *ptr;
	size_t len;
{
	char buf[128];

	if (kvm_read(kd, (u_long)kptr, (char *)ptr, len) != len) {
		memset(buf, 0, sizeof(buf));
		snprintf(buf, sizeof buf, "can't dereference kptr 0x%lx",
		    (u_long)kptr);
		KVM_ERROR(buf);
	}
}
======================================================================