From patchwork Thu Feb 28 18:26:43 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Zheng Liu X-Patchwork-Id: 224129 Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id CBFFD2C02A0 for ; Fri, 1 Mar 2013 05:12:04 +1100 (EST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1759989Ab3B1SME (ORCPT ); Thu, 28 Feb 2013 13:12:04 -0500 Received: from mail-da0-f53.google.com ([209.85.210.53]:54681 "EHLO mail-da0-f53.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1755251Ab3B1SMC (ORCPT ); Thu, 28 Feb 2013 13:12:02 -0500 Received: by mail-da0-f53.google.com with SMTP id n34so963604dal.40 for ; Thu, 28 Feb 2013 10:12:01 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=x-received:from:to:cc:subject:date:message-id:x-mailer:in-reply-to :references; bh=LMTFuUSZRPz1U7Yb9dXJYwD+kuqPnYaQVpwQGF0lzXQ=; b=tJeJTJfFXJ639iSZtEU0hvQ0PS2464aM1YSPquNZQwG32wxQWpyK7plpYJ1iIt3R8O 8oMoLFH0RsXvLosR9hG7u6n68JkswR9p1Kwt4bUJS/bX8Yh6wA47ChptLI8hxo681EcS itDF+zJCUNhFmSDoiZrZbtvZsaL5t4X+o2CJfbbaCT7rTLI96aORiLKL8w6Aa0uRnUib XlbkO4bhatdPZlbI+b5kJeaNyNfuaSXcY1u1pBu0YT05ju+uiY4l34Jv9BGdza908gZI arENQKSAzgU1sYz9f8mUyhK30pIWKdrlTHWr0EV1mvsxuCr78BpI3nhGUuFMuSBxhOjL iBwA== X-Received: by 10.68.31.130 with SMTP id a2mr10112930pbi.213.1362075121440; Thu, 28 Feb 2013 10:12:01 -0800 (PST) Received: from lz-desktop.taobao.ali.com ([182.92.247.2]) by mx.google.com with ESMTPS id jp9sm9100343pbb.7.2013.02.28.10.11.58 (version=TLSv1 cipher=RC4-SHA bits=128/128); Thu, 28 Feb 2013 10:12:00 -0800 (PST) From: Zheng Liu To: linux-ext4@vger.kernel.org Cc: Dmitry Monakhov , "Theodore Ts'o" , Zheng Liu Subject: [PATCH 5/6] ext4: ext4_split_extent shoult take care about extent zeroout v3 Date: Fri, 1 Mar 2013 02:26:43 +0800 Message-Id: <1362076004-10087-6-git-send-email-wenqing.lz@taobao.com> X-Mailer: git-send-email 1.7.12.rc2.18.g61b472e In-Reply-To: <1362076004-10087-1-git-send-email-wenqing.lz@taobao.com> References: <1362076004-10087-1-git-send-email-wenqing.lz@taobao.com> Sender: linux-ext4-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-ext4@vger.kernel.org From: Dmitry Monakhov When ext4_split_extent_at() ends up doing zeroout & conversion to initialized instead of split & conversion, ext4_split_extent() gets confused and can wrongly mark the extent back as uninitialized resulting in end IO code getting confused from large unwritten extents and may result in data loss. The example of problematic behavior is: lblk len lblk len ext4_split_extent() (ex=[1000,30,uninit], map=[1010,10]) ext4_split_extent_at() (split [1000,30,uninit] at 1020) ext4_ext_insert_extent() -> ENOSPC ext4_ext_zeroout() -> extent [1000,30] is now initialized ext4_split_extent_at() (split [1000,30,init] at 1010, MARK_UNINIT1 | MARK_UNINIT2) -> extent is split and parts marked as uninitialized Fix the problem by rechecking extent type after the first ext4_split_extent_at() returns. None of split_flags can not be applied to initialized extent so this patch also add BUG_ON to prevent similar issues in future. TESTCASE: https://github.com/dmonakhov/xfstests/commit/b8a55eb5ce28c6ff29e620ab090902fcd5833597 Changes since V2: Patch no longer depends on Jan's "disable-uninit-ext-mergring" patch. Signed-off-by: Dmitry Monakhov Reviewed-by: Jan Kara Reviewed-by: Zheng Liu Cc: "Theodore Ts'o" Cc: Zheng Liu --- fs/ext4/extents.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index 0793a13..835d82b 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -2943,6 +2943,10 @@ static int ext4_split_extent_at(handle_t *handle, newblock = split - ee_block + ext4_ext_pblock(ex); BUG_ON(split < ee_block || split >= (ee_block + ee_len)); + BUG_ON(!ext4_ext_is_uninitialized(ex) && + split_flag & (EXT4_EXT_MAY_ZEROOUT | + EXT4_EXT_MARK_UNINIT1 | + EXT4_EXT_MARK_UNINIT2)); err = ext4_ext_get_access(handle, inode, path + depth); if (err) @@ -3061,19 +3065,25 @@ static int ext4_split_extent(handle_t *handle, if (err) goto out; } - + /* + * Update path is required because previous ext4_split_extent_at() may + * result in split of original leaf or extent zeroout. + */ ext4_ext_drop_refs(path); path = ext4_ext_find_extent(inode, map->m_lblk, path); if (IS_ERR(path)) return PTR_ERR(path); + depth = ext_depth(inode); + ex = path[depth].p_ext; + uninitialized = ext4_ext_is_uninitialized(ex); + split_flag1 = 0; if (map->m_lblk >= ee_block) { - split_flag1 = split_flag & (EXT4_EXT_MAY_ZEROOUT | - EXT4_EXT_DATA_VALID2); - if (uninitialized) + split_flag1 = split_flag & EXT4_EXT_DATA_VALID2; + if (uninitialized) { split_flag1 |= EXT4_EXT_MARK_UNINIT1; - if (split_flag & EXT4_EXT_MARK_UNINIT2) - split_flag1 |= EXT4_EXT_MARK_UNINIT2; + split_flag1 |= split_flag & (EXT4_EXT_MAY_ZEROOUT | EXT4_EXT_MARK_UNINIT2); + } err = ext4_split_extent_at(handle, inode, path, map->m_lblk, split_flag1, flags); if (err)