diff options
| -rw-r--r-- | fs/nfsd/nfs3proc.c | 8 | ||||
| -rw-r--r-- | fs/nfsd/nfs3xdr.c | 16 | ||||
| -rw-r--r-- | fs/nfsd/nfsproc.c | 9 | ||||
| -rw-r--r-- | fs/nfsd/nfsxdr.c | 14 | ||||
| -rw-r--r-- | fs/nfsd/xdr.h | 2 | ||||
| -rw-r--r-- | fs/nfsd/xdr3.h | 2 | ||||
| -rw-r--r-- | include/linux/sunrpc/svc.h | 2 | ||||
| -rw-r--r-- | net/sunrpc/svc.c | 42 |
8 files changed, 65 insertions, 30 deletions
diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c index 1d0ce3c57d93..2dd95ebf4935 100644 --- a/fs/nfsd/nfs3proc.c +++ b/fs/nfsd/nfs3proc.c | |||
| @@ -192,6 +192,7 @@ nfsd3_proc_write(struct svc_rqst *rqstp) | |||
| 192 | struct nfsd3_writeres *resp = rqstp->rq_resp; | 192 | struct nfsd3_writeres *resp = rqstp->rq_resp; |
| 193 | __be32 nfserr; | 193 | __be32 nfserr; |
| 194 | unsigned long cnt = argp->len; | 194 | unsigned long cnt = argp->len; |
| 195 | unsigned int nvecs; | ||
| 195 | 196 | ||
| 196 | dprintk("nfsd: WRITE(3) %s %d bytes at %Lu%s\n", | 197 | dprintk("nfsd: WRITE(3) %s %d bytes at %Lu%s\n", |
| 197 | SVCFH_fmt(&argp->fh), | 198 | SVCFH_fmt(&argp->fh), |
| @@ -201,9 +202,12 @@ nfsd3_proc_write(struct svc_rqst *rqstp) | |||
| 201 | 202 | ||
| 202 | fh_copy(&resp->fh, &argp->fh); | 203 | fh_copy(&resp->fh, &argp->fh); |
| 203 | resp->committed = argp->stable; | 204 | resp->committed = argp->stable; |
| 205 | nvecs = svc_fill_write_vector(rqstp, &argp->first, cnt); | ||
| 206 | if (!nvecs) | ||
| 207 | RETURN_STATUS(nfserr_io); | ||
| 204 | nfserr = nfsd_write(rqstp, &resp->fh, argp->offset, | 208 | nfserr = nfsd_write(rqstp, &resp->fh, argp->offset, |
| 205 | rqstp->rq_vec, argp->vlen, | 209 | rqstp->rq_vec, nvecs, &cnt, |
| 206 | &cnt, resp->committed); | 210 | resp->committed); |
| 207 | resp->count = cnt; | 211 | resp->count = cnt; |
| 208 | RETURN_STATUS(nfserr); | 212 | RETURN_STATUS(nfserr); |
| 209 | } | 213 | } |
diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c index 1a70581e1cb2..e19fc5d8bcb5 100644 --- a/fs/nfsd/nfs3xdr.c +++ b/fs/nfsd/nfs3xdr.c | |||
| @@ -391,7 +391,7 @@ int | |||
| 391 | nfs3svc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p) | 391 | nfs3svc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p) |
| 392 | { | 392 | { |
| 393 | struct nfsd3_writeargs *args = rqstp->rq_argp; | 393 | struct nfsd3_writeargs *args = rqstp->rq_argp; |
| 394 | unsigned int len, v, hdr, dlen; | 394 | unsigned int len, hdr, dlen; |
| 395 | u32 max_blocksize = svc_max_payload(rqstp); | 395 | u32 max_blocksize = svc_max_payload(rqstp); |
| 396 | struct kvec *head = rqstp->rq_arg.head; | 396 | struct kvec *head = rqstp->rq_arg.head; |
| 397 | struct kvec *tail = rqstp->rq_arg.tail; | 397 | struct kvec *tail = rqstp->rq_arg.tail; |
| @@ -433,17 +433,9 @@ nfs3svc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p) | |||
| 433 | args->count = max_blocksize; | 433 | args->count = max_blocksize; |
| 434 | len = args->len = max_blocksize; | 434 | len = args->len = max_blocksize; |
| 435 | } | 435 | } |
| 436 | rqstp->rq_vec[0].iov_base = (void*)p; | 436 | |
| 437 | rqstp->rq_vec[0].iov_len = head->iov_len - hdr; | 437 | args->first.iov_base = (void *)p; |
| 438 | v = 0; | 438 | args->first.iov_len = head->iov_len - hdr; |
| 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; | ||
| 447 | return 1; | 439 | return 1; |
| 448 | } | 440 | } |
| 449 | 441 | ||
diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c index 43c0419b8ddb..1995ea6bfd2b 100644 --- a/fs/nfsd/nfsproc.c +++ b/fs/nfsd/nfsproc.c | |||
| @@ -212,13 +212,18 @@ nfsd_proc_write(struct svc_rqst *rqstp) | |||
| 212 | struct nfsd_attrstat *resp = rqstp->rq_resp; | 212 | struct nfsd_attrstat *resp = rqstp->rq_resp; |
| 213 | __be32 nfserr; | 213 | __be32 nfserr; |
| 214 | unsigned long cnt = argp->len; | 214 | unsigned long cnt = argp->len; |
| 215 | unsigned int nvecs; | ||
| 215 | 216 | ||
| 216 | dprintk("nfsd: WRITE %s %d bytes at %d\n", | 217 | dprintk("nfsd: WRITE %s %d bytes at %d\n", |
| 217 | SVCFH_fmt(&argp->fh), | 218 | SVCFH_fmt(&argp->fh), |
| 218 | argp->len, argp->offset); | 219 | argp->len, argp->offset); |
| 219 | 220 | ||
| 220 | nfserr = nfsd_write(rqstp, fh_copy(&resp->fh, &argp->fh), argp->offset, | 221 | nvecs = svc_fill_write_vector(rqstp, &argp->first, cnt); |
| 221 | rqstp->rq_vec, argp->vlen, &cnt, NFS_DATA_SYNC); | 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); | ||
| 222 | return nfsd_return_attrs(nfserr, resp); | 227 | return nfsd_return_attrs(nfserr, resp); |
| 223 | } | 228 | } |
| 224 | 229 | ||
diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c index 79b6064f8977..db24ae8b67e0 100644 --- a/fs/nfsd/nfsxdr.c +++ b/fs/nfsd/nfsxdr.c | |||
| @@ -287,7 +287,6 @@ nfssvc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p) | |||
| 287 | struct nfsd_writeargs *args = rqstp->rq_argp; | 287 | struct nfsd_writeargs *args = rqstp->rq_argp; |
| 288 | unsigned int len, hdr, dlen; | 288 | unsigned int len, hdr, dlen; |
| 289 | struct kvec *head = rqstp->rq_arg.head; | 289 | struct kvec *head = rqstp->rq_arg.head; |
| 290 | int v; | ||
| 291 | 290 | ||
| 292 | p = decode_fh(p, &args->fh); | 291 | p = decode_fh(p, &args->fh); |
| 293 | if (!p) | 292 | if (!p) |
| @@ -323,17 +322,8 @@ nfssvc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p) | |||
| 323 | if (dlen < XDR_QUADLEN(len)*4) | 322 | if (dlen < XDR_QUADLEN(len)*4) |
| 324 | return 0; | 323 | return 0; |
| 325 | 324 | ||
| 326 | rqstp->rq_vec[0].iov_base = (void*)p; | 325 | args->first.iov_base = (void *)p; |
| 327 | rqstp->rq_vec[0].iov_len = head->iov_len - hdr; | 326 | args->first.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; | ||
| 337 | return 1; | 327 | return 1; |
| 338 | } | 328 | } |
| 339 | 329 | ||
diff --git a/fs/nfsd/xdr.h b/fs/nfsd/xdr.h index 2f4f22e6b8cb..a765c414015e 100644 --- a/fs/nfsd/xdr.h +++ b/fs/nfsd/xdr.h | |||
| @@ -34,7 +34,7 @@ struct nfsd_writeargs { | |||
| 34 | svc_fh fh; | 34 | svc_fh fh; |
| 35 | __u32 offset; | 35 | __u32 offset; |
| 36 | int len; | 36 | int len; |
| 37 | int vlen; | 37 | struct kvec first; |
| 38 | }; | 38 | }; |
| 39 | 39 | ||
| 40 | struct nfsd_createargs { | 40 | struct nfsd_createargs { |
diff --git a/fs/nfsd/xdr3.h b/fs/nfsd/xdr3.h index 056bf8a7364e..deccf7f691e9 100644 --- a/fs/nfsd/xdr3.h +++ b/fs/nfsd/xdr3.h | |||
| @@ -41,7 +41,7 @@ struct nfsd3_writeargs { | |||
| 41 | __u32 count; | 41 | __u32 count; |
| 42 | int stable; | 42 | int stable; |
| 43 | __u32 len; | 43 | __u32 len; |
| 44 | int vlen; | 44 | struct kvec first; |
| 45 | }; | 45 | }; |
| 46 | 46 | ||
| 47 | struct nfsd3_createargs { | 47 | struct nfsd3_createargs { |
diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h index dc4c009deec1..fb3fcacc1e98 100644 --- a/include/linux/sunrpc/svc.h +++ b/include/linux/sunrpc/svc.h | |||
| @@ -495,6 +495,8 @@ void svc_wake_up(struct svc_serv *); | |||
| 495 | void svc_reserve(struct svc_rqst *rqstp, int space); | 495 | void svc_reserve(struct svc_rqst *rqstp, int space); |
| 496 | struct svc_pool * svc_pool_for_cpu(struct svc_serv *serv, int cpu); | 496 | struct svc_pool * svc_pool_for_cpu(struct svc_serv *serv, int cpu); |
| 497 | char * svc_print_addr(struct svc_rqst *, char *, size_t); | 497 | 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); | ||
| 498 | 500 | ||
| 499 | #define RPC_MAX_ADDRBUFLEN (63U) | 501 | #define RPC_MAX_ADDRBUFLEN (63U) |
| 500 | 502 | ||
diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c index f19987f5d3b5..a155e2de19aa 100644 --- a/net/sunrpc/svc.c +++ b/net/sunrpc/svc.c | |||
| @@ -1533,3 +1533,45 @@ u32 svc_max_payload(const struct svc_rqst *rqstp) | |||
| 1533 | return max; | 1533 | return max; |
| 1534 | } | 1534 | } |
| 1535 | EXPORT_SYMBOL_GPL(svc_max_payload); | 1535 | 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); | ||
