From patchwork Fri Apr 9 17:22:28 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dmitry Monakhov X-Patchwork-Id: 49856 X-Patchwork-Delegate: tytso@mit.edu 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 A2F09B7080 for ; Sat, 10 Apr 2010 03:22:42 +1000 (EST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754533Ab0DIRWk (ORCPT ); Fri, 9 Apr 2010 13:22:40 -0400 Received: from mail-bw0-f217.google.com ([209.85.218.217]:33201 "EHLO mail-bw0-f217.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754516Ab0DIRWk (ORCPT ); Fri, 9 Apr 2010 13:22:40 -0400 Received: by bwz9 with SMTP id 9so2827801bwz.29 for ; Fri, 09 Apr 2010 10:22:38 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:received:received:sender:from:to:cc:subject :date:message-id:x-mailer; bh=Q/F09NDjCNefbOpah12tvMgNdq8rJw8LMckH8Iaw2Jc=; b=ACSFCQyVunOh8CJIQ9SB8X/2d0bdKMF697JUQH8QMTLKH1BafD1/Ay5ji1kPZNjI8H u6NYXGc4rDENC+hLj0bUD3z5m+WdU9gs9bXNFI/ZZgEISJwWPFqOVYc/98ThnAkOf2AO Nu6UgEjhM0+HGBoFp5uI7B1nQ7SjZKU8nA4bc= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=sender:from:to:cc:subject:date:message-id:x-mailer; b=Hw/KQ7E7djkvo6Y3/I/GtG0sA8e//9idxxM39WncNpPDYmu55qVQJuSD/wSmjWAzso XDT3T6ag5zdf3T0AxlhHsmpTLGQxU5sAs294awOO3OM18SuumxAHxSgRBr2OD22Is3Ai Me79m55eAahe755OknCr7u+u9NV9kr+r46ZrI= Received: by 10.204.33.16 with SMTP id f16mr418429bkd.11.1270833757254; Fri, 09 Apr 2010 10:22:37 -0700 (PDT) Received: from localhost.localdomain (swsoft-msk-nat.sw.ru [195.214.232.10]) by mx.google.com with ESMTPS id 16sm595801bwz.9.2010.04.09.10.22.35 (version=TLSv1/SSLv3 cipher=RC4-MD5); Fri, 09 Apr 2010 10:22:36 -0700 (PDT) From: Dmitry Monakhov To: linux-ext4@vger.kernel.org Cc: aneesh.kumar@linux.vnet.ibm.com, tytso@mit.edu, Dmitry Monakhov Subject: [PATCH] ext4: Do not zeroout uninitialized extents beyond i_size Date: Fri, 9 Apr 2010 21:22:28 +0400 Message-Id: <1270833748-14381-1-git-send-email-dmonakhov@openvz.org> X-Mailer: git-send-email 1.6.3.3 Sender: linux-ext4-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-ext4@vger.kernel.org Zerrout trick allow us to optimize cases where it is more reasonable to explicitly zeroout extent and mark it as initialized instead of splitting to several small ones. But this optimization is not acceptable is extent is beyond i_size Because it is not possible to have initialized blocks after i_size. Fsck treat this as incorrect inode size. BUG# 15742 Signed-off-by: Dmitry Monakhov --- fs/ext4/extents.c | 49 ++++++++++++++++++++++++++++++++++++++----------- 1 files changed, 38 insertions(+), 11 deletions(-) diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index 8bdee27..bdf94f3 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -2631,11 +2631,15 @@ static int ext4_ext_convert_to_initialized(handle_t *handle, struct ext4_extent *ex2 = NULL; struct ext4_extent *ex3 = NULL; struct ext4_extent_header *eh; - ext4_lblk_t ee_block; + ext4_lblk_t ee_block, eof_block; unsigned int allocated, ee_len, depth; ext4_fsblk_t newblock; int err = 0; int ret = 0; + int may_zeroout; + ext_debug("ext4_ext_convert_to_initialized: inode %lu, logical" + "block %llu, max_blocks %u ", + inode->i_ino, (unsigned long long)iblock, max_blocks); depth = ext_depth(inode); eh = path[depth].p_hdr; @@ -2644,16 +2648,25 @@ static int ext4_ext_convert_to_initialized(handle_t *handle, ee_len = ext4_ext_get_actual_len(ex); allocated = ee_len - (iblock - ee_block); newblock = iblock - ee_block + ext_pblock(ex); + eof_block = (inode->i_size + inode->i_sb->s_blocksize - 1) >> + inode->i_sb->s_blocksize_bits; ex2 = ex; orig_ex.ee_block = ex->ee_block; orig_ex.ee_len = cpu_to_le16(ee_len); ext4_ext_store_pblock(&orig_ex, ext_pblock(ex)); + /* + * It is safe to convert extent to initialized via explicit + * zeroout only if extent is fully insde i_size or new_size. + */ + may_zeroout = ee_block + ee_len <= iblock + max_blocks || + ee_block + ee_len <= eof_block; + err = ext4_ext_get_access(handle, inode, path + depth); if (err) goto out; /* If extent has less than 2*EXT4_EXT_ZERO_LEN zerout directly */ - if (ee_len <= 2*EXT4_EXT_ZERO_LEN) { + if (ee_len <= 2*EXT4_EXT_ZERO_LEN && may_zeroout) { err = ext4_ext_zeroout(inode, &orig_ex); if (err) goto fix_extent_len; @@ -2684,7 +2697,7 @@ static int ext4_ext_convert_to_initialized(handle_t *handle, if (allocated > max_blocks) { unsigned int newdepth; /* If extent has less than EXT4_EXT_ZERO_LEN zerout directly */ - if (allocated <= EXT4_EXT_ZERO_LEN) { + if (allocated <= EXT4_EXT_ZERO_LEN && may_zeroout) { /* * iblock == ee_block is handled by the zerouout * at the beginning. @@ -2760,7 +2773,7 @@ static int ext4_ext_convert_to_initialized(handle_t *handle, ex3->ee_len = cpu_to_le16(allocated - max_blocks); ext4_ext_mark_uninitialized(ex3); err = ext4_ext_insert_extent(handle, inode, path, ex3, 0); - if (err == -ENOSPC) { + if (err == -ENOSPC && may_zeroout) { err = ext4_ext_zeroout(inode, &orig_ex); if (err) goto fix_extent_len; @@ -2784,8 +2797,11 @@ static int ext4_ext_convert_to_initialized(handle_t *handle, * update the extent length after successful insert of the * split extent */ - orig_ex.ee_len = cpu_to_le16(ee_len - - ext4_ext_get_actual_len(ex3)); + ee_len -= ext4_ext_get_actual_len(ex3); + orig_ex.ee_len = cpu_to_le16(ee_len); + may_zeroout = ee_block + ee_len <= iblock + max_blocks || + ee_block + ee_len <= eof_block; + depth = newdepth; ext4_ext_drop_refs(path); path = ext4_ext_find_extent(inode, iblock, path); @@ -2809,7 +2825,7 @@ static int ext4_ext_convert_to_initialized(handle_t *handle, * otherwise give the extent a chance to merge to left */ if (le16_to_cpu(orig_ex.ee_len) <= EXT4_EXT_ZERO_LEN && - iblock != ee_block) { + iblock != ee_block && may_zeroout) { err = ext4_ext_zeroout(inode, &orig_ex); if (err) goto fix_extent_len; @@ -2878,7 +2894,7 @@ static int ext4_ext_convert_to_initialized(handle_t *handle, goto out; insert: err = ext4_ext_insert_extent(handle, inode, path, &newex, 0); - if (err == -ENOSPC) { + if (err == -ENOSPC && may_zeroout) { err = ext4_ext_zeroout(inode, &orig_ex); if (err) goto fix_extent_len; @@ -2938,14 +2954,16 @@ static int ext4_split_unwritten_extents(handle_t *handle, struct ext4_extent *ex2 = NULL; struct ext4_extent *ex3 = NULL; struct ext4_extent_header *eh; - ext4_lblk_t ee_block; + ext4_lblk_t ee_block, eof_block; unsigned int allocated, ee_len, depth; ext4_fsblk_t newblock; int err = 0; + int may_zeroout; ext_debug("ext4_split_unwritten_extents: inode %lu," "iblock %llu, max_blocks %u\n", inode->i_ino, (unsigned long long)iblock, max_blocks); + depth = ext_depth(inode); eh = path[depth].p_hdr; ex = path[depth].p_ext; @@ -2953,10 +2971,19 @@ static int ext4_split_unwritten_extents(handle_t *handle, ee_len = ext4_ext_get_actual_len(ex); allocated = ee_len - (iblock - ee_block); newblock = iblock - ee_block + ext_pblock(ex); + eof_block = (inode->i_size + inode->i_sb->s_blocksize - 1) >> + inode->i_sb->s_blocksize_bits; + ex2 = ex; orig_ex.ee_block = ex->ee_block; orig_ex.ee_len = cpu_to_le16(ee_len); ext4_ext_store_pblock(&orig_ex, ext_pblock(ex)); + /* + * It is safe to convert extent to initialized via explicit + * zeroout only if extent is fully insde i_size or new_size. + */ + may_zeroout = ee_block + ee_len <= iblock + max_blocks || + ee_block + ee_len <= eof_block; /* * If the uninitialized extent begins at the same logical @@ -2992,7 +3019,7 @@ static int ext4_split_unwritten_extents(handle_t *handle, ex3->ee_len = cpu_to_le16(allocated - max_blocks); ext4_ext_mark_uninitialized(ex3); err = ext4_ext_insert_extent(handle, inode, path, ex3, flags); - if (err == -ENOSPC) { + if (err == -ENOSPC && may_zeroout) { err = ext4_ext_zeroout(inode, &orig_ex); if (err) goto fix_extent_len; @@ -3063,7 +3090,7 @@ static int ext4_split_unwritten_extents(handle_t *handle, goto out; insert: err = ext4_ext_insert_extent(handle, inode, path, &newex, flags); - if (err == -ENOSPC) { + if (err == -ENOSPC && may_zeroout) { err = ext4_ext_zeroout(inode, &orig_ex); if (err) goto fix_extent_len;