|
|
@@ -876,13 +876,15 @@ out:
|
|
|
* rds_message is getting to be quite complicated, and we'd like to allocate
|
|
|
* it all in one go. This figures out how big it needs to be up front.
|
|
|
*/
|
|
|
-static int rds_rm_size(struct msghdr *msg, int num_sgs)
|
|
|
+static int rds_rm_size(struct msghdr *msg, int num_sgs,
|
|
|
+ struct rds_iov_vector_arr *vct)
|
|
|
{
|
|
|
struct cmsghdr *cmsg;
|
|
|
int size = 0;
|
|
|
int cmsg_groups = 0;
|
|
|
int retval;
|
|
|
bool zcopy_cookie = false;
|
|
|
+ struct rds_iov_vector *iov, *tmp_iov;
|
|
|
|
|
|
for_each_cmsghdr(cmsg, msg) {
|
|
|
if (!CMSG_OK(msg, cmsg))
|
|
|
@@ -893,8 +895,24 @@ static int rds_rm_size(struct msghdr *msg, int num_sgs)
|
|
|
|
|
|
switch (cmsg->cmsg_type) {
|
|
|
case RDS_CMSG_RDMA_ARGS:
|
|
|
+ if (vct->indx >= vct->len) {
|
|
|
+ vct->len += vct->incr;
|
|
|
+ tmp_iov =
|
|
|
+ krealloc(vct->vec,
|
|
|
+ vct->len *
|
|
|
+ sizeof(struct rds_iov_vector),
|
|
|
+ GFP_KERNEL);
|
|
|
+ if (!tmp_iov) {
|
|
|
+ vct->len -= vct->incr;
|
|
|
+ return -ENOMEM;
|
|
|
+ }
|
|
|
+ vct->vec = tmp_iov;
|
|
|
+ }
|
|
|
+ iov = &vct->vec[vct->indx];
|
|
|
+ memset(iov, 0, sizeof(struct rds_iov_vector));
|
|
|
+ vct->indx++;
|
|
|
cmsg_groups |= 1;
|
|
|
- retval = rds_rdma_extra_size(CMSG_DATA(cmsg));
|
|
|
+ retval = rds_rdma_extra_size(CMSG_DATA(cmsg), iov);
|
|
|
if (retval < 0)
|
|
|
return retval;
|
|
|
size += retval;
|
|
|
@@ -951,10 +969,11 @@ static int rds_cmsg_zcopy(struct rds_sock *rs, struct rds_message *rm,
|
|
|
}
|
|
|
|
|
|
static int rds_cmsg_send(struct rds_sock *rs, struct rds_message *rm,
|
|
|
- struct msghdr *msg, int *allocated_mr)
|
|
|
+ struct msghdr *msg, int *allocated_mr,
|
|
|
+ struct rds_iov_vector_arr *vct)
|
|
|
{
|
|
|
struct cmsghdr *cmsg;
|
|
|
- int ret = 0;
|
|
|
+ int ret = 0, ind = 0;
|
|
|
|
|
|
for_each_cmsghdr(cmsg, msg) {
|
|
|
if (!CMSG_OK(msg, cmsg))
|
|
|
@@ -968,7 +987,10 @@ static int rds_cmsg_send(struct rds_sock *rs, struct rds_message *rm,
|
|
|
*/
|
|
|
switch (cmsg->cmsg_type) {
|
|
|
case RDS_CMSG_RDMA_ARGS:
|
|
|
- ret = rds_cmsg_rdma_args(rs, rm, cmsg);
|
|
|
+ if (ind >= vct->indx)
|
|
|
+ return -ENOMEM;
|
|
|
+ ret = rds_cmsg_rdma_args(rs, rm, cmsg, &vct->vec[ind]);
|
|
|
+ ind++;
|
|
|
break;
|
|
|
|
|
|
case RDS_CMSG_RDMA_DEST:
|
|
|
@@ -1084,6 +1106,11 @@ int rds_sendmsg(struct socket *sock, struct msghdr *msg, size_t payload_len)
|
|
|
sock_flag(rds_rs_to_sk(rs), SOCK_ZEROCOPY));
|
|
|
int num_sgs = ceil(payload_len, PAGE_SIZE);
|
|
|
int namelen;
|
|
|
+ struct rds_iov_vector_arr vct = {0};
|
|
|
+ int ind;
|
|
|
+
|
|
|
+ /* expect 1 RDMA CMSG per rds_sendmsg. can still grow if more needed. */
|
|
|
+ vct.incr = 1;
|
|
|
|
|
|
/* Mirror Linux UDP mirror of BSD error message compatibility */
|
|
|
/* XXX: Perhaps MSG_MORE someday */
|
|
|
@@ -1220,7 +1247,7 @@ int rds_sendmsg(struct socket *sock, struct msghdr *msg, size_t payload_len)
|
|
|
num_sgs = iov_iter_npages(&msg->msg_iter, INT_MAX);
|
|
|
}
|
|
|
/* size of rm including all sgs */
|
|
|
- ret = rds_rm_size(msg, num_sgs);
|
|
|
+ ret = rds_rm_size(msg, num_sgs, &vct);
|
|
|
if (ret < 0)
|
|
|
goto out;
|
|
|
|
|
|
@@ -1270,7 +1297,7 @@ int rds_sendmsg(struct socket *sock, struct msghdr *msg, size_t payload_len)
|
|
|
rm->m_conn_path = cpath;
|
|
|
|
|
|
/* Parse any control messages the user may have included. */
|
|
|
- ret = rds_cmsg_send(rs, rm, msg, &allocated_mr);
|
|
|
+ ret = rds_cmsg_send(rs, rm, msg, &allocated_mr, &vct);
|
|
|
if (ret) {
|
|
|
/* Trigger connection so that its ready for the next retry */
|
|
|
if (ret == -EAGAIN)
|
|
|
@@ -1348,9 +1375,18 @@ int rds_sendmsg(struct socket *sock, struct msghdr *msg, size_t payload_len)
|
|
|
if (ret)
|
|
|
goto out;
|
|
|
rds_message_put(rm);
|
|
|
+
|
|
|
+ for (ind = 0; ind < vct.indx; ind++)
|
|
|
+ kfree(vct.vec[ind].iov);
|
|
|
+ kfree(vct.vec);
|
|
|
+
|
|
|
return payload_len;
|
|
|
|
|
|
out:
|
|
|
+ for (ind = 0; ind < vct.indx; ind++)
|
|
|
+ kfree(vct.vec[ind].iov);
|
|
|
+ kfree(vct.vec);
|
|
|
+
|
|
|
/* If the user included a RDMA_MAP cmsg, we allocated a MR on the fly.
|
|
|
* If the sendmsg goes through, we keep the MR. If it fails with EAGAIN
|
|
|
* or in any other way, we need to destroy the MR again */
|