Skip to content

Commit 2eb2b93

Browse files
committed
SUNRPC: Convert svc_tcp_sendmsg to use bio_vecs directly
Add a helper to convert a whole xdr_buf directly into an array of bio_vecs, then send this array instead of iterating piecemeal over the xdr_buf containing the outbound RPC message. Reviewed-by: David Howells <[email protected]> Signed-off-by: Chuck Lever <[email protected]>
1 parent d424797 commit 2eb2b93

File tree

3 files changed

+72
-44
lines changed

3 files changed

+72
-44
lines changed

include/linux/sunrpc/xdr.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,8 @@ void xdr_terminate_string(const struct xdr_buf *, const u32);
139139
size_t xdr_buf_pagecount(const struct xdr_buf *buf);
140140
int xdr_alloc_bvec(struct xdr_buf *buf, gfp_t gfp);
141141
void xdr_free_bvec(struct xdr_buf *buf);
142+
unsigned int xdr_buf_to_bvec(struct bio_vec *bvec, unsigned int bvec_size,
143+
const struct xdr_buf *xdr);
142144

143145
static inline __be32 *xdr_encode_array(__be32 *p, const void *s, unsigned int len)
144146
{

net/sunrpc/svcsock.c

Lines changed: 20 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@
3636
#include <linux/skbuff.h>
3737
#include <linux/file.h>
3838
#include <linux/freezer.h>
39+
#include <linux/bvec.h>
40+
3941
#include <net/sock.h>
4042
#include <net/checksum.h>
4143
#include <net/ip.h>
@@ -1194,77 +1196,52 @@ static int svc_tcp_recvfrom(struct svc_rqst *rqstp)
11941196
return 0; /* record not complete */
11951197
}
11961198

1197-
static int svc_tcp_send_kvec(struct socket *sock, const struct kvec *vec,
1198-
int flags)
1199-
{
1200-
struct msghdr msg = { .msg_flags = MSG_SPLICE_PAGES | flags, };
1201-
1202-
iov_iter_kvec(&msg.msg_iter, ITER_SOURCE, vec, 1, vec->iov_len);
1203-
return sock_sendmsg(sock, &msg);
1204-
}
1205-
12061199
/*
12071200
* MSG_SPLICE_PAGES is used exclusively to reduce the number of
12081201
* copy operations in this path. Therefore the caller must ensure
12091202
* that the pages backing @xdr are unchanging.
12101203
*
1211-
* In addition, the logic assumes that * .bv_len is never larger
1212-
* than PAGE_SIZE.
1204+
* Note that the send is non-blocking. The caller has incremented
1205+
* the reference count on each page backing the RPC message, and
1206+
* the network layer will "put" these pages when transmission is
1207+
* complete.
1208+
*
1209+
* This is safe for our RPC services because the memory backing
1210+
* the head and tail components is never kmalloc'd. These always
1211+
* come from pages in the svc_rqst::rq_pages array.
12131212
*/
1214-
static int svc_tcp_sendmsg(struct socket *sock, struct xdr_buf *xdr,
1213+
static int svc_tcp_sendmsg(struct svc_sock *svsk, struct svc_rqst *rqstp,
12151214
rpc_fraghdr marker, unsigned int *sentp)
12161215
{
1217-
const struct kvec *head = xdr->head;
1218-
const struct kvec *tail = xdr->tail;
12191216
struct kvec rm = {
12201217
.iov_base = &marker,
12211218
.iov_len = sizeof(marker),
12221219
};
12231220
struct msghdr msg = {
1224-
.msg_flags = 0,
1221+
.msg_flags = MSG_MORE,
12251222
};
1223+
unsigned int count;
12261224
int ret;
12271225

12281226
*sentp = 0;
1229-
ret = xdr_alloc_bvec(xdr, GFP_KERNEL);
1230-
if (ret < 0)
1231-
return ret;
12321227

1233-
ret = kernel_sendmsg(sock, &msg, &rm, 1, rm.iov_len);
1228+
ret = kernel_sendmsg(svsk->sk_sock, &msg, &rm, 1, rm.iov_len);
12341229
if (ret < 0)
12351230
return ret;
12361231
*sentp += ret;
12371232
if (ret != rm.iov_len)
12381233
return -EAGAIN;
12391234

1240-
ret = svc_tcp_send_kvec(sock, head, 0);
1241-
if (ret < 0)
1242-
return ret;
1243-
*sentp += ret;
1244-
if (ret != head->iov_len)
1245-
goto out;
1246-
1247-
if (xdr_buf_pagecount(xdr)) {
1248-
xdr->bvec[0].bv_offset = offset_in_page(xdr->page_base);
1249-
xdr->bvec[0].bv_len -= offset_in_page(xdr->page_base);
1250-
}
1235+
count = xdr_buf_to_bvec(rqstp->rq_bvec, ARRAY_SIZE(rqstp->rq_bvec),
1236+
&rqstp->rq_res);
12511237

12521238
msg.msg_flags = MSG_SPLICE_PAGES;
1253-
iov_iter_bvec(&msg.msg_iter, ITER_SOURCE, xdr->bvec,
1254-
xdr_buf_pagecount(xdr), xdr->page_len);
1255-
ret = sock_sendmsg(sock, &msg);
1239+
iov_iter_bvec(&msg.msg_iter, ITER_SOURCE, rqstp->rq_bvec,
1240+
count, rqstp->rq_res.len);
1241+
ret = sock_sendmsg(svsk->sk_sock, &msg);
12561242
if (ret < 0)
12571243
return ret;
12581244
*sentp += ret;
1259-
1260-
if (tail->iov_len) {
1261-
ret = svc_tcp_send_kvec(sock, tail, 0);
1262-
if (ret < 0)
1263-
return ret;
1264-
*sentp += ret;
1265-
}
1266-
1267-
out:
12681245
return 0;
12691246
}
12701247

@@ -1295,8 +1272,7 @@ static int svc_tcp_sendto(struct svc_rqst *rqstp)
12951272
if (svc_xprt_is_dead(xprt))
12961273
goto out_notconn;
12971274
tcp_sock_set_cork(svsk->sk_sk, true);
1298-
err = svc_tcp_sendmsg(svsk->sk_sock, xdr, marker, &sent);
1299-
xdr_free_bvec(xdr);
1275+
err = svc_tcp_sendmsg(svsk, rqstp, marker, &sent);
13001276
trace_svcsock_tcp_send(xprt, err < 0 ? (long)err : sent);
13011277
if (err < 0 || sent != (xdr->len + sizeof(marker)))
13021278
goto out_close;

net/sunrpc/xdr.c

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,56 @@ xdr_free_bvec(struct xdr_buf *buf)
164164
buf->bvec = NULL;
165165
}
166166

