From patchwork Mon Dec 14 17:59:15 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vegard Nossum X-Patchwork-Id: 556575 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 2B54D1401B5 for ; Tue, 15 Dec 2015 05:00:56 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753399AbbLNR71 (ORCPT ); Mon, 14 Dec 2015 12:59:27 -0500 Received: from aserp1040.oracle.com ([141.146.126.69]:49745 "EHLO aserp1040.oracle.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752898AbbLNR7Z (ORCPT ); Mon, 14 Dec 2015 12:59:25 -0500 Received: from aserv0022.oracle.com (aserv0022.oracle.com [141.146.126.234]) by aserp1040.oracle.com (Sentrion-MTA-4.3.2/Sentrion-MTA-4.3.2) with ESMTP id tBEHxJII028244 (version=TLSv1 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Mon, 14 Dec 2015 17:59:19 GMT Received: from lenuta.oracle.com (dhcp-ukc1-twvpn-2-vpnpool-10-175-223-183.vpn.oracle.com [10.175.223.183]) by aserv0022.oracle.com (8.13.8/8.13.8) with ESMTP id tBEHxHXN011793; Mon, 14 Dec 2015 17:59:18 GMT From: Vegard Nossum To: tytso@mit.edu, adilger.kernel@dilger.ca Cc: linux-ext4@vger.kernel.org, linux-kernel@vger.kernel.org, Vegard Nossum Subject: [PATCH] ext4: handle errors during orphan cleanup Date: Mon, 14 Dec 2015 18:59:15 +0100 Message-Id: <1450115955-11537-1-git-send-email-vegard.nossum@oracle.com> X-Mailer: git-send-email 1.9.1 X-Source-IP: aserv0022.oracle.com [141.146.126.234] Sender: linux-ext4-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-ext4@vger.kernel.org If a filesystem is mounted with errors=remount-ro, then orphan cleanup can enter an infinite loop since the iput() inside the linked list traversal doesn't actually always cause es->s_last_orphan to advance to the next orphan inode (i.e. in case of errors). The bug manifests in two different ways. It's an endless spew of either: EXT4-fs (loop0): Inode 5 (ffff8800153ed720): orphan list check failed! [...] CPU: 1 PID: 957 Comm: mount Not tainted 4.4.0-rc3+ #244 ffffffff820ac0c0 ffff88001562f868 ffffffff81610cc9 ffff8800153ed7e0 ffff88001562f8a0 ffffffff8133097a 00000000000003e8 ffffffff00000001 ffff8800153ed7e0 ffffffff820ac0c0 ffff8800153ed880 ffff88001562f8c0 Call Trace: [] dump_stack+0x44/0x5b [] ext4_destroy_inode+0xba/0xc0 [] destroy_inode+0x5f/0x80 [] evict+0x1e5/0x270 [] iput+0x297/0x350 [] ext4_fill_super+0x4fa5/0x53b0 [...] or: WARNING: CPU: 0 PID: 924 at lib/list_debug.c:36 __list_add+0xf9/0x100() list_add double add: new=00000000dfba0070, prev=00000000dffba970, next=00000000dfba0070. CPU: 0 PID: 924 Comm: mount.exe Tainted: G W 4.4.0-rc3 #1 Stack: df7f59b0 60075642 6071c3ae 00000009 df7f5a30 600bc4fe df7f59c0 603f1e5f df7f5a20 600412cd df7f59e0 6040d859 Call Trace: [<60029f9b>] show_stack+0xdb/0x1a0 [<603f1e5f>] dump_stack+0x2a/0x3b [<600412cd>] warn_slowpath_common+0x9d/0xf0 [<600413f4>] warn_slowpath_fmt+0x94/0xa0 [<6040d859>] __list_add+0xf9/0x100 [<601b28d4>] ext4_fill_super+0x3e04/0x4040 [...] This was the smallest change I could find that still covers all the cases I ran into. It probably also makes sense intuitively to not continue orphan cleanup if there was an error in the meantime. Thanks to Jamie and Quentin for helping with the debugging. Signed-off-by: Vegard Nossum Cc: Jamie Iles Cc: Quentin Casasnovas Cc: stable@vger.kernel.org --- fs/ext4/super.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git fs/ext4/super.c fs/ext4/super.c index c9ab67d..8952fcc 100644 --- fs/ext4/super.c +++ fs/ext4/super.c @@ -2206,17 +2206,6 @@ static void ext4_orphan_cleanup(struct super_block *sb, return; } - if (EXT4_SB(sb)->s_mount_state & EXT4_ERROR_FS) { - /* don't clear list on RO mount w/ errors */ - if (es->s_last_orphan && !(s_flags & MS_RDONLY)) { - ext4_msg(sb, KERN_INFO, "Errors on filesystem, " - "clearing orphan list.\n"); - es->s_last_orphan = 0; - } - jbd_debug(1, "Skipping orphan recovery on fs with errors.\n"); - return; - } - if (s_flags & MS_RDONLY) { ext4_msg(sb, KERN_INFO, "orphan cleanup on readonly fs"); sb->s_flags &= ~MS_RDONLY; @@ -2239,6 +2228,17 @@ static void ext4_orphan_cleanup(struct super_block *sb, while (es->s_last_orphan) { struct inode *inode; + if (EXT4_SB(sb)->s_mount_state & EXT4_ERROR_FS) { + /* don't clear list on RO mount w/ errors */ + if (es->s_last_orphan && !(s_flags & MS_RDONLY)) { + ext4_msg(sb, KERN_INFO, "Errors on filesystem, " + "clearing orphan list.\n"); + es->s_last_orphan = 0; + } + jbd_debug(1, "Skipping rest of orphan recovery on fs with errors.\n"); + break; + } + inode = ext4_orphan_get(sb, le32_to_cpu(es->s_last_orphan)); if (IS_ERR(inode)) { es->s_last_orphan = 0;