ida和idr机制分析(盘符分配机制)

内核ida和idr机制分析(盘符分配机制)

ida和idr的机制在我个人看来,是内核管理整数资源的一种方法。在内核中,许多地方都用到了该结构(例如class的id,disk的id),更直观的说,硬盘的sda到sdz的自动排序也是依靠该机制。使用该结构的好处是可以管理大量的整数资源并且检索的时候非常高效。但是,使用该机制的另一个弊端就是:同一个槽位的硬盘进行拔插的时候,如果之前申请的整数资源没有来得及释放,那么可能会产生盘符漂移现象。这给上层软件对盘符的管理带来了困难。在本篇博文中,对具体如何解决盘符漂移不做说明。

在根据代码说明之前,我想先介绍一下该机制对整型数的灵活应用。int数值一般来说,为4个字节。那么将一个int数分为4部分的结果就是每部分8bit。在idr的机制中,采用树来管理资源,int数值的一个字节,被抽象成了树中的一层。即:对某个int值从又向左数,分别是第一层、第二层、第三层、第四层。第一层必须要有,第一层一般是树叶层。该idr树的生长方式也是从树叶开始,随着不断的生长,最开始,树根就是树叶,到最后,树根处于第四层,树叶还是第一层。特别注意说明的是,idr还有一个第0层的概念。在第0层上,可以比喻成树叶上水珠。
之前的文字描述可能比较抽象,而且也可能不太准确。下面用一个图来表示这种关系。
1187168-20170809205742652-271178544.png

假设我们现在有个a=0x0001,那么a在图中对应第一层中的1。如果有个b=0x0011,那么就必须从第二层的1上生长出一个和第一层一样的结构,再在这上面找到1.如图所示:
1187168-20170809210539886-1360774433.png

当然,如果该树管理的最大资源,还没有涉及到第三层,即最大的数第三个字节都是0,那么其实是没有必要维护第三层的。
此外,该图只是形象的说明了idr的思想,但与实际的代码并不完全一样,具体细节还需要接下来慢慢结合代码分析。在分析代码之前,再介绍一下常用运算符抑或。请观察下面的运算式:((m >> 8) & (0xF) ^ (m >> 8) ^ (0x5)) << 8 该运算的作用是将m的第二个字节置为5,第三个第四个字节不变,第一个字节清零。

下面开始结合代码分析,先分别给出ida和idr的结构说明:

168 struct ida {
169         struct idr              idr;
170         struct ida_bitmap       *free_bitmap;                                                                                                                                                                
171 };163 struct ida_bitmap {
164         long                    nr_busy;
165         unsigned long           bitmap[IDA_BITMAP_LONGS];
166 };

idr代表着上面介绍的那一棵树,因此可见,ida只是对这棵树的封装,在idr树的基础上,统一了管理办法。

 42 struct idr {                                                                                                                                                                                                 43         struct idr_layer __rcu  *hint;  /* the last layer allocated from */44         struct idr_layer __rcu  *top;45         int                     layers; /* only valid w/o concurrent changes */46         int                     cur;    /* current pos for cyclic allocation */47         spinlock_t              lock;48         int                     id_free_cnt;49         struct idr_layer        *id_free;50 };30 struct idr_layer {31         int                     prefix; /* the ID prefix of this idr_layer */32         int                     layer;  /* distance from leaf */33         struct idr_layer __rcu  *ary[1<<IDR_BITS];34         int                     count;  /* When zero, we can release it */35         union {36                 /* A zero bit means "space here" */37                 DECLARE_BITMAP(bitmap, IDR_SIZE);38                 struct rcu_head         rcu_head;39         };40 };

