diff options
author | mdf <mdf@FreeBSD.org> | 2010-09-13 18:48:23 +0000 |
---|---|---|
committer | mdf <mdf@FreeBSD.org> | 2010-09-13 18:48:23 +0000 |
commit | 3ed6eac561ccce2958e668867ea38fd005bc635b (patch) | |
tree | b0bd953f5f99c28abddea5f8c7bb39d837607940 /sys/kern/kern_malloc.c | |
parent | 9a10f7c4328c6763a33844ed9635ef3c2a7f1e84 (diff) | |
download | FreeBSD-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/kern_malloc.c')
-rw-r--r-- | sys/kern/kern_malloc.c | 58 |
1 files changed, 49 insertions, 9 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); } |