Github: idr_alloc_cyclic
Email: BuddyZhang1 buddy.zhang@aliyun.com
目录
源码分析
int idr_alloc_cyclic( struct idr * idr, void * ptr, int start, int end, gfp_t gfp)
{
u32 id = idr->idr_next;
int err, max = end > 0 ? end - 1 : INT_MAX;
if (( int) id < start)
id = start;
err = idr_alloc_u32( idr, ptr, &id, max, gfp) ;
if (( err == -ENOSPC ) && ( id > start)) {
id = start;
err = idr_alloc_u32( idr, ptr, &id, max, gfp) ;
}
if ( err)
return err;
idr->idr_next = id + 1;
return id ;
}
EXPORT_SYMBOL( idr_alloc_cyclic) ;
idr_alloc_cyclic() 函数用于周期性的分配 ID,并将 ID 与 指针进行绑定。参数 idr
指向 idr 的根节点;参数 ptr 指向与 ID 进行绑定的指针;start 参数限定了 ID 的起始
值;参数 end 限定了 ID 的终止值;参数 gfp 指向了分配时需要的标识。函数从
idr->idr_next 成员中获得 id 值,然后判断 id 是否比 start 小,如果小则将 id
设置为 start。接着调用 idr_alloc_u32() 函数从 IDR 总分配一个 ID,并将 ptr
与 ID 进行绑定。如果 ID 分配失败,那么将 id 设置为 start 从新分配 ID;如果成功
分配,则将 idr->idr_next 指向 id+1.
实践
驱动源码
/*
* IDR.
*
* (C) 2019.06.04 <buddy.zhang@aliyun.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/mm.h>
/* header of radix-tree */
#include <linux/idr.h>
/* private node */
struct node {
const char * name ;
};
/* Root of IDR */
static DEFINE_IDR ( BiscuitOS_idr );
/* node set */
static struct node node0 = { . name = "IDA" };
static struct node node1 = { . name = "IDB" };
static struct node node2 = { . name = "IDC" };
static struct node node3 = { . name = "IDD" };
static struct node node4 = { . name = "IDE" };
/* ID array */
#define IDR_ARRAY_SIZE 5
static int idr_array [ IDR_ARRAY_SIZE ];
static __init int idr_demo_init ( void )
{
struct node * np ;
int id ;
/* proload for idr_alloc */
idr_preload ( GFP_KERNEL );
/* Allocate a id from IDR */
idr_array [ 0 ] = idr_alloc_cyclic ( & BiscuitOS_idr , & node0 , 1 ,
INT_MAX , GFP_ATOMIC );
idr_array [ 1 ] = idr_alloc_cyclic ( & BiscuitOS_idr , & node1 , 1 ,
INT_MAX , GFP_ATOMIC );
idr_array [ 2 ] = idr_alloc_cyclic ( & BiscuitOS_idr , & node2 , 1 ,
INT_MAX , GFP_ATOMIC );
idr_array [ 3 ] = idr_alloc_cyclic ( & BiscuitOS_idr , & node3 , 1 ,
INT_MAX , GFP_ATOMIC );
idr_array [ 4 ] = idr_alloc_cyclic ( & BiscuitOS_idr , & node4 , 1 ,
INT_MAX , GFP_ATOMIC );
/* Interate over all slots */
idr_for_each_entry ( & BiscuitOS_idr , np , id )
printk ( "%s's ID %d \n " , np -> name , id );
/* end preload section started with idr_preload() */
idr_preload_end ();
return 0 ;
}
device_initcall ( idr_demo_init );
驱动安装
驱动的安装很简单,首先将驱动放到 drivers/BiscuitOS/ 目录下,命名为 atomic.c,
然后修改 Kconfig 文件,添加内容参考如下:
diff --git a/drivers/BiscuitOS/Kconfig b/drivers/BiscuitOS/Kconfig
index 4edc5a5..1a9abee 100644
--- a/drivers/BiscuitOS/Kconfig
+++ b/drivers/BiscuitOS/Kconfig
@@ -6 ,4 +6,14 @@ if BISCUITOS_DRV
config BISCUITOS_MISC
bool "BiscuitOS misc driver"
+config BISCUITOS_IDR
+ bool "IDR"
+
+if BISCUITOS_IDR
+
+config DEBUG_BISCUITOS_IDR
+ bool "idr_alloc_cyclic"
+
+endif # BISCUITOS_IDR
+
endif # BISCUITOS_DRV
接着修改 Makefile,请参考如下修改:
diff --git a/drivers/BiscuitOS/Makefile b/drivers/BiscuitOS/Makefile
index 82004c9..9909149 100644
--- a/drivers/BiscuitOS/Makefile
+++ b/drivers/BiscuitOS/Makefile
@@ -1 +1,2 @@
obj-$( CONFIG_BISCUITOS_MISC) += BiscuitOS_drv.o
+obj-$( CONFIG_BISCUITOS_IDR) += idr.o
--
驱动配置
驱动配置请参考下面文章中关于驱动配置一节。在配置中,勾选如下选项,如下:
Device Driver--->
[ * ] BiscuitOS Driver--->
[ * ] IDR
[ * ] idr_alloc_cyclic()
具体过程请参考:
Linux 5.0 开发环境搭建 – 驱动配置
驱动编译
驱动编译也请参考下面文章关于驱动编译一节:
Linux 5.0 开发环境搭建 – 驱动编译
驱动运行
驱动的运行,请参考下面文章中关于驱动运行一节:
Linux 5.0 开发环境搭建 – 驱动运行
启动内核,并打印如下信息:
usbcore: registered new interface driver usbhid
usbhid: USB HID core driver
IDA's ID 0
IDB' s ID 1
IDC's ID 2
IDD' s ID 3
IDE's ID 4
aaci-pl041 10004000.aaci: ARM AC' 97 Interface PL041 rev0 at 0x10004000, irq 24
aaci-pl041 10004000.aaci: FIFO 512 entries
oprofile: using arm/armv7-ca9
驱动分析
分配一个 ID,并将 ID 与一个指针相互绑定。
附录
BiscuitOS Home
BiscuitOS Driver
BiscuitOS Kernel Build
Linux Kernel
Bootlin: Elixir Cross Referencer
搭建高效的 Linux 开发环境
赞赏一下吧 🙂