Prior to commit 0c511bafdd5b309505c13c8dc7c6816686d1e103, each time
snl_realloc_msg_buffer was called, it called snl_allocz to request a
new buffer. If an existing linear buffer was used, then after the
call, the linear buffer effectively contained the old buffer contents
followed by the new buffer (so there was definitely wasted memory),
but the linear buffer state was consistent (lb->offset correctly
accounted for both copies). For example, if the initial linear buffer
was 256 bytes in size, lb->size would be 256. Using 16 bytes followed
by 32 bytes would first set lb->offset to 16, then the second realloc
would allocate 48 bytes (16 + 32) setting lb->offset to 64 (16 + 48).
Commit 0c511bafdd5b309505c13c8dc7c6816686d1e103 aimed to avoid this
memory waste by resetting the base pointer to the start of the
existing linear buffer if the new allocation was later in the same
linear buffer. This avoided some of the waste, but actually broke the
accounting. Using the same example above, the second realloc would
reuse the pointer at an offset of 0, but the linear buffer would still
claim that 64 bytes was allocated via lb->offset rather than the true
allocation of 48 bytes.
One approach would be to add some code to "extend" the allocation of
an existing linear buffer (the #if 0'd code in the diff) where a
realloc would try to increase lb->offset without setting a new base
pointer so long as there was still room remaining in the linear buffer
for the new request.
However, this change takes a simpler tack. If snl_allocz() returned
an allocation from a new linear buffer, just claim the entire linear
buffer for use by the snl_writer ensuring the accounting is correct in
both the linear buffer and the snl writer. With this approach, the
initial snl_writer size would be 256 bytes for a 256 byte linear
buffer and would only grow if it needs to allocate an entirely new
linear buffer.
Fixes: 0c511bafdd5b ("netlink: fix snl_writer and linear_buffer re-allocation logic")
Sponsored by: AFRL, DARPA