diff options
author | Andrew Tridgell <tridge@samba.org> | 2008-09-30 07:14:31 -0700 |
---|---|---|
committer | Andrew Tridgell <tridge@samba.org> | 2008-09-30 07:14:31 -0700 |
commit | 717b36c672441f8cd86bf550ab0fabc52a3a3821 (patch) | |
tree | 18f8f1f8519afc156aa11b4c4d595e097df7a3a5 /source4/lib | |
parent | d87e9ba56b00962be6b797464e77619bc6f0ba2c (diff) | |
download | samba-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
Diffstat (limited to 'source4/lib')
-rw-r--r-- | source4/lib/util/idtree.c | 14 |
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; |