X-Spam-Checker-Version: SpamAssassin 3.4.0-r929098 (2010-03-30) on oss.sgi.com X-Spam-Level: X-Spam-Status: No, score=-1.8 required=5.0 tests=BAYES_00,J_CHICKENPOX_65 autolearn=no version=3.4.0-r929098 Received: from cuda.sgi.com (cuda2.sgi.com [192.48.176.25]) by oss.sgi.com (8.14.3/8.14.3/SuSE Linux 0.8) with ESMTP id q2F9Y8vs093605 for ; Thu, 15 Mar 2012 04:34:08 -0500 X-ASG-Debug-ID: 1331804045-04cbb05c3842250001-NocioJ Received: from mx2.suse.de (cantor2.suse.de [195.135.220.15]) by cuda.sgi.com with ESMTP id Atcb4tGH4HMPsp4e (version=TLSv1 cipher=AES256-SHA bits=256 verify=NO) for ; Thu, 15 Mar 2012 02:34:06 -0700 (PDT) X-Barracuda-Envelope-From: jack@suse.cz X-Barracuda-Apparent-Source-IP: 195.135.220.15 Received: from relay1.suse.de (unknown [195.135.220.254]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by mx2.suse.de (Postfix) with ESMTP id 7BEDF906EB; Thu, 15 Mar 2012 10:34:05 +0100 (CET) Received: by quack.suse.cz (Postfix, from userid 1000) id 47A1C205D8; Thu, 15 Mar 2012 10:34:04 +0100 (CET) From: Jan Kara To: Ben Myers Cc: Dave Chinner , Alex Elder , xfs@oss.sgi.com, Christoph Hellwig , Jan Kara , stable@kernel.org Subject: [PATCH v3] xfs: Fix oops on IO error during xlog_recover_process_iunlinks() Date: Thu, 15 Mar 2012 10:34:02 +0100 X-ASG-Orig-Subj: [PATCH v3] xfs: Fix oops on IO error during xlog_recover_process_iunlinks() Message-Id: <1331804042-11580-1-git-send-email-jack@suse.cz> X-Mailer: git-send-email 1.7.1 X-Barracuda-Connect: cantor2.suse.de[195.135.220.15] X-Barracuda-Start-Time: 1331804046 X-Barracuda-Encrypted: AES256-SHA X-Barracuda-URL: http://192.48.176.25:80/cgi-mod/mark.cgi X-Virus-Scanned: by bsmtpd at sgi.com X-Barracuda-Spam-Score: 0.00 X-Barracuda-Spam-Status: No, SCORE=0.00 using per-user scores of TAG_LEVEL=1000.0 QUARANTINE_LEVEL=1000.0 KILL_LEVEL=1.3 tests= X-Barracuda-Spam-Report: Code version 3.2, rules version 3.2.2.91265 Rule breakdown below pts rule name description ---- ---------------------- -------------------------------------------------- When an IO error happens during inode deletion run from xlog_recover_process_iunlinks() filesystem gets shutdown. Thus any subsequent attempt to read buffers fails. Code in xlog_recover_process_iunlinks() does not count with the fact that read of a buffer which was read a while ago can really fail which results in the oops on agi = XFS_BUF_TO_AGI(agibp); Fix the problem by cleaning up the buffer handling in xlog_recover_process_iunlinks() as suggested by Dave Chinner. We release buffer lock but keep buffer reference to AG buffer. That is enough for buffer to stay pinned in memory and we don't have to call xfs_read_agi() all the time. CC: stable@kernel.org Signed-off-by: Jan Kara --- fs/xfs/xfs_log_recover.c | 33 +++++++++++---------------------- 1 files changed, 11 insertions(+), 22 deletions(-) diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c index 0ed9ee7..a89c2f2 100644 --- a/fs/xfs/xfs_log_recover.c +++ b/fs/xfs/xfs_log_recover.c @@ -3161,37 +3161,26 @@ xlog_recover_process_iunlinks( */ continue; } + /* + * Unlock the buffer so that it can be acquired in the normal + * course of the transaction to truncate and free each inode. + * Because we are not racing with anyone else here for the AGI + * buffer, we don't even need to hold it locked to read the + * initial unlinked bucket entries out of the buffer. We keep + * buffer reference though, so that it stays pinned in memory + * while we need the buffer. + */ agi = XFS_BUF_TO_AGI(agibp); + xfs_buf_unlock(agibp); for (bucket = 0; bucket < XFS_AGI_UNLINKED_BUCKETS; bucket++) { agino = be32_to_cpu(agi->agi_unlinked[bucket]); while (agino != NULLAGINO) { - /* - * Release the agi buffer so that it can - * be acquired in the normal course of the - * transaction to truncate and free the inode. - */ - xfs_buf_relse(agibp); - agino = xlog_recover_process_one_iunlink(mp, agno, agino, bucket); - - /* - * Reacquire the agibuffer and continue around - * the loop. This should never fail as we know - * the buffer was good earlier on. - */ - error = xfs_read_agi(mp, NULL, agno, &agibp); - ASSERT(error == 0); - agi = XFS_BUF_TO_AGI(agibp); } } - - /* - * Release the buffer for the current agi so we can - * go on to the next one. - */ - xfs_buf_relse(agibp); + xfs_buf_rele(agibp); } mp->m_dmevmask = mp_dmevmask; -- 1.7.1