Skip to content

Commit 1702e79

Browse files
jtlaytondhowells
authored andcommitted
ceph: add fscache writeback support
When updating the backing store from the pagecache (a'la writepage or writepages), write to the cache first. This allows us to keep caching files even when they are being written, as long as we have appropriate caps. Signed-off-by: Jeff Layton <[email protected]> Signed-off-by: David Howells <[email protected]> Link: https://lore.kernel.org/r/[email protected]/ # v1 Link: https://lore.kernel.org/r/[email protected]/ # v2 Link: https://lore.kernel.org/r/163906985808.143852.1383891557313186623.stgit@warthog.procyon.org.uk/ # v2 Link: https://lore.kernel.org/r/163967190257.1823006.16713609520911954804.stgit@warthog.procyon.org.uk/ # v3 Link: https://lore.kernel.org/r/164021585020.640689.6765214932458435472.stgit@warthog.procyon.org.uk/ # v4
1 parent 400e128 commit 1702e79

File tree

1 file changed

+59
-8
lines changed

1 file changed

+59
-8
lines changed

fs/ceph/addr.c

Lines changed: 59 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
#include <linux/fs.h>
66
#include <linux/mm.h>
77
#include <linux/pagemap.h>
8-
#include <linux/writeback.h> /* generic_writepages */
98
#include <linux/slab.h>
109
#include <linux/pagevec.h>
1110
#include <linux/task_io_accounting_ops.h>
@@ -384,6 +383,38 @@ static void ceph_readahead(struct readahead_control *ractl)
384383
netfs_readahead(ractl, &ceph_netfs_read_ops, (void *)(uintptr_t)got);
385384
}
386385

386+
#ifdef CONFIG_CEPH_FSCACHE
387+
static void ceph_set_page_fscache(struct page *page)
388+
{
389+
set_page_fscache(page);
390+
}
391+
392+
static void ceph_fscache_write_terminated(void *priv, ssize_t error, bool was_async)
393+
{
394+
struct inode *inode = priv;
395+
396+
if (IS_ERR_VALUE(error) && error != -ENOBUFS)
397+
ceph_fscache_invalidate(inode, false);
398+
}
399+
400+
static void ceph_fscache_write_to_cache(struct inode *inode, u64 off, u64 len, bool caching)
401+
{
402+
struct ceph_inode_info *ci = ceph_inode(inode);
403+
struct fscache_cookie *cookie = ceph_fscache_cookie(ci);
404+
405+
fscache_write_to_cache(cookie, inode->i_mapping, off, len, i_size_read(inode),
406+
ceph_fscache_write_terminated, inode, caching);
407+
}
408+
#else
409+
static inline void ceph_set_page_fscache(struct page *page)
410+
{
411+
}
412+
413+
static inline void ceph_fscache_write_to_cache(struct inode *inode, u64 off, u64 len, bool caching)
414+
{
415+
}
416+
#endif /* CONFIG_CEPH_FSCACHE */
417+
387418
struct ceph_writeback_ctl
388419
{
389420
loff_t i_size;
@@ -499,6 +530,7 @@ static int writepage_nounlock(struct page *page, struct writeback_control *wbc)
499530
struct ceph_writeback_ctl ceph_wbc;
500531
struct ceph_osd_client *osdc = &fsc->client->osdc;
501532
struct ceph_osd_request *req;
533+
bool caching = ceph_is_cache_enabled(inode);
502534

503535
dout("writepage %p idx %lu\n", page, page->index);
504536

@@ -537,16 +569,17 @@ static int writepage_nounlock(struct page *page, struct writeback_control *wbc)
537569
CONGESTION_ON_THRESH(fsc->mount_options->congestion_kb))
538570
set_bdi_congested(inode_to_bdi(inode), BLK_RW_ASYNC);
539571

