Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 7 May 2001 05:46:24 -0700
From:      Alfred Perlstein <alfred@freebsd.org>
To:        "Nick's Lists" <mrlist@noid.org>
Cc:        freebsd-stable@freebsd.org
Subject:   Re: panic: pipeinit: cannot allocate pipe -- out of kvm -- code = 3
Message-ID:  <20010507054623.Q18676@fw.wintelcom.net>
In-Reply-To: <026b01c0d1b9$161f0320$3ba2640a@int.netzero.net>; from mrlist@noid.org on Mon, Apr 30, 2001 at 02:03:33PM -0700
References:  <026b01c0d1b9$161f0320$3ba2640a@int.netzero.net>

next in thread | previous in thread | raw e-mail | index | archive | help
* Nick's Lists <mrlist@noid.org> [010430 14:03] wrote:
> The box is a dual P3 with 2g ram, running Qmail which is handling inbound
> email. I'm running 4.2 Release (though I've had similar problems with 3.4
> Stable a few months back, and never solved them either).
> 
> After a 36 - 48hrs, the box will panic with "panic: pipeinit: cannot
> allocate pipe -- out of kvm -- code = 3". It doesn't seem to happen during
> periods of peak load, the last crash occurred at 3:45AM and there have been
> days when the box has made it through our peak load times with no problems.

Here's a patch that should make pipe safe, it's untested.  If it crashes
you right away then let me know, I'll have a cleaned up patch ready
later tonight.  If it crashes you later then also let me know. :)

For now give this a shot, it forces resource allocation to happen at
pipe creation and safely resizes pipes when the system wants them to
grow.

Index: sys_pipe.c
===================================================================
RCS file: /home/ncvs/src/sys/kern/sys_pipe.c,v
retrieving revision 1.60.2.6
diff -u -r1.60.2.6 sys_pipe.c
--- sys_pipe.c	2001/02/26 04:23:16	1.60.2.6
+++ sys_pipe.c	2001/05/07 12:40:13
@@ -144,7 +144,8 @@
 static int amountpipekva;
 
 static void pipeclose __P((struct pipe *cpipe));
-static void pipeinit __P((struct pipe *cpipe));
+static void pipe_free_kmem __P((struct pipe *cpipe));
+static int pipe_create __P((struct pipe **cpipep));
 static __inline int pipelock __P((struct pipe *cpipe, int catch));
 static __inline void pipeunlock __P((struct pipe *cpipe));
 static __inline void pipeselwakeup __P((struct pipe *cpipe));
@@ -154,7 +155,7 @@
 static int pipe_direct_write __P((struct pipe *wpipe, struct uio *uio));
 static void pipe_clone_write_buffer __P((struct pipe *wpipe));
 #endif
-static void pipespace __P((struct pipe *cpipe));
+static int pipespace __P((struct pipe *cpipe, int size));
 
 static vm_zone_t pipe_zone;
 
@@ -178,11 +179,13 @@
 	if (pipe_zone == NULL)
 		pipe_zone = zinit("PIPE", sizeof (struct pipe), 0, 0, 4);
 
-	rpipe = zalloc( pipe_zone);
-	pipeinit(rpipe);
+	if (pipe_create(&rpipe) || pipe_create(&wpipe)) {
+		pipeclose(rpipe); 
+		pipeclose(wpipe); 
+		return (ENFILE);
+	}
+	
 	rpipe->pipe_state |= PIPE_DIRECTOK;
-	wpipe = zalloc( pipe_zone);
-	pipeinit(wpipe);
 	wpipe->pipe_state |= PIPE_DIRECTOK;
 
 	error = falloc(p, &rf, &fd);
@@ -231,52 +234,78 @@
 /*
  * Allocate kva for pipe circular buffer, the space is pageable
  */
-static void
-pipespace(cpipe)
+static int
+pipespace(cpipe, size)
 	struct pipe *cpipe;