idr代表图中的那棵树,idr_layer代表着图上的每个圆球,而其中的ary数组代表着每个圆球下的箭头,bitmap位图用来记录该位置下的子layer是否还有空位,如果没有将置1.
获取idr资源主要由两个api来管理。ida_pre_get和ida_get_new_above。前者负责按照该树可承载的最多layer数量申请layer资源,并存放到资源池中。后者可以指定从某个id开始,寻找下一个未被使用的id。

 896 int ida_pre_get(struct ida *ida, gfp_t gfp_mask)                                                                                                                                                            897 {898         /* allocate idr_layers */899         if (!__idr_pre_get(&ida->idr, gfp_mask))900                 return 0;901 902         /* allocate free_bitmap */903         if (!ida->free_bitmap) {904                 struct ida_bitmap *bitmap;905 906                 bitmap = kmalloc(sizeof(struct ida_bitmap), gfp_mask);907                 if (!bitmap)908                         return 0;909                   910                 free_bitmap(ida, bitmap);911         }912 913         return 1;914 }192 static int __idr_pre_get(struct idr *idp, gfp_t gfp_mask)                                                                                                                                                   193 {194         while (idp->id_free_cnt < MAX_IDR_FREE) {195                 struct idr_layer *new;196                 new = kmem_cache_zalloc(idr_layer_cache, gfp_mask);197                 if (new == NULL)198                         return (0);199                 move_to_free_list(idp, new);200         }201         return 1;202 }160 static void move_to_free_list(struct idr *idp, struct idr_layer *p)                                                                                                                                         161 {162         unsigned long flags;163 164         /*165          * Depends on the return element being zeroed.166          */167         spin_lock_irqsave(&idp->lock, flags);168         __move_to_free_list(idp, p);169         spin_unlock_irqrestore(&idp->lock, flags);170 }153 static void __move_to_free_list(struct idr *idp, struct idr_layer *p)                                                                                                                                       154 {155         p->ary[0] = idp->id_free;156         idp->id_free = p;157         idp->id_free_cnt++;158 }868 static void free_bitmap(struct ida *ida, struct ida_bitmap *bitmap)                                                                                                                                         869 {               870         unsigned long flags;871         872         if (!ida->free_bitmap) {873                 spin_lock_irqsave(&ida->idr.lock, flags);874                 if (!ida->free_bitmap) {875                         ida->free_bitmap = bitmap;876                         bitmap = NULL;877                 }       878                 spin_unlock_irqrestore(&ida->idr.lock, flags);879         }880         881         kfree(bitmap);882 }

