+static void maybe_transform_uniform_page(void *pool, unsigned long offset)
+{
+ /* FIXME: If possible and page isn't full, change to a bitmap */
+}
+
+/* Returns 0 or the size of the uniform alloc to use */
+static unsigned long suitable_for_uc(unsigned long size, unsigned long align)
+{
+ unsigned long num_elems, wastage, usize;
+ unsigned long bitmap_cost;
+
+ if (size == 0)
+ size = 1;
+
+ /* Fix up silly alignments. */
+ usize = align_up(size, align);
+
+ /* How many can fit in this page? */
+ num_elems = SUBPAGE_METAOFF / usize;
+
+ /* Can happen with bigger alignments. */
+ if (!num_elems)
+ return 0;
+
+ /* Usize maxes out at 14 bits. */
+ if (usize >= (1 << 14))
+ return 0;
+
+ /* How many bytes would be left at the end? */
+ wastage = SUBPAGE_METAOFF % usize;
+
+ /* If we can get a larger allocation within alignment constraints, we
+ * should do it, otherwise might as well leave wastage at the end. */
+ usize += align_down(wastage / num_elems, align);
+
+ /* Bitmap allocation costs 2 bits per BITMAP_GRANULARITY bytes, plus
+ * however much we waste in rounding up to BITMAP_GRANULARITY. */
+ bitmap_cost = 2 * div_up(size, BITMAP_GRANULARITY)
+ + CHAR_BIT * (align_up(size, BITMAP_GRANULARITY) - size);
+
+ /* Our cost is 1 bit, plus usize overhead */
+ if (bitmap_cost < 1 + (usize - size) * CHAR_BIT)
+ return 0;
+
+ return usize;
+}
+
+static unsigned long uniform_alloc(void *pool, unsigned long poolsize,
+ struct uniform_cache *uc,
+ unsigned long ucnum)
+{
+ uint8_t *metadata = get_page_metadata(pool, uc->page[ucnum]) + 2;
+ unsigned long i, max;
+
+ /* Simple one-bit-per-object bitmap. */
+ max = SUBPAGE_METAOFF / uc->size[ucnum];
+ for (i = 0; i < max; i++) {
+ if (!(metadata[i / CHAR_BIT] & (1 << (i % CHAR_BIT)))) {
+ metadata[i / CHAR_BIT] |= (1 << (i % CHAR_BIT));
+ return uc->page[ucnum] * getpagesize()
+ + i * uc->size[ucnum];
+ }
+ }
+
+ return 0;
+}
+
+static unsigned long new_uniform_page(void *pool, unsigned long poolsize,
+ unsigned long usize)
+{
+ unsigned long page, metalen;
+ uint8_t *metadata;
+
+ page = alloc_get_pages(pool, poolsize, 1, 1);
+ if (page == 0)
+ return 0;
+
+ metalen = uniform_metalen(usize);
+
+ /* Get metadata for page. */
+ metadata = new_metadata(pool, poolsize, metalen, UNIFORM);
+ if (!metadata) {
+ alloc_free_pages(pool, page);
+ return 0;
+ }
+
+ encode_usize(metadata, usize);
+
+ BUILD_ASSERT(FREE == 0);
+ memset(metadata + 2, 0, metalen - 2);
+
+ /* Actually, this is a subpage page now. */
+ set_page_state(pool, page, SPECIAL);
+
+ /* Set metadata pointer for page. */
+ set_page_metadata(pool, page, metadata);
+
+ return page;
+}
+