summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source4/lib/util/idtree.c14
1 files changed, 13 insertions, 1 deletions
diff --git a/source4/lib/util/idtree.c b/source4/lib/util/idtree.c
index 1e2cc2976a..392f4e81f8 100644
--- a/source4/lib/util/idtree.c
+++ b/source4/lib/util/idtree.c
@@ -105,12 +105,13 @@ static int sub_alloc(struct idr_context *idp, void *ptr, int *starting_id)
int n, m, sh;
struct idr_layer *p, *new;
struct idr_layer *pa[MAX_LEVEL];
- int l, id;
+ int l, id, oid;
uint32_t bm;
memset(pa, 0, sizeof(pa));
id = *starting_id;
+restart:
p = idp->top;
l = idp->layers;
pa[l--] = NULL;
@@ -124,12 +125,23 @@ static int sub_alloc(struct idr_context *idp, void *ptr, int *starting_id)
if (m == IDR_SIZE) {
/* no space available go back to previous layer. */
l++;
+ oid = id;
id = (id | ((1 << (IDR_BITS*l))-1)) + 1;
+
+ /* if already at the top layer, we need to grow */
if (!(p = pa[l])) {
*starting_id = id;
return -2;
}
+
+ /* If we need to go up one layer, continue the
+ * loop; otherwise, restart from the top.
+ */
+ sh = IDR_BITS * (l + 1);
+ if (oid >> sh == id >> sh)
continue;
+ else
+ goto restart;
}
if (m != n) {
sh = IDR_BITS*l;