aboutsummaryrefslogtreecommitdiff
path: root/sys/kern
diff options
context:
space:
mode:
authorAlfred Perlstein <alfred@FreeBSD.org>2001-05-08 09:09:18 +0000
committerAlfred Perlstein <alfred@FreeBSD.org>2001-05-08 09:09:18 +0000
commit97d457866211c8d0ad93fd32f60d935229277919 (patch)
treed54a6eed1ad4b810cf512b1bf822d0187c8b6bf0 /sys/kern
parent3a51f88a2721f4cf7aded2a63f20925f8d700a7c (diff)
downloadsrc-97d457866211c8d0ad93fd32f60d935229277919.tar.gz
src-97d457866211c8d0ad93fd32f60d935229277919.zip
Remove an 'optimization' I hope to never see again.
The pipe code could not handle running out of kva, it would panic if that happened. Instead return ENFILE to the application which is an acceptable error return from pipe(2). There was some slightly tricky things that needed to be worked on, namely that the pipe code can 'realloc' the size of the buffer if it detects that the pipe could use a bit more room. However if it failed the reallocation it could not cope and would panic. Fix this by attempting to grow the pipe while holding onto our old resources. If all goes well free the old resources and use the new ones, otherwise continue to use the smaller buffer already allocated. While I'm here add a few blank lines for style(9) and remove 'register'.
Notes
Notes: svn path=/head/; revision=76364
Diffstat (limited to 'sys/kern')
-rw-r--r--sys/kern/sys_pipe.c200
1 files changed, 111 insertions, 89 deletions
diff --git a/sys/kern/sys_pipe.c b/sys/kern/sys_pipe.c
index 3e63b955d295..238ace1251e4 100644
--- a/sys/kern/sys_pipe.c
+++ b/sys/kern/sys_pipe.c
@@ -144,7 +144,8 @@ static int nbigpipe;
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 void pipe_destroy_write_buffer __P((struct pipe *wpipe));
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;
@@ -170,7 +171,7 @@ pipe(p, uap)
int dummy;
} */ *uap;
{
- register struct filedesc *fdp = p->p_fd;
+ struct filedesc *fdp = p->p_fd;
struct file *rf, *wf;
struct pipe *rpipe, *wpipe;
int fd, error;
@@ -178,11 +179,13 @@ pipe(p, uap)
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);
@@ -230,61 +233,82 @@ pipe(p, uap)
/*
* Allocate kva for pipe circular buffer, the space is pageable
+ * This routine will 'realloc' the size of a pipe safely, if it fails
+ * it will retain the old buffer.
+ * If it fails it will return ENOMEM.
*/
-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)
- panic("pipeinit: cannot allocate pipe -- out of kvm -- code = %d", error);
+ if (error != KERN_SUCCESS) {
+ vm_object_deallocate(object);
+ return (ENOMEM);
+ }
+
+ /* 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;
-
- /* Buffer kva gets dynamically allocated */
- cpipe->pipe_buffer.buffer = NULL;
- /* cpipe->pipe_buffer.object = invalid */
+ *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
+ /*
+ * protect so pipeclose() doesn't follow a junk pointer
+ * if pipespace() fails.
+ */
cpipe->pipe_state = 0;
cpipe->pipe_peer = NULL;
cpipe->pipe_busy = 0;
- vfs_timestamp(&cpipe->pipe_ctime);
- cpipe->pipe_atime = cpipe->pipe_ctime;
- cpipe->pipe_mtime = cpipe->pipe_ctime;
- bzero(&cpipe->pipe_sel, sizeof cpipe->pipe_sel);
#ifndef PIPE_NODIRECT
/*
@@ -296,6 +320,18 @@ pipeinit(cpipe)
cpipe->pipe_map.npages = 0;
/* cpipe->pipe_map.ms[] = invalid */
#endif
+
+ error = pipespace(cpipe, PIPE_SIZE);
+ if (error) {
+ return (error);
+ }
+
+ vfs_timestamp(&cpipe->pipe_ctime);
+ cpipe->pipe_atime = cpipe->pipe_ctime;
+ cpipe->pipe_mtime = cpipe->pipe_ctime;
+ bzero(&cpipe->pipe_sel, sizeof cpipe->pipe_sel);
+
+ return (0);
}
@@ -308,6 +344,7 @@ pipelock(cpipe, catch)
int catch;
{
int error;
+
while (cpipe->pipe_state & PIPE_LOCK) {
cpipe->pipe_state |= PIPE_LWANT;
if ((error = tsleep( cpipe,
@@ -326,6 +363,7 @@ static __inline void
pipeunlock(cpipe)
struct pipe *cpipe;
{
+
cpipe->pipe_state &= ~PIPE_LOCK;
if (cpipe->pipe_state & PIPE_LWANT) {
cpipe->pipe_state &= ~PIPE_LWANT;
@@ -337,6 +375,7 @@ static __inline void
pipeselwakeup(cpipe)
struct pipe *cpipe;
{
+
if (cpipe->pipe_state & PIPE_SEL) {
cpipe->pipe_state &= ~PIPE_SEL;
selwakeup(&cpipe->pipe_sel);
@@ -355,7 +394,6 @@ pipe_read(fp, uio, cred, flags, p)
struct proc *p;
int flags;
{
-
struct pipe *rpipe = (struct pipe *) fp->f_data;
int error;
int nread = 0;
@@ -575,6 +613,7 @@ pipe_destroy_write_buffer(wpipe)
struct pipe *wpipe;
{
int i;
+
if (wpipe->pipe_map.kva) {
pmap_qremove(wpipe->pipe_map.kva, wpipe->pipe_map.npages);
@@ -597,7 +636,7 @@ struct pipe *wpipe;
*/
static void
pipe_clone_write_buffer(wpipe)
-struct pipe *wpipe;
+ struct pipe *wpipe;
{
int size;
int pos;
@@ -629,6 +668,7 @@ pipe_direct_write(wpipe, uio)
struct uio *uio;
{
int error;
+
retry:
while (wpipe->pipe_state & PIPE_DIRECTW) {
if ( wpipe->pipe_state & PIPE_WANTR) {
@@ -719,7 +759,6 @@ pipe_write(fp, uio, cred, flags, p)
{
int error = 0;
int orig_resid;
-
struct pipe *wpipe, *rpipe;
rpipe = (struct pipe *) fp->f_data;
@@ -742,47 +781,16 @@ pipe_write(fp, uio, cred, flags, p)
(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;
@@ -1004,10 +1012,10 @@ int
pipe_ioctl(fp, cmd, data, p)
struct file *fp;
u_long cmd;
- register caddr_t data;
+ caddr_t data;
struct proc *p;
{
- register struct pipe *mpipe = (struct pipe *)fp->f_data;
+ struct pipe *mpipe = (struct pipe *)fp->f_data;
switch (cmd) {
@@ -1056,7 +1064,7 @@ pipe_poll(fp, events, cred, p)
struct ucred *cred;
struct proc *p;
{
- register struct pipe *rpipe = (struct pipe *)fp->f_data;
+ struct pipe *rpipe = (struct pipe *)fp->f_data;
struct pipe *wpipe;
int revents = 0;
@@ -1133,6 +1141,34 @@ pipe_close(fp, p)
return 0;
}
+static void
+pipe_free_kmem(cpipe)
+ struct pipe *cpipe;
+{
+
+ if (cpipe->pipe_buffer.buffer != NULL) {
+ 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);
+ cpipe->pipe_buffer.buffer = NULL;
+ }
+#ifndef PIPE_NODIRECT
+ if (cpipe->pipe_map.kva != NULL) {
+ 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
*/
@@ -1141,6 +1177,7 @@ pipeclose(cpipe)
struct pipe *cpipe;
{
struct pipe *ppipe;
+
if (cpipe) {
pipeselwakeup(cpipe);
@@ -1169,22 +1206,7 @@ pipeclose(cpipe)
/*
* 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);
}
}