diff options
author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2009-08-10 08:54:13 -0400 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2009-08-10 08:54:13 -0400 |
commit | 074cc1deec5dee63fcd5d966b36fa4f3765b50fc (patch) | |
tree | 14508949385a168ab2e43ca5bf7423473f25d839 /fs/nfs/write.c | |
parent | c140aa91357c415c91269884518fa1d6fdebc20d (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.c | 91 |
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 | /* | 225 | static 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 | */ | ||
227 | static 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 | */ | ||
258 | static 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; | 279 | out: |
280 | return ret; | ||
269 | } | 281 | } |
270 | 282 | ||
271 | static int nfs_do_writepage(struct page *page, struct writeback_control *wbc, struct nfs_pageio_descriptor *pgio) | 283 | static 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 | ||
1598 | int 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); | ||
1624 | out_unlock: | ||
1625 | nfs_clear_page_tag_locked(req); | ||
1626 | nfs_release_request(req); | ||
1627 | out: | ||
1628 | return ret; | ||
1629 | } | ||
1630 | #endif | ||
1631 | |||
1585 | int __init nfs_init_writepagecache(void) | 1632 | int __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", |