⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 xfs_log_recover.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
			ASSIGN_ANY_LSN_HOST(log->l_last_sync_lsn, log->l_curr_cycle,					after_umount_blk);			*tail_blk = after_umount_blk;			/*			 * Note that the unmount was clean. If the unmount			 * was not clean, we need to know this to rebuild the			 * superblock counters from the perag headers if we			 * have a filesystem using non-persistent counters.			 */			log->l_mp->m_flags |= XFS_MOUNT_WAS_CLEAN;		}	}	/*	 * Make sure that there are no blocks in front of the head	 * with the same cycle number as the head.  This can happen	 * because we allow multiple outstanding log writes concurrently,	 * and the later writes might make it out before earlier ones.	 *	 * We use the lsn from before modifying it so that we'll never	 * overwrite the unmount record after a clean unmount.	 *	 * Do this only if we are going to recover the filesystem	 *	 * NOTE: This used to say "if (!readonly)"	 * However on Linux, we can & do recover a read-only filesystem.	 * We only skip recovery if NORECOVERY is specified on mount,	 * in which case we would not be here.	 *	 * But... if the -device- itself is readonly, just skip this.	 * We can't recover this device anyway, so it won't matter.	 */	if (!xfs_readonly_buftarg(log->l_mp->m_logdev_targp)) {		error = xlog_clear_stale_blocks(log, tail_lsn);	}bread_err:exit:	xlog_put_bp(bp);	if (error)		xlog_warn("XFS: failed to locate log tail");	return error;}/* * Is the log zeroed at all? * * The last binary search should be changed to perform an X block read * once X becomes small enough.  You can then search linearly through * the X blocks.  This will cut down on the number of reads we need to do. * * If the log is partially zeroed, this routine will pass back the blkno * of the first block with cycle number 0.  It won't have a complete LR * preceding it. * * Return: *	0  => the log is completely written to *	-1 => use *blk_no as the first block of the log *	>0 => error has occurred */intxlog_find_zeroed(	xlog_t		*log,	xfs_daddr_t	*blk_no){	xfs_buf_t	*bp;	xfs_caddr_t	offset;	uint	        first_cycle, last_cycle;	xfs_daddr_t	new_blk, last_blk, start_blk;	xfs_daddr_t     num_scan_bblks;	int	        error, log_bbnum = log->l_logBBsize;	*blk_no = 0;	/* check totally zeroed log */	bp = xlog_get_bp(log, 1);	if (!bp)		return ENOMEM;	if ((error = xlog_bread(log, 0, 1, bp)))		goto bp_err;	offset = xlog_align(log, 0, 1, bp);	first_cycle = GET_CYCLE(offset, ARCH_CONVERT);	if (first_cycle == 0) {		/* completely zeroed log */		*blk_no = 0;		xlog_put_bp(bp);		return -1;	}	/* check partially zeroed log */	if ((error = xlog_bread(log, log_bbnum-1, 1, bp)))		goto bp_err;	offset = xlog_align(log, log_bbnum-1, 1, bp);	last_cycle = GET_CYCLE(offset, ARCH_CONVERT);	if (last_cycle != 0) {		/* log completely written to */		xlog_put_bp(bp);		return 0;	} else if (first_cycle != 1) {		/*		 * If the cycle of the last block is zero, the cycle of		 * the first block must be 1. If it's not, maybe we're		 * not looking at a log... Bail out.		 */		xlog_warn("XFS: Log inconsistent or not a log (last==0, first!=1)");		return XFS_ERROR(EINVAL);	}	/* we have a partially zeroed log */	last_blk = log_bbnum-1;	if ((error = xlog_find_cycle_start(log, bp, 0, &last_blk, 0)))		goto bp_err;	/*	 * Validate the answer.  Because there is no way to guarantee that	 * the entire log is made up of log records which are the same size,	 * we scan over the defined maximum blocks.  At this point, the maximum	 * is not chosen to mean anything special.   XXXmiken	 */	num_scan_bblks = XLOG_TOTAL_REC_SHIFT(log);	ASSERT(num_scan_bblks <= INT_MAX);	if (last_blk < num_scan_bblks)		num_scan_bblks = last_blk;	start_blk = last_blk - num_scan_bblks;	/*	 * We search for any instances of cycle number 0 that occur before	 * our current estimate of the head.  What we're trying to detect is	 *        1 ... | 0 | 1 | 0...	 *                       ^ binary search ends here	 */	if ((error = xlog_find_verify_cycle(log, start_blk,					 (int)num_scan_bblks, 0, &new_blk)))		goto bp_err;	if (new_blk != -1)		last_blk = new_blk;	/*	 * Potentially backup over partial log record write.  We don't need	 * to search the end of the log because we know it is zero.	 */	if ((error = xlog_find_verify_log_record(log, start_blk,				&last_blk, 0)) == -1) {	    error = XFS_ERROR(EIO);	    goto bp_err;	} else if (error)	    goto bp_err;	*blk_no = last_blk;bp_err:	xlog_put_bp(bp);	if (error)		return error;	return -1;}/* * These are simple subroutines used by xlog_clear_stale_blocks() below * to initialize a buffer full of empty log record headers and write * them into the log. */STATIC voidxlog_add_record(	xlog_t			*log,	xfs_caddr_t		buf,	int			cycle,	int			block,	int			tail_cycle,	int			tail_block){	xlog_rec_header_t	*recp = (xlog_rec_header_t *)buf;	memset(buf, 0, BBSIZE);	INT_SET(recp->h_magicno, ARCH_CONVERT, XLOG_HEADER_MAGIC_NUM);	INT_SET(recp->h_cycle, ARCH_CONVERT, cycle);	INT_SET(recp->h_version, ARCH_CONVERT,			XFS_SB_VERSION_HASLOGV2(&log->l_mp->m_sb) ? 2 : 1);	ASSIGN_ANY_LSN_DISK(recp->h_lsn, cycle, block);	ASSIGN_ANY_LSN_DISK(recp->h_tail_lsn, tail_cycle, tail_block);	INT_SET(recp->h_fmt, ARCH_CONVERT, XLOG_FMT);	memcpy(&recp->h_fs_uuid, &log->l_mp->m_sb.sb_uuid, sizeof(uuid_t));}STATIC intxlog_write_log_records(	xlog_t		*log,	int		cycle,	int		start_block,	int		blocks,	int		tail_cycle,	int		tail_block){	xfs_caddr_t	offset;	xfs_buf_t	*bp;	int		balign, ealign;	int		sectbb = XLOG_SECTOR_ROUNDUP_BBCOUNT(log, 1);	int		end_block = start_block + blocks;	int		bufblks;	int		error = 0;	int		i, j = 0;	bufblks = 1 << ffs(blocks);	while (!(bp = xlog_get_bp(log, bufblks))) {		bufblks >>= 1;		if (bufblks <= log->l_sectbb_log)			return ENOMEM;	}	/* We may need to do a read at the start to fill in part of	 * the buffer in the starting sector not covered by the first	 * write below.	 */	balign = XLOG_SECTOR_ROUNDDOWN_BLKNO(log, start_block);	if (balign != start_block) {		if ((error = xlog_bread(log, start_block, 1, bp))) {			xlog_put_bp(bp);			return error;		}		j = start_block - balign;	}	for (i = start_block; i < end_block; i += bufblks) {		int		bcount, endcount;		bcount = min(bufblks, end_block - start_block);		endcount = bcount - j;		/* We may need to do a read at the end to fill in part of		 * the buffer in the final sector not covered by the write.		 * If this is the same sector as the above read, skip it.		 */		ealign = XLOG_SECTOR_ROUNDDOWN_BLKNO(log, end_block);		if (j == 0 && (start_block + endcount > ealign)) {			offset = XFS_BUF_PTR(bp);			balign = BBTOB(ealign - start_block);			XFS_BUF_SET_PTR(bp, offset + balign, BBTOB(sectbb));			if ((error = xlog_bread(log, ealign, sectbb, bp)))				break;			XFS_BUF_SET_PTR(bp, offset, bufblks);		}		offset = xlog_align(log, start_block, endcount, bp);		for (; j < endcount; j++) {			xlog_add_record(log, offset, cycle, i+j,					tail_cycle, tail_block);			offset += BBSIZE;		}		error = xlog_bwrite(log, start_block, endcount, bp);		if (error)			break;		start_block += endcount;		j = 0;	}	xlog_put_bp(bp);	return error;}/* * This routine is called to blow away any incomplete log writes out * in front of the log head.  We do this so that we won't become confused * if we come up, write only a little bit more, and then crash again. * If we leave the partial log records out there, this situation could * cause us to think those partial writes are valid blocks since they * have the current cycle number.  We get rid of them by overwriting them * with empty log records with the old cycle number rather than the * current one. * * The tail lsn is passed in rather than taken from * the log so that we will not write over the unmount record after a * clean unmount in a 512 block log.  Doing so would leave the log without * any valid log records in it until a new one was written.  If we crashed * during that time we would not be able to recover. */STATIC intxlog_clear_stale_blocks(	xlog_t		*log,	xfs_lsn_t	tail_lsn){	int		tail_cycle, head_cycle;	int		tail_block, head_block;	int		tail_distance, max_distance;	int		distance;	int		error;	tail_cycle = CYCLE_LSN(tail_lsn);	tail_block = BLOCK_LSN(tail_lsn);	head_cycle = log->l_curr_cycle;	head_block = log->l_curr_block;	/*	 * Figure out the distance between the new head of the log	 * and the tail.  We want to write over any blocks beyond the	 * head that we may have written just before the crash, but	 * we don't want to overwrite the tail of the log.	 */	if (head_cycle == tail_cycle) {		/*		 * The tail is behind the head in the physical log,		 * so the distance from the head to the tail is the		 * distance from the head to the end of the log plus		 * the distance from the beginning of the log to the		 * tail.		 */		if (unlikely(head_block < tail_block || head_block >= log->l_logBBsize)) {			XFS_ERROR_REPORT("xlog_clear_stale_blocks(1)",					 XFS_ERRLEVEL_LOW, log->l_mp);			return XFS_ERROR(EFSCORRUPTED);		}		tail_distance = tail_block + (log->l_logBBsize - head_block);	} else {		/*		 * The head is behind the tail in the physical log,		 * so the distance from the head to the tail is just		 * the tail block minus the head block.		 */		if (unlikely(head_block >= tail_block || head_cycle != (tail_cycle + 1))){			XFS_ERROR_REPORT("xlog_clear_stale_blocks(2)",					 XFS_ERRLEVEL_LOW, log->l_mp);			return XFS_ERROR(EFSCORRUPTED);		}		tail_distance = tail_block - head_block;	}	/*	 * If the head is right up against the tail, we can't clear	 * anything.	 */	if (tail_distance <= 0) {		ASSERT(tail_distance == 0);		return 0;	}	max_distance = XLOG_TOTAL_REC_SHIFT(log);	/*	 * Take the smaller of the maximum amount of outstanding I/O	 * we could have and the distance to the tail to clear out.	 * We take the smaller so that we don't overwrite the tail and	 * we don't waste all day writing from the head to the tail	 * for no reason.	 */	max_distance = MIN(max_distance, tail_distance);	if ((head_block + max_distance) <= log->l_logBBsize) {		/*		 * We can stomp all the blocks we need to without		 * wrapping around the end of the log.  Just do it		 * in a single write.  Use the cycle number of the		 * current cycle minus one so that the log will look like:		 *     n ... | n - 1 ...		 */		error = xlog_write_log_records(log, (head_cycle - 1),				head_block, max_distance, tail_cycle,				tail_block);		if (error)			return error;	} else {		/*		 * We need to wrap around the end of the physical log in		 * order to clear all the blocks.  Do it in two separate		 * I/Os.  The first write should be from the head to the		 * end of the physical log, and it should use the current		 * cycle number minus one just like above.		 */		distance = log->l_logBBsize - head_block;		error = xlog_write_log_records(log, (head_cycle - 1),				head_block, distance, tail_cycle,				tail_block);		if (error)			return error;		/*		 * Now write the blocks at the start of the physical log.		 * This writes the remainder of the blocks we want to clear.		 * It uses the current cycle number since we're now on the		 * same cycle as the head so that we get:		 *    n ... n ... | n - 1 ...		 *    ^^^^^ blocks we're writing		 */		distance = max_distance - (log->l_logBBsize - head_block);		error = xlog_write_log_records(log, head_cycle, 0, distance,				tail_cycle, tail_block);		if (error)			return error;	}	return 0;}/****************************************************************************** * *		Log recover routines * ****************************************************************************** */STATIC xlog_recover_t *xlog_recover_find_tid(	xlog_recover_t		*q,	xlog_tid_t		tid){	xlog_recover_t		*p = q;	while (p != NULL) {		if (p->r_log_tid == tid)		    break;		p = p->r_next;	}	return p;}STATIC voidxlog_recover_put_hashq(	xlog_recover_t		**q,	xlog_recover_t		*trans){	trans->r_next = *q;	*q = trans;}STATIC voidxlog_recover_add_item(	xlog_recover_item_t	**itemq){	xlog_recover_item_t	*item;	item = kmem_zalloc(sizeof(xlog_recover_item_t), KM_SLEEP);	xlog_recover_insert_item_backq(itemq, item);}STATIC intxlog_recover_add_to_cont_trans(	xlog_recover_t		*trans,	xfs_caddr_t		dp,	int			len){	xlog_recover_item_t	*item;	xfs_caddr_t		ptr, old_ptr;	int			old_len;	item = trans->r_itemq;	if (item == NULL) {		/* finish copying rest of trans header */		xlog_recover_add_item(&trans->r_itemq);		ptr = (xfs_caddr_t) &trans->r_theader +				sizeof(xfs_trans_header_t) - len;		memcpy(ptr, dp, len); /* d, s, l */		return 0;	}	item = item->ri_prev;	old_ptr = item->ri_buf[item->ri_cnt-1].i_addr;	old_len = item->ri_buf[item->ri_cnt-1].i_len;	ptr = kmem_realloc(old_ptr, len+old_len, old_len, 0u);	memcpy(&ptr[old_len], dp, len); /* d, s, l */	item->ri_buf[item->ri_cnt-1].i_len += len;	item->ri_buf[item->ri_cnt-1].i_addr = ptr;	return 0;}/*

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -