cifs: FS-Cache page management
authorSuresh Jayaraman <sjayaraman@suse.de>
Mon, 5 Jul 2010 12:43:00 +0000 (18:13 +0530)
committerSteve French <sfrench@us.ibm.com>
Mon, 2 Aug 2010 12:40:36 +0000 (12:40 +0000)
Takes care of invalidation and release of FS-Cache marked pages and also
invalidation of the FsCache page flag when the inode is removed.

Signed-off-by: Suresh Jayaraman <sjayaraman@suse.de>
Acked-by: David Howells <dhowells@redhat.com>
Signed-off-by: Steve French <sfrench@us.ibm.com>
fs/cifs/cache.c
fs/cifs/file.c
fs/cifs/fscache.c
fs/cifs/fscache.h

index b2649cfd3a04cc552457609c523c2148b563ffca..224d7bbd1fcc95d3dfadfc09e6d773d425eba95f 100644 (file)
@@ -290,6 +290,36 @@ fscache_checkaux cifs_fscache_inode_check_aux(void *cookie_netfs_data,
        return FSCACHE_CHECKAUX_OKAY;
 }
 
+static void cifs_fscache_inode_now_uncached(void *cookie_netfs_data)
+{
+       struct cifsInodeInfo *cifsi = cookie_netfs_data;
+       struct pagevec pvec;
+       pgoff_t first;
+       int loop, nr_pages;
+
+       pagevec_init(&pvec, 0);
+       first = 0;
+
+       cFYI(1, "cifs inode 0x%p now uncached", cifsi);
+
+       for (;;) {
+               nr_pages = pagevec_lookup(&pvec,
+                                         cifsi->vfs_inode.i_mapping, first,
+                                         PAGEVEC_SIZE - pagevec_count(&pvec));
+               if (!nr_pages)
+                       break;
+
+               for (loop = 0; loop < nr_pages; loop++)
+                       ClearPageFsCache(pvec.pages[loop]);
+
+               first = pvec.pages[nr_pages - 1]->index + 1;
+
+               pvec.nr = nr_pages;
+               pagevec_release(&pvec);
+               cond_resched();
+       }
+}
+
 const struct fscache_cookie_def cifs_fscache_inode_object_def = {
        .name           = "CIFS.uniqueid",
        .type           = FSCACHE_COOKIE_TYPE_DATAFILE,
@@ -297,4 +327,5 @@ const struct fscache_cookie_def cifs_fscache_inode_object_def = {
        .get_attr       = cifs_fscache_inode_get_attr,
        .get_aux        = cifs_fscache_inode_get_aux,
        .check_aux      = cifs_fscache_inode_check_aux,
+       .now_uncached   = cifs_fscache_inode_now_uncached,
 };
index d302d941f9acd0e035a0c0b7e947b8b7fe9e224f..f677ede766d122efd153022d8dfaa1d48cbae6db 100644 (file)
@@ -2267,6 +2267,22 @@ out:
        return rc;
 }
 
+static int cifs_release_page(struct page *page, gfp_t gfp)
+{
+       if (PagePrivate(page))
+               return 0;
+
+       return cifs_fscache_release_page(page, gfp);
+}
+
+static void cifs_invalidate_page(struct page *page, unsigned long offset)
+{
+       struct cifsInodeInfo *cifsi = CIFS_I(page->mapping->host);
+
+       if (offset == 0)
+               cifs_fscache_invalidate_page(page, &cifsi->vfs_inode);
+}
+
 static void
 cifs_oplock_break(struct slow_work *work)
 {
@@ -2340,6 +2356,8 @@ const struct address_space_operations cifs_addr_ops = {
        .write_begin = cifs_write_begin,
        .write_end = cifs_write_end,
        .set_page_dirty = __set_page_dirty_nobuffers,
+       .releasepage = cifs_release_page,
+       .invalidatepage = cifs_invalidate_page,
        /* .sync_page = cifs_sync_page, */
        /* .direct_IO = */
 };
@@ -2356,6 +2374,8 @@ const struct address_space_operations cifs_addr_ops_smallbuf = {
        .write_begin = cifs_write_begin,
        .write_end = cifs_write_end,
        .set_page_dirty = __set_page_dirty_nobuffers,
+       .releasepage = cifs_release_page,
+       .invalidatepage = cifs_invalidate_page,
        /* .sync_page = cifs_sync_page, */
        /* .direct_IO = */
 };
index 6c8d96758ddb2e65d818dcdb6adc714ffeab63c9..5dd9352800492b5201d1f772325a3c12faf9f488 100644 (file)
@@ -124,3 +124,29 @@ void cifs_fscache_reset_inode_cookie(struct inode *inode)
                                cifsi->fscache, old);
        }
 }
+
+int cifs_fscache_release_page(struct page *page, gfp_t gfp)
+{
+       if (PageFsCache(page)) {
+               struct inode *inode = page->mapping->host;
+               struct cifsInodeInfo *cifsi = CIFS_I(inode);
+
+               cFYI(1, "CIFS: fscache release page (0x%p/0x%p)",
+                               page, cifsi->fscache);
+               if (!fscache_maybe_release_page(cifsi->fscache, page, gfp))
+                       return 0;
+       }
+
+       return 1;
+}
+
+void __cifs_fscache_invalidate_page(struct page *page, struct inode *inode)
+{
+       struct cifsInodeInfo *cifsi = CIFS_I(inode);
+       struct fscache_cookie *cookie = cifsi->fscache;
+
+       cFYI(1, "CIFS: fscache invalidatepage (0x%p/0x%p)", page, cookie);
+       fscache_wait_on_page_write(cookie, page);
+       fscache_uncache_page(cookie, page);
+}
+
index 1008f405083530adb9471f64d0c56fd547ff63d1..5e18a21eee9dd85ae1aaa0e550c827d0db36db19 100644 (file)
@@ -48,6 +48,16 @@ extern void cifs_fscache_release_inode_cookie(struct inode *);
 extern void cifs_fscache_set_inode_cookie(struct inode *, struct file *);
 extern void cifs_fscache_reset_inode_cookie(struct inode *);
 
+extern void __cifs_fscache_invalidate_page(struct page *, struct inode *);
+extern int cifs_fscache_release_page(struct page *page, gfp_t gfp);
+
+static inline void cifs_fscache_invalidate_page(struct page *page,
+                                              struct inode *inode)
+{
+       if (PageFsCache(page))
+               __cifs_fscache_invalidate_page(page, inode);
+}
+
 #else /* CONFIG_CIFS_FSCACHE */
 static inline int cifs_fscache_register(void) { return 0; }
 static inline void cifs_fscache_unregister(void) {}
@@ -64,7 +74,13 @@ static inline void cifs_fscache_release_inode_cookie(struct inode *inode) {}
 static inline void cifs_fscache_set_inode_cookie(struct inode *inode,
                                                 struct file *filp) {}
 static inline void cifs_fscache_reset_inode_cookie(struct inode *inode) {}
+static inline void cifs_fscache_release_page(struct page *page, gfp_t gfp)
+{
+       return 1; /* May release page */
+}
 
+static inline int cifs_fscache_invalidate_page(struct page *page,
+                       struct inode *) {}
 
 #endif /* CONFIG_CIFS_FSCACHE */