⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 idr.c

📁 Lib files of linux kernel
💻 C
📖 第 1 页 / 共 2 页
字号:
	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 + -