/*
* 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?
*/
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);
#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))
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)
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 */
}
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;
/* 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;