mirror of
https://github.com/torvalds/linux.git
synced 2024-11-21 19:41:42 +00:00
e0b5b97dde
Move the min and max agblock numbers to the generic xfs_group structure so that we can start building validators for extents within an rtgroup. While we're at it, use check_add_overflow for the extent length computation because that has much better overflow checking. Signed-off-by: Darrick J. Wong <djwong@kernel.org> Reviewed-by: Christoph Hellwig <hch@lst.de>
165 lines
4.2 KiB
C
165 lines
4.2 KiB
C
/* 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 */
|