Merge branch 'next/drivers' into next/late
[linux-2.6-microblaze.git] / net / rds / send.c
index fe785ee..3d822ba 100644 (file)
@@ -876,13 +876,18 @@ 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;
+
+       if (num_sgs < 0)
+               return -EINVAL;
 
        for_each_cmsghdr(cmsg, msg) {
                if (!CMSG_OK(msg, cmsg))
@@ -893,8 +898,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 +972,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 +990,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 +1109,13 @@ 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;
+       int ind;
+
+       memset(&vct, 0, sizeof(vct));
+
+       /* 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 +1252,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;
 
@@ -1232,11 +1264,9 @@ int rds_sendmsg(struct socket *sock, struct msghdr *msg, size_t payload_len)
 
        /* Attach data to the rm */
        if (payload_len) {
-               rm->data.op_sg = rds_message_alloc_sgs(rm, num_sgs);
-               if (!rm->data.op_sg) {
-                       ret = -ENOMEM;
+               rm->data.op_sg = rds_message_alloc_sgs(rm, num_sgs, &ret);
+               if (!rm->data.op_sg)
                        goto out;
-               }
                ret = rds_message_copy_from_user(rm, &msg->msg_iter, zcopy);
                if (ret)
                        goto out;
@@ -1270,7 +1300,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 +1378,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 */