diff options
Diffstat (limited to 'fs/nfs/file.c')
-rw-r--r-- | fs/nfs/file.c | 38 |
1 files changed, 35 insertions, 3 deletions
diff --git a/fs/nfs/file.c b/fs/nfs/file.c index a87a44f84113..94e94bd11aae 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c | |||
@@ -451,11 +451,13 @@ static int nfs_write_end(struct file *file, struct address_space *mapping, | |||
451 | * - Called if either PG_private or PG_fscache is set on the page | 451 | * - Called if either PG_private or PG_fscache is set on the page |
452 | * - Caller holds page lock | 452 | * - Caller holds page lock |
453 | */ | 453 | */ |
454 | static void nfs_invalidate_page(struct page *page, unsigned long offset) | 454 | static void nfs_invalidate_page(struct page *page, unsigned int offset, |
455 | unsigned int length) | ||
455 | { | 456 | { |
456 | dfprintk(PAGECACHE, "NFS: invalidate_page(%p, %lu)\n", page, offset); | 457 | dfprintk(PAGECACHE, "NFS: invalidate_page(%p, %u, %u)\n", |
458 | page, offset, length); | ||
457 | 459 | ||
458 | if (offset != 0) | 460 | if (offset != 0 || length < PAGE_CACHE_SIZE) |
459 | return; | 461 | return; |
460 | /* Cancel any unstarted writes on this page */ | 462 | /* Cancel any unstarted writes on this page */ |
461 | nfs_wb_page_cancel(page_file_mapping(page)->host, page); | 463 | nfs_wb_page_cancel(page_file_mapping(page)->host, page); |
@@ -493,6 +495,35 @@ static int nfs_release_page(struct page *page, gfp_t gfp) | |||
493 | return nfs_fscache_release_page(page, gfp); | 495 | return nfs_fscache_release_page(page, gfp); |
494 | } | 496 | } |
495 | 497 | ||
498 | static void nfs_check_dirty_writeback(struct page *page, | ||
499 | bool *dirty, bool *writeback) | ||
500 | { | ||
501 | struct nfs_inode *nfsi; | ||
502 | struct address_space *mapping = page_file_mapping(page); | ||
503 | |||
504 | if (!mapping || PageSwapCache(page)) | ||
505 | return; | ||
506 | |||
507 | /* | ||
508 | * Check if an unstable page is currently being committed and | ||
509 | * if so, have the VM treat it as if the page is under writeback | ||
510 | * so it will not block due to pages that will shortly be freeable. | ||
511 | */ | ||
512 | nfsi = NFS_I(mapping->host); | ||
513 | if (test_bit(NFS_INO_COMMIT, &nfsi->flags)) { | ||
514 | *writeback = true; | ||
515 | return; | ||
516 | } | ||
517 | |||
518 | /* | ||
519 | * If PagePrivate() is set, then the page is not freeable and as the | ||
520 | * inode is not being committed, it's not going to be cleaned in the | ||
521 | * near future so treat it as dirty | ||
522 | */ | ||
523 | if (PagePrivate(page)) | ||
524 | *dirty = true; | ||
525 | } | ||
526 | |||
496 | /* | 527 | /* |
497 | * Attempt to clear the private state associated with a page when an error | 528 | * Attempt to clear the private state associated with a page when an error |
498 | * occurs that requires the cached contents of an inode to be written back or | 529 | * occurs that requires the cached contents of an inode to be written back or |
@@ -540,6 +571,7 @@ const struct address_space_operations nfs_file_aops = { | |||
540 | .direct_IO = nfs_direct_IO, | 571 | .direct_IO = nfs_direct_IO, |
541 | .migratepage = nfs_migrate_page, | 572 | .migratepage = nfs_migrate_page, |
542 | .launder_page = nfs_launder_page, | 573 | .launder_page = nfs_launder_page, |
574 | .is_dirty_writeback = nfs_check_dirty_writeback, | ||
543 | .error_remove_page = generic_error_remove_page, | 575 | .error_remove_page = generic_error_remove_page, |
544 | #ifdef CONFIG_NFS_SWAP | 576 | #ifdef CONFIG_NFS_SWAP |
545 | .swap_activate = nfs_swap_activate, | 577 | .swap_activate = nfs_swap_activate, |