167+
/**
168+
* xdr_buf_to_bvec - Copy components of an xdr_buf into a bio_vec array
169+
* @bvec: bio_vec array to populate
170+
* @bvec_size: element count of @bio_vec
171+
* @xdr: xdr_buf to be copied
172+
*
173+
* Returns the number of entries consumed in @bvec.
174+
*/
175+
unsigned int xdr_buf_to_bvec(struct bio_vec *bvec, unsigned int bvec_size,
176+
const struct xdr_buf *xdr)
177+
{
178+
const struct kvec *head = xdr->head;
179+
const struct kvec *tail = xdr->tail;
180+
unsigned int count = 0;
181+
182+
if (head->iov_len) {
183+
bvec_set_virt(bvec++, head->iov_base, head->iov_len);
184+
++count;
185+
}
186+
187+
if (xdr->page_len) {
188+
unsigned int offset, len, remaining;
189+
struct page **pages = xdr->pages;
190+
191+
offset = offset_in_page(xdr->page_base);
192+
remaining = xdr->page_len;
193+
while (remaining > 0) {
194+
len = min_t(unsigned int, remaining,
195+
PAGE_SIZE - offset);
196+
bvec_set_page(bvec++, *pages++, len, offset);
197+
remaining -= len;
198+
offset = 0;
199+
if (unlikely(++count > bvec_size))
200+
goto bvec_overflow;
201+
}
202+
}
203+
204+
if (tail->iov_len) {
205+
bvec_set_virt(bvec, tail->iov_base, tail->iov_len);
206+
if (unlikely(++count > bvec_size))
207+
goto bvec_overflow;
208+
}
209+
210+
return count;
211+
212+
bvec_overflow:
213+
pr_warn_once("%s: bio_vec array overflow\n", __func__);
214+
return count - 1;
215+
}
216+
167217
/**
168218
* xdr_inline_pages - Prepare receive buffer for a large reply
169219
* @xdr: xdr_buf into which reply will be placed

0 commit comments

Comments
 (0)