|
@@ -2292,12 +2292,22 @@ xlog_recover_do_inode_trans(
|
|
|
int attr_index;
|
|
|
uint fields;
|
|
|
xfs_dinode_core_t *dicp;
|
|
|
+ int need_free = 0;
|
|
|
|
|
|
if (pass == XLOG_RECOVER_PASS1) {
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
- in_f = (xfs_inode_log_format_t *)item->ri_buf[0].i_addr;
|
|
|
+ if (item->ri_buf[0].i_len == sizeof(xfs_inode_log_format_t)) {
|
|
|
+ in_f = (xfs_inode_log_format_t *)item->ri_buf[0].i_addr;
|
|
|
+ } else {
|
|
|
+ in_f = (xfs_inode_log_format_t *)kmem_alloc(
|
|
|
+ sizeof(xfs_inode_log_format_t), KM_SLEEP);
|
|
|
+ need_free = 1;
|
|
|
+ error = xfs_inode_item_format_convert(&item->ri_buf[0], in_f);
|
|
|
+ if (error)
|
|
|
+ goto error;
|
|
|
+ }
|
|
|
ino = in_f->ilf_ino;
|
|
|
mp = log->l_mp;
|
|
|
if (ITEM_TYPE(item) == XFS_LI_INODE) {
|
|
@@ -2323,8 +2333,10 @@ xlog_recover_do_inode_trans(
|
|
|
* Inode buffers can be freed, look out for it,
|
|
|
* and do not replay the inode.
|
|
|
*/
|
|
|
- if (xlog_check_buffer_cancelled(log, imap.im_blkno, imap.im_len, 0))
|
|
|
- return 0;
|
|
|
+ if (xlog_check_buffer_cancelled(log, imap.im_blkno, imap.im_len, 0)) {
|
|
|
+ error = 0;
|
|
|
+ goto error;
|
|
|
+ }
|
|
|
|
|
|
bp = xfs_buf_read_flags(mp->m_ddev_targp, imap.im_blkno, imap.im_len,
|
|
|
XFS_BUF_LOCK);
|
|
@@ -2333,7 +2345,7 @@ xlog_recover_do_inode_trans(
|
|
|
bp, imap.im_blkno);
|
|
|
error = XFS_BUF_GETERROR(bp);
|
|
|
xfs_buf_relse(bp);
|
|
|
- return error;
|
|
|
+ goto error;
|
|
|
}
|
|
|
error = 0;
|
|
|
ASSERT(in_f->ilf_fields & XFS_ILOG_CORE);
|
|
@@ -2350,7 +2362,8 @@ xlog_recover_do_inode_trans(
|
|
|
dip, bp, ino);
|
|
|
XFS_ERROR_REPORT("xlog_recover_do_inode_trans(1)",
|
|
|
XFS_ERRLEVEL_LOW, mp);
|
|
|
- return XFS_ERROR(EFSCORRUPTED);
|
|
|
+ error = EFSCORRUPTED;
|
|
|
+ goto error;
|
|
|
}
|
|
|
dicp = (xfs_dinode_core_t*)(item->ri_buf[1].i_addr);
|
|
|
if (unlikely(dicp->di_magic != XFS_DINODE_MAGIC)) {
|
|
@@ -2360,7 +2373,8 @@ xlog_recover_do_inode_trans(
|
|
|
item, ino);
|
|
|
XFS_ERROR_REPORT("xlog_recover_do_inode_trans(2)",
|
|
|
XFS_ERRLEVEL_LOW, mp);
|
|
|
- return XFS_ERROR(EFSCORRUPTED);
|
|
|
+ error = EFSCORRUPTED;
|
|
|
+ goto error;
|
|
|
}
|
|
|
|
|
|
/* Skip replay when the on disk inode is newer than the log one */
|
|
@@ -2376,7 +2390,8 @@ xlog_recover_do_inode_trans(
|
|
|
/* do nothing */
|
|
|
} else {
|
|
|
xfs_buf_relse(bp);
|
|
|
- return 0;
|
|
|
+ error = 0;
|
|
|
+ goto error;
|
|
|
}
|
|
|
}
|
|
|
/* Take the opportunity to reset the flush iteration count */
|
|
@@ -2391,7 +2406,8 @@ xlog_recover_do_inode_trans(
|
|
|
xfs_fs_cmn_err(CE_ALERT, mp,
|
|
|
"xfs_inode_recover: Bad regular inode log record, rec ptr 0x%p, ino ptr = 0x%p, ino bp = 0x%p, ino %Ld",
|
|
|
item, dip, bp, ino);
|
|
|
- return XFS_ERROR(EFSCORRUPTED);
|
|
|
+ error = EFSCORRUPTED;
|
|
|
+ goto error;
|
|
|
}
|
|
|
} else if (unlikely((dicp->di_mode & S_IFMT) == S_IFDIR)) {
|
|
|
if ((dicp->di_format != XFS_DINODE_FMT_EXTENTS) &&
|
|
@@ -2403,7 +2419,8 @@ xlog_recover_do_inode_trans(
|
|
|
xfs_fs_cmn_err(CE_ALERT, mp,
|
|
|
"xfs_inode_recover: Bad dir inode log record, rec ptr 0x%p, ino ptr = 0x%p, ino bp = 0x%p, ino %Ld",
|
|
|
item, dip, bp, ino);
|
|
|
- return XFS_ERROR(EFSCORRUPTED);
|
|
|
+ error = EFSCORRUPTED;
|
|
|
+ goto error;
|
|
|
}
|
|
|
}
|
|
|
if (unlikely(dicp->di_nextents + dicp->di_anextents > dicp->di_nblocks)){
|
|
@@ -2415,7 +2432,8 @@ xlog_recover_do_inode_trans(
|
|
|
item, dip, bp, ino,
|
|
|
dicp->di_nextents + dicp->di_anextents,
|
|
|
dicp->di_nblocks);
|
|
|
- return XFS_ERROR(EFSCORRUPTED);
|
|
|
+ error = EFSCORRUPTED;
|
|
|
+ goto error;
|
|
|
}
|
|
|
if (unlikely(dicp->di_forkoff > mp->m_sb.sb_inodesize)) {
|
|
|
XFS_CORRUPTION_ERROR("xlog_recover_do_inode_trans(6)",
|
|
@@ -2424,7 +2442,8 @@ xlog_recover_do_inode_trans(
|
|
|
xfs_fs_cmn_err(CE_ALERT, mp,
|
|
|
"xfs_inode_recover: Bad inode log rec ptr 0x%p, dino ptr 0x%p, dino bp 0x%p, ino %Ld, forkoff 0x%x",
|
|
|
item, dip, bp, ino, dicp->di_forkoff);
|
|
|
- return XFS_ERROR(EFSCORRUPTED);
|
|
|
+ error = EFSCORRUPTED;
|
|
|
+ goto error;
|
|
|
}
|
|
|
if (unlikely(item->ri_buf[1].i_len > sizeof(xfs_dinode_core_t))) {
|
|
|
XFS_CORRUPTION_ERROR("xlog_recover_do_inode_trans(7)",
|
|
@@ -2433,7 +2452,8 @@ xlog_recover_do_inode_trans(
|
|
|
xfs_fs_cmn_err(CE_ALERT, mp,
|
|
|
"xfs_inode_recover: Bad inode log record length %d, rec ptr 0x%p",
|
|
|
item->ri_buf[1].i_len, item);
|
|
|
- return XFS_ERROR(EFSCORRUPTED);
|
|
|
+ error = EFSCORRUPTED;
|
|
|
+ goto error;
|
|
|
}
|
|
|
|
|
|
/* The core is in in-core format */
|
|
@@ -2521,7 +2541,8 @@ xlog_recover_do_inode_trans(
|
|
|
xlog_warn("XFS: xlog_recover_do_inode_trans: Invalid flag");
|
|
|
ASSERT(0);
|
|
|
xfs_buf_relse(bp);
|
|
|
- return XFS_ERROR(EIO);
|
|
|
+ error = EIO;
|
|
|
+ goto error;
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -2537,7 +2558,10 @@ write_inode_buffer:
|
|
|
error = xfs_bwrite(mp, bp);
|
|
|
}
|
|
|
|
|
|
- return (error);
|
|
|
+error:
|
|
|
+ if (need_free)
|
|
|
+ kmem_free(in_f, sizeof(*in_f));
|
|
|
+ return XFS_ERROR(error);
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -2674,32 +2698,32 @@ xlog_recover_do_dquot_trans(
|
|
|
* structure into it, and adds the efi to the AIL with the given
|
|
|
* LSN.
|
|
|
*/
|
|
|
-STATIC void
|
|
|
+STATIC int
|
|
|
xlog_recover_do_efi_trans(
|
|
|
xlog_t *log,
|
|
|
xlog_recover_item_t *item,
|
|
|
xfs_lsn_t lsn,
|
|
|
int pass)
|
|
|
{
|
|
|
+ int error;
|
|
|
xfs_mount_t *mp;
|
|
|
xfs_efi_log_item_t *efip;
|
|
|
xfs_efi_log_format_t *efi_formatp;
|
|
|
SPLDECL(s);
|
|
|
|
|
|
if (pass == XLOG_RECOVER_PASS1) {
|
|
|
- return;
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
efi_formatp = (xfs_efi_log_format_t *)item->ri_buf[0].i_addr;
|
|
|
- ASSERT(item->ri_buf[0].i_len ==
|
|
|
- (sizeof(xfs_efi_log_format_t) +
|
|
|
- ((efi_formatp->efi_nextents - 1) * sizeof(xfs_extent_t))));
|
|
|
|
|
|
mp = log->l_mp;
|
|
|
efip = xfs_efi_init(mp, efi_formatp->efi_nextents);
|
|
|
- memcpy((char *)&(efip->efi_format), (char *)efi_formatp,
|
|
|
- sizeof(xfs_efi_log_format_t) +
|
|
|
- ((efi_formatp->efi_nextents - 1) * sizeof(xfs_extent_t)));
|
|
|
+ if ((error = xfs_efi_copy_format(&(item->ri_buf[0]),
|
|
|
+ &(efip->efi_format)))) {
|
|
|
+ xfs_efi_item_free(efip);
|
|
|
+ return error;
|
|
|
+ }
|
|
|
efip->efi_next_extent = efi_formatp->efi_nextents;
|
|
|
efip->efi_flags |= XFS_EFI_COMMITTED;
|
|
|
|
|
@@ -2708,6 +2732,7 @@ xlog_recover_do_efi_trans(
|
|
|
* xfs_trans_update_ail() drops the AIL lock.
|
|
|
*/
|
|
|
xfs_trans_update_ail(mp, (xfs_log_item_t *)efip, lsn, s);
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
|
|
@@ -2738,9 +2763,10 @@ xlog_recover_do_efd_trans(
|
|
|
}
|
|
|
|
|
|
efd_formatp = (xfs_efd_log_format_t *)item->ri_buf[0].i_addr;
|
|
|
- ASSERT(item->ri_buf[0].i_len ==
|
|
|
- (sizeof(xfs_efd_log_format_t) +
|
|
|
- ((efd_formatp->efd_nextents - 1) * sizeof(xfs_extent_t))));
|
|
|
+ ASSERT((item->ri_buf[0].i_len == (sizeof(xfs_efd_log_format_32_t) +
|
|
|
+ ((efd_formatp->efd_nextents - 1) * sizeof(xfs_extent_32_t)))) ||
|
|
|
+ (item->ri_buf[0].i_len == (sizeof(xfs_efd_log_format_64_t) +
|
|
|
+ ((efd_formatp->efd_nextents - 1) * sizeof(xfs_extent_64_t)))));
|
|
|
efi_id = efd_formatp->efd_efi_id;
|
|
|
|
|
|
/*
|
|
@@ -2810,15 +2836,14 @@ xlog_recover_do_trans(
|
|
|
if ((error = xlog_recover_do_buffer_trans(log, item,
|
|
|
pass)))
|
|
|
break;
|
|
|
- } else if ((ITEM_TYPE(item) == XFS_LI_INODE) ||
|
|
|
- (ITEM_TYPE(item) == XFS_LI_6_1_INODE) ||
|
|
|
- (ITEM_TYPE(item) == XFS_LI_5_3_INODE)) {
|
|
|
+ } else if ((ITEM_TYPE(item) == XFS_LI_INODE)) {
|
|
|
if ((error = xlog_recover_do_inode_trans(log, item,
|
|
|
pass)))
|
|
|
break;
|
|
|
} else if (ITEM_TYPE(item) == XFS_LI_EFI) {
|
|
|
- xlog_recover_do_efi_trans(log, item, trans->r_lsn,
|
|
|
- pass);
|
|
|
+ if ((error = xlog_recover_do_efi_trans(log, item, trans->r_lsn,
|
|
|
+ pass)))
|
|
|
+ break;
|
|
|
} else if (ITEM_TYPE(item) == XFS_LI_EFD) {
|
|
|
xlog_recover_do_efd_trans(log, item, pass);
|
|
|
} else if (ITEM_TYPE(item) == XFS_LI_DQUOT) {
|
|
@@ -3798,7 +3823,7 @@ xlog_do_log_recovery(
|
|
|
error = xlog_do_recovery_pass(log, head_blk, tail_blk,
|
|
|
XLOG_RECOVER_PASS2);
|
|
|
#ifdef DEBUG
|
|
|
- {
|
|
|
+ if (!error) {
|
|
|
int i;
|
|
|
|
|
|
for (i = 0; i < XLOG_BC_TABLE_SIZE; i++)
|