aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs/write.c
diff options
context:
space:
mode:
authorTrond Myklebust <Trond.Myklebust@netapp.com>2009-08-10 08:54:13 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2009-08-10 08:54:13 -0400
commit074cc1deec5dee63fcd5d966b36fa4f3765b50fc (patch)
tree14508949385a168ab2e43ca5bf7423473f25d839 /fs/nfs/write.c
parentc140aa91357c415c91269884518fa1d6fdebc20d (diff)
NFS: Add a ->migratepage() aop for NFS
Make NFS a bit more friendly to NUMA and memory hot removal... Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs/nfs/write.c')
-rw-r--r--fs/nfs/write.c91
1 files changed, 69 insertions, 22 deletions
diff --git a/fs/nfs/write.c b/fs/nfs/write.c
index 0a0a2ff767c3..6240e644f249 100644
--- a/fs/nfs/write.c
+++ b/fs/nfs/write.c
@@ -13,6 +13,7 @@
13#include <linux/file.h> 13#include <linux/file.h>
14#include <linux/writeback.h> 14#include <linux/writeback.h>
15#include <linux/swap.h> 15#include <linux/swap.h>
16#include <linux/migrate.h>
16 17
17#include <linux/sunrpc/clnt.h> 18#include <linux/sunrpc/clnt.h>
18#include <linux/nfs_fs.h> 19#include <linux/nfs_fs.h>
@@ -26,6 +27,7 @@
26#include "internal.h" 27#include "internal.h"
27#include "iostat.h" 28#include "iostat.h"
28#include "nfs4_fs.h" 29#include "nfs4_fs.h"
30#include "fscache.h"
29 31
30#define NFSDBG_FACILITY NFSDBG_PAGECACHE 32#define NFSDBG_FACILITY NFSDBG_PAGECACHE
31 33
@@ -220,24 +222,17 @@ static void nfs_end_page_writeback(struct page *page)
220 clear_bdi_congested(&nfss->backing_dev_info, BLK_RW_ASYNC); 222 clear_bdi_congested(&nfss->backing_dev_info, BLK_RW_ASYNC);
221} 223}
222 224
223/* 225static struct nfs_page *nfs_find_and_lock_request(struct page *page)
224 * Find an associated nfs write request, and prepare to flush it out
225 * May return an error if the user signalled nfs_wait_on_request().
226 */
227static int nfs_page_async_flush(struct nfs_pageio_descriptor *pgio,
228 struct page *page)
229{ 226{
230 struct inode *inode = page->mapping->host; 227 struct inode *inode = page->mapping->host;
231 struct nfs_page *req; 228 struct nfs_page *req;
232 int ret; 229 int ret;
233 230
234 spin_lock(&inode->i_lock); 231 spin_lock(&inode->i_lock);
235 for(;;) { 232 for (;;) {
236 req = nfs_page_find_request_locked(page); 233 req = nfs_page_find_request_locked(page);
237 if (req == NULL) { 234 if (req == NULL)
238 spin_unlock(&inode->i_lock); 235 break;
239 return 0;
240 }
241 if (nfs_set_page_tag_locked(req)) 236 if (nfs_set_page_tag_locked(req))
242 break; 237 break;
243 /* Note: If we hold the page lock, as is the case in nfs_writepage, 238 /* Note: If we hold the page lock, as is the case in nfs_writepage,
@@ -249,23 +244,40 @@ static int nfs_page_async_flush(struct nfs_pageio_descriptor *pgio,
249 ret = nfs_wait_on_request(req); 244 ret = nfs_wait_on_request(req);
250 nfs_release_request(req); 245 nfs_release_request(req);
251 if (ret != 0) 246 if (ret != 0)
252 return ret; 247 return ERR_PTR(ret);
253 spin_lock(&inode->i_lock); 248 spin_lock(&inode->i_lock);
254 } 249 }
255 if (test_bit(PG_CLEAN, &req->wb_flags)) {
256 spin_unlock(&inode->i_lock);
257 BUG();
258 }
259 if (nfs_set_page_writeback(page) != 0) {
260 spin_unlock(&inode->i_lock);
261 BUG();
262 }
263 spin_unlock(&inode->i_lock); 250 spin_unlock(&inode->i_lock);
251 return req;
252}
253
254/*
255 * Find an associated nfs write request, and prepare to flush it out
256 * May return an error if the user signalled nfs_wait_on_request().
257 */
258static int nfs_page_async_flush(struct nfs_pageio_descriptor *pgio,
259 struct page *page)
260{
261 struct nfs_page *req;
262 int ret = 0;
263
264 req = nfs_find_and_lock_request(page);
265 if (!req)
266 goto out;
267 ret = PTR_ERR(req);
268 if (IS_ERR(req))
269 goto out;
270
271 ret = nfs_set_page_writeback(page);
272 BUG_ON(ret != 0);
273 BUG_ON(test_bit(PG_CLEAN, &req->wb_flags));
274
264 if (!nfs_pageio_add_request(pgio, req)) { 275 if (!nfs_pageio_add_request(pgio, req)) {
265 nfs_redirty_request(req); 276 nfs_redirty_request(req);
266 return pgio->pg_error; 277 ret = pgio->pg_error;
267 } 278 }
268 return 0; 279out:
280 return ret;
269} 281}
270 282
271static int nfs_do_writepage(struct page *page, struct writeback_control *wbc, struct nfs_pageio_descriptor *pgio) 283static int nfs_do_writepage(struct page *page, struct writeback_control *wbc, struct nfs_pageio_descriptor *pgio)
@@ -1582,6 +1594,41 @@ int nfs_wb_page(struct inode *inode, struct page* page)
1582 return nfs_wb_page_priority(inode, page, FLUSH_STABLE); 1594 return nfs_wb_page_priority(inode, page, FLUSH_STABLE);
1583} 1595}
1584 1596
1597#ifdef CONFIG_MIGRATION
1598int nfs_migrate_page(struct address_space *mapping, struct page *newpage,
1599 struct page *page)
1600{
1601 struct nfs_page *req;
1602 int ret;
1603
1604 if (PageFsCache(page))
1605 nfs_fscache_release_page(page, GFP_KERNEL);
1606
1607 req = nfs_find_and_lock_request(page);
1608 ret = PTR_ERR(req);
1609 if (IS_ERR(req))
1610 goto out;
1611
1612 ret = migrate_page(mapping, newpage, page);
1613 if (!req)
1614 goto out;
1615 if (ret)
1616 goto out_unlock;
1617 page_cache_get(newpage);
1618 req->wb_page = newpage;
1619 SetPagePrivate(newpage);
1620 set_page_private(newpage, page_private(page));
1621 ClearPagePrivate(page);
1622 set_page_private(page, 0);
1623 page_cache_release(page);
1624out_unlock:
1625 nfs_clear_page_tag_locked(req);
1626 nfs_release_request(req);
1627out:
1628 return ret;
1629}
1630#endif
1631
1585int __init nfs_init_writepagecache(void) 1632int __init nfs_init_writepagecache(void)
1586{ 1633{
1587 nfs_wdata_cachep = kmem_cache_create("nfs_write_data", 1634 nfs_wdata_cachep = kmem_cache_create("nfs_write_data",