+	int size;
 {
+	struct vm_object *object;
+	caddr_t buffer;
 	int npages, error;
 
-	npages = round_page(cpipe->pipe_buffer.size)/PAGE_SIZE;
+	npages = round_page(size)/PAGE_SIZE;
 	/*
 	 * Create an object, I don't like the idea of paging to/from
 	 * kernel_object.
 	 * XXX -- minor change needed here for NetBSD/OpenBSD VM systems.
 	 */
-	cpipe->pipe_buffer.object = vm_object_allocate(OBJT_DEFAULT, npages);
-	cpipe->pipe_buffer.buffer = (caddr_t) vm_map_min(kernel_map);
+	object = vm_object_allocate(OBJT_DEFAULT, npages);
+	buffer = (caddr_t) vm_map_min(kernel_map);
 
 	/*
 	 * Insert the object into the kernel map, and allocate kva for it.
 	 * The map entry is, by default, pageable.
 	 * XXX -- minor change needed here for NetBSD/OpenBSD VM systems.
 	 */
-	error = vm_map_find(kernel_map, cpipe->pipe_buffer.object, 0,
-		(vm_offset_t *) &cpipe->pipe_buffer.buffer, 
-		cpipe->pipe_buffer.size, 1,
+	error = vm_map_find(kernel_map, object, 0,
+		(vm_offset_t *) &buffer, size, 1,
 		VM_PROT_ALL, VM_PROT_ALL, 0);
+
+	if (error != KERN_SUCCESS) {
+		vm_object_deallocate(object);
+		return (ENOMEM);
+	}
 
-	if (error != KERN_SUCCESS)
-		panic("pipeinit: cannot allocate pipe -- out of kvm -- code = %d", error);
+	/* free old resources if we're resizing */
+	pipe_free_kmem(cpipe);
+	cpipe->pipe_buffer.object = object;
+	cpipe->pipe_buffer.buffer = buffer;
+	cpipe->pipe_buffer.size = size;
+	cpipe->pipe_buffer.in = 0;
+	cpipe->pipe_buffer.out = 0;
+	cpipe->pipe_buffer.cnt = 0;
 	amountpipekva += cpipe->pipe_buffer.size;
+	return (0);
 }
 
 /*
  * initialize and allocate VM and memory for pipe
  */
-static void
-pipeinit(cpipe)
-	struct pipe *cpipe;
+static int
+pipe_create(cpipep)
+	struct pipe **cpipep;
 {
+	struct pipe *cpipe;
+	int error;
 
-	cpipe->pipe_buffer.in = 0;
-	cpipe->pipe_buffer.out = 0;
-	cpipe->pipe_buffer.cnt = 0;
-	cpipe->pipe_buffer.size = PIPE_SIZE;
+	*cpipep = zalloc(pipe_zone);
+	if (*cpipep == NULL)
+		return (ENOMEM);
+
+	cpipe = *cpipep;
+	
+	/* so pipespace()->pipe_free_kmem() doesn't follow junk pointer */
+	cpipe->pipe_buffer.object = NULL;
+#ifndef PIPE_NODIRECT
+	cpipe->pipe_map.kva = NULL;
+#endif
 
-	/* Buffer kva gets dynamically allocated */
-	cpipe->pipe_buffer.buffer = NULL;
-	/* cpipe->pipe_buffer.object = invalid */
+	error = pipespace(cpipe, PIPE_SIZE);
+	if (error) {
+		*cpipep = NULL;
+		zfree(pipe_zone, cpipe);
+		return (error);
+	}
 
 	cpipe->pipe_state = 0;
 	cpipe->pipe_peer = NULL;
@@ -296,6 +325,7 @@
 	cpipe->pipe_map.npages = 0;
 	/* cpipe->pipe_map.ms[] = invalid */
 #endif
+	return (0);
 }
 
 
@@ -742,47 +772,16 @@
 		(wpipe->pipe_buffer.size <= PIPE_SIZE) &&
 		(wpipe->pipe_buffer.cnt == 0)) {
 
-		if (wpipe->pipe_buffer.buffer) {
-			amountpipekva -= wpipe->pipe_buffer.size;
-			kmem_free(kernel_map,
-				(vm_offset_t)wpipe->pipe_buffer.buffer,
-				wpipe->pipe_buffer.size);
-		}
-
-#ifndef PIPE_NODIRECT
-		if (wpipe->pipe_map.kva) {
-			amountpipekva -= wpipe->pipe_buffer.size + PAGE_SIZE;
-			kmem_free(kernel_map,
-				wpipe->pipe_map.kva,
-				wpipe->pipe_buffer.size + PAGE_SIZE);
-		}
-#endif
-
-		wpipe->pipe_buffer.in = 0;
-		wpipe->pipe_buffer.out = 0;
-		wpipe->pipe_buffer.cnt = 0;
-		wpipe->pipe_buffer.size = BIG_PIPE_SIZE;
-		wpipe->pipe_buffer.buffer = NULL;
-		++nbigpipe;
-
-#ifndef PIPE_NODIRECT
-		wpipe->pipe_map.cnt = 0;
-		wpipe->pipe_map.kva = 0;
-		wpipe->pipe_map.pos = 0;
-		wpipe->pipe_map.npages = 0;
-#endif
-
-	}
-		
-
-	if( wpipe->pipe_buffer.buffer == NULL) {
 		if ((error = pipelock(wpipe,1)) == 0) {
-			pipespace(wpipe);
+			if (pipespace(wpipe, BIG_PIPE_SIZE) == 0)
+				nbigpipe++;
 			pipeunlock(wpipe);
 		} else {
 			return error;
 		}
 	}
