aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2009-04-03 11:42:44 -0400
committerDavid Howells <dhowells@redhat.com>2009-04-03 11:42:44 -0400
commit545db45f0fc0d4203b045047798ce156972a3056 (patch)
tree783db1091f5d6f21dafece81f6c94caf0aec98b8
parent6a51091d0775cdc4a923f2172c61925ad416aa32 (diff)
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>
-rw-r--r--fs/nfs/file.c18
-rw-r--r--fs/nfs/fscache.c53
-rw-r--r--fs/nfs/fscache.h34
3 files changed, 101 insertions, 4 deletions
diff --git a/fs/nfs/file.c b/fs/nfs/file.c
index f5bc54dccecb..3523b895eb4b 100644
--- a/fs/nfs/file.c
+++ b/fs/nfs/file.c
@@ -35,6 +35,7 @@
35#include "delegation.h" 35#include "delegation.h"
36#include "internal.h" 36#include "internal.h"
37#include "iostat.h" 37#include "iostat.h"
38#include "fscache.h"
38 39
39#define NFSDBG_FACILITY NFSDBG_FILE 40#define NFSDBG_FACILITY NFSDBG_FILE
40 41
@@ -413,7 +414,7 @@ static int nfs_write_end(struct file *file, struct address_space *mapping,
413 * Partially or wholly invalidate a page 414 * Partially or wholly invalidate a page
414 * - Release the private state associated with a page if undergoing complete 415 * - Release the private state associated with a page if undergoing complete
415 * page invalidation 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 * - Caller holds page lock 418 * - Caller holds page lock
418 */ 419 */
419static void nfs_invalidate_page(struct page *page, unsigned long offset) 420static void nfs_invalidate_page(struct page *page, unsigned long offset)
@@ -424,11 +425,13 @@ static void nfs_invalidate_page(struct page *page, unsigned long offset)
424 return; 425 return;
425 /* Cancel any unstarted writes on this page */ 426 /* Cancel any unstarted writes on this page */
426 nfs_wb_page_cancel(page->mapping->host, page); 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 * Attempt to release the private state associated with a page 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 * - Caller holds page lock 435 * - Caller holds page lock
433 * - Return true (may release page) or false (may not) 436 * - Return true (may release page) or false (may not)
434 */ 437 */
@@ -437,24 +440,28 @@ static int nfs_release_page(struct page *page, gfp_t gfp)
437 dfprintk(PAGECACHE, "NFS: release_page(%p)\n", page); 440 dfprintk(PAGECACHE, "NFS: release_page(%p)\n", page);
438 441
439 /* If PagePrivate() is set, then the page is not freeable */ 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 * Attempt to clear the private state associated with a page when an error 449 * Attempt to clear the private state associated with a page when an error
445 * occurs that requires the cached contents of an inode to be written back or 450 * occurs that requires the cached contents of an inode to be written back or
446 * destroyed 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 * - Caller holds page lock 453 * - Caller holds page lock
449 * - Return 0 if successful, -error otherwise 454 * - Return 0 if successful, -error otherwise
450 */ 455 */
451static int nfs_launder_page(struct page *page) 456static int nfs_launder_page(struct page *page)
452{ 457{
453 struct inode *inode = page->mapping->host; 458 struct inode *inode = page->mapping->host;
459 struct nfs_inode *nfsi = NFS_I(inode);
454 460
455 dfprintk(PAGECACHE, "NFS: launder_page(%ld, %llu)\n", 461 dfprintk(PAGECACHE, "NFS: launder_page(%ld, %llu)\n",
456 inode->i_ino, (long long)page_offset(page)); 462 inode->i_ino, (long long)page_offset(page));
457 463
464 nfs_fscache_wait_on_page_write(nfsi, page);
458 return nfs_wb_page(inode, page); 465 return nfs_wb_page(inode, page);
459} 466}
460 467
@@ -491,6 +498,9 @@ static int nfs_vm_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
491 filp->f_mapping->host->i_ino, 498 filp->f_mapping->host->i_ino,
492 (long long)page_offset(page)); 499 (long long)page_offset(page));
493 500
501 /* make sure the cache has finished storing the page */
502 nfs_fscache_wait_on_page_write(NFS_I(dentry->d_inode), page);
503
494 lock_page(page); 504 lock_page(page);
495 mapping = page->mapping; 505 mapping = page->mapping;
496 if (mapping != dentry->d_inode->i_mapping) 506 if (mapping != dentry->d_inode->i_mapping)
diff --git a/fs/nfs/fscache.c b/fs/nfs/fscache.c
index e3816eb53fb8..f673d35d8b89 100644
--- a/fs/nfs/fscache.c
+++ b/fs/nfs/fscache.c
@@ -19,6 +19,7 @@
19#include <linux/seq_file.h> 19#include <linux/seq_file.h>
20 20
21#include "internal.h" 21#include "internal.h"
22#include "iostat.h"
22#include "fscache.h" 23#include "fscache.h"
23 24
24#define NFSDBG_FACILITY NFSDBG_FSCACHE 25#define NFSDBG_FACILITY NFSDBG_FSCACHE
@@ -328,3 +329,55 @@ void nfs_fscache_reset_inode_cookie(struct inode *inode)
328 } 329 }
329 nfs_fscache_inode_unlock(inode); 330 nfs_fscache_inode_unlock(inode);
330} 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 */
338int 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 */
367void __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);
383}
diff --git a/fs/nfs/fscache.h b/fs/nfs/fscache.h
index 8b4299a0ad61..e29613a8cbd2 100644
--- a/fs/nfs/fscache.h
+++ b/fs/nfs/fscache.h
@@ -83,6 +83,31 @@ extern void nfs_fscache_zap_inode_cookie(struct inode *);
83extern void nfs_fscache_set_inode_cookie(struct inode *, struct file *); 83extern void nfs_fscache_set_inode_cookie(struct inode *, struct file *);
84extern void nfs_fscache_reset_inode_cookie(struct inode *); 84extern void nfs_fscache_reset_inode_cookie(struct inode *);
85 85
86extern void __nfs_fscache_invalidate_page(struct page *, struct inode *);
87extern int nfs_fscache_release_page(struct page *, gfp_t);
88
89/*
90 * wait for a page to complete writing to the cache
91 */
92static 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 */
103static 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#else /* CONFIG_NFS_FSCACHE */ 111#else /* CONFIG_NFS_FSCACHE */
87static inline int nfs_fscache_register(void) { return 0; } 112static inline int nfs_fscache_register(void) { return 0; }
88static inline void nfs_fscache_unregister(void) {} 113static inline void nfs_fscache_unregister(void) {}
@@ -104,5 +129,14 @@ static inline void nfs_fscache_set_inode_cookie(struct inode *inode,
104 struct file *filp) {} 129 struct file *filp) {}
105static inline void nfs_fscache_reset_inode_cookie(struct inode *inode) {} 130static inline void nfs_fscache_reset_inode_cookie(struct inode *inode) {}
106 131
132static inline int nfs_fscache_release_page(struct page *page, gfp_t gfp)
133{
134 return 1; /* True: may release page */
135}
136static inline void nfs_fscache_invalidate_page(struct page *page,
137 struct inode *inode) {}
138static inline void nfs_fscache_wait_on_page_write(struct nfs_inode *nfsi,
139 struct page *page) {}
140
107#endif /* CONFIG_NFS_FSCACHE */ 141#endif /* CONFIG_NFS_FSCACHE */
108#endif /* _NFS_FSCACHE_H */ 142#endif /* _NFS_FSCACHE_H */