899行调用__idr_pre_get分配layer。在该函数内,分配MAX_IDR_FREE个layer,之后使用move_to_free_list函数进行保存。153行可以看出,所有的未使用layer都通过idr里的id_free连接起来,layer之间通过ary[0]连接。这样,创建的资源,在之后需要使用的时候,直接取就可以了,可以节省运行时间,提高性能。
ida内还有个free_bitmap域,由于该域的操作涉及到竞争,因此,放到自旋锁中处理。881行的free是因为,防止某个线程申请好了资源,但是有一个线程比他还快,已经进入了874行。那么等之后他获取到锁后,直接不需要进入if分支,释放之前申请的资源即可。

 932 int ida_get_new_above(struct ida *ida, int starting_id, int *p_id)933 {934         struct idr_layer *pa[MAX_IDR_LEVEL + 1];935         struct ida_bitmap *bitmap;936         unsigned long flags;937         int idr_id = starting_id / IDA_BITMAP_BITS;938         int offset = starting_id % IDA_BITMAP_BITS;939         int t, id;940 941  restart:942         /* get vacant slot */943         t = idr_get_empty_slot(&ida->idr, idr_id, pa, 0, &ida->idr);944         if (t < 0)945                 return t == -ENOMEM ? -EAGAIN : t;946 947         if (t * IDA_BITMAP_BITS >= MAX_IDR_BIT)948                 return -ENOSPC;949 950         if (t != idr_id)951                 offset = 0;952         idr_id = t;953 954         /* if bitmap isn't there, create a new one */955         bitmap = (void *)pa[0]->ary[idr_id & IDR_MASK];956         if (!bitmap) {957                 spin_lock_irqsave(&ida->idr.lock, flags);958                 bitmap = ida->free_bitmap;959                 ida->free_bitmap = NULL;960                 spin_unlock_irqrestore(&ida->idr.lock, flags);961 962                 if (!bitmap)963                         return -EAGAIN;964                                                                                                                                                                                                             965                 memset(bitmap, 0, sizeof(struct ida_bitmap));966                 rcu_assign_pointer(pa[0]->ary[idr_id & IDR_MASK],967                                 (void *)bitmap);968                 pa[0]->count++;969         }970 971         /* lookup for empty slot */972         t = find_next_zero_bit(bitmap->bitmap, IDA_BITMAP_BITS, offset);973         if (t == IDA_BITMAP_BITS) {                                                                                                                                                                         974                 /* no empty slot after offset, continue to the next chunk */975                 idr_id++;976                 offset = 0;977                 goto restart;978         }979 980         id = idr_id * IDA_BITMAP_BITS + t;981         if (id >= MAX_IDR_BIT)982                 return -ENOSPC;983 984         __set_bit(t, bitmap->bitmap);985         if (++bitmap->nr_busy == IDA_BITMAP_BITS)986                 idr_mark_full(pa, idr_id);987 988         *p_id = id;989 990         /* Each leaf node can handle nearly a thousand slots and the991          * whole idea of ida is to have small memory foot print.992          * Throw away extra resources one by one after each successful993          * allocation.994          */995         if (ida->idr.id_free_cnt || ida->free_bitmap) {996                 struct idr_layer *p = get_from_free_list(&ida->idr);997                 if (p)998                         kmem_cache_free(idr_layer_cache, p);999         }
1000 
1001         return 0;
1002 }289 static int idr_get_empty_slot(struct idr *idp, int starting_id,                                                                                                                                             290                               struct idr_layer **pa, gfp_t gfp_mask,291                               struct idr *layer_idr)292 {293         struct idr_layer *p, *new;294         int layers, v, id;295         unsigned long flags;296 297         id = starting_id;298 build_up:299         p = idp->top;300         layers = idp->layers;301         if (unlikely(!p)) {302                 if (!(p = idr_layer_alloc(gfp_mask, layer_idr)))303                         return -ENOMEM;304                 p->layer = 0;305                 layers = 1;306         }307         /*308          * Add a new layer to the top of the tree if the requested309          * id is larger than the currently allocated space.310          */311         while (id > idr_max(layers)) {312                 layers++;                                                                                                                                                                                   313                 if (!p->count) {314                         /* special case: if the tree is currently empty,315                          * then we grow the tree by moving the top node316                          * upwards.317                          */318                         p->layer++;319                         WARN_ON_ONCE(p->prefix);320                         continue;321                 }322                 if (!(new = idr_layer_alloc(gfp_mask, layer_idr))) {323                         /*324                          * The allocation failed.  If we built part of325                          * the structure tear it down.326                          */327                         spin_lock_irqsave(&idp->lock, flags);328                         for (new = p; p && p != idp->top; new = p) {329                                 p = p->ary[0];330                                 new->ary[0] = NULL;331                                 new->count = 0;332                                 bitmap_clear(new->bitmap, 0, IDR_SIZE);333                                 __move_to_free_list(idp, new);334                         }335                         spin_unlock_irqrestore(&idp->lock, flags);336                         return -ENOMEM;337                 }338                 new->ary[0] = p;339                 new->count = 1;340                 new->layer = layers-1;341                 new->prefix = id & idr_layer_prefix_mask(new->layer);342                 if (bitmap_full(p->bitmap, IDR_SIZE))343                         __set_bit(0, new->bitmap);344                 p = new;345         }346         rcu_assign_pointer(idp->top, p);347         idp->layers = layers;348         v = sub_alloc(idp, &id, pa, gfp_mask, layer_idr);                                                                                                                                                   349         if (v == -EAGAIN)350                 goto build_up;351         return(v);352 }220 static int sub_alloc(struct idr *idp, int *starting_id, struct idr_layer **pa,221                      gfp_t gfp_mask, struct idr *layer_idr)222 {223         int n, m, sh;224         struct idr_layer *p, *new;225         int l, id, oid;226 227         id = *starting_id;228  restart:229         p = idp->top;230         l = idp->layers;231         pa[l--] = NULL;232         while (1) {233                 /*234                  * We run around this while until we reach the leaf node...235                  */236                 n = (id >> (IDR_BITS*l)) & IDR_MASK;237                 m = find_next_zero_bit(p->bitmap, IDR_SIZE, n);238                 if (m == IDR_SIZE) {239                         /* no space available go back to previous layer. */240                         l++;241                         oid = id;242                         id = (id | ((1 << (IDR_BITS * l)) - 1)) + 1;243 244                         /* if already at the top layer, we need to grow */245                         if (id > idr_max(idp->layers)) {246                                 *starting_id = id;247                                 return -EAGAIN;248                         }249                         p = pa[l];250                         BUG_ON(!p);251                                                                                                                                                                                                             252                         /* If we need to go up one layer, continue the253                          * loop; otherwise, restart from the top.254                          */255                         sh = IDR_BITS * (l + 1);256                         if (oid >> sh == id >> sh)257                                 continue;258                         else259                                 goto restart;260                 }                                                                                                                                                                                           261                 if (m != n) {262                         sh = IDR_BITS*l;263                         id = ((id >> sh) ^ n ^ m) << sh;264                 }265                 if ((id >= MAX_IDR_BIT) || (id < 0))266                         return -ENOSPC;267                 if (l == 0)268                         break;269                 /*270                  * Create the layer below if it is missing.271                  */272                 if (!p->ary[m]) {273                         new = idr_layer_alloc(gfp_mask, layer_idr);274                         if (!new)275                                 return -ENOMEM;276                         new->layer = l-1;277                         new->prefix = id & idr_layer_prefix_mask(new->layer);278                         rcu_assign_pointer(p->ary[m], new);279                         p->count++;280                 }281                 pa[l--] = p;282                 p = p->ary[m];283         }284 285         pa[l] = p;286         return id;287 }

