xfs: refactor and tablise growfs
v3 cover xfs: refactor and tablise growfs
THis is the third version of the growfs tablisation patchset, addressing the changes that Darrick raised. I've reposted the entire patchset because changes in early patches cascaded throw several others and it was just easier to repost the lot.
Version 3:
- fix agno variable to use xfs_agnumber_t
- change ag header table to use expanded definitions
- dropped numrecs from tables as they are always either zero or hard coded by type specific block initialisers.
Version 2:
- rebase on current for-next
- add oneshot cached buffer support
- clean up more of the typedef usage.
- move id->nfree calc to per-ag hdr init function from the freespace btree root initialisation.
- only use id->type and id->numrecs for the generic btree root block init calls.
- only call xfs_growfs_data_private() if the size is actually being changed.
- make sure we still update secondary superblocks if physical grow fails with ENOSPC.
- change secondary superblock updates to use cached one-shot buffers.
- moved the core code to libxfs so it can be shared easily with userspace.
Version 1:
https://marc.info/?l=linux-xfs&m=151746732826277&w=2
PATCH v3 1/10 xfs: one-shot cached buffers
From: Dave Chinner <[email protected]>
For the new growfs work, we want to ensure that we serialise secondary superblock updates with other operations (e.g. scrub) correctly, but we don't want to cache the buffers for long term reuse. We need cached buffers for serialisation, however.
To solve this, introduce a "oneshot" buffer which will be marshalled through the cache but then released once the last current reference goes away. If the buffer is already cached, then we ignore the "one-shot" behaviour and leave the buffer in the state it was prior to the one-shot command being run. This means we don't perturb either the working set or existing cached buffer state by a one-shot operation.
--- fs/xfs/xfs_buf.h | 12 ++++++++++++ 1 file changed, 12 insertions(+)
fs/xfs/xfs_buf.h +12 -0
@@ -347,6 +347,18 @@ extern void xfs_buf_terminate(void);void xfs_buf_set_ref (struct xfs_buf *bp,int lru_ref); +/* +* If the buffer is already on the LRU, do nothing. Otherwise set the buffer +* up with a reference count of 0 so it will be tossed from the cache when +* released. +*/ +static inline void xfs_buf_oneshot (struct xfs_buf *bp) +{ +if (!list_empty (&bp->b_lru) ||atomic_read (&bp->b_lru_ref) >1 ) +return ; +atomic_set (&bp->b_lru_ref,0 ); +} +static inline int xfs_buf_ispinned (struct xfs_buf *bp) {return atomic_read (&bp->b_pin_count);
Signature · 1 line
2.17.0
PATCH v3 2/10 xfs: factor out AG header initialisation from growfs core
In reply to Dave ChinnerFrom: Dave Chinner <[email protected]>
The intialisation of new AG headers is mostly common with the userspace mkfs code and growfs in the kernel, so start factoring it out so we can move it to libxfs and use it in both places.
--- fs/xfs/xfs_fsops.c | 637 +++++++++++++++++++++++---------------------- 1 file changed, 331 insertions(+), 306 deletions(-)
fs/xfs/xfs_fsops.c +331 -306
@@ -71,20 +71,344 @@ xfs_growfs_get_hdr_buf(return bp; } +/* +* Write new AG headers to disk. Non-transactional, but written +* synchronously so they are completed prior to the growfs transaction +* being logged. +*/ +static int +xfs_grow_ag_headers ( +struct xfs_mount *mp, +xfs_agnumber_t agno, +xfs_extlen_t agsize, +xfs_rfsblock_t *nfree) +{ +struct xfs_agf *agf; +struct xfs_agi *agi; +struct xfs_agfl *agfl; +__be32 *agfl_bno; +xfs_alloc_rec_t *arec; +struct xfs_buf *bp; +int bucket; +xfs_extlen_t tmpsize; +int error =0 ; + +/* +* AG freespace header block +*/ + bp =xfs_growfs_get_hdr_buf (mp, +XFS_AG_DADDR (mp, agno,XFS_AGF_DADDR (mp)), +XFS_FSS_TO_BB (mp,1 ),0 , + &xfs_agf_buf_ops); +if (!bp) { + error = -ENOMEM ; + goto out_error; + } + + agf =XFS_BUF_TO_AGF (bp); + agf->agf_magicnum =cpu_to_be32 (XFS_AGF_MAGIC ); + agf->agf_versionnum =cpu_to_be32 (XFS_AGF_VERSION ); + agf->agf_seqno =cpu_to_be32 (agno); + agf->agf_length =cpu_to_be32 (agsize); + agf->agf_roots[XFS_BTNUM_BNOi] =cpu_to_be32 (XFS_BNO_BLOCK (mp)); + agf->agf_roots[XFS_BTNUM_CNTi] =cpu_to_be32 (XFS_CNT_BLOCK (mp)); + agf->agf_levels[XFS_BTNUM_BNOi] =cpu_to_be32 (1 ); + agf->agf_levels[XFS_BTNUM_CNTi] =cpu_to_be32 (1 ); +if (xfs_sb_version_hasrmapbt (&mp->m_sb)) { + agf->agf_roots[XFS_BTNUM_RMAPi] = +cpu_to_be32 (XFS_RMAP_BLOCK (mp)); + agf->agf_levels[XFS_BTNUM_RMAPi] =cpu_to_be32 (1 ); + agf->agf_rmap_blocks =cpu_to_be32 (1 ); + } + + agf->agf_flfirst =cpu_to_be32 (1 ); + agf->agf_fllast =0 ; + agf->agf_flcount =0 ; + tmpsize = agsize - mp->m_ag_prealloc_blocks; + agf->agf_freeblks =cpu_to_be32 (tmpsize); + agf->agf_longest =cpu_to_be32 (tmpsize); +if (xfs_sb_version_hascrc (&mp->m_sb)) +uuid_copy (&agf->agf_uuid, &mp->m_sb.sb_meta_uuid); +if (xfs_sb_version_hasreflink (&mp->m_sb)) { + agf->agf_refcount_root =cpu_to_be32 ( +xfs_refc_block (mp)); + agf->agf_refcount_level =cpu_to_be32 (1 ); + agf->agf_refcount_blocks =cpu_to_be32 (1 ); + } + + error =xfs_bwrite (bp); +xfs_buf_relse (bp); +if (error) + goto out_error; + +/* +* AG freelist header block +*/ + bp =xfs_growfs_get_hdr_buf (mp, +XFS_AG_DADDR (mp, agno,XFS_AGFL_DADDR (mp)), +XFS_FSS_TO_BB (mp,1 ),0 , + &xfs_agfl_buf_ops); +if (!bp) { + error = -ENOMEM ; + goto out_error; + } + + agfl =XFS_BUF_TO_AGFL (bp); +if (xfs_sb_version_hascrc (&mp->m_sb)) { + agfl->agfl_magicnum =cpu_to_be32 (XFS_AGFL_MAGIC ); + agfl->agfl_seqno =cpu_to_be32 (agno); +uuid_copy (&agfl->agfl_uuid, &mp->m_sb.sb_meta_uuid); + } + + agfl_bno =XFS_BUF_TO_AGFL_BNO (mp, bp); +for (bucket =0 ; bucket <xfs_agfl_size (mp); bucket++) + agfl_bno[bucket] =cpu_to_be32 (NULLAGBLOCK ); + + error =xfs_bwrite (bp); +xfs_buf_relse (bp); +if (error) + goto out_error; + +/* +* AG inode header block +*/ + bp =xfs_growfs_get_hdr_buf (mp, +XFS_AG_DADDR (mp, agno,XFS_AGI_DADDR (mp)), +XFS_FSS_TO_BB (mp,1 ),0 , + &xfs_agi_buf_ops); +if (!bp) { + error = -ENOMEM ; + goto out_error; + } + + agi =XFS_BUF_TO_AGI (bp); + agi->agi_magicnum =cpu_to_be32 (XFS_AGI_MAGIC ); + agi->agi_versionnum =cpu_to_be32 (XFS_AGI_VERSION ); + agi->agi_seqno =cpu_to_be32 (agno); + agi->agi_length =cpu_to_be32 (agsize); + agi->agi_count =0 ; + agi->agi_root =cpu_to_be32 (XFS_IBT_BLOCK (mp)); + agi->agi_level =cpu_to_be32 (1 ); + agi->agi_freecount =0 ; + agi->agi_newino =cpu_to_be32 (NULLAGINO ); + agi->agi_dirino =cpu_to_be32 (NULLAGINO ); +if (xfs_sb_version_hascrc (&mp->m_sb)) +uuid_copy (&agi->agi_uuid, &mp->m_sb.sb_meta_uuid); +if (xfs_sb_version_hasfinobt (&mp->m_sb)) { + agi->agi_free_root =cpu_to_be32 (XFS_FIBT_BLOCK (mp)); + agi->agi_free_level =cpu_to_be32 (1 ); + } +for (bucket =0 ; bucket <XFS_AGI_UNLINKED_BUCKETS ; bucket++) + agi->agi_unlinked[bucket] =cpu_to_be32 (NULLAGINO ); + + error =xfs_bwrite (bp); +xfs_buf_relse (bp); +if (error) + goto out_error; + +/* +* BNO btree root block +*/ + bp =xfs_growfs_get_hdr_buf (mp, +XFS_AGB_TO_DADDR (mp, agno,XFS_BNO_BLOCK (mp)), +BTOBB (mp->m_sb.sb_blocksize),0 , + &xfs_allocbt_buf_ops); + +if (!bp) { + error = -ENOMEM ; + goto out_error; + } + +xfs_btree_init_block (mp, bp,XFS_BTNUM_BNO ,0 ,1 , agno,0 ); + + arec =XFS_ALLOC_REC_ADDR (mp,XFS_BUF_TO_BLOCK (bp),1 ); + arec->ar_startblock =cpu_to_be32 (mp->m_ag_prealloc_blocks); + arec->ar_blockcount =cpu_to_be32 ( + agsize -be32_to_cpu (arec->ar_startblock)); + + error =xfs_bwrite (bp); +xfs_buf_relse (bp); +if (error) + goto out_error; + +/* +* CNT btree root block +*/ + bp =xfs_growfs_get_hdr_buf (mp, +XFS_AGB_TO_DADDR (mp, agno,XFS_CNT_BLOCK (mp)), +BTOBB (mp->m_sb.sb_blocksize),0 , + &xfs_allocbt_buf_ops); +if (!bp) { + error = -ENOMEM ; + goto out_error; + } + +xfs_btree_init_block (mp, bp,XFS_BTNUM_CNT ,0 ,1 , agno,0 ); + + arec =XFS_ALLOC_REC_ADDR (mp,XFS_BUF_TO_BLOCK (bp),1 ); + arec->ar_startblock =cpu_to_be32 (mp->m_ag_prealloc_blocks); + arec->ar_blockcount =cpu_to_be32 ( + agsize -be32_to_cpu (arec->ar_startblock)); + *nfree +=be32_to_cpu (arec->ar_blockcount); + + error =xfs_bwrite (bp); +xfs_buf_relse (bp); +if (error) + goto out_error; + +/* RMAP btree root block */ +if (xfs_sb_version_hasrmapbt (&mp->m_sb)) { +struct xfs_rmap_rec *rrec; +struct xfs_btree_block *block; + + bp =xfs_growfs_get_hdr_buf (mp, +XFS_AGB_TO_DADDR (mp, agno,XFS_RMAP_BLOCK (mp)), +BTOBB (mp->m_sb.sb_blocksize),0 , + &xfs_rmapbt_buf_ops); +if (!bp) { + error = -ENOMEM ; + goto out_error; + } + +xfs_btree_init_block (mp, bp,XFS_BTNUM_RMAP ,0 ,0 , + agno,0 ); + block =XFS_BUF_TO_BLOCK (bp); + + +/* +* mark the AG header regions as static metadata The BNO +* btree block is the first block after the headers, so +* it's location defines the size of region the static +* metadata consumes. +* +* Note: unlike mkfs, we never have to account for log +* space when growing the data regions +*/ + rrec =XFS_RMAP_REC_ADDR (block,1 ); + rrec->rm_startblock =0 ; + rrec->rm_blockcount =cpu_to_be32 (XFS_BNO_BLOCK (mp)); + rrec->rm_owner =cpu_to_be64 (XFS_RMAP_OWN_FS ); + rrec->rm_offset =0 ; +be16_add_cpu (&block->bb_numrecs,1 ); + +/* account freespace btree root blocks */ + rrec =XFS_RMAP_REC_ADDR (block,2 ); + rrec->rm_startblock =cpu_to_be32 (XFS_BNO_BLOCK (mp)); + rrec->rm_blockcount =cpu_to_be32 (2 ); + rrec->rm_owner =cpu_to_be64 (XFS_RMAP_OWN_AG ); + rrec->rm_offset =0 ; +be16_add_cpu (&block->bb_numrecs,1 ); + +/* account inode btree root blocks */ + rrec =XFS_RMAP_REC_ADDR (block,3 ); + rrec->rm_startblock =cpu_to_be32 (XFS_IBT_BLOCK (mp)); + rrec->rm_blockcount =cpu_to_be32 (XFS_RMAP_BLOCK (mp) - +XFS_IBT_BLOCK (mp)); + rrec->rm_owner =cpu_to_be64 (XFS_RMAP_OWN_INOBT ); + rrec->rm_offset =0 ; +be16_add_cpu (&block->bb_numrecs,1 ); + +/* account for rmap btree root */ + rrec =XFS_RMAP_REC_ADDR (block,4 ); + rrec->rm_startblock =cpu_to_be32 (XFS_RMAP_BLOCK (mp)); + rrec->rm_blockcount =cpu_to_be32 (1 ); + rrec->rm_owner =cpu_to_be64 (XFS_RMAP_OWN_AG ); + rrec->rm_offset =0 ; +be16_add_cpu (&block->bb_numrecs,1 ); + +/* account for refc btree root */ +if (xfs_sb_version_hasreflink (&mp->m_sb)) { + rrec =XFS_RMAP_REC_ADDR (block,5 ); + rrec->rm_startblock =cpu_to_be32 (xfs_refc_block (mp)); + rrec->rm_blockcount =cpu_to_be32 (1 ); + rrec->rm_owner =cpu_to_be64 (XFS_RMAP_OWN_REFC ); + rrec->rm_offset =0 ; +be16_add_cpu (&block->bb_numrecs,1 ); + } + + error =xfs_bwrite (bp); +xfs_buf_relse (bp); +if (error) + goto out_error; + } + +/* +* INO btree root block +*/ + bp =xfs_growfs_get_hdr_buf (mp, +XFS_AGB_TO_DADDR (mp, agno,XFS_IBT_BLOCK (mp)), +BTOBB (mp->m_sb.sb_blocksize),0 , + &xfs_inobt_buf_ops); +if (!bp) { + error = -ENOMEM ; + goto out_error; + } + +xfs_btree_init_block (mp, bp,XFS_BTNUM_INO ,0 ,0 , agno,0 ); + + error =xfs_bwrite (bp); +xfs_buf_relse (bp); +if (error) + goto out_error; + +/* +* FINO btree root block +*/ +if (xfs_sb_version_hasfinobt (&mp->m_sb)) { + bp =xfs_growfs_get_hdr_buf (mp, +XFS_AGB_TO_DADDR (mp, agno,XFS_FIBT_BLOCK (mp)), +BTOBB (mp->m_sb.sb_blocksize),0 , + &xfs_inobt_buf_ops); +if (!bp) { + error = -ENOMEM ; + goto out_error; + } + +xfs_btree_init_block (mp, bp,XFS_BTNUM_FINO , +0 ,0 , agno,0 ); + + error =xfs_bwrite (bp); +xfs_buf_relse (bp); +if (error) + goto out_error; + } + +/* +* refcount btree root block +*/ +if (xfs_sb_version_hasreflink (&mp->m_sb)) { + bp =xfs_growfs_get_hdr_buf (mp, +XFS_AGB_TO_DADDR (mp, agno,xfs_refc_block (mp)), +BTOBB (mp->m_sb.sb_blocksize),0 , + &xfs_refcountbt_buf_ops); +if (!bp) { + error = -ENOMEM ; + goto out_error; + } + +xfs_btree_init_block (mp, bp,XFS_BTNUM_REFC , +0 ,0 , agno,0 ); + + error =xfs_bwrite (bp); +xfs_buf_relse (bp); +if (error) + goto out_error; + } + +out_error: +return error; +} +static int xfs_growfs_data_private (xfs_mount_t *mp,/* mount point for filesystem */ xfs_growfs_data_t *in)/* growfs data input struct */ {xfs_agf_t *agf; -struct xfs_agfl *agfl;xfs_agi_t *agi;xfs_agnumber_t agno;xfs_extlen_t agsize; -xfs_extlen_t tmpsize; -xfs_alloc_rec_t *arec;xfs_buf_t *bp; -int bucket;int dpct;int error, saved_error =0 ;xfs_agnumber_t nagcount;
@@ -141,318 +465,19 @@ xfs_growfs_data_private(*/ nfree =0 ;for (agno = nagcount -1 ; agno >= oagcount; agno--, new -= agsize) { -__be32 *agfl_bno; - -/* -* AG freespace header block -*/ - bp =xfs_growfs_get_hdr_buf (mp, -XFS_AG_DADDR (mp, agno,XFS_AGF_DADDR (mp)), -XFS_FSS_TO_BB (mp,1 ),0 , - &xfs_agf_buf_ops); -if (!bp) { - error = -ENOMEM ; - goto error0; - } - agf =XFS_BUF_TO_AGF (bp); - agf->agf_magicnum =cpu_to_be32 (XFS_AGF_MAGIC ); - agf->agf_versionnum =cpu_to_be32 (XFS_AGF_VERSION ); - agf->agf_seqno =cpu_to_be32 (agno);if (agno == nagcount -1 ) - agsize = - nb - + agsize = nb - (agno * (xfs_rfsblock_t )mp->m_sb.sb_agblocks);else agsize = mp->m_sb.sb_agblocks; - agf->agf_length =cpu_to_be32 (agsize); - agf->agf_roots[XFS_BTNUM_BNOi] =cpu_to_be32 (XFS_BNO_BLOCK (mp)); - agf->agf_roots[XFS_BTNUM_CNTi] =cpu_to_be32 (XFS_CNT_BLOCK (mp)); - agf->agf_levels[XFS_BTNUM_BNOi] =cpu_to_be32 (1 ); - agf->agf_levels[XFS_BTNUM_CNTi] =cpu_to_be32 (1 ); -if (xfs_sb_version_hasrmapbt (&mp->m_sb)) { - agf->agf_roots[XFS_BTNUM_RMAPi] = -cpu_to_be32 (XFS_RMAP_BLOCK (mp)); - agf->agf_levels[XFS_BTNUM_RMAPi] =cpu_to_be32 (1 ); - agf->agf_rmap_blocks =cpu_to_be32 (1 ); - } - - agf->agf_flfirst =cpu_to_be32 (1 ); - agf->agf_fllast =0 ; - agf->agf_flcount =0 ; - tmpsize = agsize - mp->m_ag_prealloc_blocks; - agf->agf_freeblks =cpu_to_be32 (tmpsize); - agf->agf_longest =cpu_to_be32 (tmpsize); -if (xfs_sb_version_hascrc (&mp->m_sb)) -uuid_copy (&agf->agf_uuid, &mp->m_sb.sb_meta_uuid); -if (xfs_sb_version_hasreflink (&mp->m_sb)) { - agf->agf_refcount_root =cpu_to_be32 ( -xfs_refc_block (mp)); - agf->agf_refcount_level =cpu_to_be32 (1 ); - agf->agf_refcount_blocks =cpu_to_be32 (1 ); - } - - error =xfs_bwrite (bp); -xfs_buf_relse (bp); -if (error) - goto error0; - -/* -* AG freelist header block -*/ - bp =xfs_growfs_get_hdr_buf (mp, -XFS_AG_DADDR (mp, agno,XFS_AGFL_DADDR (mp)), -XFS_FSS_TO_BB (mp,1 ),0 , - &xfs_agfl_buf_ops); -if (!bp) { - error = -ENOMEM ; - goto error0; - } - - agfl =XFS_BUF_TO_AGFL (bp); -if (xfs_sb_version_hascrc (&mp->m_sb)) { - agfl->agfl_magicnum =cpu_to_be32 (XFS_AGFL_MAGIC ); - agfl->agfl_seqno =cpu_to_be32 (agno); -uuid_copy (&agfl->agfl_uuid, &mp->m_sb.sb_meta_uuid); - } - - agfl_bno =XFS_BUF_TO_AGFL_BNO (mp, bp); -for (bucket =0 ; bucket <xfs_agfl_size (mp); bucket++) - agfl_bno[bucket] =cpu_to_be32 (NULLAGBLOCK ); - error =xfs_bwrite (bp); -xfs_buf_relse (bp); + error =xfs_grow_ag_headers (mp, agno, agsize, &nfree);if (error) goto error0; - -/* -* AG inode header block -*/ - bp =xfs_growfs_get_hdr_buf (mp, -XFS_AG_DADDR (mp, agno,XFS_AGI_DADDR (mp)), -XFS_FSS_TO_BB (mp,1 ),0 , - &xfs_agi_buf_ops); -if (!bp) { - error = -ENOMEM ; - goto error0; - } - - agi =XFS_BUF_TO_AGI (bp); - agi->agi_magicnum =cpu_to_be32 (XFS_AGI_MAGIC ); - agi->agi_versionnum =cpu_to_be32 (XFS_AGI_VERSION ); - agi->agi_seqno =cpu_to_be32 (agno); - agi->agi_length =cpu_to_be32 (agsize); - agi->agi_count =0 ; - agi->agi_root =cpu_to_be32 (XFS_IBT_BLOCK (mp)); - agi->agi_level =cpu_to_be32 (1 ); - agi->agi_freecount =0 ; - agi->agi_newino =cpu_to_be32 (NULLAGINO ); - agi->agi_dirino =cpu_to_be32 (NULLAGINO ); -if (xfs_sb_version_hascrc (&mp->m_sb)) -uuid_copy (&agi->agi_uuid, &mp->m_sb.sb_meta_uuid); -if (xfs_sb_version_hasfinobt (&mp->m_sb)) { - agi->agi_free_root =cpu_to_be32 (XFS_FIBT_BLOCK (mp)); - agi->agi_free_level =cpu_to_be32 (1 ); - } -for (bucket =0 ; bucket <XFS_AGI_UNLINKED_BUCKETS ; bucket++) - agi->agi_unlinked[bucket] =cpu_to_be32 (NULLAGINO ); - - error =xfs_bwrite (bp); -xfs_buf_relse (bp); -if (error) - goto error0; - -/* -* BNO btree root block -*/ - bp =xfs_growfs_get_hdr_buf (mp, -XFS_AGB_TO_DADDR (mp, agno,XFS_BNO_BLOCK (mp)), -BTOBB (mp->m_sb.sb_blocksize),0 , - &xfs_allocbt_buf_ops); - -if (!bp) { - error = -ENOMEM ; - goto error0; - } - -xfs_btree_init_block (mp, bp,XFS_BTNUM_BNO ,0 ,1 , agno,0 ); - - arec =XFS_ALLOC_REC_ADDR (mp,XFS_BUF_TO_BLOCK (bp),1 ); - arec->ar_startblock =cpu_to_be32 (mp->m_ag_prealloc_blocks); - arec->ar_blockcount =cpu_to_be32 ( - agsize -be32_to_cpu (arec->ar_startblock)); - - error =xfs_bwrite (bp); -xfs_buf_relse (bp); -if (error) - goto error0; - -/* -* CNT btree root block -*/ - bp =xfs_growfs_get_hdr_buf (mp, -XFS_AGB_TO_DADDR (mp, agno,XFS_CNT_BLOCK (mp)), -BTOBB (mp->m_sb.sb_blocksize),0 , - &xfs_allocbt_buf_ops); -if (!bp) { - error = -ENOMEM ; - goto error0; - } - -xfs_btree_init_block (mp, bp,XFS_BTNUM_CNT ,0 ,1 , agno,0 ); - - arec =XFS_ALLOC_REC_ADDR (mp,XFS_BUF_TO_BLOCK (bp),1 ); - arec->ar_startblock =cpu_to_be32 (mp->m_ag_prealloc_blocks); - arec->ar_blockcount =cpu_to_be32 ( - agsize -be32_to_cpu (arec->ar_startblock)); - nfree +=be32_to_cpu (arec->ar_blockcount); - - error =xfs_bwrite (bp); -xfs_buf_relse (bp); -if (error) - goto error0; - -/* RMAP btree root block */ -if (xfs_sb_version_hasrmapbt (&mp->m_sb)) { -struct xfs_rmap_rec *rrec; -struct xfs_btree_block *block; - - bp =xfs_growfs_get_hdr_buf (mp, -XFS_AGB_TO_DADDR (mp, agno,XFS_RMAP_BLOCK (mp)), -BTOBB (mp->m_sb.sb_blocksize),0 , - &xfs_rmapbt_buf_ops); -if (!bp) { - error = -ENOMEM ; - goto error0; - } - -xfs_btree_init_block (mp, bp,XFS_BTNUM_RMAP ,0 ,0 , - agno,0 ); - block =XFS_BUF_TO_BLOCK (bp); - - -/* -* mark the AG header regions as static metadata The BNO -* btree block is the first block after the headers, so -* it's location defines the size of region the static -* metadata consumes. -* -* Note: unlike mkfs, we never have to account for log -* space when growing the data regions -*/ - rrec =XFS_RMAP_REC_ADDR (block,1 ); - rrec->rm_startblock =0 ; - rrec->rm_blockcount =cpu_to_be32 (XFS_BNO_BLOCK (mp)); - rrec->rm_owner =cpu_to_be64 (XFS_RMAP_OWN_FS ); - rrec->rm_offset =0 ; -be16_add_cpu (&block->bb_numrecs,1 ); - -/* account freespace btree root blocks */ - rrec =XFS_RMAP_REC_ADDR (block,2 ); - rrec->rm_startblock =cpu_to_be32 (XFS_BNO_BLOCK (mp)); - rrec->rm_blockcount =cpu_to_be32 (2 ); - rrec->rm_owner =cpu_to_be64 (XFS_RMAP_OWN_AG ); - rrec->rm_offset =0 ; -be16_add_cpu (&block->bb_numrecs,1 ); - -/* account inode btree root blocks */ - rrec =XFS_RMAP_REC_ADDR (block,3 ); - rrec->rm_startblock =cpu_to_be32 (XFS_IBT_BLOCK (mp)); - rrec->rm_blockcount =cpu_to_be32 (XFS_RMAP_BLOCK (mp) - -XFS_IBT_BLOCK (mp)); - rrec->rm_owner =cpu_to_be64 (XFS_RMAP_OWN_INOBT ); - rrec->rm_offset =0 ; -be16_add_cpu (&block->bb_numrecs,1 ); - -/* account for rmap btree root */ - rrec =XFS_RMAP_REC_ADDR (block,4 ); - rrec->rm_startblock =cpu_to_be32 (XFS_RMAP_BLOCK (mp)); - rrec->rm_blockcount =cpu_to_be32 (1 ); - rrec->rm_owner =cpu_to_be64 (XFS_RMAP_OWN_AG ); - rrec->rm_offset =0 ; -be16_add_cpu (&block->bb_numrecs,1 ); - -/* account for refc btree root */ -if (xfs_sb_version_hasreflink (&mp->m_sb)) { - rrec =XFS_RMAP_REC_ADDR (block,5 ); - rrec->rm_startblock =cpu_to_be32 ( -xfs_refc_block (mp)); - rrec->rm_blockcount =cpu_to_be32 (1 ); - rrec->rm_owner =cpu_to_be64 (XFS_RMAP_OWN_REFC ); - rrec->rm_offset =0 ; -be16_add_cpu (&block->bb_numrecs,1 ); - } - - error =xfs_bwrite (bp); -xfs_buf_relse (bp); -if (error) - goto error0; - } - -/* -* INO btree root block -*/ - bp =xfs_growfs_get_hdr_buf (mp, -XFS_AGB_TO_DADDR (mp, agno,XFS_IBT_BLOCK (mp)), -BTOBB (mp->m_sb.sb_blocksize),0 , - &xfs_inobt_buf_ops); -if (!bp) { - error = -ENOMEM ; - goto error0; - } - -xfs_btree_init_block (mp, bp,XFS_BTNUM_INO ,0 ,0 , agno,0 ); - - error =xfs_bwrite (bp); -xfs_buf_relse (bp); -if (error) - goto error0; - -/* -* FINO btree root block -*/ -if (xfs_sb_version_hasfinobt (&mp->m_sb)) { - bp =xfs_growfs_get_hdr_buf (mp, -XFS_AGB_TO_DADDR (mp, agno,XFS_FIBT_BLOCK (mp)), -BTOBB (mp->m_sb.sb_blocksize),0 , - &xfs_inobt_buf_ops); -if (!bp) { - error = -ENOMEM ; - goto error0; - } - -xfs_btree_init_block (mp, bp,XFS_BTNUM_FINO , -0 ,0 , agno,0 ); - - error =xfs_bwrite (bp); -xfs_buf_relse (bp); -if (error) - goto error0; - } - -/* -* refcount btree root block -*/ -if (xfs_sb_version_hasreflink (&mp->m_sb)) { - bp =xfs_growfs_get_hdr_buf (mp, -XFS_AGB_TO_DADDR (mp, agno,xfs_refc_block (mp)), -BTOBB (mp->m_sb.sb_blocksize),0 , - &xfs_refcountbt_buf_ops); -if (!bp) { - error = -ENOMEM ; - goto error0; - } - -xfs_btree_init_block (mp, bp,XFS_BTNUM_REFC , -0 ,0 , agno,0 ); - - error =xfs_bwrite (bp); -xfs_buf_relse (bp); -if (error) - goto error0; - } }xfs_trans_agblocks_delta (tp, nfree); +/* * There are new blocks in the old last a.g. */
Signature · 1 line
2.17.0
Re: [PATCH 02/10] xfs: factor out AG header initialisation from growfs core
Quoted 8 lines · Dave Chinner
From: Dave Chinner <[email protected]>
The intialisation of new AG headers is mostly common with the userspace mkfs code and growfs in the kernel, so start factoring it out so we can move it to libxfs and use it in both places.
Signed-off-by Dave Chinner <[email protected]>Reviewed-by Brian Foster <[email protected]>
Looks ok,
--D
Quoted 686 lines
--- fs/xfs/xfs_fsops.c | 637 +++++++++++++++++++++++---------------------- 1 file changed, 331 insertions(+), 306 deletions(-)fs/xfs/xfs_fsops.c +331
-306@@ -71,20 +71,344 @@ xfs_growfs_get_hdr_buf(return bp; } +/* +* Write new AG headers to disk. Non-transactional, but written +* synchronously so they are completed prior to the growfs transaction +* being logged. +*/ +static int +xfs_grow_ag_headers ( +struct xfs_mount *mp, +xfs_agnumber_t agno, +xfs_extlen_t agsize, +xfs_rfsblock_t *nfree) +{ +struct xfs_agf *agf; +struct xfs_agi *agi; +struct xfs_agfl *agfl; +__be32 *agfl_bno; +xfs_alloc_rec_t *arec; +struct xfs_buf *bp; +int bucket; +xfs_extlen_t tmpsize; +int error =0 ; + +/* +* AG freespace header block +*/ + bp =xfs_growfs_get_hdr_buf (mp, +XFS_AG_DADDR (mp, agno,XFS_AGF_DADDR (mp)), +XFS_FSS_TO_BB (mp,1 ),0 , + &xfs_agf_buf_ops); +if (!bp) { + error = -ENOMEM ; + goto out_error; + } + + agf =XFS_BUF_TO_AGF (bp); + agf->agf_magicnum =cpu_to_be32 (XFS_AGF_MAGIC ); + agf->agf_versionnum =cpu_to_be32 (XFS_AGF_VERSION ); + agf->agf_seqno =cpu_to_be32 (agno); + agf->agf_length =cpu_to_be32 (agsize); + agf->agf_roots[XFS_BTNUM_BNOi] =cpu_to_be32 (XFS_BNO_BLOCK (mp)); + agf->agf_roots[XFS_BTNUM_CNTi] =cpu_to_be32 (XFS_CNT_BLOCK (mp)); + agf->agf_levels[XFS_BTNUM_BNOi] =cpu_to_be32 (1 ); + agf->agf_levels[XFS_BTNUM_CNTi] =cpu_to_be32 (1 ); +if (xfs_sb_version_hasrmapbt (&mp->m_sb)) { + agf->agf_roots[XFS_BTNUM_RMAPi] = +cpu_to_be32 (XFS_RMAP_BLOCK (mp)); + agf->agf_levels[XFS_BTNUM_RMAPi] =cpu_to_be32 (1 ); + agf->agf_rmap_blocks =cpu_to_be32 (1 ); + } + + agf->agf_flfirst =cpu_to_be32 (1 ); + agf->agf_fllast =0 ; + agf->agf_flcount =0 ; + tmpsize = agsize - mp->m_ag_prealloc_blocks; + agf->agf_freeblks =cpu_to_be32 (tmpsize); + agf->agf_longest =cpu_to_be32 (tmpsize); +if (xfs_sb_version_hascrc (&mp->m_sb)) +uuid_copy (&agf->agf_uuid, &mp->m_sb.sb_meta_uuid); +if (xfs_sb_version_hasreflink (&mp->m_sb)) { + agf->agf_refcount_root =cpu_to_be32 ( +xfs_refc_block (mp)); + agf->agf_refcount_level =cpu_to_be32 (1 ); + agf->agf_refcount_blocks =cpu_to_be32 (1 ); + } + + error =xfs_bwrite (bp); +xfs_buf_relse (bp); +if (error) + goto out_error; + +/* +* AG freelist header block +*/ + bp =xfs_growfs_get_hdr_buf (mp, +XFS_AG_DADDR (mp, agno,XFS_AGFL_DADDR (mp)), +XFS_FSS_TO_BB (mp,1 ),0 , + &xfs_agfl_buf_ops); +if (!bp) { + error = -ENOMEM ; + goto out_error; + } + + agfl =XFS_BUF_TO_AGFL (bp); +if (xfs_sb_version_hascrc (&mp->m_sb)) { + agfl->agfl_magicnum =cpu_to_be32 (XFS_AGFL_MAGIC ); + agfl->agfl_seqno =cpu_to_be32 (agno); +uuid_copy (&agfl->agfl_uuid, &mp->m_sb.sb_meta_uuid); + } + + agfl_bno =XFS_BUF_TO_AGFL_BNO (mp, bp); +for (bucket =0 ; bucket <xfs_agfl_size (mp); bucket++) + agfl_bno[bucket] =cpu_to_be32 (NULLAGBLOCK ); + + error =xfs_bwrite (bp); +xfs_buf_relse (bp); +if (error) + goto out_error; + +/* +* AG inode header block +*/ + bp =xfs_growfs_get_hdr_buf (mp, +XFS_AG_DADDR (mp, agno,XFS_AGI_DADDR (mp)), +XFS_FSS_TO_BB (mp,1 ),0 , + &xfs_agi_buf_ops); +if (!bp) { + error = -ENOMEM ; + goto out_error; + } + + agi =XFS_BUF_TO_AGI (bp); + agi->agi_magicnum =cpu_to_be32 (XFS_AGI_MAGIC ); + agi->agi_versionnum =cpu_to_be32 (XFS_AGI_VERSION ); + agi->agi_seqno =cpu_to_be32 (agno); + agi->agi_length =cpu_to_be32 (agsize); + agi->agi_count =0 ; + agi->agi_root =cpu_to_be32 (XFS_IBT_BLOCK (mp)); + agi->agi_level =cpu_to_be32 (1 ); + agi->agi_freecount =0 ; + agi->agi_newino =cpu_to_be32 (NULLAGINO ); + agi->agi_dirino =cpu_to_be32 (NULLAGINO ); +if (xfs_sb_version_hascrc (&mp->m_sb)) +uuid_copy (&agi->agi_uuid, &mp->m_sb.sb_meta_uuid); +if (xfs_sb_version_hasfinobt (&mp->m_sb)) { + agi->agi_free_root =cpu_to_be32 (XFS_FIBT_BLOCK (mp)); + agi->agi_free_level =cpu_to_be32 (1 ); + } +for (bucket =0 ; bucket <XFS_AGI_UNLINKED_BUCKETS ; bucket++) + agi->agi_unlinked[bucket] =cpu_to_be32 (NULLAGINO ); + + error =xfs_bwrite (bp); +xfs_buf_relse (bp); +if (error) + goto out_error; + +/* +* BNO btree root block +*/ + bp =xfs_growfs_get_hdr_buf (mp, +XFS_AGB_TO_DADDR (mp, agno,XFS_BNO_BLOCK (mp)), +BTOBB (mp->m_sb.sb_blocksize),0 , + &xfs_allocbt_buf_ops); + +if (!bp) { + error = -ENOMEM ; + goto out_error; + } + +xfs_btree_init_block (mp, bp,XFS_BTNUM_BNO ,0 ,1 , agno,0 ); + + arec =XFS_ALLOC_REC_ADDR (mp,XFS_BUF_TO_BLOCK (bp),1 ); + arec->ar_startblock =cpu_to_be32 (mp->m_ag_prealloc_blocks); + arec->ar_blockcount =cpu_to_be32 ( + agsize -be32_to_cpu (arec->ar_startblock)); + + error =xfs_bwrite (bp); +xfs_buf_relse (bp); +if (error) + goto out_error; + +/* +* CNT btree root block +*/ + bp =xfs_growfs_get_hdr_buf (mp, +XFS_AGB_TO_DADDR (mp, agno,XFS_CNT_BLOCK (mp)), +BTOBB (mp->m_sb.sb_blocksize),0 , + &xfs_allocbt_buf_ops); +if (!bp) { + error = -ENOMEM ; + goto out_error; + } + +xfs_btree_init_block (mp, bp,XFS_BTNUM_CNT ,0 ,1 , agno,0 ); + + arec =XFS_ALLOC_REC_ADDR (mp,XFS_BUF_TO_BLOCK (bp),1 ); + arec->ar_startblock =cpu_to_be32 (mp->m_ag_prealloc_blocks); + arec->ar_blockcount =cpu_to_be32 ( + agsize -be32_to_cpu (arec->ar_startblock)); + *nfree +=be32_to_cpu (arec->ar_blockcount); + + error =xfs_bwrite (bp); +xfs_buf_relse (bp); +if (error) + goto out_error; + +/* RMAP btree root block */ +if (xfs_sb_version_hasrmapbt (&mp->m_sb)) { +struct xfs_rmap_rec *rrec; +struct xfs_btree_block *block; + + bp =xfs_growfs_get_hdr_buf (mp, +XFS_AGB_TO_DADDR (mp, agno,XFS_RMAP_BLOCK (mp)), +BTOBB (mp->m_sb.sb_blocksize),0 , + &xfs_rmapbt_buf_ops); +if (!bp) { + error = -ENOMEM ; + goto out_error; + } + +xfs_btree_init_block (mp, bp,XFS_BTNUM_RMAP ,0 ,0 , + agno,0 ); + block =XFS_BUF_TO_BLOCK (bp); + + +/* +* mark the AG header regions as static metadata The BNO +* btree block is the first block after the headers, so +* it's location defines the size of region the static +* metadata consumes. +* +* Note: unlike mkfs, we never have to account for log +* space when growing the data regions +*/ + rrec =XFS_RMAP_REC_ADDR (block,1 ); + rrec->rm_startblock =0 ; + rrec->rm_blockcount =cpu_to_be32 (XFS_BNO_BLOCK (mp)); + rrec->rm_owner =cpu_to_be64 (XFS_RMAP_OWN_FS ); + rrec->rm_offset =0 ; +be16_add_cpu (&block->bb_numrecs,1 ); + +/* account freespace btree root blocks */ + rrec =XFS_RMAP_REC_ADDR (block,2 ); + rrec->rm_startblock =cpu_to_be32 (XFS_BNO_BLOCK (mp)); + rrec->rm_blockcount =cpu_to_be32 (2 ); + rrec->rm_owner =cpu_to_be64 (XFS_RMAP_OWN_AG ); + rrec->rm_offset =0 ; +be16_add_cpu (&block->bb_numrecs,1 ); + +/* account inode btree root blocks */ + rrec =XFS_RMAP_REC_ADDR (block,3 ); + rrec->rm_startblock =cpu_to_be32 (XFS_IBT_BLOCK (mp)); + rrec->rm_blockcount =cpu_to_be32 (XFS_RMAP_BLOCK (mp) - +XFS_IBT_BLOCK (mp)); + rrec->rm_owner =cpu_to_be64 (XFS_RMAP_OWN_INOBT ); + rrec->rm_offset =0 ; +be16_add_cpu (&block->bb_numrecs,1 ); + +/* account for rmap btree root */ + rrec =XFS_RMAP_REC_ADDR (block,4 ); + rrec->rm_startblock =cpu_to_be32 (XFS_RMAP_BLOCK (mp)); + rrec->rm_blockcount =cpu_to_be32 (1 ); + rrec->rm_owner =cpu_to_be64 (XFS_RMAP_OWN_AG ); + rrec->rm_offset =0 ; +be16_add_cpu (&block->bb_numrecs,1 ); + +/* account for refc btree root */ +if (xfs_sb_version_hasreflink (&mp->m_sb)) { + rrec =XFS_RMAP_REC_ADDR (block,5 ); + rrec->rm_startblock =cpu_to_be32 (xfs_refc_block (mp)); + rrec->rm_blockcount =cpu_to_be32 (1 ); + rrec->rm_owner =cpu_to_be64 (XFS_RMAP_OWN_REFC ); + rrec->rm_offset =0 ; +be16_add_cpu (&block->bb_numrecs,1 ); + } + + error =xfs_bwrite (bp); +xfs_buf_relse (bp); +if (error) + goto out_error; + } + +/* +* INO btree root block +*/ + bp =xfs_growfs_get_hdr_buf (mp, +XFS_AGB_TO_DADDR (mp, agno,XFS_IBT_BLOCK (mp)), +BTOBB (mp->m_sb.sb_blocksize),0 , + &xfs_inobt_buf_ops); +if (!bp) { + error = -ENOMEM ; + goto out_error; + } + +xfs_btree_init_block (mp, bp,XFS_BTNUM_INO ,0 ,0 , agno,0 ); + + error =xfs_bwrite (bp); +xfs_buf_relse (bp); +if (error) + goto out_error; + +/* +* FINO btree root block +*/ +if (xfs_sb_version_hasfinobt (&mp->m_sb)) { + bp =xfs_growfs_get_hdr_buf (mp, +XFS_AGB_TO_DADDR (mp, agno,XFS_FIBT_BLOCK (mp)), +BTOBB (mp->m_sb.sb_blocksize),0 , + &xfs_inobt_buf_ops); +if (!bp) { + error = -ENOMEM ; + goto out_error; + } + +xfs_btree_init_block (mp, bp,XFS_BTNUM_FINO , +0 ,0 , agno,0 ); + + error =xfs_bwrite (bp); +xfs_buf_relse (bp); +if (error) + goto out_error; + } + +/* +* refcount btree root block +*/ +if (xfs_sb_version_hasreflink (&mp->m_sb)) { + bp =xfs_growfs_get_hdr_buf (mp, +XFS_AGB_TO_DADDR (mp, agno,xfs_refc_block (mp)), +BTOBB (mp->m_sb.sb_blocksize),0 , + &xfs_refcountbt_buf_ops); +if (!bp) { + error = -ENOMEM ; + goto out_error; + } + +xfs_btree_init_block (mp, bp,XFS_BTNUM_REFC , +0 ,0 , agno,0 ); + + error =xfs_bwrite (bp); +xfs_buf_relse (bp); +if (error) + goto out_error; + } + +out_error: +return error; +} +static int xfs_growfs_data_private (xfs_mount_t *mp,/* mount point for filesystem */ xfs_growfs_data_t *in)/* growfs data input struct */ {xfs_agf_t *agf; -struct xfs_agfl *agfl;xfs_agi_t *agi;xfs_agnumber_t agno;xfs_extlen_t agsize; -xfs_extlen_t tmpsize; -xfs_alloc_rec_t *arec;xfs_buf_t *bp; -int bucket;int dpct;int error, saved_error =0 ;xfs_agnumber_t nagcount;@@ -141,318 +465,19 @@ xfs_growfs_data_private(*/ nfree =0 ;for (agno = nagcount -1 ; agno >= oagcount; agno--, new -= agsize) { -__be32 *agfl_bno; - -/* -* AG freespace header block -*/ - bp =xfs_growfs_get_hdr_buf (mp, -XFS_AG_DADDR (mp, agno,XFS_AGF_DADDR (mp)), -XFS_FSS_TO_BB (mp,1 ),0 , - &xfs_agf_buf_ops); -if (!bp) { - error = -ENOMEM ; - goto error0; - } - agf =XFS_BUF_TO_AGF (bp); - agf->agf_magicnum =cpu_to_be32 (XFS_AGF_MAGIC ); - agf->agf_versionnum =cpu_to_be32 (XFS_AGF_VERSION ); - agf->agf_seqno =cpu_to_be32 (agno);if (agno == nagcount -1 ) - agsize = - nb - + agsize = nb - (agno * (xfs_rfsblock_t )mp->m_sb.sb_agblocks);else agsize = mp->m_sb.sb_agblocks; - agf->agf_length =cpu_to_be32 (agsize); - agf->agf_roots[XFS_BTNUM_BNOi] =cpu_to_be32 (XFS_BNO_BLOCK (mp)); - agf->agf_roots[XFS_BTNUM_CNTi] =cpu_to_be32 (XFS_CNT_BLOCK (mp)); - agf->agf_levels[XFS_BTNUM_BNOi] =cpu_to_be32 (1 ); - agf->agf_levels[XFS_BTNUM_CNTi] =cpu_to_be32 (1 ); -if (xfs_sb_version_hasrmapbt (&mp->m_sb)) { - agf->agf_roots[XFS_BTNUM_RMAPi] = -cpu_to_be32 (XFS_RMAP_BLOCK (mp)); - agf->agf_levels[XFS_BTNUM_RMAPi] =cpu_to_be32 (1 ); - agf->agf_rmap_blocks =cpu_to_be32 (1 ); - } - - agf->agf_flfirst =cpu_to_be32 (1 ); - agf->agf_fllast =0 ; - agf->agf_flcount =0 ; - tmpsize = agsize - mp->m_ag_prealloc_blocks; - agf->agf_freeblks =cpu_to_be32 (tmpsize); - agf->agf_longest =cpu_to_be32 (tmpsize); -if (xfs_sb_version_hascrc (&mp->m_sb)) -uuid_copy (&agf->agf_uuid, &mp->m_sb.sb_meta_uuid); -if (xfs_sb_version_hasreflink (&mp->m_sb)) { - agf->agf_refcount_root =cpu_to_be32 ( -xfs_refc_block (mp)); - agf->agf_refcount_level =cpu_to_be32 (1 ); - agf->agf_refcount_blocks =cpu_to_be32 (1 ); - } - - error =xfs_bwrite (bp); -xfs_buf_relse (bp); -if (error) - goto error0; - -/* -* AG freelist header block -*/ - bp =xfs_growfs_get_hdr_buf (mp, -XFS_AG_DADDR (mp, agno,XFS_AGFL_DADDR (mp)), -XFS_FSS_TO_BB (mp,1 ),0 , - &xfs_agfl_buf_ops); -if (!bp) { - error = -ENOMEM ; - goto error0; - } - - agfl =XFS_BUF_TO_AGFL (bp); -if (xfs_sb_version_hascrc (&mp->m_sb)) { - agfl->agfl_magicnum =cpu_to_be32 (XFS_AGFL_MAGIC ); - agfl->agfl_seqno =cpu_to_be32 (agno); -uuid_copy (&agfl->agfl_uuid, &mp->m_sb.sb_meta_uuid); - } - - agfl_bno =XFS_BUF_TO_AGFL_BNO (mp, bp); -for (bucket =0 ; bucket <xfs_agfl_size (mp); bucket++) - agfl_bno[bucket] =cpu_to_be32 (NULLAGBLOCK ); - error =xfs_bwrite (bp); -xfs_buf_relse (bp); + error =xfs_grow_ag_headers (mp, agno, agsize, &nfree);if (error) goto error0; - -/* -* AG inode header block -*/ - bp =xfs_growfs_get_hdr_buf (mp, -XFS_AG_DADDR (mp, agno,XFS_AGI_DADDR (mp)), -XFS_FSS_TO_BB (mp,1 ),0 , - &xfs_agi_buf_ops); -if (!bp) { - error = -ENOMEM ; - goto error0; - } - - agi =XFS_BUF_TO_AGI (bp); - agi->agi_magicnum =cpu_to_be32 (XFS_AGI_MAGIC ); - agi->agi_versionnum =cpu_to_be32 (XFS_AGI_VERSION ); - agi->agi_seqno =cpu_to_be32 (agno); - agi->agi_length =cpu_to_be32 (agsize); - agi->agi_count =0 ; - agi->agi_root =cpu_to_be32 (XFS_IBT_BLOCK (mp)); - agi->agi_level =cpu_to_be32 (1 ); - agi->agi_freecount =0 ; - agi->agi_newino =cpu_to_be32 (NULLAGINO ); - agi->agi_dirino =cpu_to_be32 (NULLAGINO ); -if (xfs_sb_version_hascrc (&mp->m_sb)) -uuid_copy (&agi->agi_uuid, &mp->m_sb.sb_meta_uuid); -if (xfs_sb_version_hasfinobt (&mp->m_sb)) { - agi->agi_free_root =cpu_to_be32 (XFS_FIBT_BLOCK (mp)); - agi->agi_free_level =cpu_to_be32 (1 ); - } -for (bucket =0 ; bucket <XFS_AGI_UNLINKED_BUCKETS ; bucket++) - agi->agi_unlinked[bucket] =cpu_to_be32 (NULLAGINO ); - - error =xfs_bwrite (bp); -xfs_buf_relse (bp); -if (error) - goto error0; - -/* -* BNO btree root block -*/ - bp =xfs_growfs_get_hdr_buf (mp, -XFS_AGB_TO_DADDR (mp, agno,XFS_BNO_BLOCK (mp)), -BTOBB (mp->m_sb.sb_blocksize),0 , - &xfs_allocbt_buf_ops); - -if (!bp) { - error = -ENOMEM ; - goto error0; - } - -xfs_btree_init_block (mp, bp,XFS_BTNUM_BNO ,0 ,1 , agno,0 ); - - arec =XFS_ALLOC_REC_ADDR (mp,XFS_BUF_TO_BLOCK (bp),1 ); - arec->ar_startblock =cpu_to_be32 (mp->m_ag_prealloc_blocks); - arec->ar_blockcount =cpu_to_be32 ( - agsize -be32_to_cpu (arec->ar_startblock)); - - error =xfs_bwrite (bp); -xfs_buf_relse (bp); -if (error) - goto error0; - -/* -* CNT btree root block -*/ - bp =xfs_growfs_get_hdr_buf (mp, -XFS_AGB_TO_DADDR (mp, agno,XFS_CNT_BLOCK (mp)), -BTOBB (mp->m_sb.sb_blocksize),0 , - &xfs_allocbt_buf_ops); -if (!bp) { - error = -ENOMEM ; - goto error0; - } - -xfs_btree_init_block (mp, bp,XFS_BTNUM_CNT ,0 ,1 , agno,0 ); - - arec =XFS_ALLOC_REC_ADDR (mp,XFS_BUF_TO_BLOCK (bp),1 ); - arec->ar_startblock =cpu_to_be32 (mp->m_ag_prealloc_blocks); - arec->ar_blockcount =cpu_to_be32 ( - agsize -be32_to_cpu (arec->ar_startblock)); - nfree +=be32_to_cpu (arec->ar_blockcount); - - error =xfs_bwrite (bp); -xfs_buf_relse (bp); -if (error) - goto error0; - -/* RMAP btree root block */ -if (xfs_sb_version_hasrmapbt (&mp->m_sb)) { -struct xfs_rmap_rec *rrec; -struct xfs_btree_block *block; - - bp =xfs_growfs_get_hdr_buf (mp, -XFS_AGB_TO_DADDR (mp, agno,XFS_RMAP_BLOCK (mp)), -BTOBB (mp->m_sb.sb_blocksize),0 , - &xfs_rmapbt_buf_ops); -if (!bp) { - error = -ENOMEM ; - goto error0; - } - -xfs_btree_init_block (mp, bp,XFS_BTNUM_RMAP ,0 ,0 , - agno,0 ); - block =XFS_BUF_TO_BLOCK (bp); - - -/* -* mark the AG header regions as static metadata The BNO -* btree block is the first block after the headers, so -* it's location defines the size of region the static -* metadata consumes. -* -* Note: unlike mkfs, we never have to account for log -* space when growing the data regions -*/ - rrec =XFS_RMAP_REC_ADDR (block,1 ); - rrec->rm_startblock =0 ; - rrec->rm_blockcount =cpu_to_be32 (XFS_BNO_BLOCK (mp)); - rrec->rm_owner =cpu_to_be64 (XFS_RMAP_OWN_FS ); - rrec->rm_offset =0 ; -be16_add_cpu (&block->bb_numrecs,1 ); - -/* account freespace btree root blocks */ - rrec =XFS_RMAP_REC_ADDR (block,2 ); - rrec->rm_startblock =cpu_to_be32 (XFS_BNO_BLOCK (mp)); - rrec->rm_blockcount =cpu_to_be32 (2 ); - rrec->rm_owner =cpu_to_be64 (XFS_RMAP_OWN_AG ); - rrec->rm_offset =0 ; -be16_add_cpu (&block->bb_numrecs,1 ); - -/* account inode btree root blocks */ - rrec =XFS_RMAP_REC_ADDR (block,3 ); - rrec->rm_startblock =cpu_to_be32 (XFS_IBT_BLOCK (mp)); - rrec->rm_blockcount =cpu_to_be32 (XFS_RMAP_BLOCK (mp) - -XFS_IBT_BLOCK (mp)); - rrec->rm_owner =cpu_to_be64 (XFS_RMAP_OWN_INOBT ); - rrec->rm_offset =0 ; -be16_add_cpu (&block->bb_numrecs,1 ); - -/* account for rmap btree root */ - rrec =XFS_RMAP_REC_ADDR (block,4 ); - rrec->rm_startblock =cpu_to_be32 (XFS_RMAP_BLOCK (mp)); - rrec->rm_blockcount =cpu_to_be32 (1 ); - rrec->rm_owner =cpu_to_be64 (XFS_RMAP_OWN_AG ); - rrec->rm_offset =0 ; -be16_add_cpu (&block->bb_numrecs,1 ); - -/* account for refc btree root */ -if (xfs_sb_version_hasreflink (&mp->m_sb)) { - rrec =XFS_RMAP_REC_ADDR (block,5 ); - rrec->rm_startblock =cpu_to_be32 ( -xfs_refc_block (mp)); - rrec->rm_blockcount =cpu_to_be32 (1 ); - rrec->rm_owner =cpu_to_be64 (XFS_RMAP_OWN_REFC ); - rrec->rm_offset =0 ; -be16_add_cpu (&block->bb_numrecs,1 ); - } - - error =xfs_bwrite (bp); -xfs_buf_relse (bp); -if (error) - goto error0; - } - -/* -* INO btree root block -*/ - bp =xfs_growfs_get_hdr_buf (mp, -XFS_AGB_TO_DADDR (mp, agno,XFS_IBT_BLOCK (mp)), -BTOBB (mp->m_sb.sb_blocksize),0 , - &xfs_inobt_buf_ops); -if (!bp) { - error = -ENOMEM ; - goto error0; - } - -xfs_btree_init_block (mp, bp,XFS_BTNUM_INO ,0 ,0 , agno,0 ); - - error =xfs_bwrite (bp); -xfs_buf_relse (bp); -if (error) - goto error0; - -/* -* FINO btree root block -*/ -if (xfs_sb_version_hasfinobt (&mp->m_sb)) { - bp =xfs_growfs_get_hdr_buf (mp, -XFS_AGB_TO_DADDR (mp, agno,XFS_FIBT_BLOCK (mp)), -BTOBB (mp->m_sb.sb_blocksize),0 , - &xfs_inobt_buf_ops); -if (!bp) { - error = -ENOMEM ; - goto error0; - } - -xfs_btree_init_block (mp, bp,XFS_BTNUM_FINO , -0 ,0 , agno,0 ); - - error =xfs_bwrite (bp); -xfs_buf_relse (bp); -if (error) - goto error0; - } - -/* -* refcount btree root block -*/ -if (xfs_sb_version_hasreflink (&mp->m_sb)) { - bp =xfs_growfs_get_hdr_buf (mp, -XFS_AGB_TO_DADDR (mp, agno,xfs_refc_block (mp)), -BTOBB (mp->m_sb.sb_blocksize),0 , - &xfs_refcountbt_buf_ops); -if (!bp) { - error = -ENOMEM ; - goto error0; - } - -xfs_btree_init_block (mp, bp,XFS_BTNUM_REFC , -0 ,0 , agno,0 ); - - error =xfs_bwrite (bp); -xfs_buf_relse (bp); -if (error) - goto error0; - } }xfs_trans_agblocks_delta (tp, nfree); +/* * There are new blocks in the old last a.g. */ Signature · 6 lines
2.17.0 -- To unsubscribe from this list: send the line "unsubscribe linux-xfs" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH v3 3/10 xfs: convert growfs AG header init to use buffer lists
In reply to Dave ChinnerFrom: Dave Chinner <[email protected]>
We currently write all new AG headers synchronously, which can be slow for large grow operations. All we really need to do is ensure all the headers are on disk before we run the growfs transaction, so convert this to a buffer list and a delayed write operation. We block waiting for the delayed write buffer submission to complete, so this will fulfill the requirement to have all the buffers written correctly before proceeding.
--- fs/xfs/xfs_fsops.c | 74 +++++++++++++++++++++------------------------- 1 file changed, 33 insertions(+), 41 deletions(-)
fs/xfs/xfs_fsops.c +33 -41
@@ -81,7 +81,8 @@ xfs_grow_ag_headers(struct xfs_mount *mp, xfs_agnumber_t agno, xfs_extlen_t agsize, - xfs_rfsblock_t *nfree) + xfs_rfsblock_t *nfree, + struct list_head *buffer_list) { struct xfs_agf *agf;struct xfs_agi *agi;
@@ -135,11 +136,8 @@ xfs_grow_ag_headers( agf->agf_refcount_level =cpu_to_be32 (1 ); agf->agf_refcount_blocks =cpu_to_be32 (1 ); } - - error =xfs_bwrite (bp); +xfs_buf_delwri_queue (bp, buffer_list);xfs_buf_relse (bp); -if (error) - goto out_error;/* * AG freelist header block
@@ -164,10 +162,8 @@ xfs_grow_ag_headers(for (bucket =0 ; bucket <xfs_agfl_size (mp); bucket++) agfl_bno[bucket] =cpu_to_be32 (NULLAGBLOCK ); - error =xfs_bwrite (bp); +xfs_buf_delwri_queue (bp, buffer_list);xfs_buf_relse (bp); -if (error) - goto out_error;/* * AG inode header block
@@ -201,10 +197,8 @@ xfs_grow_ag_headers(for (bucket =0 ; bucket <XFS_AGI_UNLINKED_BUCKETS ; bucket++) agi->agi_unlinked[bucket] =cpu_to_be32 (NULLAGINO ); - error =xfs_bwrite (bp); +xfs_buf_delwri_queue (bp, buffer_list);xfs_buf_relse (bp); -if (error) - goto out_error;/* * BNO btree root block
@@ -226,10 +220,8 @@ xfs_grow_ag_headers( arec->ar_blockcount =cpu_to_be32 ( agsize -be32_to_cpu (arec->ar_startblock)); - error =xfs_bwrite (bp); +xfs_buf_delwri_queue (bp, buffer_list);xfs_buf_relse (bp); -if (error) - goto out_error;/* * CNT btree root block
@@ -251,10 +243,8 @@ xfs_grow_ag_headers( agsize - be32_to_cpu(arec->ar_startblock)); *nfree +=be32_to_cpu (arec->ar_blockcount); - error =xfs_bwrite (bp); +xfs_buf_delwri_queue (bp, buffer_list);xfs_buf_relse (bp); -if (error) - goto out_error;/* RMAP btree root block */ if (xfs_sb_version_hasrmapbt (&mp->m_sb)) {
@@ -326,10 +316,8 @@ xfs_grow_ag_headers(be16_add_cpu (&block->bb_numrecs,1 ); } - error =xfs_bwrite (bp); +xfs_buf_delwri_queue (bp, buffer_list);xfs_buf_relse (bp); -if (error) - goto out_error; }/*
@@ -345,11 +333,8 @@ xfs_grow_ag_headers( }xfs_btree_init_block (mp, bp,XFS_BTNUM_INO ,0 ,0 , agno,0 ); - - error =xfs_bwrite (bp); +xfs_buf_delwri_queue (bp, buffer_list);xfs_buf_relse (bp); -if (error) - goto out_error;/* * FINO btree root block
@@ -364,13 +349,9 @@ xfs_grow_ag_headers( goto out_error; } -xfs_btree_init_block (mp, bp,XFS_BTNUM_FINO , -0 ,0 , agno,0 ); - - error =xfs_bwrite (bp); +xfs_btree_init_block (mp, bp,XFS_BTNUM_FINO ,0 ,0 , agno,0 ); +xfs_buf_delwri_queue (bp, buffer_list);xfs_buf_relse (bp); -if (error) - goto out_error; }/*
@@ -386,13 +367,9 @@ xfs_grow_ag_headers( goto out_error; } -xfs_btree_init_block (mp, bp,XFS_BTNUM_REFC , -0 ,0 , agno,0 ); - - error =xfs_bwrite (bp); +xfs_btree_init_block (mp, bp,XFS_BTNUM_REFC ,0 ,0 , agno,0 ); +xfs_buf_delwri_queue (bp, buffer_list);xfs_buf_relse (bp); -if (error) - goto out_error; } out_error:
@@ -419,6 +396,7 @@ xfs_growfs_data_private(xfs_agnumber_t oagcount;int pct;xfs_trans_t *tp; +LIST_HEAD (buffer_list); nb = in->newblocks; pct = in->imaxpct;
@@ -459,9 +437,16 @@ xfs_growfs_data_private(return error;/* -* Write new AG headers to disk. Non-transactional, but written -* synchronously so they are completed prior to the growfs transaction -* being logged. +* Write new AG headers to disk. Non-transactional, but need to be +* written and completed prior to the growfs transaction being logged. +* To do this, we use a delayed write buffer list and wait for +* submission and IO completion of the list as a whole. This allows the +* IO subsystem to merge all the AG headers in a single AG into a single +* IO and hide most of the latency of the IO from us. +* +* This also means that if we get an error whilst building the buffer +* list to write, we can cancel the entire list without having written +* anything. */ nfree =0 ;for (agno = nagcount -1 ; agno >= oagcount; agno--, new -= agsize) {
@@ -472,10 +457,17 @@ xfs_growfs_data_private(else agsize = mp->m_sb.sb_agblocks; - error =xfs_grow_ag_headers (mp, agno, agsize, &nfree); -if (error) + error =xfs_grow_ag_headers (mp, agno, agsize, &nfree, + &buffer_list); +if (error) { +xfs_buf_delwri_cancel (&buffer_list); goto error0; + } } + error =xfs_buf_delwri_submit (&buffer_list); +if (error) + goto error0; +xfs_trans_agblocks_delta (tp, nfree);/*
Signature · 1 line
2.17.0
PATCH v3 4/10 xfs: factor ag btree root block initialisation
In reply to Dave ChinnerFrom: Dave Chinner <[email protected]>
Cookie cutter code, easily factored.
--- fs/xfs/xfs_fsops.c | 481 ++++++++++++++++++++++++--------------------- 1 file changed, 259 insertions(+), 222 deletions(-)
fs/xfs/xfs_fsops.c +259 -222
@@ -71,46 +71,140 @@ xfs_growfs_get_hdr_buf(return bp; } +struct aghdr_init_data { +/* per ag data */ +xfs_agnumber_t agno;/* ag to init */ +xfs_extlen_t agsize;/* new AG size */ +struct list_head buffer_list;/* buffer writeback list */ +xfs_rfsblock_t nfree;/* cumulative new free space */ + +/* per header data */ +xfs_daddr_t daddr;/* header location */ +size_t numblks;/* size of header */ +xfs_btnum_t type;/* type of btree root block */ +}; +/* -* Write new AG headers to disk. Non-transactional, but written -* synchronously so they are completed prior to the growfs transaction -* being logged. +* Generic btree root block init function */ -static int -xfs_grow_ag_headers ( +static void +xfs_btroot_init (struct xfs_mount *mp, -xfs_agnumber_t agno, -xfs_extlen_t agsize, -xfs_rfsblock_t *nfree, -struct list_head *buffer_list) +struct xfs_buf *bp, +struct aghdr_init_data *id) { -struct xfs_agf *agf; -struct xfs_agi *agi; -struct xfs_agfl *agfl; -__be32 *agfl_bno; -xfs_alloc_rec_t *arec; -struct xfs_buf *bp; -int bucket; -xfs_extlen_t tmpsize; -int error =0 ; +xfs_btree_init_block (mp, bp, id->type,0 ,0 , id->agno,0 ); +} + +/* +* Alloc btree root block init functions +*/ +static void +xfs_bnoroot_init ( +struct xfs_mount *mp, +struct xfs_buf *bp, +struct aghdr_init_data *id) +{ +struct xfs_alloc_rec *arec; + +xfs_btree_init_block (mp, bp,XFS_BTNUM_BNO ,0 ,1 , id->agno,0 ); + arec =XFS_ALLOC_REC_ADDR (mp,XFS_BUF_TO_BLOCK (bp),1 ); + arec->ar_startblock =cpu_to_be32 (mp->m_ag_prealloc_blocks); + arec->ar_blockcount =cpu_to_be32 (id->agsize - +be32_to_cpu (arec->ar_startblock)); +} + +static void +xfs_cntroot_init ( +struct xfs_mount *mp, +struct xfs_buf *bp, +struct aghdr_init_data *id) +{ +struct xfs_alloc_rec *arec; + +xfs_btree_init_block (mp, bp,XFS_BTNUM_CNT ,0 ,1 , id->agno,0 ); + arec =XFS_ALLOC_REC_ADDR (mp,XFS_BUF_TO_BLOCK (bp),1 ); + arec->ar_startblock =cpu_to_be32 (mp->m_ag_prealloc_blocks); + arec->ar_blockcount =cpu_to_be32 (id->agsize - +be32_to_cpu (arec->ar_startblock)); +} + +/* +* Reverse map root block init +*/ +static void +xfs_rmaproot_init ( +struct xfs_mount *mp, +struct xfs_buf *bp, +struct aghdr_init_data *id) +{ +struct xfs_btree_block *block =XFS_BUF_TO_BLOCK (bp); +struct xfs_rmap_rec *rrec; + +xfs_btree_init_block (mp, bp,XFS_BTNUM_RMAP ,0 ,4 , id->agno,0 );/* -* AG freespace header block +* mark the AG header regions as static metadata The BNO +* btree block is the first block after the headers, so +* it's location defines the size of region the static +* metadata consumes. +* +* Note: unlike mkfs, we never have to account for log +* space when growing the data regions */ - bp =xfs_growfs_get_hdr_buf (mp, -XFS_AG_DADDR (mp, agno,XFS_AGF_DADDR (mp)), -XFS_FSS_TO_BB (mp,1 ),0 , - &xfs_agf_buf_ops); -if (!bp) { - error = -ENOMEM ; - goto out_error; + rrec =XFS_RMAP_REC_ADDR (block,1 ); + rrec->rm_startblock =0 ; + rrec->rm_blockcount =cpu_to_be32 (XFS_BNO_BLOCK (mp)); + rrec->rm_owner =cpu_to_be64 (XFS_RMAP_OWN_FS ); + rrec->rm_offset =0 ; + +/* account freespace btree root blocks */ + rrec =XFS_RMAP_REC_ADDR (block,2 ); + rrec->rm_startblock =cpu_to_be32 (XFS_BNO_BLOCK (mp)); + rrec->rm_blockcount =cpu_to_be32 (2 ); + rrec->rm_owner =cpu_to_be64 (XFS_RMAP_OWN_AG ); + rrec->rm_offset =0 ; + +/* account inode btree root blocks */ + rrec =XFS_RMAP_REC_ADDR (block,3 ); + rrec->rm_startblock =cpu_to_be32 (XFS_IBT_BLOCK (mp)); + rrec->rm_blockcount =cpu_to_be32 (XFS_RMAP_BLOCK (mp) - +XFS_IBT_BLOCK (mp)); + rrec->rm_owner =cpu_to_be64 (XFS_RMAP_OWN_INOBT ); + rrec->rm_offset =0 ; + +/* account for rmap btree root */ + rrec =XFS_RMAP_REC_ADDR (block,4 ); + rrec->rm_startblock =cpu_to_be32 (XFS_RMAP_BLOCK (mp)); + rrec->rm_blockcount =cpu_to_be32 (1 ); + rrec->rm_owner =cpu_to_be64 (XFS_RMAP_OWN_AG ); + rrec->rm_offset =0 ; + +/* account for refc btree root */ +if (xfs_sb_version_hasreflink (&mp->m_sb)) { + rrec =XFS_RMAP_REC_ADDR (block,5 ); + rrec->rm_startblock =cpu_to_be32 (xfs_refc_block (mp)); + rrec->rm_blockcount =cpu_to_be32 (1 ); + rrec->rm_owner =cpu_to_be64 (XFS_RMAP_OWN_REFC ); + rrec->rm_offset =0 ; +be16_add_cpu (&block->bb_numrecs,1 ); } +} + + +static void +xfs_agfblock_init ( +struct xfs_mount *mp, +struct xfs_buf *bp, +struct aghdr_init_data *id) +{ +struct xfs_agf *agf =XFS_BUF_TO_AGF (bp); +xfs_extlen_t tmpsize; - agf =XFS_BUF_TO_AGF (bp); agf->agf_magicnum =cpu_to_be32 (XFS_AGF_MAGIC ); agf->agf_versionnum =cpu_to_be32 (XFS_AGF_VERSION ); - agf->agf_seqno =cpu_to_be32 (agno); - agf->agf_length =cpu_to_be32 (agsize); + agf->agf_seqno =cpu_to_be32 (id->agno); + agf->agf_length =cpu_to_be32 (id->agsize); agf->agf_roots[XFS_BTNUM_BNOi] =cpu_to_be32 (XFS_BNO_BLOCK (mp)); agf->agf_roots[XFS_BTNUM_CNTi] =cpu_to_be32 (XFS_CNT_BLOCK (mp)); agf->agf_levels[XFS_BTNUM_BNOi] =cpu_to_be32 (1 );
@@ -125,7 +219,7 @@ xfs_grow_ag_headers( agf->agf_flfirst =cpu_to_be32 (1 ); agf->agf_fllast =0 ; agf->agf_flcount =0 ; - tmpsize = agsize - mp->m_ag_prealloc_blocks; + tmpsize = id->agsize - mp->m_ag_prealloc_blocks; agf->agf_freeblks =cpu_to_be32 (tmpsize); agf->agf_longest =cpu_to_be32 (tmpsize);if (xfs_sb_version_hascrc (&mp->m_sb))
@@ -136,52 +230,42 @@ xfs_grow_ag_headers( agf->agf_refcount_level =cpu_to_be32 (1 ); agf->agf_refcount_blocks =cpu_to_be32 (1 ); } -xfs_buf_delwri_queue (bp, buffer_list); -xfs_buf_relse (bp); +} -/* -* AG freelist header block -*/ - bp =xfs_growfs_get_hdr_buf (mp, -XFS_AG_DADDR (mp, agno,XFS_AGFL_DADDR (mp)), -XFS_FSS_TO_BB (mp,1 ),0 , - &xfs_agfl_buf_ops); -if (!bp) { - error = -ENOMEM ; - goto out_error; - } +static void +xfs_agflblock_init ( +struct xfs_mount *mp, +struct xfs_buf *bp, +struct aghdr_init_data *id) +{ +struct xfs_agfl *agfl =XFS_BUF_TO_AGFL (bp); +__be32 *agfl_bno; +int bucket; - agfl =XFS_BUF_TO_AGFL (bp);if (xfs_sb_version_hascrc (&mp->m_sb)) { agfl->agfl_magicnum =cpu_to_be32 (XFS_AGFL_MAGIC ); - agfl->agfl_seqno =cpu_to_be32 (agno); + agfl->agfl_seqno =cpu_to_be32 (id->agno);uuid_copy (&agfl->agfl_uuid, &mp->m_sb.sb_meta_uuid); } agfl_bno =XFS_BUF_TO_AGFL_BNO (mp, bp);for (bucket =0 ; bucket <xfs_agfl_size (mp); bucket++) agfl_bno[bucket] =cpu_to_be32 (NULLAGBLOCK ); +} -xfs_buf_delwri_queue (bp, buffer_list); -xfs_buf_relse (bp); - -/* -* AG inode header block -*/ - bp =xfs_growfs_get_hdr_buf (mp, -XFS_AG_DADDR (mp, agno,XFS_AGI_DADDR (mp)), -XFS_FSS_TO_BB (mp,1 ),0 , - &xfs_agi_buf_ops); -if (!bp) { - error = -ENOMEM ; - goto out_error; - } +static void +xfs_agiblock_init ( +struct xfs_mount *mp, +struct xfs_buf *bp, +struct aghdr_init_data *id) +{ +struct xfs_agi *agi =XFS_BUF_TO_AGI (bp); +int bucket; - agi =XFS_BUF_TO_AGI (bp); agi->agi_magicnum =cpu_to_be32 (XFS_AGI_MAGIC ); agi->agi_versionnum =cpu_to_be32 (XFS_AGI_VERSION ); - agi->agi_seqno =cpu_to_be32 (agno); - agi->agi_length =cpu_to_be32 (agsize); + agi->agi_seqno =cpu_to_be32 (id->agno); + agi->agi_length =cpu_to_be32 (id->agsize); agi->agi_count =0 ; agi->agi_root =cpu_to_be32 (XFS_IBT_BLOCK (mp)); agi->agi_level =cpu_to_be32 (1 );
@@ -196,180 +280,133 @@ xfs_grow_ag_headers( }for (bucket =0 ; bucket <XFS_AGI_UNLINKED_BUCKETS ; bucket++) agi->agi_unlinked[bucket] =cpu_to_be32 (NULLAGINO ); +} -xfs_buf_delwri_queue (bp, buffer_list); -xfs_buf_relse (bp); - -/* -* BNO btree root block -*/ - bp =xfs_growfs_get_hdr_buf (mp, -XFS_AGB_TO_DADDR (mp, agno,XFS_BNO_BLOCK (mp)), -BTOBB (mp->m_sb.sb_blocksize),0 , - &xfs_allocbt_buf_ops); +static int +xfs_growfs_init_aghdr ( +struct xfs_mount *mp, +struct aghdr_init_data *id, +void (*work)(struct xfs_mount *,struct xfs_buf *, +struct aghdr_init_data *), +const struct xfs_buf_ops *ops) -if (!bp) { - error = -ENOMEM ; - goto out_error; - } +{ +struct xfs_buf *bp; -xfs_btree_init_block (mp, bp,XFS_BTNUM_BNO ,0 ,1 , agno,0 ); + bp =xfs_growfs_get_hdr_buf (mp, id->daddr, id->numblks,0 , ops); +if (!bp) +return -ENOMEM ; - arec =XFS_ALLOC_REC_ADDR (mp,XFS_BUF_TO_BLOCK (bp),1 ); - arec->ar_startblock =cpu_to_be32 (mp->m_ag_prealloc_blocks); - arec->ar_blockcount =cpu_to_be32 ( - agsize -be32_to_cpu (arec->ar_startblock)); + (*work)(mp, bp, id); -xfs_buf_delwri_queue (bp, buffer_list); +xfs_buf_delwri_queue (bp, &id->buffer_list);xfs_buf_relse (bp); +return 0 ; +} -/* -* CNT btree root block -*/ - bp =xfs_growfs_get_hdr_buf (mp, -XFS_AGB_TO_DADDR (mp, agno,XFS_CNT_BLOCK (mp)), -BTOBB (mp->m_sb.sb_blocksize),0 , - &xfs_allocbt_buf_ops); -if (!bp) { - error = -ENOMEM ; - goto out_error; - } - -xfs_btree_init_block (mp, bp,XFS_BTNUM_CNT ,0 ,1 , agno,0 ); +/* +* Write new AG headers to disk. Non-transactional, but written +* synchronously so they are completed prior to the growfs transaction +* being logged. +*/ +static int +xfs_grow_ag_headers ( +struct xfs_mount *mp, +struct aghdr_init_data *id) - arec =XFS_ALLOC_REC_ADDR (mp,XFS_BUF_TO_BLOCK (bp),1 ); - arec->ar_startblock =cpu_to_be32 (mp->m_ag_prealloc_blocks); - arec->ar_blockcount =cpu_to_be32 ( - agsize -be32_to_cpu (arec->ar_startblock)); - *nfree +=be32_to_cpu (arec->ar_blockcount); +{ +int error =0 ; -xfs_buf_delwri_queue (bp, buffer_list); -xfs_buf_relse (bp); +/* Account for AG free space in new AG */ + id->nfree += id->agsize - mp->m_ag_prealloc_blocks; -/* RMAP btree root block */ -if (xfs_sb_version_hasrmapbt (&mp->m_sb)) { -struct xfs_rmap_rec *rrec; -struct xfs_btree_block *block; - - bp =xfs_growfs_get_hdr_buf (mp, -XFS_AGB_TO_DADDR (mp, agno,XFS_RMAP_BLOCK (mp)), -BTOBB (mp->m_sb.sb_blocksize),0 , - &xfs_rmapbt_buf_ops); -if (!bp) { - error = -ENOMEM ; - goto out_error; - } +/* AG freespace header block */ + id->daddr =XFS_AG_DADDR (mp, id->agno,XFS_AGF_DADDR (mp)); + id->numblks =XFS_FSS_TO_BB (mp,1 ); + error =xfs_growfs_init_aghdr (mp, id, xfs_agfblock_init, + &xfs_agf_buf_ops); +if (error) + goto out_error; -xfs_btree_init_block (mp, bp,XFS_BTNUM_RMAP ,0 ,0 , - agno,0 ); - block =XFS_BUF_TO_BLOCK (bp); +/* AG freelist header block */ + id->daddr =XFS_AG_DADDR (mp, id->agno,XFS_AGFL_DADDR (mp)); + id->numblks =XFS_FSS_TO_BB (mp,1 ); + error =xfs_growfs_init_aghdr (mp, id, xfs_agflblock_init, + &xfs_agfl_buf_ops); +if (error) + goto out_error; +/* AG inode header block */ + id->daddr =XFS_AG_DADDR (mp, id->agno,XFS_AGI_DADDR (mp)); + id->numblks =XFS_FSS_TO_BB (mp,1 ); + error =xfs_growfs_init_aghdr (mp, id, xfs_agiblock_init, + &xfs_agi_buf_ops); +if (error) + goto out_error; -/* -* mark the AG header regions as static metadata The BNO -* btree block is the first block after the headers, so -* it's location defines the size of region the static -* metadata consumes. -* -* Note: unlike mkfs, we never have to account for log -* space when growing the data regions -*/ - rrec =XFS_RMAP_REC_ADDR (block,1 ); - rrec->rm_startblock =0 ; - rrec->rm_blockcount =cpu_to_be32 (XFS_BNO_BLOCK (mp)); - rrec->rm_owner =cpu_to_be64 (XFS_RMAP_OWN_FS ); - rrec->rm_offset =0 ; -be16_add_cpu (&block->bb_numrecs,1 ); -/* account freespace btree root blocks */ - rrec =XFS_RMAP_REC_ADDR (block,2 ); - rrec->rm_startblock =cpu_to_be32 (XFS_BNO_BLOCK (mp)); - rrec->rm_blockcount =cpu_to_be32 (2 ); - rrec->rm_owner =cpu_to_be64 (XFS_RMAP_OWN_AG ); - rrec->rm_offset =0 ; -be16_add_cpu (&block->bb_numrecs,1 ); +/* BNO btree root block */ + id->daddr =XFS_AGB_TO_DADDR (mp, id->agno,XFS_BNO_BLOCK (mp)); + id->numblks =BTOBB (mp->m_sb.sb_blocksize); + error =xfs_growfs_init_aghdr (mp, id, xfs_bnoroot_init, + &xfs_allocbt_buf_ops); +if (error) + goto out_error; -/* account inode btree root blocks */ - rrec =XFS_RMAP_REC_ADDR (block,3 ); - rrec->rm_startblock =cpu_to_be32 (XFS_IBT_BLOCK (mp)); - rrec->rm_blockcount =cpu_to_be32 (XFS_RMAP_BLOCK (mp) - -XFS_IBT_BLOCK (mp)); - rrec->rm_owner =cpu_to_be64 (XFS_RMAP_OWN_INOBT ); - rrec->rm_offset =0 ; -be16_add_cpu (&block->bb_numrecs,1 ); -/* account for rmap btree root */ - rrec =XFS_RMAP_REC_ADDR (block,4 ); - rrec->rm_startblock =cpu_to_be32 (XFS_RMAP_BLOCK (mp)); - rrec->rm_blockcount =cpu_to_be32 (1 ); - rrec->rm_owner =cpu_to_be64 (XFS_RMAP_OWN_AG ); - rrec->rm_offset =0 ; -be16_add_cpu (&block->bb_numrecs,1 ); +/* CNT btree root block */ + id->daddr =XFS_AGB_TO_DADDR (mp, id->agno,XFS_CNT_BLOCK (mp)); + id->numblks =BTOBB (mp->m_sb.sb_blocksize); + error =xfs_growfs_init_aghdr (mp, id, xfs_cntroot_init, + &xfs_allocbt_buf_ops); +if (error) + goto out_error; -/* account for refc btree root */ -if (xfs_sb_version_hasreflink (&mp->m_sb)) { - rrec =XFS_RMAP_REC_ADDR (block,5 ); - rrec->rm_startblock =cpu_to_be32 (xfs_refc_block (mp)); - rrec->rm_blockcount =cpu_to_be32 (1 ); - rrec->rm_owner =cpu_to_be64 (XFS_RMAP_OWN_REFC ); - rrec->rm_offset =0 ; -be16_add_cpu (&block->bb_numrecs,1 ); - } +/* RMAP btree root block */ +if (xfs_sb_version_hasrmapbt (&mp->m_sb)) { + id->daddr =XFS_AGB_TO_DADDR (mp, id->agno,XFS_RMAP_BLOCK (mp)); + id->numblks =BTOBB (mp->m_sb.sb_blocksize); + error =xfs_growfs_init_aghdr (mp, id, xfs_rmaproot_init, + &xfs_rmapbt_buf_ops); +if (error) + goto out_error; -xfs_buf_delwri_queue (bp, buffer_list); -xfs_buf_relse (bp); } -/* -* INO btree root block -*/ - bp =xfs_growfs_get_hdr_buf (mp, -XFS_AGB_TO_DADDR (mp, agno,XFS_IBT_BLOCK (mp)), -BTOBB (mp->m_sb.sb_blocksize),0 , - &xfs_inobt_buf_ops); -if (!bp) { - error = -ENOMEM ; +/* INO btree root block */ + id->daddr =XFS_AGB_TO_DADDR (mp, id->agno,XFS_IBT_BLOCK (mp)); + id->numblks =BTOBB (mp->m_sb.sb_blocksize); + id->type =XFS_BTNUM_INO ; + error =xfs_growfs_init_aghdr (mp, id, xfs_btroot_init, + &xfs_inobt_buf_ops); +if (error) goto out_error; - } -xfs_btree_init_block (mp, bp,XFS_BTNUM_INO ,0 ,0 , agno,0 ); -xfs_buf_delwri_queue (bp, buffer_list); -xfs_buf_relse (bp);/* * FINO btree root block */ if (xfs_sb_version_hasfinobt (&mp->m_sb)) { - bp =xfs_growfs_get_hdr_buf (mp, -XFS_AGB_TO_DADDR (mp, agno,XFS_FIBT_BLOCK (mp)), -BTOBB (mp->m_sb.sb_blocksize),0 , - &xfs_inobt_buf_ops); -if (!bp) { - error = -ENOMEM ; + id->daddr =XFS_AGB_TO_DADDR (mp, id->agno,XFS_FIBT_BLOCK (mp)); + id->numblks =BTOBB (mp->m_sb.sb_blocksize); + id->type =XFS_BTNUM_FINO ; + error =xfs_growfs_init_aghdr (mp, id, xfs_btroot_init, + &xfs_inobt_buf_ops); +if (error) goto out_error; - } - -xfs_btree_init_block (mp, bp,XFS_BTNUM_FINO ,0 ,0 , agno,0 ); -xfs_buf_delwri_queue (bp, buffer_list); -xfs_buf_relse (bp); }/* * refcount btree root block */ if (xfs_sb_version_hasreflink (&mp->m_sb)) { - bp =xfs_growfs_get_hdr_buf (mp, -XFS_AGB_TO_DADDR (mp, agno,xfs_refc_block (mp)), -BTOBB (mp->m_sb.sb_blocksize),0 , - &xfs_refcountbt_buf_ops); -if (!bp) { - error = -ENOMEM ; + id->daddr =XFS_AGB_TO_DADDR (mp, id->agno,xfs_refc_block (mp)); + id->numblks =BTOBB (mp->m_sb.sb_blocksize); + id->type =XFS_BTNUM_REFC ; + error =xfs_growfs_init_aghdr (mp, id, xfs_btroot_init, + &xfs_refcountbt_buf_ops); +if (error) goto out_error; - } - -xfs_btree_init_block (mp, bp,XFS_BTNUM_REFC ,0 ,0 , agno,0 ); -xfs_buf_delwri_queue (bp, buffer_list); -xfs_buf_relse (bp); } out_error:
@@ -384,7 +421,6 @@ xfs_growfs_data_private(xfs_agf_t *agf;xfs_agi_t *agi;xfs_agnumber_t agno; -xfs_extlen_t agsize;xfs_buf_t *bp;int dpct;int error, saved_error =0 ;
@@ -392,11 +428,11 @@ xfs_growfs_data_private(xfs_agnumber_t nagimax =0 ;xfs_rfsblock_t nb, nb_mod;xfs_rfsblock_t new; -xfs_rfsblock_t nfree;xfs_agnumber_t oagcount;int pct;xfs_trans_t *tp;LIST_HEAD (buffer_list); +struct aghdr_init_data id = {}; nb = in->newblocks; pct = in->imaxpct;
@@ -448,27 +484,28 @@ xfs_growfs_data_private(* list to write, we can cancel the entire list without having written * anything. */ - nfree =0 ; -for (agno = nagcount -1 ; agno >= oagcount; agno--, new -= agsize) { - -if (agno == nagcount -1 ) - agsize = nb - - (agno * (xfs_rfsblock_t )mp->m_sb.sb_agblocks); +INIT_LIST_HEAD (&id.buffer_list); +for (id.agno = nagcount -1 ; + id.agno >= oagcount; + id.agno--, new -= id.agsize) { + +if (id.agno == nagcount -1 ) + id.agsize = nb - + (id.agno * (xfs_rfsblock_t )mp->m_sb.sb_agblocks);else - agsize = mp->m_sb.sb_agblocks; + id.agsize = mp->m_sb.sb_agblocks; - error =xfs_grow_ag_headers (mp, agno, agsize, &nfree, - &buffer_list); + error =xfs_grow_ag_headers (mp, &id);if (error) { -xfs_buf_delwri_cancel (&buffer_list); +xfs_buf_delwri_cancel (&id.buffer_list); goto error0; } } - error =xfs_buf_delwri_submit (&buffer_list); + error =xfs_buf_delwri_submit (&id.buffer_list);if (error) goto error0; -xfs_trans_agblocks_delta (tp, nfree); +xfs_trans_agblocks_delta (tp, id.nfree);/* * There are new blocks in the old last a.g.
@@ -479,7 +516,7 @@ xfs_growfs_data_private(/* * Change the agi length. */ - error =xfs_ialloc_read_agi (mp, tp, agno, &bp); + error =xfs_ialloc_read_agi (mp, tp, id.agno, &bp);if (error) { goto error0; }
@@ -492,7 +529,7 @@ xfs_growfs_data_private(/* * Change agf length. */ - error =xfs_alloc_read_agf (mp, tp, agno,0 , &bp); + error =xfs_alloc_read_agf (mp, tp, id.agno,0 , &bp);if (error) { goto error0; }
@@ -511,13 +548,13 @@ xfs_growfs_data_private(* this doesn't actually exist in the rmap btree. */ xfs_rmap_ag_owner (&oinfo,XFS_RMAP_OWN_NULL ); - error =xfs_rmap_free (tp, bp, agno, + error =xfs_rmap_free (tp, bp, id.agno,be32_to_cpu (agf->agf_length) - new, new, &oinfo);if (error) goto error0; error =xfs_free_extent (tp, -XFS_AGB_TO_FSB (mp, agno, +XFS_AGB_TO_FSB (mp, id.agno,be32_to_cpu (agf->agf_length) - new), new, &oinfo,XFS_AG_RESV_NONE );if (error)
@@ -534,8 +571,8 @@ xfs_growfs_data_private(if (nb > mp->m_sb.sb_dblocks)xfs_trans_mod_sb (tp,XFS_TRANS_SB_DBLOCKS , nb - mp->m_sb.sb_dblocks); -if (nfree) -xfs_trans_mod_sb (tp,XFS_TRANS_SB_FDBLOCKS , nfree); +if (id.nfree) +xfs_trans_mod_sb (tp,XFS_TRANS_SB_FDBLOCKS , id.nfree);if (dpct)xfs_trans_mod_sb (tp,XFS_TRANS_SB_IMAXPCT , dpct);xfs_trans_set_sync (tp);
@@ -562,7 +599,7 @@ xfs_growfs_data_private(if (new) {struct xfs_perag *pag; - pag =xfs_perag_get (mp, agno); + pag =xfs_perag_get (mp, id.agno); error =xfs_ag_resv_free (pag);xfs_perag_put (pag);if (error)
Signature · 1 line
2.17.0
Re: [PATCH 04/10] xfs: factor ag btree root block initialisation
Quoted 5 lines · Dave Chinner
From: Dave Chinner <[email protected]>
Cookie cutter code, easily factored.
Signed-off-by Dave Chinner <[email protected]>
Looks ok,
--D
Quoted 658 lines
--- fs/xfs/xfs_fsops.c | 481 ++++++++++++++++++++++++--------------------- 1 file changed, 259 insertions(+), 222 deletions(-)fs/xfs/xfs_fsops.c +259
-222@@ -71,46 +71,140 @@ xfs_growfs_get_hdr_buf(return bp; } +struct aghdr_init_data { +/* per ag data */ +xfs_agnumber_t agno;/* ag to init */ +xfs_extlen_t agsize;/* new AG size */ +struct list_head buffer_list;/* buffer writeback list */ +xfs_rfsblock_t nfree;/* cumulative new free space */ + +/* per header data */ +xfs_daddr_t daddr;/* header location */ +size_t numblks;/* size of header */ +xfs_btnum_t type;/* type of btree root block */ +}; +/* -* Write new AG headers to disk. Non-transactional, but written -* synchronously so they are completed prior to the growfs transaction -* being logged. +* Generic btree root block init function */ -static int -xfs_grow_ag_headers ( +static void +xfs_btroot_init (struct xfs_mount *mp, -xfs_agnumber_t agno, -xfs_extlen_t agsize, -xfs_rfsblock_t *nfree, -struct list_head *buffer_list) +struct xfs_buf *bp, +struct aghdr_init_data *id) { -struct xfs_agf *agf; -struct xfs_agi *agi; -struct xfs_agfl *agfl; -__be32 *agfl_bno; -xfs_alloc_rec_t *arec; -struct xfs_buf *bp; -int bucket; -xfs_extlen_t tmpsize; -int error =0 ; +xfs_btree_init_block (mp, bp, id->type,0 ,0 , id->agno,0 ); +} + +/* +* Alloc btree root block init functions +*/ +static void +xfs_bnoroot_init ( +struct xfs_mount *mp, +struct xfs_buf *bp, +struct aghdr_init_data *id) +{ +struct xfs_alloc_rec *arec; + +xfs_btree_init_block (mp, bp,XFS_BTNUM_BNO ,0 ,1 , id->agno,0 ); + arec =XFS_ALLOC_REC_ADDR (mp,XFS_BUF_TO_BLOCK (bp),1 ); + arec->ar_startblock =cpu_to_be32 (mp->m_ag_prealloc_blocks); + arec->ar_blockcount =cpu_to_be32 (id->agsize - +be32_to_cpu (arec->ar_startblock)); +} + +static void +xfs_cntroot_init ( +struct xfs_mount *mp, +struct xfs_buf *bp, +struct aghdr_init_data *id) +{ +struct xfs_alloc_rec *arec; + +xfs_btree_init_block (mp, bp,XFS_BTNUM_CNT ,0 ,1 , id->agno,0 ); + arec =XFS_ALLOC_REC_ADDR (mp,XFS_BUF_TO_BLOCK (bp),1 ); + arec->ar_startblock =cpu_to_be32 (mp->m_ag_prealloc_blocks); + arec->ar_blockcount =cpu_to_be32 (id->agsize - +be32_to_cpu (arec->ar_startblock)); +} + +/* +* Reverse map root block init +*/ +static void +xfs_rmaproot_init ( +struct xfs_mount *mp, +struct xfs_buf *bp, +struct aghdr_init_data *id) +{ +struct xfs_btree_block *block =XFS_BUF_TO_BLOCK (bp); +struct xfs_rmap_rec *rrec; + +xfs_btree_init_block (mp, bp,XFS_BTNUM_RMAP ,0 ,4 , id->agno,0 );/* -* AG freespace header block +* mark the AG header regions as static metadata The BNO +* btree block is the first block after the headers, so +* it's location defines the size of region the static +* metadata consumes. +* +* Note: unlike mkfs, we never have to account for log +* space when growing the data regions */ - bp =xfs_growfs_get_hdr_buf (mp, -XFS_AG_DADDR (mp, agno,XFS_AGF_DADDR (mp)), -XFS_FSS_TO_BB (mp,1 ),0 , - &xfs_agf_buf_ops); -if (!bp) { - error = -ENOMEM ; - goto out_error; + rrec =XFS_RMAP_REC_ADDR (block,1 ); + rrec->rm_startblock =0 ; + rrec->rm_blockcount =cpu_to_be32 (XFS_BNO_BLOCK (mp)); + rrec->rm_owner =cpu_to_be64 (XFS_RMAP_OWN_FS ); + rrec->rm_offset =0 ; + +/* account freespace btree root blocks */ + rrec =XFS_RMAP_REC_ADDR (block,2 ); + rrec->rm_startblock =cpu_to_be32 (XFS_BNO_BLOCK (mp)); + rrec->rm_blockcount =cpu_to_be32 (2 ); + rrec->rm_owner =cpu_to_be64 (XFS_RMAP_OWN_AG ); + rrec->rm_offset =0 ; + +/* account inode btree root blocks */ + rrec =XFS_RMAP_REC_ADDR (block,3 ); + rrec->rm_startblock =cpu_to_be32 (XFS_IBT_BLOCK (mp)); + rrec->rm_blockcount =cpu_to_be32 (XFS_RMAP_BLOCK (mp) - +XFS_IBT_BLOCK (mp)); + rrec->rm_owner =cpu_to_be64 (XFS_RMAP_OWN_INOBT ); + rrec->rm_offset =0 ; + +/* account for rmap btree root */ + rrec =XFS_RMAP_REC_ADDR (block,4 ); + rrec->rm_startblock =cpu_to_be32 (XFS_RMAP_BLOCK (mp)); + rrec->rm_blockcount =cpu_to_be32 (1 ); + rrec->rm_owner =cpu_to_be64 (XFS_RMAP_OWN_AG ); + rrec->rm_offset =0 ; + +/* account for refc btree root */ +if (xfs_sb_version_hasreflink (&mp->m_sb)) { + rrec =XFS_RMAP_REC_ADDR (block,5 ); + rrec->rm_startblock =cpu_to_be32 (xfs_refc_block (mp)); + rrec->rm_blockcount =cpu_to_be32 (1 ); + rrec->rm_owner =cpu_to_be64 (XFS_RMAP_OWN_REFC ); + rrec->rm_offset =0 ; +be16_add_cpu (&block->bb_numrecs,1 ); } +} + + +static void +xfs_agfblock_init ( +struct xfs_mount *mp, +struct xfs_buf *bp, +struct aghdr_init_data *id) +{ +struct xfs_agf *agf =XFS_BUF_TO_AGF (bp); +xfs_extlen_t tmpsize; - agf =XFS_BUF_TO_AGF (bp); agf->agf_magicnum =cpu_to_be32 (XFS_AGF_MAGIC ); agf->agf_versionnum =cpu_to_be32 (XFS_AGF_VERSION ); - agf->agf_seqno =cpu_to_be32 (agno); - agf->agf_length =cpu_to_be32 (agsize); + agf->agf_seqno =cpu_to_be32 (id->agno); + agf->agf_length =cpu_to_be32 (id->agsize); agf->agf_roots[XFS_BTNUM_BNOi] =cpu_to_be32 (XFS_BNO_BLOCK (mp)); agf->agf_roots[XFS_BTNUM_CNTi] =cpu_to_be32 (XFS_CNT_BLOCK (mp)); agf->agf_levels[XFS_BTNUM_BNOi] =cpu_to_be32 (1 );@@ -125,7 +219,7 @@ xfs_grow_ag_headers( agf->agf_flfirst =cpu_to_be32 (1 ); agf->agf_fllast =0 ; agf->agf_flcount =0 ; - tmpsize = agsize - mp->m_ag_prealloc_blocks; + tmpsize = id->agsize - mp->m_ag_prealloc_blocks; agf->agf_freeblks =cpu_to_be32 (tmpsize); agf->agf_longest =cpu_to_be32 (tmpsize);if (xfs_sb_version_hascrc (&mp->m_sb))@@ -136,52 +230,42 @@ xfs_grow_ag_headers( agf->agf_refcount_level =cpu_to_be32 (1 ); agf->agf_refcount_blocks =cpu_to_be32 (1 ); } -xfs_buf_delwri_queue (bp, buffer_list); -xfs_buf_relse (bp); +} -/* -* AG freelist header block -*/ - bp =xfs_growfs_get_hdr_buf (mp, -XFS_AG_DADDR (mp, agno,XFS_AGFL_DADDR (mp)), -XFS_FSS_TO_BB (mp,1 ),0 , - &xfs_agfl_buf_ops); -if (!bp) { - error = -ENOMEM ; - goto out_error; - } +static void +xfs_agflblock_init ( +struct xfs_mount *mp, +struct xfs_buf *bp, +struct aghdr_init_data *id) +{ +struct xfs_agfl *agfl =XFS_BUF_TO_AGFL (bp); +__be32 *agfl_bno; +int bucket; - agfl =XFS_BUF_TO_AGFL (bp);if (xfs_sb_version_hascrc (&mp->m_sb)) { agfl->agfl_magicnum =cpu_to_be32 (XFS_AGFL_MAGIC ); - agfl->agfl_seqno =cpu_to_be32 (agno); + agfl->agfl_seqno =cpu_to_be32 (id->agno);uuid_copy (&agfl->agfl_uuid, &mp->m_sb.sb_meta_uuid); } agfl_bno =XFS_BUF_TO_AGFL_BNO (mp, bp);for (bucket =0 ; bucket <xfs_agfl_size (mp); bucket++) agfl_bno[bucket] =cpu_to_be32 (NULLAGBLOCK ); +} -xfs_buf_delwri_queue (bp, buffer_list); -xfs_buf_relse (bp); - -/* -* AG inode header block -*/ - bp =xfs_growfs_get_hdr_buf (mp, -XFS_AG_DADDR (mp, agno,XFS_AGI_DADDR (mp)), -XFS_FSS_TO_BB (mp,1 ),0 , - &xfs_agi_buf_ops); -if (!bp) { - error = -ENOMEM ; - goto out_error; - } +static void +xfs_agiblock_init ( +struct xfs_mount *mp, +struct xfs_buf *bp, +struct aghdr_init_data *id) +{ +struct xfs_agi *agi =XFS_BUF_TO_AGI (bp); +int bucket; - agi =XFS_BUF_TO_AGI (bp); agi->agi_magicnum =cpu_to_be32 (XFS_AGI_MAGIC ); agi->agi_versionnum =cpu_to_be32 (XFS_AGI_VERSION ); - agi->agi_seqno =cpu_to_be32 (agno); - agi->agi_length =cpu_to_be32 (agsize); + agi->agi_seqno =cpu_to_be32 (id->agno); + agi->agi_length =cpu_to_be32 (id->agsize); agi->agi_count =0 ; agi->agi_root =cpu_to_be32 (XFS_IBT_BLOCK (mp)); agi->agi_level =cpu_to_be32 (1 );@@ -196,180 +280,133 @@ xfs_grow_ag_headers( }for (bucket =0 ; bucket <XFS_AGI_UNLINKED_BUCKETS ; bucket++) agi->agi_unlinked[bucket] =cpu_to_be32 (NULLAGINO ); +} -xfs_buf_delwri_queue (bp, buffer_list); -xfs_buf_relse (bp); - -/* -* BNO btree root block -*/ - bp =xfs_growfs_get_hdr_buf (mp, -XFS_AGB_TO_DADDR (mp, agno,XFS_BNO_BLOCK (mp)), -BTOBB (mp->m_sb.sb_blocksize),0 , - &xfs_allocbt_buf_ops); +static int +xfs_growfs_init_aghdr ( +struct xfs_mount *mp, +struct aghdr_init_data *id, +void (*work)(struct xfs_mount *,struct xfs_buf *, +struct aghdr_init_data *), +const struct xfs_buf_ops *ops) -if (!bp) { - error = -ENOMEM ; - goto out_error; - } +{ +struct xfs_buf *bp; -xfs_btree_init_block (mp, bp,XFS_BTNUM_BNO ,0 ,1 , agno,0 ); + bp =xfs_growfs_get_hdr_buf (mp, id->daddr, id->numblks,0 , ops); +if (!bp) +return -ENOMEM ; - arec =XFS_ALLOC_REC_ADDR (mp,XFS_BUF_TO_BLOCK (bp),1 ); - arec->ar_startblock =cpu_to_be32 (mp->m_ag_prealloc_blocks); - arec->ar_blockcount =cpu_to_be32 ( - agsize -be32_to_cpu (arec->ar_startblock)); + (*work)(mp, bp, id); -xfs_buf_delwri_queue (bp, buffer_list); +xfs_buf_delwri_queue (bp, &id->buffer_list);xfs_buf_relse (bp); +return 0 ; +} -/* -* CNT btree root block -*/ - bp =xfs_growfs_get_hdr_buf (mp, -XFS_AGB_TO_DADDR (mp, agno,XFS_CNT_BLOCK (mp)), -BTOBB (mp->m_sb.sb_blocksize),0 , - &xfs_allocbt_buf_ops); -if (!bp) { - error = -ENOMEM ; - goto out_error; - } - -xfs_btree_init_block (mp, bp,XFS_BTNUM_CNT ,0 ,1 , agno,0 ); +/* +* Write new AG headers to disk. Non-transactional, but written +* synchronously so they are completed prior to the growfs transaction +* being logged. +*/ +static int +xfs_grow_ag_headers ( +struct xfs_mount *mp, +struct aghdr_init_data *id) - arec =XFS_ALLOC_REC_ADDR (mp,XFS_BUF_TO_BLOCK (bp),1 ); - arec->ar_startblock =cpu_to_be32 (mp->m_ag_prealloc_blocks); - arec->ar_blockcount =cpu_to_be32 ( - agsize -be32_to_cpu (arec->ar_startblock)); - *nfree +=be32_to_cpu (arec->ar_blockcount); +{ +int error =0 ; -xfs_buf_delwri_queue (bp, buffer_list); -xfs_buf_relse (bp); +/* Account for AG free space in new AG */ + id->nfree += id->agsize - mp->m_ag_prealloc_blocks; -/* RMAP btree root block */ -if (xfs_sb_version_hasrmapbt (&mp->m_sb)) { -struct xfs_rmap_rec *rrec; -struct xfs_btree_block *block; - - bp =xfs_growfs_get_hdr_buf (mp, -XFS_AGB_TO_DADDR (mp, agno,XFS_RMAP_BLOCK (mp)), -BTOBB (mp->m_sb.sb_blocksize),0 , - &xfs_rmapbt_buf_ops); -if (!bp) { - error = -ENOMEM ; - goto out_error; - } +/* AG freespace header block */ + id->daddr =XFS_AG_DADDR (mp, id->agno,XFS_AGF_DADDR (mp)); + id->numblks =XFS_FSS_TO_BB (mp,1 ); + error =xfs_growfs_init_aghdr (mp, id, xfs_agfblock_init, + &xfs_agf_buf_ops); +if (error) + goto out_error; -xfs_btree_init_block (mp, bp,XFS_BTNUM_RMAP ,0 ,0 , - agno,0 ); - block =XFS_BUF_TO_BLOCK (bp); +/* AG freelist header block */ + id->daddr =XFS_AG_DADDR (mp, id->agno,XFS_AGFL_DADDR (mp)); + id->numblks =XFS_FSS_TO_BB (mp,1 ); + error =xfs_growfs_init_aghdr (mp, id, xfs_agflblock_init, + &xfs_agfl_buf_ops); +if (error) + goto out_error; +/* AG inode header block */ + id->daddr =XFS_AG_DADDR (mp, id->agno,XFS_AGI_DADDR (mp)); + id->numblks =XFS_FSS_TO_BB (mp,1 ); + error =xfs_growfs_init_aghdr (mp, id, xfs_agiblock_init, + &xfs_agi_buf_ops); +if (error) + goto out_error; -/* -* mark the AG header regions as static metadata The BNO -* btree block is the first block after the headers, so -* it's location defines the size of region the static -* metadata consumes. -* -* Note: unlike mkfs, we never have to account for log -* space when growing the data regions -*/ - rrec =XFS_RMAP_REC_ADDR (block,1 ); - rrec->rm_startblock =0 ; - rrec->rm_blockcount =cpu_to_be32 (XFS_BNO_BLOCK (mp)); - rrec->rm_owner =cpu_to_be64 (XFS_RMAP_OWN_FS ); - rrec->rm_offset =0 ; -be16_add_cpu (&block->bb_numrecs,1 ); -/* account freespace btree root blocks */ - rrec =XFS_RMAP_REC_ADDR (block,2 ); - rrec->rm_startblock =cpu_to_be32 (XFS_BNO_BLOCK (mp)); - rrec->rm_blockcount =cpu_to_be32 (2 ); - rrec->rm_owner =cpu_to_be64 (XFS_RMAP_OWN_AG ); - rrec->rm_offset =0 ; -be16_add_cpu (&block->bb_numrecs,1 ); +/* BNO btree root block */ + id->daddr =XFS_AGB_TO_DADDR (mp, id->agno,XFS_BNO_BLOCK (mp)); + id->numblks =BTOBB (mp->m_sb.sb_blocksize); + error =xfs_growfs_init_aghdr (mp, id, xfs_bnoroot_init, + &xfs_allocbt_buf_ops); +if (error) + goto out_error; -/* account inode btree root blocks */ - rrec =XFS_RMAP_REC_ADDR (block,3 ); - rrec->rm_startblock =cpu_to_be32 (XFS_IBT_BLOCK (mp)); - rrec->rm_blockcount =cpu_to_be32 (XFS_RMAP_BLOCK (mp) - -XFS_IBT_BLOCK (mp)); - rrec->rm_owner =cpu_to_be64 (XFS_RMAP_OWN_INOBT ); - rrec->rm_offset =0 ; -be16_add_cpu (&block->bb_numrecs,1 ); -/* account for rmap btree root */ - rrec =XFS_RMAP_REC_ADDR (block,4 ); - rrec->rm_startblock =cpu_to_be32 (XFS_RMAP_BLOCK (mp)); - rrec->rm_blockcount =cpu_to_be32 (1 ); - rrec->rm_owner =cpu_to_be64 (XFS_RMAP_OWN_AG ); - rrec->rm_offset =0 ; -be16_add_cpu (&block->bb_numrecs,1 ); +/* CNT btree root block */ + id->daddr =XFS_AGB_TO_DADDR (mp, id->agno,XFS_CNT_BLOCK (mp)); + id->numblks =BTOBB (mp->m_sb.sb_blocksize); + error =xfs_growfs_init_aghdr (mp, id, xfs_cntroot_init, + &xfs_allocbt_buf_ops); +if (error) + goto out_error; -/* account for refc btree root */ -if (xfs_sb_version_hasreflink (&mp->m_sb)) { - rrec =XFS_RMAP_REC_ADDR (block,5 ); - rrec->rm_startblock =cpu_to_be32 (xfs_refc_block (mp)); - rrec->rm_blockcount =cpu_to_be32 (1 ); - rrec->rm_owner =cpu_to_be64 (XFS_RMAP_OWN_REFC ); - rrec->rm_offset =0 ; -be16_add_cpu (&block->bb_numrecs,1 ); - } +/* RMAP btree root block */ +if (xfs_sb_version_hasrmapbt (&mp->m_sb)) { + id->daddr =XFS_AGB_TO_DADDR (mp, id->agno,XFS_RMAP_BLOCK (mp)); + id->numblks =BTOBB (mp->m_sb.sb_blocksize); + error =xfs_growfs_init_aghdr (mp, id, xfs_rmaproot_init, + &xfs_rmapbt_buf_ops); +if (error) + goto out_error; -xfs_buf_delwri_queue (bp, buffer_list); -xfs_buf_relse (bp); } -/* -* INO btree root block -*/ - bp =xfs_growfs_get_hdr_buf (mp, -XFS_AGB_TO_DADDR (mp, agno,XFS_IBT_BLOCK (mp)), -BTOBB (mp->m_sb.sb_blocksize),0 , - &xfs_inobt_buf_ops); -if (!bp) { - error = -ENOMEM ; +/* INO btree root block */ + id->daddr =XFS_AGB_TO_DADDR (mp, id->agno,XFS_IBT_BLOCK (mp)); + id->numblks =BTOBB (mp->m_sb.sb_blocksize); + id->type =XFS_BTNUM_INO ; + error =xfs_growfs_init_aghdr (mp, id, xfs_btroot_init, + &xfs_inobt_buf_ops); +if (error) goto out_error; - } -xfs_btree_init_block (mp, bp,XFS_BTNUM_INO ,0 ,0 , agno,0 ); -xfs_buf_delwri_queue (bp, buffer_list); -xfs_buf_relse (bp);/* * FINO btree root block */ if (xfs_sb_version_hasfinobt (&mp->m_sb)) { - bp =xfs_growfs_get_hdr_buf (mp, -XFS_AGB_TO_DADDR (mp, agno,XFS_FIBT_BLOCK (mp)), -BTOBB (mp->m_sb.sb_blocksize),0 , - &xfs_inobt_buf_ops); -if (!bp) { - error = -ENOMEM ; + id->daddr =XFS_AGB_TO_DADDR (mp, id->agno,XFS_FIBT_BLOCK (mp)); + id->numblks =BTOBB (mp->m_sb.sb_blocksize); + id->type =XFS_BTNUM_FINO ; + error =xfs_growfs_init_aghdr (mp, id, xfs_btroot_init, + &xfs_inobt_buf_ops); +if (error) goto out_error; - } - -xfs_btree_init_block (mp, bp,XFS_BTNUM_FINO ,0 ,0 , agno,0 ); -xfs_buf_delwri_queue (bp, buffer_list); -xfs_buf_relse (bp); }/* * refcount btree root block */ if (xfs_sb_version_hasreflink (&mp->m_sb)) { - bp =xfs_growfs_get_hdr_buf (mp, -XFS_AGB_TO_DADDR (mp, agno,xfs_refc_block (mp)), -BTOBB (mp->m_sb.sb_blocksize),0 , - &xfs_refcountbt_buf_ops); -if (!bp) { - error = -ENOMEM ; + id->daddr =XFS_AGB_TO_DADDR (mp, id->agno,xfs_refc_block (mp)); + id->numblks =BTOBB (mp->m_sb.sb_blocksize); + id->type =XFS_BTNUM_REFC ; + error =xfs_growfs_init_aghdr (mp, id, xfs_btroot_init, + &xfs_refcountbt_buf_ops); +if (error) goto out_error; - } - -xfs_btree_init_block (mp, bp,XFS_BTNUM_REFC ,0 ,0 , agno,0 ); -xfs_buf_delwri_queue (bp, buffer_list); -xfs_buf_relse (bp); } out_error:@@ -384,7 +421,6 @@ xfs_growfs_data_private(xfs_agf_t *agf;xfs_agi_t *agi;xfs_agnumber_t agno; -xfs_extlen_t agsize;xfs_buf_t *bp;int dpct;int error, saved_error =0 ;@@ -392,11 +428,11 @@ xfs_growfs_data_private(xfs_agnumber_t nagimax =0 ;xfs_rfsblock_t nb, nb_mod;xfs_rfsblock_t new; -xfs_rfsblock_t nfree;xfs_agnumber_t oagcount;int pct;xfs_trans_t *tp;LIST_HEAD (buffer_list); +struct aghdr_init_data id = {}; nb = in->newblocks; pct = in->imaxpct;@@ -448,27 +484,28 @@ xfs_growfs_data_private(* list to write, we can cancel the entire list without having written * anything. */ - nfree =0 ; -for (agno = nagcount -1 ; agno >= oagcount; agno--, new -= agsize) { - -if (agno == nagcount -1 ) - agsize = nb - - (agno * (xfs_rfsblock_t )mp->m_sb.sb_agblocks); +INIT_LIST_HEAD (&id.buffer_list); +for (id.agno = nagcount -1 ; + id.agno >= oagcount; + id.agno--, new -= id.agsize) { + +if (id.agno == nagcount -1 ) + id.agsize = nb - + (id.agno * (xfs_rfsblock_t )mp->m_sb.sb_agblocks);else - agsize = mp->m_sb.sb_agblocks; + id.agsize = mp->m_sb.sb_agblocks; - error =xfs_grow_ag_headers (mp, agno, agsize, &nfree, - &buffer_list); + error =xfs_grow_ag_headers (mp, &id);if (error) { -xfs_buf_delwri_cancel (&buffer_list); +xfs_buf_delwri_cancel (&id.buffer_list); goto error0; } } - error =xfs_buf_delwri_submit (&buffer_list); + error =xfs_buf_delwri_submit (&id.buffer_list);if (error) goto error0; -xfs_trans_agblocks_delta (tp, nfree); +xfs_trans_agblocks_delta (tp, id.nfree);/* * There are new blocks in the old last a.g. @@ -479,7 +516,7 @@ xfs_growfs_data_private(/* * Change the agi length. */ - error =xfs_ialloc_read_agi (mp, tp, agno, &bp); + error =xfs_ialloc_read_agi (mp, tp, id.agno, &bp);if (error) { goto error0; }@@ -492,7 +529,7 @@ xfs_growfs_data_private(/* * Change agf length. */ - error =xfs_alloc_read_agf (mp, tp, agno,0 , &bp); + error =xfs_alloc_read_agf (mp, tp, id.agno,0 , &bp);if (error) { goto error0; }@@ -511,13 +548,13 @@ xfs_growfs_data_private(* this doesn't actually exist in the rmap btree. */ xfs_rmap_ag_owner (&oinfo,XFS_RMAP_OWN_NULL ); - error =xfs_rmap_free (tp, bp, agno, + error =xfs_rmap_free (tp, bp, id.agno,be32_to_cpu (agf->agf_length) - new, new, &oinfo);if (error) goto error0; error =xfs_free_extent (tp, -XFS_AGB_TO_FSB (mp, agno, +XFS_AGB_TO_FSB (mp, id.agno,be32_to_cpu (agf->agf_length) - new), new, &oinfo,XFS_AG_RESV_NONE );if (error)@@ -534,8 +571,8 @@ xfs_growfs_data_private(if (nb > mp->m_sb.sb_dblocks)xfs_trans_mod_sb (tp,XFS_TRANS_SB_DBLOCKS , nb - mp->m_sb.sb_dblocks); -if (nfree) -xfs_trans_mod_sb (tp,XFS_TRANS_SB_FDBLOCKS , nfree); +if (id.nfree) +xfs_trans_mod_sb (tp,XFS_TRANS_SB_FDBLOCKS , id.nfree);if (dpct)xfs_trans_mod_sb (tp,XFS_TRANS_SB_IMAXPCT , dpct);xfs_trans_set_sync (tp);@@ -562,7 +599,7 @@ xfs_growfs_data_private(if (new) {struct xfs_perag *pag; - pag =xfs_perag_get (mp, agno); + pag =xfs_perag_get (mp, id.agno); error =xfs_ag_resv_free (pag);xfs_perag_put (pag);if (error)Signature · 6 lines
2.17.0 -- To unsubscribe from this list: send the line "unsubscribe linux-xfs" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH v3 5/10 xfs: turn ag header initialisation into a table driven operation
In reply to Dave ChinnerFrom: Dave Chinner <[email protected]>
There's still more cookie cutter code in setting up each AG header. Separate all the variables into a simple structure and iterate a table of header definitions to initialise everything.
--- fs/xfs/xfs_fsops.c | 182 +++++++++++++++++++++++---------------------- 1 file changed, 92 insertions(+), 90 deletions(-)
fs/xfs/xfs_fsops.c +92 -90
@@ -282,12 +282,13 @@ xfs_agiblock_init( agi->agi_unlinked[bucket] =cpu_to_be32 (NULLAGINO ); } +typedef void (*aghdr_init_work_f )(struct xfs_mount *mp,struct xfs_buf *bp, +struct aghdr_init_data *id);static int xfs_growfs_init_aghdr (struct xfs_mount *mp,struct aghdr_init_data *id, -void (*work)(struct xfs_mount *,struct xfs_buf *, -struct aghdr_init_data *), +aghdr_init_work_f work,const struct xfs_buf_ops *ops) {
@@ -304,6 +305,15 @@ xfs_growfs_init_aghdr(return 0 ; } +struct xfs_aghdr_grow_data { +xfs_daddr_t daddr; +size_t numblks; +const struct xfs_buf_ops *ops; +aghdr_init_work_f work; +xfs_btnum_t type; +bool need_init; +}; +/* * Write new AG headers to disk. Non-transactional, but written * synchronously so they are completed prior to the growfs transaction
@@ -315,101 +325,93 @@ xfs_grow_ag_headers( struct aghdr_init_data *id) { +struct xfs_aghdr_grow_data aghdr_data[] = { + {/* AGF */ + .daddr =XFS_AG_DADDR (mp, id->agno,XFS_AGF_DADDR (mp)), + .numblks =XFS_FSS_TO_BB (mp,1 ), + .ops = &xfs_agf_buf_ops, + .work = &xfs_agfblock_init, + .need_init = true + }, + {/* AGFL */ + .daddr =XFS_AG_DADDR (mp, id->agno,XFS_AGFL_DADDR (mp)), + .numblks =XFS_FSS_TO_BB (mp,1 ), + .ops = &xfs_agfl_buf_ops, + .work = &xfs_agflblock_init, + .need_init = true + }, + {/* AGI */ + .daddr =XFS_AG_DADDR (mp, id->agno,XFS_AGI_DADDR (mp)), + .numblks =XFS_FSS_TO_BB (mp,1 ), + .ops = &xfs_agi_buf_ops, + .work = &xfs_agiblock_init, + .need_init = true + }, + {/* BNO root block */ + .daddr =XFS_AGB_TO_DADDR (mp, id->agno,XFS_BNO_BLOCK (mp)), + .numblks =BTOBB (mp->m_sb.sb_blocksize), + .ops = &xfs_allocbt_buf_ops, + .work = &xfs_bnoroot_init, + .need_init = true + }, + {/* CNT root block */ + .daddr =XFS_AGB_TO_DADDR (mp, id->agno,XFS_CNT_BLOCK (mp)), + .numblks =BTOBB (mp->m_sb.sb_blocksize), + .ops = &xfs_allocbt_buf_ops, + .work = &xfs_cntroot_init, + .need_init = true + }, + {/* INO root block */ + .daddr =XFS_AGB_TO_DADDR (mp, id->agno,XFS_IBT_BLOCK (mp)), + .numblks =BTOBB (mp->m_sb.sb_blocksize), + .ops = &xfs_inobt_buf_ops, + .work = &xfs_btroot_init, + .type =XFS_BTNUM_INO , + .need_init = true + }, + {/* FINO root block */ + .daddr =XFS_AGB_TO_DADDR (mp, id->agno,XFS_FIBT_BLOCK (mp)), + .numblks =BTOBB (mp->m_sb.sb_blocksize), + .ops = &xfs_inobt_buf_ops, + .work = &xfs_btroot_init, + .type =XFS_BTNUM_FINO , + .need_init =xfs_sb_version_hasfinobt (&mp->m_sb) + }, + {/* RMAP root block */ + .daddr =XFS_AGB_TO_DADDR (mp, id->agno,XFS_RMAP_BLOCK (mp)), + .numblks =BTOBB (mp->m_sb.sb_blocksize), + .ops = &xfs_rmapbt_buf_ops, + .work = &xfs_rmaproot_init, + .need_init =xfs_sb_version_hasrmapbt (&mp->m_sb) + }, + {/* REFC root block */ + .daddr =XFS_AGB_TO_DADDR (mp, id->agno,xfs_refc_block (mp)), + .numblks =BTOBB (mp->m_sb.sb_blocksize), + .ops = &xfs_refcountbt_buf_ops, + .work = &xfs_btroot_init, + .type =XFS_BTNUM_REFC , + .need_init =xfs_sb_version_hasreflink (&mp->m_sb) + }, + {/* NULL terminating block */ + .daddr =XFS_BUF_DADDR_NULL , + } + }; +struct xfs_aghdr_grow_data *dp;int error =0 ;/* Account for AG free space in new AG */ id->nfree += id->agsize - mp->m_ag_prealloc_blocks; +for (dp = &aghdr_data[0 ]; dp->daddr !=XFS_BUF_DADDR_NULL ; dp++) { +if (!dp->need_init) +continue ; -/* AG freespace header block */ - id->daddr =XFS_AG_DADDR (mp, id->agno,XFS_AGF_DADDR (mp)); - id->numblks =XFS_FSS_TO_BB (mp,1 ); - error =xfs_growfs_init_aghdr (mp, id, xfs_agfblock_init, - &xfs_agf_buf_ops); -if (error) - goto out_error; - -/* AG freelist header block */ - id->daddr =XFS_AG_DADDR (mp, id->agno,XFS_AGFL_DADDR (mp)); - id->numblks =XFS_FSS_TO_BB (mp,1 ); - error =xfs_growfs_init_aghdr (mp, id, xfs_agflblock_init, - &xfs_agfl_buf_ops); -if (error) - goto out_error; - -/* AG inode header block */ - id->daddr =XFS_AG_DADDR (mp, id->agno,XFS_AGI_DADDR (mp)); - id->numblks =XFS_FSS_TO_BB (mp,1 ); - error =xfs_growfs_init_aghdr (mp, id, xfs_agiblock_init, - &xfs_agi_buf_ops); -if (error) - goto out_error; - - -/* BNO btree root block */ - id->daddr =XFS_AGB_TO_DADDR (mp, id->agno,XFS_BNO_BLOCK (mp)); - id->numblks =BTOBB (mp->m_sb.sb_blocksize); - error =xfs_growfs_init_aghdr (mp, id, xfs_bnoroot_init, - &xfs_allocbt_buf_ops); -if (error) - goto out_error; - - -/* CNT btree root block */ - id->daddr =XFS_AGB_TO_DADDR (mp, id->agno,XFS_CNT_BLOCK (mp)); - id->numblks =BTOBB (mp->m_sb.sb_blocksize); - error =xfs_growfs_init_aghdr (mp, id, xfs_cntroot_init, - &xfs_allocbt_buf_ops); -if (error) - goto out_error; - -/* RMAP btree root block */ -if (xfs_sb_version_hasrmapbt (&mp->m_sb)) { - id->daddr =XFS_AGB_TO_DADDR (mp, id->agno,XFS_RMAP_BLOCK (mp)); - id->numblks =BTOBB (mp->m_sb.sb_blocksize); - error =xfs_growfs_init_aghdr (mp, id, xfs_rmaproot_init, - &xfs_rmapbt_buf_ops); -if (error) - goto out_error; - - } - -/* INO btree root block */ - id->daddr =XFS_AGB_TO_DADDR (mp, id->agno,XFS_IBT_BLOCK (mp)); - id->numblks =BTOBB (mp->m_sb.sb_blocksize); - id->type =XFS_BTNUM_INO ; - error =xfs_growfs_init_aghdr (mp, id, xfs_btroot_init, - &xfs_inobt_buf_ops); -if (error) - goto out_error; - - -/* -* FINO btree root block -*/ -if (xfs_sb_version_hasfinobt (&mp->m_sb)) { - id->daddr =XFS_AGB_TO_DADDR (mp, id->agno,XFS_FIBT_BLOCK (mp)); - id->numblks =BTOBB (mp->m_sb.sb_blocksize); - id->type =XFS_BTNUM_FINO ; - error =xfs_growfs_init_aghdr (mp, id, xfs_btroot_init, - &xfs_inobt_buf_ops); -if (error) - goto out_error; - } - -/* -* refcount btree root block -*/ -if (xfs_sb_version_hasreflink (&mp->m_sb)) { - id->daddr =XFS_AGB_TO_DADDR (mp, id->agno,xfs_refc_block (mp)); - id->numblks =BTOBB (mp->m_sb.sb_blocksize); - id->type =XFS_BTNUM_REFC ; - error =xfs_growfs_init_aghdr (mp, id, xfs_btroot_init, - &xfs_refcountbt_buf_ops); + id->daddr = dp->daddr; + id->numblks = dp->numblks; + id->type = dp->type; + error =xfs_growfs_init_aghdr (mp, id, dp->work, dp->ops);if (error) - goto out_error; +break ; } - -out_error:return error; }
Signature · 1 line
2.17.0
Re: [PATCH 05/10] xfs: turn ag header initialisation into a table driven operation
Quoted 108 lines · Dave Chinner
From: Dave Chinner <[email protected]>
There's still more cookie cutter code in setting up each AG header. Separate all the variables into a simple structure and iterate a table of header definitions to initialise everything.
Signed-off-by Dave Chinner <[email protected]>Reviewed-by Brian Foster <[email protected]>--- fs/xfs/xfs_fsops.c | 182 +++++++++++++++++++++++---------------------- 1 file changed, 92 insertions(+), 90 deletions(-)fs/xfs/xfs_fsops.c +68
-2@@ -282,12 +282,13 @@ xfs_agiblock_init( agi->agi_unlinked[bucket] =cpu_to_be32 (NULLAGINO ); } +typedef void (*aghdr_init_work_f )(struct xfs_mount *mp,struct xfs_buf *bp, +struct aghdr_init_data *id);static int xfs_growfs_init_aghdr (struct xfs_mount *mp,struct aghdr_init_data *id, -void (*work)(struct xfs_mount *,struct xfs_buf *, -struct aghdr_init_data *), +aghdr_init_work_f work,const struct xfs_buf_ops *ops) {@@ -304,6 +305,15 @@ xfs_growfs_init_aghdr(return 0 ; } +struct xfs_aghdr_grow_data { +xfs_daddr_t daddr; +size_t numblks; +const struct xfs_buf_ops *ops; +aghdr_init_work_f work; +xfs_btnum_t type; +bool need_init; +}; +/* * Write new AG headers to disk. Non-transactional, but written * synchronously so they are completed prior to the growfs transaction @@ -315,101 +325,93 @@ xfs_grow_ag_headers( struct aghdr_init_data *id) { +struct xfs_aghdr_grow_data aghdr_data[] = { + {/* AGF */ + .daddr =XFS_AG_DADDR (mp, id->agno,XFS_AGF_DADDR (mp)), + .numblks =XFS_FSS_TO_BB (mp,1 ), + .ops = &xfs_agf_buf_ops, + .work = &xfs_agfblock_init, + .need_init = true + }, + {/* AGFL */ + .daddr =XFS_AG_DADDR (mp, id->agno,XFS_AGFL_DADDR (mp)), + .numblks =XFS_FSS_TO_BB (mp,1 ), + .ops = &xfs_agfl_buf_ops, + .work = &xfs_agflblock_init, + .need_init = true + }, + {/* AGI */ + .daddr =XFS_AG_DADDR (mp, id->agno,XFS_AGI_DADDR (mp)), + .numblks =XFS_FSS_TO_BB (mp,1 ), + .ops = &xfs_agi_buf_ops, + .work = &xfs_agiblock_init, + .need_init = true + }, + {/* BNO root block */ + .daddr =XFS_AGB_TO_DADDR (mp, id->agno,XFS_BNO_BLOCK (mp)), + .numblks =BTOBB (mp->m_sb.sb_blocksize), + .ops = &xfs_allocbt_buf_ops, + .work = &xfs_bnoroot_init, + .need_init = true + }, + {/* CNT root block */ + .daddr =XFS_AGB_TO_DADDR (mp, id->agno,XFS_CNT_BLOCK (mp)), + .numblks =BTOBB (mp->m_sb.sb_blocksize), + .ops = &xfs_allocbt_buf_ops, + .work = &xfs_cntroot_init, + .need_init = true + }, + {/* INO root block */ + .daddr =XFS_AGB_TO_DADDR (mp, id->agno,XFS_IBT_BLOCK (mp)), + .numblks =BTOBB (mp->m_sb.sb_blocksize), + .ops = &xfs_inobt_buf_ops, + .work = &xfs_btroot_init, + .type =XFS_BTNUM_INO , + .need_init = true + }, + {/* FINO root block */ + .daddr =XFS_AGB_TO_DADDR (mp, id->agno,XFS_FIBT_BLOCK (mp)), + .numblks =BTOBB (mp->m_sb.sb_blocksize), + .ops = &xfs_inobt_buf_ops, + .work = &xfs_btroot_init, + .type =XFS_BTNUM_FINO , + .need_init =xfs_sb_version_hasfinobt (&mp->m_sb) + }, + {/* RMAP root block */ + .daddr =XFS_AGB_TO_DADDR (mp, id->agno,XFS_RMAP_BLOCK (mp)), + .numblks =BTOBB (mp->m_sb.sb_blocksize), + .ops = &xfs_rmapbt_buf_ops,
fs/xfs/xfs_fsops.c xfs_grow_ag_headers( · line 393
Quoted 10 lines
fs/xfs/xfs_fsops.c +10
-0+ .work = &xfs_rmaproot_init, + .need_init = xfs_sb_version_hasrmapbt(&mp->m_sb) + }, + {/* REFC root block */ + .daddr = XFS_AGB_TO_DADDR(mp, id->agno, xfs_refc_block(mp)), + .numblks = BTOBB(mp->m_sb.sb_blocksize), + .ops = &xfs_refcountbt_buf_ops, + .work = &xfs_btroot_init, + .type =XFS_BTNUM_REFC , + .need_init = xfs_sb_version_hasreflink(&mp->m_sb)
Muuuuch easier to read,
--D
Quoted 119 lines
fs/xfs/xfs_fsops.c +14
-88+ }, + {/* NULL terminating block */ + .daddr = XFS_BUF_DADDR_NULL, + } + }; +struct xfs_aghdr_grow_data *dp;int error =0 ;/* Account for AG free space in new AG */ id->nfree += id->agsize - mp->m_ag_prealloc_blocks; +for (dp = &aghdr_data[0 ]; dp->daddr !=XFS_BUF_DADDR_NULL ; dp++) { +if (!dp->need_init) +continue ; -/* AG freespace header block */ - id->daddr =XFS_AG_DADDR (mp, id->agno,XFS_AGF_DADDR (mp)); - id->numblks =XFS_FSS_TO_BB (mp,1 ); - error =xfs_growfs_init_aghdr (mp, id, xfs_agfblock_init, - &xfs_agf_buf_ops); -if (error) - goto out_error; - -/* AG freelist header block */ - id->daddr =XFS_AG_DADDR (mp, id->agno,XFS_AGFL_DADDR (mp)); - id->numblks =XFS_FSS_TO_BB (mp,1 ); - error =xfs_growfs_init_aghdr (mp, id, xfs_agflblock_init, - &xfs_agfl_buf_ops); -if (error) - goto out_error; - -/* AG inode header block */ - id->daddr =XFS_AG_DADDR (mp, id->agno,XFS_AGI_DADDR (mp)); - id->numblks =XFS_FSS_TO_BB (mp,1 ); - error =xfs_growfs_init_aghdr (mp, id, xfs_agiblock_init, - &xfs_agi_buf_ops); -if (error) - goto out_error; - - -/* BNO btree root block */ - id->daddr =XFS_AGB_TO_DADDR (mp, id->agno,XFS_BNO_BLOCK (mp)); - id->numblks =BTOBB (mp->m_sb.sb_blocksize); - error =xfs_growfs_init_aghdr (mp, id, xfs_bnoroot_init, - &xfs_allocbt_buf_ops); -if (error) - goto out_error; - - -/* CNT btree root block */ - id->daddr =XFS_AGB_TO_DADDR (mp, id->agno,XFS_CNT_BLOCK (mp)); - id->numblks =BTOBB (mp->m_sb.sb_blocksize); - error =xfs_growfs_init_aghdr (mp, id, xfs_cntroot_init, - &xfs_allocbt_buf_ops); -if (error) - goto out_error; - -/* RMAP btree root block */ -if (xfs_sb_version_hasrmapbt (&mp->m_sb)) { - id->daddr =XFS_AGB_TO_DADDR (mp, id->agno,XFS_RMAP_BLOCK (mp)); - id->numblks =BTOBB (mp->m_sb.sb_blocksize); - error =xfs_growfs_init_aghdr (mp, id, xfs_rmaproot_init, - &xfs_rmapbt_buf_ops); -if (error) - goto out_error; - - } - -/* INO btree root block */ - id->daddr =XFS_AGB_TO_DADDR (mp, id->agno,XFS_IBT_BLOCK (mp)); - id->numblks =BTOBB (mp->m_sb.sb_blocksize); - id->type =XFS_BTNUM_INO ; - error =xfs_growfs_init_aghdr (mp, id, xfs_btroot_init, - &xfs_inobt_buf_ops); -if (error) - goto out_error; - - -/* -* FINO btree root block -*/ -if (xfs_sb_version_hasfinobt (&mp->m_sb)) { - id->daddr =XFS_AGB_TO_DADDR (mp, id->agno,XFS_FIBT_BLOCK (mp)); - id->numblks =BTOBB (mp->m_sb.sb_blocksize); - id->type =XFS_BTNUM_FINO ; - error =xfs_growfs_init_aghdr (mp, id, xfs_btroot_init, - &xfs_inobt_buf_ops); -if (error) - goto out_error; - } - -/* -* refcount btree root block -*/ -if (xfs_sb_version_hasreflink (&mp->m_sb)) { - id->daddr =XFS_AGB_TO_DADDR (mp, id->agno,xfs_refc_block (mp)); - id->numblks =BTOBB (mp->m_sb.sb_blocksize); - id->type =XFS_BTNUM_REFC ; - error =xfs_growfs_init_aghdr (mp, id, xfs_btroot_init, - &xfs_refcountbt_buf_ops); + id->daddr = dp->daddr; + id->numblks = dp->numblks; + id->type = dp->type; + error =xfs_growfs_init_aghdr (mp, id, dp->work, dp->ops);if (error) - goto out_error; +break ; } - -out_error:return error; }Signature · 6 lines
2.17.0 -- To unsubscribe from this list: send the line "unsubscribe linux-xfs" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH v3 6/10 xfs: make imaxpct changes in growfs separate
In reply to Dave ChinnerFrom: Dave Chinner <[email protected]>
When growfs changes the imaxpct value of the filesystem, it runs through all the "change size" growfs code, whether it needs to or not. Separate out changing imaxpct into it's own function and transaction to simplify the rest of the growfs code.
--- fs/xfs/xfs_fsops.c | 69 +++++++++++++++++++++++++++++++++------------- 1 file changed, 50 insertions(+), 19 deletions(-)
fs/xfs/xfs_fsops.c +50 -19
@@ -424,25 +424,21 @@ xfs_growfs_data_private(xfs_agi_t *agi;xfs_agnumber_t agno;xfs_buf_t *bp; -int dpct;int error, saved_error =0 ;xfs_agnumber_t nagcount;xfs_agnumber_t nagimax =0 ;xfs_rfsblock_t nb, nb_mod;xfs_rfsblock_t new;xfs_agnumber_t oagcount; -int pct;xfs_trans_t *tp;LIST_HEAD (buffer_list);struct aghdr_init_data id = {}; nb = in->newblocks; - pct = in->imaxpct; -if (nb < mp->m_sb.sb_dblocks || pct <0 || pct >100 ) +if (nb < mp->m_sb.sb_dblocks)return -EINVAL ;if ((error =xfs_sb_validate_fsb_count (&mp->m_sb, nb)))return error; - dpct = pct - mp->m_sb.sb_imax_pct; error =xfs_buf_read_uncached (mp->m_ddev_targp,XFS_FSB_TO_BB (mp, nb) -XFS_FSS_TO_BB (mp,1 ),XFS_FSS_TO_BB (mp,1 ),0 , &bp,NULL );
@@ -575,8 +571,6 @@ xfs_growfs_data_private( nb - mp->m_sb.sb_dblocks);if (id.nfree)xfs_trans_mod_sb (tp,XFS_TRANS_SB_FDBLOCKS , id.nfree); -if (dpct) -xfs_trans_mod_sb (tp,XFS_TRANS_SB_IMAXPCT , dpct);xfs_trans_set_sync (tp); error =xfs_trans_commit (tp);if (error)
@@ -585,12 +579,6 @@ xfs_growfs_data_private(/* New allocation groups fully initialized, so update mount struct */ if (nagimax) mp->m_maxagi = nagimax; -if (mp->m_sb.sb_imax_pct) { -uint64_t icount = mp->m_sb.sb_dblocks * mp->m_sb.sb_imax_pct; -do_div (icount,100 ); - mp->m_maxicount = icount << mp->m_sb.sb_inopblog; - }else - mp->m_maxicount =0 ;xfs_set_low_space_thresholds (mp); mp->m_alloc_set_aside =xfs_alloc_set_aside (mp);
@@ -694,25 +682,68 @@ xfs_growfs_log_private(return -ENOSYS ; } +static int +xfs_growfs_imaxpct ( +struct xfs_mount *mp, +__u32 imaxpct) +{ +struct xfs_trans *tp; +int64_t dpct; +int error; + +if (imaxpct >100 ) +return -EINVAL ; + + error =xfs_trans_alloc (mp, &M_RES (mp)->tr_growdata, +XFS_GROWFS_SPACE_RES (mp),0 ,XFS_TRANS_RESERVE , &tp); +if (error) +return error; + + dpct = (int64_t )imaxpct - mp->m_sb.sb_imax_pct; +xfs_trans_mod_sb (tp,XFS_TRANS_SB_IMAXPCT , dpct); +xfs_trans_set_sync (tp); +return xfs_trans_commit (tp); +} +/* * protected versions of growfs function acquire and release locks on the mount * point - exported through ioctls: XFS_IOC_FSGROWFSDATA, XFS_IOC_FSGROWFSLOG, * XFS_IOC_FSGROWFSRT */ - -int xfs_growfs_data ( -xfs_mount_t *mp, -xfs_growfs_data_t *in) +struct xfs_mount *mp, +struct xfs_growfs_data *in) { -int error; +int error =0 ;if (!capable (CAP_SYS_ADMIN ))return -EPERM ;if (!mutex_trylock (&mp->m_growlock))return -EWOULDBLOCK ; - error =xfs_growfs_data_private (mp, in); + +/* update imaxpct separately to the physical grow of the filesystem */ +if (in->imaxpct != mp->m_sb.sb_imax_pct) { + error =xfs_growfs_imaxpct (mp, in->imaxpct); +if (error) + goto out_error; + } + +if (in->newblocks != mp->m_sb.sb_dblocks) { + error =xfs_growfs_data_private (mp, in); +if (error) + goto out_error; + } + +/* Post growfs calculations needed to reflect new state in operations */ +if (mp->m_sb.sb_imax_pct) { +uint64_t icount = mp->m_sb.sb_dblocks * mp->m_sb.sb_imax_pct; +do_div (icount,100 ); + mp->m_maxicount = icount << mp->m_sb.sb_inopblog; + }else + mp->m_maxicount =0 ; + +out_error:/* * Increment the generation unconditionally, the error could be from * updating the secondary superblocks, in which case the new size
Signature · 1 line
2.17.0
PATCH v3 7/10 xfs: separate secondary sb update in growfs
In reply to Dave ChinnerFrom: Dave Chinner <[email protected]>
This happens after all the transactions to update the superblock occur, and errors need to be handled slightly differently. Seperate out the code into it's own function, and clean up the error goto stack in the core growfs code as it is now much simpler.
--- fs/xfs/xfs_fsops.c | 159 ++++++++++++++++++++++++++------------------- 1 file changed, 92 insertions(+), 67 deletions(-)
fs/xfs/xfs_fsops.c +92 -67
@@ -422,9 +422,8 @@ xfs_growfs_data_private( {xfs_agf_t *agf;xfs_agi_t *agi; -xfs_agnumber_t agno;xfs_buf_t *bp; -int error, saved_error =0 ; +int error;xfs_agnumber_t nagcount;xfs_agnumber_t nagimax =0 ;xfs_rfsblock_t nb, nb_mod;
@@ -496,12 +495,12 @@ xfs_growfs_data_private( error =xfs_grow_ag_headers (mp, &id);if (error) {xfs_buf_delwri_cancel (&id.buffer_list); - goto error0; + goto out_trans_cancel; } } error =xfs_buf_delwri_submit (&id.buffer_list);if (error) - goto error0; + goto out_trans_cancel;xfs_trans_agblocks_delta (tp, id.nfree);
@@ -515,22 +514,23 @@ xfs_growfs_data_private(* Change the agi length. */ error =xfs_ialloc_read_agi (mp, tp, id.agno, &bp); -if (error) { - goto error0; - } +if (error) + goto out_trans_cancel; +ASSERT (bp); agi =XFS_BUF_TO_AGI (bp);be32_add_cpu (&agi->agi_length, new);ASSERT (nagcount == oagcount ||be32_to_cpu (agi->agi_length) == mp->m_sb.sb_agblocks);xfs_ialloc_log_agi (tp, bp,XFS_AGI_LENGTH ); +/* * Change agf length. */ error =xfs_alloc_read_agf (mp, tp, id.agno,0 , &bp); -if (error) { - goto error0; - } +if (error) + goto out_trans_cancel; +ASSERT (bp); agf =XFS_BUF_TO_AGF (bp);be32_add_cpu (&agf->agf_length, new);
@@ -550,13 +550,13 @@ xfs_growfs_data_private(be32_to_cpu (agf->agf_length) - new, new, &oinfo);if (error) - goto error0; + goto out_trans_cancel; error =xfs_free_extent (tp,XFS_AGB_TO_FSB (mp, id.agno,be32_to_cpu (agf->agf_length) - new), new, &oinfo,XFS_AG_RESV_NONE );if (error) - goto error0; + goto out_trans_cancel; }/*
@@ -593,16 +593,86 @@ xfs_growfs_data_private( error =xfs_ag_resv_free (pag);xfs_perag_put (pag);if (error) - goto out; +return error; } -/* Reserve AG metadata blocks. */ +/* +* Reserve AG metadata blocks. ENOSPC here does not mean there was a +* growfs failure, just that there still isn't space for new user data +* after the grow has been run. +*/ error =xfs_fs_reserve_ag_blocks (mp); -if (error && error != -ENOSPC ) - goto out; +if (error == -ENOSPC ) + error =0 ; +return error; + +out_trans_cancel: +xfs_trans_cancel (tp); +return error; +} + +static int +xfs_growfs_log_private ( +xfs_mount_t *mp,/* mount point for filesystem */ +xfs_growfs_log_t *in)/* growfs log input struct */ +{ +xfs_extlen_t nb; + + nb = in->newblocks; +if (nb <XFS_MIN_LOG_BLOCKS || nb <XFS_B_TO_FSB (mp,XFS_MIN_LOG_BYTES )) +return -EINVAL ; +if (nb == mp->m_sb.sb_logblocks && + in->isint == (mp->m_sb.sb_logstart !=0 )) +return -EINVAL ; +/* +* Moving the log is hard, need new interfaces to sync +* the log first, hold off all activity while moving it. +* Can have shorter or longer log in the same space, +* or transform internal to external log or vice versa. +*/ +return -ENOSYS ; +} + +static int +xfs_growfs_imaxpct ( +struct xfs_mount *mp, +__u32 imaxpct) +{ +struct xfs_trans *tp; +int dpct; +int error; + +if (imaxpct >100 ) +return -EINVAL ; + + error =xfs_trans_alloc (mp, &M_RES (mp)->tr_growdata, +XFS_GROWFS_SPACE_RES (mp),0 ,XFS_TRANS_RESERVE , &tp); +if (error) +return error; + + dpct = imaxpct - mp->m_sb.sb_imax_pct; +xfs_trans_mod_sb (tp,XFS_TRANS_SB_IMAXPCT , dpct); +xfs_trans_set_sync (tp); +return xfs_trans_commit (tp); +} + +/* +* After a grow operation, we need to update all the secondary superblocks +* to match the new state of the primary. Read/init the superblocks and update +* them appropriately. +*/ +static int +xfs_growfs_update_superblocks ( +struct xfs_mount *mp, +xfs_agnumber_t oagcount) +{ +struct xfs_buf *bp; +xfs_agnumber_t agno; +int saved_error =0 ; +int error =0 ;/* update secondary superblocks. */ -for (agno =1 ; agno < nagcount; agno++) { +for (agno =1 ; agno < mp->m_sb.sb_agcount; agno++) { error =0 ;/* * new secondary superblocks need to be zeroed, not read from
@@ -652,57 +722,7 @@ xfs_growfs_data_private( } } - out:return saved_error ? saved_error : error; - - error0: -xfs_trans_cancel (tp); -return error; -} - -static int -xfs_growfs_log_private ( -xfs_mount_t *mp,/* mount point for filesystem */ -xfs_growfs_log_t *in)/* growfs log input struct */ -{ -xfs_extlen_t nb; - - nb = in->newblocks; -if (nb <XFS_MIN_LOG_BLOCKS || nb <XFS_B_TO_FSB (mp,XFS_MIN_LOG_BYTES )) -return -EINVAL ; -if (nb == mp->m_sb.sb_logblocks && - in->isint == (mp->m_sb.sb_logstart !=0 )) -return -EINVAL ; -/* -* Moving the log is hard, need new interfaces to sync -* the log first, hold off all activity while moving it. -* Can have shorter or longer log in the same space, -* or transform internal to external log or vice versa. -*/ -return -ENOSYS ; -} - -static int -xfs_growfs_imaxpct ( -struct xfs_mount *mp, -__u32 imaxpct) -{ -struct xfs_trans *tp; -int64_t dpct; -int error; - -if (imaxpct >100 ) -return -EINVAL ; - - error =xfs_trans_alloc (mp, &M_RES (mp)->tr_growdata, -XFS_GROWFS_SPACE_RES (mp),0 ,XFS_TRANS_RESERVE , &tp); -if (error) -return error; - - dpct = (int64_t )imaxpct - mp->m_sb.sb_imax_pct; -xfs_trans_mod_sb (tp,XFS_TRANS_SB_IMAXPCT , dpct); -xfs_trans_set_sync (tp); -return xfs_trans_commit (tp); }/*
@@ -715,6 +735,7 @@ xfs_growfs_data(struct xfs_mount *mp, struct xfs_growfs_data *in) { + xfs_agnumber_t oagcount;int error =0 ;if (!capable (CAP_SYS_ADMIN ))
@@ -729,6 +750,7 @@ xfs_growfs_data( goto out_error; } + oagcount = mp->m_sb.sb_agcount;if (in->newblocks != mp->m_sb.sb_dblocks) { error =xfs_growfs_data_private (mp, in);if (error)
@@ -743,6 +765,9 @@ xfs_growfs_data( }else mp->m_maxicount =0 ; +/* Update secondary superblocks now the physical grow has completed */ + error =xfs_growfs_update_superblocks (mp, oagcount); + out_error:/* * Increment the generation unconditionally, the error could be from
Signature · 1 line
2.17.0
PATCH v3 8/10 xfs: rework secondary superblock updates in growfs
In reply to Dave ChinnerFrom: Dave Chinner <[email protected]>
Right now we wait until we've committed changes to the primary superblock before we initialise any of the new secondary superblocks. This means that if we have any write errors for new secondary superblocks we end up with garbage in place rather than zeros or even an "in progress" superblock to indicate a grow operation is being done.
To ensure we can write the secondary superblocks, initialise them earlier in the same loop that initialises the AG headers. We stamp the new secondary superblocks here with the old geometry, but set the "sb_inprogress" field to indicate that updates are being done to the superblock so they cannot be used. This will result in the secondary superblock fields being updated or triggering errors that will abort the grow before we commit any permanent changes.
This also means we can change the update mechanism of the secondary superblocks. We know that we are going to wholly overwrite the information in the struct xfs_sb in the buffer, so there's no point reading it from disk. Just allocate an uncached buffer, zero it in memory, stamp the new superblock structure in it and write it out. If we fail to write it out, then we'll leave the existing sb (old or new w/ inprogress) on disk for repair to deal with later.
--- fs/xfs/xfs_fsops.c | 102 +++++++++++++++++++++++++++++---------------- 1 file changed, 65 insertions(+), 37 deletions(-)
fs/xfs/xfs_fsops.c +65 -37
@@ -191,6 +191,25 @@ xfs_rmaproot_init( } } +/* +* Initialise new secondary superblocks with the pre-grow geometry, but mark +* them as "in progress" so we know they haven't yet been activated. This will +* get cleared when the update with the new geometry information is done after +* changes to the primary are committed. This isn't strictly necessary, but we +* get it for free with the delayed buffer write lists and it means we can tell +* if a grow operation didn't complete properly after the fact. +*/ +static void +xfs_sbblock_init ( +struct xfs_mount *mp, +struct xfs_buf *bp, +struct aghdr_init_data *id) +{ +struct xfs_dsb *dsb =XFS_BUF_TO_SBP (bp); + +xfs_sb_to_disk (dsb, &mp->m_sb); + dsb->sb_inprogress =1 ; +}static void xfs_agfblock_init(
@@ -326,6 +345,13 @@ xfs_grow_ag_headers( {struct xfs_aghdr_grow_data aghdr_data[] = { + {/* SB */ + .daddr =XFS_AG_DADDR (mp, id->agno,XFS_SB_DADDR ), + .numblks =XFS_FSS_TO_BB (mp,1 ), + .ops = &xfs_sb_buf_ops, + .work = &xfs_sbblock_init, + .need_init = true + }, {/* AGF */ .daddr =XFS_AG_DADDR (mp, id->agno,XFS_AGF_DADDR (mp)), .numblks =XFS_FSS_TO_BB (mp,1 ),
@@ -658,43 +684,30 @@ xfs_growfs_imaxpct(/* * After a grow operation, we need to update all the secondary superblocks -* to match the new state of the primary. Read/init the superblocks and update -* them appropriately. +* to match the new state of the primary. Because we are completely overwriting +* all the existing fields in the secondary superblock buffers, there is no need +* to read them in from disk. Just get a new buffer, stamp it and write it. +* +* The sb buffers need to be cached here so that we serialise against scrub +* scanning secondary superblocks, but we don't want to keep it in memory once +* it is written so we mark it as a one-shot buffer. */ static int xfs_growfs_update_superblocks ( -struct xfs_mount *mp, -xfs_agnumber_t oagcount) +struct xfs_mount *mp) { -struct xfs_buf *bp;xfs_agnumber_t agno;int saved_error =0 ;int error =0 ; +LIST_HEAD (buffer_list);/* update secondary superblocks. */ for (agno =1 ; agno < mp->m_sb.sb_agcount; agno++) { - error =0 ; -/* -* new secondary superblocks need to be zeroed, not read from -* disk as the contents of the new area we are growing into is -* completely unknown. -*/ -if (agno < oagcount) { - error =xfs_trans_read_buf (mp,NULL , mp->m_ddev_targp, -XFS_AGB_TO_DADDR (mp, agno,XFS_SB_BLOCK (mp)), -XFS_FSS_TO_BB (mp,1 ),0 , &bp, - &xfs_sb_buf_ops); - }else { - bp =xfs_trans_get_buf (NULL , mp->m_ddev_targp, -XFS_AGB_TO_DADDR (mp, agno,XFS_SB_BLOCK (mp)), -XFS_FSS_TO_BB (mp,1 ),0 ); -if (bp) { - bp->b_ops = &xfs_sb_buf_ops; -xfs_buf_zero (bp,0 ,BBTOB (bp->b_length)); - }else - error = -ENOMEM ; - } +struct xfs_buf *bp; + bp =xfs_buf_get (mp->m_ddev_targp, +XFS_AG_DADDR (mp, agno,XFS_SB_DADDR ), +XFS_FSS_TO_BB (mp,1 ),0 );/* * If we get an error reading or writing alternate superblocks, * continue. xfs_repair chooses the "best" superblock based
@@ -702,25 +715,42 @@ xfs_growfs_update_superblocks(* superblocks un-updated than updated, and xfs_repair may * pick them over the properly-updated primary. */ -if (error) { +if (!bp) {xfs_warn (mp, -"error %d reading secondary superblock for ag %d" , - error, agno); - saved_error = error; +"error allocating secondary superblock for ag %d" , + agno); +if (!saved_error) + saved_error = -ENOMEM ;continue ; } -xfs_sb_to_disk (XFS_BUF_TO_SBP (bp), &mp->m_sb); - error =xfs_bwrite (bp); + bp->b_ops = &xfs_sb_buf_ops; +xfs_buf_oneshot (bp); +xfs_buf_zero (bp,0 ,BBTOB (bp->b_length)); +xfs_sb_to_disk (XFS_BUF_TO_SBP (bp), &mp->m_sb); +xfs_buf_delwri_queue (bp, &buffer_list);xfs_buf_relse (bp); + +/* don't hold too many buffers at once */ +if (agno %16 ) +continue ; + + error =xfs_buf_delwri_submit (&buffer_list);if (error) {xfs_warn (mp, -"write error %d updating secondary superblock for ag %d" , +"write error %d updating a secondary superblock near ag %d" , error, agno); - saved_error = error; +if (!saved_error) + saved_error = error;continue ; } } + error =xfs_buf_delwri_submit (&buffer_list); +if (error) { +xfs_warn (mp, +"write error %d updating a secondary superblock near ag %d" , + error, agno); + }return saved_error ? saved_error : error; }
@@ -735,7 +765,6 @@ xfs_growfs_data(struct xfs_mount *mp, struct xfs_growfs_data *in) { - xfs_agnumber_t oagcount; int error = 0;if (!capable (CAP_SYS_ADMIN ))
@@ -750,7 +779,6 @@ xfs_growfs_data( goto out_error; } - oagcount = mp->m_sb.sb_agcount;if (in->newblocks != mp->m_sb.sb_dblocks) { error =xfs_growfs_data_private (mp, in);if (error)
@@ -766,7 +794,7 @@ xfs_growfs_data( mp->m_maxicount =0 ;/* Update secondary superblocks now the physical grow has completed */ - error =xfs_growfs_update_superblocks (mp, oagcount); + error =xfs_growfs_update_superblocks (mp); out_error:/*
Signature · 1 line
2.17.0
PATCH v3 9/10 xfs: move growfs core to libxfs
In reply to Dave ChinnerFrom: Dave Chinner <[email protected]>
So it can be shared with userspace (e.g. mkfs) easily.
--- fs/xfs/Makefile | 1 + fs/xfs/libxfs/xfs_ag.c | 404 ++++++++++++++++++++++++++++++++++ fs/xfs/libxfs/xfs_ag.h | 25 +++ fs/xfs/libxfs/xfs_sb.c | 73 +++++++ fs/xfs/libxfs/xfs_sb.h | 9 + fs/xfs/xfs_fsops.c | 479 +---------------------------------------- 6 files changed, 516 insertions(+), 475 deletions(-) create mode 100644 fs/xfs/libxfs/xfs_ag.c create mode 100644 fs/xfs/libxfs/xfs_ag.h
fs/xfs/Makefile +1 -0
@@ -28,6 +28,7 @@ xfs-y += xfs_trace.o # build the libxfs code first xfs-y += $(addprefix libxfs/, \ + xfs_ag.o \ xfs_alloc.o \ xfs_alloc_btree.o \ xfs_attr.o \
fs/xfs/libxfs/xfs_ag.c new file +404 -0
404 lines not on this page · raw message
fs/xfs/libxfs/xfs_ag.h new file +25 -0
@@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* +* Copyright (c) 2018 Red Hat, Inc. +* All rights reserved. +*/ + +#ifndef __LIBXFS_AG_H +#define __LIBXFS_AG_H 1 + +struct aghdr_init_data { +/* per ag data */ +xfs_agblock_t agno;/* ag to init */ +xfs_extlen_t agsize;/* new AG size */ +struct list_head buffer_list;/* buffer writeback list */ +xfs_rfsblock_t nfree;/* cumulative new free space */ + +/* per header data */ +xfs_daddr_t daddr;/* header location */ +size_t numblks;/* size of header */ +xfs_btnum_t type;/* type of btree root block */ +}; + +int xfs_ag_init_headers (struct xfs_mount *mp,struct aghdr_init_data *id); + +#endif /* __LIBXFS_AG_H */
fs/xfs/libxfs/xfs_sb.c +73 -0
79 lines not on this page · raw message
fs/xfs/libxfs/xfs_sb.h +9 -0
@@ -18,6 +18,13 @@#ifndef __XFS_SB_H__#define __XFS_SB_H__ +struct xfs_mount ; +struct xfs_sb ; +struct xfs_dsb ; +struct xfs_trans ; +struct xfs_fsop_geom ; +struct xfs_perag ; +/* * perag get/put wrappers for ref counting */
@@ -34,6 +41,8 @@ extern void xfs_sb_from_disk(struct xfs_sb *to, struct xfs_dsb *from);extern void xfs_sb_to_disk (struct xfs_dsb *to,struct xfs_sb *from);extern void xfs_sb_quota_from_disk (struct xfs_sb *sbp); +extern int xfs_update_secondary_sbs (struct xfs_mount *mp); +#define XFS_FS_GEOM_MAX_STRUCT_VER (4)extern int xfs_fs_geometry (struct xfs_sb *sbp,struct xfs_fsop_geom *geo,int struct_version);
fs/xfs/xfs_fsops.c +4 -475
519 lines not on this page · raw message
Signature · 1 line
2.17.0
PATCH v3 10/10 xfs: factor the ag length extension code into libxfs
In reply to Dave ChinnerFrom: Dave Chinner <[email protected]>
Growfs currently manually codes the extension of the last AG in a filesytem during the growfs process. Factor that out of the growfs code and move it into libxfs along with teh rest of the AG header modification code.
--- fs/xfs/libxfs/xfs_ag.c | 60 ++++++++++++++++++++++++++++++++++++++++++ fs/xfs/libxfs/xfs_ag.h | 7 ++++- fs/xfs/xfs_fsops.c | 58 ++-------------------------------------- 3 files changed, 68 insertions(+), 57 deletions(-)
fs/xfs/libxfs/xfs_ag.c +60 -0
@@ -16,6 +16,7 @@#include "xfs_alloc_btree.h" #include "xfs_rmap_btree.h" #include "xfs_alloc.h" +#include "xfs_ialloc.h" #include "xfs_rmap.h" #include "xfs_ag.h"
@@ -402,3 +403,62 @@ xfs_ag_init_headers( }return error; } + +/* +* Extent the AG indicated by the @id by the length passed in +*/ +int +xfs_ag_extend_space ( +struct xfs_mount *mp, +struct xfs_trans *tp, +struct aghdr_init_data *id, +xfs_extlen_t len) +{ +struct xfs_owner_info oinfo; +struct xfs_buf *bp; +struct xfs_agi *agi; +struct xfs_agf *agf; +int error; + +/* +* Change the agi length. +*/ + error =xfs_ialloc_read_agi (mp, tp, id->agno, &bp); +if (error) +return error; + + agi =XFS_BUF_TO_AGI (bp); +be32_add_cpu (&agi->agi_length, len); +ASSERT (id->agno == mp->m_sb.sb_agcount -1 || +be32_to_cpu (agi->agi_length) == mp->m_sb.sb_agblocks); +xfs_ialloc_log_agi (tp, bp,XFS_AGI_LENGTH ); + +/* +* Change agf length. +*/ + error =xfs_alloc_read_agf (mp, tp, id->agno,0 , &bp); +if (error) +return error; + + agf =XFS_BUF_TO_AGF (bp); +be32_add_cpu (&agf->agf_length, len); +ASSERT (agf->agf_length == agi->agi_length); +xfs_alloc_log_agf (tp, bp,XFS_AGF_LENGTH ); + +/* +* Free the new space. +* +* XFS_RMAP_OWN_NULL is used here to tell the rmap btree that +* this doesn't actually exist in the rmap btree. +*/ +xfs_rmap_ag_owner (&oinfo,XFS_RMAP_OWN_NULL ); + error =xfs_rmap_free (tp, bp, id->agno, +be32_to_cpu (agf->agf_length) - len, + len, &oinfo); +if (error) +return error; + +return xfs_free_extent (tp,XFS_AGB_TO_FSB (mp, id->agno, +be32_to_cpu (agf->agf_length) - len), + len, &oinfo,XFS_AG_RESV_NONE ); +}
fs/xfs/libxfs/xfs_ag.h +6 -1
@@ -7,6 +7,9 @@ #ifndef __LIBXFS_AG_H #define __LIBXFS_AG_H 1 +struct xfs_mount; +struct xfs_trans; + struct aghdr_init_data { /* per ag data */ xfs_agblock_t agno; /* ag to init */
@@ -20,6 +23,8 @@ struct aghdr_init_data { xfs_btnum_t type; /* type of btree root block */ }; -int xfs_ag_init_headers (struct xfs_mount *mp,struct aghdr_init_data *id); +int xfs_ag_init_headers (struct xfs_mount *mp,struct aghdr_init_data *id); +int xfs_ag_extend_space (struct xfs_mount *mp,struct xfs_trans *tp, +struct aghdr_init_data *id,xfs_extlen_t len);#endif /* __LIBXFS_AG_H */
fs/xfs/xfs_fsops.c +2 -56
83 lines not on this page · raw message
Signature · 1 line
2.17.0