summaryrefslogtreecommitdiffstats
path: root/sys/kern/sys_pipe.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/kern/sys_pipe.c')
-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 3e63b95..238ace1 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);
}
}
OpenPOWER on IntegriCloud