Linux IDR mechanism __linux

Source: Internet
Author: User
Tags goto message queue

I.IDR mechanism
I.IDR Introduction
Many of the system's resources are identified with an integer ID, such as process ID, file descriptor ID, IPC ID, and so on; Resource information is usually stored in the corresponding data structure (for example, process information is stored in task_struct, IPC information is stored in ipc_perm), The correlation mechanism between ID and data structure is implemented differently, and IDR mechanism is one of them.
The abbreviation for Idr,id Radix. IDR is primarily used to establish the correspondence between the ID and the pointer, which points to the corresponding data structure. IDR constructs a sparse array with the class cardinal tree structure, finds the corresponding array element with the ID index, and finds the corresponding data structure pointer.
The main use of IDR mechanism is: IPC ID (Message queue ID, Semaphore ID, shared memory ID, etc.), disk partition ID (digital part of SDA), etc.

II.IDR implementation
1.IDR structure
IDR is composed of cardinal tree, leaf node store ID corresponding pointer, trunk node for leaf node and root node in tandem without storing data. Each node has a radix child node, and each leaf node can store radix pointers.
root node, trunk node and leaf node are expressed by Idr_layer:

Wuyi struct Idr_layer {         unsigned long            bitmap; * A zero bit means "space here" * struct         idr_layer        *ary[1<<idr_bits];         int                      count;  * When zero, we can release it *
 *                      layer int;  * * distance from leaf         /struct rcu_head          rcu_head;
 57};

Bitmap: Used to identify whether the child node has free space, if the child node corresponding bit is 0, then the child node has free space, otherwise the child node is full
ARY: Storage of child node pointers at root or trunk nodes, storing pointer data at leaf nodes
Number of valid data in Count:ary
Layer: The number of layers, that is, the distance from the leaf node, if the leaf node layer=0
Rcu_head: Memory release for Idr_layer

2.idr Cardinal Tree
IDR tree with structure IDR representation

