当前位置: 首页 > news >正文

Linux中inode节点号的获取相关函数的实现

获取inode编号系统架构总览

核心函数关系

get_inode_number() ← 用户接口↓
idr_get_new() ← 标准接口封装  ↓
idr_get_new_above_int() ← 树结构管理↓  
sub_alloc() ← 实际分配算法↓
alloc_layer()/free_layer() ← 内存管理↓
idr_pre_get() ← 预分配优化

设计哲学与核心思想

分层抽象设计

  • 用户层: get_inode_number 提供简单接口
  • 适配层: idr_get_new 处理错误码标准化
  • 控制层: idr_get_new_above_int 管理树结构扩展
  • 算法层: sub_alloc 实现核心分配逻辑
  • 资源层: alloc_layer/free_layer 管理内存资源

性能优化策略

预分配机制

idr_pre_get() // 批量预分配IDR层
  • 减少系统调用: 避免每次分配都进行内存分配
  • 缓存友好: 重用最近释放的内存层
  • 锁优化: 预分配阶段无锁,分配阶段短临界区

惰性树构建

if (!p->ary[m]) {new = alloc_layer(idp); // 按需创建中间层
}
  • 稀疏优化: 只为实际使用的路径分配内存
  • 内存效率: 避免预分配整个树结构
  • 动态扩展: 自动适应ID分布模式

关键技术实现

IDR树结构设计

多层radix树

层2 (顶层) → 层1 → 层0 (叶子层)每层32槽位 (IDR_BITS=5)容量: 32^3 = 32,768个ID
  • ID号被拆分成多个位段,每个位段从高到底分别处于对应的层的槽中,槽的索引就是该位段的数值
  • 和基数树类似的一个数据结构,基数树节点的槽索引也是当前位段的值
  • 不过基数树没有位图保存槽的使用状态,只保存了当前槽分配的个数,用来判断当前节点是否可释放

智能ID分配算法

// 从起始ID开始深度优先搜索
while (1) {n = (id >> (IDR_BITS*l)) & IDR_MASK;  // 计算层索引m = find_next_bit(&bm, IDR_SIZE, n);  // 查找空闲槽位// 调整ID匹配找到的槽位
}

回溯机制

当当前分支无空间时,智能回退到父层:

l++;  // 回退到上层
id = (id | ((1 << (IDR_BITS*l))-1)) + 1;  // 调整到下一块起始

设计优势总结

可扩展性

  • 支持从几个到数百万个ID的分配
  • 动态树结构自动适应不同规模的ID需求
  • 内存使用与实际需求成比例

高性能

  • 位操作实现高效槽位查找
  • 预分配机制减少系统调用开销
  • 缓存友好的内存访问模式

灵活性

  • 支持稀疏ID分布
  • 动态树结构调整
  • 可配置的层数和槽位数

为 proc 文件系统分配唯一的 inodeget_inode_number

/** Return an inode number between PROC_DYNAMIC_FIRST and* 0xffffffff, or zero on failure.*/
static unsigned int get_inode_number(void)
{int i, inum = 0;int error;retry:if (idr_pre_get(&proc_inum_idr, GFP_KERNEL) == 0)return 0;spin_lock(&proc_inum_lock);error = idr_get_new(&proc_inum_idr, NULL, &i);spin_unlock(&proc_inum_lock);if (error == -EAGAIN)goto retry;else if (error)return 0;inum = (i & MAX_ID_MASK) + PROC_DYNAMIC_FIRST;/* inum will never be more than 0xf0ffffff, so no check* for overflow.*/return inum;
}

函数签名和注释

