Skip to content

Commit ca07eda

Browse files
committed
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. Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
1 parent cca557a commit ca07eda

File tree

2 files changed

+69
-41
lines changed

2 files changed

+69
-41
lines changed

include/linux/sunrpc/svc.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,7 @@ struct svc_rqst {
254254
struct page * *rq_page_end; /* one past the last page */
255255

256256
struct kvec rq_vec[RPCSVC_MAXPAGES]; /* generally useful.. */
257+
struct bio_vec rq_bvec[RPCSVC_MAXPAGES];
257258

258259
__be32 rq_xid; /* transmission id */
259260
u32 rq_prog; /* program number */

net/sunrpc/svcsock.c

Lines changed: 68 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -223,26 +223,62 @@ static int svc_one_sock_name(struct svc_sock *svsk, char *buf, int remaining)
223223
return len;
224224
}
225225

226+
#if ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE
227+
static 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
239+
static inline void svc_flush_bvec(const struct bio_vec *bvec, size_t size,
240+
size_t seek)
241+
{
242+
}
243+
#endif
244+
226245
/*
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.
228249
*/
229-
static ssize_t svc_recvfrom(struct svc_rqst *rqstp, struct kvec *iov,
230-
unsigned int nr, size_t buflen, unsigned int base)
250+
static ssize_t svc_tcp_read_msg(struct svc_rqst *rqstp, size_t buflen,
251+
size_t seek)
231252
{
232253
struct svc_sock *svsk =
233254
container_of(rqstp->rq_xprt, struct svc_sock, sk_xprt);
255+
struct bio_vec *bvec = rqstp->rq_bvec;
234256
struct msghdr msg = { NULL };
257+
unsigned int i;
235258
ssize_t len;
259+
size_t t;
236260

237261
rqstp->rq_xprt_hlen = 0;
238262

239263
clear_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags);
240-
iov_iter_kvec(&msg.msg_iter, READ, iov, nr, buflen);
241-
if (base != 0) {
242-
iov_iter_advance(&msg.msg_iter, base);
243-
buflen -= base;
264+
265+
for (i = 0, t = 0; t < buflen; i++, t += PAGE_SIZE) {
266+
bvec[i].bv_page = rqstp->rq_pages[i];
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;
244277
}
245278
len = sock_recvmsg(svsk->sk_sock, &msg, MSG_DONTWAIT);
279+
if (len > 0)
280+
svc_flush_bvec(bvec, len, seek);
281+
246282
/* If we read a full record, then assume there may be more
247283
* data to read (stream based sockets only!)
248284
*/
@@ -775,13 +811,14 @@ static struct svc_xprt *svc_tcp_accept(struct svc_xprt *xprt)
775811
return NULL;
776812
}
777813

778-
static unsigned int svc_tcp_restore_pages(struct svc_sock *svsk, struct svc_rqst *rqstp)
814+
static size_t svc_tcp_restore_pages(struct svc_sock *svsk,
815+
struct svc_rqst *rqstp)
779816
{
780-
unsigned int i, len, npages;
817+
size_t len = svsk->sk_datalen;
818+
unsigned int i, npages;
781819

782-
if (svsk->sk_datalen == 0)
820+
if (!len)
783821
return 0;
784-
len = svsk->sk_datalen;
785822
npages = (len + PAGE_SIZE - 1) >> PAGE_SHIFT;
786823
for (i = 0; i < npages; i++) {
787824
if (rqstp->rq_pages[i] != NULL)
@@ -917,41 +954,40 @@ static int receive_cb_reply(struct svc_sock *svsk, struct svc_rqst *rqstp)
917954
return -EAGAIN;
918955
}
919956

920-
static 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-
934957
static void svc_tcp_fragment_received(struct svc_sock *svsk)
935958
{
936959
/* If we have more data, signal svc_xprt_enqueue() to try again */
937960
svsk->sk_tcplen = 0;
938961
svsk->sk_marker = xdr_zero;
939962
}
940963

941-
/*
942-
* Receive data from a TCP socket.
964+
/**
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.
943981
*/
944982
static int svc_tcp_recvfrom(struct svc_rqst *rqstp)
945983
{
946984
struct svc_sock *svsk =
947985
container_of(rqstp->rq_xprt, struct svc_sock, sk_xprt);
948986
struct svc_serv *serv = svsk->sk_xprt.xpt_server;
949-
int len;
950-
struct kvec *vec;
951-
unsigned int want, base;
987+
size_t want, base;
988+
ssize_t len;
952989
__be32 *p;
953990
__be32 calldir;
954-
int pnum;
955991

956992
clear_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags);
957993
len = svc_tcp_read_marker(svsk, rqstp);
@@ -960,16 +996,7 @@ static int svc_tcp_recvfrom(struct svc_rqst *rqstp)
960996

961997
base = svc_tcp_restore_pages(svsk, rqstp);
962998
want = len - (svsk->sk_tcplen - sizeof(rpc_fraghdr));
963-
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);
999+
len = svc_tcp_read_msg(rqstp, base + want, base);
9731000
if (len >= 0) {
9741001
trace_svcsock_tcp_recv(&svsk->sk_xprt, len);
9751002
svsk->sk_tcplen += len;

0 commit comments

Comments
 (0)