| /* SPDX-License-Identifier: GPL-2.0 */ |
| /* |
| * Copyright (c) 2018 Red Hat, Inc. |
| */ |
| #ifndef __LIBXFS_GROUP_H |
| #define __LIBXFS_GROUP_H 1 |
| |
| struct xfs_group { |
| struct xfs_mount *xg_mount; |
| uint32_t xg_gno; |
| enum xfs_group_type xg_type; |
| atomic_t xg_ref; /* passive reference count */ |
| atomic_t xg_active_ref; /* active reference count */ |
| |
| /* Precalculated geometry info */ |
| uint32_t xg_block_count; /* max usable gbno */ |
| uint32_t xg_min_gbno; /* min usable gbno */ |
| |
| #ifdef __KERNEL__ |
| /* -- kernel only structures below this line -- */ |
| |
| /* |
| * Track freed but not yet committed extents. |
| */ |
| struct xfs_extent_busy_tree *xg_busy_extents; |
| |
| /* |
| * Bitsets of per-ag metadata that have been checked and/or are sick. |
| * Callers should hold xg_state_lock before accessing this field. |
| */ |
| uint16_t xg_checked; |
| uint16_t xg_sick; |
| spinlock_t xg_state_lock; |
| |
| /* |
| * We use xfs_drain to track the number of deferred log intent items |
| * that have been queued (but not yet processed) so that waiters (e.g. |
| * scrub) will not lock resources when other threads are in the middle |
| * of processing a chain of intent items only to find momentary |
| * inconsistencies. |
| */ |
| struct xfs_defer_drain xg_intents_drain; |
| |
| /* |
| * Hook to feed rmapbt updates to an active online repair. |
| */ |
| struct xfs_hooks xg_rmap_update_hooks; |
| #endif /* __KERNEL__ */ |
| }; |
| |
| struct xfs_group *xfs_group_get(struct xfs_mount *mp, uint32_t index, |
| enum xfs_group_type type); |
| struct xfs_group *xfs_group_get_by_fsb(struct xfs_mount *mp, |
| xfs_fsblock_t fsbno, enum xfs_group_type type); |
| struct xfs_group *xfs_group_hold(struct xfs_group *xg); |
| void xfs_group_put(struct xfs_group *xg); |
| |
| struct xfs_group *xfs_group_grab(struct xfs_mount *mp, uint32_t index, |
| enum xfs_group_type type); |
| struct xfs_group *xfs_group_next_range(struct xfs_mount *mp, |
| struct xfs_group *xg, uint32_t start_index, uint32_t end_index, |
| enum xfs_group_type type); |
| struct xfs_group *xfs_group_grab_next_mark(struct xfs_mount *mp, |
| struct xfs_group *xg, xa_mark_t mark, enum xfs_group_type type); |
| void xfs_group_rele(struct xfs_group *xg); |
| |
| void xfs_group_free(struct xfs_mount *mp, uint32_t index, |
| enum xfs_group_type type, void (*uninit)(struct xfs_group *xg)); |
| int xfs_group_insert(struct xfs_mount *mp, struct xfs_group *xg, |
| uint32_t index, enum xfs_group_type); |
| |
| #define xfs_group_set_mark(_xg, _mark) \ |
| xa_set_mark(&(_xg)->xg_mount->m_groups[(_xg)->xg_type].xa, \ |
| (_xg)->xg_gno, (_mark)) |
| #define xfs_group_clear_mark(_xg, _mark) \ |
| xa_clear_mark(&(_xg)->xg_mount->m_groups[(_xg)->xg_type].xa, \ |
| (_xg)->xg_gno, (_mark)) |
| #define xfs_group_marked(_mp, _type, _mark) \ |
| xa_marked(&(_mp)->m_groups[(_type)].xa, (_mark)) |
| |
| static inline xfs_agblock_t |
| xfs_group_max_blocks( |
| struct xfs_group *xg) |
| { |
| return xg->xg_mount->m_groups[xg->xg_type].blocks; |
| } |
| |
| static inline xfs_fsblock_t |
| xfs_group_start_fsb( |
| struct xfs_group *xg) |
| { |
| return ((xfs_fsblock_t)xg->xg_gno) << |
| xg->xg_mount->m_groups[xg->xg_type].blklog; |
| } |
| |
| static inline xfs_fsblock_t |
| xfs_gbno_to_fsb( |
| struct xfs_group *xg, |
| xfs_agblock_t gbno) |
| { |
| return xfs_group_start_fsb(xg) | gbno; |
| } |
| |
| static inline xfs_daddr_t |
| xfs_gbno_to_daddr( |
| struct xfs_group *xg, |
| xfs_agblock_t gbno) |
| { |
| struct xfs_mount *mp = xg->xg_mount; |
| uint32_t blocks = mp->m_groups[xg->xg_type].blocks; |
| |
| return XFS_FSB_TO_BB(mp, (xfs_fsblock_t)xg->xg_gno * blocks + gbno); |
| } |
| |
| static inline uint32_t |
| xfs_fsb_to_gno( |
| struct xfs_mount *mp, |
| xfs_fsblock_t fsbno, |
| enum xfs_group_type type) |
| { |
| if (!mp->m_groups[type].blklog) |
| return 0; |
| return fsbno >> mp->m_groups[type].blklog; |
| } |
| |
| static inline xfs_agblock_t |
| xfs_fsb_to_gbno( |
| struct xfs_mount *mp, |
| xfs_fsblock_t fsbno, |
| enum xfs_group_type type) |
| { |
| return fsbno & mp->m_groups[type].blkmask; |
| } |
| |
| static inline bool |
| xfs_verify_gbno( |
| struct xfs_group *xg, |
| uint32_t gbno) |
| { |
| if (gbno >= xg->xg_block_count) |
| return false; |
| if (gbno < xg->xg_min_gbno) |
| return false; |
| return true; |
| } |
| |
| static inline bool |
| xfs_verify_gbext( |
| struct xfs_group *xg, |
| uint32_t gbno, |
| uint32_t glen) |
| { |
| uint32_t end; |
| |
| if (!xfs_verify_gbno(xg, gbno)) |
| return false; |
| if (glen == 0 || check_add_overflow(gbno, glen - 1, &end)) |
| return false; |
| if (!xfs_verify_gbno(xg, end)) |
| return false; |
| return true; |
| } |
| |
| #endif /* __LIBXFS_GROUP_H */ |