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

sctp: introduce struct sctp_stream_out_ext

With the stream schedulers, sctp_stream_out will become too big to be
allocated by kmalloc and as we need to allocate with BH disabled, we
cannot use __vmalloc in sctp_stream_init().

This patch moves out the stats from sctp_stream_out to
sctp_stream_out_ext, which will be allocated only when the application
tries to sendmsg something on it.

Just the introduction of sctp_stream_out_ext would already fix the issue
described above by splitting the allocation in two. Moving the stats
to it also reduces the pressure on the allocator as we will ask for less
memory atomically when creating the socket and we will use GFP_KERNEL
later.

Then, for stream schedulers, we will just use sctp_stream_out_ext.
Tested-by: default avatarXin Long <lucien.xin@gmail.com>
Signed-off-by: default avatarMarcelo Ricardo Leitner <marcelo.leitner@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 1fdb8d8f
...@@ -84,6 +84,7 @@ struct sctp_ulpq; ...@@ -84,6 +84,7 @@ struct sctp_ulpq;
struct sctp_ep_common; struct sctp_ep_common;
struct crypto_shash; struct crypto_shash;
struct sctp_stream; struct sctp_stream;
struct sctp_stream_out;
#include <net/sctp/tsnmap.h> #include <net/sctp/tsnmap.h>
...@@ -380,6 +381,7 @@ struct sctp_sender_hb_info { ...@@ -380,6 +381,7 @@ struct sctp_sender_hb_info {
int sctp_stream_init(struct sctp_stream *stream, __u16 outcnt, __u16 incnt, int sctp_stream_init(struct sctp_stream *stream, __u16 outcnt, __u16 incnt,
gfp_t gfp); gfp_t gfp);
int sctp_stream_init_ext(struct sctp_stream *stream, __u16 sid);
void sctp_stream_free(struct sctp_stream *stream); void sctp_stream_free(struct sctp_stream *stream);
void sctp_stream_clear(struct sctp_stream *stream); void sctp_stream_clear(struct sctp_stream *stream);
void sctp_stream_update(struct sctp_stream *stream, struct sctp_stream *new); void sctp_stream_update(struct sctp_stream *stream, struct sctp_stream *new);
...@@ -1315,11 +1317,15 @@ struct sctp_inithdr_host { ...@@ -1315,11 +1317,15 @@ struct sctp_inithdr_host {
__u32 initial_tsn; __u32 initial_tsn;
}; };
struct sctp_stream_out_ext {
__u64 abandoned_unsent[SCTP_PR_INDEX(MAX) + 1];
__u64 abandoned_sent[SCTP_PR_INDEX(MAX) + 1];
};
struct sctp_stream_out { struct sctp_stream_out {
__u16 ssn; __u16 ssn;
__u8 state; __u8 state;
__u64 abandoned_unsent[SCTP_PR_INDEX(MAX) + 1]; struct sctp_stream_out_ext *ext;
__u64 abandoned_sent[SCTP_PR_INDEX(MAX) + 1];
}; };
struct sctp_stream_in { struct sctp_stream_in {
......
...@@ -311,10 +311,10 @@ int sctp_chunk_abandoned(struct sctp_chunk *chunk) ...@@ -311,10 +311,10 @@ int sctp_chunk_abandoned(struct sctp_chunk *chunk)
if (chunk->sent_count) { if (chunk->sent_count) {
chunk->asoc->abandoned_sent[SCTP_PR_INDEX(TTL)]++; chunk->asoc->abandoned_sent[SCTP_PR_INDEX(TTL)]++;
streamout->abandoned_sent[SCTP_PR_INDEX(TTL)]++; streamout->ext->abandoned_sent[SCTP_PR_INDEX(TTL)]++;
} else { } else {
chunk->asoc->abandoned_unsent[SCTP_PR_INDEX(TTL)]++; chunk->asoc->abandoned_unsent[SCTP_PR_INDEX(TTL)]++;
streamout->abandoned_unsent[SCTP_PR_INDEX(TTL)]++; streamout->ext->abandoned_unsent[SCTP_PR_INDEX(TTL)]++;
} }
return 1; return 1;
} else if (SCTP_PR_RTX_ENABLED(chunk->sinfo.sinfo_flags) && } else if (SCTP_PR_RTX_ENABLED(chunk->sinfo.sinfo_flags) &&
...@@ -323,7 +323,7 @@ int sctp_chunk_abandoned(struct sctp_chunk *chunk) ...@@ -323,7 +323,7 @@ int sctp_chunk_abandoned(struct sctp_chunk *chunk)
&chunk->asoc->stream.out[chunk->sinfo.sinfo_stream]; &chunk->asoc->stream.out[chunk->sinfo.sinfo_stream];
chunk->asoc->abandoned_sent[SCTP_PR_INDEX(RTX)]++; chunk->asoc->abandoned_sent[SCTP_PR_INDEX(RTX)]++;
streamout->abandoned_sent[SCTP_PR_INDEX(RTX)]++; streamout->ext->abandoned_sent[SCTP_PR_INDEX(RTX)]++;
return 1; return 1;
} else if (!SCTP_PR_POLICY(chunk->sinfo.sinfo_flags) && } else if (!SCTP_PR_POLICY(chunk->sinfo.sinfo_flags) &&
chunk->msg->expires_at && chunk->msg->expires_at &&
......
...@@ -366,7 +366,7 @@ static int sctp_prsctp_prune_sent(struct sctp_association *asoc, ...@@ -366,7 +366,7 @@ static int sctp_prsctp_prune_sent(struct sctp_association *asoc,
streamout = &asoc->stream.out[chk->sinfo.sinfo_stream]; streamout = &asoc->stream.out[chk->sinfo.sinfo_stream];
asoc->sent_cnt_removable--; asoc->sent_cnt_removable--;
asoc->abandoned_sent[SCTP_PR_INDEX(PRIO)]++; asoc->abandoned_sent[SCTP_PR_INDEX(PRIO)]++;
streamout->abandoned_sent[SCTP_PR_INDEX(PRIO)]++; streamout->ext->abandoned_sent[SCTP_PR_INDEX(PRIO)]++;
if (!chk->tsn_gap_acked) { if (!chk->tsn_gap_acked) {
if (chk->transport) if (chk->transport)
...@@ -404,7 +404,7 @@ static int sctp_prsctp_prune_unsent(struct sctp_association *asoc, ...@@ -404,7 +404,7 @@ static int sctp_prsctp_prune_unsent(struct sctp_association *asoc,
struct sctp_stream_out *streamout = struct sctp_stream_out *streamout =
&asoc->stream.out[chk->sinfo.sinfo_stream]; &asoc->stream.out[chk->sinfo.sinfo_stream];
streamout->abandoned_unsent[SCTP_PR_INDEX(PRIO)]++; streamout->ext->abandoned_unsent[SCTP_PR_INDEX(PRIO)]++;
} }
msg_len -= SCTP_DATA_SNDSIZE(chk) + msg_len -= SCTP_DATA_SNDSIZE(chk) +
......
...@@ -1927,6 +1927,13 @@ static int sctp_sendmsg(struct sock *sk, struct msghdr *msg, size_t msg_len) ...@@ -1927,6 +1927,13 @@ static int sctp_sendmsg(struct sock *sk, struct msghdr *msg, size_t msg_len)
goto out_free; goto out_free;
} }
/* Allocate sctp_stream_out_ext if not already done */
if (unlikely(!asoc->stream.out[sinfo->sinfo_stream].ext)) {
err = sctp_stream_init_ext(&asoc->stream, sinfo->sinfo_stream);
if (err)
goto out_free;
}
if (sctp_wspace(asoc) < msg_len) if (sctp_wspace(asoc) < msg_len)
sctp_prsctp_prune(asoc, sinfo, msg_len - sctp_wspace(asoc)); sctp_prsctp_prune(asoc, sinfo, msg_len - sctp_wspace(asoc));
...@@ -6645,7 +6652,7 @@ static int sctp_getsockopt_pr_streamstatus(struct sock *sk, int len, ...@@ -6645,7 +6652,7 @@ static int sctp_getsockopt_pr_streamstatus(struct sock *sk, int len,
char __user *optval, char __user *optval,
int __user *optlen) int __user *optlen)
{ {
struct sctp_stream_out *streamout; struct sctp_stream_out_ext *streamoute;
struct sctp_association *asoc; struct sctp_association *asoc;
struct sctp_prstatus params; struct sctp_prstatus params;
int retval = -EINVAL; int retval = -EINVAL;
...@@ -6668,21 +6675,29 @@ static int sctp_getsockopt_pr_streamstatus(struct sock *sk, int len, ...@@ -6668,21 +6675,29 @@ static int sctp_getsockopt_pr_streamstatus(struct sock *sk, int len,
if (!asoc || params.sprstat_sid >= asoc->stream.outcnt) if (!asoc || params.sprstat_sid >= asoc->stream.outcnt)
goto out; goto out;
streamout = &asoc->stream.out[params.sprstat_sid]; streamoute = asoc->stream.out[params.sprstat_sid].ext;
if (!streamoute) {
/* Not allocated yet, means all stats are 0 */
params.sprstat_abandoned_unsent = 0;
params.sprstat_abandoned_sent = 0;
retval = 0;
goto out;
}
if (policy == SCTP_PR_SCTP_NONE) { if (policy == SCTP_PR_SCTP_NONE) {
params.sprstat_abandoned_unsent = 0; params.sprstat_abandoned_unsent = 0;
params.sprstat_abandoned_sent = 0; params.sprstat_abandoned_sent = 0;
for (policy = 0; policy <= SCTP_PR_INDEX(MAX); policy++) { for (policy = 0; policy <= SCTP_PR_INDEX(MAX); policy++) {
params.sprstat_abandoned_unsent += params.sprstat_abandoned_unsent +=
streamout->abandoned_unsent[policy]; streamoute->abandoned_unsent[policy];
params.sprstat_abandoned_sent += params.sprstat_abandoned_sent +=
streamout->abandoned_sent[policy]; streamoute->abandoned_sent[policy];
} }
} else { } else {
params.sprstat_abandoned_unsent = params.sprstat_abandoned_unsent =
streamout->abandoned_unsent[__SCTP_PR_INDEX(policy)]; streamoute->abandoned_unsent[__SCTP_PR_INDEX(policy)];
params.sprstat_abandoned_sent = params.sprstat_abandoned_sent =
streamout->abandoned_sent[__SCTP_PR_INDEX(policy)]; streamoute->abandoned_sent[__SCTP_PR_INDEX(policy)];
} }
if (put_user(len, optlen) || copy_to_user(optval, &params, len)) { if (put_user(len, optlen) || copy_to_user(optval, &params, len)) {
......
...@@ -121,8 +121,24 @@ int sctp_stream_init(struct sctp_stream *stream, __u16 outcnt, __u16 incnt, ...@@ -121,8 +121,24 @@ int sctp_stream_init(struct sctp_stream *stream, __u16 outcnt, __u16 incnt,
return 0; return 0;
} }
int sctp_stream_init_ext(struct sctp_stream *stream, __u16 sid)
{
struct sctp_stream_out_ext *soute;
soute = kzalloc(sizeof(*soute), GFP_KERNEL);
if (!soute)
return -ENOMEM;
stream->out[sid].ext = soute;
return 0;
}
void sctp_stream_free(struct sctp_stream *stream) void sctp_stream_free(struct sctp_stream *stream)
{ {
int i;
for (i = 0; i < stream->outcnt; i++)
kfree(stream->out[i].ext);
kfree(stream->out); kfree(stream->out);
kfree(stream->in); kfree(stream->in);
} }
......
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