Commit 1cc16990 authored by Jeff Layton's avatar Jeff Layton Committed by Ilya Dryomov

ceph: fold ceph_update_writeable_page into ceph_write_begin

...and reorganize the loop for better clarity.
Signed-off-by: default avatarJeff Layton <jlayton@kernel.org>
Signed-off-by: default avatarIlya Dryomov <idryomov@gmail.com>
parent 6390987f
...@@ -1306,104 +1306,84 @@ ceph_find_incompatible(struct page *page) ...@@ -1306,104 +1306,84 @@ ceph_find_incompatible(struct page *page)
/* /*
* We are only allowed to write into/dirty the page if the page is * We are only allowed to write into/dirty the page if the page is
* clean, or already dirty within the same snap context. * clean, or already dirty within the same snap context.
*
* called with page locked.
* return success with page locked,
* or any failure (incl -EAGAIN) with page unlocked.
*/ */
static int ceph_update_writeable_page(struct file *file, static int ceph_write_begin(struct file *file, struct address_space *mapping,
loff_t pos, unsigned len, loff_t pos, unsigned len, unsigned flags,
struct page *page) struct page **pagep, void **fsdata)
{ {
struct inode *inode = file_inode(file); struct inode *inode = file_inode(file);
struct ceph_inode_info *ci = ceph_inode(inode); struct ceph_inode_info *ci = ceph_inode(inode);
struct ceph_snap_context *snapc; struct ceph_snap_context *snapc;
loff_t page_off = pos & PAGE_MASK; struct page *page = NULL;
pgoff_t index = pos >> PAGE_SHIFT;
int pos_in_page = pos & ~PAGE_MASK; int pos_in_page = pos & ~PAGE_MASK;
int end_in_page = pos_in_page + len; int r = 0;
loff_t i_size;
int r; dout("write_begin file %p inode %p page %p %d~%d\n", file, inode, page, (int)pos, (int)len);
for (;;) {
page = grab_cache_page_write_begin(mapping, index, 0);
if (!page) {
r = -ENOMEM;
break;
}
retry_locked:
snapc = ceph_find_incompatible(page); snapc = ceph_find_incompatible(page);
if (snapc) { if (snapc) {
if (IS_ERR(snapc)) { if (IS_ERR(snapc)) {
r = PTR_ERR(snapc); r = PTR_ERR(snapc);
goto fail_unlock; break;
} }
unlock_page(page); unlock_page(page);
put_page(page);
page = NULL;
ceph_queue_writeback(inode); ceph_queue_writeback(inode);
r = wait_event_killable(ci->i_cap_wq, r = wait_event_killable(ci->i_cap_wq,
context_is_writeable_or_written(inode, snapc)); context_is_writeable_or_written(inode, snapc));
ceph_put_snap_context(snapc); ceph_put_snap_context(snapc);
return -EAGAIN; if (r != 0)
break;
continue;
} }
if (PageUptodate(page)) { if (PageUptodate(page)) {
dout(" page %p already uptodate\n", page); dout(" page %p already uptodate\n", page);
return 0; break;
} }
/* full page? */ /*
if (pos_in_page == 0 && len == PAGE_SIZE) * In some cases we don't need to read at all:
return 0; * - full page write
* - write that lies completely beyond EOF
/* past end of file? */ * - write that covers the the page from start to EOF or beyond it
i_size = i_size_read(inode); */
if ((pos_in_page == 0 && len == PAGE_SIZE) ||
if (page_off >= i_size || (pos >= i_size_read(inode)) ||
(pos_in_page == 0 && (pos+len) >= i_size && (pos_in_page == 0 && (pos + len) >= i_size_read(inode))) {
end_in_page - pos_in_page != PAGE_SIZE)) { zero_user_segments(page, 0, pos_in_page,
dout(" zeroing %p 0 - %d and %d - %d\n", pos_in_page + len, PAGE_SIZE);
page, pos_in_page, end_in_page, (int)PAGE_SIZE); break;
zero_user_segments(page,
0, pos_in_page,
end_in_page, PAGE_SIZE);
return 0;
} }
/* we need to read it. */ /*
* We need to read it. If we get back -EINPROGRESS, then the page was
* handed off to fscache and it will be unlocked when the read completes.
* Refind the page in that case so we can reacquire the page lock. Otherwise
* we got a hard error or the read was completed synchronously.
*/
r = ceph_do_readpage(file, page); r = ceph_do_readpage(file, page);
if (r < 0) { if (r != -EINPROGRESS)
if (r == -EINPROGRESS) break;
return -EAGAIN;
goto fail_unlock;
} }
goto retry_locked;
fail_unlock:
unlock_page(page);
return r;
}
/*
* We are only allowed to write into/dirty the page if the page is
* clean, or already dirty within the same snap context.
*/
static int ceph_write_begin(struct file *file, struct address_space *mapping,
loff_t pos, unsigned len, unsigned flags,
struct page **pagep, void **fsdata)
{
struct inode *inode = file_inode(file);
struct page *page;
pgoff_t index = pos >> PAGE_SHIFT;
int r;
do {
/* get a page */
page = grab_cache_page_write_begin(mapping, index, 0);
if (!page)
return -ENOMEM;
dout("write_begin file %p inode %p page %p %d~%d\n", file,
inode, page, (int)pos, (int)len);
r = ceph_update_writeable_page(file, pos, len, page); if (r < 0) {
if (r < 0) if (page) {
unlock_page(page);
put_page(page); put_page(page);
else }
} else {
*pagep = page; *pagep = page;
} while (r == -EAGAIN); }
return r; return r;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment