| @@ -875,12 +875,13 @@ out: · 874 unmodified lines |
| 875 | * rds_message is getting to be quite complicated, and we'd like to allocate | 875 | * rds_message is getting to be quite complicated, and we'd like to allocate |
| 876 | * it all in one go. This figures out how big it needs to be up front. | 876 | * it all in one go. This figures out how big it needs to be up front. |
| 877 | */ | 877 | */ |
| 878 | static int rds_rm_size(struct msghdr *msg, int data_len) | 878 | static int rds_rm_size(struct msghdr *msg, int num_sgs) |
| 879 | { | 879 | { |
| 880 | struct cmsghdr *cmsg; | 880 | struct cmsghdr *cmsg; |
| 881 | int size = 0; | 881 | int size = 0; |
| 882 | int cmsg_groups = 0; | 882 | int cmsg_groups = 0; |
| 883 | int retval; | 883 | int retval; |
| | 884 | bool zcopy_cookie = false; |
| 884 | | 885 | |
| 885 | for_each_cmsghdr(cmsg, msg) { | 886 | for_each_cmsghdr(cmsg, msg) { |
| 886 | if (!CMSG_OK(msg, cmsg)) | 887 | if (!CMSG_OK(msg, cmsg)) |
| @@ -899,6 +900,8 @@ static int rds_rm_size(struct msghdr *msg, int data_len) · 12 unmodified lines |
| 899 | | 900 | |
| 900 | break; | 901 | break; |
| 901 | | 902 | |
| | 903 | case RDS_CMSG_ZCOPY_COOKIE: |
| | 904 | zcopy_cookie = true; |
| 902 | case RDS_CMSG_RDMA_DEST: | 905 | case RDS_CMSG_RDMA_DEST: |
| 903 | case RDS_CMSG_RDMA_MAP: | 906 | case RDS_CMSG_RDMA_MAP: |
| 904 | cmsg_groups |= 2; | 907 | cmsg_groups |= 2; |
| @@ -919,7 +922,10 @@ static int rds_rm_size(struct msghdr *msg, int data_len) · 14 unmodified lines |
| 919 | | 922 | |
| 920 | } | 923 | } |
| 921 | | 924 | |
| 922 | size += ceil(data_len, PAGE_SIZE) * sizeof(struct scatterlist); | 925 | if ((msg->msg_flags & MSG_ZEROCOPY) && !zcopy_cookie) |
| | 926 | return -EINVAL; |
| | 927 | |
| | 928 | size += num_sgs * sizeof(struct scatterlist); |
| 923 | | 929 | |
| 924 | /* Ensure (DEST, MAP) are never used with (ARGS, ATOMIC) */ | 930 | /* Ensure (DEST, MAP) are never used with (ARGS, ATOMIC) */ |
| 925 | if (cmsg_groups == 3) | 931 | if (cmsg_groups == 3) |
| @@ -928,6 +934,18 @@ static int rds_rm_size(struct msghdr *msg, int data_len) · 2 unmodified lines |
| 928 | return size; | 934 | return size; |
| 929 | } | 935 | } |
| 930 | | 936 | |
| | 937 | static int rds_cmsg_zcopy(struct rds_sock *rs, struct rds_message *rm, |
| | 938 | struct cmsghdr *cmsg) |
| | 939 | { |
| | 940 | u32 *cookie; |
| | 941 | |
| | 942 | if (cmsg->cmsg_len < CMSG_LEN(sizeof(*cookie))) |
| | 943 | return -EINVAL; |
| | 944 | cookie = CMSG_DATA(cmsg); |
| | 945 | rm->data.op_mmp_znotifier->z_cookie = *cookie; |
| | 946 | return 0; |
| | 947 | } |
| | 948 | |
| 931 | static int rds_cmsg_send(struct rds_sock *rs, struct rds_message *rm, | 949 | static int rds_cmsg_send(struct rds_sock *rs, struct rds_message *rm, |
| 932 | struct msghdr *msg, int *allocated_mr) | 950 | struct msghdr *msg, int *allocated_mr) |
| 933 | { | 951 | { |
| @@ -970,6 +988,10 @@ static int rds_cmsg_send(struct rds_sock *rs, struct rds_message *rm, · 36 unmodified lines |
| 970 | ret = rds_cmsg_atomic(rs, rm, cmsg); | 988 | ret = rds_cmsg_atomic(rs, rm, cmsg); |
| 971 | break; | 989 | break; |
| 972 | | 990 | |
| | 991 | case RDS_CMSG_ZCOPY_COOKIE: |
| | 992 | ret = rds_cmsg_zcopy(rs, rm, cmsg); |
| | 993 | break; |
| | 994 | |
| 973 | default: | 995 | default: |
| 974 | return -EINVAL; | 996 | return -EINVAL; |
| 975 | } | 997 | } |
| @@ -1040,10 +1062,13 @@ int rds_sendmsg(struct socket *sock, struct msghdr *msg, size_t payload_len) · 64 unmodified lines |
| 1040 | long timeo = sock_sndtimeo(sk, nonblock); | 1062 | long timeo = sock_sndtimeo(sk, nonblock); |
| 1041 | struct rds_conn_path *cpath; | 1063 | struct rds_conn_path *cpath; |
| 1042 | size_t total_payload_len = payload_len, rdma_payload_len = 0; | 1064 | size_t total_payload_len = payload_len, rdma_payload_len = 0; |
| | 1065 | bool zcopy = ((msg->msg_flags & MSG_ZEROCOPY) && |
| | 1066 | sock_flag(rds_rs_to_sk(rs), SOCK_ZEROCOPY)); |
| | 1067 | int num_sgs = ceil(payload_len, PAGE_SIZE); |
| 1043 | | 1068 | |
| 1044 | /* Mirror Linux UDP mirror of BSD error message compatibility */ | 1069 | /* Mirror Linux UDP mirror of BSD error message compatibility */ |
| 1045 | /* XXX: Perhaps MSG_MORE someday */ | 1070 | /* XXX: Perhaps MSG_MORE someday */ |
| 1046 | if (msg->msg_flags & ~(MSG_DONTWAIT | MSG_CMSG_COMPAT)) { | 1071 | if (msg->msg_flags & ~(MSG_DONTWAIT | MSG_CMSG_COMPAT | MSG_ZEROCOPY)) { |
| 1047 | ret = -EOPNOTSUPP; | 1072 | ret = -EOPNOTSUPP; |
| 1048 | goto out; | 1073 | goto out; |
| 1049 | } | 1074 | } |
| @@ -1087,8 +1112,15 @@ int rds_sendmsg(struct socket *sock, struct msghdr *msg, size_t payload_len) · 37 unmodified lines |
| 1087 | goto out; | 1112 | goto out; |
| 1088 | } | 1113 | } |
| 1089 | | 1114 | |
| | 1115 | if (zcopy) { |
| | 1116 | if (rs->rs_transport->t_type != RDS_TRANS_TCP) { |
| | 1117 | ret = -EOPNOTSUPP; |
| | 1118 | goto out; |
| | 1119 | } |
| | 1120 | num_sgs = iov_iter_npages(&msg->msg_iter, INT_MAX); |
| | 1121 | } |
| 1090 | /* size of rm including all sgs */ | 1122 | /* size of rm including all sgs */ |
| 1091 | ret = rds_rm_size(msg, payload_len); | 1123 | ret = rds_rm_size(msg, num_sgs); |
| 1092 | if (ret < 0) | 1124 | if (ret < 0) |
| 1093 | goto out; | 1125 | goto out; |
| 1094 | | 1126 | |
| @@ -1100,12 +1132,12 @@ int rds_sendmsg(struct socket *sock, struct msghdr *msg, size_t payload_len) · 5 unmodified lines |
| 1100 | | 1132 | |
| 1101 | /* Attach data to the rm */ | 1133 | /* Attach data to the rm */ |
| 1102 | if (payload_len) { | 1134 | if (payload_len) { |
| 1103 | rm->data.op_sg = rds_message_alloc_sgs(rm, ceil(payload_len, PAGE_SIZE)); | 1135 | rm->data.op_sg = rds_message_alloc_sgs(rm, num_sgs); |
| 1104 | if (!rm->data.op_sg) { | 1136 | if (!rm->data.op_sg) { |
| 1105 | ret = -ENOMEM; | 1137 | ret = -ENOMEM; |
| 1106 | goto out; | 1138 | goto out; |
| 1107 | } | 1139 | } |
| 1108 | ret = rds_message_copy_from_user(rm, &msg->msg_iter); | 1140 | ret = rds_message_copy_from_user(rm, &msg->msg_iter, zcopy); |
| 1109 | if (ret) | 1141 | if (ret) |
| 1110 | goto out; | 1142 | goto out; |
| 1111 | } | 1143 | } |