+ /* Is it inside this zone? */
+ if (off < start + (1ULL << zhdr->zone_bits))
+ return start;
+
+ /* In practice, start + end won't overflow. */
+ if (off >= (start + end) / 2)
+ start = (start + end) / 2;
+ else
+ end = (start + end) / 2;
+ }
+}
+
+static tdb_off_t last_zone(struct tdb_context *tdb,
+ struct free_zone_header *zhdr)
+{
+ return off_to_zone(tdb, tdb->map_size - 1, zhdr);
+}
+
+int tdb_zone_init(struct tdb_context *tdb)
+{
+ unsigned int i;
+ uint64_t randoff = 0;
+
+ /* We start in a random zone, to spread the load. */
+ for (i = 0; i < 64; i += fls64(RAND_MAX))
+ randoff ^= ((uint64_t)random()) << i;
+ randoff = sizeof(struct tdb_header)
+ + (randoff % (tdb->map_size - sizeof(struct tdb_header)));
+
+ tdb->zone_off = off_to_zone(tdb, randoff, &tdb->zhdr);
+ if (tdb->zone_off == TDB_OFF_ERR)
+ return -1;
+ return 0;
+}
+
+/* Where's the header, given a zone size of 1 << zone_bits? */
+static tdb_off_t zone_off(tdb_off_t off, unsigned int zone_bits)
+{
+ off -= sizeof(struct tdb_header);
+ return (off & ~((1ULL << zone_bits) - 1)) + sizeof(struct tdb_header);
+}
+
+/* Offset of a given bucket. */
+/* FIXME: bucket can be "unsigned" everywhere, or even uint8/16. */
+tdb_off_t bucket_off(tdb_off_t zone_off, tdb_off_t bucket)
+{
+ return zone_off
+ + sizeof(struct free_zone_header)
+ + bucket * sizeof(tdb_off_t);