A problem with kernel buffers (struct buf).

Anthony V. Discolo discolo at ucsbcsl.UUCP
Sat Aug 24 19:57:12 AEST 1985


In the work on the 4.2BSD kernel that I have been doing recently, I
have come across a problem that I do not understand.  The scenario is
this:  In a kernel process that I create at boottime (called somedaemon
below), I allocate a buffer with geteblk with a size of about 10k, and
use this buffer in two ways.  First, I use it to receive a udp packet
with soreceive(), and then I bcopy out the first 100 bytes or so, and
then I copy out the remaining bytes in the message from the buffer.
What I get is a spurious protection fault inside uiomove called from
soreceive, or at the second bcopy statement.  The fault happens after
the system has been running a while under some pretty heavy testing.
This is very sketchy, so here is the relevent code.  Comments between
(* *) describe code that I took out for brevity.

%%% BEGIN CODE %%%

#define MAXRPCSIZ	(8096 + 2048)

somedeamon()
{
	int error, bpsize;
	register caddr_t bpaddr;
	struct iovec aiov;
	struct uio auio;
	register struct mbuf *m;
	struct mbuf *nam, *from, *rights;
	struct buf *bp;
	struct in_addr *myaddr;
	register struct rpcframe *rpf;
	struct sockaddr_in rpcdaddr;

	(* creation and binding of socket *)

	bp = geteblk(MAXRPCSIZ);
	if (bp == NULL) {
		printf("somedaemon: geteblk failed\n");
		(* handle error *)
	}
	bpaddr = bp->b_un.b_addr;
	bpsize = bp->b_bufsize;
	for (;;) {
		/*
		 * Read in message.
		 */
		aiov.iov_base = bpaddr;
		aiov.iov_len = bpsize;
		auio.uio_iov = &aiov;
		auio.uio_iovcnt = 1;
		auio.uio_segflg = 1;
		auio.uio_offset = 0;
		auio.uio_resid = aiov.iov_len;
		if (bp->b_bufsize != bpsize)
			printf("somedaemon: bufsize changed, now %d\n",
			    bp->b_bufsize);
		/*
		 * WILL SOMETIMES PANIC HERE
		 */
		error = soreceive(rpc_so, &from, &auio, 0, &rights);

		(* check error, m_free from and rights *)

		m = m_get(M_WAIT, MT_RPCFRAME);
		if (m == NULL) {
			printf("somedaemon: m_get failed\n");
			continue;
		}

		rpf = mtod(m, struct rpcframe *);
		bcopy(bpaddr, (caddr_t)rpf, sizeof (struct rpcframe));
		rpf->rpc_data = NULL;
		
		(* various data integrity checks *)

		if (rpf->rpc_datasiz <= 0) {
			printf("somedaemon: datasiz <= 0\n");
			(void) m_free(m);
			continue;
		}
		else if (rpf->rpc_datasiz > bpsize - sizeof (struct rpcframe)) {
			printf("somedaemon: datasiz too large: was %d\n", rpf->rpc_datasiz);
			(void) m_free(m);
			continue;
		}

		/*
		 * Copy in the data.
		 */
		rpf->rpc_data = geteblk(rpf->rpc_datasiz)

		if (rpf->rpc_data->b_bufsize < rpf->rpc_datasiz) {
			printf("somedaemon: b_bufsize too small: was %d, should be %d\n",
			    rpf->rpc_data->b_bufsize, rpf->rpc_datasiz);
			brelse(rpf->rpc_data);
			(void) m_free(m);
			continue;
		}
		/*
		 * WILL SOMETIMES PANIC HERE
		 */
		bcopy(bpaddr + sizeof (struct rpcframe), rpcdtoc(rpf),
		    rpf->rpc_datasiz);

		(* more code - rpf->rpc_data will be brelse()d elsewhere *)
	}
}

%%% END CODE %%%

I never see the output of any of the checks on the size of the message,
or the size of the buffer, so I am assuming that it passes them.

Here are two stack traces, one for each place it panics:

sbr 8002ec64 slr 34dc
p0br 805d5600 p0lr 0 p1br 7fdd5a00 p1lr 1ffff8
*(scb-4)$c
_boot() from 80026fa6
_boot(0,0) from 80026fa6
_panic(8003fd2b) from 80011a6e
_trap() from 80027618
_Xtransflt(8065bf8c,68,0,7fffff90) from 80001151
_soreceive(8065cb0c,7fffff88,7fffff90,0,7fffff84) from 8001d5fb
_somedaemon() from 8000f25a
_main(26d) from 80008cc9

sbr 8002ec64 slr 34dc
p0br 805d5600 p0lr 0 p1br 7fdd5a00 p1lr 1ffff8
*(scb-4)$c
_boot() from 80026f76
_boot(0,0) from 80026f76
_panic(8003fcef) from 80011a3e
_trap() from 800275e8
_Xtransflt() from 80001151
_main(26c) from 80008cb1

In both cases, the pc (from the trap message) points to a movc3
instruction that includes the large buffer that somedaemon uses for
receiving the udp message (called bp in the code above).

I have figured out a way to fix this: allocate a character array
in place of the buffer.  This works fine.

If any of you have any ideas why this doesn't work, some suggestions
on where to look, or something to try in adb which might give me a clue,
*please* send me mail (or post it if you think it is important).

Thanks in advance.

-- 

uucp: {ucbvax,cepu}!ucsbcsl!discolo
arpa: ucsbcsl!discolo at BERKELEY
csnet: discolo at ucsb
USMail: U.C. Santa Barbara
	Department of Computer Science
	Santa Barbara, CA  93106
GTE: (805) 961-4178



More information about the Comp.unix.wizards mailing list