From patchwork Wed Sep 23 11:51:57 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jeff Layton X-Patchwork-Id: 292010 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-14.3 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 4140BC47426 for ; Wed, 23 Sep 2020 11:52:16 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id ED17623787 for ; Wed, 23 Sep 2020 11:52:15 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=default; t=1600861936; bh=od09BW0Qa4/D/CbXljpLsHS8TBJmMyPU1emsEJeQc4M=; h=From:To:Subject:Date:In-Reply-To:References:List-ID:From; b=VMSqGSFM3pUd+yjCDDLozyt5XRKlV7gvZwqhfdc0QkLTAQtdf12gFDGOlYI7bse1v qP146H7bFGCALgUDh3G6sxXiINOj4TJUXAMx4WR6K5lkxXWF5C4pPbgBQhAn4a7eY/ MLMArZAUniNDr+ylXlHpGK8zjzOrOU/auGTxGDDg= Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726562AbgIWLwF (ORCPT ); Wed, 23 Sep 2020 07:52:05 -0400 Received: from mail.kernel.org ([198.145.29.99]:50564 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726524AbgIWLwF (ORCPT ); Wed, 23 Sep 2020 07:52:05 -0400 Received: from tleilax.com (68-20-15-154.lightspeed.rlghnc.sbcglobal.net [68.20.15.154]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPSA id 4633A21BE5 for ; Wed, 23 Sep 2020 11:52:04 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=default; t=1600861924; bh=od09BW0Qa4/D/CbXljpLsHS8TBJmMyPU1emsEJeQc4M=; h=From:To:Subject:Date:In-Reply-To:References:From; b=iMGzmC26o84/2mO0Mvokd8p/dKaAkTtfMxo+O/9KxzEJzDRN4b73ns8wABLK7frfq hWZ06hPSdIw34DyJ7FNorrzDCBYexkzyjD5sZvOCLMjCFfnwMTcf4GwQa0BtV6ds9X 4uSVIcjdCz+0iUT5P6hnzqhzDa98PWlCntEg3cVM= From: Jeff Layton To: ceph-devel@vger.kernel.org Subject: [PATCH v2 1/5] ceph: break out writeback of incompatible snap context to separate function Date: Wed, 23 Sep 2020 07:51:57 -0400 Message-Id: <20200923115201.15664-2-jlayton@kernel.org> X-Mailer: git-send-email 2.26.2 In-Reply-To: <20200923115201.15664-1-jlayton@kernel.org> References: <20200923115201.15664-1-jlayton@kernel.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: ceph-devel@vger.kernel.org When dirtying a page, we have to flush incompatible contexts. Move the search for an incompatible context into a separate function, and fix up the caller to wait and retry if there is one. Signed-off-by: Jeff Layton --- fs/ceph/addr.c | 112 +++++++++++++++++++++++++++++-------------------- 1 file changed, 67 insertions(+), 45 deletions(-) diff --git a/fs/ceph/addr.c b/fs/ceph/addr.c index 7b1f3dad576f..f8b478237ea8 100644 --- a/fs/ceph/addr.c +++ b/fs/ceph/addr.c @@ -1298,74 +1298,96 @@ static int context_is_writeable_or_written(struct inode *inode, return ret; } -/* - * We are only allowed to write into/dirty the page if the page is - * clean, or already dirty within the same snap context. +/** + * ceph_find_incompatible - find an incompatible context and return it + * @inode: inode associated with page + * @page: page being dirtied * - * called with page locked. - * return success with page locked, - * or any failure (incl -EAGAIN) with page unlocked. + * We are only allowed to write into/dirty a page if the page is + * clean, or already dirty within the same snap context. Returns a + * conflicting context if there is one, NULL if there isn't, or a + * negative error code on other errors. + * + * Must be called with page lock held. */ -static int ceph_update_writeable_page(struct file *file, - loff_t pos, unsigned len, - struct page *page) +static struct ceph_snap_context * +ceph_find_incompatible(struct inode *inode, struct page *page) { - struct inode *inode = file_inode(file); struct ceph_fs_client *fsc = ceph_inode_to_client(inode); struct ceph_inode_info *ci = ceph_inode(inode); - loff_t page_off = pos & PAGE_MASK; - int pos_in_page = pos & ~PAGE_MASK; - int end_in_page = pos_in_page + len; - loff_t i_size; - int r; - struct ceph_snap_context *snapc, *oldest; if (READ_ONCE(fsc->mount_state) == CEPH_MOUNT_SHUTDOWN) { dout(" page %p forced umount\n", page); - unlock_page(page); - return -EIO; + return ERR_PTR(-EIO); } -retry_locked: - /* writepages currently holds page lock, but if we change that later, */ - wait_on_page_writeback(page); + for (;;) { + struct ceph_snap_context *snapc, *oldest; + + wait_on_page_writeback(page); + + snapc = page_snap_context(page); + if (!snapc || snapc == ci->i_head_snapc) + break; - snapc = page_snap_context(page); - if (snapc && snapc != ci->i_head_snapc) { /* * this page is already dirty in another (older) snap * context! is it writeable now? */ oldest = get_oldest_context(inode, NULL, NULL); if (snapc->seq > oldest->seq) { + /* not writeable -- return it for the caller to deal with */ ceph_put_snap_context(oldest); - dout(" page %p snapc %p not current or oldest\n", - page, snapc); - /* - * queue for writeback, and wait for snapc to - * be writeable or written - */ - snapc = ceph_get_snap_context(snapc); - unlock_page(page); - ceph_queue_writeback(inode); - r = wait_event_killable(ci->i_cap_wq, - context_is_writeable_or_written(inode, snapc)); - ceph_put_snap_context(snapc); - if (r == -ERESTARTSYS) - return r; - return -EAGAIN; + dout(" page %p snapc %p not current or oldest\n", page, snapc); + return ceph_get_snap_context(snapc); } ceph_put_snap_context(oldest); /* yay, writeable, do it now (without dropping page lock) */ - dout(" page %p snapc %p not current, but oldest\n", - page, snapc); - if (!clear_page_dirty_for_io(page)) - goto retry_locked; - r = writepage_nounlock(page, NULL); - if (r < 0) + dout(" page %p snapc %p not current, but oldest\n", page, snapc); + if (clear_page_dirty_for_io(page)) { + int r = writepage_nounlock(page, NULL); + if (r < 0) + return ERR_PTR(r); + } + } + return NULL; +} + +/* + * 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) +{ + 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; + int pos_in_page = pos & ~PAGE_MASK; + int end_in_page = pos_in_page + len; + loff_t i_size; + int r; + +retry_locked: + snapc = ceph_find_incompatible(inode, page); + if (snapc) { + if (IS_ERR(snapc)) { + r = PTR_ERR(snapc); goto fail_unlock; - goto retry_locked; + } + unlock_page(page); + 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 (PageUptodate(page)) { From patchwork Wed Sep 23 11:51:58 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jeff Layton X-Patchwork-Id: 292012 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-14.3 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 0E788C4727F for ; Wed, 23 Sep 2020 11:52:07 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id AA1D621D41 for ; Wed, 23 Sep 2020 11:52:06 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=default; t=1600861926; bh=0XeFjNyigicxYMQLi5vGUXio4MphwvE9Zl8lqI9qdV0=; h=From:To:Subject:Date:In-Reply-To:References:List-ID:From; b=VyOu+TOzhOPVA4YKKa8MiE0aaVeSmoaYDlMtGJz4Q2BzsuVZsPNxHhdpJWGrV0Exw pI08Huyn9BJTqtxgkRcXu8a+hgDWswbrTuLV6tctT6xUCkBbeMr4InUGqC6zyedi66 QgNNFlRllJEHMdiE/IikdpI+phL4CCNRn1Eo1DaE= Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726581AbgIWLwG (ORCPT ); Wed, 23 Sep 2020 07:52:06 -0400 Received: from mail.kernel.org ([198.145.29.99]:50570 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726550AbgIWLwF (ORCPT ); Wed, 23 Sep 2020 07:52:05 -0400 Received: from tleilax.com (68-20-15-154.lightspeed.rlghnc.sbcglobal.net [68.20.15.154]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPSA id B11212193E for ; Wed, 23 Sep 2020 11:52:04 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=default; t=1600861924; bh=0XeFjNyigicxYMQLi5vGUXio4MphwvE9Zl8lqI9qdV0=; h=From:To:Subject:Date:In-Reply-To:References:From; b=VAAGMxMiXMXLfZAUXKfjHV/lhUTKWdpKFl7qr2XBhvcJEq3c7GLli6fzhTJHBvZSD doT7sehAKm/xOmHuxsBgGVmn2j+wt6e/2PFv4CJmLJs3+zs9lQydEyI7JN6b3OYB1D /Fac3cReNqJB+s1N585yncZHEh+vlvufSGIMTx14= From: Jeff Layton To: ceph-devel@vger.kernel.org Subject: [PATCH v2 2/5] ceph: don't call ceph_update_writeable_page from page_mkwrite Date: Wed, 23 Sep 2020 07:51:58 -0400 Message-Id: <20200923115201.15664-3-jlayton@kernel.org> X-Mailer: git-send-email 2.26.2 In-Reply-To: <20200923115201.15664-1-jlayton@kernel.org> References: <20200923115201.15664-1-jlayton@kernel.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: ceph-devel@vger.kernel.org page_mkwrite should only be called with Uptodate pages, so we should only need to flush incompatible snap contexts. Signed-off-by: Jeff Layton --- fs/ceph/addr.c | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/fs/ceph/addr.c b/fs/ceph/addr.c index f8b478237ea8..c2c23b468d13 100644 --- a/fs/ceph/addr.c +++ b/fs/ceph/addr.c @@ -1300,7 +1300,6 @@ static int context_is_writeable_or_written(struct inode *inode, /** * ceph_find_incompatible - find an incompatible context and return it - * @inode: inode associated with page * @page: page being dirtied * * We are only allowed to write into/dirty a page if the page is @@ -1311,8 +1310,9 @@ static int context_is_writeable_or_written(struct inode *inode, * Must be called with page lock held. */ static struct ceph_snap_context * -ceph_find_incompatible(struct inode *inode, struct page *page) +ceph_find_incompatible(struct page *page) { + struct inode *inode = page->mapping->host; struct ceph_fs_client *fsc = ceph_inode_to_client(inode); struct ceph_inode_info *ci = ceph_inode(inode); @@ -1376,7 +1376,7 @@ static int ceph_update_writeable_page(struct file *file, int r; retry_locked: - snapc = ceph_find_incompatible(inode, page); + snapc = ceph_find_incompatible(page); if (snapc) { if (IS_ERR(snapc)) { r = PTR_ERR(snapc); @@ -1689,6 +1689,8 @@ static vm_fault_t ceph_page_mkwrite(struct vm_fault *vmf) inode_inc_iversion_raw(inode); do { + struct ceph_snap_context *snapc; + lock_page(page); if (page_mkwrite_check_truncate(page, inode) < 0) { @@ -1697,13 +1699,26 @@ static vm_fault_t ceph_page_mkwrite(struct vm_fault *vmf) break; } - err = ceph_update_writeable_page(vma->vm_file, off, len, page); - if (err >= 0) { + snapc = ceph_find_incompatible(page); + if (!snapc) { /* success. we'll keep the page locked. */ set_page_dirty(page); ret = VM_FAULT_LOCKED; + break; + } + + unlock_page(page); + + if (IS_ERR(snapc)) { + ret = VM_FAULT_SIGBUS; + break; } - } while (err == -EAGAIN); + + ceph_queue_writeback(inode); + err = wait_event_killable(ci->i_cap_wq, + context_is_writeable_or_written(inode, snapc)); + ceph_put_snap_context(snapc); + } while (err == 0); if (ret == VM_FAULT_LOCKED || ci->i_inline_version != CEPH_INLINE_NONE) { From patchwork Wed Sep 23 11:52:01 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jeff Layton X-Patchwork-Id: 292011 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-14.3 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 0AC45C2D0A8 for ; Wed, 23 Sep 2020 11:52:09 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id BC696235FD for ; Wed, 23 Sep 2020 11:52:08 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=default; t=1600861928; bh=PeyMDaPbw18gie5xl55cw70Y2YM1lB23U7NekW3yEWc=; h=From:To:Subject:Date:In-Reply-To:References:List-ID:From; b=ERrOBJekzU53XeylgXGE+5ND7bTitdPNFSNMg/r4zVdaN0vxGsA3FldEj/iU5v3Kn e/gHILJ+rVYCwoV/vpTMr3B43Xgvu1MvZcwBPz8+rcf8Ea4iIof0vZCxeEzPvWDHHe W4WCYZScNtoCeBW0r6k+PDN07FghFa6JKDrflcAM= Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726630AbgIWLwI (ORCPT ); Wed, 23 Sep 2020 07:52:08 -0400 Received: from mail.kernel.org ([198.145.29.99]:50572 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726593AbgIWLwG (ORCPT ); Wed, 23 Sep 2020 07:52:06 -0400 Received: from tleilax.com (68-20-15-154.lightspeed.rlghnc.sbcglobal.net [68.20.15.154]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPSA id 11C0A2193E for ; Wed, 23 Sep 2020 11:52:05 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=default; t=1600861926; bh=PeyMDaPbw18gie5xl55cw70Y2YM1lB23U7NekW3yEWc=; h=From:To:Subject:Date:In-Reply-To:References:From; b=FFrRS/Py1umQNP9PVHZsOVsREpKFhgufG6UeYez/HK8/jQCU1PZcKbEJuy9DsjpBR MpZd8Vj7twP1sP2ramUpYsXMKuD8Et8MuLlRqUExq9GckdTdSzLWFOmvE1ah4yqO23 NKjywwO9TVYgGv/4Y1WEKcDN9m0Rj0jDwgThzlEk= From: Jeff Layton To: ceph-devel@vger.kernel.org Subject: [PATCH v2 5/5] ceph: fold ceph_update_writeable_page into ceph_write_begin Date: Wed, 23 Sep 2020 07:52:01 -0400 Message-Id: <20200923115201.15664-6-jlayton@kernel.org> X-Mailer: git-send-email 2.26.2 In-Reply-To: <20200923115201.15664-1-jlayton@kernel.org> References: <20200923115201.15664-1-jlayton@kernel.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: ceph-devel@vger.kernel.org ...and reorganize the loop for better clarity. Signed-off-by: Jeff Layton --- fs/ceph/addr.c | 146 +++++++++++++++++++++---------------------------- 1 file changed, 63 insertions(+), 83 deletions(-) diff --git a/fs/ceph/addr.c b/fs/ceph/addr.c index 72cbaac68256..97827f68a3e7 100644 --- a/fs/ceph/addr.c +++ b/fs/ceph/addr.c @@ -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; -retry_locked: - snapc = ceph_find_incompatible(page); - if (snapc) { - if (IS_ERR(snapc)) { - r = PTR_ERR(snapc); - goto fail_unlock; + 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; } - unlock_page(page); - 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 (PageUptodate(page)) { - dout(" page %p already uptodate\n", page); - return 0; - } + snapc = ceph_find_incompatible(page); + if (snapc) { + if (IS_ERR(snapc)) { + r = PTR_ERR(snapc); + 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); + if (r != 0) + break; + continue; + } - /* full page? */ - if (pos_in_page == 0 && len == PAGE_SIZE) - return 0; + if (PageUptodate(page)) { + dout(" page %p already uptodate\n", page); + break; + } - /* 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; - } + /* + * 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 need to read it. */ - r = ceph_do_readpage(file, page); - if (r < 0) { - if (r == -EINPROGRESS) - return -EAGAIN; - goto fail_unlock; + /* + * 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); + if (r != -EINPROGRESS) + break; } - 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); - else - *pagep = page; - } while (r == -EAGAIN); - + } + } else { + *pagep = page; + } return r; }