1f6bde1fdSPoul-Henning Kamp /*- 2f6bde1fdSPoul-Henning Kamp * Copyright (c) 2004 Poul-Henning Kamp 3f6bde1fdSPoul-Henning Kamp * All rights reserved. 4f6bde1fdSPoul-Henning Kamp * 5f6bde1fdSPoul-Henning Kamp * Redistribution and use in source and binary forms, with or without 6f6bde1fdSPoul-Henning Kamp * modification, are permitted provided that the following conditions 7f6bde1fdSPoul-Henning Kamp * are met: 8f6bde1fdSPoul-Henning Kamp * 1. Redistributions of source code must retain the above copyright 9f6bde1fdSPoul-Henning Kamp * notice, this list of conditions and the following disclaimer. 10f6bde1fdSPoul-Henning Kamp * 2. Redistributions in binary form must reproduce the above copyright 11f6bde1fdSPoul-Henning Kamp * notice, this list of conditions and the following disclaimer in the 12f6bde1fdSPoul-Henning Kamp * documentation and/or other materials provided with the distribution. 13f6bde1fdSPoul-Henning Kamp * 14f6bde1fdSPoul-Henning Kamp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15f6bde1fdSPoul-Henning Kamp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16f6bde1fdSPoul-Henning Kamp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17f6bde1fdSPoul-Henning Kamp * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18f6bde1fdSPoul-Henning Kamp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19f6bde1fdSPoul-Henning Kamp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20f6bde1fdSPoul-Henning Kamp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21f6bde1fdSPoul-Henning Kamp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22f6bde1fdSPoul-Henning Kamp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23f6bde1fdSPoul-Henning Kamp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24f6bde1fdSPoul-Henning Kamp * SUCH DAMAGE. 25f6bde1fdSPoul-Henning Kamp * 26f6bde1fdSPoul-Henning Kamp * $FreeBSD$ 27f6bde1fdSPoul-Henning Kamp * 28f6bde1fdSPoul-Henning Kamp * Unit number allocation functions. 29f6bde1fdSPoul-Henning Kamp * 30f6bde1fdSPoul-Henning Kamp * These functions implement a mixed run-length/bitmap management of unit 31f6bde1fdSPoul-Henning Kamp * number spaces. 32f6bde1fdSPoul-Henning Kamp * 33f6bde1fdSPoul-Henning Kamp * Allocation is always lowest free number first. 34f6bde1fdSPoul-Henning Kamp * 35f6bde1fdSPoul-Henning Kamp * Worst case memory usage (disregarding boundary effects in the low end) 36f6bde1fdSPoul-Henning Kamp * is two bits for each slot in the unit number space. (For a full 37f6bde1fdSPoul-Henning Kamp * [0 ... UINT_MAX] space that is still a lot of course.) 38f6bde1fdSPoul-Henning Kamp * 39f6bde1fdSPoul-Henning Kamp * The typical case, where no unit numbers are freed, is managed in a 40f6bde1fdSPoul-Henning Kamp * constant sized memory footprint of: 41f6bde1fdSPoul-Henning Kamp * sizeof(struct unrhdr) + 2 * sizeof (struct unr) == 56 bytes on i386 42f6bde1fdSPoul-Henning Kamp * 43f6bde1fdSPoul-Henning Kamp * The caller must provide locking. 44f6bde1fdSPoul-Henning Kamp * 45f6bde1fdSPoul-Henning Kamp * A userland test program is included. 46f6bde1fdSPoul-Henning Kamp * 47f6bde1fdSPoul-Henning Kamp */ 48f6bde1fdSPoul-Henning Kamp 49f6bde1fdSPoul-Henning Kamp #include <sys/types.h> 50f6bde1fdSPoul-Henning Kamp #include <sys/queue.h> 51f6bde1fdSPoul-Henning Kamp #include <sys/bitstring.h> 52f6bde1fdSPoul-Henning Kamp 53f6bde1fdSPoul-Henning Kamp #ifdef _KERNEL 54f6bde1fdSPoul-Henning Kamp 55f6bde1fdSPoul-Henning Kamp #include <sys/param.h> 56f6bde1fdSPoul-Henning Kamp #include <sys/malloc.h> 57f6bde1fdSPoul-Henning Kamp #include <sys/kernel.h> 58f6bde1fdSPoul-Henning Kamp #include <sys/systm.h> 59f6bde1fdSPoul-Henning Kamp 60f6bde1fdSPoul-Henning Kamp /* 61f6bde1fdSPoul-Henning Kamp * In theory it would be smarter to allocate the individual blocks 62f6bde1fdSPoul-Henning Kamp * with the zone allocator, but at this time the expectation is that 63f6bde1fdSPoul-Henning Kamp * there will typically not even be enough allocations to fill a single 64f6bde1fdSPoul-Henning Kamp * page, so we stick with malloc for now. 65f6bde1fdSPoul-Henning Kamp */ 66f6bde1fdSPoul-Henning Kamp static MALLOC_DEFINE(M_UNIT, "Unitno", "Unit number allocation"); 67f6bde1fdSPoul-Henning Kamp 68f6bde1fdSPoul-Henning Kamp #define Malloc(foo) malloc(foo, M_UNIT, M_WAITOK | M_ZERO) 69f6bde1fdSPoul-Henning Kamp #define Free(foo) free(foo, M_UNIT) 70f6bde1fdSPoul-Henning Kamp 71f6bde1fdSPoul-Henning Kamp #else /* ...USERLAND */ 72f6bde1fdSPoul-Henning Kamp 73f6bde1fdSPoul-Henning Kamp #include <stdio.h> 74f6bde1fdSPoul-Henning Kamp #include <stdlib.h> 75f6bde1fdSPoul-Henning Kamp 76f6bde1fdSPoul-Henning Kamp #define KASSERT(cond, arg) \ 77f6bde1fdSPoul-Henning Kamp do { \ 78f6bde1fdSPoul-Henning Kamp if (!(cond)) { \ 79f6bde1fdSPoul-Henning Kamp printf arg; \ 80f6bde1fdSPoul-Henning Kamp exit (1); \ 81f6bde1fdSPoul-Henning Kamp } \ 82f6bde1fdSPoul-Henning Kamp } while (0) 83f6bde1fdSPoul-Henning Kamp 84f6bde1fdSPoul-Henning Kamp #define Malloc(foo) calloc(foo, 1) 85f6bde1fdSPoul-Henning Kamp #define Free(foo) free(foo) 86f6bde1fdSPoul-Henning Kamp 87f6bde1fdSPoul-Henning Kamp #endif 88f6bde1fdSPoul-Henning Kamp 89f6bde1fdSPoul-Henning Kamp /* 90f6bde1fdSPoul-Henning Kamp * This is our basic building block. 91f6bde1fdSPoul-Henning Kamp * 92f6bde1fdSPoul-Henning Kamp * It can be used in three different ways depending on the value of the ptr 93f6bde1fdSPoul-Henning Kamp * element: 94f6bde1fdSPoul-Henning Kamp * If ptr is NULL, it represents a run of free items. 95f6bde1fdSPoul-Henning Kamp * If ptr points to the unrhdr it represents a run of allocated items. 96f6bde1fdSPoul-Henning Kamp * Otherwise it points to an bitstring of allocated items. 97f6bde1fdSPoul-Henning Kamp * 98f6bde1fdSPoul-Henning Kamp * For runs the len field is the length of the run. 99f6bde1fdSPoul-Henning Kamp * For bitmaps the len field represents the number of allocated items. 100f6bde1fdSPoul-Henning Kamp * 101f6bde1fdSPoul-Henning Kamp * The bitmap is the same size as struct unr to optimize memory management. 102f6bde1fdSPoul-Henning Kamp */ 103f6bde1fdSPoul-Henning Kamp struct unr { 104f6bde1fdSPoul-Henning Kamp TAILQ_ENTRY(unr) list; 105f6bde1fdSPoul-Henning Kamp u_int len; 106f6bde1fdSPoul-Henning Kamp void *ptr; 107f6bde1fdSPoul-Henning Kamp }; 108f6bde1fdSPoul-Henning Kamp 109f6bde1fdSPoul-Henning Kamp /* Number of bits in the bitmap */ 110f6bde1fdSPoul-Henning Kamp #define NBITS (sizeof(struct unr) * 8) 111f6bde1fdSPoul-Henning Kamp 112f6bde1fdSPoul-Henning Kamp /* Header element for a unr number space. */ 113f6bde1fdSPoul-Henning Kamp 114f6bde1fdSPoul-Henning Kamp struct unrhdr { 115f6bde1fdSPoul-Henning Kamp TAILQ_HEAD(unrhd,unr) head; 116f6bde1fdSPoul-Henning Kamp u_int low; /* Lowest item */ 117f6bde1fdSPoul-Henning Kamp u_int high; /* Highest item */ 118f6bde1fdSPoul-Henning Kamp u_int busy; /* Count of allocated items */ 119f6bde1fdSPoul-Henning Kamp u_int alloc; /* Count of memory allocations */ 120f6bde1fdSPoul-Henning Kamp }; 121f6bde1fdSPoul-Henning Kamp 122f6bde1fdSPoul-Henning Kamp 123f6bde1fdSPoul-Henning Kamp #if defined(DIAGNOSTIC) || !defined(_KERNEL) 124f6bde1fdSPoul-Henning Kamp /* 125f6bde1fdSPoul-Henning Kamp * Consistency check function. 126f6bde1fdSPoul-Henning Kamp * 127f6bde1fdSPoul-Henning Kamp * Checks the internal consistency as well as we can. 128f6bde1fdSPoul-Henning Kamp * 129f6bde1fdSPoul-Henning Kamp * Called at all boundaries of this API. 130f6bde1fdSPoul-Henning Kamp */ 131f6bde1fdSPoul-Henning Kamp static void 132f6bde1fdSPoul-Henning Kamp check_unrhdr(struct unrhdr *uh, int line) 133f6bde1fdSPoul-Henning Kamp { 134f6bde1fdSPoul-Henning Kamp struct unr *up; 135f6bde1fdSPoul-Henning Kamp u_int x, y, z, w; 136f6bde1fdSPoul-Henning Kamp 137f6bde1fdSPoul-Henning Kamp y = 0; 138f6bde1fdSPoul-Henning Kamp z = 0; 139f6bde1fdSPoul-Henning Kamp TAILQ_FOREACH(up, &uh->head, list) { 140f6bde1fdSPoul-Henning Kamp z++; 141f6bde1fdSPoul-Henning Kamp if (up->ptr != uh && up->ptr != NULL) { 142f6bde1fdSPoul-Henning Kamp z++; 143f6bde1fdSPoul-Henning Kamp w = 0; 144f6bde1fdSPoul-Henning Kamp for (x = 0; x < NBITS; x++) 145f6bde1fdSPoul-Henning Kamp if (bit_test((bitstr_t *)up->ptr, x)) 146f6bde1fdSPoul-Henning Kamp w++; 147f6bde1fdSPoul-Henning Kamp KASSERT (w == up->len, 148f6bde1fdSPoul-Henning Kamp ("UNR inconsistency: bits %u found %u\n", 149f6bde1fdSPoul-Henning Kamp up->len, w)); 150f6bde1fdSPoul-Henning Kamp } 151f6bde1fdSPoul-Henning Kamp if (up->ptr != NULL) 152f6bde1fdSPoul-Henning Kamp y += up->len; 153f6bde1fdSPoul-Henning Kamp } 154f6bde1fdSPoul-Henning Kamp KASSERT (y == uh->busy, 155f6bde1fdSPoul-Henning Kamp ("UNR inconsistency: items %u found %u (line %d)\n", 156f6bde1fdSPoul-Henning Kamp uh->busy, y, line)); 157f6bde1fdSPoul-Henning Kamp KASSERT (z == uh->alloc, 158f6bde1fdSPoul-Henning Kamp ("UNR inconsistency: chunks %u found %u (line %d)\n", 159f6bde1fdSPoul-Henning Kamp uh->alloc, z, line)); 160f6bde1fdSPoul-Henning Kamp } 161f6bde1fdSPoul-Henning Kamp 162f6bde1fdSPoul-Henning Kamp #else 163f6bde1fdSPoul-Henning Kamp 164f6bde1fdSPoul-Henning Kamp static __inline void 165f6bde1fdSPoul-Henning Kamp check_unrhdr(struct unhdr *uh, int line) 166f6bde1fdSPoul-Henning Kamp { 167f6bde1fdSPoul-Henning Kamp 168f6bde1fdSPoul-Henning Kamp } 169f6bde1fdSPoul-Henning Kamp 170f6bde1fdSPoul-Henning Kamp #endif 171f6bde1fdSPoul-Henning Kamp 172f6bde1fdSPoul-Henning Kamp 173f6bde1fdSPoul-Henning Kamp /* 174f6bde1fdSPoul-Henning Kamp * Userland memory management. Just use calloc and keep track of how 175f6bde1fdSPoul-Henning Kamp * many elements we have allocated for check_unrhdr(). 176f6bde1fdSPoul-Henning Kamp */ 177f6bde1fdSPoul-Henning Kamp 178f6bde1fdSPoul-Henning Kamp static __inline void * 179f6bde1fdSPoul-Henning Kamp new_unr(struct unrhdr *uh) 180f6bde1fdSPoul-Henning Kamp { 181f6bde1fdSPoul-Henning Kamp uh->alloc++; 182f6bde1fdSPoul-Henning Kamp return (Malloc(sizeof (struct unr))); 183f6bde1fdSPoul-Henning Kamp 184f6bde1fdSPoul-Henning Kamp } 185f6bde1fdSPoul-Henning Kamp 186f6bde1fdSPoul-Henning Kamp static __inline void 187f6bde1fdSPoul-Henning Kamp delete_unr(struct unrhdr *uh, void *ptr) 188f6bde1fdSPoul-Henning Kamp { 189f6bde1fdSPoul-Henning Kamp uh->alloc--; 190f6bde1fdSPoul-Henning Kamp Free(ptr); 191f6bde1fdSPoul-Henning Kamp } 192f6bde1fdSPoul-Henning Kamp 193f6bde1fdSPoul-Henning Kamp /* 194f6bde1fdSPoul-Henning Kamp * Allocate a new unrheader set. 195f6bde1fdSPoul-Henning Kamp * 196f6bde1fdSPoul-Henning Kamp * Highest and lowest valid values given as paramters. 197f6bde1fdSPoul-Henning Kamp */ 198f6bde1fdSPoul-Henning Kamp 199f6bde1fdSPoul-Henning Kamp struct unrhdr * 200f6bde1fdSPoul-Henning Kamp new_unrhdr(u_int low, u_int high) 201f6bde1fdSPoul-Henning Kamp { 202f6bde1fdSPoul-Henning Kamp struct unrhdr *uh; 203f6bde1fdSPoul-Henning Kamp struct unr *up; 204f6bde1fdSPoul-Henning Kamp 205f6bde1fdSPoul-Henning Kamp KASSERT(low <= high, 206f6bde1fdSPoul-Henning Kamp ("UNR: use error: new_unrhdr(%u, %u)", low, high)); 207f6bde1fdSPoul-Henning Kamp uh = Malloc(sizeof *uh); 208f6bde1fdSPoul-Henning Kamp TAILQ_INIT(&uh->head); 209f6bde1fdSPoul-Henning Kamp uh->low = low; 210f6bde1fdSPoul-Henning Kamp uh->high = high; 211f6bde1fdSPoul-Henning Kamp up = new_unr(uh); 212f6bde1fdSPoul-Henning Kamp up->len = 1 + (high - low); 213f6bde1fdSPoul-Henning Kamp up->ptr = NULL; 214f6bde1fdSPoul-Henning Kamp TAILQ_INSERT_HEAD(&uh->head, up, list); 215f6bde1fdSPoul-Henning Kamp check_unrhdr(uh, __LINE__); 216f6bde1fdSPoul-Henning Kamp return (uh); 217f6bde1fdSPoul-Henning Kamp } 218f6bde1fdSPoul-Henning Kamp 219f6bde1fdSPoul-Henning Kamp /* 220f6bde1fdSPoul-Henning Kamp * See if a given unr should be collapsed with a neighbor 221f6bde1fdSPoul-Henning Kamp */ 222f6bde1fdSPoul-Henning Kamp static void 223f6bde1fdSPoul-Henning Kamp collapse_unr(struct unrhdr *uh, struct unr *up) 224f6bde1fdSPoul-Henning Kamp { 225f6bde1fdSPoul-Henning Kamp struct unr *upp; 226f6bde1fdSPoul-Henning Kamp 227f6bde1fdSPoul-Henning Kamp upp = TAILQ_PREV(up, unrhd, list); 228f6bde1fdSPoul-Henning Kamp if (upp != NULL && up->ptr == upp->ptr) { 229f6bde1fdSPoul-Henning Kamp up->len += upp->len; 230f6bde1fdSPoul-Henning Kamp TAILQ_REMOVE(&uh->head, upp, list); 231f6bde1fdSPoul-Henning Kamp delete_unr(uh, upp); 232f6bde1fdSPoul-Henning Kamp } 233f6bde1fdSPoul-Henning Kamp upp = TAILQ_NEXT(up, list); 234f6bde1fdSPoul-Henning Kamp if (upp != NULL && up->ptr == upp->ptr) { 235f6bde1fdSPoul-Henning Kamp up->len += upp->len; 236f6bde1fdSPoul-Henning Kamp TAILQ_REMOVE(&uh->head, upp, list); 237f6bde1fdSPoul-Henning Kamp delete_unr(uh, upp); 238f6bde1fdSPoul-Henning Kamp } 239f6bde1fdSPoul-Henning Kamp } 240f6bde1fdSPoul-Henning Kamp 241f6bde1fdSPoul-Henning Kamp /* 242f6bde1fdSPoul-Henning Kamp * Allocate a free unr. 243f6bde1fdSPoul-Henning Kamp */ 244f6bde1fdSPoul-Henning Kamp u_int 245f6bde1fdSPoul-Henning Kamp alloc_unr(struct unrhdr *uh) 246f6bde1fdSPoul-Henning Kamp { 247f6bde1fdSPoul-Henning Kamp struct unr *up, *upp; 248f6bde1fdSPoul-Henning Kamp u_int x; 249f6bde1fdSPoul-Henning Kamp int y; 250f6bde1fdSPoul-Henning Kamp 251f6bde1fdSPoul-Henning Kamp check_unrhdr(uh, __LINE__); 252f6bde1fdSPoul-Henning Kamp x = uh->low; 253f6bde1fdSPoul-Henning Kamp /* 254f6bde1fdSPoul-Henning Kamp * We can always allocate from one of the first two unrs on the list. 255f6bde1fdSPoul-Henning Kamp * The first one is likely an allocated run, but the second has to 256f6bde1fdSPoul-Henning Kamp * be a free run or a bitmap. 257f6bde1fdSPoul-Henning Kamp */ 258f6bde1fdSPoul-Henning Kamp up = TAILQ_FIRST(&uh->head); 259f6bde1fdSPoul-Henning Kamp KASSERT(up != NULL, ("UNR empty list")); 260f6bde1fdSPoul-Henning Kamp if (up->ptr == uh) { 261f6bde1fdSPoul-Henning Kamp x += up->len; 262f6bde1fdSPoul-Henning Kamp up = TAILQ_NEXT(up, list); 263f6bde1fdSPoul-Henning Kamp } 264f6bde1fdSPoul-Henning Kamp KASSERT(up != NULL, ("UNR Ran out of numbers")); /* XXX */ 265f6bde1fdSPoul-Henning Kamp KASSERT(up->ptr != uh, ("UNR second element allocated")); 266f6bde1fdSPoul-Henning Kamp 267f6bde1fdSPoul-Henning Kamp if (up->ptr != NULL) { 268f6bde1fdSPoul-Henning Kamp /* Bitmap unr */ 269f6bde1fdSPoul-Henning Kamp KASSERT(up->len < NBITS, ("UNR bitmap confusion")); 270f6bde1fdSPoul-Henning Kamp bit_ffc((bitstr_t *)up->ptr, NBITS, &y); 271f6bde1fdSPoul-Henning Kamp KASSERT(y != -1, ("UNR corruption: No clear bit in bitmap.")); 272f6bde1fdSPoul-Henning Kamp bit_set((bitstr_t *)up->ptr, y); 273f6bde1fdSPoul-Henning Kamp up->len++; 274f6bde1fdSPoul-Henning Kamp uh->busy++; 275f6bde1fdSPoul-Henning Kamp if (up->len == NBITS) { 276f6bde1fdSPoul-Henning Kamp /* The unr is all allocated, drop bitmap */ 277f6bde1fdSPoul-Henning Kamp delete_unr(uh, up->ptr); 278f6bde1fdSPoul-Henning Kamp up->ptr = uh; 279f6bde1fdSPoul-Henning Kamp collapse_unr(uh, up); 280f6bde1fdSPoul-Henning Kamp } 281f6bde1fdSPoul-Henning Kamp check_unrhdr(uh, __LINE__); 282f6bde1fdSPoul-Henning Kamp return (x + y); 283f6bde1fdSPoul-Henning Kamp } 284f6bde1fdSPoul-Henning Kamp 285f6bde1fdSPoul-Henning Kamp if (up->len == 1) { 286f6bde1fdSPoul-Henning Kamp /* Run of one free item, grab it */ 287f6bde1fdSPoul-Henning Kamp up->ptr = uh; 288f6bde1fdSPoul-Henning Kamp uh->busy++; 289f6bde1fdSPoul-Henning Kamp collapse_unr(uh, up); 290f6bde1fdSPoul-Henning Kamp check_unrhdr(uh, __LINE__); 291f6bde1fdSPoul-Henning Kamp return (x); 292f6bde1fdSPoul-Henning Kamp } 293f6bde1fdSPoul-Henning Kamp 294f6bde1fdSPoul-Henning Kamp /* 295f6bde1fdSPoul-Henning Kamp * Slice first item into an preceeding allocated run, even if we 296f6bde1fdSPoul-Henning Kamp * have to create it. Because allocation is always lowest free 297f6bde1fdSPoul-Henning Kamp * number first, we know the preceeding element (if any) to be 298f6bde1fdSPoul-Henning Kamp * an allocated run. 299f6bde1fdSPoul-Henning Kamp */ 300f6bde1fdSPoul-Henning Kamp upp = TAILQ_PREV(up, unrhd, list); 301f6bde1fdSPoul-Henning Kamp if (upp == NULL) { 302f6bde1fdSPoul-Henning Kamp upp = new_unr(uh); 303f6bde1fdSPoul-Henning Kamp upp->len = 0; 304f6bde1fdSPoul-Henning Kamp upp->ptr = uh; 305f6bde1fdSPoul-Henning Kamp TAILQ_INSERT_BEFORE(up, upp, list); 306f6bde1fdSPoul-Henning Kamp } 307f6bde1fdSPoul-Henning Kamp KASSERT(upp->ptr == uh, ("UNR list corruption")); 308f6bde1fdSPoul-Henning Kamp upp->len++; 309f6bde1fdSPoul-Henning Kamp up->len--; 310f6bde1fdSPoul-Henning Kamp uh->busy++; 311f6bde1fdSPoul-Henning Kamp check_unrhdr(uh, __LINE__); 312f6bde1fdSPoul-Henning Kamp return (x); 313f6bde1fdSPoul-Henning Kamp } 314f6bde1fdSPoul-Henning Kamp 315f6bde1fdSPoul-Henning Kamp /* 316f6bde1fdSPoul-Henning Kamp * Free a unr. 317f6bde1fdSPoul-Henning Kamp * 318f6bde1fdSPoul-Henning Kamp * If we can save unrs by using a bitmap, do so. 319f6bde1fdSPoul-Henning Kamp */ 320f6bde1fdSPoul-Henning Kamp void 321f6bde1fdSPoul-Henning Kamp free_unr(struct unrhdr *uh, u_int item) 322f6bde1fdSPoul-Henning Kamp { 323f6bde1fdSPoul-Henning Kamp struct unr *up, *upp, *upn, *ul; 324f6bde1fdSPoul-Henning Kamp u_int x, l, xl, n, pl; 325f6bde1fdSPoul-Henning Kamp 326f6bde1fdSPoul-Henning Kamp KASSERT(item >= uh->low && item <= uh->high, 327f6bde1fdSPoul-Henning Kamp ("UNR: free_unr(%u) out of range [%u...%u]", 328f6bde1fdSPoul-Henning Kamp item, uh->low, uh->high)); 329f6bde1fdSPoul-Henning Kamp check_unrhdr(uh, __LINE__); 330f6bde1fdSPoul-Henning Kamp item -= uh->low; 331f6bde1fdSPoul-Henning Kamp xl = x = 0; 332f6bde1fdSPoul-Henning Kamp /* Find the start of the potential bitmap */ 333f6bde1fdSPoul-Henning Kamp l = item - item % NBITS; 334f6bde1fdSPoul-Henning Kamp ul = 0; 335f6bde1fdSPoul-Henning Kamp TAILQ_FOREACH(up, &uh->head, list) { 336f6bde1fdSPoul-Henning Kamp 337f6bde1fdSPoul-Henning Kamp /* Keep track of which unr we'll split if we do */ 338f6bde1fdSPoul-Henning Kamp if (x <= l) { 339f6bde1fdSPoul-Henning Kamp ul = up; 340f6bde1fdSPoul-Henning Kamp xl = x; 341f6bde1fdSPoul-Henning Kamp } 342f6bde1fdSPoul-Henning Kamp 343f6bde1fdSPoul-Henning Kamp /* Handle bitmap items */ 344f6bde1fdSPoul-Henning Kamp if (up->ptr != NULL && up->ptr != uh) { 345f6bde1fdSPoul-Henning Kamp if (x + NBITS <= item) { /* not yet */ 346f6bde1fdSPoul-Henning Kamp x += NBITS; 347f6bde1fdSPoul-Henning Kamp continue; 348f6bde1fdSPoul-Henning Kamp } 349f6bde1fdSPoul-Henning Kamp KASSERT(bit_test((bitstr_t *)up->ptr, item - x) != 0, 350f6bde1fdSPoul-Henning Kamp ("UNR: Freeing free item %d (%d) (bitmap)\n", 351f6bde1fdSPoul-Henning Kamp item, item - x)); 352f6bde1fdSPoul-Henning Kamp bit_clear((bitstr_t *)up->ptr, item - x); 353f6bde1fdSPoul-Henning Kamp uh->busy--; 354f6bde1fdSPoul-Henning Kamp up->len--; 355f6bde1fdSPoul-Henning Kamp /* 356f6bde1fdSPoul-Henning Kamp * XXX: up->len == 1 could possibly be collapsed to 357f6bde1fdSPoul-Henning Kamp * XXX: neighboring runs. 358f6bde1fdSPoul-Henning Kamp */ 359f6bde1fdSPoul-Henning Kamp if (up->len > 0) 360f6bde1fdSPoul-Henning Kamp return; 361f6bde1fdSPoul-Henning Kamp /* We have freed all items in bitmap, drop it */ 362f6bde1fdSPoul-Henning Kamp delete_unr(uh, up->ptr); 363f6bde1fdSPoul-Henning Kamp up->ptr = NULL; 364f6bde1fdSPoul-Henning Kamp up->len = NBITS; 365f6bde1fdSPoul-Henning Kamp collapse_unr(uh, up); 366f6bde1fdSPoul-Henning Kamp check_unrhdr(uh, __LINE__); 367f6bde1fdSPoul-Henning Kamp return; 368f6bde1fdSPoul-Henning Kamp } 369f6bde1fdSPoul-Henning Kamp 370f6bde1fdSPoul-Henning Kamp /* Run length unr's */ 371f6bde1fdSPoul-Henning Kamp 372f6bde1fdSPoul-Henning Kamp if (x + up->len <= item) { /* not yet */ 373f6bde1fdSPoul-Henning Kamp x += up->len; 374f6bde1fdSPoul-Henning Kamp continue; 375f6bde1fdSPoul-Henning Kamp } 376f6bde1fdSPoul-Henning Kamp 377f6bde1fdSPoul-Henning Kamp /* We now have our run length unr */ 378f6bde1fdSPoul-Henning Kamp KASSERT(up->ptr == uh, 379f6bde1fdSPoul-Henning Kamp ("UNR Freeing free item %d (run))\n", item)); 380f6bde1fdSPoul-Henning Kamp 381f6bde1fdSPoul-Henning Kamp /* Just this one left, reap it */ 382f6bde1fdSPoul-Henning Kamp if (up->len == 1) { 383f6bde1fdSPoul-Henning Kamp up->ptr = NULL; 384f6bde1fdSPoul-Henning Kamp uh->busy--; 385f6bde1fdSPoul-Henning Kamp collapse_unr(uh, up); 386f6bde1fdSPoul-Henning Kamp check_unrhdr(uh, __LINE__); 387f6bde1fdSPoul-Henning Kamp return; 388f6bde1fdSPoul-Henning Kamp } 389f6bde1fdSPoul-Henning Kamp 390f6bde1fdSPoul-Henning Kamp /* Check if we can shift the item to the previous run */ 391f6bde1fdSPoul-Henning Kamp upp = TAILQ_PREV(up, unrhd, list); 392f6bde1fdSPoul-Henning Kamp if (item == x && upp != NULL && upp->ptr == NULL) { 393f6bde1fdSPoul-Henning Kamp upp->len++; 394f6bde1fdSPoul-Henning Kamp up->len--; 395f6bde1fdSPoul-Henning Kamp uh->busy--; 396f6bde1fdSPoul-Henning Kamp check_unrhdr(uh, __LINE__); 397f6bde1fdSPoul-Henning Kamp return; 398f6bde1fdSPoul-Henning Kamp } 399f6bde1fdSPoul-Henning Kamp 400f6bde1fdSPoul-Henning Kamp /* Check if we can shift the item to the next run */ 401f6bde1fdSPoul-Henning Kamp upn = TAILQ_NEXT(up, list); 402f6bde1fdSPoul-Henning Kamp if (item == x + up->len - 1 && 403f6bde1fdSPoul-Henning Kamp upn != NULL && upn->ptr == NULL) { 404f6bde1fdSPoul-Henning Kamp upn->len++; 405f6bde1fdSPoul-Henning Kamp up->len--; 406f6bde1fdSPoul-Henning Kamp uh->busy--; 407f6bde1fdSPoul-Henning Kamp check_unrhdr(uh, __LINE__); 408f6bde1fdSPoul-Henning Kamp return; 409f6bde1fdSPoul-Henning Kamp } 410f6bde1fdSPoul-Henning Kamp 411f6bde1fdSPoul-Henning Kamp /* Split off the tail end, if any. */ 412f6bde1fdSPoul-Henning Kamp pl = up->len - (1 + (item - x)); 413f6bde1fdSPoul-Henning Kamp if (pl > 0) { 414f6bde1fdSPoul-Henning Kamp upp = new_unr(uh); 415f6bde1fdSPoul-Henning Kamp upp->ptr = uh; 416f6bde1fdSPoul-Henning Kamp upp->len = pl; 417f6bde1fdSPoul-Henning Kamp TAILQ_INSERT_AFTER(&uh->head, up, upp, list); 418f6bde1fdSPoul-Henning Kamp } 419f6bde1fdSPoul-Henning Kamp 420f6bde1fdSPoul-Henning Kamp if (item == x) { 421f6bde1fdSPoul-Henning Kamp /* We are done splitting */ 422f6bde1fdSPoul-Henning Kamp up->len = 1; 423f6bde1fdSPoul-Henning Kamp up->ptr = NULL; 424f6bde1fdSPoul-Henning Kamp } else { 425f6bde1fdSPoul-Henning Kamp /* The freed item */ 426f6bde1fdSPoul-Henning Kamp upp = new_unr(uh); 427f6bde1fdSPoul-Henning Kamp upp->len = 1; 428f6bde1fdSPoul-Henning Kamp upp->ptr = NULL; 429f6bde1fdSPoul-Henning Kamp TAILQ_INSERT_AFTER(&uh->head, up, upp, list); 430f6bde1fdSPoul-Henning Kamp /* Adjust current unr */ 431f6bde1fdSPoul-Henning Kamp up->len = item - x; 432f6bde1fdSPoul-Henning Kamp } 433f6bde1fdSPoul-Henning Kamp 434f6bde1fdSPoul-Henning Kamp uh->busy--; 435f6bde1fdSPoul-Henning Kamp check_unrhdr(uh, __LINE__); 436f6bde1fdSPoul-Henning Kamp 437f6bde1fdSPoul-Henning Kamp /* Our ul marker element may have shifted one later */ 438f6bde1fdSPoul-Henning Kamp if (ul->len + xl <= l) { 439f6bde1fdSPoul-Henning Kamp xl += ul->len; 440f6bde1fdSPoul-Henning Kamp ul = TAILQ_NEXT(ul, list); 441f6bde1fdSPoul-Henning Kamp } 442f6bde1fdSPoul-Henning Kamp KASSERT(ul != NULL, ("UNR lost bitmap pointer")); 443f6bde1fdSPoul-Henning Kamp 444f6bde1fdSPoul-Henning Kamp /* Count unrs entirely inside potential bitmap */ 445f6bde1fdSPoul-Henning Kamp n = 0; 446f6bde1fdSPoul-Henning Kamp pl = xl; 447f6bde1fdSPoul-Henning Kamp item = l + NBITS; 448f6bde1fdSPoul-Henning Kamp for (up = ul; 449f6bde1fdSPoul-Henning Kamp up != NULL && pl + up->len <= item; 450f6bde1fdSPoul-Henning Kamp up = TAILQ_NEXT(up, list)) { 451f6bde1fdSPoul-Henning Kamp if (pl >= l) 452f6bde1fdSPoul-Henning Kamp n++; 453f6bde1fdSPoul-Henning Kamp pl += up->len; 454f6bde1fdSPoul-Henning Kamp } 455f6bde1fdSPoul-Henning Kamp 456f6bde1fdSPoul-Henning Kamp /* If less than three, a bitmap does not pay off */ 457f6bde1fdSPoul-Henning Kamp if (n < 3) 458f6bde1fdSPoul-Henning Kamp return; 459f6bde1fdSPoul-Henning Kamp 460f6bde1fdSPoul-Henning Kamp /* Allocate bitmap */ 461f6bde1fdSPoul-Henning Kamp upp = new_unr(uh); 462f6bde1fdSPoul-Henning Kamp upp->ptr = new_unr(uh); 463f6bde1fdSPoul-Henning Kamp 464f6bde1fdSPoul-Henning Kamp /* Insert bitmap after ul element */ 465f6bde1fdSPoul-Henning Kamp TAILQ_INSERT_AFTER(&uh->head, ul, upp, list); 466f6bde1fdSPoul-Henning Kamp 467f6bde1fdSPoul-Henning Kamp /* Slice off the tail from the ul element */ 468f6bde1fdSPoul-Henning Kamp pl = ul->len - (l - xl); 469f6bde1fdSPoul-Henning Kamp if (ul->ptr != NULL) { 470f6bde1fdSPoul-Henning Kamp bit_nset(upp->ptr, 0, pl - 1); 471f6bde1fdSPoul-Henning Kamp upp->len = pl; 472f6bde1fdSPoul-Henning Kamp } 473f6bde1fdSPoul-Henning Kamp ul->len -= pl; 474f6bde1fdSPoul-Henning Kamp 475f6bde1fdSPoul-Henning Kamp /* Ditch ul if it got reduced to zero size */ 476f6bde1fdSPoul-Henning Kamp if (ul->len == 0) { 477f6bde1fdSPoul-Henning Kamp TAILQ_REMOVE(&uh->head, ul, list); 478f6bde1fdSPoul-Henning Kamp delete_unr(uh, ul); 479f6bde1fdSPoul-Henning Kamp } 480f6bde1fdSPoul-Henning Kamp 481f6bde1fdSPoul-Henning Kamp /* Soak up run length unrs until we have absorbed NBITS */ 482f6bde1fdSPoul-Henning Kamp while (pl != NBITS) { 483f6bde1fdSPoul-Henning Kamp 484f6bde1fdSPoul-Henning Kamp /* Grab first one in line */ 485f6bde1fdSPoul-Henning Kamp upn = TAILQ_NEXT(upp, list); 486f6bde1fdSPoul-Henning Kamp 487f6bde1fdSPoul-Henning Kamp /* We may not have a multiple of NBITS totally */ 488f6bde1fdSPoul-Henning Kamp if (upn == NULL) 489f6bde1fdSPoul-Henning Kamp break; 490f6bde1fdSPoul-Henning Kamp 491f6bde1fdSPoul-Henning Kamp /* Run may extend past our new bitmap */ 492f6bde1fdSPoul-Henning Kamp n = NBITS - pl; 493f6bde1fdSPoul-Henning Kamp if (n > upn->len) 494f6bde1fdSPoul-Henning Kamp n = upn->len; 495f6bde1fdSPoul-Henning Kamp 496f6bde1fdSPoul-Henning Kamp if (upn->ptr != NULL) { 497f6bde1fdSPoul-Henning Kamp bit_nset(upp->ptr, pl, pl + n - 1); 498f6bde1fdSPoul-Henning Kamp upp->len += n; 499f6bde1fdSPoul-Henning Kamp } 500f6bde1fdSPoul-Henning Kamp pl += n; 501f6bde1fdSPoul-Henning Kamp 502f6bde1fdSPoul-Henning Kamp if (n != upn->len) { 503f6bde1fdSPoul-Henning Kamp /* We did not absorb the entire run */ 504f6bde1fdSPoul-Henning Kamp upn->len -= n; 505f6bde1fdSPoul-Henning Kamp break; 506f6bde1fdSPoul-Henning Kamp } 507f6bde1fdSPoul-Henning Kamp TAILQ_REMOVE(&uh->head, upn, list); 508f6bde1fdSPoul-Henning Kamp delete_unr(uh, upn); 509f6bde1fdSPoul-Henning Kamp } 510f6bde1fdSPoul-Henning Kamp check_unrhdr(uh, __LINE__); 511f6bde1fdSPoul-Henning Kamp return; 512f6bde1fdSPoul-Henning Kamp } 513f6bde1fdSPoul-Henning Kamp KASSERT(0 != 1, ("UNR: Fell off the end in free_unr()")); 514f6bde1fdSPoul-Henning Kamp } 515f6bde1fdSPoul-Henning Kamp 516f6bde1fdSPoul-Henning Kamp #ifndef _KERNEL /* USERLAND test driver */ 517f6bde1fdSPoul-Henning Kamp 518f6bde1fdSPoul-Henning Kamp /* 519f6bde1fdSPoul-Henning Kamp * Simple stochastic test driver for the above functions 520f6bde1fdSPoul-Henning Kamp */ 521f6bde1fdSPoul-Henning Kamp 522f6bde1fdSPoul-Henning Kamp static void 523f6bde1fdSPoul-Henning Kamp print_unr(struct unrhdr *uh, struct unr *up) 524f6bde1fdSPoul-Henning Kamp { 525f6bde1fdSPoul-Henning Kamp u_int x; 526f6bde1fdSPoul-Henning Kamp 527f6bde1fdSPoul-Henning Kamp printf(" %p len = %5u ", up, up->len); 528f6bde1fdSPoul-Henning Kamp if (up->ptr == NULL) 529f6bde1fdSPoul-Henning Kamp printf("free\n"); 530f6bde1fdSPoul-Henning Kamp else if (up->ptr == uh) 531f6bde1fdSPoul-Henning Kamp printf("alloc\n"); 532f6bde1fdSPoul-Henning Kamp else { 533f6bde1fdSPoul-Henning Kamp printf(" ["); 534f6bde1fdSPoul-Henning Kamp for (x = 0; x < NBITS; x++) { 535f6bde1fdSPoul-Henning Kamp if (bit_test((bitstr_t *)up->ptr, x)) 536f6bde1fdSPoul-Henning Kamp putchar('#'); 537f6bde1fdSPoul-Henning Kamp else 538f6bde1fdSPoul-Henning Kamp putchar(' '); 539f6bde1fdSPoul-Henning Kamp } 540f6bde1fdSPoul-Henning Kamp printf("]\n"); 541f6bde1fdSPoul-Henning Kamp } 542f6bde1fdSPoul-Henning Kamp } 543f6bde1fdSPoul-Henning Kamp 544f6bde1fdSPoul-Henning Kamp static void 545f6bde1fdSPoul-Henning Kamp print_unrhdr(struct unrhdr *uh) 546f6bde1fdSPoul-Henning Kamp { 547f6bde1fdSPoul-Henning Kamp struct unr *up; 548f6bde1fdSPoul-Henning Kamp u_int x; 549f6bde1fdSPoul-Henning Kamp 550f6bde1fdSPoul-Henning Kamp printf("%p low = %u high = %u busy %u\n", 551f6bde1fdSPoul-Henning Kamp uh, uh->low, uh->high, uh->busy); 552f6bde1fdSPoul-Henning Kamp x = uh->low; 553f6bde1fdSPoul-Henning Kamp TAILQ_FOREACH(up, &uh->head, list) { 554f6bde1fdSPoul-Henning Kamp printf(" from = %5u", x); 555f6bde1fdSPoul-Henning Kamp print_unr(uh, up); 556f6bde1fdSPoul-Henning Kamp if (up->ptr == NULL || up->ptr == uh) 557f6bde1fdSPoul-Henning Kamp x += up->len; 558f6bde1fdSPoul-Henning Kamp else 559f6bde1fdSPoul-Henning Kamp x += NBITS; 560f6bde1fdSPoul-Henning Kamp } 561f6bde1fdSPoul-Henning Kamp } 562f6bde1fdSPoul-Henning Kamp 563f6bde1fdSPoul-Henning Kamp /* Number of unrs to test */ 564f6bde1fdSPoul-Henning Kamp #define NN 10000 565f6bde1fdSPoul-Henning Kamp 566f6bde1fdSPoul-Henning Kamp int 567f6bde1fdSPoul-Henning Kamp main(int argc __unused, const char **argv __unused) 568f6bde1fdSPoul-Henning Kamp { 569f6bde1fdSPoul-Henning Kamp struct unrhdr *uh; 570f6bde1fdSPoul-Henning Kamp int i, x; 571f6bde1fdSPoul-Henning Kamp char a[NN]; 572f6bde1fdSPoul-Henning Kamp 573f6bde1fdSPoul-Henning Kamp uh = new_unrhdr(0, NN - 1); 574f6bde1fdSPoul-Henning Kamp 575f6bde1fdSPoul-Henning Kamp memset(a, 0, sizeof a); 576f6bde1fdSPoul-Henning Kamp 577f6bde1fdSPoul-Henning Kamp fprintf(stderr, "sizeof(struct unr) %d\n", sizeof (struct unr)); 578f6bde1fdSPoul-Henning Kamp fprintf(stderr, "sizeof(struct unrhdr) %d\n", sizeof (struct unrhdr)); 579f6bde1fdSPoul-Henning Kamp x = 1; 580f6bde1fdSPoul-Henning Kamp for (;;) { 581f6bde1fdSPoul-Henning Kamp i = random() % NN; 582f6bde1fdSPoul-Henning Kamp if (a[i]) { 583f6bde1fdSPoul-Henning Kamp printf("F %u\n", i); 584f6bde1fdSPoul-Henning Kamp free_unr(uh, i); 585f6bde1fdSPoul-Henning Kamp a[i] = 0; 586f6bde1fdSPoul-Henning Kamp } else { 587f6bde1fdSPoul-Henning Kamp i = alloc_unr(uh); 588f6bde1fdSPoul-Henning Kamp a[i] = 1; 589f6bde1fdSPoul-Henning Kamp printf("A %u\n", i); 590f6bde1fdSPoul-Henning Kamp } 591f6bde1fdSPoul-Henning Kamp if (1) /* XXX: change this for detailed debug printout */ 592f6bde1fdSPoul-Henning Kamp print_unrhdr(uh); 593f6bde1fdSPoul-Henning Kamp check_unrhdr(uh, __LINE__); 594f6bde1fdSPoul-Henning Kamp } 595f6bde1fdSPoul-Henning Kamp return (0); 596f6bde1fdSPoul-Henning Kamp } 597f6bde1fdSPoul-Henning Kamp #endif 598