Commit 4af6b225 authored by Yehuda Sadeh's avatar Yehuda Sadeh Committed by Sage Weil

ceph: refactor ceph_write_begin, fix ceph_page_mkwrite

Originally ceph_page_mkwrite called ceph_write_begin, hoping that
the returned locked page would be the page that it was requested
to mkwrite. Factored out relevant part of ceph_page_mkwrite and
we lock the right page anyway.
Signed-off-by: default avatarYehuda Sadeh <yehuda@hq.newdream.net>
Signed-off-by: default avatarSage Weil <sage@newdream.net>
parent 972f0d3a
...@@ -907,15 +907,13 @@ static int context_is_writeable_or_written(struct inode *inode, ...@@ -907,15 +907,13 @@ static int context_is_writeable_or_written(struct inode *inode,
* 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.
*/ */
static int ceph_write_begin(struct file *file, struct address_space *mapping, static int ceph_update_writeable_page(struct file *file,
loff_t pos, unsigned len, unsigned flags, loff_t pos, unsigned len,
struct page **pagep, void **fsdata) struct page *page)
{ {
struct inode *inode = file->f_dentry->d_inode; struct inode *inode = file->f_dentry->d_inode;
struct ceph_inode_info *ci = ceph_inode(inode); struct ceph_inode_info *ci = ceph_inode(inode);
struct ceph_mds_client *mdsc = &ceph_inode_to_client(inode)->mdsc; struct ceph_mds_client *mdsc = &ceph_inode_to_client(inode)->mdsc;
struct page *page;
pgoff_t index = pos >> PAGE_CACHE_SHIFT;
loff_t page_off = pos & PAGE_CACHE_MASK; loff_t page_off = pos & PAGE_CACHE_MASK;
int pos_in_page = pos & ~PAGE_CACHE_MASK; int pos_in_page = pos & ~PAGE_CACHE_MASK;
int end_in_page = pos_in_page + len; int end_in_page = pos_in_page + len;
...@@ -923,16 +921,6 @@ static int ceph_write_begin(struct file *file, struct address_space *mapping, ...@@ -923,16 +921,6 @@ static int ceph_write_begin(struct file *file, struct address_space *mapping,
struct ceph_snap_context *snapc; struct ceph_snap_context *snapc;
int r; int r;
/* get a page*/
retry:
page = grab_cache_page_write_begin(mapping, index, 0);
if (!page)
return -ENOMEM;
*pagep = page;
dout("write_begin file %p inode %p page %p %d~%d\n", file,
inode, page, (int)pos, (int)len);
retry_locked: retry_locked:
/* writepages currently holds page lock, but if we change that later, */ /* writepages currently holds page lock, but if we change that later, */
wait_on_page_writeback(page); wait_on_page_writeback(page);
...@@ -964,7 +952,7 @@ static int ceph_write_begin(struct file *file, struct address_space *mapping, ...@@ -964,7 +952,7 @@ static int ceph_write_begin(struct file *file, struct address_space *mapping,
wait_event_interruptible(ci->i_cap_wq, wait_event_interruptible(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);
goto retry; return -EAGAIN;
} }
/* yay, writeable, do it now (without dropping page lock) */ /* yay, writeable, do it now (without dropping page lock) */
...@@ -1021,6 +1009,35 @@ static int ceph_write_begin(struct file *file, struct address_space *mapping, ...@@ -1021,6 +1009,35 @@ static int ceph_write_begin(struct file *file, struct address_space *mapping,
return r; 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->f_dentry->d_inode;
struct page *page;
pgoff_t index = pos >> PAGE_CACHE_SHIFT;
int r;
do {
/* get a page*/
page = grab_cache_page_write_begin(mapping, index, 0);
if (!page)
return -ENOMEM;
*pagep = page;
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);
} while (r == -EAGAIN);
return r;
}
/* /*
* we don't do anything in here that simple_write_end doesn't do * we don't do anything in here that simple_write_end doesn't do
* except adjust dirty page accounting and drop read lock on * except adjust dirty page accounting and drop read lock on
...@@ -1104,8 +1121,6 @@ static int ceph_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) ...@@ -1104,8 +1121,6 @@ static int ceph_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
struct ceph_mds_client *mdsc = &ceph_inode_to_client(inode)->mdsc; struct ceph_mds_client *mdsc = &ceph_inode_to_client(inode)->mdsc;
loff_t off = page->index << PAGE_CACHE_SHIFT; loff_t off = page->index << PAGE_CACHE_SHIFT;
loff_t size, len; loff_t size, len;
struct page *locked_page = NULL;
void *fsdata = NULL;
int ret; int ret;
size = i_size_read(inode); size = i_size_read(inode);
...@@ -1116,23 +1131,30 @@ static int ceph_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) ...@@ -1116,23 +1131,30 @@ static int ceph_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
dout("page_mkwrite %p %llu~%llu page %p idx %lu\n", inode, dout("page_mkwrite %p %llu~%llu page %p idx %lu\n", inode,
off, len, page, page->index); off, len, page, page->index);
ret = ceph_write_begin(vma->vm_file, inode->i_mapping, off, len, 0,
&locked_page, &fsdata); lock_page(page);
WARN_ON(page != locked_page);
if (!ret) { ret = VM_FAULT_NOPAGE;
/* if ((off > size) ||
* doing the following, instead of calling (page->mapping != inode->i_mapping))
* ceph_write_end. Note that we keep the goto out;
* page locked
*/ ret = ceph_update_writeable_page(vma->vm_file, off, len, page);
if (ret == 0) {
/* success. we'll keep the page locked. */
set_page_dirty(page); set_page_dirty(page);
up_read(&mdsc->snap_rwsem); up_read(&mdsc->snap_rwsem);
page_cache_release(page);
ret = VM_FAULT_LOCKED; ret = VM_FAULT_LOCKED;
} else { } else {
if (ret == -ENOMEM)
ret = VM_FAULT_OOM;
else
ret = VM_FAULT_SIGBUS; ret = VM_FAULT_SIGBUS;
} }
out:
dout("page_mkwrite %p %llu~%llu = %d\n", inode, off, len, ret); dout("page_mkwrite %p %llu~%llu = %d\n", inode, off, len, ret);
if (ret != VM_FAULT_LOCKED)
unlock_page(page);
return ret; return ret;
} }
......
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