diff options
| author | Benjamin Coddington <bcodding@redhat.com> | 2017-04-19 10:11:33 -0400 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2017-05-25 09:44:48 -0400 |
| commit | f2b6f508c5417bc5f2a5a30268b5b75ae3b4a754 (patch) | |
| tree | c09b8aea1a247f53d1022b88f8022b23c4aab309 /fs | |
| parent | a8c35e5c88def2c07cd0ff1aca1af2b06363b293 (diff) | |
NFS: Use GFP_NOIO for two allocations in writeback
commit ae97aa524ef495b6276fd26f5d5449fb22975d7c upstream.
Prevent a deadlock that can occur if we wait on allocations
that try to write back our pages.
Signed-off-by: Benjamin Coddington <bcodding@redhat.com>
Fixes: 00bfa30abe869 ("NFS: Create a common pgio_alloc and pgio_release...")
Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'fs')
| -rw-r--r-- | fs/nfs/pagelist.c | 15 |
1 files changed, 11 insertions, 4 deletions
diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c index 965db474f4b0..142a74f3c59b 100644 --- a/fs/nfs/pagelist.c +++ b/fs/nfs/pagelist.c | |||
| @@ -29,13 +29,14 @@ | |||
| 29 | static struct kmem_cache *nfs_page_cachep; | 29 | static struct kmem_cache *nfs_page_cachep; |
| 30 | static const struct rpc_call_ops nfs_pgio_common_ops; | 30 | static const struct rpc_call_ops nfs_pgio_common_ops; |
| 31 | 31 | ||
| 32 | static bool nfs_pgarray_set(struct nfs_page_array *p, unsigned int pagecount) | 32 | static bool nfs_pgarray_set(struct nfs_page_array *p, unsigned int pagecount, |
| 33 | gfp_t gfp_flags) | ||
| 33 | { | 34 | { |
| 34 | p->npages = pagecount; | 35 | p->npages = pagecount; |
| 35 | if (pagecount <= ARRAY_SIZE(p->page_array)) | 36 | if (pagecount <= ARRAY_SIZE(p->page_array)) |
| 36 | p->pagevec = p->page_array; | 37 | p->pagevec = p->page_array; |
| 37 | else { | 38 | else { |
| 38 | p->pagevec = kcalloc(pagecount, sizeof(struct page *), GFP_KERNEL); | 39 | p->pagevec = kcalloc(pagecount, sizeof(struct page *), gfp_flags); |
| 39 | if (!p->pagevec) | 40 | if (!p->pagevec) |
| 40 | p->npages = 0; | 41 | p->npages = 0; |
| 41 | } | 42 | } |
| @@ -681,6 +682,7 @@ void nfs_pageio_init(struct nfs_pageio_descriptor *desc, | |||
| 681 | { | 682 | { |
| 682 | struct nfs_pgio_mirror *new; | 683 | struct nfs_pgio_mirror *new; |
| 683 | int i; | 684 | int i; |
| 685 | gfp_t gfp_flags = GFP_KERNEL; | ||
| 684 | 686 | ||
| 685 | desc->pg_moreio = 0; | 687 | desc->pg_moreio = 0; |
| 686 | desc->pg_inode = inode; | 688 | desc->pg_inode = inode; |
| @@ -700,8 +702,10 @@ void nfs_pageio_init(struct nfs_pageio_descriptor *desc, | |||
| 700 | if (pg_ops->pg_get_mirror_count) { | 702 | if (pg_ops->pg_get_mirror_count) { |
| 701 | /* until we have a request, we don't have an lseg and no | 703 | /* until we have a request, we don't have an lseg and no |
| 702 | * idea how many mirrors there will be */ | 704 | * idea how many mirrors there will be */ |
| 705 | if (desc->pg_rw_ops->rw_mode == FMODE_WRITE) | ||
| 706 | gfp_flags = GFP_NOIO; | ||
| 703 | new = kcalloc(NFS_PAGEIO_DESCRIPTOR_MIRROR_MAX, | 707 | new = kcalloc(NFS_PAGEIO_DESCRIPTOR_MIRROR_MAX, |
| 704 | sizeof(struct nfs_pgio_mirror), GFP_KERNEL); | 708 | sizeof(struct nfs_pgio_mirror), gfp_flags); |
| 705 | desc->pg_mirrors_dynamic = new; | 709 | desc->pg_mirrors_dynamic = new; |
| 706 | desc->pg_mirrors = new; | 710 | desc->pg_mirrors = new; |
| 707 | 711 | ||
| @@ -755,9 +759,12 @@ int nfs_generic_pgio(struct nfs_pageio_descriptor *desc, | |||
| 755 | struct list_head *head = &mirror->pg_list; | 759 | struct list_head *head = &mirror->pg_list; |
| 756 | struct nfs_commit_info cinfo; | 760 | struct nfs_commit_info cinfo; |
| 757 | unsigned int pagecount, pageused; | 761 | unsigned int pagecount, pageused; |
| 762 | gfp_t gfp_flags = GFP_KERNEL; | ||
| 758 | 763 | ||
| 759 | pagecount = nfs_page_array_len(mirror->pg_base, mirror->pg_count); | 764 | pagecount = nfs_page_array_len(mirror->pg_base, mirror->pg_count); |
| 760 | if (!nfs_pgarray_set(&hdr->page_array, pagecount)) { | 765 | if (desc->pg_rw_ops->rw_mode == FMODE_WRITE) |
| 766 | gfp_flags = GFP_NOIO; | ||
| 767 | if (!nfs_pgarray_set(&hdr->page_array, pagecount, gfp_flags)) { | ||
| 761 | nfs_pgio_error(hdr); | 768 | nfs_pgio_error(hdr); |
| 762 | desc->pg_error = -ENOMEM; | 769 | desc->pg_error = -ENOMEM; |
| 763 | return desc->pg_error; | 770 | return desc->pg_error; |
