162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (c) 2018 Red Hat, Inc. 462306a36Sopenharmony_ci * All rights reserved. 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#ifndef __LIBXFS_AG_H 862306a36Sopenharmony_ci#define __LIBXFS_AG_H 1 962306a36Sopenharmony_ci 1062306a36Sopenharmony_cistruct xfs_mount; 1162306a36Sopenharmony_cistruct xfs_trans; 1262306a36Sopenharmony_cistruct xfs_perag; 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci/* 1562306a36Sopenharmony_ci * Per-ag infrastructure 1662306a36Sopenharmony_ci */ 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci/* per-AG block reservation data structures*/ 1962306a36Sopenharmony_cistruct xfs_ag_resv { 2062306a36Sopenharmony_ci /* number of blocks originally reserved here */ 2162306a36Sopenharmony_ci xfs_extlen_t ar_orig_reserved; 2262306a36Sopenharmony_ci /* number of blocks reserved here */ 2362306a36Sopenharmony_ci xfs_extlen_t ar_reserved; 2462306a36Sopenharmony_ci /* number of blocks originally asked for */ 2562306a36Sopenharmony_ci xfs_extlen_t ar_asked; 2662306a36Sopenharmony_ci}; 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci/* 2962306a36Sopenharmony_ci * Per-ag incore structure, copies of information in agf and agi, to improve the 3062306a36Sopenharmony_ci * performance of allocation group selection. 3162306a36Sopenharmony_ci */ 3262306a36Sopenharmony_cistruct xfs_perag { 3362306a36Sopenharmony_ci struct xfs_mount *pag_mount; /* owner filesystem */ 3462306a36Sopenharmony_ci xfs_agnumber_t pag_agno; /* AG this structure belongs to */ 3562306a36Sopenharmony_ci atomic_t pag_ref; /* passive reference count */ 3662306a36Sopenharmony_ci atomic_t pag_active_ref; /* active reference count */ 3762306a36Sopenharmony_ci wait_queue_head_t pag_active_wq;/* woken active_ref falls to zero */ 3862306a36Sopenharmony_ci unsigned long pag_opstate; 3962306a36Sopenharmony_ci uint8_t pagf_levels[XFS_BTNUM_AGF]; 4062306a36Sopenharmony_ci /* # of levels in bno & cnt btree */ 4162306a36Sopenharmony_ci uint32_t pagf_flcount; /* count of blocks in freelist */ 4262306a36Sopenharmony_ci xfs_extlen_t pagf_freeblks; /* total free blocks */ 4362306a36Sopenharmony_ci xfs_extlen_t pagf_longest; /* longest free space */ 4462306a36Sopenharmony_ci uint32_t pagf_btreeblks; /* # of blocks held in AGF btrees */ 4562306a36Sopenharmony_ci xfs_agino_t pagi_freecount; /* number of free inodes */ 4662306a36Sopenharmony_ci xfs_agino_t pagi_count; /* number of allocated inodes */ 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci /* 4962306a36Sopenharmony_ci * Inode allocation search lookup optimisation. 5062306a36Sopenharmony_ci * If the pagino matches, the search for new inodes 5162306a36Sopenharmony_ci * doesn't need to search the near ones again straight away 5262306a36Sopenharmony_ci */ 5362306a36Sopenharmony_ci xfs_agino_t pagl_pagino; 5462306a36Sopenharmony_ci xfs_agino_t pagl_leftrec; 5562306a36Sopenharmony_ci xfs_agino_t pagl_rightrec; 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci int pagb_count; /* pagb slots in use */ 5862306a36Sopenharmony_ci uint8_t pagf_refcount_level; /* recount btree height */ 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci /* Blocks reserved for all kinds of metadata. */ 6162306a36Sopenharmony_ci struct xfs_ag_resv pag_meta_resv; 6262306a36Sopenharmony_ci /* Blocks reserved for the reverse mapping btree. */ 6362306a36Sopenharmony_ci struct xfs_ag_resv pag_rmapbt_resv; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci /* for rcu-safe freeing */ 6662306a36Sopenharmony_ci struct rcu_head rcu_head; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci /* Precalculated geometry info */ 6962306a36Sopenharmony_ci xfs_agblock_t block_count; 7062306a36Sopenharmony_ci xfs_agblock_t min_block; 7162306a36Sopenharmony_ci xfs_agino_t agino_min; 7262306a36Sopenharmony_ci xfs_agino_t agino_max; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci#ifdef __KERNEL__ 7562306a36Sopenharmony_ci /* -- kernel only structures below this line -- */ 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci /* 7862306a36Sopenharmony_ci * Bitsets of per-ag metadata that have been checked and/or are sick. 7962306a36Sopenharmony_ci * Callers should hold pag_state_lock before accessing this field. 8062306a36Sopenharmony_ci */ 8162306a36Sopenharmony_ci uint16_t pag_checked; 8262306a36Sopenharmony_ci uint16_t pag_sick; 8362306a36Sopenharmony_ci spinlock_t pag_state_lock; 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci spinlock_t pagb_lock; /* lock for pagb_tree */ 8662306a36Sopenharmony_ci struct rb_root pagb_tree; /* ordered tree of busy extents */ 8762306a36Sopenharmony_ci unsigned int pagb_gen; /* generation count for pagb_tree */ 8862306a36Sopenharmony_ci wait_queue_head_t pagb_wait; /* woken when pagb_gen changes */ 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci atomic_t pagf_fstrms; /* # of filestreams active in this AG */ 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci spinlock_t pag_ici_lock; /* incore inode cache lock */ 9362306a36Sopenharmony_ci struct radix_tree_root pag_ici_root; /* incore inode cache root */ 9462306a36Sopenharmony_ci int pag_ici_reclaimable; /* reclaimable inodes */ 9562306a36Sopenharmony_ci unsigned long pag_ici_reclaim_cursor; /* reclaim restart point */ 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci /* buffer cache index */ 9862306a36Sopenharmony_ci spinlock_t pag_buf_lock; /* lock for pag_buf_hash */ 9962306a36Sopenharmony_ci struct rhashtable pag_buf_hash; 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci /* background prealloc block trimming */ 10262306a36Sopenharmony_ci struct delayed_work pag_blockgc_work; 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci /* 10562306a36Sopenharmony_ci * We use xfs_drain to track the number of deferred log intent items 10662306a36Sopenharmony_ci * that have been queued (but not yet processed) so that waiters (e.g. 10762306a36Sopenharmony_ci * scrub) will not lock resources when other threads are in the middle 10862306a36Sopenharmony_ci * of processing a chain of intent items only to find momentary 10962306a36Sopenharmony_ci * inconsistencies. 11062306a36Sopenharmony_ci */ 11162306a36Sopenharmony_ci struct xfs_defer_drain pag_intents_drain; 11262306a36Sopenharmony_ci#endif /* __KERNEL__ */ 11362306a36Sopenharmony_ci}; 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci/* 11662306a36Sopenharmony_ci * Per-AG operational state. These are atomic flag bits. 11762306a36Sopenharmony_ci */ 11862306a36Sopenharmony_ci#define XFS_AGSTATE_AGF_INIT 0 11962306a36Sopenharmony_ci#define XFS_AGSTATE_AGI_INIT 1 12062306a36Sopenharmony_ci#define XFS_AGSTATE_PREFERS_METADATA 2 12162306a36Sopenharmony_ci#define XFS_AGSTATE_ALLOWS_INODES 3 12262306a36Sopenharmony_ci#define XFS_AGSTATE_AGFL_NEEDS_RESET 4 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci#define __XFS_AG_OPSTATE(name, NAME) \ 12562306a36Sopenharmony_cistatic inline bool xfs_perag_ ## name (struct xfs_perag *pag) \ 12662306a36Sopenharmony_ci{ \ 12762306a36Sopenharmony_ci return test_bit(XFS_AGSTATE_ ## NAME, &pag->pag_opstate); \ 12862306a36Sopenharmony_ci} 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci__XFS_AG_OPSTATE(initialised_agf, AGF_INIT) 13162306a36Sopenharmony_ci__XFS_AG_OPSTATE(initialised_agi, AGI_INIT) 13262306a36Sopenharmony_ci__XFS_AG_OPSTATE(prefers_metadata, PREFERS_METADATA) 13362306a36Sopenharmony_ci__XFS_AG_OPSTATE(allows_inodes, ALLOWS_INODES) 13462306a36Sopenharmony_ci__XFS_AG_OPSTATE(agfl_needs_reset, AGFL_NEEDS_RESET) 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ciint xfs_initialize_perag(struct xfs_mount *mp, xfs_agnumber_t agcount, 13762306a36Sopenharmony_ci xfs_rfsblock_t dcount, xfs_agnumber_t *maxagi); 13862306a36Sopenharmony_ciint xfs_initialize_perag_data(struct xfs_mount *mp, xfs_agnumber_t agno); 13962306a36Sopenharmony_civoid xfs_free_perag(struct xfs_mount *mp); 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci/* Passive AG references */ 14262306a36Sopenharmony_cistruct xfs_perag *xfs_perag_get(struct xfs_mount *mp, xfs_agnumber_t agno); 14362306a36Sopenharmony_cistruct xfs_perag *xfs_perag_get_tag(struct xfs_mount *mp, xfs_agnumber_t agno, 14462306a36Sopenharmony_ci unsigned int tag); 14562306a36Sopenharmony_cistruct xfs_perag *xfs_perag_hold(struct xfs_perag *pag); 14662306a36Sopenharmony_civoid xfs_perag_put(struct xfs_perag *pag); 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci/* Active AG references */ 14962306a36Sopenharmony_cistruct xfs_perag *xfs_perag_grab(struct xfs_mount *, xfs_agnumber_t); 15062306a36Sopenharmony_cistruct xfs_perag *xfs_perag_grab_tag(struct xfs_mount *, xfs_agnumber_t, 15162306a36Sopenharmony_ci int tag); 15262306a36Sopenharmony_civoid xfs_perag_rele(struct xfs_perag *pag); 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci/* 15562306a36Sopenharmony_ci * Per-ag geometry infomation and validation 15662306a36Sopenharmony_ci */ 15762306a36Sopenharmony_cixfs_agblock_t xfs_ag_block_count(struct xfs_mount *mp, xfs_agnumber_t agno); 15862306a36Sopenharmony_civoid xfs_agino_range(struct xfs_mount *mp, xfs_agnumber_t agno, 15962306a36Sopenharmony_ci xfs_agino_t *first, xfs_agino_t *last); 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_cistatic inline bool 16262306a36Sopenharmony_cixfs_verify_agbno(struct xfs_perag *pag, xfs_agblock_t agbno) 16362306a36Sopenharmony_ci{ 16462306a36Sopenharmony_ci if (agbno >= pag->block_count) 16562306a36Sopenharmony_ci return false; 16662306a36Sopenharmony_ci if (agbno <= pag->min_block) 16762306a36Sopenharmony_ci return false; 16862306a36Sopenharmony_ci return true; 16962306a36Sopenharmony_ci} 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_cistatic inline bool 17262306a36Sopenharmony_cixfs_verify_agbext( 17362306a36Sopenharmony_ci struct xfs_perag *pag, 17462306a36Sopenharmony_ci xfs_agblock_t agbno, 17562306a36Sopenharmony_ci xfs_agblock_t len) 17662306a36Sopenharmony_ci{ 17762306a36Sopenharmony_ci if (agbno + len <= agbno) 17862306a36Sopenharmony_ci return false; 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci if (!xfs_verify_agbno(pag, agbno)) 18162306a36Sopenharmony_ci return false; 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci return xfs_verify_agbno(pag, agbno + len - 1); 18462306a36Sopenharmony_ci} 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci/* 18762306a36Sopenharmony_ci * Verify that an AG inode number pointer neither points outside the AG 18862306a36Sopenharmony_ci * nor points at static metadata. 18962306a36Sopenharmony_ci */ 19062306a36Sopenharmony_cistatic inline bool 19162306a36Sopenharmony_cixfs_verify_agino(struct xfs_perag *pag, xfs_agino_t agino) 19262306a36Sopenharmony_ci{ 19362306a36Sopenharmony_ci if (agino < pag->agino_min) 19462306a36Sopenharmony_ci return false; 19562306a36Sopenharmony_ci if (agino > pag->agino_max) 19662306a36Sopenharmony_ci return false; 19762306a36Sopenharmony_ci return true; 19862306a36Sopenharmony_ci} 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci/* 20162306a36Sopenharmony_ci * Verify that an AG inode number pointer neither points outside the AG 20262306a36Sopenharmony_ci * nor points at static metadata, or is NULLAGINO. 20362306a36Sopenharmony_ci */ 20462306a36Sopenharmony_cistatic inline bool 20562306a36Sopenharmony_cixfs_verify_agino_or_null(struct xfs_perag *pag, xfs_agino_t agino) 20662306a36Sopenharmony_ci{ 20762306a36Sopenharmony_ci if (agino == NULLAGINO) 20862306a36Sopenharmony_ci return true; 20962306a36Sopenharmony_ci return xfs_verify_agino(pag, agino); 21062306a36Sopenharmony_ci} 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_cistatic inline bool 21362306a36Sopenharmony_cixfs_ag_contains_log(struct xfs_mount *mp, xfs_agnumber_t agno) 21462306a36Sopenharmony_ci{ 21562306a36Sopenharmony_ci return mp->m_sb.sb_logstart > 0 && 21662306a36Sopenharmony_ci agno == XFS_FSB_TO_AGNO(mp, mp->m_sb.sb_logstart); 21762306a36Sopenharmony_ci} 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci/* 22062306a36Sopenharmony_ci * Perag iteration APIs 22162306a36Sopenharmony_ci */ 22262306a36Sopenharmony_cistatic inline struct xfs_perag * 22362306a36Sopenharmony_cixfs_perag_next( 22462306a36Sopenharmony_ci struct xfs_perag *pag, 22562306a36Sopenharmony_ci xfs_agnumber_t *agno, 22662306a36Sopenharmony_ci xfs_agnumber_t end_agno) 22762306a36Sopenharmony_ci{ 22862306a36Sopenharmony_ci struct xfs_mount *mp = pag->pag_mount; 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci *agno = pag->pag_agno + 1; 23162306a36Sopenharmony_ci xfs_perag_rele(pag); 23262306a36Sopenharmony_ci while (*agno <= end_agno) { 23362306a36Sopenharmony_ci pag = xfs_perag_grab(mp, *agno); 23462306a36Sopenharmony_ci if (pag) 23562306a36Sopenharmony_ci return pag; 23662306a36Sopenharmony_ci (*agno)++; 23762306a36Sopenharmony_ci } 23862306a36Sopenharmony_ci return NULL; 23962306a36Sopenharmony_ci} 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci#define for_each_perag_range(mp, agno, end_agno, pag) \ 24262306a36Sopenharmony_ci for ((pag) = xfs_perag_grab((mp), (agno)); \ 24362306a36Sopenharmony_ci (pag) != NULL; \ 24462306a36Sopenharmony_ci (pag) = xfs_perag_next((pag), &(agno), (end_agno))) 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci#define for_each_perag_from(mp, agno, pag) \ 24762306a36Sopenharmony_ci for_each_perag_range((mp), (agno), (mp)->m_sb.sb_agcount - 1, (pag)) 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci#define for_each_perag(mp, agno, pag) \ 25062306a36Sopenharmony_ci (agno) = 0; \ 25162306a36Sopenharmony_ci for_each_perag_from((mp), (agno), (pag)) 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci#define for_each_perag_tag(mp, agno, pag, tag) \ 25462306a36Sopenharmony_ci for ((agno) = 0, (pag) = xfs_perag_grab_tag((mp), 0, (tag)); \ 25562306a36Sopenharmony_ci (pag) != NULL; \ 25662306a36Sopenharmony_ci (agno) = (pag)->pag_agno + 1, \ 25762306a36Sopenharmony_ci xfs_perag_rele(pag), \ 25862306a36Sopenharmony_ci (pag) = xfs_perag_grab_tag((mp), (agno), (tag))) 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_cistatic inline struct xfs_perag * 26162306a36Sopenharmony_cixfs_perag_next_wrap( 26262306a36Sopenharmony_ci struct xfs_perag *pag, 26362306a36Sopenharmony_ci xfs_agnumber_t *agno, 26462306a36Sopenharmony_ci xfs_agnumber_t stop_agno, 26562306a36Sopenharmony_ci xfs_agnumber_t restart_agno, 26662306a36Sopenharmony_ci xfs_agnumber_t wrap_agno) 26762306a36Sopenharmony_ci{ 26862306a36Sopenharmony_ci struct xfs_mount *mp = pag->pag_mount; 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci *agno = pag->pag_agno + 1; 27162306a36Sopenharmony_ci xfs_perag_rele(pag); 27262306a36Sopenharmony_ci while (*agno != stop_agno) { 27362306a36Sopenharmony_ci if (*agno >= wrap_agno) { 27462306a36Sopenharmony_ci if (restart_agno >= stop_agno) 27562306a36Sopenharmony_ci break; 27662306a36Sopenharmony_ci *agno = restart_agno; 27762306a36Sopenharmony_ci } 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci pag = xfs_perag_grab(mp, *agno); 28062306a36Sopenharmony_ci if (pag) 28162306a36Sopenharmony_ci return pag; 28262306a36Sopenharmony_ci (*agno)++; 28362306a36Sopenharmony_ci } 28462306a36Sopenharmony_ci return NULL; 28562306a36Sopenharmony_ci} 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci/* 28862306a36Sopenharmony_ci * Iterate all AGs from start_agno through wrap_agno, then restart_agno through 28962306a36Sopenharmony_ci * (start_agno - 1). 29062306a36Sopenharmony_ci */ 29162306a36Sopenharmony_ci#define for_each_perag_wrap_range(mp, start_agno, restart_agno, wrap_agno, agno, pag) \ 29262306a36Sopenharmony_ci for ((agno) = (start_agno), (pag) = xfs_perag_grab((mp), (agno)); \ 29362306a36Sopenharmony_ci (pag) != NULL; \ 29462306a36Sopenharmony_ci (pag) = xfs_perag_next_wrap((pag), &(agno), (start_agno), \ 29562306a36Sopenharmony_ci (restart_agno), (wrap_agno))) 29662306a36Sopenharmony_ci/* 29762306a36Sopenharmony_ci * Iterate all AGs from start_agno through wrap_agno, then 0 through 29862306a36Sopenharmony_ci * (start_agno - 1). 29962306a36Sopenharmony_ci */ 30062306a36Sopenharmony_ci#define for_each_perag_wrap_at(mp, start_agno, wrap_agno, agno, pag) \ 30162306a36Sopenharmony_ci for_each_perag_wrap_range((mp), (start_agno), 0, (wrap_agno), (agno), (pag)) 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci/* 30462306a36Sopenharmony_ci * Iterate all AGs from start_agno through to the end of the filesystem, then 0 30562306a36Sopenharmony_ci * through (start_agno - 1). 30662306a36Sopenharmony_ci */ 30762306a36Sopenharmony_ci#define for_each_perag_wrap(mp, start_agno, agno, pag) \ 30862306a36Sopenharmony_ci for_each_perag_wrap_at((mp), (start_agno), (mp)->m_sb.sb_agcount, \ 30962306a36Sopenharmony_ci (agno), (pag)) 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_cistruct aghdr_init_data { 31362306a36Sopenharmony_ci /* per ag data */ 31462306a36Sopenharmony_ci xfs_agblock_t agno; /* ag to init */ 31562306a36Sopenharmony_ci xfs_extlen_t agsize; /* new AG size */ 31662306a36Sopenharmony_ci struct list_head buffer_list; /* buffer writeback list */ 31762306a36Sopenharmony_ci xfs_rfsblock_t nfree; /* cumulative new free space */ 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci /* per header data */ 32062306a36Sopenharmony_ci xfs_daddr_t daddr; /* header location */ 32162306a36Sopenharmony_ci size_t numblks; /* size of header */ 32262306a36Sopenharmony_ci xfs_btnum_t type; /* type of btree root block */ 32362306a36Sopenharmony_ci}; 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ciint xfs_ag_init_headers(struct xfs_mount *mp, struct aghdr_init_data *id); 32662306a36Sopenharmony_ciint xfs_ag_shrink_space(struct xfs_perag *pag, struct xfs_trans **tpp, 32762306a36Sopenharmony_ci xfs_extlen_t delta); 32862306a36Sopenharmony_ciint xfs_ag_extend_space(struct xfs_perag *pag, struct xfs_trans *tp, 32962306a36Sopenharmony_ci xfs_extlen_t len); 33062306a36Sopenharmony_ciint xfs_ag_get_geometry(struct xfs_perag *pag, struct xfs_ag_geometry *ageo); 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci#endif /* __LIBXFS_AG_H */ 333