Commit 545db45f0fc0d4203b045047798ce156972a3056

Authored by David Howells
1 parent 6a51091d07

NFS: FS-Cache page management

FS-Cache page management for NFS.  This includes hooking the releasing and
invalidation of pages marked with PG_fscache (aka PG_private_2) and waiting for
completion of the write-to-cache flag (PG_fscache_write aka PG_owner_priv_2).

Signed-off-by: David Howells <dhowells@redhat.com>
Acked-by: Steve Dickson <steved@redhat.com>
Acked-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Acked-by: Al Viro <viro@zeniv.linux.org.uk>
Tested-by: Daire Byrne <Daire.Byrne@framestore.com>

Showing 3 changed files with 101 additions and 4 deletions Side-by-side Diff

... ... @@ -35,6 +35,7 @@
35 35 #include "delegation.h"
36 36 #include "internal.h"
37 37 #include "iostat.h"
  38 +#include "fscache.h"
38 39  
39 40 #define NFSDBG_FACILITY NFSDBG_FILE
40 41  
... ... @@ -413,7 +414,7 @@
413 414 * Partially or wholly invalidate a page
414 415 * - Release the private state associated with a page if undergoing complete
415 416 * page invalidation
416   - * - Called if either PG_private or PG_private_2 is set on the page
  417 + * - Called if either PG_private or PG_fscache is set on the page
417 418 * - Caller holds page lock
418 419 */
419 420 static void nfs_invalidate_page(struct page *page, unsigned long offset)
420 421  
... ... @@ -424,11 +425,13 @@
424 425 return;
425 426 /* Cancel any unstarted writes on this page */
426 427 nfs_wb_page_cancel(page->mapping->host, page);
  428 +
  429 + nfs_fscache_invalidate_page(page, page->mapping->host);
427 430 }
428 431  
429 432 /*
430 433 * Attempt to release the private state associated with a page
431   - * - Called if either PG_private or PG_private_2 is set on the page
  434 + * - Called if either PG_private or PG_fscache is set on the page
432 435 * - Caller holds page lock
433 436 * - Return true (may release page) or false (may not)
434 437 */
435 438  
436 439  
437 440  
... ... @@ -437,24 +440,28 @@
437 440 dfprintk(PAGECACHE, "NFS: release_page(%p)\n", page);
438 441  
439 442 /* If PagePrivate() is set, then the page is not freeable */
440   - return 0;
  443 + if (PagePrivate(page))
  444 + return 0;
  445 + return nfs_fscache_release_page(page, gfp);
441 446 }
442 447  
443 448 /*
444 449 * Attempt to clear the private state associated with a page when an error
445 450 * occurs that requires the cached contents of an inode to be written back or
446 451 * destroyed
447   - * - Called if either PG_private or PG_private_2 is set on the page
  452 + * - Called if either PG_private or fscache is set on the page
448 453 * - Caller holds page lock
449 454 * - Return 0 if successful, -error otherwise
450 455 */
451 456 static int nfs_launder_page(struct page *page)
452 457 {
453 458 struct inode *inode = page->mapping->host;
  459 + struct nfs_inode *nfsi = NFS_I(inode);
454 460  
455 461 dfprintk(PAGECACHE, "NFS: launder_page(%ld, %llu)\n",
456 462 inode->i_ino, (long long)page_offset(page));
457 463  
  464 + nfs_fscache_wait_on_page_write(nfsi, page);
458 465 return nfs_wb_page(inode, page);
459 466 }
460 467  
... ... @@ -490,6 +497,9 @@
490 497 dentry->d_parent->d_name.name, dentry->d_name.name,
491 498 filp->f_mapping->host->i_ino,
492 499 (long long)page_offset(page));
  500 +
  501 + /* make sure the cache has finished storing the page */
  502 + nfs_fscache_wait_on_page_write(NFS_I(dentry->d_inode), page);
493 503  
494 504 lock_page(page);
495 505 mapping = page->mapping;
... ... @@ -19,6 +19,7 @@
19 19 #include <linux/seq_file.h>
20 20  
21 21 #include "internal.h"
  22 +#include "iostat.h"
