diff options
author | mdf <mdf@FreeBSD.org> | 2010-09-09 18:33:46 +0000 |
---|---|---|
committer | mdf <mdf@FreeBSD.org> | 2010-09-09 18:33:46 +0000 |
commit | bc5468425338dbee3cd3da7d6bc2a1290ba8d2ce (patch) | |
tree | fb245e2e8ce30565e64963b84e00c3b93d9bc280 /sys/kern | |
parent | a7b4070f1f143143442a97cffdf24fc59814851f (diff) | |
download | FreeBSD-src-bc5468425338dbee3cd3da7d6bc2a1290ba8d2ce.zip FreeBSD-src-bc5468425338dbee3cd3da7d6bc2a1290ba8d2ce.tar.gz |
Add a drain function for struct sysctl_req, and use it for a variety of
handlers, some of which had to do awkward things to get a large enough
FIXEDLEN buffer.
Note that some sysctl handlers were explicitly outputting a trailing NUL
byte. This behaviour was preserved, though it should not be necessary.
Reviewed by: phk
Diffstat (limited to 'sys/kern')
-rw-r--r-- | sys/kern/kern_malloc.c | 58 | ||||
-rw-r--r-- | sys/kern/kern_sysctl.c | 28 | ||||
-rw-r--r-- | sys/kern/subr_lock.c | 20 | ||||
-rw-r--r-- | sys/kern/subr_sbuf.c | 4 | ||||
-rw-r--r-- | sys/kern/subr_sleepqueue.c | 14 | ||||
-rw-r--r-- | sys/kern/subr_witness.c | 17 |
6 files changed, 51 insertions, 90 deletions
diff --git a/sys/kern/kern_malloc.c b/sys/kern/kern_malloc.c index 1e97b55..6d9b775 100644 --- a/sys/kern/kern_malloc.c +++ b/sys/kern/kern_malloc.c @@ -828,25 +828,11 @@ sysctl_kern_malloc_stats(SYSCTL_HANDLER_ARGS) struct malloc_type_internal *mtip; struct malloc_type_header mth; struct malloc_type *mtp; - int buflen, count, error, i; + int error, i; struct sbuf sbuf; - char *buffer; + sbuf_new_for_sysctl(&sbuf, NULL, 128, req); mtx_lock(&malloc_mtx); -restart: - mtx_assert(&malloc_mtx, MA_OWNED); - count = kmemcount; - mtx_unlock(&malloc_mtx); - buflen = sizeof(mtsh) + count * (sizeof(mth) + - sizeof(struct malloc_type_stats) * MAXCPU) + 1; - buffer = malloc(buflen, M_TEMP, M_WAITOK | M_ZERO); - mtx_lock(&malloc_mtx); - if (count < kmemcount) { - free(buffer, M_TEMP); - goto restart; - } - - sbuf_new(&sbuf, buffer, buflen, SBUF_FIXEDLEN); /* * Insert stream header. @@ -855,11 +841,7 @@ restart: mtsh.mtsh_version = MALLOC_TYPE_STREAM_VERSION; mtsh.mtsh_maxcpus = MAXCPU; mtsh.mtsh_count = kmemcount; - if (sbuf_bcat(&sbuf, &mtsh, sizeof(mtsh)) < 0) { - mtx_unlock(&malloc_mtx); - error = ENOMEM; - goto out; - } + (void)sbuf_bcat(&sbuf, &mtsh, sizeof(mtsh)); /* * Insert alternating sequence of type headers and type statistics. @@ -872,30 +854,19 @@ restart: */ bzero(&mth, sizeof(mth)); strlcpy(mth.mth_name, mtp->ks_shortdesc, MALLOC_MAX_NAME); - if (sbuf_bcat(&sbuf, &mth, sizeof(mth)) < 0) { - mtx_unlock(&malloc_mtx); - error = ENOMEM; - goto out; - } + (void)sbuf_bcat(&sbuf, &mth, sizeof(mth)); /* * Insert type statistics for each CPU. */ for (i = 0; i < MAXCPU; i++) { - if (sbuf_bcat(&sbuf, &mtip->mti_stats[i], - sizeof(mtip->mti_stats[i])) < 0) { - mtx_unlock(&malloc_mtx); - error = ENOMEM; - goto out; - } + (void)sbuf_bcat(&sbuf, &mtip->mti_stats[i], + sizeof(mtip->mti_stats[i])); } } mtx_unlock(&malloc_mtx); - sbuf_finish(&sbuf); - error = SYSCTL_OUT(req, sbuf_data(&sbuf), sbuf_len(&sbuf)); -out: + error = sbuf_finish(&sbuf); sbuf_delete(&sbuf); - free(buffer, M_TEMP); return (error); } @@ -1005,26 +976,19 @@ DB_SHOW_COMMAND(multizone_matches, db_show_multizone_matches) static int sysctl_kern_mprof(SYSCTL_HANDLER_ARGS) { - int linesize = 64; struct sbuf sbuf; uint64_t count; uint64_t waste; uint64_t mem; - int bufsize; int error; - char *buf; int rsize; int size; int i; - bufsize = linesize * (KMEM_ZSIZE + 1); - bufsize += 128; /* For the stats line */ - bufsize += 128; /* For the banner line */ waste = 0; mem = 0; - buf = malloc(bufsize, M_TEMP, M_WAITOK|M_ZERO); - sbuf_new(&sbuf, buf, bufsize, SBUF_FIXEDLEN); + sbuf_new_for_sysctl(&sbuf, NULL, 128, req); sbuf_printf(&sbuf, "\n Size Requests Real Size\n"); for (i = 0; i < KMEM_ZSIZE; i++) { @@ -1042,12 +1006,8 @@ sysctl_kern_mprof(SYSCTL_HANDLER_ARGS) sbuf_printf(&sbuf, "\nTotal memory used:\t%30llu\nTotal Memory wasted:\t%30llu\n", (unsigned long long)mem, (unsigned long long)waste); - sbuf_finish(&sbuf); - - error = SYSCTL_OUT(req, sbuf_data(&sbuf), sbuf_len(&sbuf)); - + error = sbuf_finish(&sbuf); sbuf_delete(&sbuf); - free(buf, M_TEMP); return (error); } diff --git a/sys/kern/kern_sysctl.c b/sys/kern/kern_sysctl.c index b83502c..49ccc50 100644 --- a/sys/kern/kern_sysctl.c +++ b/sys/kern/kern_sysctl.c @@ -51,6 +51,7 @@ __FBSDID("$FreeBSD$"); #include <sys/jail.h> #include <sys/lock.h> #include <sys/mutex.h> +#include <sys/sbuf.h> #include <sys/sx.h> #include <sys/sysproto.h> #include <sys/uio.h> @@ -1544,3 +1545,30 @@ userland_sysctl(struct thread *td, int *name, u_int namelen, void *old, } return (error); } + +/* + * Drain into a sysctl struct. The user buffer must be wired. + */ +static int +sbuf_sysctl_drain(void *arg, const char *data, int len) +{ + struct sysctl_req *req = arg; + int error; + + error = SYSCTL_OUT(req, data, len); + KASSERT(error >= 0, ("Got unexpected negative value %d", error)); + return (error == 0 ? len : -error); +} + +struct sbuf * +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 61263f9..530ebc5 100644 --- a/sys/kern/subr_lock.c +++ b/sys/kern/subr_lock.c @@ -191,8 +191,7 @@ struct lock_prof_cpu *lp_cpu[MAXCPU]; volatile int lock_prof_enable = 0; static volatile int lock_prof_resetting; -/* SWAG: sbuf size = avg stat. line size * number of locks */ -#define LPROF_SBUF_SIZE 256 * 400 +#define LPROF_SBUF_SIZE 256 static int lock_prof_rejected; static int lock_prof_skipspin; @@ -384,8 +383,6 @@ lock_prof_type_stats(struct lock_prof_type *type, struct sbuf *sb, int spin, continue; lock_prof_sum(l, &lp, i, spin, t); lock_prof_output(&lp, sb); - if (sbuf_overflowed(sb)) - return; } } } @@ -393,13 +390,11 @@ lock_prof_type_stats(struct lock_prof_type *type, struct sbuf *sb, int spin, static int dump_lock_prof_stats(SYSCTL_HANDLER_ARGS) { - static int multiplier = 1; struct sbuf *sb; int error, cpu, t; int enabled; -retry_sbufops: - sb = sbuf_new(NULL, NULL, LPROF_SBUF_SIZE * multiplier, SBUF_FIXEDLEN); + 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"); enabled = lock_prof_enable; @@ -411,16 +406,13 @@ retry_sbufops: continue; lock_prof_type_stats(&lp_cpu[cpu]->lpc_types[0], sb, 0, t); lock_prof_type_stats(&lp_cpu[cpu]->lpc_types[1], sb, 1, t); - if (sbuf_overflowed(sb)) { - sbuf_delete(sb); - multiplier++; - goto retry_sbufops; - } } lock_prof_enable = enabled; - sbuf_finish(sb); - error = SYSCTL_OUT(req, sbuf_data(sb), sbuf_len(sb) + 1); + error = sbuf_finish(sb); + /* Output a trailing NUL. */ + if (error == 0) + error = SYSCTL_OUT(req, "", 1); sbuf_delete(sb); return (error); } diff --git a/sys/kern/subr_sbuf.c b/sys/kern/subr_sbuf.c index d7b57a5..58964fb 100644 --- a/sys/kern/subr_sbuf.c +++ b/sys/kern/subr_sbuf.c @@ -305,8 +305,8 @@ sbuf_drain(struct sbuf *s) SBUF_SETFLAG(s, SBUF_OVERFLOWED); return (s->s_error); } - - KASSERT(len > 0, ("Drain must either error or work!")); + KASSERT(len > 0 && len <= s->s_len, + ("Bad drain amount %d for sbuf %p", len, s)); s->s_len -= len; /* * Fast path for the expected case where all the data was diff --git a/sys/kern/subr_sleepqueue.c b/sys/kern/subr_sleepqueue.c index cc20799..cdf7a47 100644 --- a/sys/kern/subr_sleepqueue.c +++ b/sys/kern/subr_sleepqueue.c @@ -1018,7 +1018,7 @@ sleepq_abort(struct thread *td, int intrval) #ifdef SLEEPQUEUE_PROFILING #define SLEEPQ_PROF_LOCATIONS 1024 -#define SLEEPQ_SBUFSIZE (40 * 512) +#define SLEEPQ_SBUFSIZE 512 struct sleepq_prof { LIST_ENTRY(sleepq_prof) sp_link; const char *sp_wmesg; @@ -1123,15 +1123,13 @@ reset_sleepq_prof_stats(SYSCTL_HANDLER_ARGS) static int dump_sleepq_prof_stats(SYSCTL_HANDLER_ARGS) { - static int multiplier = 1; struct sleepq_prof *sp; struct sbuf *sb; int enabled; int error; int i; -retry_sbufops: - sb = sbuf_new(NULL, NULL, SLEEPQ_SBUFSIZE * multiplier, SBUF_FIXEDLEN); + sb = sbuf_new_for_sysctl(NULL, NULL, SLEEPQ_SBUFSIZE, req); sbuf_printf(sb, "\nwmesg\tcount\n"); enabled = prof_enabled; mtx_lock_spin(&sleepq_prof_lock); @@ -1141,19 +1139,13 @@ retry_sbufops: LIST_FOREACH(sp, &sleepq_hash[i], sp_link) { sbuf_printf(sb, "%s\t%ld\n", sp->sp_wmesg, sp->sp_count); - if (sbuf_overflowed(sb)) { - sbuf_delete(sb); - multiplier++; - goto retry_sbufops; - } } } mtx_lock_spin(&sleepq_prof_lock); prof_enabled = enabled; mtx_unlock_spin(&sleepq_prof_lock); - sbuf_finish(sb); - error = SYSCTL_OUT(req, sbuf_data(sb), sbuf_len(sb) + 1); + error = sbuf_finish(sb); sbuf_delete(sb); return (error); } diff --git a/sys/kern/subr_witness.c b/sys/kern/subr_witness.c index 201be99..3fec4c4 100644 --- a/sys/kern/subr_witness.c +++ b/sys/kern/subr_witness.c @@ -154,8 +154,7 @@ __FBSDID("$FreeBSD$"); #define MAX_W_NAME 64 #define BADSTACK_SBUF_SIZE (256 * WITNESS_COUNT) -#define CYCLEGRAPH_SBUF_SIZE 8192 -#define FULLGRAPH_SBUF_SIZE 32768 +#define FULLGRAPH_SBUF_SIZE 512 /* * These flags go in the witness relationship matrix and describe the @@ -2545,7 +2544,7 @@ sysctl_debug_witness_fullgraph(SYSCTL_HANDLER_ARGS) return (error); } error = 0; - sb = sbuf_new(NULL, NULL, FULLGRAPH_SBUF_SIZE, SBUF_FIXEDLEN); + sb = sbuf_new_for_sysctl(NULL, NULL, FULLGRAPH_SBUF_SIZE, req); if (sb == NULL) return (ENOMEM); sbuf_printf(sb, "\n"); @@ -2558,19 +2557,9 @@ sysctl_debug_witness_fullgraph(SYSCTL_HANDLER_ARGS) mtx_unlock_spin(&w_mtx); /* - * While using SBUF_FIXEDLEN, check if the sbuf overflowed. - */ - if (sbuf_overflowed(sb)) { - sbuf_delete(sb); - panic("%s: sbuf overflowed, bump FULLGRAPH_SBUF_SIZE value\n", - __func__); - } - - /* * Close the sbuf and return to userland. */ - sbuf_finish(sb); - error = SYSCTL_OUT(req, sbuf_data(sb), sbuf_len(sb) + 1); + error = sbuf_finish(sb); sbuf_delete(sb); return (error); |