Commit b608b283a962caaa280756bc8563016a71712acf

Authored by Trond Myklebust
1 parent 674b222292

NFS: kswapd must not block in nfs_release_page

See https://bugzilla.kernel.org/show_bug.cgi?id=16056

If other processes are blocked waiting for kswapd to free up some memory so
that they can make progress, then we cannot allow kswapd to block on those
processes.

Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Cc: stable@kernel.org

Showing 3 changed files with 14 additions and 4 deletions Side-by-side Diff

... ... @@ -27,6 +27,7 @@
27 27 #include <linux/pagemap.h>
28 28 #include <linux/aio.h>
29 29 #include <linux/gfp.h>
  30 +#include <linux/swap.h>
30 31  
31 32 #include <asm/uaccess.h>
32 33 #include <asm/system.h>
33 34  
... ... @@ -493,11 +494,19 @@
493 494 */
494 495 static int nfs_release_page(struct page *page, gfp_t gfp)
495 496 {
  497 + struct address_space *mapping = page->mapping;
  498 +
496 499 dfprintk(PAGECACHE, "NFS: release_page(%p)\n", page);
497 500  
498 501 /* Only do I/O if gfp is a superset of GFP_KERNEL */
499   - if ((gfp & GFP_KERNEL) == GFP_KERNEL)
500   - nfs_wb_page(page->mapping->host, page);
  502 + if (mapping && (gfp & GFP_KERNEL) == GFP_KERNEL) {
  503 + int how = FLUSH_SYNC;
  504 +
  505 + /* Don't let kswapd deadlock waiting for OOM RPC calls */
  506 + if (current_is_kswapd())
  507 + how = 0;
  508 + nfs_commit_inode(mapping->host, how);
  509 + }
501 510 /* If PagePrivate() is set, then the page is not freeable */
502 511 if (PagePrivate(page))
503 512 return 0;
... ... @@ -1379,7 +1379,7 @@
1379 1379 .rpc_release = nfs_commit_release,
1380 1380 };
1381 1381  
1382   -static int nfs_commit_inode(struct inode *inode, int how)
  1382 +int nfs_commit_inode(struct inode *inode, int how)
1383 1383 {
1384 1384 LIST_HEAD(head);
1385 1385 int may_wait = how & FLUSH_SYNC;
... ... @@ -1443,7 +1443,7 @@
1443 1443 return ret;
1444 1444 }
1445 1445 #else
1446   -static int nfs_commit_inode(struct inode *inode, int how)
  1446 +int nfs_commit_inode(struct inode *inode, int how)
1447 1447 {
1448 1448 return 0;
1449 1449 }
include/linux/nfs_fs.h
... ... @@ -493,6 +493,7 @@
493 493 extern int nfs_wb_page(struct inode *inode, struct page* page);
494 494 extern int nfs_wb_page_cancel(struct inode *inode, struct page* page);
495 495 #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
  496 +extern int nfs_commit_inode(struct inode *, int);
496 497 extern struct nfs_write_data *nfs_commitdata_alloc(void);
497 498 extern void nfs_commit_free(struct nfs_write_data *wdata);
498 499 #endif