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.pswp.cn/news/253793.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/253793.shtml
英文地址,請注明出處:http://en.pswp.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進行通信&…

internet網絡 checksum校驗和計算方法

http://hi.baidu.com/%CE%C4%B3%AD%B9%AB/blog/item/7d9a4e08f82d72b32eddd4cb.html

最有效的創建大數據模型的6個技巧

數據建模是一門復雜的科學&#xff0c;涉及組織企業的數據以適應業務流程的需求。它需要設計邏輯關系&#xff0c;以便數據可以相互關聯&#xff0c;并支持業務。然后將邏輯設計轉換成物理模型&#xff0c;該物理模型由存儲數據的存儲設備、數據庫和文件組成。 歷史上&#xff…

【轉】Castle Windsor之組件注冊

【轉】Castle Windsor之組件注冊 注冊方式較多&#xff0c;大體有這么幾種&#xff0c;學習得比較粗淺&#xff0c;先記錄&#xff1a;1、逐個注冊組件即對每個接口通過代碼指定其實現類&#xff0c;代碼&#xff1a;container.Register(Component.For<IMyService>() //接…

Verilog 補碼加法溢出判斷及處理

補碼加法運算溢出判斷三種方法&#xff1a; 一、符號位判斷 Xf、Yf分別兩個數的符號位,Zf為運算結果符號位。 當Xf Yf 0&#xff08;兩數同為正&#xff09;,而Zf1(結果為負)時,負溢出&#xff1b;當出現Xf Yf 1&#xff08;兩數同為負&#xff09;,而Zf0&#xff08;結果為…

Android繪制(三):Path結合屬性動畫, 讓圖標動起來!

Android繪制(一):來用shape繪出想要的圖形吧! Android繪制(二):來用Path繪出想要的圖形吧! 目錄 效果圖前言繪制屬性動畫最后效果圖 不廢話, 直接上效果圖, 感興趣再看下去. 其實不單單是效果圖演示的, 運用熟練的話各種圖標之間都是可以切換的. 前言 之前的文章也說了, path還…

{{view 視圖層}}微信小程序

微信小程序 view 視圖層//自學 1.數據綁定 數據綁定WXML中的動態數據均來自對應Page的data。 簡單綁定數據綁定使用"Mustache"語法&#xff08;雙大括號&#xff09;將變量包起來&#xff0c;可以作用于&#xff1a; 內容<view> {{ message }} </view>Pa…

CMOS圖像傳感器——概述

一、概述 圖像傳感器是把光學圖像信息轉換成電信號的器件。圖像傳感器是隨著電視技術在20世紀30年代發展起來的,早期圖像傳感器技術的最重要貢獻在于建立了掃描(Scan)的概念,用掃描的方法把二維空間平面上的光電信息離散成行(Line)和幀(Frame),然后按空間順序讀出形成…

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…

[LeetCode_5] Longest Palindromic Substring

LeetCode: 5. Longest Palindromic Substring class Solution { public: //動態規劃算法string longestPalindrome(string s) {int n s.length();int longestBegin 0;int maxLen 1;bool table[1000][1000] {false};for (int i 0; i < n; i) {table[i][i] true;}//對角…

冒泡排序java

一、最簡單粗暴的排序 思想為&#xff1a;讓每一個關鍵字都和它后邊的每一個關鍵字比較&#xff0c; 如果大則交換&#xff0c;這樣第一個位置的關鍵字在一次循環后一定變為最小值。 1 package demo01;2 3 class BubbleSort01 {4 public static void main(String[] args) {…

CMOS圖像傳感器——工作原理

一、像素陣列結構 一般像素陣列是由水平方向的行( Row ) 和垂直方向的列(Column)正交排列構成的。像素排列的最基本設計原則是:攝像器件像素排列的坐標,必須在顯示的時候能夠準確地還原在圖像原來的相對位置上。在大多數情況下,每個像素中心線在行的方向和列的方向,即…

追尋終極數據庫 - 事務/分析混合處理系統的交付挑戰 (3)

挑戰&#xff1a;支持多個存儲引擎 以下內容并不是新發現&#xff1a;行優化存儲適用于OLTP和運營工作負載&#xff0c;而列存儲適用于BI和分析工作負載。頻繁寫入的工作負載適用于行式存儲。對Hadoop而言&#xff0c;Hbase適合低延遲工作負載&#xff0c;列式ORC文件或Parquet…

hibernate快速入門

第一步:下載Hibernate的開發包:  http://sourceforge.net/projects/hibernate/files/hibernate3 第二步:Hibernate框架目錄結構:  documentation :Hibernate文檔  lib :Hibernate開發jar包    bytecode :操作字節碼jar包.    jpa :Hibernate的實現jpa規范.   …

U-boot給kernel傳參數和kernel讀取參數—struct tag

U-boot 會給 Linux Kernel 傳遞很多參數&#xff0c;如&#xff1a;串口&#xff0c; RAM &#xff0c; videofb 等。 而 Linux kernel 也會讀取和處理這些參數。兩者之間 通過 struct tag 來傳遞參數。 U-boot 把要傳遞給 kernel 的東西保存在 struct tag 數據結構中&#xf…

異步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…

數據倉庫事實表分類[轉]

1&#xff09;在數據倉庫領域有一個概念叫Transaction fact table&#xff0c;中文一般翻譯為“事務事實表”。 事務事實表是維度建模的數據倉庫中三種基本類型事實表中的一種&#xff0c;另外兩種分別是周期快照事實表和累積快照事實表。 事務事實表與周期快照事實表、累積快…