mirror of
https://github.com/torvalds/linux.git
synced 2024-11-21 19:41:42 +00:00
xfs: update the pag for the last AG at recovery time
Currently log recovery never updates the in-core perag values for the last allocation group when they were grown by growfs. This leads to btree record validation failures for the alloc, ialloc or finotbt trees if a transaction references this new space. Found by Brian's new growfs recovery stress test. Signed-off-by: Christoph Hellwig <hch@lst.de> Reviewed-by: Brian Foster <bfoster@redhat.com> Signed-off-by: Carlos Maiolino <cem@kernel.org>
This commit is contained in:
parent
069cf5e32b
commit
4a201dcfa1
@ -273,6 +273,23 @@ xfs_agino_range(
|
||||
return __xfs_agino_range(mp, xfs_ag_block_count(mp, agno), first, last);
|
||||
}
|
||||
|
||||
int
|
||||
xfs_update_last_ag_size(
|
||||
struct xfs_mount *mp,
|
||||
xfs_agnumber_t prev_agcount)
|
||||
{
|
||||
struct xfs_perag *pag = xfs_perag_grab(mp, prev_agcount - 1);
|
||||
|
||||
if (!pag)
|
||||
return -EFSCORRUPTED;
|
||||
pag->block_count = __xfs_ag_block_count(mp, prev_agcount - 1,
|
||||
mp->m_sb.sb_agcount, mp->m_sb.sb_dblocks);
|
||||
__xfs_agino_range(mp, pag->block_count, &pag->agino_min,
|
||||
&pag->agino_max);
|
||||
xfs_perag_rele(pag);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
xfs_initialize_perag(
|
||||
struct xfs_mount *mp,
|
||||
|
@ -150,6 +150,7 @@ int xfs_initialize_perag(struct xfs_mount *mp, xfs_agnumber_t old_agcount,
|
||||
void xfs_free_perag_range(struct xfs_mount *mp, xfs_agnumber_t first_agno,
|
||||
xfs_agnumber_t end_agno);
|
||||
int xfs_initialize_perag_data(struct xfs_mount *mp, xfs_agnumber_t agno);
|
||||
int xfs_update_last_ag_size(struct xfs_mount *mp, xfs_agnumber_t prev_agcount);
|
||||
|
||||
/* Passive AG references */
|
||||
struct xfs_perag *xfs_perag_get(struct xfs_mount *mp, xfs_agnumber_t agno);
|
||||
|
@ -708,6 +708,11 @@ xlog_recover_do_primary_sb_buffer(
|
||||
|
||||
xlog_recover_do_reg_buffer(mp, item, bp, buf_f, current_lsn);
|
||||
|
||||
if (orig_agcount == 0) {
|
||||
xfs_alert(mp, "Trying to grow file system without AGs");
|
||||
return -EFSCORRUPTED;
|
||||
}
|
||||
|
||||
/*
|
||||
* Update the in-core super block from the freshly recovered on-disk one.
|
||||
*/
|
||||
@ -718,15 +723,23 @@ xlog_recover_do_primary_sb_buffer(
|
||||
return -EFSCORRUPTED;
|
||||
}
|
||||
|
||||
/*
|
||||
* Growfs can also grow the last existing AG. In this case we also need
|
||||
* to update the length in the in-core perag structure and values
|
||||
* depending on it.
|
||||
*/
|
||||
error = xfs_update_last_ag_size(mp, orig_agcount);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
/*
|
||||
* Initialize the new perags, and also update various block and inode
|
||||
* allocator setting based off the number of AGs or total blocks.
|
||||
* Because of the latter this also needs to happen if the agcount did
|
||||
* not change.
|
||||
*/
|
||||
error = xfs_initialize_perag(mp, orig_agcount,
|
||||
mp->m_sb.sb_agcount, mp->m_sb.sb_dblocks,
|
||||
&mp->m_maxagi);
|
||||
error = xfs_initialize_perag(mp, orig_agcount, mp->m_sb.sb_agcount,
|
||||
mp->m_sb.sb_dblocks, &mp->m_maxagi);
|
||||
if (error) {
|
||||
xfs_warn(mp, "Failed recovery per-ag init: %d", error);
|
||||
return error;
|
||||
|
Loading…
Reference in New Issue
Block a user