Commit cea8768f authored by Marcelo Ricardo Leitner's avatar Marcelo Ricardo Leitner Committed by David S. Miller

sctp: allow sctp_transmit_packet and others to use gfp

Currently sctp_sendmsg() triggers some calls that will allocate memory
with GFP_ATOMIC even when not necessary. In the case of
sctp_packet_transmit it will allocate a linear skb that will be used to
construct the packet and this may cause sends to fail due to ENOMEM more
often than anticipated specially with big MTUs.

This patch thus allows it to inherit gfp flags from upper calls so that
it can use GFP_KERNEL if it was triggered by a sctp_sendmsg call or
similar. All others, like retransmits or flushes started from BH, are
still allocated using GFP_ATOMIC.

In netperf tests this didn't result in any performance drawbacks when
memory is not too fragmented and made it trigger ENOMEM way less often.
Signed-off-by: default avatarMarcelo Ricardo Leitner <marcelo.leitner@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 6f15cdbf
...@@ -201,7 +201,7 @@ struct sctp_chunk *sctp_make_cwr(const struct sctp_association *, ...@@ -201,7 +201,7 @@ struct sctp_chunk *sctp_make_cwr(const struct sctp_association *,
struct sctp_chunk * sctp_make_datafrag_empty(struct sctp_association *, struct sctp_chunk * sctp_make_datafrag_empty(struct sctp_association *,
const struct sctp_sndrcvinfo *sinfo, const struct sctp_sndrcvinfo *sinfo,
int len, const __u8 flags, int len, const __u8 flags,
__u16 ssn); __u16 ssn, gfp_t gfp);
struct sctp_chunk *sctp_make_ecne(const struct sctp_association *, struct sctp_chunk *sctp_make_ecne(const struct sctp_association *,
const __u32); const __u32);
struct sctp_chunk *sctp_make_sack(const struct sctp_association *); struct sctp_chunk *sctp_make_sack(const struct sctp_association *);
......
...@@ -655,7 +655,7 @@ void sctp_chunk_free(struct sctp_chunk *); ...@@ -655,7 +655,7 @@ void sctp_chunk_free(struct sctp_chunk *);
void *sctp_addto_chunk(struct sctp_chunk *, int len, const void *data); void *sctp_addto_chunk(struct sctp_chunk *, int len, const void *data);
struct sctp_chunk *sctp_chunkify(struct sk_buff *, struct sctp_chunk *sctp_chunkify(struct sk_buff *,
const struct sctp_association *, const struct sctp_association *,
struct sock *); struct sock *, gfp_t gfp);
void sctp_init_addrs(struct sctp_chunk *, union sctp_addr *, void sctp_init_addrs(struct sctp_chunk *, union sctp_addr *,
union sctp_addr *); union sctp_addr *);
const union sctp_addr *sctp_source(const struct sctp_chunk *chunk); const union sctp_addr *sctp_source(const struct sctp_chunk *chunk);
...@@ -717,10 +717,10 @@ struct sctp_packet *sctp_packet_init(struct sctp_packet *, ...@@ -717,10 +717,10 @@ struct sctp_packet *sctp_packet_init(struct sctp_packet *,
__u16 sport, __u16 dport); __u16 sport, __u16 dport);
struct sctp_packet *sctp_packet_config(struct sctp_packet *, __u32 vtag, int); struct sctp_packet *sctp_packet_config(struct sctp_packet *, __u32 vtag, int);
sctp_xmit_t sctp_packet_transmit_chunk(struct sctp_packet *, sctp_xmit_t sctp_packet_transmit_chunk(struct sctp_packet *,
struct sctp_chunk *, int); struct sctp_chunk *, int, gfp_t);
sctp_xmit_t sctp_packet_append_chunk(struct sctp_packet *, sctp_xmit_t sctp_packet_append_chunk(struct sctp_packet *,
struct sctp_chunk *); struct sctp_chunk *);
int sctp_packet_transmit(struct sctp_packet *); int sctp_packet_transmit(struct sctp_packet *, gfp_t);
void sctp_packet_free(struct sctp_packet *); void sctp_packet_free(struct sctp_packet *);
static inline int sctp_packet_empty(struct sctp_packet *packet) static inline int sctp_packet_empty(struct sctp_packet *packet)
...@@ -1053,7 +1053,7 @@ struct sctp_outq { ...@@ -1053,7 +1053,7 @@ struct sctp_outq {
void sctp_outq_init(struct sctp_association *, struct sctp_outq *); void sctp_outq_init(struct sctp_association *, struct sctp_outq *);
void sctp_outq_teardown(struct sctp_outq *); void sctp_outq_teardown(struct sctp_outq *);
void sctp_outq_free(struct sctp_outq*); void sctp_outq_free(struct sctp_outq*);
int sctp_outq_tail(struct sctp_outq *, struct sctp_chunk *chunk); int sctp_outq_tail(struct sctp_outq *, struct sctp_chunk *chunk, gfp_t);
int sctp_outq_sack(struct sctp_outq *, struct sctp_chunk *); int sctp_outq_sack(struct sctp_outq *, struct sctp_chunk *);
int sctp_outq_is_empty(const struct sctp_outq *); int sctp_outq_is_empty(const struct sctp_outq *);
void sctp_outq_restart(struct sctp_outq *); void sctp_outq_restart(struct sctp_outq *);
...@@ -1061,7 +1061,7 @@ void sctp_outq_restart(struct sctp_outq *); ...@@ -1061,7 +1061,7 @@ void sctp_outq_restart(struct sctp_outq *);
void sctp_retransmit(struct sctp_outq *, struct sctp_transport *, void sctp_retransmit(struct sctp_outq *, struct sctp_transport *,
sctp_retransmit_reason_t); sctp_retransmit_reason_t);
void sctp_retransmit_mark(struct sctp_outq *, struct sctp_transport *, __u8); void sctp_retransmit_mark(struct sctp_outq *, struct sctp_transport *, __u8);
int sctp_outq_uncork(struct sctp_outq *); int sctp_outq_uncork(struct sctp_outq *, gfp_t gfp);
/* Uncork and flush an outqueue. */ /* Uncork and flush an outqueue. */
static inline void sctp_outq_cork(struct sctp_outq *q) static inline void sctp_outq_cork(struct sctp_outq *q)
{ {
......
...@@ -1493,7 +1493,7 @@ void sctp_assoc_rwnd_increase(struct sctp_association *asoc, unsigned int len) ...@@ -1493,7 +1493,7 @@ void sctp_assoc_rwnd_increase(struct sctp_association *asoc, unsigned int len)
asoc->peer.sack_needed = 0; asoc->peer.sack_needed = 0;
sctp_outq_tail(&asoc->outqueue, sack); sctp_outq_tail(&asoc->outqueue, sack, GFP_ATOMIC);
/* Stop the SACK timer. */ /* Stop the SACK timer. */
timer = &asoc->timers[SCTP_EVENT_TIMEOUT_SACK]; timer = &asoc->timers[SCTP_EVENT_TIMEOUT_SACK];
......
...@@ -260,7 +260,8 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc, ...@@ -260,7 +260,8 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc,
frag |= SCTP_DATA_SACK_IMM; frag |= SCTP_DATA_SACK_IMM;
} }
chunk = sctp_make_datafrag_empty(asoc, sinfo, len, frag, 0); chunk = sctp_make_datafrag_empty(asoc, sinfo, len, frag,
0, GFP_KERNEL);
if (!chunk) { if (!chunk) {
err = -ENOMEM; err = -ENOMEM;
...@@ -296,7 +297,8 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc, ...@@ -296,7 +297,8 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc,
(sinfo->sinfo_flags & SCTP_SACK_IMMEDIATELY)) (sinfo->sinfo_flags & SCTP_SACK_IMMEDIATELY))
frag |= SCTP_DATA_SACK_IMM; frag |= SCTP_DATA_SACK_IMM;
chunk = sctp_make_datafrag_empty(asoc, sinfo, over, frag, 0); chunk = sctp_make_datafrag_empty(asoc, sinfo, over, frag,
0, GFP_KERNEL);
if (!chunk) { if (!chunk) {
err = -ENOMEM; err = -ENOMEM;
......
...@@ -221,7 +221,7 @@ int sctp_rcv(struct sk_buff *skb) ...@@ -221,7 +221,7 @@ int sctp_rcv(struct sk_buff *skb)
goto discard_release; goto discard_release;
/* Create an SCTP packet structure. */ /* Create an SCTP packet structure. */
chunk = sctp_chunkify(skb, asoc, sk); chunk = sctp_chunkify(skb, asoc, sk, GFP_ATOMIC);
if (!chunk) if (!chunk)
goto discard_release; goto discard_release;
SCTP_INPUT_CB(skb)->chunk = chunk; SCTP_INPUT_CB(skb)->chunk = chunk;
......
...@@ -153,7 +153,7 @@ void sctp_packet_free(struct sctp_packet *packet) ...@@ -153,7 +153,7 @@ void sctp_packet_free(struct sctp_packet *packet)
*/ */
sctp_xmit_t sctp_packet_transmit_chunk(struct sctp_packet *packet, sctp_xmit_t sctp_packet_transmit_chunk(struct sctp_packet *packet,
struct sctp_chunk *chunk, struct sctp_chunk *chunk,
int one_packet) int one_packet, gfp_t gfp)
{ {
sctp_xmit_t retval; sctp_xmit_t retval;
int error = 0; int error = 0;
...@@ -163,7 +163,7 @@ sctp_xmit_t sctp_packet_transmit_chunk(struct sctp_packet *packet, ...@@ -163,7 +163,7 @@ sctp_xmit_t sctp_packet_transmit_chunk(struct sctp_packet *packet,
switch ((retval = (sctp_packet_append_chunk(packet, chunk)))) { switch ((retval = (sctp_packet_append_chunk(packet, chunk)))) {
case SCTP_XMIT_PMTU_FULL: case SCTP_XMIT_PMTU_FULL:
if (!packet->has_cookie_echo) { if (!packet->has_cookie_echo) {
error = sctp_packet_transmit(packet); error = sctp_packet_transmit(packet, gfp);
if (error < 0) if (error < 0)
chunk->skb->sk->sk_err = -error; chunk->skb->sk->sk_err = -error;
...@@ -376,7 +376,7 @@ static void sctp_packet_set_owner_w(struct sk_buff *skb, struct sock *sk) ...@@ -376,7 +376,7 @@ static void sctp_packet_set_owner_w(struct sk_buff *skb, struct sock *sk)
* *
* The return value is a normal kernel error return value. * The return value is a normal kernel error return value.
*/ */
int sctp_packet_transmit(struct sctp_packet *packet) int sctp_packet_transmit(struct sctp_packet *packet, gfp_t gfp)
{ {
struct sctp_transport *tp = packet->transport; struct sctp_transport *tp = packet->transport;
struct sctp_association *asoc = tp->asoc; struct sctp_association *asoc = tp->asoc;
......
...@@ -68,7 +68,7 @@ static void sctp_mark_missing(struct sctp_outq *q, ...@@ -68,7 +68,7 @@ static void sctp_mark_missing(struct sctp_outq *q,
static void sctp_generate_fwdtsn(struct sctp_outq *q, __u32 sack_ctsn); static void sctp_generate_fwdtsn(struct sctp_outq *q, __u32 sack_ctsn);
static int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout); static int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout, gfp_t gfp);
/* Add data to the front of the queue. */ /* Add data to the front of the queue. */
static inline void sctp_outq_head_data(struct sctp_outq *q, static inline void sctp_outq_head_data(struct sctp_outq *q,
...@@ -285,7 +285,7 @@ void sctp_outq_free(struct sctp_outq *q) ...@@ -285,7 +285,7 @@ void sctp_outq_free(struct sctp_outq *q)
} }
/* Put a new chunk in an sctp_outq. */ /* Put a new chunk in an sctp_outq. */
int sctp_outq_tail(struct sctp_outq *q, struct sctp_chunk *chunk) int sctp_outq_tail(struct sctp_outq *q, struct sctp_chunk *chunk, gfp_t gfp)
{ {
struct net *net = sock_net(q->asoc->base.sk); struct net *net = sock_net(q->asoc->base.sk);
int error = 0; int error = 0;
...@@ -341,7 +341,7 @@ int sctp_outq_tail(struct sctp_outq *q, struct sctp_chunk *chunk) ...@@ -341,7 +341,7 @@ int sctp_outq_tail(struct sctp_outq *q, struct sctp_chunk *chunk)
return error; return error;
if (!q->cork) if (!q->cork)
error = sctp_outq_flush(q, 0); error = sctp_outq_flush(q, 0, gfp);
return error; return error;
} }
...@@ -510,7 +510,7 @@ void sctp_retransmit(struct sctp_outq *q, struct sctp_transport *transport, ...@@ -510,7 +510,7 @@ void sctp_retransmit(struct sctp_outq *q, struct sctp_transport *transport,
* will be flushed at the end. * will be flushed at the end.
*/ */
if (reason != SCTP_RTXR_FAST_RTX) if (reason != SCTP_RTXR_FAST_RTX)
error = sctp_outq_flush(q, /* rtx_timeout */ 1); error = sctp_outq_flush(q, /* rtx_timeout */ 1, GFP_ATOMIC);
if (error) if (error)
q->asoc->base.sk->sk_err = -error; q->asoc->base.sk->sk_err = -error;
...@@ -601,12 +601,12 @@ static int sctp_outq_flush_rtx(struct sctp_outq *q, struct sctp_packet *pkt, ...@@ -601,12 +601,12 @@ static int sctp_outq_flush_rtx(struct sctp_outq *q, struct sctp_packet *pkt,
* control chunks are already freed so there * control chunks are already freed so there
* is nothing we can do. * is nothing we can do.
*/ */
sctp_packet_transmit(pkt); sctp_packet_transmit(pkt, GFP_ATOMIC);
goto redo; goto redo;
} }
/* Send this packet. */ /* Send this packet. */
error = sctp_packet_transmit(pkt); error = sctp_packet_transmit(pkt, GFP_ATOMIC);
/* If we are retransmitting, we should only /* If we are retransmitting, we should only
* send a single packet. * send a single packet.
...@@ -622,7 +622,7 @@ static int sctp_outq_flush_rtx(struct sctp_outq *q, struct sctp_packet *pkt, ...@@ -622,7 +622,7 @@ static int sctp_outq_flush_rtx(struct sctp_outq *q, struct sctp_packet *pkt,
case SCTP_XMIT_RWND_FULL: case SCTP_XMIT_RWND_FULL:
/* Send this packet. */ /* Send this packet. */
error = sctp_packet_transmit(pkt); error = sctp_packet_transmit(pkt, GFP_ATOMIC);
/* Stop sending DATA as there is no more room /* Stop sending DATA as there is no more room
* at the receiver. * at the receiver.
...@@ -632,7 +632,7 @@ static int sctp_outq_flush_rtx(struct sctp_outq *q, struct sctp_packet *pkt, ...@@ -632,7 +632,7 @@ static int sctp_outq_flush_rtx(struct sctp_outq *q, struct sctp_packet *pkt,
case SCTP_XMIT_DELAY: case SCTP_XMIT_DELAY:
/* Send this packet. */ /* Send this packet. */
error = sctp_packet_transmit(pkt); error = sctp_packet_transmit(pkt, GFP_ATOMIC);
/* Stop sending DATA because of nagle delay. */ /* Stop sending DATA because of nagle delay. */
done = 1; done = 1;
...@@ -685,12 +685,12 @@ static int sctp_outq_flush_rtx(struct sctp_outq *q, struct sctp_packet *pkt, ...@@ -685,12 +685,12 @@ static int sctp_outq_flush_rtx(struct sctp_outq *q, struct sctp_packet *pkt,
} }
/* Cork the outqueue so queued chunks are really queued. */ /* Cork the outqueue so queued chunks are really queued. */
int sctp_outq_uncork(struct sctp_outq *q) int sctp_outq_uncork(struct sctp_outq *q, gfp_t gfp)
{ {
if (q->cork) if (q->cork)
q->cork = 0; q->cork = 0;
return sctp_outq_flush(q, 0); return sctp_outq_flush(q, 0, gfp);
} }
...@@ -703,7 +703,7 @@ int sctp_outq_uncork(struct sctp_outq *q) ...@@ -703,7 +703,7 @@ int sctp_outq_uncork(struct sctp_outq *q)
* locking concerns must be made. Today we use the sock lock to protect * locking concerns must be made. Today we use the sock lock to protect
* this function. * this function.
*/ */
static int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout) static int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout, gfp_t gfp)
{ {
struct sctp_packet *packet; struct sctp_packet *packet;
struct sctp_packet singleton; struct sctp_packet singleton;
...@@ -825,7 +825,7 @@ static int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout) ...@@ -825,7 +825,7 @@ static int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
sctp_packet_init(&singleton, transport, sport, dport); sctp_packet_init(&singleton, transport, sport, dport);
sctp_packet_config(&singleton, vtag, 0); sctp_packet_config(&singleton, vtag, 0);
sctp_packet_append_chunk(&singleton, chunk); sctp_packet_append_chunk(&singleton, chunk);
error = sctp_packet_transmit(&singleton); error = sctp_packet_transmit(&singleton, gfp);
if (error < 0) if (error < 0)
return error; return error;
break; break;
...@@ -856,7 +856,7 @@ static int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout) ...@@ -856,7 +856,7 @@ static int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
case SCTP_CID_ASCONF: case SCTP_CID_ASCONF:
case SCTP_CID_FWD_TSN: case SCTP_CID_FWD_TSN:
status = sctp_packet_transmit_chunk(packet, chunk, status = sctp_packet_transmit_chunk(packet, chunk,
one_packet); one_packet, gfp);
if (status != SCTP_XMIT_OK) { if (status != SCTP_XMIT_OK) {
/* put the chunk back */ /* put the chunk back */
list_add(&chunk->list, &q->control_chunk_list); list_add(&chunk->list, &q->control_chunk_list);
...@@ -1011,7 +1011,7 @@ static int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout) ...@@ -1011,7 +1011,7 @@ static int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
atomic_read(&chunk->skb->users) : -1); atomic_read(&chunk->skb->users) : -1);
/* Add the chunk to the packet. */ /* Add the chunk to the packet. */
status = sctp_packet_transmit_chunk(packet, chunk, 0); status = sctp_packet_transmit_chunk(packet, chunk, 0, gfp);
switch (status) { switch (status) {
case SCTP_XMIT_PMTU_FULL: case SCTP_XMIT_PMTU_FULL:
...@@ -1088,7 +1088,7 @@ static int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout) ...@@ -1088,7 +1088,7 @@ static int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
send_ready); send_ready);
packet = &t->packet; packet = &t->packet;
if (!sctp_packet_empty(packet)) if (!sctp_packet_empty(packet))
error = sctp_packet_transmit(packet); error = sctp_packet_transmit(packet, gfp);
/* Clear the burst limited state, if any */ /* Clear the burst limited state, if any */
sctp_transport_burst_reset(t); sctp_transport_burst_reset(t);
......
...@@ -62,11 +62,13 @@ ...@@ -62,11 +62,13 @@
#include <net/sctp/sm.h> #include <net/sctp/sm.h>
static struct sctp_chunk *sctp_make_control(const struct sctp_association *asoc, static struct sctp_chunk *sctp_make_control(const struct sctp_association *asoc,
__u8 type, __u8 flags, int paylen); __u8 type, __u8 flags, int paylen,
gfp_t gfp);
static struct sctp_chunk *sctp_make_data(const struct sctp_association *asoc, static struct sctp_chunk *sctp_make_data(const struct sctp_association *asoc,
__u8 flags, int paylen); __u8 flags, int paylen, gfp_t gfp);
static struct sctp_chunk *_sctp_make_chunk(const struct sctp_association *asoc, static struct sctp_chunk *_sctp_make_chunk(const struct sctp_association *asoc,
__u8 type, __u8 flags, int paylen); __u8 type, __u8 flags, int paylen,
gfp_t gfp);
static sctp_cookie_param_t *sctp_pack_cookie(const struct sctp_endpoint *ep, static sctp_cookie_param_t *sctp_pack_cookie(const struct sctp_endpoint *ep,
const struct sctp_association *asoc, const struct sctp_association *asoc,
const struct sctp_chunk *init_chunk, const struct sctp_chunk *init_chunk,
...@@ -318,7 +320,7 @@ struct sctp_chunk *sctp_make_init(const struct sctp_association *asoc, ...@@ -318,7 +320,7 @@ struct sctp_chunk *sctp_make_init(const struct sctp_association *asoc,
* PLEASE DO NOT FIXME [This version does not support Host Name.] * PLEASE DO NOT FIXME [This version does not support Host Name.]
*/ */
retval = sctp_make_control(asoc, SCTP_CID_INIT, 0, chunksize); retval = sctp_make_control(asoc, SCTP_CID_INIT, 0, chunksize, gfp);
if (!retval) if (!retval)
goto nodata; goto nodata;
...@@ -465,7 +467,7 @@ struct sctp_chunk *sctp_make_init_ack(const struct sctp_association *asoc, ...@@ -465,7 +467,7 @@ struct sctp_chunk *sctp_make_init_ack(const struct sctp_association *asoc,
num_ext); num_ext);
/* Now allocate and fill out the chunk. */ /* Now allocate and fill out the chunk. */
retval = sctp_make_control(asoc, SCTP_CID_INIT_ACK, 0, chunksize); retval = sctp_make_control(asoc, SCTP_CID_INIT_ACK, 0, chunksize, gfp);
if (!retval) if (!retval)
goto nomem_chunk; goto nomem_chunk;
...@@ -570,7 +572,8 @@ struct sctp_chunk *sctp_make_cookie_echo(const struct sctp_association *asoc, ...@@ -570,7 +572,8 @@ struct sctp_chunk *sctp_make_cookie_echo(const struct sctp_association *asoc,
cookie_len = asoc->peer.cookie_len; cookie_len = asoc->peer.cookie_len;
/* Build a cookie echo chunk. */ /* Build a cookie echo chunk. */
retval = sctp_make_control(asoc, SCTP_CID_COOKIE_ECHO, 0, cookie_len); retval = sctp_make_control(asoc, SCTP_CID_COOKIE_ECHO, 0,
cookie_len, GFP_ATOMIC);
if (!retval) if (!retval)
goto nodata; goto nodata;
retval->subh.cookie_hdr = retval->subh.cookie_hdr =
...@@ -615,7 +618,7 @@ struct sctp_chunk *sctp_make_cookie_ack(const struct sctp_association *asoc, ...@@ -615,7 +618,7 @@ struct sctp_chunk *sctp_make_cookie_ack(const struct sctp_association *asoc,
{ {
struct sctp_chunk *retval; struct sctp_chunk *retval;
retval = sctp_make_control(asoc, SCTP_CID_COOKIE_ACK, 0, 0); retval = sctp_make_control(asoc, SCTP_CID_COOKIE_ACK, 0, 0, GFP_ATOMIC);
/* RFC 2960 6.4 Multi-homed SCTP Endpoints /* RFC 2960 6.4 Multi-homed SCTP Endpoints
* *
...@@ -664,7 +667,7 @@ struct sctp_chunk *sctp_make_cwr(const struct sctp_association *asoc, ...@@ -664,7 +667,7 @@ struct sctp_chunk *sctp_make_cwr(const struct sctp_association *asoc,
cwr.lowest_tsn = htonl(lowest_tsn); cwr.lowest_tsn = htonl(lowest_tsn);
retval = sctp_make_control(asoc, SCTP_CID_ECN_CWR, 0, retval = sctp_make_control(asoc, SCTP_CID_ECN_CWR, 0,
sizeof(sctp_cwrhdr_t)); sizeof(sctp_cwrhdr_t), GFP_ATOMIC);
if (!retval) if (!retval)
goto nodata; goto nodata;
...@@ -698,7 +701,7 @@ struct sctp_chunk *sctp_make_ecne(const struct sctp_association *asoc, ...@@ -698,7 +701,7 @@ struct sctp_chunk *sctp_make_ecne(const struct sctp_association *asoc,
ecne.lowest_tsn = htonl(lowest_tsn); ecne.lowest_tsn = htonl(lowest_tsn);
retval = sctp_make_control(asoc, SCTP_CID_ECN_ECNE, 0, retval = sctp_make_control(asoc, SCTP_CID_ECN_ECNE, 0,
sizeof(sctp_ecnehdr_t)); sizeof(sctp_ecnehdr_t), GFP_ATOMIC);
if (!retval) if (!retval)
goto nodata; goto nodata;
retval->subh.ecne_hdr = retval->subh.ecne_hdr =
...@@ -713,7 +716,8 @@ struct sctp_chunk *sctp_make_ecne(const struct sctp_association *asoc, ...@@ -713,7 +716,8 @@ struct sctp_chunk *sctp_make_ecne(const struct sctp_association *asoc,
*/ */
struct sctp_chunk *sctp_make_datafrag_empty(struct sctp_association *asoc, struct sctp_chunk *sctp_make_datafrag_empty(struct sctp_association *asoc,
const struct sctp_sndrcvinfo *sinfo, const struct sctp_sndrcvinfo *sinfo,
int data_len, __u8 flags, __u16 ssn) int data_len, __u8 flags, __u16 ssn,
gfp_t gfp)
{ {
struct sctp_chunk *retval; struct sctp_chunk *retval;
struct sctp_datahdr dp; struct sctp_datahdr dp;
...@@ -734,7 +738,7 @@ struct sctp_chunk *sctp_make_datafrag_empty(struct sctp_association *asoc, ...@@ -734,7 +738,7 @@ struct sctp_chunk *sctp_make_datafrag_empty(struct sctp_association *asoc,
dp.ssn = htons(ssn); dp.ssn = htons(ssn);
chunk_len = sizeof(dp) + data_len; chunk_len = sizeof(dp) + data_len;
retval = sctp_make_data(asoc, flags, chunk_len); retval = sctp_make_data(asoc, flags, chunk_len, gfp);
if (!retval) if (!retval)
goto nodata; goto nodata;
...@@ -781,7 +785,7 @@ struct sctp_chunk *sctp_make_sack(const struct sctp_association *asoc) ...@@ -781,7 +785,7 @@ struct sctp_chunk *sctp_make_sack(const struct sctp_association *asoc)
+ sizeof(__u32) * num_dup_tsns; + sizeof(__u32) * num_dup_tsns;
/* Create the chunk. */ /* Create the chunk. */
retval = sctp_make_control(asoc, SCTP_CID_SACK, 0, len); retval = sctp_make_control(asoc, SCTP_CID_SACK, 0, len, GFP_ATOMIC);
if (!retval) if (!retval)
goto nodata; goto nodata;
...@@ -861,7 +865,7 @@ struct sctp_chunk *sctp_make_shutdown(const struct sctp_association *asoc, ...@@ -861,7 +865,7 @@ struct sctp_chunk *sctp_make_shutdown(const struct sctp_association *asoc,
shut.cum_tsn_ack = htonl(ctsn); shut.cum_tsn_ack = htonl(ctsn);
retval = sctp_make_control(asoc, SCTP_CID_SHUTDOWN, 0, retval = sctp_make_control(asoc, SCTP_CID_SHUTDOWN, 0,
sizeof(sctp_shutdownhdr_t)); sizeof(sctp_shutdownhdr_t), GFP_ATOMIC);
if (!retval) if (!retval)
goto nodata; goto nodata;
...@@ -879,7 +883,8 @@ struct sctp_chunk *sctp_make_shutdown_ack(const struct sctp_association *asoc, ...@@ -879,7 +883,8 @@ struct sctp_chunk *sctp_make_shutdown_ack(const struct sctp_association *asoc,
{ {
struct sctp_chunk *retval; struct sctp_chunk *retval;
retval = sctp_make_control(asoc, SCTP_CID_SHUTDOWN_ACK, 0, 0); retval = sctp_make_control(asoc, SCTP_CID_SHUTDOWN_ACK, 0, 0,
GFP_ATOMIC);
/* RFC 2960 6.4 Multi-homed SCTP Endpoints /* RFC 2960 6.4 Multi-homed SCTP Endpoints
* *
...@@ -908,7 +913,8 @@ struct sctp_chunk *sctp_make_shutdown_complete( ...@@ -908,7 +913,8 @@ struct sctp_chunk *sctp_make_shutdown_complete(
*/ */
flags |= asoc ? 0 : SCTP_CHUNK_FLAG_T; flags |= asoc ? 0 : SCTP_CHUNK_FLAG_T;
retval = sctp_make_control(asoc, SCTP_CID_SHUTDOWN_COMPLETE, flags, 0); retval = sctp_make_control(asoc, SCTP_CID_SHUTDOWN_COMPLETE, flags,
0, GFP_ATOMIC);
/* RFC 2960 6.4 Multi-homed SCTP Endpoints /* RFC 2960 6.4 Multi-homed SCTP Endpoints
* *
...@@ -947,7 +953,8 @@ struct sctp_chunk *sctp_make_abort(const struct sctp_association *asoc, ...@@ -947,7 +953,8 @@ struct sctp_chunk *sctp_make_abort(const struct sctp_association *asoc,
flags = SCTP_CHUNK_FLAG_T; flags = SCTP_CHUNK_FLAG_T;
} }
retval = sctp_make_control(asoc, SCTP_CID_ABORT, flags, hint); retval = sctp_make_control(asoc, SCTP_CID_ABORT, flags, hint,
GFP_ATOMIC);
/* RFC 2960 6.4 Multi-homed SCTP Endpoints /* RFC 2960 6.4 Multi-homed SCTP Endpoints
* *
...@@ -1139,7 +1146,8 @@ struct sctp_chunk *sctp_make_heartbeat(const struct sctp_association *asoc, ...@@ -1139,7 +1146,8 @@ struct sctp_chunk *sctp_make_heartbeat(const struct sctp_association *asoc,
struct sctp_chunk *retval; struct sctp_chunk *retval;
sctp_sender_hb_info_t hbinfo; sctp_sender_hb_info_t hbinfo;
retval = sctp_make_control(asoc, SCTP_CID_HEARTBEAT, 0, sizeof(hbinfo)); retval = sctp_make_control(asoc, SCTP_CID_HEARTBEAT, 0,
sizeof(hbinfo), GFP_ATOMIC);
if (!retval) if (!retval)
goto nodata; goto nodata;
...@@ -1167,7 +1175,8 @@ struct sctp_chunk *sctp_make_heartbeat_ack(const struct sctp_association *asoc, ...@@ -1167,7 +1175,8 @@ struct sctp_chunk *sctp_make_heartbeat_ack(const struct sctp_association *asoc,
{ {
struct sctp_chunk *retval; struct sctp_chunk *retval;
retval = sctp_make_control(asoc, SCTP_CID_HEARTBEAT_ACK, 0, paylen); retval = sctp_make_control(asoc, SCTP_CID_HEARTBEAT_ACK, 0, paylen,
GFP_ATOMIC);
if (!retval) if (!retval)
goto nodata; goto nodata;
...@@ -1200,7 +1209,7 @@ static struct sctp_chunk *sctp_make_op_error_space( ...@@ -1200,7 +1209,7 @@ static struct sctp_chunk *sctp_make_op_error_space(
struct sctp_chunk *retval; struct sctp_chunk *retval;
retval = sctp_make_control(asoc, SCTP_CID_ERROR, 0, retval = sctp_make_control(asoc, SCTP_CID_ERROR, 0,
sizeof(sctp_errhdr_t) + size); sizeof(sctp_errhdr_t) + size, GFP_ATOMIC);
if (!retval) if (!retval)
goto nodata; goto nodata;
...@@ -1271,7 +1280,8 @@ struct sctp_chunk *sctp_make_auth(const struct sctp_association *asoc) ...@@ -1271,7 +1280,8 @@ struct sctp_chunk *sctp_make_auth(const struct sctp_association *asoc)
return NULL; return NULL;
retval = sctp_make_control(asoc, SCTP_CID_AUTH, 0, retval = sctp_make_control(asoc, SCTP_CID_AUTH, 0,
hmac_desc->hmac_len + sizeof(sctp_authhdr_t)); hmac_desc->hmac_len + sizeof(sctp_authhdr_t),
GFP_ATOMIC);
if (!retval) if (!retval)
return NULL; return NULL;
...@@ -1309,11 +1319,11 @@ struct sctp_chunk *sctp_make_auth(const struct sctp_association *asoc) ...@@ -1309,11 +1319,11 @@ struct sctp_chunk *sctp_make_auth(const struct sctp_association *asoc)
*/ */
struct sctp_chunk *sctp_chunkify(struct sk_buff *skb, struct sctp_chunk *sctp_chunkify(struct sk_buff *skb,
const struct sctp_association *asoc, const struct sctp_association *asoc,
struct sock *sk) struct sock *sk, gfp_t gfp)
{ {
struct sctp_chunk *retval; struct sctp_chunk *retval;
retval = kmem_cache_zalloc(sctp_chunk_cachep, GFP_ATOMIC); retval = kmem_cache_zalloc(sctp_chunk_cachep, gfp);
if (!retval) if (!retval)
goto nodata; goto nodata;
...@@ -1361,7 +1371,8 @@ const union sctp_addr *sctp_source(const struct sctp_chunk *chunk) ...@@ -1361,7 +1371,8 @@ const union sctp_addr *sctp_source(const struct sctp_chunk *chunk)
* arguments, reserving enough space for a 'paylen' byte payload. * arguments, reserving enough space for a 'paylen' byte payload.
*/ */
static struct sctp_chunk *_sctp_make_chunk(const struct sctp_association *asoc, static struct sctp_chunk *_sctp_make_chunk(const struct sctp_association *asoc,
__u8 type, __u8 flags, int paylen) __u8 type, __u8 flags, int paylen,
gfp_t gfp)
{ {
struct sctp_chunk *retval; struct sctp_chunk *retval;
sctp_chunkhdr_t *chunk_hdr; sctp_chunkhdr_t *chunk_hdr;
...@@ -1369,8 +1380,7 @@ static struct sctp_chunk *_sctp_make_chunk(const struct sctp_association *asoc, ...@@ -1369,8 +1380,7 @@ static struct sctp_chunk *_sctp_make_chunk(const struct sctp_association *asoc,
struct sock *sk; struct sock *sk;
/* No need to allocate LL here, as this is only a chunk. */ /* No need to allocate LL here, as this is only a chunk. */
skb = alloc_skb(WORD_ROUND(sizeof(sctp_chunkhdr_t) + paylen), skb = alloc_skb(WORD_ROUND(sizeof(sctp_chunkhdr_t) + paylen), gfp);
GFP_ATOMIC);
if (!skb) if (!skb)
goto nodata; goto nodata;
...@@ -1381,7 +1391,7 @@ static struct sctp_chunk *_sctp_make_chunk(const struct sctp_association *asoc, ...@@ -1381,7 +1391,7 @@ static struct sctp_chunk *_sctp_make_chunk(const struct sctp_association *asoc,
chunk_hdr->length = htons(sizeof(sctp_chunkhdr_t)); chunk_hdr->length = htons(sizeof(sctp_chunkhdr_t));
sk = asoc ? asoc->base.sk : NULL; sk = asoc ? asoc->base.sk : NULL;
retval = sctp_chunkify(skb, asoc, sk); retval = sctp_chunkify(skb, asoc, sk, gfp);
if (!retval) { if (!retval) {
kfree_skb(skb); kfree_skb(skb);
goto nodata; goto nodata;
...@@ -1400,16 +1410,18 @@ static struct sctp_chunk *_sctp_make_chunk(const struct sctp_association *asoc, ...@@ -1400,16 +1410,18 @@ static struct sctp_chunk *_sctp_make_chunk(const struct sctp_association *asoc,
} }
static struct sctp_chunk *sctp_make_data(const struct sctp_association *asoc, static struct sctp_chunk *sctp_make_data(const struct sctp_association *asoc,
__u8 flags, int paylen) __u8 flags, int paylen, gfp_t gfp)
{ {
return _sctp_make_chunk(asoc, SCTP_CID_DATA, flags, paylen); return _sctp_make_chunk(asoc, SCTP_CID_DATA, flags, paylen, gfp);
} }
static struct sctp_chunk *sctp_make_control(const struct sctp_association *asoc, static struct sctp_chunk *sctp_make_control(const struct sctp_association *asoc,
__u8 type, __u8 flags, int paylen) __u8 type, __u8 flags, int paylen,
gfp_t gfp)
{ {
struct sctp_chunk *chunk = _sctp_make_chunk(asoc, type, flags, paylen); struct sctp_chunk *chunk;
chunk = _sctp_make_chunk(asoc, type, flags, paylen, gfp);
if (chunk) if (chunk)
sctp_control_set_owner_w(chunk); sctp_control_set_owner_w(chunk);
...@@ -2756,7 +2768,8 @@ static struct sctp_chunk *sctp_make_asconf(struct sctp_association *asoc, ...@@ -2756,7 +2768,8 @@ static struct sctp_chunk *sctp_make_asconf(struct sctp_association *asoc,
length += addrlen; length += addrlen;
/* Create the chunk. */ /* Create the chunk. */
retval = sctp_make_control(asoc, SCTP_CID_ASCONF, 0, length); retval = sctp_make_control(asoc, SCTP_CID_ASCONF, 0, length,
GFP_ATOMIC);
if (!retval) if (!retval)
return NULL; return NULL;
...@@ -2940,7 +2953,8 @@ static struct sctp_chunk *sctp_make_asconf_ack(const struct sctp_association *as ...@@ -2940,7 +2953,8 @@ static struct sctp_chunk *sctp_make_asconf_ack(const struct sctp_association *as
int length = sizeof(asconf) + vparam_len; int length = sizeof(asconf) + vparam_len;
/* Create the chunk. */ /* Create the chunk. */
retval = sctp_make_control(asoc, SCTP_CID_ASCONF_ACK, 0, length); retval = sctp_make_control(asoc, SCTP_CID_ASCONF_ACK, 0, length,
GFP_ATOMIC);
if (!retval) if (!retval)
return NULL; return NULL;
...@@ -3500,7 +3514,7 @@ struct sctp_chunk *sctp_make_fwdtsn(const struct sctp_association *asoc, ...@@ -3500,7 +3514,7 @@ struct sctp_chunk *sctp_make_fwdtsn(const struct sctp_association *asoc,
hint = (nstreams + 1) * sizeof(__u32); hint = (nstreams + 1) * sizeof(__u32);
retval = sctp_make_control(asoc, SCTP_CID_FWD_TSN, 0, hint); retval = sctp_make_control(asoc, SCTP_CID_FWD_TSN, 0, hint, GFP_ATOMIC);
if (!retval) if (!retval)
return NULL; return NULL;
......
...@@ -1019,13 +1019,13 @@ static void sctp_cmd_t1_timer_update(struct sctp_association *asoc, ...@@ -1019,13 +1019,13 @@ static void sctp_cmd_t1_timer_update(struct sctp_association *asoc,
* encouraged for small fragments. * encouraged for small fragments.
*/ */
static int sctp_cmd_send_msg(struct sctp_association *asoc, static int sctp_cmd_send_msg(struct sctp_association *asoc,
struct sctp_datamsg *msg) struct sctp_datamsg *msg, gfp_t gfp)
{ {
struct sctp_chunk *chunk; struct sctp_chunk *chunk;
int error = 0; int error = 0;
list_for_each_entry(chunk, &msg->chunks, frag_list) { list_for_each_entry(chunk, &msg->chunks, frag_list) {
error = sctp_outq_tail(&asoc->outqueue, chunk); error = sctp_outq_tail(&asoc->outqueue, chunk, gfp);
if (error) if (error)
break; break;
} }
...@@ -1249,7 +1249,7 @@ static int sctp_cmd_interpreter(sctp_event_t event_type, ...@@ -1249,7 +1249,7 @@ static int sctp_cmd_interpreter(sctp_event_t event_type,
case SCTP_CMD_NEW_ASOC: case SCTP_CMD_NEW_ASOC:
/* Register a new association. */ /* Register a new association. */
if (local_cork) { if (local_cork) {
sctp_outq_uncork(&asoc->outqueue); sctp_outq_uncork(&asoc->outqueue, gfp);
local_cork = 0; local_cork = 0;
} }
...@@ -1269,7 +1269,7 @@ static int sctp_cmd_interpreter(sctp_event_t event_type, ...@@ -1269,7 +1269,7 @@ static int sctp_cmd_interpreter(sctp_event_t event_type,
case SCTP_CMD_DELETE_TCB: case SCTP_CMD_DELETE_TCB:
if (local_cork) { if (local_cork) {
sctp_outq_uncork(&asoc->outqueue); sctp_outq_uncork(&asoc->outqueue, gfp);
local_cork = 0; local_cork = 0;
} }
/* Delete the current association. */ /* Delete the current association. */
...@@ -1423,13 +1423,14 @@ static int sctp_cmd_interpreter(sctp_event_t event_type, ...@@ -1423,13 +1423,14 @@ static int sctp_cmd_interpreter(sctp_event_t event_type,
local_cork = 1; local_cork = 1;
} }
/* Send a chunk to our peer. */ /* Send a chunk to our peer. */
error = sctp_outq_tail(&asoc->outqueue, cmd->obj.chunk); error = sctp_outq_tail(&asoc->outqueue, cmd->obj.chunk,
gfp);
break; break;
case SCTP_CMD_SEND_PKT: case SCTP_CMD_SEND_PKT:
/* Send a full packet to our peer. */ /* Send a full packet to our peer. */
packet = cmd->obj.packet; packet = cmd->obj.packet;
sctp_packet_transmit(packet); sctp_packet_transmit(packet, gfp);
sctp_ootb_pkt_free(packet); sctp_ootb_pkt_free(packet);
break; break;
...@@ -1639,7 +1640,7 @@ static int sctp_cmd_interpreter(sctp_event_t event_type, ...@@ -1639,7 +1640,7 @@ static int sctp_cmd_interpreter(sctp_event_t event_type,
*/ */
chunk->pdiscard = 1; chunk->pdiscard = 1;
if (asoc) { if (asoc) {
sctp_outq_uncork(&asoc->outqueue); sctp_outq_uncork(&asoc->outqueue, gfp);
local_cork = 0; local_cork = 0;
} }
break; break;
...@@ -1677,7 +1678,7 @@ static int sctp_cmd_interpreter(sctp_event_t event_type, ...@@ -1677,7 +1678,7 @@ static int sctp_cmd_interpreter(sctp_event_t event_type,
case SCTP_CMD_FORCE_PRIM_RETRAN: case SCTP_CMD_FORCE_PRIM_RETRAN:
t = asoc->peer.retran_path; t = asoc->peer.retran_path;
asoc->peer.retran_path = asoc->peer.primary_path; asoc->peer.retran_path = asoc->peer.primary_path;
error = sctp_outq_uncork(&asoc->outqueue); error = sctp_outq_uncork(&asoc->outqueue, gfp);
local_cork = 0; local_cork = 0;
asoc->peer.retran_path = t; asoc->peer.retran_path = t;
break; break;
...@@ -1704,7 +1705,7 @@ static int sctp_cmd_interpreter(sctp_event_t event_type, ...@@ -1704,7 +1705,7 @@ static int sctp_cmd_interpreter(sctp_event_t event_type,
sctp_outq_cork(&asoc->outqueue); sctp_outq_cork(&asoc->outqueue);
local_cork = 1; local_cork = 1;
} }
error = sctp_cmd_send_msg(asoc, cmd->obj.msg); error = sctp_cmd_send_msg(asoc, cmd->obj.msg, gfp);
break; break;
case SCTP_CMD_SEND_NEXT_ASCONF: case SCTP_CMD_SEND_NEXT_ASCONF:
sctp_cmd_send_asconf(asoc); sctp_cmd_send_asconf(asoc);
...@@ -1734,9 +1735,9 @@ static int sctp_cmd_interpreter(sctp_event_t event_type, ...@@ -1734,9 +1735,9 @@ static int sctp_cmd_interpreter(sctp_event_t event_type,
*/ */
if (asoc && SCTP_EVENT_T_CHUNK == event_type && chunk) { if (asoc && SCTP_EVENT_T_CHUNK == event_type && chunk) {
if (chunk->end_of_packet || chunk->singleton) if (chunk->end_of_packet || chunk->singleton)
error = sctp_outq_uncork(&asoc->outqueue); error = sctp_outq_uncork(&asoc->outqueue, gfp);
} else if (local_cork) } else if (local_cork)
error = sctp_outq_uncork(&asoc->outqueue); error = sctp_outq_uncork(&asoc->outqueue, gfp);
return error; return error;
nomem: nomem:
error = -ENOMEM; error = -ENOMEM;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment