@@ -293,6 +293,67 @@ xfs_update_last_ag_size(
return 0;
}
+static int
+xfs_perag_alloc(
+ struct xfs_mount *mp,
+ xfs_agnumber_t index,
+ xfs_agnumber_t agcount,
+ xfs_rfsblock_t dblocks)
+{
+ struct xfs_perag *pag;
+ int error;
+
+ pag = kzalloc(sizeof(*pag), GFP_KERNEL);
+ if (!pag)
+ return -ENOMEM;
+
+ pag->pag_agno = index;
+ pag->pag_mount = mp;
+
+ error = xa_insert(&mp->m_perags, index, pag, GFP_KERNEL);
+ if (error) {
+ WARN_ON_ONCE(error == -EBUSY);
+ goto out_free_pag;
+ }
+
+#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, agcount, dblocks);
+ pag->min_block = XFS_AGFL_BLOCK(mp);
+ __xfs_agino_range(mp, pag->block_count, &pag->agino_min,
+ &pag->agino_max);
+
+ return 0;
+
+out_remove_pag:
+ xfs_defer_drain_free(&pag->pag_intents_drain);
+ pag = xa_erase(&mp->m_perags, index);
+out_free_pag:
+ kfree(pag);
+ return error;
+}
+
int
xfs_initialize_perag(
struct xfs_mount *mp,
@@ -301,68 +362,22 @@ xfs_initialize_perag(
xfs_rfsblock_t dblocks,
xfs_agnumber_t *maxagi)
{
- struct xfs_perag *pag;
xfs_agnumber_t index;
int error;
+ if (orig_agcount >= new_agcount)
+ return 0;
+
for (index = orig_agcount; index < new_agcount; index++) {
- pag = kzalloc(sizeof(*pag), GFP_KERNEL);
- if (!pag) {
- error = -ENOMEM;
+ error = xfs_perag_alloc(mp, index, new_agcount, dblocks);
+ if (error)
goto out_unwind_new_pags;
- }
- pag->pag_agno = index;
- pag->pag_mount = mp;
-
- error = xa_insert(&mp->m_perags, index, pag, GFP_KERNEL);
- if (error) {
- WARN_ON_ONCE(error == -EBUSY);
- goto out_free_pag;
- }
-
-#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);
}
- index = xfs_set_inode_alloc(mp, new_agcount);
-
- if (maxagi)
- *maxagi = index;
-
+ *maxagi = xfs_set_inode_alloc(mp, new_agcount);
mp->m_ag_prealloc_blocks = xfs_prealloc_blocks(mp);
return 0;
-out_remove_pag:
- xfs_defer_drain_free(&pag->pag_intents_drain);
- pag = xa_erase(&mp->m_perags, index);
-out_free_pag:
- kfree(pag);
out_unwind_new_pags:
xfs_free_perag_range(mp, orig_agcount, index);
return error;