diff options
Diffstat (limited to 'net/rds/send.c')
-rw-r--r-- | net/rds/send.c | 61 |
1 files changed, 50 insertions, 11 deletions
diff --git a/net/rds/send.c b/net/rds/send.c index fe785ee819dd..3d822bad7de9 100644 --- a/net/rds/send.c +++ b/net/rds/send.c | |||
@@ -876,13 +876,18 @@ out: | |||
876 | * rds_message is getting to be quite complicated, and we'd like to allocate | 876 | * rds_message is getting to be quite complicated, and we'd like to allocate |
877 | * it all in one go. This figures out how big it needs to be up front. | 877 | * it all in one go. This figures out how big it needs to be up front. |
878 | */ | 878 | */ |
879 | static int rds_rm_size(struct msghdr *msg, int num_sgs) | 879 | static int rds_rm_size(struct msghdr *msg, int num_sgs, |
880 | struct rds_iov_vector_arr *vct) | ||
880 | { | 881 | { |
881 | struct cmsghdr *cmsg; | 882 | struct cmsghdr *cmsg; |
882 | int size = 0; | 883 | int size = 0; |
883 | int cmsg_groups = 0; | 884 | int cmsg_groups = 0; |
884 | int retval; | 885 | int retval; |
885 | bool zcopy_cookie = false; | 886 | bool zcopy_cookie = false; |
887 | struct rds_iov_vector *iov, *tmp_iov; | ||
888 | |||
889 | if (num_sgs < 0) | ||
890 | return -EINVAL; | ||
886 | 891 | ||
887 | for_each_cmsghdr(cmsg, msg) { | 892 | for_each_cmsghdr(cmsg, msg) { |
888 | if (!CMSG_OK(msg, cmsg)) | 893 | if (!CMSG_OK(msg, cmsg)) |
@@ -893,8 +898,24 @@ static int rds_rm_size(struct msghdr *msg, int num_sgs) | |||
893 | 898 | ||
894 | switch (cmsg->cmsg_type) { | 899 | switch (cmsg->cmsg_type) { |
895 | case RDS_CMSG_RDMA_ARGS: | 900 | case RDS_CMSG_RDMA_ARGS: |
901 | if (vct->indx >= vct->len) { | ||
902 | vct->len += vct->incr; | ||
903 | tmp_iov = | ||
904 | krealloc(vct->vec, | ||
905 | vct->len * | ||
906 | sizeof(struct rds_iov_vector), | ||
907 | GFP_KERNEL); | ||
908 | if (!tmp_iov) { | ||
909 | vct->len -= vct->incr; | ||
910 | return -ENOMEM; | ||
911 | } | ||
912 | vct->vec = tmp_iov; | ||
913 | } | ||
914 | iov = &vct->vec[vct->indx]; | ||
915 | memset(iov, 0, sizeof(struct rds_iov_vector)); | ||
916 | vct->indx++; | ||
896 | cmsg_groups |= 1; | 917 | cmsg_groups |= 1; |
897 | retval = rds_rdma_extra_size(CMSG_DATA(cmsg)); | 918 | retval = rds_rdma_extra_size(CMSG_DATA(cmsg), iov); |
898 | if (retval < 0) | 919 | if (retval < 0) |
899 | return retval; | 920 | return retval; |
900 | size += retval; | 921 | size += retval; |
@@ -951,10 +972,11 @@ static int rds_cmsg_zcopy(struct rds_sock *rs, struct rds_message *rm, | |||
951 | } | 972 | } |
952 | 973 | ||
953 | static int rds_cmsg_send(struct rds_sock *rs, struct rds_message *rm, | 974 | static int rds_cmsg_send(struct rds_sock *rs, struct rds_message *rm, |
954 | struct msghdr *msg, int *allocated_mr) | 975 | struct msghdr *msg, int *allocated_mr, |
976 | struct rds_iov_vector_arr *vct) | ||
955 | { | 977 | { |
956 | struct cmsghdr *cmsg; | 978 | struct cmsghdr *cmsg; |
957 | int ret = 0; | 979 | int ret = 0, ind = 0; |
958 | 980 | ||
959 | for_each_cmsghdr(cmsg, msg) { | 981 | for_each_cmsghdr(cmsg, msg) { |
960 | if (!CMSG_OK(msg, cmsg)) | 982 | if (!CMSG_OK(msg, cmsg)) |
@@ -968,7 +990,10 @@ static int rds_cmsg_send(struct rds_sock *rs, struct rds_message *rm, | |||
968 | */ | 990 | */ |
969 | switch (cmsg->cmsg_type) { | 991 | switch (cmsg->cmsg_type) { |
970 | case RDS_CMSG_RDMA_ARGS: | 992 | case RDS_CMSG_RDMA_ARGS: |
971 | ret = rds_cmsg_rdma_args(rs, rm, cmsg); | 993 | if (ind >= vct->indx) |
994 | return -ENOMEM; | ||
995 | ret = rds_cmsg_rdma_args(rs, rm, cmsg, &vct->vec[ind]); | ||
996 | ind++; | ||
972 | break; | 997 | break; |
973 | 998 | ||
974 | case RDS_CMSG_RDMA_DEST: | 999 | case RDS_CMSG_RDMA_DEST: |
@@ -1084,6 +1109,13 @@ int rds_sendmsg(struct socket *sock, struct msghdr *msg, size_t payload_len) | |||
1084 | sock_flag(rds_rs_to_sk(rs), SOCK_ZEROCOPY)); | 1109 | sock_flag(rds_rs_to_sk(rs), SOCK_ZEROCOPY)); |
1085 | int num_sgs = ceil(payload_len, PAGE_SIZE); | 1110 | int num_sgs = ceil(payload_len, PAGE_SIZE); |
1086 | int namelen; | 1111 | int namelen; |
1112 | struct rds_iov_vector_arr vct; | ||
1113 | int ind; | ||
1114 | |||
1115 | memset(&vct, 0, sizeof(vct)); | ||
1116 | |||
1117 | /* expect 1 RDMA CMSG per rds_sendmsg. can still grow if more needed. */ | ||
1118 | vct.incr = 1; | ||
1087 | 1119 | ||
1088 | /* Mirror Linux UDP mirror of BSD error message compatibility */ | 1120 | /* Mirror Linux UDP mirror of BSD error message compatibility */ |
1089 | /* XXX: Perhaps MSG_MORE someday */ | 1121 | /* XXX: Perhaps MSG_MORE someday */ |
@@ -1220,7 +1252,7 @@ int rds_sendmsg(struct socket *sock, struct msghdr *msg, size_t payload_len) | |||
1220 | num_sgs = iov_iter_npages(&msg->msg_iter, INT_MAX); | 1252 | num_sgs = iov_iter_npages(&msg->msg_iter, INT_MAX); |
1221 | } | 1253 | } |
1222 | /* size of rm including all sgs */ | 1254 | /* size of rm including all sgs */ |
1223 | ret = rds_rm_size(msg, num_sgs); | 1255 | ret = rds_rm_size(msg, num_sgs, &vct); |
1224 | if (ret < 0) | 1256 | if (ret < 0) |
1225 | goto out; | 1257 | goto out; |
1226 | 1258 | ||
@@ -1232,11 +1264,9 @@ int rds_sendmsg(struct socket *sock, struct msghdr *msg, size_t payload_len) | |||
1232 | 1264 | ||
1233 | /* Attach data to the rm */ | 1265 | /* Attach data to the rm */ |
1234 | if (payload_len) { | 1266 | if (payload_len) { |
1235 | rm->data.op_sg = rds_message_alloc_sgs(rm, num_sgs); | 1267 | rm->data.op_sg = rds_message_alloc_sgs(rm, num_sgs, &ret); |
1236 | if (!rm->data.op_sg) { | 1268 | if (!rm->data.op_sg) |
1237 | ret = -ENOMEM; | ||
1238 | goto out; | 1269 | goto out; |
1239 | } | ||
1240 | ret = rds_message_copy_from_user(rm, &msg->msg_iter, zcopy); | 1270 | ret = rds_message_copy_from_user(rm, &msg->msg_iter, zcopy); |
1241 | if (ret) | 1271 | if (ret) |
1242 | goto out; | 1272 | goto out; |
@@ -1270,7 +1300,7 @@ int rds_sendmsg(struct socket *sock, struct msghdr *msg, size_t payload_len) | |||
1270 | rm->m_conn_path = cpath; | 1300 | rm->m_conn_path = cpath; |
1271 | 1301 | ||
1272 | /* Parse any control messages the user may have included. */ | 1302 | /* Parse any control messages the user may have included. */ |
1273 | ret = rds_cmsg_send(rs, rm, msg, &allocated_mr); | 1303 | ret = rds_cmsg_send(rs, rm, msg, &allocated_mr, &vct); |
1274 | if (ret) { | 1304 | if (ret) { |
1275 | /* Trigger connection so that its ready for the next retry */ | 1305 | /* Trigger connection so that its ready for the next retry */ |
1276 | if (ret == -EAGAIN) | 1306 | if (ret == -EAGAIN) |
@@ -1348,9 +1378,18 @@ int rds_sendmsg(struct socket *sock, struct msghdr *msg, size_t payload_len) | |||
1348 | if (ret) | 1378 | if (ret) |
1349 | goto out; | 1379 | goto out; |
1350 | rds_message_put(rm); | 1380 | rds_message_put(rm); |
1381 | |||
1382 | for (ind = 0; ind < vct.indx; ind++) | ||
1383 | kfree(vct.vec[ind].iov); | ||
1384 | kfree(vct.vec); | ||
1385 | |||
1351 | return payload_len; | 1386 | return payload_len; |
1352 | 1387 | ||
1353 | out: | 1388 | out: |
1389 | for (ind = 0; ind < vct.indx; ind++) | ||
1390 | kfree(vct.vec[ind].iov); | ||
1391 | kfree(vct.vec); | ||
1392 | |||
1354 | /* If the user included a RDMA_MAP cmsg, we allocated a MR on the fly. | 1393 | /* If the user included a RDMA_MAP cmsg, we allocated a MR on the fly. |
1355 | * If the sendmsg goes through, we keep the MR. If it fails with EAGAIN | 1394 | * If the sendmsg goes through, we keep the MR. If it fails with EAGAIN |
1356 | * or in any other way, we need to destroy the MR again */ | 1395 | * or in any other way, we need to destroy the MR again */ |