Received: by 2002:a05:6a10:c604:0:0:0:0 with SMTP id y4csp3613013pxt; Tue, 10 Aug 2021 07:30:18 -0700 (PDT) X-Google-Smtp-Source: ABdhPJw/1shbvCXEoMkf/644ZV9/6IYurCExDDZ3ZTZowpLOgpmAhmMdL3G1vPdSEmmg4OJ0jmu6 X-Received: by 2002:a17:906:779a:: with SMTP id s26mr9916641ejm.106.1628605818227; Tue, 10 Aug 2021 07:30:18 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1628605818; cv=none; d=google.com; s=arc-20160816; b=zT+qUqiLFNrdwUJoL8qYBKepjZ3RsYAf38FlbRxe8CF4q6vCr+9UFPP0S2dytMcJvw xFApiH5MTvTn/j8J5VEPMXpv1uO/QTB7irqi9Wv41tN1ow/jOvlGkOE7H/GxgxPc/wju rEF1tw2uaIi7YP5TmNIy+gMWpK0/d9Rp0mbJLPbuDW1Mo2hlIMMDxSt529VjXZQwXaJj sY+tLl2U/9YkxjlFMVsW1IGYwRa0dTScIneUW9otgpP/U3WXDZfMxmTXuEkuXyGgUz9N tjzxbVsoUcr290chIoad4wLRKMYbFejk8BIsQ9g5TCHN/cW6PTJSvLBf3saRwE/fq+PE A/IA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from; bh=ChtQyGn7PAOogxrJrMJhNszJxomeXQ/1jPRkD/HnBnI=; b=YAyR9lTxvVQ5hRKP/d8yiWTb9eJA/fJ4oHmY8gYezYLWWFWEwErlIkfxRmSn0w2yZi bsOK/oD8o2BHoE3eusHHgThczwTR1lymIBvDOp7ee0SiNf+WL/rsHzj+xUTULBgWjbog IgOZtYLEogF+j2jiGg5VlFa+fs/Z03diQRcFYfa48YvvEm97B8d8SQIZs4o6gJpXgICX vZDKHwabSiO4Pph40/G8fgm3PcqIojA9R3S+xyLG/u4gRRELeI4WG5MEIuzGej/GDrx3 gfasy9X0oe40f7ofbeViPu3u/X5IqlZgRnmJBJJqeBJiC7nEdJx17lEstI0fxTb+Dcl3 pyqw== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: domain of linux-ext4-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-ext4-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=huawei.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id h6si6168125edv.408.2021.08.10.07.29.50; Tue, 10 Aug 2021 07:30:18 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-ext4-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; spf=pass (google.com: domain of linux-ext4-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-ext4-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=huawei.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S241210AbhHJOSw (ORCPT + 99 others); Tue, 10 Aug 2021 10:18:52 -0400 Received: from szxga03-in.huawei.com ([45.249.212.189]:13302 "EHLO szxga03-in.huawei.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S242846AbhHJORK (ORCPT ); Tue, 10 Aug 2021 10:17:10 -0400 Received: from dggeme752-chm.china.huawei.com (unknown [172.30.72.55]) by szxga03-in.huawei.com (SkyGuard) with ESMTP id 4GkZdF6jnXz7tH8; Tue, 10 Aug 2021 22:11:45 +0800 (CST) Received: from huawei.com (10.175.127.227) by dggeme752-chm.china.huawei.com (10.3.19.98) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256) id 15.1.2176.2; Tue, 10 Aug 2021 22:16:43 +0800 From: Zhang Yi To: CC: , , , , Subject: [PATCH 3/3] ext4: prevent getting empty inode buffer Date: Tue, 10 Aug 2021 22:27:22 +0800 Message-ID: <20210810142722.923175-4-yi.zhang@huawei.com> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20210810142722.923175-1-yi.zhang@huawei.com> References: <20210810142722.923175-1-yi.zhang@huawei.com> MIME-Version: 1.0 Content-Transfer-Encoding: 7BIT Content-Type: text/plain; charset=US-ASCII X-Originating-IP: [10.175.127.227] X-ClientProxiedBy: dggems704-chm.china.huawei.com (10.3.19.181) To dggeme752-chm.china.huawei.com (10.3.19.98) X-CFilter-Loop: Reflected Precedence: bulk List-ID: X-Mailing-List: linux-ext4@vger.kernel.org In ext4_get_inode_loc(), we may skip IO and get an zero && uptodate inode buffer when the inode monopolize an inode block for performance reason. For most cases, ext4_mark_iloc_dirty() will fill the inode buffer to make it fine, but we could miss this call if something bad happened. Finally, __ext4_get_inode_loc_noinmem() may probably get an empty inode buffer and trigger ext4 error. For example, if we remove a nonexistent xattr on inode A, ext4_xattr_set_handle() will return ENODATA before invoking ext4_mark_iloc_dirty(), it will left an uptodate but zero buffer. We will get checksum error message in ext4_iget() when getting inode again. EXT4-fs error (device sda): ext4_lookup:1784: inode #131074: comm cat: iget: checksum invalid Even worse, if we allocate another inode B at the same inode block, it will corrupt the inode A on disk when write back inode B. So this patch clear uptodate flag and mark buffer new if we get an empty buffer, clear it after we fill inode data or making read IO. Signed-off-by: Zhang Yi --- fs/ext4/inode.c | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index eae1b2d0b550..1f36289e9ef6 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -4292,6 +4292,18 @@ int ext4_truncate(struct inode *inode) return err; } +static void ext4_end_inode_loc_read(struct buffer_head *bh, int uptodate) +{ + if (buffer_new(bh)) + clear_buffer_new(bh); + if (uptodate) + set_buffer_uptodate(bh); + else + clear_buffer_uptodate(bh); + unlock_buffer(bh); + put_bh(bh); +} + /* * ext4_get_inode_loc returns with an extra refcount against the inode's * underlying buffer_head on success. If 'in_mem' is true, we have all @@ -4367,9 +4379,11 @@ static int __ext4_get_inode_loc(struct super_block *sb, unsigned long ino, } brelse(bitmap_bh); if (i == start + inodes_per_block) { - /* all other inodes are free, so skip I/O */ - memset(bh->b_data, 0, bh->b_size); - set_buffer_uptodate(bh); + if (!buffer_new(bh)) { + /* all other inodes are free, so skip I/O */ + memset(bh->b_data, 0, bh->b_size); + set_buffer_new(bh); + } unlock_buffer(bh); goto has_buffer; } @@ -4408,7 +4422,7 @@ static int __ext4_get_inode_loc(struct super_block *sb, unsigned long ino, * Read the block from disk. */ trace_ext4_load_inode(sb, ino); - ext4_read_bh_nowait(bh, REQ_META | REQ_PRIO, NULL); + ext4_read_bh_nowait(bh, REQ_META | REQ_PRIO, ext4_end_inode_loc_read); blk_finish_plug(&plug); wait_on_buffer(bh); ext4_simulate_fail_bh(sb, bh, EXT4_SIM_INODE_EIO); @@ -5132,6 +5146,11 @@ static int ext4_do_update_inode(handle_t *handle, if (err) goto out_brelse; ext4_clear_inode_state(inode, EXT4_STATE_NEW); + if (buffer_new(bh)) { + clear_buffer_new(bh); + set_buffer_uptodate(bh); + } + if (set_large_file) { BUFFER_TRACE(EXT4_SB(sb)->s_sbh, "get write access"); err = ext4_journal_get_write_access(handle, EXT4_SB(sb)->s_sbh); -- 2.31.1