• Thomas Graf's avatar
    sctp: Don't charge for data in sndbuf again when transmitting packet · 4c3a5bda
    Thomas Graf authored
    SCTP charges wmem_alloc via sctp_set_owner_w() in sctp_sendmsg() and via
    skb_set_owner_w() in sctp_packet_transmit(). If a sender runs out of
    sndbuf it will sleep in sctp_wait_for_sndbuf() and expects to be waken up
    by __sctp_write_space().
    
    Buffer space charged via sctp_set_owner_w() is released in sctp_wfree()
    which calls __sctp_write_space() directly.
    
    Buffer space charged via skb_set_owner_w() is released via sock_wfree()
    which calls sk->sk_write_space() _if_ SOCK_USE_WRITE_QUEUE is not set.
    sctp_endpoint_init() sets SOCK_USE_WRITE_QUEUE on all sockets.
    
    Therefore if sctp_packet_transmit() manages to queue up more than sndbuf
    bytes, sctp_wait_for_sndbuf() will never be woken up again unless it is
    interrupted by a signal.
    
    This could be fixed by clearing the SOCK_USE_WRITE_QUEUE flag but ...
    
    Charging for the data twice does not make sense in the first place, it
    leads to overcharging sndbuf by a factor 2. Therefore this patch only
    charges a single byte in wmem_alloc when transmitting an SCTP packet to
    ensure that the socket stays alive until the packet has been released.
    
    This means that control chunks are no longer accounted for in wmem_alloc
    which I believe is not a problem as skb->truesize will typically lead
    to overcharging anyway and thus compensates for any control overhead.
    Signed-off-by: default avatarThomas Graf <tgraf@suug.ch>
    CC: Vlad Yasevich <vyasevic@redhat.com>
    CC: Neil Horman <nhorman@tuxdriver.com>
    CC: David Miller <davem@davemloft.net>
    Acked-by: default avatarVlad Yasevich <vyasevich@gmail.com>
    Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
    4c3a5bda
output.c 22.9 KB