diff options
author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2011-05-11 18:00:51 -0400 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2011-05-11 22:52:13 -0400 |
commit | a75b9df9d3bfc3cd1083974c045ae31ce5f3434f (patch) | |
tree | 039cc65774c895d704f23a2c89b7f1bcd736e0b9 /fs/nfs/pnfs.c | |
parent | 2887fe45522843149ccf72e01f43813be4fb36c5 (diff) |
NFSv4.1: Ensure that layoutget uses the correct gfp modes
Currently, writebacks may end up recursing back into the filesystem due to
GFP_KERNEL direct reclaims in the pnfs subsystem.
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs/nfs/pnfs.c')
-rw-r--r-- | fs/nfs/pnfs.c | 33 |
1 files changed, 19 insertions, 14 deletions
diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c index 65455f58b109..f57f5281a520 100644 --- a/fs/nfs/pnfs.c +++ b/fs/nfs/pnfs.c | |||
@@ -467,7 +467,8 @@ pnfs_choose_layoutget_stateid(nfs4_stateid *dst, struct pnfs_layout_hdr *lo, | |||
467 | static struct pnfs_layout_segment * | 467 | static struct pnfs_layout_segment * |
468 | send_layoutget(struct pnfs_layout_hdr *lo, | 468 | send_layoutget(struct pnfs_layout_hdr *lo, |
469 | struct nfs_open_context *ctx, | 469 | struct nfs_open_context *ctx, |
470 | u32 iomode) | 470 | u32 iomode, |
471 | gfp_t gfp_flags) | ||
471 | { | 472 | { |
472 | struct inode *ino = lo->plh_inode; | 473 | struct inode *ino = lo->plh_inode; |
473 | struct nfs_server *server = NFS_SERVER(ino); | 474 | struct nfs_server *server = NFS_SERVER(ino); |
@@ -480,7 +481,7 @@ send_layoutget(struct pnfs_layout_hdr *lo, | |||
480 | dprintk("--> %s\n", __func__); | 481 | dprintk("--> %s\n", __func__); |
481 | 482 | ||
482 | BUG_ON(ctx == NULL); | 483 | BUG_ON(ctx == NULL); |
483 | lgp = kzalloc(sizeof(*lgp), GFP_KERNEL); | 484 | lgp = kzalloc(sizeof(*lgp), gfp_flags); |
484 | if (lgp == NULL) | 485 | if (lgp == NULL) |
485 | return NULL; | 486 | return NULL; |
486 | 487 | ||
@@ -488,12 +489,12 @@ send_layoutget(struct pnfs_layout_hdr *lo, | |||
488 | max_resp_sz = server->nfs_client->cl_session->fc_attrs.max_resp_sz; | 489 | max_resp_sz = server->nfs_client->cl_session->fc_attrs.max_resp_sz; |
489 | max_pages = max_resp_sz >> PAGE_SHIFT; | 490 | max_pages = max_resp_sz >> PAGE_SHIFT; |
490 | 491 | ||
491 | pages = kzalloc(max_pages * sizeof(struct page *), GFP_KERNEL); | 492 | pages = kzalloc(max_pages * sizeof(struct page *), gfp_flags); |
492 | if (!pages) | 493 | if (!pages) |
493 | goto out_err_free; | 494 | goto out_err_free; |
494 | 495 | ||
495 | for (i = 0; i < max_pages; i++) { | 496 | for (i = 0; i < max_pages; i++) { |
496 | pages[i] = alloc_page(GFP_KERNEL); | 497 | pages[i] = alloc_page(gfp_flags); |
497 | if (!pages[i]) | 498 | if (!pages[i]) |
498 | goto out_err_free; | 499 | goto out_err_free; |
499 | } | 500 | } |
@@ -509,6 +510,7 @@ send_layoutget(struct pnfs_layout_hdr *lo, | |||
509 | lgp->args.layout.pages = pages; | 510 | lgp->args.layout.pages = pages; |
510 | lgp->args.layout.pglen = max_pages * PAGE_SIZE; | 511 | lgp->args.layout.pglen = max_pages * PAGE_SIZE; |
511 | lgp->lsegpp = &lseg; | 512 | lgp->lsegpp = &lseg; |
513 | lgp->gfp_flags = gfp_flags; | ||
512 | 514 | ||
513 | /* Synchronously retrieve layout information from server and | 515 | /* Synchronously retrieve layout information from server and |
514 | * store in lseg. | 516 | * store in lseg. |
@@ -666,11 +668,11 @@ pnfs_insert_layout(struct pnfs_layout_hdr *lo, | |||
666 | } | 668 | } |
667 | 669 | ||
668 | static struct pnfs_layout_hdr * | 670 | static struct pnfs_layout_hdr * |
669 | alloc_init_layout_hdr(struct inode *ino) | 671 | alloc_init_layout_hdr(struct inode *ino, gfp_t gfp_flags) |
670 | { | 672 | { |
671 | struct pnfs_layout_hdr *lo; | 673 | struct pnfs_layout_hdr *lo; |
672 | 674 | ||
673 | lo = kzalloc(sizeof(struct pnfs_layout_hdr), GFP_KERNEL); | 675 | lo = kzalloc(sizeof(struct pnfs_layout_hdr), gfp_flags); |
674 | if (!lo) | 676 | if (!lo) |
675 | return NULL; | 677 | return NULL; |
676 | atomic_set(&lo->plh_refcount, 1); | 678 | atomic_set(&lo->plh_refcount, 1); |
@@ -682,7 +684,7 @@ alloc_init_layout_hdr(struct inode *ino) | |||
682 | } | 684 | } |
683 | 685 | ||
684 | static struct pnfs_layout_hdr * | 686 | static struct pnfs_layout_hdr * |
685 | pnfs_find_alloc_layout(struct inode *ino) | 687 | pnfs_find_alloc_layout(struct inode *ino, gfp_t gfp_flags) |
686 | { | 688 | { |
687 | struct nfs_inode *nfsi = NFS_I(ino); | 689 | struct nfs_inode *nfsi = NFS_I(ino); |
688 | struct pnfs_layout_hdr *new = NULL; | 690 | struct pnfs_layout_hdr *new = NULL; |
@@ -697,7 +699,7 @@ pnfs_find_alloc_layout(struct inode *ino) | |||
697 | return nfsi->layout; | 699 | return nfsi->layout; |
698 | } | 700 | } |
699 | spin_unlock(&ino->i_lock); | 701 | spin_unlock(&ino->i_lock); |
700 | new = alloc_init_layout_hdr(ino); | 702 | new = alloc_init_layout_hdr(ino, gfp_flags); |
701 | spin_lock(&ino->i_lock); | 703 | spin_lock(&ino->i_lock); |
702 | 704 | ||
703 | if (likely(nfsi->layout == NULL)) /* Won the race? */ | 705 | if (likely(nfsi->layout == NULL)) /* Won the race? */ |
@@ -757,7 +759,8 @@ pnfs_find_lseg(struct pnfs_layout_hdr *lo, u32 iomode) | |||
757 | struct pnfs_layout_segment * | 759 | struct pnfs_layout_segment * |
758 | pnfs_update_layout(struct inode *ino, | 760 | pnfs_update_layout(struct inode *ino, |
759 | struct nfs_open_context *ctx, | 761 | struct nfs_open_context *ctx, |
760 | enum pnfs_iomode iomode) | 762 | enum pnfs_iomode iomode, |
763 | gfp_t gfp_flags) | ||
761 | { | 764 | { |
762 | struct nfs_inode *nfsi = NFS_I(ino); | 765 | struct nfs_inode *nfsi = NFS_I(ino); |
763 | struct nfs_client *clp = NFS_SERVER(ino)->nfs_client; | 766 | struct nfs_client *clp = NFS_SERVER(ino)->nfs_client; |
@@ -768,7 +771,7 @@ pnfs_update_layout(struct inode *ino, | |||
768 | if (!pnfs_enabled_sb(NFS_SERVER(ino))) | 771 | if (!pnfs_enabled_sb(NFS_SERVER(ino))) |
769 | return NULL; | 772 | return NULL; |
770 | spin_lock(&ino->i_lock); | 773 | spin_lock(&ino->i_lock); |
771 | lo = pnfs_find_alloc_layout(ino); | 774 | lo = pnfs_find_alloc_layout(ino, gfp_flags); |
772 | if (lo == NULL) { | 775 | if (lo == NULL) { |
773 | dprintk("%s ERROR: can't get pnfs_layout_hdr\n", __func__); | 776 | dprintk("%s ERROR: can't get pnfs_layout_hdr\n", __func__); |
774 | goto out_unlock; | 777 | goto out_unlock; |
@@ -808,7 +811,7 @@ pnfs_update_layout(struct inode *ino, | |||
808 | spin_unlock(&clp->cl_lock); | 811 | spin_unlock(&clp->cl_lock); |
809 | } | 812 | } |
810 | 813 | ||
811 | lseg = send_layoutget(lo, ctx, iomode); | 814 | lseg = send_layoutget(lo, ctx, iomode, gfp_flags); |
812 | if (!lseg && first) { | 815 | if (!lseg && first) { |
813 | spin_lock(&clp->cl_lock); | 816 | spin_lock(&clp->cl_lock); |
814 | list_del_init(&lo->plh_layouts); | 817 | list_del_init(&lo->plh_layouts); |
@@ -847,7 +850,7 @@ pnfs_layout_process(struct nfs4_layoutget *lgp) | |||
847 | goto out; | 850 | goto out; |
848 | } | 851 | } |
849 | /* Inject layout blob into I/O device driver */ | 852 | /* Inject layout blob into I/O device driver */ |
850 | lseg = NFS_SERVER(ino)->pnfs_curr_ld->alloc_lseg(lo, res); | 853 | lseg = NFS_SERVER(ino)->pnfs_curr_ld->alloc_lseg(lo, res, lgp->gfp_flags); |
851 | if (!lseg || IS_ERR(lseg)) { | 854 | if (!lseg || IS_ERR(lseg)) { |
852 | if (!lseg) | 855 | if (!lseg) |
853 | status = -ENOMEM; | 856 | status = -ENOMEM; |
@@ -900,7 +903,8 @@ static int pnfs_read_pg_test(struct nfs_pageio_descriptor *pgio, | |||
900 | /* This is first coelesce call for a series of nfs_pages */ | 903 | /* This is first coelesce call for a series of nfs_pages */ |
901 | pgio->pg_lseg = pnfs_update_layout(pgio->pg_inode, | 904 | pgio->pg_lseg = pnfs_update_layout(pgio->pg_inode, |
902 | prev->wb_context, | 905 | prev->wb_context, |
903 | IOMODE_READ); | 906 | IOMODE_READ, |
907 | GFP_KERNEL); | ||
904 | } | 908 | } |
905 | return NFS_SERVER(pgio->pg_inode)->pnfs_curr_ld->pg_test(pgio, prev, req); | 909 | return NFS_SERVER(pgio->pg_inode)->pnfs_curr_ld->pg_test(pgio, prev, req); |
906 | } | 910 | } |
@@ -922,7 +926,8 @@ static int pnfs_write_pg_test(struct nfs_pageio_descriptor *pgio, | |||
922 | /* This is first coelesce call for a series of nfs_pages */ | 926 | /* This is first coelesce call for a series of nfs_pages */ |
923 | pgio->pg_lseg = pnfs_update_layout(pgio->pg_inode, | 927 | pgio->pg_lseg = pnfs_update_layout(pgio->pg_inode, |
924 | prev->wb_context, | 928 | prev->wb_context, |
925 | IOMODE_RW); | 929 | IOMODE_RW, |
930 | GFP_NOFS); | ||
926 | } | 931 | } |
927 | return NFS_SERVER(pgio->pg_inode)->pnfs_curr_ld->pg_test(pgio, prev, req); | 932 | return NFS_SERVER(pgio->pg_inode)->pnfs_curr_ld->pg_test(pgio, prev, req); |
928 | } | 933 | } |