Skip to content

Commit 8154ef2

Browse files
chuckleverJ. Bruce Fields
authored andcommitted
NFSD: Clean up legacy NFS WRITE argument XDR decoders
Move common code in NFSD's legacy NFS WRITE decoders into a helper. The immediate benefit is reduction of code duplication and some nice micro-optimizations (see below). In the long term, this helper can perform a per-transport call-out to fill the rq_vec (say, using RDMA Reads). The legacy WRITE decoders and procs are changed to work like NFSv4, which constructs the rq_vec just before it is about to call vfs_writev. Why? Calling a transport call-out from the proc instead of the XDR decoder means that the incoming FH can be resolved to a particular filesystem and file. This would allow pages from the backing file to be presented to the transport to be filled, rather than presenting anonymous pages and copying or flipping them into the file's page cache later. I also prefer using the pages in rq_arg.pages, instead of pulling the data pages directly out of the rqstp::rq_pages array. This is currently the way the NFSv3 write decoder works, but the other two do not seem to take this approach. Fixing this removes the only reference to rq_pages found in NFSD, eliminating an NFSD assumption about how transports use the pages in rq_pages. Lastly, avoid setting up the first element of rq_vec as a zero- length buffer. This happens with an RDMA transport when a normal Read chunk is present because the data payload is in rq_arg's page list (none of it is in the head buffer). Signed-off-by: Chuck Lever <chuck.lever@oracle.com> Signed-off-by: J. Bruce Fields <bfields@redhat.com>
1 parent fff4080 commit 8154ef2

File tree

8 files changed

+65
-30
lines changed

8 files changed

+65
-30
lines changed

fs/nfsd/nfs3proc.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,7 @@ nfsd3_proc_write(struct svc_rqst *rqstp)
192192
struct nfsd3_writeres *resp = rqstp->rq_resp;
193193
__be32 nfserr;
194194
unsigned long cnt = argp->len;
195+
unsigned int nvecs;
195196

196197
dprintk("nfsd: WRITE(3) %s %d bytes at %Lu%s\n",
197198
SVCFH_fmt(&argp->fh),
@@ -201,9 +202,12 @@ nfsd3_proc_write(struct svc_rqst *rqstp)
201202

202203
fh_copy(&resp->fh, &argp->fh);
203204
resp->committed = argp->stable;
205+
nvecs = svc_fill_write_vector(rqstp, &argp->first, cnt);
206+
if (!nvecs)
207+
RETURN_STATUS(nfserr_io);
204208
nfserr = nfsd_write(rqstp, &resp->fh, argp->offset,
205-
rqstp->rq_vec, argp->vlen,
206-
&cnt, resp->committed);
209+
rqstp->rq_vec, nvecs, &cnt,
210+
resp->committed);
207211
resp->count = cnt;
208212
RETURN_STATUS(nfserr);
209213
}

fs/nfsd/nfs3xdr.c

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -391,7 +391,7 @@ int
391391
nfs3svc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p)
392392
{
393393
struct nfsd3_writeargs *args = rqstp->rq_argp;
394-
unsigned int len, v, hdr, dlen;
394+
unsigned int len, hdr, dlen;
395395
u32 max_blocksize = svc_max_payload(rqstp);
396396
struct kvec *head = rqstp->rq_arg.head;
397397
struct kvec *tail = rqstp->rq_arg.tail;
@@ -433,17 +433,9 @@ nfs3svc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p)
433433
args->count = max_blocksize;
434434
len = args->len = max_blocksize;
435435
}
436-
rqstp->rq_vec[0].iov_base = (void*)p;
437-
rqstp->rq_vec[0].iov_len = head->iov_len - hdr;
438-
v = 0;
439-
while (len > rqstp->rq_vec[v].iov_len) {
440-
len -= rqstp->rq_vec[v].iov_len;
441-
v++;
442-
rqstp->rq_vec[v].iov_base = page_address(rqstp->rq_pages[v]);
443-
rqstp->rq_vec[v].iov_len = PAGE_SIZE;
444-
}
445-
rqstp->rq_vec[v].iov_len = len;
446-
args->vlen = v + 1;
436+
437+
args->first.iov_base = (void *)p;
438+
args->first.iov_len = head->iov_len - hdr;
447439
return 1;
448440
}
449441

fs/nfsd/nfsproc.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -212,13 +212,18 @@ nfsd_proc_write(struct svc_rqst *rqstp)
212212
struct nfsd_attrstat *resp = rqstp->rq_resp;
213213
__be32 nfserr;
214214
unsigned long cnt = argp->len;
215+
unsigned int nvecs;
215216

216217
dprintk("nfsd: WRITE %s %d bytes at %d\n",
217218
SVCFH_fmt(&argp->fh),
218219
argp->len, argp->offset);
219220

