diff --git a/sys/fs/fifofs/fifo_vnops.c b/sys/fs/fifofs/fifo_vnops.c --- a/sys/fs/fifofs/fifo_vnops.c +++ b/sys/fs/fifofs/fifo_vnops.c @@ -140,9 +140,7 @@ if (fp == NULL || (ap->a_mode & FEXEC) != 0) return (EINVAL); if ((fip = vp->v_fifoinfo) == NULL) { - error = pipe_named_ctor(&fpipe, td); - if (error != 0) - return (error); + pipe_named_ctor(&fpipe, td); fip = malloc(sizeof(*fip), M_VNODE, M_WAITOK | M_ZERO); fip->fi_pipe = fpipe; fpipe->pipe_wgen = 0; diff --git a/sys/kern/sys_pipe.c b/sys/kern/sys_pipe.c --- a/sys/kern/sys_pipe.c +++ b/sys/kern/sys_pipe.c @@ -114,6 +114,7 @@ #include #include #include +#include #include @@ -223,8 +224,8 @@ static void pipeinit(void *dummy __unused); static void pipeclose(struct pipe *cpipe); static void pipe_free_kmem(struct pipe *cpipe); -static int pipe_create(struct pipe *pipe, bool backing); -static int pipe_paircreate(struct thread *td, struct pipepair **p_pp); +static void pipe_create(struct pipe *pipe, bool backing); +static void pipe_paircreate(struct thread *td, struct pipepair **p_pp); static __inline int pipelock(struct pipe *cpipe, bool catch); static __inline void pipeunlock(struct pipe *cpipe); static void pipe_timestamp(struct timespec *tsp); @@ -356,12 +357,11 @@ mtx_destroy(&pp->pp_mtx); } -static int +static void pipe_paircreate(struct thread *td, struct pipepair **p_pp) { struct pipepair *pp; struct pipe *rpipe, *wpipe; - int error; *p_pp = pp = uma_zalloc(pipe_zone, M_WAITOK); #ifdef MAC @@ -383,50 +383,21 @@ * Only the forward direction pipe is backed by big buffer by * default. */ - error = pipe_create(rpipe, true); - if (error != 0) - goto fail; - error = pipe_create(wpipe, false); - if (error != 0) { - /* - * This cleanup leaves the pipe inode number for rpipe - * still allocated, but never used. We do not free - * inode numbers for opened pipes, which is required - * for correctness because numbers must be unique. - * But also it avoids any memory use by the unr - * allocator, so stashing away the transient inode - * number is reasonable. - */ - pipe_free_kmem(rpipe); - goto fail; - } + pipe_create(rpipe, true); + pipe_create(wpipe, false); rpipe->pipe_state |= PIPE_DIRECTOK; wpipe->pipe_state |= PIPE_DIRECTOK; - return (0); - -fail: - knlist_destroy(&rpipe->pipe_sel.si_note); - knlist_destroy(&wpipe->pipe_sel.si_note); -#ifdef MAC - mac_pipe_destroy(pp); -#endif - uma_zfree(pipe_zone, pp); - return (error); } -int +void pipe_named_ctor(struct pipe **ppipe, struct thread *td) { struct pipepair *pp; - int error; - error = pipe_paircreate(td, &pp); - if (error != 0) - return (error); + pipe_paircreate(td, &pp); pp->pp_rpipe.pipe_type |= PIPE_TYPE_NAMED; *ppipe = &pp->pp_rpipe; - return (0); } void @@ -470,9 +441,7 @@ struct pipepair *pp; int fd, fflags, error; - error = pipe_paircreate(td, &pp); - if (error != 0) - return (error); + pipe_paircreate(td, &pp); rpipe = &pp->pp_rpipe; wpipe = &pp->pp_wpipe; error = falloc_caps(td, &rf, &fd, flags, fcaps1); @@ -549,6 +518,20 @@ return (error); } +static void +pipekva_enomem(void) +{ + static int curfail = 0; + static struct timeval lastfail; + + pipeallocfail++; + if (!ppsratecheck(&lastfail, &curfail, 1)) + return; + printf("pid %d (%s), jid %d, uid %d: kern.ipc.maxpipekva exceeded\n", + curproc->p_pid, curproc->p_comm, curproc->p_ucred->cr_prison->pr_id, + curproc->p_ucred->cr_uid); +} + /* * Allocate kva for pipe circular buffer, the space is pageable * This routine will 'realloc' the size of a pipe safely, if it fails @@ -560,8 +543,6 @@ { caddr_t buffer; int error, cnt, firstseg; - static int curfail = 0; - static struct timeval lastfail; KASSERT(!mtx_owned(PIPE_MTX(cpipe)), ("pipespace: pipe mutex locked")); KASSERT(!(cpipe->pipe_state & PIPE_DIRECTW), @@ -584,9 +565,7 @@ goto retry; } if (cpipe->pipe_buffer.buffer == NULL) { - pipeallocfail++; - if (ppsratecheck(&lastfail, &curfail, 1)) - printf("kern.ipc.maxpipekva exceeded; see tuning(7)\n"); + pipekva_enomem(); } else { piperesizefail++; } @@ -694,16 +673,21 @@ * Initialize and allocate VM and memory for pipe. The structure * will start out zero'd from the ctor, so we just manage the kmem. */ -static int +static void pipe_create(struct pipe *pipe, bool large_backing) { - int error; - error = pipespace_new(pipe, !large_backing || amountpipekva > + /* + * Note that pipespace_new() can fail if pipe map is exhausted + * (as a result of too many pipes created), but we ignore the + * error here as it is not fatal and could be provoked by + * unprivileged users. The pipe will be unused in absolute majority + * of cases anyways, so it is not a big deal. If the condition + * persists, the write() will re-try allocation and report it then. + */ + (void)pipespace_new(pipe, !large_backing || amountpipekva > maxpipekva / 2 ? SMALL_PIPE_SIZE : PIPE_SIZE); - if (error == 0) - pipe->pipe_ino = alloc_unr64(&pipeino_unr); - return (error); + pipe->pipe_ino = alloc_unr64(&pipeino_unr); } /* ARGSUSED */ @@ -1159,7 +1143,17 @@ pipespace(wpipe, desiredsize); PIPE_LOCK(wpipe); } - MPASS(wpipe->pipe_buffer.size != 0); + if (wpipe->pipe_buffer.size == 0) { + /* + * This can only happen for reverse direction use of pipes + * in a complete OOM situation. + */ + error = ENOMEM; + --wpipe->pipe_busy; + pipeunlock(wpipe); + PIPE_UNLOCK(wpipe); + return (error); + } orig_resid = uio->uio_resid; diff --git a/sys/sys/pipe.h b/sys/sys/pipe.h --- a/sys/sys/pipe.h +++ b/sys/sys/pipe.h @@ -145,7 +145,7 @@ #ifdef _KERNEL void pipe_dtor(struct pipe *dpipe); -int pipe_named_ctor(struct pipe **ppipe, struct thread *td); +void pipe_named_ctor(struct pipe **ppipe, struct thread *td); void pipeselwakeup(struct pipe *cpipe); #endif #endif /* !_SYS_PIPE_H_ */