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.c85
1 files changed, 68 insertions, 17 deletions
diff --git a/sys/kern/sys_pipe.c b/sys/kern/sys_pipe.c
index 5782b60..838ff80 100644
--- a/sys/kern/sys_pipe.c
+++ b/sys/kern/sys_pipe.c
@@ -45,6 +45,28 @@
* happen for small transfers so that the system will not spend all of
* its time context switching. PIPE_SIZE is constrained by the
* amount of kernel virtual memory.
+ *
+ * In order to limit the resource use of pipes, three sysctls exist:
+ *
+ * kern.ipc.maxpipes - A limit on the total number of pipes in the system.
+ * Note that since pipes are bidirectional, the effective value is this
+ * number divided by two.
+ *
+ * kern.ipc.maxpipekva - This value limits the amount of pageable memory that
+ * can be used by pipes. Whenever the amount in use exceeds this value,
+ * all new pipes will be SMALL_PIPE_SIZE in size, rather than PIPE_SIZE.
+ * Big pipe creation will be limited as well.
+ *
+ * kern.ipc.maxpipekvawired - This value limits the amount of memory that may
+ * be wired in order to facilitate direct copies using page flipping.
+ * Whenever this value is exceeded, pipes will fall back to using regular
+ * copies.
+ *
+ * These values are autotuned in subr_param.c.
+ *
+ * Memory usage may be monitored through the sysctls
+ * kern.ipc.pipes, kern.ipc.pipekva and kern.ipc.pipekvawired.
+ *
*/
#include <sys/cdefs.h>
@@ -68,6 +90,7 @@ __FBSDID("$FreeBSD$");
#include <sys/poll.h>
#include <sys/selinfo.h>
#include <sys/signalvar.h>
+#include <sys/sysctl.h>
#include <sys/sysproto.h>
#include <sys/pipe.h>
#include <sys/proc.h>
@@ -148,24 +171,29 @@ static struct filterops pipe_wfiltops =
#define MAXPIPESIZE (2*PIPE_SIZE/3)
/*
- * Maximum amount of kva for pipes -- this is kind-of a soft limit, but
- * is there so that on large systems, we don't exhaust it.
- */
-#define MAXPIPEKVA (8*1024*1024)
-
-/*
- * Limit for direct transfers, we cannot, of course limit
- * the amount of kva for pipes in general though.
- */
-#define LIMITPIPEKVA (16*1024*1024)
-
-/*
* Limit the number of "big" pipes
*/
#define LIMITBIGPIPES 32
static int nbigpipe;
+static int amountpipes;
static int amountpipekva;
+static int amountpipekvawired;
+
+SYSCTL_DECL(_kern_ipc);
+
+SYSCTL_INT(_kern_ipc, OID_AUTO, maxpipes, CTLFLAG_RW,
+ &maxpipes, 0, "");
+SYSCTL_INT(_kern_ipc, OID_AUTO, maxpipekva, CTLFLAG_RW,
+ &maxpipekva, 0, "Pipe KVA limit");
+SYSCTL_INT(_kern_ipc, OID_AUTO, maxpipekvawired, CTLFLAG_RW,
+ &maxpipekvawired, 0, "Pipe KVA wired limit");
+SYSCTL_INT(_kern_ipc, OID_AUTO, pipes, CTLFLAG_RD,
+ &amountpipes, 0, "");
+SYSCTL_INT(_kern_ipc, OID_AUTO, pipekva, CTLFLAG_RD,
+ &amountpipekva, 0, "Pipe KVA usage");
+SYSCTL_INT(_kern_ipc, OID_AUTO, pipekvawired, CTLFLAG_RD,
+ &amountpipekvawired, 0, "Pipe wired KVA usage");
static void pipeinit(void *dummy __unused);
static void pipeclose(struct pipe *cpipe);
@@ -303,11 +331,19 @@ pipespace(cpipe, size)
struct vm_object *object;
caddr_t buffer;
int npages, error;
+ static int curfail = 0;
+ static struct timeval lastfail;
GIANT_REQUIRED;
KASSERT(cpipe->pipe_mtxp == NULL || !mtx_owned(PIPE_MTX(cpipe)),
("pipespace: pipe mutex locked"));
+ if (amountpipes > maxpipes) {
+ if (ppsratecheck(&lastfail, &curfail, 1))
+ printf("kern.maxpipes exceeded, please see tuning(7).\n");
+ return (ENOMEM);
+ }
+
npages = round_page(size)/PAGE_SIZE;
/*
* Create an object, I don't like the idea of paging to/from
@@ -339,6 +375,7 @@ pipespace(cpipe, size)
cpipe->pipe_buffer.in = 0;
cpipe->pipe_buffer.out = 0;
cpipe->pipe_buffer.cnt = 0;
+ atomic_add_int(&amountpipes, 1);
atomic_add_int(&amountpipekva, cpipe->pipe_buffer.size);
return (0);
}
@@ -385,7 +422,13 @@ pipe_create(cpipep)
#endif
cpipe->pipe_mtxp = NULL; /* avoid pipespace assertion */
- error = pipespace(cpipe, PIPE_SIZE);
+ /*
+ * Reduce to 1/4th pipe size if we're over our global max.
+ */
+ if (amountpipekva > maxpipekva)
+ error = pipespace(cpipe, SMALL_PIPE_SIZE);
+ else
+ error = pipespace(cpipe, PIPE_SIZE);
if (error)
return (error);
@@ -654,8 +697,11 @@ pipe_build_write_buffer(wpipe, uio)
int j;
vm_page_lock_queues();
- for (j = 0; j < i; j++)
+ for (j = 0; j < i; j++) {
vm_page_unwire(wpipe->pipe_map.ms[j], 1);
+ atomic_subtract_int(&amountpipekvawired,
+ PAGE_SIZE);
+ }
vm_page_unlock_queues();
return (EFAULT);
}
@@ -663,6 +709,7 @@ pipe_build_write_buffer(wpipe, uio)
m = PHYS_TO_VM_PAGE(paddr);
vm_page_lock_queues();
vm_page_wire(m);
+ atomic_add_int(&amountpipekvawired, PAGE_SIZE);
vm_page_unlock_queues();
wpipe->pipe_map.ms[i] = m;
}
@@ -719,7 +766,7 @@ pipe_destroy_write_buffer(wpipe)
if (wpipe->pipe_map.kva) {
pmap_qremove(wpipe->pipe_map.kva, wpipe->pipe_map.npages);
- if (amountpipekva > MAXPIPEKVA) {
+ if (amountpipekva > maxpipekva) {
vm_offset_t kva = wpipe->pipe_map.kva;
wpipe->pipe_map.kva = 0;
kmem_free(kernel_map, kva,
@@ -729,8 +776,10 @@ pipe_destroy_write_buffer(wpipe)
}
}
vm_page_lock_queues();
- for (i = 0; i < wpipe->pipe_map.npages; i++)
+ for (i = 0; i < wpipe->pipe_map.npages; i++) {
vm_page_unwire(wpipe->pipe_map.ms[i], 1);
+ atomic_subtract_int(&amountpipekvawired, PAGE_SIZE);
+ }
vm_page_unlock_queues();
wpipe->pipe_map.npages = 0;
}
@@ -904,6 +953,7 @@ pipe_write(fp, uio, active_cred, flags, td)
* so.
*/
if ((uio->uio_resid > PIPE_SIZE) &&
+ (amountpipekva < maxpipekva) &&
(nbigpipe < LIMITBIGPIPES) &&
(wpipe->pipe_state & PIPE_DIRECTW) == 0 &&
(wpipe->pipe_buffer.size <= PIPE_SIZE) &&
@@ -950,7 +1000,7 @@ pipe_write(fp, uio, active_cred, flags, td)
*/
if ((uio->uio_iov->iov_len >= PIPE_MINDIRECT) &&
(fp->f_flag & FNONBLOCK) == 0 &&
- (wpipe->pipe_map.kva || (amountpipekva < LIMITPIPEKVA)) &&
+ amountpipekvawired < maxpipekvawired &&
(uio->uio_iov->iov_len >= PIPE_MINDIRECT)) {
error = pipe_direct_write(wpipe, uio);
if (error)
@@ -1357,6 +1407,7 @@ pipe_free_kmem(cpipe)
if (cpipe->pipe_buffer.size > PIPE_SIZE)
--nbigpipe;
atomic_subtract_int(&amountpipekva, cpipe->pipe_buffer.size);
+ atomic_subtract_int(&amountpipes, 1);
kmem_free(kernel_map,
(vm_offset_t)cpipe->pipe_buffer.buffer,
cpipe->pipe_buffer.size);
OpenPOWER on IntegriCloud