summaryrefslogtreecommitdiffstats
path: root/sys/kern
diff options
context:
space:
mode:
authormdf <mdf@FreeBSD.org>2010-09-13 18:48:23 +0000
committermdf <mdf@FreeBSD.org>2010-09-13 18:48:23 +0000
commit3ed6eac561ccce2958e668867ea38fd005bc635b (patch)
treeb0bd953f5f99c28abddea5f8c7bb39d837607940 /sys/kern
parent9a10f7c4328c6763a33844ed9635ef3c2a7f1e84 (diff)
downloadFreeBSD-src-3ed6eac561ccce2958e668867ea38fd005bc635b.zip
FreeBSD-src-3ed6eac561ccce2958e668867ea38fd005bc635b.tar.gz
Revert r212370, as it causes a LOR on powerpc. powerpc does a few
unexpected things in copyout(9) and so wiring the user buffer is not sufficient to perform a copyout(9) while holding a random mutex. Requested by: nwhitehorn
Diffstat (limited to 'sys/kern')
-rw-r--r--sys/kern/kern_malloc.c58
-rw-r--r--sys/kern/kern_sysctl.c28
-rw-r--r--sys/kern/subr_lock.c20
-rw-r--r--sys/kern/subr_sbuf.c4
-rw-r--r--sys/kern/subr_sleepqueue.c14
-rw-r--r--sys/kern/subr_witness.c17
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);
OpenPOWER on IntegriCloud