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);
|
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
|
int
|
||||||
xfs_initialize_perag(
|
xfs_initialize_perag(
|
||||||
struct xfs_mount *mp,
|
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,
|
void xfs_free_perag_range(struct xfs_mount *mp, xfs_agnumber_t first_agno,
|
||||||
xfs_agnumber_t end_agno);
|
xfs_agnumber_t end_agno);
|
||||||
int xfs_initialize_perag_data(struct xfs_mount *mp, xfs_agnumber_t 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 */
|
/* Passive AG references */
|
||||||
struct xfs_perag *xfs_perag_get(struct xfs_mount *mp, xfs_agnumber_t agno);
|
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);
|
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.
|
* 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;
|
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
|
* Initialize the new perags, and also update various block and inode
|
||||||
* allocator setting based off the number of AGs or total blocks.
|
* allocator setting based off the number of AGs or total blocks.
|
||||||
* Because of the latter this also needs to happen if the agcount did
|
* Because of the latter this also needs to happen if the agcount did
|
||||||
* not change.
|
* not change.
|
||||||
*/
|
*/
|
||||||
error = xfs_initialize_perag(mp, orig_agcount,
|
error = xfs_initialize_perag(mp, orig_agcount, mp->m_sb.sb_agcount,
|
||||||
mp->m_sb.sb_agcount, mp->m_sb.sb_dblocks,
|
mp->m_sb.sb_dblocks, &mp->m_maxagi);
|
||||||
&mp->m_maxagi);
|
|
||||||
if (error) {
|
if (error) {
|
||||||
xfs_warn(mp, "Failed recovery per-ag init: %d", error);
|
xfs_warn(mp, "Failed recovery per-ag init: %d", error);
|
||||||
return error;
|
return error;
|
||||||
|
Loading…
Reference in New Issue
Block a user