/** Freeing is actually easier, as we never have to worry about splitting blocks. Note that this function can only free addresses and sizes that are correctly aligned, so it's only really safe to call this with addresses returned from buddy_alloc(). We simply mark the incoming block as free, then while we are not at the top level of the tree, see if the buddy is also free. If so, we mark them both as unavailable and move up the tree one level. { */ void buddy_free(buddy_t *bd, uint64_t addr, unsigned sz) { uint64_t offs = addr - bd->start; unsigned log_sz = log2_roundup(sz); unsigned idx = offs >> log_sz; while (log_sz >= MIN_BUDDY_SZ_LOG2) { int order_idx = log_sz - MIN_BUDDY_SZ_LOG2; /* Mark this node free. */ bitmap_set(&bd->orders[order_idx], idx); /* Can we coalesce up another level? */ if (log_sz == MAX_BUDDY_SZ_LOG2) break; /* Is this node's buddy also free? */ if (bitmap_isset(&bd->orders[order_idx], BUDDY(idx)) == 0) /* no :( */ break; /* FIXME: Ensure max(this, buddy) wouldn't go over the max extent of the region. */ /* Mark them both non free. */ bitmap_clear(&bd->orders[order_idx], idx); bitmap_clear(&bd->orders[order_idx], BUDDY(idx)); /* Move up an order. */ idx = DEC_ORDER(idx); ++log_sz; } }
void buddy_free(buddy_t *bd, uint64_t addr, unsigned sz) { uint64_t offs = addr - bd->start; unsigned log_sz = log2_roundup(sz); unsigned idx = offs >> log_sz; while (log_sz >= MIN_BUDDY_SZ_LOG2) { int order_idx = log_sz - MIN_BUDDY_SZ_LOG2; // Mark node free bitmap_set(&bd->orders[order_idx], idx); // Can we coalese up another level? if (log_sz == MAX_BUDDY_SZ_LOG2) { break; } if (bitmap_isset(&bd->orders[order_idx], BUDDY(idx)) == 0) { // guess not... break; } // Mark both non-free bitmap_clear(&bd->orders[order_idx], idx); bitmap_clear(&bd->orders[order_idx], BUDDY(idx)); // Move up an order idx = DEC_ORDER(idx); log_sz++; } }