Use an inode flag, I_PINNING_FSCACHE_WB, to indicate that a cookie is
pinned in use by that inode for the purposes of writeback.

Pinning is necessary because the in-use pin from the open file is released
before the writeback takes place, but if the resources aren't pinned, the
dirty data can't be written to the cache.

Signed-off-by: David Howells <dhowe...@redhat.com>
---

 fs/fscache/io.c         |   38 ++++++++++++++++++++++++++++++++++++++
 include/linux/fscache.h |   41 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 79 insertions(+)

diff --git a/fs/fscache/io.c b/fs/fscache/io.c
index ef4b0606019d..25976413fe34 100644
--- a/fs/fscache/io.c
+++ b/fs/fscache/io.c
@@ -214,3 +214,41 @@ int __fscache_fallback_write_page(struct fscache_cookie 
*cookie, struct page *pa
        return ret;
 }
 EXPORT_SYMBOL(__fscache_fallback_write_page);
+
+/**
+ * fscache_set_page_dirty - Mark page dirty and pin a cache object for 
writeback
+ * @page: The page being dirtied
+ * @cookie: The cookie referring to the cache object
+ *
+ * Set the dirty flag on a page and pin an in-use cache object in memory when
+ * dirtying a page so that writeback can later write to it.  This is intended
+ * to be called from the filesystem's ->set_page_dirty() method.
+ *
+ *  Returns 1 if PG_dirty was set on the page, 0 otherwise.
+ */
+int fscache_set_page_dirty(struct page *page, struct fscache_cookie *cookie)
+{
+       struct inode *inode = page->mapping->host;
+       bool need_use = false;
+
+       _enter("");
+
+       if (!__set_page_dirty_nobuffers(page))
+               return 0;
+       if (!fscache_cookie_valid(cookie))
+               return 1;
+
+       if (!(inode->i_state & I_PINNING_FSCACHE_WB)) {
+               spin_lock(&inode->i_lock);
+               if (!(inode->i_state & I_PINNING_FSCACHE_WB)) {
+                       inode->i_state |= I_PINNING_FSCACHE_WB;
+                       need_use = true;
+               }
+               spin_unlock(&inode->i_lock);
+
+               if (need_use)
+                       fscache_use_cookie(cookie, true);
+       }
+       return 1;
+}
+EXPORT_SYMBOL(fscache_set_page_dirty);
diff --git a/include/linux/fscache.h b/include/linux/fscache.h
index fa7eef2674bf..abf5413c3151 100644
--- a/include/linux/fscache.h
+++ b/include/linux/fscache.h
@@ -512,6 +512,47 @@ int fscache_write(struct netfs_cache_resources *cres,
 
 #endif /* FSCACHE_USE_NEW_IO_API */
 
+#if __fscache_available
+extern int fscache_set_page_dirty(struct page *page, struct fscache_cookie 
*cookie);
+#else
+#define fscache_set_page_dirty(PAGE, COOKIE) 
(__set_page_dirty_nobuffers((PAGE)))
+#endif
+
+/**
+ * fscache_unpin_writeback - Unpin writeback resources
+ * @wbc: The writeback control
+ * @cookie: The cookie referring to the cache object
+ *
+ * Unpin the writeback resources pinned by fscache_set_page_dirty().  This is
+ * intended to be called by the netfs's ->write_inode() method.
+ */
+static inline void fscache_unpin_writeback(struct writeback_control *wbc,
+                                          struct fscache_cookie *cookie)
+{
+       if (wbc->unpinned_fscache_wb)
+               fscache_unuse_cookie(cookie, NULL, NULL);
+}
+
+/**
+ * fscache_clear_inode_writeback - Clear writeback resources pinned by an inode
+ * @cookie: The cookie referring to the cache object
+ * @inode: The inode to clean up
+ * @aux: Auxiliary data to apply to the inode
+ *
+ * Clear any writeback resources held by an inode when the inode is evicted.
+ * This must be called before clear_inode() is called.
+ */
+static inline void fscache_clear_inode_writeback(struct fscache_cookie *cookie,
+                                                struct inode *inode,
+                                                const void *aux)
+{
+       if (inode->i_state & I_PINNING_FSCACHE_WB) {
+               loff_t i_size = i_size_read(inode);
+               fscache_unuse_cookie(cookie, aux, &i_size);
+       }
+
+}
+
 #ifdef FSCACHE_USE_FALLBACK_IO_API
 
 /**


--
Linux-cachefs mailing list
Linux-cachefs@redhat.com
https://listman.redhat.com/mailman/listinfo/linux-cachefs

Reply via email to