fs: nfs: inform the VM about pages being committed or unstable
authorMel Gorman <mgorman@suse.de>
Wed, 3 Jul 2013 22:02:06 +0000 (15:02 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 3 Jul 2013 23:07:29 +0000 (16:07 -0700)
VM page reclaim uses dirty and writeback page states to determine if
flushers are cleaning pages too slowly and that page reclaim should
stall waiting on flushers to catch up.  Page state in NFS is a bit more
complex and a clean page can be unreclaimable due to being unstable
which is effectively "dirty" from the perspective of the VM from reclaim
context.  Similarly, if the inode is currently being committed then it's
similar to being under writeback.

This patch adds a is_dirty_writeback() handled for NFS that checks if a
pages backing inode is being committed and should be accounted as
writeback and if a page has private state indicating that it is
effectively dirty.

Signed-off-by: Mel Gorman <mgorman@suse.de>
Cc: Johannes Weiner <hannes@cmpxchg.org>
Cc: Michal Hocko <mhocko@suse.cz>
Cc: Rik van Riel <riel@redhat.com>
Cc: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
Cc: Jiri Slaby <jslaby@suse.cz>
Cc: Valdis Kletnieks <Valdis.Kletnieks@vt.edu>
Cc: Zlatko Calusic <zcalusic@bitsync.net>
Cc: dormando <dormando@rydia.net>
Cc: Trond Myklebust <trond.myklebust@fys.uio.no>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
fs/nfs/file.c

index 6b4a79f..94e94bd 100644 (file)
@@ -495,6 +495,35 @@ static int nfs_release_page(struct page *page, gfp_t gfp)
        return nfs_fscache_release_page(page, gfp);
 }
 
+static void nfs_check_dirty_writeback(struct page *page,
+                               bool *dirty, bool *writeback)
+{
+       struct nfs_inode *nfsi;
+       struct address_space *mapping = page_file_mapping(page);
+
+       if (!mapping || PageSwapCache(page))
+               return;
+
+       /*
+        * Check if an unstable page is currently being committed and
+        * if so, have the VM treat it as if the page is under writeback
+        * so it will not block due to pages that will shortly be freeable.
+        */
+       nfsi = NFS_I(mapping->host);
+       if (test_bit(NFS_INO_COMMIT, &nfsi->flags)) {
+               *writeback = true;
+               return;
+       }
+
+       /*
+        * If PagePrivate() is set, then the page is not freeable and as the
+        * inode is not being committed, it's not going to be cleaned in the
+        * near future so treat it as dirty
+        */
+       if (PagePrivate(page))
+               *dirty = true;
+}
+
 /*
  * Attempt to clear the private state associated with a page when an error
  * occurs that requires the cached contents of an inode to be written back or
@@ -542,6 +571,7 @@ const struct address_space_operations nfs_file_aops = {
        .direct_IO = nfs_direct_IO,
        .migratepage = nfs_migrate_page,
        .launder_page = nfs_launder_page,
+       .is_dirty_writeback = nfs_check_dirty_writeback,
        .error_remove_page = generic_error_remove_page,
 #ifdef CONFIG_NFS_SWAP
        .swap_activate = nfs_swap_activate,