1f6bde1fdSPoul-Henning Kamp /*- 24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause 38a36da99SPedro F. Giffuni * 4f6bde1fdSPoul-Henning Kamp * Copyright (c) 2004 Poul-Henning Kamp 5f6bde1fdSPoul-Henning Kamp * All rights reserved. 6f6bde1fdSPoul-Henning Kamp * 7f6bde1fdSPoul-Henning Kamp * Redistribution and use in source and binary forms, with or without 8f6bde1fdSPoul-Henning Kamp * modification, are permitted provided that the following conditions 9f6bde1fdSPoul-Henning Kamp * are met: 10f6bde1fdSPoul-Henning Kamp * 1. Redistributions of source code must retain the above copyright 11f6bde1fdSPoul-Henning Kamp * notice, this list of conditions and the following disclaimer. 12f6bde1fdSPoul-Henning Kamp * 2. Redistributions in binary form must reproduce the above copyright 13f6bde1fdSPoul-Henning Kamp * notice, this list of conditions and the following disclaimer in the 14f6bde1fdSPoul-Henning Kamp * documentation and/or other materials provided with the distribution. 15f6bde1fdSPoul-Henning Kamp * 16f6bde1fdSPoul-Henning Kamp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17f6bde1fdSPoul-Henning Kamp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18f6bde1fdSPoul-Henning Kamp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19f6bde1fdSPoul-Henning Kamp * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20f6bde1fdSPoul-Henning Kamp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21f6bde1fdSPoul-Henning Kamp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22f6bde1fdSPoul-Henning Kamp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23f6bde1fdSPoul-Henning Kamp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24f6bde1fdSPoul-Henning Kamp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25f6bde1fdSPoul-Henning Kamp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26f6bde1fdSPoul-Henning Kamp * SUCH DAMAGE. 27f6bde1fdSPoul-Henning Kamp * 28d9a54d5cSPoul-Henning Kamp * 29d9a54d5cSPoul-Henning Kamp * Unit number allocation functions. 30f6bde1fdSPoul-Henning Kamp * 31f6bde1fdSPoul-Henning Kamp * These functions implement a mixed run-length/bitmap management of unit 32d9a54d5cSPoul-Henning Kamp * number spaces in a very memory efficient manner. 33f6bde1fdSPoul-Henning Kamp * 34d9a54d5cSPoul-Henning Kamp * Allocation policy is always lowest free number first. 35f6bde1fdSPoul-Henning Kamp * 36d9a54d5cSPoul-Henning Kamp * A return value of -1 signals that no more unit numbers are available. 37f6bde1fdSPoul-Henning Kamp * 38d9a54d5cSPoul-Henning Kamp * There is no cost associated with the range of unitnumbers, so unless 39d9a54d5cSPoul-Henning Kamp * the resource really is finite, specify INT_MAX to new_unrhdr() and 40d9a54d5cSPoul-Henning Kamp * forget about checking the return value. 41f6bde1fdSPoul-Henning Kamp * 42d9a54d5cSPoul-Henning Kamp * If a mutex is not provided when the unit number space is created, a 43d9a54d5cSPoul-Henning Kamp * default global mutex is used. The advantage to passing a mutex in, is 446bccea7cSRebecca Cran * that the alloc_unrl() function can be called with the mutex already 45d9a54d5cSPoul-Henning Kamp * held (it will not be released by alloc_unrl()). 46d9a54d5cSPoul-Henning Kamp * 47d9a54d5cSPoul-Henning Kamp * The allocation function alloc_unr{l}() never sleeps (but it may block on 48d9a54d5cSPoul-Henning Kamp * the mutex of course). 49d9a54d5cSPoul-Henning Kamp * 50d9a54d5cSPoul-Henning Kamp * Freeing a unit number may require allocating memory, and can therefore 51d9a54d5cSPoul-Henning Kamp * sleep so the free_unr() function does not come in a pre-locked variant. 52f6bde1fdSPoul-Henning Kamp * 53f6bde1fdSPoul-Henning Kamp * A userland test program is included. 54f6bde1fdSPoul-Henning Kamp * 556bccea7cSRebecca Cran * Memory usage is a very complex function of the exact allocation 56d9a54d5cSPoul-Henning Kamp * pattern, but always very compact: 57d9a54d5cSPoul-Henning Kamp * * For the very typical case where a single unbroken run of unit 58d9a54d5cSPoul-Henning Kamp * numbers are allocated 44 bytes are used on i386. 59d9a54d5cSPoul-Henning Kamp * * For a unit number space of 1000 units and the random pattern 60d9a54d5cSPoul-Henning Kamp * in the usermode test program included, the worst case usage 61d9a54d5cSPoul-Henning Kamp * was 252 bytes on i386 for 500 allocated and 500 free units. 62d9a54d5cSPoul-Henning Kamp * * For a unit number space of 10000 units and the random pattern 63d9a54d5cSPoul-Henning Kamp * in the usermode test program included, the worst case usage 64d9a54d5cSPoul-Henning Kamp * was 798 bytes on i386 for 5000 allocated and 5000 free units. 65d9a54d5cSPoul-Henning Kamp * * The worst case is where every other unit number is allocated and 6696240c89SEitan Adler * the rest are free. In that case 44 + N/4 bytes are used where 67d9a54d5cSPoul-Henning Kamp * N is the number of the highest unit allocated. 68f6bde1fdSPoul-Henning Kamp */ 69f6bde1fdSPoul-Henning Kamp 708907f744SAlan Somers #include <sys/param.h> 71f6bde1fdSPoul-Henning Kamp #include <sys/types.h> 72dc872d46SKonstantin Belousov #include <sys/_unrhdr.h> 73f6bde1fdSPoul-Henning Kamp 74f6bde1fdSPoul-Henning Kamp #ifdef _KERNEL 75f6bde1fdSPoul-Henning Kamp 76794277daSAlan Somers #include <sys/bitstring.h> 77f6bde1fdSPoul-Henning Kamp #include <sys/malloc.h> 78f6bde1fdSPoul-Henning Kamp #include <sys/kernel.h> 79f6bde1fdSPoul-Henning Kamp #include <sys/systm.h> 80d9a54d5cSPoul-Henning Kamp #include <sys/limits.h> 81d9a54d5cSPoul-Henning Kamp #include <sys/lock.h> 82d9a54d5cSPoul-Henning Kamp #include <sys/mutex.h> 83f6bde1fdSPoul-Henning Kamp 84f6bde1fdSPoul-Henning Kamp /* 85f6bde1fdSPoul-Henning Kamp * In theory it would be smarter to allocate the individual blocks 86f6bde1fdSPoul-Henning Kamp * with the zone allocator, but at this time the expectation is that 87f6bde1fdSPoul-Henning Kamp * there will typically not even be enough allocations to fill a single 88f6bde1fdSPoul-Henning Kamp * page, so we stick with malloc for now. 89f6bde1fdSPoul-Henning Kamp */ 90f6bde1fdSPoul-Henning Kamp static MALLOC_DEFINE(M_UNIT, "Unitno", "Unit number allocation"); 91f6bde1fdSPoul-Henning Kamp 92f6bde1fdSPoul-Henning Kamp #define Malloc(foo) malloc(foo, M_UNIT, M_WAITOK | M_ZERO) 93f6bde1fdSPoul-Henning Kamp #define Free(foo) free(foo, M_UNIT) 94f6bde1fdSPoul-Henning Kamp 95d9a54d5cSPoul-Henning Kamp static struct mtx unitmtx; 96d9a54d5cSPoul-Henning Kamp 97d9a54d5cSPoul-Henning Kamp MTX_SYSINIT(unit, &unitmtx, "unit# allocation", MTX_DEF); 98d9a54d5cSPoul-Henning Kamp 99f6bde1fdSPoul-Henning Kamp #else /* ...USERLAND */ 100f6bde1fdSPoul-Henning Kamp 101794277daSAlan Somers #include <bitstring.h> 102794277daSAlan Somers #include <err.h> 103794277daSAlan Somers #include <errno.h> 104794277daSAlan Somers #include <getopt.h> 105794277daSAlan Somers #include <stdbool.h> 106f6bde1fdSPoul-Henning Kamp #include <stdio.h> 107f6bde1fdSPoul-Henning Kamp #include <stdlib.h> 108d9a54d5cSPoul-Henning Kamp #include <string.h> 109f6bde1fdSPoul-Henning Kamp 110f6bde1fdSPoul-Henning Kamp #define KASSERT(cond, arg) \ 111f6bde1fdSPoul-Henning Kamp do { \ 112f6bde1fdSPoul-Henning Kamp if (!(cond)) { \ 113f6bde1fdSPoul-Henning Kamp printf arg; \ 114d9a54d5cSPoul-Henning Kamp abort(); \ 115f6bde1fdSPoul-Henning Kamp } \ 116f6bde1fdSPoul-Henning Kamp } while (0) 117f6bde1fdSPoul-Henning Kamp 118d9a54d5cSPoul-Henning Kamp static int no_alloc; 119d9a54d5cSPoul-Henning Kamp #define Malloc(foo) _Malloc(foo, __LINE__) 120d9a54d5cSPoul-Henning Kamp static void * 121d9a54d5cSPoul-Henning Kamp _Malloc(size_t foo, int line) 122d9a54d5cSPoul-Henning Kamp { 123d9a54d5cSPoul-Henning Kamp 124d9a54d5cSPoul-Henning Kamp KASSERT(no_alloc == 0, ("malloc in wrong place() line %d", line)); 125d9a54d5cSPoul-Henning Kamp return (calloc(foo, 1)); 126d9a54d5cSPoul-Henning Kamp } 127f6bde1fdSPoul-Henning Kamp #define Free(foo) free(foo) 128f6bde1fdSPoul-Henning Kamp 129d9a54d5cSPoul-Henning Kamp struct unrhdr; 130d9a54d5cSPoul-Henning Kamp 1316fe78ad4SKonstantin Belousov #define UNR_NO_MTX ((void *)(uintptr_t)-1) 1326fe78ad4SKonstantin Belousov 133d9a54d5cSPoul-Henning Kamp struct mtx { 134d9a54d5cSPoul-Henning Kamp int state; 135d9a54d5cSPoul-Henning Kamp } unitmtx; 136d9a54d5cSPoul-Henning Kamp 137d9a54d5cSPoul-Henning Kamp static void 138d9a54d5cSPoul-Henning Kamp mtx_lock(struct mtx *mp) 139d9a54d5cSPoul-Henning Kamp { 140d9a54d5cSPoul-Henning Kamp KASSERT(mp->state == 0, ("mutex already locked")); 141d9a54d5cSPoul-Henning Kamp mp->state = 1; 142d9a54d5cSPoul-Henning Kamp } 143d9a54d5cSPoul-Henning Kamp 144d9a54d5cSPoul-Henning Kamp static void 145d9a54d5cSPoul-Henning Kamp mtx_unlock(struct mtx *mp) 146d9a54d5cSPoul-Henning Kamp { 147d9a54d5cSPoul-Henning Kamp KASSERT(mp->state == 1, ("mutex not locked")); 148d9a54d5cSPoul-Henning Kamp mp->state = 0; 149d9a54d5cSPoul-Henning Kamp } 150d9a54d5cSPoul-Henning Kamp 151d9a54d5cSPoul-Henning Kamp #define MA_OWNED 9 152d9a54d5cSPoul-Henning Kamp 153d9a54d5cSPoul-Henning Kamp static void 154d9a54d5cSPoul-Henning Kamp mtx_assert(struct mtx *mp, int flag) 155d9a54d5cSPoul-Henning Kamp { 156d9a54d5cSPoul-Henning Kamp if (flag == MA_OWNED) { 157d9a54d5cSPoul-Henning Kamp KASSERT(mp->state == 1, ("mtx_assert(MA_OWNED) not true")); 158d9a54d5cSPoul-Henning Kamp } 159d9a54d5cSPoul-Henning Kamp } 160d9a54d5cSPoul-Henning Kamp 161d9a54d5cSPoul-Henning Kamp #define CTASSERT(foo) 16224e8eaf1SJaakko Heinonen #define WITNESS_WARN(flags, lock, fmt, ...) (void)0 163d9a54d5cSPoul-Henning Kamp 164d9a54d5cSPoul-Henning Kamp #endif /* USERLAND */ 165f6bde1fdSPoul-Henning Kamp 166f6bde1fdSPoul-Henning Kamp /* 167f6bde1fdSPoul-Henning Kamp * This is our basic building block. 168f6bde1fdSPoul-Henning Kamp * 169f6bde1fdSPoul-Henning Kamp * It can be used in three different ways depending on the value of the ptr 170f6bde1fdSPoul-Henning Kamp * element: 171f6bde1fdSPoul-Henning Kamp * If ptr is NULL, it represents a run of free items. 172f6bde1fdSPoul-Henning Kamp * If ptr points to the unrhdr it represents a run of allocated items. 1738907f744SAlan Somers * Otherwise it points to a bitstring of allocated items. 174f6bde1fdSPoul-Henning Kamp * 175f6bde1fdSPoul-Henning Kamp * For runs the len field is the length of the run. 176f6bde1fdSPoul-Henning Kamp * For bitmaps the len field represents the number of allocated items. 177f6bde1fdSPoul-Henning Kamp * 178f6bde1fdSPoul-Henning Kamp * The bitmap is the same size as struct unr to optimize memory management. 179d44f4770SKonstantin Belousov * 180d44f4770SKonstantin Belousov * Two special ranges are not covered by unrs: 181d44f4770SKonstantin Belousov * - at the start of the allocator space, all elements in [low, low + first) 182d44f4770SKonstantin Belousov * are allocated; 183d44f4770SKonstantin Belousov * - at the end of the allocator space, all elements in [high - last, high] 184d44f4770SKonstantin Belousov * are free. 185f6bde1fdSPoul-Henning Kamp */ 186f6bde1fdSPoul-Henning Kamp struct unr { 187f6bde1fdSPoul-Henning Kamp TAILQ_ENTRY(unr) list; 188f6bde1fdSPoul-Henning Kamp u_int len; 189f6bde1fdSPoul-Henning Kamp void *ptr; 190f6bde1fdSPoul-Henning Kamp }; 191f6bde1fdSPoul-Henning Kamp 192d9a54d5cSPoul-Henning Kamp struct unrb { 1938907f744SAlan Somers bitstr_t map[sizeof(struct unr) / sizeof(bitstr_t)]; 194d9a54d5cSPoul-Henning Kamp }; 195d9a54d5cSPoul-Henning Kamp 1968907f744SAlan Somers CTASSERT((sizeof(struct unr) % sizeof(bitstr_t)) == 0); 197d9a54d5cSPoul-Henning Kamp 1988907f744SAlan Somers /* Number of bits we can store in the bitmap */ 199042ec55fSKonstantin Belousov #define NBITS (NBBY * sizeof(((struct unrb *)NULL)->map)) 2008907f744SAlan Somers 20136b1f8a8SKonstantin Belousov static inline bool 20236b1f8a8SKonstantin Belousov is_bitmap(struct unrhdr *uh, struct unr *up) 20336b1f8a8SKonstantin Belousov { 20436b1f8a8SKonstantin Belousov return (up->ptr != uh && up->ptr != NULL); 20536b1f8a8SKonstantin Belousov } 20636b1f8a8SKonstantin Belousov 2078907f744SAlan Somers /* Is the unrb empty in at least the first len bits? */ 2088907f744SAlan Somers static inline bool 2098907f744SAlan Somers ub_empty(struct unrb *ub, int len) { 2108907f744SAlan Somers int first_set; 2118907f744SAlan Somers 2128907f744SAlan Somers bit_ffs(ub->map, len, &first_set); 2138907f744SAlan Somers return (first_set == -1); 2148907f744SAlan Somers } 2158907f744SAlan Somers 2168907f744SAlan Somers /* Is the unrb full? That is, is the number of set elements equal to len? */ 2178907f744SAlan Somers static inline bool 2188907f744SAlan Somers ub_full(struct unrb *ub, int len) 2198907f744SAlan Somers { 2208907f744SAlan Somers int first_clear; 2218907f744SAlan Somers 2228907f744SAlan Somers bit_ffc(ub->map, len, &first_clear); 2238907f744SAlan Somers return (first_clear == -1); 2248907f744SAlan Somers } 2258907f744SAlan Somers 226a014e0a3SKonstantin Belousov /* 227a014e0a3SKonstantin Belousov * start: ipos = -1, upos = NULL; 228a014e0a3SKonstantin Belousov * end: ipos = -1, upos = uh 229a014e0a3SKonstantin Belousov */ 230a014e0a3SKonstantin Belousov struct unrhdr_iter { 231a014e0a3SKonstantin Belousov struct unrhdr *uh; 232a014e0a3SKonstantin Belousov int ipos; 233a014e0a3SKonstantin Belousov int upos_first_item; 234a014e0a3SKonstantin Belousov void *upos; 235a014e0a3SKonstantin Belousov }; 236a014e0a3SKonstantin Belousov 237a014e0a3SKonstantin Belousov void * 238a014e0a3SKonstantin Belousov create_iter_unr(struct unrhdr *uh) 239a014e0a3SKonstantin Belousov { 240a014e0a3SKonstantin Belousov struct unrhdr_iter *iter; 241a014e0a3SKonstantin Belousov 242a014e0a3SKonstantin Belousov iter = Malloc(sizeof(*iter)); 243a014e0a3SKonstantin Belousov iter->ipos = -1; 244a014e0a3SKonstantin Belousov iter->uh = uh; 245a014e0a3SKonstantin Belousov iter->upos = NULL; 246a014e0a3SKonstantin Belousov iter->upos_first_item = -1; 247a014e0a3SKonstantin Belousov return (iter); 248a014e0a3SKonstantin Belousov } 249a014e0a3SKonstantin Belousov 250a014e0a3SKonstantin Belousov static void 251a014e0a3SKonstantin Belousov next_iter_unrl(struct unrhdr *uh, struct unrhdr_iter *iter) 252a014e0a3SKonstantin Belousov { 253a014e0a3SKonstantin Belousov struct unr *up; 254a014e0a3SKonstantin Belousov struct unrb *ub; 255a014e0a3SKonstantin Belousov u_int y; 256a014e0a3SKonstantin Belousov int c; 257a014e0a3SKonstantin Belousov 258a014e0a3SKonstantin Belousov if (iter->ipos == -1) { 259a014e0a3SKonstantin Belousov if (iter->upos == uh) 260a014e0a3SKonstantin Belousov return; 261a014e0a3SKonstantin Belousov y = uh->low - 1; 262a014e0a3SKonstantin Belousov if (uh->first == 0) { 263a014e0a3SKonstantin Belousov up = TAILQ_FIRST(&uh->head); 264a014e0a3SKonstantin Belousov if (up == NULL) { 265a014e0a3SKonstantin Belousov iter->upos = uh; 266a014e0a3SKonstantin Belousov return; 267a014e0a3SKonstantin Belousov } 268a014e0a3SKonstantin Belousov iter->upos = up; 269a014e0a3SKonstantin Belousov if (up->ptr == NULL) 270a014e0a3SKonstantin Belousov iter->upos = NULL; 271a014e0a3SKonstantin Belousov else 272a014e0a3SKonstantin Belousov iter->upos_first_item = uh->low; 273a014e0a3SKonstantin Belousov } 274a014e0a3SKonstantin Belousov } else { 275a014e0a3SKonstantin Belousov y = iter->ipos; 276a014e0a3SKonstantin Belousov } 277a014e0a3SKonstantin Belousov 278a014e0a3SKonstantin Belousov up = iter->upos; 279a014e0a3SKonstantin Belousov 280a014e0a3SKonstantin Belousov /* Special case for the compacted [low, first) run. */ 281a014e0a3SKonstantin Belousov if (up == NULL) { 282a014e0a3SKonstantin Belousov if (y + 1 < uh->low + uh->first) { 283a014e0a3SKonstantin Belousov iter->ipos = y + 1; 284a014e0a3SKonstantin Belousov return; 285a014e0a3SKonstantin Belousov } 286a014e0a3SKonstantin Belousov up = iter->upos = TAILQ_FIRST(&uh->head); 287a014e0a3SKonstantin Belousov iter->upos_first_item = uh->low + uh->first; 288a014e0a3SKonstantin Belousov } 289a014e0a3SKonstantin Belousov 290a014e0a3SKonstantin Belousov for (;;) { 291a014e0a3SKonstantin Belousov if (y + 1 < iter->upos_first_item + up->len) { 292a014e0a3SKonstantin Belousov if (up->ptr == uh) { 293a014e0a3SKonstantin Belousov iter->ipos = y + 1; 294a014e0a3SKonstantin Belousov return; 295a014e0a3SKonstantin Belousov } else if (is_bitmap(uh, up)) { 296a014e0a3SKonstantin Belousov ub = up->ptr; 297a014e0a3SKonstantin Belousov bit_ffs_at(&ub->map[0], 298a014e0a3SKonstantin Belousov y + 1 - iter->upos_first_item, 299a014e0a3SKonstantin Belousov up->len, &c); 300a014e0a3SKonstantin Belousov if (c != -1) { 301a014e0a3SKonstantin Belousov iter->ipos = iter->upos_first_item + c; 302a014e0a3SKonstantin Belousov return; 303a014e0a3SKonstantin Belousov } 304a014e0a3SKonstantin Belousov } 305a014e0a3SKonstantin Belousov } 306a014e0a3SKonstantin Belousov iter->upos_first_item += up->len; 307a014e0a3SKonstantin Belousov y = iter->upos_first_item - 1; 308a014e0a3SKonstantin Belousov up = iter->upos = TAILQ_NEXT((struct unr *)iter->upos, list); 309a014e0a3SKonstantin Belousov if (iter->upos == NULL) { 310a014e0a3SKonstantin Belousov iter->ipos = -1; 311a014e0a3SKonstantin Belousov iter->upos = uh; 312a014e0a3SKonstantin Belousov return; 313a014e0a3SKonstantin Belousov } 314a014e0a3SKonstantin Belousov } 315a014e0a3SKonstantin Belousov } 316a014e0a3SKonstantin Belousov 317a014e0a3SKonstantin Belousov /* 318a014e0a3SKonstantin Belousov * returns -1 on end, otherwise the next element 319a014e0a3SKonstantin Belousov */ 320a014e0a3SKonstantin Belousov int 321a014e0a3SKonstantin Belousov next_iter_unr(void *handle) 322a014e0a3SKonstantin Belousov { 323a014e0a3SKonstantin Belousov struct unrhdr *uh; 324a014e0a3SKonstantin Belousov struct unrhdr_iter *iter; 325a014e0a3SKonstantin Belousov 326a014e0a3SKonstantin Belousov iter = handle; 327a014e0a3SKonstantin Belousov uh = iter->uh; 328a014e0a3SKonstantin Belousov if (uh->mtx != NULL) 329a014e0a3SKonstantin Belousov mtx_lock(uh->mtx); 330a014e0a3SKonstantin Belousov next_iter_unrl(uh, iter); 331a014e0a3SKonstantin Belousov if (uh->mtx != NULL) 332a014e0a3SKonstantin Belousov mtx_unlock(uh->mtx); 333a014e0a3SKonstantin Belousov return (iter->ipos); 334a014e0a3SKonstantin Belousov } 335a014e0a3SKonstantin Belousov 336a014e0a3SKonstantin Belousov void 337a014e0a3SKonstantin Belousov free_iter_unr(void *handle) 338a014e0a3SKonstantin Belousov { 339a014e0a3SKonstantin Belousov Free(handle); 340a014e0a3SKonstantin Belousov } 341a014e0a3SKonstantin Belousov 342f6bde1fdSPoul-Henning Kamp #if defined(DIAGNOSTIC) || !defined(_KERNEL) 343f6bde1fdSPoul-Henning Kamp /* 344f6bde1fdSPoul-Henning Kamp * Consistency check function. 345f6bde1fdSPoul-Henning Kamp * 346f6bde1fdSPoul-Henning Kamp * Checks the internal consistency as well as we can. 347f6bde1fdSPoul-Henning Kamp * 348f6bde1fdSPoul-Henning Kamp * Called at all boundaries of this API. 349f6bde1fdSPoul-Henning Kamp */ 350f6bde1fdSPoul-Henning Kamp static void 351f6bde1fdSPoul-Henning Kamp check_unrhdr(struct unrhdr *uh, int line) 352f6bde1fdSPoul-Henning Kamp { 353f6bde1fdSPoul-Henning Kamp struct unr *up; 354d9a54d5cSPoul-Henning Kamp struct unrb *ub; 3551b82e02fSAlan Somers int w; 356*1384a0b9SKonstantin Belousov u_int y __diagused, z __diagused; 357f6bde1fdSPoul-Henning Kamp 358d9a54d5cSPoul-Henning Kamp y = uh->first; 359f6bde1fdSPoul-Henning Kamp z = 0; 360f6bde1fdSPoul-Henning Kamp TAILQ_FOREACH(up, &uh->head, list) { 361f6bde1fdSPoul-Henning Kamp z++; 36236b1f8a8SKonstantin Belousov if (is_bitmap(uh, up)) { 363d9a54d5cSPoul-Henning Kamp ub = up->ptr; 364d9a54d5cSPoul-Henning Kamp KASSERT (up->len <= NBITS, 3658907f744SAlan Somers ("UNR inconsistency: len %u max %zd (line %d)\n", 366d9a54d5cSPoul-Henning Kamp up->len, NBITS, line)); 367f6bde1fdSPoul-Henning Kamp z++; 368f6bde1fdSPoul-Henning Kamp w = 0; 3691b82e02fSAlan Somers bit_count(ub->map, 0, up->len, &w); 370d9a54d5cSPoul-Henning Kamp y += w; 371d9a54d5cSPoul-Henning Kamp } else if (up->ptr != NULL) 372f6bde1fdSPoul-Henning Kamp y += up->len; 373f6bde1fdSPoul-Henning Kamp } 374f6bde1fdSPoul-Henning Kamp KASSERT (y == uh->busy, 375f6bde1fdSPoul-Henning Kamp ("UNR inconsistency: items %u found %u (line %d)\n", 376f6bde1fdSPoul-Henning Kamp uh->busy, y, line)); 377f6bde1fdSPoul-Henning Kamp KASSERT (z == uh->alloc, 378f6bde1fdSPoul-Henning Kamp ("UNR inconsistency: chunks %u found %u (line %d)\n", 379f6bde1fdSPoul-Henning Kamp uh->alloc, z, line)); 380f6bde1fdSPoul-Henning Kamp } 381f6bde1fdSPoul-Henning Kamp 382f6bde1fdSPoul-Henning Kamp #else 383f6bde1fdSPoul-Henning Kamp 384f6bde1fdSPoul-Henning Kamp static __inline void 3858907f744SAlan Somers check_unrhdr(struct unrhdr *uh __unused, int line __unused) 386f6bde1fdSPoul-Henning Kamp { 387f6bde1fdSPoul-Henning Kamp 388f6bde1fdSPoul-Henning Kamp } 389f6bde1fdSPoul-Henning Kamp 390f6bde1fdSPoul-Henning Kamp #endif 391f6bde1fdSPoul-Henning Kamp 392f6bde1fdSPoul-Henning Kamp /* 393f6bde1fdSPoul-Henning Kamp * Userland memory management. Just use calloc and keep track of how 394f6bde1fdSPoul-Henning Kamp * many elements we have allocated for check_unrhdr(). 395f6bde1fdSPoul-Henning Kamp */ 396f6bde1fdSPoul-Henning Kamp 397f6bde1fdSPoul-Henning Kamp static __inline void * 398d9a54d5cSPoul-Henning Kamp new_unr(struct unrhdr *uh, void **p1, void **p2) 399f6bde1fdSPoul-Henning Kamp { 400d9a54d5cSPoul-Henning Kamp void *p; 401f6bde1fdSPoul-Henning Kamp 402d9a54d5cSPoul-Henning Kamp uh->alloc++; 403d9a54d5cSPoul-Henning Kamp KASSERT(*p1 != NULL || *p2 != NULL, ("Out of cached memory")); 404d9a54d5cSPoul-Henning Kamp if (*p1 != NULL) { 405d9a54d5cSPoul-Henning Kamp p = *p1; 406d9a54d5cSPoul-Henning Kamp *p1 = NULL; 407d9a54d5cSPoul-Henning Kamp return (p); 408d9a54d5cSPoul-Henning Kamp } else { 409d9a54d5cSPoul-Henning Kamp p = *p2; 410d9a54d5cSPoul-Henning Kamp *p2 = NULL; 411d9a54d5cSPoul-Henning Kamp return (p); 412d9a54d5cSPoul-Henning Kamp } 413f6bde1fdSPoul-Henning Kamp } 414f6bde1fdSPoul-Henning Kamp 415f6bde1fdSPoul-Henning Kamp static __inline void 416f6bde1fdSPoul-Henning Kamp delete_unr(struct unrhdr *uh, void *ptr) 417f6bde1fdSPoul-Henning Kamp { 41809828ba9SKonstantin Belousov struct unr *up; 419d9a54d5cSPoul-Henning Kamp 420f6bde1fdSPoul-Henning Kamp uh->alloc--; 42109828ba9SKonstantin Belousov up = ptr; 42209828ba9SKonstantin Belousov TAILQ_INSERT_TAIL(&uh->ppfree, up, list); 42309828ba9SKonstantin Belousov } 42409828ba9SKonstantin Belousov 42509828ba9SKonstantin Belousov void 42609828ba9SKonstantin Belousov clean_unrhdrl(struct unrhdr *uh) 42709828ba9SKonstantin Belousov { 42809828ba9SKonstantin Belousov struct unr *up; 42909828ba9SKonstantin Belousov 430e59b940dSKonstantin Belousov if (uh->mtx != NULL) 43109828ba9SKonstantin Belousov mtx_assert(uh->mtx, MA_OWNED); 43209828ba9SKonstantin Belousov while ((up = TAILQ_FIRST(&uh->ppfree)) != NULL) { 43309828ba9SKonstantin Belousov TAILQ_REMOVE(&uh->ppfree, up, list); 434e59b940dSKonstantin Belousov if (uh->mtx != NULL) 43509828ba9SKonstantin Belousov mtx_unlock(uh->mtx); 43609828ba9SKonstantin Belousov Free(up); 437e59b940dSKonstantin Belousov if (uh->mtx != NULL) 43809828ba9SKonstantin Belousov mtx_lock(uh->mtx); 43909828ba9SKonstantin Belousov } 44009828ba9SKonstantin Belousov 44109828ba9SKonstantin Belousov } 44209828ba9SKonstantin Belousov 44309828ba9SKonstantin Belousov void 44409828ba9SKonstantin Belousov clean_unrhdr(struct unrhdr *uh) 44509828ba9SKonstantin Belousov { 44609828ba9SKonstantin Belousov 447e59b940dSKonstantin Belousov if (uh->mtx != NULL) 44809828ba9SKonstantin Belousov mtx_lock(uh->mtx); 44909828ba9SKonstantin Belousov clean_unrhdrl(uh); 450e59b940dSKonstantin Belousov if (uh->mtx != NULL) 45109828ba9SKonstantin Belousov mtx_unlock(uh->mtx); 452f6bde1fdSPoul-Henning Kamp } 453f6bde1fdSPoul-Henning Kamp 454dc872d46SKonstantin Belousov void 455dc872d46SKonstantin Belousov init_unrhdr(struct unrhdr *uh, int low, int high, struct mtx *mutex) 456f6bde1fdSPoul-Henning Kamp { 457f6bde1fdSPoul-Henning Kamp 458831aa555SJaakko Heinonen KASSERT(low >= 0 && low <= high, 459501812f2SJaakko Heinonen ("UNR: use error: new_unrhdr(%d, %d)", low, high)); 460e59b940dSKonstantin Belousov if (mutex == UNR_NO_MTX) 461e59b940dSKonstantin Belousov uh->mtx = NULL; 462e59b940dSKonstantin Belousov else if (mutex != NULL) 463d9a54d5cSPoul-Henning Kamp uh->mtx = mutex; 464d9a54d5cSPoul-Henning Kamp else 465d9a54d5cSPoul-Henning Kamp uh->mtx = &unitmtx; 466f6bde1fdSPoul-Henning Kamp TAILQ_INIT(&uh->head); 46709828ba9SKonstantin Belousov TAILQ_INIT(&uh->ppfree); 468f6bde1fdSPoul-Henning Kamp uh->low = low; 469f6bde1fdSPoul-Henning Kamp uh->high = high; 470d9a54d5cSPoul-Henning Kamp uh->first = 0; 471d9a54d5cSPoul-Henning Kamp uh->last = 1 + (high - low); 472c4be460eSKonstantin Belousov uh->busy = 0; 473c4be460eSKonstantin Belousov uh->alloc = 0; 474f6bde1fdSPoul-Henning Kamp check_unrhdr(uh, __LINE__); 475dc872d46SKonstantin Belousov } 476dc872d46SKonstantin Belousov 477dc872d46SKonstantin Belousov /* 478dc872d46SKonstantin Belousov * Allocate a new unrheader set. 479dc872d46SKonstantin Belousov * 480dc872d46SKonstantin Belousov * Highest and lowest valid values given as parameters. 481dc872d46SKonstantin Belousov */ 482dc872d46SKonstantin Belousov 483dc872d46SKonstantin Belousov struct unrhdr * 484dc872d46SKonstantin Belousov new_unrhdr(int low, int high, struct mtx *mutex) 485dc872d46SKonstantin Belousov { 486dc872d46SKonstantin Belousov struct unrhdr *uh; 487dc872d46SKonstantin Belousov 488dc872d46SKonstantin Belousov uh = Malloc(sizeof *uh); 489dc872d46SKonstantin Belousov init_unrhdr(uh, low, high, mutex); 490f6bde1fdSPoul-Henning Kamp return (uh); 491f6bde1fdSPoul-Henning Kamp } 492f6bde1fdSPoul-Henning Kamp 493e4fea39eSPoul-Henning Kamp void 494e4fea39eSPoul-Henning Kamp delete_unrhdr(struct unrhdr *uh) 495e4fea39eSPoul-Henning Kamp { 496e4fea39eSPoul-Henning Kamp 497d9a54d5cSPoul-Henning Kamp check_unrhdr(uh, __LINE__); 498e4fea39eSPoul-Henning Kamp KASSERT(uh->busy == 0, ("unrhdr has %u allocations", uh->busy)); 499e4fea39eSPoul-Henning Kamp KASSERT(uh->alloc == 0, ("UNR memory leak in delete_unrhdr")); 50009828ba9SKonstantin Belousov KASSERT(TAILQ_FIRST(&uh->ppfree) == NULL, 50109828ba9SKonstantin Belousov ("unrhdr has postponed item for free")); 502e4fea39eSPoul-Henning Kamp Free(uh); 503e4fea39eSPoul-Henning Kamp } 504e4fea39eSPoul-Henning Kamp 505333dcaa4SMatt Joras void 506333dcaa4SMatt Joras clear_unrhdr(struct unrhdr *uh) 507333dcaa4SMatt Joras { 508333dcaa4SMatt Joras struct unr *up, *uq; 509333dcaa4SMatt Joras 510333dcaa4SMatt Joras KASSERT(TAILQ_EMPTY(&uh->ppfree), 511333dcaa4SMatt Joras ("unrhdr has postponed item for free")); 5120d8e0405SMatt Joras TAILQ_FOREACH_SAFE(up, &uh->head, list, uq) { 513333dcaa4SMatt Joras if (up->ptr != uh) { 514333dcaa4SMatt Joras Free(up->ptr); 515333dcaa4SMatt Joras } 516333dcaa4SMatt Joras Free(up); 517333dcaa4SMatt Joras } 518333dcaa4SMatt Joras uh->busy = 0; 519333dcaa4SMatt Joras uh->alloc = 0; 5200d8e0405SMatt Joras init_unrhdr(uh, uh->low, uh->high, uh->mtx); 5210d8e0405SMatt Joras 5220d8e0405SMatt Joras check_unrhdr(uh, __LINE__); 523333dcaa4SMatt Joras } 524333dcaa4SMatt Joras 525f6bde1fdSPoul-Henning Kamp /* 526d9a54d5cSPoul-Henning Kamp * Look for sequence of items which can be combined into a bitmap, if 527d9a54d5cSPoul-Henning Kamp * multiple are present, take the one which saves most memory. 528d9a54d5cSPoul-Henning Kamp * 529d9a54d5cSPoul-Henning Kamp * Return (1) if a sequence was found to indicate that another call 530d9a54d5cSPoul-Henning Kamp * might be able to do more. Return (0) if we found no suitable sequence. 531d9a54d5cSPoul-Henning Kamp * 532d9a54d5cSPoul-Henning Kamp * NB: called from alloc_unr(), no new memory allocation allowed. 533d9a54d5cSPoul-Henning Kamp */ 534d9a54d5cSPoul-Henning Kamp static int 535d9a54d5cSPoul-Henning Kamp optimize_unr(struct unrhdr *uh) 536d9a54d5cSPoul-Henning Kamp { 537d9a54d5cSPoul-Henning Kamp struct unr *up, *uf, *us; 538d9a54d5cSPoul-Henning Kamp struct unrb *ub, *ubf; 539d9a54d5cSPoul-Henning Kamp u_int a, l, ba; 540d9a54d5cSPoul-Henning Kamp 541d9a54d5cSPoul-Henning Kamp /* 542d9a54d5cSPoul-Henning Kamp * Look for the run of items (if any) which when collapsed into 543d9a54d5cSPoul-Henning Kamp * a bitmap would save most memory. 544d9a54d5cSPoul-Henning Kamp */ 545d9a54d5cSPoul-Henning Kamp us = NULL; 546d9a54d5cSPoul-Henning Kamp ba = 0; 547d9a54d5cSPoul-Henning Kamp TAILQ_FOREACH(uf, &uh->head, list) { 548d9a54d5cSPoul-Henning Kamp if (uf->len >= NBITS) 549d9a54d5cSPoul-Henning Kamp continue; 550d9a54d5cSPoul-Henning Kamp a = 1; 551d9a54d5cSPoul-Henning Kamp if (is_bitmap(uh, uf)) 552d9a54d5cSPoul-Henning Kamp a++; 553d9a54d5cSPoul-Henning Kamp l = uf->len; 554d9a54d5cSPoul-Henning Kamp up = uf; 555d9a54d5cSPoul-Henning Kamp while (1) { 556d9a54d5cSPoul-Henning Kamp up = TAILQ_NEXT(up, list); 557d9a54d5cSPoul-Henning Kamp if (up == NULL) 558d9a54d5cSPoul-Henning Kamp break; 559d9a54d5cSPoul-Henning Kamp if ((up->len + l) > NBITS) 560d9a54d5cSPoul-Henning Kamp break; 561d9a54d5cSPoul-Henning Kamp a++; 562d9a54d5cSPoul-Henning Kamp if (is_bitmap(uh, up)) 563d9a54d5cSPoul-Henning Kamp a++; 564d9a54d5cSPoul-Henning Kamp l += up->len; 565d9a54d5cSPoul-Henning Kamp } 566d9a54d5cSPoul-Henning Kamp if (a > ba) { 567d9a54d5cSPoul-Henning Kamp ba = a; 568d9a54d5cSPoul-Henning Kamp us = uf; 569d9a54d5cSPoul-Henning Kamp } 570d9a54d5cSPoul-Henning Kamp } 571d9a54d5cSPoul-Henning Kamp if (ba < 3) 572d9a54d5cSPoul-Henning Kamp return (0); 573d9a54d5cSPoul-Henning Kamp 574d9a54d5cSPoul-Henning Kamp /* 575d9a54d5cSPoul-Henning Kamp * If the first element is not a bitmap, make it one. 576d9a54d5cSPoul-Henning Kamp * Trying to do so without allocating more memory complicates things 577d9a54d5cSPoul-Henning Kamp * a bit 578d9a54d5cSPoul-Henning Kamp */ 579d9a54d5cSPoul-Henning Kamp if (!is_bitmap(uh, us)) { 580d9a54d5cSPoul-Henning Kamp uf = TAILQ_NEXT(us, list); 581d9a54d5cSPoul-Henning Kamp TAILQ_REMOVE(&uh->head, us, list); 582d9a54d5cSPoul-Henning Kamp a = us->len; 583d9a54d5cSPoul-Henning Kamp l = us->ptr == uh ? 1 : 0; 584d9a54d5cSPoul-Henning Kamp ub = (void *)us; 5858907f744SAlan Somers bit_nclear(ub->map, 0, NBITS - 1); 5868907f744SAlan Somers if (l) 587d9a54d5cSPoul-Henning Kamp bit_nset(ub->map, 0, a); 588d9a54d5cSPoul-Henning Kamp if (!is_bitmap(uh, uf)) { 5898907f744SAlan Somers if (uf->ptr == NULL) 590d9a54d5cSPoul-Henning Kamp bit_nclear(ub->map, a, a + uf->len - 1); 5918907f744SAlan Somers else 592d9a54d5cSPoul-Henning Kamp bit_nset(ub->map, a, a + uf->len - 1); 593d9a54d5cSPoul-Henning Kamp uf->ptr = ub; 594d9a54d5cSPoul-Henning Kamp uf->len += a; 595d9a54d5cSPoul-Henning Kamp us = uf; 596d9a54d5cSPoul-Henning Kamp } else { 597d9a54d5cSPoul-Henning Kamp ubf = uf->ptr; 598d9a54d5cSPoul-Henning Kamp for (l = 0; l < uf->len; l++, a++) { 5998907f744SAlan Somers if (bit_test(ubf->map, l)) 600d9a54d5cSPoul-Henning Kamp bit_set(ub->map, a); 6018907f744SAlan Somers else 602d9a54d5cSPoul-Henning Kamp bit_clear(ub->map, a); 603d9a54d5cSPoul-Henning Kamp } 604d9a54d5cSPoul-Henning Kamp uf->len = a; 605d9a54d5cSPoul-Henning Kamp delete_unr(uh, uf->ptr); 606d9a54d5cSPoul-Henning Kamp uf->ptr = ub; 607d9a54d5cSPoul-Henning Kamp us = uf; 608d9a54d5cSPoul-Henning Kamp } 609d9a54d5cSPoul-Henning Kamp } 610d9a54d5cSPoul-Henning Kamp ub = us->ptr; 611d9a54d5cSPoul-Henning Kamp while (1) { 612d9a54d5cSPoul-Henning Kamp uf = TAILQ_NEXT(us, list); 613d9a54d5cSPoul-Henning Kamp if (uf == NULL) 614d9a54d5cSPoul-Henning Kamp return (1); 615d9a54d5cSPoul-Henning Kamp if (uf->len + us->len > NBITS) 616d9a54d5cSPoul-Henning Kamp return (1); 617d9a54d5cSPoul-Henning Kamp if (uf->ptr == NULL) { 618d9a54d5cSPoul-Henning Kamp bit_nclear(ub->map, us->len, us->len + uf->len - 1); 619d9a54d5cSPoul-Henning Kamp us->len += uf->len; 620d9a54d5cSPoul-Henning Kamp TAILQ_REMOVE(&uh->head, uf, list); 621d9a54d5cSPoul-Henning Kamp delete_unr(uh, uf); 622d9a54d5cSPoul-Henning Kamp } else if (uf->ptr == uh) { 623d9a54d5cSPoul-Henning Kamp bit_nset(ub->map, us->len, us->len + uf->len - 1); 624d9a54d5cSPoul-Henning Kamp us->len += uf->len; 625d9a54d5cSPoul-Henning Kamp TAILQ_REMOVE(&uh->head, uf, list); 626d9a54d5cSPoul-Henning Kamp delete_unr(uh, uf); 627d9a54d5cSPoul-Henning Kamp } else { 628d9a54d5cSPoul-Henning Kamp ubf = uf->ptr; 629d9a54d5cSPoul-Henning Kamp for (l = 0; l < uf->len; l++, us->len++) { 6308907f744SAlan Somers if (bit_test(ubf->map, l)) 631d9a54d5cSPoul-Henning Kamp bit_set(ub->map, us->len); 6328907f744SAlan Somers else 633d9a54d5cSPoul-Henning Kamp bit_clear(ub->map, us->len); 634d9a54d5cSPoul-Henning Kamp } 635d9a54d5cSPoul-Henning Kamp TAILQ_REMOVE(&uh->head, uf, list); 636d9a54d5cSPoul-Henning Kamp delete_unr(uh, ubf); 637d9a54d5cSPoul-Henning Kamp delete_unr(uh, uf); 638d9a54d5cSPoul-Henning Kamp } 639d9a54d5cSPoul-Henning Kamp } 640d9a54d5cSPoul-Henning Kamp } 641d9a54d5cSPoul-Henning Kamp 642d9a54d5cSPoul-Henning Kamp /* 643d9a54d5cSPoul-Henning Kamp * See if a given unr should be collapsed with a neighbor. 644d9a54d5cSPoul-Henning Kamp * 645d9a54d5cSPoul-Henning Kamp * NB: called from alloc_unr(), no new memory allocation allowed. 646f6bde1fdSPoul-Henning Kamp */ 647f6bde1fdSPoul-Henning Kamp static void 648f6bde1fdSPoul-Henning Kamp collapse_unr(struct unrhdr *uh, struct unr *up) 649f6bde1fdSPoul-Henning Kamp { 650f6bde1fdSPoul-Henning Kamp struct unr *upp; 651d9a54d5cSPoul-Henning Kamp struct unrb *ub; 652f6bde1fdSPoul-Henning Kamp 653d9a54d5cSPoul-Henning Kamp /* If bitmap is all set or clear, change it to runlength */ 654d9a54d5cSPoul-Henning Kamp if (is_bitmap(uh, up)) { 655d9a54d5cSPoul-Henning Kamp ub = up->ptr; 6568907f744SAlan Somers if (ub_full(ub, up->len)) { 657d9a54d5cSPoul-Henning Kamp delete_unr(uh, up->ptr); 658d9a54d5cSPoul-Henning Kamp up->ptr = uh; 6598907f744SAlan Somers } else if (ub_empty(ub, up->len)) { 660d9a54d5cSPoul-Henning Kamp delete_unr(uh, up->ptr); 661d9a54d5cSPoul-Henning Kamp up->ptr = NULL; 662d9a54d5cSPoul-Henning Kamp } 663d9a54d5cSPoul-Henning Kamp } 664d9a54d5cSPoul-Henning Kamp 665d9a54d5cSPoul-Henning Kamp /* If nothing left in runlength, delete it */ 666d9a54d5cSPoul-Henning Kamp if (up->len == 0) { 667d9a54d5cSPoul-Henning Kamp upp = TAILQ_PREV(up, unrhd, list); 668d9a54d5cSPoul-Henning Kamp if (upp == NULL) 669d9a54d5cSPoul-Henning Kamp upp = TAILQ_NEXT(up, list); 670d9a54d5cSPoul-Henning Kamp TAILQ_REMOVE(&uh->head, up, list); 671d9a54d5cSPoul-Henning Kamp delete_unr(uh, up); 672d9a54d5cSPoul-Henning Kamp up = upp; 673d9a54d5cSPoul-Henning Kamp } 674d9a54d5cSPoul-Henning Kamp 675d9a54d5cSPoul-Henning Kamp /* If we have "hot-spot" still, merge with neighbor if possible */ 676d9a54d5cSPoul-Henning Kamp if (up != NULL) { 677f6bde1fdSPoul-Henning Kamp upp = TAILQ_PREV(up, unrhd, list); 678f6bde1fdSPoul-Henning Kamp if (upp != NULL && up->ptr == upp->ptr) { 679f6bde1fdSPoul-Henning Kamp up->len += upp->len; 680f6bde1fdSPoul-Henning Kamp TAILQ_REMOVE(&uh->head, upp, list); 681f6bde1fdSPoul-Henning Kamp delete_unr(uh, upp); 682f6bde1fdSPoul-Henning Kamp } 683f6bde1fdSPoul-Henning Kamp upp = TAILQ_NEXT(up, list); 684f6bde1fdSPoul-Henning Kamp if (upp != NULL && up->ptr == upp->ptr) { 685f6bde1fdSPoul-Henning Kamp up->len += upp->len; 686f6bde1fdSPoul-Henning Kamp TAILQ_REMOVE(&uh->head, upp, list); 687f6bde1fdSPoul-Henning Kamp delete_unr(uh, upp); 688f6bde1fdSPoul-Henning Kamp } 689f6bde1fdSPoul-Henning Kamp } 690f6bde1fdSPoul-Henning Kamp 691d9a54d5cSPoul-Henning Kamp /* Merge into ->first if possible */ 692d9a54d5cSPoul-Henning Kamp upp = TAILQ_FIRST(&uh->head); 693d9a54d5cSPoul-Henning Kamp if (upp != NULL && upp->ptr == uh) { 694d9a54d5cSPoul-Henning Kamp uh->first += upp->len; 695d9a54d5cSPoul-Henning Kamp TAILQ_REMOVE(&uh->head, upp, list); 696d9a54d5cSPoul-Henning Kamp delete_unr(uh, upp); 697d9a54d5cSPoul-Henning Kamp if (up == upp) 698d9a54d5cSPoul-Henning Kamp up = NULL; 699d9a54d5cSPoul-Henning Kamp } 700d9a54d5cSPoul-Henning Kamp 701d9a54d5cSPoul-Henning Kamp /* Merge into ->last if possible */ 702d9a54d5cSPoul-Henning Kamp upp = TAILQ_LAST(&uh->head, unrhd); 703d9a54d5cSPoul-Henning Kamp if (upp != NULL && upp->ptr == NULL) { 704d9a54d5cSPoul-Henning Kamp uh->last += upp->len; 705d9a54d5cSPoul-Henning Kamp TAILQ_REMOVE(&uh->head, upp, list); 706d9a54d5cSPoul-Henning Kamp delete_unr(uh, upp); 707d9a54d5cSPoul-Henning Kamp if (up == upp) 708d9a54d5cSPoul-Henning Kamp up = NULL; 709d9a54d5cSPoul-Henning Kamp } 710d9a54d5cSPoul-Henning Kamp 711d9a54d5cSPoul-Henning Kamp /* Try to make bitmaps */ 712d9a54d5cSPoul-Henning Kamp while (optimize_unr(uh)) 713d9a54d5cSPoul-Henning Kamp continue; 714d9a54d5cSPoul-Henning Kamp } 715d9a54d5cSPoul-Henning Kamp 716f6bde1fdSPoul-Henning Kamp /* 717f6bde1fdSPoul-Henning Kamp * Allocate a free unr. 718f6bde1fdSPoul-Henning Kamp */ 719d9a54d5cSPoul-Henning Kamp int 720d9a54d5cSPoul-Henning Kamp alloc_unrl(struct unrhdr *uh) 721f6bde1fdSPoul-Henning Kamp { 722d9a54d5cSPoul-Henning Kamp struct unr *up; 723d9a54d5cSPoul-Henning Kamp struct unrb *ub; 724f6bde1fdSPoul-Henning Kamp u_int x; 725f6bde1fdSPoul-Henning Kamp int y; 726f6bde1fdSPoul-Henning Kamp 727e59b940dSKonstantin Belousov if (uh->mtx != NULL) 728d9a54d5cSPoul-Henning Kamp mtx_assert(uh->mtx, MA_OWNED); 729f6bde1fdSPoul-Henning Kamp check_unrhdr(uh, __LINE__); 730d9a54d5cSPoul-Henning Kamp x = uh->low + uh->first; 731d9a54d5cSPoul-Henning Kamp 732f6bde1fdSPoul-Henning Kamp up = TAILQ_FIRST(&uh->head); 733f6bde1fdSPoul-Henning Kamp 734d9a54d5cSPoul-Henning Kamp /* 735d9a54d5cSPoul-Henning Kamp * If we have an ideal split, just adjust the first+last 736d9a54d5cSPoul-Henning Kamp */ 737d9a54d5cSPoul-Henning Kamp if (up == NULL && uh->last > 0) { 738d9a54d5cSPoul-Henning Kamp uh->first++; 739d9a54d5cSPoul-Henning Kamp uh->last--; 740f6bde1fdSPoul-Henning Kamp uh->busy++; 741f6bde1fdSPoul-Henning Kamp return (x); 742f6bde1fdSPoul-Henning Kamp } 743f6bde1fdSPoul-Henning Kamp 744f6bde1fdSPoul-Henning Kamp /* 745d9a54d5cSPoul-Henning Kamp * We can always allocate from the first list element, so if we have 746d9a54d5cSPoul-Henning Kamp * nothing on the list, we must have run out of unit numbers. 747f6bde1fdSPoul-Henning Kamp */ 74893f6c81eSPoul-Henning Kamp if (up == NULL) 749d9a54d5cSPoul-Henning Kamp return (-1); 750d9a54d5cSPoul-Henning Kamp 751d9a54d5cSPoul-Henning Kamp KASSERT(up->ptr != uh, ("UNR first element is allocated")); 752d9a54d5cSPoul-Henning Kamp 753d9a54d5cSPoul-Henning Kamp if (up->ptr == NULL) { /* free run */ 754d9a54d5cSPoul-Henning Kamp uh->first++; 755f6bde1fdSPoul-Henning Kamp up->len--; 756d9a54d5cSPoul-Henning Kamp } else { /* bitmap */ 757d9a54d5cSPoul-Henning Kamp ub = up->ptr; 758d9a54d5cSPoul-Henning Kamp bit_ffc(ub->map, up->len, &y); 759d9a54d5cSPoul-Henning Kamp KASSERT(y != -1, ("UNR corruption: No clear bit in bitmap.")); 760d9a54d5cSPoul-Henning Kamp bit_set(ub->map, y); 761d9a54d5cSPoul-Henning Kamp x += y; 762d9a54d5cSPoul-Henning Kamp } 763f6bde1fdSPoul-Henning Kamp uh->busy++; 764d9a54d5cSPoul-Henning Kamp collapse_unr(uh, up); 765f6bde1fdSPoul-Henning Kamp return (x); 766f6bde1fdSPoul-Henning Kamp } 767f6bde1fdSPoul-Henning Kamp 768d9a54d5cSPoul-Henning Kamp int 769d9a54d5cSPoul-Henning Kamp alloc_unr(struct unrhdr *uh) 770d9a54d5cSPoul-Henning Kamp { 771d9a54d5cSPoul-Henning Kamp int i; 772d9a54d5cSPoul-Henning Kamp 773e59b940dSKonstantin Belousov if (uh->mtx != NULL) 774d9a54d5cSPoul-Henning Kamp mtx_lock(uh->mtx); 775d9a54d5cSPoul-Henning Kamp i = alloc_unrl(uh); 77609828ba9SKonstantin Belousov clean_unrhdrl(uh); 777e59b940dSKonstantin Belousov if (uh->mtx != NULL) 778d9a54d5cSPoul-Henning Kamp mtx_unlock(uh->mtx); 779d9a54d5cSPoul-Henning Kamp return (i); 780d9a54d5cSPoul-Henning Kamp } 781d9a54d5cSPoul-Henning Kamp 78213c02cbbSJaakko Heinonen static int 78313c02cbbSJaakko Heinonen alloc_unr_specificl(struct unrhdr *uh, u_int item, void **p1, void **p2) 78413c02cbbSJaakko Heinonen { 78513c02cbbSJaakko Heinonen struct unr *up, *upn; 78613c02cbbSJaakko Heinonen struct unrb *ub; 78713c02cbbSJaakko Heinonen u_int i, last, tl; 78813c02cbbSJaakko Heinonen 789e59b940dSKonstantin Belousov if (uh->mtx != NULL) 79013c02cbbSJaakko Heinonen mtx_assert(uh->mtx, MA_OWNED); 79113c02cbbSJaakko Heinonen 79213c02cbbSJaakko Heinonen if (item < uh->low + uh->first || item > uh->high) 79313c02cbbSJaakko Heinonen return (-1); 79413c02cbbSJaakko Heinonen 79513c02cbbSJaakko Heinonen up = TAILQ_FIRST(&uh->head); 79613c02cbbSJaakko Heinonen /* Ideal split. */ 79713c02cbbSJaakko Heinonen if (up == NULL && item - uh->low == uh->first) { 79813c02cbbSJaakko Heinonen uh->first++; 79913c02cbbSJaakko Heinonen uh->last--; 80013c02cbbSJaakko Heinonen uh->busy++; 80113c02cbbSJaakko Heinonen check_unrhdr(uh, __LINE__); 80213c02cbbSJaakko Heinonen return (item); 80313c02cbbSJaakko Heinonen } 80413c02cbbSJaakko Heinonen 80513c02cbbSJaakko Heinonen i = item - uh->low - uh->first; 80613c02cbbSJaakko Heinonen 80713c02cbbSJaakko Heinonen if (up == NULL) { 80813c02cbbSJaakko Heinonen up = new_unr(uh, p1, p2); 80913c02cbbSJaakko Heinonen up->ptr = NULL; 81013c02cbbSJaakko Heinonen up->len = i; 81113c02cbbSJaakko Heinonen TAILQ_INSERT_TAIL(&uh->head, up, list); 81213c02cbbSJaakko Heinonen up = new_unr(uh, p1, p2); 81313c02cbbSJaakko Heinonen up->ptr = uh; 81413c02cbbSJaakko Heinonen up->len = 1; 81513c02cbbSJaakko Heinonen TAILQ_INSERT_TAIL(&uh->head, up, list); 81613c02cbbSJaakko Heinonen uh->last = uh->high - uh->low - i; 81713c02cbbSJaakko Heinonen uh->busy++; 81813c02cbbSJaakko Heinonen check_unrhdr(uh, __LINE__); 81913c02cbbSJaakko Heinonen return (item); 82013c02cbbSJaakko Heinonen } else { 82113c02cbbSJaakko Heinonen /* Find the item which contains the unit we want to allocate. */ 82213c02cbbSJaakko Heinonen TAILQ_FOREACH(up, &uh->head, list) { 82313c02cbbSJaakko Heinonen if (up->len > i) 82413c02cbbSJaakko Heinonen break; 82513c02cbbSJaakko Heinonen i -= up->len; 82613c02cbbSJaakko Heinonen } 82713c02cbbSJaakko Heinonen } 82813c02cbbSJaakko Heinonen 82913c02cbbSJaakko Heinonen if (up == NULL) { 83013c02cbbSJaakko Heinonen if (i > 0) { 83113c02cbbSJaakko Heinonen up = new_unr(uh, p1, p2); 83213c02cbbSJaakko Heinonen up->ptr = NULL; 83313c02cbbSJaakko Heinonen up->len = i; 83413c02cbbSJaakko Heinonen TAILQ_INSERT_TAIL(&uh->head, up, list); 83513c02cbbSJaakko Heinonen } 83613c02cbbSJaakko Heinonen up = new_unr(uh, p1, p2); 83713c02cbbSJaakko Heinonen up->ptr = uh; 83813c02cbbSJaakko Heinonen up->len = 1; 83913c02cbbSJaakko Heinonen TAILQ_INSERT_TAIL(&uh->head, up, list); 84013c02cbbSJaakko Heinonen goto done; 84113c02cbbSJaakko Heinonen } 84213c02cbbSJaakko Heinonen 84313c02cbbSJaakko Heinonen if (is_bitmap(uh, up)) { 84413c02cbbSJaakko Heinonen ub = up->ptr; 84513c02cbbSJaakko Heinonen if (bit_test(ub->map, i) == 0) { 84613c02cbbSJaakko Heinonen bit_set(ub->map, i); 84713c02cbbSJaakko Heinonen goto done; 84813c02cbbSJaakko Heinonen } else 84913c02cbbSJaakko Heinonen return (-1); 85013c02cbbSJaakko Heinonen } else if (up->ptr == uh) 85113c02cbbSJaakko Heinonen return (-1); 85213c02cbbSJaakko Heinonen 85313c02cbbSJaakko Heinonen KASSERT(up->ptr == NULL, 85413c02cbbSJaakko Heinonen ("alloc_unr_specificl: up->ptr != NULL (up=%p)", up)); 85513c02cbbSJaakko Heinonen 85613c02cbbSJaakko Heinonen /* Split off the tail end, if any. */ 85713c02cbbSJaakko Heinonen tl = up->len - (1 + i); 85813c02cbbSJaakko Heinonen if (tl > 0) { 85913c02cbbSJaakko Heinonen upn = new_unr(uh, p1, p2); 86013c02cbbSJaakko Heinonen upn->ptr = NULL; 86113c02cbbSJaakko Heinonen upn->len = tl; 86213c02cbbSJaakko Heinonen TAILQ_INSERT_AFTER(&uh->head, up, upn, list); 86313c02cbbSJaakko Heinonen } 86413c02cbbSJaakko Heinonen 86513c02cbbSJaakko Heinonen /* Split off head end, if any */ 86613c02cbbSJaakko Heinonen if (i > 0) { 86713c02cbbSJaakko Heinonen upn = new_unr(uh, p1, p2); 86813c02cbbSJaakko Heinonen upn->len = i; 86913c02cbbSJaakko Heinonen upn->ptr = NULL; 87013c02cbbSJaakko Heinonen TAILQ_INSERT_BEFORE(up, upn, list); 87113c02cbbSJaakko Heinonen } 87213c02cbbSJaakko Heinonen up->len = 1; 87313c02cbbSJaakko Heinonen up->ptr = uh; 87413c02cbbSJaakko Heinonen 87513c02cbbSJaakko Heinonen done: 87613c02cbbSJaakko Heinonen last = uh->high - uh->low - (item - uh->low); 87713c02cbbSJaakko Heinonen if (uh->last > last) 87813c02cbbSJaakko Heinonen uh->last = last; 87913c02cbbSJaakko Heinonen uh->busy++; 88013c02cbbSJaakko Heinonen collapse_unr(uh, up); 88113c02cbbSJaakko Heinonen check_unrhdr(uh, __LINE__); 88213c02cbbSJaakko Heinonen return (item); 88313c02cbbSJaakko Heinonen } 88413c02cbbSJaakko Heinonen 88513c02cbbSJaakko Heinonen int 88613c02cbbSJaakko Heinonen alloc_unr_specific(struct unrhdr *uh, u_int item) 88713c02cbbSJaakko Heinonen { 88813c02cbbSJaakko Heinonen void *p1, *p2; 88913c02cbbSJaakko Heinonen int i; 89013c02cbbSJaakko Heinonen 89113c02cbbSJaakko Heinonen WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, "alloc_unr_specific"); 89213c02cbbSJaakko Heinonen 89313c02cbbSJaakko Heinonen p1 = Malloc(sizeof(struct unr)); 89413c02cbbSJaakko Heinonen p2 = Malloc(sizeof(struct unr)); 89513c02cbbSJaakko Heinonen 896e59b940dSKonstantin Belousov if (uh->mtx != NULL) 89713c02cbbSJaakko Heinonen mtx_lock(uh->mtx); 89813c02cbbSJaakko Heinonen i = alloc_unr_specificl(uh, item, &p1, &p2); 899e59b940dSKonstantin Belousov if (uh->mtx != NULL) 90013c02cbbSJaakko Heinonen mtx_unlock(uh->mtx); 90113c02cbbSJaakko Heinonen 90213c02cbbSJaakko Heinonen if (p1 != NULL) 90313c02cbbSJaakko Heinonen Free(p1); 90413c02cbbSJaakko Heinonen if (p2 != NULL) 90513c02cbbSJaakko Heinonen Free(p2); 90613c02cbbSJaakko Heinonen 90713c02cbbSJaakko Heinonen return (i); 90813c02cbbSJaakko Heinonen } 90913c02cbbSJaakko Heinonen 910f6bde1fdSPoul-Henning Kamp /* 911f6bde1fdSPoul-Henning Kamp * Free a unr. 912f6bde1fdSPoul-Henning Kamp * 913f6bde1fdSPoul-Henning Kamp * If we can save unrs by using a bitmap, do so. 914f6bde1fdSPoul-Henning Kamp */ 915d9a54d5cSPoul-Henning Kamp static void 916d9a54d5cSPoul-Henning Kamp free_unrl(struct unrhdr *uh, u_int item, void **p1, void **p2) 917f6bde1fdSPoul-Henning Kamp { 918d9a54d5cSPoul-Henning Kamp struct unr *up, *upp, *upn; 919d9a54d5cSPoul-Henning Kamp struct unrb *ub; 920d9a54d5cSPoul-Henning Kamp u_int pl; 921f6bde1fdSPoul-Henning Kamp 922f6bde1fdSPoul-Henning Kamp KASSERT(item >= uh->low && item <= uh->high, 923f6bde1fdSPoul-Henning Kamp ("UNR: free_unr(%u) out of range [%u...%u]", 924f6bde1fdSPoul-Henning Kamp item, uh->low, uh->high)); 925f6bde1fdSPoul-Henning Kamp check_unrhdr(uh, __LINE__); 926f6bde1fdSPoul-Henning Kamp item -= uh->low; 927d9a54d5cSPoul-Henning Kamp upp = TAILQ_FIRST(&uh->head); 928f6bde1fdSPoul-Henning Kamp /* 929d9a54d5cSPoul-Henning Kamp * Freeing in the ideal split case 930f6bde1fdSPoul-Henning Kamp */ 931d9a54d5cSPoul-Henning Kamp if (item + 1 == uh->first && upp == NULL) { 932d9a54d5cSPoul-Henning Kamp uh->last++; 933d9a54d5cSPoul-Henning Kamp uh->first--; 934d9a54d5cSPoul-Henning Kamp uh->busy--; 935f6bde1fdSPoul-Henning Kamp check_unrhdr(uh, __LINE__); 936f6bde1fdSPoul-Henning Kamp return; 937f6bde1fdSPoul-Henning Kamp } 938d9a54d5cSPoul-Henning Kamp /* 939d9a54d5cSPoul-Henning Kamp * Freeing in the ->first section. Create a run starting at the 940d9a54d5cSPoul-Henning Kamp * freed item. The code below will subdivide it. 941d9a54d5cSPoul-Henning Kamp */ 942d9a54d5cSPoul-Henning Kamp if (item < uh->first) { 943d9a54d5cSPoul-Henning Kamp up = new_unr(uh, p1, p2); 944d9a54d5cSPoul-Henning Kamp up->ptr = uh; 945d9a54d5cSPoul-Henning Kamp up->len = uh->first - item; 946d9a54d5cSPoul-Henning Kamp TAILQ_INSERT_HEAD(&uh->head, up, list); 947d9a54d5cSPoul-Henning Kamp uh->first -= up->len; 948f6bde1fdSPoul-Henning Kamp } 949f6bde1fdSPoul-Henning Kamp 950d9a54d5cSPoul-Henning Kamp item -= uh->first; 951d9a54d5cSPoul-Henning Kamp 952d9a54d5cSPoul-Henning Kamp /* Find the item which contains the unit we want to free */ 953d9a54d5cSPoul-Henning Kamp TAILQ_FOREACH(up, &uh->head, list) { 954d9a54d5cSPoul-Henning Kamp if (up->len > item) 955d9a54d5cSPoul-Henning Kamp break; 956d9a54d5cSPoul-Henning Kamp item -= up->len; 957d9a54d5cSPoul-Henning Kamp } 958d9a54d5cSPoul-Henning Kamp 959d9a54d5cSPoul-Henning Kamp /* Handle bitmap items */ 960d9a54d5cSPoul-Henning Kamp if (is_bitmap(uh, up)) { 961d9a54d5cSPoul-Henning Kamp ub = up->ptr; 962d9a54d5cSPoul-Henning Kamp 963d9a54d5cSPoul-Henning Kamp KASSERT(bit_test(ub->map, item) != 0, 964d9a54d5cSPoul-Henning Kamp ("UNR: Freeing free item %d (bitmap)\n", item)); 965d9a54d5cSPoul-Henning Kamp bit_clear(ub->map, item); 966d9a54d5cSPoul-Henning Kamp uh->busy--; 967d9a54d5cSPoul-Henning Kamp collapse_unr(uh, up); 968d9a54d5cSPoul-Henning Kamp return; 969d9a54d5cSPoul-Henning Kamp } 970d9a54d5cSPoul-Henning Kamp 971d9a54d5cSPoul-Henning Kamp KASSERT(up->ptr == uh, ("UNR Freeing free item %d (run))\n", item)); 972f6bde1fdSPoul-Henning Kamp 973f6bde1fdSPoul-Henning Kamp /* Just this one left, reap it */ 974f6bde1fdSPoul-Henning Kamp if (up->len == 1) { 975f6bde1fdSPoul-Henning Kamp up->ptr = NULL; 976f6bde1fdSPoul-Henning Kamp uh->busy--; 977f6bde1fdSPoul-Henning Kamp collapse_unr(uh, up); 978f6bde1fdSPoul-Henning Kamp return; 979f6bde1fdSPoul-Henning Kamp } 980f6bde1fdSPoul-Henning Kamp 981d9a54d5cSPoul-Henning Kamp /* Check if we can shift the item into the previous 'free' run */ 982f6bde1fdSPoul-Henning Kamp upp = TAILQ_PREV(up, unrhd, list); 983d9a54d5cSPoul-Henning Kamp if (item == 0 && upp != NULL && upp->ptr == NULL) { 984f6bde1fdSPoul-Henning Kamp upp->len++; 985f6bde1fdSPoul-Henning Kamp up->len--; 986f6bde1fdSPoul-Henning Kamp uh->busy--; 987d9a54d5cSPoul-Henning Kamp collapse_unr(uh, up); 988f6bde1fdSPoul-Henning Kamp return; 989f6bde1fdSPoul-Henning Kamp } 990f6bde1fdSPoul-Henning Kamp 991d9a54d5cSPoul-Henning Kamp /* Check if we can shift the item to the next 'free' run */ 992f6bde1fdSPoul-Henning Kamp upn = TAILQ_NEXT(up, list); 993d9a54d5cSPoul-Henning Kamp if (item == up->len - 1 && upn != NULL && upn->ptr == NULL) { 994f6bde1fdSPoul-Henning Kamp upn->len++; 995f6bde1fdSPoul-Henning Kamp up->len--; 996f6bde1fdSPoul-Henning Kamp uh->busy--; 997d9a54d5cSPoul-Henning Kamp collapse_unr(uh, up); 998f6bde1fdSPoul-Henning Kamp return; 999f6bde1fdSPoul-Henning Kamp } 1000f6bde1fdSPoul-Henning Kamp 1001f6bde1fdSPoul-Henning Kamp /* Split off the tail end, if any. */ 1002d9a54d5cSPoul-Henning Kamp pl = up->len - (1 + item); 1003f6bde1fdSPoul-Henning Kamp if (pl > 0) { 1004d9a54d5cSPoul-Henning Kamp upp = new_unr(uh, p1, p2); 1005f6bde1fdSPoul-Henning Kamp upp->ptr = uh; 1006f6bde1fdSPoul-Henning Kamp upp->len = pl; 1007f6bde1fdSPoul-Henning Kamp TAILQ_INSERT_AFTER(&uh->head, up, upp, list); 1008f6bde1fdSPoul-Henning Kamp } 1009f6bde1fdSPoul-Henning Kamp 1010d9a54d5cSPoul-Henning Kamp /* Split off head end, if any */ 1011d9a54d5cSPoul-Henning Kamp if (item > 0) { 1012d9a54d5cSPoul-Henning Kamp upp = new_unr(uh, p1, p2); 1013d9a54d5cSPoul-Henning Kamp upp->len = item; 1014d9a54d5cSPoul-Henning Kamp upp->ptr = uh; 1015d9a54d5cSPoul-Henning Kamp TAILQ_INSERT_BEFORE(up, upp, list); 1016d9a54d5cSPoul-Henning Kamp } 1017f6bde1fdSPoul-Henning Kamp up->len = 1; 1018f6bde1fdSPoul-Henning Kamp up->ptr = NULL; 1019f6bde1fdSPoul-Henning Kamp uh->busy--; 1020d9a54d5cSPoul-Henning Kamp collapse_unr(uh, up); 1021f6bde1fdSPoul-Henning Kamp } 1022f6bde1fdSPoul-Henning Kamp 1023d9a54d5cSPoul-Henning Kamp void 1024d9a54d5cSPoul-Henning Kamp free_unr(struct unrhdr *uh, u_int item) 1025d9a54d5cSPoul-Henning Kamp { 1026d9a54d5cSPoul-Henning Kamp void *p1, *p2; 1027f6bde1fdSPoul-Henning Kamp 10287550e3eaSKonstantin Belousov WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, "free_unr"); 1029d9a54d5cSPoul-Henning Kamp p1 = Malloc(sizeof(struct unr)); 1030d9a54d5cSPoul-Henning Kamp p2 = Malloc(sizeof(struct unr)); 1031e59b940dSKonstantin Belousov if (uh->mtx != NULL) 1032d9a54d5cSPoul-Henning Kamp mtx_lock(uh->mtx); 1033d9a54d5cSPoul-Henning Kamp free_unrl(uh, item, &p1, &p2); 103409828ba9SKonstantin Belousov clean_unrhdrl(uh); 1035e59b940dSKonstantin Belousov if (uh->mtx != NULL) 1036d9a54d5cSPoul-Henning Kamp mtx_unlock(uh->mtx); 1037d9a54d5cSPoul-Henning Kamp if (p1 != NULL) 1038d9a54d5cSPoul-Henning Kamp Free(p1); 1039d9a54d5cSPoul-Henning Kamp if (p2 != NULL) 1040d9a54d5cSPoul-Henning Kamp Free(p2); 1041f6bde1fdSPoul-Henning Kamp } 1042f6bde1fdSPoul-Henning Kamp 1043f386b277SKonstantin Belousov #ifdef _KERNEL 1044f386b277SKonstantin Belousov #include "opt_ddb.h" 1045f386b277SKonstantin Belousov #ifdef DDB 1046f386b277SKonstantin Belousov #include <ddb/ddb.h> 1047f386b277SKonstantin Belousov #endif 1048f386b277SKonstantin Belousov #endif 104993f6c81eSPoul-Henning Kamp 1050f386b277SKonstantin Belousov #if (defined(_KERNEL) && defined(DDB)) || !defined(_KERNEL) 1051f6bde1fdSPoul-Henning Kamp 1052f386b277SKonstantin Belousov #if !defined(_KERNEL) 1053f386b277SKonstantin Belousov #define db_printf printf 1054f386b277SKonstantin Belousov #endif 1055794277daSAlan Somers 1056f6bde1fdSPoul-Henning Kamp static void 1057f6bde1fdSPoul-Henning Kamp print_unr(struct unrhdr *uh, struct unr *up) 1058f6bde1fdSPoul-Henning Kamp { 1059f6bde1fdSPoul-Henning Kamp u_int x; 1060d9a54d5cSPoul-Henning Kamp struct unrb *ub; 1061f6bde1fdSPoul-Henning Kamp 1062f386b277SKonstantin Belousov db_printf(" %p len = %5u ", up, up->len); 1063f6bde1fdSPoul-Henning Kamp if (up->ptr == NULL) 1064f386b277SKonstantin Belousov db_printf("free\n"); 1065f6bde1fdSPoul-Henning Kamp else if (up->ptr == uh) 1066f386b277SKonstantin Belousov db_printf("alloc\n"); 1067f6bde1fdSPoul-Henning Kamp else { 1068d9a54d5cSPoul-Henning Kamp ub = up->ptr; 1069f386b277SKonstantin Belousov db_printf("bitmap ["); 1070d9a54d5cSPoul-Henning Kamp for (x = 0; x < up->len; x++) { 1071d9a54d5cSPoul-Henning Kamp if (bit_test(ub->map, x)) 1072f386b277SKonstantin Belousov db_printf("#"); 1073f6bde1fdSPoul-Henning Kamp else 1074f386b277SKonstantin Belousov db_printf(" "); 1075f6bde1fdSPoul-Henning Kamp } 1076f386b277SKonstantin Belousov db_printf("]\n"); 1077f6bde1fdSPoul-Henning Kamp } 1078f6bde1fdSPoul-Henning Kamp } 1079f6bde1fdSPoul-Henning Kamp 1080f6bde1fdSPoul-Henning Kamp static void 1081f6bde1fdSPoul-Henning Kamp print_unrhdr(struct unrhdr *uh) 1082f6bde1fdSPoul-Henning Kamp { 1083f6bde1fdSPoul-Henning Kamp struct unr *up; 1084f6bde1fdSPoul-Henning Kamp u_int x; 1085f6bde1fdSPoul-Henning Kamp 1086f386b277SKonstantin Belousov db_printf( 1087d9a54d5cSPoul-Henning Kamp "%p low = %u high = %u first = %u last = %u busy %u chunks = %u\n", 1088d9a54d5cSPoul-Henning Kamp uh, uh->low, uh->high, uh->first, uh->last, uh->busy, uh->alloc); 1089d9a54d5cSPoul-Henning Kamp x = uh->low + uh->first; 1090f6bde1fdSPoul-Henning Kamp TAILQ_FOREACH(up, &uh->head, list) { 1091f386b277SKonstantin Belousov db_printf(" from = %5u", x); 1092f6bde1fdSPoul-Henning Kamp print_unr(uh, up); 1093f6bde1fdSPoul-Henning Kamp if (up->ptr == NULL || up->ptr == uh) 1094f6bde1fdSPoul-Henning Kamp x += up->len; 1095f6bde1fdSPoul-Henning Kamp else 1096f6bde1fdSPoul-Henning Kamp x += NBITS; 1097f6bde1fdSPoul-Henning Kamp } 1098f6bde1fdSPoul-Henning Kamp } 1099f6bde1fdSPoul-Henning Kamp 1100f386b277SKonstantin Belousov #endif 1101f386b277SKonstantin Belousov 1102f386b277SKonstantin Belousov #if defined(_KERNEL) && defined(DDB) 1103f386b277SKonstantin Belousov DB_SHOW_COMMAND(unrhdr, unrhdr_print_unrhdr) 1104f386b277SKonstantin Belousov { 1105f386b277SKonstantin Belousov if (!have_addr) { 1106f386b277SKonstantin Belousov db_printf("show unrhdr addr\n"); 1107f386b277SKonstantin Belousov return; 1108f386b277SKonstantin Belousov } 1109f386b277SKonstantin Belousov 1110f386b277SKonstantin Belousov print_unrhdr((struct unrhdr *)addr); 1111f386b277SKonstantin Belousov } 1112c4cc0cabSKonstantin Belousov 1113c4cc0cabSKonstantin Belousov static void 1114c4cc0cabSKonstantin Belousov print_unrhdr_iter(struct unrhdr_iter *iter) 1115c4cc0cabSKonstantin Belousov { 1116c4cc0cabSKonstantin Belousov db_printf("iter %p unrhdr %p ipos %d upos %p ufi %d\n", 1117c4cc0cabSKonstantin Belousov iter, iter->uh, iter->ipos, iter->upos, iter->upos_first_item); 1118c4cc0cabSKonstantin Belousov } 1119c4cc0cabSKonstantin Belousov 1120c4cc0cabSKonstantin Belousov DB_SHOW_COMMAND(unrhdr_iter, unrhdr_print_iter) 1121c4cc0cabSKonstantin Belousov { 1122c4cc0cabSKonstantin Belousov if (!have_addr) { 1123c4cc0cabSKonstantin Belousov db_printf("show unrhdr_iter addr\n"); 1124c4cc0cabSKonstantin Belousov return; 1125c4cc0cabSKonstantin Belousov } 1126c4cc0cabSKonstantin Belousov 1127c4cc0cabSKonstantin Belousov print_unrhdr_iter((struct unrhdr_iter *)addr); 1128c4cc0cabSKonstantin Belousov } 1129f386b277SKonstantin Belousov #endif 1130f386b277SKonstantin Belousov 1131f386b277SKonstantin Belousov #ifndef _KERNEL /* USERLAND test driver */ 1132f386b277SKonstantin Belousov 1133f386b277SKonstantin Belousov /* 1134f386b277SKonstantin Belousov * Simple stochastic test driver for the above functions. The code resides 1135f386b277SKonstantin Belousov * here so that it can access static functions and structures. 1136f386b277SKonstantin Belousov */ 1137f386b277SKonstantin Belousov 1138f386b277SKonstantin Belousov static bool verbose; 1139f386b277SKonstantin Belousov #define VPRINTF(...) {if (verbose) printf(__VA_ARGS__);} 1140f386b277SKonstantin Belousov 114113c02cbbSJaakko Heinonen static void 114213c02cbbSJaakko Heinonen test_alloc_unr(struct unrhdr *uh, u_int i, char a[]) 114313c02cbbSJaakko Heinonen { 114413c02cbbSJaakko Heinonen int j; 114513c02cbbSJaakko Heinonen 114613c02cbbSJaakko Heinonen if (a[i]) { 1147794277daSAlan Somers VPRINTF("F %u\n", i); 114813c02cbbSJaakko Heinonen free_unr(uh, i); 114913c02cbbSJaakko Heinonen a[i] = 0; 115013c02cbbSJaakko Heinonen } else { 115113c02cbbSJaakko Heinonen no_alloc = 1; 115213c02cbbSJaakko Heinonen j = alloc_unr(uh); 115313c02cbbSJaakko Heinonen if (j != -1) { 115413c02cbbSJaakko Heinonen a[j] = 1; 1155794277daSAlan Somers VPRINTF("A %d\n", j); 115613c02cbbSJaakko Heinonen } 115713c02cbbSJaakko Heinonen no_alloc = 0; 115813c02cbbSJaakko Heinonen } 115913c02cbbSJaakko Heinonen } 116013c02cbbSJaakko Heinonen 116113c02cbbSJaakko Heinonen static void 116213c02cbbSJaakko Heinonen test_alloc_unr_specific(struct unrhdr *uh, u_int i, char a[]) 116313c02cbbSJaakko Heinonen { 116413c02cbbSJaakko Heinonen int j; 116513c02cbbSJaakko Heinonen 116613c02cbbSJaakko Heinonen j = alloc_unr_specific(uh, i); 116713c02cbbSJaakko Heinonen if (j == -1) { 1168794277daSAlan Somers VPRINTF("F %u\n", i); 116913c02cbbSJaakko Heinonen a[i] = 0; 117013c02cbbSJaakko Heinonen free_unr(uh, i); 117113c02cbbSJaakko Heinonen } else { 117213c02cbbSJaakko Heinonen a[i] = 1; 1173794277daSAlan Somers VPRINTF("A %d\n", j); 117413c02cbbSJaakko Heinonen } 117513c02cbbSJaakko Heinonen } 117613c02cbbSJaakko Heinonen 117712db3c91SKonstantin Belousov #define TBASE 7 117812db3c91SKonstantin Belousov #define XSIZE 10 117912db3c91SKonstantin Belousov #define ISIZE 1000 118012db3c91SKonstantin Belousov 118112db3c91SKonstantin Belousov static int 118212db3c91SKonstantin Belousov test_iter_compar(const void *a, const void *b) 118312db3c91SKonstantin Belousov { 118412db3c91SKonstantin Belousov return (*(const int *)a - *(const int *)b); 118512db3c91SKonstantin Belousov } 118612db3c91SKonstantin Belousov 118712db3c91SKonstantin Belousov static void 118812db3c91SKonstantin Belousov test_iter_fill(int *vals, struct unrhdr *uh, int i, int v, int *res) 118912db3c91SKonstantin Belousov { 119012db3c91SKonstantin Belousov int x; 119112db3c91SKonstantin Belousov 119212db3c91SKonstantin Belousov vals[i] = v; 119312db3c91SKonstantin Belousov x = alloc_unr_specific(uh, v); 119412db3c91SKonstantin Belousov if (x != v) { 119512db3c91SKonstantin Belousov VPRINTF("alloc_unr_specific failed %d %d\n", x, v); 119612db3c91SKonstantin Belousov *res = 1; 119712db3c91SKonstantin Belousov } 119812db3c91SKonstantin Belousov } 119912db3c91SKonstantin Belousov 1200794277daSAlan Somers static void 1201a014e0a3SKonstantin Belousov test_iter(void) 1202a014e0a3SKonstantin Belousov { 120312db3c91SKonstantin Belousov struct unrhdr *uh; 120412db3c91SKonstantin Belousov void *ihandle; 120512db3c91SKonstantin Belousov int vals[ISIZE]; 120612db3c91SKonstantin Belousov int i, j, v, x, res; 120712db3c91SKonstantin Belousov 120812db3c91SKonstantin Belousov res = 0; 120912db3c91SKonstantin Belousov uh = new_unrhdr(TBASE, INT_MAX, NULL); 121012db3c91SKonstantin Belousov for (i = 0; i < XSIZE; i++) { 121112db3c91SKonstantin Belousov vals[i] = i + TBASE; 121212db3c91SKonstantin Belousov x = alloc_unr_specific(uh, i + TBASE); 121312db3c91SKonstantin Belousov if (x != i + TBASE) { 121412db3c91SKonstantin Belousov VPRINTF("alloc_unr_specific failed %d %d\n", x, 121512db3c91SKonstantin Belousov i + TBASE); 121612db3c91SKonstantin Belousov res = 1; 121712db3c91SKonstantin Belousov } 121812db3c91SKonstantin Belousov } 121912db3c91SKonstantin Belousov for (; i < ISIZE; i++) { 122012db3c91SKonstantin Belousov for (;;) { 122112db3c91SKonstantin Belousov again: 122212db3c91SKonstantin Belousov v = arc4random_uniform(INT_MAX); 122312db3c91SKonstantin Belousov if (v < TBASE) 122412db3c91SKonstantin Belousov goto again; 122512db3c91SKonstantin Belousov for (j = 0; j < i; j++) { 122612db3c91SKonstantin Belousov if (v == vals[j] || v + 1 == vals[j]) 122712db3c91SKonstantin Belousov goto again; 122812db3c91SKonstantin Belousov } 122912db3c91SKonstantin Belousov break; 123012db3c91SKonstantin Belousov } 123112db3c91SKonstantin Belousov test_iter_fill(vals, uh, i, v, &res); 123212db3c91SKonstantin Belousov i++, v++; 123312db3c91SKonstantin Belousov if (i < ISIZE) 123412db3c91SKonstantin Belousov test_iter_fill(vals, uh, i, v, &res); 123512db3c91SKonstantin Belousov } 123612db3c91SKonstantin Belousov qsort(vals, ISIZE, sizeof(vals[0]), test_iter_compar); 123712db3c91SKonstantin Belousov 123812db3c91SKonstantin Belousov ihandle = create_iter_unr(uh); 123912db3c91SKonstantin Belousov i = 0; 124012db3c91SKonstantin Belousov while ((v = next_iter_unr(ihandle)) != -1) { 124112db3c91SKonstantin Belousov if (vals[i] != v) { 124212db3c91SKonstantin Belousov VPRINTF("iter %d: iter %d != val %d\n", i, v, vals[i]); 124312db3c91SKonstantin Belousov if (res == 0) { 124412db3c91SKonstantin Belousov if (verbose) 124512db3c91SKonstantin Belousov print_unrhdr(uh); 124612db3c91SKonstantin Belousov res = 1; 124712db3c91SKonstantin Belousov } 124812db3c91SKonstantin Belousov } else { 124912db3c91SKonstantin Belousov VPRINTF("iter %d: val %d\n", i, v); 125012db3c91SKonstantin Belousov } 125112db3c91SKonstantin Belousov i++; 125212db3c91SKonstantin Belousov } 125312db3c91SKonstantin Belousov free_iter_unr(ihandle); 125412db3c91SKonstantin Belousov clean_unrhdr(uh); 125512db3c91SKonstantin Belousov clear_unrhdr(uh); 125612db3c91SKonstantin Belousov delete_unrhdr(uh); 125712db3c91SKonstantin Belousov exit(res); 1258a014e0a3SKonstantin Belousov } 1259a014e0a3SKonstantin Belousov 1260a014e0a3SKonstantin Belousov static void 1261794277daSAlan Somers usage(char **argv) 1262794277daSAlan Somers { 126312db3c91SKonstantin Belousov printf("%s [-h] [-i] [-r REPETITIONS] [-v]\n", argv[0]); 1264794277daSAlan Somers } 1265f6bde1fdSPoul-Henning Kamp 1266f6bde1fdSPoul-Henning Kamp int 1267794277daSAlan Somers main(int argc, char **argv) 1268f6bde1fdSPoul-Henning Kamp { 1269f6bde1fdSPoul-Henning Kamp struct unrhdr *uh; 1270794277daSAlan Somers char *a; 1271794277daSAlan Somers long count = 10000; /* Number of unrs to test */ 127237f32e53SAlan Somers long reps = 1, m; 1273794277daSAlan Somers int ch; 1274cd565040SConrad Meyer u_int i; 127512db3c91SKonstantin Belousov bool testing_iter; 1276794277daSAlan Somers 1277794277daSAlan Somers verbose = false; 127812db3c91SKonstantin Belousov testing_iter = false; 1279794277daSAlan Somers 128012db3c91SKonstantin Belousov while ((ch = getopt(argc, argv, "hir:v")) != -1) { 1281794277daSAlan Somers switch (ch) { 128212db3c91SKonstantin Belousov case 'i': 128312db3c91SKonstantin Belousov testing_iter = true; 128412db3c91SKonstantin Belousov break; 1285794277daSAlan Somers case 'r': 1286794277daSAlan Somers errno = 0; 1287794277daSAlan Somers reps = strtol(optarg, NULL, 0); 1288794277daSAlan Somers if (errno == ERANGE || errno == EINVAL) { 1289794277daSAlan Somers usage(argv); 1290794277daSAlan Somers exit(2); 1291794277daSAlan Somers } 1292794277daSAlan Somers 1293794277daSAlan Somers break; 1294794277daSAlan Somers case 'v': 1295794277daSAlan Somers verbose = true; 1296794277daSAlan Somers break; 1297794277daSAlan Somers case 'h': 1298794277daSAlan Somers default: 1299794277daSAlan Somers usage(argv); 1300794277daSAlan Somers exit(2); 1301794277daSAlan Somers } 1302794277daSAlan Somers } 1303f6bde1fdSPoul-Henning Kamp 1304d9a54d5cSPoul-Henning Kamp setbuf(stdout, NULL); 130512db3c91SKonstantin Belousov 130612db3c91SKonstantin Belousov if (testing_iter) 130712db3c91SKonstantin Belousov test_iter(); 130812db3c91SKonstantin Belousov 1309794277daSAlan Somers uh = new_unrhdr(0, count - 1, NULL); 1310d9a54d5cSPoul-Henning Kamp print_unrhdr(uh); 1311f6bde1fdSPoul-Henning Kamp 1312794277daSAlan Somers a = calloc(count, sizeof(char)); 1313794277daSAlan Somers if (a == NULL) 1314794277daSAlan Somers err(1, "calloc failed"); 1315f6bde1fdSPoul-Henning Kamp 1316794277daSAlan Somers printf("sizeof(struct unr) %zu\n", sizeof(struct unr)); 1317794277daSAlan Somers printf("sizeof(struct unrb) %zu\n", sizeof(struct unrb)); 1318794277daSAlan Somers printf("sizeof(struct unrhdr) %zu\n", sizeof(struct unrhdr)); 1319b4f69365SEd Maste printf("NBITS %lu\n", (unsigned long)NBITS); 1320794277daSAlan Somers for (m = 0; m < count * reps; m++) { 1321cd565040SConrad Meyer i = arc4random_uniform(count); 1322d9a54d5cSPoul-Henning Kamp #if 0 1323d9a54d5cSPoul-Henning Kamp if (a[i] && (j & 1)) 1324d9a54d5cSPoul-Henning Kamp continue; 1325d9a54d5cSPoul-Henning Kamp #endif 1326cd565040SConrad Meyer if ((arc4random() & 1) != 0) 132713c02cbbSJaakko Heinonen test_alloc_unr(uh, i, a); 132813c02cbbSJaakko Heinonen else 132913c02cbbSJaakko Heinonen test_alloc_unr_specific(uh, i, a); 133013c02cbbSJaakko Heinonen 1331794277daSAlan Somers if (verbose) 1332f6bde1fdSPoul-Henning Kamp print_unrhdr(uh); 1333f6bde1fdSPoul-Henning Kamp check_unrhdr(uh, __LINE__); 1334f6bde1fdSPoul-Henning Kamp } 133537f32e53SAlan Somers for (i = 0; i < (u_int)count; i++) { 1336d9a54d5cSPoul-Henning Kamp if (a[i]) { 1337794277daSAlan Somers if (verbose) { 1338d9a54d5cSPoul-Henning Kamp printf("C %u\n", i); 1339e4fea39eSPoul-Henning Kamp print_unrhdr(uh); 1340d9a54d5cSPoul-Henning Kamp } 1341794277daSAlan Somers free_unr(uh, i); 1342794277daSAlan Somers } 1343d9a54d5cSPoul-Henning Kamp } 1344d9a54d5cSPoul-Henning Kamp print_unrhdr(uh); 1345e4fea39eSPoul-Henning Kamp delete_unrhdr(uh); 1346794277daSAlan Somers free(a); 1347f6bde1fdSPoul-Henning Kamp return (0); 1348f6bde1fdSPoul-Henning Kamp } 1349f6bde1fdSPoul-Henning Kamp #endif 1350