540-
set_page_writeback(page);
541572
req = ceph_osdc_new_request(osdc, &ci->i_layout, ceph_vino(inode), page_off, &len, 0, 1,
542573
CEPH_OSD_OP_WRITE, CEPH_OSD_FLAG_WRITE, snapc,
543574
ceph_wbc.truncate_seq, ceph_wbc.truncate_size,
544575
true);
545-
if (IS_ERR(req)) {
546-
redirty_page_for_writepage(wbc, page);
547-
end_page_writeback(page);
576+
if (IS_ERR(req))
548577
return PTR_ERR(req);
549-
}
578+
579+
set_page_writeback(page);
580+
if (caching)
581+
ceph_set_page_fscache(page);
582+
ceph_fscache_write_to_cache(inode, page_off, len, caching);
550583

551584
/* it may be a short write due to an object boundary */
552585
WARN_ON_ONCE(len > thp_size(page));
@@ -605,6 +638,9 @@ static int ceph_writepage(struct page *page, struct writeback_control *wbc)
605638
struct inode *inode = page->mapping->host;
606639
BUG_ON(!inode);
607640
ihold(inode);
641+
642+
wait_on_page_fscache(page);
643+
608644
err = writepage_nounlock(page, wbc);
609645
if (err == -ERESTARTSYS) {
610646
/* direct memory reclaimer was killed by SIGKILL. return 0
@@ -726,6 +762,7 @@ static int ceph_writepages_start(struct address_space *mapping,
726762
struct ceph_writeback_ctl ceph_wbc;
727763
bool should_loop, range_whole = false;
728764
bool done = false;
765+
bool caching = ceph_is_cache_enabled(inode);
729766

730767
dout("writepages_start %p (mode=%s)\n", inode,
731768
wbc->sync_mode == WB_SYNC_NONE ? "NONE" :
@@ -849,14 +886,15 @@ static int ceph_writepages_start(struct address_space *mapping,
849886
unlock_page(page);
850887
break;
851888
}
852-
if (PageWriteback(page)) {
889+
if (PageWriteback(page) || PageFsCache(page)) {
853890
if (wbc->sync_mode == WB_SYNC_NONE) {
854891
dout("%p under writeback\n", page);
855892
unlock_page(page);
856893
continue;
857894
}
858895
dout("waiting on writeback %p\n", page);
859896
wait_on_page_writeback(page);
897+
wait_on_page_fscache(page);
860898
}
861899

862900
if (!clear_page_dirty_for_io(page)) {
@@ -989,9 +1027,19 @@ static int ceph_writepages_start(struct address_space *mapping,
9891027
op_idx = 0;
9901028
for (i = 0; i < locked_pages; i++) {
9911029
u64 cur_offset = page_offset(pages[i]);
1030+
/*
1031+
* Discontinuity in page range? Ceph can handle that by just passing
1032+
* multiple extents in the write op.
1033+
*/
9921034
if (offset + len != cur_offset) {
1035+
/* If it's full, stop here */
9931036
if (op_idx + 1 == req->r_num_ops)
9941037
break;
1038+
1039+
/* Kick off an fscache write with what we have so far. */
1040+
ceph_fscache_write_to_cache(inode, offset, len, caching);
1041+
1042+
/* Start a new extent */
9951043
osd_req_op_extent_dup_last(req, op_idx,
9961044
cur_offset - offset);
9971045
dout("writepages got pages at %llu~%llu\n",
@@ -1002,14 +1050,17 @@ static int ceph_writepages_start(struct address_space *mapping,
10021050
osd_req_op_extent_update(req, op_idx, len);
10031051

10041052
len = 0;
1005-
offset = cur_offset;
1053+
offset = cur_offset;
10061054
data_pages = pages + i;
10071055
op_idx++;
10081056
}
10091057

10101058
set_page_writeback(pages[i]);
1059+
if (caching)
1060+
ceph_set_page_fscache(pages[i]);
10111061
len += thp_size(page);
10121062
}
1063+
ceph_fscache_write_to_cache(inode, offset, len, caching);
10131064

10141065
if (ceph_wbc.size_stable) {
10151066
len = min(len, ceph_wbc.i_size - offset);

0 commit comments

Comments
 (0)