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 */ |