diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/sctp/endpointola.c | 1 | ||||
-rw-r--r-- | net/sctp/protocol.c | 3 | ||||
-rw-r--r-- | net/sctp/socket.c | 36 | ||||
-rw-r--r-- | net/sctp/sysctl.c | 8 |
4 files changed, 43 insertions, 5 deletions
diff --git a/net/sctp/endpointola.c b/net/sctp/endpointola.c index 544b750..334f617 100644 --- a/net/sctp/endpointola.c +++ b/net/sctp/endpointola.c @@ -125,6 +125,7 @@ static struct sctp_endpoint *sctp_endpoint_init(struct sctp_endpoint *ep, sp->autoclose * HZ; /* Use SCTP specific send buffer space queues. */ + ep->sndbuf_policy = sctp_sndbuf_policy; sk->sk_write_space = sctp_write_space; sock_set_flag(sk, SOCK_USE_WRITE_QUEUE); diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index 23c85a2..2e1f9c3 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -1043,6 +1043,9 @@ SCTP_STATIC __init int sctp_init(void) sctp_max_retrans_path = 5; sctp_max_retrans_init = 8; + /* Sendbuffer growth - do per-socket accounting */ + sctp_sndbuf_policy = 0; + /* HB.interval - 30 seconds */ sctp_hb_interval = 30 * HZ; diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 32f2249..0b338ec 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -115,9 +115,17 @@ static inline int sctp_wspace(struct sctp_association *asoc) struct sock *sk = asoc->base.sk; int amt = 0; - amt = sk->sk_sndbuf - asoc->sndbuf_used; + if (asoc->ep->sndbuf_policy) { + /* make sure that no association uses more than sk_sndbuf */ + amt = sk->sk_sndbuf - asoc->sndbuf_used; + } else { + /* do socket level accounting */ + amt = sk->sk_sndbuf - atomic_read(&sk->sk_wmem_alloc); + } + if (amt < 0) amt = 0; + return amt; } @@ -138,12 +146,21 @@ static inline void sctp_set_owner_w(struct sctp_chunk *chunk) /* The sndbuf space is tracked per association. */ sctp_association_hold(asoc); + skb_set_owner_w(chunk->skb, sk); + chunk->skb->destructor = sctp_wfree; /* Save the chunk pointer in skb for sctp_wfree to use later. */ *((struct sctp_chunk **)(chunk->skb->cb)) = chunk; - asoc->sndbuf_used += SCTP_DATA_SNDSIZE(chunk); - sk->sk_wmem_queued += SCTP_DATA_SNDSIZE(chunk); + asoc->sndbuf_used += SCTP_DATA_SNDSIZE(chunk) + + sizeof(struct sk_buff) + + sizeof(struct sctp_chunk); + + sk->sk_wmem_queued += SCTP_DATA_SNDSIZE(chunk) + + sizeof(struct sk_buff) + + sizeof(struct sctp_chunk); + + atomic_add(sizeof(struct sctp_chunk), &sk->sk_wmem_alloc); } /* Verify that this is a valid address. */ @@ -4422,8 +4439,17 @@ static void sctp_wfree(struct sk_buff *skb) chunk = *((struct sctp_chunk **)(skb->cb)); asoc = chunk->asoc; sk = asoc->base.sk; - asoc->sndbuf_used -= SCTP_DATA_SNDSIZE(chunk); - sk->sk_wmem_queued -= SCTP_DATA_SNDSIZE(chunk); + asoc->sndbuf_used -= SCTP_DATA_SNDSIZE(chunk) + + sizeof(struct sk_buff) + + sizeof(struct sctp_chunk); + + sk->sk_wmem_queued -= SCTP_DATA_SNDSIZE(chunk) + + sizeof(struct sk_buff) + + sizeof(struct sctp_chunk); + + atomic_sub(sizeof(struct sctp_chunk), &sk->sk_wmem_alloc); + + sock_wfree(skb); __sctp_write_space(asoc); sctp_association_put(asoc); diff --git a/net/sctp/sysctl.c b/net/sctp/sysctl.c index 89fa20c..7fc3184 100644 --- a/net/sctp/sysctl.c +++ b/net/sctp/sysctl.c @@ -110,6 +110,14 @@ static ctl_table sctp_table[] = { .proc_handler = &proc_dointvec }, { + .ctl_name = NET_SCTP_SNDBUF_POLICY, + .procname = "sndbuf_policy", + .data = &sctp_sndbuf_policy, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec + }, + { .ctl_name = NET_SCTP_PATH_MAX_RETRANS, .procname = "path_max_retrans", .data = &sctp_max_retrans_path, |