History

SUNRPC: Refactor svc_recvfrom()

This function is not currently "generic" so remove the documenting comment and rename it appropriately. Its internals are converted to use bio_vecs for reading from the transport socket. In existing typical sunrpc uses of bio_vecs, the bio_vec array is allocated dynamically. Here, instead, an array of bio_vecs is added to svc_rqst. The lifetime of this array can be greater than one call to xpo_recvfrom(): - Multiple calls to xpo_recvfrom() might be needed to read an RPC message completely. - At some later point, rq_arg.bvecs will point to this array and it will carry the received message into svc_process(). I also expect that a future optimization will remove either the rq_vec or rq_pages array in favor of rq_bvec, thus conserving the size of struct svc_rqst.

Chuck Lever committed 6 years ago

Commit ca07eda1 parent cca557a2 files · +69 −41Browse files

Unified · Split

2 files
  1. include/linux/sunrpc/svc.h +1 −0
  2. net/sunrpc/svcsock.c +68 −41
include/linux/sunrpc/svc.h+1−0
@@ -254,6 +254,7 @@ struct svc_rqst { · 253 unmodified lines
254 struct page * *rq_page_end; /* one past the last page */254 struct page * *rq_page_end; /* one past the last page */
255 255
256 struct kvec rq_vec[RPCSVC_MAXPAGES]; /* generally useful.. */256 struct kvec rq_vec[RPCSVC_MAXPAGES]; /* generally useful.. */
257 struct bio_vec rq_bvec[RPCSVC_MAXPAGES];
257 258
258 __be32 rq_xid; /* transmission id */259 __be32 rq_xid; /* transmission id */
259 u32 rq_prog; /* program number */260 u32 rq_prog; /* program number */
net/sunrpc/svcsock.c+68−41
@@ -223,26 +223,62 @@ static int svc_one_sock_name(struct svc_sock *svsk, char *buf, int remaining) · 222 unmodified lines
223 return len;223 return len;
224}224}
225 225
226#if ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE
227static void svc_flush_bvec(const struct bio_vec *bvec, size_t size, size_t seek)
228{
229 struct bvec_iter bi = {
230 .bi_size = size,
231 };
232 struct bio_vec bv;
233
234 bvec_iter_advance(bvec, &bi, seek & PAGE_MASK);
235 for_each_bvec(bv, bvec, bi, bi)
236 flush_dcache_page(bv.bv_page);
237}
238#else
239static inline void svc_flush_bvec(const struct bio_vec *bvec, size_t size,
240 size_t seek)
241{
242}
243#endif
244
226/*245/*
227 * Generic recvfrom routine.246 * Read from @rqstp's transport socket. The incoming message fills whole
247 * pages in @rqstp's rq_pages array until the last page of the message
248 * has been received into a partial page.
228 */249 */
229static ssize_t svc_recvfrom(struct svc_rqst *rqstp, struct kvec *iov,250static ssize_t svc_tcp_read_msg(struct svc_rqst *rqstp, size_t buflen,
230 unsigned int nr, size_t buflen, unsigned int base)251 size_t seek)
231{252{
232 struct svc_sock *svsk =253 struct svc_sock *svsk =
233 container_of(rqstp->rq_xprt, struct svc_sock, sk_xprt);254 container_of(rqstp->rq_xprt, struct svc_sock, sk_xprt);
255 struct bio_vec *bvec = rqstp->rq_bvec;
234 struct msghdr msg = { NULL };256 struct msghdr msg = { NULL };
257 unsigned int i;
235 ssize_t len;258 ssize_t len;
259 size_t t;
236 260
237 rqstp->rq_xprt_hlen = 0;261 rqstp->rq_xprt_hlen = 0;
238 262
239 clear_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags);263 clear_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags);
240 iov_iter_kvec(&msg.msg_iter, READ, iov, nr, buflen);264
241 if (base != 0) {265 for (i = 0, t = 0; t < buflen; i++, t += PAGE_SIZE) {
242 iov_iter_advance(&msg.msg_iter, base);266 bvec[i].bv_page = rqstp->rq_pages[i];
243 buflen -= base;267 bvec[i].bv_len = PAGE_SIZE;
268 bvec[i].bv_offset = 0;
269 }
270 rqstp->rq_respages = &rqstp->rq_pages[i];
271 rqstp->rq_next_page = rqstp->rq_respages + 1;
272
273 iov_iter_bvec(&msg.msg_iter, READ, bvec, i, buflen);
274 if (seek) {
275 iov_iter_advance(&msg.msg_iter, seek);
276 buflen -= seek;
244 }277 }
245 len = sock_recvmsg(svsk->sk_sock, &msg, MSG_DONTWAIT);278 len = sock_recvmsg(svsk->sk_sock, &msg, MSG_DONTWAIT);
279 if (len > 0)
280 svc_flush_bvec(bvec, len, seek);
281
246 /* If we read a full record, then assume there may be more282 /* If we read a full record, then assume there may be more
247 * data to read (stream based sockets only!)283 * data to read (stream based sockets only!)
248 */284 */
@@ -775,13 +811,14 @@ failed: · 526 unmodified lines
775 return NULL;811 return NULL;
776}812}
777 813
778static unsigned int svc_tcp_restore_pages(struct svc_sock *svsk, struct svc_rqst *rqstp)814static size_t svc_tcp_restore_pages(struct svc_sock *svsk,
815 struct svc_rqst *rqstp)
779{816{
780 unsigned int i, len, npages;817 size_t len = svsk->sk_datalen;
818 unsigned int i, npages;
781 819
782 if (svsk->sk_datalen == 0)820 if (!len)
783 return 0;821 return 0;
784 len = svsk->sk_datalen;
785 npages = (len + PAGE_SIZE - 1) >> PAGE_SHIFT;822 npages = (len + PAGE_SIZE - 1) >> PAGE_SHIFT;
786 for (i = 0; i < npages; i++) {823 for (i = 0; i < npages; i++) {
787 if (rqstp->rq_pages[i] != NULL)824 if (rqstp->rq_pages[i] != NULL)
@@ -917,20 +954,6 @@ unlock_eagain: · 129 unmodified lines
917 return -EAGAIN;954 return -EAGAIN;
918}955}
919 956
920static int copy_pages_to_kvecs(struct kvec *vec, struct page **pages, int len)
921{
922 int i = 0;
923 int t = 0;
924
925 while (t < len) {
926 vec[i].iov_base = page_address(pages[i]);
927 vec[i].iov_len = PAGE_SIZE;
928 i++;
929 t += PAGE_SIZE;
930 }
931 return i;
932}
933
934static void svc_tcp_fragment_received(struct svc_sock *svsk)957static void svc_tcp_fragment_received(struct svc_sock *svsk)
935{958{
936 /* If we have more data, signal svc_xprt_enqueue() to try again */959 /* If we have more data, signal svc_xprt_enqueue() to try again */
@@ -938,20 +961,33 @@ static void svc_tcp_fragment_received(struct svc_sock *svsk) · 1 unmodified line
938 svsk->sk_marker = xdr_zero;961 svsk->sk_marker = xdr_zero;
939}962}
940 963
941/*964/**
942 * Receive data from a TCP socket.965 * svc_tcp_recvfrom - Receive data from a TCP socket
966 * @rqstp: request structure into which to receive an RPC Call
967 *
968 * Called in a loop when XPT_DATA has been set.
969 *
970 * Read the 4-byte stream record marker, then use the record length
971 * in that marker to set up exactly the resources needed to receive
972 * the next RPC message into @rqstp.
973 *
974 * Returns:
975 * On success, the number of bytes in a received RPC Call, or
976 * %0 if a complete RPC Call message was not ready to return
977 *
978 * The zero return case handles partial receives and callback Replies.
979 * The state of a partial receive is preserved in the svc_sock for
980 * the next call to svc_tcp_recvfrom.
943 */981 */
944static int svc_tcp_recvfrom(struct svc_rqst *rqstp)982static int svc_tcp_recvfrom(struct svc_rqst *rqstp)
945{983{
946 struct svc_sock *svsk =984 struct svc_sock *svsk =
947 container_of(rqstp->rq_xprt, struct svc_sock, sk_xprt);985 container_of(rqstp->rq_xprt, struct svc_sock, sk_xprt);
948 struct svc_serv *serv = svsk->sk_xprt.xpt_server;986 struct svc_serv *serv = svsk->sk_xprt.xpt_server;
949 int len;987 size_t want, base;
950 struct kvec *vec;988 ssize_t len;
951 unsigned int want, base;
952 __be32 *p;989 __be32 *p;
953 __be32 calldir;990 __be32 calldir;
954 int pnum;
955 991
956 clear_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags);992 clear_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags);
957 len = svc_tcp_read_marker(svsk, rqstp);993 len = svc_tcp_read_marker(svsk, rqstp);
@@ -960,16 +996,7 @@ static int svc_tcp_recvfrom(struct svc_rqst *rqstp) · 2 unmodified lines
960 996
961 base = svc_tcp_restore_pages(svsk, rqstp);997 base = svc_tcp_restore_pages(svsk, rqstp);
962 want = len - (svsk->sk_tcplen - sizeof(rpc_fraghdr));998 want = len - (svsk->sk_tcplen - sizeof(rpc_fraghdr));
963 999 len = svc_tcp_read_msg(rqstp, base + want, base);
964 vec = rqstp->rq_vec;
965
966 pnum = copy_pages_to_kvecs(&vec[0], &rqstp->rq_pages[0], base + want);
967
968 rqstp->rq_respages = &rqstp->rq_pages[pnum];
969 rqstp->rq_next_page = rqstp->rq_respages + 1;
970
971 /* Now receive data */
972 len = svc_recvfrom(rqstp, vec, pnum, base + want, base);
973 if (len >= 0) {1000 if (len >= 0) {
974 trace_svcsock_tcp_recv(&svsk->sk_xprt, len);1001 trace_svcsock_tcp_recv(&svsk->sk_xprt, len);
975 svsk->sk_tcplen += len;1002 svsk->sk_tcplen += len;