Annotation of Gnu-Mach/kern/slab.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * Copyright (c) 2011 Free Software Foundation.
        !             3:  *
        !             4:  * This program is free software; you can redistribute it and/or modify
        !             5:  * it under the terms of the GNU General Public License as published by
        !             6:  * the Free Software Foundation; either version 2 of the License, or
        !             7:  * (at your option) any later version.
        !             8:  *
        !             9:  * This program is distributed in the hope that it will be useful,
        !            10:  * but WITHOUT ANY WARRANTY; without even the implied warranty of
        !            11:  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
        !            12:  * GNU General Public License for more details.
        !            13:  *
        !            14:  * You should have received a copy of the GNU General Public License along
        !            15:  * with this program; if not, write to the Free Software Foundation, Inc.,
        !            16:  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
        !            17:  */
        !            18: 
        !            19: /*
        !            20:  * Copyright (c) 2010, 2011 Richard Braun.
        !            21:  * All rights reserved.
        !            22:  *
        !            23:  * Redistribution and use in source and binary forms, with or without
        !            24:  * modification, are permitted provided that the following conditions
        !            25:  * are met:
        !            26:  * 1. Redistributions of source code must retain the above copyright
        !            27:  *    notice, this list of conditions and the following disclaimer.
        !            28:  * 2. Redistributions in binary form must reproduce the above copyright
        !            29:  *    notice, this list of conditions and the following disclaimer in the
        !            30:  *    documentation and/or other materials provided with the distribution.
        !            31:  *
        !            32:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
        !            33:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
        !            34:  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
        !            35:  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
        !            36:  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
        !            37:  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
        !            38:  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
        !            39:  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
        !            40:  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
        !            41:  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
        !            42:  *
        !            43:  *
        !            44:  * Object caching and general purpose memory allocator.
        !            45:  *
        !            46:  * This allocator is based on the paper "The Slab Allocator: An Object-Caching
        !            47:  * Kernel Memory Allocator" by Jeff Bonwick.
        !            48:  *
        !            49:  * It allows the allocation of objects (i.e. fixed-size typed buffers) from
        !            50:  * caches and is efficient in both space and time. This implementation follows
        !            51:  * many of the indications from the paper mentioned. The most notable
        !            52:  * differences are outlined below.
        !            53:  *
        !            54:  * The per-cache self-scaling hash table for buffer-to-bufctl conversion,
        !            55:  * described in 3.2.3 "Slab Layout for Large Objects", has been replaced by
        !            56:  * a red-black tree storing slabs, sorted by address. The use of a
        !            57:  * self-balancing tree for buffer-to-slab conversions provides a few advantages
        !            58:  * over a hash table. Unlike a hash table, a BST provides a "lookup nearest"
        !            59:  * operation, so obtaining the slab data (whether it is embedded in the slab or
        !            60:  * off slab) from a buffer address simply consists of a "lookup nearest towards
        !            61:  * 0" tree search. Storing slabs instead of buffers also considerably reduces
        !            62:  * the number of elements to retain. Finally, a self-balancing tree is a true
        !            63:  * self-scaling data structure, whereas a hash table requires periodic
        !            64:  * maintenance and complete resizing, which is expensive. The only drawback is
        !            65:  * that releasing a buffer to the slab layer takes logarithmic time instead of
        !            66:  * constant time. But as the data set size is kept reasonable (because slabs
        !            67:  * are stored instead of buffers) and because the CPU pool layer services most
        !            68:  * requests, avoiding many accesses to the slab layer, it is considered an
        !            69:  * acceptable tradeoff.
        !            70:  *
        !            71:  * This implementation uses per-cpu pools of objects, which service most
        !            72:  * allocation requests. These pools act as caches (but are named differently
        !            73:  * to avoid confusion with CPU caches) that reduce contention on multiprocessor
        !            74:  * systems. When a pool is empty and cannot provide an object, it is filled by
        !            75:  * transferring multiple objects from the slab layer. The symmetric case is
        !            76:  * handled likewise.
        !            77:  */
        !            78: 
        !            79: #include <string.h>
        !            80: #include <kern/assert.h>
        !            81: #include <kern/mach_clock.h>
        !            82: #include <kern/printf.h>
        !            83: #include <kern/slab.h>
        !            84: #include <kern/kalloc.h>
        !            85: #include <kern/cpu_number.h>
        !            86: #include <mach/vm_param.h>
        !            87: #include <mach/machine/vm_types.h>
        !            88: #include <vm/vm_kern.h>
        !            89: #include <vm/vm_types.h>
        !            90: #include <sys/types.h>
        !            91: 
        !            92: #ifdef MACH_DEBUG
        !            93: #include <mach_debug/slab_info.h>
        !            94: #endif
        !            95: 
        !            96: /*
        !            97:  * Utility macros.
        !            98:  */
        !            99: #define ARRAY_SIZE(x)   (sizeof(x) / sizeof((x)[0]))
        !           100: #define P2ALIGNED(x, a) (((x) & ((a) - 1)) == 0)
        !           101: #define ISP2(x)         P2ALIGNED(x, x)
        !           102: #define P2ALIGN(x, a)   ((x) & -(a))
        !           103: #define P2ROUND(x, a)   (-(-(x) & -(a)))
        !           104: #define P2END(x, a)     (-(~(x) & -(a)))
        !           105: #define likely(expr)    __builtin_expect(!!(expr), 1)
        !           106: #define unlikely(expr)  __builtin_expect(!!(expr), 0)
        !           107: 
        !           108: /*
        !           109:  * Minimum required alignment.
        !           110:  */
        !           111: #define KMEM_ALIGN_MIN 8
        !           112: 
        !           113: /*
        !           114:  * Minimum number of buffers per slab.
        !           115:  *
        !           116:  * This value is ignored when the slab size exceeds a threshold.
        !           117:  */
        !           118: #define KMEM_MIN_BUFS_PER_SLAB 8
        !           119: 
        !           120: /*
        !           121:  * Special slab size beyond which the minimum number of buffers per slab is
        !           122:  * ignored when computing the slab size of a cache.
        !           123:  */
        !           124: #define KMEM_SLAB_SIZE_THRESHOLD (8 * PAGE_SIZE)
        !           125: 
        !           126: /*
        !           127:  * Special buffer size under which slab data is unconditionnally allocated
        !           128:  * from its associated slab.
        !           129:  */
        !           130: #define KMEM_BUF_SIZE_THRESHOLD (PAGE_SIZE / 8)
        !           131: 
        !           132: /*
        !           133:  * Time (in ticks) between two garbage collection operations.
        !           134:  */
        !           135: #define KMEM_GC_INTERVAL (5 * hz)
        !           136: 
        !           137: /*
        !           138:  * The transfer size of a CPU pool is computed by dividing the pool size by
        !           139:  * this value.
        !           140:  */
        !           141: #define KMEM_CPU_POOL_TRANSFER_RATIO 2
        !           142: 
        !           143: /*
        !           144:  * Redzone guard word.
        !           145:  */
        !           146: #ifdef __LP64__
        !           147: #if _HOST_BIG_ENDIAN
        !           148: #define KMEM_REDZONE_WORD 0xfeedfacefeedfaceUL
        !           149: #else /* _HOST_BIG_ENDIAN */
        !           150: #define KMEM_REDZONE_WORD 0xcefaedfecefaedfeUL
        !           151: #endif /* _HOST_BIG_ENDIAN */
        !           152: #else /* __LP64__ */
        !           153: #if _HOST_BIG_ENDIAN
        !           154: #define KMEM_REDZONE_WORD 0xfeedfaceUL
        !           155: #else /* _HOST_BIG_ENDIAN */
        !           156: #define KMEM_REDZONE_WORD 0xcefaedfeUL
        !           157: #endif /* _HOST_BIG_ENDIAN */
        !           158: #endif /* __LP64__ */
        !           159: 
        !           160: /*
        !           161:  * Redzone byte for padding.
        !           162:  */
        !           163: #define KMEM_REDZONE_BYTE 0xbb
        !           164: 
        !           165: /*
        !           166:  * Size of the VM submap from which default backend functions allocate.
        !           167:  */
        !           168: #define KMEM_MAP_SIZE (128 * 1024 * 1024)
        !           169: 
        !           170: /*
        !           171:  * Shift for the first kalloc cache size.
        !           172:  */
        !           173: #define KALLOC_FIRST_SHIFT 5
        !           174: 
        !           175: /*
        !           176:  * Number of caches backing general purpose allocations.
        !           177:  */
        !           178: #define KALLOC_NR_CACHES 13
        !           179: 
        !           180: /*
        !           181:  * Values the buftag state member can take.
        !           182:  */
        !           183: #ifdef __LP64__
        !           184: #if _HOST_BIG_ENDIAN
        !           185: #define KMEM_BUFTAG_ALLOC   0xa110c8eda110c8edUL
        !           186: #define KMEM_BUFTAG_FREE    0xf4eeb10cf4eeb10cUL
        !           187: #else /* _HOST_BIG_ENDIAN */
        !           188: #define KMEM_BUFTAG_ALLOC   0xedc810a1edc810a1UL
        !           189: #define KMEM_BUFTAG_FREE    0x0cb1eef40cb1eef4UL
        !           190: #endif /* _HOST_BIG_ENDIAN */
        !           191: #else /* __LP64__ */
        !           192: #if _HOST_BIG_ENDIAN
        !           193: #define KMEM_BUFTAG_ALLOC   0xa110c8edUL
        !           194: #define KMEM_BUFTAG_FREE    0xf4eeb10cUL
        !           195: #else /* _HOST_BIG_ENDIAN */
        !           196: #define KMEM_BUFTAG_ALLOC   0xedc810a1UL
        !           197: #define KMEM_BUFTAG_FREE    0x0cb1eef4UL
        !           198: #endif /* _HOST_BIG_ENDIAN */
        !           199: #endif /* __LP64__ */
        !           200: 
        !           201: /*
        !           202:  * Free and uninitialized patterns.
        !           203:  *
        !           204:  * These values are unconditionnally 64-bit wide since buffers are at least
        !           205:  * 8-byte aligned.
        !           206:  */
        !           207: #if _HOST_BIG_ENDIAN
        !           208: #define KMEM_FREE_PATTERN   0xdeadbeefdeadbeefULL
        !           209: #define KMEM_UNINIT_PATTERN 0xbaddcafebaddcafeULL
        !           210: #else /* _HOST_BIG_ENDIAN */
        !           211: #define KMEM_FREE_PATTERN   0xefbeaddeefbeaddeULL
        !           212: #define KMEM_UNINIT_PATTERN 0xfecaddbafecaddbaULL
        !           213: #endif /* _HOST_BIG_ENDIAN */
        !           214: 
        !           215: /*
        !           216:  * Cache flags.
        !           217:  *
        !           218:  * The flags don't change once set and can be tested without locking.
        !           219:  */
        !           220: #define KMEM_CF_NO_CPU_POOL     0x01    /* CPU pool layer disabled */
        !           221: #define KMEM_CF_SLAB_EXTERNAL   0x02    /* Slab data is off slab */
        !           222: #define KMEM_CF_NO_RECLAIM      0x04    /* Slabs are not reclaimable */
        !           223: #define KMEM_CF_VERIFY          0x08    /* Debugging facilities enabled */
        !           224: #define KMEM_CF_DIRECT          0x10    /* No buf-to-slab tree lookup */
        !           225: 
        !           226: /*
        !           227:  * Options for kmem_cache_alloc_verify().
        !           228:  */
        !           229: #define KMEM_AV_NOCONSTRUCT 0
        !           230: #define KMEM_AV_CONSTRUCT   1
        !           231: 
        !           232: /*
        !           233:  * Error codes for kmem_cache_error().
        !           234:  */
        !           235: #define KMEM_ERR_INVALID    0   /* Invalid address being freed */
        !           236: #define KMEM_ERR_DOUBLEFREE 1   /* Freeing already free address */
        !           237: #define KMEM_ERR_BUFTAG     2   /* Invalid buftag content */
        !           238: #define KMEM_ERR_MODIFIED   3   /* Buffer modified while free */
        !           239: #define KMEM_ERR_REDZONE    4   /* Redzone violation */
        !           240: 
        !           241: #if SLAB_USE_CPU_POOLS
        !           242: /*
        !           243:  * Available CPU pool types.
        !           244:  *
        !           245:  * For each entry, the CPU pool size applies from the entry buf_size
        !           246:  * (excluded) up to (and including) the buf_size of the preceding entry.
        !           247:  *
        !           248:  * See struct kmem_cpu_pool_type for a description of the values.
        !           249:  */
        !           250: static struct kmem_cpu_pool_type kmem_cpu_pool_types[] = {
        !           251:     {  32768,   1, 0,           NULL },
        !           252:     {   4096,   8, CPU_L1_SIZE, NULL },
        !           253:     {    256,  64, CPU_L1_SIZE, NULL },
        !           254:     {      0, 128, CPU_L1_SIZE, NULL }
        !           255: };
        !           256: 
        !           257: /*
        !           258:  * Caches where CPU pool arrays are allocated from.
        !           259:  */
        !           260: static struct kmem_cache kmem_cpu_array_caches[ARRAY_SIZE(kmem_cpu_pool_types)];
        !           261: #endif /* SLAB_USE_CPU_POOLS */
        !           262: 
        !           263: /*
        !           264:  * Cache for off slab data.
        !           265:  */
        !           266: static struct kmem_cache kmem_slab_cache;
        !           267: 
        !           268: /*
        !           269:  * General purpose caches array.
        !           270:  */
        !           271: static struct kmem_cache kalloc_caches[KALLOC_NR_CACHES];
        !           272: 
        !           273: /*
        !           274:  * List of all caches managed by the allocator.
        !           275:  */
        !           276: static struct list kmem_cache_list;
        !           277: static unsigned int kmem_nr_caches;
        !           278: static simple_lock_data_t __attribute__((used)) kmem_cache_list_lock;
        !           279: 
        !           280: /*
        !           281:  * VM submap for slab caches.
        !           282:  */
        !           283: static struct vm_map kmem_map_store;
        !           284: vm_map_t kmem_map = &kmem_map_store;
        !           285: 
        !           286: /*
        !           287:  * Time of the last memory reclaim, in clock ticks.
        !           288:  */
        !           289: static unsigned long kmem_gc_last_tick;
        !           290: 
        !           291: #define kmem_error(format, ...)                         \
        !           292:     printf("mem: error: %s(): " format "\n", __func__,  \
        !           293:            ## __VA_ARGS__)
        !           294: 
        !           295: #define kmem_warn(format, ...)                              \
        !           296:     printf("mem: warning: %s(): " format "\n", __func__,    \
        !           297:            ## __VA_ARGS__)
        !           298: 
        !           299: #define kmem_print(format, ...) \
        !           300:     printf(format "\n", ## __VA_ARGS__)
        !           301: 
        !           302: static void kmem_cache_error(struct kmem_cache *cache, void *buf, int error,
        !           303:                              void *arg);
        !           304: static void * kmem_cache_alloc_from_slab(struct kmem_cache *cache);
        !           305: static void kmem_cache_free_to_slab(struct kmem_cache *cache, void *buf);
        !           306: 
        !           307: static void * kmem_buf_verify_bytes(void *buf, void *pattern, size_t size)
        !           308: {
        !           309:     char *ptr, *pattern_ptr, *end;
        !           310: 
        !           311:     end = buf + size;
        !           312: 
        !           313:     for (ptr = buf, pattern_ptr = pattern; ptr < end; ptr++, pattern_ptr++)
        !           314:         if (*ptr != *pattern_ptr)
        !           315:             return ptr;
        !           316: 
        !           317:     return NULL;
        !           318: }
        !           319: 
        !           320: static void * kmem_buf_verify(void *buf, uint64_t pattern, vm_size_t size)
        !           321: {
        !           322:     uint64_t *ptr, *end;
        !           323: 
        !           324:     assert(P2ALIGNED((unsigned long)buf, sizeof(uint64_t)));
        !           325:     assert(P2ALIGNED(size, sizeof(uint64_t)));
        !           326: 
        !           327:     end = buf + size;
        !           328: 
        !           329:     for (ptr = buf; ptr < end; ptr++)
        !           330:         if (*ptr != pattern)
        !           331:             return kmem_buf_verify_bytes(ptr, &pattern, sizeof(pattern));
        !           332: 
        !           333:     return NULL;
        !           334: }
        !           335: 
        !           336: static void kmem_buf_fill(void *buf, uint64_t pattern, size_t size)
        !           337: {
        !           338:     uint64_t *ptr, *end;
        !           339: 
        !           340:     assert(P2ALIGNED((unsigned long)buf, sizeof(uint64_t)));
        !           341:     assert(P2ALIGNED(size, sizeof(uint64_t)));
        !           342: 
        !           343:     end = buf + size;
        !           344: 
        !           345:     for (ptr = buf; ptr < end; ptr++)
        !           346:         *ptr = pattern;
        !           347: }
        !           348: 
        !           349: static void * kmem_buf_verify_fill(void *buf, uint64_t old, uint64_t new,
        !           350:                                    size_t size)
        !           351: {
        !           352:     uint64_t *ptr, *end;
        !           353: 
        !           354:     assert(P2ALIGNED((unsigned long)buf, sizeof(uint64_t)));
        !           355:     assert(P2ALIGNED(size, sizeof(uint64_t)));
        !           356: 
        !           357:     end = buf + size;
        !           358: 
        !           359:     for (ptr = buf; ptr < end; ptr++) {
        !           360:         if (*ptr != old)
        !           361:             return kmem_buf_verify_bytes(ptr, &old, sizeof(old));
        !           362: 
        !           363:         *ptr = new;
        !           364:     }
        !           365: 
        !           366:     return NULL;
        !           367: }
        !           368: 
        !           369: static inline union kmem_bufctl *
        !           370: kmem_buf_to_bufctl(void *buf, struct kmem_cache *cache)
        !           371: {
        !           372:     return (union kmem_bufctl *)(buf + cache->bufctl_dist);
        !           373: }
        !           374: 
        !           375: static inline struct kmem_buftag *
        !           376: kmem_buf_to_buftag(void *buf, struct kmem_cache *cache)
        !           377: {
        !           378:     return (struct kmem_buftag *)(buf + cache->buftag_dist);
        !           379: }
        !           380: 
        !           381: static inline void * kmem_bufctl_to_buf(union kmem_bufctl *bufctl,
        !           382:                                         struct kmem_cache *cache)
        !           383: {
        !           384:     return (void *)bufctl - cache->bufctl_dist;
        !           385: }
        !           386: 
        !           387: static vm_offset_t kmem_pagealloc(vm_size_t size)
        !           388: {
        !           389:     vm_offset_t addr;
        !           390:     kern_return_t kr;
        !           391: 
        !           392:     kr = kmem_alloc_wired(kmem_map, &addr, size);
        !           393: 
        !           394:     if (kr != KERN_SUCCESS)
        !           395:         return 0;
        !           396: 
        !           397:     return addr;
        !           398: }
        !           399: 
        !           400: static void kmem_pagefree(vm_offset_t ptr, vm_size_t size)
        !           401: {
        !           402:     kmem_free(kmem_map, ptr, size);
        !           403: }
        !           404: 
        !           405: static void kmem_slab_create_verify(struct kmem_slab *slab,
        !           406:                                     struct kmem_cache *cache)
        !           407: {
        !           408:     struct kmem_buftag *buftag;
        !           409:     size_t buf_size;
        !           410:     unsigned long buffers;
        !           411:     void *buf;
        !           412: 
        !           413:     buf_size = cache->buf_size;
        !           414:     buf = slab->addr;
        !           415:     buftag = kmem_buf_to_buftag(buf, cache);
        !           416: 
        !           417:     for (buffers = cache->bufs_per_slab; buffers != 0; buffers--) {
        !           418:         kmem_buf_fill(buf, KMEM_FREE_PATTERN, cache->bufctl_dist);
        !           419:         buftag->state = KMEM_BUFTAG_FREE;
        !           420:         buf += buf_size;
        !           421:         buftag = kmem_buf_to_buftag(buf, cache);
        !           422:     }
        !           423: }
        !           424: 
        !           425: /*
        !           426:  * Create an empty slab for a cache.
        !           427:  *
        !           428:  * The caller must drop all locks before calling this function.
        !           429:  */
        !           430: static struct kmem_slab * kmem_slab_create(struct kmem_cache *cache,
        !           431:                                            size_t color)
        !           432: {
        !           433:     struct kmem_slab *slab;
        !           434:     union kmem_bufctl *bufctl;
        !           435:     size_t buf_size;
        !           436:     unsigned long buffers;
        !           437:     void *slab_buf;
        !           438: 
        !           439:     if (cache->slab_alloc_fn == NULL)
        !           440:         slab_buf = (void *)kmem_pagealloc(cache->slab_size);
        !           441:     else
        !           442:         slab_buf = (void *)cache->slab_alloc_fn(cache->slab_size);
        !           443: 
        !           444:     if (slab_buf == NULL)
        !           445:         return NULL;
        !           446: 
        !           447:     if (cache->flags & KMEM_CF_SLAB_EXTERNAL) {
        !           448:         assert(!(cache->flags & KMEM_CF_NO_RECLAIM));
        !           449:         slab = (struct kmem_slab *)kmem_cache_alloc(&kmem_slab_cache);
        !           450: 
        !           451:         if (slab == NULL) {
        !           452:             if (cache->slab_free_fn == NULL)
        !           453:                 kmem_pagefree((vm_offset_t)slab_buf, cache->slab_size);
        !           454:             else
        !           455:                 cache->slab_free_fn((vm_offset_t)slab_buf, cache->slab_size);
        !           456: 
        !           457:             return NULL;
        !           458:         }
        !           459:     } else {
        !           460:         slab = (struct kmem_slab *)(slab_buf + cache->slab_size) - 1;
        !           461:     }
        !           462: 
        !           463:     list_node_init(&slab->list_node);
        !           464:     rbtree_node_init(&slab->tree_node);
        !           465:     slab->nr_refs = 0;
        !           466:     slab->first_free = NULL;
        !           467:     slab->addr = slab_buf + color;
        !           468: 
        !           469:     buf_size = cache->buf_size;
        !           470:     bufctl = kmem_buf_to_bufctl(slab->addr, cache);
        !           471: 
        !           472:     for (buffers = cache->bufs_per_slab; buffers != 0; buffers--) {
        !           473:         bufctl->next = slab->first_free;
        !           474:         slab->first_free = bufctl;
        !           475:         bufctl = (union kmem_bufctl *)((void *)bufctl + buf_size);
        !           476:     }
        !           477: 
        !           478:     if (cache->flags & KMEM_CF_VERIFY)
        !           479:         kmem_slab_create_verify(slab, cache);
        !           480: 
        !           481:     return slab;
        !           482: }
        !           483: 
        !           484: static void kmem_slab_destroy_verify(struct kmem_slab *slab,
        !           485:                                      struct kmem_cache *cache)
        !           486: {
        !           487:     struct kmem_buftag *buftag;
        !           488:     size_t buf_size;
        !           489:     unsigned long buffers;
        !           490:     void *buf, *addr;
        !           491: 
        !           492:     buf_size = cache->buf_size;
        !           493:     buf = slab->addr;
        !           494:     buftag = kmem_buf_to_buftag(buf, cache);
        !           495: 
        !           496:     for (buffers = cache->bufs_per_slab; buffers != 0; buffers--) {
        !           497:         if (buftag->state != KMEM_BUFTAG_FREE)
        !           498:             kmem_cache_error(cache, buf, KMEM_ERR_BUFTAG, buftag);
        !           499: 
        !           500:         addr = kmem_buf_verify(buf, KMEM_FREE_PATTERN, cache->bufctl_dist);
        !           501: 
        !           502:         if (addr != NULL)
        !           503:             kmem_cache_error(cache, buf, KMEM_ERR_MODIFIED, addr);
        !           504: 
        !           505:         buf += buf_size;
        !           506:         buftag = kmem_buf_to_buftag(buf, cache);
        !           507:     }
        !           508: }
        !           509: 
        !           510: /*
        !           511:  * Destroy a slab.
        !           512:  *
        !           513:  * The caller must drop all locks before calling this function.
        !           514:  */
        !           515: static void kmem_slab_destroy(struct kmem_slab *slab, struct kmem_cache *cache)
        !           516: {
        !           517:     vm_offset_t slab_buf;
        !           518: 
        !           519:     assert(slab->nr_refs == 0);
        !           520:     assert(slab->first_free != NULL);
        !           521:     assert(!(cache->flags & KMEM_CF_NO_RECLAIM));
        !           522: 
        !           523:     if (cache->flags & KMEM_CF_VERIFY)
        !           524:         kmem_slab_destroy_verify(slab, cache);
        !           525: 
        !           526:     slab_buf = (vm_offset_t)P2ALIGN((unsigned long)slab->addr, PAGE_SIZE);
        !           527: 
        !           528:     if (cache->slab_free_fn == NULL)
        !           529:         kmem_pagefree(slab_buf, cache->slab_size);
        !           530:     else
        !           531:         cache->slab_free_fn(slab_buf, cache->slab_size);
        !           532: 
        !           533:     if (cache->flags & KMEM_CF_SLAB_EXTERNAL)
        !           534:         kmem_cache_free(&kmem_slab_cache, (vm_offset_t)slab);
        !           535: }
        !           536: 
        !           537: static inline int kmem_slab_use_tree(int flags)
        !           538: {
        !           539:     return !(flags & KMEM_CF_DIRECT) || (flags & KMEM_CF_VERIFY);
        !           540: }
        !           541: 
        !           542: static inline int kmem_slab_cmp_lookup(const void *addr,
        !           543:                                        const struct rbtree_node *node)
        !           544: {
        !           545:     struct kmem_slab *slab;
        !           546: 
        !           547:     slab = rbtree_entry(node, struct kmem_slab, tree_node);
        !           548: 
        !           549:     if (addr == slab->addr)
        !           550:         return 0;
        !           551:     else if (addr < slab->addr)
        !           552:         return -1;
        !           553:     else
        !           554:         return 1;
        !           555: }
        !           556: 
        !           557: static inline int kmem_slab_cmp_insert(const struct rbtree_node *a,
        !           558:                                        const struct rbtree_node *b)
        !           559: {
        !           560:     struct kmem_slab *slab;
        !           561: 
        !           562:     slab = rbtree_entry(a, struct kmem_slab, tree_node);
        !           563:     return kmem_slab_cmp_lookup(slab->addr, b);
        !           564: }
        !           565: 
        !           566: #if SLAB_USE_CPU_POOLS
        !           567: static void kmem_cpu_pool_init(struct kmem_cpu_pool *cpu_pool,
        !           568:                                struct kmem_cache *cache)
        !           569: {
        !           570:     simple_lock_init(&cpu_pool->lock);
        !           571:     cpu_pool->flags = cache->flags;
        !           572:     cpu_pool->size = 0;
        !           573:     cpu_pool->transfer_size = 0;
        !           574:     cpu_pool->nr_objs = 0;
        !           575:     cpu_pool->array = NULL;
        !           576: }
        !           577: 
        !           578: /*
        !           579:  * Return a CPU pool.
        !           580:  *
        !           581:  * This function will generally return the pool matching the CPU running the
        !           582:  * calling thread. Because of context switches and thread migration, the
        !           583:  * caller might be running on another processor after this function returns.
        !           584:  * Although not optimal, this should rarely happen, and it doesn't affect the
        !           585:  * allocator operations in any other way, as CPU pools are always valid, and
        !           586:  * their access is serialized by a lock.
        !           587:  */
        !           588: static inline struct kmem_cpu_pool * kmem_cpu_pool_get(struct kmem_cache *cache)
        !           589: {
        !           590:     return &cache->cpu_pools[cpu_number()];
        !           591: }
        !           592: 
        !           593: static inline void kmem_cpu_pool_build(struct kmem_cpu_pool *cpu_pool,
        !           594:                                        struct kmem_cache *cache, void **array)
        !           595: {
        !           596:     cpu_pool->size = cache->cpu_pool_type->array_size;
        !           597:     cpu_pool->transfer_size = (cpu_pool->size
        !           598:                                + KMEM_CPU_POOL_TRANSFER_RATIO - 1)
        !           599:                               / KMEM_CPU_POOL_TRANSFER_RATIO;
        !           600:     cpu_pool->array = array;
        !           601: }
        !           602: 
        !           603: static inline void * kmem_cpu_pool_pop(struct kmem_cpu_pool *cpu_pool)
        !           604: {
        !           605:     cpu_pool->nr_objs--;
        !           606:     return cpu_pool->array[cpu_pool->nr_objs];
        !           607: }
        !           608: 
        !           609: static inline void kmem_cpu_pool_push(struct kmem_cpu_pool *cpu_pool, void *obj)
        !           610: {
        !           611:     cpu_pool->array[cpu_pool->nr_objs] = obj;
        !           612:     cpu_pool->nr_objs++;
        !           613: }
        !           614: 
        !           615: static int kmem_cpu_pool_fill(struct kmem_cpu_pool *cpu_pool,
        !           616:                               struct kmem_cache *cache)
        !           617: {
        !           618:     kmem_cache_ctor_t ctor;
        !           619:     void *buf;
        !           620:     int i;
        !           621: 
        !           622:     ctor = (cpu_pool->flags & KMEM_CF_VERIFY) ? NULL : cache->ctor;
        !           623: 
        !           624:     simple_lock(&cache->lock);
        !           625: 
        !           626:     for (i = 0; i < cpu_pool->transfer_size; i++) {
        !           627:         buf = kmem_cache_alloc_from_slab(cache);
        !           628: 
        !           629:         if (buf == NULL)
        !           630:             break;
        !           631: 
        !           632:         if (ctor != NULL)
        !           633:             ctor(buf);
        !           634: 
        !           635:         kmem_cpu_pool_push(cpu_pool, buf);
        !           636:     }
        !           637: 
        !           638:     simple_unlock(&cache->lock);
        !           639: 
        !           640:     return i;
        !           641: }
        !           642: 
        !           643: static void kmem_cpu_pool_drain(struct kmem_cpu_pool *cpu_pool,
        !           644:                                 struct kmem_cache *cache)
        !           645: {
        !           646:     void *obj;
        !           647:     int i;
        !           648: 
        !           649:     simple_lock(&cache->lock);
        !           650: 
        !           651:     for (i = cpu_pool->transfer_size; i > 0; i--) {
        !           652:         obj = kmem_cpu_pool_pop(cpu_pool);
        !           653:         kmem_cache_free_to_slab(cache, obj);
        !           654:     }
        !           655: 
        !           656:     simple_unlock(&cache->lock);
        !           657: }
        !           658: #endif /* SLAB_USE_CPU_POOLS */
        !           659: 
        !           660: static void kmem_cache_error(struct kmem_cache *cache, void *buf, int error,
        !           661:                              void *arg)
        !           662: {
        !           663:     struct kmem_buftag *buftag;
        !           664: 
        !           665:     kmem_error("cache: %s, buffer: %p", cache->name, (void *)buf);
        !           666: 
        !           667:     switch(error) {
        !           668:     case KMEM_ERR_INVALID:
        !           669:         kmem_error("freeing invalid address");
        !           670:         break;
        !           671:     case KMEM_ERR_DOUBLEFREE:
        !           672:         kmem_error("attempting to free the same address twice");
        !           673:         break;
        !           674:     case KMEM_ERR_BUFTAG:
        !           675:         buftag = arg;
        !           676:         kmem_error("invalid buftag content, buftag state: %p",
        !           677:                    (void *)buftag->state);
        !           678:         break;
        !           679:     case KMEM_ERR_MODIFIED:
        !           680:         kmem_error("free buffer modified, fault address: %p, "
        !           681:                    "offset in buffer: %td", arg, arg - buf);
        !           682:         break;
        !           683:     case KMEM_ERR_REDZONE:
        !           684:         kmem_error("write beyond end of buffer, fault address: %p, "
        !           685:                    "offset in buffer: %td", arg, arg - buf);
        !           686:         break;
        !           687:     default:
        !           688:         kmem_error("unknown error");
        !           689:     }
        !           690: 
        !           691:     /*
        !           692:      * Never reached.
        !           693:      */
        !           694: }
        !           695: 
        !           696: /*
        !           697:  * Compute an appropriate slab size for the given cache.
        !           698:  *
        !           699:  * Once the slab size is known, this function sets the related properties
        !           700:  * (buffers per slab and maximum color). It can also set the KMEM_CF_DIRECT
        !           701:  * and/or KMEM_CF_SLAB_EXTERNAL flags depending on the resulting layout.
        !           702:  */
        !           703: static void kmem_cache_compute_sizes(struct kmem_cache *cache, int flags)
        !           704: {
        !           705:     size_t i, buffers, buf_size, slab_size, free_slab_size, optimal_size;
        !           706:     size_t waste, waste_min;
        !           707:     int embed, optimal_embed = optimal_embed;
        !           708: 
        !           709:     buf_size = cache->buf_size;
        !           710: 
        !           711:     if (buf_size < KMEM_BUF_SIZE_THRESHOLD)
        !           712:         flags |= KMEM_CACHE_NOOFFSLAB;
        !           713: 
        !           714:     i = 0;
        !           715:     waste_min = (size_t)-1;
        !           716: 
        !           717:     do {
        !           718:         i++;
        !           719:         slab_size = P2ROUND(i * buf_size, PAGE_SIZE);
        !           720:         free_slab_size = slab_size;
        !           721: 
        !           722:         if (flags & KMEM_CACHE_NOOFFSLAB)
        !           723:             free_slab_size -= sizeof(struct kmem_slab);
        !           724: 
        !           725:         buffers = free_slab_size / buf_size;
        !           726:         waste = free_slab_size % buf_size;
        !           727: 
        !           728:         if (buffers > i)
        !           729:             i = buffers;
        !           730: 
        !           731:         if (flags & KMEM_CACHE_NOOFFSLAB)
        !           732:             embed = 1;
        !           733:         else if (sizeof(struct kmem_slab) <= waste) {
        !           734:             embed = 1;
        !           735:             waste -= sizeof(struct kmem_slab);
        !           736:         } else {
        !           737:             embed = 0;
        !           738:         }
        !           739: 
        !           740:         if (waste <= waste_min) {
        !           741:             waste_min = waste;
        !           742:             optimal_size = slab_size;
        !           743:             optimal_embed = embed;
        !           744:         }
        !           745:     } while ((buffers < KMEM_MIN_BUFS_PER_SLAB)
        !           746:              && (slab_size < KMEM_SLAB_SIZE_THRESHOLD));
        !           747: 
        !           748:     assert(!(flags & KMEM_CACHE_NOOFFSLAB) || optimal_embed);
        !           749: 
        !           750:     cache->slab_size = optimal_size;
        !           751:     slab_size = cache->slab_size - (optimal_embed
        !           752:                 ? sizeof(struct kmem_slab)
        !           753:                 : 0);
        !           754:     cache->bufs_per_slab = slab_size / buf_size;
        !           755:     cache->color_max = slab_size % buf_size;
        !           756: 
        !           757:     if (cache->color_max >= PAGE_SIZE)
        !           758:         cache->color_max = PAGE_SIZE - 1;
        !           759: 
        !           760:     if (optimal_embed) {
        !           761:         if (cache->slab_size == PAGE_SIZE)
        !           762:             cache->flags |= KMEM_CF_DIRECT;
        !           763:     } else {
        !           764:         cache->flags |= KMEM_CF_SLAB_EXTERNAL;
        !           765:     }
        !           766: }
        !           767: 
        !           768: void kmem_cache_init(struct kmem_cache *cache, const char *name,
        !           769:                      size_t obj_size, size_t align, kmem_cache_ctor_t ctor,
        !           770:                      kmem_slab_alloc_fn_t slab_alloc_fn,
        !           771:                      kmem_slab_free_fn_t slab_free_fn, int flags)
        !           772: {
        !           773: #if SLAB_USE_CPU_POOLS
        !           774:     struct kmem_cpu_pool_type *cpu_pool_type;
        !           775:     size_t i;
        !           776: #endif /* SLAB_USE_CPU_POOLS */
        !           777:     size_t buf_size;
        !           778: 
        !           779: #if SLAB_VERIFY
        !           780:     cache->flags = KMEM_CF_VERIFY;
        !           781: #else /* SLAB_VERIFY */
        !           782:     cache->flags = 0;
        !           783: #endif /* SLAB_VERIFY */
        !           784: 
        !           785:     if (flags & KMEM_CACHE_NOCPUPOOL)
        !           786:         cache->flags |= KMEM_CF_NO_CPU_POOL;
        !           787: 
        !           788:     if (flags & KMEM_CACHE_NORECLAIM) {
        !           789:         assert(slab_free_fn == NULL);
        !           790:         flags |= KMEM_CACHE_NOOFFSLAB;
        !           791:         cache->flags |= KMEM_CF_NO_RECLAIM;
        !           792:     }
        !           793: 
        !           794:     if (flags & KMEM_CACHE_VERIFY)
        !           795:         cache->flags |= KMEM_CF_VERIFY;
        !           796: 
        !           797:     if (align < KMEM_ALIGN_MIN)
        !           798:         align = KMEM_ALIGN_MIN;
        !           799: 
        !           800:     assert(obj_size > 0);
        !           801:     assert(ISP2(align));
        !           802:     assert(align < PAGE_SIZE);
        !           803: 
        !           804:     buf_size = P2ROUND(obj_size, align);
        !           805: 
        !           806:     simple_lock_init(&cache->lock);
        !           807:     list_node_init(&cache->node);
        !           808:     list_init(&cache->partial_slabs);
        !           809:     list_init(&cache->free_slabs);
        !           810:     rbtree_init(&cache->active_slabs);
        !           811:     cache->obj_size = obj_size;
        !           812:     cache->align = align;
        !           813:     cache->buf_size = buf_size;
        !           814:     cache->bufctl_dist = buf_size - sizeof(union kmem_bufctl);
        !           815:     cache->color = 0;
        !           816:     cache->nr_objs = 0;
        !           817:     cache->nr_bufs = 0;
        !           818:     cache->nr_slabs = 0;
        !           819:     cache->nr_free_slabs = 0;
        !           820:     cache->ctor = ctor;
        !           821:     cache->slab_alloc_fn = slab_alloc_fn;
        !           822:     cache->slab_free_fn = slab_free_fn;
        !           823:     strncpy(cache->name, name, sizeof(cache->name));
        !           824:     cache->name[sizeof(cache->name) - 1] = '\0';
        !           825:     cache->buftag_dist = 0;
        !           826:     cache->redzone_pad = 0;
        !           827: 
        !           828:     if (cache->flags & KMEM_CF_VERIFY) {
        !           829:         cache->bufctl_dist = buf_size;
        !           830:         cache->buftag_dist = cache->bufctl_dist + sizeof(union kmem_bufctl);
        !           831:         cache->redzone_pad = cache->bufctl_dist - cache->obj_size;
        !           832:         buf_size += sizeof(union kmem_bufctl) + sizeof(struct kmem_buftag);
        !           833:         buf_size = P2ROUND(buf_size, align);
        !           834:         cache->buf_size = buf_size;
        !           835:     }
        !           836: 
        !           837:     kmem_cache_compute_sizes(cache, flags);
        !           838: 
        !           839: #if SLAB_USE_CPU_POOLS
        !           840:     for (cpu_pool_type = kmem_cpu_pool_types;
        !           841:          buf_size <= cpu_pool_type->buf_size;
        !           842:          cpu_pool_type++);
        !           843: 
        !           844:     cache->cpu_pool_type = cpu_pool_type;
        !           845: 
        !           846:     for (i = 0; i < ARRAY_SIZE(cache->cpu_pools); i++)
        !           847:         kmem_cpu_pool_init(&cache->cpu_pools[i], cache);
        !           848: #endif /* SLAB_USE_CPU_POOLS */
        !           849: 
        !           850:     simple_lock(&kmem_cache_list_lock);
        !           851:     list_insert_tail(&kmem_cache_list, &cache->node);
        !           852:     kmem_nr_caches++;
        !           853:     simple_unlock(&kmem_cache_list_lock);
        !           854: }
        !           855: 
        !           856: static inline int kmem_cache_empty(struct kmem_cache *cache)
        !           857: {
        !           858:     return cache->nr_objs == cache->nr_bufs;
        !           859: }
        !           860: 
        !           861: static int kmem_cache_grow(struct kmem_cache *cache)
        !           862: {
        !           863:     struct kmem_slab *slab;
        !           864:     size_t color;
        !           865:     int empty;
        !           866: 
        !           867:     simple_lock(&cache->lock);
        !           868: 
        !           869:     if (!kmem_cache_empty(cache)) {
        !           870:         simple_unlock(&cache->lock);
        !           871:         return 1;
        !           872:     }
        !           873: 
        !           874:     color = cache->color;
        !           875:     cache->color += cache->align;
        !           876: 
        !           877:     if (cache->color > cache->color_max)
        !           878:         cache->color = 0;
        !           879: 
        !           880:     simple_unlock(&cache->lock);
        !           881: 
        !           882:     slab = kmem_slab_create(cache, color);
        !           883: 
        !           884:     simple_lock(&cache->lock);
        !           885: 
        !           886:     if (slab != NULL) {
        !           887:         list_insert_head(&cache->free_slabs, &slab->list_node);
        !           888:         cache->nr_bufs += cache->bufs_per_slab;
        !           889:         cache->nr_slabs++;
        !           890:         cache->nr_free_slabs++;
        !           891:     }
        !           892: 
        !           893:     /*
        !           894:      * Even if our slab creation failed, another thread might have succeeded
        !           895:      * in growing the cache.
        !           896:      */
        !           897:     empty = kmem_cache_empty(cache);
        !           898: 
        !           899:     simple_unlock(&cache->lock);
        !           900: 
        !           901:     return !empty;
        !           902: }
        !           903: 
        !           904: static void kmem_cache_reap(struct kmem_cache *cache)
        !           905: {
        !           906:     struct kmem_slab *slab;
        !           907:     struct list dead_slabs;
        !           908:     unsigned long nr_free_slabs;
        !           909: 
        !           910:     if (cache->flags & KMEM_CF_NO_RECLAIM)
        !           911:         return;
        !           912: 
        !           913:     simple_lock(&cache->lock);
        !           914:     list_set_head(&dead_slabs, &cache->free_slabs);
        !           915:     list_init(&cache->free_slabs);
        !           916:     nr_free_slabs = cache->nr_free_slabs;
        !           917:     cache->nr_bufs -= cache->bufs_per_slab * nr_free_slabs;
        !           918:     cache->nr_slabs -= nr_free_slabs;
        !           919:     cache->nr_free_slabs = 0;
        !           920:     simple_unlock(&cache->lock);
        !           921: 
        !           922:     while (!list_empty(&dead_slabs)) {
        !           923:         slab = list_first_entry(&dead_slabs, struct kmem_slab, list_node);
        !           924:         list_remove(&slab->list_node);
        !           925:         kmem_slab_destroy(slab, cache);
        !           926:         nr_free_slabs--;
        !           927:     }
        !           928: 
        !           929:     assert(nr_free_slabs == 0);
        !           930: }
        !           931: 
        !           932: /*
        !           933:  * Allocate a raw (unconstructed) buffer from the slab layer of a cache.
        !           934:  *
        !           935:  * The cache must be locked before calling this function.
        !           936:  */
        !           937: static void * kmem_cache_alloc_from_slab(struct kmem_cache *cache)
        !           938: {
        !           939:     struct kmem_slab *slab;
        !           940:     union kmem_bufctl *bufctl;
        !           941: 
        !           942:     if (!list_empty(&cache->partial_slabs))
        !           943:         slab = list_first_entry(&cache->partial_slabs, struct kmem_slab,
        !           944:                                 list_node);
        !           945:     else if (!list_empty(&cache->free_slabs))
        !           946:         slab = list_first_entry(&cache->free_slabs, struct kmem_slab,
        !           947:                                 list_node);
        !           948:     else
        !           949:         return NULL;
        !           950: 
        !           951:     bufctl = slab->first_free;
        !           952:     assert(bufctl != NULL);
        !           953:     slab->first_free = bufctl->next;
        !           954:     slab->nr_refs++;
        !           955:     cache->nr_objs++;
        !           956: 
        !           957:     if (slab->nr_refs == cache->bufs_per_slab) {
        !           958:         /* The slab has become complete */
        !           959:         list_remove(&slab->list_node);
        !           960: 
        !           961:         if (slab->nr_refs == 1)
        !           962:             cache->nr_free_slabs--;
        !           963:     } else if (slab->nr_refs == 1) {
        !           964:         /*
        !           965:          * The slab has become partial. Insert the new slab at the end of
        !           966:          * the list to reduce fragmentation.
        !           967:          */
        !           968:         list_remove(&slab->list_node);
        !           969:         list_insert_tail(&cache->partial_slabs, &slab->list_node);
        !           970:         cache->nr_free_slabs--;
        !           971:     }
        !           972: 
        !           973:     if ((slab->nr_refs == 1) && kmem_slab_use_tree(cache->flags))
        !           974:         rbtree_insert(&cache->active_slabs, &slab->tree_node,
        !           975:                       kmem_slab_cmp_insert);
        !           976: 
        !           977:     return kmem_bufctl_to_buf(bufctl, cache);
        !           978: }
        !           979: 
        !           980: /*
        !           981:  * Release a buffer to the slab layer of a cache.
        !           982:  *
        !           983:  * The cache must be locked before calling this function.
        !           984:  */
        !           985: static void kmem_cache_free_to_slab(struct kmem_cache *cache, void *buf)
        !           986: {
        !           987:     struct kmem_slab *slab;
        !           988:     union kmem_bufctl *bufctl;
        !           989: 
        !           990:     if (cache->flags & KMEM_CF_DIRECT) {
        !           991:         assert(cache->slab_size == PAGE_SIZE);
        !           992:         slab = (struct kmem_slab *)P2END((unsigned long)buf, cache->slab_size)
        !           993:                - 1;
        !           994:     } else {
        !           995:         struct rbtree_node *node;
        !           996: 
        !           997:         node = rbtree_lookup_nearest(&cache->active_slabs, buf,
        !           998:                                      kmem_slab_cmp_lookup, RBTREE_LEFT);
        !           999:         assert(node != NULL);
        !          1000:         slab = rbtree_entry(node, struct kmem_slab, tree_node);
        !          1001:         assert((unsigned long)buf < (P2ALIGN((unsigned long)slab->addr
        !          1002:                                              + cache->slab_size, PAGE_SIZE)));
        !          1003:     }
        !          1004: 
        !          1005:     assert(slab->nr_refs >= 1);
        !          1006:     assert(slab->nr_refs <= cache->bufs_per_slab);
        !          1007:     bufctl = kmem_buf_to_bufctl(buf, cache);
        !          1008:     bufctl->next = slab->first_free;
        !          1009:     slab->first_free = bufctl;
        !          1010:     slab->nr_refs--;
        !          1011:     cache->nr_objs--;
        !          1012: 
        !          1013:     if (slab->nr_refs == 0) {
        !          1014:         /* The slab has become free */
        !          1015: 
        !          1016:         if (kmem_slab_use_tree(cache->flags))
        !          1017:             rbtree_remove(&cache->active_slabs, &slab->tree_node);
        !          1018: 
        !          1019:         if (cache->bufs_per_slab > 1)
        !          1020:             list_remove(&slab->list_node);
        !          1021: 
        !          1022:         list_insert_head(&cache->free_slabs, &slab->list_node);
        !          1023:         cache->nr_free_slabs++;
        !          1024:     } else if (slab->nr_refs == (cache->bufs_per_slab - 1)) {
        !          1025:         /* The slab has become partial */
        !          1026:         list_insert_head(&cache->partial_slabs, &slab->list_node);
        !          1027:     }
        !          1028: }
        !          1029: 
        !          1030: static void kmem_cache_alloc_verify(struct kmem_cache *cache, void *buf,
        !          1031:                                     int construct)
        !          1032: {
        !          1033:     struct kmem_buftag *buftag;
        !          1034:     union kmem_bufctl *bufctl;
        !          1035:     void *addr;
        !          1036: 
        !          1037:     buftag = kmem_buf_to_buftag(buf, cache);
        !          1038: 
        !          1039:     if (buftag->state != KMEM_BUFTAG_FREE)
        !          1040:         kmem_cache_error(cache, buf, KMEM_ERR_BUFTAG, buftag);
        !          1041: 
        !          1042:     addr = kmem_buf_verify_fill(buf, KMEM_FREE_PATTERN, KMEM_UNINIT_PATTERN,
        !          1043:                                 cache->bufctl_dist);
        !          1044: 
        !          1045:     if (addr != NULL)
        !          1046:         kmem_cache_error(cache, buf, KMEM_ERR_MODIFIED, addr);
        !          1047: 
        !          1048:     addr = buf + cache->obj_size;
        !          1049:     memset(addr, KMEM_REDZONE_BYTE, cache->redzone_pad);
        !          1050: 
        !          1051:     bufctl = kmem_buf_to_bufctl(buf, cache);
        !          1052:     bufctl->redzone = KMEM_REDZONE_WORD;
        !          1053:     buftag->state = KMEM_BUFTAG_ALLOC;
        !          1054: 
        !          1055:     if (construct && (cache->ctor != NULL))
        !          1056:         cache->ctor(buf);
        !          1057: }
        !          1058: 
        !          1059: vm_offset_t kmem_cache_alloc(struct kmem_cache *cache)
        !          1060: {
        !          1061:     int filled;
        !          1062:     void *buf;
        !          1063: 
        !          1064: #if SLAB_USE_CPU_POOLS
        !          1065:     struct kmem_cpu_pool *cpu_pool;
        !          1066: 
        !          1067:     cpu_pool = kmem_cpu_pool_get(cache);
        !          1068: 
        !          1069:     if (cpu_pool->flags & KMEM_CF_NO_CPU_POOL)
        !          1070:         goto slab_alloc;
        !          1071: 
        !          1072:     simple_lock(&cpu_pool->lock);
        !          1073: 
        !          1074: fast_alloc:
        !          1075:     if (likely(cpu_pool->nr_objs > 0)) {
        !          1076:         buf = kmem_cpu_pool_pop(cpu_pool);
        !          1077:         simple_unlock(&cpu_pool->lock);
        !          1078: 
        !          1079:         if (cpu_pool->flags & KMEM_CF_VERIFY)
        !          1080:             kmem_cache_alloc_verify(cache, buf, KMEM_AV_CONSTRUCT);
        !          1081: 
        !          1082:         return (vm_offset_t)buf;
        !          1083:     }
        !          1084: 
        !          1085:     if (cpu_pool->array != NULL) {
        !          1086:         filled = kmem_cpu_pool_fill(cpu_pool, cache);
        !          1087: 
        !          1088:         if (!filled) {
        !          1089:             simple_unlock(&cpu_pool->lock);
        !          1090: 
        !          1091:             filled = kmem_cache_grow(cache);
        !          1092: 
        !          1093:             if (!filled)
        !          1094:                 return 0;
        !          1095: 
        !          1096:             simple_lock(&cpu_pool->lock);
        !          1097:         }
        !          1098: 
        !          1099:         goto fast_alloc;
        !          1100:     }
        !          1101: 
        !          1102:     simple_unlock(&cpu_pool->lock);
        !          1103: #endif /* SLAB_USE_CPU_POOLS */
        !          1104: 
        !          1105: slab_alloc:
        !          1106:     simple_lock(&cache->lock);
        !          1107:     buf = kmem_cache_alloc_from_slab(cache);
        !          1108:     simple_unlock(&cache->lock);
        !          1109: 
        !          1110:     if (buf == NULL) {
        !          1111:         filled = kmem_cache_grow(cache);
        !          1112: 
        !          1113:         if (!filled)
        !          1114:             return 0;
        !          1115: 
        !          1116:         goto slab_alloc;
        !          1117:     }
        !          1118: 
        !          1119:     if (cache->flags & KMEM_CF_VERIFY)
        !          1120:         kmem_cache_alloc_verify(cache, buf, KMEM_AV_NOCONSTRUCT);
        !          1121: 
        !          1122:     if (cache->ctor != NULL)
        !          1123:         cache->ctor(buf);
        !          1124: 
        !          1125:     return (vm_offset_t)buf;
        !          1126: }
        !          1127: 
        !          1128: static void kmem_cache_free_verify(struct kmem_cache *cache, void *buf)
        !          1129: {
        !          1130:     struct rbtree_node *node;
        !          1131:     struct kmem_buftag *buftag;
        !          1132:     struct kmem_slab *slab;
        !          1133:     union kmem_bufctl *bufctl;
        !          1134:     unsigned char *redzone_byte;
        !          1135:     unsigned long slabend;
        !          1136: 
        !          1137:     simple_lock(&cache->lock);
        !          1138:     node = rbtree_lookup_nearest(&cache->active_slabs, buf,
        !          1139:                                  kmem_slab_cmp_lookup, RBTREE_LEFT);
        !          1140:     simple_unlock(&cache->lock);
        !          1141: 
        !          1142:     if (node == NULL)
        !          1143:         kmem_cache_error(cache, buf, KMEM_ERR_INVALID, NULL);
        !          1144: 
        !          1145:     slab = rbtree_entry(node, struct kmem_slab, tree_node);
        !          1146:     slabend = P2ALIGN((unsigned long)slab->addr + cache->slab_size, PAGE_SIZE);
        !          1147: 
        !          1148:     if ((unsigned long)buf >= slabend)
        !          1149:         kmem_cache_error(cache, buf, KMEM_ERR_INVALID, NULL);
        !          1150: 
        !          1151:     if ((((unsigned long)buf - (unsigned long)slab->addr) % cache->buf_size)
        !          1152:         != 0)
        !          1153:         kmem_cache_error(cache, buf, KMEM_ERR_INVALID, NULL);
        !          1154: 
        !          1155:     /*
        !          1156:      * As the buffer address is valid, accessing its buftag is safe.
        !          1157:      */
        !          1158:     buftag = kmem_buf_to_buftag(buf, cache);
        !          1159: 
        !          1160:     if (buftag->state != KMEM_BUFTAG_ALLOC) {
        !          1161:         if (buftag->state == KMEM_BUFTAG_FREE)
        !          1162:             kmem_cache_error(cache, buf, KMEM_ERR_DOUBLEFREE, NULL);
        !          1163:         else
        !          1164:             kmem_cache_error(cache, buf, KMEM_ERR_BUFTAG, buftag);
        !          1165:     }
        !          1166: 
        !          1167:     redzone_byte = buf + cache->obj_size;
        !          1168:     bufctl = kmem_buf_to_bufctl(buf, cache);
        !          1169: 
        !          1170:     while (redzone_byte < (unsigned char *)bufctl) {
        !          1171:         if (*redzone_byte != KMEM_REDZONE_BYTE)
        !          1172:             kmem_cache_error(cache, buf, KMEM_ERR_REDZONE, redzone_byte);
        !          1173: 
        !          1174:         redzone_byte++;
        !          1175:     }
        !          1176: 
        !          1177:     if (bufctl->redzone != KMEM_REDZONE_WORD) {
        !          1178:         unsigned long word;
        !          1179: 
        !          1180:         word = KMEM_REDZONE_WORD;
        !          1181:         redzone_byte = kmem_buf_verify_bytes(&bufctl->redzone, &word,
        !          1182:                                              sizeof(bufctl->redzone));
        !          1183:         kmem_cache_error(cache, buf, KMEM_ERR_REDZONE, redzone_byte);
        !          1184:     }
        !          1185: 
        !          1186:     kmem_buf_fill(buf, KMEM_FREE_PATTERN, cache->bufctl_dist);
        !          1187:     buftag->state = KMEM_BUFTAG_FREE;
        !          1188: }
        !          1189: 
        !          1190: void kmem_cache_free(struct kmem_cache *cache, vm_offset_t obj)
        !          1191: {
        !          1192: #if SLAB_USE_CPU_POOLS
        !          1193:     struct kmem_cpu_pool *cpu_pool;
        !          1194:     void **array;
        !          1195: 
        !          1196:     cpu_pool = kmem_cpu_pool_get(cache);
        !          1197: 
        !          1198:     if (cpu_pool->flags & KMEM_CF_VERIFY) {
        !          1199: #else /* SLAB_USE_CPU_POOLS */
        !          1200:     if (cache->flags & KMEM_CF_VERIFY) {
        !          1201: #endif /* SLAB_USE_CPU_POOLS */
        !          1202:         kmem_cache_free_verify(cache, (void *)obj);
        !          1203:     }
        !          1204: 
        !          1205: #if SLAB_USE_CPU_POOLS
        !          1206:     if (cpu_pool->flags & KMEM_CF_NO_CPU_POOL)
        !          1207:         goto slab_free;
        !          1208: 
        !          1209:     simple_lock(&cpu_pool->lock);
        !          1210: 
        !          1211: fast_free:
        !          1212:     if (likely(cpu_pool->nr_objs < cpu_pool->size)) {
        !          1213:         kmem_cpu_pool_push(cpu_pool, (void *)obj);
        !          1214:         simple_unlock(&cpu_pool->lock);
        !          1215:         return;
        !          1216:     }
        !          1217: 
        !          1218:     if (cpu_pool->array != NULL) {
        !          1219:         kmem_cpu_pool_drain(cpu_pool, cache);
        !          1220:         goto fast_free;
        !          1221:     }
        !          1222: 
        !          1223:     simple_unlock(&cpu_pool->lock);
        !          1224: 
        !          1225:     array = (void *)kmem_cache_alloc(cache->cpu_pool_type->array_cache);
        !          1226: 
        !          1227:     if (array != NULL) {
        !          1228:         simple_lock(&cpu_pool->lock);
        !          1229: 
        !          1230:         /*
        !          1231:          * Another thread may have built the CPU pool while the lock was
        !          1232:          * dropped.
        !          1233:          */
        !          1234:         if (cpu_pool->array != NULL) {
        !          1235:             simple_unlock(&cpu_pool->lock);
        !          1236:             kmem_cache_free(cache->cpu_pool_type->array_cache,
        !          1237:                             (vm_offset_t)array);
        !          1238:             simple_lock(&cpu_pool->lock);
        !          1239:             goto fast_free;
        !          1240:         }
        !          1241: 
        !          1242:         kmem_cpu_pool_build(cpu_pool, cache, array);
        !          1243:         goto fast_free;
        !          1244:     }
        !          1245: 
        !          1246: slab_free:
        !          1247: #endif /* SLAB_USE_CPU_POOLS */
        !          1248: 
        !          1249:     simple_lock(&cache->lock);
        !          1250:     kmem_cache_free_to_slab(cache, (void *)obj);
        !          1251:     simple_unlock(&cache->lock);
        !          1252: }
        !          1253: 
        !          1254: void slab_collect(void)
        !          1255: {
        !          1256:     struct kmem_cache *cache;
        !          1257: 
        !          1258:     if (elapsed_ticks <= (kmem_gc_last_tick + KMEM_GC_INTERVAL))
        !          1259:         return;
        !          1260: 
        !          1261:     kmem_gc_last_tick = elapsed_ticks;
        !          1262: 
        !          1263:     simple_lock(&kmem_cache_list_lock);
        !          1264: 
        !          1265:     list_for_each_entry(&kmem_cache_list, cache, node)
        !          1266:         kmem_cache_reap(cache);
        !          1267: 
        !          1268:     simple_unlock(&kmem_cache_list_lock);
        !          1269: }
        !          1270: 
        !          1271: void slab_bootstrap(void)
        !          1272: {
        !          1273:     /* Make sure a bufctl can always be stored in a buffer */
        !          1274:     assert(sizeof(union kmem_bufctl) <= KMEM_ALIGN_MIN);
        !          1275: 
        !          1276:     list_init(&kmem_cache_list);
        !          1277:     simple_lock_init(&kmem_cache_list_lock);
        !          1278: }
        !          1279: 
        !          1280: void slab_init(void)
        !          1281: {
        !          1282:     vm_offset_t min, max;
        !          1283: 
        !          1284: #if SLAB_USE_CPU_POOLS
        !          1285:     struct kmem_cpu_pool_type *cpu_pool_type;
        !          1286:     char name[KMEM_CACHE_NAME_SIZE];
        !          1287:     size_t i, size;
        !          1288: #endif /* SLAB_USE_CPU_POOLS */
        !          1289: 
        !          1290:     kmem_submap(kmem_map, kernel_map, &min, &max, KMEM_MAP_SIZE, FALSE);
        !          1291: 
        !          1292: #if SLAB_USE_CPU_POOLS
        !          1293:     for (i = 0; i < ARRAY_SIZE(kmem_cpu_pool_types); i++) {
        !          1294:         cpu_pool_type = &kmem_cpu_pool_types[i];
        !          1295:         cpu_pool_type->array_cache = &kmem_cpu_array_caches[i];
        !          1296:         sprintf(name, "kmem_cpu_array_%d", cpu_pool_type->array_size);
        !          1297:         size = sizeof(void *) * cpu_pool_type->array_size;
        !          1298:         kmem_cache_init(cpu_pool_type->array_cache, name, size,
        !          1299:                         cpu_pool_type->array_align, NULL, NULL, NULL, 0);
        !          1300:     }
        !          1301: #endif /* SLAB_USE_CPU_POOLS */
        !          1302: 
        !          1303:     /*
        !          1304:      * Prevent off slab data for the slab cache to avoid infinite recursion.
        !          1305:      */
        !          1306:     kmem_cache_init(&kmem_slab_cache, "kmem_slab", sizeof(struct kmem_slab),
        !          1307:                     0, NULL, NULL, NULL, KMEM_CACHE_NOOFFSLAB);
        !          1308: }
        !          1309: 
        !          1310: static vm_offset_t kalloc_pagealloc(vm_size_t size)
        !          1311: {
        !          1312:     vm_offset_t addr;
        !          1313:     kern_return_t kr;
        !          1314: 
        !          1315:     kr = kmem_alloc_wired(kmem_map, &addr, size);
        !          1316: 
        !          1317:     if (kr != KERN_SUCCESS)
        !          1318:         return 0;
        !          1319: 
        !          1320:     return addr;
        !          1321: }
        !          1322: 
        !          1323: static void kalloc_pagefree(vm_offset_t ptr, vm_size_t size)
        !          1324: {
        !          1325:     kmem_free(kmem_map, ptr, size);
        !          1326: }
        !          1327: 
        !          1328: void kalloc_init(void)
        !          1329: {
        !          1330:     char name[KMEM_CACHE_NAME_SIZE];
        !          1331:     size_t i, size;
        !          1332: 
        !          1333:     size = 1 << KALLOC_FIRST_SHIFT;
        !          1334: 
        !          1335:     for (i = 0; i < ARRAY_SIZE(kalloc_caches); i++) {
        !          1336:         sprintf(name, "kalloc_%lu", size);
        !          1337:         kmem_cache_init(&kalloc_caches[i], name, size, 0, NULL,
        !          1338:                         kalloc_pagealloc, kalloc_pagefree, 0);
        !          1339:         size <<= 1;
        !          1340:     }
        !          1341: }
        !          1342: 
        !          1343: /*
        !          1344:  * Return the kalloc cache index matching the given allocation size, which
        !          1345:  * must be strictly greater than 0.
        !          1346:  */
        !          1347: static inline size_t kalloc_get_index(unsigned long size)
        !          1348: {
        !          1349:     assert(size != 0);
        !          1350: 
        !          1351:     size = (size - 1) >> KALLOC_FIRST_SHIFT;
        !          1352: 
        !          1353:     if (size == 0)
        !          1354:         return 0;
        !          1355:     else
        !          1356:         return (sizeof(long) * 8) - __builtin_clzl(size);
        !          1357: }
        !          1358: 
        !          1359: static void kalloc_verify(struct kmem_cache *cache, void *buf, size_t size)
        !          1360: {
        !          1361:     size_t redzone_size;
        !          1362:     void *redzone;
        !          1363: 
        !          1364:     assert(size <= cache->obj_size);
        !          1365: 
        !          1366:     redzone = buf + size;
        !          1367:     redzone_size = cache->obj_size - size;
        !          1368:     memset(redzone, KMEM_REDZONE_BYTE, redzone_size);
        !          1369: }
        !          1370: 
        !          1371: vm_offset_t kalloc(vm_size_t size)
        !          1372: {
        !          1373:     size_t index;
        !          1374:     void *buf;
        !          1375: 
        !          1376:     if (size == 0)
        !          1377:         return 0;
        !          1378: 
        !          1379:     index = kalloc_get_index(size);
        !          1380: 
        !          1381:     if (index < ARRAY_SIZE(kalloc_caches)) {
        !          1382:         struct kmem_cache *cache;
        !          1383: 
        !          1384:         cache = &kalloc_caches[index];
        !          1385:         buf = (void *)kmem_cache_alloc(cache);
        !          1386: 
        !          1387:         if ((buf != 0) && (cache->flags & KMEM_CF_VERIFY))
        !          1388:             kalloc_verify(cache, buf, size);
        !          1389:     } else
        !          1390:         buf = (void *)kalloc_pagealloc(size);
        !          1391: 
        !          1392:     return (vm_offset_t)buf;
        !          1393: }
        !          1394: 
        !          1395: static void kfree_verify(struct kmem_cache *cache, void *buf, size_t size)
        !          1396: {
        !          1397:     unsigned char *redzone_byte, *redzone_end;
        !          1398: 
        !          1399:     assert(size <= cache->obj_size);
        !          1400: 
        !          1401:     redzone_byte = buf + size;
        !          1402:     redzone_end = buf + cache->obj_size;
        !          1403: 
        !          1404:     while (redzone_byte < redzone_end) {
        !          1405:         if (*redzone_byte != KMEM_REDZONE_BYTE)
        !          1406:             kmem_cache_error(cache, buf, KMEM_ERR_REDZONE, redzone_byte);
        !          1407: 
        !          1408:         redzone_byte++;
        !          1409:     }
        !          1410: }
        !          1411: 
        !          1412: void kfree(vm_offset_t data, vm_size_t size)
        !          1413: {
        !          1414:     size_t index;
        !          1415: 
        !          1416:     if ((data == 0) || (size == 0))
        !          1417:         return;
        !          1418: 
        !          1419:     index = kalloc_get_index(size);
        !          1420: 
        !          1421:     if (index < ARRAY_SIZE(kalloc_caches)) {
        !          1422:         struct kmem_cache *cache;
        !          1423: 
        !          1424:         cache = &kalloc_caches[index];
        !          1425: 
        !          1426:         if (cache->flags & KMEM_CF_VERIFY)
        !          1427:             kfree_verify(cache, (void *)data, size);
        !          1428: 
        !          1429:         kmem_cache_free(cache, data);
        !          1430:     } else {
        !          1431:         kalloc_pagefree(data, size);
        !          1432:     }
        !          1433: }
        !          1434: 
        !          1435: void slab_info(void)
        !          1436: {
        !          1437:     struct kmem_cache *cache;
        !          1438:     vm_size_t mem_usage, mem_reclaimable;
        !          1439: 
        !          1440:     printf("cache                  obj slab  bufs   objs   bufs "
        !          1441:            "   total reclaimable\n"
        !          1442:            "name                  size size /slab  usage  count "
        !          1443:            "  memory      memory\n");
        !          1444: 
        !          1445:     simple_lock(&kmem_cache_list_lock);
        !          1446: 
        !          1447:     list_for_each_entry(&kmem_cache_list, cache, node) {
        !          1448:         simple_lock(&cache->lock);
        !          1449: 
        !          1450:         mem_usage = (cache->nr_slabs * cache->slab_size) >> 10;
        !          1451:         mem_reclaimable = (cache->nr_free_slabs * cache->slab_size) >> 10;
        !          1452: 
        !          1453:         printf("%-19s %6lu %3luk  %4lu %6lu %6lu %7uk %10uk\n",
        !          1454:                cache->name, cache->obj_size, cache->slab_size >> 10,
        !          1455:                cache->bufs_per_slab, cache->nr_objs, cache->nr_bufs,
        !          1456:                mem_usage, mem_reclaimable);
        !          1457: 
        !          1458:         simple_unlock(&cache->lock);
        !          1459:     }
        !          1460: 
        !          1461:     simple_unlock(&kmem_cache_list_lock);
        !          1462: }
        !          1463: 
        !          1464: #if MACH_DEBUG
        !          1465: kern_return_t host_slab_info(host_t host, cache_info_array_t *infop,
        !          1466:                              unsigned int *infoCntp)
        !          1467: {
        !          1468:     struct kmem_cache *cache;
        !          1469:     cache_info_t *info;
        !          1470:     unsigned int i, nr_caches;
        !          1471:     vm_size_t info_size = info_size;
        !          1472:     kern_return_t kr;
        !          1473: 
        !          1474:     if (host == HOST_NULL)
        !          1475:         return KERN_INVALID_HOST;
        !          1476: 
        !          1477:     /*
        !          1478:      * Assume the cache list is unaltered once the kernel is ready.
        !          1479:      */
        !          1480: 
        !          1481:     simple_lock(&kmem_cache_list_lock);
        !          1482:     nr_caches = kmem_nr_caches;
        !          1483:     simple_unlock(&kmem_cache_list_lock);
        !          1484: 
        !          1485:     if (nr_caches <= *infoCntp)
        !          1486:         info = *infop;
        !          1487:     else {
        !          1488:         vm_offset_t info_addr;
        !          1489: 
        !          1490:         info_size = round_page(nr_caches * sizeof(*info));
        !          1491:         kr = kmem_alloc_pageable(ipc_kernel_map, &info_addr, info_size);
        !          1492: 
        !          1493:         if (kr != KERN_SUCCESS)
        !          1494:             return kr;
        !          1495: 
        !          1496:         info = (cache_info_t *)info_addr;
        !          1497:     }
        !          1498: 
        !          1499:     if (info == NULL)
        !          1500:         return KERN_RESOURCE_SHORTAGE;
        !          1501: 
        !          1502:     i = 0;
        !          1503: 
        !          1504:     list_for_each_entry(&kmem_cache_list, cache, node) {
        !          1505:         simple_lock(&cache_lock);
        !          1506:         info[i].flags = ((cache->flags & KMEM_CF_NO_CPU_POOL)
        !          1507:                          ? CACHE_FLAGS_NO_CPU_POOL : 0)
        !          1508:                         | ((cache->flags & KMEM_CF_SLAB_EXTERNAL)
        !          1509:                            ? CACHE_FLAGS_SLAB_EXTERNAL : 0)
        !          1510:                         | ((cache->flags & KMEM_CF_NO_RECLAIM)
        !          1511:                            ? CACHE_FLAGS_NO_RECLAIM : 0)
        !          1512:                         | ((cache->flags & KMEM_CF_VERIFY)
        !          1513:                            ? CACHE_FLAGS_VERIFY : 0)
        !          1514:                         | ((cache->flags & KMEM_CF_DIRECT)
        !          1515:                            ? CACHE_FLAGS_DIRECT : 0);
        !          1516: #if SLAB_USE_CPU_POOLS
        !          1517:         info[i].cpu_pool_size = cache->cpu_pool_type->array_size;
        !          1518: #else /* SLAB_USE_CPU_POOLS */
        !          1519:         info[i].cpu_pool_size = 0;
        !          1520: #endif /* SLAB_USE_CPU_POOLS */
        !          1521:         info[i].obj_size = cache->obj_size;
        !          1522:         info[i].align = cache->align;
        !          1523:         info[i].buf_size = cache->buf_size;
        !          1524:         info[i].slab_size = cache->slab_size;
        !          1525:         info[i].bufs_per_slab = cache->bufs_per_slab;
        !          1526:         info[i].nr_objs = cache->nr_objs;
        !          1527:         info[i].nr_bufs = cache->nr_bufs;
        !          1528:         info[i].nr_slabs = cache->nr_slabs;
        !          1529:         info[i].nr_free_slabs = cache->nr_free_slabs;
        !          1530:         strncpy(info[i].name, cache->name, sizeof(info[i].name));
        !          1531:         info[i].name[sizeof(info[i].name) - 1] = '\0';
        !          1532:         simple_unlock(&cache->lock);
        !          1533: 
        !          1534:         i++;
        !          1535:     }
        !          1536: 
        !          1537:     if (info != *infop) {
        !          1538:         vm_map_copy_t copy;
        !          1539:         vm_size_t used;
        !          1540: 
        !          1541:         used = nr_caches * sizeof(*info);
        !          1542: 
        !          1543:         if (used != info_size)
        !          1544:             memset((char *)info + used, 0, info_size - used);
        !          1545: 
        !          1546:         kr = vm_map_copyin(ipc_kernel_map, (vm_offset_t)info, used, TRUE,
        !          1547:                            &copy);
        !          1548: 
        !          1549:         assert(kr == KERN_SUCCESS);
        !          1550:         *infop = (cache_info_t *)copy;
        !          1551:     }
        !          1552: 
        !          1553:     *infoCntp = nr_caches;
        !          1554: 
        !          1555:     return KERN_SUCCESS;
        !          1556: }
        !          1557: #endif /* MACH_DEBUG */

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.