/** Return an inode number between PROC_DYNAMIC_FIRST and* 0xffffffff, or zero on failure.*/
static unsigned int get_inode_number(void)
{
  • 功能: 分配一个唯一的 inode 号,用于 proc 文件系统
  • 范围: 从 PROC_DYNAMIC_FIRST0xffffffff
  • 返回值: 成功返回 inode 号,失败返回 0
  • static: 只在当前文件中可见

第一段:变量声明

        int i, inum = 0;int error;
  • i: 用于存储 IDR 分配的内部 ID
  • inum: 最终返回的 inode 号,初始化为 0(错误值)
  • error: 错误码

第二段:IDR 预分配准备

retry:if (idr_pre_get(&proc_inum_idr, GFP_KERNEL) == 0)return 0;
  • 标签: retry: - 重试跳转标签
  • 预分配检查: idr_pre_get(&proc_inum_idr, GFP_KERNEL)
    • proc_inum_idr: 全局的 IDR(ID分配器)对象
    • GFP_KERNEL: 内存分配标志(可能睡眠)
  • 失败返回: 如果预分配失败(返回 0),直接返回 0

IDR 机制:Linux 内核的整数ID分配器,用于高效分配和管理唯一ID

第三段:获取自旋锁并分配ID

        spin_lock(&proc_inum_lock);error = idr_get_new(&proc_inum_idr, NULL, &i);spin_unlock(&proc_inum_lock);
  • 加锁: spin_lock(&proc_inum_lock) - 获取保护IDR的自旋锁
  • 分配ID: idr_get_new(&proc_inum_idr, NULL, &i)
    • 从IDR分配一个新的ID
    • NULL: 不关联任何数据指针
    • &i: 输出参数,存储分配的ID
  • 解锁: spin_unlock(&proc_inum_lock) - 释放自旋锁

第四段:错误处理和重试

        if (error == -EAGAIN)goto retry;else if (error)return 0;
  • 重试条件: error == -EAGAIN - 如果错误码表示需要重试
  • 跳转重试: goto retry - 回到预分配步骤重新尝试
  • 其他错误: 如果是其他错误,返回 0 表示失败

-EAGAIN 场景:IDR 需要扩展但预分配时没有准备足够内存,需要重新预分配

第五段:计算最终 inode

        inum = (i & MAX_ID_MASK) + PROC_DYNAMIC_FIRST;
  • 掩码处理: i & MAX_ID_MASK - 确保ID在有效范围内
  • 偏移调整: + PROC_DYNAMIC_FIRST - 加上动态inode号的起始偏移
  • 结果: 得到最终的 proc inode

第六段:注释和返回

        /* inum will never be more than 0xf0ffffff, so no check* for overflow.*/return inum;
}
  • 返回结果: 返回计算得到的 inode

为IDR分配器预分配足够的内存层idr_pre_get

int idr_pre_get(struct idr *idp, unsigned gfp_mask)
{while (idp->id_free_cnt < IDR_FREE_MAX) {struct idr_layer *new;new = kmem_cache_alloc(idr_layer_cache, gfp_mask);if(new == NULL)return (0);free_layer(idp, new);}return 1;
}

函数签名

