aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs/xfs_log_recover.c
diff options
context:
space:
mode:
authorJan Kara <jack@suse.cz>2012-03-15 05:34:02 -0400
committerLuis Henriques <luis.henriques@canonical.com>2012-04-05 11:17:31 -0400
commite57ce09d66a6f1fe76cb89335cb2a65c11b097d5 (patch)
tree097d3bd7831c023dd9dfd7fb572d230b21996142 /fs/xfs/xfs_log_recover.c
parent591e1ff82e342ae4f489611f10b736a2d21cd2a6 (diff)
xfs: Fix oops on IO error during xlog_recover_process_iunlinks()
BugLink: http://bugs.launchpad.net/bugs/971808 commit d97d32edcd732110758799ae60af725e5110b3dc upstream. 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. Signed-off-by: Jan Kara <jack@suse.cz> Reviewed-by: Dave Chinner <dchinner@redhat.com> Signed-off-by: Ben Myers <bpm@sgi.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'fs/xfs/xfs_log_recover.c')
-rw-r--r--fs/xfs/xfs_log_recover.c33
1 files changed, 11 insertions, 22 deletions
diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c
index 04142caedb2..b75fd67ca37 100644
--- a/fs/xfs/xfs_log_recover.c
+++ b/fs/xfs/xfs_log_recover.c
@@ -3159,37 +3159,26 @@ xlog_recover_process_iunlinks(
3159 */ 3159 */
3160 continue; 3160 continue;
3161 } 3161 }
3162 /*
3163 * Unlock the buffer so that it can be acquired in the normal
3164 * course of the transaction to truncate and free each inode.
3165 * Because we are not racing with anyone else here for the AGI
3166 * buffer, we don't even need to hold it locked to read the
3167 * initial unlinked bucket entries out of the buffer. We keep
3168 * buffer reference though, so that it stays pinned in memory
3169 * while we need the buffer.
3170 */
3162 agi = XFS_BUF_TO_AGI(agibp); 3171 agi = XFS_BUF_TO_AGI(agibp);
3172 xfs_buf_unlock(agibp);
3163 3173
3164 for (bucket = 0; bucket < XFS_AGI_UNLINKED_BUCKETS; bucket++) { 3174 for (bucket = 0; bucket < XFS_AGI_UNLINKED_BUCKETS; bucket++) {
3165 agino = be32_to_cpu(agi->agi_unlinked[bucket]); 3175 agino = be32_to_cpu(agi->agi_unlinked[bucket]);
3166 while (agino != NULLAGINO) { 3176 while (agino != NULLAGINO) {
3167 /*
3168 * Release the agi buffer so that it can
3169 * be acquired in the normal course of the
3170 * transaction to truncate and free the inode.
3171 */
3172 xfs_buf_relse(agibp);
3173
3174 agino = xlog_recover_process_one_iunlink(mp, 3177 agino = xlog_recover_process_one_iunlink(mp,
3175 agno, agino, bucket); 3178 agno, agino, bucket);
3176
3177 /*
3178 * Reacquire the agibuffer and continue around
3179 * the loop. This should never fail as we know
3180 * the buffer was good earlier on.
3181 */
3182 error = xfs_read_agi(mp, NULL, agno, &agibp);
3183 ASSERT(error == 0);
3184 agi = XFS_BUF_TO_AGI(agibp);
3185 } 3179 }
3186 } 3180 }
3187 3181 xfs_buf_rele(agibp);
3188 /*
3189 * Release the buffer for the current agi so we can
3190 * go on to the next one.
3191 */
3192 xfs_buf_relse(agibp);
3193 } 3182 }
3194 3183
3195 mp->m_dmevmask = mp_dmevmask; 3184 mp->m_dmevmask = mp_dmevmask;