summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Tridgell <tridge@samba.org>2008-09-30 07:14:31 -0700
committerAndrew Tridgell <tridge@samba.org>2008-09-30 07:14:31 -0700
commit717b36c672441f8cd86bf550ab0fabc52a3a3821 (patch)
tree18f8f1f8519afc156aa11b4c4d595e097df7a3a5
parentd87e9ba56b00962be6b797464e77619bc6f0ba2c (diff)
downloadsamba-717b36c672441f8cd86bf550ab0fabc52a3a3821.tar.gz
samba-717b36c672441f8cd86bf550ab0fabc52a3a3821.tar.bz2
samba-717b36c672441f8cd86bf550ab0fabc52a3a3821.zip
merged a bugfix for the idtree code from the Linux kernel. This
matches commit 7aae6dd80e265aa9402ed507caaff4a5dba55069 in the kernel. Many thanks to Jim Houston for pointing out this fix to us
-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;