merged a bugfix for the idtree code from the Linux kernel. This
authorAndrew Tridgell <tridge@samba.org>
Tue, 30 Sep 2008 14:09:06 +0000 (07:09 -0700)
committerAndrew Tridgell <tridge@samba.org>
Tue, 30 Sep 2008 14:09:06 +0000 (07:09 -0700)
matches commit 7aae6dd80e265aa9402ed507caaff4a5dba55069 in the kernel.

Many thanks to Jim Houston for pointing out this fix to us

lib/util/idtree.c

index 6fef3d15c48eb1ea73a0a9bf0b02fc533275c61a..1b69319da5057446dc5b99baf2c1268d35a4ae91 100644 (file)
@@ -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;
                        }
-                       continue;
+
+                       /* 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;