int idr_pre_get(struct idr *idp, unsigned gfp_mask)
{
  • 返回值: int - 成功返回1,失败返回0
  • 参数:
    • struct idr *idp: 指向IDR结构的指针
    • unsigned gfp_mask: 内存分配标志

第一段:循环条件

        while (idp->id_free_cnt < IDR_FREE_MAX) {
  • 循环条件: idp->id_free_cnt < IDR_FREE_MAX
  • idp->id_free_cnt: IDR结构中空闲层数量的计数器
  • IDR_FREE_MAX: 预定义的最大空闲层数量常量
  • 目的: 当空闲层数量不足时,持续分配直到达到最大值

第二段:内存分配

                struct idr_layer *new;new = kmem_cache_alloc(idr_layer_cache, gfp_mask);
  • 变量声明: new - 新分配的IDR层指针
  • 内存分配: kmem_cache_alloc(idr_layer_cache, gfp_mask)
    • idr_layer_cache: 预先创建的IDR层slab缓存
    • gfp_mask: 内存分配标志(如 GFP_KERNEL
  • 目的: 从slab缓存中分配一个IDR层结构体

第三段:分配失败检查

                if(new == NULL)return (0);
  • 空指针检查: if(new == NULL) - 检查内存分配是否成功
  • 失败返回: return (0) - 如果分配失败,立即返回0表示失败
  • 资源不足: 通常是因为系统内存不足

第四段:添加到空闲链表

                free_layer(idp, new);}
  • 释放层: free_layer(idp, new) - 将新分配的层添加到IDR的空闲链表中
  • 函数作用: 增加 idp->id_free_cnt 计数器,将层放入空闲链表
  • 循环继续: 回到while条件检查,直到空闲层数量足够

第五段:成功返回

        return 1;
}
  • 成功返回: return 1 - 表示预分配成功完成
  • 条件满足: 现在IDR有足够的空闲层来处理后续的ID分配

函数功能总结

主要功能: 为IDR分配器预分配足够的内存层,确保后续的ID分配操作能够成功执行

IDR 层结构分析

IDR 层级结构
IDR 根 (idr)|v
层0 (idr_layer) → 层1 (idr_layer) → ... → 层N (idr_layer)|                 |v                 v
位图数组          位图数组

每个 idr_layer 包含:

  • 指向子层的指针数组
  • 位图信息
  • 层数信息
空闲链表管理
idr → id_free: [层A] → [层B] → [层C] → NULL↑         ↑         ↑空闲链表头  预分配的  预分配的空闲层    空闲层

分配和释放IDR层alloc_layerfree_layer

static struct idr_layer *alloc_layer(struct idr *idp)
{struct idr_layer *p;spin_lock(&idp->lock);if ((p = idp->id_free)) {idp->id_free = p->ary[0];idp->id_free_cnt--;p->ary[0] = NULL;}spin_unlock(&idp->lock);return(p);
}
static void free_layer(struct idr *idp, struct idr_layer *p)
{/** Depends on the return element being zeroed.*/spin_lock(&idp->lock);p->ary[0] = idp->id_free;idp->id_free = p;idp->id_free_cnt++;spin_unlock(&idp->lock);
}

函数1:alloc_layer - 分配IDR层

函数签名

static struct idr_layer *alloc_layer(struct idr *idp)
{
  • 返回值: struct idr_layer * - 成功返回分配的层指针,失败返回NULL
  • 参数: struct idr *idp - 指向IDR结构的指针
  • static: 只在当前文件中可见

第一段:变量声明和加锁

        struct idr_layer *p;spin_lock(&idp->lock);
  • 变量声明: p - 用于存储分配的IDR层指针
  • 获取锁: spin_lock(&idp->lock) - 获取IDR结构的自旋锁
  • 目的: 保护对IDR空闲链表的并发访问

第二段:从空闲链表获取层

        if ((p = idp->id_free)) {
  • 条件赋值: (p = idp->id_free) - 将空闲链表头赋值给p,并检查是否为NULL
  • 链表检查: 如果空闲链表不为空,进入if块
  • idp->id_free: 指向空闲链表第一个IDR层的指针

第三段:更新空闲链表

                idp->id_free = p->ary[0];idp->id_free_cnt--;
  • 移动链表头: idp->id_free = p->ary[0] - 将链表头指向下一个空闲层
  • 减少计数器: idp->id_free_cnt-- - 空闲层数量减1
  • 链表操作: 相当于从链表头部移除一个节点

第四段:初始化分配的层

                p->ary[0] = NULL;}
  • 清空指针: p->ary[0] = NULL - 清空分配层的第一个指针槽
  • 准备使用: 确保层处于干净状态,可供后续使用

第五段:释放锁并返回

        spin_unlock(&idp->lock);return(p);
}
  • 释放锁: spin_unlock(&idp->lock) - 释放IDR自旋锁
  • 返回结果: return(p) - 返回分配的层指针(如果链表为空则返回NULL)

函数2:free_layer - 释放IDR层

函数签名

static void free_layer(struct idr *idp, struct idr_layer *p)
{
  • 返回值: void - 没有返回值
  • 参数:
    • struct idr *idp: 指向IDR结构的指针
    • struct idr_layer *p: 要释放的IDR层指针

第一段:注释说明

        /** Depends on the return element being zeroed.*/
  • 重要注释: 说明这个函数依赖于返回的元素被清零
  • 隐含要求: 调用者应该确保 p->ary[0] 已经被清空

第二段:加锁操作

        spin_lock(&idp->lock);
  • 获取锁: spin_lock(&idp->lock) - 获取IDR结构的自旋锁
  • 目的: 保护对IDR空闲链表的并发访问

第三段:添加到空闲链表头部

        p->ary[0] = idp->id_free;idp->id_free = p;
  • 设置next指针: p->ary[0] = idp->id_free - 将当前层指向原链表头
  • 更新链表头: idp->id_free = p - 将链表头指向新释放的层
  • 链表操作: 相当于在链表头部插入一个新节点

第四段:更新计数器并释放锁

        idp->id_free_cnt++;spin_unlock(&idp->lock);
}
  • 增加计数器: idp->id_free_cnt++ - 空闲层数量加1
  • 释放锁: spin_unlock(&idp->lock) - 释放IDR自旋锁

函数功能总结

数据结构分析

IDR 空闲链表结构
idp (IDR结构)↓
id_free → [层A] → [层B] → [层C] → NULL↓        ↓        ↓ary[0]   ary[0]   ary[0]=层B     =层C     =NULL
链表操作原理

alloc_layer(分配):

分配前: id_free → [A] → [B] → [C] → NULL
分配后: id_free → [B] → [C] → NULL
返回: [A] (且 A->ary[0] = NULL)

free_layer(释放):

释放前: id_free → [B] → [C] → NULL
释放 [A]: A->ary[0] = B (原链表头)
更新: id_free → [A] → [B] → [C] → NULL

调用ID分配函数idr_get_new

int idr_get_new(struct idr *idp, void *ptr, int *id)
{int rv;rv = idr_get_new_above_int(idp, ptr, 0);/** This is a cheap hack until the IDR code can be fixed to* return proper error values.*/if (rv < 0) {if (rv == -1)return -EAGAIN;else /* Will be -3 */return -ENOSPC;}*id = rv;return 0;
}

函数签名

int idr_get_new(struct idr *idp, void *ptr, int *id)
{
  • 返回值: int - 成功返回0,失败返回错误码
  • 参数:
    • struct idr *idp: 指向IDR结构的指针
    • void *ptr: 要与ID关联的数据指针
    • int *id: 输出参数,存储分配到的ID

第一段:变量声明和核心调用

        int rv;rv = idr_get_new_above_int(idp, ptr, 0);
  • 变量声明: rv - 存储底层函数的返回值
  • 调用核心函数: idr_get_new_above_int(idp, ptr, 0)
    • idp: 传递的IDR结构指针
    • ptr: 要关联的数据指针
    • 0: 起始ID号,表示从最小的可用ID开始分配
  • 功能: 实际执行ID分配的核心函数

第二段:错误处理 - EAGAIN

        if (rv < 0) {if (rv == -1)return -EAGAIN;
  • 错误检查: if (rv < 0) - 检查返回值是否为错误
  • 特定错误: if (rv == -1) - 检查是否为-1错误
  • 返回标准错误: return -EAGAIN - 转换为"再试一次"错误码

-EAGAIN 含义: 临时性失败,建议调用者重试操作

第三段:错误处理 - ENOSPC

                else /* Will be -3 */return -ENOSPC;
  • 其他错误: else - 处理所有其他负值错误
  • 返回标准错误: return -ENOSPC - 转换为"没有空间"错误码

-ENOSPC 含义: 没有可用的ID空间,永久性失败

第五段:成功处理

        }*id = rv;return 0;
}
  • 成功路径: 如果 rv >= 0,表示分配成功
  • 设置输出ID: *id = rv - 将分配到的ID写入输出参数
  • 返回成功: return 0 - 返回0表示操作成功

实际执行ID分配函数idr_get_new_above_int

static int idr_get_new_above_int(struct idr *idp, void *ptr, int starting_id)
{struct idr_layer *p, *new;int layers, v, id;id = starting_id;
build_up:p = idp->top;layers = idp->layers;if (unlikely(!p)) {if (!(p = alloc_layer(idp)))return -1;layers = 1;}/** Add a new layer to the top of the tree if the requested* id is larger than the currently allocated space.*/while ((layers < MAX_LEVEL) && (id >= (1 << (layers*IDR_BITS)))) {layers++;if (!p->count)continue;if (!(new = alloc_layer(idp))) {/** The allocation failed.  If we built part of* the structure tear it down.*/for (new = p; p && p != idp->top; new = p) {p = p->ary[0];new->ary[0] = NULL;new->bitmap = new->count = 0;free_layer(idp, new);}return -1;}new->ary[0] = p;new->count = 1;if (p->bitmap == IDR_FULL)__set_bit(0, &new->bitmap);p = new;}idp->top = p;idp->layers = layers;v = sub_alloc(idp, ptr, &id);if (v == -2)goto build_up;return(v);
}

函数签名

static int idr_get_new_above_int(struct idr *idp, void *ptr, int starting_id)
{
  • 返回值: int - 成功返回分配的ID,失败返回错误码
  • 参数:
    • struct idr *idp: 指向IDR结构的指针
    • void *ptr: 要与ID关联的数据指针
    • int starting_id: 起始ID号,从该值开始寻找可用ID

第一段:变量声明

        struct idr_layer *p, *new;int layers, v, id;id = starting_id;
  • 变量声明:
    • p, new: IDR层指针,用于遍历和创建新层
    • layers: 当前IDR的层数
    • v: 子分配函数的返回值
    • id: 要分配的ID,初始化为起始ID
  • 初始化: id = starting_id - 从指定的起始ID开始

第二段:标签和初始层获取

build_up:p = idp->top;layers = idp->layers;
  • 标签: build_up: - 用于重试的跳转标签
  • 获取顶层: p = idp->top - 获取IDR的顶层指针
  • 获取层数: layers = idp->layers - 获取当前层数

第三段:空IDR初始化

        if (unlikely(!p)) {if (!(p = alloc_layer(idp)))return -1;layers = 1;}
  • 空检查: if (unlikely(!p)) - 检查IDR是否为空(没有顶层)
  • 分配新层: p = alloc_layer(idp) - 分配第一个IDR层
  • 分配失败: 如果分配失败,返回-1(EAGAIN)
  • 设置层数: layers = 1 - 新IDR只有一层

第四段:扩展IDR层数循环

        while ((layers < MAX_LEVEL) && (id >= (1 << (layers*IDR_BITS)))) {
  • 循环条件:
    • layers < MAX_LEVEL: 层数未达到最大值
    • id >= (1 << (layers*IDR_BITS)): 请求的ID超出当前层数的容量
  • 容量计算: 1 << (layers*IDR_BITS) - 当前层数能表示的最大ID+1

第五段:增加层数

                layers++;if (!p->count)continue;
  • 增加层数: layers++ - 需要增加一层
  • 空层检查: if (!p->count) - 如果当前层是空的,继续下一轮循环
  • 优化: 空层不需要立即分配新层,可以延迟

第六段:分配新层

                if (!(new = alloc_layer(idp))) {
  • 分配新层: new = alloc_layer(idp) - 尝试分配新的IDR层
  • 分配失败检查: 如果分配失败,进入错误处理

第七段:分配失败的回滚处理

                        for (new = p; p && p != idp->top; new = p) {p = p->ary[0];new->ary[0] = NULL;new->bitmap = new->count = 0;free_layer(idp, new);}return -1;
  • 回滚循环: 遍历并释放部分构建的结构
  • 指针清理: new->ary[0] = NULL - 清空指针
  • 状态重置: new->bitmap = new->count = 0 - 重置状态
  • 释放层: free_layer(idp, new) - 将层返回空闲链表
  • 返回错误: return -1 - 返回EAGAIN错误

第八段:构建新层结构

                new->ary[0] = p;new->count = 1;if (p->bitmap == IDR_FULL)__set_bit(0, &new->bitmap);p = new;}
  • 设置子层: new->ary[0] = p - 新层指向原来子层
  • 设置计数: new->count = 1 - 新层有一个子层
  • 位图设置: 如果原来子层已满,设置新层的位图
  • 更新指针: p = new - 将新层设为当前层

第九段:更新IDR结构

        idp->top = p;idp->layers = layers;
  • 更新顶层: idp->top = p - 设置新的顶层指针
  • 更新层数: idp->layers = layers - 设置新的层数

第十段:执行子分配

        v = sub_alloc(idp, ptr, &id);if (v == -2)goto build_up;return(v);
}
  • 子分配调用: v = sub_alloc(idp, ptr, &id) - 在构建好的结构中分配ID
  • 冲突重试: if (v == -2) - 如果发生冲突,重新构建结构
  • 返回结果: return(v) - 返回分配结果(成功ID或错误码)

函数功能总结

主要功能: 在IDR树中分配一个新的ID,必要时扩展树结构以容纳更大的ID值

关键设计细节

1. 动态扩展策略
while ((layers < MAX_LEVEL) && (id >= (1 << (layers*IDR_BITS))))
  • 按需扩展: 只有当请求的ID超出当前容量时才扩展
  • 渐进增长: 每次增加一层,容量指数级增长
  • 容量检查: 数学计算确保扩展的正确性
2. 空层优化
if (!p->count)continue;
  • 延迟分配: 如果当前层是空的,跳过立即分配
  • 性能优化: 避免不必要的内存分配
  • 资源节约: 只在真正需要时分配新层

在已构建的IDR树结构中实际分配一个可用的IDsub_alloc

static int sub_alloc(struct idr *idp, void *ptr, int *starting_id)
{int n, m, sh;struct idr_layer *p, *new;struct idr_layer *pa[MAX_LEVEL];int l, id;long bm;id = *starting_id;p = idp->top;l = idp->layers;pa[l--] = NULL;while (1) {/** We run around this while until we reach the leaf node...*/n = (id >> (IDR_BITS*l)) & IDR_MASK;bm = ~p->bitmap;m = find_next_bit(&bm, IDR_SIZE, n);if (m == IDR_SIZE) {/* no space available go back to previous layer. */l++;id = (id | ((1 << (IDR_BITS*l))-1)) + 1;if (!(p = pa[l])) {*starting_id = id;return -2;}continue;}if (m != n) {sh = IDR_BITS*l;id = ((id >> sh) ^ n ^ m) << sh;}if ((id >= MAX_ID_BIT) || (id < 0))return -3;if (l == 0)break;/** Create the layer below if it is missing.*/if (!p->ary[m]) {if (!(new = alloc_layer(idp)))return -1;p->ary[m] = new;p->count++;}pa[l--] = p;p = p->ary[m];}/** We have reached the leaf node, plant the* users pointer and return the raw id.*/p->ary[m] = (struct idr_layer *)ptr;__set_bit(m, &p->bitmap);p->count++;/** If this layer is full mark the bit in the layer above* to show that this part of the radix tree is full.* This may complete the layer above and require walking* up the radix tree.*/n = id;while (p->bitmap == IDR_FULL) {if (!(p = pa[++l]))break;n = n >> IDR_BITS;__set_bit((n & IDR_MASK), &p->bitmap);}return(id);
}

函数签名

static int sub_alloc(struct idr *idp, void *ptr, int *starting_id)
{
  • 返回值: int - 成功返回分配的ID,失败返回错误码
  • 参数:
    • struct idr *idp: 指向IDR结构的指针
    • void *ptr: 要与ID关联的数据指针
    • int *starting_id: 输入输出参数,起始ID和最终分配的ID

第一段:变量声明

        int n, m, sh;struct idr_layer *p, *new;struct idr_layer *pa[MAX_LEVEL];int l, id;long bm;id = *starting_id;
  • 变量声明:
    • n, m, sh: 临时整数变量,用于位操作
    • p, new: IDR层指针
    • pa[MAX_LEVEL]: 路径数组,记录遍历路径
    • l: 当前层数
    • id: 当前处理的ID
    • bm: 位图操作变量
  • 初始化: id = *starting_id - 从起始ID开始

第二段:初始化遍历状态

        p = idp->top;l = idp->layers;pa[l--] = NULL;
  • 获取顶层: p = idp->top - 从IDR顶层开始
  • 获取层数: l = idp->layers - 当前总层数
  • 路径数组: pa[l--] = NULL - 初始化路径数组,层数递减

第三段:主循环开始

        while (1) {/** We run around this while until we reach the leaf node...*/
  • 无限循环: 直到找到叶子节点或失败

第四段:计算当前层索引

                n = (id >> (IDR_BITS*l)) & IDR_MASK;
  • 提取层索引: 从ID中提取当前层的索引
  • 位操作:
    • id >> (IDR_BITS*l): 将ID右移到当前层
    • & IDR_MASK: 取模得到当前层槽位索引

第五段:查找可用槽位

                bm = ~p->bitmap;m = find_next_bit(&bm, IDR_SIZE, n);
  • 反转位图: bm = ~p->bitmap - 将已使用的位反转,得到空闲位
  • 查找空闲位: find_next_bit(&bm, IDR_SIZE, n) - 从位置n开始查找第一个空闲位

第六段:当前层无空闲槽位处理

                if (m == IDR_SIZE) {/* no space available go back to previous layer. */l++;id = (id | ((1 << (IDR_BITS*l))-1)) + 1;if (!(p = pa[l])) {*starting_id = id;return -2;}continue;}
  • 无空间检查: m == IDR_SIZE - 当前层没有空闲槽位
  • 回退到上层: l++ - 回到上一层
  • ID调整: id = (id | ((1 << (IDR_BITS*l))-1)) + 1 - 将ID设置为下一块的起始
  • 路径检查: 如果已经回到顶层且无空间,返回-2,重新基于新id构建层结构
  • 继续循环: 在上一层继续查找

第七段:调整ID以匹配找到的槽位

                if (m != n) {sh = IDR_BITS*l;id = ((id >> sh) ^ n ^ m) << sh;}
  • 槽位不匹配: 如果找到的槽位m不等于期望的n
  • 计算位移: sh = IDR_BITS*l - 当前层的位移量
  • 调整ID: 将ID的当前层部分从n改为m,保持其他层不变

第八段:ID范围检查

                if ((id >= MAX_ID_BIT) || (id < 0))return -3;
  • 范围检查: 确保ID在有效范围内
  • 超出范围: 如果ID超出最大限制或为负,返回-3(空间不足)

第九段:到达叶子节点检查

                if (l == 0)break;
  • 叶子节点检查: l == 0 - 如果到达最底层(叶子层)
  • 跳出循环: 找到目标位置,跳出循环

第十段:创建缺失的中间层

                if (!p->ary[m]) {if (!(new = alloc_layer(idp)))return -1;p->ary[m] = new;p->count++;}
  • 子层检查: !p->ary[m] - 检查下一层是否存在
  • 分配新层: new = alloc_layer(idp) - 分配新的IDR层
  • 分配失败: 返回-1(EAGAIN)
  • 设置指针: p->ary[m] = new - 连接新层
  • 增加计数: p->count++ - 增加子层计数

第十一段:继续向下遍历

                pa[l--] = p;p = p->ary[m];}
  • 保存路径: pa[l--] = p - 将当前层保存到路径数组
  • 移动到下层: p = p->ary[m] - 进入下一层
  • 层数递减: l-- - 层数减1

第十二段:设置叶子节点数据

        p->ary[m] = (struct idr_layer *)ptr;__set_bit(m, &p->bitmap);p->count++;
  • 存储数据: p->ary[m] = (struct idr_layer *)ptr - 在叶子节点存储用户数据
  • 标记使用: __set_bit(m, &p->bitmap) - 标记该槽位已使用
  • 增加计数: p->count++ - 增加叶子节点使用计数

第十三段:向上传播满状态

        n = id;while (p->bitmap == IDR_FULL) {if (!(p = pa[++l]))break;n = n >> IDR_BITS;__set_bit((n & IDR_MASK), &p->bitmap);}
  • 保存ID: n = id - 保存分配的ID用于向上传播
  • 满状态传播: 如果当前层已满,向上层传播
  • 移动到上层: p = pa[++l] - 回到父层
  • 计算父层索引: n = n >> IDR_BITS - 获取在父层的索引
  • 标记父层: __set_bit((n & IDR_MASK), &p->bitmap) - 标记父层对应槽位

第十四段:返回结果

        return(id);
}
  • 返回分配的ID: 成功完成分配,返回最终分配的ID

函数功能总结

主要功能: 在已构建的IDR树结构中实际分配一个可用的ID,并关联用户数据

关键设计细节

1. 路径记录数组
struct idr_layer *pa[MAX_LEVEL];
  • 记录遍历路径: 保存从根到叶子的所有层指针
  • 支持回溯: 当需要回退到上层时使用
  • 满状态传播: 用于向上标记满状态
2. 位图管理策略
bm = ~p->bitmap;
m = find_next_bit(&bm, IDR_SIZE, n);
  • 高效查找: 使用位操作快速查找空闲槽位
  • 从起始位置开始: 从期望位置n开始查找
  • 位图反转: 将已使用位图反转得到空闲位图
3. 动态层创建
if (!p->ary[m]) {new = alloc_layer(idp);p->ary[m] = new;
}
  • 惰性分配: 只在需要时创建中间层
  • 节省内存: 稀疏ID分布时节省大量内存
  • 按需扩展: 随着ID分配自动扩展树结构
4. ID调整算法
id = ((id >> sh) ^ n ^ m) << sh;
  • 精确调整: 只改变当前层的索引,保持其他层不变
  • 位操作高效: 使用异或和移位快速调整
  • 保持连续性: 尽量保持ID的连续性
5. 满状态传播
while (p->bitmap == IDR_FULL) {p = pa[++l];__set_bit((n & IDR_MASK), &p->bitmap);
}
  • 优化查找: 标记满的子树,避免无效搜索
  • 自底向上: 从叶子节点向上传播
  • 性能提升: 减少未来分配时的搜索范围
http://www.dtcms.com/a/516798.html

相关文章:

  • tslib库介绍与使用
  • CyclicBarrier
  • 有哪个网站做正品港货网站建设中常见的问题
  • 【GD32】输出时钟配置
  • 昆明网站建设系统有哪些心理服务网站建设内容
  • 企业网站开发需求文档百度广告怎么投放多少钱
  • 官网站内优化怎么做深圳网站建设燦
  • wordpress本地备份网站首页排名seo搜索优化
  • 全星质量管理 QMS:构建高科技制造业数字化质量生态,筑牢全链路管控
  • Python 应用上架 Microsoft Store 完整指南(2025)
  • 免费低代码平台怎么选?斑斑低代码与云表低代码深度测评!
  • 大型网站开发框架有哪些wordpress选项下拉菜单
  • App 使用 HTTPS 的工程化实战,从接入到真机排查的一线指南
  • JDK 21 API增强详解
  • 化妆品可做的团购网站有哪些有个能写文章做任务的网站
  • 【JVM】详解 类加载器与类加载过程
  • 织梦移动网站模板免费下载佛山国内快速建站
  • 九九乘法表(C语言)
  • AI赋能:下一代海外社媒推广的智能化路径
  • i2c 时序解析
  • 基于线程池的配电房图像检测
  • 天河网站+建设信科网络龙口网页设计
  • 企业官网网站建设咨询手机网站模板下载免费
  • 线性代数直觉(三):特征值(eigenvalue)与特征向量(eigenvector)为何物?
  • 学生个人网站建设模板郑州开发软件公司
  • [Agent可视化] 智能体核心(Rust) | WASI沙箱 | `grpc_server.rs`
  • 东莞网站建设方案托管桂林做网站的公司有哪些
  • 所有搜索引擎蜘蛛不来网站了最新军事报道
  • Java | Lombok @Builder.Default 排障指南:为什么 build 时默认值丢失?
  • 东莞网站快速优化排名中国品牌网站建设