- /* Start at exact size bucket, and search up... */
- for (b = find_free_head(tdb, start_b);
- b < TDB_FREE_BUCKETS;
- b = find_free_head(tdb, b + 1)) {
- /* Try getting one from list. */
- off = lock_and_alloc(tdb, tdb->flist_off,
- b, keylen, datalen, want_extra,
- hashlow);
- if (off == TDB_OFF_ERR)
- return TDB_OFF_ERR;
- if (off != 0)
- return off;
- /* Didn't work. Try next bucket. */
+ ftable_off = tdb->ftable_off;
+ ftable = tdb->ftable;
+ while (!wrapped || ftable_off != tdb->ftable_off) {
+ /* Start at exact size bucket, and search up... */
+ for (b = find_free_head(tdb, ftable_off, start_b);
+ b < TDB_FREE_BUCKETS;
+ b = find_free_head(tdb, ftable_off, b + 1)) {
+ /* Try getting one from list. */
+ off = lock_and_alloc(tdb, ftable_off,
+ b, keylen, datalen, want_extra,
+ magic, hashlow);
+ if (TDB_OFF_IS_ERR(off))
+ return off;
+ if (off != 0) {
+ if (b == start_b)
+ add_stat(tdb, alloc_bucket_exact, 1);
+ if (b == TDB_FREE_BUCKETS - 1)
+ add_stat(tdb, alloc_bucket_max, 1);
+ /* Worked? Stay using this list. */
+ tdb->ftable_off = ftable_off;
+ tdb->ftable = ftable;
+ return off;
+ }
+ /* Didn't work. Try next bucket. */
+ }
+
+ if (TDB_OFF_IS_ERR(b)) {
+ return b;
+ }
+
+ /* Hmm, try next table. */
+ ftable_off = next_ftable(tdb, ftable_off);
+ if (TDB_OFF_IS_ERR(ftable_off)) {
+ return ftable_off;
+ }
+ ftable++;
+
+ if (ftable_off == 0) {
+ wrapped = true;
+ ftable_off = first_ftable(tdb);
+ if (TDB_OFF_IS_ERR(ftable_off)) {
+ return ftable_off;
+ }
+ ftable = 0;
+ }