xfs: convert perag lookup to xarray

Convert the perag lookup from the legacy radix tree to the xarray,
which allows for much nicer iteration and bulk lookup semantics.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Darrick J. Wong <djwong@kernel.org>
Signed-off-by: Chandan Babu R <chandanbabu@kernel.org>
This commit is contained in:
Christoph Hellwig 2024-08-29 07:08:40 +03:00 committed by Chandan Babu R
parent f9ffd095c8
commit 32fa4059fe
4 changed files with 35 additions and 52 deletions

View File

@ -46,7 +46,7 @@ xfs_perag_get(
struct xfs_perag *pag; struct xfs_perag *pag;
rcu_read_lock(); rcu_read_lock();
pag = radix_tree_lookup(&mp->m_perag_tree, agno); pag = xa_load(&mp->m_perags, agno);
if (pag) { if (pag) {
trace_xfs_perag_get(pag, _RET_IP_); trace_xfs_perag_get(pag, _RET_IP_);
ASSERT(atomic_read(&pag->pag_ref) >= 0); ASSERT(atomic_read(&pag->pag_ref) >= 0);
@ -92,7 +92,7 @@ xfs_perag_grab(
struct xfs_perag *pag; struct xfs_perag *pag;
rcu_read_lock(); rcu_read_lock();
pag = radix_tree_lookup(&mp->m_perag_tree, agno); pag = xa_load(&mp->m_perags, agno);
if (pag) { if (pag) {
trace_xfs_perag_grab(pag, _RET_IP_); trace_xfs_perag_grab(pag, _RET_IP_);
if (!atomic_inc_not_zero(&pag->pag_active_ref)) if (!atomic_inc_not_zero(&pag->pag_active_ref))
@ -195,9 +195,7 @@ xfs_free_perag(
xfs_agnumber_t agno; xfs_agnumber_t agno;
for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) { for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) {
spin_lock(&mp->m_perag_lock); pag = xa_erase(&mp->m_perags, agno);
pag = radix_tree_delete(&mp->m_perag_tree, agno);
spin_unlock(&mp->m_perag_lock);
ASSERT(pag); ASSERT(pag);
XFS_IS_CORRUPT(pag->pag_mount, atomic_read(&pag->pag_ref) != 0); XFS_IS_CORRUPT(pag->pag_mount, atomic_read(&pag->pag_ref) != 0);
xfs_defer_drain_free(&pag->pag_intents_drain); xfs_defer_drain_free(&pag->pag_intents_drain);
@ -286,9 +284,7 @@ xfs_free_unused_perag_range(
xfs_agnumber_t index; xfs_agnumber_t index;
for (index = agstart; index < agend; index++) { for (index = agstart; index < agend; index++) {
spin_lock(&mp->m_perag_lock); pag = xa_erase(&mp->m_perags, index);
pag = radix_tree_delete(&mp->m_perag_tree, index);
spin_unlock(&mp->m_perag_lock);
if (!pag) if (!pag)
break; break;
xfs_buf_cache_destroy(&pag->pag_bcache); xfs_buf_cache_destroy(&pag->pag_bcache);
@ -329,20 +325,11 @@ xfs_initialize_perag(
pag->pag_agno = index; pag->pag_agno = index;
pag->pag_mount = mp; pag->pag_mount = mp;
error = radix_tree_preload(GFP_KERNEL | __GFP_RETRY_MAYFAIL); error = xa_insert(&mp->m_perags, index, pag, GFP_KERNEL);
if (error) if (error) {
goto out_free_pag; WARN_ON_ONCE(error == -EBUSY);
spin_lock(&mp->m_perag_lock);
if (radix_tree_insert(&mp->m_perag_tree, index, pag)) {
WARN_ON_ONCE(1);
spin_unlock(&mp->m_perag_lock);
radix_tree_preload_end();
error = -EEXIST;
goto out_free_pag; goto out_free_pag;
} }
spin_unlock(&mp->m_perag_lock);
radix_tree_preload_end();
#ifdef __KERNEL__ #ifdef __KERNEL__
/* Place kernel structure only init below this point. */ /* Place kernel structure only init below this point. */
@ -390,9 +377,7 @@ xfs_initialize_perag(
out_remove_pag: out_remove_pag:
xfs_defer_drain_free(&pag->pag_intents_drain); xfs_defer_drain_free(&pag->pag_intents_drain);
spin_lock(&mp->m_perag_lock); pag = xa_erase(&mp->m_perags, index);
radix_tree_delete(&mp->m_perag_tree, index);
spin_unlock(&mp->m_perag_lock);
out_free_pag: out_free_pag:
kfree(pag); kfree(pag);
out_unwind_new_pags: out_unwind_new_pags:

View File

@ -65,6 +65,18 @@ static int xfs_icwalk_ag(struct xfs_perag *pag,
XFS_ICWALK_FLAG_RECLAIM_SICK | \ XFS_ICWALK_FLAG_RECLAIM_SICK | \
XFS_ICWALK_FLAG_UNION) XFS_ICWALK_FLAG_UNION)
/* Marks for the perag xarray */
#define XFS_PERAG_RECLAIM_MARK XA_MARK_0
#define XFS_PERAG_BLOCKGC_MARK XA_MARK_1
static inline xa_mark_t ici_tag_to_mark(unsigned int tag)
{
if (tag == XFS_ICI_RECLAIM_TAG)
return XFS_PERAG_RECLAIM_MARK;
ASSERT(tag == XFS_ICI_BLOCKGC_TAG);
return XFS_PERAG_BLOCKGC_MARK;
}
/* /*
* Allocate and initialise an xfs_inode. * Allocate and initialise an xfs_inode.
*/ */
@ -191,7 +203,7 @@ xfs_reclaim_work_queue(
{ {
rcu_read_lock(); rcu_read_lock();
if (radix_tree_tagged(&mp->m_perag_tree, XFS_ICI_RECLAIM_TAG)) { if (xa_marked(&mp->m_perags, XFS_PERAG_RECLAIM_MARK)) {
queue_delayed_work(mp->m_reclaim_workqueue, &mp->m_reclaim_work, queue_delayed_work(mp->m_reclaim_workqueue, &mp->m_reclaim_work,
msecs_to_jiffies(xfs_syncd_centisecs / 6 * 10)); msecs_to_jiffies(xfs_syncd_centisecs / 6 * 10));
} }
@ -241,9 +253,7 @@ xfs_perag_set_inode_tag(
return; return;
/* propagate the tag up into the perag radix tree */ /* propagate the tag up into the perag radix tree */
spin_lock(&mp->m_perag_lock); xa_set_mark(&mp->m_perags, pag->pag_agno, ici_tag_to_mark(tag));
radix_tree_tag_set(&mp->m_perag_tree, pag->pag_agno, tag);
spin_unlock(&mp->m_perag_lock);
/* start background work */ /* start background work */
switch (tag) { switch (tag) {
@ -285,9 +295,7 @@ xfs_perag_clear_inode_tag(
return; return;
/* clear the tag from the perag radix tree */ /* clear the tag from the perag radix tree */
spin_lock(&mp->m_perag_lock); xa_clear_mark(&mp->m_perags, pag->pag_agno, ici_tag_to_mark(tag));
radix_tree_tag_clear(&mp->m_perag_tree, pag->pag_agno, tag);
spin_unlock(&mp->m_perag_lock);
trace_xfs_perag_clear_inode_tag(pag, _RET_IP_); trace_xfs_perag_clear_inode_tag(pag, _RET_IP_);
} }
@ -302,7 +310,6 @@ xfs_perag_get_next_tag(
unsigned int tag) unsigned int tag)
{ {
unsigned long index = 0; unsigned long index = 0;
int found;
if (pag) { if (pag) {
index = pag->pag_agno + 1; index = pag->pag_agno + 1;
@ -310,14 +317,11 @@ xfs_perag_get_next_tag(
} }
rcu_read_lock(); rcu_read_lock();
found = radix_tree_gang_lookup_tag(&mp->m_perag_tree, pag = xa_find(&mp->m_perags, &index, ULONG_MAX, ici_tag_to_mark(tag));
(void **)&pag, index, 1, tag); if (pag) {
if (found <= 0) { trace_xfs_perag_get_next_tag(pag, _RET_IP_);
rcu_read_unlock(); atomic_inc(&pag->pag_ref);
return NULL;
} }
trace_xfs_perag_get_next_tag(pag, _RET_IP_);
atomic_inc(&pag->pag_ref);
rcu_read_unlock(); rcu_read_unlock();
return pag; return pag;
} }
@ -332,7 +336,6 @@ xfs_perag_grab_next_tag(
int tag) int tag)
{ {
unsigned long index = 0; unsigned long index = 0;
int found;
if (pag) { if (pag) {
index = pag->pag_agno + 1; index = pag->pag_agno + 1;
@ -340,15 +343,12 @@ xfs_perag_grab_next_tag(
} }
rcu_read_lock(); rcu_read_lock();
found = radix_tree_gang_lookup_tag(&mp->m_perag_tree, pag = xa_find(&mp->m_perags, &index, ULONG_MAX, ici_tag_to_mark(tag));
(void **)&pag, index, 1, tag); if (pag) {
if (found <= 0) { trace_xfs_perag_grab_next_tag(pag, _RET_IP_);
rcu_read_unlock(); if (!atomic_inc_not_zero(&pag->pag_active_ref))
return NULL; pag = NULL;
} }
trace_xfs_perag_grab_next_tag(pag, _RET_IP_);
if (!atomic_inc_not_zero(&pag->pag_active_ref))
pag = NULL;
rcu_read_unlock(); rcu_read_unlock();
return pag; return pag;
} }
@ -1038,7 +1038,7 @@ xfs_reclaim_inodes(
if (xfs_want_reclaim_sick(mp)) if (xfs_want_reclaim_sick(mp))
icw.icw_flags |= XFS_ICWALK_FLAG_RECLAIM_SICK; icw.icw_flags |= XFS_ICWALK_FLAG_RECLAIM_SICK;
while (radix_tree_tagged(&mp->m_perag_tree, XFS_ICI_RECLAIM_TAG)) { while (xa_marked(&mp->m_perags, XFS_PERAG_RECLAIM_MARK)) {
xfs_ail_push_all_sync(mp->m_ail); xfs_ail_push_all_sync(mp->m_ail);
xfs_icwalk(mp, XFS_ICWALK_RECLAIM, &icw); xfs_icwalk(mp, XFS_ICWALK_RECLAIM, &icw);
} }

View File

@ -208,8 +208,7 @@ typedef struct xfs_mount {
*/ */
atomic64_t m_allocbt_blks; atomic64_t m_allocbt_blks;
struct radix_tree_root m_perag_tree; /* per-ag accounting info */ struct xarray m_perags; /* per-ag accounting info */
spinlock_t m_perag_lock; /* lock for m_perag_tree */
uint64_t m_resblks; /* total reserved blocks */ uint64_t m_resblks; /* total reserved blocks */
uint64_t m_resblks_avail;/* available reserved blocks */ uint64_t m_resblks_avail;/* available reserved blocks */
uint64_t m_resblks_save; /* reserved blks @ remount,ro */ uint64_t m_resblks_save; /* reserved blks @ remount,ro */

View File

@ -2009,8 +2009,7 @@ static int xfs_init_fs_context(
return -ENOMEM; return -ENOMEM;
spin_lock_init(&mp->m_sb_lock); spin_lock_init(&mp->m_sb_lock);
INIT_RADIX_TREE(&mp->m_perag_tree, GFP_ATOMIC); xa_init(&mp->m_perags);
spin_lock_init(&mp->m_perag_lock);
mutex_init(&mp->m_growlock); mutex_init(&mp->m_growlock);
INIT_WORK(&mp->m_flush_inodes_work, xfs_flush_inodes_worker); INIT_WORK(&mp->m_flush_inodes_work, xfs_flush_inodes_worker);
INIT_DELAYED_WORK(&mp->m_reclaim_work, xfs_reclaim_worker); INIT_DELAYED_WORK(&mp->m_reclaim_work, xfs_reclaim_worker);