struct IDR         struct idr_layer *top;         struct Idr_layer *id_free;
 An         int               layers/* Only valid without concurrent changes
 /=         int               id_free_cnt;         spinlock_t        lock;
 65};

Top: Point to Cardinal root node
Id_free: A list of cache pools that point to Idr_layer
Layers: Number of cardinality tree layers
ID_FREE_CNT: Cache Pool Size
LOCK:IDR lock, protect Cardinal tree

3. Cardinal Tree Structure Chart

3. Macro definition
Idr_bits: The number of child node index digits, 5 or 6;bitmap is a long type, indicating that the number of child nodes is sizeof (long) *8;long 32-bit, can represent 32 child nodes, then the number of index digits to 5;long for 64 digits, the number of index digits is 6
Idr_size: Number of sub nodes, (1 << idr_bits)
Idr_mask: Sub-node Index mask ((1 << idr_bits)-1)
Max_id_shift:id Space size digits, (sizeof (int) *8-1), ID space is 0~0x7fffffff, positive integer
Max_level: The number of layers required to represent the ID space, (max_id_shift + idr_bits-1)/Idr_bits;n layer cardinality tree represents the number of ID spaces =idr_size^n=1<< (n*idr_bits), Indicates that the entire ID space requires N=roundup (log2 (1<<max_id_shift)/idr_bits) = (Max_id_shift + idr_bits-1)/Idr_bits layer
Idr_free_max: Represents the maximum number of nodes required for IDR cache in the allocation ID process, Max_level + max_level, the tree may need to be enlarged during the allocation ID process, and nodes are allocated if the nodes are empty; To assign an ID with a value of 0x7fffffff, you first have to expand the Max_level node, and then add the MAX_LEVEL-1 node before you can assign the ID correctly.

II.IDR Allocation ID
I. Cache reservation
The cardinality tree is the dynamic allocation of the tree node in the allocation ID, if the node does not exist will be removed from the IDR cache available nodes are automatically added to the tree; In the process of allocating IDs, the maximum number of 2*MAX_LEVEL-1 nodes is added, so the cache must be guaranteed to have 2*MAX_LEVEL-1 nodes. To ensure that no memory is available for allocation.

lib/idr.c:108/** 109 * idr_pre_get-reserver Resources for IDR allocation @idp: IDR Han DLE * @gfp_mask: Memory allocation Flags 112 * 113 * This function should is called prior to locking and calling The 114 * idr_get_new* functions.
It preallocates enough memory to satisfy the worst possible.
116 * 117 * If The system is really out of memory this function returns 0, 118 * otherwise 1. 119/Idr_pre_get int (struct IDR *idp, gfp_t gfp_mask) 121 {122 while (Idp->id_free_cnt < Idr_free_ma X) {123 struct Idr_layer *new; 124 new = Kmem_cache_zalloc (Idr_layer_cache, gfp_mask); 12
5 if (new = NULL) 126 return (0);
127 move_to_free_list (IDP, new);
128} 129 return 1; 130} 


Ii.idr Cardinality tree Expansion
When IDR represents an ID space size that does not meet the requirements, will expand the IDR tree, mainly to increase the number of IDR tree layer, the number of trees from N to n+1, then the root node of n-level tree will be the first node of the n+1 layer. The
IDR cardinality is automatically expanded when assigning IDs, and the implementation code is Idr_get_empty_slot:

Idr_get_empty_slot (struct IDR *idp, int starting_id, 203 struct, Idr_layer **p         A) 204 {205 struct idr_layer *p, *new; 206 int layers, V, id; 207 unsigned long flags; 208 209
id = starting_id;
210 build_up:211 p = idp->top;
212 layers = idp->layers; 213 if (Unlikely (!p)) {214 if (!) (
p = get_from_free_list (IDP)) 215 return-1;
216 P->layer = 0;
217 layers = 1; 218} 219/* * ADD a new layer to the "top of" the "the" of the tree if the requested 221 * ID is L
Arger than the currently allocated space. 222 */223 while (Layers < (MAX_LEVEL-1) && (id >= (1 << (layers*idr_bits))) {2
layers++;                    The IF (!p->count) {special/* Case:if is currently empty, 227      * Then we grow the moving the top node 228 * upwards.
229 * * 230 p->layer++;
231 continue; 232} 233 if (!) (  New = Get_from_free_list (IDP)) {234/* 235 * The allocation failed.
If we built part of 236 * The structure tear it down.
237 * * * 238 spin_lock_irqsave (&idp->lock, flags); 239 for (new = P && p!= idp->top; new = p) {p
= p->ary[0];
241 New->ary[0] = NULL;
242 New->bitmap = New->count = 0;
243 __move_to_free_list (IDP, new); 244} 245 Spin_unlock_irqrestore (&idp->lock, flags);
246 return-1;
247} 248 new->ary[0] = p;
249 New->count = 1;
New->layer = layers-1;
251 if (P->bitmap = = idr_full) 252 __set_bit (0, &new->bitmap);
253 p = new;
254} 255 Rcu_assign_pointer (Idp->top, p);
256 idp->layers = layers;
257 v = sub_alloc (IDP, &id, PA);
258 if (v = = idr_need_to_grow) 259 goto build_up;
return (v); 261}


The allocation steps are as follows:
1. Since IDR initialization, the cardinality tree does not have any tree nodes, and if there are no root nodes, the root node is created and layer=0, which means that the root node is also a leaf node
2. If the lookup start ID has exceeded the size space of the cardinality tree, the cardinality tree will be enlarged;
A. If the current tree is an empty tree, directly modify the level of the tree and the root node
B. Otherwise, the root node of the original tree is used as the first element of the new root node, and the root node is recycled until the expansion requirement is satisfied; If the expansion process fails, the previously added node is deleted
3. Modify the root node level information of the tree
4. Allocate an idle ID from the cardinality tree, and if the tree requires expansion, expand the tree based on the ID size.

The cardinality tree expansion process is shown in the following illustration, where the green portion is the expansion node:

III.IDR Allocation ID
IDR allocation ID, this process may add a new node of the tree, implemented as Sub_alloc

sub_alloc static int (struct IDR *idp, int *starting_id, struct idr_layer **pa) 134 {135 int n, m, SH; 136
struct Idr_layer *p, *new;
137 int L, ID, OID;
138 unsigned long BM;
139 140 id = *starting_id;
restart:142 p = idp->top;
143 L = idp->layers;
144 pa[l--] = NULL; 145 while (1) {146/* 147 * We run around this while until We reach the leaf nod
E...
148 * * 149 n = (id >> (idr_bits*l)) & Idr_mask;
The BM = ~p->bitmap;
151 m = find_next_bit (&AMP;BM, Idr_size, N); 152 if (M = = idr_size) {153/* no space available down to previous layer. */1
l++;
The OID = ID; 156 id = (ID | ((1 << (Idr_bits * L))-1)
+ 1; 158/* If already at the top layer, We need to grow * * * 159 if (ID >= 1 << (idp->layers * idr_bits)) {160
*starting_id = ID;
161 return Idr_need_to_grow;
162} 163 p = pa[l];
164 bug_on (!P); 165 166/* If We need to go up one layer, continue the 167 * loop;
Otherwise, restart from the top.
169 sh = idr_bits * (l + 1);
170 if (oid >> sh = = ID >> sh) 171 continue;
172 else 173 goto restart;                         174} 175 if (M!= N) {176 sh = idr_bits*l; 177
id = ((id >> sh) ^ n ^ m) << sh; 178} 179 if ((ID >= max_id_bit) ||
(ID < 0))
180 return idr_nomore_space;
181 if (L = = 0) is a break;
183/* 184 * Create the layer below if it is missing. 185 */186 if (!p->ary[m]) {187 new = Get_from_free_list (IDP)
;
188 if (!new) 189 return-1;
190 New->layer = L-1;
191 Rcu_assign_pointer (P->ary[m], new);
p->count++;
193} 194 pa[l--] = p;
195 p = p->ary[m];
196} 197 198 Pa[l] = p;
199 return ID; 200}

The

Allocation ID procedure is as follows:
1. Find the ID space at the beginning of the starting_id, and if there is no free space, you need to expand the cardinality tree
2. According to the starting_id recursive node, if the child node has no space, Then fall back to the superior or top level and continue to look for the idle ID according to the enlarged STARTING_ID
  NOTE: In the recursive process, there is a need for the parent node to identify the child node in bitmap, but the free interval of the child nodes may appear before the ID, and no free space after the ID. So there will be a fallback superior or top-level situation
  Note: A node has 32 or 64 intervals, corresponding to each element of the ARY
  If the node does not have an idle ID, fall back to the upper level and offset an interval back to find the free ID If the parent interval is the last interval of the node, fallback to the root node to start the lookup again. The
  fallback top and root two things are as follows:
    layer = 6    5     4  & nbsp;  3     2     1     0
        id = 00 00000 00000 00000 11111 00001 00000 when
    a. When looking for the No. 0 level No. 0 (00000) interval, because the interval does not have an idle ID, the Back up the superior and offset the interval that is the 2nd (00001+1) interval; because the upper two intervals belong to the same node, you can continue to find
    B. When looking for the 1th layer 1th (00001) interval, because the interval does not have an idle ID, Returns the superior and offsets the interval, that is, the No. 0 (11111+1) interval; because the upper two intervals do not belong to the same node, the root node continues to look for
3. If the node does not exist in a recursive child node procedure, add a node
4. Recursion to the leaf node, then the loop ends, and returns the free ID of the leaf node

.

Note:
Line 156: id = (ID | ((1 << (Idr_bits * L))-1) + 1; Returns to the upper level and offsets an interval;
Line 169: SH = idr_bits * (l + 1); To determine whether the interval between the offset and the original range is at the same node.
176 line: sh = idr_bits*l; id = ((id >> sh) ^ n ^ m) << sh; The field value representing L-level in ID is modified by N to M, which can be regarded as id=id>> (sh+idr_bits) << (sh+idr_bits) +n^n^m& Lt;<sh=id>> (sh+idr_bits) << (sh+idr_bits) +m<<sh

The fallback to the upper or top level is shown in the following illustration:


A nodal point bitmap=0x0000ffff,b node bitmap=0x0000ffff,d node bitmap=0x00000000
When an idle ID is looked up from 977, a node is found, but a node does not have an idle ID, it is rolled back to the upper c.ary[30], and an interval is c.ary[31], because c.ary[30] and c.ary[31 are e.ary[0]=e.ary[0 at the same node. ; continue to find from c.ary[31], and you will find an idle id=992 at B-junction.
When looking for an idle ID from 1009, a b node is found, but B nodes do not have an idle ID, fall back to the upper c.ary[31], and are collectively referred to as an interval d.ary[0], because c.ary[31] and d.ary[0] are not in the same node that is e.ary[0]!=e.ary[. 1] to return to the top node E and to id=1024 the idle ID from the point of view, the free id=1024 is found at D-Junction

III.IDR Release ID
I. Delete ID
IDR Release ID is implemented as:

353 static void Sub_remove (struct IDR *idp, int shift, int id) 354 {355 struct Idr_layer *p = idp->top; 356
struct Idr_layer **pa[max_level];
357 struct Idr_layer ***paa = &pa[0];
358 struct Idr_layer *to_free;
359 int n;
360 361 *PAA = NULL;
362 *++PAA = &idp->top;                 363 364 while (Shift > 0) && p) {365 n = (ID >> shift) & Idr_mask; 366
__clear_bit (n, &p->bitmap);
367 *++PAA = &p->ary[n];
368 p = p->ary[n];
369 Shift-= idr_bits;
370} 371 n = ID & idr_mask; 372 if (likely (p!= NULL && test_bit (n, &p->bitmap))) {373 __clear_bit (n, &AMP;P-&G
T;BITMAP);
374 Rcu_assign_pointer (P->ary[n], NULL);
375 To_free = NULL;                 376 while (*PAA &&!-((**PAA)->count)) {377        if (to_free) 378 Free_layer (To_free);
379 To_free = **PAA;
380 **paa--= NULL;
381} 382 if (!*PAA) 383 idp->layers = 0;
384 if (to_free) 385 free_layer (To_free);
386} else 387 idr_remove_warning (ID); 388}

1. Set the bitmap that corresponds to the node of the cardinality tree path represented by ID 0
2. If the node on the path is an empty node, delete the node at the same point

Ii. Base Tree reduction
The cardinality tree shrink implementation is idr_remove:

390/** 391 * Idr_remove-remove the given ID and free it ' s slot 392 * @idp: IDR handle 393 * @id: Unique key 394 * * 
395 void Idr_remove (struct IDR *IDP, int id) 396 {397 struct idr_layer *p; 398 struct; 399/* Mask off Upper bits we don ' t use for the search.
* * 401 ID &= max_id_mask;
402 403 Sub_remove (IDP, (idp->layers-1) * idr_bits, id);             404 if (idp->top && idp->top->count = 1 && (idp->layers > 1) && 405  Idp->top->ary[0]) {406/* 407 * Single child at leftmost slot:we can shrink
The tree. 408 * This are not needed anymore since when layers are 409 * inserted, they are in
Serted at the top of the existing 410.
411 * * 412 To_free = idp->top;
413 p = idp->top->ary[0]; 414 RCU_assign_pointer (Idp->top, p);
415--idp->layers;
416 To_free->bitmap = To_free->count = 0;
417 Free_layer (To_free); 418} 419 while (idp->id_free_cnt >= idr_free_max) {420 p = get_from_free_list (IDP)
;                  421/* 422 * note:we don ' t call the RCU callback here, since the 423
* Layers that fall to the freelist are those that have been 424 * preallocated.
425 * * 426 kmem_cache_free (Idr_layer_cache, p);
427} 428 return; 429}

1. If the root node uses only 0 intervals, the root node is deleted and the node represented by the 0 interval as the root node
2. Release the extra nodes in the IDR cache

IV.IDR Lookup ID corresponding pointer
ID lookup to find the pointer value stored in the leaf node based on the ID value
The lookup process is implemented by Idr_find:

490/** 491 * Idr_find-return pointer for given ID 492 * @idp: IDR handle 493 * @id: Lookup key 494 * 495 * return  The pointer given the ID it has been registered with.
A%null 496 * Return indicates of that @id isn't valid or you passed%null in 497 * idr_get_new (). 498 * 499 * This function can is called under Rcu_read_lock (), given that the leaf * pointers lifetimes are
Ly managed.         501 */502 void *idr_find (struct IDR *IDP, int id) 503 {504 int n; 505 struct Idr_layer *p; 506 507
p = rcu_dereference (idp->top);
508 if (!P) 509 return NULL;
510 n = (p->layer+1) * idr_bits; 511 * * Mask off Upper bits we don ' t use for the search.
* * 513 ID &= max_id_mask;
514 515 if (id >= (1 << N)) 516 return NULL;
517 bug_on (n = 0); 518 519 while (n > 0 && p) {520 N-= idr_bits; 521 bug_on (n!= P>layer*idr_bits);
522 p = rcu_dereference (p->ary[(ID >> N) & Idr_mask]);
523} 524 return ((void *) p); 525}

Note: Take the corresponding field value in the ID as the interval index of the node, find the corresponding child node until the leaf node;

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.