diff options
author | David Howells <dhowells@redhat.com> | 2009-04-03 11:42:44 -0400 |
---|---|---|
committer | David Howells <dhowells@redhat.com> | 2009-04-03 11:42:44 -0400 |
commit | 545db45f0fc0d4203b045047798ce156972a3056 (patch) | |
tree | 783db1091f5d6f21dafece81f6c94caf0aec98b8 | |
parent | 6a51091d0775cdc4a923f2172c61925ad416aa32 (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.c | 18 | ||||
-rw-r--r-- | fs/nfs/fscache.c | 53 | ||||
-rw-r--r-- | fs/nfs/fscache.h | 34 |
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 | */ |
419 | static void nfs_invalidate_page(struct page *page, unsigned long offset) | 420 | static 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 | */ |
451 | static int nfs_launder_page(struct page *page) | 456 | static 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 | */ | ||
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); | ||
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 *); | |||
83 | extern void nfs_fscache_set_inode_cookie(struct inode *, struct file *); | 83 | extern void nfs_fscache_set_inode_cookie(struct inode *, struct file *); |
84 | extern void nfs_fscache_reset_inode_cookie(struct inode *); | 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 | #else /* CONFIG_NFS_FSCACHE */ | 111 | #else /* CONFIG_NFS_FSCACHE */ |
87 | static inline int nfs_fscache_register(void) { return 0; } | 112 | static inline int nfs_fscache_register(void) { return 0; } |
88 | static inline void nfs_fscache_unregister(void) {} | 113 | static 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) {} |
105 | static inline void nfs_fscache_reset_inode_cookie(struct inode *inode) {} | 130 | static inline void nfs_fscache_reset_inode_cookie(struct inode *inode) {} |
106 | 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) {} | ||
140 | |||
107 | #endif /* CONFIG_NFS_FSCACHE */ | 141 | #endif /* CONFIG_NFS_FSCACHE */ |
108 | #endif /* _NFS_FSCACHE_H */ | 142 | #endif /* _NFS_FSCACHE_H */ |