|
@@ -994,6 +994,26 @@ static int rds_send_mprds_hash(struct rds_sock *rs, struct rds_connection *conn)
|
|
|
return hash;
|
|
|
}
|
|
|
|
|
|
+static int rds_rdma_bytes(struct msghdr *msg, size_t *rdma_bytes)
|
|
|
+{
|
|
|
+ struct rds_rdma_args *args;
|
|
|
+ struct cmsghdr *cmsg;
|
|
|
+
|
|
|
+ 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;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
int rds_sendmsg(struct socket *sock, struct msghdr *msg, size_t payload_len)
|
|
|
{
|
|
|
struct sock *sk = sock->sk;
|
|
@@ -1008,6 +1028,7 @@ int rds_sendmsg(struct socket *sock, struct msghdr *msg, size_t payload_len)
|
|
|
int nonblock = msg->msg_flags & MSG_DONTWAIT;
|
|
|
long timeo = sock_sndtimeo(sk, nonblock);
|
|
|
struct rds_conn_path *cpath;
|
|
|
+ size_t total_payload_len = payload_len, rdma_payload_len = 0;
|
|
|
|
|
|
/* Mirror Linux UDP mirror of BSD error message compatibility */
|
|
|
/* XXX: Perhaps MSG_MORE someday */
|
|
@@ -1040,6 +1061,16 @@ 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;
|
|
|
+
|
|
|
+ total_payload_len += rdma_payload_len;
|
|
|
+ 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;
|