+		
+	KASSERT(wpipe->pipe_buffer.buffer != NULL, ("pipe buffer gone"));
 
 	++wpipe->pipe_busy;
 	orig_resid = uio->uio_resid;
@@ -1132,6 +1131,33 @@
 	return 0;
 }
 
+static void
+pipe_free_kmem(cpipe)
+	struct pipe *cpipe;
+{
+
+	if (cpipe->pipe_buffer.buffer) {
+		if (cpipe->pipe_buffer.size > PIPE_SIZE)
+			--nbigpipe;
+		amountpipekva -= cpipe->pipe_buffer.size;
+		kmem_free(kernel_map,
+			(vm_offset_t)cpipe->pipe_buffer.buffer,
+			cpipe->pipe_buffer.size);
+	}
+#ifndef PIPE_NODIRECT
+	if (cpipe->pipe_map.kva) {
+		amountpipekva -= cpipe->pipe_buffer.size + PAGE_SIZE;
+		kmem_free(kernel_map,
+			cpipe->pipe_map.kva,
+			cpipe->pipe_buffer.size + PAGE_SIZE);
+		cpipe->pipe_map.cnt = 0;
+		cpipe->pipe_map.kva = 0;
+		cpipe->pipe_map.pos = 0;
+		cpipe->pipe_map.npages = 0;
+	}
+#endif
+}
+
 /*
  * shutdown the pipe
  */
@@ -1140,6 +1166,7 @@
 	struct pipe *cpipe;
 {
 	struct pipe *ppipe;
+
 	if (cpipe) {
 		
 		pipeselwakeup(cpipe);
@@ -1168,22 +1195,7 @@
 		/*
 		 * free resources
 		 */
-		if (cpipe->pipe_buffer.buffer) {
-			if (cpipe->pipe_buffer.size > PIPE_SIZE)
-				--nbigpipe;
-			amountpipekva -= cpipe->pipe_buffer.size;
-			kmem_free(kernel_map,
-				(vm_offset_t)cpipe->pipe_buffer.buffer,
-				cpipe->pipe_buffer.size);
-		}
-#ifndef PIPE_NODIRECT
-		if (cpipe->pipe_map.kva) {
-			amountpipekva -= cpipe->pipe_buffer.size + PAGE_SIZE;
-			kmem_free(kernel_map,
-				cpipe->pipe_map.kva,
-				cpipe->pipe_buffer.size + PAGE_SIZE);
-		}
-#endif
+		pipe_free_kmem(cpipe);
 		zfree(pipe_zone, cpipe);
 	}
 }




To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-stable" in the body of the message




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