diff options
Diffstat (limited to 'lib/idr.c')
-rw-r--r-- | lib/idr.c | 16 |
1 files changed, 14 insertions, 2 deletions
@@ -100,10 +100,11 @@ static int sub_alloc(struct idr *idp, void *ptr, int *starting_id) | |||
100 | int n, m, sh; | 100 | int n, m, sh; |
101 | struct idr_layer *p, *new; | 101 | struct idr_layer *p, *new; |
102 | struct idr_layer *pa[MAX_LEVEL]; | 102 | struct idr_layer *pa[MAX_LEVEL]; |
103 | int l, id; | 103 | int l, id, oid; |
104 | long bm; | 104 | long bm; |
105 | 105 | ||
106 | id = *starting_id; | 106 | id = *starting_id; |
107 | restart: | ||
107 | p = idp->top; | 108 | p = idp->top; |
108 | l = idp->layers; | 109 | l = idp->layers; |
109 | pa[l--] = NULL; | 110 | pa[l--] = NULL; |
@@ -117,12 +118,23 @@ static int sub_alloc(struct idr *idp, void *ptr, int *starting_id) | |||
117 | if (m == IDR_SIZE) { | 118 | if (m == IDR_SIZE) { |
118 | /* no space available go back to previous layer. */ | 119 | /* no space available go back to previous layer. */ |
119 | l++; | 120 | l++; |
121 | oid = id; | ||
120 | id = (id | ((1 << (IDR_BITS * l)) - 1)) + 1; | 122 | id = (id | ((1 << (IDR_BITS * l)) - 1)) + 1; |
123 | |||
124 | /* if already at the top layer, we need to grow */ | ||
121 | if (!(p = pa[l])) { | 125 | if (!(p = pa[l])) { |
122 | *starting_id = id; | 126 | *starting_id = id; |
123 | return -2; | 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 | if (m != n) { | 139 | if (m != n) { |
128 | sh = IDR_BITS*l; | 140 | sh = IDR_BITS*l; |