aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/nfsd/nfs3proc.c8
-rw-r--r--fs/nfsd/nfs3xdr.c16
-rw-r--r--fs/nfsd/nfsproc.c9
-rw-r--r--fs/nfsd/nfsxdr.c14
-rw-r--r--fs/nfsd/xdr.h2
-rw-r--r--fs/nfsd/xdr3.h2
-rw-r--r--include/linux/sunrpc/svc.h2
-rw-r--r--net/sunrpc/svc.c42
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
391nfs3svc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p) 391nfs3svc_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
40struct nfsd_createargs { 40struct 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
47struct nfsd3_createargs { 47struct 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 *);
495void svc_reserve(struct svc_rqst *rqstp, int space); 495void svc_reserve(struct svc_rqst *rqstp, int space);
496struct svc_pool * svc_pool_for_cpu(struct svc_serv *serv, int cpu); 496struct svc_pool * svc_pool_for_cpu(struct svc_serv *serv, int cpu);
497char * svc_print_addr(struct svc_rqst *, char *, size_t); 497char * svc_print_addr(struct svc_rqst *, char *, size_t);
498unsigned 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}
1535EXPORT_SYMBOL_GPL(svc_max_payload); 1535EXPORT_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 */
1545unsigned 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}
1577EXPORT_SYMBOL_GPL(svc_fill_write_vector);