220-
nfserr = nfsd_write(rqstp, fh_copy(&resp->fh, &argp->fh), argp->offset,
221-
rqstp->rq_vec, argp->vlen, &cnt, NFS_DATA_SYNC);
221+
nvecs = svc_fill_write_vector(rqstp, &argp->first, cnt);
222+
if (!nvecs)
223+
return nfserr_io;
224+
nfserr = nfsd_write(rqstp, fh_copy(&resp->fh, &argp->fh),
225+
argp->offset, rqstp->rq_vec, nvecs,
226+
&cnt, NFS_DATA_SYNC);
222227
return nfsd_return_attrs(nfserr, resp);
223228
}
224229

fs/nfsd/nfsxdr.c

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -287,7 +287,6 @@ nfssvc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p)
287287
struct nfsd_writeargs *args = rqstp->rq_argp;
288288
unsigned int len, hdr, dlen;
289289
struct kvec *head = rqstp->rq_arg.head;
290-
int v;
291290

292291
p = decode_fh(p, &args->fh);
293292
if (!p)
@@ -323,17 +322,8 @@ nfssvc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p)
323322
if (dlen < XDR_QUADLEN(len)*4)
324323
return 0;
325324

326-
rqstp->rq_vec[0].iov_base = (void*)p;
327-
rqstp->rq_vec[0].iov_len = head->iov_len - hdr;
328-
v = 0;
329-
while (len > rqstp->rq_vec[v].iov_len) {
330-
len -= rqstp->rq_vec[v].iov_len;
331-
v++;
332-
rqstp->rq_vec[v].iov_base = page_address(rqstp->rq_pages[v]);
333-
rqstp->rq_vec[v].iov_len = PAGE_SIZE;
334-
}
335-
rqstp->rq_vec[v].iov_len = len;
336-
args->vlen = v + 1;
325+
args->first.iov_base = (void *)p;
326+
args->first.iov_len = head->iov_len - hdr;
337327
return 1;
338328
}
339329

fs/nfsd/xdr.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ struct nfsd_writeargs {
3434
svc_fh fh;
3535
__u32 offset;
3636
int len;
37-
int vlen;
37+
struct kvec first;
3838
};
3939

4040
struct nfsd_createargs {

fs/nfsd/xdr3.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ struct nfsd3_writeargs {
4141
__u32 count;
4242
int stable;
4343
__u32 len;
44-
int vlen;
44+
struct kvec first;
4545
};
4646

4747
struct nfsd3_createargs {

include/linux/sunrpc/svc.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -495,6 +495,8 @@ void svc_wake_up(struct svc_serv *);
495495
void svc_reserve(struct svc_rqst *rqstp, int space);
496496
struct svc_pool * svc_pool_for_cpu(struct svc_serv *serv, int cpu);
497497
char * svc_print_addr(struct svc_rqst *, char *, size_t);
498+
unsigned int svc_fill_write_vector(struct svc_rqst *rqstp,
499+
struct kvec *first, size_t total);
498500

499501
#define RPC_MAX_ADDRBUFLEN (63U)
500502

net/sunrpc/svc.c

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1533,3 +1533,45 @@ u32 svc_max_payload(const struct svc_rqst *rqstp)
15331533
return max;
15341534
}
15351535
EXPORT_SYMBOL_GPL(svc_max_payload);
1536+
1537+
/**
1538+
* svc_fill_write_vector - Construct data argument for VFS write call
1539+
* @rqstp: svc_rqst to operate on
1540+
* @first: buffer containing first section of write payload
1541+
* @total: total number of bytes of write payload
1542+
*
1543+
* Returns the number of elements populated in the data argument array.
1544+
*/
1545+
unsigned int svc_fill_write_vector(struct svc_rqst *rqstp, struct kvec *first,
1546+
size_t total)
1547+
{
1548+
struct kvec *vec = rqstp->rq_vec;
1549+
struct page **pages;
1550+
unsigned int i;
1551+
1552+
/* Some types of transport can present the write payload
1553+
* entirely in rq_arg.pages. In this case, @first is empty.
1554+
*/
1555+
i = 0;
1556+
if (first->iov_len) {
1557+
vec[i].iov_base = first->iov_base;
1558+
vec[i].iov_len = min_t(size_t, total, first->iov_len);
1559+
total -= vec[i].iov_len;
1560+
++i;
1561+
}
1562+
1563+
WARN_ON_ONCE(rqstp->rq_arg.page_base != 0);
1564+
pages = rqstp->rq_arg.pages;
1565+
while (total) {
1566+
vec[i].iov_base = page_address(*pages);
1567+
vec[i].iov_len = min_t(size_t, total, PAGE_SIZE);
1568+
total -= vec[i].iov_len;
1569+
++i;
1570+
1571+
++pages;
1572+
}
1573+
1574+
WARN_ON_ONCE(i > ARRAY_SIZE(rqstp->rq_vec));
1575+
return i;
1576+
}
1577+
EXPORT_SYMBOL_GPL(svc_fill_write_vector);

0 commit comments

Comments
 (0)