1e9c4d8bfSChristoph Hellwig // SPDX-License-Identifier: GPL-2.0 2e9c4d8bfSChristoph Hellwig /* 3e9c4d8bfSChristoph Hellwig * Copyright (c) 2018 Red Hat, Inc. 4e9c4d8bfSChristoph Hellwig */ 5e9c4d8bfSChristoph Hellwig 6e9c4d8bfSChristoph Hellwig #include "xfs.h" 7e9c4d8bfSChristoph Hellwig #include "xfs_shared.h" 8e9c4d8bfSChristoph Hellwig #include "xfs_format.h" 9e9c4d8bfSChristoph Hellwig #include "xfs_trans_resv.h" 10e9c4d8bfSChristoph Hellwig #include "xfs_mount.h" 11e9c4d8bfSChristoph Hellwig #include "xfs_error.h" 12e9c4d8bfSChristoph Hellwig #include "xfs_trace.h" 13adbc76aaSChristoph Hellwig #include "xfs_extent_busy.h" 14e9c4d8bfSChristoph Hellwig #include "xfs_group.h" 15e9c4d8bfSChristoph Hellwig 16e9c4d8bfSChristoph Hellwig /* 17e9c4d8bfSChristoph Hellwig * Groups can have passive and active references. 18e9c4d8bfSChristoph Hellwig * 19e9c4d8bfSChristoph Hellwig * For passive references the code freeing a group is responsible for cleaning 20e9c4d8bfSChristoph Hellwig * up objects that hold the passive references (e.g. cached buffers). 21e9c4d8bfSChristoph Hellwig * Routines manipulating passive references are xfs_group_get, xfs_group_hold 22e9c4d8bfSChristoph Hellwig * and xfs_group_put. 23e9c4d8bfSChristoph Hellwig * 24e9c4d8bfSChristoph Hellwig * Active references are for short term access to the group for walking trees or 25e9c4d8bfSChristoph Hellwig * accessing state. If a group is being shrunk or offlined, the lookup will fail 26e9c4d8bfSChristoph Hellwig * to find that group and return NULL instead. 27e9c4d8bfSChristoph Hellwig * Routines manipulating active references are xfs_group_grab and 28e9c4d8bfSChristoph Hellwig * xfs_group_rele. 29e9c4d8bfSChristoph Hellwig */ 30e9c4d8bfSChristoph Hellwig 31e9c4d8bfSChristoph Hellwig struct xfs_group * 32e9c4d8bfSChristoph Hellwig xfs_group_get( 33e9c4d8bfSChristoph Hellwig struct xfs_mount *mp, 34e9c4d8bfSChristoph Hellwig uint32_t index, 35e9c4d8bfSChristoph Hellwig enum xfs_group_type type) 36e9c4d8bfSChristoph Hellwig { 37e9c4d8bfSChristoph Hellwig struct xfs_group *xg; 38e9c4d8bfSChristoph Hellwig 39e9c4d8bfSChristoph Hellwig rcu_read_lock(); 40e9c4d8bfSChristoph Hellwig xg = xa_load(&mp->m_groups[type].xa, index); 41e9c4d8bfSChristoph Hellwig if (xg) { 42e9c4d8bfSChristoph Hellwig trace_xfs_group_get(xg, _RET_IP_); 43e9c4d8bfSChristoph Hellwig ASSERT(atomic_read(&xg->xg_ref) >= 0); 44e9c4d8bfSChristoph Hellwig atomic_inc(&xg->xg_ref); 45e9c4d8bfSChristoph Hellwig } 46e9c4d8bfSChristoph Hellwig rcu_read_unlock(); 47e9c4d8bfSChristoph Hellwig return xg; 48e9c4d8bfSChristoph Hellwig } 49e9c4d8bfSChristoph Hellwig 50e9c4d8bfSChristoph Hellwig struct xfs_group * 51e9c4d8bfSChristoph Hellwig xfs_group_hold( 52e9c4d8bfSChristoph Hellwig struct xfs_group *xg) 53e9c4d8bfSChristoph Hellwig { 54e9c4d8bfSChristoph Hellwig ASSERT(atomic_read(&xg->xg_ref) > 0 || 55e9c4d8bfSChristoph Hellwig atomic_read(&xg->xg_active_ref) > 0); 56e9c4d8bfSChristoph Hellwig 57e9c4d8bfSChristoph Hellwig trace_xfs_group_hold(xg, _RET_IP_); 58e9c4d8bfSChristoph Hellwig atomic_inc(&xg->xg_ref); 59e9c4d8bfSChristoph Hellwig return xg; 60e9c4d8bfSChristoph Hellwig } 61e9c4d8bfSChristoph Hellwig 62e9c4d8bfSChristoph Hellwig void 63e9c4d8bfSChristoph Hellwig xfs_group_put( 64e9c4d8bfSChristoph Hellwig struct xfs_group *xg) 65e9c4d8bfSChristoph Hellwig { 66e9c4d8bfSChristoph Hellwig trace_xfs_group_put(xg, _RET_IP_); 67e9c4d8bfSChristoph Hellwig 68e9c4d8bfSChristoph Hellwig ASSERT(atomic_read(&xg->xg_ref) > 0); 69e9c4d8bfSChristoph Hellwig atomic_dec(&xg->xg_ref); 70e9c4d8bfSChristoph Hellwig } 71e9c4d8bfSChristoph Hellwig 72e9c4d8bfSChristoph Hellwig struct xfs_group * 73e9c4d8bfSChristoph Hellwig xfs_group_grab( 74e9c4d8bfSChristoph Hellwig struct xfs_mount *mp, 75e9c4d8bfSChristoph Hellwig uint32_t index, 76e9c4d8bfSChristoph Hellwig enum xfs_group_type type) 77e9c4d8bfSChristoph Hellwig { 78e9c4d8bfSChristoph Hellwig struct xfs_group *xg; 79e9c4d8bfSChristoph Hellwig 80e9c4d8bfSChristoph Hellwig rcu_read_lock(); 81e9c4d8bfSChristoph Hellwig xg = xa_load(&mp->m_groups[type].xa, index); 82e9c4d8bfSChristoph Hellwig if (xg) { 83e9c4d8bfSChristoph Hellwig trace_xfs_group_grab(xg, _RET_IP_); 84e9c4d8bfSChristoph Hellwig if (!atomic_inc_not_zero(&xg->xg_active_ref)) 85e9c4d8bfSChristoph Hellwig xg = NULL; 86e9c4d8bfSChristoph Hellwig } 87e9c4d8bfSChristoph Hellwig rcu_read_unlock(); 88e9c4d8bfSChristoph Hellwig return xg; 89e9c4d8bfSChristoph Hellwig } 90e9c4d8bfSChristoph Hellwig 91e9c4d8bfSChristoph Hellwig /* 9281992877SChristoph Hellwig * Iterate to the next group. To start the iteration at @start_index, a %NULL 9381992877SChristoph Hellwig * @xg is passed, else the previous group returned from this function. The 9481992877SChristoph Hellwig * caller should break out of the loop when this returns %NULL. If the caller 9581992877SChristoph Hellwig * wants to break out of a loop that did not finish it needs to release the 9681992877SChristoph Hellwig * active reference to @xg using xfs_group_rele() itself. 9781992877SChristoph Hellwig */ 9881992877SChristoph Hellwig struct xfs_group * 9981992877SChristoph Hellwig xfs_group_next_range( 10081992877SChristoph Hellwig struct xfs_mount *mp, 10181992877SChristoph Hellwig struct xfs_group *xg, 10281992877SChristoph Hellwig uint32_t start_index, 10381992877SChristoph Hellwig uint32_t end_index, 10481992877SChristoph Hellwig enum xfs_group_type type) 10581992877SChristoph Hellwig { 10681992877SChristoph Hellwig uint32_t index = start_index; 10781992877SChristoph Hellwig 10881992877SChristoph Hellwig if (xg) { 10981992877SChristoph Hellwig index = xg->xg_gno + 1; 11081992877SChristoph Hellwig xfs_group_rele(xg); 11181992877SChristoph Hellwig } 11281992877SChristoph Hellwig if (index > end_index) 11381992877SChristoph Hellwig return NULL; 11481992877SChristoph Hellwig return xfs_group_grab(mp, index, type); 11581992877SChristoph Hellwig } 11681992877SChristoph Hellwig 11781992877SChristoph Hellwig /* 118e9c4d8bfSChristoph Hellwig * Find the next group after @xg, or the first group if @xg is NULL. 119e9c4d8bfSChristoph Hellwig */ 120e9c4d8bfSChristoph Hellwig struct xfs_group * 121e9c4d8bfSChristoph Hellwig xfs_group_grab_next_mark( 122e9c4d8bfSChristoph Hellwig struct xfs_mount *mp, 123e9c4d8bfSChristoph Hellwig struct xfs_group *xg, 124e9c4d8bfSChristoph Hellwig xa_mark_t mark, 125e9c4d8bfSChristoph Hellwig enum xfs_group_type type) 126e9c4d8bfSChristoph Hellwig { 127e9c4d8bfSChristoph Hellwig unsigned long index = 0; 128e9c4d8bfSChristoph Hellwig 129e9c4d8bfSChristoph Hellwig if (xg) { 130e9c4d8bfSChristoph Hellwig index = xg->xg_gno + 1; 131e9c4d8bfSChristoph Hellwig xfs_group_rele(xg); 132e9c4d8bfSChristoph Hellwig } 133e9c4d8bfSChristoph Hellwig 134e9c4d8bfSChristoph Hellwig rcu_read_lock(); 135e9c4d8bfSChristoph Hellwig xg = xa_find(&mp->m_groups[type].xa, &index, ULONG_MAX, mark); 136e9c4d8bfSChristoph Hellwig if (xg) { 137e9c4d8bfSChristoph Hellwig trace_xfs_group_grab_next_tag(xg, _RET_IP_); 138e9c4d8bfSChristoph Hellwig if (!atomic_inc_not_zero(&xg->xg_active_ref)) 139e9c4d8bfSChristoph Hellwig xg = NULL; 140e9c4d8bfSChristoph Hellwig } 141e9c4d8bfSChristoph Hellwig rcu_read_unlock(); 142e9c4d8bfSChristoph Hellwig return xg; 143e9c4d8bfSChristoph Hellwig } 144e9c4d8bfSChristoph Hellwig 145e9c4d8bfSChristoph Hellwig void 146e9c4d8bfSChristoph Hellwig xfs_group_rele( 147e9c4d8bfSChristoph Hellwig struct xfs_group *xg) 148e9c4d8bfSChristoph Hellwig { 149e9c4d8bfSChristoph Hellwig trace_xfs_group_rele(xg, _RET_IP_); 150e9c4d8bfSChristoph Hellwig atomic_dec(&xg->xg_active_ref); 151e9c4d8bfSChristoph Hellwig } 152e9c4d8bfSChristoph Hellwig 153e9c4d8bfSChristoph Hellwig void 154e9c4d8bfSChristoph Hellwig xfs_group_free( 155e9c4d8bfSChristoph Hellwig struct xfs_mount *mp, 156e9c4d8bfSChristoph Hellwig uint32_t index, 157e9c4d8bfSChristoph Hellwig enum xfs_group_type type, 158e9c4d8bfSChristoph Hellwig void (*uninit)(struct xfs_group *xg)) 159e9c4d8bfSChristoph Hellwig { 160e9c4d8bfSChristoph Hellwig struct xfs_group *xg = xa_erase(&mp->m_groups[type].xa, index); 161e9c4d8bfSChristoph Hellwig 162e9c4d8bfSChristoph Hellwig XFS_IS_CORRUPT(mp, atomic_read(&xg->xg_ref) != 0); 163e9c4d8bfSChristoph Hellwig 16434cf3a6fSChristoph Hellwig xfs_defer_drain_free(&xg->xg_intents_drain); 165adbc76aaSChristoph Hellwig #ifdef __KERNEL__ 166adbc76aaSChristoph Hellwig kfree(xg->xg_busy_extents); 167adbc76aaSChristoph Hellwig #endif 16834cf3a6fSChristoph Hellwig 169e9c4d8bfSChristoph Hellwig if (uninit) 170e9c4d8bfSChristoph Hellwig uninit(xg); 171e9c4d8bfSChristoph Hellwig 172e9c4d8bfSChristoph Hellwig /* drop the mount's active reference */ 173e9c4d8bfSChristoph Hellwig xfs_group_rele(xg); 174e9c4d8bfSChristoph Hellwig XFS_IS_CORRUPT(mp, atomic_read(&xg->xg_active_ref) != 0); 175e9c4d8bfSChristoph Hellwig kfree_rcu_mightsleep(xg); 176e9c4d8bfSChristoph Hellwig } 177e9c4d8bfSChristoph Hellwig 178e9c4d8bfSChristoph Hellwig int 179e9c4d8bfSChristoph Hellwig xfs_group_insert( 180e9c4d8bfSChristoph Hellwig struct xfs_mount *mp, 181e9c4d8bfSChristoph Hellwig struct xfs_group *xg, 182e9c4d8bfSChristoph Hellwig uint32_t index, 183e9c4d8bfSChristoph Hellwig enum xfs_group_type type) 184e9c4d8bfSChristoph Hellwig { 185e9c4d8bfSChristoph Hellwig int error; 186e9c4d8bfSChristoph Hellwig 187e9c4d8bfSChristoph Hellwig xg->xg_mount = mp; 188e9c4d8bfSChristoph Hellwig xg->xg_gno = index; 189e9c4d8bfSChristoph Hellwig xg->xg_type = type; 190e9c4d8bfSChristoph Hellwig 1915c8483ceSChristoph Hellwig #ifdef __KERNEL__ 192adbc76aaSChristoph Hellwig xg->xg_busy_extents = xfs_extent_busy_alloc(); 193adbc76aaSChristoph Hellwig if (!xg->xg_busy_extents) 194adbc76aaSChristoph Hellwig return -ENOMEM; 1955c8483ceSChristoph Hellwig spin_lock_init(&xg->xg_state_lock); 196eb4a84a3SChristoph Hellwig xfs_hooks_init(&xg->xg_rmap_update_hooks); 1975c8483ceSChristoph Hellwig #endif 19834cf3a6fSChristoph Hellwig xfs_defer_drain_init(&xg->xg_intents_drain); 1995c8483ceSChristoph Hellwig 200e9c4d8bfSChristoph Hellwig /* Active ref owned by mount indicates group is online. */ 201e9c4d8bfSChristoph Hellwig atomic_set(&xg->xg_active_ref, 1); 202e9c4d8bfSChristoph Hellwig 203e9c4d8bfSChristoph Hellwig error = xa_insert(&mp->m_groups[type].xa, index, xg, GFP_KERNEL); 204e9c4d8bfSChristoph Hellwig if (error) { 205e9c4d8bfSChristoph Hellwig WARN_ON_ONCE(error == -EBUSY); 206adbc76aaSChristoph Hellwig goto out_drain; 207e9c4d8bfSChristoph Hellwig } 208e9c4d8bfSChristoph Hellwig 209e9c4d8bfSChristoph Hellwig return 0; 210adbc76aaSChristoph Hellwig out_drain: 211adbc76aaSChristoph Hellwig xfs_defer_drain_free(&xg->xg_intents_drain); 212adbc76aaSChristoph Hellwig #ifdef __KERNEL__ 213adbc76aaSChristoph Hellwig kfree(xg->xg_busy_extents); 214adbc76aaSChristoph Hellwig #endif 215adbc76aaSChristoph Hellwig return error; 216e9c4d8bfSChristoph Hellwig } 217*759cc198SChristoph Hellwig 218*759cc198SChristoph Hellwig struct xfs_group * 219*759cc198SChristoph Hellwig xfs_group_get_by_fsb( 220*759cc198SChristoph Hellwig struct xfs_mount *mp, 221*759cc198SChristoph Hellwig xfs_fsblock_t fsbno, 222*759cc198SChristoph Hellwig enum xfs_group_type type) 223*759cc198SChristoph Hellwig { 224*759cc198SChristoph Hellwig return xfs_group_get(mp, xfs_fsb_to_gno(mp, fsbno, type), type); 225*759cc198SChristoph Hellwig } 226