When writing to the server from afs_writepage() or afs_writepages(), copy the data to the cache object too. Signed-off-by: David Howells <dhowells@xxxxxxxxxx> --- fs/afs/write.c | 124 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 119 insertions(+), 5 deletions(-) diff --git a/fs/afs/write.c b/fs/afs/write.c index 312d8f07533e..38637dc6043c 100644 --- a/fs/afs/write.c +++ b/fs/afs/write.c @@ -13,6 +13,9 @@ #include <linux/pagevec.h> #include "internal.h" +static void afs_write_to_cache(struct afs_vnode *vnode, + pgoff_t start, pgoff_t end, loff_t a, loff_t b); + /* * mark a page as having been made dirty and thus needing writeback */ @@ -389,6 +392,8 @@ static int afs_write_back_from_locked_page(struct address_space *mapping, count = 1; if (test_set_page_writeback(primary_page)) BUG(); + if (TestSetPageFsCache(primary_page)) + BUG(); /* Find all consecutive lockable dirty pages that have contiguous * written regions, stopping when we find a page that is not @@ -437,7 +442,8 @@ static int afs_write_back_from_locked_page(struct address_space *mapping, break; if (!trylock_page(page)) break; - if (!PageDirty(page) || PageWriteback(page)) { + if (!PageDirty(page) || PageWriteback(page) || + PageFsCache(page)) { unlock_page(page); break; } @@ -459,6 +465,8 @@ static int afs_write_back_from_locked_page(struct address_space *mapping, BUG(); if (test_set_page_writeback(page)) BUG(); + if (TestSetPageFsCache(page)) + BUG(); unlock_page(page); put_page(page); } @@ -489,8 +497,13 @@ static int afs_write_back_from_locked_page(struct address_space *mapping, b = last; b <<= PAGE_SHIFT; b += to; - iov_iter_mapping(&iter, WRITE, mapping, a, b - a); + /* Speculatively write to the cache. We have to fix this up later if + * the store fails. + */ + afs_write_to_cache(vnode, first, last + 1, a, b); + + iov_iter_mapping(&iter, WRITE, mapping, a, b - a); ret = afs_store_data(vnode, &iter, a, first, last); switch (ret) { case 0: @@ -543,6 +556,10 @@ int afs_writepage(struct page *page, struct writeback_control *wbc) _enter("{%lx},", page->index); +#ifdef CONFIG_AFS_FSCACHE + wait_on_page_fscache(page); +#endif + ret = afs_write_back_from_locked_page(page->mapping, wbc, page, wbc->range_end >> PAGE_SHIFT); if (ret < 0) { @@ -570,7 +587,7 @@ static int afs_writepages_region(struct address_space *mapping, do { n = find_get_pages_range_tag(mapping, &index, end, - PAGECACHE_TAG_DIRTY, 1, &page); + PAGECACHE_TAG_DIRTY, 1, &page); if (!n) break; @@ -595,10 +612,14 @@ static int afs_writepages_region(struct address_space *mapping, continue; } - if (PageWriteback(page)) { + if (PageWriteback(page) || PageFsCache(page)) { unlock_page(page); - if (wbc->sync_mode != WB_SYNC_NONE) + if (wbc->sync_mode != WB_SYNC_NONE) { wait_on_page_writeback(page); +#ifdef CONFIG_AFS_FSCACHE + wait_on_page_fscache(page); +#endif + } put_page(page); continue; } @@ -818,3 +839,96 @@ int afs_launder_page(struct page *page) ClearPagePrivate(page); return ret; } + +/* + * Clear the PG_fscache flag from a sequence of pages and wake up anyone who's + * waiting. The last page is included in the sequence. + */ +static void afs_clear_fscache_bits(struct address_space *mapping, + pgoff_t start, pgoff_t last) +{ + struct page *page; + + XA_STATE(xas, &mapping->i_pages, start); + + rcu_read_lock(); + xas_for_each(&xas, page, last) { + unlock_page_fscache(page); + } + rcu_read_unlock(); +} + +/* + * Deal with the completion of writing the data to the cache. + */ +static void afs_write_to_cache_done(struct fscache_io_request *_req) +{ + struct afs_read *req = container_of(_req, struct afs_read, cache); + pgoff_t index = req->cache.pos >> PAGE_SHIFT; + pgoff_t last = index + req->cache.nr_pages - 1; + + _enter("%lx,%x,%llx", index, req->cache.nr_pages, req->cache.transferred); + + afs_clear_fscache_bits(req->cache.mapping, index, last); + + if (req->cache.error && req->cache.error != -ENOBUFS) { + struct afs_vnode *vnode = req->vnode; + struct afs_vnode_cache_aux aux = { + .data_version = vnode->status.data_version, + }; + _debug("inval wr %d", req->cache.error); + fscache_invalidate(req->cache.cookie, &aux, + i_size_read(&vnode->vfs_inode), 0); + } +} + +static const struct fscache_io_request_ops afs_write_req_ops = { + .get = afs_req_get, + .put = afs_req_put, +}; + +/* + * Save the write to the cache also. + */ +static void afs_write_to_cache(struct afs_vnode *vnode, + pgoff_t start, pgoff_t end, loff_t a, loff_t b) +{ + struct afs_read *req; + struct iov_iter iter; + unsigned int x; + + struct fscache_extent extent = { + .start = start, + .block_end = end, + .limit = end, + }; + + _enter("%lx,%lx,%llx,%llx", start, end, a, b); + + x = fscache_shape_extent(afs_vnode_cache(vnode), &extent, + i_size_read(&vnode->vfs_inode), true); + if (!(x & FSCACHE_WRITE_TO_CACHE)) + goto abandon; + + req = afs_alloc_read(GFP_KERNEL); + if (!req) + goto abandon; + + fscache_init_io_request(&req->cache, afs_vnode_cache(vnode), + &afs_write_req_ops); + req->vnode = vnode; + req->cache.pos = round_down(a, extent.dio_block_size); + req->cache.len = round_up(b, extent.dio_block_size) - req->cache.pos; + req->cache.nr_pages = end - start; + req->cache.mapping = vnode->vfs_inode.i_mapping; + req->cache.io_done = &afs_write_to_cache_done; + + iov_iter_mapping(&iter, WRITE, req->cache.mapping, + req->cache.pos, req->cache.len); + fscache_write(&req->cache, &iter); + afs_put_read(req); + return; + +abandon: + afs_clear_fscache_bits(vnode->vfs_inode.i_mapping, start, end); +}