📄 idr.c
字号:
n = idp->layers * IDR_BITS; p = idp->top; max = 1 << n; id = 0; while (id < max) { while (n > IDR_BITS && p) { n -= IDR_BITS; *paa++ = p; p = p->ary[(id >> n) & IDR_MASK]; } id += 1 << n; while (n < fls(id)) { if (p) free_layer(p); n += IDR_BITS; p = *--paa; } } rcu_assign_pointer(idp->top, NULL); idp->layers = 0;}EXPORT_SYMBOL(idr_remove_all);/** * idr_destroy - release all cached layers within an idr tree * idp: idr handle */void idr_destroy(struct idr *idp){ while (idp->id_free_cnt) { struct idr_layer *p = get_from_free_list(idp); kmem_cache_free(idr_layer_cache, p); }}EXPORT_SYMBOL(idr_destroy);/** * idr_find - return pointer for given id * @idp: idr handle * @id: lookup key * * Return the pointer given the id it has been registered with. A %NULL * return indicates that @id is not valid or you passed %NULL in * idr_get_new(). * * This function can be called under rcu_read_lock(), given that the leaf * pointers lifetimes are correctly managed. */void *idr_find(struct idr *idp, int id){ int n; struct idr_layer *p; n = idp->layers * IDR_BITS; p = rcu_dereference(idp->top); /* Mask off upper bits we don't use for the search. */ id &= MAX_ID_MASK; if (id >= (1 << n)) return NULL; while (n > 0 && p) { n -= IDR_BITS; p = rcu_dereference(p->ary[(id >> n) & IDR_MASK]); } return((void *)p);}EXPORT_SYMBOL(idr_find);/** * idr_for_each - iterate through all stored pointers * @idp: idr handle * @fn: function to be called for each pointer * @data: data passed back to callback function * * Iterate over the pointers registered with the given idr. The * callback function will be called for each pointer currently * registered, passing the id, the pointer and the data pointer passed * to this function. It is not safe to modify the idr tree while in * the callback, so functions such as idr_get_new and idr_remove are * not allowed. * * We check the return of @fn each time. If it returns anything other * than 0, we break out and return that value. * * The caller must serialize idr_for_each() vs idr_get_new() and idr_remove(). */int idr_for_each(struct idr *idp, int (*fn)(int id, void *p, void *data), void *data){ int n, id, max, error = 0; struct idr_layer *p; struct idr_layer *pa[MAX_LEVEL]; struct idr_layer **paa = &pa[0]; n = idp->layers * IDR_BITS; p = rcu_dereference(idp->top); max = 1 << n; id = 0; while (id < max) { while (n > 0 && p) { n -= IDR_BITS; *paa++ = p; p = rcu_dereference(p->ary[(id >> n) & IDR_MASK]); } if (p) { error = fn(id, (void *)p, data); if (error) break; } id += 1 << n; while (n < fls(id)) { n += IDR_BITS; p = *--paa; } } return error;}EXPORT_SYMBOL(idr_for_each);/** * idr_replace - replace pointer for given id * @idp: idr handle * @ptr: pointer you want associated with the id * @id: lookup key * * Replace the pointer registered with an id and return the old value. * A -ENOENT return indicates that @id was not found. * A -EINVAL return indicates that @id was not within valid constraints. * * The caller must serialize with writers. */void *idr_replace(struct idr *idp, void *ptr, int id){ int n; struct idr_layer *p, *old_p; n = idp->layers * IDR_BITS; p = idp->top; id &= MAX_ID_MASK; if (id >= (1 << n)) return ERR_PTR(-EINVAL); n -= IDR_BITS; while ((n > 0) && p) { p = p->ary[(id >> n) & IDR_MASK]; n -= IDR_BITS; } n = id & IDR_MASK; if (unlikely(p == NULL || !test_bit(n, &p->bitmap))) return ERR_PTR(-ENOENT); old_p = p->ary[n]; rcu_assign_pointer(p->ary[n], ptr); return old_p;}EXPORT_SYMBOL(idr_replace);static void idr_cache_ctor(void *idr_layer){ memset(idr_layer, 0, sizeof(struct idr_layer));}void __init idr_init_cache(void){ idr_layer_cache = kmem_cache_create("idr_layer_cache", sizeof(struct idr_layer), 0, SLAB_PANIC, idr_cache_ctor);}/** * idr_init - initialize idr handle * @idp: idr handle * * This function is use to set up the handle (@idp) that you will pass * to the rest of the functions. */void idr_init(struct idr *idp){ memset(idp, 0, sizeof(struct idr)); spin_lock_init(&idp->lock);}EXPORT_SYMBOL(idr_init);/* * IDA - IDR based ID allocator * * this is id allocator without id -> pointer translation. Memory * usage is much lower than full blown idr because each id only * occupies a bit. ida uses a custom leaf node which contains * IDA_BITMAP_BITS slots. * * 2007-04-25 written by Tejun Heo <htejun@gmail.com> */static void free_bitmap(struct ida *ida, struct ida_bitmap *bitmap){ unsigned long flags; if (!ida->free_bitmap) { spin_lock_irqsave(&ida->idr.lock, flags); if (!ida->free_bitmap) { ida->free_bitmap = bitmap; bitmap = NULL; } spin_unlock_irqrestore(&ida->idr.lock, flags); } kfree(bitmap);}/** * ida_pre_get - reserve resources for ida allocation * @ida: ida handle * @gfp_mask: memory allocation flag * * This function should be called prior to locking and calling the * following function. It preallocates enough memory to satisfy the * worst possible allocation. * * If the system is REALLY out of memory this function returns 0, * otherwise 1. */int ida_pre_get(struct ida *ida, gfp_t gfp_mask){ /* allocate idr_layers */ if (!idr_pre_get(&ida->idr, gfp_mask)) return 0; /* allocate free_bitmap */ if (!ida->free_bitmap) { struct ida_bitmap *bitmap; bitmap = kmalloc(sizeof(struct ida_bitmap), gfp_mask); if (!bitmap) return 0; free_bitmap(ida, bitmap); } return 1;}EXPORT_SYMBOL(ida_pre_get);/** * ida_get_new_above - allocate new ID above or equal to a start id * @ida: ida handle * @staring_id: id to start search at * @p_id: pointer to the allocated handle * * Allocate new ID above or equal to @ida. It should be called with * any required locks. * * If memory is required, it will return -EAGAIN, you should unlock * and go back to the ida_pre_get() call. If the ida is full, it will * return -ENOSPC. * * @p_id returns a value in the range 0 ... 0x7fffffff. */int ida_get_new_above(struct ida *ida, int starting_id, int *p_id){ struct idr_layer *pa[MAX_LEVEL]; struct ida_bitmap *bitmap; unsigned long flags; int idr_id = starting_id / IDA_BITMAP_BITS; int offset = starting_id % IDA_BITMAP_BITS; int t, id; restart: /* get vacant slot */ t = idr_get_empty_slot(&ida->idr, idr_id, pa); if (t < 0) return _idr_rc_to_errno(t); if (t * IDA_BITMAP_BITS >= MAX_ID_BIT) return -ENOSPC; if (t != idr_id) offset = 0; idr_id = t; /* if bitmap isn't there, create a new one */ bitmap = (void *)pa[0]->ary[idr_id & IDR_MASK]; if (!bitmap) { spin_lock_irqsave(&ida->idr.lock, flags); bitmap = ida->free_bitmap; ida->free_bitmap = NULL; spin_unlock_irqrestore(&ida->idr.lock, flags); if (!bitmap) return -EAGAIN; memset(bitmap, 0, sizeof(struct ida_bitmap)); rcu_assign_pointer(pa[0]->ary[idr_id & IDR_MASK], (void *)bitmap); pa[0]->count++; } /* lookup for empty slot */ t = find_next_zero_bit(bitmap->bitmap, IDA_BITMAP_BITS, offset); if (t == IDA_BITMAP_BITS) { /* no empty slot after offset, continue to the next chunk */ idr_id++; offset = 0; goto restart; } id = idr_id * IDA_BITMAP_BITS + t; if (id >= MAX_ID_BIT) return -ENOSPC; __set_bit(t, bitmap->bitmap); if (++bitmap->nr_busy == IDA_BITMAP_BITS) idr_mark_full(pa, idr_id); *p_id = id; /* Each leaf node can handle nearly a thousand slots and the * whole idea of ida is to have small memory foot print. * Throw away extra resources one by one after each successful * allocation. */ if (ida->idr.id_free_cnt || ida->free_bitmap) { struct idr_layer *p = get_from_free_list(&ida->idr); if (p) kmem_cache_free(idr_layer_cache, p); } return 0;}EXPORT_SYMBOL(ida_get_new_above);/** * ida_get_new - allocate new ID * @ida: idr handle * @p_id: pointer to the allocated handle * * Allocate new ID. It should be called with any required locks. * * If memory is required, it will return -EAGAIN, you should unlock * and go back to the idr_pre_get() call. If the idr is full, it will * return -ENOSPC. * * @id returns a value in the range 0 ... 0x7fffffff. */int ida_get_new(struct ida *ida, int *p_id){ return ida_get_new_above(ida, 0, p_id);}EXPORT_SYMBOL(ida_get_new);/** * ida_remove - remove the given ID * @ida: ida handle * @id: ID to free */void ida_remove(struct ida *ida, int id){ struct idr_layer *p = ida->idr.top; int shift = (ida->idr.layers - 1) * IDR_BITS; int idr_id = id / IDA_BITMAP_BITS; int offset = id % IDA_BITMAP_BITS; int n; struct ida_bitmap *bitmap; /* clear full bits while looking up the leaf idr_layer */ while ((shift > 0) && p) { n = (idr_id >> shift) & IDR_MASK; __clear_bit(n, &p->bitmap); p = p->ary[n]; shift -= IDR_BITS; } if (p == NULL) goto err; n = idr_id & IDR_MASK; __clear_bit(n, &p->bitmap); bitmap = (void *)p->ary[n]; if (!test_bit(offset, bitmap->bitmap)) goto err; /* update bitmap and remove it if empty */ __clear_bit(offset, bitmap->bitmap); if (--bitmap->nr_busy == 0) { __set_bit(n, &p->bitmap); /* to please idr_remove() */ idr_remove(&ida->idr, idr_id); free_bitmap(ida, bitmap); } return; err: printk(KERN_WARNING "ida_remove called for id=%d which is not allocated.\n", id);}EXPORT_SYMBOL(ida_remove);/** * ida_destroy - release all cached layers within an ida tree * ida: ida handle */void ida_destroy(struct ida *ida){ idr_destroy(&ida->idr); kfree(ida->free_bitmap);}EXPORT_SYMBOL(ida_destroy);/** * ida_init - initialize ida handle * @ida: ida handle * * This function is use to set up the handle (@ida) that you will pass * to the rest of the functions. */void ida_init(struct ida *ida){ memset(ida, 0, sizeof(struct ida)); idr_init(&ida->idr);}EXPORT_SYMBOL(ida_init);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -