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

📄 xfs_log_recover.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* * Copyright (c) 2000-2006 Silicon Graphics, Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write the Free Software Foundation, * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA */#include "xfs.h"#include "xfs_fs.h"#include "xfs_types.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_dir2.h"#include "xfs_dmapi.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_dir2_sf.h"#include "xfs_attr_sf.h"#include "xfs_dinode.h"#include "xfs_inode.h"#include "xfs_inode_item.h"#include "xfs_imap.h"#include "xfs_alloc.h"#include "xfs_ialloc.h"#include "xfs_log_priv.h"#include "xfs_buf_item.h"#include "xfs_log_recover.h"#include "xfs_extfree_item.h"#include "xfs_trans_priv.h"#include "xfs_quota.h"#include "xfs_rw.h"STATIC int	xlog_find_zeroed(xlog_t *, xfs_daddr_t *);STATIC int	xlog_clear_stale_blocks(xlog_t *, xfs_lsn_t);STATIC void	xlog_recover_insert_item_backq(xlog_recover_item_t **q,					       xlog_recover_item_t *item);#if defined(DEBUG)STATIC void	xlog_recover_check_summary(xlog_t *);STATIC void	xlog_recover_check_ail(xfs_mount_t *, xfs_log_item_t *, int);#else#define	xlog_recover_check_summary(log)#define	xlog_recover_check_ail(mp, lip, gen)#endif/* * Sector aligned buffer routines for buffer create/read/write/access */#define XLOG_SECTOR_ROUNDUP_BBCOUNT(log, bbs)	\	( ((log)->l_sectbb_mask && (bbs & (log)->l_sectbb_mask)) ? \	((bbs + (log)->l_sectbb_mask + 1) & ~(log)->l_sectbb_mask) : (bbs) )#define XLOG_SECTOR_ROUNDDOWN_BLKNO(log, bno)	((bno) & ~(log)->l_sectbb_mask)xfs_buf_t *xlog_get_bp(	xlog_t		*log,	int		num_bblks){	ASSERT(num_bblks > 0);	if (log->l_sectbb_log) {		if (num_bblks > 1)			num_bblks += XLOG_SECTOR_ROUNDUP_BBCOUNT(log, 1);		num_bblks = XLOG_SECTOR_ROUNDUP_BBCOUNT(log, num_bblks);	}	return xfs_buf_get_noaddr(BBTOB(num_bblks), log->l_mp->m_logdev_targp);}voidxlog_put_bp(	xfs_buf_t	*bp){	xfs_buf_free(bp);}/* * nbblks should be uint, but oh well.  Just want to catch that 32-bit length. */intxlog_bread(	xlog_t		*log,	xfs_daddr_t	blk_no,	int		nbblks,	xfs_buf_t	*bp){	int		error;	if (log->l_sectbb_log) {		blk_no = XLOG_SECTOR_ROUNDDOWN_BLKNO(log, blk_no);		nbblks = XLOG_SECTOR_ROUNDUP_BBCOUNT(log, nbblks);	}	ASSERT(nbblks > 0);	ASSERT(BBTOB(nbblks) <= XFS_BUF_SIZE(bp));	ASSERT(bp);	XFS_BUF_SET_ADDR(bp, log->l_logBBstart + blk_no);	XFS_BUF_READ(bp);	XFS_BUF_BUSY(bp);	XFS_BUF_SET_COUNT(bp, BBTOB(nbblks));	XFS_BUF_SET_TARGET(bp, log->l_mp->m_logdev_targp);	xfsbdstrat(log->l_mp, bp);	if ((error = xfs_iowait(bp)))		xfs_ioerror_alert("xlog_bread", log->l_mp,				  bp, XFS_BUF_ADDR(bp));	return error;}/* * Write out the buffer at the given block for the given number of blocks. * The buffer is kept locked across the write and is returned locked. * This can only be used for synchronous log writes. */STATIC intxlog_bwrite(	xlog_t		*log,	xfs_daddr_t	blk_no,	int		nbblks,	xfs_buf_t	*bp){	int		error;	if (log->l_sectbb_log) {		blk_no = XLOG_SECTOR_ROUNDDOWN_BLKNO(log, blk_no);		nbblks = XLOG_SECTOR_ROUNDUP_BBCOUNT(log, nbblks);	}	ASSERT(nbblks > 0);	ASSERT(BBTOB(nbblks) <= XFS_BUF_SIZE(bp));	XFS_BUF_SET_ADDR(bp, log->l_logBBstart + blk_no);	XFS_BUF_ZEROFLAGS(bp);	XFS_BUF_BUSY(bp);	XFS_BUF_HOLD(bp);	XFS_BUF_PSEMA(bp, PRIBIO);	XFS_BUF_SET_COUNT(bp, BBTOB(nbblks));	XFS_BUF_SET_TARGET(bp, log->l_mp->m_logdev_targp);	if ((error = xfs_bwrite(log->l_mp, bp)))		xfs_ioerror_alert("xlog_bwrite", log->l_mp,				  bp, XFS_BUF_ADDR(bp));	return error;}STATIC xfs_caddr_txlog_align(	xlog_t		*log,	xfs_daddr_t	blk_no,	int		nbblks,	xfs_buf_t	*bp){	xfs_caddr_t	ptr;	if (!log->l_sectbb_log)		return XFS_BUF_PTR(bp);	ptr = XFS_BUF_PTR(bp) + BBTOB((int)blk_no & log->l_sectbb_mask);	ASSERT(XFS_BUF_SIZE(bp) >=		BBTOB(nbblks + (blk_no & log->l_sectbb_mask)));	return ptr;}#ifdef DEBUG/* * dump debug superblock and log record information */STATIC voidxlog_header_check_dump(	xfs_mount_t		*mp,	xlog_rec_header_t	*head){	int			b;	cmn_err(CE_DEBUG, "%s:  SB : uuid = ", __FUNCTION__);	for (b = 0; b < 16; b++)		cmn_err(CE_DEBUG, "%02x", ((uchar_t *)&mp->m_sb.sb_uuid)[b]);	cmn_err(CE_DEBUG, ", fmt = %d\n", XLOG_FMT);	cmn_err(CE_DEBUG, "    log : uuid = ");	for (b = 0; b < 16; b++)		cmn_err(CE_DEBUG, "%02x",((uchar_t *)&head->h_fs_uuid)[b]);	cmn_err(CE_DEBUG, ", fmt = %d\n", INT_GET(head->h_fmt, ARCH_CONVERT));}#else#define xlog_header_check_dump(mp, head)#endif/* * check log record header for recovery */STATIC intxlog_header_check_recover(	xfs_mount_t		*mp,	xlog_rec_header_t	*head){	ASSERT(INT_GET(head->h_magicno, ARCH_CONVERT) == XLOG_HEADER_MAGIC_NUM);	/*	 * IRIX doesn't write the h_fmt field and leaves it zeroed	 * (XLOG_FMT_UNKNOWN). This stops us from trying to recover	 * a dirty log created in IRIX.	 */	if (unlikely(INT_GET(head->h_fmt, ARCH_CONVERT) != XLOG_FMT)) {		xlog_warn(	"XFS: dirty log written in incompatible format - can't recover");		xlog_header_check_dump(mp, head);		XFS_ERROR_REPORT("xlog_header_check_recover(1)",				 XFS_ERRLEVEL_HIGH, mp);		return XFS_ERROR(EFSCORRUPTED);	} else if (unlikely(!uuid_equal(&mp->m_sb.sb_uuid, &head->h_fs_uuid))) {		xlog_warn(	"XFS: dirty log entry has mismatched uuid - can't recover");		xlog_header_check_dump(mp, head);		XFS_ERROR_REPORT("xlog_header_check_recover(2)",				 XFS_ERRLEVEL_HIGH, mp);		return XFS_ERROR(EFSCORRUPTED);	}	return 0;}/* * read the head block of the log and check the header */STATIC intxlog_header_check_mount(	xfs_mount_t		*mp,	xlog_rec_header_t	*head){	ASSERT(INT_GET(head->h_magicno, ARCH_CONVERT) == XLOG_HEADER_MAGIC_NUM);	if (uuid_is_nil(&head->h_fs_uuid)) {		/*		 * IRIX doesn't write the h_fs_uuid or h_fmt fields. If		 * h_fs_uuid is nil, we assume this log was last mounted		 * by IRIX and continue.		 */		xlog_warn("XFS: nil uuid in log - IRIX style log");	} else if (unlikely(!uuid_equal(&mp->m_sb.sb_uuid, &head->h_fs_uuid))) {		xlog_warn("XFS: log has mismatched uuid - can't recover");		xlog_header_check_dump(mp, head);		XFS_ERROR_REPORT("xlog_header_check_mount",				 XFS_ERRLEVEL_HIGH, mp);		return XFS_ERROR(EFSCORRUPTED);	}	return 0;}STATIC voidxlog_recover_iodone(	struct xfs_buf	*bp){	xfs_mount_t	*mp;	ASSERT(XFS_BUF_FSPRIVATE(bp, void *));	if (XFS_BUF_GETERROR(bp)) {		/*		 * We're not going to bother about retrying		 * this during recovery. One strike!		 */		mp = XFS_BUF_FSPRIVATE(bp, xfs_mount_t *);		xfs_ioerror_alert("xlog_recover_iodone",				  mp, bp, XFS_BUF_ADDR(bp));		xfs_force_shutdown(mp, SHUTDOWN_META_IO_ERROR);	}	XFS_BUF_SET_FSPRIVATE(bp, NULL);	XFS_BUF_CLR_IODONE_FUNC(bp);	xfs_biodone(bp);}/* * This routine finds (to an approximation) the first block in the physical * log which contains the given cycle.  It uses a binary search algorithm. * Note that the algorithm can not be perfect because the disk will not * necessarily be perfect. */intxlog_find_cycle_start(	xlog_t		*log,	xfs_buf_t	*bp,	xfs_daddr_t	first_blk,	xfs_daddr_t	*last_blk,	uint		cycle){	xfs_caddr_t	offset;	xfs_daddr_t	mid_blk;	uint		mid_cycle;	int		error;	mid_blk = BLK_AVG(first_blk, *last_blk);	while (mid_blk != first_blk && mid_blk != *last_blk) {		if ((error = xlog_bread(log, mid_blk, 1, bp)))			return error;		offset = xlog_align(log, mid_blk, 1, bp);		mid_cycle = GET_CYCLE(offset, ARCH_CONVERT);		if (mid_cycle == cycle) {			*last_blk = mid_blk;			/* last_half_cycle == mid_cycle */		} else {			first_blk = mid_blk;			/* first_half_cycle == mid_cycle */		}		mid_blk = BLK_AVG(first_blk, *last_blk);	}	ASSERT((mid_blk == first_blk && mid_blk+1 == *last_blk) ||	       (mid_blk == *last_blk && mid_blk-1 == first_blk));	return 0;}/* * Check that the range of blocks does not contain the cycle number * given.  The scan needs to occur from front to back and the ptr into the * region must be updated since a later routine will need to perform another * test.  If the region is completely good, we end up returning the same * last block number. * * Set blkno to -1 if we encounter no errors.  This is an invalid block number * since we don't ever expect logs to get this large. */STATIC intxlog_find_verify_cycle(	xlog_t		*log,	xfs_daddr_t	start_blk,	int		nbblks,	uint		stop_on_cycle_no,	xfs_daddr_t	*new_blk){	xfs_daddr_t	i, j;	uint		cycle;	xfs_buf_t	*bp;	xfs_daddr_t	bufblks;	xfs_caddr_t	buf = NULL;	int		error = 0;	bufblks = 1 << ffs(nbblks);	while (!(bp = xlog_get_bp(log, bufblks))) {		/* can't get enough memory to do everything in one big buffer */		bufblks >>= 1;		if (bufblks <= log->l_sectbb_log)			return ENOMEM;	}	for (i = start_blk; i < start_blk + nbblks; i += bufblks) {		int	bcount;		bcount = min(bufblks, (start_blk + nbblks - i));		if ((error = xlog_bread(log, i, bcount, bp)))			goto out;		buf = xlog_align(log, i, bcount, bp);		for (j = 0; j < bcount; j++) {			cycle = GET_CYCLE(buf, ARCH_CONVERT);			if (cycle == stop_on_cycle_no) {				*new_blk = i+j;				goto out;			}			buf += BBSIZE;		}	}	*new_blk = -1;out:	xlog_put_bp(bp);	return error;}/* * Potentially backup over partial log record write. * * In the typical case, last_blk is the number of the block directly after * a good log record.  Therefore, we subtract one to get the block number * of the last block in the given buffer.  extra_bblks contains the number * of blocks we would have read on a previous read.  This happens when the * last log record is split over the end of the physical log. * * extra_bblks is the number of blocks potentially verified on a previous * call to this routine. */STATIC intxlog_find_verify_log_record(	xlog_t			*log,	xfs_daddr_t		start_blk,	xfs_daddr_t		*last_blk,	int			extra_bblks){	xfs_daddr_t		i;	xfs_buf_t		*bp;	xfs_caddr_t		offset = NULL;	xlog_rec_header_t	*head = NULL;	int			error = 0;	int			smallmem = 0;	int			num_blks = *last_blk - start_blk;	int			xhdrs;	ASSERT(start_blk != 0 || *last_blk != start_blk);	if (!(bp = xlog_get_bp(log, num_blks))) {		if (!(bp = xlog_get_bp(log, 1)))			return ENOMEM;		smallmem = 1;	} else {		if ((error = xlog_bread(log, start_blk, num_blks, bp)))			goto out;		offset = xlog_align(log, start_blk, num_blks, bp);		offset += ((num_blks - 1) << BBSHIFT);	}	for (i = (*last_blk) - 1; i >= 0; i--) {		if (i < start_blk) {			/* valid log record not found */			xlog_warn(		"XFS: Log inconsistent (didn't find previous header)");			ASSERT(0);			error = XFS_ERROR(EIO);			goto out;		}		if (smallmem) {			if ((error = xlog_bread(log, i, 1, bp)))				goto out;			offset = xlog_align(log, i, 1, bp);		}		head = (xlog_rec_header_t *)offset;		if (XLOG_HEADER_MAGIC_NUM ==		    INT_GET(head->h_magicno, ARCH_CONVERT))			break;		if (!smallmem)			offset -= BBSIZE;	}	/*	 * We hit the beginning of the physical log & still no header.  Return	 * to caller.  If caller can handle a return of -1, then this routine	 * will be called again for the end of the physical log.	 */	if (i == -1) {

⌨️ 快捷键说明

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