diff --git a/fs/xfs/libxfs/xfs_log_recover.h b/fs/xfs/libxfs/xfs_log_recover.h index a5100a11faf9cd26943a21410f6f7c0d9fb34e96..1190537d02b71cd1d43f480320ebf6d590ebc28c 100644 --- a/fs/xfs/libxfs/xfs_log_recover.h +++ b/fs/xfs/libxfs/xfs_log_recover.h @@ -18,6 +18,7 @@ enum xlog_recover_reorder { XLOG_REORDER_ITEM_LIST, XLOG_REORDER_INODE_BUFFER_LIST, XLOG_REORDER_CANCEL_LIST, + XLOG_REORDER_SB_BUFFER_LIST, }; struct xlog_recover_item_ops { diff --git a/fs/xfs/xfs_buf_item.c b/fs/xfs/xfs_buf_item.c index 023d4e0385dd08da8928f2492bf2b7fd09851c37..f782363cdb386ad501295ef0f643cdd576bdbcde 100644 --- a/fs/xfs/xfs_buf_item.c +++ b/fs/xfs/xfs_buf_item.c @@ -776,7 +776,7 @@ xfs_buf_item_committed( trace_xfs_buf_item_committed(bip); - if ((bip->bli_flags & XFS_BLI_INODE_ALLOC_BUF) && lip->li_lsn != 0) + if ((bip->bli_flags & XFS_BLI_KEEP_LSN) && lip->li_lsn != 0) return lip->li_lsn; return lsn; } diff --git a/fs/xfs/xfs_buf_item.h b/fs/xfs/xfs_buf_item.h index 4d8a6aece995d9a103b85c07fb5b1d0727f240e4..51e8ec085786cc5d27ee620409abbf4f829b4197 100644 --- a/fs/xfs/xfs_buf_item.h +++ b/fs/xfs/xfs_buf_item.h @@ -20,6 +20,11 @@ struct xfs_mount; #define XFS_BLI_STALE_INODE (1u << 5) #define XFS_BLI_INODE_BUF (1u << 6) #define XFS_BLI_ORDERED (1u << 7) +#define XFS_BLI_GROW_SB_BUF (1u << 8) + +#define XFS_BLI_KEEP_LSN \ + (XFS_BLI_INODE_ALLOC_BUF | \ + XFS_BLI_GROW_SB_BUF) #define XFS_BLI_FLAGS \ { XFS_BLI_HOLD, "HOLD" }, \ @@ -29,7 +34,8 @@ struct xfs_mount; { XFS_BLI_INODE_ALLOC_BUF, "INODE_ALLOC" }, \ { XFS_BLI_STALE_INODE, "STALE_INODE" }, \ { XFS_BLI_INODE_BUF, "INODE_BUF" }, \ - { XFS_BLI_ORDERED, "ORDERED" } + { XFS_BLI_ORDERED, "ORDERED" }, \ + { XFS_BLI_GROW_SB_BUF, "GROW_SB" } /* * This is the in core log item structure used to track information diff --git a/fs/xfs/xfs_buf_item_recover.c b/fs/xfs/xfs_buf_item_recover.c index 43167f543afc33f5471d0d11c27917d19ab9a13c..2383cc2d035406ad9fa3de77b3e077aa19da3e94 100644 --- a/fs/xfs/xfs_buf_item_recover.c +++ b/fs/xfs/xfs_buf_item_recover.c @@ -22,6 +22,8 @@ #include "xfs_inode.h" #include "xfs_dir2.h" #include "xfs_quota.h" +#include "xfs_sb.h" +#include "xfs_ag.h" /* * This is the number of entries in the l_buf_cancel_table used during @@ -160,6 +162,8 @@ xlog_recover_buf_reorder( return XLOG_REORDER_CANCEL_LIST; if (buf_f->blf_flags & XFS_BLF_INODE_BUF) return XLOG_REORDER_INODE_BUFFER_LIST; + if (buf_f->blf_blkno == XFS_SB_DADDR) + return XLOG_REORDER_SB_BUFFER_LIST; return XLOG_REORDER_BUFFER_LIST; } @@ -946,13 +950,10 @@ xlog_recover_buf_commit_pass2( /* * We're skipping replay of this buffer log item due to the log - * item LSN being behind the ondisk buffer. Verify the buffer - * contents since we aren't going to run the write verifier. + * item LSN being behind the ondisk buffer. clear XBF_DONE flag + * of the buffer to prevent buffer from being used without verify. */ - if (bp->b_ops) { - bp->b_ops->verify_read(bp); - error = bp->b_error; - } + bp->b_flags &= ~XBF_DONE; goto out_release; } @@ -969,6 +970,29 @@ xlog_recover_buf_commit_pass2( goto out_release; } else { xlog_recover_do_reg_buffer(mp, item, bp, buf_f, current_lsn); + /* + * If the superblock buffer is modified, we also need to modify the + * content of the mp. + */ + if (bp->b_maps[0].bm_bn == XFS_SB_DADDR && bp->b_ops) { + struct xfs_dsb *sb = bp->b_addr; + + bp->b_ops->verify_write(bp); + error = bp->b_error; + if (error) + goto out_release; + + if (be32_to_cpu(sb->sb_agcount) > mp->m_sb.sb_agcount) { + error = xfs_initialize_perag(mp, + be32_to_cpu(sb->sb_agcount), + be64_to_cpu(sb->sb_dblocks), + &mp->m_maxagi); + if (error) + goto out_release; + } + + xfs_sb_from_disk(&mp->m_sb, sb); + } } /* diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c index a1e18b24971a28eedcf79b4d43b16778b42133f8..7606ce475088edb0268c4cb7ca207a0d315e5e5d 100644 --- a/fs/xfs/xfs_log_recover.c +++ b/fs/xfs/xfs_log_recover.c @@ -1900,6 +1900,9 @@ xlog_recover_reorder_trans( case XLOG_REORDER_BUFFER_LIST: list_move_tail(&item->ri_list, &buffer_list); break; + case XLOG_REORDER_SB_BUFFER_LIST: + list_move(&item->ri_list, &buffer_list); + break; case XLOG_REORDER_CANCEL_LIST: trace_xfs_log_recover_item_reorder_head(log, trans, item, pass); @@ -1963,6 +1966,25 @@ xlog_recover_items_pass2( return error; } +#define XLOG_RECOVER_COMMIT_QUEUE_MAX 100 +static inline bool +xlog_recover_should_pass2( + struct xlog_recover_item *item, + int items_queued) +{ + struct xfs_buf_log_format *buf_f; + + if (items_queued >= XLOG_RECOVER_COMMIT_QUEUE_MAX) + return true; + if (ITEM_TYPE(item) == XFS_LI_BUF) { + buf_f = item->ri_buf[0].i_addr; + if (buf_f->blf_blkno == XFS_SB_DADDR) + return true; + } + + return false; +} + /* * Perform the transaction. * @@ -1983,8 +2005,6 @@ xlog_recover_commit_trans( LIST_HEAD (ra_list); LIST_HEAD (done_list); - #define XLOG_RECOVER_COMMIT_QUEUE_MAX 100 - hlist_del_init(&trans->r_list); error = xlog_recover_reorder_trans(log, trans, pass); @@ -2004,7 +2024,7 @@ xlog_recover_commit_trans( item->ri_ops->ra_pass2(log, item); list_move_tail(&item->ri_list, &ra_list); items_queued++; - if (items_queued >= XLOG_RECOVER_COMMIT_QUEUE_MAX) { + if (xlog_recover_should_pass2(item, items_queued)) { error = xlog_recover_items_pass2(log, trans, buffer_list, &ra_list); list_splice_tail_init(&ra_list, &done_list); diff --git a/fs/xfs/xfs_trans.c b/fs/xfs/xfs_trans.c index 8c0bfc9a33b116cd74606daa2d6de4fc8362f004..1ec339ca50531cf4f831de406845552d9eaa580b 100644 --- a/fs/xfs/xfs_trans.c +++ b/fs/xfs/xfs_trans.c @@ -24,6 +24,7 @@ #include "xfs_dquot_item.h" #include "xfs_dquot.h" #include "xfs_icache.h" +#include "xfs_buf_item.h" struct kmem_cache *xfs_trans_cache; @@ -476,9 +477,12 @@ xfs_trans_apply_sb_deltas( { struct xfs_dsb *sbp; struct xfs_buf *bp; + struct xfs_buf_log_item *bip; int whole = 0; + int grow = 0; bp = xfs_trans_getsb(tp); + bip = bp->b_log_item; sbp = bp->b_addr; /* @@ -524,10 +528,12 @@ xfs_trans_apply_sb_deltas( if (tp->t_dblocks_delta) { be64_add_cpu(&sbp->sb_dblocks, tp->t_dblocks_delta); whole = 1; + grow = 1; } if (tp->t_agcount_delta) { be32_add_cpu(&sbp->sb_agcount, tp->t_agcount_delta); whole = 1; + grow = 1; } if (tp->t_imaxpct_delta) { sbp->sb_imax_pct += tp->t_imaxpct_delta; @@ -555,6 +561,8 @@ xfs_trans_apply_sb_deltas( } xfs_trans_buf_set_type(tp, bp, XFS_BLFT_SB_BUF); + if (grow) + bip->bli_flags |= XFS_BLI_GROW_SB_BUF; if (whole) /* * Log the whole thing, the fields are noncontiguous.