summaryrefslogtreecommitdiff
path: root/fs/ceph
diff options
context:
space:
mode:
authorYan, Zheng <zyan@redhat.com>2017-09-01 17:03:16 +0800
committerIlya Dryomov <idryomov@gmail.com>2017-09-06 19:57:00 +0200
commitf275635ee0b6641151dfaf07b901d7c8d4d8e987 (patch)
treeefd8a52829dc0727823a765d78c9ae86fa5a73bd /fs/ceph
parent7e1ee54a07b6f00f4b6dd9cd24505d3b76774ddc (diff)
ceph: wait on writeback after writing snapshot data
In sync mode, writepages() needs to write all dirty pages. But it can only write dirty pages associated with the oldest snapc. To write dirty pages associated with next snapc, it needs to wait until current writes complete. Without this wait, writepages() keeps looking up dirty pages, but the found dirty pages are not writeable. It wastes CPU time. Signed-off-by: "Yan, Zheng" <zyan@redhat.com> Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
Diffstat (limited to 'fs/ceph')
-rw-r--r--fs/ceph/addr.c24
1 files changed, 24 insertions, 0 deletions
diff --git a/fs/ceph/addr.c b/fs/ceph/addr.c
index 1ffdb903eb79..b3e3edc09d80 100644
--- a/fs/ceph/addr.c
+++ b/fs/ceph/addr.c
@@ -1165,6 +1165,30 @@ release_pvec_pages:
/* more to do; loop back to beginning of file */
dout("writepages looping back to beginning of file\n");
end = start_index - 1; /* OK even when start_index == 0 */
+
+ /* to write dirty pages associated with next snapc,
+ * we need to wait until current writes complete */
+ if (wbc->sync_mode != WB_SYNC_NONE &&
+ start_index == 0 && /* all dirty pages were checked */
+ !ceph_wbc.head_snapc) {
+ struct page *page;
+ unsigned i, nr;
+ index = 0;
+ while ((index <= end) &&
+ (nr = pagevec_lookup_tag(&pvec, mapping, &index,
+ PAGECACHE_TAG_WRITEBACK,
+ PAGEVEC_SIZE))) {
+ for (i = 0; i < nr; i++) {
+ page = pvec.pages[i];
+ if (page_snap_context(page) != snapc)
+ continue;
+ wait_on_page_writeback(page);
+ }
+ pagevec_release(&pvec);
+ cond_resched();
+ }
+ }
+
start_index = 0;
index = 0;
goto retry;