Skip to content
  • David Daney's avatar
    Staging: octeon-ethernet: Fix race freeing transmit buffers. · a620c163
    David Daney authored
    
    
    The existing code had the following race:
    
    Thread-1                       Thread-2
    
    inc/read in_use
                                   inc/read in_use
    inc tx_free_list[qos].len
                                   inc tx_free_list[qos].len
    
    The actual in_use value was incremented twice, but thread-1 is going
    to free memory based on its stale value, and will free one too many
    times.  The result is that memory is freed back to the kernel while
    its packet is still in the transmit buffer.  If the memory is
    overwritten before it is transmitted, the hardware will put a valid
    checksum on it and send it out (just like it does with good packets).
    If by chance the TCP flags are clobbered but not the addresses or
    ports, the result can be a broken TCP stream.
    
    The fix is to track the number of freed packets in a single location
    (a Fetch-and-Add Unit register).  That way it can never get out of sync
    with itself.
    
    We try to free up to MAX_SKB_TO_FREE (currently 10) buffers at a time.
    If fewer are available we adjust the free count with the difference.
    The action of claiming buffers to free is atomic so two threads cannot
    claim the same buffers.
    
    Signed-off-by: default avatarDavid Daney <ddaney@caviumnetworks.com>
    Signed-off-by: default avatarRalf Baechle <ralf@linux-mips.org>
    a620c163