diff options
| -rw-r--r-- | fs/nfs/nfs4proc.c | 57 | ||||
| -rw-r--r-- | fs/nfs/pnfs.c | 39 | ||||
| -rw-r--r-- | fs/nfs/pnfs.h | 2 |
3 files changed, 58 insertions, 40 deletions
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index a99a8d948721..6a78d49da5c1 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
| @@ -6223,11 +6223,58 @@ static void nfs4_layoutget_done(struct rpc_task *task, void *calldata) | |||
| 6223 | dprintk("<-- %s\n", __func__); | 6223 | dprintk("<-- %s\n", __func__); |
| 6224 | } | 6224 | } |
| 6225 | 6225 | ||
| 6226 | static size_t max_response_pages(struct nfs_server *server) | ||
| 6227 | { | ||
| 6228 | u32 max_resp_sz = server->nfs_client->cl_session->fc_attrs.max_resp_sz; | ||
| 6229 | return nfs_page_array_len(0, max_resp_sz); | ||
| 6230 | } | ||
| 6231 | |||
| 6232 | static void nfs4_free_pages(struct page **pages, size_t size) | ||
| 6233 | { | ||
| 6234 | int i; | ||
| 6235 | |||
| 6236 | if (!pages) | ||
| 6237 | return; | ||
| 6238 | |||
| 6239 | for (i = 0; i < size; i++) { | ||
| 6240 | if (!pages[i]) | ||
| 6241 | break; | ||
| 6242 | __free_page(pages[i]); | ||
| 6243 | } | ||
| 6244 | kfree(pages); | ||
| 6245 | } | ||
| 6246 | |||
| 6247 | static struct page **nfs4_alloc_pages(size_t size, gfp_t gfp_flags) | ||
| 6248 | { | ||
| 6249 | struct page **pages; | ||
| 6250 | int i; | ||
| 6251 | |||
| 6252 | pages = kcalloc(size, sizeof(struct page *), gfp_flags); | ||
| 6253 | if (!pages) { | ||
| 6254 | dprintk("%s: can't alloc array of %zu pages\n", __func__, size); | ||
| 6255 | return NULL; | ||
| 6256 | } | ||
| 6257 | |||
| 6258 | for (i = 0; i < size; i++) { | ||
| 6259 | pages[i] = alloc_page(gfp_flags); | ||
| 6260 | if (!pages[i]) { | ||
| 6261 | dprintk("%s: failed to allocate page\n", __func__); | ||
| 6262 | nfs4_free_pages(pages, size); | ||
| 6263 | return NULL; | ||
| 6264 | } | ||
| 6265 | } | ||
| 6266 | |||
| 6267 | return pages; | ||
| 6268 | } | ||
| 6269 | |||
| 6226 | static void nfs4_layoutget_release(void *calldata) | 6270 | static void nfs4_layoutget_release(void *calldata) |
| 6227 | { | 6271 | { |
| 6228 | struct nfs4_layoutget *lgp = calldata; | 6272 | struct nfs4_layoutget *lgp = calldata; |
| 6273 | struct nfs_server *server = NFS_SERVER(lgp->args.inode); | ||
| 6274 | size_t max_pages = max_response_pages(server); | ||
| 6229 | 6275 | ||
| 6230 | dprintk("--> %s\n", __func__); | 6276 | dprintk("--> %s\n", __func__); |
| 6277 | nfs4_free_pages(lgp->args.layout.pages, max_pages); | ||
| 6231 | put_nfs_open_context(lgp->args.ctx); | 6278 | put_nfs_open_context(lgp->args.ctx); |
| 6232 | kfree(calldata); | 6279 | kfree(calldata); |
| 6233 | dprintk("<-- %s\n", __func__); | 6280 | dprintk("<-- %s\n", __func__); |
| @@ -6239,9 +6286,10 @@ static const struct rpc_call_ops nfs4_layoutget_call_ops = { | |||
| 6239 | .rpc_release = nfs4_layoutget_release, | 6286 | .rpc_release = nfs4_layoutget_release, |
| 6240 | }; | 6287 | }; |
| 6241 | 6288 | ||
| 6242 | int nfs4_proc_layoutget(struct nfs4_layoutget *lgp) | 6289 | int nfs4_proc_layoutget(struct nfs4_layoutget *lgp, gfp_t gfp_flags) |
| 6243 | { | 6290 | { |
| 6244 | struct nfs_server *server = NFS_SERVER(lgp->args.inode); | 6291 | struct nfs_server *server = NFS_SERVER(lgp->args.inode); |
| 6292 | size_t max_pages = max_response_pages(server); | ||
| 6245 | struct rpc_task *task; | 6293 | struct rpc_task *task; |
| 6246 | struct rpc_message msg = { | 6294 | struct rpc_message msg = { |
| 6247 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LAYOUTGET], | 6295 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LAYOUTGET], |
| @@ -6259,6 +6307,13 @@ int nfs4_proc_layoutget(struct nfs4_layoutget *lgp) | |||
| 6259 | 6307 | ||
| 6260 | dprintk("--> %s\n", __func__); | 6308 | dprintk("--> %s\n", __func__); |
| 6261 | 6309 | ||
| 6310 | lgp->args.layout.pages = nfs4_alloc_pages(max_pages, gfp_flags); | ||
| 6311 | if (!lgp->args.layout.pages) { | ||
| 6312 | nfs4_layoutget_release(lgp); | ||
| 6313 | return -ENOMEM; | ||
| 6314 | } | ||
| 6315 | lgp->args.layout.pglen = max_pages * PAGE_SIZE; | ||
| 6316 | |||
| 6262 | lgp->res.layoutp = &lgp->args.layout; | 6317 | lgp->res.layoutp = &lgp->args.layout; |
| 6263 | lgp->res.seq_res.sr_slot = NULL; | 6318 | lgp->res.seq_res.sr_slot = NULL; |
| 6264 | nfs41_init_sequence(&lgp->args.seq_args, &lgp->res.seq_res, 0); | 6319 | nfs41_init_sequence(&lgp->args.seq_args, &lgp->res.seq_res, 0); |
diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c index 76875bfcf19c..2e00feacd4be 100644 --- a/fs/nfs/pnfs.c +++ b/fs/nfs/pnfs.c | |||
| @@ -583,9 +583,6 @@ send_layoutget(struct pnfs_layout_hdr *lo, | |||
| 583 | struct nfs_server *server = NFS_SERVER(ino); | 583 | struct nfs_server *server = NFS_SERVER(ino); |
| 584 | struct nfs4_layoutget *lgp; | 584 | struct nfs4_layoutget *lgp; |
| 585 | struct pnfs_layout_segment *lseg = NULL; | 585 | struct pnfs_layout_segment *lseg = NULL; |
| 586 | struct page **pages = NULL; | ||
| 587 | int i; | ||
| 588 | u32 max_resp_sz, max_pages; | ||
| 589 | 586 | ||
| 590 | dprintk("--> %s\n", __func__); | 587 | dprintk("--> %s\n", __func__); |
| 591 | 588 | ||
| @@ -594,20 +591,6 @@ send_layoutget(struct pnfs_layout_hdr *lo, | |||
| 594 | if (lgp == NULL) | 591 | if (lgp == NULL) |
| 595 | return NULL; | 592 | return NULL; |
| 596 | 593 | ||
| 597 | /* allocate pages for xdr post processing */ | ||
| 598 | max_resp_sz = server->nfs_client->cl_session->fc_attrs.max_resp_sz; | ||
| 599 | max_pages = nfs_page_array_len(0, max_resp_sz); | ||
| 600 | |||
| 601 | pages = kcalloc(max_pages, sizeof(struct page *), gfp_flags); | ||
| 602 | if (!pages) | ||
| 603 | goto out_err_free; | ||
| 604 | |||
| 605 | for (i = 0; i < max_pages; i++) { | ||
| 606 | pages[i] = alloc_page(gfp_flags); | ||
| 607 | if (!pages[i]) | ||
| 608 | goto out_err_free; | ||
| 609 | } | ||
| 610 | |||
| 611 | lgp->args.minlength = PAGE_CACHE_SIZE; | 594 | lgp->args.minlength = PAGE_CACHE_SIZE; |
| 612 | if (lgp->args.minlength > range->length) | 595 | if (lgp->args.minlength > range->length) |
| 613 | lgp->args.minlength = range->length; | 596 | lgp->args.minlength = range->length; |
| @@ -616,39 +599,19 @@ send_layoutget(struct pnfs_layout_hdr *lo, | |||
| 616 | lgp->args.type = server->pnfs_curr_ld->id; | 599 | lgp->args.type = server->pnfs_curr_ld->id; |
| 617 | lgp->args.inode = ino; | 600 | lgp->args.inode = ino; |
| 618 | lgp->args.ctx = get_nfs_open_context(ctx); | 601 | lgp->args.ctx = get_nfs_open_context(ctx); |
| 619 | lgp->args.layout.pages = pages; | ||
| 620 | lgp->args.layout.pglen = max_pages * PAGE_SIZE; | ||
| 621 | lgp->lsegpp = &lseg; | 602 | lgp->lsegpp = &lseg; |
| 622 | lgp->gfp_flags = gfp_flags; | 603 | lgp->gfp_flags = gfp_flags; |
| 623 | 604 | ||
| 624 | /* Synchronously retrieve layout information from server and | 605 | /* Synchronously retrieve layout information from server and |
| 625 | * store in lseg. | 606 | * store in lseg. |
| 626 | */ | 607 | */ |
| 627 | nfs4_proc_layoutget(lgp); | 608 | nfs4_proc_layoutget(lgp, gfp_flags); |
| 628 | if (!lseg) { | 609 | if (!lseg) { |
| 629 | /* remember that LAYOUTGET failed and suspend trying */ | 610 | /* remember that LAYOUTGET failed and suspend trying */ |
| 630 | set_bit(lo_fail_bit(range->iomode), &lo->plh_flags); | 611 | set_bit(lo_fail_bit(range->iomode), &lo->plh_flags); |
| 631 | } | 612 | } |
| 632 | 613 | ||
| 633 | /* free xdr pages */ | ||
| 634 | for (i = 0; i < max_pages; i++) | ||
| 635 | __free_page(pages[i]); | ||
| 636 | kfree(pages); | ||
| 637 | |||
| 638 | return lseg; | 614 | return lseg; |
| 639 | |||
| 640 | out_err_free: | ||
| 641 | /* free any allocated xdr pages, lgp as it's not used */ | ||
| 642 | if (pages) { | ||
| 643 | for (i = 0; i < max_pages; i++) { | ||
| 644 | if (!pages[i]) | ||
| 645 | break; | ||
| 646 | __free_page(pages[i]); | ||
| 647 | } | ||
| 648 | kfree(pages); | ||
| 649 | } | ||
| 650 | kfree(lgp); | ||
| 651 | return NULL; | ||
| 652 | } | 615 | } |
| 653 | 616 | ||
| 654 | /* | 617 | /* |
diff --git a/fs/nfs/pnfs.h b/fs/nfs/pnfs.h index 2c6c80503ba4..5ea019e80b4c 100644 --- a/fs/nfs/pnfs.h +++ b/fs/nfs/pnfs.h | |||
| @@ -172,7 +172,7 @@ extern int nfs4_proc_getdevicelist(struct nfs_server *server, | |||
| 172 | struct pnfs_devicelist *devlist); | 172 | struct pnfs_devicelist *devlist); |
| 173 | extern int nfs4_proc_getdeviceinfo(struct nfs_server *server, | 173 | extern int nfs4_proc_getdeviceinfo(struct nfs_server *server, |
| 174 | struct pnfs_device *dev); | 174 | struct pnfs_device *dev); |
| 175 | extern int nfs4_proc_layoutget(struct nfs4_layoutget *lgp); | 175 | extern int nfs4_proc_layoutget(struct nfs4_layoutget *lgp, gfp_t gfp_flags); |
| 176 | extern int nfs4_proc_layoutreturn(struct nfs4_layoutreturn *lrp); | 176 | extern int nfs4_proc_layoutreturn(struct nfs4_layoutreturn *lrp); |
| 177 | 177 | ||
| 178 | /* pnfs.c */ | 178 | /* pnfs.c */ |
