ILD

内核数据结构之:idr
作者:YUAN JIANPENG 邮箱:yuanjp@hust.edu.cn
发布时间:2018-7-8 站点:Inside Linux Development

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/




Copyright © linuxdev.cc 2017-2024. Some Rights Reserved.