diff options
Diffstat (limited to 'fs/xfs/xfs_log_recover.c')
| -rw-r--r-- | fs/xfs/xfs_log_recover.c | 229 | 
1 files changed, 58 insertions, 171 deletions
diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c index cc179878fe4..981af0f6504 100644 --- a/fs/xfs/xfs_log_recover.c +++ b/fs/xfs/xfs_log_recover.c @@ -17,42 +17,34 @@   */  #include "xfs.h"  #include "xfs_fs.h" +#include "xfs_shared.h"  #include "xfs_format.h" +#include "xfs_log_format.h" +#include "xfs_trans_resv.h"  #include "xfs_bit.h" -#include "xfs_log.h"  #include "xfs_inum.h" -#include "xfs_trans.h"  #include "xfs_sb.h"  #include "xfs_ag.h"  #include "xfs_mount.h" -#include "xfs_error.h" -#include "xfs_bmap_btree.h" -#include "xfs_alloc_btree.h" -#include "xfs_ialloc_btree.h" -#include "xfs_btree.h" -#include "xfs_dinode.h" +#include "xfs_da_format.h"  #include "xfs_inode.h" -#include "xfs_inode_item.h" -#include "xfs_alloc.h" -#include "xfs_ialloc.h" +#include "xfs_trans.h" +#include "xfs_log.h"  #include "xfs_log_priv.h" -#include "xfs_buf_item.h"  #include "xfs_log_recover.h" +#include "xfs_inode_item.h"  #include "xfs_extfree_item.h"  #include "xfs_trans_priv.h" +#include "xfs_alloc.h" +#include "xfs_ialloc.h"  #include "xfs_quota.h"  #include "xfs_cksum.h"  #include "xfs_trace.h"  #include "xfs_icache.h" -#include "xfs_icreate_item.h" - -/* Need all the magic numbers and buffer ops structures from these headers */ -#include "xfs_symlink.h" -#include "xfs_da_btree.h" -#include "xfs_dir2_format.h" +#include "xfs_bmap_btree.h" +#include "xfs_dinode.h" +#include "xfs_error.h"  #include "xfs_dir2.h" -#include "xfs_attr_leaf.h" -#include "xfs_attr_remote.h"  #define BLK_AVG(blk1, blk2)	((blk1+blk2) >> 1) @@ -201,7 +193,10 @@ xlog_bread_noalign(  	bp->b_io_length = nbblks;  	bp->b_error = 0; -	xfsbdstrat(log->l_mp, bp); +	if (XFS_FORCED_SHUTDOWN(log->l_mp)) +		return XFS_ERROR(EIO); + +	xfs_buf_iorequest(bp);  	error = xfs_buf_iowait(bp);  	if (error)  		xfs_buf_ioerror_alert(bp, __func__); @@ -305,9 +300,9 @@ xlog_header_check_dump(  	xfs_mount_t		*mp,  	xlog_rec_header_t	*head)  { -	xfs_debug(mp, "%s:  SB : uuid = %pU, fmt = %d\n", +	xfs_debug(mp, "%s:  SB : uuid = %pU, fmt = %d",  		__func__, &mp->m_sb.sb_uuid, XLOG_FMT); -	xfs_debug(mp, "    log : uuid = %pU, fmt = %d\n", +	xfs_debug(mp, "    log : uuid = %pU, fmt = %d",  		&head->h_fs_uuid, be32_to_cpu(head->h_fmt));  }  #else @@ -1585,6 +1580,7 @@ xlog_recover_add_to_trans(  		"bad number of regions (%d) in inode log format",  				  in_f->ilf_size);  			ASSERT(0); +			kmem_free(ptr);  			return XFS_ERROR(EIO);  		} @@ -1658,6 +1654,7 @@ xlog_recover_reorder_trans(  	int			pass)  {  	xlog_recover_item_t	*item, *n; +	int			error = 0;  	LIST_HEAD(sort_list);  	LIST_HEAD(cancel_list);  	LIST_HEAD(buffer_list); @@ -1699,9 +1696,17 @@ xlog_recover_reorder_trans(  				"%s: unrecognized type of log operation",  				__func__);  			ASSERT(0); -			return XFS_ERROR(EIO); +			/* +			 * return the remaining items back to the transaction +			 * item list so they can be freed in caller. +			 */ +			if (!list_empty(&sort_list)) +				list_splice_init(&sort_list, &trans->r_itemq); +			error = XFS_ERROR(EIO); +			goto out;  		}  	} +out:  	ASSERT(list_empty(&sort_list));  	if (!list_empty(&buffer_list))  		list_splice(&buffer_list, &trans->r_itemq); @@ -1711,7 +1716,7 @@ xlog_recover_reorder_trans(  		list_splice_tail(&inode_buffer_list, &trans->r_itemq);  	if (!list_empty(&cancel_list))  		list_splice_tail(&cancel_list, &trans->r_itemq); -	return 0; +	return error;  }  /* @@ -2133,7 +2138,9 @@ xlog_recover_validate_buf_type(  			bp->b_ops = &xfs_allocbt_buf_ops;  			break;  		case XFS_IBT_CRC_MAGIC: +		case XFS_FIBT_CRC_MAGIC:  		case XFS_IBT_MAGIC: +		case XFS_FIBT_MAGIC:  			bp->b_ops = &xfs_inobt_buf_ops;  			break;  		case XFS_BMAP_CRC_MAGIC: @@ -2361,7 +2368,7 @@ xlog_recover_do_reg_buffer(  					item->ri_buf[i].i_len, __func__);  				goto next;  			} -			error = xfs_qm_dqcheck(mp, item->ri_buf[i].i_addr, +			error = xfs_dqcheck(mp, item->ri_buf[i].i_addr,  					       -1, 0, XFS_QMOPT_DOWARN,  					       "dquot_buf_recover");  			if (error) @@ -2393,133 +2400,6 @@ xlog_recover_do_reg_buffer(  }  /* - * Do some primitive error checking on ondisk dquot data structures. - */ -int -xfs_qm_dqcheck( -	struct xfs_mount *mp, -	xfs_disk_dquot_t *ddq, -	xfs_dqid_t	 id, -	uint		 type,	  /* used only when IO_dorepair is true */ -	uint		 flags, -	char		 *str) -{ -	xfs_dqblk_t	 *d = (xfs_dqblk_t *)ddq; -	int		errs = 0; - -	/* -	 * We can encounter an uninitialized dquot buffer for 2 reasons: -	 * 1. If we crash while deleting the quotainode(s), and those blks got -	 *    used for user data. This is because we take the path of regular -	 *    file deletion; however, the size field of quotainodes is never -	 *    updated, so all the tricks that we play in itruncate_finish -	 *    don't quite matter. -	 * -	 * 2. We don't play the quota buffers when there's a quotaoff logitem. -	 *    But the allocation will be replayed so we'll end up with an -	 *    uninitialized quota block. -	 * -	 * This is all fine; things are still consistent, and we haven't lost -	 * any quota information. Just don't complain about bad dquot blks. -	 */ -	if (ddq->d_magic != cpu_to_be16(XFS_DQUOT_MAGIC)) { -		if (flags & XFS_QMOPT_DOWARN) -			xfs_alert(mp, -			"%s : XFS dquot ID 0x%x, magic 0x%x != 0x%x", -			str, id, be16_to_cpu(ddq->d_magic), XFS_DQUOT_MAGIC); -		errs++; -	} -	if (ddq->d_version != XFS_DQUOT_VERSION) { -		if (flags & XFS_QMOPT_DOWARN) -			xfs_alert(mp, -			"%s : XFS dquot ID 0x%x, version 0x%x != 0x%x", -			str, id, ddq->d_version, XFS_DQUOT_VERSION); -		errs++; -	} - -	if (ddq->d_flags != XFS_DQ_USER && -	    ddq->d_flags != XFS_DQ_PROJ && -	    ddq->d_flags != XFS_DQ_GROUP) { -		if (flags & XFS_QMOPT_DOWARN) -			xfs_alert(mp, -			"%s : XFS dquot ID 0x%x, unknown flags 0x%x", -			str, id, ddq->d_flags); -		errs++; -	} - -	if (id != -1 && id != be32_to_cpu(ddq->d_id)) { -		if (flags & XFS_QMOPT_DOWARN) -			xfs_alert(mp, -			"%s : ondisk-dquot 0x%p, ID mismatch: " -			"0x%x expected, found id 0x%x", -			str, ddq, id, be32_to_cpu(ddq->d_id)); -		errs++; -	} - -	if (!errs && ddq->d_id) { -		if (ddq->d_blk_softlimit && -		    be64_to_cpu(ddq->d_bcount) > -				be64_to_cpu(ddq->d_blk_softlimit)) { -			if (!ddq->d_btimer) { -				if (flags & XFS_QMOPT_DOWARN) -					xfs_alert(mp, -			"%s : Dquot ID 0x%x (0x%p) BLK TIMER NOT STARTED", -					str, (int)be32_to_cpu(ddq->d_id), ddq); -				errs++; -			} -		} -		if (ddq->d_ino_softlimit && -		    be64_to_cpu(ddq->d_icount) > -				be64_to_cpu(ddq->d_ino_softlimit)) { -			if (!ddq->d_itimer) { -				if (flags & XFS_QMOPT_DOWARN) -					xfs_alert(mp, -			"%s : Dquot ID 0x%x (0x%p) INODE TIMER NOT STARTED", -					str, (int)be32_to_cpu(ddq->d_id), ddq); -				errs++; -			} -		} -		if (ddq->d_rtb_softlimit && -		    be64_to_cpu(ddq->d_rtbcount) > -				be64_to_cpu(ddq->d_rtb_softlimit)) { -			if (!ddq->d_rtbtimer) { -				if (flags & XFS_QMOPT_DOWARN) -					xfs_alert(mp, -			"%s : Dquot ID 0x%x (0x%p) RTBLK TIMER NOT STARTED", -					str, (int)be32_to_cpu(ddq->d_id), ddq); -				errs++; -			} -		} -	} - -	if (!errs || !(flags & XFS_QMOPT_DQREPAIR)) -		return errs; - -	if (flags & XFS_QMOPT_DOWARN) -		xfs_notice(mp, "Re-initializing dquot ID 0x%x", id); - -	/* -	 * Typically, a repair is only requested by quotacheck. -	 */ -	ASSERT(id != -1); -	ASSERT(flags & XFS_QMOPT_DQREPAIR); -	memset(d, 0, sizeof(xfs_dqblk_t)); - -	d->dd_diskdq.d_magic = cpu_to_be16(XFS_DQUOT_MAGIC); -	d->dd_diskdq.d_version = XFS_DQUOT_VERSION; -	d->dd_diskdq.d_flags = type; -	d->dd_diskdq.d_id = cpu_to_be32(id); - -	if (xfs_sb_version_hascrc(&mp->m_sb)) { -		uuid_copy(&d->dd_uuid, &mp->m_sb.sb_uuid); -		xfs_update_cksum((char *)d, sizeof(struct xfs_dqblk), -				 XFS_DQUOT_CRC_OFF); -	} - -	return errs; -} - -/*   * Perform a dquot buffer recovery.   * Simple algorithm: if we have found a QUOTAOFF log item of the same type   * (ie. USR or GRP), then just toss this buffer away; don't recover it. @@ -2648,19 +2528,19 @@ xlog_recover_buffer_pass2(  	 *  	 * Also make sure that only inode buffers with good sizes stay in  	 * the buffer cache.  The kernel moves inodes in buffers of 1 block -	 * or XFS_INODE_CLUSTER_SIZE bytes, whichever is bigger.  The inode +	 * or mp->m_inode_cluster_size bytes, whichever is bigger.  The inode  	 * buffers in the log can be a different size if the log was generated  	 * by an older kernel using unclustered inode buffers or a newer kernel  	 * running with a different inode cluster size.  Regardless, if the -	 * the inode buffer size isn't MAX(blocksize, XFS_INODE_CLUSTER_SIZE) -	 * for *our* value of XFS_INODE_CLUSTER_SIZE, then we need to keep +	 * the inode buffer size isn't MAX(blocksize, mp->m_inode_cluster_size) +	 * for *our* value of mp->m_inode_cluster_size, then we need to keep  	 * the buffer out of the buffer cache so that the buffer won't  	 * overlap with future reads of those inodes.  	 */  	if (XFS_DINODE_MAGIC ==  	    be16_to_cpu(*((__be16 *)xfs_buf_offset(bp, 0))) &&  	    (BBTOB(bp->b_io_length) != MAX(log->l_mp->m_sb.sb_blocksize, -			(__uint32_t)XFS_INODE_CLUSTER_SIZE(log->l_mp)))) { +			(__uint32_t)log->l_mp->m_inode_cluster_size))) {  		xfs_buf_stale(bp);  		error = xfs_bwrite(bp);  	} else { @@ -3124,7 +3004,7 @@ xlog_recover_dquot_pass2(  	 */  	dq_f = item->ri_buf[0].i_addr;  	ASSERT(dq_f); -	error = xfs_qm_dqcheck(mp, recddq, dq_f->qlf_id, 0, XFS_QMOPT_DOWARN, +	error = xfs_dqcheck(mp, recddq, dq_f->qlf_id, 0, XFS_QMOPT_DOWARN,  			   "xlog_recover_dquot_pass2 (log copy)");  	if (error)  		return XFS_ERROR(EIO); @@ -3144,7 +3024,7 @@ xlog_recover_dquot_pass2(  	 * was among a chunk of dquots created earlier, and we did some  	 * minimal initialization then.  	 */ -	error = xfs_qm_dqcheck(mp, ddq, dq_f->qlf_id, 0, XFS_QMOPT_DOWARN, +	error = xfs_dqcheck(mp, ddq, dq_f->qlf_id, 0, XFS_QMOPT_DOWARN,  			   "xlog_recover_dquot_pass2");  	if (error) {  		xfs_buf_relse(bp); @@ -3267,7 +3147,7 @@ xlog_recover_efd_pass2(  		}  		lip = xfs_trans_ail_cursor_next(ailp, &cur);  	} -	xfs_trans_ail_cursor_done(ailp, &cur); +	xfs_trans_ail_cursor_done(&cur);  	spin_unlock(&ailp->xa_lock);  	return 0; @@ -3333,10 +3213,10 @@ xlog_recover_do_icreate_pass2(  	}  	/* existing allocation is fixed value */ -	ASSERT(count == XFS_IALLOC_INODES(mp)); -	ASSERT(length == XFS_IALLOC_BLOCKS(mp)); -	if (count != XFS_IALLOC_INODES(mp) || -	     length != XFS_IALLOC_BLOCKS(mp)) { +	ASSERT(count == mp->m_ialloc_inos); +	ASSERT(length == mp->m_ialloc_blks); +	if (count != mp->m_ialloc_inos || +	     length != mp->m_ialloc_blks) {  		xfs_warn(log->l_mp, "xlog_recover_do_icreate_trans: bad count 2");  		return EINVAL;  	} @@ -3642,8 +3522,7 @@ out:  STATIC int  xlog_recover_unmount_trans( -	struct xlog		*log, -	struct xlog_recover	*trans) +	struct xlog		*log)  {  	/* Do nothing now */  	xfs_warn(log->l_mp, "%s: Unmount LR", __func__); @@ -3717,7 +3596,7 @@ xlog_recover_process_data(  								trans, pass);  				break;  			case XLOG_UNMOUNT_TRANS: -				error = xlog_recover_unmount_trans(log, trans); +				error = xlog_recover_unmount_trans(log);  				break;  			case XLOG_WAS_CONT_TRANS:  				error = xlog_recover_add_to_cont_trans(log, @@ -3742,8 +3621,10 @@ xlog_recover_process_data(  				error = XFS_ERROR(EIO);  				break;  			} -			if (error) +			if (error) { +				xlog_recover_free_trans(trans);  				return error; +			}  		}  		dp += be32_to_cpu(ohead->oh_len);  		num_logops--; @@ -3877,7 +3758,7 @@ xlog_recover_process_efis(  		lip = xfs_trans_ail_cursor_next(ailp, &cur);  	}  out: -	xfs_trans_ail_cursor_done(ailp, &cur); +	xfs_trans_ail_cursor_done(&cur);  	spin_unlock(&ailp->xa_lock);  	return error;  } @@ -4076,7 +3957,7 @@ xlog_unpack_data_crc(  	if (crc != rhead->h_crc) {  		if (rhead->h_crc || xfs_sb_version_hascrc(&log->l_mp->m_sb)) {  			xfs_alert(log->l_mp, -		"log record CRC mismatch: found 0x%x, expected 0x%x.\n", +		"log record CRC mismatch: found 0x%x, expected 0x%x.",  					le32_to_cpu(rhead->h_crc),  					le32_to_cpu(crc));  			xfs_hex_dump(dp, 32); @@ -4531,7 +4412,13 @@ xlog_do_recover(  	XFS_BUF_READ(bp);  	XFS_BUF_UNASYNC(bp);  	bp->b_ops = &xfs_sb_buf_ops; -	xfsbdstrat(log->l_mp, bp); + +	if (XFS_FORCED_SHUTDOWN(log->l_mp)) { +		xfs_buf_relse(bp); +		return XFS_ERROR(EIO); +	} + +	xfs_buf_iorequest(bp);  	error = xfs_buf_iowait(bp);  	if (error) {  		xfs_buf_ioerror_alert(bp, __func__);  | 
