struct sctp_association *, sctp_socket_type_t);
static char *sctp_hmac_alg = SCTP_COOKIE_HMAC_ALG;
+extern struct kmem_cache *sctp_bucket_cachep;
+extern int sysctl_sctp_mem[3];
+extern int sysctl_sctp_rmem[3];
+extern int sysctl_sctp_wmem[3];
+
+static int sctp_memory_pressure;
+static atomic_t sctp_memory_allocated;
+static atomic_t sctp_sockets_allocated;
+
+static void sctp_enter_memory_pressure(void)
+{
+ sctp_memory_pressure = 1;
+}
+
+
/* Get the sndbuf space available at the time on the association. */
static inline int sctp_wspace(struct sctp_association *asoc)
{
- struct sock *sk = asoc->base.sk;
- int amt = 0;
+ int amt;
- if (asoc->ep->sndbuf_policy) {
- /* make sure that no association uses more than sk_sndbuf */
- amt = sk->sk_sndbuf - asoc->sndbuf_used;
+ if (asoc->ep->sndbuf_policy)
+ amt = asoc->sndbuf_used;
+ else
+ amt = atomic_read(&asoc->base.sk->sk_wmem_alloc);
+
+ if (amt >= asoc->base.sk->sk_sndbuf) {
+ if (asoc->base.sk->sk_userlocks & SOCK_SNDBUF_LOCK)
+ amt = 0;
+ else {
+ amt = sk_stream_wspace(asoc->base.sk);
+ if (amt < 0)
+ amt = 0;
+ }
} else {
- /* do socket level accounting */
- amt = sk->sk_sndbuf - atomic_read(&sk->sk_wmem_alloc);
+ amt = asoc->base.sk->sk_sndbuf - amt;
}
-
- if (amt < 0)
- amt = 0;
-
return amt;
}
sizeof(struct sctp_chunk);
atomic_add(sizeof(struct sctp_chunk), &sk->sk_wmem_alloc);
+ sk_charge_skb(sk, chunk->skb);
}
/* Verify that this is a valid address. */
sp->hmac = NULL;
SCTP_DBG_OBJCNT_INC(sock);
+ atomic_inc(&sctp_sockets_allocated);
return 0;
}
/* Release our hold on the endpoint. */
ep = sctp_sk(sk)->ep;
sctp_endpoint_free(ep);
-
+ atomic_dec(&sctp_sockets_allocated);
return 0;
}
atomic_sub(sizeof(struct sctp_chunk), &sk->sk_wmem_alloc);
+ /*
+ * This undoes what is done via sk_charge_skb
+ */
+ sk->sk_wmem_queued -= skb->truesize;
+ sk->sk_forward_alloc += skb->truesize;
+
sock_wfree(skb);
__sctp_write_space(asoc);
struct sctp_ulpevent *event = sctp_skb2event(skb);
atomic_sub(event->rmem_len, &sk->sk_rmem_alloc);
+
+ /*
+ * Mimic the behavior of sk_stream_rfree
+ */
+ sk->sk_forward_alloc += event->rmem_len;
}
sctp_release_sock(newsk);
}
+
/* This proto struct describes the ULP interface for SCTP. */
struct proto sctp_prot = {
.name = "SCTP",
.unhash = sctp_unhash,
.get_port = sctp_get_port,
.obj_size = sizeof(struct sctp_sock),
+ .sysctl_mem = sysctl_sctp_mem,
+ .sysctl_rmem = sysctl_sctp_rmem,
+ .sysctl_wmem = sysctl_sctp_wmem,
+ .memory_pressure = &sctp_memory_pressure,
+ .enter_memory_pressure = sctp_enter_memory_pressure,
+ .memory_allocated = &sctp_memory_allocated,
};
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
.unhash = sctp_unhash,
.get_port = sctp_get_port,
.obj_size = sizeof(struct sctp6_sock),
+ .sysctl_mem = sysctl_sctp_mem,
+ .sysctl_rmem = sysctl_sctp_rmem,
+ .sysctl_wmem = sysctl_sctp_wmem,
+ .memory_pressure = &sctp_memory_pressure,
+ .enter_memory_pressure = sctp_enter_memory_pressure,
+ .memory_allocated = &sctp_memory_allocated,
};
#endif /* defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */