#include <linux/fs.h>
 #include <linux/mm.h>
 #include <linux/pagemap.h>
-#include <linux/writeback.h>   /* generic_writepages */
 #include <linux/slab.h>
 #include <linux/pagevec.h>
 #include <linux/task_io_accounting_ops.h>
        netfs_readahead(ractl, &ceph_netfs_read_ops, (void *)(uintptr_t)got);
 }
 
+#ifdef CONFIG_CEPH_FSCACHE
+static void ceph_set_page_fscache(struct page *page)
+{
+       set_page_fscache(page);
+}
+
+static void ceph_fscache_write_terminated(void *priv, ssize_t error, bool was_async)
+{
+       struct inode *inode = priv;
+
+       if (IS_ERR_VALUE(error) && error != -ENOBUFS)
+               ceph_fscache_invalidate(inode, false);
+}
+
+static void ceph_fscache_write_to_cache(struct inode *inode, u64 off, u64 len, bool caching)
+{
+       struct ceph_inode_info *ci = ceph_inode(inode);
+       struct fscache_cookie *cookie = ceph_fscache_cookie(ci);
+
+       fscache_write_to_cache(cookie, inode->i_mapping, off, len, i_size_read(inode),
+                              ceph_fscache_write_terminated, inode, caching);
+}
+#else
+static inline void ceph_set_page_fscache(struct page *page)
+{
+}
+
+static inline void ceph_fscache_write_to_cache(struct inode *inode, u64 off, u64 len, bool caching)
+{
+}
+#endif /* CONFIG_CEPH_FSCACHE */
+
 struct ceph_writeback_ctl
 {
        loff_t i_size;
        struct ceph_writeback_ctl ceph_wbc;
        struct ceph_osd_client *osdc = &fsc->client->osdc;
        struct ceph_osd_request *req;
+       bool caching = ceph_is_cache_enabled(inode);
 
        dout("writepage %p idx %lu\n", page, page->index);
 
            CONGESTION_ON_THRESH(fsc->mount_options->congestion_kb))
                set_bdi_congested(inode_to_bdi(inode), BLK_RW_ASYNC);
 
-       set_page_writeback(page);
        req = ceph_osdc_new_request(osdc, &ci->i_layout, ceph_vino(inode), page_off, &len, 0, 1,
                                    CEPH_OSD_OP_WRITE, CEPH_OSD_FLAG_WRITE, snapc,
                                    ceph_wbc.truncate_seq, ceph_wbc.truncate_size,
                                    true);
-       if (IS_ERR(req)) {
-               redirty_page_for_writepage(wbc, page);
-               end_page_writeback(page);
+       if (IS_ERR(req))
                return PTR_ERR(req);
-       }
+
+       set_page_writeback(page);
+       if (caching)
+               ceph_set_page_fscache(page);
+       ceph_fscache_write_to_cache(inode, page_off, len, caching);
 
        /* it may be a short write due to an object boundary */
        WARN_ON_ONCE(len > thp_size(page));
        struct inode *inode = page->mapping->host;
        BUG_ON(!inode);
        ihold(inode);
+
+       wait_on_page_fscache(page);
+
        err = writepage_nounlock(page, wbc);
        if (err == -ERESTARTSYS) {
                /* direct memory reclaimer was killed by SIGKILL. return 0
        struct ceph_writeback_ctl ceph_wbc;
        bool should_loop, range_whole = false;
        bool done = false;
+       bool caching = ceph_is_cache_enabled(inode);
 
        dout("writepages_start %p (mode=%s)\n", inode,
             wbc->sync_mode == WB_SYNC_NONE ? "NONE" :
                                unlock_page(page);
                                break;
                        }
-                       if (PageWriteback(page)) {
+                       if (PageWriteback(page) || PageFsCache(page)) {
                                if (wbc->sync_mode == WB_SYNC_NONE) {
                                        dout("%p under writeback\n", page);
                                        unlock_page(page);
                                }
                                dout("waiting on writeback %p\n", page);
                                wait_on_page_writeback(page);
+                               wait_on_page_fscache(page);
                        }
 
                        if (!clear_page_dirty_for_io(page)) {
                op_idx = 0;
                for (i = 0; i < locked_pages; i++) {
                        u64 cur_offset = page_offset(pages[i]);
+                       /*
+                        * Discontinuity in page range? Ceph can handle that by just passing
+                        * multiple extents in the write op.
+                        */
                        if (offset + len != cur_offset) {
+                               /* If it's full, stop here */
                                if (op_idx + 1 == req->r_num_ops)
                                        break;
+
+                               /* Kick off an fscache write with what we have so far. */
+                               ceph_fscache_write_to_cache(inode, offset, len, caching);
+
+                               /* Start a new extent */
                                osd_req_op_extent_dup_last(req, op_idx,
                                                           cur_offset - offset);
                                dout("writepages got pages at %llu~%llu\n",
                                osd_req_op_extent_update(req, op_idx, len);
 
                                len = 0;
-                               offset = cur_offset; 
+                               offset = cur_offset;
                                data_pages = pages + i;
                                op_idx++;
                        }
 
                        set_page_writeback(pages[i]);
+                       if (caching)
+                               ceph_set_page_fscache(pages[i]);
                        len += thp_size(page);
                }
+               ceph_fscache_write_to_cache(inode, offset, len, caching);
 
                if (ceph_wbc.size_stable) {
                        len = min(len, ceph_wbc.i_size - offset);