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

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
Loading
Loading
Loading
Loading
+63 −83
Original line number Diff line number Diff line
@@ -1306,104 +1306,84 @@ ceph_find_incompatible(struct page *page)
/*
 * We are only allowed to write into/dirty the page if the page is
 * 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,
			    loff_t pos, unsigned len,
			    struct page *page)
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 ceph_inode_info *ci = ceph_inode(inode);
	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 end_in_page = pos_in_page + len;
	loff_t i_size;
	int r;
	int r = 0;

	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);
		if (snapc) {
			if (IS_ERR(snapc)) {
				r = PTR_ERR(snapc);
			goto fail_unlock;
				break;
			}
			unlock_page(page);
			put_page(page);
			page = NULL;
			ceph_queue_writeback(inode);
			r = wait_event_killable(ci->i_cap_wq,
						context_is_writeable_or_written(inode, snapc));
			ceph_put_snap_context(snapc);
		return -EAGAIN;
			if (r != 0)
				break;
			continue;
		}

		if (PageUptodate(page)) {
			dout(" page %p already uptodate\n", page);
		return 0;
	}

	/* full page? */
	if (pos_in_page == 0 && len == PAGE_SIZE)
		return 0;

	/* past end of file? */
	i_size = i_size_read(inode);

	if (page_off >= i_size ||
	    (pos_in_page == 0 && (pos+len) >= i_size &&
	     end_in_page - pos_in_page != PAGE_SIZE)) {
		dout(" zeroing %p 0 - %d and %d - %d\n",
		     page, pos_in_page, end_in_page, (int)PAGE_SIZE);
		zero_user_segments(page,
				   0, pos_in_page,
				   end_in_page, PAGE_SIZE);
		return 0;
			break;
		}

	/* we need to read it. */
	r = ceph_do_readpage(file, page);
	if (r < 0) {
		if (r == -EINPROGRESS)
			return -EAGAIN;
		goto fail_unlock;
	}
	goto retry_locked;
fail_unlock:
	unlock_page(page);
	return r;
		/*
		 * In some cases we don't need to read at all:
		 * - full page write
		 * - write that lies completely beyond EOF
		 * - write that covers the the page from start to EOF or beyond it
		 */
		if ((pos_in_page == 0 && len == PAGE_SIZE) ||
		    (pos >= i_size_read(inode)) ||
		    (pos_in_page == 0 && (pos + len) >= i_size_read(inode))) {
			zero_user_segments(page, 0, pos_in_page,
					   pos_in_page + len, PAGE_SIZE);
			break;
		}

		/*
 * We are only allowed to write into/dirty the page if the page is
 * clean, or already dirty within the same snap context.
		 * 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.
		 */
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_do_readpage(file, page);
		if (r != -EINPROGRESS)
			break;
	}

		r = ceph_update_writeable_page(file, pos, len, page);
		if (r < 0)
	if (r < 0) {
		if (page) {
			unlock_page(page);
			put_page(page);
		else
		}
	} else {
		*pagep = page;
	} while (r == -EAGAIN);

	}
	return r;
}