由于代码较长。为了方便叙述,假设当前idr树中没有被使用的id。现在调用ida_get_new_above从0开始找下一个可用的id。由于我们给出了假设,因此可以预期到得到的结果是0.我们带着这样的假设去分析代码。
943行进入idr_get_empty_slot。301行由于是第一次申请id,因此将进入该分支,分配一个top,即根节点。此时,304行看出根节点层数为第0层。305行layers表示总层数,为1层。由于是从0开始分配,因此311行循环不进入,直接跳过。346行通过rcu方式配置了top域。348行开始真正分配。
该函数工作开始,保存了几个量,如227~230所示。考虑到我们从0开始,则id=0,p为刚刚分配的根节点,l=1。232行的循环是为了使l>1时,能不断遍历到第0层。237行得到m=0.if分支显然不会进入,跳过。由于231行l--,所以267行的时候,跳出循环。285行保存了根节点,之后返回0.
回到943行,t取到0.pa[0]内保存的一定是叶子节点的地址。我们这里因为只有1层,根节点就是叶子节点。955行显然取到一个NULL,那么将ida中的free_bitmap转交给它,并在966行转交给根节点的ary[0]。972行检测当前层数是否还有剩余空位,这里需要说明的是,一般情况下,一个节点(layer)管理8*128个id,这种管理就是直接通过数组进行管理的。这个数组就是ida申请的数组,在该函数内通过强转保存到了ary[0]内。那么此时,肯定返回0. 980行id=0.984行配置相应位为1. 985~986行判断该节点是否已满,如果之后没有空闲了,将设置为该位置已满。这是通过根节点下的bitmap去设置的。988行将id值赋给p_id,之后返回。
在这里,将对之前的假设做出一个纠正。我们开始假设是从0开始寻找,是假设ida_get_new_above里的参数staring_id是从哪个数开始查找的意思。实际上,通过走读分析,我们可以看到,该starting_id其实代表某个layer。

