xfs: split xfs_initialize_perag

Factor out a xfs_perag_alloc helper that allocates a single perag
structure.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Darrick J. Wong <djwong@kernel.org>
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
This commit is contained in:
Christoph Hellwig 2024-11-03 20:18:36 -08:00 committed by Darrick J. Wong
parent c4ae021bcb
commit 201c5fa342
3 changed files with 76 additions and 58 deletions

View File

@ -272,6 +272,10 @@ xfs_agino_range(
return __xfs_agino_range(mp, xfs_ag_block_count(mp, agno), first, last);
}
/*
* Update the perag of the previous tail AG if it has been changed during
* recovery (i.e. recovery of a growfs).
*/
int
xfs_update_last_ag_size(
struct xfs_mount *mp,
@ -289,69 +293,57 @@ xfs_update_last_ag_size(
return 0;
}
int
xfs_initialize_perag(
static int
xfs_perag_alloc(
struct xfs_mount *mp,
xfs_agnumber_t old_agcount,
xfs_agnumber_t new_agcount,
xfs_rfsblock_t dblocks,
xfs_agnumber_t *maxagi)
xfs_agnumber_t index,
xfs_agnumber_t agcount,
xfs_rfsblock_t dblocks)
{
struct xfs_perag *pag;
xfs_agnumber_t index;
int error;
for (index = old_agcount; index < new_agcount; index++) {
pag = kzalloc(sizeof(*pag), GFP_KERNEL);
if (!pag) {
error = -ENOMEM;
goto out_unwind_new_pags;
}
pag->pag_agno = index;
pag->pag_mount = mp;
pag = kzalloc(sizeof(*pag), GFP_KERNEL);
if (!pag)
return -ENOMEM;
error = xa_insert(&mp->m_perags, index, pag, GFP_KERNEL);
if (error) {
WARN_ON_ONCE(error == -EBUSY);
goto out_free_pag;
}
pag->pag_agno = index;
pag->pag_mount = mp;
#ifdef __KERNEL__
/* Place kernel structure only init below this point. */
spin_lock_init(&pag->pag_ici_lock);
spin_lock_init(&pag->pagb_lock);
spin_lock_init(&pag->pag_state_lock);
INIT_DELAYED_WORK(&pag->pag_blockgc_work, xfs_blockgc_worker);
INIT_RADIX_TREE(&pag->pag_ici_root, GFP_ATOMIC);
xfs_defer_drain_init(&pag->pag_intents_drain);
init_waitqueue_head(&pag->pagb_wait);
pag->pagb_tree = RB_ROOT;
xfs_hooks_init(&pag->pag_rmap_update_hooks);
#endif /* __KERNEL__ */
error = xfs_buf_cache_init(&pag->pag_bcache);
if (error)
goto out_remove_pag;
/* Active ref owned by mount indicates AG is online. */
atomic_set(&pag->pag_active_ref, 1);
/*
* Pre-calculated geometry
*/
pag->block_count = __xfs_ag_block_count(mp, index, new_agcount,
dblocks);
pag->min_block = XFS_AGFL_BLOCK(mp);
__xfs_agino_range(mp, pag->block_count, &pag->agino_min,
&pag->agino_max);
error = xa_insert(&mp->m_perags, index, pag, GFP_KERNEL);
if (error) {
WARN_ON_ONCE(error == -EBUSY);
goto out_free_pag;
}
index = xfs_set_inode_alloc(mp, new_agcount);
#ifdef __KERNEL__
/* Place kernel structure only init below this point. */
spin_lock_init(&pag->pag_ici_lock);
spin_lock_init(&pag->pagb_lock);
spin_lock_init(&pag->pag_state_lock);
INIT_DELAYED_WORK(&pag->pag_blockgc_work, xfs_blockgc_worker);
INIT_RADIX_TREE(&pag->pag_ici_root, GFP_ATOMIC);
xfs_defer_drain_init(&pag->pag_intents_drain);
init_waitqueue_head(&pag->pagb_wait);
pag->pagb_tree = RB_ROOT;
xfs_hooks_init(&pag->pag_rmap_update_hooks);
#endif /* __KERNEL__ */
if (maxagi)
*maxagi = index;
error = xfs_buf_cache_init(&pag->pag_bcache);
if (error)
goto out_remove_pag;
/* Active ref owned by mount indicates AG is online. */
atomic_set(&pag->pag_active_ref, 1);
/*
* Pre-calculated geometry
*/
pag->block_count = __xfs_ag_block_count(mp, index, agcount, dblocks);
pag->min_block = XFS_AGFL_BLOCK(mp);
__xfs_agino_range(mp, pag->block_count, &pag->agino_min,
&pag->agino_max);
mp->m_ag_prealloc_blocks = xfs_prealloc_blocks(mp);
return 0;
out_remove_pag:
@ -359,8 +351,35 @@ out_remove_pag:
pag = xa_erase(&mp->m_perags, index);
out_free_pag:
kfree(pag);
return error;
}
int
xfs_initialize_perag(
struct xfs_mount *mp,
xfs_agnumber_t orig_agcount,
xfs_agnumber_t new_agcount,
xfs_rfsblock_t dblocks,
xfs_agnumber_t *maxagi)
{
xfs_agnumber_t index;
int error;
if (orig_agcount >= new_agcount)
return 0;
for (index = orig_agcount; index < new_agcount; index++) {
error = xfs_perag_alloc(mp, index, new_agcount, dblocks);
if (error)
goto out_unwind_new_pags;
}
*maxagi = xfs_set_inode_alloc(mp, new_agcount);
mp->m_ag_prealloc_blocks = xfs_prealloc_blocks(mp);
return 0;
out_unwind_new_pags:
xfs_free_perag_range(mp, old_agcount, index);
xfs_free_perag_range(mp, orig_agcount, index);
return error;
}

View File

@ -142,8 +142,8 @@ __XFS_AG_OPSTATE(prefers_metadata, PREFERS_METADATA)
__XFS_AG_OPSTATE(allows_inodes, ALLOWS_INODES)
__XFS_AG_OPSTATE(agfl_needs_reset, AGFL_NEEDS_RESET)
int xfs_initialize_perag(struct xfs_mount *mp, xfs_agnumber_t old_agcount,
xfs_agnumber_t agcount, xfs_rfsblock_t dcount,
int xfs_initialize_perag(struct xfs_mount *mp, xfs_agnumber_t orig_agcount,
xfs_agnumber_t new_agcount, xfs_rfsblock_t dcount,
xfs_agnumber_t *maxagi);
void xfs_free_perag_range(struct xfs_mount *mp, xfs_agnumber_t first_agno,
xfs_agnumber_t end_agno);

View File

@ -724,9 +724,8 @@ xlog_recover_do_primary_sb_buffer(
}
/*
* 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.
* If the last AG was grown or shrunk, 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)