|
@@ -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,
|