From 3a0891b9a49e42d05519a2f8b33c86267eb63d35 Mon Sep 17 00:00:00 2001 From: Avinash Repaka Date: Mon, 29 Feb 2016 15:30:57 -0800 Subject: [PATCH] RDS: Make message size limit compliant with spec This patch limits RDS messages(both RDMA & non-RDMA) and RDS MR size to RDS_MAX_MSG_SIZE(1MB) irrespective of underlying transport layer. Orabug: 24455231 This patch also takes care of adding rdma payload to total payload before QoS check is done. Orabug: 22303625 Signed-off-by: Avinash Repaka Signed-off-by: Santosh Shilimkar --- net/rds/rdma.c | 10 +++++++++- net/rds/rds.h | 3 +++ net/rds/send.c | 27 ++++++++++++++++++++------- 3 files changed, 32 insertions(+), 8 deletions(-) diff --git a/net/rds/rdma.c b/net/rds/rdma.c index 37b99465ab77..9fe3bc342ef5 100644 --- a/net/rds/rdma.c +++ b/net/rds/rdma.c @@ -39,7 +39,6 @@ /* * XXX * - build with sparse - * - should we limit the size of a mr region? let transport return failure? * - should we detect duplicate keys on a socket? hmm. * - an rdma is an mlock, apply rlimit? */ @@ -200,6 +199,15 @@ static int __rds_rdma_map(struct rds_sock *rs, struct rds_get_mr_args *args, goto out; } + /* + * we restrict the size of mr irrespective of underlying transport + * To account for unaligned mr regions, we subtract one from nr_pages + */ + if ((nr_pages - 1) > (RDS_MAX_MSG_SIZE >> PAGE_SHIFT)) { + ret = -EMSGSIZE; + goto out; + } + rdsdebug("RDS: get_mr addr %llx len %llu nr_pages %u\n", args->vec.addr, args->vec.bytes, nr_pages); diff --git a/net/rds/rds.h b/net/rds/rds.h index abfa291c0296..4f1012c89363 100644 --- a/net/rds/rds.h +++ b/net/rds/rds.h @@ -99,6 +99,9 @@ enum { #define RDS_FRAG_SIZE ((unsigned int)(1 << RDS_FRAG_SHIFT)) #define RDS_MAX_FRAG_SIZE SZ_16K +/* Used to limit both RDMA and non-RDMA RDS message to 1MB */ +#define RDS_MAX_MSG_SIZE ((unsigned int)(1 << 20)) + #define RDS_CONG_MAP_BYTES (65536 / 8) #define RDS_CONG_PAGE_SIZE (1UL << 12) #define RDS_CONG_MAP_LONGS (RDS_CONG_MAP_BYTES / sizeof(unsigned long)) diff --git a/net/rds/send.c b/net/rds/send.c index 2b0888511c2e..a15759099650 100644 --- a/net/rds/send.c +++ b/net/rds/send.c @@ -1171,20 +1171,25 @@ static int rds_cmsg_send(struct rds_sock *rs, struct rds_message *rm, return ret; } -static inline unsigned int rds_rdma_bytes(struct msghdr *msg) +static inline int rds_rdma_bytes(struct msghdr *msg, size_t *rdma_bytes) { struct rds_rdma_args *args; struct cmsghdr *cmsg; - unsigned int rdma_bytes = 0; for_each_cmsghdr(cmsg, msg) { + if (!CMSG_OK(msg, cmsg)) + return -EINVAL; + + if (cmsg->cmsg_level != SOL_RDS) + continue; + if (cmsg->cmsg_type == RDS_CMSG_RDMA_ARGS) { args = CMSG_DATA(cmsg); - rdma_bytes += args->remote_vec.bytes; + *rdma_bytes += args->remote_vec.bytes; } } - return rdma_bytes; + return 0; } int rds_sendmsg(struct socket *sock, struct msghdr *msg, size_t payload_len) @@ -1200,7 +1205,7 @@ int rds_sendmsg(struct socket *sock, struct msghdr *msg, size_t payload_len) int queued = 0, allocated_mr = 0; int nonblock = msg->msg_flags & MSG_DONTWAIT; long timeo = sock_sndtimeo(sk, nonblock); - size_t total_payload_len = payload_len; + size_t total_payload_len = payload_len, rdma_payload_len = 0; bool large_page; /* Mirror Linux UDP mirror of BSD error message compatibility */ @@ -1236,6 +1241,15 @@ int rds_sendmsg(struct socket *sock, struct msghdr *msg, size_t payload_len) } release_sock(sk); + ret = rds_rdma_bytes(msg, &rdma_payload_len); + if (ret) + goto out; + + if (max_t(size_t, payload_len, rdma_payload_len) > RDS_MAX_MSG_SIZE) { + ret = -EMSGSIZE; + goto out; + } + if (payload_len > rds_sk_sndbuf(rs)) { ret = -EMSGSIZE; goto out; @@ -1267,8 +1281,7 @@ int rds_sendmsg(struct socket *sock, struct msghdr *msg, size_t payload_len) /* For RDMA operation(s), add up rmda bytes to payload to make * sure its within system QoS threshold limits. */ - if (rm->rdma.op_active) - total_payload_len += rds_rdma_bytes(msg); + total_payload_len += rdma_payload_len; if (rds_check_qos_threshold(rs->rs_tos, total_payload_len)) { ret = -EINVAL; -- 2.50.1