Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branch 'sctp-fix-sk_wmem_queued-and-use-it-to-check-for-writable-space'

Xin Long says:

====================
sctp: fix sk_wmem_queued and use it to check for writable space

sctp doesn't count and use asoc sndbuf_used, sk sk_wmem_alloc and
sk_wmem_queued properly, which also causes some problem.

This patchset is to improve it.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>

+17 -55
-5
include/net/sctp/constants.h
··· 148 148 #define sctp_chunk_is_data(a) (a->chunk_hdr->type == SCTP_CID_DATA || \ 149 149 a->chunk_hdr->type == SCTP_CID_I_DATA) 150 150 151 - /* Calculate the actual data size in a data chunk */ 152 - #define SCTP_DATA_SNDSIZE(c) ((int)((unsigned long)(c->chunk_end) - \ 153 - (unsigned long)(c->chunk_hdr) - \ 154 - sctp_datachk_len(&c->asoc->stream))) 155 - 156 151 /* Internal error codes */ 157 152 enum sctp_ierror { 158 153 SCTP_IERROR_NO_ERROR = 0,
+2 -6
net/sctp/outqueue.c
··· 385 385 asoc->outqueue.outstanding_bytes -= sctp_data_size(chk); 386 386 } 387 387 388 - msg_len -= SCTP_DATA_SNDSIZE(chk) + 389 - sizeof(struct sk_buff) + 390 - sizeof(struct sctp_chunk); 388 + msg_len -= chk->skb->truesize + sizeof(struct sctp_chunk); 391 389 if (msg_len <= 0) 392 390 break; 393 391 } ··· 419 421 streamout->ext->abandoned_unsent[SCTP_PR_INDEX(PRIO)]++; 420 422 } 421 423 422 - msg_len -= SCTP_DATA_SNDSIZE(chk) + 423 - sizeof(struct sk_buff) + 424 - sizeof(struct sctp_chunk); 424 + msg_len -= chk->skb->truesize + sizeof(struct sctp_chunk); 425 425 sctp_chunk_free(chk); 426 426 if (msg_len <= 0) 427 427 break;
+15 -44
net/sctp/socket.c
··· 83 83 #include <net/sctp/stream_sched.h> 84 84 85 85 /* Forward declarations for internal helper functions. */ 86 - static int sctp_writeable(struct sock *sk); 86 + static bool sctp_writeable(struct sock *sk); 87 87 static void sctp_wfree(struct sk_buff *skb); 88 88 static int sctp_wait_for_sndbuf(struct sctp_association *asoc, long *timeo_p, 89 89 size_t msg_len); ··· 119 119 /* Get the sndbuf space available at the time on the association. */ 120 120 static inline int sctp_wspace(struct sctp_association *asoc) 121 121 { 122 - int amt; 122 + struct sock *sk = asoc->base.sk; 123 123 124 - if (asoc->ep->sndbuf_policy) 125 - amt = asoc->sndbuf_used; 126 - else 127 - amt = sk_wmem_alloc_get(asoc->base.sk); 128 - 129 - if (amt >= asoc->base.sk->sk_sndbuf) { 130 - if (asoc->base.sk->sk_userlocks & SOCK_SNDBUF_LOCK) 131 - amt = 0; 132 - else { 133 - amt = sk_stream_wspace(asoc->base.sk); 134 - if (amt < 0) 135 - amt = 0; 136 - } 137 - } else { 138 - amt = asoc->base.sk->sk_sndbuf - amt; 139 - } 140 - return amt; 124 + return asoc->ep->sndbuf_policy ? sk->sk_sndbuf - asoc->sndbuf_used 125 + : sk_stream_wspace(sk); 141 126 } 142 127 143 128 /* Increment the used sndbuf space count of the corresponding association by ··· 151 166 /* Save the chunk pointer in skb for sctp_wfree to use later. */ 152 167 skb_shinfo(chunk->skb)->destructor_arg = chunk; 153 168 154 - asoc->sndbuf_used += SCTP_DATA_SNDSIZE(chunk) + 155 - sizeof(struct sk_buff) + 156 - sizeof(struct sctp_chunk); 157 - 158 169 refcount_add(sizeof(struct sctp_chunk), &sk->sk_wmem_alloc); 159 - sk->sk_wmem_queued += chunk->skb->truesize; 170 + asoc->sndbuf_used += chunk->skb->truesize + sizeof(struct sctp_chunk); 171 + sk->sk_wmem_queued += chunk->skb->truesize + sizeof(struct sctp_chunk); 160 172 sk_mem_charge(sk, chunk->skb->truesize); 161 173 } 162 174 ··· 1910 1928 asoc->pmtu_pending = 0; 1911 1929 } 1912 1930 1913 - if (sctp_wspace(asoc) < msg_len) 1931 + if (sctp_wspace(asoc) < (int)msg_len) 1914 1932 sctp_prsctp_prune(asoc, sinfo, msg_len - sctp_wspace(asoc)); 1915 1933 1916 - if (!sctp_wspace(asoc)) { 1934 + if (sctp_wspace(asoc) <= 0) { 1917 1935 timeo = sock_sndtimeo(sk, msg->msg_flags & MSG_DONTWAIT); 1918 1936 err = sctp_wait_for_sndbuf(asoc, &timeo, msg_len); 1919 1937 if (err) ··· 8442 8460 struct sctp_association *asoc = chunk->asoc; 8443 8461 struct sock *sk = asoc->base.sk; 8444 8462 8445 - asoc->sndbuf_used -= SCTP_DATA_SNDSIZE(chunk) + 8446 - sizeof(struct sk_buff) + 8447 - sizeof(struct sctp_chunk); 8448 - 8449 - WARN_ON(refcount_sub_and_test(sizeof(struct sctp_chunk), &sk->sk_wmem_alloc)); 8450 - 8451 - /* 8452 - * This undoes what is done via sctp_set_owner_w and sk_mem_charge 8453 - */ 8454 - sk->sk_wmem_queued -= skb->truesize; 8455 8463 sk_mem_uncharge(sk, skb->truesize); 8464 + sk->sk_wmem_queued -= skb->truesize + sizeof(struct sctp_chunk); 8465 + asoc->sndbuf_used -= skb->truesize + sizeof(struct sctp_chunk); 8466 + WARN_ON(refcount_sub_and_test(sizeof(struct sctp_chunk), 8467 + &sk->sk_wmem_alloc)); 8456 8468 8457 8469 if (chunk->shkey) { 8458 8470 struct sctp_shared_key *shkey = chunk->shkey; ··· 8520 8544 goto do_error; 8521 8545 if (signal_pending(current)) 8522 8546 goto do_interrupted; 8523 - if (msg_len <= sctp_wspace(asoc)) 8547 + if ((int)msg_len <= sctp_wspace(asoc)) 8524 8548 break; 8525 8549 8526 8550 /* Let another process have a go. Since we are going ··· 8595 8619 * UDP-style sockets or TCP-style sockets, this code should work. 8596 8620 * - Daisy 8597 8621 */ 8598 - static int sctp_writeable(struct sock *sk) 8622 + static bool sctp_writeable(struct sock *sk) 8599 8623 { 8600 - int amt = 0; 8601 - 8602 - amt = sk->sk_sndbuf - sk_wmem_alloc_get(sk); 8603 - if (amt < 0) 8604 - amt = 0; 8605 - return amt; 8624 + return sk->sk_sndbuf > sk->sk_wmem_queued; 8606 8625 } 8607 8626 8608 8627 /* Wait for an association to go into ESTABLISHED state. If timeout is 0,