aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorBenjamin Coddington <bcodding@redhat.com>2017-04-19 10:11:33 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2017-05-25 09:44:48 -0400
commitf2b6f508c5417bc5f2a5a30268b5b75ae3b4a754 (patch)
treec09b8aea1a247f53d1022b88f8022b23c4aab309 /fs
parenta8c35e5c88def2c07cd0ff1aca1af2b06363b293 (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.c15
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 @@
29static struct kmem_cache *nfs_page_cachep; 29static struct kmem_cache *nfs_page_cachep;
30static const struct rpc_call_ops nfs_pgio_common_ops; 30static const struct rpc_call_ops nfs_pgio_common_ops;
31 31
32static bool nfs_pgarray_set(struct nfs_page_array *p, unsigned int pagecount) 32static 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;