1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * linux/net/sunrpc/socklib.c 4 * 5 * Common socket helper routines for RPC client and server 6 * 7 * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de> 8 */ 9 10 #include <linux/compiler.h> 11 #include <linux/netdevice.h> 12 #include <linux/gfp.h> 13 #include <linux/skbuff.h> 14 #include <linux/types.h> 15 #include <linux/pagemap.h> 16 #include <linux/udp.h> 17 #include <linux/sunrpc/msg_prot.h> 18 #include <linux/sunrpc/sched.h> 19 #include <linux/sunrpc/xdr.h> 20 #include <linux/export.h> 21 22 #include "socklib.h" 23 24 /* 25 * Helper structure for copying from an sk_buff. 26 */ 27 struct xdr_skb_reader { 28 struct sk_buff *skb; 29 unsigned int offset; 30 bool need_checksum; 31 size_t count; 32 __wsum csum; 33 }; 34 35 /** 36 * xdr_skb_read_bits - copy some data bits from skb to internal buffer 37 * @desc: sk_buff copy helper 38 * @to: copy destination 39 * @len: number of bytes to copy 40 * 41 * Possibly called several times to iterate over an sk_buff and copy data out of 42 * it. 43 */ 44 static size_t 45 xdr_skb_read_bits(struct xdr_skb_reader *desc, void *to, size_t len) 46 { 47 len = min(len, desc->count); 48 49 if (desc->need_checksum) { 50 __wsum csum; 51 52 csum = skb_copy_and_csum_bits(desc->skb, desc->offset, to, len); 53 desc->csum = csum_block_add(desc->csum, csum, desc->offset); 54 } else { 55 if (unlikely(skb_copy_bits(desc->skb, desc->offset, to, len))) 56 return 0; 57 } 58 59 desc->count -= len; 60 desc->offset += len; 61 return len; 62 } 63 64 static ssize_t 65 xdr_partial_copy_from_skb(struct xdr_buf *xdr, struct xdr_skb_reader *desc) 66 { 67 struct page **ppage = xdr->pages + (xdr->page_base >> PAGE_SHIFT); 68 unsigned int poff = xdr->page_base & ~PAGE_MASK; 69 unsigned int pglen = xdr->page_len; 70 ssize_t copied = 0; 71 size_t ret; 72 73 if (xdr->head[0].iov_len == 0) 74 return 0; 75 76 ret = xdr_skb_read_bits(desc, xdr->head[0].iov_base, 77 xdr->head[0].iov_len); 78 if (ret != xdr->head[0].iov_len || !desc->count) 79 return ret; 80 copied += ret; 81 82 while (pglen) { 83 unsigned int len = min(PAGE_SIZE - poff, pglen); 84 char *kaddr; 85 86 /* ACL likes to be lazy in allocating pages - ACLs 87 * are small by default but can get huge. */ 88 if ((xdr->flags & XDRBUF_SPARSE_PAGES) && *ppage == NULL) { 89 *ppage = alloc_page(GFP_NOWAIT | __GFP_NOWARN); 90 if (unlikely(*ppage == NULL)) { 91 if (copied == 0) 92 return -ENOMEM; 93 return copied; 94 } 95 } 96 97 kaddr = kmap_atomic(*ppage); 98 ret = xdr_skb_read_bits(desc, kaddr + poff, len); 99 flush_dcache_page(*ppage); 100 kunmap_atomic(kaddr); 101 102 copied += ret; 103 if (ret != len || !desc->count) 104 return copied; 105 ppage++; 106 pglen -= len; 107 poff = 0; 108 } 109 110 if (xdr->tail[0].iov_len) { 111 copied += xdr_skb_read_bits(desc, xdr->tail[0].iov_base, 112 xdr->tail[0].iov_len); 113 } 114 115 return copied; 116 } 117 118 /** 119 * csum_partial_copy_to_xdr - checksum and copy data 120 * @xdr: target XDR buffer 121 * @skb: source skb 122 * 123 * We have set things up such that we perform the checksum of the UDP 124 * packet in parallel with the copies into the RPC client iovec. -DaveM 125 */ 126 int csum_partial_copy_to_xdr(struct xdr_buf *xdr, struct sk_buff *skb) 127 { 128 struct xdr_skb_reader desc = { 129 .skb = skb, 130 .count = skb->len - desc.offset, 131 }; 132 133 if (skb_csum_unnecessary(skb)) { 134 if (xdr_partial_copy_from_skb(xdr, &desc) < 0) 135 return -1; 136 if (desc.count) 137 return -1; 138 return 0; 139 } 140 141 desc.need_checksum = true; 142 desc.csum = csum_partial(skb->data, desc.offset, skb->csum); 143 if (xdr_partial_copy_from_skb(xdr, &desc) < 0) 144 return -1; 145 if (desc.offset != skb->len) { 146 __wsum csum2; 147 csum2 = skb_checksum(skb, desc.offset, skb->len - desc.offset, 0); 148 desc.csum = csum_block_add(desc.csum, csum2, desc.offset); 149 } 150 if (desc.count) 151 return -1; 152 if (csum_fold(desc.csum)) 153 return -1; 154 if (unlikely(skb->ip_summed == CHECKSUM_COMPLETE) && 155 !skb->csum_complete_sw) 156 netdev_rx_csum_fault(skb->dev, skb); 157 return 0; 158 } 159 160 static inline int xprt_sendmsg(struct socket *sock, struct msghdr *msg, 161 size_t seek) 162 { 163 if (seek) 164 iov_iter_advance(&msg->msg_iter, seek); 165 return sock_sendmsg(sock, msg); 166 } 167 168 static int xprt_send_kvec(struct socket *sock, struct msghdr *msg, 169 struct kvec *vec, size_t seek) 170 { 171 iov_iter_kvec(&msg->msg_iter, ITER_SOURCE, vec, 1, vec->iov_len); 172 return xprt_sendmsg(sock, msg, seek); 173 } 174 175 static int xprt_send_pagedata(struct socket *sock, struct msghdr *msg, 176 struct xdr_buf *xdr, size_t base) 177 { 178 iov_iter_bvec(&msg->msg_iter, ITER_SOURCE, xdr->bvec, xdr_buf_pagecount(xdr), 179 xdr->page_len + xdr->page_base); 180 return xprt_sendmsg(sock, msg, base + xdr->page_base); 181 } 182 183 /* Common case: 184 * - stream transport 185 * - sending from byte 0 of the message 186 * - the message is wholly contained in @xdr's head iovec 187 */ 188 static int xprt_send_rm_and_kvec(struct socket *sock, struct msghdr *msg, 189 rpc_fraghdr marker, struct kvec *vec, 190 size_t base) 191 { 192 struct kvec iov[2] = { 193 [0] = { 194 .iov_base = &marker, 195 .iov_len = sizeof(marker) 196 }, 197 [1] = *vec, 198 }; 199 size_t len = iov[0].iov_len + iov[1].iov_len; 200 201 iov_iter_kvec(&msg->msg_iter, ITER_SOURCE, iov, 2, len); 202 return xprt_sendmsg(sock, msg, base); 203 } 204 205 /** 206 * xprt_sock_sendmsg - write an xdr_buf directly to a socket 207 * @sock: open socket to send on 208 * @msg: socket message metadata 209 * @xdr: xdr_buf containing this request 210 * @base: starting position in the buffer 211 * @marker: stream record marker field 212 * @sent_p: return the total number of bytes successfully queued for sending 213 * 214 * Return values: 215 * On success, returns zero and fills in @sent_p. 216 * %-ENOTSOCK if @sock is not a struct socket. 217 */ 218 int xprt_sock_sendmsg(struct socket *sock, struct msghdr *msg, 219 struct xdr_buf *xdr, unsigned int base, 220 rpc_fraghdr marker, unsigned int *sent_p) 221 { 222 unsigned int rmsize = marker ? sizeof(marker) : 0; 223 unsigned int remainder = rmsize + xdr->len - base; 224 unsigned int want; 225 int err = 0; 226 227 *sent_p = 0; 228 229 if (unlikely(!sock)) 230 return -ENOTSOCK; 231 232 msg->msg_flags |= MSG_MORE; 233 want = xdr->head[0].iov_len + rmsize; 234 if (base < want) { 235 unsigned int len = want - base; 236 237 remainder -= len; 238 if (remainder == 0) 239 msg->msg_flags &= ~MSG_MORE; 240 if (rmsize) 241 err = xprt_send_rm_and_kvec(sock, msg, marker, 242 &xdr->head[0], base); 243 else 244 err = xprt_send_kvec(sock, msg, &xdr->head[0], base); 245 if (remainder == 0 || err != len) 246 goto out; 247 *sent_p += err; 248 base = 0; 249 } else { 250 base -= want; 251 } 252 253 if (base < xdr->page_len) { 254 unsigned int len = xdr->page_len - base; 255 256 remainder -= len; 257 if (remainder == 0) 258 msg->msg_flags &= ~MSG_MORE; 259 err = xprt_send_pagedata(sock, msg, xdr, base); 260 if (remainder == 0 || err != len) 261 goto out; 262 *sent_p += err; 263 base = 0; 264 } else { 265 base -= xdr->page_len; 266 } 267 268 if (base >= xdr->tail[0].iov_len) 269 return 0; 270 msg->msg_flags &= ~MSG_MORE; 271 err = xprt_send_kvec(sock, msg, &xdr->tail[0], base); 272 out: 273 if (err > 0) { 274 *sent_p += err; 275 err = 0; 276 } 277 return err; 278 } 279