diff options
author | Tom Herbert <tom@herbertland.com> | 2016-03-07 17:11:09 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2016-03-09 16:36:15 -0500 |
commit | f29698fc6b3a45a5c6147eca8379f38be8232117 (patch) | |
tree | faad89f5af8cda7df1eb6b5a447fffcacf9a8d68 /net/kcm | |
parent | 91687355b92735e5f247ed163b3b0b4d14c3cab6 (diff) |
kcm: Sendpage support
Implement kcm_sendpage. Set in sendpage to kcm_sendpage in both
dgram and seqpacket ops.
Signed-off-by: Tom Herbert <tom@herbertland.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/kcm')
-rw-r--r-- | net/kcm/kcmsock.c | 147 |
1 files changed, 145 insertions, 2 deletions
diff --git a/net/kcm/kcmsock.c b/net/kcm/kcmsock.c index 982ea5f77bfc..9ac24995691c 100644 --- a/net/kcm/kcmsock.c +++ b/net/kcm/kcmsock.c | |||
@@ -990,6 +990,149 @@ static void kcm_push(struct kcm_sock *kcm) | |||
990 | kcm_write_msgs(kcm); | 990 | kcm_write_msgs(kcm); |
991 | } | 991 | } |
992 | 992 | ||
993 | static ssize_t kcm_sendpage(struct socket *sock, struct page *page, | ||
994 | int offset, size_t size, int flags) | ||
995 | |||
996 | { | ||
997 | struct sock *sk = sock->sk; | ||
998 | struct kcm_sock *kcm = kcm_sk(sk); | ||
999 | struct sk_buff *skb = NULL, *head = NULL; | ||
1000 | long timeo = sock_sndtimeo(sk, flags & MSG_DONTWAIT); | ||
1001 | bool eor; | ||
1002 | int err = 0; | ||
1003 | int i; | ||
1004 | |||
1005 | if (flags & MSG_SENDPAGE_NOTLAST) | ||
1006 | flags |= MSG_MORE; | ||
1007 | |||
1008 | /* No MSG_EOR from splice, only look at MSG_MORE */ | ||
1009 | eor = !(flags & MSG_MORE); | ||
1010 | |||
1011 | lock_sock(sk); | ||
1012 | |||
1013 | sk_clear_bit(SOCKWQ_ASYNC_NOSPACE, sk); | ||
1014 | |||
1015 | err = -EPIPE; | ||
1016 | if (sk->sk_err) | ||
1017 | goto out_error; | ||
1018 | |||
1019 | if (kcm->seq_skb) { | ||
1020 | /* Previously opened message */ | ||
1021 | head = kcm->seq_skb; | ||
1022 | skb = kcm_tx_msg(head)->last_skb; | ||
1023 | i = skb_shinfo(skb)->nr_frags; | ||
1024 | |||
1025 | if (skb_can_coalesce(skb, i, page, offset)) { | ||
1026 | skb_frag_size_add(&skb_shinfo(skb)->frags[i - 1], size); | ||
1027 | skb_shinfo(skb)->tx_flags |= SKBTX_SHARED_FRAG; | ||
1028 | goto coalesced; | ||
1029 | } | ||
1030 | |||
1031 | if (i >= MAX_SKB_FRAGS) { | ||
1032 | struct sk_buff *tskb; | ||
1033 | |||
1034 | tskb = alloc_skb(0, sk->sk_allocation); | ||
1035 | while (!tskb) { | ||
1036 | kcm_push(kcm); | ||
1037 | err = sk_stream_wait_memory(sk, &timeo); | ||
1038 | if (err) | ||
1039 | goto out_error; | ||
1040 | } | ||
1041 | |||
1042 | if (head == skb) | ||
1043 | skb_shinfo(head)->frag_list = tskb; | ||
1044 | else | ||
1045 | skb->next = tskb; | ||
1046 | |||
1047 | skb = tskb; | ||
1048 | skb->ip_summed = CHECKSUM_UNNECESSARY; | ||
1049 | i = 0; | ||
1050 | } | ||
1051 | } else { | ||
1052 | /* Call the sk_stream functions to manage the sndbuf mem. */ | ||
1053 | if (!sk_stream_memory_free(sk)) { | ||
1054 | kcm_push(kcm); | ||
1055 | set_bit(SOCK_NOSPACE, &sk->sk_socket->flags); | ||
1056 | err = sk_stream_wait_memory(sk, &timeo); | ||
1057 | if (err) | ||
1058 | goto out_error; | ||
1059 | } | ||
1060 | |||
1061 | head = alloc_skb(0, sk->sk_allocation); | ||
1062 | while (!head) { | ||
1063 | kcm_push(kcm); | ||
1064 | err = sk_stream_wait_memory(sk, &timeo); | ||
1065 | if (err) | ||
1066 | goto out_error; | ||
1067 | } | ||
1068 | |||
1069 | skb = head; | ||
1070 | i = 0; | ||
1071 | } | ||
1072 | |||
1073 | get_page(page); | ||
1074 | skb_fill_page_desc(skb, i, page, offset, size); | ||
1075 | skb_shinfo(skb)->tx_flags |= SKBTX_SHARED_FRAG; | ||
1076 | |||
1077 | coalesced: | ||
1078 | skb->len += size; | ||
1079 | skb->data_len += size; | ||
1080 | skb->truesize += size; | ||
1081 | sk->sk_wmem_queued += size; | ||
1082 | sk_mem_charge(sk, size); | ||
1083 | |||
1084 | if (head != skb) { | ||
1085 | head->len += size; | ||
1086 | head->data_len += size; | ||
1087 | head->truesize += size; | ||
1088 | } | ||
1089 | |||
1090 | if (eor) { | ||
1091 | bool not_busy = skb_queue_empty(&sk->sk_write_queue); | ||
1092 | |||
1093 | /* Message complete, queue it on send buffer */ | ||
1094 | __skb_queue_tail(&sk->sk_write_queue, head); | ||
1095 | kcm->seq_skb = NULL; | ||
1096 | KCM_STATS_INCR(kcm->stats.tx_msgs); | ||
1097 | |||
1098 | if (flags & MSG_BATCH) { | ||
1099 | kcm->tx_wait_more = true; | ||
1100 | } else if (kcm->tx_wait_more || not_busy) { | ||
1101 | err = kcm_write_msgs(kcm); | ||
1102 | if (err < 0) { | ||
1103 | /* We got a hard error in write_msgs but have | ||
1104 | * already queued this message. Report an error | ||
1105 | * in the socket, but don't affect return value | ||
1106 | * from sendmsg | ||
1107 | */ | ||
1108 | pr_warn("KCM: Hard failure on kcm_write_msgs\n"); | ||
1109 | report_csk_error(&kcm->sk, -err); | ||
1110 | } | ||
1111 | } | ||
1112 | } else { | ||
1113 | /* Message not complete, save state */ | ||
1114 | kcm->seq_skb = head; | ||
1115 | kcm_tx_msg(head)->last_skb = skb; | ||
1116 | } | ||
1117 | |||
1118 | KCM_STATS_ADD(kcm->stats.tx_bytes, size); | ||
1119 | |||
1120 | release_sock(sk); | ||
1121 | return size; | ||
1122 | |||
1123 | out_error: | ||
1124 | kcm_push(kcm); | ||
1125 | |||
1126 | err = sk_stream_error(sk, flags, err); | ||
1127 | |||
1128 | /* make sure we wake any epoll edge trigger waiter */ | ||
1129 | if (unlikely(skb_queue_len(&sk->sk_write_queue) == 0 && err == -EAGAIN)) | ||
1130 | sk->sk_write_space(sk); | ||
1131 | |||
1132 | release_sock(sk); | ||
1133 | return err; | ||
1134 | } | ||
1135 | |||
993 | static int kcm_sendmsg(struct socket *sock, struct msghdr *msg, size_t len) | 1136 | static int kcm_sendmsg(struct socket *sock, struct msghdr *msg, size_t len) |
994 | { | 1137 | { |
995 | struct sock *sk = sock->sk; | 1138 | struct sock *sk = sock->sk; |
@@ -1995,7 +2138,7 @@ static const struct proto_ops kcm_dgram_ops = { | |||
1995 | .sendmsg = kcm_sendmsg, | 2138 | .sendmsg = kcm_sendmsg, |
1996 | .recvmsg = kcm_recvmsg, | 2139 | .recvmsg = kcm_recvmsg, |
1997 | .mmap = sock_no_mmap, | 2140 | .mmap = sock_no_mmap, |
1998 | .sendpage = sock_no_sendpage, | 2141 | .sendpage = kcm_sendpage, |
1999 | }; | 2142 | }; |
2000 | 2143 | ||
2001 | static const struct proto_ops kcm_seqpacket_ops = { | 2144 | static const struct proto_ops kcm_seqpacket_ops = { |
@@ -2016,7 +2159,7 @@ static const struct proto_ops kcm_seqpacket_ops = { | |||
2016 | .sendmsg = kcm_sendmsg, | 2159 | .sendmsg = kcm_sendmsg, |
2017 | .recvmsg = kcm_recvmsg, | 2160 | .recvmsg = kcm_recvmsg, |
2018 | .mmap = sock_no_mmap, | 2161 | .mmap = sock_no_mmap, |
2019 | .sendpage = sock_no_sendpage, | 2162 | .sendpage = kcm_sendpage, |
2020 | .splice_read = kcm_splice_read, | 2163 | .splice_read = kcm_splice_read, |
2021 | }; | 2164 | }; |
2022 | 2165 | ||