From: David Howells Make it possible for the NFS filesystem to make use of the network filesystem local caching service (FS-Cache). To be able to use this, an updated mount program is required. This can be obtained from: http://people.redhat.com/steved/cachefs/util-linux/ To mount an NFS filesystem to use caching, add an "fsc" option to the mount: mount warthog:/ /a -o fsc Signed-off-by: David Howells Signed-off-by: Andrew Morton --- fs/nfs/file.c | 29 +++++++++++++++++++---------- fs/nfs/fscache.c | 2 ++ fs/nfs/fscache.h | 26 ++++++++++++++++++-------- 3 files changed, 39 insertions(+), 18 deletions(-) diff -puN fs/nfs/file.c~nfs-use-local-caching-12 fs/nfs/file.c --- a/fs/nfs/file.c~nfs-use-local-caching-12 +++ a/fs/nfs/file.c @@ -314,6 +314,12 @@ static int nfs_commit_write(struct file return status; } +/* + * partially or wholly invalidate a page + * - release the private state associated with a page if undergoing complete + * page invalidation + * - caller holds page lock + */ static void nfs_invalidate_page(struct page *page, unsigned long offset) { struct inode *inode = page->mapping->host; @@ -330,10 +336,13 @@ static void nfs_invalidate_page(struct p ClearPagePrivate(page); } +/* + * release the private state associated with a page, if the page isn't busy + * - caller holds page lock + * - return true (may release) or false (may not) + */ static int nfs_release_page(struct page *page, gfp_t gfp) { - int error; - if ((gfp & __GFP_FS) == 0) { /* * Avoid deadlock on nfs_wait_on_request(). @@ -341,17 +350,17 @@ static int nfs_release_page(struct page return 0; } - error = nfs_wb_page(page->mapping->host, page); + if (nfs_wb_page(page->mapping->host, page) < 0) + return 0; - if (error == 0) { - nfs_fscache_release_page(page); + if (nfs_fscache_release_page(page) < 0) + return 0; - /* may have been set due to either caching or writing */ - ClearPagePrivate(page); - } + /* PG_private may have been set due to either caching or writing */ + BUG_ON(page->private != 0); + ClearPagePrivate(page); - /* releasepage() returns true/false */ - return (error == 0) ? 1 : 0; + return 1; } /* diff -puN fs/nfs/fscache.c~nfs-use-local-caching-12 fs/nfs/fscache.c --- a/fs/nfs/fscache.c~nfs-use-local-caching-12 +++ a/fs/nfs/fscache.c @@ -140,6 +140,8 @@ static void nfs_fh_mark_pages_cached(voi dprintk("NFS: nfs_fh_mark_pages_cached: nfs_inode 0x%p pages %ld\n", nfsi, cached_pvec->nr); + BUG_ON(!nfsi->fscache); + for (loop = 0; loop < cached_pvec->nr; loop++) SetPageNfsCached(cached_pvec->pages[loop]); } diff -puN fs/nfs/fscache.h~nfs-use-local-caching-12 fs/nfs/fscache.h --- a/fs/nfs/fscache.h~nfs-use-local-caching-12 +++ a/fs/nfs/fscache.h @@ -203,23 +203,28 @@ static inline void nfs_fscache_install_v } /* - * release the caching state associated with a page + * release the caching state associated with a page, if the page isn't busy + * interacting with the cache */ -static void nfs_fscache_release_page(struct page *page) +static inline int nfs_fscache_release_page(struct page *page) { + if (PageFsMisc(page)) + return -EBUSY; + if (PageNfsCached(page)) { struct nfs_inode *nfsi = NFS_I(page->mapping->host); - BUG_ON(nfsi->fscache == NULL); + BUG_ON(!nfsi->fscache); dfprintk(FSCACHE, "NFS: fscache releasepage (0x%p/0x%p/0x%p)\n", nfsi->fscache, page, nfsi); - wait_on_page_fs_misc(page); fscache_uncache_page(nfsi->fscache, page); atomic_inc(&nfs_fscache_uncache_page); ClearPageNfsCached(page); } + + return 0; } /* @@ -230,19 +235,24 @@ static inline void nfs_fscache_invalidat struct inode *inode, unsigned long offset) { - if (PageNfsCached(page)) { - struct nfs_inode *nfsi = NFS_I(page->mapping->host); + struct nfs_inode *nfsi = NFS_I(page->mapping->host); + if (PageNfsCached(page)) { BUG_ON(!nfsi->fscache); dfprintk(FSCACHE, "NFS: fscache invalidatepage (0x%p/0x%p/0x%p)\n", nfsi->fscache, page, nfsi); + wait_on_page_fs_misc(page); + if (offset == 0) { BUG_ON(!PageLocked(page)); - if (!PageWriteback(page)) - nfs_fscache_release_page(page); + if (!PageWriteback(page)) { + fscache_uncache_page(nfsi->fscache, page); + atomic_inc(&nfs_fscache_uncache_page); + ClearPageNfsCached(page); + } } } } _