1
0
mirror of https://git.FreeBSD.org/src.git synced 2024-12-16 10:20:30 +00:00

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'.
This commit is contained in:
Alfred Perlstein 2001-05-08 09:09:18 +00:00
parent 3a51f88a27
commit 97d4578662
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=76364

View File

@ -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);
}
}