Skip to content

Commit 074cc1d

Browse files
Trond MyklebustTrond Myklebust
authored andcommitted
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>
1 parent c140aa9 commit 074cc1d

File tree

3 files changed

+76
-22
lines changed

3 files changed

+76
-22
lines changed

fs/nfs/file.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -479,6 +479,7 @@ const struct address_space_operations nfs_file_aops = {
479479
.invalidatepage = nfs_invalidate_page,
480480
.releasepage = nfs_release_page,
481481
.direct_IO = nfs_direct_IO,
482+
.migratepage = nfs_migrate_page,
482483
.launder_page = nfs_launder_page,
483484
};
484485

fs/nfs/internal.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,12 @@ extern void nfs_read_prepare(struct rpc_task *task, void *calldata);
248248

249249
/* write.c */
250250
extern void nfs_write_prepare(struct rpc_task *task, void *calldata);
251+
#ifdef CONFIG_MIGRATION
252+
extern int nfs_migrate_page(struct address_space *,
253+
struct page *, struct page *);
254+
#else
255+
#define nfs_migrate_page NULL
256+
#endif
251257

252258
/* nfs4proc.c */
253259
extern int _nfs4_call_sync(struct nfs_server *server,

fs/nfs/write.c

Lines changed: 69 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include <linux/file.h>
1414
#include <linux/writeback.h>
1515
#include <linux/swap.h>
16+
#include <linux/migrate.h>
1617

1718
#include <linux/sunrpc/clnt.h>
1819
#include <linux/nfs_fs.h>
@@ -26,6 +27,7 @@
2627
#include "internal.h"
2728
#include "iostat.h"
2829
#include "nfs4_fs.h"
30+
#include "fscache.h"
2931

3032
#define NFSDBG_FACILITY NFSDBG_PAGECACHE
3133

@@ -220,24 +222,17 @@ static void nfs_end_page_writeback(struct page *page)
220222
clear_bdi_congested(&nfss->backing_dev_info, BLK_RW_ASYNC);
221223
}
222224

223-
/*
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)
225+
static struct nfs_page *nfs_find_and_lock_request(struct page *page)
229226
{
230227
struct inode *inode = page->mapping->host;
231228
struct nfs_page *req;
232229
int ret;
233230

234231
spin_lock(&inode->i_lock);
235-
for(;;) {
232+
for (;;) {
236233
req = nfs_page_find_request_locked(page);
237-
if (req == NULL) {
238-
spin_unlock(&inode->i_lock);
239-
return 0;
240-
}
234+
if (req == NULL)
235+
break;
241236
if (nfs_set_page_tag_locked(req))
242237
break;
243238
/* 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,
249244
ret = nfs_wait_on_request(req);
250245
nfs_release_request(req);
251246
if (ret != 0)
252-
return ret;
247+
return ERR_PTR(ret);
253248
spin_lock(&inode->i_lock);
254249
}
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-
}
263250
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+
264275
if (!nfs_pageio_add_request(pgio, req)) {
265276
nfs_redirty_request(req);
266-
return pgio->pg_error;
277+
ret = pgio->pg_error;
267278
}
268-
return 0;
279+
out:
280+
return ret;
269281
}
270282

271283
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)
15821594
return nfs_wb_page_priority(inode, page, FLUSH_STABLE);
15831595
}
15841596

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+
15851632
int __init nfs_init_writepagecache(void)
15861633
{
15871634
nfs_wdata_cachep = kmem_cache_create("nfs_write_data",

0 commit comments

Comments
 (0)