From 7fc649fc41274dcd3ffbed0d354a418b71e65786 Mon Sep 17 00:00:00 2001 From: mdf Date: Thu, 27 Jan 2011 00:34:12 +0000 Subject: Explicitly wire the user buffer rather than doing it implicitly in sbuf_new_for_sysctl(9). This allows using an sbuf with a SYSCTL_OUT drain for extremely large amounts of data where the caller knows that appropriate references are held, and sleeping is not an issue. Inspired by: rwatson --- sys/kern/kern_malloc.c | 6 ++++++ sys/kern/kern_sysctl.c | 6 ++---- sys/kern/subr_lock.c | 3 +++ sys/kern/subr_sleepqueue.c | 3 +++ sys/kern/subr_witness.c | 4 ++++ 5 files changed, 18 insertions(+), 4 deletions(-) (limited to 'sys/kern') diff --git a/sys/kern/kern_malloc.c b/sys/kern/kern_malloc.c index 9c7ff40..a3a9795 100644 --- a/sys/kern/kern_malloc.c +++ b/sys/kern/kern_malloc.c @@ -862,6 +862,9 @@ sysctl_kern_malloc_stats(SYSCTL_HANDLER_ARGS) int error, i; struct sbuf sbuf; + error = sysctl_wire_old_buffer(req, 0); + if (error != 0) + return (error); sbuf_new_for_sysctl(&sbuf, NULL, 128, req); mtx_lock(&malloc_mtx); @@ -1019,6 +1022,9 @@ sysctl_kern_mprof(SYSCTL_HANDLER_ARGS) waste = 0; mem = 0; + error = sysctl_wire_old_buffer(req, 0); + if (error != 0) + return (error); sbuf_new_for_sysctl(&sbuf, NULL, 128, req); sbuf_printf(&sbuf, "\n Size Requests Real Size\n"); diff --git a/sys/kern/kern_sysctl.c b/sys/kern/kern_sysctl.c index 7769a6d..cde8a0c 100644 --- a/sys/kern/kern_sysctl.c +++ b/sys/kern/kern_sysctl.c @@ -1591,7 +1591,8 @@ userland_sysctl(struct thread *td, int *name, u_int namelen, void *old, } /* - * Drain into a sysctl struct. The user buffer must be wired. + * Drain into a sysctl struct. The user buffer should be wired if a page + * fault would cause issue. */ static int sbuf_sysctl_drain(void *arg, const char *data, int len) @@ -1609,9 +1610,6 @@ sbuf_new_for_sysctl(struct sbuf *s, char *buf, int length, struct sysctl_req *req) { - /* Wire the user buffer, so we can write without blocking. */ - sysctl_wire_old_buffer(req, 0); - s = sbuf_new(s, buf, length, SBUF_FIXEDLEN); sbuf_set_drain(s, sbuf_sysctl_drain, req); return (s); diff --git a/sys/kern/subr_lock.c b/sys/kern/subr_lock.c index 25c1965..be9fa31 100644 --- a/sys/kern/subr_lock.c +++ b/sys/kern/subr_lock.c @@ -393,6 +393,9 @@ dump_lock_prof_stats(SYSCTL_HANDLER_ARGS) int error, cpu, t; int enabled; + error = sysctl_wire_old_buffer(req, 0); + if (error != 0) + return (error); sb = sbuf_new_for_sysctl(NULL, NULL, LPROF_SBUF_SIZE, req); sbuf_printf(sb, "\n%8s %9s %11s %11s %11s %6s %6s %2s %6s %s\n", "max", "wait_max", "total", "wait_total", "count", "avg", "wait_avg", "cnt_hold", "cnt_lock", "name"); diff --git a/sys/kern/subr_sleepqueue.c b/sys/kern/subr_sleepqueue.c index 5d1ae86..4ef7c48 100644 --- a/sys/kern/subr_sleepqueue.c +++ b/sys/kern/subr_sleepqueue.c @@ -1130,6 +1130,9 @@ dump_sleepq_prof_stats(SYSCTL_HANDLER_ARGS) int error; int i; + error = sysctl_wire_old_buffer(req, 0); + if (error != 0) + return (error); sb = sbuf_new_for_sysctl(NULL, NULL, SLEEPQ_SBUFSIZE, req); sbuf_printf(sb, "\nwmesg\tcount\n"); enabled = prof_enabled; diff --git a/sys/kern/subr_witness.c b/sys/kern/subr_witness.c index 3fec4c4..e1c00fe 100644 --- a/sys/kern/subr_witness.c +++ b/sys/kern/subr_witness.c @@ -2544,6 +2544,10 @@ sysctl_debug_witness_fullgraph(SYSCTL_HANDLER_ARGS) return (error); } error = 0; + + error = sysctl_wire_old_buffer(req, 0); + if (error != 0) + return (error); sb = sbuf_new_for_sysctl(NULL, NULL, FULLGRAPH_SBUF_SIZE, req); if (sb == NULL) return (ENOMEM); -- cgit v1.1