aboutsummaryrefslogtreecommitdiffstats
path: root/net/rds
diff options
context:
space:
mode:
authorMukesh Kacker <mukesh.kacker@oracle.com>2015-08-22 18:45:34 -0400
committerDavid S. Miller <davem@davemloft.net>2015-08-25 16:35:31 -0400
commit06e8941e22f5cbaa4051f06d7ac99e3f302f6d48 (patch)
tree4c2361bd9d0920c4f3bcd15a035592dc40d7fc5e /net/rds
parentdfcec251d22bab947d10cf37e9ad67085cf7f097 (diff)
RDS: return EMSGSIZE for oversize requests before processing/queueing
rds_send_queue_rm() allows for the "current datagram" being queued to exceed SO_SNDBUF thresholds by checking bytes queued without counting in length of current datagram. (Since sk_sndbuf is set to twice requested SO_SNDBUF value as a kernel heuristic this is usually fine!) If this "current datagram" squeezing past the threshold is itself many times the size of the sk_sndbuf threshold itself then even twice the SO_SNDBUF does not save us and it gets queued but cannot be transmitted. Threads block and deadlock and device becomes unusable. The check for this datagram not exceeding SNDBUF thresholds (EMSGSIZE) is not done on this datagram as that check is only done if queueing attempt fails. (Datagrams that follow this datagram fail queueing attempts, go through the check and eventually trip EMSGSIZE error but zero length datagrams silently fail!) This fix moves the check for datagrams exceeding SNDBUF limits before any processing or queueing is attempted and returns EMSGSIZE early in the rds_sndmsg() code. This change also ensures that all datagrams get checked for exceeding SNDBUF/sk_sndbuf size limits and the large datagrams that exceed those limits do not get to rds_send_queue_rm() code for processing. Signed-off-by: Mukesh Kacker <mukesh.kacker@oracle.com> Signed-off-by: Santosh Shilimkar <ssantosh@kernel.org> Signed-off-by: Santosh Shilimkar <santosh.shilimkar@oracle.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/rds')
-rw-r--r--net/rds/send.c11
1 files changed, 6 insertions, 5 deletions
diff --git a/net/rds/send.c b/net/rds/send.c
index b40c2ea8e89a..4df61a515b83 100644
--- a/net/rds/send.c
+++ b/net/rds/send.c
@@ -1015,6 +1015,11 @@ int rds_sendmsg(struct socket *sock, struct msghdr *msg, size_t payload_len)
1015 goto out; 1015 goto out;
1016 } 1016 }
1017 1017
1018 if (payload_len > rds_sk_sndbuf(rs)) {
1019 ret = -EMSGSIZE;
1020 goto out;
1021 }
1022
1018 /* size of rm including all sgs */ 1023 /* size of rm including all sgs */
1019 ret = rds_rm_size(msg, payload_len); 1024 ret = rds_rm_size(msg, payload_len);
1020 if (ret < 0) 1025 if (ret < 0)
@@ -1087,11 +1092,7 @@ int rds_sendmsg(struct socket *sock, struct msghdr *msg, size_t payload_len)
1087 while (!rds_send_queue_rm(rs, conn, rm, rs->rs_bound_port, 1092 while (!rds_send_queue_rm(rs, conn, rm, rs->rs_bound_port,
1088 dport, &queued)) { 1093 dport, &queued)) {
1089 rds_stats_inc(s_send_queue_full); 1094 rds_stats_inc(s_send_queue_full);
1090 /* XXX make sure this is reasonable */ 1095
1091 if (payload_len > rds_sk_sndbuf(rs)) {
1092 ret = -EMSGSIZE;
1093 goto out;
1094 }
1095 if (nonblock) { 1096 if (nonblock) {
1096 ret = -EAGAIN; 1097 ret = -EAGAIN;
1097 goto out; 1098 goto out;