- tdb_off_t num, len, i, hoff;
-
- /* FIXME: Maybe lock more in search? Maybe don't lock if scan
- * finds none? */
-again:
- len = (1ULL << tdb->header.v.hash_bits) - (chain + 1);
- hoff = tdb->header.v.hash_off + (chain + 1) * sizeof(tdb_off_t);
- num = tdb_find_zero_off(tdb, hoff, len);
-
- /* We want to lock the zero entry, too. In the wrap case,
- * this locks one extra. That's harmless. */
- num++;
-
- for (i = chain + 1; i < chain + 1 + num; i++) {
- if (tdb_lock_list(tdb, i, F_WRLCK, TDB_LOCK_WAIT) == -1) {
- if (i != chain + 1)
- unlock_lists(tdb, chain + 1, i-1, F_WRLCK);
- return -1;
- }
- }
-
- /* The wrap case: we need those locks out of order! */
- if (unlikely(num == len + 1)) {
- *extra_locks = tdb_find_zero_off(tdb, tdb->header.v.hash_off,
- 1ULL << tdb->header.v.hash_bits);
- (*extra_locks)++;
- for (i = 0; i < *extra_locks; i++) {
- if (tdb_lock_list(tdb, i, F_WRLCK, TDB_LOCK_NOWAIT)) {
- /* Failed. Caller must lock in order. */
- if (i)
- unlock_lists(tdb, 0, i-1, F_WRLCK);
- unlock_lists(tdb, chain + 1, chain + num,
- F_WRLCK);
- return 1;
- }
- }
- num += *extra_locks;
- }
-
- /* Now we have the locks, be certain that offset is still 0! */
- hoff = tdb->header.v.hash_off
- + (((chain + num) * sizeof(tdb_off_t))
- & ((1ULL << tdb->header.v.hash_bits) - 1));
-
- if (unlikely(tdb_read_off(tdb, hoff) != 0)) {
- unlock_lists(tdb, chain + 1, chain + num, F_WRLCK);
- goto again;
- }
-
- /* OK, all locked. Unlink first one. */
- hoff = tdb->header.v.hash_off + chain * sizeof(tdb_off_t);
- if (tdb_write_off(tdb, hoff, 0) == -1)
- goto unlock_err;
-
- /* Rehash the rest. */
- for (i = 1; i < num; i++) {
- tdb_off_t off;
- uint64_t h;
-
- hoff = tdb->header.v.hash_off
- + (((chain + i) * sizeof(tdb_off_t))
- & ((1ULL << tdb->header.v.hash_bits) - 1));
- off = tdb_read_off(tdb, hoff);
- if (unlikely(off == TDB_OFF_ERR))
- goto unlock_err;
-
- /* Maybe use a bit to indicate it is in ideal place? */
- h = hash_record(tdb, off);
- /* Is it happy where it is? */
- if ((h & ((1ULL << tdb->header.v.hash_bits)-1)) == (chain + i))
- continue;