Commit 7aae6dd80e265aa9402ed507caaff4a5dba55069
Committed by
Greg Kroah-Hartman
1 parent
dc0afa8388
Exists in
master
and in
20 other branches
idr: fix obscure bug in allocation path
In sub_alloc(), when bitmap search fails, it goes up one level to continue search. This is done by updating the id cursor and searching the upper level again. If the cursor was at the end of the upper level, we need to go further than that. This wasn't implemented and when that happens the part of the cursor which indexes into the upper level wraps and sub_alloc() ends up searching the wrong bitmap. It allocates id which doesn't match the actual slot. This patch fixes this by restarting from the top if the search needs to go higher than one level. Signed-off-by: Tejun Heo <htejun@gmail.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Showing 1 changed file with 14 additions and 2 deletions Side-by-side Diff
lib/idr.c
... | ... | @@ -100,10 +100,11 @@ |
100 | 100 | int n, m, sh; |
101 | 101 | struct idr_layer *p, *new; |
102 | 102 | struct idr_layer *pa[MAX_LEVEL]; |
103 | - int l, id; | |
103 | + int l, id, oid; | |
104 | 104 | long bm; |
105 | 105 | |
106 | 106 | id = *starting_id; |
107 | + restart: | |
107 | 108 | p = idp->top; |
108 | 109 | l = idp->layers; |
109 | 110 | pa[l--] = NULL; |
110 | 111 | |
111 | 112 | |
... | ... | @@ -117,12 +118,23 @@ |
117 | 118 | if (m == IDR_SIZE) { |
118 | 119 | /* no space available go back to previous layer. */ |
119 | 120 | l++; |
121 | + oid = id; | |
120 | 122 | id = (id | ((1 << (IDR_BITS * l)) - 1)) + 1; |
123 | + | |
124 | + /* if already at the top layer, we need to grow */ | |
121 | 125 | if (!(p = pa[l])) { |
122 | 126 | *starting_id = id; |
123 | 127 | return -2; |
124 | 128 | } |
125 | - continue; | |
129 | + | |
130 | + /* If we need to go up one layer, continue the | |
131 | + * loop; otherwise, restart from the top. | |
132 | + */ | |
133 | + sh = IDR_BITS * (l + 1); | |
134 | + if (oid >> sh == id >> sh) | |
135 | + continue; | |
136 | + else | |
137 | + goto restart; | |
126 | 138 | } |
127 | 139 | if (m != n) { |
128 | 140 | sh = IDR_BITS*l; |