Commit 545db45f0fc0d4203b045047798ce156972a3056
1 parent
6a51091d07
Exists in
master
and in
7 other branches
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
fs/nfs/file.c
... | ... | @@ -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; |
fs/nfs/fscache.c
... | ... | @@ -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 | } |
fs/nfs/fscache.h
... | ... | @@ -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 */ |