通过这样的分析,相信对于整个流程已经有了简单的认知。代码其他部分主要涉及到stating_id指定的layer不存在,分配新的layer。或者starting_id超过了当前层数所能提供的最大id,则idr必须开始生长的过程。对于这些部分,相信经过前面的分析,这些都已经变的很简单,本文不再详细说明。留给读者自行分析。

转载于:https://www.cnblogs.com/wyk930511/p/7327778.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/253793.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MIPI CSI-2学习

CSI&#xff08;Camera Serial Interface&#xff09;定义了摄像头外设与主机控制器之间的接口&#xff0c;旨在确定摄像头与主机控制器在移动应用中的标准。 关键词描述 缩写解释CCICamera Control Interface&#xff08;物理层组件&#xff0c;通常使用I2C或I3C进行通信&…

nand flash坏块管理OOB,BBT,ECC

0.NAND的操作管理方式 NAND FLASH的管理方式&#xff1a;以三星FLASH为例&#xff0c;一片Nand flash为一个设备(device)&#xff0c;1 (Device) xxxx (Blocks)&#xff0c;1 (Block) xxxx (Pages)&#xff0c;1(Page) 528 (Bytes) 数据块大小(512Bytes) OOB 块大小(16Byte…

小白学git2

你已经在本地创建了一个Git仓库后&#xff0c;又想在GitHub创建一个Git仓库&#xff0c;并且让这两个仓库进行远程同步&#xff0c;这样&#xff0c;GitHub上的仓库既可以作为备份&#xff0c;又可以让其他人通过该仓库来协作&#xff0c;真是一举多得。 首先&#xff0c;登陆G…

CMOS图像传感器——工作原理

一、像素阵列结构 一般像素阵列是由水平方向的行( Row ) 和垂直方向的列(Column)正交排列构成的。像素排列的最基本设计原则是:摄像器件像素排列的坐标,必须在显示的时候能够准确地还原在图像原来的相对位置上。在大多数情况下,每个像素中心线在行的方向和列的方向,即…

追寻终极数据库 - 事务/分析混合处理系统的交付挑战 (3)

挑战&#xff1a;支持多个存储引擎 以下内容并不是新发现&#xff1a;行优化存储适用于OLTP和运营工作负载&#xff0c;而列存储适用于BI和分析工作负载。频繁写入的工作负载适用于行式存储。对Hadoop而言&#xff0c;Hbase适合低延迟工作负载&#xff0c;列式ORC文件或Parquet…

异步FIFO设计(Verilog)

FIFO&#xff08;First In First Out&#xff09;是异步数据传输时经常使用的存储器。该存储器的特点是数据先进先出&#xff08;后进后出&#xff09;。其实&#xff0c;多位宽数据的异步传输问题&#xff0c;无论是从快时钟到慢时钟域&#xff0c;还是从慢时钟到快时钟域&…

python中RabbitMQ的使用(路由键模糊匹配)

路由键模糊匹配 使用正则表达式进行匹配。其中“#”表示所有、全部的意思&#xff1b;“*”只匹配到一个词。 匹配规则&#xff1a; 路由键&#xff1a;routings [ happy.work, happy.life , happy.work.teacher, sad.work, sad.life, sad.work.teacher ] "#"&am…

时钟切换处理(Verilog)

随着各种应用场景的限制&#xff0c;芯片在运行时往往需要在不同的应用下切换不同的时钟源&#xff0c;例如低功耗和高性能模式就分别需要低频率和高频率的时钟。两个时钟源有可能是同源且同步的&#xff0c;也有可能是不相关的。直接使用选择逻辑进行时钟切换大概率会导致分频…

Angular Elements 组件在非angular 页面中使用的DEMO

2019独角兽企业重金招聘Python工程师标准>>> 一、Angular Elements 介绍 Angular Elements 是伴随Angular6.0一起推出的新技术。它借助Chrome浏览器的ShadowDom API&#xff0c;实现一种自定义组件。 这种组件可以用Angular普通组件的开发技术进行编写&#xff0c;…

卢卡斯定理

