FreeBSD / vm_map / options DIAGNOSTIC
The check walks the map's tree once, depth-first. It carries three things: cur, the entry being checked; lbound, the nearest ancestor the walk went right from; and ubound, the nearest ancestor it went left from. Every entry in the subtree under cur must lie within [lbound->end, ubound->start]; touching a bound is allowed, since neighboring entries often abut. A fourth thing, pending, holds the sides it has put off.
At the top of the tree both bounds are the header, which plays both ends at once: its end is the map's minimum address and its start is the maximum. A leaf has no children, so its links point at its in-order neighbors instead, and those neighbors are exactly the bounds: a link equal to its bound is a thread, anything else is a child.
end is the floor and its start is the ceiling, so it serves as lbound for the leftmost entries and as ubound for the rightmost ones. max_free is the largest gap in a subtree, counting the gaps to its bounds; the walk recomputes it from the two sides and compares.| Assertion | With the values at b | Result |
|---|---|---|
cur != header | b is an entry | holds |
cur->start < cur->end | 5 < 6 | holds |
lbound->end <= cur->start | header->end 0 <= 5 | holds |
cur->end <= ubound->start | 6 <= d->start 9 | holds |
left == header || left->start < cur->start | left is a: 1 < 5 | holds |
right == header || cur->start < right->start | right is c: 5 < 7 | holds |
left != header || header->right == cur | left is a, not the header | not applicable |
right != header || header->left == cur | right is c, not the header | not applicable |
max_free == max(max_left, max_right) | a is a child, so max_left = a->max_free = 3; c is a child, so max_right = c->max_free = 1; max is 3, and b->max_free is 3 | holds |
| Then the move | With the values at b | Outcome |
|---|---|---|
left != lbound and right != ubound | a is not the header, c is not d | two children: one side must wait |
left span cur->start - lbound->end | 5 - 0 = 5 | 5 < 3 is false, so the right side goes first |
right span ubound->start - cur->end | 9 - 6 = 3 | |
pending[sp] = { cur, the far bound } | { b, lbound = header } | sp becomes 2 |
| descend right | lbound = b, ubound stays d, cur = c | step 3 checks c against (b, d) |
max_free; a child side contributes the child's own max_free. The spans use the bounds, not the children, so the right side can be the smaller one even when the left child is the nearer address. Before step 1 the function also checks that header->end <= header->start (0 <= 256) and that a map with no root has both header links pointing at the header itself.| Step | cur | lbound | ubound | Links | Spans L / R | Action | Pending after |
|---|---|---|---|---|---|---|---|
| 1 | d | header | header | b child, f child | 9 / 246 | left first; push {d, header}; ubound = d | {d, header} |
| 2 | b | header | d | a child, c child | 5 / 3 | right first; push {b, header}; lbound = b | {d, header} {b, header} |
| 3 | c | b | d | b thread, d thread | pop {b, header}: 7 < 5 is false, so the left side remains; lbound = header, ubound = b, cur = a | {d, header} | |
| 4 | a | header | b | header thread (header->right == a), b thread | pop {d, header}: 1 < 9, so the right side remains; lbound = d, ubound = header, cur = f | empty | |
| 5 | f | d | header | e child, g child | 3 / 242 | left first; push {f, header}; ubound = f | {f, header} |
| 6 | e | d | f | d thread, f thread | pop {f, header}: 11 < 13, so the right side remains; lbound = f, ubound = header, cur = g | empty | |
| 7 | g | f | header | f thread, header thread (header->left == g) | nothing pending: done | empty |
cur->start with the node's start: the bounds guarantee everything under the left child is below the node and everything under the right child is above it, so that one comparison says which side was visited. The node itself becomes the near bound of the side that remains, and the saved bound returns as the far one.pending[sizeof(vm_offset_t) * NBBY] and overflow is an assertion, not a case.