22 23 #include "fscache.h"
23 24  
24 25 #define NFSDBG_FACILITY NFSDBG_FSCACHE
... ... @@ -327,5 +328,57 @@
327 328 nfss, nfsi, old, nfsi->fscache);
328 329 }
329 330 nfs_fscache_inode_unlock(inode);
  331 +}
  332 +
  333 +/*
  334 + * Release the caching state associated with a page, if the page isn't busy
  335 + * interacting with the cache.
  336 + * - Returns true (can release page) or false (page busy).
  337 + */
  338 +int nfs_fscache_release_page(struct page *page, gfp_t gfp)
  339 +{
  340 + struct nfs_inode *nfsi = NFS_I(page->mapping->host);
  341 + struct fscache_cookie *cookie = nfsi->fscache;
  342 +
  343 + BUG_ON(!cookie);
  344 +
  345 + if (fscache_check_page_write(cookie, page)) {
  346 + if (!(gfp & __GFP_WAIT))
  347 + return 0;
  348 + fscache_wait_on_page_write(cookie, page);
  349 + }
  350 +
  351 + if (PageFsCache(page)) {
  352 + dfprintk(FSCACHE, "NFS: fscache releasepage (0x%p/0x%p/0x%p)\n",
  353 + cookie, page, nfsi);
  354 +
  355 + fscache_uncache_page(cookie, page);
  356 + nfs_add_fscache_stats(page->mapping->host,
  357 + NFSIOS_FSCACHE_PAGES_UNCACHED, 1);
  358 + }
  359 +
  360 + return 1;
  361 +}
  362 +
  363 +/*
  364 + * Release the caching state associated with a page if undergoing complete page
  365 + * invalidation.
  366 + */
  367 +void __nfs_fscache_invalidate_page(struct page *page, struct inode *inode)
  368 +{
  369 + struct nfs_inode *nfsi = NFS_I(inode);
  370 + struct fscache_cookie *cookie = nfsi->fscache;
  371 +
  372 + BUG_ON(!cookie);
  373 +
  374 + dfprintk(FSCACHE, "NFS: fscache invalidatepage (0x%p/0x%p/0x%p)\n",
  375 + cookie, page, nfsi);
  376 +
  377 + fscache_wait_on_page_write(cookie, page);
  378 +
  379 + BUG_ON(!PageLocked(page));
  380 + fscache_uncache_page(cookie, page);
  381 + nfs_add_fscache_stats(page->mapping->host,
  382 + NFSIOS_FSCACHE_PAGES_UNCACHED, 1);
330 383 }
... ... @@ -83,6 +83,31 @@
83 83 extern void nfs_fscache_set_inode_cookie(struct inode *, struct file *);
84 84 extern void nfs_fscache_reset_inode_cookie(struct inode *);
85 85  
  86 +extern void __nfs_fscache_invalidate_page(struct page *, struct inode *);
  87 +extern int nfs_fscache_release_page(struct page *, gfp_t);
  88 +
  89 +/*
  90 + * wait for a page to complete writing to the cache
  91 + */
  92 +static inline void nfs_fscache_wait_on_page_write(struct nfs_inode *nfsi,
  93 + struct page *page)
  94 +{
  95 + if (PageFsCache(page))
  96 + fscache_wait_on_page_write(nfsi->fscache, page);
  97 +}
  98 +
  99 +/*
  100 + * release the caching state associated with a page if undergoing complete page
  101 + * invalidation
  102 + */
  103 +static inline void nfs_fscache_invalidate_page(struct page *page,
  104 + struct inode *inode)
  105 +{
  106 + if (PageFsCache(page))
  107 + __nfs_fscache_invalidate_page(page, inode);
  108 +}
  109 +
  110 +
86 111 #else /* CONFIG_NFS_FSCACHE */
87 112 static inline int nfs_fscache_register(void) { return 0; }
88 113 static inline void nfs_fscache_unregister(void) {}
... ... @@ -103,6 +128,15 @@
103 128 static inline void nfs_fscache_set_inode_cookie(struct inode *inode,
104 129 struct file *filp) {}
105 130 static inline void nfs_fscache_reset_inode_cookie(struct inode *inode) {}
  131 +
  132 +static inline int nfs_fscache_release_page(struct page *page, gfp_t gfp)
  133 +{
  134 + return 1; /* True: may release page */
  135 +}
  136 +static inline void nfs_fscache_invalidate_page(struct page *page,
  137 + struct inode *inode) {}
  138 +static inline void nfs_fscache_wait_on_page_write(struct nfs_inode *nfsi,
  139 + struct page *page) {}
106 140  
107 141 #endif /* CONFIG_NFS_FSCACHE */
108 142 #endif /* _NFS_FSCACHE_H */