aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2010-07-30 22:02:21 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2010-07-30 22:02:21 -0400
commitfc71ff8a6c187ecc1ba79ee5688668af97a970fc (patch)
tree50fff02480afe0e7d233e62bb9f42965308d7ffc
parent1cf66e16160653b4ac92e3ada57fc0bc48798145 (diff)
parentcfb506e1d330387dfaf334dd493b3773d388863d (diff)
Merge branch 'bugfixes' of git://git.linux-nfs.org/projects/trondmy/nfs-2.6
* 'bugfixes' of git://git.linux-nfs.org/projects/trondmy/nfs-2.6: NFS: Ensure that writepage respects the nonblock flag NFS: kswapd must not block in nfs_release_page nfs: include space for the NUL in root path
-rw-r--r--fs/nfs/file.c13
-rw-r--r--fs/nfs/nfsroot.c2
-rw-r--r--fs/nfs/write.c27
-rw-r--r--include/linux/nfs_fs.h1
4 files changed, 32 insertions, 11 deletions
diff --git a/fs/nfs/file.c b/fs/nfs/file.c
index 36a5e74f51b4..f036153d9f50 100644
--- a/fs/nfs/file.c
+++ b/fs/nfs/file.c
@@ -27,6 +27,7 @@
27#include <linux/pagemap.h> 27#include <linux/pagemap.h>
28#include <linux/aio.h> 28#include <linux/aio.h>
29#include <linux/gfp.h> 29#include <linux/gfp.h>
30#include <linux/swap.h>
30 31
31#include <asm/uaccess.h> 32#include <asm/uaccess.h>
32#include <asm/system.h> 33#include <asm/system.h>
@@ -493,11 +494,19 @@ static void nfs_invalidate_page(struct page *page, unsigned long offset)
493 */ 494 */
494static int nfs_release_page(struct page *page, gfp_t gfp) 495static int nfs_release_page(struct page *page, gfp_t gfp)
495{ 496{
497 struct address_space *mapping = page->mapping;
498
496 dfprintk(PAGECACHE, "NFS: release_page(%p)\n", page); 499 dfprintk(PAGECACHE, "NFS: release_page(%p)\n", page);
497 500
498 /* Only do I/O if gfp is a superset of GFP_KERNEL */ 501 /* Only do I/O if gfp is a superset of GFP_KERNEL */
499 if ((gfp & GFP_KERNEL) == GFP_KERNEL) 502 if (mapping && (gfp & GFP_KERNEL) == GFP_KERNEL) {
500 nfs_wb_page(page->mapping->host, page); 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 /* If PagePrivate() is set, then the page is not freeable */ 510 /* If PagePrivate() is set, then the page is not freeable */
502 if (PagePrivate(page)) 511 if (PagePrivate(page))
503 return 0; 512 return 0;
diff --git a/fs/nfs/nfsroot.c b/fs/nfs/nfsroot.c
index 6bd19d843af7..df101d9f546a 100644
--- a/fs/nfs/nfsroot.c
+++ b/fs/nfs/nfsroot.c
@@ -105,7 +105,7 @@ static char nfs_root_name[256] __initdata = "";
105static __be32 servaddr __initdata = 0; 105static __be32 servaddr __initdata = 0;
106 106
107/* Name of directory to mount */ 107/* Name of directory to mount */
108static char nfs_export_path[NFS_MAXPATHLEN] __initdata = { 0, }; 108static char nfs_export_path[NFS_MAXPATHLEN + 1] __initdata = { 0, };
109 109
110/* NFS-related data */ 110/* NFS-related data */
111static struct nfs_mount_data nfs_data __initdata = { 0, };/* NFS mount info */ 111static struct nfs_mount_data nfs_data __initdata = { 0, };/* NFS mount info */
diff --git a/fs/nfs/write.c b/fs/nfs/write.c
index 91679e2631ee..bb72ad34d51d 100644
--- a/fs/nfs/write.c
+++ b/fs/nfs/write.c
@@ -222,7 +222,7 @@ static void nfs_end_page_writeback(struct page *page)
222 clear_bdi_congested(&nfss->backing_dev_info, BLK_RW_ASYNC); 222 clear_bdi_congested(&nfss->backing_dev_info, BLK_RW_ASYNC);
223} 223}
224 224
225static struct nfs_page *nfs_find_and_lock_request(struct page *page) 225static struct nfs_page *nfs_find_and_lock_request(struct page *page, bool nonblock)
226{ 226{
227 struct inode *inode = page->mapping->host; 227 struct inode *inode = page->mapping->host;
228 struct nfs_page *req; 228 struct nfs_page *req;
@@ -241,7 +241,10 @@ static struct nfs_page *nfs_find_and_lock_request(struct page *page)
241 * request as dirty (in which case we don't care). 241 * request as dirty (in which case we don't care).
242 */ 242 */
243 spin_unlock(&inode->i_lock); 243 spin_unlock(&inode->i_lock);
244 ret = nfs_wait_on_request(req); 244 if (!nonblock)
245 ret = nfs_wait_on_request(req);
246 else
247 ret = -EAGAIN;
245 nfs_release_request(req); 248 nfs_release_request(req);
246 if (ret != 0) 249 if (ret != 0)
247 return ERR_PTR(ret); 250 return ERR_PTR(ret);
@@ -256,12 +259,12 @@ static struct nfs_page *nfs_find_and_lock_request(struct page *page)
256 * May return an error if the user signalled nfs_wait_on_request(). 259 * May return an error if the user signalled nfs_wait_on_request().
257 */ 260 */
258static int nfs_page_async_flush(struct nfs_pageio_descriptor *pgio, 261static int nfs_page_async_flush(struct nfs_pageio_descriptor *pgio,
259 struct page *page) 262 struct page *page, bool nonblock)
260{ 263{
261 struct nfs_page *req; 264 struct nfs_page *req;
262 int ret = 0; 265 int ret = 0;
263 266
264 req = nfs_find_and_lock_request(page); 267 req = nfs_find_and_lock_request(page, nonblock);
265 if (!req) 268 if (!req)
266 goto out; 269 goto out;
267 ret = PTR_ERR(req); 270 ret = PTR_ERR(req);
@@ -283,12 +286,20 @@ out:
283static int nfs_do_writepage(struct page *page, struct writeback_control *wbc, struct nfs_pageio_descriptor *pgio) 286static int nfs_do_writepage(struct page *page, struct writeback_control *wbc, struct nfs_pageio_descriptor *pgio)
284{ 287{
285 struct inode *inode = page->mapping->host; 288 struct inode *inode = page->mapping->host;
289 int ret;
286 290
287 nfs_inc_stats(inode, NFSIOS_VFSWRITEPAGE); 291 nfs_inc_stats(inode, NFSIOS_VFSWRITEPAGE);
288 nfs_add_stats(inode, NFSIOS_WRITEPAGES, 1); 292 nfs_add_stats(inode, NFSIOS_WRITEPAGES, 1);
289 293
290 nfs_pageio_cond_complete(pgio, page->index); 294 nfs_pageio_cond_complete(pgio, page->index);
291 return nfs_page_async_flush(pgio, page); 295 ret = nfs_page_async_flush(pgio, page,
296 wbc->sync_mode == WB_SYNC_NONE ||
297 wbc->nonblocking != 0);
298 if (ret == -EAGAIN) {
299 redirty_page_for_writepage(wbc, page);
300 ret = 0;
301 }
302 return ret;
292} 303}
293 304
294/* 305/*
@@ -1379,7 +1390,7 @@ static const struct rpc_call_ops nfs_commit_ops = {
1379 .rpc_release = nfs_commit_release, 1390 .rpc_release = nfs_commit_release,
1380}; 1391};
1381 1392
1382static int nfs_commit_inode(struct inode *inode, int how) 1393int nfs_commit_inode(struct inode *inode, int how)
1383{ 1394{
1384 LIST_HEAD(head); 1395 LIST_HEAD(head);
1385 int may_wait = how & FLUSH_SYNC; 1396 int may_wait = how & FLUSH_SYNC;
@@ -1443,7 +1454,7 @@ out_mark_dirty:
1443 return ret; 1454 return ret;
1444} 1455}
1445#else 1456#else
1446static int nfs_commit_inode(struct inode *inode, int how) 1457int nfs_commit_inode(struct inode *inode, int how)
1447{ 1458{
1448 return 0; 1459 return 0;
1449} 1460}
@@ -1546,7 +1557,7 @@ int nfs_migrate_page(struct address_space *mapping, struct page *newpage,
1546 1557
1547 nfs_fscache_release_page(page, GFP_KERNEL); 1558 nfs_fscache_release_page(page, GFP_KERNEL);
1548 1559
1549 req = nfs_find_and_lock_request(page); 1560 req = nfs_find_and_lock_request(page, false);
1550 ret = PTR_ERR(req); 1561 ret = PTR_ERR(req);
1551 if (IS_ERR(req)) 1562 if (IS_ERR(req))
1552 goto out; 1563 goto out;
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
index 77c2ae53431c..f6e2455f13d1 100644
--- a/include/linux/nfs_fs.h
+++ b/include/linux/nfs_fs.h
@@ -493,6 +493,7 @@ extern int nfs_wb_all(struct inode *inode);
493extern int nfs_wb_page(struct inode *inode, struct page* page); 493extern int nfs_wb_page(struct inode *inode, struct page* page);
494extern int nfs_wb_page_cancel(struct inode *inode, struct page* page); 494extern int nfs_wb_page_cancel(struct inode *inode, struct page* page);
495#if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) 495#if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
496extern int nfs_commit_inode(struct inode *, int);
496extern struct nfs_write_data *nfs_commitdata_alloc(void); 497extern struct nfs_write_data *nfs_commitdata_alloc(void);
497extern void nfs_commit_free(struct nfs_write_data *wdata); 498extern void nfs_commit_free(struct nfs_write_data *wdata);
498#endif 499#endif