// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2023-2025 Christoph Hellwig.
* Copyright (c) 2024-2025, Western Digital Corporation or its affiliates.
*/
#include "xfs.h"
#include "xfs_shared.h"
#include "xfs_format.h"
#include "xfs_log_format.h"
#include "xfs_error.h"
#include "xfs_trans_resv.h"
#include "xfs_mount.h"
#include "xfs_inode.h"
#include "xfs_iomap.h"
#include "xfs_trans.h"
#include "xfs_alloc.h"
#include "xfs_bmap.h"
#include "xfs_bmap_btree.h"
#include "xfs_trans_space.h"
#include "xfs_refcount.h"
#include "xfs_rtbitmap.h"
#include "xfs_rtrmap_btree.h"
#include "xfs_zone_alloc.h"
#include "xfs_zone_priv.h"
#include "xfs_zones.h"
#include "xfs_trace.h"
#include "xfs_mru_cache.h"
void
xfs_open_zone_put(
struct xfs_open_zone *oz)
{
if (atomic_dec_and_test(&oz->oz_ref)) {
xfs_rtgroup_rele(oz->oz_rtg);
kfree(oz);
}
}
static inline uint32_t
xfs_zone_bucket(
struct xfs_mount *mp,
uint32_t used_blocks)
{
return XFS_ZONE_USED_BUCKETS * used_blocks /
mp->m_groups[XG_TYPE_RTG].blocks;
}
static inline void
xfs_zone_add_to_bucket(
struct xfs_zone_info *zi,
xfs_rgnumber_t rgno,
uint32_t to_bucket)
{
__set_bit(rgno, zi->zi_used_bucket_bitmap[to_bucket]);
zi->zi_used_bucket_entries[to_bucket]++;
}
static inline void
xfs_zone_remove_from_bucket(
struct xfs_zone_info *zi,
xfs_rgnumber_t rgno,
uint32_t from_bucket)
{
__clear_bit(rgno, zi->zi_used_bucket_bitmap[from_bucket]);
zi->zi_used_bucket_entries[from_bucket]--;
}
static void
xfs_zone_account_reclaimable(
struct xfs_rtgroup *rtg,
uint32_t freed)
{
struct xfs_group *xg = &rtg->rtg_group;
struct xfs_mount *mp = rtg_mount(rtg);
struct xfs_zone_info *zi = mp->m_zone_info;
uint32_t used = rtg_rmap(rtg)->i_used_blocks;
xfs_rgnumber_t rgno = rtg_rgno(rtg);
uint32_t from_bucket = xfs_zone_bucket(mp, used + freed);
uint32_t to_bucket = xfs_zone_bucket(mp, used);
bool was_full = (used + freed == rtg_blocks(rtg));
/*
* This can be called from log recovery, where the zone_info structure
* hasn't been allocated yet. Skip all work as xfs_mount_zones will
* add the zones to the right buckets before the file systems becomes
* active.
*/
if (!zi)
return;
if (!used) {
/*
* The zone is now empty, remove it from the bottom bucket and
* trigger a reset.
*/
trace_xfs_zone_emptied(rtg);
if (!was_full)
xfs_group_clear_mark(xg, XFS_RTG_RECLAIMABLE);
spin_lock