From patchwork Wed Dec 7 17:25:24 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andy Whitcroft X-Patchwork-Id: 129997 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from chlorine.canonical.com (chlorine.canonical.com [91.189.94.204]) by ozlabs.org (Postfix) with ESMTP id A6CAE1007D5 for ; Thu, 8 Dec 2011 04:25:37 +1100 (EST) Received: from localhost ([127.0.0.1] helo=chlorine.canonical.com) by chlorine.canonical.com with esmtp (Exim 4.71) (envelope-from ) id 1RYLFH-0000kc-V3; Wed, 07 Dec 2011 17:25:28 +0000 Received: from youngberry.canonical.com ([91.189.89.112]) by chlorine.canonical.com with esmtp (Exim 4.71) (envelope-from ) id 1RYLFF-0000k1-Tn for kernel-team@lists.ubuntu.com; Wed, 07 Dec 2011 17:25:25 +0000 Received: from [91.189.88.12] (helo=localhost.localdomain) by youngberry.canonical.com with esmtpsa (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1RYLFF-0003WR-RC; Wed, 07 Dec 2011 17:25:25 +0000 From: Andy Whitcroft To: kernel-team@lists.ubuntu.com Subject: [PATCH 1/1] UBUNTU: SAUCE: ext4: correct partial write discard size calculation Date: Wed, 7 Dec 2011 17:25:24 +0000 Message-Id: <1323278724-13255-2-git-send-email-apw@canonical.com> X-Mailer: git-send-email 1.7.5.4 In-Reply-To: <1323278724-13255-1-git-send-email-apw@canonical.com> References: <1323278724-13255-1-git-send-email-apw@canonical.com> Cc: Andy Whitcroft X-BeenThere: kernel-team@lists.ubuntu.com X-Mailman-Version: 2.1.13 Precedence: list List-Id: Kernel team discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: kernel-team-bounces@lists.ubuntu.com Errors-To: kernel-team-bounces@lists.ubuntu.com When copying large numbers of files we are seeing occasional write failures with errno EINVAL. These are being returned from ext4_da_write_end() when attempting to discard the end portion of a partial write. The error is detected and reported by the page index check below: int ext4_discard_partial_page_buffers_no_lock(handle_t *handle, struct inode *inode, struct page *page, loff_t from, loff_t length, int flags) { [...] if (index != page->index) return -EINVAL; [...] This code was introduced by the commit below: commit 02fac1297eb3f471a27368271aadd285548297b0 Author: Allison Henderson Date: Tue Sep 6 21:53:01 2011 -0400 ext4: fix partial page writes This error is triggering when a write occurs at pos == 0 and results in 0 bytes being written (copied == 0): page_len = PAGE_CACHE_SIZE - ((pos + copied - 1) & (PAGE_CACHE_SIZE - 1)); if (page_len > 0) { ret = ext4_discard_partial_page_buffers_no_lock(handle, inode, page, pos + copied - 1, page_len, [...] In this case we will calculate that we need to clear out only one byte of the page. As we are aligned at the page boundary and wrote 0 bytes we actually need to clear the entire page. Also note that when we attempt to apply the discard we will apply it at offset -1 (0 + 0 - 1), which is the wrong place: page_len = 4096 - ((0 + 0 - 1) & 4095) page_len = 1 Firstly fix up the offset calculation. Once this is done the erroring case will correctly believe that the entire page needs to be discarded. However in this case we did not actually write to the page so the page is not instantiated and no discard is required. So also only apply the discard where we are not discarding the entire page. BugLink: http://bugs.launchpad.net/bugs/894768 Signed-off-by: Andy Whitcroft --- fs/ext4/inode.c | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 848f436..6314283 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -2534,11 +2534,11 @@ static int ext4_da_write_end(struct file *file, page, fsdata); page_len = PAGE_CACHE_SIZE - - ((pos + copied - 1) & (PAGE_CACHE_SIZE - 1)); + ((pos + copied) & (PAGE_CACHE_SIZE - 1)); - if (page_len > 0) { + if (page_len > 0 && page_len < PAGE_CACHE_SIZE) { ret = ext4_discard_partial_page_buffers_no_lock(handle, - inode, page, pos + copied - 1, page_len, + inode, page, pos + copied, page_len, EXT4_DISCARD_PARTIAL_PG_ZERO_UNMAPPED); }