diff options
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, 90 insertions, 51 deletions
diff --git a/sys/kern/kern_malloc.c b/sys/kern/kern_malloc.c index 6d9b775..1e97b55 100644 --- a/sys/kern/kern_malloc.c +++ b/sys/kern/kern_malloc.c @@ -828,11 +828,25 @@ sysctl_kern_malloc_stats(SYSCTL_HANDLER_ARGS) struct malloc_type_internal *mtip; struct malloc_type_header mth; struct malloc_type *mtp; - int error, i; + int buflen, count, 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. @@ -841,7 +855,11 @@ sysctl_kern_malloc_stats(SYSCTL_HANDLER_ARGS) mtsh.mtsh_version = MALLOC_TYPE_STREAM_VERSION; mtsh.mtsh_maxcpus = MAXCPU; mtsh.mtsh_count = kmemcount; - (void)sbuf_bcat(&sbuf, &mtsh, sizeof(mtsh)); + if (sbuf_bcat(&sbuf, &mtsh, sizeof(mtsh)) < 0) { + mtx_unlock(&malloc_mtx); + error = ENOMEM; + goto out; + } /* * Insert alternating sequence of type headers and type statistics. @@ -854,19 +872,30 @@ sysctl_kern_malloc_stats(SYSCTL_HANDLER_ARGS) */ bzero(&mth, sizeof(mth)); strlcpy(mth.mth_name, mtp->ks_shortdesc, MALLOC_MAX_NAME); - (void)sbuf_bcat(&sbuf, &mth, sizeof(mth)); + if (sbuf_bcat(&sbuf, &mth, sizeof(mth)) < 0) { + mtx_unlock(&malloc_mtx); + error = ENOMEM; + goto out; + } /* * Insert type statistics for each CPU. */ for (i = 0; i < MAXCPU; i++) { - (void)sbuf_bcat(&sbuf, &mtip->mti_stats[i], - sizeof(mtip->mti_stats[i])); + if (sbuf_bcat(&sbuf, &mtip->mti_stats[i], + sizeof(mtip->mti_stats[i])) < 0) { + mtx_unlock(&malloc_mtx); + error = ENOMEM; + goto out; + } } } mtx_unlock(&malloc_mtx); - error = sbuf_finish(&sbuf); + sbuf_finish(&sbuf); + error = SYSCTL_OUT(req, sbuf_data(&sbuf), sbuf_len(&sbuf)); +out: sbuf_delete(&sbuf); + free(buffer, M_TEMP); return (error); } @@ -976,19 +1005,26 @@ 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; - sbuf_new_for_sysctl(&sbuf, NULL, 128, req); + buf = malloc(bufsize, M_TEMP, M_WAITOK|M_ZERO); + sbuf_new(&sbuf, buf, bufsize, SBUF_FIXEDLEN); sbuf_printf(&sbuf, "\n Size Requests Real Size\n"); for (i = 0; i < KMEM_ZSIZE; i++) { @@ -1006,8 +1042,12 @@ 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); - error = sbuf_finish(&sbuf); + sbuf_finish(&sbuf); + + error = SYSCTL_OUT(req, sbuf_data(&sbuf), sbuf_len(&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 49ccc50..b83502c 100644 --- a/sys/kern/kern_sysctl.c +++ b/sys/kern/kern_sysctl.c @@ -51,7 +51,6 @@ __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> @@ -1545,30 +1544,3 @@ 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 530ebc5..0c97052 100644 --- a/sys/kern/subr_lock.c +++ b/sys/kern/subr_lock.c @@ -191,7 +191,8 @@ struct lock_prof_cpu *lp_cpu[MAXCPU]; volatile int lock_prof_enable = 0; static volatile int lock_prof_resetting; -#define LPROF_SBUF_SIZE 256 +/* SWAG: sbuf size = avg stat. line size * number of locks */ +#define LPROF_SBUF_SIZE 256 * 400 static int lock_prof_rejected; static int lock_prof_skipspin; @@ -383,6 +384,8 @@ 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_error(sb) != 0) + return; } } } @@ -390,11 +393,13 @@ 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; - sb = sbuf_new_for_sysctl(NULL, NULL, LPROF_SBUF_SIZE, req); +retry_sbufops: + sb = sbuf_new(NULL, NULL, LPROF_SBUF_SIZE * multiplier, SBUF_FIXEDLEN); 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; @@ -406,13 +411,16 @@ dump_lock_prof_stats(SYSCTL_HANDLER_ARGS) 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_error(sb) != 0) { + sbuf_delete(sb); + multiplier++; + goto retry_sbufops; + } } lock_prof_enable = enabled; - error = sbuf_finish(sb); - /* Output a trailing NUL. */ - if (error == 0) - error = SYSCTL_OUT(req, "", 1); + sbuf_finish(sb); + error = SYSCTL_OUT(req, sbuf_data(sb), sbuf_len(sb) + 1); sbuf_delete(sb); return (error); } diff --git a/sys/kern/subr_sbuf.c b/sys/kern/subr_sbuf.c index 0d083b4..e81faa5 100644 --- a/sys/kern/subr_sbuf.c +++ b/sys/kern/subr_sbuf.c @@ -303,8 +303,8 @@ sbuf_drain(struct sbuf *s) s->s_error = -len; return (s->s_error); } - KASSERT(len > 0 && len <= s->s_len, - ("Bad drain amount %d for sbuf %p", len, s)); + + KASSERT(len > 0, ("Drain must either error or work!")); 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 cdf7a47..b8be8f4 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 512 +#define SLEEPQ_SBUFSIZE (40 * 512) struct sleepq_prof { LIST_ENTRY(sleepq_prof) sp_link; const char *sp_wmesg; @@ -1123,13 +1123,15 @@ 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; - sb = sbuf_new_for_sysctl(NULL, NULL, SLEEPQ_SBUFSIZE, req); +retry_sbufops: + sb = sbuf_new(NULL, NULL, SLEEPQ_SBUFSIZE * multiplier, SBUF_FIXEDLEN); sbuf_printf(sb, "\nwmesg\tcount\n"); enabled = prof_enabled; mtx_lock_spin(&sleepq_prof_lock); @@ -1139,13 +1141,19 @@ dump_sleepq_prof_stats(SYSCTL_HANDLER_ARGS) LIST_FOREACH(sp, &sleepq_hash[i], sp_link) { sbuf_printf(sb, "%s\t%ld\n", sp->sp_wmesg, sp->sp_count); + if (sbuf_error(sb) != 0) { + sbuf_delete(sb); + multiplier++; + goto retry_sbufops; + } } } mtx_lock_spin(&sleepq_prof_lock); prof_enabled = enabled; mtx_unlock_spin(&sleepq_prof_lock); - error = sbuf_finish(sb); + sbuf_finish(sb); + error = SYSCTL_OUT(req, sbuf_data(sb), sbuf_len(sb) + 1); sbuf_delete(sb); return (error); } diff --git a/sys/kern/subr_witness.c b/sys/kern/subr_witness.c index 3fec4c4..e5aa8dca 100644 --- a/sys/kern/subr_witness.c +++ b/sys/kern/subr_witness.c @@ -154,7 +154,8 @@ __FBSDID("$FreeBSD$"); #define MAX_W_NAME 64 #define BADSTACK_SBUF_SIZE (256 * WITNESS_COUNT) -#define FULLGRAPH_SBUF_SIZE 512 +#define CYCLEGRAPH_SBUF_SIZE 8192 +#define FULLGRAPH_SBUF_SIZE 32768 /* * These flags go in the witness relationship matrix and describe the @@ -2544,7 +2545,7 @@ sysctl_debug_witness_fullgraph(SYSCTL_HANDLER_ARGS) return (error); } error = 0; - sb = sbuf_new_for_sysctl(NULL, NULL, FULLGRAPH_SBUF_SIZE, req); + sb = sbuf_new(NULL, NULL, FULLGRAPH_SBUF_SIZE, SBUF_FIXEDLEN); if (sb == NULL) return (ENOMEM); sbuf_printf(sb, "\n"); @@ -2557,9 +2558,19 @@ sysctl_debug_witness_fullgraph(SYSCTL_HANDLER_ARGS) mtx_unlock_spin(&w_mtx); /* + * While using SBUF_FIXEDLEN, check if the sbuf overflowed. + */ + if (sbuf_error(sb) != 0) { + sbuf_delete(sb); + panic("%s: sbuf overflowed, bump FULLGRAPH_SBUF_SIZE value\n", + __func__); + } + + /* * Close the sbuf and return to userland. */ - error = sbuf_finish(sb); + sbuf_finish(sb); + error = SYSCTL_OUT(req, sbuf_data(sb), sbuf_len(sb) + 1); sbuf_delete(sb); return (error); |