diff options
Diffstat (limited to 'fs/xfs/xfs_log_recover.c')
-rw-r--r-- | fs/xfs/xfs_log_recover.c | 295 |
1 files changed, 176 insertions, 119 deletions
diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c index ee34899396b2..2b2383f1895e 100644 --- a/fs/xfs/xfs_log_recover.c +++ b/fs/xfs/xfs_log_recover.c @@ -24,6 +24,7 @@ #include "xfs_bit.h" #include "xfs_sb.h" #include "xfs_mount.h" +#include "xfs_defer.h" #include "xfs_da_format.h" #include "xfs_da_btree.h" #include "xfs_inode.h" @@ -85,17 +86,21 @@ struct xfs_buf_cancel { */ /* - * Verify the given count of basic blocks is valid number of blocks - * to specify for an operation involving the given XFS log buffer. - * Returns nonzero if the count is valid, 0 otherwise. + * Verify the log-relative block number and length in basic blocks are valid for + * an operation involving the given XFS log buffer. Returns true if the fields + * are valid, false otherwise. */ - -static inline int -xlog_buf_bbcount_valid( +static inline bool +xlog_verify_bp( struct xlog *log, + xfs_daddr_t blk_no, int bbcount) { - return bbcount > 0 && bbcount <= log->l_logBBsize; + if (blk_no < 0 || blk_no >= log->l_logBBsize) + return false; + if (bbcount <= 0 || (blk_no + bbcount) > log->l_logBBsize) + return false; + return true; } /* @@ -110,7 +115,11 @@ xlog_get_bp( { struct xfs_buf *bp; - if (!xlog_buf_bbcount_valid(log, nbblks)) { + /* + * Pass log block 0 since we don't have an addr yet, buffer will be + * verified on read. + */ + if (!xlog_verify_bp(log, 0, nbblks)) { xfs_warn(log->l_mp, "Invalid block length (0x%x) for buffer", nbblks); XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_HIGH, log->l_mp); @@ -180,9 +189,10 @@ xlog_bread_noalign( { int error; - if (!xlog_buf_bbcount_valid(log, nbblks)) { - xfs_warn(log->l_mp, "Invalid block length (0x%x) for buffer", - nbblks); + if (!xlog_verify_bp(log, blk_no, nbblks)) { + xfs_warn(log->l_mp, + "Invalid log block/length (0x%llx, 0x%x) for buffer", + blk_no, nbblks); XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_HIGH, log->l_mp); return -EFSCORRUPTED; } @@ -265,9 +275,10 @@ xlog_bwrite( { int error; - if (!xlog_buf_bbcount_valid(log, nbblks)) { - xfs_warn(log->l_mp, "Invalid block length (0x%x) for buffer", - nbblks); + if (!xlog_verify_bp(log, blk_no, nbblks)) { + xfs_warn(log->l_mp, + "Invalid log block/length (0x%llx, 0x%x) for buffer", + blk_no, nbblks); XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_HIGH, log->l_mp); return -EFSCORRUPTED; } @@ -389,9 +400,9 @@ xlog_recover_iodone( * On v5 supers, a bli could be attached to update the metadata LSN. * Clean it up. */ - if (bp->b_fspriv) + if (bp->b_log_item) xfs_buf_item_relse(bp); - ASSERT(bp->b_fspriv == NULL); + ASSERT(bp->b_log_item == NULL); bp->b_iodone = NULL; xfs_buf_ioend(bp); @@ -753,7 +764,7 @@ xlog_find_head( * in the in-core log. The following number can be made tighter if * we actually look at the block size of the filesystem. */ - num_scan_bblks = XLOG_TOTAL_REC_SHIFT(log); + num_scan_bblks = min_t(int, log_bbnum, XLOG_TOTAL_REC_SHIFT(log)); if (head_blk >= num_scan_bblks) { /* * We are guaranteed that the entire check can be performed @@ -2207,7 +2218,7 @@ xlog_recover_do_inode_buffer( next_unlinked_offset - reg_buf_offset; if (unlikely(*logged_nextp == 0)) { xfs_alert(mp, - "Bad inode buffer log record (ptr = 0x%p, bp = 0x%p). " + "Bad inode buffer log record (ptr = "PTR_FMT", bp = "PTR_FMT"). " "Trying to replay bad (0) inode di_next_unlinked field.", item, bp); XFS_ERROR_REPORT("xlog_recover_do_inode_buf", @@ -2619,7 +2630,7 @@ xlog_recover_validate_buf_type( ASSERT(!bp->b_iodone || bp->b_iodone == xlog_recover_iodone); bp->b_iodone = xlog_recover_iodone; xfs_buf_item_init(bp, mp); - bip = bp->b_fspriv; + bip = bp->b_log_item; bip->bli_item.li_lsn = current_lsn; } } @@ -2641,7 +2652,7 @@ xlog_recover_do_reg_buffer( int i; int bit; int nbits; - int error; + xfs_failaddr_t fa; trace_xfs_log_recover_buf_reg_buf(mp->m_log, buf_f); @@ -2676,7 +2687,7 @@ xlog_recover_do_reg_buffer( * the first dquot in the buffer should do. XXXThis is * probably a good thing to do for other buf types also. */ - error = 0; + fa = NULL; if (buf_f->blf_flags & (XFS_BLF_UDQUOT_BUF|XFS_BLF_PDQUOT_BUF|XFS_BLF_GDQUOT_BUF)) { if (item->ri_buf[i].i_addr == NULL) { @@ -2690,11 +2701,14 @@ xlog_recover_do_reg_buffer( item->ri_buf[i].i_len, __func__); goto next; } - error = xfs_dqcheck(mp, item->ri_buf[i].i_addr, - -1, 0, XFS_QMOPT_DOWARN, - "dquot_buf_recover"); - if (error) + fa = xfs_dquot_verify(mp, item->ri_buf[i].i_addr, + -1, 0, 0); + if (fa) { + xfs_alert(mp, + "dquot corrupt at %pS trying to replay into block 0x%llx", + fa, bp->b_bn); goto next; + } } memcpy(xfs_buf_offset(bp, @@ -2946,6 +2960,10 @@ xfs_recover_inode_owner_change( if (error) goto out_free_ip; + if (!xfs_inode_verify_forks(ip)) { + error = -EFSCORRUPTED; + goto out_free_ip; + } if (in_f->ilf_fields & XFS_ILOG_DOWNER) { ASSERT(in_f->ilf_fields & XFS_ILOG_DBROOT); @@ -2975,7 +2993,7 @@ xlog_recover_inode_pass2( struct xlog_recover_item *item, xfs_lsn_t current_lsn) { - xfs_inode_log_format_t *in_f; + struct xfs_inode_log_format *in_f; xfs_mount_t *mp = log->l_mp; xfs_buf_t *bp; xfs_dinode_t *dip; @@ -2989,10 +3007,10 @@ xlog_recover_inode_pass2( uint isize; int need_free = 0; - if (item->ri_buf[0].i_len == sizeof(xfs_inode_log_format_t)) { + if (item->ri_buf[0].i_len == sizeof(struct xfs_inode_log_format)) { in_f = item->ri_buf[0].i_addr; } else { - in_f = kmem_alloc(sizeof(xfs_inode_log_format_t), KM_SLEEP); + in_f = kmem_alloc(sizeof(struct xfs_inode_log_format), KM_SLEEP); need_free = 1; error = xfs_inode_item_format_convert(&item->ri_buf[0], in_f); if (error) @@ -3031,7 +3049,7 @@ xlog_recover_inode_pass2( */ if (unlikely(dip->di_magic != cpu_to_be16(XFS_DINODE_MAGIC))) { xfs_alert(mp, - "%s: Bad inode magic number, dip = 0x%p, dino bp = 0x%p, ino = %Ld", + "%s: Bad inode magic number, dip = "PTR_FMT", dino bp = "PTR_FMT", ino = %Ld", __func__, dip, bp, in_f->ilf_ino); XFS_ERROR_REPORT("xlog_recover_inode_pass2(1)", XFS_ERRLEVEL_LOW, mp); @@ -3041,7 +3059,7 @@ xlog_recover_inode_pass2( ldip = item->ri_buf[1].i_addr; if (unlikely(ldip->di_magic != XFS_DINODE_MAGIC)) { xfs_alert(mp, - "%s: Bad inode log record, rec ptr 0x%p, ino %Ld", + "%s: Bad inode log record, rec ptr "PTR_FMT", ino %Ld", __func__, item, in_f->ilf_ino); XFS_ERROR_REPORT("xlog_recover_inode_pass2(2)", XFS_ERRLEVEL_LOW, mp); @@ -3099,8 +3117,8 @@ xlog_recover_inode_pass2( XFS_CORRUPTION_ERROR("xlog_recover_inode_pass2(3)", XFS_ERRLEVEL_LOW, mp, ldip); xfs_alert(mp, - "%s: Bad regular inode log record, rec ptr 0x%p, " - "ino ptr = 0x%p, ino bp = 0x%p, ino %Ld", + "%s: Bad regular inode log record, rec ptr "PTR_FMT", " + "ino ptr = "PTR_FMT", ino bp = "PTR_FMT", ino %Ld", __func__, item, dip, bp, in_f->ilf_ino); error = -EFSCORRUPTED; goto out_release; @@ -3112,8 +3130,8 @@ xlog_recover_inode_pass2( XFS_CORRUPTION_ERROR("xlog_recover_inode_pass2(4)", XFS_ERRLEVEL_LOW, mp, ldip); xfs_alert(mp, - "%s: Bad dir inode log record, rec ptr 0x%p, " - "ino ptr = 0x%p, ino bp = 0x%p, ino %Ld", + "%s: Bad dir inode log record, rec ptr "PTR_FMT", " + "ino ptr = "PTR_FMT", ino bp = "PTR_FMT", ino %Ld", __func__, item, dip, bp, in_f->ilf_ino); error = -EFSCORRUPTED; goto out_release; @@ -3123,8 +3141,8 @@ xlog_recover_inode_pass2( XFS_CORRUPTION_ERROR("xlog_recover_inode_pass2(5)", XFS_ERRLEVEL_LOW, mp, ldip); xfs_alert(mp, - "%s: Bad inode log record, rec ptr 0x%p, dino ptr 0x%p, " - "dino bp 0x%p, ino %Ld, total extents = %d, nblocks = %Ld", + "%s: Bad inode log record, rec ptr "PTR_FMT", dino ptr "PTR_FMT", " + "dino bp "PTR_FMT", ino %Ld, total extents = %d, nblocks = %Ld", __func__, item, dip, bp, in_f->ilf_ino, ldip->di_nextents + ldip->di_anextents, ldip->di_nblocks); @@ -3135,8 +3153,8 @@ xlog_recover_inode_pass2( XFS_CORRUPTION_ERROR("xlog_recover_inode_pass2(6)", XFS_ERRLEVEL_LOW, mp, ldip); xfs_alert(mp, - "%s: Bad inode log record, rec ptr 0x%p, dino ptr 0x%p, " - "dino bp 0x%p, ino %Ld, forkoff 0x%x", __func__, + "%s: Bad inode log record, rec ptr "PTR_FMT", dino ptr "PTR_FMT", " + "dino bp "PTR_FMT", ino %Ld, forkoff 0x%x", __func__, item, dip, bp, in_f->ilf_ino, ldip->di_forkoff); error = -EFSCORRUPTED; goto out_release; @@ -3146,7 +3164,7 @@ xlog_recover_inode_pass2( XFS_CORRUPTION_ERROR("xlog_recover_inode_pass2(7)", XFS_ERRLEVEL_LOW, mp, ldip); xfs_alert(mp, - "%s: Bad inode log record length %d, rec ptr 0x%p", + "%s: Bad inode log record length %d, rec ptr "PTR_FMT, __func__, item->ri_buf[1].i_len, item); error = -EFSCORRUPTED; goto out_release; @@ -3155,24 +3173,9 @@ xlog_recover_inode_pass2( /* recover the log dinode inode into the on disk inode */ xfs_log_dinode_to_disk(ldip, dip); - /* the rest is in on-disk format */ - if (item->ri_buf[1].i_len > isize) { - memcpy((char *)dip + isize, - item->ri_buf[1].i_addr + isize, - item->ri_buf[1].i_len - isize); - } - fields = in_f->ilf_fields; - switch (fields & (XFS_ILOG_DEV | XFS_ILOG_UUID)) { - case XFS_ILOG_DEV: + if (fields & XFS_ILOG_DEV) xfs_dinode_put_rdev(dip, in_f->ilf_u.ilfu_rdev); - break; - case XFS_ILOG_UUID: - memcpy(XFS_DFORK_DPTR(dip), - &in_f->ilf_u.ilfu_uuid, - sizeof(uuid_t)); - break; - } if (in_f->ilf_size == 2) goto out_owner_change; @@ -3242,7 +3245,9 @@ xlog_recover_inode_pass2( } out_owner_change: - if (in_f->ilf_fields & (XFS_ILOG_DOWNER|XFS_ILOG_AOWNER)) + /* Recover the swapext owner change unless inode has been deleted */ + if ((in_f->ilf_fields & (XFS_ILOG_DOWNER|XFS_ILOG_AOWNER)) && + (dip->di_mode != 0)) error = xfs_recover_inode_owner_change(mp, dip, in_f, buffer_list); /* re-generate the checksum. */ @@ -3300,6 +3305,7 @@ xlog_recover_dquot_pass2( xfs_mount_t *mp = log->l_mp; xfs_buf_t *bp; struct xfs_disk_dquot *ddq, *recddq; + xfs_failaddr_t fa; int error; xfs_dq_logformat_t *dq_f; uint type; @@ -3342,10 +3348,12 @@ xlog_recover_dquot_pass2( */ dq_f = item->ri_buf[0].i_addr; ASSERT(dq_f); - error = xfs_dqcheck(mp, recddq, dq_f->qlf_id, 0, XFS_QMOPT_DOWARN, - "xlog_recover_dquot_pass2 (log copy)"); - if (error) + fa = xfs_dquot_verify(mp, recddq, dq_f->qlf_id, 0, 0); + if (fa) { + xfs_alert(mp, "corrupt dquot ID 0x%x in log at %pS", + dq_f->qlf_id, fa); return -EIO; + } ASSERT(dq_f->qlf_len == 1); /* @@ -3421,7 +3429,7 @@ xlog_recover_efi_pass2( } atomic_set(&efip->efi_next_extent, efi_formatp->efi_nextents); - spin_lock(&log->l_ailp->xa_lock); + spin_lock(&log->l_ailp->ail_lock); /* * The EFI has two references. One for the EFD and one for EFI to ensure * it makes it into the AIL. Insert the EFI into the AIL directly and @@ -3464,7 +3472,7 @@ xlog_recover_efd_pass2( * Search for the EFI with the id in the EFD format structure in the * AIL. */ - spin_lock(&ailp->xa_lock); + spin_lock(&ailp->ail_lock); lip = xfs_trans_ail_cursor_first(ailp, &cur, 0); while (lip != NULL) { if (lip->li_type == XFS_LI_EFI) { @@ -3474,9 +3482,9 @@ xlog_recover_efd_pass2( * Drop the EFD reference to the EFI. This * removes the EFI from the AIL and frees it. */ - spin_unlock(&ailp->xa_lock); + spin_unlock(&ailp->ail_lock); xfs_efi_release(efip); - spin_lock(&ailp->xa_lock); + spin_lock(&ailp->ail_lock); break; } } @@ -3484,7 +3492,7 @@ xlog_recover_efd_pass2( } xfs_trans_ail_cursor_done(&cur); - spin_unlock(&ailp->xa_lock); + spin_unlock(&ailp->ail_lock); return 0; } @@ -3517,7 +3525,7 @@ xlog_recover_rui_pass2( } atomic_set(&ruip->rui_next_extent, rui_formatp->rui_nextents); - spin_lock(&log->l_ailp->xa_lock); + spin_lock(&log->l_ailp->ail_lock); /* * The RUI has two references. One for the RUD and one for RUI to ensure * it makes it into the AIL. Insert the RUI into the AIL directly and @@ -3557,7 +3565,7 @@ xlog_recover_rud_pass2( * Search for the RUI with the id in the RUD format structure in the * AIL. */ - spin_lock(&ailp->xa_lock); + spin_lock(&ailp->ail_lock); lip = xfs_trans_ail_cursor_first(ailp, &cur, 0); while (lip != NULL) { if (lip->li_type == XFS_LI_RUI) { @@ -3567,9 +3575,9 @@ xlog_recover_rud_pass2( * Drop the RUD reference to the RUI. This * removes the RUI from the AIL and frees it. */ - spin_unlock(&ailp->xa_lock); + spin_unlock(&ailp->ail_lock); xfs_rui_release(ruip); - spin_lock(&ailp->xa_lock); + spin_lock(&ailp->ail_lock); break; } } @@ -3577,7 +3585,7 @@ xlog_recover_rud_pass2( } xfs_trans_ail_cursor_done(&cur); - spin_unlock(&ailp->xa_lock); + spin_unlock(&ailp->ail_lock); return 0; } @@ -3633,7 +3641,7 @@ xlog_recover_cui_pass2( } atomic_set(&cuip->cui_next_extent, cui_formatp->cui_nextents); - spin_lock(&log->l_ailp->xa_lock); + spin_lock(&log->l_ailp->ail_lock); /* * The CUI has two references. One for the CUD and one for CUI to ensure * it makes it into the AIL. Insert the CUI into the AIL directly and @@ -3674,7 +3682,7 @@ xlog_recover_cud_pass2( * Search for the CUI with the id in the CUD format structure in the * AIL. */ - spin_lock(&ailp->xa_lock); + spin_lock(&ailp->ail_lock); lip = xfs_trans_ail_cursor_first(ailp, &cur, 0); while (lip != NULL) { if (lip->li_type == XFS_LI_CUI) { @@ -3684,9 +3692,9 @@ xlog_recover_cud_pass2( * Drop the CUD reference to the CUI. This * removes the CUI from the AIL and frees it. */ - spin_unlock(&ailp->xa_lock); + spin_unlock(&ailp->ail_lock); xfs_cui_release(cuip); - spin_lock(&ailp->xa_lock); + spin_lock(&ailp->ail_lock); break; } } @@ -3694,7 +3702,7 @@ xlog_recover_cud_pass2( } xfs_trans_ail_cursor_done(&cur); - spin_unlock(&ailp->xa_lock); + spin_unlock(&ailp->ail_lock); return 0; } @@ -3752,7 +3760,7 @@ xlog_recover_bui_pass2( } atomic_set(&buip->bui_next_extent, bui_formatp->bui_nextents); - spin_lock(&log->l_ailp->xa_lock); + spin_lock(&log->l_ailp->ail_lock); /* * The RUI has two references. One for the RUD and one for RUI to ensure * it makes it into the AIL. Insert the RUI into the AIL directly and @@ -3793,7 +3801,7 @@ xlog_recover_bud_pass2( * Search for the BUI with the id in the BUD format structure in the * AIL. */ - spin_lock(&ailp->xa_lock); + spin_lock(&ailp->ail_lock); lip = xfs_trans_ail_cursor_first(ailp, &cur, 0); while (lip != NULL) { if (lip->li_type == XFS_LI_BUI) { @@ -3803,9 +3811,9 @@ xlog_recover_bud_pass2( * Drop the BUD reference to the BUI. This * removes the BUI from the AIL and frees it. */ - spin_unlock(&ailp->xa_lock); + spin_unlock(&ailp->ail_lock); xfs_bui_release(buip); - spin_lock(&ailp->xa_lock); + spin_lock(&ailp->ail_lock); break; } } @@ -3813,7 +3821,7 @@ xlog_recover_bud_pass2( } xfs_trans_ail_cursor_done(&cur); - spin_unlock(&ailp->xa_lock); + spin_unlock(&ailp->ail_lock); return 0; } @@ -4297,7 +4305,7 @@ xlog_recover_add_to_trans( char *dp, int len) { - xfs_inode_log_format_t *in_f; /* any will do */ + struct xfs_inode_log_format *in_f; /* any will do */ xlog_recover_item_t *item; char *ptr; @@ -4331,7 +4339,7 @@ xlog_recover_add_to_trans( ptr = kmem_alloc(len, KM_SLEEP); memcpy(ptr, dp, len); - in_f = (xfs_inode_log_format_t *)ptr; + in_f = (struct xfs_inode_log_format *)ptr; /* take the tail entry */ item = list_entry(trans->r_itemq.prev, xlog_recover_item_t, ri_list); @@ -4646,9 +4654,9 @@ xlog_recover_process_efi( if (test_bit(XFS_EFI_RECOVERED, &efip->efi_flags)) return 0; - spin_unlock(&ailp->xa_lock); + spin_unlock(&ailp->ail_lock); error = xfs_efi_recover(mp, efip); - spin_lock(&ailp->xa_lock); + spin_lock(&ailp->ail_lock); return error; } @@ -4664,9 +4672,9 @@ xlog_recover_cancel_efi( efip = container_of(lip, struct xfs_efi_log_item, efi_item); - spin_unlock(&ailp->xa_lock); + spin_unlock(&ailp->ail_lock); xfs_efi_release(efip); - spin_lock(&ailp->xa_lock); + spin_lock(&ailp->ail_lock); } /* Recover the RUI if necessary. */ @@ -4686,9 +4694,9 @@ xlog_recover_process_rui( if (test_bit(XFS_RUI_RECOVERED, &ruip->rui_flags)) return 0; - spin_unlock(&ailp->xa_lock); + spin_unlock(&ailp->ail_lock); error = xfs_rui_recover(mp, ruip); - spin_lock(&ailp->xa_lock); + spin_lock(&ailp->ail_lock); return error; } @@ -4704,9 +4712,9 @@ xlog_recover_cancel_rui( ruip = container_of(lip, struct xfs_rui_log_item, rui_item); - spin_unlock(&ailp->xa_lock); + spin_unlock(&ailp->ail_lock); xfs_rui_release(ruip); - spin_lock(&ailp->xa_lock); + spin_lock(&ailp->ail_lock); } /* Recover the CUI if necessary. */ @@ -4714,7 +4722,8 @@ STATIC int xlog_recover_process_cui( struct xfs_mount *mp, struct xfs_ail *ailp, - struct xfs_log_item *lip) + struct xfs_log_item *lip, + struct xfs_defer_ops *dfops) { struct xfs_cui_log_item *cuip; int error; @@ -4726,9 +4735,9 @@ xlog_recover_process_cui( if (test_bit(XFS_CUI_RECOVERED, &cuip->cui_flags)) return 0; - spin_unlock(&ailp->xa_lock); - error = xfs_cui_recover(mp, cuip); - spin_lock(&ailp->xa_lock); + spin_unlock(&ailp->ail_lock); + error = xfs_cui_recover(mp, cuip, dfops); + spin_lock(&ailp->ail_lock); return error; } @@ -4744,9 +4753,9 @@ xlog_recover_cancel_cui( cuip = container_of(lip, struct xfs_cui_log_item, cui_item); - spin_unlock(&ailp->xa_lock); + spin_unlock(&ailp->ail_lock); xfs_cui_release(cuip); - spin_lock(&ailp->xa_lock); + spin_lock(&ailp->ail_lock); } /* Recover the BUI if necessary. */ @@ -4754,7 +4763,8 @@ STATIC int xlog_recover_process_bui( struct xfs_mount *mp, struct xfs_ail *ailp, - struct xfs_log_item *lip) + struct xfs_log_item *lip, + struct xfs_defer_ops *dfops) { struct xfs_bui_log_item *buip; int error; @@ -4766,9 +4776,9 @@ xlog_recover_process_bui( if (test_bit(XFS_BUI_RECOVERED, &buip->bui_flags)) return 0; - spin_unlock(&ailp->xa_lock); - error = xfs_bui_recover(mp, buip); - spin_lock(&ailp->xa_lock); + spin_unlock(&ailp->ail_lock); + error = xfs_bui_recover(mp, buip, dfops); + spin_lock(&ailp->ail_lock); return error; } @@ -4784,9 +4794,9 @@ xlog_recover_cancel_bui( buip = container_of(lip, struct xfs_bui_log_item, bui_item); - spin_unlock(&ailp->xa_lock); + spin_unlock(&ailp->ail_lock); xfs_bui_release(buip); - spin_lock(&ailp->xa_lock); + spin_lock(&ailp->ail_lock); } /* Is this log item a deferred action intent? */ @@ -4803,6 +4813,46 @@ static inline bool xlog_item_is_intent(struct xfs_log_item *lip) } } +/* Take all the collected deferred ops and finish them in order. */ +static int +xlog_finish_defer_ops( + struct xfs_mount *mp, + struct xfs_defer_ops *dfops) +{ + struct xfs_trans *tp; + int64_t freeblks; + uint resblks; + int error; + + /* + * We're finishing the defer_ops that accumulated as a result of + * recovering unfinished intent items during log recovery. We + * reserve an itruncate transaction because it is the largest + * permanent transaction type. Since we're the only user of the fs + * right now, take 93% (15/16) of the available free blocks. Use + * weird math to avoid a 64-bit division. + */ + freeblks = percpu_counter_sum(&mp->m_fdblocks); + if (freeblks <= 0) + return -ENOSPC; + resblks = min_t(int64_t, UINT_MAX, freeblks); + resblks = (resblks * 15) >> 4; + error = xfs_trans_alloc(mp, &M_RES(mp)->tr_itruncate, resblks, + 0, XFS_TRANS_RESERVE, &tp); + if (error) + return error; + + error = xfs_defer_finish(&tp, dfops); + if (error) + goto out_cancel; + + return xfs_trans_commit(tp); + +out_cancel: + xfs_trans_cancel(tp); + return error; +} + /* * When this is called, all of the log intent items which did not have * corresponding log done items should be in the AIL. What we do now @@ -4823,20 +4873,23 @@ STATIC int xlog_recover_process_intents( struct xlog *log) { - struct xfs_log_item *lip; - int error = 0; + struct xfs_defer_ops dfops; struct xfs_ail_cursor cur; + struct xfs_log_item *lip; struct xfs_ail *ailp; + xfs_fsblock_t firstfsb; + int error = 0; #if defined(DEBUG) || defined(XFS_WARN) xfs_lsn_t last_lsn; #endif ailp = log->l_ailp; - spin_lock(&ailp->xa_lock); + spin_lock(&ailp->ail_lock); lip = xfs_trans_ail_cursor_first(ailp, &cur, 0); #if defined(DEBUG) || defined(XFS_WARN) last_lsn = xlog_assign_lsn(log->l_curr_cycle, log->l_curr_block); #endif + xfs_defer_init(&dfops, &firstfsb); while (lip != NULL) { /* * We're done when we see something other than an intent. @@ -4857,6 +4910,12 @@ xlog_recover_process_intents( */ ASSERT(XFS_LSN_CMP(last_lsn, lip->li_lsn) >= 0); + /* + * NOTE: If your intent processing routine can create more + * deferred ops, you /must/ attach them to the dfops in this + * routine or else those subsequent intents will get + * replayed in the wrong order! + */ switch (lip->li_type) { case XFS_LI_EFI: error = xlog_recover_process_efi(log->l_mp, ailp, lip); @@ -4865,10 +4924,12 @@ xlog_recover_process_intents( error = xlog_recover_process_rui(log->l_mp, ailp, lip); break; case XFS_LI_CUI: - error = xlog_recover_process_cui(log->l_mp, ailp, lip); + error = xlog_recover_process_cui(log->l_mp, ailp, lip, + &dfops); break; case XFS_LI_BUI: - error = xlog_recover_process_bui(log->l_mp, ailp, lip); + error = xlog_recover_process_bui(log->l_mp, ailp, lip, + &dfops); break; } if (error) @@ -4877,7 +4938,12 @@ xlog_recover_process_intents( } out: xfs_trans_ail_cursor_done(&cur); - spin_unlock(&ailp->xa_lock); + spin_unlock(&ailp->ail_lock); + if (error) + xfs_defer_cancel(&dfops); + else + error = xlog_finish_defer_ops(log->l_mp, &dfops); + return error; } @@ -4895,7 +4961,7 @@ xlog_recover_cancel_intents( struct xfs_ail *ailp; ailp = log->l_ailp; - spin_lock(&ailp->xa_lock); + spin_lock(&ailp->ail_lock); lip = xfs_trans_ail_cursor_first(ailp, &cur, 0); while (lip != NULL) { /* @@ -4929,7 +4995,7 @@ xlog_recover_cancel_intents( } xfs_trans_ail_cursor_done(&cur); - spin_unlock(&ailp->xa_lock); + spin_unlock(&ailp->ail_lock); return error; } @@ -5056,16 +5122,9 @@ xlog_recover_process_iunlinks( xfs_agino_t agino; int bucket; int error; - uint mp_dmevmask; mp = log->l_mp; - /* - * Prevent any DMAPI event from being sent while in this function. - */ - mp_dmevmask = mp->m_dmevmask; - mp->m_dmevmask = 0; - for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) { /* * Find the agi for this ag. @@ -5101,8 +5160,6 @@ xlog_recover_process_iunlinks( } xfs_buf_rele(agibp); } - - mp->m_dmevmask = mp_dmevmask; } STATIC int @@ -5823,7 +5880,7 @@ xlog_recover_cancel( * Read all of the agf and agi counters and check that they * are consistent with the superblock counters. */ -void +STATIC void xlog_recover_check_summary( struct xlog *log) { |