ceph: optimize pagevec iterating in ceph_writepages_start()

ceph_writepages_start() supports writing non-continuous pages.
If it encounters a non-dirty or non-writeable page in pagevec,
it can continue to check the rest pages in pagevec.

Signed-off-by: "Yan, Zheng" <zyan@redhat.com>
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
This commit is contained in:
Yan, Zheng 2017-08-31 16:55:48 +08:00 committed by Ilya Dryomov
parent 05455e1177
commit 0713e5f24b

View File

@ -851,7 +851,6 @@ static int ceph_writepages_start(struct address_space *mapping,
while (!done && index <= end) {
unsigned i;
int first;
pgoff_t strip_unit_end = 0;
int num_ops = 0, op_idx;
int pvec_pages, locked_pages = 0;
@ -864,7 +863,6 @@ static int ceph_writepages_start(struct address_space *mapping,
max_pages = max_pages_ever;
get_more_pages:
first = -1;
want = min(end - index,
min((pgoff_t)PAGEVEC_SIZE,
max_pages - (pgoff_t)locked_pages) - 1)
@ -888,7 +886,7 @@ static int ceph_writepages_start(struct address_space *mapping,
unlikely(page->mapping != mapping)) {
dout("!dirty or !mapping %p\n", page);
unlock_page(page);
break;
continue;
}
if (!wbc->range_cyclic && page->index > end) {
dout("end of range %p\n", page);
@ -901,10 +899,6 @@ static int ceph_writepages_start(struct address_space *mapping,
unlock_page(page);
break;
}
if (wbc->sync_mode != WB_SYNC_NONE) {
dout("waiting on writeback %p\n", page);
wait_on_page_writeback(page);
}
if (page_offset(page) >= ceph_wbc.i_size) {
dout("%p page eof %llu\n",
page, ceph_wbc.i_size);
@ -913,9 +907,13 @@ static int ceph_writepages_start(struct address_space *mapping,
break;
}
if (PageWriteback(page)) {
dout("%p under writeback\n", page);
unlock_page(page);
break;
if (wbc->sync_mode == WB_SYNC_NONE) {
dout("%p under writeback\n", page);
unlock_page(page);
continue;
}
dout("waiting on writeback %p\n", page);
wait_on_page_writeback(page);
}
/* only if matching snap context */
@ -924,15 +922,13 @@ static int ceph_writepages_start(struct address_space *mapping,
dout("page snapc %p %lld > oldest %p %lld\n",
pgsnapc, pgsnapc->seq, snapc, snapc->seq);
unlock_page(page);
if (!locked_pages)
continue; /* keep looking for snap */
break;
continue;
}
if (!clear_page_dirty_for_io(page)) {
dout("%p !clear_page_dirty_for_io\n", page);
unlock_page(page);
break;
continue;
}
/*
@ -988,8 +984,6 @@ static int ceph_writepages_start(struct address_space *mapping,
}
/* note position of first page in pvec */
if (first < 0)
first = i;
dout("%p will write page %p idx %lu\n",
inode, page, page->index);
@ -1000,8 +994,10 @@ static int ceph_writepages_start(struct address_space *mapping,
BLK_RW_ASYNC);
}
pages[locked_pages] = page;
locked_pages++;
pages[locked_pages++] = page;
pvec.pages[i] = NULL;
len += PAGE_SIZE;
}
@ -1009,23 +1005,23 @@ static int ceph_writepages_start(struct address_space *mapping,
if (!locked_pages)
goto release_pvec_pages;
if (i) {
int j;
BUG_ON(!locked_pages || first < 0);
unsigned j, n = 0;
/* shift unused page to beginning of pvec */
for (j = 0; j < pvec_pages; j++) {
if (!pvec.pages[j])
continue;
if (n < j)
pvec.pages[n] = pvec.pages[j];
n++;
}
pvec.nr = n;
if (pvec_pages && i == pvec_pages &&
locked_pages < max_pages) {
dout("reached end pvec, trying for more\n");
pagevec_reinit(&pvec);
pagevec_release(&pvec);
goto get_more_pages;
}
/* shift unused pages over in the pvec... we
* will need to release them below. */
for (j = i; j < pvec_pages; j++) {
dout(" pvec leftover page %p\n", pvec.pages[j]);
pvec.pages[j-i+first] = pvec.pages[j];
}
pvec.nr -= i-first;
}
new_request: