18d59ecb2SHans Petter Selasky /*- 28d59ecb2SHans Petter Selasky * Copyright (c) 2010 Isilon Systems, Inc. 38d59ecb2SHans Petter Selasky * Copyright (c) 2010 iX Systems, Inc. 48d59ecb2SHans Petter Selasky * Copyright (c) 2010 Panasas, Inc. 5427cefdeSHans Petter Selasky * Copyright (c) 2013-2017 Mellanox Technologies, Ltd. 68d59ecb2SHans Petter Selasky * All rights reserved. 78d59ecb2SHans Petter Selasky * 88d59ecb2SHans Petter Selasky * Redistribution and use in source and binary forms, with or without 98d59ecb2SHans Petter Selasky * modification, are permitted provided that the following conditions 108d59ecb2SHans Petter Selasky * are met: 118d59ecb2SHans Petter Selasky * 1. Redistributions of source code must retain the above copyright 128d59ecb2SHans Petter Selasky * notice unmodified, this list of conditions, and the following 138d59ecb2SHans Petter Selasky * disclaimer. 148d59ecb2SHans Petter Selasky * 2. Redistributions in binary form must reproduce the above copyright 158d59ecb2SHans Petter Selasky * notice, this list of conditions and the following disclaimer in the 168d59ecb2SHans Petter Selasky * documentation and/or other materials provided with the distribution. 178d59ecb2SHans Petter Selasky * 188d59ecb2SHans Petter Selasky * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 198d59ecb2SHans Petter Selasky * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 208d59ecb2SHans Petter Selasky * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 218d59ecb2SHans Petter Selasky * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 228d59ecb2SHans Petter Selasky * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 238d59ecb2SHans Petter Selasky * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 248d59ecb2SHans Petter Selasky * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 258d59ecb2SHans Petter Selasky * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 268d59ecb2SHans Petter Selasky * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 278d59ecb2SHans Petter Selasky * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 288d59ecb2SHans Petter Selasky */ 298d59ecb2SHans Petter Selasky 308d59ecb2SHans Petter Selasky #include <sys/param.h> 318d59ecb2SHans Petter Selasky #include <sys/systm.h> 328d59ecb2SHans Petter Selasky #include <sys/malloc.h> 338d59ecb2SHans Petter Selasky #include <sys/kernel.h> 348d59ecb2SHans Petter Selasky #include <sys/sysctl.h> 358d59ecb2SHans Petter Selasky #include <sys/lock.h> 368d59ecb2SHans Petter Selasky #include <sys/mutex.h> 378d59ecb2SHans Petter Selasky 388d59ecb2SHans Petter Selasky #include <machine/stdarg.h> 398d59ecb2SHans Petter Selasky 40c9dd0b48SHans Petter Selasky #include <linux/bitmap.h> 418d59ecb2SHans Petter Selasky #include <linux/kobject.h> 428d59ecb2SHans Petter Selasky #include <linux/slab.h> 438d59ecb2SHans Petter Selasky #include <linux/idr.h> 448d59ecb2SHans Petter Selasky #include <linux/err.h> 458d59ecb2SHans Petter Selasky 46427cefdeSHans Petter Selasky #define MAX_IDR_LEVEL ((MAX_IDR_SHIFT + IDR_BITS - 1) / IDR_BITS) 47427cefdeSHans Petter Selasky #define MAX_IDR_FREE (MAX_IDR_LEVEL * 2) 48427cefdeSHans Petter Selasky 49427cefdeSHans Petter Selasky struct linux_idr_cache { 50427cefdeSHans Petter Selasky spinlock_t lock; 51427cefdeSHans Petter Selasky struct idr_layer *head; 52427cefdeSHans Petter Selasky unsigned count; 53427cefdeSHans Petter Selasky }; 54427cefdeSHans Petter Selasky 552bf95012SAndrew Turner DPCPU_DEFINE_STATIC(struct linux_idr_cache, linux_idr_cache); 56427cefdeSHans Petter Selasky 578d59ecb2SHans Petter Selasky /* 588d59ecb2SHans Petter Selasky * IDR Implementation. 598d59ecb2SHans Petter Selasky * 608d59ecb2SHans Petter Selasky * This is quick and dirty and not as re-entrant as the linux version 618d59ecb2SHans Petter Selasky * however it should be fairly fast. It is basically a radix tree with 628d59ecb2SHans Petter Selasky * a builtin bitmap for allocation. 638d59ecb2SHans Petter Selasky */ 648d59ecb2SHans Petter Selasky static MALLOC_DEFINE(M_IDR, "idr", "Linux IDR compat"); 658d59ecb2SHans Petter Selasky 66427cefdeSHans Petter Selasky static struct idr_layer * 67427cefdeSHans Petter Selasky idr_preload_dequeue_locked(struct linux_idr_cache *lic) 68427cefdeSHans Petter Selasky { 69427cefdeSHans Petter Selasky struct idr_layer *retval; 70427cefdeSHans Petter Selasky 71427cefdeSHans Petter Selasky /* check if wrong thread is trying to dequeue */ 72ae38a1a1SEmmanuel Vadot if (mtx_owned(&lic->lock) == 0) 73427cefdeSHans Petter Selasky return (NULL); 74427cefdeSHans Petter Selasky 75427cefdeSHans Petter Selasky retval = lic->head; 76427cefdeSHans Petter Selasky if (likely(retval != NULL)) { 77427cefdeSHans Petter Selasky lic->head = retval->ary[0]; 78427cefdeSHans Petter Selasky lic->count--; 79427cefdeSHans Petter Selasky retval->ary[0] = NULL; 80427cefdeSHans Petter Selasky } 81427cefdeSHans Petter Selasky return (retval); 82427cefdeSHans Petter Selasky } 83427cefdeSHans Petter Selasky 84427cefdeSHans Petter Selasky static void 85427cefdeSHans Petter Selasky idr_preload_init(void *arg) 86427cefdeSHans Petter Selasky { 87427cefdeSHans Petter Selasky int cpu; 88427cefdeSHans Petter Selasky 89427cefdeSHans Petter Selasky CPU_FOREACH(cpu) { 90427cefdeSHans Petter Selasky struct linux_idr_cache *lic = 91427cefdeSHans Petter Selasky DPCPU_ID_PTR(cpu, linux_idr_cache); 92427cefdeSHans Petter Selasky 93427cefdeSHans Petter Selasky spin_lock_init(&lic->lock); 94427cefdeSHans Petter Selasky } 95427cefdeSHans Petter Selasky } 9625b3ef2cSHans Petter Selasky SYSINIT(idr_preload_init, SI_SUB_CPU, SI_ORDER_ANY, idr_preload_init, NULL); 97427cefdeSHans Petter Selasky 98427cefdeSHans Petter Selasky static void 99427cefdeSHans Petter Selasky idr_preload_uninit(void *arg) 100427cefdeSHans Petter Selasky { 101427cefdeSHans Petter Selasky int cpu; 102427cefdeSHans Petter Selasky 103427cefdeSHans Petter Selasky CPU_FOREACH(cpu) { 104427cefdeSHans Petter Selasky struct idr_layer *cacheval; 105427cefdeSHans Petter Selasky struct linux_idr_cache *lic = 106427cefdeSHans Petter Selasky DPCPU_ID_PTR(cpu, linux_idr_cache); 107427cefdeSHans Petter Selasky 108427cefdeSHans Petter Selasky while (1) { 109427cefdeSHans Petter Selasky spin_lock(&lic->lock); 110427cefdeSHans Petter Selasky cacheval = idr_preload_dequeue_locked(lic); 111427cefdeSHans Petter Selasky spin_unlock(&lic->lock); 112427cefdeSHans Petter Selasky 113427cefdeSHans Petter Selasky if (cacheval == NULL) 114427cefdeSHans Petter Selasky break; 115427cefdeSHans Petter Selasky free(cacheval, M_IDR); 116427cefdeSHans Petter Selasky } 117427cefdeSHans Petter Selasky spin_lock_destroy(&lic->lock); 118427cefdeSHans Petter Selasky } 119427cefdeSHans Petter Selasky } 120427cefdeSHans Petter Selasky SYSUNINIT(idr_preload_uninit, SI_SUB_LOCK, SI_ORDER_FIRST, idr_preload_uninit, NULL); 121427cefdeSHans Petter Selasky 122427cefdeSHans Petter Selasky void 123427cefdeSHans Petter Selasky idr_preload(gfp_t gfp_mask) 124427cefdeSHans Petter Selasky { 125427cefdeSHans Petter Selasky struct linux_idr_cache *lic; 126427cefdeSHans Petter Selasky struct idr_layer *cacheval; 127427cefdeSHans Petter Selasky 128427cefdeSHans Petter Selasky sched_pin(); 129427cefdeSHans Petter Selasky 130427cefdeSHans Petter Selasky lic = &DPCPU_GET(linux_idr_cache); 131427cefdeSHans Petter Selasky 132427cefdeSHans Petter Selasky /* fill up cache */ 133427cefdeSHans Petter Selasky spin_lock(&lic->lock); 134427cefdeSHans Petter Selasky while (lic->count < MAX_IDR_FREE) { 135427cefdeSHans Petter Selasky spin_unlock(&lic->lock); 136427cefdeSHans Petter Selasky cacheval = malloc(sizeof(*cacheval), M_IDR, M_ZERO | gfp_mask); 137427cefdeSHans Petter Selasky spin_lock(&lic->lock); 138427cefdeSHans Petter Selasky if (cacheval == NULL) 139427cefdeSHans Petter Selasky break; 140427cefdeSHans Petter Selasky cacheval->ary[0] = lic->head; 141427cefdeSHans Petter Selasky lic->head = cacheval; 142427cefdeSHans Petter Selasky lic->count++; 143427cefdeSHans Petter Selasky } 144427cefdeSHans Petter Selasky } 145427cefdeSHans Petter Selasky 146427cefdeSHans Petter Selasky void 147427cefdeSHans Petter Selasky idr_preload_end(void) 148427cefdeSHans Petter Selasky { 149427cefdeSHans Petter Selasky struct linux_idr_cache *lic; 150427cefdeSHans Petter Selasky 151427cefdeSHans Petter Selasky lic = &DPCPU_GET(linux_idr_cache); 152427cefdeSHans Petter Selasky spin_unlock(&lic->lock); 153427cefdeSHans Petter Selasky sched_unpin(); 154427cefdeSHans Petter Selasky } 155427cefdeSHans Petter Selasky 1568d59ecb2SHans Petter Selasky static inline int 1578d59ecb2SHans Petter Selasky idr_max(struct idr *idr) 1588d59ecb2SHans Petter Selasky { 1598d59ecb2SHans Petter Selasky return (1 << (idr->layers * IDR_BITS)) - 1; 1608d59ecb2SHans Petter Selasky } 1618d59ecb2SHans Petter Selasky 1628d59ecb2SHans Petter Selasky static inline int 1638d59ecb2SHans Petter Selasky idr_pos(int id, int layer) 1648d59ecb2SHans Petter Selasky { 1658d59ecb2SHans Petter Selasky return (id >> (IDR_BITS * layer)) & IDR_MASK; 1668d59ecb2SHans Petter Selasky } 1678d59ecb2SHans Petter Selasky 1688d59ecb2SHans Petter Selasky void 1698d59ecb2SHans Petter Selasky idr_init(struct idr *idr) 1708d59ecb2SHans Petter Selasky { 1718d59ecb2SHans Petter Selasky bzero(idr, sizeof(*idr)); 1728d59ecb2SHans Petter Selasky mtx_init(&idr->lock, "idr", NULL, MTX_DEF); 1738d59ecb2SHans Petter Selasky } 1748d59ecb2SHans Petter Selasky 1758d59ecb2SHans Petter Selasky /* Only frees cached pages. */ 1768d59ecb2SHans Petter Selasky void 1778d59ecb2SHans Petter Selasky idr_destroy(struct idr *idr) 1788d59ecb2SHans Petter Selasky { 1798d59ecb2SHans Petter Selasky struct idr_layer *il, *iln; 1808d59ecb2SHans Petter Selasky 181*613723baSAustin Shafer /* 182*613723baSAustin Shafer * This idr can be reused, and this function might be called multiple times 183*613723baSAustin Shafer * without a idr_init(). Check if this is the case. If we do not do this 184*613723baSAustin Shafer * then the mutex will panic while asserting that it is valid. 185*613723baSAustin Shafer */ 186*613723baSAustin Shafer if (mtx_initialized(&idr->lock) == 0) 187*613723baSAustin Shafer return; 188*613723baSAustin Shafer 1898d59ecb2SHans Petter Selasky idr_remove_all(idr); 1908d59ecb2SHans Petter Selasky mtx_lock(&idr->lock); 1918d59ecb2SHans Petter Selasky for (il = idr->free; il != NULL; il = iln) { 1928d59ecb2SHans Petter Selasky iln = il->ary[0]; 1938d59ecb2SHans Petter Selasky free(il, M_IDR); 1948d59ecb2SHans Petter Selasky } 1958d59ecb2SHans Petter Selasky mtx_unlock(&idr->lock); 1965d35d777SHans Petter Selasky mtx_destroy(&idr->lock); 1978d59ecb2SHans Petter Selasky } 1988d59ecb2SHans Petter Selasky 1998d59ecb2SHans Petter Selasky static void 2008d59ecb2SHans Petter Selasky idr_remove_layer(struct idr_layer *il, int layer) 2018d59ecb2SHans Petter Selasky { 2028d59ecb2SHans Petter Selasky int i; 2038d59ecb2SHans Petter Selasky 2048d59ecb2SHans Petter Selasky if (il == NULL) 2058d59ecb2SHans Petter Selasky return; 2068d59ecb2SHans Petter Selasky if (layer == 0) { 2078d59ecb2SHans Petter Selasky free(il, M_IDR); 2088d59ecb2SHans Petter Selasky return; 2098d59ecb2SHans Petter Selasky } 2108d59ecb2SHans Petter Selasky for (i = 0; i < IDR_SIZE; i++) 2118d59ecb2SHans Petter Selasky if (il->ary[i]) 2128d59ecb2SHans Petter Selasky idr_remove_layer(il->ary[i], layer - 1); 2138d59ecb2SHans Petter Selasky } 2148d59ecb2SHans Petter Selasky 2158d59ecb2SHans Petter Selasky void 2168d59ecb2SHans Petter Selasky idr_remove_all(struct idr *idr) 2178d59ecb2SHans Petter Selasky { 2188d59ecb2SHans Petter Selasky 2198d59ecb2SHans Petter Selasky mtx_lock(&idr->lock); 2208d59ecb2SHans Petter Selasky idr_remove_layer(idr->top, idr->layers - 1); 2218d59ecb2SHans Petter Selasky idr->top = NULL; 2228d59ecb2SHans Petter Selasky idr->layers = 0; 2238d59ecb2SHans Petter Selasky mtx_unlock(&idr->lock); 2248d59ecb2SHans Petter Selasky } 2258d59ecb2SHans Petter Selasky 22669d6653bSHans Petter Selasky static void * 2272d1bee65SHans Petter Selasky idr_remove_locked(struct idr *idr, int id) 2288d59ecb2SHans Petter Selasky { 2298d59ecb2SHans Petter Selasky struct idr_layer *il; 23069d6653bSHans Petter Selasky void *res; 2318d59ecb2SHans Petter Selasky int layer; 2328d59ecb2SHans Petter Selasky int idx; 2338d59ecb2SHans Petter Selasky 2348d59ecb2SHans Petter Selasky id &= MAX_ID_MASK; 2358d59ecb2SHans Petter Selasky il = idr->top; 2368d59ecb2SHans Petter Selasky layer = idr->layers - 1; 2372d1bee65SHans Petter Selasky if (il == NULL || id > idr_max(idr)) 23869d6653bSHans Petter Selasky return (NULL); 2398d59ecb2SHans Petter Selasky /* 2408d59ecb2SHans Petter Selasky * Walk down the tree to this item setting bitmaps along the way 2418d59ecb2SHans Petter Selasky * as we know at least one item will be free along this path. 2428d59ecb2SHans Petter Selasky */ 2438d59ecb2SHans Petter Selasky while (layer && il) { 2448d59ecb2SHans Petter Selasky idx = idr_pos(id, layer); 2458d59ecb2SHans Petter Selasky il->bitmap |= 1 << idx; 2468d59ecb2SHans Petter Selasky il = il->ary[idx]; 2478d59ecb2SHans Petter Selasky layer--; 2488d59ecb2SHans Petter Selasky } 2498d59ecb2SHans Petter Selasky idx = id & IDR_MASK; 2508d59ecb2SHans Petter Selasky /* 2518d59ecb2SHans Petter Selasky * At this point we've set free space bitmaps up the whole tree. 2528d59ecb2SHans Petter Selasky * We could make this non-fatal and unwind but linux dumps a stack 2538d59ecb2SHans Petter Selasky * and a warning so I don't think it's necessary. 2548d59ecb2SHans Petter Selasky */ 2558d59ecb2SHans Petter Selasky if (il == NULL || (il->bitmap & (1 << idx)) != 0) 2568d59ecb2SHans Petter Selasky panic("idr_remove: Item %d not allocated (%p, %p)\n", 2578d59ecb2SHans Petter Selasky id, idr, il); 25869d6653bSHans Petter Selasky res = il->ary[idx]; 2598d59ecb2SHans Petter Selasky il->ary[idx] = NULL; 2608d59ecb2SHans Petter Selasky il->bitmap |= 1 << idx; 26169d6653bSHans Petter Selasky 26269d6653bSHans Petter Selasky return (res); 2632d1bee65SHans Petter Selasky } 2642d1bee65SHans Petter Selasky 26569d6653bSHans Petter Selasky void * 2662d1bee65SHans Petter Selasky idr_remove(struct idr *idr, int id) 2672d1bee65SHans Petter Selasky { 26869d6653bSHans Petter Selasky void *res; 26969d6653bSHans Petter Selasky 2702d1bee65SHans Petter Selasky mtx_lock(&idr->lock); 27169d6653bSHans Petter Selasky res = idr_remove_locked(idr, id); 2728d59ecb2SHans Petter Selasky mtx_unlock(&idr->lock); 27369d6653bSHans Petter Selasky 27469d6653bSHans Petter Selasky return (res); 2758d59ecb2SHans Petter Selasky } 2768d59ecb2SHans Petter Selasky 277f8221002SHans Petter Selasky static inline struct idr_layer * 278f8221002SHans Petter Selasky idr_find_layer_locked(struct idr *idr, int id) 279f8221002SHans Petter Selasky { 280f8221002SHans Petter Selasky struct idr_layer *il; 281f8221002SHans Petter Selasky int layer; 282f8221002SHans Petter Selasky 283f8221002SHans Petter Selasky id &= MAX_ID_MASK; 284f8221002SHans Petter Selasky il = idr->top; 285f8221002SHans Petter Selasky layer = idr->layers - 1; 286f8221002SHans Petter Selasky if (il == NULL || id > idr_max(idr)) 287f8221002SHans Petter Selasky return (NULL); 288f8221002SHans Petter Selasky while (layer && il) { 289f8221002SHans Petter Selasky il = il->ary[idr_pos(id, layer)]; 290f8221002SHans Petter Selasky layer--; 291f8221002SHans Petter Selasky } 292f8221002SHans Petter Selasky return (il); 293f8221002SHans Petter Selasky } 294f8221002SHans Petter Selasky 2958d59ecb2SHans Petter Selasky void * 2968d59ecb2SHans Petter Selasky idr_replace(struct idr *idr, void *ptr, int id) 2978d59ecb2SHans Petter Selasky { 2988d59ecb2SHans Petter Selasky struct idr_layer *il; 2998d59ecb2SHans Petter Selasky void *res; 3008d59ecb2SHans Petter Selasky int idx; 3018d59ecb2SHans Petter Selasky 3028d59ecb2SHans Petter Selasky mtx_lock(&idr->lock); 303f8221002SHans Petter Selasky il = idr_find_layer_locked(idr, id); 3048d59ecb2SHans Petter Selasky idx = id & IDR_MASK; 305f8221002SHans Petter Selasky 306f8221002SHans Petter Selasky /* Replace still returns an error if the item was not allocated. */ 307f8221002SHans Petter Selasky if (il == NULL || (il->bitmap & (1 << idx))) { 308f8221002SHans Petter Selasky res = ERR_PTR(-ENOENT); 309f8221002SHans Petter Selasky } else { 3108d59ecb2SHans Petter Selasky res = il->ary[idx]; 3118d59ecb2SHans Petter Selasky il->ary[idx] = ptr; 3128d59ecb2SHans Petter Selasky } 3138d59ecb2SHans Petter Selasky mtx_unlock(&idr->lock); 3148d59ecb2SHans Petter Selasky return (res); 3158d59ecb2SHans Petter Selasky } 3168d59ecb2SHans Petter Selasky 3178d59ecb2SHans Petter Selasky static inline void * 3188d59ecb2SHans Petter Selasky idr_find_locked(struct idr *idr, int id) 3198d59ecb2SHans Petter Selasky { 3208d59ecb2SHans Petter Selasky struct idr_layer *il; 3218d59ecb2SHans Petter Selasky void *res; 3228d59ecb2SHans Petter Selasky 3238d59ecb2SHans Petter Selasky mtx_assert(&idr->lock, MA_OWNED); 324f8221002SHans Petter Selasky il = idr_find_layer_locked(idr, id); 3258d59ecb2SHans Petter Selasky if (il != NULL) 3268d59ecb2SHans Petter Selasky res = il->ary[id & IDR_MASK]; 327f8221002SHans Petter Selasky else 328f8221002SHans Petter Selasky res = NULL; 3298d59ecb2SHans Petter Selasky return (res); 3308d59ecb2SHans Petter Selasky } 3318d59ecb2SHans Petter Selasky 3328d59ecb2SHans Petter Selasky void * 3338d59ecb2SHans Petter Selasky idr_find(struct idr *idr, int id) 3348d59ecb2SHans Petter Selasky { 3358d59ecb2SHans Petter Selasky void *res; 3368d59ecb2SHans Petter Selasky 3378d59ecb2SHans Petter Selasky mtx_lock(&idr->lock); 3388d59ecb2SHans Petter Selasky res = idr_find_locked(idr, id); 3398d59ecb2SHans Petter Selasky mtx_unlock(&idr->lock); 3408d59ecb2SHans Petter Selasky return (res); 3418d59ecb2SHans Petter Selasky } 3428d59ecb2SHans Petter Selasky 343fd42d623SHans Petter Selasky void * 344fd42d623SHans Petter Selasky idr_get_next(struct idr *idr, int *nextidp) 345fd42d623SHans Petter Selasky { 346fd42d623SHans Petter Selasky void *res = NULL; 347fd42d623SHans Petter Selasky int id = *nextidp; 348fd42d623SHans Petter Selasky 349fd42d623SHans Petter Selasky mtx_lock(&idr->lock); 350fd42d623SHans Petter Selasky for (; id <= idr_max(idr); id++) { 351fd42d623SHans Petter Selasky res = idr_find_locked(idr, id); 352fd42d623SHans Petter Selasky if (res == NULL) 353fd42d623SHans Petter Selasky continue; 354fd42d623SHans Petter Selasky *nextidp = id; 355fd42d623SHans Petter Selasky break; 356fd42d623SHans Petter Selasky } 357fd42d623SHans Petter Selasky mtx_unlock(&idr->lock); 358fd42d623SHans Petter Selasky return (res); 359fd42d623SHans Petter Selasky } 360fd42d623SHans Petter Selasky 3618d59ecb2SHans Petter Selasky int 3628d59ecb2SHans Petter Selasky idr_pre_get(struct idr *idr, gfp_t gfp_mask) 3638d59ecb2SHans Petter Selasky { 3648d59ecb2SHans Petter Selasky struct idr_layer *il, *iln; 3658d59ecb2SHans Petter Selasky struct idr_layer *head; 3668d59ecb2SHans Petter Selasky int need; 3678d59ecb2SHans Petter Selasky 3688d59ecb2SHans Petter Selasky mtx_lock(&idr->lock); 3698d59ecb2SHans Petter Selasky for (;;) { 3708d59ecb2SHans Petter Selasky need = idr->layers + 1; 3718d59ecb2SHans Petter Selasky for (il = idr->free; il != NULL; il = il->ary[0]) 3728d59ecb2SHans Petter Selasky need--; 3738d59ecb2SHans Petter Selasky mtx_unlock(&idr->lock); 3748d59ecb2SHans Petter Selasky if (need <= 0) 3758d59ecb2SHans Petter Selasky break; 3768d59ecb2SHans Petter Selasky for (head = NULL; need; need--) { 3778d59ecb2SHans Petter Selasky iln = malloc(sizeof(*il), M_IDR, M_ZERO | gfp_mask); 3788d59ecb2SHans Petter Selasky if (iln == NULL) 3798d59ecb2SHans Petter Selasky break; 3808d59ecb2SHans Petter Selasky bitmap_fill(&iln->bitmap, IDR_SIZE); 3818d59ecb2SHans Petter Selasky if (head != NULL) { 3828d59ecb2SHans Petter Selasky il->ary[0] = iln; 3838d59ecb2SHans Petter Selasky il = iln; 3848d59ecb2SHans Petter Selasky } else 3858d59ecb2SHans Petter Selasky head = il = iln; 3868d59ecb2SHans Petter Selasky } 3878d59ecb2SHans Petter Selasky if (head == NULL) 3888d59ecb2SHans Petter Selasky return (0); 3898d59ecb2SHans Petter Selasky mtx_lock(&idr->lock); 3908d59ecb2SHans Petter Selasky il->ary[0] = idr->free; 3918d59ecb2SHans Petter Selasky idr->free = head; 3928d59ecb2SHans Petter Selasky } 3938d59ecb2SHans Petter Selasky return (1); 3948d59ecb2SHans Petter Selasky } 3958d59ecb2SHans Petter Selasky 396427cefdeSHans Petter Selasky static struct idr_layer * 397427cefdeSHans Petter Selasky idr_free_list_get(struct idr *idp) 3988d59ecb2SHans Petter Selasky { 3998d59ecb2SHans Petter Selasky struct idr_layer *il; 4008d59ecb2SHans Petter Selasky 401427cefdeSHans Petter Selasky if ((il = idp->free) != NULL) { 402427cefdeSHans Petter Selasky idp->free = il->ary[0]; 4038d59ecb2SHans Petter Selasky il->ary[0] = NULL; 404427cefdeSHans Petter Selasky } 4058d59ecb2SHans Petter Selasky return (il); 4068d59ecb2SHans Petter Selasky } 407427cefdeSHans Petter Selasky 408427cefdeSHans Petter Selasky static inline struct idr_layer * 409427cefdeSHans Petter Selasky idr_get(struct idr *idp) 410427cefdeSHans Petter Selasky { 411427cefdeSHans Petter Selasky struct idr_layer *il; 412427cefdeSHans Petter Selasky 413427cefdeSHans Petter Selasky if ((il = idr_free_list_get(idp)) != NULL) { 414427cefdeSHans Petter Selasky MPASS(il->bitmap != 0); 415427cefdeSHans Petter Selasky } else if ((il = malloc(sizeof(*il), M_IDR, M_ZERO | M_NOWAIT)) != NULL) { 4168d59ecb2SHans Petter Selasky bitmap_fill(&il->bitmap, IDR_SIZE); 417427cefdeSHans Petter Selasky } else if ((il = idr_preload_dequeue_locked(&DPCPU_GET(linux_idr_cache))) != NULL) { 418427cefdeSHans Petter Selasky bitmap_fill(&il->bitmap, IDR_SIZE); 419427cefdeSHans Petter Selasky } else { 420427cefdeSHans Petter Selasky return (NULL); 421427cefdeSHans Petter Selasky } 4228d59ecb2SHans Petter Selasky return (il); 4238d59ecb2SHans Petter Selasky } 4248d59ecb2SHans Petter Selasky 4258d59ecb2SHans Petter Selasky /* 4268d59ecb2SHans Petter Selasky * Could be implemented as get_new_above(idr, ptr, 0, idp) but written 4278d59ecb2SHans Petter Selasky * first for simplicity sake. 4288d59ecb2SHans Petter Selasky */ 4292d1bee65SHans Petter Selasky static int 4302d1bee65SHans Petter Selasky idr_get_new_locked(struct idr *idr, void *ptr, int *idp) 4318d59ecb2SHans Petter Selasky { 4328d59ecb2SHans Petter Selasky struct idr_layer *stack[MAX_LEVEL]; 4338d59ecb2SHans Petter Selasky struct idr_layer *il; 4348d59ecb2SHans Petter Selasky int error; 4358d59ecb2SHans Petter Selasky int layer; 4368d59ecb2SHans Petter Selasky int idx; 4378d59ecb2SHans Petter Selasky int id; 4388d59ecb2SHans Petter Selasky 4392d1bee65SHans Petter Selasky mtx_assert(&idr->lock, MA_OWNED); 4402d1bee65SHans Petter Selasky 4418d59ecb2SHans Petter Selasky error = -EAGAIN; 4428d59ecb2SHans Petter Selasky /* 4438d59ecb2SHans Petter Selasky * Expand the tree until there is free space. 4448d59ecb2SHans Petter Selasky */ 4458d59ecb2SHans Petter Selasky if (idr->top == NULL || idr->top->bitmap == 0) { 4468d59ecb2SHans Petter Selasky if (idr->layers == MAX_LEVEL + 1) { 4478d59ecb2SHans Petter Selasky error = -ENOSPC; 4488d59ecb2SHans Petter Selasky goto out; 4498d59ecb2SHans Petter Selasky } 4508d59ecb2SHans Petter Selasky il = idr_get(idr); 4518d59ecb2SHans Petter Selasky if (il == NULL) 4528d59ecb2SHans Petter Selasky goto out; 4538d59ecb2SHans Petter Selasky il->ary[0] = idr->top; 4548d59ecb2SHans Petter Selasky if (idr->top) 4558d59ecb2SHans Petter Selasky il->bitmap &= ~1; 4568d59ecb2SHans Petter Selasky idr->top = il; 4578d59ecb2SHans Petter Selasky idr->layers++; 4588d59ecb2SHans Petter Selasky } 4598d59ecb2SHans Petter Selasky il = idr->top; 4608d59ecb2SHans Petter Selasky id = 0; 4618d59ecb2SHans Petter Selasky /* 4628d59ecb2SHans Petter Selasky * Walk the tree following free bitmaps, record our path. 4638d59ecb2SHans Petter Selasky */ 4648d59ecb2SHans Petter Selasky for (layer = idr->layers - 1;; layer--) { 4658d59ecb2SHans Petter Selasky stack[layer] = il; 4668d59ecb2SHans Petter Selasky idx = ffsl(il->bitmap); 4678d59ecb2SHans Petter Selasky if (idx == 0) 4688d59ecb2SHans Petter Selasky panic("idr_get_new: Invalid leaf state (%p, %p)\n", 4698d59ecb2SHans Petter Selasky idr, il); 4708d59ecb2SHans Petter Selasky idx--; 4718d59ecb2SHans Petter Selasky id |= idx << (layer * IDR_BITS); 4728d59ecb2SHans Petter Selasky if (layer == 0) 4738d59ecb2SHans Petter Selasky break; 4748d59ecb2SHans Petter Selasky if (il->ary[idx] == NULL) { 4758d59ecb2SHans Petter Selasky il->ary[idx] = idr_get(idr); 4768d59ecb2SHans Petter Selasky if (il->ary[idx] == NULL) 4778d59ecb2SHans Petter Selasky goto out; 4788d59ecb2SHans Petter Selasky } 4798d59ecb2SHans Petter Selasky il = il->ary[idx]; 4808d59ecb2SHans Petter Selasky } 4818d59ecb2SHans Petter Selasky /* 4828d59ecb2SHans Petter Selasky * Allocate the leaf to the consumer. 4838d59ecb2SHans Petter Selasky */ 4848d59ecb2SHans Petter Selasky il->bitmap &= ~(1 << idx); 4858d59ecb2SHans Petter Selasky il->ary[idx] = ptr; 4868d59ecb2SHans Petter Selasky *idp = id; 4878d59ecb2SHans Petter Selasky /* 4888d59ecb2SHans Petter Selasky * Clear bitmaps potentially up to the root. 4898d59ecb2SHans Petter Selasky */ 4908d59ecb2SHans Petter Selasky while (il->bitmap == 0 && ++layer < idr->layers) { 4918d59ecb2SHans Petter Selasky il = stack[layer]; 4928d59ecb2SHans Petter Selasky il->bitmap &= ~(1 << idr_pos(id, layer)); 4938d59ecb2SHans Petter Selasky } 4948d59ecb2SHans Petter Selasky error = 0; 4958d59ecb2SHans Petter Selasky out: 4968d59ecb2SHans Petter Selasky #ifdef INVARIANTS 4978d59ecb2SHans Petter Selasky if (error == 0 && idr_find_locked(idr, id) != ptr) { 4988d59ecb2SHans Petter Selasky panic("idr_get_new: Failed for idr %p, id %d, ptr %p\n", 4998d59ecb2SHans Petter Selasky idr, id, ptr); 5008d59ecb2SHans Petter Selasky } 5018d59ecb2SHans Petter Selasky #endif 5028d59ecb2SHans Petter Selasky return (error); 5038d59ecb2SHans Petter Selasky } 5048d59ecb2SHans Petter Selasky 5058d59ecb2SHans Petter Selasky int 5062d1bee65SHans Petter Selasky idr_get_new(struct idr *idr, void *ptr, int *idp) 5072d1bee65SHans Petter Selasky { 5082d1bee65SHans Petter Selasky int retval; 5092d1bee65SHans Petter Selasky 5102d1bee65SHans Petter Selasky mtx_lock(&idr->lock); 5112d1bee65SHans Petter Selasky retval = idr_get_new_locked(idr, ptr, idp); 5122d1bee65SHans Petter Selasky mtx_unlock(&idr->lock); 5132d1bee65SHans Petter Selasky return (retval); 5142d1bee65SHans Petter Selasky } 5152d1bee65SHans Petter Selasky 5162d1bee65SHans Petter Selasky static int 5172d1bee65SHans Petter Selasky idr_get_new_above_locked(struct idr *idr, void *ptr, int starting_id, int *idp) 5188d59ecb2SHans Petter Selasky { 5198d59ecb2SHans Petter Selasky struct idr_layer *stack[MAX_LEVEL]; 5208d59ecb2SHans Petter Selasky struct idr_layer *il; 5218d59ecb2SHans Petter Selasky int error; 5228d59ecb2SHans Petter Selasky int layer; 5238d59ecb2SHans Petter Selasky int idx, sidx; 5248d59ecb2SHans Petter Selasky int id; 5258d59ecb2SHans Petter Selasky 5262d1bee65SHans Petter Selasky mtx_assert(&idr->lock, MA_OWNED); 5272d1bee65SHans Petter Selasky 5288d59ecb2SHans Petter Selasky error = -EAGAIN; 5298d59ecb2SHans Petter Selasky /* 5308d59ecb2SHans Petter Selasky * Compute the layers required to support starting_id and the mask 5318d59ecb2SHans Petter Selasky * at the top layer. 5328d59ecb2SHans Petter Selasky */ 5338d59ecb2SHans Petter Selasky restart: 5348d59ecb2SHans Petter Selasky idx = starting_id; 5358d59ecb2SHans Petter Selasky layer = 0; 5368d59ecb2SHans Petter Selasky while (idx & ~IDR_MASK) { 5378d59ecb2SHans Petter Selasky layer++; 5388d59ecb2SHans Petter Selasky idx >>= IDR_BITS; 5398d59ecb2SHans Petter Selasky } 5408d59ecb2SHans Petter Selasky if (layer == MAX_LEVEL + 1) { 5418d59ecb2SHans Petter Selasky error = -ENOSPC; 5428d59ecb2SHans Petter Selasky goto out; 5438d59ecb2SHans Petter Selasky } 5448d59ecb2SHans Petter Selasky /* 5458d59ecb2SHans Petter Selasky * Expand the tree until there is free space at or beyond starting_id. 5468d59ecb2SHans Petter Selasky */ 5478d59ecb2SHans Petter Selasky while (idr->layers <= layer || 5488d59ecb2SHans Petter Selasky idr->top->bitmap < (1 << idr_pos(starting_id, idr->layers - 1))) { 5498d59ecb2SHans Petter Selasky if (idr->layers == MAX_LEVEL + 1) { 5508d59ecb2SHans Petter Selasky error = -ENOSPC; 5518d59ecb2SHans Petter Selasky goto out; 5528d59ecb2SHans Petter Selasky } 5538d59ecb2SHans Petter Selasky il = idr_get(idr); 5548d59ecb2SHans Petter Selasky if (il == NULL) 5558d59ecb2SHans Petter Selasky goto out; 5568d59ecb2SHans Petter Selasky il->ary[0] = idr->top; 5578d59ecb2SHans Petter Selasky if (idr->top && idr->top->bitmap == 0) 5588d59ecb2SHans Petter Selasky il->bitmap &= ~1; 5598d59ecb2SHans Petter Selasky idr->top = il; 5608d59ecb2SHans Petter Selasky idr->layers++; 5618d59ecb2SHans Petter Selasky } 5628d59ecb2SHans Petter Selasky il = idr->top; 5638d59ecb2SHans Petter Selasky id = 0; 5648d59ecb2SHans Petter Selasky /* 5658d59ecb2SHans Petter Selasky * Walk the tree following free bitmaps, record our path. 5668d59ecb2SHans Petter Selasky */ 5678d59ecb2SHans Petter Selasky for (layer = idr->layers - 1;; layer--) { 5688d59ecb2SHans Petter Selasky stack[layer] = il; 5698d59ecb2SHans Petter Selasky sidx = idr_pos(starting_id, layer); 5708d59ecb2SHans Petter Selasky /* Returns index numbered from 0 or size if none exists. */ 5718d59ecb2SHans Petter Selasky idx = find_next_bit(&il->bitmap, IDR_SIZE, sidx); 5728d59ecb2SHans Petter Selasky if (idx == IDR_SIZE && sidx == 0) 5738d59ecb2SHans Petter Selasky panic("idr_get_new: Invalid leaf state (%p, %p)\n", 5748d59ecb2SHans Petter Selasky idr, il); 5758d59ecb2SHans Petter Selasky /* 5768d59ecb2SHans Petter Selasky * We may have walked a path where there was a free bit but 5778d59ecb2SHans Petter Selasky * it was lower than what we wanted. Restart the search with 5788d59ecb2SHans Petter Selasky * a larger starting id. id contains the progress we made so 5798d59ecb2SHans Petter Selasky * far. Search the leaf one above this level. This may 5808d59ecb2SHans Petter Selasky * restart as many as MAX_LEVEL times but that is expected 5818d59ecb2SHans Petter Selasky * to be rare. 5828d59ecb2SHans Petter Selasky */ 5838d59ecb2SHans Petter Selasky if (idx == IDR_SIZE) { 5848d59ecb2SHans Petter Selasky starting_id = id + (1 << ((layer + 1) * IDR_BITS)); 5858d59ecb2SHans Petter Selasky goto restart; 5868d59ecb2SHans Petter Selasky } 5878d59ecb2SHans Petter Selasky if (idx > sidx) 5888d59ecb2SHans Petter Selasky starting_id = 0; /* Search the whole subtree. */ 5898d59ecb2SHans Petter Selasky id |= idx << (layer * IDR_BITS); 5908d59ecb2SHans Petter Selasky if (layer == 0) 5918d59ecb2SHans Petter Selasky break; 5928d59ecb2SHans Petter Selasky if (il->ary[idx] == NULL) { 5938d59ecb2SHans Petter Selasky il->ary[idx] = idr_get(idr); 5948d59ecb2SHans Petter Selasky if (il->ary[idx] == NULL) 5958d59ecb2SHans Petter Selasky goto out; 5968d59ecb2SHans Petter Selasky } 5978d59ecb2SHans Petter Selasky il = il->ary[idx]; 5988d59ecb2SHans Petter Selasky } 5998d59ecb2SHans Petter Selasky /* 6008d59ecb2SHans Petter Selasky * Allocate the leaf to the consumer. 6018d59ecb2SHans Petter Selasky */ 6028d59ecb2SHans Petter Selasky il->bitmap &= ~(1 << idx); 6038d59ecb2SHans Petter Selasky il->ary[idx] = ptr; 6048d59ecb2SHans Petter Selasky *idp = id; 6058d59ecb2SHans Petter Selasky /* 6068d59ecb2SHans Petter Selasky * Clear bitmaps potentially up to the root. 6078d59ecb2SHans Petter Selasky */ 6088d59ecb2SHans Petter Selasky while (il->bitmap == 0 && ++layer < idr->layers) { 6098d59ecb2SHans Petter Selasky il = stack[layer]; 6108d59ecb2SHans Petter Selasky il->bitmap &= ~(1 << idr_pos(id, layer)); 6118d59ecb2SHans Petter Selasky } 6128d59ecb2SHans Petter Selasky error = 0; 6138d59ecb2SHans Petter Selasky out: 6148d59ecb2SHans Petter Selasky #ifdef INVARIANTS 6158d59ecb2SHans Petter Selasky if (error == 0 && idr_find_locked(idr, id) != ptr) { 6168d59ecb2SHans Petter Selasky panic("idr_get_new_above: Failed for idr %p, id %d, ptr %p\n", 6178d59ecb2SHans Petter Selasky idr, id, ptr); 6188d59ecb2SHans Petter Selasky } 6198d59ecb2SHans Petter Selasky #endif 6208d59ecb2SHans Petter Selasky return (error); 6218d59ecb2SHans Petter Selasky } 6222d1bee65SHans Petter Selasky 6232d1bee65SHans Petter Selasky int 6242d1bee65SHans Petter Selasky idr_get_new_above(struct idr *idr, void *ptr, int starting_id, int *idp) 6252d1bee65SHans Petter Selasky { 6262d1bee65SHans Petter Selasky int retval; 6272d1bee65SHans Petter Selasky 6282d1bee65SHans Petter Selasky mtx_lock(&idr->lock); 6292d1bee65SHans Petter Selasky retval = idr_get_new_above_locked(idr, ptr, starting_id, idp); 6302d1bee65SHans Petter Selasky mtx_unlock(&idr->lock); 6312d1bee65SHans Petter Selasky return (retval); 6322d1bee65SHans Petter Selasky } 6332d1bee65SHans Petter Selasky 634fd42d623SHans Petter Selasky int 635fd42d623SHans Petter Selasky ida_get_new_above(struct ida *ida, int starting_id, int *p_id) 636fd42d623SHans Petter Selasky { 637fd42d623SHans Petter Selasky return (idr_get_new_above(&ida->idr, NULL, starting_id, p_id)); 638fd42d623SHans Petter Selasky } 639fd42d623SHans Petter Selasky 6402d1bee65SHans Petter Selasky static int 6412d1bee65SHans Petter Selasky idr_alloc_locked(struct idr *idr, void *ptr, int start, int end) 6422d1bee65SHans Petter Selasky { 6432d1bee65SHans Petter Selasky int max = end > 0 ? end - 1 : INT_MAX; 6442d1bee65SHans Petter Selasky int error; 6452d1bee65SHans Petter Selasky int id; 6462d1bee65SHans Petter Selasky 6472d1bee65SHans Petter Selasky mtx_assert(&idr->lock, MA_OWNED); 6482d1bee65SHans Petter Selasky 6492d1bee65SHans Petter Selasky if (unlikely(start < 0)) 6502d1bee65SHans Petter Selasky return (-EINVAL); 6512d1bee65SHans Petter Selasky if (unlikely(max < start)) 6522d1bee65SHans Petter Selasky return (-ENOSPC); 6532d1bee65SHans Petter Selasky 6542d1bee65SHans Petter Selasky if (start == 0) 6552d1bee65SHans Petter Selasky error = idr_get_new_locked(idr, ptr, &id); 6562d1bee65SHans Petter Selasky else 6572d1bee65SHans Petter Selasky error = idr_get_new_above_locked(idr, ptr, start, &id); 6582d1bee65SHans Petter Selasky 6592d1bee65SHans Petter Selasky if (unlikely(error < 0)) 6602d1bee65SHans Petter Selasky return (error); 6612d1bee65SHans Petter Selasky if (unlikely(id > max)) { 6622d1bee65SHans Petter Selasky idr_remove_locked(idr, id); 6632d1bee65SHans Petter Selasky return (-ENOSPC); 6642d1bee65SHans Petter Selasky } 6652d1bee65SHans Petter Selasky return (id); 6662d1bee65SHans Petter Selasky } 6672d1bee65SHans Petter Selasky 6682d1bee65SHans Petter Selasky int 6692d1bee65SHans Petter Selasky idr_alloc(struct idr *idr, void *ptr, int start, int end, gfp_t gfp_mask) 6702d1bee65SHans Petter Selasky { 6712d1bee65SHans Petter Selasky int retval; 6722d1bee65SHans Petter Selasky 6732d1bee65SHans Petter Selasky mtx_lock(&idr->lock); 6742d1bee65SHans Petter Selasky retval = idr_alloc_locked(idr, ptr, start, end); 6752d1bee65SHans Petter Selasky mtx_unlock(&idr->lock); 6762d1bee65SHans Petter Selasky return (retval); 6772d1bee65SHans Petter Selasky } 6782d1bee65SHans Petter Selasky 6792d1bee65SHans Petter Selasky int 6802d1bee65SHans Petter Selasky idr_alloc_cyclic(struct idr *idr, void *ptr, int start, int end, gfp_t gfp_mask) 6812d1bee65SHans Petter Selasky { 6822d1bee65SHans Petter Selasky int retval; 6832d1bee65SHans Petter Selasky 6842d1bee65SHans Petter Selasky mtx_lock(&idr->lock); 6852d1bee65SHans Petter Selasky retval = idr_alloc_locked(idr, ptr, max(start, idr->next_cyclic_id), end); 6862d1bee65SHans Petter Selasky if (unlikely(retval == -ENOSPC)) 6872d1bee65SHans Petter Selasky retval = idr_alloc_locked(idr, ptr, start, end); 6882d1bee65SHans Petter Selasky if (likely(retval >= 0)) 6892d1bee65SHans Petter Selasky idr->next_cyclic_id = retval + 1; 6902d1bee65SHans Petter Selasky mtx_unlock(&idr->lock); 6912d1bee65SHans Petter Selasky return (retval); 6922d1bee65SHans Petter Selasky } 693fd42d623SHans Petter Selasky 694fd42d623SHans Petter Selasky static int 695f885420dSHans Petter Selasky idr_for_each_layer(struct idr_layer *il, int offset, int layer, 696fd42d623SHans Petter Selasky int (*f)(int id, void *p, void *data), void *data) 697fd42d623SHans Petter Selasky { 698fd42d623SHans Petter Selasky int i, err; 699fd42d623SHans Petter Selasky 700fd42d623SHans Petter Selasky if (il == NULL) 701fd42d623SHans Petter Selasky return (0); 702fd42d623SHans Petter Selasky if (layer == 0) { 703fd42d623SHans Petter Selasky for (i = 0; i < IDR_SIZE; i++) { 704fd42d623SHans Petter Selasky if (il->ary[i] == NULL) 705fd42d623SHans Petter Selasky continue; 706f885420dSHans Petter Selasky err = f(i + offset, il->ary[i], data); 707fd42d623SHans Petter Selasky if (err) 708fd42d623SHans Petter Selasky return (err); 709fd42d623SHans Petter Selasky } 710fd42d623SHans Petter Selasky return (0); 711fd42d623SHans Petter Selasky } 712fd42d623SHans Petter Selasky for (i = 0; i < IDR_SIZE; i++) { 713fd42d623SHans Petter Selasky if (il->ary[i] == NULL) 714fd42d623SHans Petter Selasky continue; 715f885420dSHans Petter Selasky err = idr_for_each_layer(il->ary[i], 716f885420dSHans Petter Selasky (i + offset) * IDR_SIZE, layer - 1, f, data); 717fd42d623SHans Petter Selasky if (err) 718fd42d623SHans Petter Selasky return (err); 719fd42d623SHans Petter Selasky } 720fd42d623SHans Petter Selasky return (0); 721fd42d623SHans Petter Selasky } 722fd42d623SHans Petter Selasky 723dacb734eSHans Petter Selasky /* NOTE: It is not allowed to modify the IDR tree while it is being iterated */ 724fd42d623SHans Petter Selasky int 725fd42d623SHans Petter Selasky idr_for_each(struct idr *idp, int (*f)(int id, void *p, void *data), void *data) 726fd42d623SHans Petter Selasky { 727f885420dSHans Petter Selasky return (idr_for_each_layer(idp->top, 0, idp->layers - 1, f, data)); 728fd42d623SHans Petter Selasky } 729fd42d623SHans Petter Selasky 73069d6653bSHans Petter Selasky static int 73169d6653bSHans Petter Selasky idr_has_entry(int id, void *p, void *data) 73269d6653bSHans Petter Selasky { 73369d6653bSHans Petter Selasky 73469d6653bSHans Petter Selasky return (1); 73569d6653bSHans Petter Selasky } 73669d6653bSHans Petter Selasky 73769d6653bSHans Petter Selasky bool 73869d6653bSHans Petter Selasky idr_is_empty(struct idr *idp) 73969d6653bSHans Petter Selasky { 74069d6653bSHans Petter Selasky 74169d6653bSHans Petter Selasky return (idr_for_each(idp, idr_has_entry, NULL) == 0); 74269d6653bSHans Petter Selasky } 74369d6653bSHans Petter Selasky 744fd42d623SHans Petter Selasky int 745fd42d623SHans Petter Selasky ida_pre_get(struct ida *ida, gfp_t flags) 746fd42d623SHans Petter Selasky { 747fd42d623SHans Petter Selasky if (idr_pre_get(&ida->idr, flags) == 0) 748fd42d623SHans Petter Selasky return (0); 749fd42d623SHans Petter Selasky 750fd42d623SHans Petter Selasky if (ida->free_bitmap == NULL) { 751fd42d623SHans Petter Selasky ida->free_bitmap = 752fd42d623SHans Petter Selasky malloc(sizeof(struct ida_bitmap), M_IDR, flags); 753fd42d623SHans Petter Selasky } 754fd42d623SHans Petter Selasky return (ida->free_bitmap != NULL); 755fd42d623SHans Petter Selasky } 756fd42d623SHans Petter Selasky 757fd42d623SHans Petter Selasky int 758fd42d623SHans Petter Selasky ida_simple_get(struct ida *ida, unsigned int start, unsigned int end, 759fd42d623SHans Petter Selasky gfp_t flags) 760fd42d623SHans Petter Selasky { 761fd42d623SHans Petter Selasky int ret, id; 762fd42d623SHans Petter Selasky unsigned int max; 763fd42d623SHans Petter Selasky 764fd42d623SHans Petter Selasky MPASS((int)start >= 0); 765fd42d623SHans Petter Selasky 766c7312643SVladimir Kondratyev if ((int)end <= 0) 767c7312643SVladimir Kondratyev max = INT_MAX; 768fd42d623SHans Petter Selasky else { 769fd42d623SHans Petter Selasky MPASS(end > start); 770fd42d623SHans Petter Selasky max = end - 1; 771fd42d623SHans Petter Selasky } 772fd42d623SHans Petter Selasky again: 773fd42d623SHans Petter Selasky if (!ida_pre_get(ida, flags)) 774fd42d623SHans Petter Selasky return (-ENOMEM); 775fd42d623SHans Petter Selasky 776fd42d623SHans Petter Selasky if ((ret = ida_get_new_above(ida, start, &id)) == 0) { 777fd42d623SHans Petter Selasky if (id > max) { 778fd42d623SHans Petter Selasky ida_remove(ida, id); 779fd42d623SHans Petter Selasky ret = -ENOSPC; 780fd42d623SHans Petter Selasky } else { 781fd42d623SHans Petter Selasky ret = id; 782fd42d623SHans Petter Selasky } 783fd42d623SHans Petter Selasky } 784fd42d623SHans Petter Selasky if (__predict_false(ret == -EAGAIN)) 785fd42d623SHans Petter Selasky goto again; 786fd42d623SHans Petter Selasky 787fd42d623SHans Petter Selasky return (ret); 788fd42d623SHans Petter Selasky } 789fd42d623SHans Petter Selasky 790fd42d623SHans Petter Selasky void 791fd42d623SHans Petter Selasky ida_simple_remove(struct ida *ida, unsigned int id) 792fd42d623SHans Petter Selasky { 793fd42d623SHans Petter Selasky idr_remove(&ida->idr, id); 794fd42d623SHans Petter Selasky } 795fd42d623SHans Petter Selasky 796fd42d623SHans Petter Selasky void 797fd42d623SHans Petter Selasky ida_remove(struct ida *ida, int id) 798fd42d623SHans Petter Selasky { 799fd42d623SHans Petter Selasky idr_remove(&ida->idr, id); 800fd42d623SHans Petter Selasky } 801fd42d623SHans Petter Selasky 802fd42d623SHans Petter Selasky void 803fd42d623SHans Petter Selasky ida_init(struct ida *ida) 804fd42d623SHans Petter Selasky { 805fd42d623SHans Petter Selasky idr_init(&ida->idr); 806fd42d623SHans Petter Selasky } 807fd42d623SHans Petter Selasky 808fd42d623SHans Petter Selasky void 809fd42d623SHans Petter Selasky ida_destroy(struct ida *ida) 810fd42d623SHans Petter Selasky { 811fd42d623SHans Petter Selasky idr_destroy(&ida->idr); 812fd42d623SHans Petter Selasky free(ida->free_bitmap, M_IDR); 813*613723baSAustin Shafer ida->free_bitmap = NULL; 814fd42d623SHans Petter Selasky } 815