root/kern/kern_malloc.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. malloc
  2. free
  3. kmeminit_nkmempages
  4. kmeminit
  5. sysctl_malloc
  6. malloc_roundup
  7. malloc_printit

    1 /*      $OpenBSD: kern_malloc.c,v 1.70 2007/05/29 00:17:32 thib Exp $   */
    2 /*      $NetBSD: kern_malloc.c,v 1.15.4.2 1996/06/13 17:10:56 cgd Exp $ */
    3 
    4 /*
    5  * Copyright (c) 1987, 1991, 1993
    6  *      The Regents of the University of California.  All rights reserved.
    7  *
    8  * Redistribution and use in source and binary forms, with or without
    9  * modification, are permitted provided that the following conditions
   10  * are met:
   11  * 1. Redistributions of source code must retain the above copyright
   12  *    notice, this list of conditions and the following disclaimer.
   13  * 2. Redistributions in binary form must reproduce the above copyright
   14  *    notice, this list of conditions and the following disclaimer in the
   15  *    documentation and/or other materials provided with the distribution.
   16  * 3. Neither the name of the University nor the names of its contributors
   17  *    may be used to endorse or promote products derived from this software
   18  *    without specific prior written permission.
   19  *
   20  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   30  * SUCH DAMAGE.
   31  *
   32  *      @(#)kern_malloc.c       8.3 (Berkeley) 1/4/94
   33  */
   34 
   35 #include <sys/param.h>
   36 #include <sys/proc.h>
   37 #include <sys/kernel.h>
   38 #include <sys/malloc.h>
   39 #include <sys/systm.h>
   40 #include <sys/sysctl.h>
   41 #include <sys/time.h>
   42 #include <sys/rwlock.h>
   43 
   44 #include <uvm/uvm_extern.h>
   45 
   46 static struct vm_map kmem_map_store;
   47 struct vm_map *kmem_map = NULL;
   48 
   49 #ifdef NKMEMCLUSTERS
   50 #error NKMEMCLUSTERS is obsolete; remove it from your kernel config file and use NKMEMPAGES instead or let the kernel auto-size
   51 #endif
   52 
   53 /*
   54  * Default number of pages in kmem_map.  We attempt to calculate this
   55  * at run-time, but allow it to be either patched or set in the kernel
   56  * config file.
   57  */
   58 #ifndef NKMEMPAGES
   59 #define NKMEMPAGES      0
   60 #endif
   61 u_int   nkmempages = NKMEMPAGES;
   62 
   63 /*
   64  * Defaults for lower- and upper-bounds for the kmem_map page count.
   65  * Can be overridden by kernel config options.
   66  */
   67 #ifndef NKMEMPAGES_MIN
   68 #define NKMEMPAGES_MIN  NKMEMPAGES_MIN_DEFAULT
   69 #endif
   70 u_int   nkmempages_min = 0;
   71 
   72 #ifndef NKMEMPAGES_MAX
   73 #define NKMEMPAGES_MAX  NKMEMPAGES_MAX_DEFAULT
   74 #endif
   75 u_int   nkmempages_max = 0;
   76 
   77 struct kmembuckets bucket[MINBUCKET + 16];
   78 struct kmemstats kmemstats[M_LAST];
   79 struct kmemusage *kmemusage;
   80 char *kmembase, *kmemlimit;
   81 char buckstring[16 * sizeof("123456,")];
   82 int buckstring_init = 0;
   83 #if defined(KMEMSTATS) || defined(DIAGNOSTIC) || defined(FFS_SOFTUPDATES)
   84 char *memname[] = INITKMEMNAMES;
   85 char *memall = NULL;
   86 struct rwlock sysctl_kmemlock = RWLOCK_INITIALIZER("sysctlklk");
   87 #endif
   88 
   89 #ifdef DIAGNOSTIC
   90 /*
   91  * This structure provides a set of masks to catch unaligned frees.
   92  */
   93 const long addrmask[] = { 0,
   94         0x00000001, 0x00000003, 0x00000007, 0x0000000f,
   95         0x0000001f, 0x0000003f, 0x0000007f, 0x000000ff,
   96         0x000001ff, 0x000003ff, 0x000007ff, 0x00000fff,
   97         0x00001fff, 0x00003fff, 0x00007fff, 0x0000ffff,
   98 };
   99 
  100 /*
  101  * The WEIRD_ADDR is used as known text to copy into free objects so
  102  * that modifications after frees can be detected.
  103  */
  104 #ifdef DEADBEEF0
  105 #define WEIRD_ADDR      ((unsigned) DEADBEEF0)
  106 #else
  107 #define WEIRD_ADDR      ((unsigned) 0xdeadbeef)
  108 #endif
  109 #define MAX_COPY        32
  110 
  111 /*
  112  * Normally the freelist structure is used only to hold the list pointer
  113  * for free objects.  However, when running with diagnostics, the first
  114  * 8 bytes of the structure is unused except for diagnostic information,
  115  * and the free list pointer is at offset 8 in the structure.  Since the
  116  * first 8 bytes is the portion of the structure most often modified, this
  117  * helps to detect memory reuse problems and avoid free list corruption.
  118  */
  119 struct freelist {
  120         int32_t spare0;
  121         int16_t type;
  122         int16_t spare1;
  123         caddr_t next;
  124 };
  125 #else /* !DIAGNOSTIC */
  126 struct freelist {
  127         caddr_t next;
  128 };
  129 #endif /* DIAGNOSTIC */
  130 
  131 #ifndef SMALL_KERNEL
  132 struct timeval malloc_errintvl = { 5, 0 };
  133 struct timeval malloc_lasterr;
  134 #endif
  135 
  136 /*
  137  * Allocate a block of memory
  138  */
  139 void *
  140 malloc(unsigned long size, int type, int flags)
  141 {
  142         struct kmembuckets *kbp;
  143         struct kmemusage *kup;
  144         struct freelist *freep;
  145         long indx, npg, allocsize;
  146         int s;
  147         caddr_t va, cp, savedlist;
  148 #ifdef DIAGNOSTIC
  149         int32_t *end, *lp;
  150         int copysize;
  151         char *savedtype;
  152 #endif
  153 #ifdef KMEMSTATS
  154         struct kmemstats *ksp = &kmemstats[type];
  155 
  156         if (((unsigned long)type) >= M_LAST)
  157                 panic("malloc - bogus type");
  158 #endif
  159 
  160 #ifdef MALLOC_DEBUG
  161         if (debug_malloc(size, type, flags, (void **)&va))
  162                 return (va);
  163 #endif
  164 
  165         if (size > 65535 * PAGE_SIZE) {
  166                 if (flags & M_CANFAIL) {
  167 #ifndef SMALL_KERNEL
  168                         if (ratecheck(&malloc_lasterr, &malloc_errintvl))
  169                                 printf("malloc(): allocation too large, "
  170                                     "type = %d, size = %lu\n", type, size);
  171 #endif
  172                         return (NULL);
  173                 } else
  174                         panic("malloc: allocation too large");
  175         }
  176 
  177         indx = BUCKETINDX(size);
  178         kbp = &bucket[indx];
  179         s = splvm();
  180 #ifdef KMEMSTATS
  181         while (ksp->ks_memuse >= ksp->ks_limit) {
  182                 if (flags & M_NOWAIT) {
  183                         splx(s);
  184                         return (NULL);
  185                 }
  186                 if (ksp->ks_limblocks < 65535)
  187                         ksp->ks_limblocks++;
  188                 tsleep(ksp, PSWP+2, memname[type], 0);
  189         }
  190         ksp->ks_size |= 1 << indx;
  191 #endif
  192 #ifdef DIAGNOSTIC
  193         copysize = 1 << indx < MAX_COPY ? 1 << indx : MAX_COPY;
  194 #endif
  195         if (kbp->kb_next == NULL) {
  196                 kbp->kb_last = NULL;
  197                 if (size > MAXALLOCSAVE)
  198                         allocsize = round_page(size);
  199                 else
  200                         allocsize = 1 << indx;
  201                 npg = btoc(allocsize);
  202                 va = (caddr_t) uvm_km_kmemalloc(kmem_map, NULL,
  203                     (vsize_t)ctob(npg), 
  204                     ((flags & M_NOWAIT) ? UVM_KMF_NOWAIT : 0) |
  205                     ((flags & M_CANFAIL) ? UVM_KMF_CANFAIL : 0));
  206                 if (va == NULL) {
  207                         /*
  208                          * Kmem_malloc() can return NULL, even if it can
  209                          * wait, if there is no map space available, because
  210                          * it can't fix that problem.  Neither can we,
  211                          * right now.  (We should release pages which
  212                          * are completely free and which are in buckets
  213                          * with too many free elements.)
  214                          */
  215                         if ((flags & (M_NOWAIT|M_CANFAIL)) == 0)
  216                                 panic("malloc: out of space in kmem_map");
  217                         splx(s);
  218                         return (NULL);
  219                 }
  220 #ifdef KMEMSTATS
  221                 kbp->kb_total += kbp->kb_elmpercl;
  222 #endif
  223                 kup = btokup(va);
  224                 kup->ku_indx = indx;
  225                 if (allocsize > MAXALLOCSAVE) {
  226                         kup->ku_pagecnt = npg;
  227 #ifdef KMEMSTATS
  228                         ksp->ks_memuse += allocsize;
  229 #endif
  230                         goto out;
  231                 }
  232 #ifdef KMEMSTATS
  233                 kup->ku_freecnt = kbp->kb_elmpercl;
  234                 kbp->kb_totalfree += kbp->kb_elmpercl;
  235 #endif
  236                 /*
  237                  * Just in case we blocked while allocating memory,
  238                  * and someone else also allocated memory for this
  239                  * bucket, don't assume the list is still empty.
  240                  */
  241                 savedlist = kbp->kb_next;
  242                 kbp->kb_next = cp = va + (npg * PAGE_SIZE) - allocsize;
  243                 for (;;) {
  244                         freep = (struct freelist *)cp;
  245 #ifdef DIAGNOSTIC
  246                         /*
  247                          * Copy in known text to detect modification
  248                          * after freeing.
  249                          */
  250                         end = (int32_t *)&cp[copysize];
  251                         for (lp = (int32_t *)cp; lp < end; lp++)
  252                                 *lp = WEIRD_ADDR;
  253                         freep->type = M_FREE;
  254 #endif /* DIAGNOSTIC */
  255                         if (cp <= va)
  256                                 break;
  257                         cp -= allocsize;
  258                         freep->next = cp;
  259                 }
  260                 freep->next = savedlist;
  261                 if (kbp->kb_last == NULL)
  262                         kbp->kb_last = (caddr_t)freep;
  263         }
  264         va = kbp->kb_next;
  265         kbp->kb_next = ((struct freelist *)va)->next;
  266 #ifdef DIAGNOSTIC
  267         freep = (struct freelist *)va;
  268         savedtype = (unsigned)freep->type < M_LAST ?
  269                 memname[freep->type] : "???";
  270         if (kbp->kb_next) {
  271                 int rv;
  272                 vaddr_t addr = (vaddr_t)kbp->kb_next;
  273 
  274                 vm_map_lock(kmem_map);
  275                 rv = uvm_map_checkprot(kmem_map, addr,
  276                     addr + sizeof(struct freelist), VM_PROT_WRITE);
  277                 vm_map_unlock(kmem_map);
  278 
  279                 if (!rv)  {
  280                 printf("%s %d of object %p size 0x%lx %s %s (invalid addr %p)\n",
  281                         "Data modified on freelist: word", 
  282                         (int32_t *)&kbp->kb_next - (int32_t *)kbp, va, size,
  283                         "previous type", savedtype, kbp->kb_next);
  284                 kbp->kb_next = NULL;
  285                 }
  286         }
  287 
  288         /* Fill the fields that we've used with WEIRD_ADDR */
  289 #if BYTE_ORDER == BIG_ENDIAN
  290         freep->type = WEIRD_ADDR >> 16;
  291 #endif
  292 #if BYTE_ORDER == LITTLE_ENDIAN
  293         freep->type = (short)WEIRD_ADDR;
  294 #endif
  295         end = (int32_t *)&freep->next +
  296             (sizeof(freep->next) / sizeof(int32_t));
  297         for (lp = (int32_t *)&freep->next; lp < end; lp++)
  298                 *lp = WEIRD_ADDR;
  299 
  300         /* and check that the data hasn't been modified. */
  301         end = (int32_t *)&va[copysize];
  302         for (lp = (int32_t *)va; lp < end; lp++) {
  303                 if (*lp == WEIRD_ADDR)
  304                         continue;
  305                 printf("%s %d of object %p size 0x%lx %s %s (0x%x != 0x%x)\n",
  306                         "Data modified on freelist: word", lp - (int32_t *)va,
  307                         va, size, "previous type", savedtype, *lp, WEIRD_ADDR);
  308                 break;
  309         }
  310 
  311         freep->spare0 = 0;
  312 #endif /* DIAGNOSTIC */
  313 #ifdef KMEMSTATS
  314         kup = btokup(va);
  315         if (kup->ku_indx != indx)
  316                 panic("malloc: wrong bucket");
  317         if (kup->ku_freecnt == 0)
  318                 panic("malloc: lost data");
  319         kup->ku_freecnt--;
  320         kbp->kb_totalfree--;
  321         ksp->ks_memuse += 1 << indx;
  322 out:
  323         kbp->kb_calls++;
  324         ksp->ks_inuse++;
  325         ksp->ks_calls++;
  326         if (ksp->ks_memuse > ksp->ks_maxused)
  327                 ksp->ks_maxused = ksp->ks_memuse;
  328 #else
  329 out:
  330 #endif
  331         splx(s);
  332         return (va);
  333 }
  334 
  335 /*
  336  * Free a block of memory allocated by malloc.
  337  */
  338 void
  339 free(void *addr, int type)
  340 {
  341         struct kmembuckets *kbp;
  342         struct kmemusage *kup;
  343         struct freelist *freep;
  344         long size;
  345         int s;
  346 #ifdef DIAGNOSTIC
  347         caddr_t cp;
  348         int32_t *end, *lp;
  349         long alloc, copysize;
  350 #endif
  351 #ifdef KMEMSTATS
  352         struct kmemstats *ksp = &kmemstats[type];
  353 #endif
  354 
  355 #ifdef MALLOC_DEBUG
  356         if (debug_free(addr, type))
  357                 return;
  358 #endif
  359 
  360 #ifdef DIAGNOSTIC
  361         if (addr < (void *)kmembase || addr >= (void *)kmemlimit)
  362                 panic("free: non-malloced addr %p type %s", addr,
  363                     memname[type]);
  364 #endif
  365 
  366         kup = btokup(addr);
  367         size = 1 << kup->ku_indx;
  368         kbp = &bucket[kup->ku_indx];
  369         s = splvm();
  370 #ifdef DIAGNOSTIC
  371         /*
  372          * Check for returns of data that do not point to the
  373          * beginning of the allocation.
  374          */
  375         if (size > PAGE_SIZE)
  376                 alloc = addrmask[BUCKETINDX(PAGE_SIZE)];
  377         else
  378                 alloc = addrmask[kup->ku_indx];
  379         if (((u_long)addr & alloc) != 0)
  380                 panic("free: unaligned addr %p, size %ld, type %s, mask %ld",
  381                         addr, size, memname[type], alloc);
  382 #endif /* DIAGNOSTIC */
  383         if (size > MAXALLOCSAVE) {
  384                 uvm_km_free(kmem_map, (vaddr_t)addr, ctob(kup->ku_pagecnt));
  385 #ifdef KMEMSTATS
  386                 size = kup->ku_pagecnt << PGSHIFT;
  387                 ksp->ks_memuse -= size;
  388                 kup->ku_indx = 0;
  389                 kup->ku_pagecnt = 0;
  390                 if (ksp->ks_memuse + size >= ksp->ks_limit &&
  391                     ksp->ks_memuse < ksp->ks_limit)
  392                         wakeup(ksp);
  393                 ksp->ks_inuse--;
  394                 kbp->kb_total -= 1;
  395 #endif
  396                 splx(s);
  397                 return;
  398         }
  399         freep = (struct freelist *)addr;
  400 #ifdef DIAGNOSTIC
  401         /*
  402          * Check for multiple frees. Use a quick check to see if
  403          * it looks free before laboriously searching the freelist.
  404          */
  405         if (freep->spare0 == WEIRD_ADDR) {
  406                 for (cp = kbp->kb_next; cp;
  407                     cp = ((struct freelist *)cp)->next) {
  408                         if (addr != cp)
  409                                 continue;
  410                         printf("multiply freed item %p\n", addr);
  411                         panic("free: duplicated free");
  412                 }
  413         }
  414         /*
  415          * Copy in known text to detect modification after freeing
  416          * and to make it look free. Also, save the type being freed
  417          * so we can list likely culprit if modification is detected
  418          * when the object is reallocated.
  419          */
  420         copysize = size < MAX_COPY ? size : MAX_COPY;
  421         end = (int32_t *)&((caddr_t)addr)[copysize];
  422         for (lp = (int32_t *)addr; lp < end; lp++)
  423                 *lp = WEIRD_ADDR;
  424         freep->type = type;
  425 #endif /* DIAGNOSTIC */
  426 #ifdef KMEMSTATS
  427         kup->ku_freecnt++;
  428         if (kup->ku_freecnt >= kbp->kb_elmpercl) {
  429                 if (kup->ku_freecnt > kbp->kb_elmpercl)
  430                         panic("free: multiple frees");
  431                 else if (kbp->kb_totalfree > kbp->kb_highwat)
  432                         kbp->kb_couldfree++;
  433         }
  434         kbp->kb_totalfree++;
  435         ksp->ks_memuse -= size;
  436         if (ksp->ks_memuse + size >= ksp->ks_limit &&
  437             ksp->ks_memuse < ksp->ks_limit)
  438                 wakeup(ksp);
  439         ksp->ks_inuse--;
  440 #endif
  441         if (kbp->kb_next == NULL)
  442                 kbp->kb_next = addr;
  443         else
  444                 ((struct freelist *)kbp->kb_last)->next = addr;
  445         freep->next = NULL;
  446         kbp->kb_last = addr;
  447         splx(s);
  448 }
  449 
  450 /*
  451  * Compute the number of pages that kmem_map will map, that is,
  452  * the size of the kernel malloc arena.
  453  */
  454 void
  455 kmeminit_nkmempages(void)
  456 {
  457         u_int npages;
  458 
  459         if (nkmempages != 0) {
  460                 /*
  461                  * It's already been set (by us being here before, or
  462                  * by patching or kernel config options), bail out now.
  463                  */
  464                 return;
  465         }
  466 
  467         /*
  468          * We can't initialize these variables at compilation time, since
  469          * the page size may not be known (on sparc GENERIC kernels, for
  470          * example). But we still want the MD code to be able to provide
  471          * better values.
  472          */
  473         if (nkmempages_min == 0)
  474                 nkmempages_min = NKMEMPAGES_MIN;
  475         if (nkmempages_max == 0)
  476                 nkmempages_max = NKMEMPAGES_MAX;
  477 
  478         /*
  479          * We use the following (simple) formula:
  480          *
  481          *      - Starting point is physical memory / 4.
  482          *
  483          *      - Clamp it down to nkmempages_max.
  484          *
  485          *      - Round it up to nkmempages_min.
  486          */
  487         npages = physmem / 4;
  488 
  489         if (npages > nkmempages_max)
  490                 npages = nkmempages_max;
  491 
  492         if (npages < nkmempages_min)
  493                 npages = nkmempages_min;
  494 
  495         nkmempages = npages;
  496 }
  497 
  498 /*
  499  * Initialize the kernel memory allocator
  500  */
  501 void
  502 kmeminit(void)
  503 {
  504         vaddr_t base, limit;
  505 #ifdef KMEMSTATS
  506         long indx;
  507 #endif
  508 
  509 #ifdef DIAGNOSTIC
  510         if (sizeof(struct freelist) > (1 << MINBUCKET))
  511                 panic("kmeminit: minbucket too small/struct freelist too big");
  512 #endif
  513 
  514         /*
  515          * Compute the number of kmem_map pages, if we have not
  516          * done so already.
  517          */
  518         kmeminit_nkmempages();
  519         base = vm_map_min(kernel_map);
  520         kmem_map = uvm_km_suballoc(kernel_map, &base, &limit,
  521             (vsize_t)(nkmempages * PAGE_SIZE), VM_MAP_INTRSAFE, FALSE,
  522             &kmem_map_store);
  523         kmembase = (char *)base;
  524         kmemlimit = (char *)limit;
  525         kmemusage = (struct kmemusage *) uvm_km_zalloc(kernel_map,
  526                 (vsize_t)(nkmempages * sizeof(struct kmemusage)));
  527 #ifdef KMEMSTATS
  528         for (indx = 0; indx < MINBUCKET + 16; indx++) {
  529                 if (1 << indx >= PAGE_SIZE)
  530                         bucket[indx].kb_elmpercl = 1;
  531                 else
  532                         bucket[indx].kb_elmpercl = PAGE_SIZE / (1 << indx);
  533                 bucket[indx].kb_highwat = 5 * bucket[indx].kb_elmpercl;
  534         }
  535         for (indx = 0; indx < M_LAST; indx++)
  536                 kmemstats[indx].ks_limit = nkmempages * PAGE_SIZE * 6 / 10;
  537 #endif
  538 #ifdef MALLOC_DEBUG
  539         debug_malloc_init();
  540 #endif
  541 }
  542 
  543 /*
  544  * Return kernel malloc statistics information.
  545  */
  546 int
  547 sysctl_malloc(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp,
  548     size_t newlen, struct proc *p)
  549 {
  550         struct kmembuckets kb;
  551         int i, siz;
  552 
  553         if (namelen != 2 && name[0] != KERN_MALLOC_BUCKETS &&
  554             name[0] != KERN_MALLOC_KMEMNAMES)
  555                 return (ENOTDIR);               /* overloaded */
  556 
  557         switch (name[0]) {
  558         case KERN_MALLOC_BUCKETS:
  559                 /* Initialize the first time */
  560                 if (buckstring_init == 0) {
  561                         buckstring_init = 1;
  562                         bzero(buckstring, sizeof(buckstring));
  563                         for (siz = 0, i = MINBUCKET; i < MINBUCKET + 16; i++) {
  564                                 snprintf(buckstring + siz,
  565                                     sizeof buckstring - siz,
  566                                     "%d,", (u_int)(1<<i));
  567                                 siz += strlen(buckstring + siz);
  568                         }
  569                         /* Remove trailing comma */
  570                         if (siz)
  571                                 buckstring[siz - 1] = '\0';
  572                 }
  573                 return (sysctl_rdstring(oldp, oldlenp, newp, buckstring));
  574 
  575         case KERN_MALLOC_BUCKET:
  576                 bcopy(&bucket[BUCKETINDX(name[1])], &kb, sizeof(kb));
  577                 kb.kb_next = kb.kb_last = 0;
  578                 return (sysctl_rdstruct(oldp, oldlenp, newp, &kb, sizeof(kb)));
  579         case KERN_MALLOC_KMEMSTATS:
  580 #ifdef KMEMSTATS
  581                 if ((name[1] < 0) || (name[1] >= M_LAST))
  582                         return (EINVAL);
  583                 return (sysctl_rdstruct(oldp, oldlenp, newp,
  584                     &kmemstats[name[1]], sizeof(struct kmemstats)));
  585 #else
  586                 return (EOPNOTSUPP);
  587 #endif
  588         case KERN_MALLOC_KMEMNAMES:
  589 #if defined(KMEMSTATS) || defined(DIAGNOSTIC) || defined(FFS_SOFTUPDATES)
  590                 if (memall == NULL) {
  591                         int totlen;
  592 
  593                         i = rw_enter(&sysctl_kmemlock, RW_WRITE|RW_INTR);
  594                         if (i)
  595                                 return (i);
  596 
  597                         /* Figure out how large a buffer we need */
  598                         for (totlen = 0, i = 0; i < M_LAST; i++) {
  599                                 if (memname[i])
  600                                         totlen += strlen(memname[i]);
  601                                 totlen++;
  602                         }
  603                         memall = malloc(totlen + M_LAST, M_SYSCTL, M_WAITOK);
  604                         bzero(memall, totlen + M_LAST);
  605                         for (siz = 0, i = 0; i < M_LAST; i++) {
  606                                 snprintf(memall + siz, 
  607                                     totlen + M_LAST - siz,
  608                                     "%s,", memname[i] ? memname[i] : "");
  609                                 siz += strlen(memall + siz);
  610                         }
  611                         /* Remove trailing comma */
  612                         if (siz)
  613                                 memall[siz - 1] = '\0';
  614 
  615                         /* Now, convert all spaces to underscores */
  616                         for (i = 0; i < totlen; i++)
  617                                 if (memall[i] == ' ')
  618                                         memall[i] = '_';
  619                         rw_exit_write(&sysctl_kmemlock);
  620                 }
  621                 return (sysctl_rdstring(oldp, oldlenp, newp, memall));
  622 #else
  623                 return (EOPNOTSUPP);
  624 #endif
  625         default:
  626                 return (EOPNOTSUPP);
  627         }
  628         /* NOTREACHED */
  629 }
  630 
  631 /*
  632  * Round up a size to how much malloc would actually allocate.
  633  */
  634 size_t
  635 malloc_roundup(size_t sz)
  636 {
  637         if (sz > MAXALLOCSAVE)
  638                 return round_page(sz);
  639 
  640         return (1 << BUCKETINDX(sz));
  641 }
  642 
  643 #if defined(DDB)
  644 #include <machine/db_machdep.h>
  645 #include <ddb/db_interface.h>
  646 #include <ddb/db_output.h>
  647 
  648 void
  649 malloc_printit(int (*pr)(const char *, ...))
  650 {
  651 #ifdef KMEMSTATS
  652         struct kmemstats *km;
  653         int i;
  654 
  655         (*pr)("%15s %5s  %6s  %7s  %6s %9s %8s %8s\n",
  656             "Type", "InUse", "MemUse", "HighUse", "Limit", "Requests",
  657             "Type Lim", "Kern Lim");
  658         for (i = 0, km = kmemstats; i < M_LAST; i++, km++) {
  659                 if (!km->ks_calls || !memname[i])
  660                         continue;
  661 
  662                 (*pr)("%15s %5ld %6ldK %7ldK %6ldK %9ld %8d %8d\n",
  663                     memname[i], km->ks_inuse, km->ks_memuse / 1024,
  664                     km->ks_maxused / 1024, km->ks_limit / 1024, 
  665                     km->ks_calls, km->ks_limblocks, km->ks_mapblocks);
  666         }
  667 #else
  668         (*pr)("No KMEMSTATS compiled in\n");
  669 #endif
  670 }
  671 #endif /* DDB */

/* [<][>][^][v][top][bottom][index][help] */