卢卡斯定理:解决一类组合数取模问题 A、B是非负整数&#xff0c;p是质数。AB写成p进制&#xff1a;Aa[n]a[n-1]...a[0]&#xff0c;Bb[n]b[n-1]...b[0]。 则组合数C(A,B)与C(a[n],b[n])*C(a[n-1],b[n-1])*...*C(a[0],b[0]) modp同余 即&#xff1a;Lucas(n,m,p)c(n%p,m%p)*Luc…

loadrunner中对https证书的配置

1、准备好网站的证书&#xff0c;一般证书是cer格式&#xff1b; 2、因为loadrunner只支持pem格式的证书&#xff0c;所以要将证书转换格式&#xff0c;利用openssl工具&#xff1b;&#xff08;或者直接让开发提供pem格式的证书&#xff09;3、得到pem格式的证书之后&#xff…

Datapath综合代码规范(Verilog)

一、一般准则 1、有符号数运算 利用类型“signed”完成有符号数运算&#xff0c;而不是用无符号数模拟有符号数运算。这样可以得到更好的QoR。在资源报告中检查操作数的类型和大小。 2、符号/零扩展 尽量不要手动扩展。verilog利用signed/unsigned会自动完成扩展。这样代码可…

CMOS 图像传感器——Skipping 和 Binning 模式

在通常的CMOS读取方式中&#xff0c;由于像素读取规模的差异&#xff0c;不同的分辨率对应不同的帧率。在通道带宽固定的前提下&#xff0c;想要提高帧率就要考虑是否需要缩小视野&#xff08;外圈裁切&#xff09;。若不希望视野缩小&#xff0c;需要减少采样的分辨率。 常用的…

APB协议学习

APB(Advanced Peripheral Bus) 1、APB的概述与特点 APB主要用于低带宽的周边外设之间的连接&#xff0c;例如UART、1284等&#xff0c;它的总线架构不像AHB支持多个主模块&#xff0c;在APB里面唯一的主模块就是APB 桥。其特性包括&#xff1a;两个时钟周期传输&#xff1b;无…

私有协议栈开发

通信协议从广义上区分&#xff0c;可以分为公有协议和私有协议。由于私有协议的灵活性&#xff0c;它往往会在某个公司或者组织内部使用&#xff0c;按需定制&#xff0c;也因为如此&#xff0c;升级起来会非常方便&#xff0c;灵活性好。绝大多数的私有协议传输层都基于TCP/IP…

数字图像处理——2D降噪

图像降噪处理主要分为2D&#xff08;空域&#xff09;与3D降噪&#xff08;时域/多帧&#xff09;&#xff0c;而2D降噪由于相关的实现算法丰富&#xff0c;效果各异&#xff0c;有着丰富的研究价值。理解2D降噪算法的流程&#xff0c;也对其他的增强算法有很大的帮助&#xff…

项目开发(Require + E.js)

最近在做的几个项目&#xff0c;分别用了不同的框架跟方式&#xff0c;有个H5的项目&#xff0c;用了vue框架&#xff0c; 这个项目我还没有正式加入进去&#xff0c; 等手头的这个项目完成就可以去搞vue了&#xff0c; 现在手头的这个项目是一个招聘的项目&#xff0c; 用到了…

AHB协议学习

1. 简介 AHB(Advanced High Performance Bus)总线规范是AMBA(Advanced Microcontroller Bus Architecture) V2.0总线规范的一部分&#xff0c;AMBA总线规范是ARM公司提出的总线规范&#xff0c;被大多数SoC设计采用&#xff0c;它规定了AHB (Advanced High-performance Bus)、A…

数字图像处理——引导滤波

一、概述 引导滤波是由何恺明等人于2010年发表在ECCV的文章《Guided Image Filtering》中提出的&#xff0c;后续于2013年发表。引导过滤器根据局部线性模型原理&#xff0c;通过考虑引导图像的内容来计算过滤输出&#xff0c;引导图像可以是输入图像本身或另一个不同的图像。具…