IDR分配一个整数,并关联到一个指针。内核很多地方有这个应用场景,如device names,POSIX timers等。
IDR底层通过radix tree实现。相关文件:
lib/radix-tree.c
lib/idr.c
include/idr.h
有3种方式定义并初始化一个idr变量:
1 静态分配,然后初始化
1 2  | static struct idr dca_idr;idr_init(&dca_idr); | 
2 静态分配同时初始化,不再需要使用idr_init()初始化
1  | static DEFINE_IDR(dca_idr); | 
3 动态分配,然后初始化
1 2  | struct idr *dca_idr = kmalloc(xxx);idr_init(&dca_idr); | 
分配ID的旧接口如下:
1 2  | int idr_pre_get(struct idr *idp, gfp_t gfp_mask);int idr_get_new(struct idr *idp, void *ptr, int *id); | 
idr_pre_get用在原子上下文之外,用于预分配内存,不需要锁。而idr_get_new需要锁保护(radix tree操作需要锁保护),因此分成了两个接口。
Tejun指出了之前接口的缺陷,并提交了Patch,新的接口如下:
1 2 3  | void idr_preload(gfp_t gfp_mask);int idr_alloc(struct idr *idp, void *ptr, int start, int end, gfp_t gfp_mask);void idr_preload_end(void); | 
idr_perload不需要idr指针,它使用percpu buffer,如果分配成功返回非0,并且禁止抢占。
并发修改idr是不允许的,因此idr_alloc需要加锁。idr_alloc()分配[start, end)范围内未用的ID,如果end小于等于0,则等价于最大值。如果没有可用ID,则返回-ENOSPC,返回值大于等于0,则是成功分配的ID。
idr_preload_end,开启抢占。
分配ID典型的用法如下:
1 2 3 4 5 6 7 8 9 10 11  | idr_preload(GFP_KERNEL);spin_lock(&dca_idr_lock);ret = idr_alloc(&dca_idr, dca, 0, 0, GFP_NOWAIT);if (ret >= 0)    dca->id = ret;spin_unlock(&dca_idr_lock);idr_preload_end();if (ret < 0)    return ret; | 
删除分配的ID:
1  | void *idr_remove(struct idr *idr, unsigned long id) | 
由于删除修改了IDR,因此需要上锁。如果id之前不在IDR中,返回NULL,否则返回关联的指针。
销毁IDR
1  | void idr_destroy(struct idr *idr) | 
销毁所有IDR的内部内存。IDR变成空,可以释放IDR,或者重新使用。
参考:
https://lwn.net/Articles/536293/
idr: implement idr_alloc() and convert existing users. https://lwn.net/Articles/536019/
Re: [PATCHSET] idr: implement idr_alloc() and convert existing users. https://lwn.net/Articles/536352/
Re: [PATCHSET] idr: implement idr_alloc() and convert existing users. https://lwn.net/Articles/536353/