1*8d59ecb2SHans Petter Selasky /*- 2*8d59ecb2SHans Petter Selasky * Copyright (c) 2010 Isilon Systems, Inc. 3*8d59ecb2SHans Petter Selasky * Copyright (c) 2010 iX Systems, Inc. 4*8d59ecb2SHans Petter Selasky * Copyright (c) 2010 Panasas, Inc. 5*8d59ecb2SHans Petter Selasky * Copyright (c) 2013, 2014 Mellanox Technologies, Ltd. 6*8d59ecb2SHans Petter Selasky * All rights reserved. 7*8d59ecb2SHans Petter Selasky * 8*8d59ecb2SHans Petter Selasky * Redistribution and use in source and binary forms, with or without 9*8d59ecb2SHans Petter Selasky * modification, are permitted provided that the following conditions 10*8d59ecb2SHans Petter Selasky * are met: 11*8d59ecb2SHans Petter Selasky * 1. Redistributions of source code must retain the above copyright 12*8d59ecb2SHans Petter Selasky * notice unmodified, this list of conditions, and the following 13*8d59ecb2SHans Petter Selasky * disclaimer. 14*8d59ecb2SHans Petter Selasky * 2. Redistributions in binary form must reproduce the above copyright 15*8d59ecb2SHans Petter Selasky * notice, this list of conditions and the following disclaimer in the 16*8d59ecb2SHans Petter Selasky * documentation and/or other materials provided with the distribution. 17*8d59ecb2SHans Petter Selasky * 18*8d59ecb2SHans Petter Selasky * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19*8d59ecb2SHans Petter Selasky * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20*8d59ecb2SHans Petter Selasky * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21*8d59ecb2SHans Petter Selasky * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22*8d59ecb2SHans Petter Selasky * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23*8d59ecb2SHans Petter Selasky * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24*8d59ecb2SHans Petter Selasky * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25*8d59ecb2SHans Petter Selasky * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26*8d59ecb2SHans Petter Selasky * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27*8d59ecb2SHans Petter Selasky * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28*8d59ecb2SHans Petter Selasky */ 29*8d59ecb2SHans Petter Selasky 30*8d59ecb2SHans Petter Selasky #include <sys/cdefs.h> 31*8d59ecb2SHans Petter Selasky __FBSDID("$FreeBSD$"); 32*8d59ecb2SHans Petter Selasky 33*8d59ecb2SHans Petter Selasky #include <sys/param.h> 34*8d59ecb2SHans Petter Selasky #include <sys/systm.h> 35*8d59ecb2SHans Petter Selasky #include <sys/malloc.h> 36*8d59ecb2SHans Petter Selasky #include <sys/kernel.h> 37*8d59ecb2SHans Petter Selasky #include <sys/sysctl.h> 38*8d59ecb2SHans Petter Selasky #include <sys/lock.h> 39*8d59ecb2SHans Petter Selasky #include <sys/mutex.h> 40*8d59ecb2SHans Petter Selasky 41*8d59ecb2SHans Petter Selasky #include <machine/stdarg.h> 42*8d59ecb2SHans Petter Selasky 43*8d59ecb2SHans Petter Selasky #include <linux/bitops.h> 44*8d59ecb2SHans Petter Selasky #include <linux/kobject.h> 45*8d59ecb2SHans Petter Selasky #include <linux/slab.h> 46*8d59ecb2SHans Petter Selasky #include <linux/idr.h> 47*8d59ecb2SHans Petter Selasky #include <linux/err.h> 48*8d59ecb2SHans Petter Selasky 49*8d59ecb2SHans Petter Selasky /* 50*8d59ecb2SHans Petter Selasky * IDR Implementation. 51*8d59ecb2SHans Petter Selasky * 52*8d59ecb2SHans Petter Selasky * This is quick and dirty and not as re-entrant as the linux version 53*8d59ecb2SHans Petter Selasky * however it should be fairly fast. It is basically a radix tree with 54*8d59ecb2SHans Petter Selasky * a builtin bitmap for allocation. 55*8d59ecb2SHans Petter Selasky */ 56*8d59ecb2SHans Petter Selasky static MALLOC_DEFINE(M_IDR, "idr", "Linux IDR compat"); 57*8d59ecb2SHans Petter Selasky 58*8d59ecb2SHans Petter Selasky static inline int 59*8d59ecb2SHans Petter Selasky idr_max(struct idr *idr) 60*8d59ecb2SHans Petter Selasky { 61*8d59ecb2SHans Petter Selasky return (1 << (idr->layers * IDR_BITS)) - 1; 62*8d59ecb2SHans Petter Selasky } 63*8d59ecb2SHans Petter Selasky 64*8d59ecb2SHans Petter Selasky static inline int 65*8d59ecb2SHans Petter Selasky idr_pos(int id, int layer) 66*8d59ecb2SHans Petter Selasky { 67*8d59ecb2SHans Petter Selasky return (id >> (IDR_BITS * layer)) & IDR_MASK; 68*8d59ecb2SHans Petter Selasky } 69*8d59ecb2SHans Petter Selasky 70*8d59ecb2SHans Petter Selasky void 71*8d59ecb2SHans Petter Selasky idr_init(struct idr *idr) 72*8d59ecb2SHans Petter Selasky { 73*8d59ecb2SHans Petter Selasky bzero(idr, sizeof(*idr)); 74*8d59ecb2SHans Petter Selasky mtx_init(&idr->lock, "idr", NULL, MTX_DEF); 75*8d59ecb2SHans Petter Selasky } 76*8d59ecb2SHans Petter Selasky 77*8d59ecb2SHans Petter Selasky /* Only frees cached pages. */ 78*8d59ecb2SHans Petter Selasky void 79*8d59ecb2SHans Petter Selasky idr_destroy(struct idr *idr) 80*8d59ecb2SHans Petter Selasky { 81*8d59ecb2SHans Petter Selasky struct idr_layer *il, *iln; 82*8d59ecb2SHans Petter Selasky 83*8d59ecb2SHans Petter Selasky idr_remove_all(idr); 84*8d59ecb2SHans Petter Selasky mtx_lock(&idr->lock); 85*8d59ecb2SHans Petter Selasky for (il = idr->free; il != NULL; il = iln) { 86*8d59ecb2SHans Petter Selasky iln = il->ary[0]; 87*8d59ecb2SHans Petter Selasky free(il, M_IDR); 88*8d59ecb2SHans Petter Selasky } 89*8d59ecb2SHans Petter Selasky mtx_unlock(&idr->lock); 90*8d59ecb2SHans Petter Selasky } 91*8d59ecb2SHans Petter Selasky 92*8d59ecb2SHans Petter Selasky static void 93*8d59ecb2SHans Petter Selasky idr_remove_layer(struct idr_layer *il, int layer) 94*8d59ecb2SHans Petter Selasky { 95*8d59ecb2SHans Petter Selasky int i; 96*8d59ecb2SHans Petter Selasky 97*8d59ecb2SHans Petter Selasky if (il == NULL) 98*8d59ecb2SHans Petter Selasky return; 99*8d59ecb2SHans Petter Selasky if (layer == 0) { 100*8d59ecb2SHans Petter Selasky free(il, M_IDR); 101*8d59ecb2SHans Petter Selasky return; 102*8d59ecb2SHans Petter Selasky } 103*8d59ecb2SHans Petter Selasky for (i = 0; i < IDR_SIZE; i++) 104*8d59ecb2SHans Petter Selasky if (il->ary[i]) 105*8d59ecb2SHans Petter Selasky idr_remove_layer(il->ary[i], layer - 1); 106*8d59ecb2SHans Petter Selasky } 107*8d59ecb2SHans Petter Selasky 108*8d59ecb2SHans Petter Selasky void 109*8d59ecb2SHans Petter Selasky idr_remove_all(struct idr *idr) 110*8d59ecb2SHans Petter Selasky { 111*8d59ecb2SHans Petter Selasky 112*8d59ecb2SHans Petter Selasky mtx_lock(&idr->lock); 113*8d59ecb2SHans Petter Selasky idr_remove_layer(idr->top, idr->layers - 1); 114*8d59ecb2SHans Petter Selasky idr->top = NULL; 115*8d59ecb2SHans Petter Selasky idr->layers = 0; 116*8d59ecb2SHans Petter Selasky mtx_unlock(&idr->lock); 117*8d59ecb2SHans Petter Selasky } 118*8d59ecb2SHans Petter Selasky 119*8d59ecb2SHans Petter Selasky void 120*8d59ecb2SHans Petter Selasky idr_remove(struct idr *idr, int id) 121*8d59ecb2SHans Petter Selasky { 122*8d59ecb2SHans Petter Selasky struct idr_layer *il; 123*8d59ecb2SHans Petter Selasky int layer; 124*8d59ecb2SHans Petter Selasky int idx; 125*8d59ecb2SHans Petter Selasky 126*8d59ecb2SHans Petter Selasky id &= MAX_ID_MASK; 127*8d59ecb2SHans Petter Selasky mtx_lock(&idr->lock); 128*8d59ecb2SHans Petter Selasky il = idr->top; 129*8d59ecb2SHans Petter Selasky layer = idr->layers - 1; 130*8d59ecb2SHans Petter Selasky if (il == NULL || id > idr_max(idr)) { 131*8d59ecb2SHans Petter Selasky mtx_unlock(&idr->lock); 132*8d59ecb2SHans Petter Selasky return; 133*8d59ecb2SHans Petter Selasky } 134*8d59ecb2SHans Petter Selasky /* 135*8d59ecb2SHans Petter Selasky * Walk down the tree to this item setting bitmaps along the way 136*8d59ecb2SHans Petter Selasky * as we know at least one item will be free along this path. 137*8d59ecb2SHans Petter Selasky */ 138*8d59ecb2SHans Petter Selasky while (layer && il) { 139*8d59ecb2SHans Petter Selasky idx = idr_pos(id, layer); 140*8d59ecb2SHans Petter Selasky il->bitmap |= 1 << idx; 141*8d59ecb2SHans Petter Selasky il = il->ary[idx]; 142*8d59ecb2SHans Petter Selasky layer--; 143*8d59ecb2SHans Petter Selasky } 144*8d59ecb2SHans Petter Selasky idx = id & IDR_MASK; 145*8d59ecb2SHans Petter Selasky /* 146*8d59ecb2SHans Petter Selasky * At this point we've set free space bitmaps up the whole tree. 147*8d59ecb2SHans Petter Selasky * We could make this non-fatal and unwind but linux dumps a stack 148*8d59ecb2SHans Petter Selasky * and a warning so I don't think it's necessary. 149*8d59ecb2SHans Petter Selasky */ 150*8d59ecb2SHans Petter Selasky if (il == NULL || (il->bitmap & (1 << idx)) != 0) 151*8d59ecb2SHans Petter Selasky panic("idr_remove: Item %d not allocated (%p, %p)\n", 152*8d59ecb2SHans Petter Selasky id, idr, il); 153*8d59ecb2SHans Petter Selasky il->ary[idx] = NULL; 154*8d59ecb2SHans Petter Selasky il->bitmap |= 1 << idx; 155*8d59ecb2SHans Petter Selasky mtx_unlock(&idr->lock); 156*8d59ecb2SHans Petter Selasky return; 157*8d59ecb2SHans Petter Selasky } 158*8d59ecb2SHans Petter Selasky 159*8d59ecb2SHans Petter Selasky void * 160*8d59ecb2SHans Petter Selasky idr_replace(struct idr *idr, void *ptr, int id) 161*8d59ecb2SHans Petter Selasky { 162*8d59ecb2SHans Petter Selasky struct idr_layer *il; 163*8d59ecb2SHans Petter Selasky void *res; 164*8d59ecb2SHans Petter Selasky int layer; 165*8d59ecb2SHans Petter Selasky int idx; 166*8d59ecb2SHans Petter Selasky 167*8d59ecb2SHans Petter Selasky res = ERR_PTR(-EINVAL); 168*8d59ecb2SHans Petter Selasky id &= MAX_ID_MASK; 169*8d59ecb2SHans Petter Selasky mtx_lock(&idr->lock); 170*8d59ecb2SHans Petter Selasky il = idr->top; 171*8d59ecb2SHans Petter Selasky layer = idr->layers - 1; 172*8d59ecb2SHans Petter Selasky if (il == NULL || id > idr_max(idr)) 173*8d59ecb2SHans Petter Selasky goto out; 174*8d59ecb2SHans Petter Selasky while (layer && il) { 175*8d59ecb2SHans Petter Selasky il = il->ary[idr_pos(id, layer)]; 176*8d59ecb2SHans Petter Selasky layer--; 177*8d59ecb2SHans Petter Selasky } 178*8d59ecb2SHans Petter Selasky idx = id & IDR_MASK; 179*8d59ecb2SHans Petter Selasky /* 180*8d59ecb2SHans Petter Selasky * Replace still returns an error if the item was not allocated. 181*8d59ecb2SHans Petter Selasky */ 182*8d59ecb2SHans Petter Selasky if (il != NULL && (il->bitmap & (1 << idx)) != 0) { 183*8d59ecb2SHans Petter Selasky res = il->ary[idx]; 184*8d59ecb2SHans Petter Selasky il->ary[idx] = ptr; 185*8d59ecb2SHans Petter Selasky } 186*8d59ecb2SHans Petter Selasky out: 187*8d59ecb2SHans Petter Selasky mtx_unlock(&idr->lock); 188*8d59ecb2SHans Petter Selasky return (res); 189*8d59ecb2SHans Petter Selasky } 190*8d59ecb2SHans Petter Selasky 191*8d59ecb2SHans Petter Selasky static inline void * 192*8d59ecb2SHans Petter Selasky idr_find_locked(struct idr *idr, int id) 193*8d59ecb2SHans Petter Selasky { 194*8d59ecb2SHans Petter Selasky struct idr_layer *il; 195*8d59ecb2SHans Petter Selasky void *res; 196*8d59ecb2SHans Petter Selasky int layer; 197*8d59ecb2SHans Petter Selasky 198*8d59ecb2SHans Petter Selasky mtx_assert(&idr->lock, MA_OWNED); 199*8d59ecb2SHans Petter Selasky 200*8d59ecb2SHans Petter Selasky id &= MAX_ID_MASK; 201*8d59ecb2SHans Petter Selasky res = NULL; 202*8d59ecb2SHans Petter Selasky il = idr->top; 203*8d59ecb2SHans Petter Selasky layer = idr->layers - 1; 204*8d59ecb2SHans Petter Selasky if (il == NULL || id > idr_max(idr)) 205*8d59ecb2SHans Petter Selasky return (NULL); 206*8d59ecb2SHans Petter Selasky while (layer && il) { 207*8d59ecb2SHans Petter Selasky il = il->ary[idr_pos(id, layer)]; 208*8d59ecb2SHans Petter Selasky layer--; 209*8d59ecb2SHans Petter Selasky } 210*8d59ecb2SHans Petter Selasky if (il != NULL) 211*8d59ecb2SHans Petter Selasky res = il->ary[id & IDR_MASK]; 212*8d59ecb2SHans Petter Selasky return (res); 213*8d59ecb2SHans Petter Selasky } 214*8d59ecb2SHans Petter Selasky 215*8d59ecb2SHans Petter Selasky void * 216*8d59ecb2SHans Petter Selasky idr_find(struct idr *idr, int id) 217*8d59ecb2SHans Petter Selasky { 218*8d59ecb2SHans Petter Selasky void *res; 219*8d59ecb2SHans Petter Selasky 220*8d59ecb2SHans Petter Selasky mtx_lock(&idr->lock); 221*8d59ecb2SHans Petter Selasky res = idr_find_locked(idr, id); 222*8d59ecb2SHans Petter Selasky mtx_unlock(&idr->lock); 223*8d59ecb2SHans Petter Selasky return (res); 224*8d59ecb2SHans Petter Selasky } 225*8d59ecb2SHans Petter Selasky 226*8d59ecb2SHans Petter Selasky int 227*8d59ecb2SHans Petter Selasky idr_pre_get(struct idr *idr, gfp_t gfp_mask) 228*8d59ecb2SHans Petter Selasky { 229*8d59ecb2SHans Petter Selasky struct idr_layer *il, *iln; 230*8d59ecb2SHans Petter Selasky struct idr_layer *head; 231*8d59ecb2SHans Petter Selasky int need; 232*8d59ecb2SHans Petter Selasky 233*8d59ecb2SHans Petter Selasky mtx_lock(&idr->lock); 234*8d59ecb2SHans Petter Selasky for (;;) { 235*8d59ecb2SHans Petter Selasky need = idr->layers + 1; 236*8d59ecb2SHans Petter Selasky for (il = idr->free; il != NULL; il = il->ary[0]) 237*8d59ecb2SHans Petter Selasky need--; 238*8d59ecb2SHans Petter Selasky mtx_unlock(&idr->lock); 239*8d59ecb2SHans Petter Selasky if (need <= 0) 240*8d59ecb2SHans Petter Selasky break; 241*8d59ecb2SHans Petter Selasky for (head = NULL; need; need--) { 242*8d59ecb2SHans Petter Selasky iln = malloc(sizeof(*il), M_IDR, M_ZERO | gfp_mask); 243*8d59ecb2SHans Petter Selasky if (iln == NULL) 244*8d59ecb2SHans Petter Selasky break; 245*8d59ecb2SHans Petter Selasky bitmap_fill(&iln->bitmap, IDR_SIZE); 246*8d59ecb2SHans Petter Selasky if (head != NULL) { 247*8d59ecb2SHans Petter Selasky il->ary[0] = iln; 248*8d59ecb2SHans Petter Selasky il = iln; 249*8d59ecb2SHans Petter Selasky } else 250*8d59ecb2SHans Petter Selasky head = il = iln; 251*8d59ecb2SHans Petter Selasky } 252*8d59ecb2SHans Petter Selasky if (head == NULL) 253*8d59ecb2SHans Petter Selasky return (0); 254*8d59ecb2SHans Petter Selasky mtx_lock(&idr->lock); 255*8d59ecb2SHans Petter Selasky il->ary[0] = idr->free; 256*8d59ecb2SHans Petter Selasky idr->free = head; 257*8d59ecb2SHans Petter Selasky } 258*8d59ecb2SHans Petter Selasky return (1); 259*8d59ecb2SHans Petter Selasky } 260*8d59ecb2SHans Petter Selasky 261*8d59ecb2SHans Petter Selasky static inline struct idr_layer * 262*8d59ecb2SHans Petter Selasky idr_get(struct idr *idr) 263*8d59ecb2SHans Petter Selasky { 264*8d59ecb2SHans Petter Selasky struct idr_layer *il; 265*8d59ecb2SHans Petter Selasky 266*8d59ecb2SHans Petter Selasky il = idr->free; 267*8d59ecb2SHans Petter Selasky if (il) { 268*8d59ecb2SHans Petter Selasky idr->free = il->ary[0]; 269*8d59ecb2SHans Petter Selasky il->ary[0] = NULL; 270*8d59ecb2SHans Petter Selasky return (il); 271*8d59ecb2SHans Petter Selasky } 272*8d59ecb2SHans Petter Selasky il = malloc(sizeof(*il), M_IDR, M_ZERO | M_NOWAIT); 273*8d59ecb2SHans Petter Selasky bitmap_fill(&il->bitmap, IDR_SIZE); 274*8d59ecb2SHans Petter Selasky return (il); 275*8d59ecb2SHans Petter Selasky } 276*8d59ecb2SHans Petter Selasky 277*8d59ecb2SHans Petter Selasky /* 278*8d59ecb2SHans Petter Selasky * Could be implemented as get_new_above(idr, ptr, 0, idp) but written 279*8d59ecb2SHans Petter Selasky * first for simplicity sake. 280*8d59ecb2SHans Petter Selasky */ 281*8d59ecb2SHans Petter Selasky int 282*8d59ecb2SHans Petter Selasky idr_get_new(struct idr *idr, void *ptr, int *idp) 283*8d59ecb2SHans Petter Selasky { 284*8d59ecb2SHans Petter Selasky struct idr_layer *stack[MAX_LEVEL]; 285*8d59ecb2SHans Petter Selasky struct idr_layer *il; 286*8d59ecb2SHans Petter Selasky int error; 287*8d59ecb2SHans Petter Selasky int layer; 288*8d59ecb2SHans Petter Selasky int idx; 289*8d59ecb2SHans Petter Selasky int id; 290*8d59ecb2SHans Petter Selasky 291*8d59ecb2SHans Petter Selasky error = -EAGAIN; 292*8d59ecb2SHans Petter Selasky mtx_lock(&idr->lock); 293*8d59ecb2SHans Petter Selasky /* 294*8d59ecb2SHans Petter Selasky * Expand the tree until there is free space. 295*8d59ecb2SHans Petter Selasky */ 296*8d59ecb2SHans Petter Selasky if (idr->top == NULL || idr->top->bitmap == 0) { 297*8d59ecb2SHans Petter Selasky if (idr->layers == MAX_LEVEL + 1) { 298*8d59ecb2SHans Petter Selasky error = -ENOSPC; 299*8d59ecb2SHans Petter Selasky goto out; 300*8d59ecb2SHans Petter Selasky } 301*8d59ecb2SHans Petter Selasky il = idr_get(idr); 302*8d59ecb2SHans Petter Selasky if (il == NULL) 303*8d59ecb2SHans Petter Selasky goto out; 304*8d59ecb2SHans Petter Selasky il->ary[0] = idr->top; 305*8d59ecb2SHans Petter Selasky if (idr->top) 306*8d59ecb2SHans Petter Selasky il->bitmap &= ~1; 307*8d59ecb2SHans Petter Selasky idr->top = il; 308*8d59ecb2SHans Petter Selasky idr->layers++; 309*8d59ecb2SHans Petter Selasky } 310*8d59ecb2SHans Petter Selasky il = idr->top; 311*8d59ecb2SHans Petter Selasky id = 0; 312*8d59ecb2SHans Petter Selasky /* 313*8d59ecb2SHans Petter Selasky * Walk the tree following free bitmaps, record our path. 314*8d59ecb2SHans Petter Selasky */ 315*8d59ecb2SHans Petter Selasky for (layer = idr->layers - 1;; layer--) { 316*8d59ecb2SHans Petter Selasky stack[layer] = il; 317*8d59ecb2SHans Petter Selasky idx = ffsl(il->bitmap); 318*8d59ecb2SHans Petter Selasky if (idx == 0) 319*8d59ecb2SHans Petter Selasky panic("idr_get_new: Invalid leaf state (%p, %p)\n", 320*8d59ecb2SHans Petter Selasky idr, il); 321*8d59ecb2SHans Petter Selasky idx--; 322*8d59ecb2SHans Petter Selasky id |= idx << (layer * IDR_BITS); 323*8d59ecb2SHans Petter Selasky if (layer == 0) 324*8d59ecb2SHans Petter Selasky break; 325*8d59ecb2SHans Petter Selasky if (il->ary[idx] == NULL) { 326*8d59ecb2SHans Petter Selasky il->ary[idx] = idr_get(idr); 327*8d59ecb2SHans Petter Selasky if (il->ary[idx] == NULL) 328*8d59ecb2SHans Petter Selasky goto out; 329*8d59ecb2SHans Petter Selasky } 330*8d59ecb2SHans Petter Selasky il = il->ary[idx]; 331*8d59ecb2SHans Petter Selasky } 332*8d59ecb2SHans Petter Selasky /* 333*8d59ecb2SHans Petter Selasky * Allocate the leaf to the consumer. 334*8d59ecb2SHans Petter Selasky */ 335*8d59ecb2SHans Petter Selasky il->bitmap &= ~(1 << idx); 336*8d59ecb2SHans Petter Selasky il->ary[idx] = ptr; 337*8d59ecb2SHans Petter Selasky *idp = id; 338*8d59ecb2SHans Petter Selasky /* 339*8d59ecb2SHans Petter Selasky * Clear bitmaps potentially up to the root. 340*8d59ecb2SHans Petter Selasky */ 341*8d59ecb2SHans Petter Selasky while (il->bitmap == 0 && ++layer < idr->layers) { 342*8d59ecb2SHans Petter Selasky il = stack[layer]; 343*8d59ecb2SHans Petter Selasky il->bitmap &= ~(1 << idr_pos(id, layer)); 344*8d59ecb2SHans Petter Selasky } 345*8d59ecb2SHans Petter Selasky error = 0; 346*8d59ecb2SHans Petter Selasky out: 347*8d59ecb2SHans Petter Selasky #ifdef INVARIANTS 348*8d59ecb2SHans Petter Selasky if (error == 0 && idr_find_locked(idr, id) != ptr) { 349*8d59ecb2SHans Petter Selasky panic("idr_get_new: Failed for idr %p, id %d, ptr %p\n", 350*8d59ecb2SHans Petter Selasky idr, id, ptr); 351*8d59ecb2SHans Petter Selasky } 352*8d59ecb2SHans Petter Selasky #endif 353*8d59ecb2SHans Petter Selasky mtx_unlock(&idr->lock); 354*8d59ecb2SHans Petter Selasky return (error); 355*8d59ecb2SHans Petter Selasky } 356*8d59ecb2SHans Petter Selasky 357*8d59ecb2SHans Petter Selasky int 358*8d59ecb2SHans Petter Selasky idr_get_new_above(struct idr *idr, void *ptr, int starting_id, int *idp) 359*8d59ecb2SHans Petter Selasky { 360*8d59ecb2SHans Petter Selasky struct idr_layer *stack[MAX_LEVEL]; 361*8d59ecb2SHans Petter Selasky struct idr_layer *il; 362*8d59ecb2SHans Petter Selasky int error; 363*8d59ecb2SHans Petter Selasky int layer; 364*8d59ecb2SHans Petter Selasky int idx, sidx; 365*8d59ecb2SHans Petter Selasky int id; 366*8d59ecb2SHans Petter Selasky 367*8d59ecb2SHans Petter Selasky error = -EAGAIN; 368*8d59ecb2SHans Petter Selasky mtx_lock(&idr->lock); 369*8d59ecb2SHans Petter Selasky /* 370*8d59ecb2SHans Petter Selasky * Compute the layers required to support starting_id and the mask 371*8d59ecb2SHans Petter Selasky * at the top layer. 372*8d59ecb2SHans Petter Selasky */ 373*8d59ecb2SHans Petter Selasky restart: 374*8d59ecb2SHans Petter Selasky idx = starting_id; 375*8d59ecb2SHans Petter Selasky layer = 0; 376*8d59ecb2SHans Petter Selasky while (idx & ~IDR_MASK) { 377*8d59ecb2SHans Petter Selasky layer++; 378*8d59ecb2SHans Petter Selasky idx >>= IDR_BITS; 379*8d59ecb2SHans Petter Selasky } 380*8d59ecb2SHans Petter Selasky if (layer == MAX_LEVEL + 1) { 381*8d59ecb2SHans Petter Selasky error = -ENOSPC; 382*8d59ecb2SHans Petter Selasky goto out; 383*8d59ecb2SHans Petter Selasky } 384*8d59ecb2SHans Petter Selasky /* 385*8d59ecb2SHans Petter Selasky * Expand the tree until there is free space at or beyond starting_id. 386*8d59ecb2SHans Petter Selasky */ 387*8d59ecb2SHans Petter Selasky while (idr->layers <= layer || 388*8d59ecb2SHans Petter Selasky idr->top->bitmap < (1 << idr_pos(starting_id, idr->layers - 1))) { 389*8d59ecb2SHans Petter Selasky if (idr->layers == MAX_LEVEL + 1) { 390*8d59ecb2SHans Petter Selasky error = -ENOSPC; 391*8d59ecb2SHans Petter Selasky goto out; 392*8d59ecb2SHans Petter Selasky } 393*8d59ecb2SHans Petter Selasky il = idr_get(idr); 394*8d59ecb2SHans Petter Selasky if (il == NULL) 395*8d59ecb2SHans Petter Selasky goto out; 396*8d59ecb2SHans Petter Selasky il->ary[0] = idr->top; 397*8d59ecb2SHans Petter Selasky if (idr->top && idr->top->bitmap == 0) 398*8d59ecb2SHans Petter Selasky il->bitmap &= ~1; 399*8d59ecb2SHans Petter Selasky idr->top = il; 400*8d59ecb2SHans Petter Selasky idr->layers++; 401*8d59ecb2SHans Petter Selasky } 402*8d59ecb2SHans Petter Selasky il = idr->top; 403*8d59ecb2SHans Petter Selasky id = 0; 404*8d59ecb2SHans Petter Selasky /* 405*8d59ecb2SHans Petter Selasky * Walk the tree following free bitmaps, record our path. 406*8d59ecb2SHans Petter Selasky */ 407*8d59ecb2SHans Petter Selasky for (layer = idr->layers - 1;; layer--) { 408*8d59ecb2SHans Petter Selasky stack[layer] = il; 409*8d59ecb2SHans Petter Selasky sidx = idr_pos(starting_id, layer); 410*8d59ecb2SHans Petter Selasky /* Returns index numbered from 0 or size if none exists. */ 411*8d59ecb2SHans Petter Selasky idx = find_next_bit(&il->bitmap, IDR_SIZE, sidx); 412*8d59ecb2SHans Petter Selasky if (idx == IDR_SIZE && sidx == 0) 413*8d59ecb2SHans Petter Selasky panic("idr_get_new: Invalid leaf state (%p, %p)\n", 414*8d59ecb2SHans Petter Selasky idr, il); 415*8d59ecb2SHans Petter Selasky /* 416*8d59ecb2SHans Petter Selasky * We may have walked a path where there was a free bit but 417*8d59ecb2SHans Petter Selasky * it was lower than what we wanted. Restart the search with 418*8d59ecb2SHans Petter Selasky * a larger starting id. id contains the progress we made so 419*8d59ecb2SHans Petter Selasky * far. Search the leaf one above this level. This may 420*8d59ecb2SHans Petter Selasky * restart as many as MAX_LEVEL times but that is expected 421*8d59ecb2SHans Petter Selasky * to be rare. 422*8d59ecb2SHans Petter Selasky */ 423*8d59ecb2SHans Petter Selasky if (idx == IDR_SIZE) { 424*8d59ecb2SHans Petter Selasky starting_id = id + (1 << ((layer + 1) * IDR_BITS)); 425*8d59ecb2SHans Petter Selasky goto restart; 426*8d59ecb2SHans Petter Selasky } 427*8d59ecb2SHans Petter Selasky if (idx > sidx) 428*8d59ecb2SHans Petter Selasky starting_id = 0; /* Search the whole subtree. */ 429*8d59ecb2SHans Petter Selasky id |= idx << (layer * IDR_BITS); 430*8d59ecb2SHans Petter Selasky if (layer == 0) 431*8d59ecb2SHans Petter Selasky break; 432*8d59ecb2SHans Petter Selasky if (il->ary[idx] == NULL) { 433*8d59ecb2SHans Petter Selasky il->ary[idx] = idr_get(idr); 434*8d59ecb2SHans Petter Selasky if (il->ary[idx] == NULL) 435*8d59ecb2SHans Petter Selasky goto out; 436*8d59ecb2SHans Petter Selasky } 437*8d59ecb2SHans Petter Selasky il = il->ary[idx]; 438*8d59ecb2SHans Petter Selasky } 439*8d59ecb2SHans Petter Selasky /* 440*8d59ecb2SHans Petter Selasky * Allocate the leaf to the consumer. 441*8d59ecb2SHans Petter Selasky */ 442*8d59ecb2SHans Petter Selasky il->bitmap &= ~(1 << idx); 443*8d59ecb2SHans Petter Selasky il->ary[idx] = ptr; 444*8d59ecb2SHans Petter Selasky *idp = id; 445*8d59ecb2SHans Petter Selasky /* 446*8d59ecb2SHans Petter Selasky * Clear bitmaps potentially up to the root. 447*8d59ecb2SHans Petter Selasky */ 448*8d59ecb2SHans Petter Selasky while (il->bitmap == 0 && ++layer < idr->layers) { 449*8d59ecb2SHans Petter Selasky il = stack[layer]; 450*8d59ecb2SHans Petter Selasky il->bitmap &= ~(1 << idr_pos(id, layer)); 451*8d59ecb2SHans Petter Selasky } 452*8d59ecb2SHans Petter Selasky error = 0; 453*8d59ecb2SHans Petter Selasky out: 454*8d59ecb2SHans Petter Selasky #ifdef INVARIANTS 455*8d59ecb2SHans Petter Selasky if (error == 0 && idr_find_locked(idr, id) != ptr) { 456*8d59ecb2SHans Petter Selasky panic("idr_get_new_above: Failed for idr %p, id %d, ptr %p\n", 457*8d59ecb2SHans Petter Selasky idr, id, ptr); 458*8d59ecb2SHans Petter Selasky } 459*8d59ecb2SHans Petter Selasky #endif 460*8d59ecb2SHans Petter Selasky mtx_unlock(&idr->lock); 461*8d59ecb2SHans Petter Selasky return (error); 462*8d59ecb2SHans Petter Selasky } 463