All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC 00/22] xfs: initial agnumber -> perag conversions for shrink
@ 2021-05-06  7:20 Dave Chinner
  2021-05-06  7:20 ` [PATCH 01/22] xfs: move xfs_perag_get/put to xfs_ag.[ch] Dave Chinner
                   ` (21 more replies)
  0 siblings, 22 replies; 87+ messages in thread
From: Dave Chinner @ 2021-05-06  7:20 UTC (permalink / raw)
  To: linux-xfs

Hi folks,

After I proposed that we use active references to the perag to be
able to gate shrink removing AGs and hence perags safely, it was
obvious that we've got a fair bit of work to do actually use perags
in all the places we need to.

There's a lot of code right now that iterates ag numbers and then
looks up perags from that, often multiple times for the same perag
in the one operation. IF we want to use reference counted perags for
access control, then we nee dto convert all these uses to perag
iterators, not agno iterators.

This patchset does not include any of the active/passive reference
counting needed for shrink gating - we have to get perags in use in
all the palces we need first before that will work effectively, and
that's what this patchset starts to address.

It's also been clear as I've been doing these conversions that
having a perag available in places that are doing AG specific work
allows for significant cleanups and optimisations to be made. One
such example is fleshed out in this patch (inode allocation), but
there are many more if we do things like start moving AG geometry
information into the perag. This means we no longer need to run a
calculation to determine what the size of the AG is, which is
important because the verify functions consume a large amount
of CPU doing exactly this sort of check on block and inode numbers
throughout the code.

It also leads to repeated patterns where we have a perag in hand
before we have to read an AGI or AGF buffer to lock the AG for the
operation we are about to perform. There are many optimisations on
both the buffer caching and AG locking strategies that we can build
on from this. e.g. moving AGI/AGF locking into the pag rather than
using the buffer lock, doing pag+agbno based buffer cache lookups
instead of daddr based lookups that then have to look up the pag,
etc.

IOWs, this turns a lot of the code we have on it's head and there's
significant potential for code simplification and algorithmic
optimisations to be made as a result. A lot of this sort of thing
will be medium term work rather than done up front - shrink is the
initial priority, so widespread conversion comes first.

[Patches 1-4]

The first step of this is consolidating all the perag management -
init, free, get, put, etc into a common location. THis is spread all
over the place right now, so move it all into libxfs/xfs_ag.[ch].
This does expose kernel only bits of the perag to libxfs and hence
userspace, so the structures and code is rearranged to minimise the
number of ifdefs that need to be added to the userspace codebase.
The perag iterator in xfs_icache.c is promoted to a first class API
and expanded to the needs of the code as required. 

[Patches 5-10]

These are the first basic perag iterator conversions and changes to
pass the perag down the stack from those iterators where
appropriate. A lot of this is obvious, simple changes, though in
some places we stop passing the perag down the stack because the
code enters into an as yet unconverted subsystem that still uses raw
AGs.

[Patches 11-16]

These replace the agno passed in the btree cursor for per-ag btree
operations with a perag that is passed to the cursor init function.
The cursor takes it's own reference to the perag, and the reference
is dropped when the cursor is deleted. Hence we get reference
coverage for the entire time the cursor is active, even if the code
that initialised the cursor drops it's reference before the cursor
or any of it's children (duplicates) have been deleted.

The first patch adds the perag infrastructure for the cursor, the
next four patches convert a btree cursor at a time, and the last
removes the agno from the cursor once it is unused.

[Patches 17-21]

These patches are a demonstration of the simplifications and
cleanups that come from plumbing the perag through interfaces that
select and then operate on a specific AG. In this case the inode
allocation algorithm does up to three walks across all AGs before it
either allocates an inode or fails. Two of these walks are purely
just to select the AG, and even then it doesn't guarantee inode
allocation success so there's a third walk if the selected AG
allocation fails.

These patches collapse the selection and allocation into a single
loop, simplifies the error handling because xfs_dir_ialloc() always
returns ENOSPC if no AG was selected for inode allocation or we fail
to allocate an inode in any AG, gets rid of xfs_dir_ialloc()
wrapper, converts inode allocation to run entirely from a single
perag instance, and then factors xfs_dialloc() into a much, much
simpler loop which is easy to understand.

Hence we end up with the same inode allocation logic, but it only
needs two complete iterations at worst, makes AG selection and
allocation atomic w.r.t. shrink and chops out out over 100 lines of
code from this hot code path.

[Patch 22]

Converts the unlink path to pass perags through it.

There's more conversion work to be done, but this patchset gets
through a large chunk of it in one hit. Most of the iterators are
converted, so once this is solidified we can move on to converting
these to active references for being able to free perags while the
fs is still active.

Indeed, this allows more than just shrink - if we can safely detect
a perag is unreferenced and take it out of service, we have the
infrastructure we need to be able to implement a memory shrinker for
perags. That is a big step towards supporting extremely large
numbers of AGs in the filesystem - we can't really support millions
of AGs in a filesystem if they must all be loading into memory at
all times. We can already do demand based initialisation of perags,
but we cannot do memory pressure based reclaim. Reference counting
for shrink gives us the necessary capability for demand based
reclaim of perags....

This approach solves more than one problem we really need to solve,
and hence I think it's worth making this scope of changes now to
support shrink operations....

Thoughts, comments, welcome..

Cheers,

Dave.



^ permalink raw reply	[flat|nested] 87+ messages in thread

* [PATCH 01/22] xfs: move xfs_perag_get/put to xfs_ag.[ch]
  2021-05-06  7:20 [RFC 00/22] xfs: initial agnumber -> perag conversions for shrink Dave Chinner
@ 2021-05-06  7:20 ` Dave Chinner
  2021-05-10 12:52   ` Brian Foster
  2021-05-10 22:28   ` Darrick J. Wong
  2021-05-06  7:20 ` [PATCH 02/22] xfs: prepare for moving perag definitions and support to libxfs Dave Chinner
                   ` (20 subsequent siblings)
  21 siblings, 2 replies; 87+ messages in thread
From: Dave Chinner @ 2021-05-06  7:20 UTC (permalink / raw)
  To: linux-xfs

From: Dave Chinner <dchinner@redhat.com>

They are AG functions, not superblock functions, so move them to the
appropriate location.

Signed-off-by: Dave Chinner <dchinner@redhat.com>
---
 fs/xfs/libxfs/xfs_ag.c             | 135 +++++++++++++++++++++++++++++
 fs/xfs/libxfs/xfs_ag.h             |  10 +++
 fs/xfs/libxfs/xfs_ag_resv.c        |   2 +-
 fs/xfs/libxfs/xfs_alloc.c          |   2 +-
 fs/xfs/libxfs/xfs_alloc_btree.c    |   2 +-
 fs/xfs/libxfs/xfs_attr_leaf.c      |   1 +
 fs/xfs/libxfs/xfs_bmap.c           |   1 +
 fs/xfs/libxfs/xfs_ialloc.c         |   2 +-
 fs/xfs/libxfs/xfs_refcount_btree.c |   2 +-
 fs/xfs/libxfs/xfs_rmap.c           |   1 +
 fs/xfs/libxfs/xfs_rmap_btree.c     |   2 +-
 fs/xfs/libxfs/xfs_sb.c             | 133 ----------------------------
 fs/xfs/libxfs/xfs_sb.h             |   9 --
 fs/xfs/scrub/agheader.c            |   1 +
 fs/xfs/scrub/agheader_repair.c     |   1 +
 fs/xfs/scrub/common.c              |   2 +-
 fs/xfs/scrub/fscounters.c          |   2 +-
 fs/xfs/scrub/health.c              |   2 +-
 fs/xfs/scrub/repair.c              |   1 +
 fs/xfs/xfs_buf.c                   |   2 +-
 fs/xfs/xfs_discard.c               |   2 +-
 fs/xfs/xfs_extent_busy.c           |   2 +-
 fs/xfs/xfs_filestream.c            |   2 +-
 fs/xfs/xfs_health.c                |   2 +-
 fs/xfs/xfs_icache.c                |   2 +-
 fs/xfs/xfs_inode.c                 |   2 +-
 fs/xfs/xfs_log_recover.c           |   1 +
 fs/xfs/xfs_mount.c                 |   1 +
 fs/xfs/xfs_qm.c                    |   1 +
 fs/xfs/xfs_reflink.c               |   2 +-
 fs/xfs/xfs_super.c                 |   1 +
 31 files changed, 172 insertions(+), 159 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_ag.c b/fs/xfs/libxfs/xfs_ag.c
index c68a36688474..2ca31dc46fe8 100644
--- a/fs/xfs/libxfs/xfs_ag.c
+++ b/fs/xfs/libxfs/xfs_ag.c
@@ -27,6 +27,141 @@
 #include "xfs_defer.h"
 #include "xfs_log_format.h"
 #include "xfs_trans.h"
+#include "xfs_trace.h"
+
+/*
+ * Passive reference counting access wrappers to the perag structures.  If the
+ * per-ag structure is to be freed, the freeing code is responsible for cleaning
+ * up objects with passive references before freeing the structure. This is
+ * things like cached buffers.
+ */
+struct xfs_perag *
+xfs_perag_get(
+	struct xfs_mount	*mp,
+	xfs_agnumber_t		agno)
+{
+	struct xfs_perag	*pag;
+	int			ref = 0;
+
+	rcu_read_lock();
+	pag = radix_tree_lookup(&mp->m_perag_tree, agno);
+	if (pag) {
+		ASSERT(atomic_read(&pag->pag_ref) >= 0);
+		ref = atomic_inc_return(&pag->pag_ref);
+	}
+	rcu_read_unlock();
+	trace_xfs_perag_get(mp, agno, ref, _RET_IP_);
+	return pag;
+}
+
+/*
+ * search from @first to find the next perag with the given tag set.
+ */
+struct xfs_perag *
+xfs_perag_get_tag(
+	struct xfs_mount	*mp,
+	xfs_agnumber_t		first,
+	int			tag)
+{
+	struct xfs_perag	*pag;
+	int			found;
+	int			ref;
+
+	rcu_read_lock();
+	found = radix_tree_gang_lookup_tag(&mp->m_perag_tree,
+					(void **)&pag, first, 1, tag);
+	if (found <= 0) {
+		rcu_read_unlock();
+		return NULL;
+	}
+	ref = atomic_inc_return(&pag->pag_ref);
+	rcu_read_unlock();
+	trace_xfs_perag_get_tag(mp, pag->pag_agno, ref, _RET_IP_);
+	return pag;
+}
+
+void
+xfs_perag_put(
+	struct xfs_perag	*pag)
+{
+	int	ref;
+
+	ASSERT(atomic_read(&pag->pag_ref) > 0);
+	ref = atomic_dec_return(&pag->pag_ref);
+	trace_xfs_perag_put(pag->pag_mount, pag->pag_agno, ref, _RET_IP_);
+}
+
+/*
+ * xfs_initialize_perag_data
+ *
+ * Read in each per-ag structure so we can count up the number of
+ * allocated inodes, free inodes and used filesystem blocks as this
+ * information is no longer persistent in the superblock. Once we have
+ * this information, write it into the in-core superblock structure.
+ */
+int
+xfs_initialize_perag_data(
+	struct xfs_mount *mp,
+	xfs_agnumber_t	agcount)
+{
+	xfs_agnumber_t	index;
+	xfs_perag_t	*pag;
+	xfs_sb_t	*sbp = &mp->m_sb;
+	uint64_t	ifree = 0;
+	uint64_t	ialloc = 0;
+	uint64_t	bfree = 0;
+	uint64_t	bfreelst = 0;
+	uint64_t	btree = 0;
+	uint64_t	fdblocks;
+	int		error = 0;
+
+	for (index = 0; index < agcount; index++) {
+		/*
+		 * read the agf, then the agi. This gets us
+		 * all the information we need and populates the
+		 * per-ag structures for us.
+		 */
+		error = xfs_alloc_pagf_init(mp, NULL, index, 0);
+		if (error)
+			return error;
+
+		error = xfs_ialloc_pagi_init(mp, NULL, index);
+		if (error)
+			return error;
+		pag = xfs_perag_get(mp, index);
+		ifree += pag->pagi_freecount;
+		ialloc += pag->pagi_count;
+		bfree += pag->pagf_freeblks;
+		bfreelst += pag->pagf_flcount;
+		btree += pag->pagf_btreeblks;
+		xfs_perag_put(pag);
+	}
+	fdblocks = bfree + bfreelst + btree;
+
+	/*
+	 * If the new summary counts are obviously incorrect, fail the
+	 * mount operation because that implies the AGFs are also corrupt.
+	 * Clear FS_COUNTERS so that we don't unmount with a dirty log, which
+	 * will prevent xfs_repair from fixing anything.
+	 */
+	if (fdblocks > sbp->sb_dblocks || ifree > ialloc) {
+		xfs_alert(mp, "AGF corruption. Please run xfs_repair.");
+		error = -EFSCORRUPTED;
+		goto out;
+	}
+
+	/* Overwrite incore superblock counters with just-read data */
+	spin_lock(&mp->m_sb_lock);
+	sbp->sb_ifree = ifree;
+	sbp->sb_icount = ialloc;
+	sbp->sb_fdblocks = fdblocks;
+	spin_unlock(&mp->m_sb_lock);
+
+	xfs_reinit_percpu_counters(mp);
+out:
+	xfs_fs_mark_healthy(mp, XFS_SICK_FS_COUNTERS);
+	return error;
+}
 
 static int
 xfs_get_aghdr_buf(
diff --git a/fs/xfs/libxfs/xfs_ag.h b/fs/xfs/libxfs/xfs_ag.h
index 4535de1d88ea..cb1bd1c03cd7 100644
--- a/fs/xfs/libxfs/xfs_ag.h
+++ b/fs/xfs/libxfs/xfs_ag.h
@@ -9,6 +9,16 @@
 
 struct xfs_mount;
 struct xfs_trans;
+struct xfs_perag;
+
+/*
+ * perag get/put wrappers for ref counting
+ */
+int	xfs_initialize_perag_data(struct xfs_mount *, xfs_agnumber_t);
+struct xfs_perag *xfs_perag_get(struct xfs_mount *, xfs_agnumber_t);
+struct xfs_perag *xfs_perag_get_tag(struct xfs_mount *, xfs_agnumber_t,
+				   int tag);
+void	xfs_perag_put(struct xfs_perag *pag);
 
 struct aghdr_init_data {
 	/* per ag data */
diff --git a/fs/xfs/libxfs/xfs_ag_resv.c b/fs/xfs/libxfs/xfs_ag_resv.c
index e32a1833d523..2e3dcdfd4984 100644
--- a/fs/xfs/libxfs/xfs_ag_resv.c
+++ b/fs/xfs/libxfs/xfs_ag_resv.c
@@ -19,7 +19,7 @@
 #include "xfs_btree.h"
 #include "xfs_refcount_btree.h"
 #include "xfs_ialloc_btree.h"
-#include "xfs_sb.h"
+#include "xfs_ag.h"
 #include "xfs_ag_resv.h"
 
 /*
diff --git a/fs/xfs/libxfs/xfs_alloc.c b/fs/xfs/libxfs/xfs_alloc.c
index 82b7cbb1f24f..dc2b77829915 100644
--- a/fs/xfs/libxfs/xfs_alloc.c
+++ b/fs/xfs/libxfs/xfs_alloc.c
@@ -10,7 +10,6 @@
 #include "xfs_shared.h"
 #include "xfs_trans_resv.h"
 #include "xfs_bit.h"
-#include "xfs_sb.h"
 #include "xfs_mount.h"
 #include "xfs_defer.h"
 #include "xfs_btree.h"
@@ -24,6 +23,7 @@
 #include "xfs_trans.h"
 #include "xfs_buf_item.h"
 #include "xfs_log.h"
+#include "xfs_ag.h"
 #include "xfs_ag_resv.h"
 #include "xfs_bmap.h"
 
diff --git a/fs/xfs/libxfs/xfs_alloc_btree.c b/fs/xfs/libxfs/xfs_alloc_btree.c
index a43e4c50e69b..a540b6e799e0 100644
--- a/fs/xfs/libxfs/xfs_alloc_btree.c
+++ b/fs/xfs/libxfs/xfs_alloc_btree.c
@@ -9,7 +9,6 @@
 #include "xfs_format.h"
 #include "xfs_log_format.h"
 #include "xfs_trans_resv.h"
-#include "xfs_sb.h"
 #include "xfs_mount.h"
 #include "xfs_btree.h"
 #include "xfs_btree_staging.h"
@@ -19,6 +18,7 @@
 #include "xfs_error.h"
 #include "xfs_trace.h"
 #include "xfs_trans.h"
+#include "xfs_ag.h"
 
 
 STATIC struct xfs_btree_cur *
diff --git a/fs/xfs/libxfs/xfs_attr_leaf.c b/fs/xfs/libxfs/xfs_attr_leaf.c
index 556184b63061..aa371d005131 100644
--- a/fs/xfs/libxfs/xfs_attr_leaf.c
+++ b/fs/xfs/libxfs/xfs_attr_leaf.c
@@ -27,6 +27,7 @@
 #include "xfs_buf_item.h"
 #include "xfs_dir2.h"
 #include "xfs_log.h"
+#include "xfs_ag.h"
 
 
 /*
diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c
index 7e3b9b01431e..2086c55b67bd 100644
--- a/fs/xfs/libxfs/xfs_bmap.c
+++ b/fs/xfs/libxfs/xfs_bmap.c
@@ -31,6 +31,7 @@
 #include "xfs_attr_leaf.h"
 #include "xfs_filestream.h"
 #include "xfs_rmap.h"
+#include "xfs_ag.h"
 #include "xfs_ag_resv.h"
 #include "xfs_refcount.h"
 #include "xfs_icache.h"
diff --git a/fs/xfs/libxfs/xfs_ialloc.c b/fs/xfs/libxfs/xfs_ialloc.c
index eefdb518fe64..8dc9225a5353 100644
--- a/fs/xfs/libxfs/xfs_ialloc.c
+++ b/fs/xfs/libxfs/xfs_ialloc.c
@@ -10,7 +10,6 @@
 #include "xfs_log_format.h"
 #include "xfs_trans_resv.h"
 #include "xfs_bit.h"
-#include "xfs_sb.h"
 #include "xfs_mount.h"
 #include "xfs_inode.h"
 #include "xfs_btree.h"
@@ -27,6 +26,7 @@
 #include "xfs_trace.h"
 #include "xfs_log.h"
 #include "xfs_rmap.h"
+#include "xfs_ag.h"
 
 /*
  * Lookup a record by ino in the btree given by cur.
diff --git a/fs/xfs/libxfs/xfs_refcount_btree.c b/fs/xfs/libxfs/xfs_refcount_btree.c
index a6ac60ae9421..b281f0c674f5 100644
--- a/fs/xfs/libxfs/xfs_refcount_btree.c
+++ b/fs/xfs/libxfs/xfs_refcount_btree.c
@@ -9,7 +9,6 @@
 #include "xfs_format.h"
 #include "xfs_log_format.h"
 #include "xfs_trans_resv.h"
-#include "xfs_sb.h"
 #include "xfs_mount.h"
 #include "xfs_btree.h"
 #include "xfs_btree_staging.h"
@@ -20,6 +19,7 @@
 #include "xfs_trans.h"
 #include "xfs_bit.h"
 #include "xfs_rmap.h"
+#include "xfs_ag.h"
 
 static struct xfs_btree_cur *
 xfs_refcountbt_dup_cursor(
diff --git a/fs/xfs/libxfs/xfs_rmap.c b/fs/xfs/libxfs/xfs_rmap.c
index 10e0cf9949a2..61e8f10436ac 100644
--- a/fs/xfs/libxfs/xfs_rmap.c
+++ b/fs/xfs/libxfs/xfs_rmap.c
@@ -21,6 +21,7 @@
 #include "xfs_errortag.h"
 #include "xfs_error.h"
 #include "xfs_inode.h"
+#include "xfs_ag.h"
 
 /*
  * Lookup the first record less than or equal to [bno, len, owner, offset]
diff --git a/fs/xfs/libxfs/xfs_rmap_btree.c b/fs/xfs/libxfs/xfs_rmap_btree.c
index 9f5bcbd834c3..f1fee42dda2d 100644
--- a/fs/xfs/libxfs/xfs_rmap_btree.c
+++ b/fs/xfs/libxfs/xfs_rmap_btree.c
@@ -9,7 +9,6 @@
 #include "xfs_format.h"
 #include "xfs_log_format.h"
 #include "xfs_trans_resv.h"
-#include "xfs_sb.h"
 #include "xfs_mount.h"
 #include "xfs_trans.h"
 #include "xfs_alloc.h"
@@ -20,6 +19,7 @@
 #include "xfs_trace.h"
 #include "xfs_error.h"
 #include "xfs_extent_busy.h"
+#include "xfs_ag.h"
 #include "xfs_ag_resv.h"
 
 /*
diff --git a/fs/xfs/libxfs/xfs_sb.c b/fs/xfs/libxfs/xfs_sb.c
index dfbbcbd448c1..cbcfce8cebf1 100644
--- a/fs/xfs/libxfs/xfs_sb.c
+++ b/fs/xfs/libxfs/xfs_sb.c
@@ -30,67 +30,6 @@
  * Physical superblock buffer manipulations. Shared with libxfs in userspace.
  */
 
-/*
- * Reference counting access wrappers to the perag structures.
- * Because we never free per-ag structures, the only thing we
- * have to protect against changes is the tree structure itself.
- */
-struct xfs_perag *
-xfs_perag_get(
-	struct xfs_mount	*mp,
-	xfs_agnumber_t		agno)
-{
-	struct xfs_perag	*pag;
-	int			ref = 0;
-
-	rcu_read_lock();
-	pag = radix_tree_lookup(&mp->m_perag_tree, agno);
-	if (pag) {
-		ASSERT(atomic_read(&pag->pag_ref) >= 0);
-		ref = atomic_inc_return(&pag->pag_ref);
-	}
-	rcu_read_unlock();
-	trace_xfs_perag_get(mp, agno, ref, _RET_IP_);
-	return pag;
-}
-
-/*
- * search from @first to find the next perag with the given tag set.
- */
-struct xfs_perag *
-xfs_perag_get_tag(
-	struct xfs_mount	*mp,
-	xfs_agnumber_t		first,
-	int			tag)
-{
-	struct xfs_perag	*pag;
-	int			found;
-	int			ref;
-
-	rcu_read_lock();
-	found = radix_tree_gang_lookup_tag(&mp->m_perag_tree,
-					(void **)&pag, first, 1, tag);
-	if (found <= 0) {
-		rcu_read_unlock();
-		return NULL;
-	}
-	ref = atomic_inc_return(&pag->pag_ref);
-	rcu_read_unlock();
-	trace_xfs_perag_get_tag(mp, pag->pag_agno, ref, _RET_IP_);
-	return pag;
-}
-
-void
-xfs_perag_put(
-	struct xfs_perag	*pag)
-{
-	int	ref;
-
-	ASSERT(atomic_read(&pag->pag_ref) > 0);
-	ref = atomic_dec_return(&pag->pag_ref);
-	trace_xfs_perag_put(pag->pag_mount, pag->pag_agno, ref, _RET_IP_);
-}
-
 /* Check all the superblock fields we care about when reading one in. */
 STATIC int
 xfs_validate_sb_read(
@@ -841,78 +780,6 @@ xfs_sb_mount_common(
 	mp->m_ag_max_usable = xfs_alloc_ag_max_usable(mp);
 }
 
-/*
- * xfs_initialize_perag_data
- *
- * Read in each per-ag structure so we can count up the number of
- * allocated inodes, free inodes and used filesystem blocks as this
- * information is no longer persistent in the superblock. Once we have
- * this information, write it into the in-core superblock structure.
- */
-int
-xfs_initialize_perag_data(
-	struct xfs_mount *mp,
-	xfs_agnumber_t	agcount)
-{
-	xfs_agnumber_t	index;
-	xfs_perag_t	*pag;
-	xfs_sb_t	*sbp = &mp->m_sb;
-	uint64_t	ifree = 0;
-	uint64_t	ialloc = 0;
-	uint64_t	bfree = 0;
-	uint64_t	bfreelst = 0;
-	uint64_t	btree = 0;
-	uint64_t	fdblocks;
-	int		error = 0;
-
-	for (index = 0; index < agcount; index++) {
-		/*
-		 * read the agf, then the agi. This gets us
-		 * all the information we need and populates the
-		 * per-ag structures for us.
-		 */
-		error = xfs_alloc_pagf_init(mp, NULL, index, 0);
-		if (error)
-			return error;
-
-		error = xfs_ialloc_pagi_init(mp, NULL, index);
-		if (error)
-			return error;
-		pag = xfs_perag_get(mp, index);
-		ifree += pag->pagi_freecount;
-		ialloc += pag->pagi_count;
-		bfree += pag->pagf_freeblks;
-		bfreelst += pag->pagf_flcount;
-		btree += pag->pagf_btreeblks;
-		xfs_perag_put(pag);
-	}
-	fdblocks = bfree + bfreelst + btree;
-
-	/*
-	 * If the new summary counts are obviously incorrect, fail the
-	 * mount operation because that implies the AGFs are also corrupt.
-	 * Clear FS_COUNTERS so that we don't unmount with a dirty log, which
-	 * will prevent xfs_repair from fixing anything.
-	 */
-	if (fdblocks > sbp->sb_dblocks || ifree > ialloc) {
-		xfs_alert(mp, "AGF corruption. Please run xfs_repair.");
-		error = -EFSCORRUPTED;
-		goto out;
-	}
-
-	/* Overwrite incore superblock counters with just-read data */
-	spin_lock(&mp->m_sb_lock);
-	sbp->sb_ifree = ifree;
-	sbp->sb_icount = ialloc;
-	sbp->sb_fdblocks = fdblocks;
-	spin_unlock(&mp->m_sb_lock);
-
-	xfs_reinit_percpu_counters(mp);
-out:
-	xfs_fs_mark_healthy(mp, XFS_SICK_FS_COUNTERS);
-	return error;
-}
-
 /*
  * xfs_log_sb() can be used to copy arbitrary changes to the in-core superblock
  * into the superblock buffer to be logged.  It does not provide the higher
diff --git a/fs/xfs/libxfs/xfs_sb.h b/fs/xfs/libxfs/xfs_sb.h
index f79f9dc632b6..0c1602d9b53d 100644
--- a/fs/xfs/libxfs/xfs_sb.h
+++ b/fs/xfs/libxfs/xfs_sb.h
@@ -13,15 +13,6 @@ struct xfs_trans;
 struct xfs_fsop_geom;
 struct xfs_perag;
 
-/*
- * perag get/put wrappers for ref counting
- */
-extern struct xfs_perag *xfs_perag_get(struct xfs_mount *, xfs_agnumber_t);
-extern struct xfs_perag *xfs_perag_get_tag(struct xfs_mount *, xfs_agnumber_t,
-					   int tag);
-extern void	xfs_perag_put(struct xfs_perag *pag);
-extern int	xfs_initialize_perag_data(struct xfs_mount *, xfs_agnumber_t);
-
 extern void	xfs_log_sb(struct xfs_trans *tp);
 extern int	xfs_sync_sb(struct xfs_mount *mp, bool wait);
 extern int	xfs_sync_sb_buf(struct xfs_mount *mp);
diff --git a/fs/xfs/scrub/agheader.c b/fs/xfs/scrub/agheader.c
index 7a2f9b5f2db5..64a7a30f4ac0 100644
--- a/fs/xfs/scrub/agheader.c
+++ b/fs/xfs/scrub/agheader.c
@@ -14,6 +14,7 @@
 #include "xfs_alloc.h"
 #include "xfs_ialloc.h"
 #include "xfs_rmap.h"
+#include "xfs_ag.h"
 #include "scrub/scrub.h"
 #include "scrub/common.h"
 
diff --git a/fs/xfs/scrub/agheader_repair.c b/fs/xfs/scrub/agheader_repair.c
index 23690f824ffa..1cdfbd57f36b 100644
--- a/fs/xfs/scrub/agheader_repair.c
+++ b/fs/xfs/scrub/agheader_repair.c
@@ -20,6 +20,7 @@
 #include "xfs_rmap.h"
 #include "xfs_rmap_btree.h"
 #include "xfs_refcount_btree.h"
+#include "xfs_ag.h"
 #include "scrub/scrub.h"
 #include "scrub/common.h"
 #include "scrub/trace.h"
diff --git a/fs/xfs/scrub/common.c b/fs/xfs/scrub/common.c
index aa874607618a..c8da976b50fc 100644
--- a/fs/xfs/scrub/common.c
+++ b/fs/xfs/scrub/common.c
@@ -12,7 +12,6 @@
 #include "xfs_btree.h"
 #include "xfs_log_format.h"
 #include "xfs_trans.h"
-#include "xfs_sb.h"
 #include "xfs_inode.h"
 #include "xfs_icache.h"
 #include "xfs_alloc.h"
@@ -26,6 +25,7 @@
 #include "xfs_trans_priv.h"
 #include "xfs_attr.h"
 #include "xfs_reflink.h"
+#include "xfs_ag.h"
 #include "scrub/scrub.h"
 #include "scrub/common.h"
 #include "scrub/trace.h"
diff --git a/fs/xfs/scrub/fscounters.c b/fs/xfs/scrub/fscounters.c
index f1d1a8c58853..453ae9adf94c 100644
--- a/fs/xfs/scrub/fscounters.c
+++ b/fs/xfs/scrub/fscounters.c
@@ -9,11 +9,11 @@
 #include "xfs_format.h"
 #include "xfs_trans_resv.h"
 #include "xfs_mount.h"
-#include "xfs_sb.h"
 #include "xfs_alloc.h"
 #include "xfs_ialloc.h"
 #include "xfs_health.h"
 #include "xfs_btree.h"
+#include "xfs_ag.h"
 #include "scrub/scrub.h"
 #include "scrub/common.h"
 #include "scrub/trace.h"
diff --git a/fs/xfs/scrub/health.c b/fs/xfs/scrub/health.c
index 3de59b5c2ce6..2e61df3bca83 100644
--- a/fs/xfs/scrub/health.c
+++ b/fs/xfs/scrub/health.c
@@ -8,7 +8,7 @@
 #include "xfs_shared.h"
 #include "xfs_format.h"
 #include "xfs_btree.h"
-#include "xfs_sb.h"
+#include "xfs_ag.h"
 #include "xfs_health.h"
 #include "scrub/scrub.h"
 #include "scrub/health.h"
diff --git a/fs/xfs/scrub/repair.c b/fs/xfs/scrub/repair.c
index c2857d854c83..1308b62a8170 100644
--- a/fs/xfs/scrub/repair.c
+++ b/fs/xfs/scrub/repair.c
@@ -22,6 +22,7 @@
 #include "xfs_rmap_btree.h"
 #include "xfs_refcount_btree.h"
 #include "xfs_extent_busy.h"
+#include "xfs_ag.h"
 #include "xfs_ag_resv.h"
 #include "xfs_quota.h"
 #include "scrub/scrub.h"
diff --git a/fs/xfs/xfs_buf.c b/fs/xfs/xfs_buf.c
index 37a1d12762d8..38245c49b1b6 100644
--- a/fs/xfs/xfs_buf.c
+++ b/fs/xfs/xfs_buf.c
@@ -10,7 +10,6 @@
 #include "xfs_format.h"
 #include "xfs_log_format.h"
 #include "xfs_trans_resv.h"
-#include "xfs_sb.h"
 #include "xfs_mount.h"
 #include "xfs_trace.h"
 #include "xfs_log.h"
@@ -19,6 +18,7 @@
 #include "xfs_buf_item.h"
 #include "xfs_errortag.h"
 #include "xfs_error.h"
+#include "xfs_ag.h"
 
 static kmem_zone_t *xfs_buf_zone;
 
diff --git a/fs/xfs/xfs_discard.c b/fs/xfs/xfs_discard.c
index f979d0d7e6cd..3bf6dba1a040 100644
--- a/fs/xfs/xfs_discard.c
+++ b/fs/xfs/xfs_discard.c
@@ -8,7 +8,6 @@
 #include "xfs_format.h"
 #include "xfs_log_format.h"
 #include "xfs_trans_resv.h"
-#include "xfs_sb.h"
 #include "xfs_mount.h"
 #include "xfs_btree.h"
 #include "xfs_alloc_btree.h"
@@ -18,6 +17,7 @@
 #include "xfs_extent_busy.h"
 #include "xfs_trace.h"
 #include "xfs_log.h"
+#include "xfs_ag.h"
 
 STATIC int
 xfs_trim_extents(
diff --git a/fs/xfs/xfs_extent_busy.c b/fs/xfs/xfs_extent_busy.c
index ef17c1f6db32..184732aa8674 100644
--- a/fs/xfs/xfs_extent_busy.c
+++ b/fs/xfs/xfs_extent_busy.c
@@ -11,13 +11,13 @@
 #include "xfs_log_format.h"
 #include "xfs_shared.h"
 #include "xfs_trans_resv.h"
-#include "xfs_sb.h"
 #include "xfs_mount.h"
 #include "xfs_alloc.h"
 #include "xfs_extent_busy.h"
 #include "xfs_trace.h"
 #include "xfs_trans.h"
 #include "xfs_log.h"
+#include "xfs_ag.h"
 
 void
 xfs_extent_busy_insert(
diff --git a/fs/xfs/xfs_filestream.c b/fs/xfs/xfs_filestream.c
index db23e455eb91..eed6ca5f8f91 100644
--- a/fs/xfs/xfs_filestream.c
+++ b/fs/xfs/xfs_filestream.c
@@ -9,13 +9,13 @@
 #include "xfs_format.h"
 #include "xfs_log_format.h"
 #include "xfs_trans_resv.h"
-#include "xfs_sb.h"
 #include "xfs_mount.h"
 #include "xfs_inode.h"
 #include "xfs_bmap.h"
 #include "xfs_alloc.h"
 #include "xfs_mru_cache.h"
 #include "xfs_trace.h"
+#include "xfs_ag.h"
 #include "xfs_ag_resv.h"
 #include "xfs_trans.h"
 #include "xfs_filestream.h"
diff --git a/fs/xfs/xfs_health.c b/fs/xfs/xfs_health.c
index 8e0cb05a7142..b79475ea3dbd 100644
--- a/fs/xfs/xfs_health.c
+++ b/fs/xfs/xfs_health.c
@@ -9,11 +9,11 @@
 #include "xfs_format.h"
 #include "xfs_log_format.h"
 #include "xfs_trans_resv.h"
-#include "xfs_sb.h"
 #include "xfs_mount.h"
 #include "xfs_inode.h"
 #include "xfs_trace.h"
 #include "xfs_health.h"
+#include "xfs_ag.h"
 
 /*
  * Warn about metadata corruption that we detected but haven't fixed, and
diff --git a/fs/xfs/xfs_icache.c b/fs/xfs/xfs_icache.c
index 3c81daca0e9a..588ea2bf88bb 100644
--- a/fs/xfs/xfs_icache.c
+++ b/fs/xfs/xfs_icache.c
@@ -9,7 +9,6 @@
 #include "xfs_format.h"
 #include "xfs_log_format.h"
 #include "xfs_trans_resv.h"
-#include "xfs_sb.h"
 #include "xfs_mount.h"
 #include "xfs_inode.h"
 #include "xfs_trans.h"
@@ -23,6 +22,7 @@
 #include "xfs_dquot.h"
 #include "xfs_reflink.h"
 #include "xfs_ialloc.h"
+#include "xfs_ag.h"
 
 #include <linux/iversion.h>
 
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
index 17c2d8b18283..25910b145d70 100644
--- a/fs/xfs/xfs_inode.c
+++ b/fs/xfs/xfs_inode.c
@@ -11,7 +11,6 @@
 #include "xfs_format.h"
 #include "xfs_log_format.h"
 #include "xfs_trans_resv.h"
-#include "xfs_sb.h"
 #include "xfs_mount.h"
 #include "xfs_defer.h"
 #include "xfs_inode.h"
@@ -35,6 +34,7 @@
 #include "xfs_log.h"
 #include "xfs_bmap_btree.h"
 #include "xfs_reflink.h"
+#include "xfs_ag.h"
 
 kmem_zone_t *xfs_inode_zone;
 
diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c
index e5dd1c0c2f03..fee2a4e80241 100644
--- a/fs/xfs/xfs_log_recover.c
+++ b/fs/xfs/xfs_log_recover.c
@@ -25,6 +25,7 @@
 #include "xfs_icache.h"
 #include "xfs_error.h"
 #include "xfs_buf_item.h"
+#include "xfs_ag.h"
 
 #define BLK_AVG(blk1, blk2)	((blk1+blk2) >> 1)
 
diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c
index bdfee1943796..21c630dde476 100644
--- a/fs/xfs/xfs_mount.c
+++ b/fs/xfs/xfs_mount.c
@@ -32,6 +32,7 @@
 #include "xfs_extent_busy.h"
 #include "xfs_health.h"
 #include "xfs_trace.h"
+#include "xfs_ag.h"
 
 static DEFINE_MUTEX(xfs_uuid_table_mutex);
 static int xfs_uuid_table_size;
diff --git a/fs/xfs/xfs_qm.c b/fs/xfs/xfs_qm.c
index 4bf949a89d0d..f7baf4dc2554 100644
--- a/fs/xfs/xfs_qm.c
+++ b/fs/xfs/xfs_qm.c
@@ -23,6 +23,7 @@
 #include "xfs_trace.h"
 #include "xfs_icache.h"
 #include "xfs_error.h"
+#include "xfs_ag.h"
 
 /*
  * The global quota manager. There is only one of these for the entire
diff --git a/fs/xfs/xfs_reflink.c b/fs/xfs/xfs_reflink.c
index 060695d6d56a..f297d68a931b 100644
--- a/fs/xfs/xfs_reflink.c
+++ b/fs/xfs/xfs_reflink.c
@@ -27,7 +27,7 @@
 #include "xfs_quota.h"
 #include "xfs_reflink.h"
 #include "xfs_iomap.h"
-#include "xfs_sb.h"
+#include "xfs_ag.h"
 #include "xfs_ag_resv.h"
 
 /*
diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c
index a2dab05332ac..688309dbe18b 100644
--- a/fs/xfs/xfs_super.c
+++ b/fs/xfs/xfs_super.c
@@ -36,6 +36,7 @@
 #include "xfs_bmap_item.h"
 #include "xfs_reflink.h"
 #include "xfs_pwork.h"
+#include "xfs_ag.h"
 
 #include <linux/magic.h>
 #include <linux/fs_context.h>
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 87+ messages in thread

* [PATCH 02/22] xfs: prepare for moving perag definitions and support to libxfs
  2021-05-06  7:20 [RFC 00/22] xfs: initial agnumber -> perag conversions for shrink Dave Chinner
  2021-05-06  7:20 ` [PATCH 01/22] xfs: move xfs_perag_get/put to xfs_ag.[ch] Dave Chinner
@ 2021-05-06  7:20 ` Dave Chinner
  2021-05-10 12:53   ` Brian Foster
  2021-05-06  7:20 ` [PATCH 03/22] xfs: move perag structure and setup to libxfs/xfs_ag.[ch] Dave Chinner
                   ` (19 subsequent siblings)
  21 siblings, 1 reply; 87+ messages in thread
From: Dave Chinner @ 2021-05-06  7:20 UTC (permalink / raw)
  To: linux-xfs

From: Dave Chinner <dchinner@redhat.com>

The perag structures really need to be defined with the rest of the
AG support infrastructure. The struct xfs_perag and init/teardown
has been placed in xfs_mount.[ch] because there are differences in
the structure between kernel and userspace. Mainly that userspace
doesn't have a lot of the internal stuff that the kernel has for
caches and discard and other such structures.

However, it makes more sense to move this to libxfs than to keep
this separation because we are now moving to use struct perags
everywhere in the code instead of passing raw agnumber_t values
about. Hence we shoudl really move the support infrastructure to
libxfs/xfs_ag.[ch].

To do this without breaking userspace, first we need to rearrange
the structures and code so that all the kernel specific code is
located together. This makes it simple for userspace to ifdef out
the all the parts it does not need, minimising the code differences
between kernel and userspace. The next commit will do the move...

Signed-off-by: Dave Chinner <dchinner@redhat.com>
---
 fs/xfs/xfs_mount.c | 50 ++++++++++++++++++++++++++--------------------
 fs/xfs/xfs_mount.h | 19 +++++++++---------
 2 files changed, 38 insertions(+), 31 deletions(-)

diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c
index 21c630dde476..2e6d42014346 100644
--- a/fs/xfs/xfs_mount.c
+++ b/fs/xfs/xfs_mount.c
@@ -148,9 +148,11 @@ xfs_free_perag(
 		spin_unlock(&mp->m_perag_lock);
 		ASSERT(pag);
 		ASSERT(atomic_read(&pag->pag_ref) == 0);
+
 		cancel_delayed_work_sync(&pag->pag_blockgc_work);
 		xfs_iunlink_destroy(pag);
 		xfs_buf_hash_destroy(pag);
+
 		call_rcu(&pag->rcu_head, __xfs_free_perag);
 	}
 }
@@ -175,14 +177,14 @@ xfs_sb_validate_fsb_count(
 
 int
 xfs_initialize_perag(
-	xfs_mount_t	*mp,
-	xfs_agnumber_t	agcount,
-	xfs_agnumber_t	*maxagi)
+	struct xfs_mount	*mp,
+	xfs_agnumber_t		agcount,
+	xfs_agnumber_t		*maxagi)
 {
-	xfs_agnumber_t	index;
-	xfs_agnumber_t	first_initialised = NULLAGNUMBER;
-	xfs_perag_t	*pag;
-	int		error = -ENOMEM;
+	struct xfs_perag	*pag;
+	xfs_agnumber_t		index;
+	xfs_agnumber_t		first_initialised = NULLAGNUMBER;
+	int			error;
 
 	/*
 	 * Walk the current per-ag tree so we don't try to initialise AGs
@@ -203,17 +205,6 @@ xfs_initialize_perag(
 		}
 		pag->pag_agno = index;
 		pag->pag_mount = mp;
-		spin_lock_init(&pag->pag_ici_lock);
-		INIT_DELAYED_WORK(&pag->pag_blockgc_work, xfs_blockgc_worker);
-		INIT_RADIX_TREE(&pag->pag_ici_root, GFP_ATOMIC);
-
-		error = xfs_buf_hash_init(pag);
-		if (error)
-			goto out_free_pag;
-		init_waitqueue_head(&pag->pagb_wait);
-		spin_lock_init(&pag->pagb_lock);
-		pag->pagb_count = 0;
-		pag->pagb_tree = RB_ROOT;
 
 		error = radix_tree_preload(GFP_NOFS);
 		if (error)
@@ -229,13 +220,27 @@ xfs_initialize_perag(
 		}
 		spin_unlock(&mp->m_perag_lock);
 		radix_tree_preload_end();
-		/* first new pag is fully initialized */
-		if (first_initialised == NULLAGNUMBER)
-			first_initialised = index;
+
+		spin_lock_init(&pag->pag_ici_lock);
+		spin_lock_init(&pag->pagb_lock);
+		spin_lock_init(&pag->pag_state_lock);
+		INIT_DELAYED_WORK(&pag->pag_blockgc_work, xfs_blockgc_worker);
+		INIT_RADIX_TREE(&pag->pag_ici_root, GFP_ATOMIC);
+		init_waitqueue_head(&pag->pagb_wait);
+		pag->pagb_count = 0;
+		pag->pagb_tree = RB_ROOT;
+
+		error = xfs_buf_hash_init(pag);
+		if (error)
+			goto out_free_pag;
+
 		error = xfs_iunlink_init(pag);
 		if (error)
 			goto out_hash_destroy;
-		spin_lock_init(&pag->pag_state_lock);
+
+		/* first new pag is fully initialized */
+		if (first_initialised == NULLAGNUMBER)
+			first_initialised = index;
 	}
 
 	index = xfs_set_inode_alloc(mp, agcount);
@@ -249,6 +254,7 @@ xfs_initialize_perag(
 out_hash_destroy:
 	xfs_buf_hash_destroy(pag);
 out_free_pag:
+	pag = radix_tree_delete(&mp->m_perag_tree, index);
 	kmem_free(pag);
 out_unwind_new_pags:
 	/* unwind any prior newly initialized pags */
diff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h
index bb67274ee23f..6e534be5eea8 100644
--- a/fs/xfs/xfs_mount.h
+++ b/fs/xfs/xfs_mount.h
@@ -338,6 +338,16 @@ typedef struct xfs_perag {
 	xfs_agino_t	pagl_leftrec;
 	xfs_agino_t	pagl_rightrec;
 
+	int		pagb_count;	/* pagb slots in use */
+	uint8_t		pagf_refcount_level; /* recount btree height */
+
+	/* Blocks reserved for all kinds of metadata. */
+	struct xfs_ag_resv	pag_meta_resv;
+	/* Blocks reserved for the reverse mapping btree. */
+	struct xfs_ag_resv	pag_rmapbt_resv;
+
+	/* -- kernel only structures below this line -- */
+
 	/*
 	 * Bitsets of per-ag metadata that have been checked and/or are sick.
 	 * Callers should hold pag_state_lock before accessing this field.
@@ -364,19 +374,10 @@ typedef struct xfs_perag {
 
 	/* for rcu-safe freeing */
 	struct rcu_head	rcu_head;
-	int		pagb_count;	/* pagb slots in use */
-
-	/* Blocks reserved for all kinds of metadata. */
-	struct xfs_ag_resv	pag_meta_resv;
-	/* Blocks reserved for the reverse mapping btree. */
-	struct xfs_ag_resv	pag_rmapbt_resv;
 
 	/* background prealloc block trimming */
 	struct delayed_work	pag_blockgc_work;
 
-	/* reference count */
-	uint8_t			pagf_refcount_level;
-
 	/*
 	 * Unlinked inode information.  This incore information reflects
 	 * data stored in the AGI, so callers must hold the AGI buffer lock
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 87+ messages in thread

* [PATCH 03/22] xfs: move perag structure and setup to libxfs/xfs_ag.[ch]
  2021-05-06  7:20 [RFC 00/22] xfs: initial agnumber -> perag conversions for shrink Dave Chinner
  2021-05-06  7:20 ` [PATCH 01/22] xfs: move xfs_perag_get/put to xfs_ag.[ch] Dave Chinner
  2021-05-06  7:20 ` [PATCH 02/22] xfs: prepare for moving perag definitions and support to libxfs Dave Chinner
@ 2021-05-06  7:20 ` Dave Chinner
  2021-05-10 22:26   ` Darrick J. Wong
  2021-05-06  7:20 ` [PATCH 04/22] xfs: make for_each_perag... a first class citizen Dave Chinner
                   ` (18 subsequent siblings)
  21 siblings, 1 reply; 87+ messages in thread
From: Dave Chinner @ 2021-05-06  7:20 UTC (permalink / raw)
  To: linux-xfs

From: Dave Chinner <dchinner@redhat.com>

Move the xfs_perag infrastructure to the libxfs files that contain
all the per AG infrastructure. This helps set up for passing perags
around all the code instead of bare agnos with minimal extra
includes for existing files.

Signed-off-by: Dave Chinner <dchinner@redhat.com>
---
 fs/xfs/libxfs/xfs_ag.c      | 133 ++++++++++++++++++++++++++++++++++++
 fs/xfs/libxfs/xfs_ag.h      |  98 +++++++++++++++++++++++++-
 fs/xfs/libxfs/xfs_ag_resv.h |  15 ++++
 fs/xfs/libxfs/xfs_btree.c   |   1 +
 fs/xfs/xfs_mount.c          | 131 -----------------------------------
 fs/xfs/xfs_mount.h          | 111 +-----------------------------
 fs/xfs/xfs_trace.c          |   2 +
 7 files changed, 250 insertions(+), 241 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_ag.c b/fs/xfs/libxfs/xfs_ag.c
index 2ca31dc46fe8..14d8b866dc6d 100644
--- a/fs/xfs/libxfs/xfs_ag.c
+++ b/fs/xfs/libxfs/xfs_ag.c
@@ -28,6 +28,9 @@
 #include "xfs_log_format.h"
 #include "xfs_trans.h"
 #include "xfs_trace.h"
+#include "xfs_inode.h"
+#include "xfs_icache.h"
+
 
 /*
  * Passive reference counting access wrappers to the perag structures.  If the
@@ -163,6 +166,136 @@ xfs_initialize_perag_data(
 	return error;
 }
 
+STATIC void
+__xfs_free_perag(
+	struct rcu_head	*head)
+{
+	struct xfs_perag *pag = container_of(head, struct xfs_perag, rcu_head);
+
+	ASSERT(!delayed_work_pending(&pag->pag_blockgc_work));
+	ASSERT(atomic_read(&pag->pag_ref) == 0);
+	kmem_free(pag);
+}
+
+/*
+ * Free up the per-ag resources associated with the mount structure.
+ */
+void
+xfs_free_perag(
+	struct xfs_mount	*mp)
+{
+	struct xfs_perag	*pag;
+	xfs_agnumber_t		agno;
+
+	for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) {
+		spin_lock(&mp->m_perag_lock);
+		pag = radix_tree_delete(&mp->m_perag_tree, agno);
+		spin_unlock(&mp->m_perag_lock);
+		ASSERT(pag);
+		ASSERT(atomic_read(&pag->pag_ref) == 0);
+
+		cancel_delayed_work_sync(&pag->pag_blockgc_work);
+		xfs_iunlink_destroy(pag);
+		xfs_buf_hash_destroy(pag);
+
+		call_rcu(&pag->rcu_head, __xfs_free_perag);
+	}
+}
+
+int
+xfs_initialize_perag(
+	struct xfs_mount	*mp,
+	xfs_agnumber_t		agcount,
+	xfs_agnumber_t		*maxagi)
+{
+	struct xfs_perag	*pag;
+	xfs_agnumber_t		index;
+	xfs_agnumber_t		first_initialised = NULLAGNUMBER;
+	int			error;
+
+	/*
+	 * Walk the current per-ag tree so we don't try to initialise AGs
+	 * that already exist (growfs case). Allocate and insert all the
+	 * AGs we don't find ready for initialisation.
+	 */
+	for (index = 0; index < agcount; index++) {
+		pag = xfs_perag_get(mp, index);
+		if (pag) {
+			xfs_perag_put(pag);
+			continue;
+		}
+
+		pag = kmem_zalloc(sizeof(*pag), KM_MAYFAIL);
+		if (!pag) {
+			error = -ENOMEM;
+			goto out_unwind_new_pags;
+		}
+		pag->pag_agno = index;
+		pag->pag_mount = mp;
+
+		error = radix_tree_preload(GFP_NOFS);
+		if (error)
+			goto out_hash_destroy;
+
+		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_hash_destroy;
+		}
+		spin_unlock(&mp->m_perag_lock);
+		radix_tree_preload_end();
+
+		spin_lock_init(&pag->pag_ici_lock);
+		spin_lock_init(&pag->pagb_lock);
+		spin_lock_init(&pag->pag_state_lock);
+		INIT_DELAYED_WORK(&pag->pag_blockgc_work, xfs_blockgc_worker);
+		INIT_RADIX_TREE(&pag->pag_ici_root, GFP_ATOMIC);
+		init_waitqueue_head(&pag->pagb_wait);
+		pag->pagb_count = 0;
+		pag->pagb_tree = RB_ROOT;
+
+		error = xfs_buf_hash_init(pag);
+		if (error)
+			goto out_free_pag;
+
+		error = xfs_iunlink_init(pag);
+		if (error)
+			goto out_hash_destroy;
+
+		/* first new pag is fully initialized */
+		if (first_initialised == NULLAGNUMBER)
+			first_initialised = index;
+	}
+
+	index = xfs_set_inode_alloc(mp, agcount);
+
+	if (maxagi)
+		*maxagi = index;
+
+	mp->m_ag_prealloc_blocks = xfs_prealloc_blocks(mp);
+	return 0;
+
+out_hash_destroy:
+	xfs_buf_hash_destroy(pag);
+out_free_pag:
+	pag = radix_tree_delete(&mp->m_perag_tree, index);
+	kmem_free(pag);
+out_unwind_new_pags:
+	/* unwind any prior newly initialized pags */
+	for (index = first_initialised; index < agcount; index++) {
+		pag = radix_tree_delete(&mp->m_perag_tree, index);
+		if (!pag)
+			break;
+		xfs_buf_hash_destroy(pag);
+		xfs_iunlink_destroy(pag);
+		kmem_free(pag);
+	}
+	return error;
+}
+
 static int
 xfs_get_aghdr_buf(
 	struct xfs_mount	*mp,
diff --git a/fs/xfs/libxfs/xfs_ag.h b/fs/xfs/libxfs/xfs_ag.h
index cb1bd1c03cd7..ec37f9d9f310 100644
--- a/fs/xfs/libxfs/xfs_ag.h
+++ b/fs/xfs/libxfs/xfs_ag.h
@@ -12,9 +12,103 @@ struct xfs_trans;
 struct xfs_perag;
 
 /*
- * perag get/put wrappers for ref counting
+ * Per-ag infrastructure
  */
-int	xfs_initialize_perag_data(struct xfs_mount *, xfs_agnumber_t);
+
+/* per-AG block reservation data structures*/
+struct xfs_ag_resv {
+	/* number of blocks originally reserved here */
+	xfs_extlen_t			ar_orig_reserved;
+	/* number of blocks reserved here */
+	xfs_extlen_t			ar_reserved;
+	/* number of blocks originally asked for */
+	xfs_extlen_t			ar_asked;
+};
+
+/*
+ * Per-ag incore structure, copies of information in agf and agi, to improve the
+ * performance of allocation group selection.
+ */
+typedef struct xfs_perag {
+	struct xfs_mount *pag_mount;	/* owner filesystem */
+	xfs_agnumber_t	pag_agno;	/* AG this structure belongs to */
+	atomic_t	pag_ref;	/* perag reference count */
+	char		pagf_init;	/* this agf's entry is initialized */
+	char		pagi_init;	/* this agi's entry is initialized */
+	char		pagf_metadata;	/* the agf is preferred to be metadata */
+	char		pagi_inodeok;	/* The agi is ok for inodes */
+	uint8_t		pagf_levels[XFS_BTNUM_AGF];
+					/* # of levels in bno & cnt btree */
+	bool		pagf_agflreset; /* agfl requires reset before use */
+	uint32_t	pagf_flcount;	/* count of blocks in freelist */
+	xfs_extlen_t	pagf_freeblks;	/* total free blocks */
+	xfs_extlen_t	pagf_longest;	/* longest free space */
+	uint32_t	pagf_btreeblks;	/* # of blocks held in AGF btrees */
+	xfs_agino_t	pagi_freecount;	/* number of free inodes */
+	xfs_agino_t	pagi_count;	/* number of allocated inodes */
+
+	/*
+	 * Inode allocation search lookup optimisation.
+	 * If the pagino matches, the search for new inodes
+	 * doesn't need to search the near ones again straight away
+	 */
+	xfs_agino_t	pagl_pagino;
+	xfs_agino_t	pagl_leftrec;
+	xfs_agino_t	pagl_rightrec;
+
+	int		pagb_count;	/* pagb slots in use */
+	uint8_t		pagf_refcount_level; /* recount btree height */
+
+	/* Blocks reserved for all kinds of metadata. */
+	struct xfs_ag_resv	pag_meta_resv;
+	/* Blocks reserved for the reverse mapping btree. */
+	struct xfs_ag_resv	pag_rmapbt_resv;
+
+	/* -- kernel only structures below this line -- */
+
+	/*
+	 * Bitsets of per-ag metadata that have been checked and/or are sick.
+	 * Callers should hold pag_state_lock before accessing this field.
+	 */
+	uint16_t	pag_checked;
+	uint16_t	pag_sick;
+	spinlock_t	pag_state_lock;
+
+	spinlock_t	pagb_lock;	/* lock for pagb_tree */
+	struct rb_root	pagb_tree;	/* ordered tree of busy extents */
+	unsigned int	pagb_gen;	/* generation count for pagb_tree */
+	wait_queue_head_t pagb_wait;	/* woken when pagb_gen changes */
+
+	atomic_t        pagf_fstrms;    /* # of filestreams active in this AG */
+
+	spinlock_t	pag_ici_lock;	/* incore inode cache lock */
+	struct radix_tree_root pag_ici_root;	/* incore inode cache root */
+	int		pag_ici_reclaimable;	/* reclaimable inodes */
+	unsigned long	pag_ici_reclaim_cursor;	/* reclaim restart point */
+
+	/* buffer cache index */
+	spinlock_t	pag_buf_lock;	/* lock for pag_buf_hash */
+	struct rhashtable pag_buf_hash;
+
+	/* for rcu-safe freeing */
+	struct rcu_head	rcu_head;
+
+	/* background prealloc block trimming */
+	struct delayed_work	pag_blockgc_work;
+
+	/*
+	 * Unlinked inode information.  This incore information reflects
+	 * data stored in the AGI, so callers must hold the AGI buffer lock
+	 * or have some other means to control concurrency.
+	 */
+	struct rhashtable	pagi_unlinked_hash;
+} xfs_perag_t;
+
+int xfs_initialize_perag(struct xfs_mount *mp, xfs_agnumber_t agcount,
+			xfs_agnumber_t *maxagi);
+int xfs_initialize_perag_data(struct xfs_mount *, xfs_agnumber_t);
+void xfs_free_perag(struct xfs_mount *mp);
+
 struct xfs_perag *xfs_perag_get(struct xfs_mount *, xfs_agnumber_t);
 struct xfs_perag *xfs_perag_get_tag(struct xfs_mount *, xfs_agnumber_t,
 				   int tag);
diff --git a/fs/xfs/libxfs/xfs_ag_resv.h b/fs/xfs/libxfs/xfs_ag_resv.h
index 8a8eb4bc48bb..b74b210008ea 100644
--- a/fs/xfs/libxfs/xfs_ag_resv.h
+++ b/fs/xfs/libxfs/xfs_ag_resv.h
@@ -18,6 +18,21 @@ void xfs_ag_resv_alloc_extent(struct xfs_perag *pag, enum xfs_ag_resv_type type,
 void xfs_ag_resv_free_extent(struct xfs_perag *pag, enum xfs_ag_resv_type type,
 		struct xfs_trans *tp, xfs_extlen_t len);
 
+static inline struct xfs_ag_resv *
+xfs_perag_resv(
+	struct xfs_perag	*pag,
+	enum xfs_ag_resv_type	type)
+{
+	switch (type) {
+	case XFS_AG_RESV_METADATA:
+		return &pag->pag_meta_resv;
+	case XFS_AG_RESV_RMAPBT:
+		return &pag->pag_rmapbt_resv;
+	default:
+		return NULL;
+	}
+}
+
 /*
  * RMAPBT reservation accounting wrappers. Since rmapbt blocks are sourced from
  * the AGFL, they are allocated one at a time and the reservation updates don't
diff --git a/fs/xfs/libxfs/xfs_btree.c b/fs/xfs/libxfs/xfs_btree.c
index 5b6fcb9b44e2..0f12b885600d 100644
--- a/fs/xfs/libxfs/xfs_btree.c
+++ b/fs/xfs/libxfs/xfs_btree.c
@@ -21,6 +21,7 @@
 #include "xfs_alloc.h"
 #include "xfs_log.h"
 #include "xfs_btree_staging.h"
+#include "xfs_ag.h"
 
 /*
  * Cursor allocation zone.
diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c
index 2e6d42014346..c3a96fb3ad80 100644
--- a/fs/xfs/xfs_mount.c
+++ b/fs/xfs/xfs_mount.c
@@ -120,43 +120,6 @@ xfs_uuid_unmount(
 	mutex_unlock(&xfs_uuid_table_mutex);
 }
 
-
-STATIC void
-__xfs_free_perag(
-	struct rcu_head	*head)
-{
-	struct xfs_perag *pag = container_of(head, struct xfs_perag, rcu_head);
-
-	ASSERT(!delayed_work_pending(&pag->pag_blockgc_work));
-	ASSERT(atomic_read(&pag->pag_ref) == 0);
-	kmem_free(pag);
-}
-
-/*
- * Free up the per-ag resources associated with the mount structure.
- */
-STATIC void
-xfs_free_perag(
-	xfs_mount_t	*mp)
-{
-	xfs_agnumber_t	agno;
-	struct xfs_perag *pag;
-
-	for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) {
-		spin_lock(&mp->m_perag_lock);
-		pag = radix_tree_delete(&mp->m_perag_tree, agno);
-		spin_unlock(&mp->m_perag_lock);
-		ASSERT(pag);
-		ASSERT(atomic_read(&pag->pag_ref) == 0);
-
-		cancel_delayed_work_sync(&pag->pag_blockgc_work);
-		xfs_iunlink_destroy(pag);
-		xfs_buf_hash_destroy(pag);
-
-		call_rcu(&pag->rcu_head, __xfs_free_perag);
-	}
-}
-
 /*
  * Check size of device based on the (data/realtime) block count.
  * Note: this check is used by the growfs code as well as mount.
@@ -175,100 +138,6 @@ xfs_sb_validate_fsb_count(
 	return 0;
 }
 
-int
-xfs_initialize_perag(
-	struct xfs_mount	*mp,
-	xfs_agnumber_t		agcount,
-	xfs_agnumber_t		*maxagi)
-{
-	struct xfs_perag	*pag;
-	xfs_agnumber_t		index;
-	xfs_agnumber_t		first_initialised = NULLAGNUMBER;
-	int			error;
-
-	/*
-	 * Walk the current per-ag tree so we don't try to initialise AGs
-	 * that already exist (growfs case). Allocate and insert all the
-	 * AGs we don't find ready for initialisation.
-	 */
-	for (index = 0; index < agcount; index++) {
-		pag = xfs_perag_get(mp, index);
-		if (pag) {
-			xfs_perag_put(pag);
-			continue;
-		}
-
-		pag = kmem_zalloc(sizeof(*pag), KM_MAYFAIL);
-		if (!pag) {
-			error = -ENOMEM;
-			goto out_unwind_new_pags;
-		}
-		pag->pag_agno = index;
-		pag->pag_mount = mp;
-
-		error = radix_tree_preload(GFP_NOFS);
-		if (error)
-			goto out_hash_destroy;
-
-		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_hash_destroy;
-		}
-		spin_unlock(&mp->m_perag_lock);
-		radix_tree_preload_end();
-
-		spin_lock_init(&pag->pag_ici_lock);
-		spin_lock_init(&pag->pagb_lock);
-		spin_lock_init(&pag->pag_state_lock);
-		INIT_DELAYED_WORK(&pag->pag_blockgc_work, xfs_blockgc_worker);
-		INIT_RADIX_TREE(&pag->pag_ici_root, GFP_ATOMIC);
-		init_waitqueue_head(&pag->pagb_wait);
-		pag->pagb_count = 0;
-		pag->pagb_tree = RB_ROOT;
-
-		error = xfs_buf_hash_init(pag);
-		if (error)
-			goto out_free_pag;
-
-		error = xfs_iunlink_init(pag);
-		if (error)
-			goto out_hash_destroy;
-
-		/* first new pag is fully initialized */
-		if (first_initialised == NULLAGNUMBER)
-			first_initialised = index;
-	}
-
-	index = xfs_set_inode_alloc(mp, agcount);
-
-	if (maxagi)
-		*maxagi = index;
-
-	mp->m_ag_prealloc_blocks = xfs_prealloc_blocks(mp);
-	return 0;
-
-out_hash_destroy:
-	xfs_buf_hash_destroy(pag);
-out_free_pag:
-	pag = radix_tree_delete(&mp->m_perag_tree, index);
-	kmem_free(pag);
-out_unwind_new_pags:
-	/* unwind any prior newly initialized pags */
-	for (index = first_initialised; index < agcount; index++) {
-		pag = radix_tree_delete(&mp->m_perag_tree, index);
-		if (!pag)
-			break;
-		xfs_buf_hash_destroy(pag);
-		xfs_iunlink_destroy(pag);
-		kmem_free(pag);
-	}
-	return error;
-}
-
 /*
  * xfs_readsb
  *
diff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h
index 6e534be5eea8..c78b63fe779a 100644
--- a/fs/xfs/xfs_mount.h
+++ b/fs/xfs/xfs_mount.h
@@ -12,6 +12,7 @@ struct xfs_mru_cache;
 struct xfs_ail;
 struct xfs_quotainfo;
 struct xfs_da_geometry;
+struct xfs_perag;
 
 /* dynamic preallocation free space thresholds, 5% down to 1% */
 enum {
@@ -297,118 +298,12 @@ xfs_daddr_to_agbno(struct xfs_mount *mp, xfs_daddr_t d)
 	return (xfs_agblock_t) do_div(ld, mp->m_sb.sb_agblocks);
 }
 
-/* per-AG block reservation data structures*/
-struct xfs_ag_resv {
-	/* number of blocks originally reserved here */
-	xfs_extlen_t			ar_orig_reserved;
-	/* number of blocks reserved here */
-	xfs_extlen_t			ar_reserved;
-	/* number of blocks originally asked for */
-	xfs_extlen_t			ar_asked;
-};
-
-/*
- * Per-ag incore structure, copies of information in agf and agi, to improve the
- * performance of allocation group selection.
- */
-typedef struct xfs_perag {
-	struct xfs_mount *pag_mount;	/* owner filesystem */
-	xfs_agnumber_t	pag_agno;	/* AG this structure belongs to */
-	atomic_t	pag_ref;	/* perag reference count */
-	char		pagf_init;	/* this agf's entry is initialized */
-	char		pagi_init;	/* this agi's entry is initialized */
-	char		pagf_metadata;	/* the agf is preferred to be metadata */
-	char		pagi_inodeok;	/* The agi is ok for inodes */
-	uint8_t		pagf_levels[XFS_BTNUM_AGF];
-					/* # of levels in bno & cnt btree */
-	bool		pagf_agflreset; /* agfl requires reset before use */
-	uint32_t	pagf_flcount;	/* count of blocks in freelist */
-	xfs_extlen_t	pagf_freeblks;	/* total free blocks */
-	xfs_extlen_t	pagf_longest;	/* longest free space */
-	uint32_t	pagf_btreeblks;	/* # of blocks held in AGF btrees */
-	xfs_agino_t	pagi_freecount;	/* number of free inodes */
-	xfs_agino_t	pagi_count;	/* number of allocated inodes */
-
-	/*
-	 * Inode allocation search lookup optimisation.
-	 * If the pagino matches, the search for new inodes
-	 * doesn't need to search the near ones again straight away
-	 */
-	xfs_agino_t	pagl_pagino;
-	xfs_agino_t	pagl_leftrec;
-	xfs_agino_t	pagl_rightrec;
-
-	int		pagb_count;	/* pagb slots in use */
-	uint8_t		pagf_refcount_level; /* recount btree height */
-
-	/* Blocks reserved for all kinds of metadata. */
-	struct xfs_ag_resv	pag_meta_resv;
-	/* Blocks reserved for the reverse mapping btree. */
-	struct xfs_ag_resv	pag_rmapbt_resv;
-
-	/* -- kernel only structures below this line -- */
-
-	/*
-	 * Bitsets of per-ag metadata that have been checked and/or are sick.
-	 * Callers should hold pag_state_lock before accessing this field.
-	 */
-	uint16_t	pag_checked;
-	uint16_t	pag_sick;
-	spinlock_t	pag_state_lock;
-
-	spinlock_t	pagb_lock;	/* lock for pagb_tree */
-	struct rb_root	pagb_tree;	/* ordered tree of busy extents */
-	unsigned int	pagb_gen;	/* generation count for pagb_tree */
-	wait_queue_head_t pagb_wait;	/* woken when pagb_gen changes */
-
-	atomic_t        pagf_fstrms;    /* # of filestreams active in this AG */
-
-	spinlock_t	pag_ici_lock;	/* incore inode cache lock */
-	struct radix_tree_root pag_ici_root;	/* incore inode cache root */
-	int		pag_ici_reclaimable;	/* reclaimable inodes */
-	unsigned long	pag_ici_reclaim_cursor;	/* reclaim restart point */
-
-	/* buffer cache index */
-	spinlock_t	pag_buf_lock;	/* lock for pag_buf_hash */
-	struct rhashtable pag_buf_hash;
-
-	/* for rcu-safe freeing */
-	struct rcu_head	rcu_head;
-
-	/* background prealloc block trimming */
-	struct delayed_work	pag_blockgc_work;
-
-	/*
-	 * Unlinked inode information.  This incore information reflects
-	 * data stored in the AGI, so callers must hold the AGI buffer lock
-	 * or have some other means to control concurrency.
-	 */
-	struct rhashtable	pagi_unlinked_hash;
-} xfs_perag_t;
-
-static inline struct xfs_ag_resv *
-xfs_perag_resv(
-	struct xfs_perag	*pag,
-	enum xfs_ag_resv_type	type)
-{
-	switch (type) {
-	case XFS_AG_RESV_METADATA:
-		return &pag->pag_meta_resv;
-	case XFS_AG_RESV_RMAPBT:
-		return &pag->pag_rmapbt_resv;
-	default:
-		return NULL;
-	}
-}
-
-int xfs_buf_hash_init(xfs_perag_t *pag);
-void xfs_buf_hash_destroy(xfs_perag_t *pag);
+int xfs_buf_hash_init(struct xfs_perag *pag);
+void xfs_buf_hash_destroy(struct xfs_perag *pag);
 
 extern void	xfs_uuid_table_free(void);
 extern uint64_t xfs_default_resblks(xfs_mount_t *mp);
 extern int	xfs_mountfs(xfs_mount_t *mp);
-extern int	xfs_initialize_perag(xfs_mount_t *mp, xfs_agnumber_t agcount,
-				     xfs_agnumber_t *maxagi);
 extern void	xfs_unmountfs(xfs_mount_t *);
 
 extern int	xfs_mod_fdblocks(struct xfs_mount *mp, int64_t delta,
diff --git a/fs/xfs/xfs_trace.c b/fs/xfs/xfs_trace.c
index 9b8d703dc9fd..7e01e00550ac 100644
--- a/fs/xfs/xfs_trace.c
+++ b/fs/xfs/xfs_trace.c
@@ -30,6 +30,8 @@
 #include "xfs_fsmap.h"
 #include "xfs_btree_staging.h"
 #include "xfs_icache.h"
+#include "xfs_ag.h"
+#include "xfs_ag_resv.h"
 
 /*
  * We include this last to have the helpers above available for the trace
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 87+ messages in thread

* [PATCH 04/22] xfs: make for_each_perag... a first class citizen
  2021-05-06  7:20 [RFC 00/22] xfs: initial agnumber -> perag conversions for shrink Dave Chinner
                   ` (2 preceding siblings ...)
  2021-05-06  7:20 ` [PATCH 03/22] xfs: move perag structure and setup to libxfs/xfs_ag.[ch] Dave Chinner
@ 2021-05-06  7:20 ` Dave Chinner
  2021-05-10 12:53   ` Brian Foster
  2021-05-06  7:20 ` [PATCH 05/22] xfs: convert raw ag walks to use for_each_perag Dave Chinner
                   ` (17 subsequent siblings)
  21 siblings, 1 reply; 87+ messages in thread
From: Dave Chinner @ 2021-05-06  7:20 UTC (permalink / raw)
  To: linux-xfs

From: Dave Chinner <dchinner@redhat.com>

for_each_perag_tag() is defined in xfs_icache.c for local use.
Promote this to xfs_ag.h and define equivalent iteration functions
so that we can use them to iterate AGs instead to replace open coded
perag walks and perag lookups.

We also convert as many of the straight forward open coded AG walks
to use these iterators as possible. Anything that is not a direct
conversion to an iterator is ignored and will be updated in future
commits.

Signed-off-by: Dave Chinner <dchinner@redhat.com>
---
 fs/xfs/libxfs/xfs_ag.h    | 17 +++++++++++++++++
 fs/xfs/scrub/fscounters.c | 36 ++++++++++++++----------------------
 fs/xfs/xfs_extent_busy.c  |  7 ++-----
 fs/xfs/xfs_fsops.c        |  8 ++------
 fs/xfs/xfs_health.c       |  4 +---
 fs/xfs/xfs_icache.c       | 15 ++-------------
 6 files changed, 38 insertions(+), 49 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_ag.h b/fs/xfs/libxfs/xfs_ag.h
index ec37f9d9f310..33783120263c 100644
--- a/fs/xfs/libxfs/xfs_ag.h
+++ b/fs/xfs/libxfs/xfs_ag.h
@@ -114,6 +114,23 @@ struct xfs_perag *xfs_perag_get_tag(struct xfs_mount *, xfs_agnumber_t,
 				   int tag);
 void	xfs_perag_put(struct xfs_perag *pag);
 
+/*
+ * Perag iteration APIs
+ */
+#define for_each_perag(mp, next_agno, pag) \
+	for ((next_agno) = 0, (pag) = xfs_perag_get((mp), 0); \
+		(pag) != NULL; \
+		(next_agno) = (pag)->pag_agno + 1, \
+		xfs_perag_put(pag), \
+		(pag) = xfs_perag_get((mp), (next_agno)))
+
+#define for_each_perag_tag(mp, next_agno, pag, tag) \
+	for ((next_agno) = 0, (pag) = xfs_perag_get_tag((mp), 0, (tag)); \
+		(pag) != NULL; \
+		(next_agno) = (pag)->pag_agno + 1, \
+		xfs_perag_put(pag), \
+		(pag) = xfs_perag_get_tag((mp), (next_agno), (tag)))
+
 struct aghdr_init_data {
 	/* per ag data */
 	xfs_agblock_t		agno;		/* ag to init */
diff --git a/fs/xfs/scrub/fscounters.c b/fs/xfs/scrub/fscounters.c
index 453ae9adf94c..2dfdac566399 100644
--- a/fs/xfs/scrub/fscounters.c
+++ b/fs/xfs/scrub/fscounters.c
@@ -71,11 +71,11 @@ xchk_fscount_warmup(
 	xfs_agnumber_t		agno;
 	int			error = 0;
 
-	for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) {
-		pag = xfs_perag_get(mp, agno);
-
+	for_each_perag(mp, agno, pag) {
+		if (xchk_should_terminate(sc, &error))
+			break;
 		if (pag->pagi_init && pag->pagf_init)
-			goto next_loop_perag;
+			continue;
 
 		/* Lock both AG headers. */
 		error = xfs_ialloc_read_agi(mp, sc->tp, agno, &agi_bp);
@@ -89,21 +89,15 @@ xchk_fscount_warmup(
 		 * These are supposed to be initialized by the header read
 		 * function.
 		 */
-		error = -EFSCORRUPTED;
-		if (!pag->pagi_init || !pag->pagf_init)
+		if (!pag->pagi_init || !pag->pagf_init) {
+			error = -EFSCORRUPTED;
 			break;
+		}
 
 		xfs_buf_relse(agf_bp);
 		agf_bp = NULL;
 		xfs_buf_relse(agi_bp);
 		agi_bp = NULL;
-next_loop_perag:
-		xfs_perag_put(pag);
-		pag = NULL;
-		error = 0;
-
-		if (xchk_should_terminate(sc, &error))
-			break;
 	}
 
 	if (agf_bp)
@@ -196,13 +190,14 @@ xchk_fscount_aggregate_agcounts(
 	fsc->ifree = 0;
 	fsc->fdblocks = 0;
 
-	for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) {
-		pag = xfs_perag_get(mp, agno);
+	for_each_perag(mp, agno, pag) {
+		if (xchk_should_terminate(sc, &error))
+			break;
 
 		/* This somehow got unset since the warmup? */
 		if (!pag->pagi_init || !pag->pagf_init) {
-			xfs_perag_put(pag);
-			return -EFSCORRUPTED;
+			error = -EFSCORRUPTED;
+			break;
 		}
 
 		/* Count all the inodes */
@@ -229,12 +224,9 @@ xchk_fscount_aggregate_agcounts(
 		fsc->fdblocks -= pag->pag_meta_resv.ar_reserved;
 		fsc->fdblocks -= pag->pag_rmapbt_resv.ar_orig_reserved;
 
-		xfs_perag_put(pag);
-
-		if (xchk_should_terminate(sc, &error))
-			break;
 	}
-
+	if (pag)
+		xfs_perag_put(pag);
 	if (error)
 		return error;
 
diff --git a/fs/xfs/xfs_extent_busy.c b/fs/xfs/xfs_extent_busy.c
index 184732aa8674..6af0b5a1c7b0 100644
--- a/fs/xfs/xfs_extent_busy.c
+++ b/fs/xfs/xfs_extent_busy.c
@@ -605,12 +605,11 @@ void
 xfs_extent_busy_wait_all(
 	struct xfs_mount	*mp)
 {
+	struct xfs_perag	*pag;
 	DEFINE_WAIT		(wait);
 	xfs_agnumber_t		agno;
 
-	for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) {
-		struct xfs_perag *pag = xfs_perag_get(mp, agno);
-
+	for_each_perag(mp, agno, pag) {
 		do {
 			prepare_to_wait(&pag->pagb_wait, &wait, TASK_KILLABLE);
 			if  (RB_EMPTY_ROOT(&pag->pagb_tree))
@@ -618,8 +617,6 @@ xfs_extent_busy_wait_all(
 			schedule();
 		} while (1);
 		finish_wait(&pag->pagb_wait, &wait);
-
-		xfs_perag_put(pag);
 	}
 }
 
diff --git a/fs/xfs/xfs_fsops.c b/fs/xfs/xfs_fsops.c
index be9cf88d2ad7..07c745cd483e 100644
--- a/fs/xfs/xfs_fsops.c
+++ b/fs/xfs/xfs_fsops.c
@@ -576,10 +576,8 @@ xfs_fs_reserve_ag_blocks(
 	int			err2;
 
 	mp->m_finobt_nores = false;
-	for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) {
-		pag = xfs_perag_get(mp, agno);
+	for_each_perag(mp, agno, pag) {
 		err2 = xfs_ag_resv_init(pag, NULL);
-		xfs_perag_put(pag);
 		if (err2 && !error)
 			error = err2;
 	}
@@ -605,10 +603,8 @@ xfs_fs_unreserve_ag_blocks(
 	int			error = 0;
 	int			err2;
 
-	for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) {
-		pag = xfs_perag_get(mp, agno);
+	for_each_perag(mp, agno, pag) {
 		err2 = xfs_ag_resv_free(pag);
-		xfs_perag_put(pag);
 		if (err2 && !error)
 			error = err2;
 	}
diff --git a/fs/xfs/xfs_health.c b/fs/xfs/xfs_health.c
index b79475ea3dbd..5de3195f6cb2 100644
--- a/fs/xfs/xfs_health.c
+++ b/fs/xfs/xfs_health.c
@@ -34,14 +34,12 @@ xfs_health_unmount(
 		return;
 
 	/* Measure AG corruption levels. */
-	for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) {
-		pag = xfs_perag_get(mp, agno);
+	for_each_perag(mp, agno, pag) {
 		xfs_ag_measure_sickness(pag, &sick, &checked);
 		if (sick) {
 			trace_xfs_ag_unfixed_corruption(mp, agno, sick);
 			warn = true;
 		}
-		xfs_perag_put(pag);
 	}
 
 	/* Measure realtime volume corruption levels. */
diff --git a/fs/xfs/xfs_icache.c b/fs/xfs/xfs_icache.c
index 588ea2bf88bb..7dad83a6f586 100644
--- a/fs/xfs/xfs_icache.c
+++ b/fs/xfs/xfs_icache.c
@@ -1061,15 +1061,13 @@ xfs_reclaim_inodes_ag(
 	int			*nr_to_scan)
 {
 	struct xfs_perag	*pag;
-	xfs_agnumber_t		ag = 0;
+	xfs_agnumber_t		agno;
 
-	while ((pag = xfs_perag_get_tag(mp, ag, XFS_ICI_RECLAIM_TAG))) {
+	for_each_perag_tag(mp, agno, pag, XFS_ICI_RECLAIM_TAG) {
 		unsigned long	first_index = 0;
 		int		done = 0;
 		int		nr_found = 0;
 
-		ag = pag->pag_agno + 1;
-
 		first_index = READ_ONCE(pag->pag_ici_reclaim_cursor);
 		do {
 			struct xfs_inode *batch[XFS_LOOKUP_BATCH];
@@ -1134,7 +1132,6 @@ xfs_reclaim_inodes_ag(
 		if (done)
 			first_index = 0;
 		WRITE_ONCE(pag->pag_ici_reclaim_cursor, first_index);
-		xfs_perag_put(pag);
 	}
 }
 
@@ -1554,14 +1551,6 @@ xfs_inode_clear_cowblocks_tag(
 	return xfs_blockgc_clear_iflag(ip, XFS_ICOWBLOCKS);
 }
 
-#define for_each_perag_tag(mp, next_agno, pag, tag) \
-	for ((next_agno) = 0, (pag) = xfs_perag_get_tag((mp), 0, (tag)); \
-		(pag) != NULL; \
-		(next_agno) = (pag)->pag_agno + 1, \
-		xfs_perag_put(pag), \
-		(pag) = xfs_perag_get_tag((mp), (next_agno), (tag)))
-
-
 /* Disable post-EOF and CoW block auto-reclamation. */
 void
 xfs_blockgc_stop(
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 87+ messages in thread

* [PATCH 05/22] xfs: convert raw ag walks to use for_each_perag
  2021-05-06  7:20 [RFC 00/22] xfs: initial agnumber -> perag conversions for shrink Dave Chinner
                   ` (3 preceding siblings ...)
  2021-05-06  7:20 ` [PATCH 04/22] xfs: make for_each_perag... a first class citizen Dave Chinner
@ 2021-05-06  7:20 ` Dave Chinner
  2021-05-10 12:54   ` Brian Foster
  2021-05-06  7:20 ` [PATCH 06/22] xfs: convert xfs_iwalk to use perag references Dave Chinner
                   ` (16 subsequent siblings)
  21 siblings, 1 reply; 87+ messages in thread
From: Dave Chinner @ 2021-05-06  7:20 UTC (permalink / raw)
  To: linux-xfs

From: Dave Chinner <dchinner@redhat.com>

Convert the raw walks to an iterator, pulling the current AG out of
pag->pag_agno instead of the loop iterator variable.

Signed-off-by: Dave Chinner <dchinner@redhat.com>
---
 fs/xfs/libxfs/xfs_types.c |  4 ++-
 fs/xfs/scrub/bmap.c       |  6 +++--
 fs/xfs/xfs_log_recover.c  | 55 ++++++++++++++++++---------------------
 fs/xfs/xfs_reflink.c      |  9 ++++---
 4 files changed, 39 insertions(+), 35 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_types.c b/fs/xfs/libxfs/xfs_types.c
index 04801362e1a7..e8f4abee7892 100644
--- a/fs/xfs/libxfs/xfs_types.c
+++ b/fs/xfs/libxfs/xfs_types.c
@@ -11,6 +11,7 @@
 #include "xfs_trans_resv.h"
 #include "xfs_bit.h"
 #include "xfs_mount.h"
+#include "xfs_ag.h"
 
 /* Find the size of the AG, in blocks. */
 inline xfs_agblock_t
@@ -222,12 +223,13 @@ xfs_icount_range(
 	unsigned long long	*max)
 {
 	unsigned long long	nr_inos = 0;
+	struct xfs_perag	*pag;
 	xfs_agnumber_t		agno;
 
 	/* root, rtbitmap, rtsum all live in the first chunk */
 	*min = XFS_INODES_PER_CHUNK;
 
-	for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) {
+	for_each_perag(mp, agno, pag) {
 		xfs_agino_t	first, last;
 
 		xfs_agino_range(mp, agno, &first, &last);
diff --git a/fs/xfs/scrub/bmap.c b/fs/xfs/scrub/bmap.c
index b5ebf1d1b4db..c60a1990d629 100644
--- a/fs/xfs/scrub/bmap.c
+++ b/fs/xfs/scrub/bmap.c
@@ -22,6 +22,7 @@
 #include "scrub/scrub.h"
 #include "scrub/common.h"
 #include "scrub/btree.h"
+#include "xfs_ag.h"
 
 /* Set us up with an inode's bmap. */
 int
@@ -575,6 +576,7 @@ xchk_bmap_check_rmaps(
 	int			whichfork)
 {
 	struct xfs_ifork	*ifp = XFS_IFORK_PTR(sc->ip, whichfork);
+	struct xfs_perag	*pag;
 	xfs_agnumber_t		agno;
 	bool			zero_size;
 	int			error;
@@ -607,8 +609,8 @@ xchk_bmap_check_rmaps(
 	    (zero_size || ifp->if_nextents > 0))
 		return 0;
 
-	for (agno = 0; agno < sc->mp->m_sb.sb_agcount; agno++) {
-		error = xchk_bmap_check_ag_rmaps(sc, whichfork, agno);
+	for_each_perag(sc->mp, agno, pag) {
+		error = xchk_bmap_check_ag_rmaps(sc, whichfork, pag->pag_agno);
 		if (error)
 			return error;
 		if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c
index fee2a4e80241..1227503d2246 100644
--- a/fs/xfs/xfs_log_recover.c
+++ b/fs/xfs/xfs_log_recover.c
@@ -2742,21 +2742,17 @@ STATIC void
 xlog_recover_process_iunlinks(
 	struct xlog	*log)
 {
-	xfs_mount_t	*mp;
-	xfs_agnumber_t	agno;
-	xfs_agi_t	*agi;
-	struct xfs_buf	*agibp;
-	xfs_agino_t	agino;
-	int		bucket;
-	int		error;
-
-	mp = log->l_mp;
+	struct xfs_mount	*mp = log->l_mp;
+	struct xfs_perag	*pag;
+	xfs_agnumber_t		agno;
+	struct xfs_agi		*agi;
+	struct xfs_buf		*agibp;
+	xfs_agino_t		agino;
+	int			bucket;
+	int			error;
 
-	for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) {
-		/*
-		 * Find the agi for this ag.
-		 */
-		error = xfs_read_agi(mp, NULL, agno, &agibp);
+	for_each_perag(mp, agno, pag) {
+		error = xfs_read_agi(mp, NULL, pag->pag_agno, &agibp);
 		if (error) {
 			/*
 			 * AGI is b0rked. Don't process it.
@@ -2782,7 +2778,7 @@ xlog_recover_process_iunlinks(
 			agino = be32_to_cpu(agi->agi_unlinked[bucket]);
 			while (agino != NULLAGINO) {
 				agino = xlog_recover_process_one_iunlink(mp,
-							agno, agino, bucket);
+						pag->pag_agno, agino, bucket);
 				cond_resched();
 			}
 		}
@@ -3494,27 +3490,28 @@ xlog_recover_cancel(
  */
 STATIC void
 xlog_recover_check_summary(
-	struct xlog	*log)
+	struct xlog		*log)
 {
-	xfs_mount_t	*mp;
-	struct xfs_buf	*agfbp;
-	struct xfs_buf	*agibp;
-	xfs_agnumber_t	agno;
-	uint64_t	freeblks;
-	uint64_t	itotal;
-	uint64_t	ifree;
-	int		error;
+	struct xfs_mount	*mp = log->l_mp;
+	struct xfs_perag	*pag;
+	struct xfs_buf		*agfbp;
+	struct xfs_buf		*agibp;
+	xfs_agnumber_t		agno;
+	uint64_t		freeblks;
+	uint64_t		itotal;
+	uint64_t		ifree;
+	int			error;
 
 	mp = log->l_mp;
 
 	freeblks = 0LL;
 	itotal = 0LL;
 	ifree = 0LL;
-	for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) {
-		error = xfs_read_agf(mp, NULL, agno, 0, &agfbp);
+	for_each_perag(mp, agno, pag) {
+		error = xfs_read_agf(mp, NULL, pag->pag_agno, 0, &agfbp);
 		if (error) {
 			xfs_alert(mp, "%s agf read failed agno %d error %d",
-						__func__, agno, error);
+						__func__, pag->pag_agno, error);
 		} else {
 			struct xfs_agf	*agfp = agfbp->b_addr;
 
@@ -3523,10 +3520,10 @@ xlog_recover_check_summary(
 			xfs_buf_relse(agfbp);
 		}
 
-		error = xfs_read_agi(mp, NULL, agno, &agibp);
+		error = xfs_read_agi(mp, NULL, pag->pag_agno, &agibp);
 		if (error) {
 			xfs_alert(mp, "%s agi read failed agno %d error %d",
-						__func__, agno, error);
+						__func__, pag->pag_agno, error);
 		} else {
 			struct xfs_agi	*agi = agibp->b_addr;
 
diff --git a/fs/xfs/xfs_reflink.c b/fs/xfs/xfs_reflink.c
index f297d68a931b..0e430b0c1b16 100644
--- a/fs/xfs/xfs_reflink.c
+++ b/fs/xfs/xfs_reflink.c
@@ -755,16 +755,19 @@ int
 xfs_reflink_recover_cow(
 	struct xfs_mount	*mp)
 {
+	struct xfs_perag	*pag;
 	xfs_agnumber_t		agno;
 	int			error = 0;
 
 	if (!xfs_sb_version_hasreflink(&mp->m_sb))
 		return 0;
 
-	for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) {
-		error = xfs_refcount_recover_cow_leftovers(mp, agno);
-		if (error)
+	for_each_perag(mp, agno, pag) {
+		error = xfs_refcount_recover_cow_leftovers(mp, pag->pag_agno);
+		if (error) {
+			xfs_perag_put(pag);
 			break;
+		}
 	}
 
 	return error;
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 87+ messages in thread

* [PATCH 06/22] xfs: convert xfs_iwalk to use perag references
  2021-05-06  7:20 [RFC 00/22] xfs: initial agnumber -> perag conversions for shrink Dave Chinner
                   ` (4 preceding siblings ...)
  2021-05-06  7:20 ` [PATCH 05/22] xfs: convert raw ag walks to use for_each_perag Dave Chinner
@ 2021-05-06  7:20 ` Dave Chinner
  2021-05-10 13:41   ` Brian Foster
  2021-05-12 22:08   ` Darrick J. Wong
  2021-05-06  7:20 ` [PATCH 07/22] xfs: convert secondary superblock walk to use perags Dave Chinner
                   ` (15 subsequent siblings)
  21 siblings, 2 replies; 87+ messages in thread
From: Dave Chinner @ 2021-05-06  7:20 UTC (permalink / raw)
  To: linux-xfs

From: Dave Chinner <dchinner@redhat.com>

Rather than manually walking the ags and passing agnunbers around,
pass the perag for the AG we are currently working on around in the
iwalk structure.

Signed-off-by: Dave Chinner <dchinner@redhat.com>
---
 fs/xfs/libxfs/xfs_ag.h |  8 +++-
 fs/xfs/xfs_iwalk.c     | 86 ++++++++++++++++++++++++++----------------
 2 files changed, 60 insertions(+), 34 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_ag.h b/fs/xfs/libxfs/xfs_ag.h
index 33783120263c..3fa88222dacd 100644
--- a/fs/xfs/libxfs/xfs_ag.h
+++ b/fs/xfs/libxfs/xfs_ag.h
@@ -117,13 +117,17 @@ void	xfs_perag_put(struct xfs_perag *pag);
 /*
  * Perag iteration APIs
  */
-#define for_each_perag(mp, next_agno, pag) \
-	for ((next_agno) = 0, (pag) = xfs_perag_get((mp), 0); \
+#define for_each_perag_from(mp, next_agno, pag) \
+	for ((pag) = xfs_perag_get((mp), (next_agno)); \
 		(pag) != NULL; \
 		(next_agno) = (pag)->pag_agno + 1, \
 		xfs_perag_put(pag), \
 		(pag) = xfs_perag_get((mp), (next_agno)))
 
+#define for_each_perag(mp, next_agno, pag) \
+	(next_agno) = 0; \
+	for_each_perag_from((mp), (next_agno), (pag))
+
 #define for_each_perag_tag(mp, next_agno, pag, tag) \
 	for ((next_agno) = 0, (pag) = xfs_perag_get_tag((mp), 0, (tag)); \
 		(pag) != NULL; \
diff --git a/fs/xfs/xfs_iwalk.c b/fs/xfs/xfs_iwalk.c
index c4a340f1f1e1..c7e8f48a3ec4 100644
--- a/fs/xfs/xfs_iwalk.c
+++ b/fs/xfs/xfs_iwalk.c
@@ -21,6 +21,7 @@
 #include "xfs_health.h"
 #include "xfs_trans.h"
 #include "xfs_pwork.h"
+#include "xfs_ag.h"
 
 /*
  * Walking Inodes in the Filesystem
@@ -51,6 +52,7 @@ struct xfs_iwalk_ag {
 
 	struct xfs_mount		*mp;
 	struct xfs_trans		*tp;
+	struct xfs_perag		*pag;
 
 	/* Where do we start the traversal? */
 	xfs_ino_t			startino;
@@ -90,7 +92,7 @@ struct xfs_iwalk_ag {
 STATIC void
 xfs_iwalk_ichunk_ra(
 	struct xfs_mount		*mp,
-	xfs_agnumber_t			agno,
+	struct xfs_perag		*pag,
 	struct xfs_inobt_rec_incore	*irec)
 {
 	struct xfs_ino_geometry		*igeo = M_IGEO(mp);
@@ -106,7 +108,7 @@ xfs_iwalk_ichunk_ra(
 
 		imask = xfs_inobt_maskn(i, igeo->inodes_per_cluster);
 		if (imask & ~irec->ir_free) {
-			xfs_btree_reada_bufs(mp, agno, agbno,
+			xfs_btree_reada_bufs(mp, pag->pag_agno, agbno,
 					igeo->blocks_per_cluster,
 					&xfs_inode_buf_ops);
 		}
@@ -174,26 +176,25 @@ xfs_iwalk_free(
 /* For each inuse inode in each cached inobt record, call our function. */
 STATIC int
 xfs_iwalk_ag_recs(
-	struct xfs_iwalk_ag		*iwag)
+	struct xfs_iwalk_ag	*iwag)
 {
-	struct xfs_mount		*mp = iwag->mp;
-	struct xfs_trans		*tp = iwag->tp;
-	xfs_ino_t			ino;
-	unsigned int			i, j;
-	xfs_agnumber_t			agno;
-	int				error;
+	struct xfs_mount	*mp = iwag->mp;
+	struct xfs_trans	*tp = iwag->tp;
+	struct xfs_perag	*pag = iwag->pag;
+	xfs_ino_t		ino;
+	unsigned int		i, j;
+	int			error;
 
-	agno = XFS_INO_TO_AGNO(mp, iwag->startino);
 	for (i = 0; i < iwag->nr_recs; i++) {
 		struct xfs_inobt_rec_incore	*irec = &iwag->recs[i];
 
-		trace_xfs_iwalk_ag_rec(mp, agno, irec);
+		trace_xfs_iwalk_ag_rec(mp, pag->pag_agno, irec);
 
 		if (xfs_pwork_want_abort(&iwag->pwork))
 			return 0;
 
 		if (iwag->inobt_walk_fn) {
-			error = iwag->inobt_walk_fn(mp, tp, agno, irec,
+			error = iwag->inobt_walk_fn(mp, tp, pag->pag_agno, irec,
 					iwag->data);
 			if (error)
 				return error;
@@ -211,7 +212,8 @@ xfs_iwalk_ag_recs(
 				continue;
 
 			/* Otherwise call our function. */
-			ino = XFS_AGINO_TO_INO(mp, agno, irec->ir_startino + j);
+			ino = XFS_AGINO_TO_INO(mp, pag->pag_agno,
+						irec->ir_startino + j);
 			error = iwag->iwalk_fn(mp, tp, ino, iwag->data);
 			if (error)
 				return error;
@@ -257,7 +259,6 @@ xfs_iwalk_del_inobt(
 STATIC int
 xfs_iwalk_ag_start(
 	struct xfs_iwalk_ag	*iwag,
-	xfs_agnumber_t		agno,
 	xfs_agino_t		agino,
 	struct xfs_btree_cur	**curpp,
 	struct xfs_buf		**agi_bpp,
@@ -265,12 +266,14 @@ xfs_iwalk_ag_start(
 {
 	struct xfs_mount	*mp = iwag->mp;
 	struct xfs_trans	*tp = iwag->tp;
+	struct xfs_perag	*pag = iwag->pag;
 	struct xfs_inobt_rec_incore *irec;
 	int			error;
 
 	/* Set up a fresh cursor and empty the inobt cache. */
 	iwag->nr_recs = 0;
-	error = xfs_inobt_cur(mp, tp, agno, XFS_BTNUM_INO, curpp, agi_bpp);
+	error = xfs_inobt_cur(mp, tp, pag->pag_agno, XFS_BTNUM_INO,
+				curpp, agi_bpp);
 	if (error)
 		return error;
 
@@ -304,7 +307,7 @@ xfs_iwalk_ag_start(
 	if (XFS_IS_CORRUPT(mp, *has_more != 1))
 		return -EFSCORRUPTED;
 
-	iwag->lastino = XFS_AGINO_TO_INO(mp, agno,
+	iwag->lastino = XFS_AGINO_TO_INO(mp, pag->pag_agno,
 				irec->ir_startino + XFS_INODES_PER_CHUNK - 1);
 
 	/*
@@ -345,7 +348,6 @@ xfs_iwalk_ag_start(
 STATIC int
 xfs_iwalk_run_callbacks(
 	struct xfs_iwalk_ag		*iwag,
-	xfs_agnumber_t			agno,
 	struct xfs_btree_cur		**curpp,
 	struct xfs_buf			**agi_bpp,
 	int				*has_more)
@@ -376,7 +378,8 @@ xfs_iwalk_run_callbacks(
 		return 0;
 
 	/* ...and recreate the cursor just past where we left off. */
-	error = xfs_inobt_cur(mp, tp, agno, XFS_BTNUM_INO, curpp, agi_bpp);
+	error = xfs_inobt_cur(mp, tp, iwag->pag->pag_agno, XFS_BTNUM_INO,
+				curpp, agi_bpp);
 	if (error)
 		return error;
 
@@ -390,17 +393,17 @@ xfs_iwalk_ag(
 {
 	struct xfs_mount		*mp = iwag->mp;
 	struct xfs_trans		*tp = iwag->tp;
+	struct xfs_perag		*pag = iwag->pag;
 	struct xfs_buf			*agi_bp = NULL;
 	struct xfs_btree_cur		*cur = NULL;
-	xfs_agnumber_t			agno;
 	xfs_agino_t			agino;
 	int				has_more;
 	int				error = 0;
 
 	/* Set up our cursor at the right place in the inode btree. */
-	agno = XFS_INO_TO_AGNO(mp, iwag->startino);
+	ASSERT(pag->pag_agno == XFS_INO_TO_AGNO(mp, iwag->startino));
 	agino = XFS_INO_TO_AGINO(mp, iwag->startino);
-	error = xfs_iwalk_ag_start(iwag, agno, agino, &cur, &agi_bp, &has_more);
+	error = xfs_iwalk_ag_start(iwag, agino, &cur, &agi_bp, &has_more);
 
 	while (!error && has_more) {
 		struct xfs_inobt_rec_incore	*irec;
@@ -417,7 +420,7 @@ xfs_iwalk_ag(
 			break;
 
 		/* Make sure that we always move forward. */
-		rec_fsino = XFS_AGINO_TO_INO(mp, agno, irec->ir_startino);
+		rec_fsino = XFS_AGINO_TO_INO(mp, pag->pag_agno, irec->ir_startino);
 		if (iwag->lastino != NULLFSINO &&
 		    XFS_IS_CORRUPT(mp, iwag->lastino >= rec_fsino)) {
 			error = -EFSCORRUPTED;
@@ -438,7 +441,7 @@ xfs_iwalk_ag(
 		 * walking the inodes.
 		 */
 		if (iwag->iwalk_fn)
-			xfs_iwalk_ichunk_ra(mp, agno, irec);
+			xfs_iwalk_ichunk_ra(mp, pag, irec);
 
 		/*
 		 * If there's space in the buffer for more records, increment
@@ -458,15 +461,14 @@ xfs_iwalk_ag(
 		 * we would be if we had been able to increment like above.
 		 */
 		ASSERT(has_more);
-		error = xfs_iwalk_run_callbacks(iwag, agno, &cur, &agi_bp,
-				&has_more);
+		error = xfs_iwalk_run_callbacks(iwag, &cur, &agi_bp, &has_more);
 	}
 
 	if (iwag->nr_recs == 0 || error)
 		goto out;
 
 	/* Walk the unprocessed records in the cache. */
-	error = xfs_iwalk_run_callbacks(iwag, agno, &cur, &agi_bp, &has_more);
+	error = xfs_iwalk_run_callbacks(iwag, &cur, &agi_bp, &has_more);
 
 out:
 	xfs_iwalk_del_inobt(tp, &cur, &agi_bp, error);
@@ -555,6 +557,7 @@ xfs_iwalk(
 		.pwork		= XFS_PWORK_SINGLE_THREADED,
 		.lastino	= NULLFSINO,
 	};
+	struct xfs_perag	*pag;
 	xfs_agnumber_t		agno = XFS_INO_TO_AGNO(mp, startino);
 	int			error;
 
@@ -565,15 +568,19 @@ xfs_iwalk(
 	if (error)
 		return error;
 
-	for (; agno < mp->m_sb.sb_agcount; agno++) {
+	for_each_perag_from(mp, agno, pag) {
+		iwag.pag = pag;
 		error = xfs_iwalk_ag(&iwag);
 		if (error)
 			break;
 		iwag.startino = XFS_AGINO_TO_INO(mp, agno + 1, 0);
 		if (flags & XFS_INOBT_WALK_SAME_AG)
 			break;
+		iwag.pag = NULL;
 	}
 
+	if (iwag.pag)
+		xfs_perag_put(pag);
 	xfs_iwalk_free(&iwag);
 	return error;
 }
@@ -598,6 +605,7 @@ xfs_iwalk_ag_work(
 	error = xfs_iwalk_ag(iwag);
 	xfs_iwalk_free(iwag);
 out:
+	xfs_perag_put(iwag->pag);
 	kmem_free(iwag);
 	return error;
 }
@@ -617,6 +625,7 @@ xfs_iwalk_threaded(
 	void			*data)
 {
 	struct xfs_pwork_ctl	pctl;
+	struct xfs_perag	*pag;
 	xfs_agnumber_t		agno = XFS_INO_TO_AGNO(mp, startino);
 	int			error;
 
@@ -627,7 +636,7 @@ xfs_iwalk_threaded(
 	if (error)
 		return error;
 
-	for (; agno < mp->m_sb.sb_agcount; agno++) {
+	for_each_perag_from(mp, agno, pag) {
 		struct xfs_iwalk_ag	*iwag;
 
 		if (xfs_pwork_ctl_want_abort(&pctl))
@@ -635,17 +644,25 @@ xfs_iwalk_threaded(
 
 		iwag = kmem_zalloc(sizeof(struct xfs_iwalk_ag), 0);
 		iwag->mp = mp;
+
+		/*
+		 * perag is being handed off to async work, so take another
+		 * reference for the async work to release.
+		 */
+		atomic_inc(&pag->pag_ref);
+		iwag->pag = pag;
 		iwag->iwalk_fn = iwalk_fn;
 		iwag->data = data;
 		iwag->startino = startino;
 		iwag->sz_recs = xfs_iwalk_prefetch(inode_records);
 		iwag->lastino = NULLFSINO;
 		xfs_pwork_queue(&pctl, &iwag->pwork);
-		startino = XFS_AGINO_TO_INO(mp, agno + 1, 0);
+		startino = XFS_AGINO_TO_INO(mp, pag->pag_agno + 1, 0);
 		if (flags & XFS_INOBT_WALK_SAME_AG)
 			break;
 	}
-
+	if (pag)
+		xfs_perag_put(pag);
 	if (polled)
 		xfs_pwork_poll(&pctl);
 	return xfs_pwork_destroy(&pctl);
@@ -715,6 +732,7 @@ xfs_inobt_walk(
 		.pwork		= XFS_PWORK_SINGLE_THREADED,
 		.lastino	= NULLFSINO,
 	};
+	struct xfs_perag	*pag;
 	xfs_agnumber_t		agno = XFS_INO_TO_AGNO(mp, startino);
 	int			error;
 
@@ -725,15 +743,19 @@ xfs_inobt_walk(
 	if (error)
 		return error;
 
-	for (; agno < mp->m_sb.sb_agcount; agno++) {
+	for_each_perag_from(mp, agno, pag) {
+		iwag.pag = pag;
 		error = xfs_iwalk_ag(&iwag);
 		if (error)
 			break;
-		iwag.startino = XFS_AGINO_TO_INO(mp, agno + 1, 0);
+		iwag.startino = XFS_AGINO_TO_INO(mp, pag->pag_agno + 1, 0);
 		if (flags & XFS_INOBT_WALK_SAME_AG)
 			break;
+		iwag.pag = NULL;
 	}
 
+	if (iwag.pag)
+		xfs_perag_put(pag);
 	xfs_iwalk_free(&iwag);
 	return error;
 }
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 87+ messages in thread

* [PATCH 07/22] xfs: convert secondary superblock walk to use perags
  2021-05-06  7:20 [RFC 00/22] xfs: initial agnumber -> perag conversions for shrink Dave Chinner
                   ` (5 preceding siblings ...)
  2021-05-06  7:20 ` [PATCH 06/22] xfs: convert xfs_iwalk to use perag references Dave Chinner
@ 2021-05-06  7:20 ` Dave Chinner
  2021-05-10 13:41   ` Brian Foster
  2021-05-12 22:09   ` Darrick J. Wong
  2021-05-06  7:20 ` [PATCH 08/22] xfs: pass perags through to the busy extent code Dave Chinner
                   ` (14 subsequent siblings)
  21 siblings, 2 replies; 87+ messages in thread
From: Dave Chinner @ 2021-05-06  7:20 UTC (permalink / raw)
  To: linux-xfs

From: Dave Chinner <dchinner@redhat.com>

Clean up the last external manual AG walk.

Signed-off-by: Dave Chinner <dchinner@redhat.com>
---
 fs/xfs/libxfs/xfs_sb.c | 12 +++++++-----
 1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_sb.c b/fs/xfs/libxfs/xfs_sb.c
index cbcfce8cebf1..7d4c238540d4 100644
--- a/fs/xfs/libxfs/xfs_sb.c
+++ b/fs/xfs/libxfs/xfs_sb.c
@@ -25,6 +25,7 @@
 #include "xfs_refcount_btree.h"
 #include "xfs_da_format.h"
 #include "xfs_health.h"
+#include "xfs_ag.h"
 
 /*
  * Physical superblock buffer manipulations. Shared with libxfs in userspace.
@@ -856,17 +857,18 @@ int
 xfs_update_secondary_sbs(
 	struct xfs_mount	*mp)
 {
-	xfs_agnumber_t		agno;
+	struct xfs_perag	*pag;
+	xfs_agnumber_t		agno = 1;
 	int			saved_error = 0;
 	int			error = 0;
 	LIST_HEAD		(buffer_list);
 
 	/* update secondary superblocks. */
-	for (agno = 1; agno < mp->m_sb.sb_agcount; agno++) {
+	for_each_perag_from(mp, agno, pag) {
 		struct xfs_buf		*bp;
 
 		error = xfs_buf_get(mp->m_ddev_targp,
-				 XFS_AG_DADDR(mp, agno, XFS_SB_DADDR),
+				 XFS_AG_DADDR(mp, pag->pag_agno, XFS_SB_DADDR),
 				 XFS_FSS_TO_BB(mp, 1), &bp);
 		/*
 		 * If we get an error reading or writing alternate superblocks,
@@ -878,7 +880,7 @@ xfs_update_secondary_sbs(
 		if (error) {
 			xfs_warn(mp,
 		"error allocating secondary superblock for ag %d",
-				agno);
+				pag->pag_agno);
 			if (!saved_error)
 				saved_error = error;
 			continue;
@@ -899,7 +901,7 @@ xfs_update_secondary_sbs(
 		if (error) {
 			xfs_warn(mp,
 		"write error %d updating a secondary superblock near ag %d",
-				error, agno);
+				error, pag->pag_agno);
 			if (!saved_error)
 				saved_error = error;
 			continue;
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 87+ messages in thread

* [PATCH 08/22] xfs: pass perags through to the busy extent code
  2021-05-06  7:20 [RFC 00/22] xfs: initial agnumber -> perag conversions for shrink Dave Chinner
                   ` (6 preceding siblings ...)
  2021-05-06  7:20 ` [PATCH 07/22] xfs: convert secondary superblock walk to use perags Dave Chinner
@ 2021-05-06  7:20 ` Dave Chinner
  2021-05-11 12:29   ` Brian Foster
  2021-05-12 22:13   ` Darrick J. Wong
  2021-05-06  7:20 ` [PATCH 09/22] xfs: push perags through the ag reservation callouts Dave Chinner
                   ` (13 subsequent siblings)
  21 siblings, 2 replies; 87+ messages in thread
From: Dave Chinner @ 2021-05-06  7:20 UTC (permalink / raw)
  To: linux-xfs

From: Dave Chinner <dchinner@redhat.com>

All of the callers of the busy extent API either have perag
references available to use so we can pass a perag to the busy
extent functions rather than having them have to do unnecessary
lookups.

Signed-off-by: Dave Chinner <dchinner@redhat.com>
---
 fs/xfs/libxfs/xfs_alloc.c       | 37 +++++++++++++++++----------------
 fs/xfs/libxfs/xfs_alloc.h       |  2 +-
 fs/xfs/libxfs/xfs_alloc_btree.c |  5 ++---
 fs/xfs/libxfs/xfs_rmap.c        | 32 ++++++++++++++++------------
 fs/xfs/libxfs/xfs_rmap_btree.c  |  7 +++----
 fs/xfs/scrub/repair.c           |  4 ++--
 fs/xfs/xfs_discard.c            |  2 +-
 fs/xfs/xfs_extent_busy.c        | 24 ++++++---------------
 fs/xfs/xfs_extent_busy.h        |  7 ++++---
 9 files changed, 57 insertions(+), 63 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_alloc.c b/fs/xfs/libxfs/xfs_alloc.c
index dc2b77829915..ce31c00dbf6f 100644
--- a/fs/xfs/libxfs/xfs_alloc.c
+++ b/fs/xfs/libxfs/xfs_alloc.c
@@ -1063,7 +1063,7 @@ xfs_alloc_ag_vextent_small(
 	if (fbno == NULLAGBLOCK)
 		goto out;
 
-	xfs_extent_busy_reuse(args->mp, args->agno, fbno, 1,
+	xfs_extent_busy_reuse(args->mp, args->pag, fbno, 1,
 			      (args->datatype & XFS_ALLOC_NOBUSY));
 
 	if (args->datatype & XFS_ALLOC_USERDATA) {
@@ -1178,7 +1178,7 @@ xfs_alloc_ag_vextent(
 		if (error)
 			return error;
 
-		ASSERT(!xfs_extent_busy_search(args->mp, args->agno,
+		ASSERT(!xfs_extent_busy_search(args->mp, args->pag,
 					      args->agbno, args->len));
 	}
 
@@ -3292,7 +3292,7 @@ xfs_alloc_vextent(
 int
 xfs_free_extent_fix_freelist(
 	struct xfs_trans	*tp,
-	xfs_agnumber_t		agno,
+	struct xfs_perag	*pag,
 	struct xfs_buf		**agbp)
 {
 	struct xfs_alloc_arg	args;
@@ -3301,7 +3301,8 @@ xfs_free_extent_fix_freelist(
 	memset(&args, 0, sizeof(struct xfs_alloc_arg));
 	args.tp = tp;
 	args.mp = tp->t_mountp;
-	args.agno = agno;
+	args.agno = pag->pag_agno;
+	args.pag = pag;
 
 	/*
 	 * validate that the block number is legal - the enables us to detect
@@ -3310,17 +3311,12 @@ xfs_free_extent_fix_freelist(
 	if (args.agno >= args.mp->m_sb.sb_agcount)
 		return -EFSCORRUPTED;
 
-	args.pag = xfs_perag_get(args.mp, args.agno);
-	ASSERT(args.pag);
-
 	error = xfs_alloc_fix_freelist(&args, XFS_ALLOC_FLAG_FREEING);
 	if (error)
-		goto out;
+		return error;
 
 	*agbp = args.agbp;
-out:
-	xfs_perag_put(args.pag);
-	return error;
+	return 0;
 }
 
 /*
@@ -3344,6 +3340,7 @@ __xfs_free_extent(
 	struct xfs_agf			*agf;
 	int				error;
 	unsigned int			busy_flags = 0;
+	struct xfs_perag		*pag;
 
 	ASSERT(len != 0);
 	ASSERT(type != XFS_AG_RESV_AGFL);
@@ -3352,33 +3349,37 @@ __xfs_free_extent(
 			XFS_ERRTAG_FREE_EXTENT))
 		return -EIO;
 
-	error = xfs_free_extent_fix_freelist(tp, agno, &agbp);
+	pag = xfs_perag_get(mp, agno);
+	error = xfs_free_extent_fix_freelist(tp, pag, &agbp);
 	if (error)
-		return error;
+		goto err;
 	agf = agbp->b_addr;
 
 	if (XFS_IS_CORRUPT(mp, agbno >= mp->m_sb.sb_agblocks)) {
 		error = -EFSCORRUPTED;
-		goto err;
+		goto err_release;
 	}
 
 	/* validate the extent size is legal now we have the agf locked */
 	if (XFS_IS_CORRUPT(mp, agbno + len > be32_to_cpu(agf->agf_length))) {
 		error = -EFSCORRUPTED;
-		goto err;
+		goto err_release;
 	}
 
 	error = xfs_free_ag_extent(tp, agbp, agno, agbno, len, oinfo, type);
 	if (error)
-		goto err;
+		goto err_release;
 
 	if (skip_discard)
 		busy_flags |= XFS_EXTENT_BUSY_SKIP_DISCARD;
-	xfs_extent_busy_insert(tp, agno, agbno, len, busy_flags);
+	xfs_extent_busy_insert(tp, pag, agbno, len, busy_flags);
+	xfs_perag_put(pag);
 	return 0;
 
-err:
+err_release:
 	xfs_trans_brelse(tp, agbp);
+err:
+	xfs_perag_put(pag);
 	return error;
 }
 
diff --git a/fs/xfs/libxfs/xfs_alloc.h b/fs/xfs/libxfs/xfs_alloc.h
index a4427c5775c2..e30900b6f8ba 100644
--- a/fs/xfs/libxfs/xfs_alloc.h
+++ b/fs/xfs/libxfs/xfs_alloc.h
@@ -214,7 +214,7 @@ int xfs_alloc_read_agfl(struct xfs_mount *mp, struct xfs_trans *tp,
 int xfs_free_agfl_block(struct xfs_trans *, xfs_agnumber_t, xfs_agblock_t,
 			struct xfs_buf *, struct xfs_owner_info *);
 int xfs_alloc_fix_freelist(struct xfs_alloc_arg *args, int flags);
-int xfs_free_extent_fix_freelist(struct xfs_trans *tp, xfs_agnumber_t agno,
+int xfs_free_extent_fix_freelist(struct xfs_trans *tp, struct xfs_perag *pag,
 		struct xfs_buf **agbp);
 
 xfs_extlen_t xfs_prealloc_blocks(struct xfs_mount *mp);
diff --git a/fs/xfs/libxfs/xfs_alloc_btree.c b/fs/xfs/libxfs/xfs_alloc_btree.c
index a540b6e799e0..19fdf87e86b9 100644
--- a/fs/xfs/libxfs/xfs_alloc_btree.c
+++ b/fs/xfs/libxfs/xfs_alloc_btree.c
@@ -72,7 +72,7 @@ xfs_allocbt_alloc_block(
 	}
 
 	atomic64_inc(&cur->bc_mp->m_allocbt_blks);
-	xfs_extent_busy_reuse(cur->bc_mp, cur->bc_ag.agno, bno, 1, false);
+	xfs_extent_busy_reuse(cur->bc_mp, cur->bc_ag.agbp->b_pag, bno, 1, false);
 
 	new->s = cpu_to_be32(bno);
 
@@ -86,7 +86,6 @@ xfs_allocbt_free_block(
 	struct xfs_buf		*bp)
 {
 	struct xfs_buf		*agbp = cur->bc_ag.agbp;
-	struct xfs_agf		*agf = agbp->b_addr;
 	xfs_agblock_t		bno;
 	int			error;
 
@@ -96,7 +95,7 @@ xfs_allocbt_free_block(
 		return error;
 
 	atomic64_dec(&cur->bc_mp->m_allocbt_blks);
-	xfs_extent_busy_insert(cur->bc_tp, be32_to_cpu(agf->agf_seqno), bno, 1,
+	xfs_extent_busy_insert(cur->bc_tp, agbp->b_pag, bno, 1,
 			      XFS_EXTENT_BUSY_SKIP_DISCARD);
 	return 0;
 }
diff --git a/fs/xfs/libxfs/xfs_rmap.c b/fs/xfs/libxfs/xfs_rmap.c
index 61e8f10436ac..1d0a6b686eea 100644
--- a/fs/xfs/libxfs/xfs_rmap.c
+++ b/fs/xfs/libxfs/xfs_rmap.c
@@ -11,6 +11,7 @@
 #include "xfs_trans_resv.h"
 #include "xfs_bit.h"
 #include "xfs_mount.h"
+#include "xfs_sb.h"
 #include "xfs_defer.h"
 #include "xfs_btree.h"
 #include "xfs_trans.h"
@@ -2363,31 +2364,32 @@ xfs_rmap_finish_one(
 	struct xfs_btree_cur		**pcur)
 {
 	struct xfs_mount		*mp = tp->t_mountp;
+	struct xfs_perag		*pag;
 	struct xfs_btree_cur		*rcur;
 	struct xfs_buf			*agbp = NULL;
 	int				error = 0;
-	xfs_agnumber_t			agno;
 	struct xfs_owner_info		oinfo;
 	xfs_agblock_t			bno;
 	bool				unwritten;
 
-	agno = XFS_FSB_TO_AGNO(mp, startblock);
-	ASSERT(agno != NULLAGNUMBER);
+	pag = xfs_perag_get(mp, XFS_FSB_TO_AGNO(mp, startblock));
 	bno = XFS_FSB_TO_AGBNO(mp, startblock);
 
-	trace_xfs_rmap_deferred(mp, agno, type, bno, owner, whichfork,
+	trace_xfs_rmap_deferred(mp, pag->pag_agno, type, bno, owner, whichfork,
 			startoff, blockcount, state);
 
-	if (XFS_TEST_ERROR(false, mp,
-			XFS_ERRTAG_RMAP_FINISH_ONE))
-		return -EIO;
+	if (XFS_TEST_ERROR(false, mp, XFS_ERRTAG_RMAP_FINISH_ONE)) {
+		error = -EIO;
+		goto out_drop;
+	}
+
 
 	/*
 	 * If we haven't gotten a cursor or the cursor AG doesn't match
 	 * the startblock, get one now.
 	 */
 	rcur = *pcur;
-	if (rcur != NULL && rcur->bc_ag.agno != agno) {
+	if (rcur != NULL && rcur->bc_ag.agno != pag->pag_agno) {
 		xfs_rmap_finish_one_cleanup(tp, rcur, 0);
 		rcur = NULL;
 		*pcur = NULL;
@@ -2398,13 +2400,15 @@ xfs_rmap_finish_one(
 		 * rmapbt, because a shape change could cause us to
 		 * allocate blocks.
 		 */
-		error = xfs_free_extent_fix_freelist(tp, agno, &agbp);
+		error = xfs_free_extent_fix_freelist(tp, pag, &agbp);
 		if (error)
-			return error;
-		if (XFS_IS_CORRUPT(tp->t_mountp, !agbp))
-			return -EFSCORRUPTED;
+			goto out_drop;
+		if (XFS_IS_CORRUPT(tp->t_mountp, !agbp)) {
+			error = -EFSCORRUPTED;
+			goto out_drop;
+		}
 
-		rcur = xfs_rmapbt_init_cursor(mp, tp, agbp, agno);
+		rcur = xfs_rmapbt_init_cursor(mp, tp, agbp, pag->pag_agno);
 	}
 	*pcur = rcur;
 
@@ -2442,6 +2446,8 @@ xfs_rmap_finish_one(
 		ASSERT(0);
 		error = -EFSCORRUPTED;
 	}
+out_drop:
+	xfs_perag_put(pag);
 	return error;
 }
 
diff --git a/fs/xfs/libxfs/xfs_rmap_btree.c b/fs/xfs/libxfs/xfs_rmap_btree.c
index f1fee42dda2d..46a5295ecf35 100644
--- a/fs/xfs/libxfs/xfs_rmap_btree.c
+++ b/fs/xfs/libxfs/xfs_rmap_btree.c
@@ -100,8 +100,7 @@ xfs_rmapbt_alloc_block(
 		return 0;
 	}
 
-	xfs_extent_busy_reuse(cur->bc_mp, cur->bc_ag.agno, bno, 1,
-			false);
+	xfs_extent_busy_reuse(cur->bc_mp, agbp->b_pag, bno, 1, false);
 
 	new->s = cpu_to_be32(bno);
 	be32_add_cpu(&agf->agf_rmap_blocks, 1);
@@ -133,10 +132,10 @@ xfs_rmapbt_free_block(
 	if (error)
 		return error;
 
-	xfs_extent_busy_insert(cur->bc_tp, be32_to_cpu(agf->agf_seqno), bno, 1,
+	pag = cur->bc_ag.agbp->b_pag;
+	xfs_extent_busy_insert(cur->bc_tp, pag, bno, 1,
 			      XFS_EXTENT_BUSY_SKIP_DISCARD);
 
-	pag = cur->bc_ag.agbp->b_pag;
 	xfs_ag_resv_free_extent(pag, XFS_AG_RESV_RMAPBT, NULL, 1);
 	return 0;
 }
diff --git a/fs/xfs/scrub/repair.c b/fs/xfs/scrub/repair.c
index 1308b62a8170..6b62872c4d10 100644
--- a/fs/xfs/scrub/repair.c
+++ b/fs/xfs/scrub/repair.c
@@ -304,7 +304,7 @@ xrep_alloc_ag_block(
 			return error;
 		if (bno == NULLAGBLOCK)
 			return -ENOSPC;
-		xfs_extent_busy_reuse(sc->mp, sc->sa.agno, bno,
+		xfs_extent_busy_reuse(sc->mp, sc->sa.pag, bno,
 				1, false);
 		*fsbno = XFS_AGB_TO_FSB(sc->mp, sc->sa.agno, bno);
 		if (resv == XFS_AG_RESV_RMAPBT)
@@ -519,7 +519,7 @@ xrep_put_freelist(
 			agbno, 0);
 	if (error)
 		return error;
-	xfs_extent_busy_insert(sc->tp, sc->sa.agno, agbno, 1,
+	xfs_extent_busy_insert(sc->tp, sc->sa.pag, agbno, 1,
 			XFS_EXTENT_BUSY_SKIP_DISCARD);
 
 	return 0;
diff --git a/fs/xfs/xfs_discard.c b/fs/xfs/xfs_discard.c
index 3bf6dba1a040..972864250bd2 100644
--- a/fs/xfs/xfs_discard.c
+++ b/fs/xfs/xfs_discard.c
@@ -108,7 +108,7 @@ xfs_trim_extents(
 		 * If any blocks in the range are still busy, skip the
 		 * discard and try again the next time.
 		 */
-		if (xfs_extent_busy_search(mp, agno, fbno, flen)) {
+		if (xfs_extent_busy_search(mp, pag, fbno, flen)) {
 			trace_xfs_discard_busy(mp, agno, fbno, flen);
 			goto next_extent;
 		}
diff --git a/fs/xfs/xfs_extent_busy.c b/fs/xfs/xfs_extent_busy.c
index 6af0b5a1c7b0..a0ea63fcc50d 100644
--- a/fs/xfs/xfs_extent_busy.c
+++ b/fs/xfs/xfs_extent_busy.c
@@ -22,28 +22,26 @@
 void
 xfs_extent_busy_insert(
 	struct xfs_trans	*tp,
-	xfs_agnumber_t		agno,
+	struct xfs_perag	*pag,
 	xfs_agblock_t		bno,
 	xfs_extlen_t		len,
 	unsigned int		flags)
 {
 	struct xfs_extent_busy	*new;
 	struct xfs_extent_busy	*busyp;
-	struct xfs_perag	*pag;
 	struct rb_node		**rbp;
 	struct rb_node		*parent = NULL;
 
 	new = kmem_zalloc(sizeof(struct xfs_extent_busy), 0);
-	new->agno = agno;
+	new->agno = pag->pag_agno;
 	new->bno = bno;
 	new->length = len;
 	INIT_LIST_HEAD(&new->list);
 	new->flags = flags;
 
 	/* trace before insert to be able to see failed inserts */
-	trace_xfs_extent_busy(tp->t_mountp, agno, bno, len);
+	trace_xfs_extent_busy(tp->t_mountp, pag->pag_agno, bno, len);
 
-	pag = xfs_perag_get(tp->t_mountp, new->agno);
 	spin_lock(&pag->pagb_lock);
 	rbp = &pag->pagb_tree.rb_node;
 	while (*rbp) {
@@ -66,7 +64,6 @@ xfs_extent_busy_insert(
 
 	list_add(&new->list, &tp->t_busy);
 	spin_unlock(&pag->pagb_lock);
-	xfs_perag_put(pag);
 }
 
 /*
@@ -81,21 +78,17 @@ xfs_extent_busy_insert(
 int
 xfs_extent_busy_search(
 	struct xfs_mount	*mp,
-	xfs_agnumber_t		agno,
+	struct xfs_perag	*pag,
 	xfs_agblock_t		bno,
 	xfs_extlen_t		len)
 {
-	struct xfs_perag	*pag;
 	struct rb_node		*rbp;
 	struct xfs_extent_busy	*busyp;
 	int			match = 0;
 
-	pag = xfs_perag_get(mp, agno);
+	/* find closest start bno overlap */
 	spin_lock(&pag->pagb_lock);
-
 	rbp = pag->pagb_tree.rb_node;
-
-	/* find closest start bno overlap */
 	while (rbp) {
 		busyp = rb_entry(rbp, struct xfs_extent_busy, rb_node);
 		if (bno < busyp->bno) {
@@ -115,7 +108,6 @@ xfs_extent_busy_search(
 		}
 	}
 	spin_unlock(&pag->pagb_lock);
-	xfs_perag_put(pag);
 	return match;
 }
 
@@ -281,17 +273,14 @@ xfs_extent_busy_update_extent(
 void
 xfs_extent_busy_reuse(
 	struct xfs_mount	*mp,
-	xfs_agnumber_t		agno,
+	struct xfs_perag	*pag,
 	xfs_agblock_t		fbno,
 	xfs_extlen_t		flen,
 	bool			userdata)
 {
-	struct xfs_perag	*pag;
 	struct rb_node		*rbp;
 
 	ASSERT(flen > 0);
-
-	pag = xfs_perag_get(mp, agno);
 	spin_lock(&pag->pagb_lock);
 restart:
 	rbp = pag->pagb_tree.rb_node;
@@ -314,7 +303,6 @@ xfs_extent_busy_reuse(
 			goto restart;
 	}
 	spin_unlock(&pag->pagb_lock);
-	xfs_perag_put(pag);
 }
 
 /*
diff --git a/fs/xfs/xfs_extent_busy.h b/fs/xfs/xfs_extent_busy.h
index 990ab3891971..8031617bb6ef 100644
--- a/fs/xfs/xfs_extent_busy.h
+++ b/fs/xfs/xfs_extent_busy.h
@@ -9,6 +9,7 @@
 #define	__XFS_EXTENT_BUSY_H__
 
 struct xfs_mount;
+struct xfs_perag;
 struct xfs_trans;
 struct xfs_alloc_arg;
 
@@ -31,7 +32,7 @@ struct xfs_extent_busy {
 };
 
 void
-xfs_extent_busy_insert(struct xfs_trans *tp, xfs_agnumber_t agno,
+xfs_extent_busy_insert(struct xfs_trans *tp, struct xfs_perag *pag,
 	xfs_agblock_t bno, xfs_extlen_t len, unsigned int flags);
 
 void
@@ -39,11 +40,11 @@ xfs_extent_busy_clear(struct xfs_mount *mp, struct list_head *list,
 	bool do_discard);
 
 int
-xfs_extent_busy_search(struct xfs_mount *mp, xfs_agnumber_t agno,
+xfs_extent_busy_search(struct xfs_mount *mp, struct xfs_perag *pag,
 	xfs_agblock_t bno, xfs_extlen_t len);
 
 void
-xfs_extent_busy_reuse(struct xfs_mount *mp, xfs_agnumber_t agno,
+xfs_extent_busy_reuse(struct xfs_mount *mp, struct xfs_perag *pag,
 	xfs_agblock_t fbno, xfs_extlen_t flen, bool userdata);
 
 bool
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 87+ messages in thread

* [PATCH 09/22] xfs: push perags through the ag reservation callouts
  2021-05-06  7:20 [RFC 00/22] xfs: initial agnumber -> perag conversions for shrink Dave Chinner
                   ` (7 preceding siblings ...)
  2021-05-06  7:20 ` [PATCH 08/22] xfs: pass perags through to the busy extent code Dave Chinner
@ 2021-05-06  7:20 ` Dave Chinner
  2021-05-11 12:29   ` Brian Foster
  2021-05-12 22:16   ` Darrick J. Wong
  2021-05-06  7:20 ` [PATCH 10/22] xfs: pass perags around in fsmap data dev functions Dave Chinner
                   ` (12 subsequent siblings)
  21 siblings, 2 replies; 87+ messages in thread
From: Dave Chinner @ 2021-05-06  7:20 UTC (permalink / raw)
  To: linux-xfs

From: Dave Chinner <dchinner@redhat.com>

We currently pass an agno from the AG reservation functions to the
individual feature accounting functions, which then may have to do
perag lookups to access per-AG state. Plumb the perag through from
the highest AG reservation layer to the feature callouts so they
don't have to look it up again.

Signed-off-by: Dave Chinner <dchinner@redhat.com>
---
 fs/xfs/libxfs/xfs_ag_resv.c        |  9 ++++-----
 fs/xfs/libxfs/xfs_ialloc_btree.c   | 17 +++++++++--------
 fs/xfs/libxfs/xfs_ialloc_btree.h   |  2 +-
 fs/xfs/libxfs/xfs_refcount_btree.c |  7 +++----
 fs/xfs/libxfs/xfs_refcount_btree.h |  3 ++-
 fs/xfs/libxfs/xfs_rmap_btree.c     |  6 +++---
 fs/xfs/libxfs/xfs_rmap_btree.h     |  2 +-
 7 files changed, 23 insertions(+), 23 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_ag_resv.c b/fs/xfs/libxfs/xfs_ag_resv.c
index 2e3dcdfd4984..f7394a8ecf6b 100644
--- a/fs/xfs/libxfs/xfs_ag_resv.c
+++ b/fs/xfs/libxfs/xfs_ag_resv.c
@@ -250,7 +250,6 @@ xfs_ag_resv_init(
 	struct xfs_trans		*tp)
 {
 	struct xfs_mount		*mp = pag->pag_mount;
-	xfs_agnumber_t			agno = pag->pag_agno;
 	xfs_extlen_t			ask;
 	xfs_extlen_t			used;
 	int				error = 0, error2;
@@ -260,11 +259,11 @@ xfs_ag_resv_init(
 	if (pag->pag_meta_resv.ar_asked == 0) {
 		ask = used = 0;
 
-		error = xfs_refcountbt_calc_reserves(mp, tp, agno, &ask, &used);
+		error = xfs_refcountbt_calc_reserves(mp, tp, pag, &ask, &used);
 		if (error)
 			goto out;
 
-		error = xfs_finobt_calc_reserves(mp, tp, agno, &ask, &used);
+		error = xfs_finobt_calc_reserves(mp, tp, pag, &ask, &used);
 		if (error)
 			goto out;
 
@@ -282,7 +281,7 @@ xfs_ag_resv_init(
 
 			mp->m_finobt_nores = true;
 
-			error = xfs_refcountbt_calc_reserves(mp, tp, agno, &ask,
+			error = xfs_refcountbt_calc_reserves(mp, tp, pag, &ask,
 					&used);
 			if (error)
 				goto out;
@@ -300,7 +299,7 @@ xfs_ag_resv_init(
 	if (pag->pag_rmapbt_resv.ar_asked == 0) {
 		ask = used = 0;
 
-		error = xfs_rmapbt_calc_reserves(mp, tp, agno, &ask, &used);
+		error = xfs_rmapbt_calc_reserves(mp, tp, pag, &ask, &used);
 		if (error)
 			goto out;
 
diff --git a/fs/xfs/libxfs/xfs_ialloc_btree.c b/fs/xfs/libxfs/xfs_ialloc_btree.c
index 4c5831646bd9..4ec8ea1331a5 100644
--- a/fs/xfs/libxfs/xfs_ialloc_btree.c
+++ b/fs/xfs/libxfs/xfs_ialloc_btree.c
@@ -20,6 +20,7 @@
 #include "xfs_trace.h"
 #include "xfs_trans.h"
 #include "xfs_rmap.h"
+#include "xfs_ag.h"
 
 STATIC int
 xfs_inobt_get_minrecs(
@@ -680,7 +681,7 @@ static int
 xfs_inobt_count_blocks(
 	struct xfs_mount	*mp,
 	struct xfs_trans	*tp,
-	xfs_agnumber_t		agno,
+	struct xfs_perag	*pag,
 	xfs_btnum_t		btnum,
 	xfs_extlen_t		*tree_blocks)
 {
@@ -688,7 +689,7 @@ xfs_inobt_count_blocks(
 	struct xfs_btree_cur	*cur = NULL;
 	int			error;
 
-	error = xfs_inobt_cur(mp, tp, agno, btnum, &cur, &agbp);
+	error = xfs_inobt_cur(mp, tp, pag->pag_agno, btnum, &cur, &agbp);
 	if (error)
 		return error;
 
@@ -704,14 +705,14 @@ static int
 xfs_finobt_read_blocks(
 	struct xfs_mount	*mp,
 	struct xfs_trans	*tp,
-	xfs_agnumber_t		agno,
+	struct xfs_perag	*pag,
 	xfs_extlen_t		*tree_blocks)
 {
 	struct xfs_buf		*agbp;
 	struct xfs_agi		*agi;
 	int			error;
 
-	error = xfs_ialloc_read_agi(mp, tp, agno, &agbp);
+	error = xfs_ialloc_read_agi(mp, tp, pag->pag_agno, &agbp);
 	if (error)
 		return error;
 
@@ -728,7 +729,7 @@ int
 xfs_finobt_calc_reserves(
 	struct xfs_mount	*mp,
 	struct xfs_trans	*tp,
-	xfs_agnumber_t		agno,
+	struct xfs_perag	*pag,
 	xfs_extlen_t		*ask,
 	xfs_extlen_t		*used)
 {
@@ -739,14 +740,14 @@ xfs_finobt_calc_reserves(
 		return 0;
 
 	if (xfs_sb_version_hasinobtcounts(&mp->m_sb))
-		error = xfs_finobt_read_blocks(mp, tp, agno, &tree_len);
+		error = xfs_finobt_read_blocks(mp, tp, pag, &tree_len);
 	else
-		error = xfs_inobt_count_blocks(mp, tp, agno, XFS_BTNUM_FINO,
+		error = xfs_inobt_count_blocks(mp, tp, pag, XFS_BTNUM_FINO,
 				&tree_len);
 	if (error)
 		return error;
 
-	*ask += xfs_inobt_max_size(mp, agno);
+	*ask += xfs_inobt_max_size(mp, pag->pag_agno);
 	*used += tree_len;
 	return 0;
 }
diff --git a/fs/xfs/libxfs/xfs_ialloc_btree.h b/fs/xfs/libxfs/xfs_ialloc_btree.h
index 35bbd978c272..d5afe01fb2de 100644
--- a/fs/xfs/libxfs/xfs_ialloc_btree.h
+++ b/fs/xfs/libxfs/xfs_ialloc_btree.h
@@ -64,7 +64,7 @@ int xfs_inobt_rec_check_count(struct xfs_mount *,
 #endif	/* DEBUG */
 
 int xfs_finobt_calc_reserves(struct xfs_mount *mp, struct xfs_trans *tp,
-		xfs_agnumber_t agno, xfs_extlen_t *ask, xfs_extlen_t *used);
+		struct xfs_perag *pag, xfs_extlen_t *ask, xfs_extlen_t *used);
 extern xfs_extlen_t xfs_iallocbt_calc_size(struct xfs_mount *mp,
 		unsigned long long len);
 int xfs_inobt_cur(struct xfs_mount *mp, struct xfs_trans *tp,
diff --git a/fs/xfs/libxfs/xfs_refcount_btree.c b/fs/xfs/libxfs/xfs_refcount_btree.c
index b281f0c674f5..c4ddf9ded00b 100644
--- a/fs/xfs/libxfs/xfs_refcount_btree.c
+++ b/fs/xfs/libxfs/xfs_refcount_btree.c
@@ -450,7 +450,7 @@ int
 xfs_refcountbt_calc_reserves(
 	struct xfs_mount	*mp,
 	struct xfs_trans	*tp,
-	xfs_agnumber_t		agno,
+	struct xfs_perag	*pag,
 	xfs_extlen_t		*ask,
 	xfs_extlen_t		*used)
 {
@@ -463,8 +463,7 @@ xfs_refcountbt_calc_reserves(
 	if (!xfs_sb_version_hasreflink(&mp->m_sb))
 		return 0;
 
-
-	error = xfs_alloc_read_agf(mp, tp, agno, 0, &agbp);
+	error = xfs_alloc_read_agf(mp, tp, pag->pag_agno, 0, &agbp);
 	if (error)
 		return error;
 
@@ -479,7 +478,7 @@ xfs_refcountbt_calc_reserves(
 	 * expansion.  We therefore can pretend the space isn't there.
 	 */
 	if (mp->m_sb.sb_logstart &&
-	    XFS_FSB_TO_AGNO(mp, mp->m_sb.sb_logstart) == agno)
+	    XFS_FSB_TO_AGNO(mp, mp->m_sb.sb_logstart) == pag->pag_agno)
 		agblocks -= mp->m_sb.sb_logblocks;
 
 	*ask += xfs_refcountbt_max_size(mp, agblocks);
diff --git a/fs/xfs/libxfs/xfs_refcount_btree.h b/fs/xfs/libxfs/xfs_refcount_btree.h
index 69dc515db671..eab1b0c672c0 100644
--- a/fs/xfs/libxfs/xfs_refcount_btree.h
+++ b/fs/xfs/libxfs/xfs_refcount_btree.h
@@ -13,6 +13,7 @@
 struct xfs_buf;
 struct xfs_btree_cur;
 struct xfs_mount;
+struct xfs_perag;
 struct xbtree_afakeroot;
 
 /*
@@ -58,7 +59,7 @@ extern xfs_extlen_t xfs_refcountbt_max_size(struct xfs_mount *mp,
 		xfs_agblock_t agblocks);
 
 extern int xfs_refcountbt_calc_reserves(struct xfs_mount *mp,
-		struct xfs_trans *tp, xfs_agnumber_t agno, xfs_extlen_t *ask,
+		struct xfs_trans *tp, struct xfs_perag *pag, xfs_extlen_t *ask,
 		xfs_extlen_t *used);
 
 void xfs_refcountbt_commit_staged_btree(struct xfs_btree_cur *cur,
diff --git a/fs/xfs/libxfs/xfs_rmap_btree.c b/fs/xfs/libxfs/xfs_rmap_btree.c
index 46a5295ecf35..ba2f7064451b 100644
--- a/fs/xfs/libxfs/xfs_rmap_btree.c
+++ b/fs/xfs/libxfs/xfs_rmap_btree.c
@@ -595,7 +595,7 @@ int
 xfs_rmapbt_calc_reserves(
 	struct xfs_mount	*mp,
 	struct xfs_trans	*tp,
-	xfs_agnumber_t		agno,
+	struct xfs_perag	*pag,
 	xfs_extlen_t		*ask,
 	xfs_extlen_t		*used)
 {
@@ -608,7 +608,7 @@ xfs_rmapbt_calc_reserves(
 	if (!xfs_sb_version_hasrmapbt(&mp->m_sb))
 		return 0;
 
-	error = xfs_alloc_read_agf(mp, tp, agno, 0, &agbp);
+	error = xfs_alloc_read_agf(mp, tp, pag->pag_agno, 0, &agbp);
 	if (error)
 		return error;
 
@@ -623,7 +623,7 @@ xfs_rmapbt_calc_reserves(
 	 * expansion.  We therefore can pretend the space isn't there.
 	 */
 	if (mp->m_sb.sb_logstart &&
-	    XFS_FSB_TO_AGNO(mp, mp->m_sb.sb_logstart) == agno)
+	    XFS_FSB_TO_AGNO(mp, mp->m_sb.sb_logstart) == pag->pag_agno)
 		agblocks -= mp->m_sb.sb_logblocks;
 
 	/* Reserve 1% of the AG or enough for 1 block per record. */
diff --git a/fs/xfs/libxfs/xfs_rmap_btree.h b/fs/xfs/libxfs/xfs_rmap_btree.h
index 115c3455a734..57fab72e26ad 100644
--- a/fs/xfs/libxfs/xfs_rmap_btree.h
+++ b/fs/xfs/libxfs/xfs_rmap_btree.h
@@ -57,6 +57,6 @@ extern xfs_extlen_t xfs_rmapbt_max_size(struct xfs_mount *mp,
 		xfs_agblock_t agblocks);
 
 extern int xfs_rmapbt_calc_reserves(struct xfs_mount *mp, struct xfs_trans *tp,
-		xfs_agnumber_t agno, xfs_extlen_t *ask, xfs_extlen_t *used);
+		struct xfs_perag *pag, xfs_extlen_t *ask, xfs_extlen_t *used);
 
 #endif	/* __XFS_RMAP_BTREE_H__ */
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 87+ messages in thread

* [PATCH 10/22] xfs: pass perags around in fsmap data dev functions
  2021-05-06  7:20 [RFC 00/22] xfs: initial agnumber -> perag conversions for shrink Dave Chinner
                   ` (8 preceding siblings ...)
  2021-05-06  7:20 ` [PATCH 09/22] xfs: push perags through the ag reservation callouts Dave Chinner
@ 2021-05-06  7:20 ` Dave Chinner
  2021-05-11 12:30   ` Brian Foster
  2021-05-12 22:23   ` Darrick J. Wong
  2021-05-06  7:20 ` [PATCH 11/22] xfs: add a perag to the btree cursor Dave Chinner
                   ` (11 subsequent siblings)
  21 siblings, 2 replies; 87+ messages in thread
From: Dave Chinner @ 2021-05-06  7:20 UTC (permalink / raw)
  To: linux-xfs

From: Dave Chinner <dchinner@redhat.com>

Needs a [from, to] ranged AG walk, and the perag to be stuffed into
the info structure for callouts to use.

Signed-off-by: Dave Chinner <dchinner@redhat.com>
---
 fs/xfs/libxfs/xfs_ag.h | 14 ++++++--
 fs/xfs/xfs_fsmap.c     | 75 ++++++++++++++++++++++++++----------------
 2 files changed, 58 insertions(+), 31 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_ag.h b/fs/xfs/libxfs/xfs_ag.h
index 3fa88222dacd..bebbe1bfce27 100644
--- a/fs/xfs/libxfs/xfs_ag.h
+++ b/fs/xfs/libxfs/xfs_ag.h
@@ -116,14 +116,24 @@ void	xfs_perag_put(struct xfs_perag *pag);
 
 /*
  * Perag iteration APIs
+ *
+ * XXX: for_each_perag_range() usage really needs an iterator to clean up when
+ * we terminate at end_agno because we may have taken a reference to the perag
+ * beyond end_agno. RIght now callers have to be careful to catch and clean that
+ * up themselves. This is not necessary for the callers of for_each_perag() and
+ * for_each_perag_from() because they terminate at sb_agcount where there are
+ * no perag structures in tree beyond end_agno.
  */
-#define for_each_perag_from(mp, next_agno, pag) \
+#define for_each_perag_range(mp, next_agno, end_agno, pag) \
 	for ((pag) = xfs_perag_get((mp), (next_agno)); \
-		(pag) != NULL; \
+		(pag) != NULL && (next_agno) <= (end_agno); \
 		(next_agno) = (pag)->pag_agno + 1, \
 		xfs_perag_put(pag), \
 		(pag) = xfs_perag_get((mp), (next_agno)))
 
+#define for_each_perag_from(mp, next_agno, pag) \
+	for_each_perag_range((mp), (next_agno), (mp)->m_sb.sb_agcount, (pag))
+
 #define for_each_perag(mp, next_agno, pag) \
 	(next_agno) = 0; \
 	for_each_perag_from((mp), (next_agno), (pag))
diff --git a/fs/xfs/xfs_fsmap.c b/fs/xfs/xfs_fsmap.c
index 34f2b971ce43..835dd6e3819b 100644
--- a/fs/xfs/xfs_fsmap.c
+++ b/fs/xfs/xfs_fsmap.c
@@ -24,6 +24,7 @@
 #include "xfs_refcount_btree.h"
 #include "xfs_alloc_btree.h"
 #include "xfs_rtalloc.h"
+#include "xfs_ag.h"
 
 /* Convert an xfs_fsmap to an fsmap. */
 static void
@@ -157,10 +158,10 @@ struct xfs_getfsmap_info {
 	struct xfs_fsmap_head	*head;
 	struct fsmap		*fsmap_recs;	/* mapping records */
 	struct xfs_buf		*agf_bp;	/* AGF, for refcount queries */
+	struct xfs_perag	*pag;		/* AG info, if applicable */
 	xfs_daddr_t		next_daddr;	/* next daddr we expect */
 	u64			missing_owner;	/* owner of holes */
 	u32			dev;		/* device id */
-	xfs_agnumber_t		agno;		/* AG number, if applicable */
 	struct xfs_rmap_irec	low;		/* low rmap key */
 	struct xfs_rmap_irec	high;		/* high rmap key */
 	bool			last;		/* last extent? */
@@ -203,14 +204,14 @@ xfs_getfsmap_is_shared(
 	*stat = false;
 	if (!xfs_sb_version_hasreflink(&mp->m_sb))
 		return 0;
-	/* rt files will have agno set to NULLAGNUMBER */
-	if (info->agno == NULLAGNUMBER)
+	/* rt files will have no perag structure */
+	if (!info->pag)
 		return 0;
 
 	/* Are there any shared blocks here? */
 	flen = 0;
 	cur = xfs_refcountbt_init_cursor(mp, tp, info->agf_bp,
-			info->agno);
+			info->pag->pag_agno);
 
 	error = xfs_refcount_find_shared(cur, rec->rm_startblock,
 			rec->rm_blockcount, &fbno, &flen, false);
@@ -311,7 +312,8 @@ xfs_getfsmap_helper(
 	if (info->head->fmh_entries >= info->head->fmh_count)
 		return -ECANCELED;
 
-	trace_xfs_fsmap_mapping(mp, info->dev, info->agno, rec);
+	trace_xfs_fsmap_mapping(mp, info->dev,
+			info->pag ? info->pag->pag_agno : NULLAGNUMBER, rec);
 
 	fmr.fmr_device = info->dev;
 	fmr.fmr_physical = rec_daddr;
@@ -429,8 +431,8 @@ xfs_getfsmap_logdev(
 	info->high.rm_flags = XFS_RMAP_KEY_FLAGS | XFS_RMAP_REC_FLAGS;
 	info->missing_owner = XFS_FMR_OWN_FREE;
 
-	trace_xfs_fsmap_low_key(mp, info->dev, info->agno, &info->low);
-	trace_xfs_fsmap_high_key(mp, info->dev, info->agno, &info->high);
+	trace_xfs_fsmap_low_key(mp, info->dev, NULLAGNUMBER, &info->low);
+	trace_xfs_fsmap_high_key(mp, info->dev, NULLAGNUMBER, &info->high);
 
 	if (keys[0].fmr_physical > 0)
 		return 0;
@@ -508,8 +510,8 @@ __xfs_getfsmap_rtdev(
 	info->high.rm_blockcount = 0;
 	xfs_getfsmap_set_irec_flags(&info->high, &keys[1]);
 
-	trace_xfs_fsmap_low_key(mp, info->dev, info->agno, &info->low);
-	trace_xfs_fsmap_high_key(mp, info->dev, info->agno, &info->high);
+	trace_xfs_fsmap_low_key(mp, info->dev, NULLAGNUMBER, &info->low);
+	trace_xfs_fsmap_high_key(mp, info->dev, NULLAGNUMBER, &info->high);
 
 	return query_fn(tp, info);
 }
@@ -572,6 +574,7 @@ __xfs_getfsmap_datadev(
 	void				*priv)
 {
 	struct xfs_mount		*mp = tp->t_mountp;
+	struct xfs_perag		*pag;
 	struct xfs_btree_cur		*bt_cur = NULL;
 	xfs_fsblock_t			start_fsb;
 	xfs_fsblock_t			end_fsb;
@@ -610,20 +613,20 @@ __xfs_getfsmap_datadev(
 	start_ag = XFS_FSB_TO_AGNO(mp, start_fsb);
 	end_ag = XFS_FSB_TO_AGNO(mp, end_fsb);
 
-	/* Query each AG */
-	for (info->agno = start_ag; info->agno <= end_ag; info->agno++) {
+	for_each_perag_range(mp, start_ag, end_ag, pag) {
 		/*
 		 * Set the AG high key from the fsmap high key if this
 		 * is the last AG that we're querying.
 		 */
-		if (info->agno == end_ag) {
+		info->pag = pag;
+		if (pag->pag_agno == end_ag) {
 			info->high.rm_startblock = XFS_FSB_TO_AGBNO(mp,
 					end_fsb);
 			info->high.rm_offset = XFS_BB_TO_FSBT(mp,
 					keys[1].fmr_offset);
 			error = xfs_fsmap_owner_to_rmap(&info->high, &keys[1]);
 			if (error)
-				goto err;
+				break;
 			xfs_getfsmap_set_irec_flags(&info->high, &keys[1]);
 		}
 
@@ -634,38 +637,45 @@ __xfs_getfsmap_datadev(
 			info->agf_bp = NULL;
 		}
 
-		error = xfs_alloc_read_agf(mp, tp, info->agno, 0,
+		error = xfs_alloc_read_agf(mp, tp, pag->pag_agno, 0,
 				&info->agf_bp);
 		if (error)
-			goto err;
+			break;
 
-		trace_xfs_fsmap_low_key(mp, info->dev, info->agno, &info->low);
-		trace_xfs_fsmap_high_key(mp, info->dev, info->agno,
+		trace_xfs_fsmap_low_key(mp, info->dev, pag->pag_agno,
+				&info->low);
+		trace_xfs_fsmap_high_key(mp, info->dev, pag->pag_agno,
 				&info->high);
 
 		error = query_fn(tp, info, &bt_cur, priv);
 		if (error)
-			goto err;
+			break;
 
 		/*
 		 * Set the AG low key to the start of the AG prior to
 		 * moving on to the next AG.
 		 */
-		if (info->agno == start_ag) {
+		if (pag->pag_agno == start_ag) {
 			info->low.rm_startblock = 0;
 			info->low.rm_owner = 0;
 			info->low.rm_offset = 0;
 			info->low.rm_flags = 0;
 		}
-	}
 
-	/* Report any gap at the end of the AG */
-	info->last = true;
-	error = query_fn(tp, info, &bt_cur, priv);
-	if (error)
-		goto err;
+		/*
+		 * If this is the last AG, report any gap at the end of it
+		 * before we drop the reference to the perag when the loop
+		 * terminates.
+		 */
+		if (pag->pag_agno == end_ag) {
+			info->last = true;
+			error = query_fn(tp, info, &bt_cur, priv);
+			if (error)
+				break;
+		}
+		info->pag = NULL;
+	}
 
-err:
 	if (bt_cur)
 		xfs_btree_del_cursor(bt_cur, error < 0 ? XFS_BTREE_ERROR :
 							 XFS_BTREE_NOERROR);
@@ -673,6 +683,13 @@ __xfs_getfsmap_datadev(
 		xfs_trans_brelse(tp, info->agf_bp);
 		info->agf_bp = NULL;
 	}
+	if (info->pag) {
+		xfs_perag_put(info->pag);
+		info->pag = NULL;
+	} else if (pag) {
+		/* loop termination case */
+		xfs_perag_put(pag);
+	}
 
 	return error;
 }
@@ -691,7 +708,7 @@ xfs_getfsmap_datadev_rmapbt_query(
 
 	/* Allocate cursor for this AG and query_range it. */
 	*curpp = xfs_rmapbt_init_cursor(tp->t_mountp, tp, info->agf_bp,
-			info->agno);
+			info->pag->pag_agno);
 	return xfs_rmap_query_range(*curpp, &info->low, &info->high,
 			xfs_getfsmap_datadev_helper, info);
 }
@@ -724,7 +741,7 @@ xfs_getfsmap_datadev_bnobt_query(
 
 	/* Allocate cursor for this AG and query_range it. */
 	*curpp = xfs_allocbt_init_cursor(tp->t_mountp, tp, info->agf_bp,
-			info->agno, XFS_BTNUM_BNO);
+			info->pag->pag_agno, XFS_BTNUM_BNO);
 	key->ar_startblock = info->low.rm_startblock;
 	key[1].ar_startblock = info->high.rm_startblock;
 	return xfs_alloc_query_range(*curpp, key, &key[1],
@@ -937,7 +954,7 @@ xfs_getfsmap(
 
 		info.dev = handlers[i].dev;
 		info.last = false;
-		info.agno = NULLAGNUMBER;
+		info.pag = NULL;
 		error = handlers[i].fn(tp, dkeys, &info);
 		if (error)
 			break;
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 87+ messages in thread

* [PATCH 11/22] xfs: add a perag to the btree cursor
  2021-05-06  7:20 [RFC 00/22] xfs: initial agnumber -> perag conversions for shrink Dave Chinner
                   ` (9 preceding siblings ...)
  2021-05-06  7:20 ` [PATCH 10/22] xfs: pass perags around in fsmap data dev functions Dave Chinner
@ 2021-05-06  7:20 ` Dave Chinner
  2021-05-11 12:30   ` Brian Foster
  2021-05-12 22:40   ` Darrick J. Wong
  2021-05-06  7:20 ` [PATCH 12/22] xfs: convert rmap btree cursor to using a perag Dave Chinner
                   ` (10 subsequent siblings)
  21 siblings, 2 replies; 87+ messages in thread
From: Dave Chinner @ 2021-05-06  7:20 UTC (permalink / raw)
  To: linux-xfs

From: Dave Chinner <dchinner@redhat.com>

Which will eventually completely replace the agno in it.

Signed-off-by: Dave Chinner <dchinner@redhat.com>
---
 fs/xfs/libxfs/xfs_alloc.c          | 25 +++++++++++++++----------
 fs/xfs/libxfs/xfs_alloc_btree.c    | 13 ++++++++++---
 fs/xfs/libxfs/xfs_alloc_btree.h    |  3 ++-
 fs/xfs/libxfs/xfs_btree.c          |  2 ++
 fs/xfs/libxfs/xfs_btree.h          |  4 +++-
 fs/xfs/libxfs/xfs_ialloc.c         | 16 ++++++++--------
 fs/xfs/libxfs/xfs_ialloc_btree.c   | 15 +++++++++++----
 fs/xfs/libxfs/xfs_ialloc_btree.h   |  7 ++++---
 fs/xfs/libxfs/xfs_refcount.c       |  4 ++--
 fs/xfs/libxfs/xfs_refcount_btree.c | 17 ++++++++++++-----
 fs/xfs/libxfs/xfs_refcount_btree.h |  2 +-
 fs/xfs/libxfs/xfs_rmap.c           |  6 +++---
 fs/xfs/libxfs/xfs_rmap_btree.c     | 17 ++++++++++++-----
 fs/xfs/libxfs/xfs_rmap_btree.h     |  2 +-
 fs/xfs/scrub/agheader_repair.c     | 20 +++++++++++---------
 fs/xfs/scrub/bmap.c                |  2 +-
 fs/xfs/scrub/common.c              | 12 ++++++------
 fs/xfs/scrub/repair.c              |  5 +++--
 fs/xfs/xfs_discard.c               |  2 +-
 fs/xfs/xfs_fsmap.c                 |  6 +++---
 fs/xfs/xfs_reflink.c               |  2 +-
 21 files changed, 112 insertions(+), 70 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_alloc.c b/fs/xfs/libxfs/xfs_alloc.c
index ce31c00dbf6f..7ec4af6bf494 100644
--- a/fs/xfs/libxfs/xfs_alloc.c
+++ b/fs/xfs/libxfs/xfs_alloc.c
@@ -776,7 +776,8 @@ xfs_alloc_cur_setup(
 	 */
 	if (!acur->cnt)
 		acur->cnt = xfs_allocbt_init_cursor(args->mp, args->tp,
-					args->agbp, args->agno, XFS_BTNUM_CNT);
+						args->agbp, args->agno,
+						args->pag, XFS_BTNUM_CNT);
 	error = xfs_alloc_lookup_ge(acur->cnt, 0, args->maxlen, &i);
 	if (error)
 		return error;
@@ -786,10 +787,12 @@ xfs_alloc_cur_setup(
 	 */
 	if (!acur->bnolt)
 		acur->bnolt = xfs_allocbt_init_cursor(args->mp, args->tp,
-					args->agbp, args->agno, XFS_BTNUM_BNO);
+						args->agbp, args->agno,
+						args->pag, XFS_BTNUM_BNO);
 	if (!acur->bnogt)
 		acur->bnogt = xfs_allocbt_init_cursor(args->mp, args->tp,
-					args->agbp, args->agno, XFS_BTNUM_BNO);
+						args->agbp, args->agno,
+						args->pag, XFS_BTNUM_BNO);
 	return i == 1 ? 0 : -ENOSPC;
 }
 
@@ -1217,7 +1220,7 @@ xfs_alloc_ag_vextent_exact(
 	 * Allocate/initialize a cursor for the by-number freespace btree.
 	 */
 	bno_cur = xfs_allocbt_init_cursor(args->mp, args->tp, args->agbp,
-					  args->agno, XFS_BTNUM_BNO);
+					  args->agno, args->pag, XFS_BTNUM_BNO);
 
 	/*
 	 * Lookup bno and minlen in the btree (minlen is irrelevant, really).
@@ -1277,7 +1280,7 @@ xfs_alloc_ag_vextent_exact(
 	 * Allocate/initialize a cursor for the by-size btree.
 	 */
 	cnt_cur = xfs_allocbt_init_cursor(args->mp, args->tp, args->agbp,
-		args->agno, XFS_BTNUM_CNT);
+					args->agno, args->pag, XFS_BTNUM_CNT);
 	ASSERT(args->agbno + args->len <= be32_to_cpu(agf->agf_length));
 	error = xfs_alloc_fixup_trees(cnt_cur, bno_cur, fbno, flen, args->agbno,
 				      args->len, XFSA_FIXUP_BNO_OK);
@@ -1674,7 +1677,7 @@ xfs_alloc_ag_vextent_size(
 	 * Allocate and initialize a cursor for the by-size btree.
 	 */
 	cnt_cur = xfs_allocbt_init_cursor(args->mp, args->tp, args->agbp,
-		args->agno, XFS_BTNUM_CNT);
+					args->agno, args->pag, XFS_BTNUM_CNT);
 	bno_cur = NULL;
 	busy = false;
 
@@ -1837,7 +1840,7 @@ xfs_alloc_ag_vextent_size(
 	 * Allocate and initialize a cursor for the by-block tree.
 	 */
 	bno_cur = xfs_allocbt_init_cursor(args->mp, args->tp, args->agbp,
-		args->agno, XFS_BTNUM_BNO);
+					args->agno, args->pag, XFS_BTNUM_BNO);
 	if ((error = xfs_alloc_fixup_trees(cnt_cur, bno_cur, fbno, flen,
 			rbno, rlen, XFSA_FIXUP_CNT_OK)))
 		goto error0;
@@ -1909,7 +1912,8 @@ xfs_free_ag_extent(
 	/*
 	 * Allocate and initialize a cursor for the by-block btree.
 	 */
-	bno_cur = xfs_allocbt_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_BNO);
+	bno_cur = xfs_allocbt_init_cursor(mp, tp, agbp, agno,
+					NULL, XFS_BTNUM_BNO);
 	/*
 	 * Look for a neighboring block on the left (lower block numbers)
 	 * that is contiguous with this space.
@@ -1979,7 +1983,8 @@ xfs_free_ag_extent(
 	/*
 	 * Now allocate and initialize a cursor for the by-size tree.
 	 */
-	cnt_cur = xfs_allocbt_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_CNT);
+	cnt_cur = xfs_allocbt_init_cursor(mp, tp, agbp, agno,
+					NULL, XFS_BTNUM_CNT);
 	/*
 	 * Have both left and right contiguous neighbors.
 	 * Merge all three into a single free block.
@@ -2490,7 +2495,7 @@ xfs_exact_minlen_extent_available(
 	int			error = 0;
 
 	cnt_cur = xfs_allocbt_init_cursor(args->mp, args->tp, agbp,
-			args->agno, XFS_BTNUM_CNT);
+					args->agno, args->pag, XFS_BTNUM_CNT);
 	error = xfs_alloc_lookup_ge(cnt_cur, 0, args->minlen, stat);
 	if (error)
 		goto out;
diff --git a/fs/xfs/libxfs/xfs_alloc_btree.c b/fs/xfs/libxfs/xfs_alloc_btree.c
index 19fdf87e86b9..a52ab25bbf0b 100644
--- a/fs/xfs/libxfs/xfs_alloc_btree.c
+++ b/fs/xfs/libxfs/xfs_alloc_btree.c
@@ -27,7 +27,7 @@ xfs_allocbt_dup_cursor(
 {
 	return xfs_allocbt_init_cursor(cur->bc_mp, cur->bc_tp,
 			cur->bc_ag.agbp, cur->bc_ag.agno,
-			cur->bc_btnum);
+			cur->bc_ag.pag, cur->bc_btnum);
 }
 
 STATIC void
@@ -473,6 +473,7 @@ xfs_allocbt_init_common(
 	struct xfs_mount	*mp,
 	struct xfs_trans	*tp,
 	xfs_agnumber_t		agno,
+	struct xfs_perag	*pag,
 	xfs_btnum_t		btnum)
 {
 	struct xfs_btree_cur	*cur;
@@ -497,6 +498,11 @@ xfs_allocbt_init_common(
 
 	cur->bc_ag.agno = agno;
 	cur->bc_ag.abt.active = false;
+	if (pag) {
+		/* take a reference for the cursor */
+		atomic_inc(&pag->pag_ref);
+	}
+	cur->bc_ag.pag = pag;
 
 	if (xfs_sb_version_hascrc(&mp->m_sb))
 		cur->bc_flags |= XFS_BTREE_CRC_BLOCKS;
@@ -513,12 +519,13 @@ xfs_allocbt_init_cursor(
 	struct xfs_trans	*tp,		/* transaction pointer */
 	struct xfs_buf		*agbp,		/* buffer for agf structure */
 	xfs_agnumber_t		agno,		/* allocation group number */
+	struct xfs_perag	*pag,
 	xfs_btnum_t		btnum)		/* btree identifier */
 {
 	struct xfs_agf		*agf = agbp->b_addr;
 	struct xfs_btree_cur	*cur;
 
-	cur = xfs_allocbt_init_common(mp, tp, agno, btnum);
+	cur = xfs_allocbt_init_common(mp, tp, agno, pag, btnum);
 	if (btnum == XFS_BTNUM_CNT)
 		cur->bc_nlevels = be32_to_cpu(agf->agf_levels[XFS_BTNUM_CNT]);
 	else
@@ -539,7 +546,7 @@ xfs_allocbt_stage_cursor(
 {
 	struct xfs_btree_cur	*cur;
 
-	cur = xfs_allocbt_init_common(mp, NULL, agno, btnum);
+	cur = xfs_allocbt_init_common(mp, NULL, agno, NULL, btnum);
 	xfs_btree_stage_afakeroot(cur, afake);
 	return cur;
 }
diff --git a/fs/xfs/libxfs/xfs_alloc_btree.h b/fs/xfs/libxfs/xfs_alloc_btree.h
index a5b998e950fe..a10cedba18d8 100644
--- a/fs/xfs/libxfs/xfs_alloc_btree.h
+++ b/fs/xfs/libxfs/xfs_alloc_btree.h
@@ -13,6 +13,7 @@
 struct xfs_buf;
 struct xfs_btree_cur;
 struct xfs_mount;
+struct xfs_perag;
 struct xbtree_afakeroot;
 
 /*
@@ -48,7 +49,7 @@ struct xbtree_afakeroot;
 
 extern struct xfs_btree_cur *xfs_allocbt_init_cursor(struct xfs_mount *,
 		struct xfs_trans *, struct xfs_buf *,
-		xfs_agnumber_t, xfs_btnum_t);
+		xfs_agnumber_t, struct xfs_perag *pag, xfs_btnum_t);
 struct xfs_btree_cur *xfs_allocbt_stage_cursor(struct xfs_mount *mp,
 		struct xbtree_afakeroot *afake, xfs_agnumber_t agno,
 		xfs_btnum_t btnum);
diff --git a/fs/xfs/libxfs/xfs_btree.c b/fs/xfs/libxfs/xfs_btree.c
index 0f12b885600d..44044317c0fb 100644
--- a/fs/xfs/libxfs/xfs_btree.c
+++ b/fs/xfs/libxfs/xfs_btree.c
@@ -377,6 +377,8 @@ xfs_btree_del_cursor(
 	       XFS_FORCED_SHUTDOWN(cur->bc_mp));
 	if (unlikely(cur->bc_flags & XFS_BTREE_STAGING))
 		kmem_free(cur->bc_ops);
+	if (!(cur->bc_flags & XFS_BTREE_LONG_PTRS) && cur->bc_ag.pag)
+		xfs_perag_put(cur->bc_ag.pag);
 	kmem_cache_free(xfs_btree_cur_zone, cur);
 }
 
diff --git a/fs/xfs/libxfs/xfs_btree.h b/fs/xfs/libxfs/xfs_btree.h
index 10e50cbacacf..8233f8679ba9 100644
--- a/fs/xfs/libxfs/xfs_btree.h
+++ b/fs/xfs/libxfs/xfs_btree.h
@@ -11,6 +11,7 @@ struct xfs_inode;
 struct xfs_mount;
 struct xfs_trans;
 struct xfs_ifork;
+struct xfs_perag;
 
 extern kmem_zone_t	*xfs_btree_cur_zone;
 
@@ -180,11 +181,12 @@ union xfs_btree_irec {
 
 /* Per-AG btree information. */
 struct xfs_btree_cur_ag {
+	xfs_agnumber_t		agno;
+	struct xfs_perag	*pag;
 	union {
 		struct xfs_buf		*agbp;
 		struct xbtree_afakeroot	*afake;	/* for staging cursor */
 	};
-	xfs_agnumber_t		agno;
 	union {
 		struct {
 			unsigned long nr_ops;	/* # record updates */
diff --git a/fs/xfs/libxfs/xfs_ialloc.c b/fs/xfs/libxfs/xfs_ialloc.c
index 8dc9225a5353..905872bab426 100644
--- a/fs/xfs/libxfs/xfs_ialloc.c
+++ b/fs/xfs/libxfs/xfs_ialloc.c
@@ -183,7 +183,7 @@ xfs_inobt_insert(
 	int			i;
 	int			error;
 
-	cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, btnum);
+	cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, NULL, btnum);
 
 	for (thisino = newino;
 	     thisino < newino + newlen;
@@ -531,7 +531,7 @@ xfs_inobt_insert_sprec(
 	int				i;
 	struct xfs_inobt_rec_incore	rec;
 
-	cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, btnum);
+	cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, NULL, btnum);
 
 	/* the new record is pre-aligned so we know where to look */
 	error = xfs_inobt_lookup(cur, nrec->ir_startino, XFS_LOOKUP_EQ, &i);
@@ -1145,7 +1145,7 @@ xfs_dialloc_ag_inobt(
 	ASSERT(pag->pagi_freecount > 0);
 
  restart_pagno:
-	cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_INO);
+	cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, NULL, XFS_BTNUM_INO);
 	/*
 	 * If pagino is 0 (this is the root inode allocation) use newino.
 	 * This must work because we've just allocated some.
@@ -1598,7 +1598,7 @@ xfs_dialloc_ag(
 	if (!pagino)
 		pagino = be32_to_cpu(agi->agi_newino);
 
-	cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_FINO);
+	cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, NULL, XFS_BTNUM_FINO);
 
 	error = xfs_check_agi_freecount(cur, agi);
 	if (error)
@@ -1641,7 +1641,7 @@ xfs_dialloc_ag(
 	 * the original freecount. If all is well, make the equivalent update to
 	 * the inobt using the finobt record and offset information.
 	 */
-	icur = xfs_inobt_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_INO);
+	icur = xfs_inobt_init_cursor(mp, tp, agbp, agno, NULL, XFS_BTNUM_INO);
 
 	error = xfs_check_agi_freecount(icur, agi);
 	if (error)
@@ -1954,7 +1954,7 @@ xfs_difree_inobt(
 	/*
 	 * Initialize the cursor.
 	 */
-	cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_INO);
+	cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, NULL, XFS_BTNUM_INO);
 
 	error = xfs_check_agi_freecount(cur, agi);
 	if (error)
@@ -2080,7 +2080,7 @@ xfs_difree_finobt(
 	int				error;
 	int				i;
 
-	cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_FINO);
+	cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, NULL, XFS_BTNUM_FINO);
 
 	error = xfs_inobt_lookup(cur, ibtrec->ir_startino, XFS_LOOKUP_EQ, &i);
 	if (error)
@@ -2281,7 +2281,7 @@ xfs_imap_lookup(
 	 * we have a record, we need to ensure it contains the inode number
 	 * we are looking up.
 	 */
-	cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_INO);
+	cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, NULL, XFS_BTNUM_INO);
 	error = xfs_inobt_lookup(cur, agino, XFS_LOOKUP_LE, &i);
 	if (!error) {
 		if (i)
diff --git a/fs/xfs/libxfs/xfs_ialloc_btree.c b/fs/xfs/libxfs/xfs_ialloc_btree.c
index 4ec8ea1331a5..6c4efdf01674 100644
--- a/fs/xfs/libxfs/xfs_ialloc_btree.c
+++ b/fs/xfs/libxfs/xfs_ialloc_btree.c
@@ -36,7 +36,7 @@ xfs_inobt_dup_cursor(
 {
 	return xfs_inobt_init_cursor(cur->bc_mp, cur->bc_tp,
 			cur->bc_ag.agbp, cur->bc_ag.agno,
-			cur->bc_btnum);
+			cur->bc_ag.pag, cur->bc_btnum);
 }
 
 STATIC void
@@ -429,6 +429,7 @@ xfs_inobt_init_common(
 	struct xfs_mount	*mp,		/* file system mount point */
 	struct xfs_trans	*tp,		/* transaction pointer */
 	xfs_agnumber_t		agno,		/* allocation group number */
+	struct xfs_perag	*pag,
 	xfs_btnum_t		btnum)		/* ialloc or free ino btree */
 {
 	struct xfs_btree_cur	*cur;
@@ -451,6 +452,11 @@ xfs_inobt_init_common(
 		cur->bc_flags |= XFS_BTREE_CRC_BLOCKS;
 
 	cur->bc_ag.agno = agno;
+	if (pag) {
+		/* take a reference for the cursor */
+		atomic_inc(&pag->pag_ref);
+	}
+	cur->bc_ag.pag = pag;
 	return cur;
 }
 
@@ -461,12 +467,13 @@ xfs_inobt_init_cursor(
 	struct xfs_trans	*tp,
 	struct xfs_buf		*agbp,
 	xfs_agnumber_t		agno,
+	struct xfs_perag	*pag,
 	xfs_btnum_t		btnum)
 {
 	struct xfs_btree_cur	*cur;
 	struct xfs_agi		*agi = agbp->b_addr;
 
-	cur = xfs_inobt_init_common(mp, tp, agno, btnum);
+	cur = xfs_inobt_init_common(mp, tp, agno, pag, btnum);
 	if (btnum == XFS_BTNUM_INO)
 		cur->bc_nlevels = be32_to_cpu(agi->agi_level);
 	else
@@ -485,7 +492,7 @@ xfs_inobt_stage_cursor(
 {
 	struct xfs_btree_cur	*cur;
 
-	cur = xfs_inobt_init_common(mp, NULL, agno, btnum);
+	cur = xfs_inobt_init_common(mp, NULL, agno, NULL, btnum);
 	xfs_btree_stage_afakeroot(cur, afake);
 	return cur;
 }
@@ -672,7 +679,7 @@ xfs_inobt_cur(
 	if (error)
 		return error;
 
-	cur = xfs_inobt_init_cursor(mp, tp, *agi_bpp, agno, which);
+	cur = xfs_inobt_init_cursor(mp, tp, *agi_bpp, agno, NULL, which);
 	*curpp = cur;
 	return 0;
 }
diff --git a/fs/xfs/libxfs/xfs_ialloc_btree.h b/fs/xfs/libxfs/xfs_ialloc_btree.h
index d5afe01fb2de..04dfa7eee81f 100644
--- a/fs/xfs/libxfs/xfs_ialloc_btree.h
+++ b/fs/xfs/libxfs/xfs_ialloc_btree.h
@@ -13,6 +13,7 @@
 struct xfs_buf;
 struct xfs_btree_cur;
 struct xfs_mount;
+struct xfs_perag;
 
 /*
  * Btree block header size depends on a superblock flag.
@@ -45,9 +46,9 @@ struct xfs_mount;
 		 (maxrecs) * sizeof(xfs_inobt_key_t) + \
 		 ((index) - 1) * sizeof(xfs_inobt_ptr_t)))
 
-extern struct xfs_btree_cur *xfs_inobt_init_cursor(struct xfs_mount *,
-		struct xfs_trans *, struct xfs_buf *, xfs_agnumber_t,
-		xfs_btnum_t);
+extern struct xfs_btree_cur *xfs_inobt_init_cursor(struct xfs_mount *mp,
+		struct xfs_trans *tp, struct xfs_buf *agbp, xfs_agnumber_t agno,
+		struct xfs_perag *pag, xfs_btnum_t btnum);
 struct xfs_btree_cur *xfs_inobt_stage_cursor(struct xfs_mount *mp,
 		struct xbtree_afakeroot *afake, xfs_agnumber_t agno,
 		xfs_btnum_t btnum);
diff --git a/fs/xfs/libxfs/xfs_refcount.c b/fs/xfs/libxfs/xfs_refcount.c
index 2037b9f23069..1c2bd2949d7d 100644
--- a/fs/xfs/libxfs/xfs_refcount.c
+++ b/fs/xfs/libxfs/xfs_refcount.c
@@ -1178,7 +1178,7 @@ xfs_refcount_finish_one(
 		if (error)
 			return error;
 
-		rcur = xfs_refcountbt_init_cursor(mp, tp, agbp, agno);
+		rcur = xfs_refcountbt_init_cursor(mp, tp, agbp, agno, NULL);
 		rcur->bc_ag.refc.nr_ops = nr_ops;
 		rcur->bc_ag.refc.shape_changes = shape_changes;
 	}
@@ -1707,7 +1707,7 @@ xfs_refcount_recover_cow_leftovers(
 	error = xfs_alloc_read_agf(mp, tp, agno, 0, &agbp);
 	if (error)
 		goto out_trans;
-	cur = xfs_refcountbt_init_cursor(mp, tp, agbp, agno);
+	cur = xfs_refcountbt_init_cursor(mp, tp, agbp, agno, NULL);
 
 	/* Find all the leftover CoW staging extents. */
 	memset(&low, 0, sizeof(low));
diff --git a/fs/xfs/libxfs/xfs_refcount_btree.c b/fs/xfs/libxfs/xfs_refcount_btree.c
index c4ddf9ded00b..74f8ac0209f1 100644
--- a/fs/xfs/libxfs/xfs_refcount_btree.c
+++ b/fs/xfs/libxfs/xfs_refcount_btree.c
@@ -26,7 +26,7 @@ xfs_refcountbt_dup_cursor(
 	struct xfs_btree_cur	*cur)
 {
 	return xfs_refcountbt_init_cursor(cur->bc_mp, cur->bc_tp,
-			cur->bc_ag.agbp, cur->bc_ag.agno);
+			cur->bc_ag.agbp, cur->bc_ag.agno, cur->bc_ag.pag);
 }
 
 STATIC void
@@ -316,7 +316,8 @@ static struct xfs_btree_cur *
 xfs_refcountbt_init_common(
 	struct xfs_mount	*mp,
 	struct xfs_trans	*tp,
-	xfs_agnumber_t		agno)
+	xfs_agnumber_t		agno,
+	struct xfs_perag	*pag)
 {
 	struct xfs_btree_cur	*cur;
 
@@ -332,6 +333,11 @@ xfs_refcountbt_init_common(
 
 	cur->bc_ag.agno = agno;
 	cur->bc_flags |= XFS_BTREE_CRC_BLOCKS;
+	if (pag) {
+		/* take a reference for the cursor */
+		atomic_inc(&pag->pag_ref);
+	}
+	cur->bc_ag.pag = pag;
 
 	cur->bc_ag.refc.nr_ops = 0;
 	cur->bc_ag.refc.shape_changes = 0;
@@ -345,12 +351,13 @@ xfs_refcountbt_init_cursor(
 	struct xfs_mount	*mp,
 	struct xfs_trans	*tp,
 	struct xfs_buf		*agbp,
-	xfs_agnumber_t		agno)
+	xfs_agnumber_t		agno,
+	struct xfs_perag	*pag)
 {
 	struct xfs_agf		*agf = agbp->b_addr;
 	struct xfs_btree_cur	*cur;
 
-	cur = xfs_refcountbt_init_common(mp, tp, agno);
+	cur = xfs_refcountbt_init_common(mp, tp, agno, pag);
 	cur->bc_nlevels = be32_to_cpu(agf->agf_refcount_level);
 	cur->bc_ag.agbp = agbp;
 	return cur;
@@ -365,7 +372,7 @@ xfs_refcountbt_stage_cursor(
 {
 	struct xfs_btree_cur	*cur;
 
-	cur = xfs_refcountbt_init_common(mp, NULL, agno);
+	cur = xfs_refcountbt_init_common(mp, NULL, agno, NULL);
 	xfs_btree_stage_afakeroot(cur, afake);
 	return cur;
 }
diff --git a/fs/xfs/libxfs/xfs_refcount_btree.h b/fs/xfs/libxfs/xfs_refcount_btree.h
index eab1b0c672c0..8b82a39f104a 100644
--- a/fs/xfs/libxfs/xfs_refcount_btree.h
+++ b/fs/xfs/libxfs/xfs_refcount_btree.h
@@ -47,7 +47,7 @@ struct xbtree_afakeroot;
 
 extern struct xfs_btree_cur *xfs_refcountbt_init_cursor(struct xfs_mount *mp,
 		struct xfs_trans *tp, struct xfs_buf *agbp,
-		xfs_agnumber_t agno);
+		xfs_agnumber_t agno, struct xfs_perag *pag);
 struct xfs_btree_cur *xfs_refcountbt_stage_cursor(struct xfs_mount *mp,
 		struct xbtree_afakeroot *afake, xfs_agnumber_t agno);
 extern int xfs_refcountbt_maxrecs(int blocklen, bool leaf);
diff --git a/fs/xfs/libxfs/xfs_rmap.c b/fs/xfs/libxfs/xfs_rmap.c
index 1d0a6b686eea..0d7a6997120c 100644
--- a/fs/xfs/libxfs/xfs_rmap.c
+++ b/fs/xfs/libxfs/xfs_rmap.c
@@ -708,7 +708,7 @@ xfs_rmap_free(
 	if (!xfs_sb_version_hasrmapbt(&mp->m_sb))
 		return 0;
 
-	cur = xfs_rmapbt_init_cursor(mp, tp, agbp, agno);
+	cur = xfs_rmapbt_init_cursor(mp, tp, agbp, agno, NULL);
 
 	error = xfs_rmap_unmap(cur, bno, len, false, oinfo);
 
@@ -962,7 +962,7 @@ xfs_rmap_alloc(
 	if (!xfs_sb_version_hasrmapbt(&mp->m_sb))
 		return 0;
 
-	cur = xfs_rmapbt_init_cursor(mp, tp, agbp, agno);
+	cur = xfs_rmapbt_init_cursor(mp, tp, agbp, agno, NULL);
 	error = xfs_rmap_map(cur, bno, len, false, oinfo);
 
 	xfs_btree_del_cursor(cur, error);
@@ -2408,7 +2408,7 @@ xfs_rmap_finish_one(
 			goto out_drop;
 		}
 
-		rcur = xfs_rmapbt_init_cursor(mp, tp, agbp, pag->pag_agno);
+		rcur = xfs_rmapbt_init_cursor(mp, tp, agbp, pag->pag_agno, pag);
 	}
 	*pcur = rcur;
 
diff --git a/fs/xfs/libxfs/xfs_rmap_btree.c b/fs/xfs/libxfs/xfs_rmap_btree.c
index ba2f7064451b..7bef8feeded1 100644
--- a/fs/xfs/libxfs/xfs_rmap_btree.c
+++ b/fs/xfs/libxfs/xfs_rmap_btree.c
@@ -52,7 +52,7 @@ xfs_rmapbt_dup_cursor(
 	struct xfs_btree_cur	*cur)
 {
 	return xfs_rmapbt_init_cursor(cur->bc_mp, cur->bc_tp,
-			cur->bc_ag.agbp, cur->bc_ag.agno);
+			cur->bc_ag.agbp, cur->bc_ag.agno, cur->bc_ag.pag);
 }
 
 STATIC void
@@ -449,7 +449,8 @@ static struct xfs_btree_cur *
 xfs_rmapbt_init_common(
 	struct xfs_mount	*mp,
 	struct xfs_trans	*tp,
-	xfs_agnumber_t		agno)
+	xfs_agnumber_t		agno,
+	struct xfs_perag	*pag)
 {
 	struct xfs_btree_cur	*cur;
 
@@ -463,6 +464,11 @@ xfs_rmapbt_init_common(
 	cur->bc_statoff = XFS_STATS_CALC_INDEX(xs_rmap_2);
 	cur->bc_ag.agno = agno;
 	cur->bc_ops = &xfs_rmapbt_ops;
+	if (pag) {
+		/* take a reference for the cursor */
+		atomic_inc(&pag->pag_ref);
+	}
+	cur->bc_ag.pag = pag;
 
 	return cur;
 }
@@ -473,12 +479,13 @@ xfs_rmapbt_init_cursor(
 	struct xfs_mount	*mp,
 	struct xfs_trans	*tp,
 	struct xfs_buf		*agbp,
-	xfs_agnumber_t		agno)
+	xfs_agnumber_t		agno,
+	struct xfs_perag	*pag)
 {
 	struct xfs_agf		*agf = agbp->b_addr;
 	struct xfs_btree_cur	*cur;
 
-	cur = xfs_rmapbt_init_common(mp, tp, agno);
+	cur = xfs_rmapbt_init_common(mp, tp, agno, pag);
 	cur->bc_nlevels = be32_to_cpu(agf->agf_levels[XFS_BTNUM_RMAP]);
 	cur->bc_ag.agbp = agbp;
 	return cur;
@@ -493,7 +500,7 @@ xfs_rmapbt_stage_cursor(
 {
 	struct xfs_btree_cur	*cur;
 
-	cur = xfs_rmapbt_init_common(mp, NULL, agno);
+	cur = xfs_rmapbt_init_common(mp, NULL, agno, NULL);
 	xfs_btree_stage_afakeroot(cur, afake);
 	return cur;
 }
diff --git a/fs/xfs/libxfs/xfs_rmap_btree.h b/fs/xfs/libxfs/xfs_rmap_btree.h
index 57fab72e26ad..c94f418cc06b 100644
--- a/fs/xfs/libxfs/xfs_rmap_btree.h
+++ b/fs/xfs/libxfs/xfs_rmap_btree.h
@@ -43,7 +43,7 @@ struct xbtree_afakeroot;
 
 struct xfs_btree_cur *xfs_rmapbt_init_cursor(struct xfs_mount *mp,
 				struct xfs_trans *tp, struct xfs_buf *bp,
-				xfs_agnumber_t agno);
+				xfs_agnumber_t agno, struct xfs_perag *pag);
 struct xfs_btree_cur *xfs_rmapbt_stage_cursor(struct xfs_mount *mp,
 		struct xbtree_afakeroot *afake, xfs_agnumber_t agno);
 void xfs_rmapbt_commit_staged_btree(struct xfs_btree_cur *cur,
diff --git a/fs/xfs/scrub/agheader_repair.c b/fs/xfs/scrub/agheader_repair.c
index 1cdfbd57f36b..5dd91bf04c18 100644
--- a/fs/xfs/scrub/agheader_repair.c
+++ b/fs/xfs/scrub/agheader_repair.c
@@ -247,7 +247,7 @@ xrep_agf_calc_from_btrees(
 
 	/* Update the AGF counters from the bnobt. */
 	cur = xfs_allocbt_init_cursor(mp, sc->tp, agf_bp, sc->sa.agno,
-			XFS_BTNUM_BNO);
+			sc->sa.pag, XFS_BTNUM_BNO);
 	error = xfs_alloc_query_all(cur, xrep_agf_walk_allocbt, &raa);
 	if (error)
 		goto err;
@@ -261,7 +261,7 @@ xrep_agf_calc_from_btrees(
 
 	/* Update the AGF counters from the cntbt. */
 	cur = xfs_allocbt_init_cursor(mp, sc->tp, agf_bp, sc->sa.agno,
-			XFS_BTNUM_CNT);
+			sc->sa.pag, XFS_BTNUM_CNT);
 	error = xfs_btree_count_blocks(cur, &blocks);
 	if (error)
 		goto err;
@@ -269,7 +269,8 @@ xrep_agf_calc_from_btrees(
 	btreeblks += blocks - 1;
 
 	/* Update the AGF counters from the rmapbt. */
-	cur = xfs_rmapbt_init_cursor(mp, sc->tp, agf_bp, sc->sa.agno);
+	cur = xfs_rmapbt_init_cursor(mp, sc->tp, agf_bp, sc->sa.agno,
+			sc->sa.pag);
 	error = xfs_btree_count_blocks(cur, &blocks);
 	if (error)
 		goto err;
@@ -282,7 +283,7 @@ xrep_agf_calc_from_btrees(
 	/* Update the AGF counters from the refcountbt. */
 	if (xfs_sb_version_hasreflink(&mp->m_sb)) {
 		cur = xfs_refcountbt_init_cursor(mp, sc->tp, agf_bp,
-				sc->sa.agno);
+				sc->sa.agno, sc->sa.pag);
 		error = xfs_btree_count_blocks(cur, &blocks);
 		if (error)
 			goto err;
@@ -490,7 +491,8 @@ xrep_agfl_collect_blocks(
 	xbitmap_init(&ra.agmetablocks);
 
 	/* Find all space used by the free space btrees & rmapbt. */
-	cur = xfs_rmapbt_init_cursor(mp, sc->tp, agf_bp, sc->sa.agno);
+	cur = xfs_rmapbt_init_cursor(mp, sc->tp, agf_bp, sc->sa.agno,
+			sc->sa.pag);
 	error = xfs_rmap_query_all(cur, xrep_agfl_walk_rmap, &ra);
 	if (error)
 		goto err;
@@ -498,7 +500,7 @@ xrep_agfl_collect_blocks(
 
 	/* Find all blocks currently being used by the bnobt. */
 	cur = xfs_allocbt_init_cursor(mp, sc->tp, agf_bp, sc->sa.agno,
-			XFS_BTNUM_BNO);
+			sc->sa.pag, XFS_BTNUM_BNO);
 	error = xbitmap_set_btblocks(&ra.agmetablocks, cur);
 	if (error)
 		goto err;
@@ -506,7 +508,7 @@ xrep_agfl_collect_blocks(
 
 	/* Find all blocks currently being used by the cntbt. */
 	cur = xfs_allocbt_init_cursor(mp, sc->tp, agf_bp, sc->sa.agno,
-			XFS_BTNUM_CNT);
+			sc->sa.pag, XFS_BTNUM_CNT);
 	error = xbitmap_set_btblocks(&ra.agmetablocks, cur);
 	if (error)
 		goto err;
@@ -807,7 +809,7 @@ xrep_agi_calc_from_btrees(
 	int			error;
 
 	cur = xfs_inobt_init_cursor(mp, sc->tp, agi_bp, sc->sa.agno,
-			XFS_BTNUM_INO);
+			sc->sa.pag, XFS_BTNUM_INO);
 	error = xfs_ialloc_count_inodes(cur, &count, &freecount);
 	if (error)
 		goto err;
@@ -829,7 +831,7 @@ xrep_agi_calc_from_btrees(
 		xfs_agblock_t	blocks;
 
 		cur = xfs_inobt_init_cursor(mp, sc->tp, agi_bp, sc->sa.agno,
-				XFS_BTNUM_FINO);
+				sc->sa.pag, XFS_BTNUM_FINO);
 		error = xfs_btree_count_blocks(cur, &blocks);
 		if (error)
 			goto err;
diff --git a/fs/xfs/scrub/bmap.c b/fs/xfs/scrub/bmap.c
index c60a1990d629..a792d9ffd61e 100644
--- a/fs/xfs/scrub/bmap.c
+++ b/fs/xfs/scrub/bmap.c
@@ -556,7 +556,7 @@ xchk_bmap_check_ag_rmaps(
 	if (error)
 		return error;
 
-	cur = xfs_rmapbt_init_cursor(sc->mp, sc->tp, agf, agno);
+	cur = xfs_rmapbt_init_cursor(sc->mp, sc->tp, agf, agno, NULL);
 
 	sbcri.sc = sc;
 	sbcri.whichfork = whichfork;
diff --git a/fs/xfs/scrub/common.c b/fs/xfs/scrub/common.c
index c8da976b50fc..50768559fb60 100644
--- a/fs/xfs/scrub/common.c
+++ b/fs/xfs/scrub/common.c
@@ -465,42 +465,42 @@ xchk_ag_btcur_init(
 	    xchk_ag_btree_healthy_enough(sc, sa->pag, XFS_BTNUM_BNO)) {
 		/* Set up a bnobt cursor for cross-referencing. */
 		sa->bno_cur = xfs_allocbt_init_cursor(mp, sc->tp, sa->agf_bp,
-				agno, XFS_BTNUM_BNO);
+				agno, sa->pag, XFS_BTNUM_BNO);
 	}
 
 	if (sa->agf_bp &&
 	    xchk_ag_btree_healthy_enough(sc, sa->pag, XFS_BTNUM_CNT)) {
 		/* Set up a cntbt cursor for cross-referencing. */
 		sa->cnt_cur = xfs_allocbt_init_cursor(mp, sc->tp, sa->agf_bp,
-				agno, XFS_BTNUM_CNT);
+				agno, sa->pag, XFS_BTNUM_CNT);
 	}
 
 	/* Set up a inobt cursor for cross-referencing. */
 	if (sa->agi_bp &&
 	    xchk_ag_btree_healthy_enough(sc, sa->pag, XFS_BTNUM_INO)) {
 		sa->ino_cur = xfs_inobt_init_cursor(mp, sc->tp, sa->agi_bp,
-					agno, XFS_BTNUM_INO);
+				agno, sa->pag, XFS_BTNUM_INO);
 	}
 
 	/* Set up a finobt cursor for cross-referencing. */
 	if (sa->agi_bp && xfs_sb_version_hasfinobt(&mp->m_sb) &&
 	    xchk_ag_btree_healthy_enough(sc, sa->pag, XFS_BTNUM_FINO)) {
 		sa->fino_cur = xfs_inobt_init_cursor(mp, sc->tp, sa->agi_bp,
-				agno, XFS_BTNUM_FINO);
+				agno, sa->pag, XFS_BTNUM_FINO);
 	}
 
 	/* Set up a rmapbt cursor for cross-referencing. */
 	if (sa->agf_bp && xfs_sb_version_hasrmapbt(&mp->m_sb) &&
 	    xchk_ag_btree_healthy_enough(sc, sa->pag, XFS_BTNUM_RMAP)) {
 		sa->rmap_cur = xfs_rmapbt_init_cursor(mp, sc->tp, sa->agf_bp,
-				agno);
+				agno, sa->pag);
 	}
 
 	/* Set up a refcountbt cursor for cross-referencing. */
 	if (sa->agf_bp && xfs_sb_version_hasreflink(&mp->m_sb) &&
 	    xchk_ag_btree_healthy_enough(sc, sa->pag, XFS_BTNUM_REFC)) {
 		sa->refc_cur = xfs_refcountbt_init_cursor(mp, sc->tp,
-				sa->agf_bp, agno);
+				sa->agf_bp, agno, sa->pag);
 	}
 }
 
diff --git a/fs/xfs/scrub/repair.c b/fs/xfs/scrub/repair.c
index 6b62872c4d10..862dc56fd8cd 100644
--- a/fs/xfs/scrub/repair.c
+++ b/fs/xfs/scrub/repair.c
@@ -555,7 +555,7 @@ xrep_reap_block(
 	} else {
 		agf_bp = sc->sa.agf_bp;
 	}
-	cur = xfs_rmapbt_init_cursor(sc->mp, sc->tp, agf_bp, agno);
+	cur = xfs_rmapbt_init_cursor(sc->mp, sc->tp, agf_bp, agno, sc->sa.pag);
 
 	/* Can we find any other rmappings? */
 	error = xfs_rmap_has_other_keys(cur, agbno, 1, oinfo, &has_other_rmap);
@@ -892,7 +892,8 @@ xrep_find_ag_btree_roots(
 		fab->height = 0;
 	}
 
-	cur = xfs_rmapbt_init_cursor(mp, sc->tp, agf_bp, sc->sa.agno);
+	cur = xfs_rmapbt_init_cursor(mp, sc->tp, agf_bp, sc->sa.agno,
+			sc->sa.pag);
 	error = xfs_rmap_query_all(cur, xrep_findroot_rmap, &ri);
 	xfs_btree_del_cursor(cur, error);
 
diff --git a/fs/xfs/xfs_discard.c b/fs/xfs/xfs_discard.c
index 972864250bd2..311ebaad4f5a 100644
--- a/fs/xfs/xfs_discard.c
+++ b/fs/xfs/xfs_discard.c
@@ -50,7 +50,7 @@ xfs_trim_extents(
 		goto out_put_perag;
 	agf = agbp->b_addr;
 
-	cur = xfs_allocbt_init_cursor(mp, NULL, agbp, agno, XFS_BTNUM_CNT);
+	cur = xfs_allocbt_init_cursor(mp, NULL, agbp, agno, pag, XFS_BTNUM_CNT);
 
 	/*
 	 * Look up the longest btree in the AGF and start with it.
diff --git a/fs/xfs/xfs_fsmap.c b/fs/xfs/xfs_fsmap.c
index 835dd6e3819b..b654a2bf9a9f 100644
--- a/fs/xfs/xfs_fsmap.c
+++ b/fs/xfs/xfs_fsmap.c
@@ -211,7 +211,7 @@ xfs_getfsmap_is_shared(
 	/* Are there any shared blocks here? */
 	flen = 0;
 	cur = xfs_refcountbt_init_cursor(mp, tp, info->agf_bp,
-			info->pag->pag_agno);
+			info->pag->pag_agno, info->pag);
 
 	error = xfs_refcount_find_shared(cur, rec->rm_startblock,
 			rec->rm_blockcount, &fbno, &flen, false);
@@ -708,7 +708,7 @@ xfs_getfsmap_datadev_rmapbt_query(
 
 	/* Allocate cursor for this AG and query_range it. */
 	*curpp = xfs_rmapbt_init_cursor(tp->t_mountp, tp, info->agf_bp,
-			info->pag->pag_agno);
+			info->pag->pag_agno, info->pag);
 	return xfs_rmap_query_range(*curpp, &info->low, &info->high,
 			xfs_getfsmap_datadev_helper, info);
 }
@@ -741,7 +741,7 @@ xfs_getfsmap_datadev_bnobt_query(
 
 	/* Allocate cursor for this AG and query_range it. */
 	*curpp = xfs_allocbt_init_cursor(tp->t_mountp, tp, info->agf_bp,
-			info->pag->pag_agno, XFS_BTNUM_BNO);
+			info->pag->pag_agno, info->pag, XFS_BTNUM_BNO);
 	key->ar_startblock = info->low.rm_startblock;
 	key[1].ar_startblock = info->high.rm_startblock;
 	return xfs_alloc_query_range(*curpp, key, &key[1],
diff --git a/fs/xfs/xfs_reflink.c b/fs/xfs/xfs_reflink.c
index 0e430b0c1b16..28ffe1817f9b 100644
--- a/fs/xfs/xfs_reflink.c
+++ b/fs/xfs/xfs_reflink.c
@@ -144,7 +144,7 @@ xfs_reflink_find_shared(
 	if (error)
 		return error;
 
-	cur = xfs_refcountbt_init_cursor(mp, tp, agbp, agno);
+	cur = xfs_refcountbt_init_cursor(mp, tp, agbp, agno, NULL);
 
 	error = xfs_refcount_find_shared(cur, agbno, aglen, fbno, flen,
 			find_end_of_shared);
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 87+ messages in thread

* [PATCH 12/22] xfs: convert rmap btree cursor to using a perag
  2021-05-06  7:20 [RFC 00/22] xfs: initial agnumber -> perag conversions for shrink Dave Chinner
                   ` (10 preceding siblings ...)
  2021-05-06  7:20 ` [PATCH 11/22] xfs: add a perag to the btree cursor Dave Chinner
@ 2021-05-06  7:20 ` Dave Chinner
  2021-05-11 12:30   ` Brian Foster
  2021-05-12 22:45   ` Darrick J. Wong
  2021-05-06  7:20 ` [PATCH 13/22] xfs: convert refcount btree cursor to use perags Dave Chinner
                   ` (9 subsequent siblings)
  21 siblings, 2 replies; 87+ messages in thread
From: Dave Chinner @ 2021-05-06  7:20 UTC (permalink / raw)
  To: linux-xfs

From: Dave Chinner <dchinner@redhat.com>

Signed-off-by: Dave Chinner <dchinner@redhat.com>
---
 fs/xfs/libxfs/xfs_ag.c         |  2 +-
 fs/xfs/libxfs/xfs_alloc.c      |  7 ++++---
 fs/xfs/libxfs/xfs_rmap.c       | 10 ++++-----
 fs/xfs/libxfs/xfs_rmap.h       |  6 ++++--
 fs/xfs/libxfs/xfs_rmap_btree.c | 37 +++++++++++++++-------------------
 fs/xfs/libxfs/xfs_rmap_btree.h |  4 ++--
 fs/xfs/scrub/agheader_repair.c |  6 ++----
 fs/xfs/scrub/bmap.c            |  2 +-
 fs/xfs/scrub/common.c          |  2 +-
 fs/xfs/scrub/repair.c          | 10 ++++-----
 fs/xfs/xfs_fsmap.c             |  2 +-
 11 files changed, 42 insertions(+), 46 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_ag.c b/fs/xfs/libxfs/xfs_ag.c
index 14d8b866dc6d..44f2787f3556 100644
--- a/fs/xfs/libxfs/xfs_ag.c
+++ b/fs/xfs/libxfs/xfs_ag.c
@@ -914,7 +914,7 @@ xfs_ag_extend_space(
 	 * XFS_RMAP_OINFO_SKIP_UPDATE is used here to tell the rmap btree that
 	 * this doesn't actually exist in the rmap btree.
 	 */
-	error = xfs_rmap_free(tp, bp, id->agno,
+	error = xfs_rmap_free(tp, bp, bp->b_pag,
 				be32_to_cpu(agf->agf_length) - len,
 				len, &XFS_RMAP_OINFO_SKIP_UPDATE);
 	if (error)
diff --git a/fs/xfs/libxfs/xfs_alloc.c b/fs/xfs/libxfs/xfs_alloc.c
index 7ec4af6bf494..10747cc4d8f6 100644
--- a/fs/xfs/libxfs/xfs_alloc.c
+++ b/fs/xfs/libxfs/xfs_alloc.c
@@ -1092,7 +1092,7 @@ xfs_alloc_ag_vextent_small(
 	 * If we're feeding an AGFL block to something that doesn't live in the
 	 * free space, we need to clear out the OWN_AG rmap.
 	 */
-	error = xfs_rmap_free(args->tp, args->agbp, args->agno, fbno, 1,
+	error = xfs_rmap_free(args->tp, args->agbp, args->pag, fbno, 1,
 			      &XFS_RMAP_OINFO_AG);
 	if (error)
 		goto error;
@@ -1169,7 +1169,7 @@ xfs_alloc_ag_vextent(
 
 	/* if not file data, insert new block into the reverse map btree */
 	if (!xfs_rmap_should_skip_owner_update(&args->oinfo)) {
-		error = xfs_rmap_alloc(args->tp, args->agbp, args->agno,
+		error = xfs_rmap_alloc(args->tp, args->agbp, args->pag,
 				       args->agbno, args->len, &args->oinfo);
 		if (error)
 			return error;
@@ -1899,12 +1899,13 @@ xfs_free_ag_extent(
 	int				haveright; /* have a right neighbor */
 	int				i;
 	int				error;
+	struct xfs_perag		*pag = agbp->b_pag;
 
 	bno_cur = cnt_cur = NULL;
 	mp = tp->t_mountp;
 
 	if (!xfs_rmap_should_skip_owner_update(oinfo)) {
-		error = xfs_rmap_free(tp, agbp, agno, bno, len, oinfo);
+		error = xfs_rmap_free(tp, agbp, pag, bno, len, oinfo);
 		if (error)
 			goto error0;
 	}
diff --git a/fs/xfs/libxfs/xfs_rmap.c b/fs/xfs/libxfs/xfs_rmap.c
index 0d7a6997120c..b23f949ee15c 100644
--- a/fs/xfs/libxfs/xfs_rmap.c
+++ b/fs/xfs/libxfs/xfs_rmap.c
@@ -696,7 +696,7 @@ int
 xfs_rmap_free(
 	struct xfs_trans		*tp,
 	struct xfs_buf			*agbp,
-	xfs_agnumber_t			agno,
+	struct xfs_perag		*pag,
 	xfs_agblock_t			bno,
 	xfs_extlen_t			len,
 	const struct xfs_owner_info	*oinfo)
@@ -708,7 +708,7 @@ xfs_rmap_free(
 	if (!xfs_sb_version_hasrmapbt(&mp->m_sb))
 		return 0;
 
-	cur = xfs_rmapbt_init_cursor(mp, tp, agbp, agno, NULL);
+	cur = xfs_rmapbt_init_cursor(mp, tp, agbp, pag);
 
 	error = xfs_rmap_unmap(cur, bno, len, false, oinfo);
 
@@ -950,7 +950,7 @@ int
 xfs_rmap_alloc(
 	struct xfs_trans		*tp,
 	struct xfs_buf			*agbp,
-	xfs_agnumber_t			agno,
+	struct xfs_perag		*pag,
 	xfs_agblock_t			bno,
 	xfs_extlen_t			len,
 	const struct xfs_owner_info	*oinfo)
@@ -962,7 +962,7 @@ xfs_rmap_alloc(
 	if (!xfs_sb_version_hasrmapbt(&mp->m_sb))
 		return 0;
 
-	cur = xfs_rmapbt_init_cursor(mp, tp, agbp, agno, NULL);
+	cur = xfs_rmapbt_init_cursor(mp, tp, agbp, pag);
 	error = xfs_rmap_map(cur, bno, len, false, oinfo);
 
 	xfs_btree_del_cursor(cur, error);
@@ -2408,7 +2408,7 @@ xfs_rmap_finish_one(
 			goto out_drop;
 		}
 
-		rcur = xfs_rmapbt_init_cursor(mp, tp, agbp, pag->pag_agno, pag);
+		rcur = xfs_rmapbt_init_cursor(mp, tp, agbp, pag);
 	}
 	*pcur = rcur;
 
diff --git a/fs/xfs/libxfs/xfs_rmap.h b/fs/xfs/libxfs/xfs_rmap.h
index abe633403fd1..f2423cf7f1e2 100644
--- a/fs/xfs/libxfs/xfs_rmap.h
+++ b/fs/xfs/libxfs/xfs_rmap.h
@@ -6,6 +6,8 @@
 #ifndef __XFS_RMAP_H__
 #define __XFS_RMAP_H__
 
+struct xfs_perag;
+
 static inline void
 xfs_rmap_ino_bmbt_owner(
 	struct xfs_owner_info	*oi,
@@ -113,10 +115,10 @@ xfs_owner_info_pack(
 }
 
 int xfs_rmap_alloc(struct xfs_trans *tp, struct xfs_buf *agbp,
-		   xfs_agnumber_t agno, xfs_agblock_t bno, xfs_extlen_t len,
+		   struct xfs_perag *pag, xfs_agblock_t bno, xfs_extlen_t len,
 		   const struct xfs_owner_info *oinfo);
 int xfs_rmap_free(struct xfs_trans *tp, struct xfs_buf *agbp,
-		  xfs_agnumber_t agno, xfs_agblock_t bno, xfs_extlen_t len,
+		  struct xfs_perag *pag, xfs_agblock_t bno, xfs_extlen_t len,
 		  const struct xfs_owner_info *oinfo);
 
 int xfs_rmap_lookup_le(struct xfs_btree_cur *cur, xfs_agblock_t bno,
diff --git a/fs/xfs/libxfs/xfs_rmap_btree.c b/fs/xfs/libxfs/xfs_rmap_btree.c
index 7bef8feeded1..cafe181bc92d 100644
--- a/fs/xfs/libxfs/xfs_rmap_btree.c
+++ b/fs/xfs/libxfs/xfs_rmap_btree.c
@@ -52,7 +52,7 @@ xfs_rmapbt_dup_cursor(
 	struct xfs_btree_cur	*cur)
 {
 	return xfs_rmapbt_init_cursor(cur->bc_mp, cur->bc_tp,
-			cur->bc_ag.agbp, cur->bc_ag.agno, cur->bc_ag.pag);
+				cur->bc_ag.agbp, cur->bc_ag.pag);
 }
 
 STATIC void
@@ -64,13 +64,12 @@ xfs_rmapbt_set_root(
 	struct xfs_buf		*agbp = cur->bc_ag.agbp;
 	struct xfs_agf		*agf = agbp->b_addr;
 	int			btnum = cur->bc_btnum;
-	struct xfs_perag	*pag = agbp->b_pag;
 
 	ASSERT(ptr->s != 0);
 
 	agf->agf_roots[btnum] = ptr->s;
 	be32_add_cpu(&agf->agf_levels[btnum], inc);
-	pag->pagf_levels[btnum] += inc;
+	cur->bc_ag.pag->pagf_levels[btnum] += inc;
 
 	xfs_alloc_log_agf(cur->bc_tp, agbp, XFS_AGF_ROOTS | XFS_AGF_LEVELS);
 }
@@ -84,6 +83,7 @@ xfs_rmapbt_alloc_block(
 {
 	struct xfs_buf		*agbp = cur->bc_ag.agbp;
 	struct xfs_agf		*agf = agbp->b_addr;
+	struct xfs_perag	*pag = cur->bc_ag.pag;
 	int			error;
 	xfs_agblock_t		bno;
 
@@ -93,20 +93,19 @@ xfs_rmapbt_alloc_block(
 	if (error)
 		return error;
 
-	trace_xfs_rmapbt_alloc_block(cur->bc_mp, cur->bc_ag.agno,
-			bno, 1);
+	trace_xfs_rmapbt_alloc_block(cur->bc_mp, pag->pag_agno, bno, 1);
 	if (bno == NULLAGBLOCK) {
 		*stat = 0;
 		return 0;
 	}
 
-	xfs_extent_busy_reuse(cur->bc_mp, agbp->b_pag, bno, 1, false);
+	xfs_extent_busy_reuse(cur->bc_mp, pag, bno, 1, false);
 
 	new->s = cpu_to_be32(bno);
 	be32_add_cpu(&agf->agf_rmap_blocks, 1);
 	xfs_alloc_log_agf(cur->bc_tp, agbp, XFS_AGF_RMAP_BLOCKS);
 
-	xfs_ag_resv_rmapbt_alloc(cur->bc_mp, cur->bc_ag.agno);
+	xfs_ag_resv_rmapbt_alloc(cur->bc_mp, pag->pag_agno);
 
 	*stat = 1;
 	return 0;
@@ -119,12 +118,12 @@ xfs_rmapbt_free_block(
 {
 	struct xfs_buf		*agbp = cur->bc_ag.agbp;
 	struct xfs_agf		*agf = agbp->b_addr;
-	struct xfs_perag	*pag;
+	struct xfs_perag	*pag = cur->bc_ag.pag;
 	xfs_agblock_t		bno;
 	int			error;
 
 	bno = xfs_daddr_to_agbno(cur->bc_mp, XFS_BUF_ADDR(bp));
-	trace_xfs_rmapbt_free_block(cur->bc_mp, cur->bc_ag.agno,
+	trace_xfs_rmapbt_free_block(cur->bc_mp, pag->pag_agno,
 			bno, 1);
 	be32_add_cpu(&agf->agf_rmap_blocks, -1);
 	xfs_alloc_log_agf(cur->bc_tp, agbp, XFS_AGF_RMAP_BLOCKS);
@@ -132,7 +131,6 @@ xfs_rmapbt_free_block(
 	if (error)
 		return error;
 
-	pag = cur->bc_ag.agbp->b_pag;
 	xfs_extent_busy_insert(cur->bc_tp, pag, bno, 1,
 			      XFS_EXTENT_BUSY_SKIP_DISCARD);
 
@@ -214,7 +212,7 @@ xfs_rmapbt_init_ptr_from_cur(
 {
 	struct xfs_agf		*agf = cur->bc_ag.agbp->b_addr;
 
-	ASSERT(cur->bc_ag.agno == be32_to_cpu(agf->agf_seqno));
+	ASSERT(cur->bc_ag.pag->pag_agno == be32_to_cpu(agf->agf_seqno));
 
 	ptr->s = agf->agf_roots[cur->bc_btnum];
 }
@@ -449,7 +447,6 @@ static struct xfs_btree_cur *
 xfs_rmapbt_init_common(
 	struct xfs_mount	*mp,
 	struct xfs_trans	*tp,
-	xfs_agnumber_t		agno,
 	struct xfs_perag	*pag)
 {
 	struct xfs_btree_cur	*cur;
@@ -462,13 +459,12 @@ xfs_rmapbt_init_common(
 	cur->bc_flags = XFS_BTREE_CRC_BLOCKS | XFS_BTREE_OVERLAPPING;
 	cur->bc_blocklog = mp->m_sb.sb_blocklog;
 	cur->bc_statoff = XFS_STATS_CALC_INDEX(xs_rmap_2);
-	cur->bc_ag.agno = agno;
 	cur->bc_ops = &xfs_rmapbt_ops;
-	if (pag) {
-		/* take a reference for the cursor */
-		atomic_inc(&pag->pag_ref);
-	}
+
+	/* take a reference for the cursor */
+	atomic_inc(&pag->pag_ref);
 	cur->bc_ag.pag = pag;
+	cur->bc_ag.agno = pag->pag_agno;
 
 	return cur;
 }
@@ -479,13 +475,12 @@ xfs_rmapbt_init_cursor(
 	struct xfs_mount	*mp,
 	struct xfs_trans	*tp,
 	struct xfs_buf		*agbp,
-	xfs_agnumber_t		agno,
 	struct xfs_perag	*pag)
 {
 	struct xfs_agf		*agf = agbp->b_addr;
 	struct xfs_btree_cur	*cur;
 
-	cur = xfs_rmapbt_init_common(mp, tp, agno, pag);
+	cur = xfs_rmapbt_init_common(mp, tp, pag);
 	cur->bc_nlevels = be32_to_cpu(agf->agf_levels[XFS_BTNUM_RMAP]);
 	cur->bc_ag.agbp = agbp;
 	return cur;
@@ -496,11 +491,11 @@ struct xfs_btree_cur *
 xfs_rmapbt_stage_cursor(
 	struct xfs_mount	*mp,
 	struct xbtree_afakeroot	*afake,
-	xfs_agnumber_t		agno)
+	struct xfs_perag	*pag)
 {
 	struct xfs_btree_cur	*cur;
 
-	cur = xfs_rmapbt_init_common(mp, NULL, agno, NULL);
+	cur = xfs_rmapbt_init_common(mp, NULL, pag);
 	xfs_btree_stage_afakeroot(cur, afake);
 	return cur;
 }
diff --git a/fs/xfs/libxfs/xfs_rmap_btree.h b/fs/xfs/libxfs/xfs_rmap_btree.h
index c94f418cc06b..88d8d18788a2 100644
--- a/fs/xfs/libxfs/xfs_rmap_btree.h
+++ b/fs/xfs/libxfs/xfs_rmap_btree.h
@@ -43,9 +43,9 @@ struct xbtree_afakeroot;
 
 struct xfs_btree_cur *xfs_rmapbt_init_cursor(struct xfs_mount *mp,
 				struct xfs_trans *tp, struct xfs_buf *bp,
-				xfs_agnumber_t agno, struct xfs_perag *pag);
+				struct xfs_perag *pag);
 struct xfs_btree_cur *xfs_rmapbt_stage_cursor(struct xfs_mount *mp,
-		struct xbtree_afakeroot *afake, xfs_agnumber_t agno);
+		struct xbtree_afakeroot *afake, struct xfs_perag *pag);
 void xfs_rmapbt_commit_staged_btree(struct xfs_btree_cur *cur,
 		struct xfs_trans *tp, struct xfs_buf *agbp);
 int xfs_rmapbt_maxrecs(int blocklen, int leaf);
diff --git a/fs/xfs/scrub/agheader_repair.c b/fs/xfs/scrub/agheader_repair.c
index 5dd91bf04c18..981c689e3d95 100644
--- a/fs/xfs/scrub/agheader_repair.c
+++ b/fs/xfs/scrub/agheader_repair.c
@@ -269,8 +269,7 @@ xrep_agf_calc_from_btrees(
 	btreeblks += blocks - 1;
 
 	/* Update the AGF counters from the rmapbt. */
-	cur = xfs_rmapbt_init_cursor(mp, sc->tp, agf_bp, sc->sa.agno,
-			sc->sa.pag);
+	cur = xfs_rmapbt_init_cursor(mp, sc->tp, agf_bp, sc->sa.pag);
 	error = xfs_btree_count_blocks(cur, &blocks);
 	if (error)
 		goto err;
@@ -491,8 +490,7 @@ xrep_agfl_collect_blocks(
 	xbitmap_init(&ra.agmetablocks);
 
 	/* Find all space used by the free space btrees & rmapbt. */
-	cur = xfs_rmapbt_init_cursor(mp, sc->tp, agf_bp, sc->sa.agno,
-			sc->sa.pag);
+	cur = xfs_rmapbt_init_cursor(mp, sc->tp, agf_bp, sc->sa.pag);
 	error = xfs_rmap_query_all(cur, xrep_agfl_walk_rmap, &ra);
 	if (error)
 		goto err;
diff --git a/fs/xfs/scrub/bmap.c b/fs/xfs/scrub/bmap.c
index a792d9ffd61e..b20c3f03b3c5 100644
--- a/fs/xfs/scrub/bmap.c
+++ b/fs/xfs/scrub/bmap.c
@@ -556,7 +556,7 @@ xchk_bmap_check_ag_rmaps(
 	if (error)
 		return error;
 
-	cur = xfs_rmapbt_init_cursor(sc->mp, sc->tp, agf, agno, NULL);
+	cur = xfs_rmapbt_init_cursor(sc->mp, sc->tp, agf, sc->sa.pag);
 
 	sbcri.sc = sc;
 	sbcri.whichfork = whichfork;
diff --git a/fs/xfs/scrub/common.c b/fs/xfs/scrub/common.c
index 50768559fb60..48381c1adeed 100644
--- a/fs/xfs/scrub/common.c
+++ b/fs/xfs/scrub/common.c
@@ -493,7 +493,7 @@ xchk_ag_btcur_init(
 	if (sa->agf_bp && xfs_sb_version_hasrmapbt(&mp->m_sb) &&
 	    xchk_ag_btree_healthy_enough(sc, sa->pag, XFS_BTNUM_RMAP)) {
 		sa->rmap_cur = xfs_rmapbt_init_cursor(mp, sc->tp, sa->agf_bp,
-				agno, sa->pag);
+				sa->pag);
 	}
 
 	/* Set up a refcountbt cursor for cross-referencing. */
diff --git a/fs/xfs/scrub/repair.c b/fs/xfs/scrub/repair.c
index 862dc56fd8cd..5cf1c3707b6a 100644
--- a/fs/xfs/scrub/repair.c
+++ b/fs/xfs/scrub/repair.c
@@ -509,7 +509,7 @@ xrep_put_freelist(
 	 * create an rmap for the block prior to merging it or else other
 	 * parts will break.
 	 */
-	error = xfs_rmap_alloc(sc->tp, sc->sa.agf_bp, sc->sa.agno, agbno, 1,
+	error = xfs_rmap_alloc(sc->tp, sc->sa.agf_bp, sc->sa.pag, agbno, 1,
 			&XFS_RMAP_OINFO_AG);
 	if (error)
 		return error;
@@ -555,7 +555,7 @@ xrep_reap_block(
 	} else {
 		agf_bp = sc->sa.agf_bp;
 	}
-	cur = xfs_rmapbt_init_cursor(sc->mp, sc->tp, agf_bp, agno, sc->sa.pag);
+	cur = xfs_rmapbt_init_cursor(sc->mp, sc->tp, agf_bp, sc->sa.pag);
 
 	/* Can we find any other rmappings? */
 	error = xfs_rmap_has_other_keys(cur, agbno, 1, oinfo, &has_other_rmap);
@@ -577,7 +577,8 @@ xrep_reap_block(
 	 * to run xfs_repair.
 	 */
 	if (has_other_rmap)
-		error = xfs_rmap_free(sc->tp, agf_bp, agno, agbno, 1, oinfo);
+		error = xfs_rmap_free(sc->tp, agf_bp, sc->sa.pag, agbno,
+					1, oinfo);
 	else if (resv == XFS_AG_RESV_AGFL)
 		error = xrep_put_freelist(sc, agbno);
 	else
@@ -892,8 +893,7 @@ xrep_find_ag_btree_roots(
 		fab->height = 0;
 	}
 
-	cur = xfs_rmapbt_init_cursor(mp, sc->tp, agf_bp, sc->sa.agno,
-			sc->sa.pag);
+	cur = xfs_rmapbt_init_cursor(mp, sc->tp, agf_bp, sc->sa.pag);
 	error = xfs_rmap_query_all(cur, xrep_findroot_rmap, &ri);
 	xfs_btree_del_cursor(cur, error);
 
diff --git a/fs/xfs/xfs_fsmap.c b/fs/xfs/xfs_fsmap.c
index b654a2bf9a9f..7bfe9ea35de0 100644
--- a/fs/xfs/xfs_fsmap.c
+++ b/fs/xfs/xfs_fsmap.c
@@ -708,7 +708,7 @@ xfs_getfsmap_datadev_rmapbt_query(
 
 	/* Allocate cursor for this AG and query_range it. */
 	*curpp = xfs_rmapbt_init_cursor(tp->t_mountp, tp, info->agf_bp,
-			info->pag->pag_agno, info->pag);
+			info->pag);
 	return xfs_rmap_query_range(*curpp, &info->low, &info->high,
 			xfs_getfsmap_datadev_helper, info);
 }
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 87+ messages in thread

* [PATCH 13/22] xfs: convert refcount btree cursor to use perags
  2021-05-06  7:20 [RFC 00/22] xfs: initial agnumber -> perag conversions for shrink Dave Chinner
                   ` (11 preceding siblings ...)
  2021-05-06  7:20 ` [PATCH 12/22] xfs: convert rmap btree cursor to using a perag Dave Chinner
@ 2021-05-06  7:20 ` Dave Chinner
  2021-05-11 12:30   ` Brian Foster
  2021-05-12 22:47   ` Darrick J. Wong
  2021-05-06  7:20 ` [PATCH 14/22] xfs: convert allocbt cursors " Dave Chinner
                   ` (8 subsequent siblings)
  21 siblings, 2 replies; 87+ messages in thread
From: Dave Chinner @ 2021-05-06  7:20 UTC (permalink / raw)
  To: linux-xfs

From: Dave Chinner <dchinner@redhat.com>

Signed-off-by: Dave Chinner <dchinner@redhat.com>
---
 fs/xfs/libxfs/xfs_refcount.c       | 39 +++++++++++++++++-------------
 fs/xfs/libxfs/xfs_refcount.h       |  9 ++++++-
 fs/xfs/libxfs/xfs_refcount_btree.c | 22 +++++++----------
 fs/xfs/libxfs/xfs_refcount_btree.h |  4 +--
 fs/xfs/scrub/agheader_repair.c     |  2 +-
 fs/xfs/scrub/bmap.c                |  8 +++---
 fs/xfs/scrub/common.c              |  2 +-
 fs/xfs/xfs_fsmap.c                 |  3 +--
 fs/xfs/xfs_reflink.c               |  4 +--
 9 files changed, 50 insertions(+), 43 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_refcount.c b/fs/xfs/libxfs/xfs_refcount.c
index 1c2bd2949d7d..3c2b99cbd57d 100644
--- a/fs/xfs/libxfs/xfs_refcount.c
+++ b/fs/xfs/libxfs/xfs_refcount.c
@@ -22,6 +22,7 @@
 #include "xfs_bit.h"
 #include "xfs_refcount.h"
 #include "xfs_rmap.h"
+#include "xfs_ag.h"
 
 /* Allowable refcount adjustment amounts. */
 enum xfs_refc_adjust_op {
@@ -1142,14 +1143,13 @@ xfs_refcount_finish_one(
 	struct xfs_btree_cur		*rcur;
 	struct xfs_buf			*agbp = NULL;
 	int				error = 0;
-	xfs_agnumber_t			agno;
 	xfs_agblock_t			bno;
 	xfs_agblock_t			new_agbno;
 	unsigned long			nr_ops = 0;
 	int				shape_changes = 0;
+	struct xfs_perag		*pag;
 
-	agno = XFS_FSB_TO_AGNO(mp, startblock);
-	ASSERT(agno != NULLAGNUMBER);
+	pag = xfs_perag_get(mp, XFS_FSB_TO_AGNO(mp, startblock));
 	bno = XFS_FSB_TO_AGBNO(mp, startblock);
 
 	trace_xfs_refcount_deferred(mp, XFS_FSB_TO_AGNO(mp, startblock),
@@ -1157,15 +1157,17 @@ xfs_refcount_finish_one(
 			blockcount);
 
 	if (XFS_TEST_ERROR(false, mp,
-			XFS_ERRTAG_REFCOUNT_FINISH_ONE))
-		return -EIO;
+			XFS_ERRTAG_REFCOUNT_FINISH_ONE)) {
+		error = -EIO;
+		goto out_drop;
+	}
 
 	/*
 	 * If we haven't gotten a cursor or the cursor AG doesn't match
 	 * the startblock, get one now.
 	 */
 	rcur = *pcur;
-	if (rcur != NULL && rcur->bc_ag.agno != agno) {
+	if (rcur != NULL && rcur->bc_ag.pag != pag) {
 		nr_ops = rcur->bc_ag.refc.nr_ops;
 		shape_changes = rcur->bc_ag.refc.shape_changes;
 		xfs_refcount_finish_one_cleanup(tp, rcur, 0);
@@ -1173,12 +1175,12 @@ xfs_refcount_finish_one(
 		*pcur = NULL;
 	}
 	if (rcur == NULL) {
-		error = xfs_alloc_read_agf(tp->t_mountp, tp, agno,
+		error = xfs_alloc_read_agf(tp->t_mountp, tp, pag->pag_agno,
 				XFS_ALLOC_FLAG_FREEING, &agbp);
 		if (error)
-			return error;
+			goto out_drop;
 
-		rcur = xfs_refcountbt_init_cursor(mp, tp, agbp, agno, NULL);
+		rcur = xfs_refcountbt_init_cursor(mp, tp, agbp, pag);
 		rcur->bc_ag.refc.nr_ops = nr_ops;
 		rcur->bc_ag.refc.shape_changes = shape_changes;
 	}
@@ -1188,12 +1190,12 @@ xfs_refcount_finish_one(
 	case XFS_REFCOUNT_INCREASE:
 		error = xfs_refcount_adjust(rcur, bno, blockcount, &new_agbno,
 			new_len, XFS_REFCOUNT_ADJUST_INCREASE, NULL);
-		*new_fsb = XFS_AGB_TO_FSB(mp, agno, new_agbno);
+		*new_fsb = XFS_AGB_TO_FSB(mp, pag->pag_agno, new_agbno);
 		break;
 	case XFS_REFCOUNT_DECREASE:
 		error = xfs_refcount_adjust(rcur, bno, blockcount, &new_agbno,
 			new_len, XFS_REFCOUNT_ADJUST_DECREASE, NULL);
-		*new_fsb = XFS_AGB_TO_FSB(mp, agno, new_agbno);
+		*new_fsb = XFS_AGB_TO_FSB(mp, pag->pag_agno, new_agbno);
 		break;
 	case XFS_REFCOUNT_ALLOC_COW:
 		*new_fsb = startblock + blockcount;
@@ -1210,8 +1212,10 @@ xfs_refcount_finish_one(
 		error = -EFSCORRUPTED;
 	}
 	if (!error && *new_len > 0)
-		trace_xfs_refcount_finish_one_leftover(mp, agno, type,
+		trace_xfs_refcount_finish_one_leftover(mp, pag->pag_agno, type,
 				bno, blockcount, new_agbno, *new_len);
+out_drop:
+	xfs_perag_put(pag);
 	return error;
 }
 
@@ -1672,7 +1676,7 @@ xfs_refcount_recover_extent(
 int
 xfs_refcount_recover_cow_leftovers(
 	struct xfs_mount		*mp,
-	xfs_agnumber_t			agno)
+	struct xfs_perag		*pag)
 {
 	struct xfs_trans		*tp;
 	struct xfs_btree_cur		*cur;
@@ -1704,10 +1708,10 @@ xfs_refcount_recover_cow_leftovers(
 	if (error)
 		return error;
 
-	error = xfs_alloc_read_agf(mp, tp, agno, 0, &agbp);
+	error = xfs_alloc_read_agf(mp, tp, pag->pag_agno, 0, &agbp);
 	if (error)
 		goto out_trans;
-	cur = xfs_refcountbt_init_cursor(mp, tp, agbp, agno, NULL);
+	cur = xfs_refcountbt_init_cursor(mp, tp, agbp, pag);
 
 	/* Find all the leftover CoW staging extents. */
 	memset(&low, 0, sizeof(low));
@@ -1729,11 +1733,12 @@ xfs_refcount_recover_cow_leftovers(
 		if (error)
 			goto out_free;
 
-		trace_xfs_refcount_recover_extent(mp, agno, &rr->rr_rrec);
+		trace_xfs_refcount_recover_extent(mp, pag->pag_agno,
+				&rr->rr_rrec);
 
 		/* Free the orphan record */
 		agbno = rr->rr_rrec.rc_startblock - XFS_REFC_COW_START;
-		fsb = XFS_AGB_TO_FSB(mp, agno, agbno);
+		fsb = XFS_AGB_TO_FSB(mp, pag->pag_agno, agbno);
 		xfs_refcount_free_cow_extent(tp, fsb,
 				rr->rr_rrec.rc_blockcount);
 
diff --git a/fs/xfs/libxfs/xfs_refcount.h b/fs/xfs/libxfs/xfs_refcount.h
index 209795539c8d..9f6e9aae4da0 100644
--- a/fs/xfs/libxfs/xfs_refcount.h
+++ b/fs/xfs/libxfs/xfs_refcount.h
@@ -6,6 +6,13 @@
 #ifndef __XFS_REFCOUNT_H__
 #define __XFS_REFCOUNT_H__
 
+struct xfs_trans;
+struct xfs_mount;
+struct xfs_perag;
+struct xfs_btree_cur;
+struct xfs_bmbt_irec;
+struct xfs_refcount_irec;
+
 extern int xfs_refcount_lookup_le(struct xfs_btree_cur *cur,
 		xfs_agblock_t bno, int *stat);
 extern int xfs_refcount_lookup_ge(struct xfs_btree_cur *cur,
@@ -50,7 +57,7 @@ void xfs_refcount_alloc_cow_extent(struct xfs_trans *tp, xfs_fsblock_t fsb,
 void xfs_refcount_free_cow_extent(struct xfs_trans *tp, xfs_fsblock_t fsb,
 		xfs_extlen_t len);
 extern int xfs_refcount_recover_cow_leftovers(struct xfs_mount *mp,
-		xfs_agnumber_t agno);
+		struct xfs_perag *pag);
 
 /*
  * While we're adjusting the refcounts records of an extent, we have
diff --git a/fs/xfs/libxfs/xfs_refcount_btree.c b/fs/xfs/libxfs/xfs_refcount_btree.c
index 74f8ac0209f1..8f6577cb3475 100644
--- a/fs/xfs/libxfs/xfs_refcount_btree.c
+++ b/fs/xfs/libxfs/xfs_refcount_btree.c
@@ -26,7 +26,7 @@ xfs_refcountbt_dup_cursor(
 	struct xfs_btree_cur	*cur)
 {
 	return xfs_refcountbt_init_cursor(cur->bc_mp, cur->bc_tp,
-			cur->bc_ag.agbp, cur->bc_ag.agno, cur->bc_ag.pag);
+			cur->bc_ag.agbp, cur->bc_ag.pag);
 }
 
 STATIC void
@@ -316,13 +316,11 @@ static struct xfs_btree_cur *
 xfs_refcountbt_init_common(
 	struct xfs_mount	*mp,
 	struct xfs_trans	*tp,
-	xfs_agnumber_t		agno,
 	struct xfs_perag	*pag)
 {
 	struct xfs_btree_cur	*cur;
 
-	ASSERT(agno != NULLAGNUMBER);
-	ASSERT(agno < mp->m_sb.sb_agcount);
+	ASSERT(pag->pag_agno < mp->m_sb.sb_agcount);
 
 	cur = kmem_cache_zalloc(xfs_btree_cur_zone, GFP_NOFS | __GFP_NOFAIL);
 	cur->bc_tp = tp;
@@ -331,13 +329,12 @@ xfs_refcountbt_init_common(
 	cur->bc_blocklog = mp->m_sb.sb_blocklog;
 	cur->bc_statoff = XFS_STATS_CALC_INDEX(xs_refcbt_2);
 
-	cur->bc_ag.agno = agno;
 	cur->bc_flags |= XFS_BTREE_CRC_BLOCKS;
-	if (pag) {
-		/* take a reference for the cursor */
-		atomic_inc(&pag->pag_ref);
-	}
+
+	/* take a reference for the cursor */
+	atomic_inc(&pag->pag_ref);
 	cur->bc_ag.pag = pag;
+	cur->bc_ag.agno = pag->pag_agno;
 
 	cur->bc_ag.refc.nr_ops = 0;
 	cur->bc_ag.refc.shape_changes = 0;
@@ -351,13 +348,12 @@ xfs_refcountbt_init_cursor(
 	struct xfs_mount	*mp,
 	struct xfs_trans	*tp,
 	struct xfs_buf		*agbp,
-	xfs_agnumber_t		agno,
 	struct xfs_perag	*pag)
 {
 	struct xfs_agf		*agf = agbp->b_addr;
 	struct xfs_btree_cur	*cur;
 
-	cur = xfs_refcountbt_init_common(mp, tp, agno, pag);
+	cur = xfs_refcountbt_init_common(mp, tp, pag);
 	cur->bc_nlevels = be32_to_cpu(agf->agf_refcount_level);
 	cur->bc_ag.agbp = agbp;
 	return cur;
@@ -368,11 +364,11 @@ struct xfs_btree_cur *
 xfs_refcountbt_stage_cursor(
 	struct xfs_mount	*mp,
 	struct xbtree_afakeroot	*afake,
-	xfs_agnumber_t		agno)
+	struct xfs_perag	*pag)
 {
 	struct xfs_btree_cur	*cur;
 
-	cur = xfs_refcountbt_init_common(mp, NULL, agno, NULL);
+	cur = xfs_refcountbt_init_common(mp, NULL, pag);
 	xfs_btree_stage_afakeroot(cur, afake);
 	return cur;
 }
diff --git a/fs/xfs/libxfs/xfs_refcount_btree.h b/fs/xfs/libxfs/xfs_refcount_btree.h
index 8b82a39f104a..bd9ed9e1e41f 100644
--- a/fs/xfs/libxfs/xfs_refcount_btree.h
+++ b/fs/xfs/libxfs/xfs_refcount_btree.h
@@ -47,9 +47,9 @@ struct xbtree_afakeroot;
 
 extern struct xfs_btree_cur *xfs_refcountbt_init_cursor(struct xfs_mount *mp,
 		struct xfs_trans *tp, struct xfs_buf *agbp,
-		xfs_agnumber_t agno, struct xfs_perag *pag);
+		struct xfs_perag *pag);
 struct xfs_btree_cur *xfs_refcountbt_stage_cursor(struct xfs_mount *mp,
-		struct xbtree_afakeroot *afake, xfs_agnumber_t agno);
+		struct xbtree_afakeroot *afake, struct xfs_perag *pag);
 extern int xfs_refcountbt_maxrecs(int blocklen, bool leaf);
 extern void xfs_refcountbt_compute_maxlevels(struct xfs_mount *mp);
 
diff --git a/fs/xfs/scrub/agheader_repair.c b/fs/xfs/scrub/agheader_repair.c
index 981c689e3d95..251410c19198 100644
--- a/fs/xfs/scrub/agheader_repair.c
+++ b/fs/xfs/scrub/agheader_repair.c
@@ -282,7 +282,7 @@ xrep_agf_calc_from_btrees(
 	/* Update the AGF counters from the refcountbt. */
 	if (xfs_sb_version_hasreflink(&mp->m_sb)) {
 		cur = xfs_refcountbt_init_cursor(mp, sc->tp, agf_bp,
-				sc->sa.agno, sc->sa.pag);
+				sc->sa.pag);
 		error = xfs_btree_count_blocks(cur, &blocks);
 		if (error)
 			goto err;
diff --git a/fs/xfs/scrub/bmap.c b/fs/xfs/scrub/bmap.c
index b20c3f03b3c5..5adef162115d 100644
--- a/fs/xfs/scrub/bmap.c
+++ b/fs/xfs/scrub/bmap.c
@@ -545,18 +545,18 @@ STATIC int
 xchk_bmap_check_ag_rmaps(
 	struct xfs_scrub		*sc,
 	int				whichfork,
-	xfs_agnumber_t			agno)
+	struct xfs_perag		*pag)
 {
 	struct xchk_bmap_check_rmap_info	sbcri;
 	struct xfs_btree_cur		*cur;
 	struct xfs_buf			*agf;
 	int				error;
 
-	error = xfs_alloc_read_agf(sc->mp, sc->tp, agno, 0, &agf);
+	error = xfs_alloc_read_agf(sc->mp, sc->tp, pag->pag_agno, 0, &agf);
 	if (error)
 		return error;
 
-	cur = xfs_rmapbt_init_cursor(sc->mp, sc->tp, agf, sc->sa.pag);
+	cur = xfs_rmapbt_init_cursor(sc->mp, sc->tp, agf, pag);
 
 	sbcri.sc = sc;
 	sbcri.whichfork = whichfork;
@@ -610,7 +610,7 @@ xchk_bmap_check_rmaps(
 		return 0;
 
 	for_each_perag(sc->mp, agno, pag) {
-		error = xchk_bmap_check_ag_rmaps(sc, whichfork, pag->pag_agno);
+		error = xchk_bmap_check_ag_rmaps(sc, whichfork, pag);
 		if (error)
 			return error;
 		if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
diff --git a/fs/xfs/scrub/common.c b/fs/xfs/scrub/common.c
index 48381c1adeed..cc7688ce79b2 100644
--- a/fs/xfs/scrub/common.c
+++ b/fs/xfs/scrub/common.c
@@ -500,7 +500,7 @@ xchk_ag_btcur_init(
 	if (sa->agf_bp && xfs_sb_version_hasreflink(&mp->m_sb) &&
 	    xchk_ag_btree_healthy_enough(sc, sa->pag, XFS_BTNUM_REFC)) {
 		sa->refc_cur = xfs_refcountbt_init_cursor(mp, sc->tp,
-				sa->agf_bp, agno, sa->pag);
+				sa->agf_bp, sa->pag);
 	}
 }
 
diff --git a/fs/xfs/xfs_fsmap.c b/fs/xfs/xfs_fsmap.c
index 7bfe9ea35de0..623cabaeafee 100644
--- a/fs/xfs/xfs_fsmap.c
+++ b/fs/xfs/xfs_fsmap.c
@@ -210,8 +210,7 @@ xfs_getfsmap_is_shared(
 
 	/* Are there any shared blocks here? */
 	flen = 0;
-	cur = xfs_refcountbt_init_cursor(mp, tp, info->agf_bp,
-			info->pag->pag_agno, info->pag);
+	cur = xfs_refcountbt_init_cursor(mp, tp, info->agf_bp, info->pag);
 
 	error = xfs_refcount_find_shared(cur, rec->rm_startblock,
 			rec->rm_blockcount, &fbno, &flen, false);
diff --git a/fs/xfs/xfs_reflink.c b/fs/xfs/xfs_reflink.c
index 28ffe1817f9b..c256104772cb 100644
--- a/fs/xfs/xfs_reflink.c
+++ b/fs/xfs/xfs_reflink.c
@@ -144,7 +144,7 @@ xfs_reflink_find_shared(
 	if (error)
 		return error;
 
-	cur = xfs_refcountbt_init_cursor(mp, tp, agbp, agno, NULL);
+	cur = xfs_refcountbt_init_cursor(mp, tp, agbp, agbp->b_pag);
 
 	error = xfs_refcount_find_shared(cur, agbno, aglen, fbno, flen,
 			find_end_of_shared);
@@ -763,7 +763,7 @@ xfs_reflink_recover_cow(
 		return 0;
 
 	for_each_perag(mp, agno, pag) {
-		error = xfs_refcount_recover_cow_leftovers(mp, pag->pag_agno);
+		error = xfs_refcount_recover_cow_leftovers(mp, pag);
 		if (error) {
 			xfs_perag_put(pag);
 			break;
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 87+ messages in thread

* [PATCH 14/22] xfs: convert allocbt cursors to use perags
  2021-05-06  7:20 [RFC 00/22] xfs: initial agnumber -> perag conversions for shrink Dave Chinner
                   ` (12 preceding siblings ...)
  2021-05-06  7:20 ` [PATCH 13/22] xfs: convert refcount btree cursor to use perags Dave Chinner
@ 2021-05-06  7:20 ` Dave Chinner
  2021-05-11 12:30   ` Brian Foster
  2021-05-13  3:55   ` Darrick J. Wong
  2021-05-06  7:20 ` [PATCH 15/22] xfs: use perag for ialloc btree cursors Dave Chinner
                   ` (7 subsequent siblings)
  21 siblings, 2 replies; 87+ messages in thread
From: Dave Chinner @ 2021-05-06  7:20 UTC (permalink / raw)
  To: linux-xfs

From: Dave Chinner <dchinner@redhat.com>

Signed-off-by: Dave Chinner <dchinner@redhat.com>
---
 fs/xfs/libxfs/xfs_alloc.c       | 25 ++++++++++---------------
 fs/xfs/libxfs/xfs_alloc_btree.c | 26 ++++++++++----------------
 fs/xfs/libxfs/xfs_alloc_btree.h |  8 ++++----
 fs/xfs/scrub/agheader_repair.c  |  8 ++++----
 fs/xfs/scrub/common.c           |  4 ++--
 fs/xfs/xfs_discard.c            |  2 +-
 fs/xfs/xfs_fsmap.c              |  2 +-
 7 files changed, 32 insertions(+), 43 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_alloc.c b/fs/xfs/libxfs/xfs_alloc.c
index 10747cc4d8f6..c99a80286efa 100644
--- a/fs/xfs/libxfs/xfs_alloc.c
+++ b/fs/xfs/libxfs/xfs_alloc.c
@@ -776,8 +776,7 @@ xfs_alloc_cur_setup(
 	 */
 	if (!acur->cnt)
 		acur->cnt = xfs_allocbt_init_cursor(args->mp, args->tp,
-						args->agbp, args->agno,
-						args->pag, XFS_BTNUM_CNT);
+					args->agbp, args->pag, XFS_BTNUM_CNT);
 	error = xfs_alloc_lookup_ge(acur->cnt, 0, args->maxlen, &i);
 	if (error)
 		return error;
@@ -787,12 +786,10 @@ xfs_alloc_cur_setup(
 	 */
 	if (!acur->bnolt)
 		acur->bnolt = xfs_allocbt_init_cursor(args->mp, args->tp,
-						args->agbp, args->agno,
-						args->pag, XFS_BTNUM_BNO);
+					args->agbp, args->pag, XFS_BTNUM_BNO);
 	if (!acur->bnogt)
 		acur->bnogt = xfs_allocbt_init_cursor(args->mp, args->tp,
-						args->agbp, args->agno,
-						args->pag, XFS_BTNUM_BNO);
+					args->agbp, args->pag, XFS_BTNUM_BNO);
 	return i == 1 ? 0 : -ENOSPC;
 }
 
@@ -1220,7 +1217,7 @@ xfs_alloc_ag_vextent_exact(
 	 * Allocate/initialize a cursor for the by-number freespace btree.
 	 */
 	bno_cur = xfs_allocbt_init_cursor(args->mp, args->tp, args->agbp,
-					  args->agno, args->pag, XFS_BTNUM_BNO);
+					  args->pag, XFS_BTNUM_BNO);
 
 	/*
 	 * Lookup bno and minlen in the btree (minlen is irrelevant, really).
@@ -1280,7 +1277,7 @@ xfs_alloc_ag_vextent_exact(
 	 * Allocate/initialize a cursor for the by-size btree.
 	 */
 	cnt_cur = xfs_allocbt_init_cursor(args->mp, args->tp, args->agbp,
-					args->agno, args->pag, XFS_BTNUM_CNT);
+					args->pag, XFS_BTNUM_CNT);
 	ASSERT(args->agbno + args->len <= be32_to_cpu(agf->agf_length));
 	error = xfs_alloc_fixup_trees(cnt_cur, bno_cur, fbno, flen, args->agbno,
 				      args->len, XFSA_FIXUP_BNO_OK);
@@ -1677,7 +1674,7 @@ xfs_alloc_ag_vextent_size(
 	 * Allocate and initialize a cursor for the by-size btree.
 	 */
 	cnt_cur = xfs_allocbt_init_cursor(args->mp, args->tp, args->agbp,
-					args->agno, args->pag, XFS_BTNUM_CNT);
+					args->pag, XFS_BTNUM_CNT);
 	bno_cur = NULL;
 	busy = false;
 
@@ -1840,7 +1837,7 @@ xfs_alloc_ag_vextent_size(
 	 * Allocate and initialize a cursor for the by-block tree.
 	 */
 	bno_cur = xfs_allocbt_init_cursor(args->mp, args->tp, args->agbp,
-					args->agno, args->pag, XFS_BTNUM_BNO);
+					args->pag, XFS_BTNUM_BNO);
 	if ((error = xfs_alloc_fixup_trees(cnt_cur, bno_cur, fbno, flen,
 			rbno, rlen, XFSA_FIXUP_CNT_OK)))
 		goto error0;
@@ -1913,8 +1910,7 @@ xfs_free_ag_extent(
 	/*
 	 * Allocate and initialize a cursor for the by-block btree.
 	 */
-	bno_cur = xfs_allocbt_init_cursor(mp, tp, agbp, agno,
-					NULL, XFS_BTNUM_BNO);
+	bno_cur = xfs_allocbt_init_cursor(mp, tp, agbp, pag, XFS_BTNUM_BNO);
 	/*
 	 * Look for a neighboring block on the left (lower block numbers)
 	 * that is contiguous with this space.
@@ -1984,8 +1980,7 @@ xfs_free_ag_extent(
 	/*
 	 * Now allocate and initialize a cursor for the by-size tree.
 	 */
-	cnt_cur = xfs_allocbt_init_cursor(mp, tp, agbp, agno,
-					NULL, XFS_BTNUM_CNT);
+	cnt_cur = xfs_allocbt_init_cursor(mp, tp, agbp, pag, XFS_BTNUM_CNT);
 	/*
 	 * Have both left and right contiguous neighbors.
 	 * Merge all three into a single free block.
@@ -2496,7 +2491,7 @@ xfs_exact_minlen_extent_available(
 	int			error = 0;
 
 	cnt_cur = xfs_allocbt_init_cursor(args->mp, args->tp, agbp,
-					args->agno, args->pag, XFS_BTNUM_CNT);
+					args->pag, XFS_BTNUM_CNT);
 	error = xfs_alloc_lookup_ge(cnt_cur, 0, args->minlen, stat);
 	if (error)
 		goto out;
diff --git a/fs/xfs/libxfs/xfs_alloc_btree.c b/fs/xfs/libxfs/xfs_alloc_btree.c
index a52ab25bbf0b..0c2e4cff4ee3 100644
--- a/fs/xfs/libxfs/xfs_alloc_btree.c
+++ b/fs/xfs/libxfs/xfs_alloc_btree.c
@@ -26,8 +26,7 @@ xfs_allocbt_dup_cursor(
 	struct xfs_btree_cur	*cur)
 {
 	return xfs_allocbt_init_cursor(cur->bc_mp, cur->bc_tp,
-			cur->bc_ag.agbp, cur->bc_ag.agno,
-			cur->bc_ag.pag, cur->bc_btnum);
+			cur->bc_ag.agbp, cur->bc_ag.pag, cur->bc_btnum);
 }
 
 STATIC void
@@ -39,13 +38,12 @@ xfs_allocbt_set_root(
 	struct xfs_buf		*agbp = cur->bc_ag.agbp;
 	struct xfs_agf		*agf = agbp->b_addr;
 	int			btnum = cur->bc_btnum;
-	struct xfs_perag	*pag = agbp->b_pag;
 
 	ASSERT(ptr->s != 0);
 
 	agf->agf_roots[btnum] = ptr->s;
 	be32_add_cpu(&agf->agf_levels[btnum], inc);
-	pag->pagf_levels[btnum] += inc;
+	cur->bc_ag.pag->pagf_levels[btnum] += inc;
 
 	xfs_alloc_log_agf(cur->bc_tp, agbp, XFS_AGF_ROOTS | XFS_AGF_LEVELS);
 }
@@ -224,7 +222,7 @@ xfs_allocbt_init_ptr_from_cur(
 {
 	struct xfs_agf		*agf = cur->bc_ag.agbp->b_addr;
 
-	ASSERT(cur->bc_ag.agno == be32_to_cpu(agf->agf_seqno));
+	ASSERT(cur->bc_ag.pag->pag_agno == be32_to_cpu(agf->agf_seqno));
 
 	ptr->s = agf->agf_roots[cur->bc_btnum];
 }
@@ -472,7 +470,6 @@ STATIC struct xfs_btree_cur *
 xfs_allocbt_init_common(
 	struct xfs_mount	*mp,
 	struct xfs_trans	*tp,
-	xfs_agnumber_t		agno,
 	struct xfs_perag	*pag,
 	xfs_btnum_t		btnum)
 {
@@ -486,6 +483,7 @@ xfs_allocbt_init_common(
 	cur->bc_mp = mp;
 	cur->bc_btnum = btnum;
 	cur->bc_blocklog = mp->m_sb.sb_blocklog;
+	cur->bc_ag.abt.active = false;
 
 	if (btnum == XFS_BTNUM_CNT) {
 		cur->bc_ops = &xfs_cntbt_ops;
@@ -496,13 +494,10 @@ xfs_allocbt_init_common(
 		cur->bc_statoff = XFS_STATS_CALC_INDEX(xs_abtb_2);
 	}
 
-	cur->bc_ag.agno = agno;
-	cur->bc_ag.abt.active = false;
-	if (pag) {
-		/* take a reference for the cursor */
-		atomic_inc(&pag->pag_ref);
-	}
+	/* take a reference for the cursor */
+	atomic_inc(&pag->pag_ref);
 	cur->bc_ag.pag = pag;
+	cur->bc_ag.agno = pag->pag_agno;
 
 	if (xfs_sb_version_hascrc(&mp->m_sb))
 		cur->bc_flags |= XFS_BTREE_CRC_BLOCKS;
@@ -518,14 +513,13 @@ xfs_allocbt_init_cursor(
 	struct xfs_mount	*mp,		/* file system mount point */
 	struct xfs_trans	*tp,		/* transaction pointer */
 	struct xfs_buf		*agbp,		/* buffer for agf structure */
-	xfs_agnumber_t		agno,		/* allocation group number */
 	struct xfs_perag	*pag,
 	xfs_btnum_t		btnum)		/* btree identifier */
 {
 	struct xfs_agf		*agf = agbp->b_addr;
 	struct xfs_btree_cur	*cur;
 
-	cur = xfs_allocbt_init_common(mp, tp, agno, pag, btnum);
+	cur = xfs_allocbt_init_common(mp, tp, pag, btnum);
 	if (btnum == XFS_BTNUM_CNT)
 		cur->bc_nlevels = be32_to_cpu(agf->agf_levels[XFS_BTNUM_CNT]);
 	else
@@ -541,12 +535,12 @@ struct xfs_btree_cur *
 xfs_allocbt_stage_cursor(
 	struct xfs_mount	*mp,
 	struct xbtree_afakeroot	*afake,
-	xfs_agnumber_t		agno,
+	struct xfs_perag	*pag,
 	xfs_btnum_t		btnum)
 {
 	struct xfs_btree_cur	*cur;
 
-	cur = xfs_allocbt_init_common(mp, NULL, agno, NULL, btnum);
+	cur = xfs_allocbt_init_common(mp, NULL, pag, btnum);
 	xfs_btree_stage_afakeroot(cur, afake);
 	return cur;
 }
diff --git a/fs/xfs/libxfs/xfs_alloc_btree.h b/fs/xfs/libxfs/xfs_alloc_btree.h
index a10cedba18d8..9eb4c667a6b8 100644
--- a/fs/xfs/libxfs/xfs_alloc_btree.h
+++ b/fs/xfs/libxfs/xfs_alloc_btree.h
@@ -47,11 +47,11 @@ struct xbtree_afakeroot;
 		 (maxrecs) * sizeof(xfs_alloc_key_t) + \
 		 ((index) - 1) * sizeof(xfs_alloc_ptr_t)))
 
-extern struct xfs_btree_cur *xfs_allocbt_init_cursor(struct xfs_mount *,
-		struct xfs_trans *, struct xfs_buf *,
-		xfs_agnumber_t, struct xfs_perag *pag, xfs_btnum_t);
+extern struct xfs_btree_cur *xfs_allocbt_init_cursor(struct xfs_mount *mp,
+		struct xfs_trans *tp, struct xfs_buf *bp,
+		struct xfs_perag *pag, xfs_btnum_t btnum);
 struct xfs_btree_cur *xfs_allocbt_stage_cursor(struct xfs_mount *mp,
-		struct xbtree_afakeroot *afake, xfs_agnumber_t agno,
+		struct xbtree_afakeroot *afake, struct xfs_perag *pag,
 		xfs_btnum_t btnum);
 extern int xfs_allocbt_maxrecs(struct xfs_mount *, int, int);
 extern xfs_extlen_t xfs_allocbt_calc_size(struct xfs_mount *mp,
diff --git a/fs/xfs/scrub/agheader_repair.c b/fs/xfs/scrub/agheader_repair.c
index 251410c19198..ee2d85e3fd4a 100644
--- a/fs/xfs/scrub/agheader_repair.c
+++ b/fs/xfs/scrub/agheader_repair.c
@@ -246,7 +246,7 @@ xrep_agf_calc_from_btrees(
 	int			error;
 
 	/* Update the AGF counters from the bnobt. */
-	cur = xfs_allocbt_init_cursor(mp, sc->tp, agf_bp, sc->sa.agno,
+	cur = xfs_allocbt_init_cursor(mp, sc->tp, agf_bp,
 			sc->sa.pag, XFS_BTNUM_BNO);
 	error = xfs_alloc_query_all(cur, xrep_agf_walk_allocbt, &raa);
 	if (error)
@@ -260,7 +260,7 @@ xrep_agf_calc_from_btrees(
 	agf->agf_longest = cpu_to_be32(raa.longest);
 
 	/* Update the AGF counters from the cntbt. */
-	cur = xfs_allocbt_init_cursor(mp, sc->tp, agf_bp, sc->sa.agno,
+	cur = xfs_allocbt_init_cursor(mp, sc->tp, agf_bp,
 			sc->sa.pag, XFS_BTNUM_CNT);
 	error = xfs_btree_count_blocks(cur, &blocks);
 	if (error)
@@ -497,7 +497,7 @@ xrep_agfl_collect_blocks(
 	xfs_btree_del_cursor(cur, error);
 
 	/* Find all blocks currently being used by the bnobt. */
-	cur = xfs_allocbt_init_cursor(mp, sc->tp, agf_bp, sc->sa.agno,
+	cur = xfs_allocbt_init_cursor(mp, sc->tp, agf_bp,
 			sc->sa.pag, XFS_BTNUM_BNO);
 	error = xbitmap_set_btblocks(&ra.agmetablocks, cur);
 	if (error)
@@ -505,7 +505,7 @@ xrep_agfl_collect_blocks(
 	xfs_btree_del_cursor(cur, error);
 
 	/* Find all blocks currently being used by the cntbt. */
-	cur = xfs_allocbt_init_cursor(mp, sc->tp, agf_bp, sc->sa.agno,
+	cur = xfs_allocbt_init_cursor(mp, sc->tp, agf_bp,
 			sc->sa.pag, XFS_BTNUM_CNT);
 	error = xbitmap_set_btblocks(&ra.agmetablocks, cur);
 	if (error)
diff --git a/fs/xfs/scrub/common.c b/fs/xfs/scrub/common.c
index cc7688ce79b2..3035f8cee6f6 100644
--- a/fs/xfs/scrub/common.c
+++ b/fs/xfs/scrub/common.c
@@ -465,14 +465,14 @@ xchk_ag_btcur_init(
 	    xchk_ag_btree_healthy_enough(sc, sa->pag, XFS_BTNUM_BNO)) {
 		/* Set up a bnobt cursor for cross-referencing. */
 		sa->bno_cur = xfs_allocbt_init_cursor(mp, sc->tp, sa->agf_bp,
-				agno, sa->pag, XFS_BTNUM_BNO);
+				sa->pag, XFS_BTNUM_BNO);
 	}
 
 	if (sa->agf_bp &&
 	    xchk_ag_btree_healthy_enough(sc, sa->pag, XFS_BTNUM_CNT)) {
 		/* Set up a cntbt cursor for cross-referencing. */
 		sa->cnt_cur = xfs_allocbt_init_cursor(mp, sc->tp, sa->agf_bp,
-				agno, sa->pag, XFS_BTNUM_CNT);
+				sa->pag, XFS_BTNUM_CNT);
 	}
 
 	/* Set up a inobt cursor for cross-referencing. */
diff --git a/fs/xfs/xfs_discard.c b/fs/xfs/xfs_discard.c
index 311ebaad4f5a..736df5660f1f 100644
--- a/fs/xfs/xfs_discard.c
+++ b/fs/xfs/xfs_discard.c
@@ -50,7 +50,7 @@ xfs_trim_extents(
 		goto out_put_perag;
 	agf = agbp->b_addr;
 
-	cur = xfs_allocbt_init_cursor(mp, NULL, agbp, agno, pag, XFS_BTNUM_CNT);
+	cur = xfs_allocbt_init_cursor(mp, NULL, agbp, pag, XFS_BTNUM_CNT);
 
 	/*
 	 * Look up the longest btree in the AGF and start with it.
diff --git a/fs/xfs/xfs_fsmap.c b/fs/xfs/xfs_fsmap.c
index 623cabaeafee..7501dd941a63 100644
--- a/fs/xfs/xfs_fsmap.c
+++ b/fs/xfs/xfs_fsmap.c
@@ -740,7 +740,7 @@ xfs_getfsmap_datadev_bnobt_query(
 
 	/* Allocate cursor for this AG and query_range it. */
 	*curpp = xfs_allocbt_init_cursor(tp->t_mountp, tp, info->agf_bp,
-			info->pag->pag_agno, info->pag, XFS_BTNUM_BNO);
+			info->pag, XFS_BTNUM_BNO);
 	key->ar_startblock = info->low.rm_startblock;
 	key[1].ar_startblock = info->high.rm_startblock;
 	return xfs_alloc_query_range(*curpp, key, &key[1],
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 87+ messages in thread

* [PATCH 15/22] xfs: use perag for ialloc btree cursors
  2021-05-06  7:20 [RFC 00/22] xfs: initial agnumber -> perag conversions for shrink Dave Chinner
                   ` (13 preceding siblings ...)
  2021-05-06  7:20 ` [PATCH 14/22] xfs: convert allocbt cursors " Dave Chinner
@ 2021-05-06  7:20 ` Dave Chinner
  2021-05-11 12:30   ` Brian Foster
  2021-05-13  3:55   ` Darrick J. Wong
  2021-05-06  7:20 ` [PATCH 16/22] xfs: remove agno from btree cursor Dave Chinner
                   ` (6 subsequent siblings)
  21 siblings, 2 replies; 87+ messages in thread
From: Dave Chinner @ 2021-05-06  7:20 UTC (permalink / raw)
  To: linux-xfs

From: Dave Chinner <dchinner@redhat.com>

Signed-off-by: Dave Chinner <dchinner@redhat.com>
---
 fs/xfs/libxfs/xfs_ialloc.c       | 177 ++++++++++++++++---------------
 fs/xfs/libxfs/xfs_ialloc_btree.c |  27 ++---
 fs/xfs/libxfs/xfs_ialloc_btree.h |   6 +-
 fs/xfs/scrub/agheader_repair.c   |   4 +-
 fs/xfs/scrub/common.c            |   5 +-
 fs/xfs/xfs_iwalk.c               |   6 +-
 6 files changed, 109 insertions(+), 116 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_ialloc.c b/fs/xfs/libxfs/xfs_ialloc.c
index 905872bab426..e6f64d41e208 100644
--- a/fs/xfs/libxfs/xfs_ialloc.c
+++ b/fs/xfs/libxfs/xfs_ialloc.c
@@ -172,18 +172,17 @@ xfs_inobt_insert(
 	struct xfs_mount	*mp,
 	struct xfs_trans	*tp,
 	struct xfs_buf		*agbp,
+	struct xfs_perag	*pag,
 	xfs_agino_t		newino,
 	xfs_agino_t		newlen,
 	xfs_btnum_t		btnum)
 {
 	struct xfs_btree_cur	*cur;
-	struct xfs_agi		*agi = agbp->b_addr;
-	xfs_agnumber_t		agno = be32_to_cpu(agi->agi_seqno);
 	xfs_agino_t		thisino;
 	int			i;
 	int			error;
 
-	cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, NULL, btnum);
+	cur = xfs_inobt_init_cursor(mp, tp, agbp, pag, btnum);
 
 	for (thisino = newino;
 	     thisino < newino + newlen;
@@ -520,18 +519,17 @@ xfs_inobt_insert_sprec(
 	struct xfs_mount		*mp,
 	struct xfs_trans		*tp,
 	struct xfs_buf			*agbp,
+	struct xfs_perag		*pag,
 	int				btnum,
 	struct xfs_inobt_rec_incore	*nrec,	/* in/out: new/merged rec. */
 	bool				merge)	/* merge or replace */
 {
 	struct xfs_btree_cur		*cur;
-	struct xfs_agi			*agi = agbp->b_addr;
-	xfs_agnumber_t			agno = be32_to_cpu(agi->agi_seqno);
 	int				error;
 	int				i;
 	struct xfs_inobt_rec_incore	rec;
 
-	cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, NULL, btnum);
+	cur = xfs_inobt_init_cursor(mp, tp, agbp, pag, btnum);
 
 	/* the new record is pre-aligned so we know where to look */
 	error = xfs_inobt_lookup(cur, nrec->ir_startino, XFS_LOOKUP_EQ, &i);
@@ -578,14 +576,14 @@ xfs_inobt_insert_sprec(
 			goto error;
 		}
 
-		trace_xfs_irec_merge_pre(mp, agno, rec.ir_startino,
+		trace_xfs_irec_merge_pre(mp, pag->pag_agno, rec.ir_startino,
 					 rec.ir_holemask, nrec->ir_startino,
 					 nrec->ir_holemask);
 
 		/* merge to nrec to output the updated record */
 		__xfs_inobt_rec_merge(nrec, &rec);
 
-		trace_xfs_irec_merge_post(mp, agno, nrec->ir_startino,
+		trace_xfs_irec_merge_post(mp, pag->pag_agno, nrec->ir_startino,
 					  nrec->ir_holemask);
 
 		error = xfs_inobt_rec_check_count(mp, nrec);
@@ -613,21 +611,20 @@ xfs_inobt_insert_sprec(
 STATIC int
 xfs_ialloc_ag_alloc(
 	struct xfs_trans	*tp,
-	struct xfs_buf		*agbp)
+	struct xfs_buf		*agbp,
+	struct xfs_perag	*pag)
 {
 	struct xfs_agi		*agi;
 	struct xfs_alloc_arg	args;
-	xfs_agnumber_t		agno;
 	int			error;
 	xfs_agino_t		newino;		/* new first inode's number */
 	xfs_agino_t		newlen;		/* new number of inodes */
 	int			isaligned = 0;	/* inode allocation at stripe */
 						/* unit boundary */
 	/* init. to full chunk */
-	uint16_t		allocmask = (uint16_t) -1;
 	struct xfs_inobt_rec_incore rec;
-	struct xfs_perag	*pag;
 	struct xfs_ino_geometry	*igeo = M_IGEO(tp->t_mountp);
+	uint16_t		allocmask = (uint16_t) -1;
 	int			do_sparse = 0;
 
 	memset(&args, 0, sizeof(args));
@@ -660,14 +657,13 @@ xfs_ialloc_ag_alloc(
 	 */
 	agi = agbp->b_addr;
 	newino = be32_to_cpu(agi->agi_newino);
-	agno = be32_to_cpu(agi->agi_seqno);
 	args.agbno = XFS_AGINO_TO_AGBNO(args.mp, newino) +
 		     igeo->ialloc_blks;
 	if (do_sparse)
 		goto sparse_alloc;
 	if (likely(newino != NULLAGINO &&
 		  (args.agbno < be32_to_cpu(agi->agi_length)))) {
-		args.fsbno = XFS_AGB_TO_FSB(args.mp, agno, args.agbno);
+		args.fsbno = XFS_AGB_TO_FSB(args.mp, pag->pag_agno, args.agbno);
 		args.type = XFS_ALLOCTYPE_THIS_BNO;
 		args.prod = 1;
 
@@ -727,7 +723,7 @@ xfs_ialloc_ag_alloc(
 		 * For now, just allocate blocks up front.
 		 */
 		args.agbno = be32_to_cpu(agi->agi_root);
-		args.fsbno = XFS_AGB_TO_FSB(args.mp, agno, args.agbno);
+		args.fsbno = XFS_AGB_TO_FSB(args.mp, pag->pag_agno, args.agbno);
 		/*
 		 * Allocate a fixed-size extent of inodes.
 		 */
@@ -748,7 +744,7 @@ xfs_ialloc_ag_alloc(
 	if (isaligned && args.fsbno == NULLFSBLOCK) {
 		args.type = XFS_ALLOCTYPE_NEAR_BNO;
 		args.agbno = be32_to_cpu(agi->agi_root);
-		args.fsbno = XFS_AGB_TO_FSB(args.mp, agno, args.agbno);
+		args.fsbno = XFS_AGB_TO_FSB(args.mp, pag->pag_agno, args.agbno);
 		args.alignment = igeo->cluster_align;
 		if ((error = xfs_alloc_vextent(&args)))
 			return error;
@@ -764,7 +760,7 @@ xfs_ialloc_ag_alloc(
 sparse_alloc:
 		args.type = XFS_ALLOCTYPE_NEAR_BNO;
 		args.agbno = be32_to_cpu(agi->agi_root);
-		args.fsbno = XFS_AGB_TO_FSB(args.mp, agno, args.agbno);
+		args.fsbno = XFS_AGB_TO_FSB(args.mp, pag->pag_agno, args.agbno);
 		args.alignment = args.mp->m_sb.sb_spino_align;
 		args.prod = 1;
 
@@ -809,7 +805,7 @@ xfs_ialloc_ag_alloc(
 	 * rather than a linear progression to prevent the next generation
 	 * number from being easily guessable.
 	 */
-	error = xfs_ialloc_inode_init(args.mp, tp, NULL, newlen, agno,
+	error = xfs_ialloc_inode_init(args.mp, tp, NULL, newlen, pag->pag_agno,
 			args.agbno, args.len, prandom_u32());
 
 	if (error)
@@ -836,12 +832,12 @@ xfs_ialloc_ag_alloc(
 		 * if necessary. If a merge does occur, rec is updated to the
 		 * merged record.
 		 */
-		error = xfs_inobt_insert_sprec(args.mp, tp, agbp, XFS_BTNUM_INO,
-					       &rec, true);
+		error = xfs_inobt_insert_sprec(args.mp, tp, agbp, pag,
+				XFS_BTNUM_INO, &rec, true);
 		if (error == -EFSCORRUPTED) {
 			xfs_alert(args.mp,
 	"invalid sparse inode record: ino 0x%llx holemask 0x%x count %u",
-				  XFS_AGINO_TO_INO(args.mp, agno,
+				  XFS_AGINO_TO_INO(args.mp, pag->pag_agno,
 						   rec.ir_startino),
 				  rec.ir_holemask, rec.ir_count);
 			xfs_force_shutdown(args.mp, SHUTDOWN_CORRUPT_INCORE);
@@ -861,21 +857,20 @@ xfs_ialloc_ag_alloc(
 		 * existing record with this one.
 		 */
 		if (xfs_sb_version_hasfinobt(&args.mp->m_sb)) {
-			error = xfs_inobt_insert_sprec(args.mp, tp, agbp,
-						       XFS_BTNUM_FINO, &rec,
-						       false);
+			error = xfs_inobt_insert_sprec(args.mp, tp, agbp, pag,
+				       XFS_BTNUM_FINO, &rec, false);
 			if (error)
 				return error;
 		}
 	} else {
 		/* full chunk - insert new records to both btrees */
-		error = xfs_inobt_insert(args.mp, tp, agbp, newino, newlen,
+		error = xfs_inobt_insert(args.mp, tp, agbp, pag, newino, newlen,
 					 XFS_BTNUM_INO);
 		if (error)
 			return error;
 
 		if (xfs_sb_version_hasfinobt(&args.mp->m_sb)) {
-			error = xfs_inobt_insert(args.mp, tp, agbp, newino,
+			error = xfs_inobt_insert(args.mp, tp, agbp, pag, newino,
 						 newlen, XFS_BTNUM_FINO);
 			if (error)
 				return error;
@@ -887,7 +882,6 @@ xfs_ialloc_ag_alloc(
 	 */
 	be32_add_cpu(&agi->agi_count, newlen);
 	be32_add_cpu(&agi->agi_freecount, newlen);
-	pag = agbp->b_pag;
 	pag->pagi_freecount += newlen;
 	pag->pagi_count += newlen;
 	agi->agi_newino = cpu_to_be32(newino);
@@ -1123,15 +1117,14 @@ STATIC int
 xfs_dialloc_ag_inobt(
 	struct xfs_trans	*tp,
 	struct xfs_buf		*agbp,
+	struct xfs_perag	*pag,
 	xfs_ino_t		parent,
 	xfs_ino_t		*inop)
 {
 	struct xfs_mount	*mp = tp->t_mountp;
 	struct xfs_agi		*agi = agbp->b_addr;
-	xfs_agnumber_t		agno = be32_to_cpu(agi->agi_seqno);
 	xfs_agnumber_t		pagno = XFS_INO_TO_AGNO(mp, parent);
 	xfs_agino_t		pagino = XFS_INO_TO_AGINO(mp, parent);
-	struct xfs_perag	*pag = agbp->b_pag;
 	struct xfs_btree_cur	*cur, *tcur;
 	struct xfs_inobt_rec_incore rec, trec;
 	xfs_ino_t		ino;
@@ -1145,7 +1138,7 @@ xfs_dialloc_ag_inobt(
 	ASSERT(pag->pagi_freecount > 0);
 
  restart_pagno:
-	cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, NULL, XFS_BTNUM_INO);
+	cur = xfs_inobt_init_cursor(mp, tp, agbp, pag, XFS_BTNUM_INO);
 	/*
 	 * If pagino is 0 (this is the root inode allocation) use newino.
 	 * This must work because we've just allocated some.
@@ -1160,7 +1153,7 @@ xfs_dialloc_ag_inobt(
 	/*
 	 * If in the same AG as the parent, try to get near the parent.
 	 */
-	if (pagno == agno) {
+	if (pagno == pag->pag_agno) {
 		int		doneleft;	/* done, to the left */
 		int		doneright;	/* done, to the right */
 
@@ -1363,7 +1356,7 @@ xfs_dialloc_ag_inobt(
 	ASSERT(offset < XFS_INODES_PER_CHUNK);
 	ASSERT((XFS_AGINO_TO_OFFSET(mp, rec.ir_startino) %
 				   XFS_INODES_PER_CHUNK) == 0);
-	ino = XFS_AGINO_TO_INO(mp, agno, rec.ir_startino + offset);
+	ino = XFS_AGINO_TO_INO(mp, pag->pag_agno, rec.ir_startino + offset);
 	rec.ir_free &= ~XFS_INOBT_MASK(offset);
 	rec.ir_freecount--;
 	error = xfs_inobt_update(cur, &rec);
@@ -1577,7 +1570,6 @@ xfs_dialloc_ag(
 {
 	struct xfs_mount		*mp = tp->t_mountp;
 	struct xfs_agi			*agi = agbp->b_addr;
-	xfs_agnumber_t			agno = be32_to_cpu(agi->agi_seqno);
 	xfs_agnumber_t			pagno = XFS_INO_TO_AGNO(mp, parent);
 	xfs_agino_t			pagino = XFS_INO_TO_AGINO(mp, parent);
 	struct xfs_btree_cur		*cur;	/* finobt cursor */
@@ -1587,9 +1579,10 @@ xfs_dialloc_ag(
 	int				error;
 	int				offset;
 	int				i;
+	struct xfs_perag		*pag = agbp->b_pag;
 
 	if (!xfs_sb_version_hasfinobt(&mp->m_sb))
-		return xfs_dialloc_ag_inobt(tp, agbp, parent, inop);
+		return xfs_dialloc_ag_inobt(tp, agbp, pag, parent, inop);
 
 	/*
 	 * If pagino is 0 (this is the root inode allocation) use newino.
@@ -1598,7 +1591,7 @@ xfs_dialloc_ag(
 	if (!pagino)
 		pagino = be32_to_cpu(agi->agi_newino);
 
-	cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, NULL, XFS_BTNUM_FINO);
+	cur = xfs_inobt_init_cursor(mp, tp, agbp, pag, XFS_BTNUM_FINO);
 
 	error = xfs_check_agi_freecount(cur, agi);
 	if (error)
@@ -1609,7 +1602,7 @@ xfs_dialloc_ag(
 	 * parent. If so, find the closest available inode to the parent. If
 	 * not, consider the agi hint or find the first free inode in the AG.
 	 */
-	if (agno == pagno)
+	if (pag->pag_agno == pagno)
 		error = xfs_dialloc_ag_finobt_near(pagino, &cur, &rec);
 	else
 		error = xfs_dialloc_ag_finobt_newino(agi, cur, &rec);
@@ -1621,7 +1614,7 @@ xfs_dialloc_ag(
 	ASSERT(offset < XFS_INODES_PER_CHUNK);
 	ASSERT((XFS_AGINO_TO_OFFSET(mp, rec.ir_startino) %
 				   XFS_INODES_PER_CHUNK) == 0);
-	ino = XFS_AGINO_TO_INO(mp, agno, rec.ir_startino + offset);
+	ino = XFS_AGINO_TO_INO(mp, pag->pag_agno, rec.ir_startino + offset);
 
 	/*
 	 * Modify or remove the finobt record.
@@ -1641,7 +1634,7 @@ xfs_dialloc_ag(
 	 * the original freecount. If all is well, make the equivalent update to
 	 * the inobt using the finobt record and offset information.
 	 */
-	icur = xfs_inobt_init_cursor(mp, tp, agbp, agno, NULL, XFS_BTNUM_INO);
+	icur = xfs_inobt_init_cursor(mp, tp, agbp, pag, XFS_BTNUM_INO);
 
 	error = xfs_check_agi_freecount(icur, agi);
 	if (error)
@@ -1657,7 +1650,7 @@ xfs_dialloc_ag(
 	 */
 	be32_add_cpu(&agi->agi_freecount, -1);
 	xfs_ialloc_log_agi(tp, agbp, XFS_AGI_FREECOUNT);
-	agbp->b_pag->pagi_freecount--;
+	pag->pagi_freecount--;
 
 	xfs_trans_mod_sb(tp, XFS_TRANS_SB_IFREE, -1);
 
@@ -1809,7 +1802,7 @@ xfs_dialloc_select_ag(
 		if (!okalloc)
 			goto nextag_relse_buffer;
 
-		error = xfs_ialloc_ag_alloc(*tpp, agbp);
+		error = xfs_ialloc_ag_alloc(*tpp, agbp, pag);
 		if (error < 0) {
 			xfs_trans_brelse(*tpp, agbp);
 
@@ -1935,12 +1928,12 @@ xfs_difree_inobt(
 	struct xfs_mount		*mp,
 	struct xfs_trans		*tp,
 	struct xfs_buf			*agbp,
+	struct xfs_perag		*pag,
 	xfs_agino_t			agino,
 	struct xfs_icluster		*xic,
 	struct xfs_inobt_rec_incore	*orec)
 {
 	struct xfs_agi			*agi = agbp->b_addr;
-	xfs_agnumber_t			agno = be32_to_cpu(agi->agi_seqno);
 	struct xfs_btree_cur		*cur;
 	struct xfs_inobt_rec_incore	rec;
 	int				ilen;
@@ -1954,7 +1947,7 @@ xfs_difree_inobt(
 	/*
 	 * Initialize the cursor.
 	 */
-	cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, NULL, XFS_BTNUM_INO);
+	cur = xfs_inobt_init_cursor(mp, tp, agbp, pag, XFS_BTNUM_INO);
 
 	error = xfs_check_agi_freecount(cur, agi);
 	if (error)
@@ -2005,7 +1998,8 @@ xfs_difree_inobt(
 		struct xfs_perag	*pag = agbp->b_pag;
 
 		xic->deleted = true;
-		xic->first_ino = XFS_AGINO_TO_INO(mp, agno, rec.ir_startino);
+		xic->first_ino = XFS_AGINO_TO_INO(mp, pag->pag_agno,
+				rec.ir_startino);
 		xic->alloc = xfs_inobt_irec_to_allocmask(&rec);
 
 		/*
@@ -2028,7 +2022,7 @@ xfs_difree_inobt(
 			goto error0;
 		}
 
-		xfs_difree_inode_chunk(tp, agno, &rec);
+		xfs_difree_inode_chunk(tp, pag->pag_agno, &rec);
 	} else {
 		xic->deleted = false;
 
@@ -2044,7 +2038,7 @@ xfs_difree_inobt(
 		 */
 		be32_add_cpu(&agi->agi_freecount, 1);
 		xfs_ialloc_log_agi(tp, agbp, XFS_AGI_FREECOUNT);
-		agbp->b_pag->pagi_freecount++;
+		pag->pagi_freecount++;
 		xfs_trans_mod_sb(tp, XFS_TRANS_SB_IFREE, 1);
 	}
 
@@ -2069,18 +2063,18 @@ xfs_difree_finobt(
 	struct xfs_mount		*mp,
 	struct xfs_trans		*tp,
 	struct xfs_buf			*agbp,
+	struct xfs_perag		*pag,
 	xfs_agino_t			agino,
 	struct xfs_inobt_rec_incore	*ibtrec) /* inobt record */
 {
 	struct xfs_agi			*agi = agbp->b_addr;
-	xfs_agnumber_t			agno = be32_to_cpu(agi->agi_seqno);
 	struct xfs_btree_cur		*cur;
 	struct xfs_inobt_rec_incore	rec;
 	int				offset = agino - ibtrec->ir_startino;
 	int				error;
 	int				i;
 
-	cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, NULL, XFS_BTNUM_FINO);
+	cur = xfs_inobt_init_cursor(mp, tp, agbp, pag, XFS_BTNUM_FINO);
 
 	error = xfs_inobt_lookup(cur, ibtrec->ir_startino, XFS_LOOKUP_EQ, &i);
 	if (error)
@@ -2188,16 +2182,15 @@ xfs_difree(
 	xfs_agino_t		agino;	/* allocation group inode number */
 	xfs_agnumber_t		agno;	/* allocation group number */
 	int			error;	/* error return value */
-	struct xfs_mount	*mp;	/* mount structure for filesystem */
+	struct xfs_mount	*mp = tp->t_mountp;
 	struct xfs_inobt_rec_incore rec;/* btree record */
-
-	mp = tp->t_mountp;
+	struct xfs_perag	*pag;
 
 	/*
 	 * Break up inode number into its components.
 	 */
 	agno = XFS_INO_TO_AGNO(mp, inode);
-	if (agno >= mp->m_sb.sb_agcount)  {
+	if (agno >= mp->m_sb.sb_agcount) {
 		xfs_warn(mp, "%s: agno >= mp->m_sb.sb_agcount (%d >= %d).",
 			__func__, agno, mp->m_sb.sb_agcount);
 		ASSERT(0);
@@ -2231,7 +2224,8 @@ xfs_difree(
 	/*
 	 * Fix up the inode allocation btree.
 	 */
-	error = xfs_difree_inobt(mp, tp, agbp, agino, xic, &rec);
+	pag = agbp->b_pag;
+	error = xfs_difree_inobt(mp, tp, agbp, pag, agino, xic, &rec);
 	if (error)
 		goto error0;
 
@@ -2239,7 +2233,7 @@ xfs_difree(
 	 * Fix up the free inode btree.
 	 */
 	if (xfs_sb_version_hasfinobt(&mp->m_sb)) {
-		error = xfs_difree_finobt(mp, tp, agbp, agino, &rec);
+		error = xfs_difree_finobt(mp, tp, agbp, pag, agino, &rec);
 		if (error)
 			goto error0;
 	}
@@ -2254,7 +2248,7 @@ STATIC int
 xfs_imap_lookup(
 	struct xfs_mount	*mp,
 	struct xfs_trans	*tp,
-	xfs_agnumber_t		agno,
+	struct xfs_perag	*pag,
 	xfs_agino_t		agino,
 	xfs_agblock_t		agbno,
 	xfs_agblock_t		*chunk_agbno,
@@ -2267,11 +2261,11 @@ xfs_imap_lookup(
 	int			error;
 	int			i;
 
-	error = xfs_ialloc_read_agi(mp, tp, agno, &agbp);
+	error = xfs_ialloc_read_agi(mp, tp, pag->pag_agno, &agbp);
 	if (error) {
 		xfs_alert(mp,
 			"%s: xfs_ialloc_read_agi() returned error %d, agno %d",
-			__func__, error, agno);
+			__func__, error, pag->pag_agno);
 		return error;
 	}
 
@@ -2281,7 +2275,7 @@ xfs_imap_lookup(
 	 * we have a record, we need to ensure it contains the inode number
 	 * we are looking up.
 	 */
-	cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, NULL, XFS_BTNUM_INO);
+	cur = xfs_inobt_init_cursor(mp, tp, agbp, pag, XFS_BTNUM_INO);
 	error = xfs_inobt_lookup(cur, agino, XFS_LOOKUP_LE, &i);
 	if (!error) {
 		if (i)
@@ -2315,42 +2309,44 @@ xfs_imap_lookup(
  */
 int
 xfs_imap(
-	xfs_mount_t	 *mp,	/* file system mount structure */
-	xfs_trans_t	 *tp,	/* transaction pointer */
-	xfs_ino_t	ino,	/* inode to locate */
-	struct xfs_imap	*imap,	/* location map structure */
-	uint		flags)	/* flags for inode btree lookup */
+	struct xfs_mount	 *mp,	/* file system mount structure */
+	struct xfs_trans	 *tp,	/* transaction pointer */
+	xfs_ino_t		ino,	/* inode to locate */
+	struct xfs_imap		*imap,	/* location map structure */
+	uint			flags)	/* flags for inode btree lookup */
 {
-	xfs_agblock_t	agbno;	/* block number of inode in the alloc group */
-	xfs_agino_t	agino;	/* inode number within alloc group */
-	xfs_agnumber_t	agno;	/* allocation group number */
-	xfs_agblock_t	chunk_agbno;	/* first block in inode chunk */
-	xfs_agblock_t	cluster_agbno;	/* first block in inode cluster */
-	int		error;	/* error code */
-	int		offset;	/* index of inode in its buffer */
-	xfs_agblock_t	offset_agbno;	/* blks from chunk start to inode */
+	xfs_agblock_t		agbno;	/* block number of inode in the alloc group */
+	xfs_agino_t		agino;	/* inode number within alloc group */
+	xfs_agblock_t		chunk_agbno;	/* first block in inode chunk */
+	xfs_agblock_t		cluster_agbno;	/* first block in inode cluster */
+	int			error;	/* error code */
+	int			offset;	/* index of inode in its buffer */
+	xfs_agblock_t		offset_agbno;	/* blks from chunk start to inode */
+	struct xfs_perag	*pag;
 
 	ASSERT(ino != NULLFSINO);
 
 	/*
 	 * Split up the inode number into its parts.
 	 */
-	agno = XFS_INO_TO_AGNO(mp, ino);
+	pag = xfs_perag_get(mp, XFS_INO_TO_AGNO(mp, ino));
 	agino = XFS_INO_TO_AGINO(mp, ino);
 	agbno = XFS_AGINO_TO_AGBNO(mp, agino);
-	if (agno >= mp->m_sb.sb_agcount || agbno >= mp->m_sb.sb_agblocks ||
-	    ino != XFS_AGINO_TO_INO(mp, agno, agino)) {
+	if (!pag || agbno >= mp->m_sb.sb_agblocks ||
+	    ino != XFS_AGINO_TO_INO(mp, pag->pag_agno, agino)) {
+		error = -EINVAL;
 #ifdef DEBUG
 		/*
 		 * Don't output diagnostic information for untrusted inodes
 		 * as they can be invalid without implying corruption.
 		 */
 		if (flags & XFS_IGET_UNTRUSTED)
-			return -EINVAL;
-		if (agno >= mp->m_sb.sb_agcount) {
+			goto out_drop;
+		if (!pag) {
 			xfs_alert(mp,
 				"%s: agno (%d) >= mp->m_sb.sb_agcount (%d)",
-				__func__, agno, mp->m_sb.sb_agcount);
+				__func__, XFS_INO_TO_AGNO(mp, ino),
+				mp->m_sb.sb_agcount);
 		}
 		if (agbno >= mp->m_sb.sb_agblocks) {
 			xfs_alert(mp,
@@ -2358,15 +2354,15 @@ xfs_imap(
 				__func__, (unsigned long long)agbno,
 				(unsigned long)mp->m_sb.sb_agblocks);
 		}
-		if (ino != XFS_AGINO_TO_INO(mp, agno, agino)) {
+		if (pag && ino != XFS_AGINO_TO_INO(mp, pag->pag_agno, agino)) {
 			xfs_alert(mp,
 		"%s: ino (0x%llx) != XFS_AGINO_TO_INO() (0x%llx)",
 				__func__, ino,
-				XFS_AGINO_TO_INO(mp, agno, agino));
+				XFS_AGINO_TO_INO(mp, pag->pag_agno, agino));
 		}
 		xfs_stack_trace();
 #endif /* DEBUG */
-		return -EINVAL;
+		goto out_drop;
 	}
 
 	/*
@@ -2377,10 +2373,10 @@ xfs_imap(
 	 * in all cases where an untrusted inode number is passed.
 	 */
 	if (flags & XFS_IGET_UNTRUSTED) {
-		error = xfs_imap_lookup(mp, tp, agno, agino, agbno,
+		error = xfs_imap_lookup(mp, tp, pag, agino, agbno,
 					&chunk_agbno, &offset_agbno, flags);
 		if (error)
-			return error;
+			goto out_drop;
 		goto out_map;
 	}
 
@@ -2392,11 +2388,12 @@ xfs_imap(
 		offset = XFS_INO_TO_OFFSET(mp, ino);
 		ASSERT(offset < mp->m_sb.sb_inopblock);
 
-		imap->im_blkno = XFS_AGB_TO_DADDR(mp, agno, agbno);
+		imap->im_blkno = XFS_AGB_TO_DADDR(mp, pag->pag_agno, agbno);
 		imap->im_len = XFS_FSB_TO_BB(mp, 1);
 		imap->im_boffset = (unsigned short)(offset <<
 							mp->m_sb.sb_inodelog);
-		return 0;
+		error = 0;
+		goto out_drop;
 	}
 
 	/*
@@ -2408,10 +2405,10 @@ xfs_imap(
 		offset_agbno = agbno & M_IGEO(mp)->inoalign_mask;
 		chunk_agbno = agbno - offset_agbno;
 	} else {
-		error = xfs_imap_lookup(mp, tp, agno, agino, agbno,
+		error = xfs_imap_lookup(mp, tp, pag, agino, agbno,
 					&chunk_agbno, &offset_agbno, flags);
 		if (error)
-			return error;
+			goto out_drop;
 	}
 
 out_map:
@@ -2422,7 +2419,7 @@ xfs_imap(
 	offset = ((agbno - cluster_agbno) * mp->m_sb.sb_inopblock) +
 		XFS_INO_TO_OFFSET(mp, ino);
 
-	imap->im_blkno = XFS_AGB_TO_DADDR(mp, agno, cluster_agbno);
+	imap->im_blkno = XFS_AGB_TO_DADDR(mp, pag->pag_agno, cluster_agbno);
 	imap->im_len = XFS_FSB_TO_BB(mp, M_IGEO(mp)->blocks_per_cluster);
 	imap->im_boffset = (unsigned short)(offset << mp->m_sb.sb_inodelog);
 
@@ -2439,9 +2436,13 @@ xfs_imap(
 			__func__, (unsigned long long) imap->im_blkno,
 			(unsigned long long) imap->im_len,
 			XFS_FSB_TO_BB(mp, mp->m_sb.sb_dblocks));
-		return -EINVAL;
+		error = -EINVAL;
+		goto out_drop;
 	}
-	return 0;
+	error = 0;
+out_drop:
+	xfs_perag_put(pag);
+	return error;
 }
 
 /*
diff --git a/fs/xfs/libxfs/xfs_ialloc_btree.c b/fs/xfs/libxfs/xfs_ialloc_btree.c
index 6c4efdf01674..450161b53648 100644
--- a/fs/xfs/libxfs/xfs_ialloc_btree.c
+++ b/fs/xfs/libxfs/xfs_ialloc_btree.c
@@ -35,8 +35,7 @@ xfs_inobt_dup_cursor(
 	struct xfs_btree_cur	*cur)
 {
 	return xfs_inobt_init_cursor(cur->bc_mp, cur->bc_tp,
-			cur->bc_ag.agbp, cur->bc_ag.agno,
-			cur->bc_ag.pag, cur->bc_btnum);
+			cur->bc_ag.agbp, cur->bc_ag.pag, cur->bc_btnum);
 }
 
 STATIC void
@@ -428,7 +427,6 @@ static struct xfs_btree_cur *
 xfs_inobt_init_common(
 	struct xfs_mount	*mp,		/* file system mount point */
 	struct xfs_trans	*tp,		/* transaction pointer */
-	xfs_agnumber_t		agno,		/* allocation group number */
 	struct xfs_perag	*pag,
 	xfs_btnum_t		btnum)		/* ialloc or free ino btree */
 {
@@ -451,12 +449,10 @@ xfs_inobt_init_common(
 	if (xfs_sb_version_hascrc(&mp->m_sb))
 		cur->bc_flags |= XFS_BTREE_CRC_BLOCKS;
 
-	cur->bc_ag.agno = agno;
-	if (pag) {
-		/* take a reference for the cursor */
-		atomic_inc(&pag->pag_ref);
-	}
+	/* take a reference for the cursor */
+	atomic_inc(&pag->pag_ref);
 	cur->bc_ag.pag = pag;
+	cur->bc_ag.agno = pag->pag_agno;
 	return cur;
 }
 
@@ -466,14 +462,13 @@ xfs_inobt_init_cursor(
 	struct xfs_mount	*mp,
 	struct xfs_trans	*tp,
 	struct xfs_buf		*agbp,
-	xfs_agnumber_t		agno,
 	struct xfs_perag	*pag,
 	xfs_btnum_t		btnum)
 {
 	struct xfs_btree_cur	*cur;
 	struct xfs_agi		*agi = agbp->b_addr;
 
-	cur = xfs_inobt_init_common(mp, tp, agno, pag, btnum);
+	cur = xfs_inobt_init_common(mp, tp, pag, btnum);
 	if (btnum == XFS_BTNUM_INO)
 		cur->bc_nlevels = be32_to_cpu(agi->agi_level);
 	else
@@ -487,12 +482,12 @@ struct xfs_btree_cur *
 xfs_inobt_stage_cursor(
 	struct xfs_mount	*mp,
 	struct xbtree_afakeroot	*afake,
-	xfs_agnumber_t		agno,
+	struct xfs_perag	*pag,
 	xfs_btnum_t		btnum)
 {
 	struct xfs_btree_cur	*cur;
 
-	cur = xfs_inobt_init_common(mp, NULL, agno, NULL, btnum);
+	cur = xfs_inobt_init_common(mp, NULL, pag, btnum);
 	xfs_btree_stage_afakeroot(cur, afake);
 	return cur;
 }
@@ -664,7 +659,7 @@ int
 xfs_inobt_cur(
 	struct xfs_mount	*mp,
 	struct xfs_trans	*tp,
-	xfs_agnumber_t		agno,
+	struct xfs_perag	*pag,
 	xfs_btnum_t		which,
 	struct xfs_btree_cur	**curpp,
 	struct xfs_buf		**agi_bpp)
@@ -675,11 +670,11 @@ xfs_inobt_cur(
 	ASSERT(*agi_bpp == NULL);
 	ASSERT(*curpp == NULL);
 
-	error = xfs_ialloc_read_agi(mp, tp, agno, agi_bpp);
+	error = xfs_ialloc_read_agi(mp, tp, pag->pag_agno, agi_bpp);
 	if (error)
 		return error;
 
-	cur = xfs_inobt_init_cursor(mp, tp, *agi_bpp, agno, NULL, which);
+	cur = xfs_inobt_init_cursor(mp, tp, *agi_bpp, pag, which);
 	*curpp = cur;
 	return 0;
 }
@@ -696,7 +691,7 @@ xfs_inobt_count_blocks(
 	struct xfs_btree_cur	*cur = NULL;
 	int			error;
 
-	error = xfs_inobt_cur(mp, tp, pag->pag_agno, btnum, &cur, &agbp);
+	error = xfs_inobt_cur(mp, tp, pag, btnum, &cur, &agbp);
 	if (error)
 		return error;
 
diff --git a/fs/xfs/libxfs/xfs_ialloc_btree.h b/fs/xfs/libxfs/xfs_ialloc_btree.h
index 04dfa7eee81f..e530c82b2217 100644
--- a/fs/xfs/libxfs/xfs_ialloc_btree.h
+++ b/fs/xfs/libxfs/xfs_ialloc_btree.h
@@ -47,10 +47,10 @@ struct xfs_perag;
 		 ((index) - 1) * sizeof(xfs_inobt_ptr_t)))
 
 extern struct xfs_btree_cur *xfs_inobt_init_cursor(struct xfs_mount *mp,
-		struct xfs_trans *tp, struct xfs_buf *agbp, xfs_agnumber_t agno,
+		struct xfs_trans *tp, struct xfs_buf *agbp,
 		struct xfs_perag *pag, xfs_btnum_t btnum);
 struct xfs_btree_cur *xfs_inobt_stage_cursor(struct xfs_mount *mp,
-		struct xbtree_afakeroot *afake, xfs_agnumber_t agno,
+		struct xbtree_afakeroot *afake, struct xfs_perag *pag,
 		xfs_btnum_t btnum);
 extern int xfs_inobt_maxrecs(struct xfs_mount *, int, int);
 
@@ -69,7 +69,7 @@ int xfs_finobt_calc_reserves(struct xfs_mount *mp, struct xfs_trans *tp,
 extern xfs_extlen_t xfs_iallocbt_calc_size(struct xfs_mount *mp,
 		unsigned long long len);
 int xfs_inobt_cur(struct xfs_mount *mp, struct xfs_trans *tp,
-		xfs_agnumber_t agno, xfs_btnum_t btnum,
+		struct xfs_perag *pag, xfs_btnum_t btnum,
 		struct xfs_btree_cur **curpp, struct xfs_buf **agi_bpp);
 
 void xfs_inobt_commit_staged_btree(struct xfs_btree_cur *cur,
diff --git a/fs/xfs/scrub/agheader_repair.c b/fs/xfs/scrub/agheader_repair.c
index ee2d85e3fd4a..ecc9146647ba 100644
--- a/fs/xfs/scrub/agheader_repair.c
+++ b/fs/xfs/scrub/agheader_repair.c
@@ -806,7 +806,7 @@ xrep_agi_calc_from_btrees(
 	xfs_agino_t		freecount;
 	int			error;
 
-	cur = xfs_inobt_init_cursor(mp, sc->tp, agi_bp, sc->sa.agno,
+	cur = xfs_inobt_init_cursor(mp, sc->tp, agi_bp,
 			sc->sa.pag, XFS_BTNUM_INO);
 	error = xfs_ialloc_count_inodes(cur, &count, &freecount);
 	if (error)
@@ -828,7 +828,7 @@ xrep_agi_calc_from_btrees(
 	    xfs_sb_version_hasinobtcounts(&mp->m_sb)) {
 		xfs_agblock_t	blocks;
 
-		cur = xfs_inobt_init_cursor(mp, sc->tp, agi_bp, sc->sa.agno,
+		cur = xfs_inobt_init_cursor(mp, sc->tp, agi_bp,
 				sc->sa.pag, XFS_BTNUM_FINO);
 		error = xfs_btree_count_blocks(cur, &blocks);
 		if (error)
diff --git a/fs/xfs/scrub/common.c b/fs/xfs/scrub/common.c
index 3035f8cee6f6..64c3b9b78d0d 100644
--- a/fs/xfs/scrub/common.c
+++ b/fs/xfs/scrub/common.c
@@ -458,7 +458,6 @@ xchk_ag_btcur_init(
 	struct xchk_ag		*sa)
 {
 	struct xfs_mount	*mp = sc->mp;
-	xfs_agnumber_t		agno = sa->agno;
 
 	xchk_perag_get(sc->mp, sa);
 	if (sa->agf_bp &&
@@ -479,14 +478,14 @@ xchk_ag_btcur_init(
 	if (sa->agi_bp &&
 	    xchk_ag_btree_healthy_enough(sc, sa->pag, XFS_BTNUM_INO)) {
 		sa->ino_cur = xfs_inobt_init_cursor(mp, sc->tp, sa->agi_bp,
-				agno, sa->pag, XFS_BTNUM_INO);
+				sa->pag, XFS_BTNUM_INO);
 	}
 
 	/* Set up a finobt cursor for cross-referencing. */
 	if (sa->agi_bp && xfs_sb_version_hasfinobt(&mp->m_sb) &&
 	    xchk_ag_btree_healthy_enough(sc, sa->pag, XFS_BTNUM_FINO)) {
 		sa->fino_cur = xfs_inobt_init_cursor(mp, sc->tp, sa->agi_bp,
-				agno, sa->pag, XFS_BTNUM_FINO);
+				sa->pag, XFS_BTNUM_FINO);
 	}
 
 	/* Set up a rmapbt cursor for cross-referencing. */
diff --git a/fs/xfs/xfs_iwalk.c b/fs/xfs/xfs_iwalk.c
index c7e8f48a3ec4..917d51eefee3 100644
--- a/fs/xfs/xfs_iwalk.c
+++ b/fs/xfs/xfs_iwalk.c
@@ -272,8 +272,7 @@ xfs_iwalk_ag_start(
 
 	/* Set up a fresh cursor and empty the inobt cache. */
 	iwag->nr_recs = 0;
-	error = xfs_inobt_cur(mp, tp, pag->pag_agno, XFS_BTNUM_INO,
-				curpp, agi_bpp);
+	error = xfs_inobt_cur(mp, tp, pag, XFS_BTNUM_INO, curpp, agi_bpp);
 	if (error)
 		return error;
 
@@ -378,8 +377,7 @@ xfs_iwalk_run_callbacks(
 		return 0;
 
 	/* ...and recreate the cursor just past where we left off. */
-	error = xfs_inobt_cur(mp, tp, iwag->pag->pag_agno, XFS_BTNUM_INO,
-				curpp, agi_bpp);
+	error = xfs_inobt_cur(mp, tp, iwag->pag, XFS_BTNUM_INO, curpp, agi_bpp);
 	if (error)
 		return error;
 
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 87+ messages in thread

* [PATCH 16/22] xfs: remove agno from btree cursor
  2021-05-06  7:20 [RFC 00/22] xfs: initial agnumber -> perag conversions for shrink Dave Chinner
                   ` (14 preceding siblings ...)
  2021-05-06  7:20 ` [PATCH 15/22] xfs: use perag for ialloc btree cursors Dave Chinner
@ 2021-05-06  7:20 ` Dave Chinner
  2021-05-11 12:34   ` Brian Foster
  2021-05-12 22:52   ` Darrick J. Wong
  2021-05-06  7:20 ` [PATCH 17/22] xfs: simplify xfs_dialloc_select_ag() return values Dave Chinner
                   ` (5 subsequent siblings)
  21 siblings, 2 replies; 87+ messages in thread
From: Dave Chinner @ 2021-05-06  7:20 UTC (permalink / raw)
  To: linux-xfs

From: Dave Chinner <dchinner@redhat.com>

Now that everything passes a perag, the agno is not needed anymore.
Convert all the users to use pag->pag_agno instead and remove the
agno from the cursor. This was largely done as an automated search
and replace.

Signed-off-by: Dave Chinner <dchinner@redhat.com>
---
 fs/xfs/libxfs/xfs_alloc.c          |   2 +-
 fs/xfs/libxfs/xfs_alloc_btree.c    |   1 -
 fs/xfs/libxfs/xfs_btree.c          |  12 ++--
 fs/xfs/libxfs/xfs_btree.h          |   1 -
 fs/xfs/libxfs/xfs_ialloc.c         |   2 +-
 fs/xfs/libxfs/xfs_ialloc_btree.c   |   7 +-
 fs/xfs/libxfs/xfs_refcount.c       |  82 +++++++++++-----------
 fs/xfs/libxfs/xfs_refcount_btree.c |  11 ++-
 fs/xfs/libxfs/xfs_rmap.c           | 108 ++++++++++++++---------------
 fs/xfs/libxfs/xfs_rmap_btree.c     |   1 -
 fs/xfs/scrub/agheader_repair.c     |   2 +-
 fs/xfs/scrub/alloc.c               |   3 +-
 fs/xfs/scrub/bmap.c                |   2 +-
 fs/xfs/scrub/ialloc.c              |   9 +--
 fs/xfs/scrub/refcount.c            |   3 +-
 fs/xfs/scrub/rmap.c                |   3 +-
 fs/xfs/scrub/trace.c               |   3 +-
 fs/xfs/xfs_fsmap.c                 |   4 +-
 fs/xfs/xfs_trace.h                 |   4 +-
 19 files changed, 130 insertions(+), 130 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_alloc.c b/fs/xfs/libxfs/xfs_alloc.c
index c99a80286efa..f7864f33c1f0 100644
--- a/fs/xfs/libxfs/xfs_alloc.c
+++ b/fs/xfs/libxfs/xfs_alloc.c
@@ -230,7 +230,7 @@ xfs_alloc_get_rec(
 	int			*stat)	/* output: success/failure */
 {
 	struct xfs_mount	*mp = cur->bc_mp;
-	xfs_agnumber_t		agno = cur->bc_ag.agno;
+	xfs_agnumber_t		agno = cur->bc_ag.pag->pag_agno;
 	union xfs_btree_rec	*rec;
 	int			error;
 
diff --git a/fs/xfs/libxfs/xfs_alloc_btree.c b/fs/xfs/libxfs/xfs_alloc_btree.c
index 0c2e4cff4ee3..6b363f78cfa2 100644
--- a/fs/xfs/libxfs/xfs_alloc_btree.c
+++ b/fs/xfs/libxfs/xfs_alloc_btree.c
@@ -497,7 +497,6 @@ xfs_allocbt_init_common(
 	/* take a reference for the cursor */
 	atomic_inc(&pag->pag_ref);
 	cur->bc_ag.pag = pag;
-	cur->bc_ag.agno = pag->pag_agno;
 
 	if (xfs_sb_version_hascrc(&mp->m_sb))
 		cur->bc_flags |= XFS_BTREE_CRC_BLOCKS;
diff --git a/fs/xfs/libxfs/xfs_btree.c b/fs/xfs/libxfs/xfs_btree.c
index 44044317c0fb..be74a6b53689 100644
--- a/fs/xfs/libxfs/xfs_btree.c
+++ b/fs/xfs/libxfs/xfs_btree.c
@@ -216,7 +216,7 @@ xfs_btree_check_sptr(
 {
 	if (level <= 0)
 		return false;
-	return xfs_verify_agbno(cur->bc_mp, cur->bc_ag.agno, agbno);
+	return xfs_verify_agbno(cur->bc_mp, cur->bc_ag.pag->pag_agno, agbno);
 }
 
 /*
@@ -245,7 +245,7 @@ xfs_btree_check_ptr(
 			return 0;
 		xfs_err(cur->bc_mp,
 "AG %u: Corrupt btree %d pointer at level %d index %d.",
-				cur->bc_ag.agno, cur->bc_btnum,
+				cur->bc_ag.pag->pag_agno, cur->bc_btnum,
 				level, index);
 	}
 
@@ -888,13 +888,13 @@ xfs_btree_readahead_sblock(
 
 
 	if ((lr & XFS_BTCUR_LEFTRA) && left != NULLAGBLOCK) {
-		xfs_btree_reada_bufs(cur->bc_mp, cur->bc_ag.agno,
+		xfs_btree_reada_bufs(cur->bc_mp, cur->bc_ag.pag->pag_agno,
 				     left, 1, cur->bc_ops->buf_ops);
 		rval++;
 	}
 
 	if ((lr & XFS_BTCUR_RIGHTRA) && right != NULLAGBLOCK) {
-		xfs_btree_reada_bufs(cur->bc_mp, cur->bc_ag.agno,
+		xfs_btree_reada_bufs(cur->bc_mp, cur->bc_ag.pag->pag_agno,
 				     right, 1, cur->bc_ops->buf_ops);
 		rval++;
 	}
@@ -952,7 +952,7 @@ xfs_btree_ptr_to_daddr(
 		*daddr = XFS_FSB_TO_DADDR(cur->bc_mp, fsbno);
 	} else {
 		agbno = be32_to_cpu(ptr->s);
-		*daddr = XFS_AGB_TO_DADDR(cur->bc_mp, cur->bc_ag.agno,
+		*daddr = XFS_AGB_TO_DADDR(cur->bc_mp, cur->bc_ag.pag->pag_agno,
 				agbno);
 	}
 
@@ -1153,7 +1153,7 @@ xfs_btree_init_block_cur(
 	if (cur->bc_flags & XFS_BTREE_LONG_PTRS)
 		owner = cur->bc_ino.ip->i_ino;
 	else
-		owner = cur->bc_ag.agno;
+		owner = cur->bc_ag.pag->pag_agno;
 
 	xfs_btree_init_block_int(cur->bc_mp, XFS_BUF_TO_BLOCK(bp), bp->b_bn,
 				 cur->bc_btnum, level, numrecs,
diff --git a/fs/xfs/libxfs/xfs_btree.h b/fs/xfs/libxfs/xfs_btree.h
index 8233f8679ba9..13bbcf107e5d 100644
--- a/fs/xfs/libxfs/xfs_btree.h
+++ b/fs/xfs/libxfs/xfs_btree.h
@@ -181,7 +181,6 @@ union xfs_btree_irec {
 
 /* Per-AG btree information. */
 struct xfs_btree_cur_ag {
-	xfs_agnumber_t		agno;
 	struct xfs_perag	*pag;
 	union {
 		struct xfs_buf		*agbp;
diff --git a/fs/xfs/libxfs/xfs_ialloc.c b/fs/xfs/libxfs/xfs_ialloc.c
index e6f64d41e208..4540fbcd68a3 100644
--- a/fs/xfs/libxfs/xfs_ialloc.c
+++ b/fs/xfs/libxfs/xfs_ialloc.c
@@ -105,7 +105,7 @@ xfs_inobt_get_rec(
 	int				*stat)
 {
 	struct xfs_mount		*mp = cur->bc_mp;
-	xfs_agnumber_t			agno = cur->bc_ag.agno;
+	xfs_agnumber_t			agno = cur->bc_ag.pag->pag_agno;
 	union xfs_btree_rec		*rec;
 	int				error;
 	uint64_t			realfree;
diff --git a/fs/xfs/libxfs/xfs_ialloc_btree.c b/fs/xfs/libxfs/xfs_ialloc_btree.c
index 450161b53648..823a038939f8 100644
--- a/fs/xfs/libxfs/xfs_ialloc_btree.c
+++ b/fs/xfs/libxfs/xfs_ialloc_btree.c
@@ -102,7 +102,7 @@ __xfs_inobt_alloc_block(
 	args.tp = cur->bc_tp;
 	args.mp = cur->bc_mp;
 	args.oinfo = XFS_RMAP_OINFO_INOBT;
-	args.fsbno = XFS_AGB_TO_FSB(args.mp, cur->bc_ag.agno, sbno);
+	args.fsbno = XFS_AGB_TO_FSB(args.mp, cur->bc_ag.pag->pag_agno, sbno);
 	args.minlen = 1;
 	args.maxlen = 1;
 	args.prod = 1;
@@ -235,7 +235,7 @@ xfs_inobt_init_ptr_from_cur(
 {
 	struct xfs_agi		*agi = cur->bc_ag.agbp->b_addr;
 
-	ASSERT(cur->bc_ag.agno == be32_to_cpu(agi->agi_seqno));
+	ASSERT(cur->bc_ag.pag->pag_agno == be32_to_cpu(agi->agi_seqno));
 
 	ptr->s = agi->agi_root;
 }
@@ -247,7 +247,7 @@ xfs_finobt_init_ptr_from_cur(
 {
 	struct xfs_agi		*agi = cur->bc_ag.agbp->b_addr;
 
-	ASSERT(cur->bc_ag.agno == be32_to_cpu(agi->agi_seqno));
+	ASSERT(cur->bc_ag.pag->pag_agno == be32_to_cpu(agi->agi_seqno));
 	ptr->s = agi->agi_free_root;
 }
 
@@ -452,7 +452,6 @@ xfs_inobt_init_common(
 	/* take a reference for the cursor */
 	atomic_inc(&pag->pag_ref);
 	cur->bc_ag.pag = pag;
-	cur->bc_ag.agno = pag->pag_agno;
 	return cur;
 }
 
diff --git a/fs/xfs/libxfs/xfs_refcount.c b/fs/xfs/libxfs/xfs_refcount.c
index 3c2b99cbd57d..82b2810d85a6 100644
--- a/fs/xfs/libxfs/xfs_refcount.c
+++ b/fs/xfs/libxfs/xfs_refcount.c
@@ -47,7 +47,7 @@ xfs_refcount_lookup_le(
 	xfs_agblock_t		bno,
 	int			*stat)
 {
-	trace_xfs_refcount_lookup(cur->bc_mp, cur->bc_ag.agno, bno,
+	trace_xfs_refcount_lookup(cur->bc_mp, cur->bc_ag.pag->pag_agno, bno,
 			XFS_LOOKUP_LE);
 	cur->bc_rec.rc.rc_startblock = bno;
 	cur->bc_rec.rc.rc_blockcount = 0;
@@ -64,7 +64,7 @@ xfs_refcount_lookup_ge(
 	xfs_agblock_t		bno,
 	int			*stat)
 {
-	trace_xfs_refcount_lookup(cur->bc_mp, cur->bc_ag.agno, bno,
+	trace_xfs_refcount_lookup(cur->bc_mp, cur->bc_ag.pag->pag_agno, bno,
 			XFS_LOOKUP_GE);
 	cur->bc_rec.rc.rc_startblock = bno;
 	cur->bc_rec.rc.rc_blockcount = 0;
@@ -81,7 +81,7 @@ xfs_refcount_lookup_eq(
 	xfs_agblock_t		bno,
 	int			*stat)
 {
-	trace_xfs_refcount_lookup(cur->bc_mp, cur->bc_ag.agno, bno,
+	trace_xfs_refcount_lookup(cur->bc_mp, cur->bc_ag.pag->pag_agno, bno,
 			XFS_LOOKUP_LE);
 	cur->bc_rec.rc.rc_startblock = bno;
 	cur->bc_rec.rc.rc_blockcount = 0;
@@ -109,7 +109,7 @@ xfs_refcount_get_rec(
 	int				*stat)
 {
 	struct xfs_mount		*mp = cur->bc_mp;
-	xfs_agnumber_t			agno = cur->bc_ag.agno;
+	xfs_agnumber_t			agno = cur->bc_ag.pag->pag_agno;
 	union xfs_btree_rec		*rec;
 	int				error;
 	xfs_agblock_t			realstart;
@@ -120,7 +120,7 @@ xfs_refcount_get_rec(
 
 	xfs_refcount_btrec_to_irec(rec, irec);
 
-	agno = cur->bc_ag.agno;
+	agno = cur->bc_ag.pag->pag_agno;
 	if (irec->rc_blockcount == 0 || irec->rc_blockcount > MAXREFCEXTLEN)
 		goto out_bad_rec;
 
@@ -145,7 +145,7 @@ xfs_refcount_get_rec(
 	if (irec->rc_refcount == 0 || irec->rc_refcount > MAXREFCOUNT)
 		goto out_bad_rec;
 
-	trace_xfs_refcount_get(cur->bc_mp, cur->bc_ag.agno, irec);
+	trace_xfs_refcount_get(cur->bc_mp, cur->bc_ag.pag->pag_agno, irec);
 	return 0;
 
 out_bad_rec:
@@ -170,14 +170,14 @@ xfs_refcount_update(
 	union xfs_btree_rec	rec;
 	int			error;
 
-	trace_xfs_refcount_update(cur->bc_mp, cur->bc_ag.agno, irec);
+	trace_xfs_refcount_update(cur->bc_mp, cur->bc_ag.pag->pag_agno, irec);
 	rec.refc.rc_startblock = cpu_to_be32(irec->rc_startblock);
 	rec.refc.rc_blockcount = cpu_to_be32(irec->rc_blockcount);
 	rec.refc.rc_refcount = cpu_to_be32(irec->rc_refcount);
 	error = xfs_btree_update(cur, &rec);
 	if (error)
 		trace_xfs_refcount_update_error(cur->bc_mp,
-				cur->bc_ag.agno, error, _RET_IP_);
+				cur->bc_ag.pag->pag_agno, error, _RET_IP_);
 	return error;
 }
 
@@ -194,7 +194,7 @@ xfs_refcount_insert(
 {
 	int				error;
 
-	trace_xfs_refcount_insert(cur->bc_mp, cur->bc_ag.agno, irec);
+	trace_xfs_refcount_insert(cur->bc_mp, cur->bc_ag.pag->pag_agno, irec);
 	cur->bc_rec.rc.rc_startblock = irec->rc_startblock;
 	cur->bc_rec.rc.rc_blockcount = irec->rc_blockcount;
 	cur->bc_rec.rc.rc_refcount = irec->rc_refcount;
@@ -209,7 +209,7 @@ xfs_refcount_insert(
 out_error:
 	if (error)
 		trace_xfs_refcount_insert_error(cur->bc_mp,
-				cur->bc_ag.agno, error, _RET_IP_);
+				cur->bc_ag.pag->pag_agno, error, _RET_IP_);
 	return error;
 }
 
@@ -235,7 +235,7 @@ xfs_refcount_delete(
 		error = -EFSCORRUPTED;
 		goto out_error;
 	}
-	trace_xfs_refcount_delete(cur->bc_mp, cur->bc_ag.agno, &irec);
+	trace_xfs_refcount_delete(cur->bc_mp, cur->bc_ag.pag->pag_agno, &irec);
 	error = xfs_btree_delete(cur, i);
 	if (XFS_IS_CORRUPT(cur->bc_mp, *i != 1)) {
 		error = -EFSCORRUPTED;
@@ -247,7 +247,7 @@ xfs_refcount_delete(
 out_error:
 	if (error)
 		trace_xfs_refcount_delete_error(cur->bc_mp,
-				cur->bc_ag.agno, error, _RET_IP_);
+				cur->bc_ag.pag->pag_agno, error, _RET_IP_);
 	return error;
 }
 
@@ -367,7 +367,7 @@ xfs_refcount_split_extent(
 		return 0;
 
 	*shape_changed = true;
-	trace_xfs_refcount_split_extent(cur->bc_mp, cur->bc_ag.agno,
+	trace_xfs_refcount_split_extent(cur->bc_mp, cur->bc_ag.pag->pag_agno,
 			&rcext, agbno);
 
 	/* Establish the right extent. */
@@ -392,7 +392,7 @@ xfs_refcount_split_extent(
 
 out_error:
 	trace_xfs_refcount_split_extent_error(cur->bc_mp,
-			cur->bc_ag.agno, error, _RET_IP_);
+			cur->bc_ag.pag->pag_agno, error, _RET_IP_);
 	return error;
 }
 
@@ -412,7 +412,7 @@ xfs_refcount_merge_center_extents(
 	int				found_rec;
 
 	trace_xfs_refcount_merge_center_extents(cur->bc_mp,
-			cur->bc_ag.agno, left, center, right);
+			cur->bc_ag.pag->pag_agno, left, center, right);
 
 	/*
 	 * Make sure the center and right extents are not in the btree.
@@ -469,7 +469,7 @@ xfs_refcount_merge_center_extents(
 
 out_error:
 	trace_xfs_refcount_merge_center_extents_error(cur->bc_mp,
-			cur->bc_ag.agno, error, _RET_IP_);
+			cur->bc_ag.pag->pag_agno, error, _RET_IP_);
 	return error;
 }
 
@@ -488,7 +488,7 @@ xfs_refcount_merge_left_extent(
 	int				found_rec;
 
 	trace_xfs_refcount_merge_left_extent(cur->bc_mp,
-			cur->bc_ag.agno, left, cleft);
+			cur->bc_ag.pag->pag_agno, left, cleft);
 
 	/* If the extent at agbno (cleft) wasn't synthesized, remove it. */
 	if (cleft->rc_refcount > 1) {
@@ -531,7 +531,7 @@ xfs_refcount_merge_left_extent(
 
 out_error:
 	trace_xfs_refcount_merge_left_extent_error(cur->bc_mp,
-			cur->bc_ag.agno, error, _RET_IP_);
+			cur->bc_ag.pag->pag_agno, error, _RET_IP_);
 	return error;
 }
 
@@ -549,7 +549,7 @@ xfs_refcount_merge_right_extent(
 	int				found_rec;
 
 	trace_xfs_refcount_merge_right_extent(cur->bc_mp,
-			cur->bc_ag.agno, cright, right);
+			cur->bc_ag.pag->pag_agno, cright, right);
 
 	/*
 	 * If the extent ending at agbno+aglen (cright) wasn't synthesized,
@@ -595,7 +595,7 @@ xfs_refcount_merge_right_extent(
 
 out_error:
 	trace_xfs_refcount_merge_right_extent_error(cur->bc_mp,
-			cur->bc_ag.agno, error, _RET_IP_);
+			cur->bc_ag.pag->pag_agno, error, _RET_IP_);
 	return error;
 }
 
@@ -680,13 +680,13 @@ xfs_refcount_find_left_extents(
 		cleft->rc_blockcount = aglen;
 		cleft->rc_refcount = 1;
 	}
-	trace_xfs_refcount_find_left_extent(cur->bc_mp, cur->bc_ag.agno,
+	trace_xfs_refcount_find_left_extent(cur->bc_mp, cur->bc_ag.pag->pag_agno,
 			left, cleft, agbno);
 	return error;
 
 out_error:
 	trace_xfs_refcount_find_left_extent_error(cur->bc_mp,
-			cur->bc_ag.agno, error, _RET_IP_);
+			cur->bc_ag.pag->pag_agno, error, _RET_IP_);
 	return error;
 }
 
@@ -769,13 +769,13 @@ xfs_refcount_find_right_extents(
 		cright->rc_blockcount = aglen;
 		cright->rc_refcount = 1;
 	}
-	trace_xfs_refcount_find_right_extent(cur->bc_mp, cur->bc_ag.agno,
+	trace_xfs_refcount_find_right_extent(cur->bc_mp, cur->bc_ag.pag->pag_agno,
 			cright, right, agbno + aglen);
 	return error;
 
 out_error:
 	trace_xfs_refcount_find_right_extent_error(cur->bc_mp,
-			cur->bc_ag.agno, error, _RET_IP_);
+			cur->bc_ag.pag->pag_agno, error, _RET_IP_);
 	return error;
 }
 
@@ -953,7 +953,7 @@ xfs_refcount_adjust_extents(
 					ext.rc_startblock - *agbno);
 			tmp.rc_refcount = 1 + adj;
 			trace_xfs_refcount_modify_extent(cur->bc_mp,
-					cur->bc_ag.agno, &tmp);
+					cur->bc_ag.pag->pag_agno, &tmp);
 
 			/*
 			 * Either cover the hole (increment) or
@@ -972,7 +972,7 @@ xfs_refcount_adjust_extents(
 				cur->bc_ag.refc.nr_ops++;
 			} else {
 				fsbno = XFS_AGB_TO_FSB(cur->bc_mp,
-						cur->bc_ag.agno,
+						cur->bc_ag.pag->pag_agno,
 						tmp.rc_startblock);
 				xfs_bmap_add_free(cur->bc_tp, fsbno,
 						  tmp.rc_blockcount, oinfo);
@@ -999,7 +999,7 @@ xfs_refcount_adjust_extents(
 			goto skip;
 		ext.rc_refcount += adj;
 		trace_xfs_refcount_modify_extent(cur->bc_mp,
-				cur->bc_ag.agno, &ext);
+				cur->bc_ag.pag->pag_agno, &ext);
 		if (ext.rc_refcount > 1) {
 			error = xfs_refcount_update(cur, &ext);
 			if (error)
@@ -1017,7 +1017,7 @@ xfs_refcount_adjust_extents(
 			goto advloop;
 		} else {
 			fsbno = XFS_AGB_TO_FSB(cur->bc_mp,
-					cur->bc_ag.agno,
+					cur->bc_ag.pag->pag_agno,
 					ext.rc_startblock);
 			xfs_bmap_add_free(cur->bc_tp, fsbno, ext.rc_blockcount,
 					  oinfo);
@@ -1036,7 +1036,7 @@ xfs_refcount_adjust_extents(
 	return error;
 out_error:
 	trace_xfs_refcount_modify_extent_error(cur->bc_mp,
-			cur->bc_ag.agno, error, _RET_IP_);
+			cur->bc_ag.pag->pag_agno, error, _RET_IP_);
 	return error;
 }
 
@@ -1058,10 +1058,10 @@ xfs_refcount_adjust(
 	*new_agbno = agbno;
 	*new_aglen = aglen;
 	if (adj == XFS_REFCOUNT_ADJUST_INCREASE)
-		trace_xfs_refcount_increase(cur->bc_mp, cur->bc_ag.agno,
+		trace_xfs_refcount_increase(cur->bc_mp, cur->bc_ag.pag->pag_agno,
 				agbno, aglen);
 	else
-		trace_xfs_refcount_decrease(cur->bc_mp, cur->bc_ag.agno,
+		trace_xfs_refcount_decrease(cur->bc_mp, cur->bc_ag.pag->pag_agno,
 				agbno, aglen);
 
 	/*
@@ -1100,7 +1100,7 @@ xfs_refcount_adjust(
 	return 0;
 
 out_error:
-	trace_xfs_refcount_adjust_error(cur->bc_mp, cur->bc_ag.agno,
+	trace_xfs_refcount_adjust_error(cur->bc_mp, cur->bc_ag.pag->pag_agno,
 			error, _RET_IP_);
 	return error;
 }
@@ -1298,7 +1298,7 @@ xfs_refcount_find_shared(
 	int				have;
 	int				error;
 
-	trace_xfs_refcount_find_shared(cur->bc_mp, cur->bc_ag.agno,
+	trace_xfs_refcount_find_shared(cur->bc_mp, cur->bc_ag.pag->pag_agno,
 			agbno, aglen);
 
 	/* By default, skip the whole range */
@@ -1378,12 +1378,12 @@ xfs_refcount_find_shared(
 
 done:
 	trace_xfs_refcount_find_shared_result(cur->bc_mp,
-			cur->bc_ag.agno, *fbno, *flen);
+			cur->bc_ag.pag->pag_agno, *fbno, *flen);
 
 out_error:
 	if (error)
 		trace_xfs_refcount_find_shared_error(cur->bc_mp,
-				cur->bc_ag.agno, error, _RET_IP_);
+				cur->bc_ag.pag->pag_agno, error, _RET_IP_);
 	return error;
 }
 
@@ -1480,7 +1480,7 @@ xfs_refcount_adjust_cow_extents(
 		tmp.rc_blockcount = aglen;
 		tmp.rc_refcount = 1;
 		trace_xfs_refcount_modify_extent(cur->bc_mp,
-				cur->bc_ag.agno, &tmp);
+				cur->bc_ag.pag->pag_agno, &tmp);
 
 		error = xfs_refcount_insert(cur, &tmp,
 				&found_tmp);
@@ -1508,7 +1508,7 @@ xfs_refcount_adjust_cow_extents(
 
 		ext.rc_refcount = 0;
 		trace_xfs_refcount_modify_extent(cur->bc_mp,
-				cur->bc_ag.agno, &ext);
+				cur->bc_ag.pag->pag_agno, &ext);
 		error = xfs_refcount_delete(cur, &found_rec);
 		if (error)
 			goto out_error;
@@ -1524,7 +1524,7 @@ xfs_refcount_adjust_cow_extents(
 	return error;
 out_error:
 	trace_xfs_refcount_modify_extent_error(cur->bc_mp,
-			cur->bc_ag.agno, error, _RET_IP_);
+			cur->bc_ag.pag->pag_agno, error, _RET_IP_);
 	return error;
 }
 
@@ -1570,7 +1570,7 @@ xfs_refcount_adjust_cow(
 	return 0;
 
 out_error:
-	trace_xfs_refcount_adjust_cow_error(cur->bc_mp, cur->bc_ag.agno,
+	trace_xfs_refcount_adjust_cow_error(cur->bc_mp, cur->bc_ag.pag->pag_agno,
 			error, _RET_IP_);
 	return error;
 }
@@ -1584,7 +1584,7 @@ __xfs_refcount_cow_alloc(
 	xfs_agblock_t		agbno,
 	xfs_extlen_t		aglen)
 {
-	trace_xfs_refcount_cow_increase(rcur->bc_mp, rcur->bc_ag.agno,
+	trace_xfs_refcount_cow_increase(rcur->bc_mp, rcur->bc_ag.pag->pag_agno,
 			agbno, aglen);
 
 	/* Add refcount btree reservation */
@@ -1601,7 +1601,7 @@ __xfs_refcount_cow_free(
 	xfs_agblock_t		agbno,
 	xfs_extlen_t		aglen)
 {
-	trace_xfs_refcount_cow_decrease(rcur->bc_mp, rcur->bc_ag.agno,
+	trace_xfs_refcount_cow_decrease(rcur->bc_mp, rcur->bc_ag.pag->pag_agno,
 			agbno, aglen);
 
 	/* Remove refcount btree reservation */
diff --git a/fs/xfs/libxfs/xfs_refcount_btree.c b/fs/xfs/libxfs/xfs_refcount_btree.c
index 8f6577cb3475..92d336c17e83 100644
--- a/fs/xfs/libxfs/xfs_refcount_btree.c
+++ b/fs/xfs/libxfs/xfs_refcount_btree.c
@@ -65,7 +65,7 @@ xfs_refcountbt_alloc_block(
 	args.tp = cur->bc_tp;
 	args.mp = cur->bc_mp;
 	args.type = XFS_ALLOCTYPE_NEAR_BNO;
-	args.fsbno = XFS_AGB_TO_FSB(cur->bc_mp, cur->bc_ag.agno,
+	args.fsbno = XFS_AGB_TO_FSB(cur->bc_mp, cur->bc_ag.pag->pag_agno,
 			xfs_refc_block(args.mp));
 	args.oinfo = XFS_RMAP_OINFO_REFC;
 	args.minlen = args.maxlen = args.prod = 1;
@@ -74,13 +74,13 @@ xfs_refcountbt_alloc_block(
 	error = xfs_alloc_vextent(&args);
 	if (error)
 		goto out_error;
-	trace_xfs_refcountbt_alloc_block(cur->bc_mp, cur->bc_ag.agno,
+	trace_xfs_refcountbt_alloc_block(cur->bc_mp, cur->bc_ag.pag->pag_agno,
 			args.agbno, 1);
 	if (args.fsbno == NULLFSBLOCK) {
 		*stat = 0;
 		return 0;
 	}
-	ASSERT(args.agno == cur->bc_ag.agno);
+	ASSERT(args.agno == cur->bc_ag.pag->pag_agno);
 	ASSERT(args.len == 1);
 
 	new->s = cpu_to_be32(args.agbno);
@@ -105,7 +105,7 @@ xfs_refcountbt_free_block(
 	xfs_fsblock_t		fsbno = XFS_DADDR_TO_FSB(mp, XFS_BUF_ADDR(bp));
 	int			error;
 
-	trace_xfs_refcountbt_free_block(cur->bc_mp, cur->bc_ag.agno,
+	trace_xfs_refcountbt_free_block(cur->bc_mp, cur->bc_ag.pag->pag_agno,
 			XFS_FSB_TO_AGBNO(cur->bc_mp, fsbno), 1);
 	be32_add_cpu(&agf->agf_refcount_blocks, -1);
 	xfs_alloc_log_agf(cur->bc_tp, agbp, XFS_AGF_REFCOUNT_BLOCKS);
@@ -170,7 +170,7 @@ xfs_refcountbt_init_ptr_from_cur(
 {
 	struct xfs_agf		*agf = cur->bc_ag.agbp->b_addr;
 
-	ASSERT(cur->bc_ag.agno == be32_to_cpu(agf->agf_seqno));
+	ASSERT(cur->bc_ag.pag->pag_agno == be32_to_cpu(agf->agf_seqno));
 
 	ptr->s = agf->agf_refcount_root;
 }
@@ -334,7 +334,6 @@ xfs_refcountbt_init_common(
 	/* take a reference for the cursor */
 	atomic_inc(&pag->pag_ref);
 	cur->bc_ag.pag = pag;
-	cur->bc_ag.agno = pag->pag_agno;
 
 	cur->bc_ag.refc.nr_ops = 0;
 	cur->bc_ag.refc.shape_changes = 0;
diff --git a/fs/xfs/libxfs/xfs_rmap.c b/fs/xfs/libxfs/xfs_rmap.c
index b23f949ee15c..d1dfad0204e3 100644
--- a/fs/xfs/libxfs/xfs_rmap.c
+++ b/fs/xfs/libxfs/xfs_rmap.c
@@ -81,7 +81,7 @@ xfs_rmap_update(
 	union xfs_btree_rec	rec;
 	int			error;
 
-	trace_xfs_rmap_update(cur->bc_mp, cur->bc_ag.agno,
+	trace_xfs_rmap_update(cur->bc_mp, cur->bc_ag.pag->pag_agno,
 			irec->rm_startblock, irec->rm_blockcount,
 			irec->rm_owner, irec->rm_offset, irec->rm_flags);
 
@@ -93,7 +93,7 @@ xfs_rmap_update(
 	error = xfs_btree_update(cur, &rec);
 	if (error)
 		trace_xfs_rmap_update_error(cur->bc_mp,
-				cur->bc_ag.agno, error, _RET_IP_);
+				cur->bc_ag.pag->pag_agno, error, _RET_IP_);
 	return error;
 }
 
@@ -109,7 +109,7 @@ xfs_rmap_insert(
 	int			i;
 	int			error;
 
-	trace_xfs_rmap_insert(rcur->bc_mp, rcur->bc_ag.agno, agbno,
+	trace_xfs_rmap_insert(rcur->bc_mp, rcur->bc_ag.pag->pag_agno, agbno,
 			len, owner, offset, flags);
 
 	error = xfs_rmap_lookup_eq(rcur, agbno, len, owner, offset, flags, &i);
@@ -135,7 +135,7 @@ xfs_rmap_insert(
 done:
 	if (error)
 		trace_xfs_rmap_insert_error(rcur->bc_mp,
-				rcur->bc_ag.agno, error, _RET_IP_);
+				rcur->bc_ag.pag->pag_agno, error, _RET_IP_);
 	return error;
 }
 
@@ -151,7 +151,7 @@ xfs_rmap_delete(
 	int			i;
 	int			error;
 
-	trace_xfs_rmap_delete(rcur->bc_mp, rcur->bc_ag.agno, agbno,
+	trace_xfs_rmap_delete(rcur->bc_mp, rcur->bc_ag.pag->pag_agno, agbno,
 			len, owner, offset, flags);
 
 	error = xfs_rmap_lookup_eq(rcur, agbno, len, owner, offset, flags, &i);
@@ -172,7 +172,7 @@ xfs_rmap_delete(
 done:
 	if (error)
 		trace_xfs_rmap_delete_error(rcur->bc_mp,
-				rcur->bc_ag.agno, error, _RET_IP_);
+				rcur->bc_ag.pag->pag_agno, error, _RET_IP_);
 	return error;
 }
 
@@ -199,7 +199,7 @@ xfs_rmap_get_rec(
 	int			*stat)
 {
 	struct xfs_mount	*mp = cur->bc_mp;
-	xfs_agnumber_t		agno = cur->bc_ag.agno;
+	xfs_agnumber_t		agno = cur->bc_ag.pag->pag_agno;
 	union xfs_btree_rec	*rec;
 	int			error;
 
@@ -262,7 +262,7 @@ xfs_rmap_find_left_neighbor_helper(
 	struct xfs_find_left_neighbor_info	*info = priv;
 
 	trace_xfs_rmap_find_left_neighbor_candidate(cur->bc_mp,
-			cur->bc_ag.agno, rec->rm_startblock,
+			cur->bc_ag.pag->pag_agno, rec->rm_startblock,
 			rec->rm_blockcount, rec->rm_owner, rec->rm_offset,
 			rec->rm_flags);
 
@@ -314,7 +314,7 @@ xfs_rmap_find_left_neighbor(
 	info.stat = stat;
 
 	trace_xfs_rmap_find_left_neighbor_query(cur->bc_mp,
-			cur->bc_ag.agno, bno, 0, owner, offset, flags);
+			cur->bc_ag.pag->pag_agno, bno, 0, owner, offset, flags);
 
 	error = xfs_rmap_query_range(cur, &info.high, &info.high,
 			xfs_rmap_find_left_neighbor_helper, &info);
@@ -322,7 +322,7 @@ xfs_rmap_find_left_neighbor(
 		error = 0;
 	if (*stat)
 		trace_xfs_rmap_find_left_neighbor_result(cur->bc_mp,
-				cur->bc_ag.agno, irec->rm_startblock,
+				cur->bc_ag.pag->pag_agno, irec->rm_startblock,
 				irec->rm_blockcount, irec->rm_owner,
 				irec->rm_offset, irec->rm_flags);
 	return error;
@@ -338,7 +338,7 @@ xfs_rmap_lookup_le_range_helper(
 	struct xfs_find_left_neighbor_info	*info = priv;
 
 	trace_xfs_rmap_lookup_le_range_candidate(cur->bc_mp,
-			cur->bc_ag.agno, rec->rm_startblock,
+			cur->bc_ag.pag->pag_agno, rec->rm_startblock,
 			rec->rm_blockcount, rec->rm_owner, rec->rm_offset,
 			rec->rm_flags);
 
@@ -387,14 +387,14 @@ xfs_rmap_lookup_le_range(
 	info.stat = stat;
 
 	trace_xfs_rmap_lookup_le_range(cur->bc_mp,
-			cur->bc_ag.agno, bno, 0, owner, offset, flags);
+			cur->bc_ag.pag->pag_agno, bno, 0, owner, offset, flags);
 	error = xfs_rmap_query_range(cur, &info.high, &info.high,
 			xfs_rmap_lookup_le_range_helper, &info);
 	if (error == -ECANCELED)
 		error = 0;
 	if (*stat)
 		trace_xfs_rmap_lookup_le_range_result(cur->bc_mp,
-				cur->bc_ag.agno, irec->rm_startblock,
+				cur->bc_ag.pag->pag_agno, irec->rm_startblock,
 				irec->rm_blockcount, irec->rm_owner,
 				irec->rm_offset, irec->rm_flags);
 	return error;
@@ -500,7 +500,7 @@ xfs_rmap_unmap(
 			(flags & XFS_RMAP_BMBT_BLOCK);
 	if (unwritten)
 		flags |= XFS_RMAP_UNWRITTEN;
-	trace_xfs_rmap_unmap(mp, cur->bc_ag.agno, bno, len,
+	trace_xfs_rmap_unmap(mp, cur->bc_ag.pag->pag_agno, bno, len,
 			unwritten, oinfo);
 
 	/*
@@ -524,7 +524,7 @@ xfs_rmap_unmap(
 		goto out_error;
 	}
 	trace_xfs_rmap_lookup_le_range_result(cur->bc_mp,
-			cur->bc_ag.agno, ltrec.rm_startblock,
+			cur->bc_ag.pag->pag_agno, ltrec.rm_startblock,
 			ltrec.rm_blockcount, ltrec.rm_owner,
 			ltrec.rm_offset, ltrec.rm_flags);
 	ltoff = ltrec.rm_offset;
@@ -590,7 +590,7 @@ xfs_rmap_unmap(
 
 	if (ltrec.rm_startblock == bno && ltrec.rm_blockcount == len) {
 		/* exact match, simply remove the record from rmap tree */
-		trace_xfs_rmap_delete(mp, cur->bc_ag.agno,
+		trace_xfs_rmap_delete(mp, cur->bc_ag.pag->pag_agno,
 				ltrec.rm_startblock, ltrec.rm_blockcount,
 				ltrec.rm_owner, ltrec.rm_offset,
 				ltrec.rm_flags);
@@ -668,7 +668,7 @@ xfs_rmap_unmap(
 		else
 			cur->bc_rec.r.rm_offset = offset + len;
 		cur->bc_rec.r.rm_flags = flags;
-		trace_xfs_rmap_insert(mp, cur->bc_ag.agno,
+		trace_xfs_rmap_insert(mp, cur->bc_ag.pag->pag_agno,
 				cur->bc_rec.r.rm_startblock,
 				cur->bc_rec.r.rm_blockcount,
 				cur->bc_rec.r.rm_owner,
@@ -680,11 +680,11 @@ xfs_rmap_unmap(
 	}
 
 out_done:
-	trace_xfs_rmap_unmap_done(mp, cur->bc_ag.agno, bno, len,
+	trace_xfs_rmap_unmap_done(mp, cur->bc_ag.pag->pag_agno, bno, len,
 			unwritten, oinfo);
 out_error:
 	if (error)
-		trace_xfs_rmap_unmap_error(mp, cur->bc_ag.agno,
+		trace_xfs_rmap_unmap_error(mp, cur->bc_ag.pag->pag_agno,
 				error, _RET_IP_);
 	return error;
 }
@@ -775,7 +775,7 @@ xfs_rmap_map(
 			(flags & XFS_RMAP_BMBT_BLOCK);
 	if (unwritten)
 		flags |= XFS_RMAP_UNWRITTEN;
-	trace_xfs_rmap_map(mp, cur->bc_ag.agno, bno, len,
+	trace_xfs_rmap_map(mp, cur->bc_ag.pag->pag_agno, bno, len,
 			unwritten, oinfo);
 	ASSERT(!xfs_rmap_should_skip_owner_update(oinfo));
 
@@ -797,7 +797,7 @@ xfs_rmap_map(
 			goto out_error;
 		}
 		trace_xfs_rmap_lookup_le_range_result(cur->bc_mp,
-				cur->bc_ag.agno, ltrec.rm_startblock,
+				cur->bc_ag.pag->pag_agno, ltrec.rm_startblock,
 				ltrec.rm_blockcount, ltrec.rm_owner,
 				ltrec.rm_offset, ltrec.rm_flags);
 
@@ -833,7 +833,7 @@ xfs_rmap_map(
 			goto out_error;
 		}
 		trace_xfs_rmap_find_right_neighbor_result(cur->bc_mp,
-			cur->bc_ag.agno, gtrec.rm_startblock,
+			cur->bc_ag.pag->pag_agno, gtrec.rm_startblock,
 			gtrec.rm_blockcount, gtrec.rm_owner,
 			gtrec.rm_offset, gtrec.rm_flags);
 		if (!xfs_rmap_is_mergeable(&gtrec, owner, flags))
@@ -872,7 +872,7 @@ xfs_rmap_map(
 			 * result: |rrrrrrrrrrrrrrrrrrrrrrrrrrrrr|
 			 */
 			ltrec.rm_blockcount += gtrec.rm_blockcount;
-			trace_xfs_rmap_delete(mp, cur->bc_ag.agno,
+			trace_xfs_rmap_delete(mp, cur->bc_ag.pag->pag_agno,
 					gtrec.rm_startblock,
 					gtrec.rm_blockcount,
 					gtrec.rm_owner,
@@ -923,7 +923,7 @@ xfs_rmap_map(
 		cur->bc_rec.r.rm_owner = owner;
 		cur->bc_rec.r.rm_offset = offset;
 		cur->bc_rec.r.rm_flags = flags;
-		trace_xfs_rmap_insert(mp, cur->bc_ag.agno, bno, len,
+		trace_xfs_rmap_insert(mp, cur->bc_ag.pag->pag_agno, bno, len,
 			owner, offset, flags);
 		error = xfs_btree_insert(cur, &i);
 		if (error)
@@ -934,11 +934,11 @@ xfs_rmap_map(
 		}
 	}
 
-	trace_xfs_rmap_map_done(mp, cur->bc_ag.agno, bno, len,
+	trace_xfs_rmap_map_done(mp, cur->bc_ag.pag->pag_agno, bno, len,
 			unwritten, oinfo);
 out_error:
 	if (error)
-		trace_xfs_rmap_map_error(mp, cur->bc_ag.agno,
+		trace_xfs_rmap_map_error(mp, cur->bc_ag.pag->pag_agno,
 				error, _RET_IP_);
 	return error;
 }
@@ -1012,7 +1012,7 @@ xfs_rmap_convert(
 			(flags & (XFS_RMAP_ATTR_FORK | XFS_RMAP_BMBT_BLOCK))));
 	oldext = unwritten ? XFS_RMAP_UNWRITTEN : 0;
 	new_endoff = offset + len;
-	trace_xfs_rmap_convert(mp, cur->bc_ag.agno, bno, len,
+	trace_xfs_rmap_convert(mp, cur->bc_ag.pag->pag_agno, bno, len,
 			unwritten, oinfo);
 
 	/*
@@ -1036,7 +1036,7 @@ xfs_rmap_convert(
 		goto done;
 	}
 	trace_xfs_rmap_lookup_le_range_result(cur->bc_mp,
-			cur->bc_ag.agno, PREV.rm_startblock,
+			cur->bc_ag.pag->pag_agno, PREV.rm_startblock,
 			PREV.rm_blockcount, PREV.rm_owner,
 			PREV.rm_offset, PREV.rm_flags);
 
@@ -1078,7 +1078,7 @@ xfs_rmap_convert(
 			goto done;
 		}
 		trace_xfs_rmap_find_left_neighbor_result(cur->bc_mp,
-				cur->bc_ag.agno, LEFT.rm_startblock,
+				cur->bc_ag.pag->pag_agno, LEFT.rm_startblock,
 				LEFT.rm_blockcount, LEFT.rm_owner,
 				LEFT.rm_offset, LEFT.rm_flags);
 		if (LEFT.rm_startblock + LEFT.rm_blockcount == bno &&
@@ -1116,7 +1116,7 @@ xfs_rmap_convert(
 			goto done;
 		}
 		trace_xfs_rmap_find_right_neighbor_result(cur->bc_mp,
-				cur->bc_ag.agno, RIGHT.rm_startblock,
+				cur->bc_ag.pag->pag_agno, RIGHT.rm_startblock,
 				RIGHT.rm_blockcount, RIGHT.rm_owner,
 				RIGHT.rm_offset, RIGHT.rm_flags);
 		if (bno + len == RIGHT.rm_startblock &&
@@ -1134,7 +1134,7 @@ xfs_rmap_convert(
 	     RIGHT.rm_blockcount > XFS_RMAP_LEN_MAX)
 		state &= ~RMAP_RIGHT_CONTIG;
 
-	trace_xfs_rmap_convert_state(mp, cur->bc_ag.agno, state,
+	trace_xfs_rmap_convert_state(mp, cur->bc_ag.pag->pag_agno, state,
 			_RET_IP_);
 
 	/* reset the cursor back to PREV */
@@ -1164,7 +1164,7 @@ xfs_rmap_convert(
 			error = -EFSCORRUPTED;
 			goto done;
 		}
-		trace_xfs_rmap_delete(mp, cur->bc_ag.agno,
+		trace_xfs_rmap_delete(mp, cur->bc_ag.pag->pag_agno,
 				RIGHT.rm_startblock, RIGHT.rm_blockcount,
 				RIGHT.rm_owner, RIGHT.rm_offset,
 				RIGHT.rm_flags);
@@ -1182,7 +1182,7 @@ xfs_rmap_convert(
 			error = -EFSCORRUPTED;
 			goto done;
 		}
-		trace_xfs_rmap_delete(mp, cur->bc_ag.agno,
+		trace_xfs_rmap_delete(mp, cur->bc_ag.pag->pag_agno,
 				PREV.rm_startblock, PREV.rm_blockcount,
 				PREV.rm_owner, PREV.rm_offset,
 				PREV.rm_flags);
@@ -1212,7 +1212,7 @@ xfs_rmap_convert(
 		 * Setting all of a previous oldext extent to newext.
 		 * The left neighbor is contiguous, the right is not.
 		 */
-		trace_xfs_rmap_delete(mp, cur->bc_ag.agno,
+		trace_xfs_rmap_delete(mp, cur->bc_ag.pag->pag_agno,
 				PREV.rm_startblock, PREV.rm_blockcount,
 				PREV.rm_owner, PREV.rm_offset,
 				PREV.rm_flags);
@@ -1249,7 +1249,7 @@ xfs_rmap_convert(
 			error = -EFSCORRUPTED;
 			goto done;
 		}
-		trace_xfs_rmap_delete(mp, cur->bc_ag.agno,
+		trace_xfs_rmap_delete(mp, cur->bc_ag.pag->pag_agno,
 				RIGHT.rm_startblock, RIGHT.rm_blockcount,
 				RIGHT.rm_owner, RIGHT.rm_offset,
 				RIGHT.rm_flags);
@@ -1328,7 +1328,7 @@ xfs_rmap_convert(
 		NEW.rm_blockcount = len;
 		NEW.rm_flags = newext;
 		cur->bc_rec.r = NEW;
-		trace_xfs_rmap_insert(mp, cur->bc_ag.agno, bno,
+		trace_xfs_rmap_insert(mp, cur->bc_ag.pag->pag_agno, bno,
 				len, owner, offset, newext);
 		error = xfs_btree_insert(cur, &i);
 		if (error)
@@ -1385,7 +1385,7 @@ xfs_rmap_convert(
 		NEW.rm_blockcount = len;
 		NEW.rm_flags = newext;
 		cur->bc_rec.r = NEW;
-		trace_xfs_rmap_insert(mp, cur->bc_ag.agno, bno,
+		trace_xfs_rmap_insert(mp, cur->bc_ag.pag->pag_agno, bno,
 				len, owner, offset, newext);
 		error = xfs_btree_insert(cur, &i);
 		if (error)
@@ -1416,7 +1416,7 @@ xfs_rmap_convert(
 		NEW = PREV;
 		NEW.rm_blockcount = offset - PREV.rm_offset;
 		cur->bc_rec.r = NEW;
-		trace_xfs_rmap_insert(mp, cur->bc_ag.agno,
+		trace_xfs_rmap_insert(mp, cur->bc_ag.pag->pag_agno,
 				NEW.rm_startblock, NEW.rm_blockcount,
 				NEW.rm_owner, NEW.rm_offset,
 				NEW.rm_flags);
@@ -1443,7 +1443,7 @@ xfs_rmap_convert(
 		/* new middle extent - newext */
 		cur->bc_rec.r.rm_flags &= ~XFS_RMAP_UNWRITTEN;
 		cur->bc_rec.r.rm_flags |= newext;
-		trace_xfs_rmap_insert(mp, cur->bc_ag.agno, bno, len,
+		trace_xfs_rmap_insert(mp, cur->bc_ag.pag->pag_agno, bno, len,
 				owner, offset, newext);
 		error = xfs_btree_insert(cur, &i);
 		if (error)
@@ -1467,12 +1467,12 @@ xfs_rmap_convert(
 		ASSERT(0);
 	}
 
-	trace_xfs_rmap_convert_done(mp, cur->bc_ag.agno, bno, len,
+	trace_xfs_rmap_convert_done(mp, cur->bc_ag.pag->pag_agno, bno, len,
 			unwritten, oinfo);
 done:
 	if (error)
 		trace_xfs_rmap_convert_error(cur->bc_mp,
-				cur->bc_ag.agno, error, _RET_IP_);
+				cur->bc_ag.pag->pag_agno, error, _RET_IP_);
 	return error;
 }
 
@@ -1508,7 +1508,7 @@ xfs_rmap_convert_shared(
 			(flags & (XFS_RMAP_ATTR_FORK | XFS_RMAP_BMBT_BLOCK))));
 	oldext = unwritten ? XFS_RMAP_UNWRITTEN : 0;
 	new_endoff = offset + len;
-	trace_xfs_rmap_convert(mp, cur->bc_ag.agno, bno, len,
+	trace_xfs_rmap_convert(mp, cur->bc_ag.pag->pag_agno, bno, len,
 			unwritten, oinfo);
 
 	/*
@@ -1575,7 +1575,7 @@ xfs_rmap_convert_shared(
 			goto done;
 		}
 		trace_xfs_rmap_find_right_neighbor_result(cur->bc_mp,
-				cur->bc_ag.agno, RIGHT.rm_startblock,
+				cur->bc_ag.pag->pag_agno, RIGHT.rm_startblock,
 				RIGHT.rm_blockcount, RIGHT.rm_owner,
 				RIGHT.rm_offset, RIGHT.rm_flags);
 		if (xfs_rmap_is_mergeable(&RIGHT, owner, newext))
@@ -1591,7 +1591,7 @@ xfs_rmap_convert_shared(
 	     RIGHT.rm_blockcount > XFS_RMAP_LEN_MAX)
 		state &= ~RMAP_RIGHT_CONTIG;
 
-	trace_xfs_rmap_convert_state(mp, cur->bc_ag.agno, state,
+	trace_xfs_rmap_convert_state(mp, cur->bc_ag.pag->pag_agno, state,
 			_RET_IP_);
 	/*
 	 * Switch out based on the FILLING and CONTIG state bits.
@@ -1882,12 +1882,12 @@ xfs_rmap_convert_shared(
 		ASSERT(0);
 	}
 
-	trace_xfs_rmap_convert_done(mp, cur->bc_ag.agno, bno, len,
+	trace_xfs_rmap_convert_done(mp, cur->bc_ag.pag->pag_agno, bno, len,
 			unwritten, oinfo);
 done:
 	if (error)
 		trace_xfs_rmap_convert_error(cur->bc_mp,
-				cur->bc_ag.agno, error, _RET_IP_);
+				cur->bc_ag.pag->pag_agno, error, _RET_IP_);
 	return error;
 }
 
@@ -1925,7 +1925,7 @@ xfs_rmap_unmap_shared(
 	xfs_owner_info_unpack(oinfo, &owner, &offset, &flags);
 	if (unwritten)
 		flags |= XFS_RMAP_UNWRITTEN;
-	trace_xfs_rmap_unmap(mp, cur->bc_ag.agno, bno, len,
+	trace_xfs_rmap_unmap(mp, cur->bc_ag.pag->pag_agno, bno, len,
 			unwritten, oinfo);
 
 	/*
@@ -2074,12 +2074,12 @@ xfs_rmap_unmap_shared(
 			goto out_error;
 	}
 
-	trace_xfs_rmap_unmap_done(mp, cur->bc_ag.agno, bno, len,
+	trace_xfs_rmap_unmap_done(mp, cur->bc_ag.pag->pag_agno, bno, len,
 			unwritten, oinfo);
 out_error:
 	if (error)
 		trace_xfs_rmap_unmap_error(cur->bc_mp,
-				cur->bc_ag.agno, error, _RET_IP_);
+				cur->bc_ag.pag->pag_agno, error, _RET_IP_);
 	return error;
 }
 
@@ -2114,7 +2114,7 @@ xfs_rmap_map_shared(
 	xfs_owner_info_unpack(oinfo, &owner, &offset, &flags);
 	if (unwritten)
 		flags |= XFS_RMAP_UNWRITTEN;
-	trace_xfs_rmap_map(mp, cur->bc_ag.agno, bno, len,
+	trace_xfs_rmap_map(mp, cur->bc_ag.pag->pag_agno, bno, len,
 			unwritten, oinfo);
 
 	/* Is there a left record that abuts our range? */
@@ -2140,7 +2140,7 @@ xfs_rmap_map_shared(
 			goto out_error;
 		}
 		trace_xfs_rmap_find_right_neighbor_result(cur->bc_mp,
-			cur->bc_ag.agno, gtrec.rm_startblock,
+			cur->bc_ag.pag->pag_agno, gtrec.rm_startblock,
 			gtrec.rm_blockcount, gtrec.rm_owner,
 			gtrec.rm_offset, gtrec.rm_flags);
 
@@ -2233,12 +2233,12 @@ xfs_rmap_map_shared(
 			goto out_error;
 	}
 
-	trace_xfs_rmap_map_done(mp, cur->bc_ag.agno, bno, len,
+	trace_xfs_rmap_map_done(mp, cur->bc_ag.pag->pag_agno, bno, len,
 			unwritten, oinfo);
 out_error:
 	if (error)
 		trace_xfs_rmap_map_error(cur->bc_mp,
-				cur->bc_ag.agno, error, _RET_IP_);
+				cur->bc_ag.pag->pag_agno, error, _RET_IP_);
 	return error;
 }
 
@@ -2389,7 +2389,7 @@ xfs_rmap_finish_one(
 	 * the startblock, get one now.
 	 */
 	rcur = *pcur;
-	if (rcur != NULL && rcur->bc_ag.agno != pag->pag_agno) {
+	if (rcur != NULL && rcur->bc_ag.pag != pag) {
 		xfs_rmap_finish_one_cleanup(tp, rcur, 0);
 		rcur = NULL;
 		*pcur = NULL;
diff --git a/fs/xfs/libxfs/xfs_rmap_btree.c b/fs/xfs/libxfs/xfs_rmap_btree.c
index cafe181bc92d..f29bc71b9950 100644
--- a/fs/xfs/libxfs/xfs_rmap_btree.c
+++ b/fs/xfs/libxfs/xfs_rmap_btree.c
@@ -464,7 +464,6 @@ xfs_rmapbt_init_common(
 	/* take a reference for the cursor */
 	atomic_inc(&pag->pag_ref);
 	cur->bc_ag.pag = pag;
-	cur->bc_ag.agno = pag->pag_agno;
 
 	return cur;
 }
diff --git a/fs/xfs/scrub/agheader_repair.c b/fs/xfs/scrub/agheader_repair.c
index ecc9146647ba..e95f8c98f0f7 100644
--- a/fs/xfs/scrub/agheader_repair.c
+++ b/fs/xfs/scrub/agheader_repair.c
@@ -454,7 +454,7 @@ xrep_agfl_walk_rmap(
 
 	/* Record all the OWN_AG blocks. */
 	if (rec->rm_owner == XFS_RMAP_OWN_AG) {
-		fsb = XFS_AGB_TO_FSB(cur->bc_mp, cur->bc_ag.agno,
+		fsb = XFS_AGB_TO_FSB(cur->bc_mp, cur->bc_ag.pag->pag_agno,
 				rec->rm_startblock);
 		error = xbitmap_set(ra->freesp, fsb, rec->rm_blockcount);
 		if (error)
diff --git a/fs/xfs/scrub/alloc.c b/fs/xfs/scrub/alloc.c
index 2720bd7fe53b..d5741980094a 100644
--- a/fs/xfs/scrub/alloc.c
+++ b/fs/xfs/scrub/alloc.c
@@ -15,6 +15,7 @@
 #include "scrub/scrub.h"
 #include "scrub/common.h"
 #include "scrub/btree.h"
+#include "xfs_ag.h"
 
 /*
  * Set us up to scrub free space btrees.
@@ -93,7 +94,7 @@ xchk_allocbt_rec(
 	union xfs_btree_rec	*rec)
 {
 	struct xfs_mount	*mp = bs->cur->bc_mp;
-	xfs_agnumber_t		agno = bs->cur->bc_ag.agno;
+	xfs_agnumber_t		agno = bs->cur->bc_ag.pag->pag_agno;
 	xfs_agblock_t		bno;
 	xfs_extlen_t		len;
 
diff --git a/fs/xfs/scrub/bmap.c b/fs/xfs/scrub/bmap.c
index 5adef162115d..b9c205a2fede 100644
--- a/fs/xfs/scrub/bmap.c
+++ b/fs/xfs/scrub/bmap.c
@@ -515,7 +515,7 @@ xchk_bmap_check_rmap(
 			xchk_fblock_set_corrupt(sc, sbcri->whichfork,
 					rec->rm_offset);
 		if (irec.br_startblock != XFS_AGB_TO_FSB(sc->mp,
-				cur->bc_ag.agno, rec->rm_startblock))
+				cur->bc_ag.pag->pag_agno, rec->rm_startblock))
 			xchk_fblock_set_corrupt(sc, sbcri->whichfork,
 					rec->rm_offset);
 		if (irec.br_blockcount > rec->rm_blockcount)
diff --git a/fs/xfs/scrub/ialloc.c b/fs/xfs/scrub/ialloc.c
index 8d9f3fb0cd22..30e568596b79 100644
--- a/fs/xfs/scrub/ialloc.c
+++ b/fs/xfs/scrub/ialloc.c
@@ -21,6 +21,7 @@
 #include "scrub/common.h"
 #include "scrub/btree.h"
 #include "scrub/trace.h"
+#include "xfs_ag.h"
 
 /*
  * Set us up to scrub inode btrees.
@@ -103,7 +104,7 @@ xchk_iallocbt_chunk(
 	xfs_extlen_t			len)
 {
 	struct xfs_mount		*mp = bs->cur->bc_mp;
-	xfs_agnumber_t			agno = bs->cur->bc_ag.agno;
+	xfs_agnumber_t			agno = bs->cur->bc_ag.pag->pag_agno;
 	xfs_agblock_t			bno;
 
 	bno = XFS_AGINO_TO_AGBNO(mp, agino);
@@ -163,7 +164,7 @@ xchk_iallocbt_check_cluster_ifree(
 	 * the record, compute which fs inode we're talking about.
 	 */
 	agino = irec->ir_startino + irec_ino;
-	fsino = XFS_AGINO_TO_INO(mp, bs->cur->bc_ag.agno, agino);
+	fsino = XFS_AGINO_TO_INO(mp, bs->cur->bc_ag.pag->pag_agno, agino);
 	irec_free = (irec->ir_free & XFS_INOBT_MASK(irec_ino));
 
 	if (be16_to_cpu(dip->di_magic) != XFS_DINODE_MAGIC ||
@@ -213,7 +214,7 @@ xchk_iallocbt_check_cluster(
 	struct xfs_mount		*mp = bs->cur->bc_mp;
 	struct xfs_buf			*cluster_bp;
 	unsigned int			nr_inodes;
-	xfs_agnumber_t			agno = bs->cur->bc_ag.agno;
+	xfs_agnumber_t			agno = bs->cur->bc_ag.pag->pag_agno;
 	xfs_agblock_t			agbno;
 	unsigned int			cluster_index;
 	uint16_t			cluster_mask = 0;
@@ -423,7 +424,7 @@ xchk_iallocbt_rec(
 	struct xchk_iallocbt		*iabt = bs->private;
 	struct xfs_inobt_rec_incore	irec;
 	uint64_t			holes;
-	xfs_agnumber_t			agno = bs->cur->bc_ag.agno;
+	xfs_agnumber_t			agno = bs->cur->bc_ag.pag->pag_agno;
 	xfs_agino_t			agino;
 	xfs_extlen_t			len;
 	int				holecount;
diff --git a/fs/xfs/scrub/refcount.c b/fs/xfs/scrub/refcount.c
index 744530a66c0c..7014b7408bad 100644
--- a/fs/xfs/scrub/refcount.c
+++ b/fs/xfs/scrub/refcount.c
@@ -13,6 +13,7 @@
 #include "scrub/scrub.h"
 #include "scrub/common.h"
 #include "scrub/btree.h"
+#include "xfs_ag.h"
 
 /*
  * Set us up to scrub reference count btrees.
@@ -333,7 +334,7 @@ xchk_refcountbt_rec(
 {
 	struct xfs_mount	*mp = bs->cur->bc_mp;
 	xfs_agblock_t		*cow_blocks = bs->private;
-	xfs_agnumber_t		agno = bs->cur->bc_ag.agno;
+	xfs_agnumber_t		agno = bs->cur->bc_ag.pag->pag_agno;
 	xfs_agblock_t		bno;
 	xfs_extlen_t		len;
 	xfs_nlink_t		refcount;
diff --git a/fs/xfs/scrub/rmap.c b/fs/xfs/scrub/rmap.c
index a4f17477c5d1..fc306573f0ac 100644
--- a/fs/xfs/scrub/rmap.c
+++ b/fs/xfs/scrub/rmap.c
@@ -15,6 +15,7 @@
 #include "scrub/scrub.h"
 #include "scrub/common.h"
 #include "scrub/btree.h"
+#include "xfs_ag.h"
 
 /*
  * Set us up to scrub reverse mapping btrees.
@@ -91,7 +92,7 @@ xchk_rmapbt_rec(
 {
 	struct xfs_mount	*mp = bs->cur->bc_mp;
 	struct xfs_rmap_irec	irec;
-	xfs_agnumber_t		agno = bs->cur->bc_ag.agno;
+	xfs_agnumber_t		agno = bs->cur->bc_ag.pag->pag_agno;
 	bool			non_inode;
 	bool			is_unwritten;
 	bool			is_bmbt;
diff --git a/fs/xfs/scrub/trace.c b/fs/xfs/scrub/trace.c
index 2c6c248be823..03882a605a3c 100644
--- a/fs/xfs/scrub/trace.c
+++ b/fs/xfs/scrub/trace.c
@@ -13,6 +13,7 @@
 #include "xfs_inode.h"
 #include "xfs_btree.h"
 #include "scrub/scrub.h"
+#include "xfs_ag.h"
 
 /* Figure out which block the btree cursor was pointing to. */
 static inline xfs_fsblock_t
@@ -26,7 +27,7 @@ xchk_btree_cur_fsbno(
 		 cur->bc_flags & XFS_BTREE_LONG_PTRS)
 		return XFS_INO_TO_FSB(cur->bc_mp, cur->bc_ino.ip->i_ino);
 	else if (!(cur->bc_flags & XFS_BTREE_LONG_PTRS))
-		return XFS_AGB_TO_FSB(cur->bc_mp, cur->bc_ag.agno, 0);
+		return XFS_AGB_TO_FSB(cur->bc_mp, cur->bc_ag.pag->pag_agno, 0);
 	return NULLFSBLOCK;
 }
 
diff --git a/fs/xfs/xfs_fsmap.c b/fs/xfs/xfs_fsmap.c
index 7501dd941a63..7d0b09c1366e 100644
--- a/fs/xfs/xfs_fsmap.c
+++ b/fs/xfs/xfs_fsmap.c
@@ -355,7 +355,7 @@ xfs_getfsmap_datadev_helper(
 	xfs_fsblock_t			fsb;
 	xfs_daddr_t			rec_daddr;
 
-	fsb = XFS_AGB_TO_FSB(mp, cur->bc_ag.agno, rec->rm_startblock);
+	fsb = XFS_AGB_TO_FSB(mp, cur->bc_ag.pag->pag_agno, rec->rm_startblock);
 	rec_daddr = XFS_FSB_TO_DADDR(mp, fsb);
 
 	return xfs_getfsmap_helper(cur->bc_tp, info, rec, rec_daddr);
@@ -373,7 +373,7 @@ xfs_getfsmap_datadev_bnobt_helper(
 	struct xfs_rmap_irec		irec;
 	xfs_daddr_t			rec_daddr;
 
-	rec_daddr = XFS_AGB_TO_DADDR(mp, cur->bc_ag.agno,
+	rec_daddr = XFS_AGB_TO_DADDR(mp, cur->bc_ag.pag->pag_agno,
 			rec->ar_startblock);
 
 	irec.rm_startblock = rec->ar_startblock;
diff --git a/fs/xfs/xfs_trace.h b/fs/xfs/xfs_trace.h
index 808ae337b222..5ba9c6396dcb 100644
--- a/fs/xfs/xfs_trace.h
+++ b/fs/xfs/xfs_trace.h
@@ -3730,7 +3730,7 @@ TRACE_EVENT(xfs_btree_commit_afakeroot,
 	TP_fast_assign(
 		__entry->dev = cur->bc_mp->m_super->s_dev;
 		__entry->btnum = cur->bc_btnum;
-		__entry->agno = cur->bc_ag.agno;
+		__entry->agno = cur->bc_ag.pag->pag_agno;
 		__entry->agbno = cur->bc_ag.afake->af_root;
 		__entry->levels = cur->bc_ag.afake->af_levels;
 		__entry->blocks = cur->bc_ag.afake->af_blocks;
@@ -3845,7 +3845,7 @@ TRACE_EVENT(xfs_btree_bload_block,
 			__entry->agno = XFS_FSB_TO_AGNO(cur->bc_mp, fsb);
 			__entry->agbno = XFS_FSB_TO_AGBNO(cur->bc_mp, fsb);
 		} else {
-			__entry->agno = cur->bc_ag.agno;
+			__entry->agno = cur->bc_ag.pag->pag_agno;
 			__entry->agbno = be32_to_cpu(ptr->s);
 		}
 		__entry->nr_records = nr_records;
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 87+ messages in thread

* [PATCH 17/22] xfs: simplify xfs_dialloc_select_ag() return values
  2021-05-06  7:20 [RFC 00/22] xfs: initial agnumber -> perag conversions for shrink Dave Chinner
                   ` (15 preceding siblings ...)
  2021-05-06  7:20 ` [PATCH 16/22] xfs: remove agno from btree cursor Dave Chinner
@ 2021-05-06  7:20 ` Dave Chinner
  2021-05-12 12:49   ` Brian Foster
  2021-05-12 22:55   ` Darrick J. Wong
  2021-05-06  7:20 ` [PATCH 18/22] xfs: collapse AG selection for inode allocation Dave Chinner
                   ` (4 subsequent siblings)
  21 siblings, 2 replies; 87+ messages in thread
From: Dave Chinner @ 2021-05-06  7:20 UTC (permalink / raw)
  To: linux-xfs

From: Dave Chinner <dchinner@redhat.com>

The only caller of xfs_dialloc_select_ag() will always return
-ENOSPC to it's caller if the agbp returned from
xfs_dialloc_select_ag() is NULL. IOWs, failure to find a candidate
AGI we can allocate inodes from is always an ENOSPC condition, so
move this logic up into xfs_dialloc_select_ag() so we can simplify
the return logic in this function.

xfs_dialloc_select_ag() now only ever returns 0 with a locked
agbp, or an error with no agbp.

Signed-off-by: Dave Chinner <dchinner@redhat.com>
---
 fs/xfs/libxfs/xfs_ialloc.c | 23 ++++++++---------------
 fs/xfs/xfs_inode.c         |  3 ---
 2 files changed, 8 insertions(+), 18 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_ialloc.c b/fs/xfs/libxfs/xfs_ialloc.c
index 4540fbcd68a3..872591e8f5cb 100644
--- a/fs/xfs/libxfs/xfs_ialloc.c
+++ b/fs/xfs/libxfs/xfs_ialloc.c
@@ -1717,7 +1717,7 @@ xfs_dialloc_roll(
  * This function will ensure that the selected AG has free inodes available to
  * allocate from. The selected AGI will be returned locked to the caller, and it
  * will allocate more free inodes if required. If no free inodes are found or
- * can be allocated, no AGI will be returned.
+ * can be allocated, -ENOSPC be returned.
  */
 int
 xfs_dialloc_select_ag(
@@ -1730,7 +1730,6 @@ xfs_dialloc_select_ag(
 	struct xfs_buf		*agbp;
 	xfs_agnumber_t		agno;
 	int			error;
-	bool			noroom = false;
 	xfs_agnumber_t		start_agno;
 	struct xfs_perag	*pag;
 	struct xfs_ino_geometry	*igeo = M_IGEO(mp);
@@ -1744,7 +1743,7 @@ xfs_dialloc_select_ag(
 	 */
 	start_agno = xfs_ialloc_ag_select(*tpp, parent, mode);
 	if (start_agno == NULLAGNUMBER)
-		return 0;
+		return -ENOSPC;
 
 	/*
 	 * If we have already hit the ceiling of inode blocks then clear
@@ -1757,7 +1756,6 @@ xfs_dialloc_select_ag(
 	if (igeo->maxicount &&
 	    percpu_counter_read_positive(&mp->m_icount) + igeo->ialloc_inos
 							> igeo->maxicount) {
-		noroom = true;
 		okalloc = false;
 	}
 
@@ -1794,10 +1792,8 @@ xfs_dialloc_select_ag(
 		if (error)
 			break;
 
-		if (pag->pagi_freecount) {
-			xfs_perag_put(pag);
+		if (pag->pagi_freecount)
 			goto found_ag;
-		}
 
 		if (!okalloc)
 			goto nextag_relse_buffer;
@@ -1805,9 +1801,6 @@ xfs_dialloc_select_ag(
 		error = xfs_ialloc_ag_alloc(*tpp, agbp, pag);
 		if (error < 0) {
 			xfs_trans_brelse(*tpp, agbp);
-
-			if (error == -ENOSPC)
-				error = 0;
 			break;
 		}
 
@@ -1818,12 +1811,11 @@ xfs_dialloc_select_ag(
 			 * allocate one of the new inodes.
 			 */
 			ASSERT(pag->pagi_freecount > 0);
-			xfs_perag_put(pag);
 
 			error = xfs_dialloc_roll(tpp, agbp);
 			if (error) {
 				xfs_buf_relse(agbp);
-				return error;
+				break;
 			}
 			goto found_ag;
 		}
@@ -1831,16 +1823,17 @@ xfs_dialloc_select_ag(
 nextag_relse_buffer:
 		xfs_trans_brelse(*tpp, agbp);
 nextag:
-		xfs_perag_put(pag);
 		if (++agno == mp->m_sb.sb_agcount)
 			agno = 0;
 		if (agno == start_agno)
-			return noroom ? -ENOSPC : 0;
+			break;
+		xfs_perag_put(pag);
 	}
 
 	xfs_perag_put(pag);
-	return error;
+	return error ? error : -ENOSPC;
 found_ag:
+	xfs_perag_put(pag);
 	*IO_agbp = agbp;
 	return 0;
 }
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
index 25910b145d70..3918c99fa95b 100644
--- a/fs/xfs/xfs_inode.c
+++ b/fs/xfs/xfs_inode.c
@@ -923,9 +923,6 @@ xfs_dir_ialloc(
 	if (error)
 		return error;
 
-	if (!agibp)
-		return -ENOSPC;
-
 	/* Allocate an inode from the selected AG */
 	error = xfs_dialloc_ag(*tpp, agibp, parent_ino, &ino);
 	if (error)
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 87+ messages in thread

* [PATCH 18/22] xfs: collapse AG selection for inode allocation
  2021-05-06  7:20 [RFC 00/22] xfs: initial agnumber -> perag conversions for shrink Dave Chinner
                   ` (16 preceding siblings ...)
  2021-05-06  7:20 ` [PATCH 17/22] xfs: simplify xfs_dialloc_select_ag() return values Dave Chinner
@ 2021-05-06  7:20 ` Dave Chinner
  2021-05-12 12:52   ` Brian Foster
  2021-05-12 23:11   ` Darrick J. Wong
  2021-05-06  7:20 ` [PATCH 19/22] xfs: get rid of xfs_dir_ialloc() Dave Chinner
                   ` (3 subsequent siblings)
  21 siblings, 2 replies; 87+ messages in thread
From: Dave Chinner @ 2021-05-06  7:20 UTC (permalink / raw)
  To: linux-xfs

From: Dave Chinner <dchinner@redhat.com>

xfs_dialloc_select_ag() does a lot of repetitive work. It first
calls xfs_ialloc_ag_select() to select the AG to start allocation
attempts in, which can do up to two entire loops across the perags
that inodes can be allocated in. This is simply checking if there is
spce available to allocate inodes in an AG, and it returns when it
finds the first candidate AG.

xfs_dialloc_select_ag() then does it's own iterative walk across
all the perags locking the AGIs and trying to allocate inodes from
the locked AG. It also doesn't limit the search to mp->m_maxagi,
so it will walk all AGs whether they can allocate inodes or not.

Hence if we are really low on inodes, we could do almost 3 entire
walks across the whole perag range before we find an allocation
group we can allocate inodes in or report ENOSPC.

Because xfs_ialloc_ag_select() returns on the first candidate AG it
finds, we can simply do these checks directly in
xfs_dialloc_select_ag() before we lock and try to allocate inodes.
This reduces the inode allocation pass down to 2 perag sweeps at
most - one for aligned inode cluster allocation and if we can't
allocate full, aligned inode clusters anywhere we'll do another pass
trying to do sparse inode cluster allocation.

This also removes a big chunk of duplicate code.

Signed-off-by: Dave Chinner <dchinner@redhat.com>
---
 fs/xfs/libxfs/xfs_ialloc.c | 221 +++++++++++++------------------------
 1 file changed, 75 insertions(+), 146 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_ialloc.c b/fs/xfs/libxfs/xfs_ialloc.c
index 872591e8f5cb..b22556556bba 100644
--- a/fs/xfs/libxfs/xfs_ialloc.c
+++ b/fs/xfs/libxfs/xfs_ialloc.c
@@ -899,139 +899,6 @@ xfs_ialloc_ag_alloc(
 	return 0;
 }
 
-STATIC xfs_agnumber_t
-xfs_ialloc_next_ag(
-	xfs_mount_t	*mp)
-{
-	xfs_agnumber_t	agno;
-
-	spin_lock(&mp->m_agirotor_lock);
-	agno = mp->m_agirotor;
-	if (++mp->m_agirotor >= mp->m_maxagi)
-		mp->m_agirotor = 0;
-	spin_unlock(&mp->m_agirotor_lock);
-
-	return agno;
-}
-
-/*
- * Select an allocation group to look for a free inode in, based on the parent
- * inode and the mode.  Return the allocation group buffer.
- */
-STATIC xfs_agnumber_t
-xfs_ialloc_ag_select(
-	xfs_trans_t	*tp,		/* transaction pointer */
-	xfs_ino_t	parent,		/* parent directory inode number */
-	umode_t		mode)		/* bits set to indicate file type */
-{
-	xfs_agnumber_t	agcount;	/* number of ag's in the filesystem */
-	xfs_agnumber_t	agno;		/* current ag number */
-	int		flags;		/* alloc buffer locking flags */
-	xfs_extlen_t	ineed;		/* blocks needed for inode allocation */
-	xfs_extlen_t	longest = 0;	/* longest extent available */
-	xfs_mount_t	*mp;		/* mount point structure */
-	int		needspace;	/* file mode implies space allocated */
-	xfs_perag_t	*pag;		/* per allocation group data */
-	xfs_agnumber_t	pagno;		/* parent (starting) ag number */
-	int		error;
-
-	/*
-	 * Files of these types need at least one block if length > 0
-	 * (and they won't fit in the inode, but that's hard to figure out).
-	 */
-	needspace = S_ISDIR(mode) || S_ISREG(mode) || S_ISLNK(mode);
-	mp = tp->t_mountp;
-	agcount = mp->m_maxagi;
-	if (S_ISDIR(mode))
-		pagno = xfs_ialloc_next_ag(mp);
-	else {
-		pagno = XFS_INO_TO_AGNO(mp, parent);
-		if (pagno >= agcount)
-			pagno = 0;
-	}
-
-	ASSERT(pagno < agcount);
-
-	/*
-	 * Loop through allocation groups, looking for one with a little
-	 * free space in it.  Note we don't look for free inodes, exactly.
-	 * Instead, we include whether there is a need to allocate inodes
-	 * to mean that blocks must be allocated for them,
-	 * if none are currently free.
-	 */
-	agno = pagno;
-	flags = XFS_ALLOC_FLAG_TRYLOCK;
-	for (;;) {
-		pag = xfs_perag_get(mp, agno);
-		if (!pag->pagi_inodeok) {
-			xfs_ialloc_next_ag(mp);
-			goto nextag;
-		}
-
-		if (!pag->pagi_init) {
-			error = xfs_ialloc_pagi_init(mp, tp, agno);
-			if (error)
-				goto nextag;
-		}
-
-		if (pag->pagi_freecount) {
-			xfs_perag_put(pag);
-			return agno;
-		}
-
-		if (!pag->pagf_init) {
-			error = xfs_alloc_pagf_init(mp, tp, agno, flags);
-			if (error)
-				goto nextag;
-		}
-
-		/*
-		 * Check that there is enough free space for the file plus a
-		 * chunk of inodes if we need to allocate some. If this is the
-		 * first pass across the AGs, take into account the potential
-		 * space needed for alignment of inode chunks when checking the
-		 * longest contiguous free space in the AG - this prevents us
-		 * from getting ENOSPC because we have free space larger than
-		 * ialloc_blks but alignment constraints prevent us from using
-		 * it.
-		 *
-		 * If we can't find an AG with space for full alignment slack to
-		 * be taken into account, we must be near ENOSPC in all AGs.
-		 * Hence we don't include alignment for the second pass and so
-		 * if we fail allocation due to alignment issues then it is most
-		 * likely a real ENOSPC condition.
-		 */
-		ineed = M_IGEO(mp)->ialloc_min_blks;
-		if (flags && ineed > 1)
-			ineed += M_IGEO(mp)->cluster_align;
-		longest = pag->pagf_longest;
-		if (!longest)
-			longest = pag->pagf_flcount > 0;
-
-		if (pag->pagf_freeblks >= needspace + ineed &&
-		    longest >= ineed) {
-			xfs_perag_put(pag);
-			return agno;
-		}
-nextag:
-		xfs_perag_put(pag);
-		/*
-		 * No point in iterating over the rest, if we're shutting
-		 * down.
-		 */
-		if (XFS_FORCED_SHUTDOWN(mp))
-			return NULLAGNUMBER;
-		agno++;
-		if (agno >= agcount)
-			agno = 0;
-		if (agno == pagno) {
-			if (flags == 0)
-				return NULLAGNUMBER;
-			flags = 0;
-		}
-	}
-}
-
 /*
  * Try to retrieve the next record to the left/right from the current one.
  */
@@ -1708,6 +1575,21 @@ xfs_dialloc_roll(
 	return 0;
 }
 
+STATIC xfs_agnumber_t
+xfs_ialloc_next_ag(
+	xfs_mount_t	*mp)
+{
+	xfs_agnumber_t	agno;
+
+	spin_lock(&mp->m_agirotor_lock);
+	agno = mp->m_agirotor;
+	if (++mp->m_agirotor >= mp->m_maxagi)
+		mp->m_agirotor = 0;
+	spin_unlock(&mp->m_agirotor_lock);
+
+	return agno;
+}
+
 /*
  * Select and prepare an AG for inode allocation.
  *
@@ -1734,16 +1616,23 @@ xfs_dialloc_select_ag(
 	struct xfs_perag	*pag;
 	struct xfs_ino_geometry	*igeo = M_IGEO(mp);
 	bool			okalloc = true;
+	int			needspace;
+	int			flags;
 
 	*IO_agbp = NULL;
 
 	/*
-	 * We do not have an agbp, so select an initial allocation
-	 * group for inode allocation.
+	 * Files of these types need at least one block if length > 0
+	 * (and they won't fit in the inode, but that's hard to figure out).
 	 */
-	start_agno = xfs_ialloc_ag_select(*tpp, parent, mode);
-	if (start_agno == NULLAGNUMBER)
-		return -ENOSPC;
+	needspace = S_ISDIR(mode) || S_ISREG(mode) || S_ISLNK(mode);
+	if (S_ISDIR(mode))
+		start_agno = xfs_ialloc_next_ag(mp);
+	else {
+		start_agno = XFS_INO_TO_AGNO(mp, parent);
+		if (start_agno >= mp->m_maxagi)
+			start_agno = 0;
+	}
 
 	/*
 	 * If we have already hit the ceiling of inode blocks then clear
@@ -1765,12 +1654,14 @@ xfs_dialloc_select_ag(
 	 * allocation groups upward, wrapping at the end.
 	 */
 	agno = start_agno;
+	flags = XFS_ALLOC_FLAG_TRYLOCK;
 	for (;;) {
+		xfs_extlen_t	ineed;
+		xfs_extlen_t	longest = 0;
+
 		pag = xfs_perag_get(mp, agno);
-		if (!pag->pagi_inodeok) {
-			xfs_ialloc_next_ag(mp);
+		if (!pag->pagi_inodeok)
 			goto nextag;
-		}
 
 		if (!pag->pagi_init) {
 			error = xfs_ialloc_pagi_init(mp, *tpp, agno);
@@ -1778,10 +1669,41 @@ xfs_dialloc_select_ag(
 				break;
 		}
 
+		if (!pag->pagi_freecount)
+			goto nextag;
+		if (!okalloc)
+			goto nextag;
+
+		if (!pag->pagf_init) {
+			error = xfs_alloc_pagf_init(mp, *tpp, agno, flags);
+			if (error)
+				goto nextag;
+		}
+
 		/*
-		 * Do a first racy fast path check if this AG is usable.
+		 * Check that there is enough free space for the file plus a
+		 * chunk of inodes if we need to allocate some. If this is the
+		 * first pass across the AGs, take into account the potential
+		 * space needed for alignment of inode chunks when checking the
+		 * longest contiguous free space in the AG - this prevents us
+		 * from getting ENOSPC because we have free space larger than
+		 * ialloc_blks but alignment constraints prevent us from using
+		 * it.
+		 *
+		 * If we can't find an AG with space for full alignment slack to
+		 * be taken into account, we must be near ENOSPC in all AGs.
+		 * Hence we don't include alignment for the second pass and so
+		 * if we fail allocation due to alignment issues then it is most
+		 * likely a real ENOSPC condition.
 		 */
-		if (!pag->pagi_freecount && !okalloc)
+		ineed = M_IGEO(mp)->ialloc_min_blks;
+		if (flags && ineed > 1)
+			ineed += M_IGEO(mp)->cluster_align;
+		longest = pag->pagf_longest;
+		if (!longest)
+			longest = pag->pagf_flcount > 0;
+
+		if (pag->pagf_freeblks < needspace + ineed || longest < ineed)
 			goto nextag;
 
 		/*
@@ -1823,10 +1745,17 @@ xfs_dialloc_select_ag(
 nextag_relse_buffer:
 		xfs_trans_brelse(*tpp, agbp);
 nextag:
-		if (++agno == mp->m_sb.sb_agcount)
-			agno = 0;
-		if (agno == start_agno)
+		if (XFS_FORCED_SHUTDOWN(mp)) {
+			error = -EFSCORRUPTED;
 			break;
+		}
+		if (++agno == mp->m_maxagi)
+			agno = 0;
+		if (agno == start_agno) {
+			if (!flags)
+				break;
+			flags = 0;
+		}
 		xfs_perag_put(pag);
 	}
 
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 87+ messages in thread

* [PATCH 19/22] xfs: get rid of xfs_dir_ialloc()
  2021-05-06  7:20 [RFC 00/22] xfs: initial agnumber -> perag conversions for shrink Dave Chinner
                   ` (17 preceding siblings ...)
  2021-05-06  7:20 ` [PATCH 18/22] xfs: collapse AG selection for inode allocation Dave Chinner
@ 2021-05-06  7:20 ` Dave Chinner
  2021-05-06 11:26     ` kernel test robot
                     ` (3 more replies)
  2021-05-06  7:20 ` [PATCH 20/22] xfs: inode allocation can use a single perag instance Dave Chinner
                   ` (2 subsequent siblings)
  21 siblings, 4 replies; 87+ messages in thread
From: Dave Chinner @ 2021-05-06  7:20 UTC (permalink / raw)
  To: linux-xfs

From: Dave Chinner <dchinner@redhat.com>

This is just a simple wrapper around the per-ag inode allocation
that doesn't need to exist. The internal mechanism to select and
allocate within an AG does not need to be exposed outside
xfs_ialloc.c, and it being exposed simply makes it harder to follow
the code and simplify it.

This is simplified by internalising xf_dialloc_select_ag() and
xfs_dialloc_ag() into a single xfs_dialloc() function and then
xfs_dir_ialloc() can go away.

Signed-off-by: Dave Chinner <dchinner@redhat.com>
---
 fs/xfs/libxfs/xfs_ialloc.c | 15 +++++----
 fs/xfs/libxfs/xfs_ialloc.h | 27 +++-------------
 fs/xfs/xfs_inode.c         | 66 +++++++-------------------------------
 fs/xfs/xfs_inode.h         |  9 +++---
 fs/xfs/xfs_qm.c            |  9 ++++--
 fs/xfs/xfs_symlink.c       |  9 ++++--
 6 files changed, 43 insertions(+), 92 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_ialloc.c b/fs/xfs/libxfs/xfs_ialloc.c
index b22556556bba..2c0ef2dd46d9 100644
--- a/fs/xfs/libxfs/xfs_ialloc.c
+++ b/fs/xfs/libxfs/xfs_ialloc.c
@@ -1602,24 +1602,23 @@ xfs_ialloc_next_ag(
  * can be allocated, -ENOSPC be returned.
  */
 int
-xfs_dialloc_select_ag(
+xfs_dialloc(
 	struct xfs_trans	**tpp,
 	xfs_ino_t		parent,
 	umode_t			mode,
-	struct xfs_buf		**IO_agbp)
+	xfs_ino_t		*new_ino)
 {
 	struct xfs_mount	*mp = (*tpp)->t_mountp;
 	struct xfs_buf		*agbp;
 	xfs_agnumber_t		agno;
-	int			error;
+	int			error = 0;
 	xfs_agnumber_t		start_agno;
 	struct xfs_perag	*pag;
 	struct xfs_ino_geometry	*igeo = M_IGEO(mp);
 	bool			okalloc = true;
 	int			needspace;
 	int			flags;
-
-	*IO_agbp = NULL;
+	xfs_ino_t		ino;
 
 	/*
 	 * Files of these types need at least one block if length > 0
@@ -1763,7 +1762,11 @@ xfs_dialloc_select_ag(
 	return error ? error : -ENOSPC;
 found_ag:
 	xfs_perag_put(pag);
-	*IO_agbp = agbp;
+	/* Allocate an inode in the found AG */
+	error = xfs_dialloc_ag(*tpp, agbp, parent, &ino);
+	if (error)
+		return error;
+	*new_ino = ino;
 	return 0;
 }
 
diff --git a/fs/xfs/libxfs/xfs_ialloc.h b/fs/xfs/libxfs/xfs_ialloc.h
index 3511086a7ae1..886f6748fb22 100644
--- a/fs/xfs/libxfs/xfs_ialloc.h
+++ b/fs/xfs/libxfs/xfs_ialloc.h
@@ -33,30 +33,11 @@ xfs_make_iptr(struct xfs_mount *mp, struct xfs_buf *b, int o)
 }
 
 /*
- * Allocate an inode on disk.
- * Mode is used to tell whether the new inode will need space, and whether
- * it is a directory.
- *
- * There are two phases to inode allocation: selecting an AG and ensuring
- * that it contains free inodes, followed by allocating one of the free
- * inodes. xfs_dialloc_select_ag() does the former and returns a locked AGI
- * to the caller, ensuring that followup call to xfs_dialloc_ag() will
- * have free inodes to allocate from. xfs_dialloc_ag() will return the inode
- * number of the free inode we allocated.
+ * Allocate an inode on disk.  Mode is used to tell whether the new inode will
+ * need space, and whether it is a directory.
  */
-int					/* error */
-xfs_dialloc_select_ag(
-	struct xfs_trans **tpp,		/* double pointer of transaction */
-	xfs_ino_t	parent,		/* parent inode (directory) */
-	umode_t		mode,		/* mode bits for new inode */
-	struct xfs_buf	**IO_agbp);
-
-int
-xfs_dialloc_ag(
-	struct xfs_trans	*tp,
-	struct xfs_buf		*agbp,
-	xfs_ino_t		parent,
-	xfs_ino_t		*inop);
+int xfs_dialloc(struct xfs_trans **tpp, xfs_ino_t parent, umode_t mode,
+		xfs_ino_t *new_ino);
 
 /*
  * Free disk inode.  Carefully avoids touching the incore inode, all
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
index 3918c99fa95b..26668b6846e2 100644
--- a/fs/xfs/xfs_inode.c
+++ b/fs/xfs/xfs_inode.c
@@ -749,7 +749,7 @@ xfs_inode_inherit_flags2(
  * Initialise a newly allocated inode and return the in-core inode to the
  * caller locked exclusively.
  */
-static int
+int
 xfs_init_new_inode(
 	struct user_namespace	*mnt_userns,
 	struct xfs_trans	*tp,
@@ -885,54 +885,6 @@ xfs_init_new_inode(
 	return 0;
 }
 
-/*
- * Allocates a new inode from disk and return a pointer to the incore copy. This
- * routine will internally commit the current transaction and allocate a new one
- * if we needed to allocate more on-disk free inodes to perform the requested
- * operation.
- *
- * If we are allocating quota inodes, we do not have a parent inode to attach to
- * or associate with (i.e. dp == NULL) because they are not linked into the
- * directory structure - they are attached directly to the superblock - and so
- * have no parent.
- */
-int
-xfs_dir_ialloc(
-	struct user_namespace	*mnt_userns,
-	struct xfs_trans	**tpp,
-	struct xfs_inode	*dp,
-	umode_t			mode,
-	xfs_nlink_t		nlink,
-	dev_t			rdev,
-	prid_t			prid,
-	bool			init_xattrs,
-	struct xfs_inode	**ipp)
-{
-	struct xfs_buf		*agibp;
-	xfs_ino_t		parent_ino = dp ? dp->i_ino : 0;
-	xfs_ino_t		ino;
-	int			error;
-
-	ASSERT((*tpp)->t_flags & XFS_TRANS_PERM_LOG_RES);
-
-	/*
-	 * Call the space management code to pick the on-disk inode to be
-	 * allocated.
-	 */
-	error = xfs_dialloc_select_ag(tpp, parent_ino, mode, &agibp);
-	if (error)
-		return error;
-
-	/* Allocate an inode from the selected AG */
-	error = xfs_dialloc_ag(*tpp, agibp, parent_ino, &ino);
-	if (error)
-		return error;
-	ASSERT(ino != NULLFSINO);
-
-	return xfs_init_new_inode(mnt_userns, *tpp, dp, ino, mode, nlink, rdev,
-				  prid, init_xattrs, ipp);
-}
-
 /*
  * Decrement the link count on an inode & log the change.  If this causes the
  * link count to go to zero, move the inode to AGI unlinked list so that it can
@@ -990,6 +942,7 @@ xfs_create(
 	struct xfs_dquot	*pdqp = NULL;
 	struct xfs_trans_res	*tres;
 	uint			resblks;
+	xfs_ino_t		ino;
 
 	trace_xfs_create(dp, name);
 
@@ -1046,14 +999,16 @@ xfs_create(
 	 * entry pointing to them, but a directory also the "." entry
 	 * pointing to itself.
 	 */
-	error = xfs_dir_ialloc(mnt_userns, &tp, dp, mode, is_dir ? 2 : 1, rdev,
-			       prid, init_xattrs, &ip);
+	error = xfs_dialloc(&tp, dp->i_ino, mode, &ino);
+	if (!error)
+		error = xfs_init_new_inode(mnt_userns, tp, dp, ino, mode,
+				is_dir ? 2 : 1, rdev, prid, init_xattrs, &ip);
 	if (error)
 		goto out_trans_cancel;
 
 	/*
 	 * Now we join the directory inode to the transaction.  We do not do it
-	 * earlier because xfs_dir_ialloc might commit the previous transaction
+	 * earlier because xfs_dialloc might commit the previous transaction
 	 * (and release all the locks).  An error from here on will result in
 	 * the transaction cancel unlocking dp so don't do it explicitly in the
 	 * error path.
@@ -1143,6 +1098,7 @@ xfs_create_tmpfile(
 	struct xfs_dquot	*pdqp = NULL;
 	struct xfs_trans_res	*tres;
 	uint			resblks;
+	xfs_ino_t		ino;
 
 	if (XFS_FORCED_SHUTDOWN(mp))
 		return -EIO;
@@ -1167,8 +1123,10 @@ xfs_create_tmpfile(
 	if (error)
 		goto out_release_dquots;
 
-	error = xfs_dir_ialloc(mnt_userns, &tp, dp, mode, 0, 0, prid,
-				false, &ip);
+	error = xfs_dialloc(&tp, dp->i_ino, mode, &ino);
+	if (!error)
+		error = xfs_init_new_inode(mnt_userns, tp, dp, ino, mode,
+				0, 0, prid, false, &ip);
 	if (error)
 		goto out_trans_cancel;
 
diff --git a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h
index ca826cfba91c..4b6703dbffb8 100644
--- a/fs/xfs/xfs_inode.h
+++ b/fs/xfs/xfs_inode.h
@@ -431,11 +431,10 @@ void		xfs_lock_two_inodes(struct xfs_inode *ip0, uint ip0_mode,
 xfs_extlen_t	xfs_get_extsz_hint(struct xfs_inode *ip);
 xfs_extlen_t	xfs_get_cowextsz_hint(struct xfs_inode *ip);
 
-int		xfs_dir_ialloc(struct user_namespace *mnt_userns,
-			       struct xfs_trans **tpp, struct xfs_inode *dp,
-			       umode_t mode, xfs_nlink_t nlink, dev_t dev,
-			       prid_t prid, bool need_xattr,
-			       struct xfs_inode **ipp);
+int xfs_init_new_inode(struct user_namespace *mnt_userns, struct xfs_trans *tp,
+		struct xfs_inode *pip, xfs_ino_t ino, umode_t mode,
+		xfs_nlink_t nlink, dev_t rdev, prid_t prid, bool init_xattrs,
+		struct xfs_inode **ipp);
 
 static inline int
 xfs_itruncate_extents(
diff --git a/fs/xfs/xfs_qm.c b/fs/xfs/xfs_qm.c
index f7baf4dc2554..fe341f3fd419 100644
--- a/fs/xfs/xfs_qm.c
+++ b/fs/xfs/xfs_qm.c
@@ -24,6 +24,7 @@
 #include "xfs_icache.h"
 #include "xfs_error.h"
 #include "xfs_ag.h"
+#include "xfs_ialloc.h"
 
 /*
  * The global quota manager. There is only one of these for the entire
@@ -788,8 +789,12 @@ xfs_qm_qino_alloc(
 		return error;
 
 	if (need_alloc) {
-		error = xfs_dir_ialloc(&init_user_ns, &tp, NULL, S_IFREG, 1, 0,
-				       0, false, ipp);
+		xfs_ino_t	ino;
+
+		error = xfs_dialloc(&tp, 0, S_IFREG, &ino);
+		if (!error)
+			error = xfs_init_new_inode(&init_user_ns, tp, NULL, ino,
+					S_IFREG, 1, 0, 0, false, ipp);
 		if (error) {
 			xfs_trans_cancel(tp);
 			return error;
diff --git a/fs/xfs/xfs_symlink.c b/fs/xfs/xfs_symlink.c
index b4fa70282383..44596c31f4c9 100644
--- a/fs/xfs/xfs_symlink.c
+++ b/fs/xfs/xfs_symlink.c
@@ -21,6 +21,7 @@
 #include "xfs_trans_space.h"
 #include "xfs_trace.h"
 #include "xfs_trans.h"
+#include "xfs_ialloc.h"
 
 /* ----- Kernel only functions below ----- */
 int
@@ -161,6 +162,7 @@ xfs_symlink(
 	struct xfs_dquot	*gdqp = NULL;
 	struct xfs_dquot	*pdqp = NULL;
 	uint			resblks;
+	xfs_ino_t		ino;
 
 	*ipp = NULL;
 
@@ -223,8 +225,11 @@ xfs_symlink(
 	/*
 	 * Allocate an inode for the symlink.
 	 */
-	error = xfs_dir_ialloc(mnt_userns, &tp, dp, S_IFLNK | (mode & ~S_IFMT),
-			       1, 0, prid, false, &ip);
+	error = xfs_dialloc(&tp, dp->i_ino, S_IFLNK, &ino);
+	if (!error)
+		error = xfs_init_new_inode(mnt_userns, tp, dp, ino,
+				S_IFLNK | (mode & ~S_IFMT), 1, 0, prid,
+				false, &ip);
 	if (error)
 		goto out_trans_cancel;
 
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 87+ messages in thread

* [PATCH 20/22] xfs: inode allocation can use a single perag instance
  2021-05-06  7:20 [RFC 00/22] xfs: initial agnumber -> perag conversions for shrink Dave Chinner
                   ` (18 preceding siblings ...)
  2021-05-06  7:20 ` [PATCH 19/22] xfs: get rid of xfs_dir_ialloc() Dave Chinner
@ 2021-05-06  7:20 ` Dave Chinner
  2021-05-12 12:52   ` Brian Foster
  2021-05-12 23:19   ` Darrick J. Wong
  2021-05-06  7:20 ` [PATCH 21/22] xfs: clean up and simplify xfs_dialloc() Dave Chinner
  2021-05-06  7:20 ` [PATCH 22/22] xfs: use perag through unlink processing Dave Chinner
  21 siblings, 2 replies; 87+ messages in thread
From: Dave Chinner @ 2021-05-06  7:20 UTC (permalink / raw)
  To: linux-xfs

From: Dave Chinner <dchinner@redhat.com>

Now that we've internalised the two-phase inode allocation, we can
now easily make the AG selection and allocation atomic from the
perspective of a single perag context. This will ensure AGs going
offline/away cannot occur between the selection and allocation
steps.

Signed-off-by: Dave Chinner <dchinner@redhat.com>
---
 fs/xfs/libxfs/xfs_ialloc.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_ialloc.c b/fs/xfs/libxfs/xfs_ialloc.c
index 2c0ef2dd46d9..d749bb7c7a69 100644
--- a/fs/xfs/libxfs/xfs_ialloc.c
+++ b/fs/xfs/libxfs/xfs_ialloc.c
@@ -1432,6 +1432,7 @@ int
 xfs_dialloc_ag(
 	struct xfs_trans	*tp,
 	struct xfs_buf		*agbp,
+	struct xfs_perag	*pag,
 	xfs_ino_t		parent,
 	xfs_ino_t		*inop)
 {
@@ -1446,7 +1447,6 @@ xfs_dialloc_ag(
 	int				error;
 	int				offset;
 	int				i;
-	struct xfs_perag		*pag = agbp->b_pag;
 
 	if (!xfs_sb_version_hasfinobt(&mp->m_sb))
 		return xfs_dialloc_ag_inobt(tp, agbp, pag, parent, inop);
@@ -1761,9 +1761,9 @@ xfs_dialloc(
 	xfs_perag_put(pag);
 	return error ? error : -ENOSPC;
 found_ag:
-	xfs_perag_put(pag);
 	/* Allocate an inode in the found AG */
-	error = xfs_dialloc_ag(*tpp, agbp, parent, &ino);
+	error = xfs_dialloc_ag(*tpp, agbp, pag, parent, &ino);
+	xfs_perag_put(pag);
 	if (error)
 		return error;
 	*new_ino = ino;
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 87+ messages in thread

* [PATCH 21/22] xfs: clean up and simplify xfs_dialloc()
  2021-05-06  7:20 [RFC 00/22] xfs: initial agnumber -> perag conversions for shrink Dave Chinner
                   ` (19 preceding siblings ...)
  2021-05-06  7:20 ` [PATCH 20/22] xfs: inode allocation can use a single perag instance Dave Chinner
@ 2021-05-06  7:20 ` Dave Chinner
  2021-05-12 21:49   ` Darrick J. Wong
  2021-05-06  7:20 ` [PATCH 22/22] xfs: use perag through unlink processing Dave Chinner
  21 siblings, 1 reply; 87+ messages in thread
From: Dave Chinner @ 2021-05-06  7:20 UTC (permalink / raw)
  To: linux-xfs

From: Dave Chinner <dchinner@redhat.com>

Because it's a mess.

Signed-off-by: Dave Chinner <dchinner@redhat.com>
---
 fs/xfs/libxfs/xfs_ialloc.c | 270 +++++++++++++++++++++----------------
 1 file changed, 153 insertions(+), 117 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_ialloc.c b/fs/xfs/libxfs/xfs_ialloc.c
index d749bb7c7a69..340bb95d7bc1 100644
--- a/fs/xfs/libxfs/xfs_ialloc.c
+++ b/fs/xfs/libxfs/xfs_ialloc.c
@@ -604,9 +604,10 @@ xfs_inobt_insert_sprec(
 }
 
 /*
- * Allocate new inodes in the allocation group specified by agbp.
- * Returns 0 if inodes were allocated in this AG; 1 if there was no space
- * in this AG; or the usual negative error code.
+ * Allocate new inodes in the allocation group specified by agbp.  Returns 0 if
+ * inodes were allocated in this AG; -EAGAIN if there was no space in this AG so
+ * the caller knows it can try another AG, a hard -ENOSPC when over the maximum
+ * inode count threshold, or the usual negative error code for other errors.
  */
 STATIC int
 xfs_ialloc_ag_alloc(
@@ -792,7 +793,7 @@ xfs_ialloc_ag_alloc(
 	}
 
 	if (args.fsbno == NULLFSBLOCK)
-		return 1;
+		return -EAGAIN;
 
 	ASSERT(args.len == args.minlen);
 
@@ -1568,14 +1569,17 @@ xfs_dialloc_roll(
 	/* Re-attach the quota info that we detached from prev trx. */
 	tp->t_dqinfo = dqinfo;
 
-	*tpp = tp;
-	if (error)
-		return error;
+	/*
+	 * Join the buffer even on commit error so that the buffer is released
+	 * when the caller cancels the transaction and doesn't have to handle
+	 * this error case specially.
+	 */
 	xfs_trans_bjoin(tp, agibp);
-	return 0;
+	*tpp = tp;
+	return error;
 }
 
-STATIC xfs_agnumber_t
+static xfs_agnumber_t
 xfs_ialloc_next_ag(
 	xfs_mount_t	*mp)
 {
@@ -1590,16 +1594,136 @@ xfs_ialloc_next_ag(
 	return agno;
 }
 
+static bool
+xfs_dialloc_good_ag(
+	struct xfs_trans	*tp,
+	struct xfs_perag	*pag,
+	umode_t			mode,
+	int			flags,
+	bool			ok_alloc)
+{
+	struct xfs_mount	*mp = tp->t_mountp;
+	xfs_extlen_t		ineed;
+	xfs_extlen_t		longest = 0;
+	int			needspace;
+	int			error;
+
+	if (!pag->pagi_inodeok)
+		return false;
+
+	if (!pag->pagi_init) {
+		error = xfs_ialloc_pagi_init(mp, tp, pag->pag_agno);
+		if (error)
+			return false;
+	}
+
+	if (pag->pagi_freecount)
+		return true;
+	if (!ok_alloc)
+		return false;
+
+	if (!pag->pagf_init) {
+		error = xfs_alloc_pagf_init(mp, tp, pag->pag_agno, flags);
+		if (error)
+			return false;
+	}
+
+	/*
+	 * Check that there is enough free space for the file plus a chunk of
+	 * inodes if we need to allocate some. If this is the first pass across
+	 * the AGs, take into account the potential space needed for alignment
+	 * of inode chunks when checking the longest contiguous free space in
+	 * the AG - this prevents us from getting ENOSPC because we have free
+	 * space larger than ialloc_blks but alignment constraints prevent us
+	 * from using it.
+	 *
+	 * If we can't find an AG with space for full alignment slack to be
+	 * taken into account, we must be near ENOSPC in all AGs.  Hence we
+	 * don't include alignment for the second pass and so if we fail
+	 * allocation due to alignment issues then it is most likely a real
+	 * ENOSPC condition.
+	 *
+	 * XXX(dgc): this calculation is now bogus thanks to the per-ag
+	 * reservations that xfs_alloc_fix_freelist() now does via
+	 * xfs_alloc_space_available(). When the AG fills up, pagf_freeblks will
+	 * be more than large enough for the check below to succeed, but
+	 * xfs_alloc_space_available() will fail because of the non-zero
+	 * metadata reservation and hence we won't actually be able to allocate
+	 * more inodes in this AG. We do soooo much unnecessary work near ENOSPC
+	 * because of this.
+	 */
+	ineed = M_IGEO(mp)->ialloc_min_blks;
+	if (flags && ineed > 1)
+		ineed += M_IGEO(mp)->cluster_align;
+	longest = pag->pagf_longest;
+	if (!longest)
+		longest = pag->pagf_flcount > 0;
+	needspace = S_ISDIR(mode) || S_ISREG(mode) || S_ISLNK(mode);
+
+	if (pag->pagf_freeblks < needspace + ineed || longest < ineed)
+		return false;
+	return true;
+}
+
+static int
+xfs_dialloc_try_ag(
+	struct xfs_trans	**tpp,
+	struct xfs_perag	*pag,
+	xfs_ino_t		parent,
+	xfs_ino_t		*new_ino,
+	bool			ok_alloc)
+{
+	struct xfs_buf		*agbp;
+	xfs_ino_t		ino;
+	int			error;
+
+	/*
+	 * Then read in the AGI buffer and recheck with the AGI buffer
+	 * lock held.
+	 */
+	error = xfs_ialloc_read_agi(pag->pag_mount, *tpp, pag->pag_agno, &agbp);
+	if (error)
+		return error;
+
+	if (!pag->pagi_freecount) {
+		if (!ok_alloc) {
+			error = -EAGAIN;
+			goto out_release;
+		}
+
+		error = xfs_ialloc_ag_alloc(*tpp, agbp, pag);
+		if (error < 0)
+			goto out_release;
+
+		/*
+		 * We successfully allocated space for an inode cluster in this
+		 * AG.  Roll the transaction so that we can allocate one of the
+		 * new inodes.
+		 */
+		ASSERT(pag->pagi_freecount > 0);
+		error = xfs_dialloc_roll(tpp, agbp);
+		if (error)
+			goto out_release;
+	}
+
+	/* Allocate an inode in the found AG */
+	error = xfs_dialloc_ag(*tpp, agbp, pag, parent, &ino);
+	if (!error)
+		*new_ino = ino;
+	return error;
+
+out_release:
+	xfs_trans_brelse(*tpp, agbp);
+	return error;
+}
+
 /*
- * Select and prepare an AG for inode allocation.
+ * Allocate an on-disk inode.
  *
  * Mode is used to tell whether the new inode is a directory and hence where to
- * locate it.
- *
- * This function will ensure that the selected AG has free inodes available to
- * allocate from. The selected AGI will be returned locked to the caller, and it
- * will allocate more free inodes if required. If no free inodes are found or
- * can be allocated, -ENOSPC be returned.
+ * locate it. The on-disk inode that is allocated will be returned in @new_ino
+ * on success, otherwise an error will be set to indicate the failure (e.g.
+ * -ENOSPC).
  */
 int
 xfs_dialloc(
@@ -1609,14 +1733,12 @@ xfs_dialloc(
 	xfs_ino_t		*new_ino)
 {
 	struct xfs_mount	*mp = (*tpp)->t_mountp;
-	struct xfs_buf		*agbp;
 	xfs_agnumber_t		agno;
 	int			error = 0;
 	xfs_agnumber_t		start_agno;
 	struct xfs_perag	*pag;
 	struct xfs_ino_geometry	*igeo = M_IGEO(mp);
-	bool			okalloc = true;
-	int			needspace;
+	bool			ok_alloc = true;
 	int			flags;
 	xfs_ino_t		ino;
 
@@ -1624,7 +1746,6 @@ xfs_dialloc(
 	 * Files of these types need at least one block if length > 0
 	 * (and they won't fit in the inode, but that's hard to figure out).
 	 */
-	needspace = S_ISDIR(mode) || S_ISREG(mode) || S_ISLNK(mode);
 	if (S_ISDIR(mode))
 		start_agno = xfs_ialloc_next_ag(mp);
 	else {
@@ -1635,7 +1756,7 @@ xfs_dialloc(
 
 	/*
 	 * If we have already hit the ceiling of inode blocks then clear
-	 * okalloc so we scan all available agi structures for a free
+	 * ok_alloc so we scan all available agi structures for a free
 	 * inode.
 	 *
 	 * Read rough value of mp->m_icount by percpu_counter_read_positive,
@@ -1644,7 +1765,7 @@ xfs_dialloc(
 	if (igeo->maxicount &&
 	    percpu_counter_read_positive(&mp->m_icount) + igeo->ialloc_inos
 							> igeo->maxicount) {
-		okalloc = false;
+		ok_alloc = false;
 	}
 
 	/*
@@ -1655,95 +1776,14 @@ xfs_dialloc(
 	agno = start_agno;
 	flags = XFS_ALLOC_FLAG_TRYLOCK;
 	for (;;) {
-		xfs_extlen_t	ineed;
-		xfs_extlen_t	longest = 0;
-
 		pag = xfs_perag_get(mp, agno);
-		if (!pag->pagi_inodeok)
-			goto nextag;
-
-		if (!pag->pagi_init) {
-			error = xfs_ialloc_pagi_init(mp, *tpp, agno);
-			if (error)
-				break;
-		}
-
-		if (!pag->pagi_freecount)
-			goto nextag;
-		if (!okalloc)
-			goto nextag;
-
-		if (!pag->pagf_init) {
-			error = xfs_alloc_pagf_init(mp, *tpp, agno, flags);
-			if (error)
-				goto nextag;
-		}
-
-		/*
-		 * Check that there is enough free space for the file plus a
-		 * chunk of inodes if we need to allocate some. If this is the
-		 * first pass across the AGs, take into account the potential
-		 * space needed for alignment of inode chunks when checking the
-		 * longest contiguous free space in the AG - this prevents us
-		 * from getting ENOSPC because we have free space larger than
-		 * ialloc_blks but alignment constraints prevent us from using
-		 * it.
-		 *
-		 * If we can't find an AG with space for full alignment slack to
-		 * be taken into account, we must be near ENOSPC in all AGs.
-		 * Hence we don't include alignment for the second pass and so
-		 * if we fail allocation due to alignment issues then it is most
-		 * likely a real ENOSPC condition.
-		 */
-		ineed = M_IGEO(mp)->ialloc_min_blks;
-		if (flags && ineed > 1)
-			ineed += M_IGEO(mp)->cluster_align;
-		longest = pag->pagf_longest;
-		if (!longest)
-			longest = pag->pagf_flcount > 0;
-
-		if (pag->pagf_freeblks < needspace + ineed || longest < ineed)
-			goto nextag;
-
-		/*
-		 * Then read in the AGI buffer and recheck with the AGI buffer
-		 * lock held.
-		 */
-		error = xfs_ialloc_read_agi(mp, *tpp, agno, &agbp);
-		if (error)
-			break;
-
-		if (pag->pagi_freecount)
-			goto found_ag;
-
-		if (!okalloc)
-			goto nextag_relse_buffer;
-
-		error = xfs_ialloc_ag_alloc(*tpp, agbp, pag);
-		if (error < 0) {
-			xfs_trans_brelse(*tpp, agbp);
-			break;
-		}
-
-		if (error == 0) {
-			/*
-			 * We successfully allocated space for an inode cluster
-			 * in this AG.  Roll the transaction so that we can
-			 * allocate one of the new inodes.
-			 */
-			ASSERT(pag->pagi_freecount > 0);
-
-			error = xfs_dialloc_roll(tpp, agbp);
-			if (error) {
-				xfs_buf_relse(agbp);
+		if (xfs_dialloc_good_ag(*tpp, pag, mode, flags, ok_alloc)) {
+			error = xfs_dialloc_try_ag(tpp, pag, parent,
+					&ino, ok_alloc);
+			if (error != -EAGAIN)
 				break;
-			}
-			goto found_ag;
 		}
 
-nextag_relse_buffer:
-		xfs_trans_brelse(*tpp, agbp);
-nextag:
 		if (XFS_FORCED_SHUTDOWN(mp)) {
 			error = -EFSCORRUPTED;
 			break;
@@ -1751,23 +1791,19 @@ xfs_dialloc(
 		if (++agno == mp->m_maxagi)
 			agno = 0;
 		if (agno == start_agno) {
-			if (!flags)
+			if (!flags) {
+				error = -ENOSPC;
 				break;
+			}
 			flags = 0;
 		}
 		xfs_perag_put(pag);
 	}
 
+	if (!error)
+		*new_ino = ino;
 	xfs_perag_put(pag);
-	return error ? error : -ENOSPC;
-found_ag:
-	/* Allocate an inode in the found AG */
-	error = xfs_dialloc_ag(*tpp, agbp, pag, parent, &ino);
-	xfs_perag_put(pag);
-	if (error)
-		return error;
-	*new_ino = ino;
-	return 0;
+	return error;
 }
 
 /*
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 87+ messages in thread

* [PATCH 22/22] xfs: use perag through unlink processing
  2021-05-06  7:20 [RFC 00/22] xfs: initial agnumber -> perag conversions for shrink Dave Chinner
                   ` (20 preceding siblings ...)
  2021-05-06  7:20 ` [PATCH 21/22] xfs: clean up and simplify xfs_dialloc() Dave Chinner
@ 2021-05-06  7:20 ` Dave Chinner
  2021-05-12 21:37   ` Darrick J. Wong
  21 siblings, 1 reply; 87+ messages in thread
From: Dave Chinner @ 2021-05-06  7:20 UTC (permalink / raw)
  To: linux-xfs

From: Dave Chinner <dchinner@redhat.com>

Unlinked lists are held in the perag, and freeing of inodes needs to
be passed a perag, too, so look up the perag early in the unlink
processing and use it throughout.

Signed-off-by: Dave Chinner <dchinner@redhat.com>
---
 fs/xfs/libxfs/xfs_ialloc.c |  23 +++----
 fs/xfs/libxfs/xfs_ialloc.h |  13 +---
 fs/xfs/xfs_inode.c         | 131 +++++++++++++++++++++----------------
 3 files changed, 87 insertions(+), 80 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_ialloc.c b/fs/xfs/libxfs/xfs_ialloc.c
index 340bb95d7bc1..be84820588c6 100644
--- a/fs/xfs/libxfs/xfs_ialloc.c
+++ b/fs/xfs/libxfs/xfs_ialloc.c
@@ -2133,35 +2133,33 @@ xfs_difree_finobt(
  */
 int
 xfs_difree(
-	struct xfs_trans	*tp,		/* transaction pointer */
-	xfs_ino_t		inode,		/* inode to be freed */
-	struct xfs_icluster	*xic)	/* cluster info if deleted */
+	struct xfs_trans	*tp,
+	struct xfs_perag	*pag,
+	xfs_ino_t		inode,
+	struct xfs_icluster	*xic)
 {
 	/* REFERENCED */
 	xfs_agblock_t		agbno;	/* block number containing inode */
 	struct xfs_buf		*agbp;	/* buffer for allocation group header */
 	xfs_agino_t		agino;	/* allocation group inode number */
-	xfs_agnumber_t		agno;	/* allocation group number */
 	int			error;	/* error return value */
 	struct xfs_mount	*mp = tp->t_mountp;
 	struct xfs_inobt_rec_incore rec;/* btree record */
-	struct xfs_perag	*pag;
 
 	/*
 	 * Break up inode number into its components.
 	 */
-	agno = XFS_INO_TO_AGNO(mp, inode);
-	if (agno >= mp->m_sb.sb_agcount) {
-		xfs_warn(mp, "%s: agno >= mp->m_sb.sb_agcount (%d >= %d).",
-			__func__, agno, mp->m_sb.sb_agcount);
+	if (pag->pag_agno != XFS_INO_TO_AGNO(mp, inode)) {
+		xfs_warn(mp, "%s: agno != pag->pag_agno (%d != %d).",
+			__func__, XFS_INO_TO_AGNO(mp, inode), pag->pag_agno);
 		ASSERT(0);
 		return -EINVAL;
 	}
 	agino = XFS_INO_TO_AGINO(mp, inode);
-	if (inode != XFS_AGINO_TO_INO(mp, agno, agino))  {
+	if (inode != XFS_AGINO_TO_INO(mp, pag->pag_agno, agino))  {
 		xfs_warn(mp, "%s: inode != XFS_AGINO_TO_INO() (%llu != %llu).",
 			__func__, (unsigned long long)inode,
-			(unsigned long long)XFS_AGINO_TO_INO(mp, agno, agino));
+			(unsigned long long)XFS_AGINO_TO_INO(mp, pag->pag_agno, agino));
 		ASSERT(0);
 		return -EINVAL;
 	}
@@ -2175,7 +2173,7 @@ xfs_difree(
 	/*
 	 * Get the allocation group header.
 	 */
-	error = xfs_ialloc_read_agi(mp, tp, agno, &agbp);
+	error = xfs_ialloc_read_agi(mp, tp, pag->pag_agno, &agbp);
 	if (error) {
 		xfs_warn(mp, "%s: xfs_ialloc_read_agi() returned error %d.",
 			__func__, error);
@@ -2185,7 +2183,6 @@ xfs_difree(
 	/*
 	 * Fix up the inode allocation btree.
 	 */
-	pag = agbp->b_pag;
 	error = xfs_difree_inobt(mp, tp, agbp, pag, agino, xic, &rec);
 	if (error)
 		goto error0;
diff --git a/fs/xfs/libxfs/xfs_ialloc.h b/fs/xfs/libxfs/xfs_ialloc.h
index 886f6748fb22..9df7c80408ff 100644
--- a/fs/xfs/libxfs/xfs_ialloc.h
+++ b/fs/xfs/libxfs/xfs_ialloc.h
@@ -39,17 +39,8 @@ xfs_make_iptr(struct xfs_mount *mp, struct xfs_buf *b, int o)
 int xfs_dialloc(struct xfs_trans **tpp, xfs_ino_t parent, umode_t mode,
 		xfs_ino_t *new_ino);
 
-/*
- * Free disk inode.  Carefully avoids touching the incore inode, all
- * manipulations incore are the caller's responsibility.
- * The on-disk inode is not changed by this operation, only the
- * btree (free inode mask) is changed.
- */
-int					/* error */
-xfs_difree(
-	struct xfs_trans *tp,		/* transaction pointer */
-	xfs_ino_t	inode,		/* inode to be freed */
-	struct xfs_icluster *ifree);	/* cluster info if deleted */
+int xfs_difree(struct xfs_trans *tp, struct xfs_perag *pag,
+		xfs_ino_t ino, struct xfs_icluster *ifree);
 
 /*
  * Return the location of the inode in imap, for mapping it into a buffer.
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
index 26668b6846e2..aad98a982382 100644
--- a/fs/xfs/xfs_inode.c
+++ b/fs/xfs/xfs_inode.c
@@ -45,7 +45,8 @@ kmem_zone_t *xfs_inode_zone;
 #define	XFS_ITRUNC_MAX_EXTENTS	2
 
 STATIC int xfs_iunlink(struct xfs_trans *, struct xfs_inode *);
-STATIC int xfs_iunlink_remove(struct xfs_trans *, struct xfs_inode *);
+STATIC int xfs_iunlink_remove(struct xfs_trans *tp, struct xfs_perag *pag,
+	struct xfs_inode *);
 
 /*
  * helper function to extract extent size hint from inode
@@ -1241,7 +1242,11 @@ xfs_link(
 	 * Handle initial link state of O_TMPFILE inode
 	 */
 	if (VFS_I(sip)->i_nlink == 0) {
-		error = xfs_iunlink_remove(tp, sip);
+		struct xfs_perag	*pag;
+
+		pag = xfs_perag_get(mp, XFS_INO_TO_AGNO(mp, sip->i_ino));
+		error = xfs_iunlink_remove(tp, pag, sip);
+		xfs_perag_put(pag);
 		if (error)
 			goto error_return;
 	}
@@ -1934,7 +1939,7 @@ xfs_iunlink_destroy(
 STATIC int
 xfs_iunlink_update_bucket(
 	struct xfs_trans	*tp,
-	xfs_agnumber_t		agno,
+	struct xfs_perag	*pag,
 	struct xfs_buf		*agibp,
 	unsigned int		bucket_index,
 	xfs_agino_t		new_agino)
@@ -1943,10 +1948,10 @@ xfs_iunlink_update_bucket(
 	xfs_agino_t		old_value;
 	int			offset;
 
-	ASSERT(xfs_verify_agino_or_null(tp->t_mountp, agno, new_agino));
+	ASSERT(xfs_verify_agino_or_null(tp->t_mountp, pag->pag_agno, new_agino));
 
 	old_value = be32_to_cpu(agi->agi_unlinked[bucket_index]);
-	trace_xfs_iunlink_update_bucket(tp->t_mountp, agno, bucket_index,
+	trace_xfs_iunlink_update_bucket(tp->t_mountp, pag->pag_agno, bucket_index,
 			old_value, new_agino);
 
 	/*
@@ -1970,7 +1975,7 @@ xfs_iunlink_update_bucket(
 STATIC void
 xfs_iunlink_update_dinode(
 	struct xfs_trans	*tp,
-	xfs_agnumber_t		agno,
+	struct xfs_perag	*pag,
 	xfs_agino_t		agino,
 	struct xfs_buf		*ibp,
 	struct xfs_dinode	*dip,
@@ -1980,9 +1985,9 @@ xfs_iunlink_update_dinode(
 	struct xfs_mount	*mp = tp->t_mountp;
 	int			offset;
 
-	ASSERT(xfs_verify_agino_or_null(mp, agno, next_agino));
+	ASSERT(xfs_verify_agino_or_null(mp, pag->pag_agno, next_agino));
 
-	trace_xfs_iunlink_update_dinode(mp, agno, agino,
+	trace_xfs_iunlink_update_dinode(mp, pag->pag_agno, agino,
 			be32_to_cpu(dip->di_next_unlinked), next_agino);
 
 	dip->di_next_unlinked = cpu_to_be32(next_agino);
@@ -2000,7 +2005,7 @@ STATIC int
 xfs_iunlink_update_inode(
 	struct xfs_trans	*tp,
 	struct xfs_inode	*ip,
-	xfs_agnumber_t		agno,
+	struct xfs_perag	*pag,
 	xfs_agino_t		next_agino,
 	xfs_agino_t		*old_next_agino)
 {
@@ -2010,7 +2015,7 @@ xfs_iunlink_update_inode(
 	xfs_agino_t		old_value;
 	int			error;
 
-	ASSERT(xfs_verify_agino_or_null(mp, agno, next_agino));
+	ASSERT(xfs_verify_agino_or_null(mp, pag->pag_agno, next_agino));
 
 	error = xfs_imap_to_bp(mp, tp, &ip->i_imap, &ibp);
 	if (error)
@@ -2019,7 +2024,7 @@ xfs_iunlink_update_inode(
 
 	/* Make sure the old pointer isn't garbage. */
 	old_value = be32_to_cpu(dip->di_next_unlinked);
-	if (!xfs_verify_agino_or_null(mp, agno, old_value)) {
+	if (!xfs_verify_agino_or_null(mp, pag->pag_agno, old_value)) {
 		xfs_inode_verifier_error(ip, -EFSCORRUPTED, __func__, dip,
 				sizeof(*dip), __this_address);
 		error = -EFSCORRUPTED;
@@ -2042,7 +2047,7 @@ xfs_iunlink_update_inode(
 	}
 
 	/* Ok, update the new pointer. */
-	xfs_iunlink_update_dinode(tp, agno, XFS_INO_TO_AGINO(mp, ip->i_ino),
+	xfs_iunlink_update_dinode(tp, pag, XFS_INO_TO_AGINO(mp, ip->i_ino),
 			ibp, dip, &ip->i_imap, next_agino);
 	return 0;
 out:
@@ -2063,10 +2068,10 @@ xfs_iunlink(
 	struct xfs_inode	*ip)
 {
 	struct xfs_mount	*mp = tp->t_mountp;
+	struct xfs_perag	*pag;
 	struct xfs_agi		*agi;
 	struct xfs_buf		*agibp;
 	xfs_agino_t		next_agino;
-	xfs_agnumber_t		agno = XFS_INO_TO_AGNO(mp, ip->i_ino);
 	xfs_agino_t		agino = XFS_INO_TO_AGINO(mp, ip->i_ino);
 	short			bucket_index = agino % XFS_AGI_UNLINKED_BUCKETS;
 	int			error;
@@ -2075,10 +2080,12 @@ xfs_iunlink(
 	ASSERT(VFS_I(ip)->i_mode != 0);
 	trace_xfs_iunlink(ip);
 
+	pag = xfs_perag_get(mp, XFS_INO_TO_AGNO(mp, ip->i_ino));
+
 	/* Get the agi buffer first.  It ensures lock ordering on the list. */
-	error = xfs_read_agi(mp, tp, agno, &agibp);
+	error = xfs_read_agi(mp, tp, pag->pag_agno, &agibp);
 	if (error)
-		return error;
+		goto out;
 	agi = agibp->b_addr;
 
 	/*
@@ -2088,9 +2095,10 @@ xfs_iunlink(
 	 */
 	next_agino = be32_to_cpu(agi->agi_unlinked[bucket_index]);
 	if (next_agino == agino ||
-	    !xfs_verify_agino_or_null(mp, agno, next_agino)) {
+	    !xfs_verify_agino_or_null(mp, pag->pag_agno, next_agino)) {
 		xfs_buf_mark_corrupt(agibp);
-		return -EFSCORRUPTED;
+		error = -EFSCORRUPTED;
+		goto out;
 	}
 
 	if (next_agino != NULLAGINO) {
@@ -2100,23 +2108,26 @@ xfs_iunlink(
 		 * There is already another inode in the bucket, so point this
 		 * inode to the current head of the list.
 		 */
-		error = xfs_iunlink_update_inode(tp, ip, agno, next_agino,
+		error = xfs_iunlink_update_inode(tp, ip, pag, next_agino,
 				&old_agino);
 		if (error)
-			return error;
+			goto out;
 		ASSERT(old_agino == NULLAGINO);
 
 		/*
 		 * agino has been unlinked, add a backref from the next inode
 		 * back to agino.
 		 */
-		error = xfs_iunlink_add_backref(agibp->b_pag, agino, next_agino);
+		error = xfs_iunlink_add_backref(pag, agino, next_agino);
 		if (error)
-			return error;
+			goto out;
 	}
 
 	/* Point the head of the list to point to this inode. */
-	return xfs_iunlink_update_bucket(tp, agno, agibp, bucket_index, agino);
+	error = xfs_iunlink_update_bucket(tp, pag, agibp, bucket_index, agino);
+out:
+	xfs_perag_put(pag);
+	return error;
 }
 
 /* Return the imap, dinode pointer, and buffer for an inode. */
@@ -2164,14 +2175,13 @@ xfs_iunlink_map_ino(
 STATIC int
 xfs_iunlink_map_prev(
 	struct xfs_trans	*tp,
-	xfs_agnumber_t		agno,
+	struct xfs_perag	*pag,
 	xfs_agino_t		head_agino,
 	xfs_agino_t		target_agino,
 	xfs_agino_t		*agino,
 	struct xfs_imap		*imap,
 	struct xfs_dinode	**dipp,
-	struct xfs_buf		**bpp,
-	struct xfs_perag	*pag)
+	struct xfs_buf		**bpp)
 {
 	struct xfs_mount	*mp = tp->t_mountp;
 	xfs_agino_t		next_agino;
@@ -2183,7 +2193,8 @@ xfs_iunlink_map_prev(
 	/* See if our backref cache can find it faster. */
 	*agino = xfs_iunlink_lookup_backref(pag, target_agino);
 	if (*agino != NULLAGINO) {
-		error = xfs_iunlink_map_ino(tp, agno, *agino, imap, dipp, bpp);
+		error = xfs_iunlink_map_ino(tp, pag->pag_agno, *agino, imap,
+				dipp, bpp);
 		if (error)
 			return error;
 
@@ -2199,7 +2210,7 @@ xfs_iunlink_map_prev(
 		WARN_ON_ONCE(1);
 	}
 
-	trace_xfs_iunlink_map_prev_fallback(mp, agno);
+	trace_xfs_iunlink_map_prev_fallback(mp, pag->pag_agno);
 
 	/* Otherwise, walk the entire bucket until we find it. */
 	next_agino = head_agino;
@@ -2210,8 +2221,8 @@ xfs_iunlink_map_prev(
 			xfs_trans_brelse(tp, *bpp);
 
 		*agino = next_agino;
-		error = xfs_iunlink_map_ino(tp, agno, next_agino, imap, dipp,
-				bpp);
+		error = xfs_iunlink_map_ino(tp, pag->pag_agno, next_agino, imap,
+				dipp, bpp);
 		if (error)
 			return error;
 
@@ -2220,7 +2231,7 @@ xfs_iunlink_map_prev(
 		 * Make sure this pointer is valid and isn't an obvious
 		 * infinite loop.
 		 */
-		if (!xfs_verify_agino(mp, agno, unlinked_agino) ||
+		if (!xfs_verify_agino(mp, pag->pag_agno, unlinked_agino) ||
 		    next_agino == unlinked_agino) {
 			XFS_CORRUPTION_ERROR(__func__,
 					XFS_ERRLEVEL_LOW, mp,
@@ -2240,6 +2251,7 @@ xfs_iunlink_map_prev(
 STATIC int
 xfs_iunlink_remove(
 	struct xfs_trans	*tp,
+	struct xfs_perag	*pag,
 	struct xfs_inode	*ip)
 {
 	struct xfs_mount	*mp = tp->t_mountp;
@@ -2247,7 +2259,6 @@ xfs_iunlink_remove(
 	struct xfs_buf		*agibp;
 	struct xfs_buf		*last_ibp;
 	struct xfs_dinode	*last_dip = NULL;
-	xfs_agnumber_t		agno = XFS_INO_TO_AGNO(mp, ip->i_ino);
 	xfs_agino_t		agino = XFS_INO_TO_AGINO(mp, ip->i_ino);
 	xfs_agino_t		next_agino;
 	xfs_agino_t		head_agino;
@@ -2257,7 +2268,7 @@ xfs_iunlink_remove(
 	trace_xfs_iunlink_remove(ip);
 
 	/* Get the agi buffer first.  It ensures lock ordering on the list. */
-	error = xfs_read_agi(mp, tp, agno, &agibp);
+	error = xfs_read_agi(mp, tp, pag->pag_agno, &agibp);
 	if (error)
 		return error;
 	agi = agibp->b_addr;
@@ -2267,7 +2278,7 @@ xfs_iunlink_remove(
 	 * go on.  Make sure the head pointer isn't garbage.
 	 */
 	head_agino = be32_to_cpu(agi->agi_unlinked[bucket_index]);
-	if (!xfs_verify_agino(mp, agno, head_agino)) {
+	if (!xfs_verify_agino(mp, pag->pag_agno, head_agino)) {
 		XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,
 				agi, sizeof(*agi));
 		return -EFSCORRUPTED;
@@ -2278,7 +2289,7 @@ xfs_iunlink_remove(
 	 * the old pointer value so that we can update whatever was previous
 	 * to us in the list to point to whatever was next in the list.
 	 */
-	error = xfs_iunlink_update_inode(tp, ip, agno, NULLAGINO, &next_agino);
+	error = xfs_iunlink_update_inode(tp, ip, pag, NULLAGINO, &next_agino);
 	if (error)
 		return error;
 
@@ -2290,8 +2301,7 @@ xfs_iunlink_remove(
 	 * this inode's backref to point from the next inode.
 	 */
 	if (next_agino != NULLAGINO) {
-		error = xfs_iunlink_change_backref(agibp->b_pag, next_agino,
-				NULLAGINO);
+		error = xfs_iunlink_change_backref(pag, next_agino, NULLAGINO);
 		if (error)
 			return error;
 	}
@@ -2301,14 +2311,13 @@ xfs_iunlink_remove(
 		xfs_agino_t	prev_agino;
 
 		/* We need to search the list for the inode being freed. */
-		error = xfs_iunlink_map_prev(tp, agno, head_agino, agino,
-				&prev_agino, &imap, &last_dip, &last_ibp,
-				agibp->b_pag);
+		error = xfs_iunlink_map_prev(tp, pag, head_agino, agino,
+				&prev_agino, &imap, &last_dip, &last_ibp);
 		if (error)
 			return error;
 
 		/* Point the previous inode on the list to the next inode. */
-		xfs_iunlink_update_dinode(tp, agno, prev_agino, last_ibp,
+		xfs_iunlink_update_dinode(tp, pag, prev_agino, last_ibp,
 				last_dip, &imap, next_agino);
 
 		/*
@@ -2324,7 +2333,7 @@ xfs_iunlink_remove(
 	}
 
 	/* Point the head of the list to the next unlinked inode. */
-	return xfs_iunlink_update_bucket(tp, agno, agibp, bucket_index,
+	return xfs_iunlink_update_bucket(tp, pag, agibp, bucket_index,
 			next_agino);
 }
 
@@ -2335,12 +2344,11 @@ xfs_iunlink_remove(
  */
 static void
 xfs_ifree_mark_inode_stale(
-	struct xfs_buf		*bp,
+	struct xfs_perag	*pag,
 	struct xfs_inode	*free_ip,
 	xfs_ino_t		inum)
 {
-	struct xfs_mount	*mp = bp->b_mount;
-	struct xfs_perag	*pag = bp->b_pag;
+	struct xfs_mount	*mp = pag->pag_mount;
 	struct xfs_inode_log_item *iip;
 	struct xfs_inode	*ip;
 
@@ -2430,10 +2438,11 @@ xfs_ifree_mark_inode_stale(
  * inodes that are in memory - they all must be marked stale and attached to
  * the cluster buffer.
  */
-STATIC int
+static int
 xfs_ifree_cluster(
-	struct xfs_inode	*free_ip,
 	struct xfs_trans	*tp,
+	struct xfs_perag	*pag,
+	struct xfs_inode	*free_ip,
 	struct xfs_icluster	*xic)
 {
 	struct xfs_mount	*mp = free_ip->i_mount;
@@ -2495,7 +2504,7 @@ xfs_ifree_cluster(
 		 * already marked XFS_ISTALE.
 		 */
 		for (i = 0; i < igeo->inodes_per_cluster; i++)
-			xfs_ifree_mark_inode_stale(bp, free_ip, inum + i);
+			xfs_ifree_mark_inode_stale(pag, free_ip, inum + i);
 
 		xfs_trans_stale_inode_buf(tp, bp);
 		xfs_trans_binval(tp, bp);
@@ -2518,9 +2527,11 @@ xfs_ifree(
 	struct xfs_trans	*tp,
 	struct xfs_inode	*ip)
 {
-	int			error;
+	struct xfs_mount	*mp = ip->i_mount;
+	struct xfs_perag	*pag;
 	struct xfs_icluster	xic = { 0 };
 	struct xfs_inode_log_item *iip = ip->i_itemp;
+	int			error;
 
 	ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
 	ASSERT(VFS_I(ip)->i_nlink == 0);
@@ -2528,16 +2539,18 @@ xfs_ifree(
 	ASSERT(ip->i_disk_size == 0 || !S_ISREG(VFS_I(ip)->i_mode));
 	ASSERT(ip->i_nblocks == 0);
 
+	pag = xfs_perag_get(mp, XFS_INO_TO_AGNO(mp, ip->i_ino));
+
 	/*
 	 * Pull the on-disk inode from the AGI unlinked list.
 	 */
-	error = xfs_iunlink_remove(tp, ip);
+	error = xfs_iunlink_remove(tp, pag, ip);
 	if (error)
-		return error;
+		goto out;
 
-	error = xfs_difree(tp, ip->i_ino, &xic);
+	error = xfs_difree(tp, pag, ip->i_ino, &xic);
 	if (error)
-		return error;
+		goto out;
 
 	/*
 	 * Free any local-format data sitting around before we reset the
@@ -2552,7 +2565,7 @@ xfs_ifree(
 
 	VFS_I(ip)->i_mode = 0;		/* mark incore inode as free */
 	ip->i_diflags = 0;
-	ip->i_diflags2 = ip->i_mount->m_ino_geo.new_diflags2;
+	ip->i_diflags2 = mp->m_ino_geo.new_diflags2;
 	ip->i_forkoff = 0;		/* mark the attr fork not in use */
 	ip->i_df.if_format = XFS_DINODE_FMT_EXTENTS;
 	if (xfs_iflags_test(ip, XFS_IPRESERVE_DM_FIELDS))
@@ -2571,8 +2584,9 @@ xfs_ifree(
 	xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
 
 	if (xic.deleted)
-		error = xfs_ifree_cluster(ip, tp, &xic);
-
+		error = xfs_ifree_cluster(tp, pag, ip, &xic);
+out:
+	xfs_perag_put(pag);
 	return error;
 }
 
@@ -3176,8 +3190,13 @@ xfs_rename(
 	 * in future.
 	 */
 	if (wip) {
+		struct xfs_perag	*pag;
+
 		ASSERT(VFS_I(wip)->i_nlink == 0);
-		error = xfs_iunlink_remove(tp, wip);
+
+		pag = xfs_perag_get(mp, XFS_INO_TO_AGNO(mp, wip->i_ino));
+		error = xfs_iunlink_remove(tp, pag, wip);
+		xfs_perag_put(pag);
 		if (error)
 			goto out_trans_cancel;
 
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 87+ messages in thread

* Re: [PATCH 19/22] xfs: get rid of xfs_dir_ialloc()
  2021-05-06  7:20 ` [PATCH 19/22] xfs: get rid of xfs_dir_ialloc() Dave Chinner
@ 2021-05-06 11:26     ` kernel test robot
  2021-05-06 11:26     ` kernel test robot
                       ` (2 subsequent siblings)
  3 siblings, 0 replies; 87+ messages in thread
From: kernel test robot @ 2021-05-06 11:26 UTC (permalink / raw)
  To: Dave Chinner, linux-xfs; +Cc: kbuild-all

[-- Attachment #1: Type: text/plain, Size: 1683 bytes --]

Hi Dave,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on xfs-linux/for-next]
[also build test WARNING on next-20210506]
[cannot apply to v5.12]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Dave-Chinner/xfs-initial-agnumber-perag-conversions-for-shrink/20210506-154106
base:   https://git.kernel.org/pub/scm/fs/xfs/xfs-linux.git for-next
config: x86_64-randconfig-s021-20210506 (attached as .config)
compiler: gcc-9 (Debian 9.3.0-22) 9.3.0
reproduce:
        # apt-get install sparse
        # sparse version: v0.6.3-341-g8af24329-dirty
        # https://github.com/0day-ci/linux/commit/193950fea5de60d6cc113c09886d30f577bfba96
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Dave-Chinner/xfs-initial-agnumber-perag-conversions-for-shrink/20210506-154106
        git checkout 193950fea5de60d6cc113c09886d30f577bfba96
        # save the attached .config to linux build tree
        make W=1 C=1 CF='-fdiagnostic-prefix -D__CHECK_ENDIAN__' W=1 ARCH=x86_64 

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>


sparse warnings: (new ones prefixed by >>)
>> fs/xfs/libxfs/xfs_ialloc.c:1432:1: sparse: sparse: symbol 'xfs_dialloc_ag' was not declared. Should it be static?

Please review and possibly fold the followup patch.

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 38023 bytes --]

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 19/22] xfs: get rid of xfs_dir_ialloc()
@ 2021-05-06 11:26     ` kernel test robot
  0 siblings, 0 replies; 87+ messages in thread
From: kernel test robot @ 2021-05-06 11:26 UTC (permalink / raw)
  To: kbuild-all

[-- Attachment #1: Type: text/plain, Size: 1722 bytes --]

Hi Dave,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on xfs-linux/for-next]
[also build test WARNING on next-20210506]
[cannot apply to v5.12]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Dave-Chinner/xfs-initial-agnumber-perag-conversions-for-shrink/20210506-154106
base:   https://git.kernel.org/pub/scm/fs/xfs/xfs-linux.git for-next
config: x86_64-randconfig-s021-20210506 (attached as .config)
compiler: gcc-9 (Debian 9.3.0-22) 9.3.0
reproduce:
        # apt-get install sparse
        # sparse version: v0.6.3-341-g8af24329-dirty
        # https://github.com/0day-ci/linux/commit/193950fea5de60d6cc113c09886d30f577bfba96
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Dave-Chinner/xfs-initial-agnumber-perag-conversions-for-shrink/20210506-154106
        git checkout 193950fea5de60d6cc113c09886d30f577bfba96
        # save the attached .config to linux build tree
        make W=1 C=1 CF='-fdiagnostic-prefix -D__CHECK_ENDIAN__' W=1 ARCH=x86_64 

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>


sparse warnings: (new ones prefixed by >>)
>> fs/xfs/libxfs/xfs_ialloc.c:1432:1: sparse: sparse: symbol 'xfs_dialloc_ag' was not declared. Should it be static?

Please review and possibly fold the followup patch.

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all(a)lists.01.org

[-- Attachment #2: config.gz --]
[-- Type: application/gzip, Size: 38023 bytes --]

^ permalink raw reply	[flat|nested] 87+ messages in thread

* [RFC PATCH] xfs: xfs_dialloc_ag can be static
  2021-05-06  7:20 ` [PATCH 19/22] xfs: get rid of xfs_dir_ialloc() Dave Chinner
@ 2021-05-06 11:26     ` kernel test robot
  2021-05-06 11:26     ` kernel test robot
                       ` (2 subsequent siblings)
  3 siblings, 0 replies; 87+ messages in thread
From: kernel test robot @ 2021-05-06 11:26 UTC (permalink / raw)
  To: Dave Chinner, linux-xfs; +Cc: kbuild-all

fs/xfs/libxfs/xfs_ialloc.c:1432:1: warning: symbol 'xfs_dialloc_ag' was not declared. Should it be static?

Reported-by: kernel test robot <lkp@intel.com>
Signed-off-by: kernel test robot <lkp@intel.com>
---
 xfs_ialloc.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/fs/xfs/libxfs/xfs_ialloc.c b/fs/xfs/libxfs/xfs_ialloc.c
index 2c0ef2dd46d91..1c3fb08186743 100644
--- a/fs/xfs/libxfs/xfs_ialloc.c
+++ b/fs/xfs/libxfs/xfs_ialloc.c
@@ -1428,7 +1428,7 @@ xfs_dialloc_ag_update_inobt(
  * The caller selected an AG for us, and made sure that free inodes are
  * available.
  */
-int
+static int
 xfs_dialloc_ag(
 	struct xfs_trans	*tp,
 	struct xfs_buf		*agbp,

^ permalink raw reply related	[flat|nested] 87+ messages in thread

* [RFC PATCH] xfs: xfs_dialloc_ag can be static
@ 2021-05-06 11:26     ` kernel test robot
  0 siblings, 0 replies; 87+ messages in thread
From: kernel test robot @ 2021-05-06 11:26 UTC (permalink / raw)
  To: kbuild-all

[-- Attachment #1: Type: text/plain, Size: 703 bytes --]

fs/xfs/libxfs/xfs_ialloc.c:1432:1: warning: symbol 'xfs_dialloc_ag' was not declared. Should it be static?

Reported-by: kernel test robot <lkp@intel.com>
Signed-off-by: kernel test robot <lkp@intel.com>
---
 xfs_ialloc.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/fs/xfs/libxfs/xfs_ialloc.c b/fs/xfs/libxfs/xfs_ialloc.c
index 2c0ef2dd46d91..1c3fb08186743 100644
--- a/fs/xfs/libxfs/xfs_ialloc.c
+++ b/fs/xfs/libxfs/xfs_ialloc.c
@@ -1428,7 +1428,7 @@ xfs_dialloc_ag_update_inobt(
  * The caller selected an AG for us, and made sure that free inodes are
  * available.
  */
-int
+static int
 xfs_dialloc_ag(
 	struct xfs_trans	*tp,
 	struct xfs_buf		*agbp,

^ permalink raw reply related	[flat|nested] 87+ messages in thread

* Re: [PATCH 01/22] xfs: move xfs_perag_get/put to xfs_ag.[ch]
  2021-05-06  7:20 ` [PATCH 01/22] xfs: move xfs_perag_get/put to xfs_ag.[ch] Dave Chinner
@ 2021-05-10 12:52   ` Brian Foster
  2021-05-11  7:18     ` Dave Chinner
  2021-05-10 22:28   ` Darrick J. Wong
  1 sibling, 1 reply; 87+ messages in thread
From: Brian Foster @ 2021-05-10 12:52 UTC (permalink / raw)
  To: Dave Chinner; +Cc: linux-xfs

On Thu, May 06, 2021 at 05:20:33PM +1000, Dave Chinner wrote:
> From: Dave Chinner <dchinner@redhat.com>
> 
> They are AG functions, not superblock functions, so move them to the
> appropriate location.
> 
> Signed-off-by: Dave Chinner <dchinner@redhat.com>
> ---
...
> 
> diff --git a/fs/xfs/libxfs/xfs_ag.c b/fs/xfs/libxfs/xfs_ag.c
> index c68a36688474..2ca31dc46fe8 100644
> --- a/fs/xfs/libxfs/xfs_ag.c
> +++ b/fs/xfs/libxfs/xfs_ag.c
> @@ -27,6 +27,141 @@
>  #include "xfs_defer.h"
>  #include "xfs_log_format.h"
>  #include "xfs_trans.h"
> +#include "xfs_trace.h"

The corresponding xfs_trace.h include can now be removed from
libxfs/xfs_sb.c. Otherwise looks like a straightforward move:

Reviewed-by: Brian Foster <bfoster@redhat.com>

> +
> +/*
> + * Passive reference counting access wrappers to the perag structures.  If the
> + * per-ag structure is to be freed, the freeing code is responsible for cleaning
> + * up objects with passive references before freeing the structure. This is
> + * things like cached buffers.
> + */
> +struct xfs_perag *
> +xfs_perag_get(
> +	struct xfs_mount	*mp,
> +	xfs_agnumber_t		agno)
> +{
> +	struct xfs_perag	*pag;
> +	int			ref = 0;
> +
> +	rcu_read_lock();
> +	pag = radix_tree_lookup(&mp->m_perag_tree, agno);
> +	if (pag) {
> +		ASSERT(atomic_read(&pag->pag_ref) >= 0);
> +		ref = atomic_inc_return(&pag->pag_ref);
> +	}
> +	rcu_read_unlock();
> +	trace_xfs_perag_get(mp, agno, ref, _RET_IP_);
> +	return pag;
> +}
> +
> +/*
> + * search from @first to find the next perag with the given tag set.
> + */
> +struct xfs_perag *
> +xfs_perag_get_tag(
> +	struct xfs_mount	*mp,
> +	xfs_agnumber_t		first,
> +	int			tag)
> +{
> +	struct xfs_perag	*pag;
> +	int			found;
> +	int			ref;
> +
> +	rcu_read_lock();
> +	found = radix_tree_gang_lookup_tag(&mp->m_perag_tree,
> +					(void **)&pag, first, 1, tag);
> +	if (found <= 0) {
> +		rcu_read_unlock();
> +		return NULL;
> +	}
> +	ref = atomic_inc_return(&pag->pag_ref);
> +	rcu_read_unlock();
> +	trace_xfs_perag_get_tag(mp, pag->pag_agno, ref, _RET_IP_);
> +	return pag;
> +}
> +
> +void
> +xfs_perag_put(
> +	struct xfs_perag	*pag)
> +{
> +	int	ref;
> +
> +	ASSERT(atomic_read(&pag->pag_ref) > 0);
> +	ref = atomic_dec_return(&pag->pag_ref);
> +	trace_xfs_perag_put(pag->pag_mount, pag->pag_agno, ref, _RET_IP_);
> +}
> +
> +/*
> + * xfs_initialize_perag_data
> + *
> + * Read in each per-ag structure so we can count up the number of
> + * allocated inodes, free inodes and used filesystem blocks as this
> + * information is no longer persistent in the superblock. Once we have
> + * this information, write it into the in-core superblock structure.
> + */
> +int
> +xfs_initialize_perag_data(
> +	struct xfs_mount *mp,
> +	xfs_agnumber_t	agcount)
> +{
> +	xfs_agnumber_t	index;
> +	xfs_perag_t	*pag;
> +	xfs_sb_t	*sbp = &mp->m_sb;
> +	uint64_t	ifree = 0;
> +	uint64_t	ialloc = 0;
> +	uint64_t	bfree = 0;
> +	uint64_t	bfreelst = 0;
> +	uint64_t	btree = 0;
> +	uint64_t	fdblocks;
> +	int		error = 0;
> +
> +	for (index = 0; index < agcount; index++) {
> +		/*
> +		 * read the agf, then the agi. This gets us
> +		 * all the information we need and populates the
> +		 * per-ag structures for us.
> +		 */
> +		error = xfs_alloc_pagf_init(mp, NULL, index, 0);
> +		if (error)
> +			return error;
> +
> +		error = xfs_ialloc_pagi_init(mp, NULL, index);
> +		if (error)
> +			return error;
> +		pag = xfs_perag_get(mp, index);
> +		ifree += pag->pagi_freecount;
> +		ialloc += pag->pagi_count;
> +		bfree += pag->pagf_freeblks;
> +		bfreelst += pag->pagf_flcount;
> +		btree += pag->pagf_btreeblks;
> +		xfs_perag_put(pag);
> +	}
> +	fdblocks = bfree + bfreelst + btree;
> +
> +	/*
> +	 * If the new summary counts are obviously incorrect, fail the
> +	 * mount operation because that implies the AGFs are also corrupt.
> +	 * Clear FS_COUNTERS so that we don't unmount with a dirty log, which
> +	 * will prevent xfs_repair from fixing anything.
> +	 */
> +	if (fdblocks > sbp->sb_dblocks || ifree > ialloc) {
> +		xfs_alert(mp, "AGF corruption. Please run xfs_repair.");
> +		error = -EFSCORRUPTED;
> +		goto out;
> +	}
> +
> +	/* Overwrite incore superblock counters with just-read data */
> +	spin_lock(&mp->m_sb_lock);
> +	sbp->sb_ifree = ifree;
> +	sbp->sb_icount = ialloc;
> +	sbp->sb_fdblocks = fdblocks;
> +	spin_unlock(&mp->m_sb_lock);
> +
> +	xfs_reinit_percpu_counters(mp);
> +out:
> +	xfs_fs_mark_healthy(mp, XFS_SICK_FS_COUNTERS);
> +	return error;
> +}
>  
>  static int
>  xfs_get_aghdr_buf(
> diff --git a/fs/xfs/libxfs/xfs_ag.h b/fs/xfs/libxfs/xfs_ag.h
> index 4535de1d88ea..cb1bd1c03cd7 100644
> --- a/fs/xfs/libxfs/xfs_ag.h
> +++ b/fs/xfs/libxfs/xfs_ag.h
> @@ -9,6 +9,16 @@
>  
>  struct xfs_mount;
>  struct xfs_trans;
> +struct xfs_perag;
> +
> +/*
> + * perag get/put wrappers for ref counting
> + */
> +int	xfs_initialize_perag_data(struct xfs_mount *, xfs_agnumber_t);
> +struct xfs_perag *xfs_perag_get(struct xfs_mount *, xfs_agnumber_t);
> +struct xfs_perag *xfs_perag_get_tag(struct xfs_mount *, xfs_agnumber_t,
> +				   int tag);
> +void	xfs_perag_put(struct xfs_perag *pag);
>  
>  struct aghdr_init_data {
>  	/* per ag data */
> diff --git a/fs/xfs/libxfs/xfs_ag_resv.c b/fs/xfs/libxfs/xfs_ag_resv.c
> index e32a1833d523..2e3dcdfd4984 100644
> --- a/fs/xfs/libxfs/xfs_ag_resv.c
> +++ b/fs/xfs/libxfs/xfs_ag_resv.c
> @@ -19,7 +19,7 @@
>  #include "xfs_btree.h"
>  #include "xfs_refcount_btree.h"
>  #include "xfs_ialloc_btree.h"
> -#include "xfs_sb.h"
> +#include "xfs_ag.h"
>  #include "xfs_ag_resv.h"
>  
>  /*
> diff --git a/fs/xfs/libxfs/xfs_alloc.c b/fs/xfs/libxfs/xfs_alloc.c
> index 82b7cbb1f24f..dc2b77829915 100644
> --- a/fs/xfs/libxfs/xfs_alloc.c
> +++ b/fs/xfs/libxfs/xfs_alloc.c
> @@ -10,7 +10,6 @@
>  #include "xfs_shared.h"
>  #include "xfs_trans_resv.h"
>  #include "xfs_bit.h"
> -#include "xfs_sb.h"
>  #include "xfs_mount.h"
>  #include "xfs_defer.h"
>  #include "xfs_btree.h"
> @@ -24,6 +23,7 @@
>  #include "xfs_trans.h"
>  #include "xfs_buf_item.h"
>  #include "xfs_log.h"
> +#include "xfs_ag.h"
>  #include "xfs_ag_resv.h"
>  #include "xfs_bmap.h"
>  
> diff --git a/fs/xfs/libxfs/xfs_alloc_btree.c b/fs/xfs/libxfs/xfs_alloc_btree.c
> index a43e4c50e69b..a540b6e799e0 100644
> --- a/fs/xfs/libxfs/xfs_alloc_btree.c
> +++ b/fs/xfs/libxfs/xfs_alloc_btree.c
> @@ -9,7 +9,6 @@
>  #include "xfs_format.h"
>  #include "xfs_log_format.h"
>  #include "xfs_trans_resv.h"
> -#include "xfs_sb.h"
>  #include "xfs_mount.h"
>  #include "xfs_btree.h"
>  #include "xfs_btree_staging.h"
> @@ -19,6 +18,7 @@
>  #include "xfs_error.h"
>  #include "xfs_trace.h"
>  #include "xfs_trans.h"
> +#include "xfs_ag.h"
>  
>  
>  STATIC struct xfs_btree_cur *
> diff --git a/fs/xfs/libxfs/xfs_attr_leaf.c b/fs/xfs/libxfs/xfs_attr_leaf.c
> index 556184b63061..aa371d005131 100644
> --- a/fs/xfs/libxfs/xfs_attr_leaf.c
> +++ b/fs/xfs/libxfs/xfs_attr_leaf.c
> @@ -27,6 +27,7 @@
>  #include "xfs_buf_item.h"
>  #include "xfs_dir2.h"
>  #include "xfs_log.h"
> +#include "xfs_ag.h"
>  
>  
>  /*
> diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c
> index 7e3b9b01431e..2086c55b67bd 100644
> --- a/fs/xfs/libxfs/xfs_bmap.c
> +++ b/fs/xfs/libxfs/xfs_bmap.c
> @@ -31,6 +31,7 @@
>  #include "xfs_attr_leaf.h"
>  #include "xfs_filestream.h"
>  #include "xfs_rmap.h"
> +#include "xfs_ag.h"
>  #include "xfs_ag_resv.h"
>  #include "xfs_refcount.h"
>  #include "xfs_icache.h"
> diff --git a/fs/xfs/libxfs/xfs_ialloc.c b/fs/xfs/libxfs/xfs_ialloc.c
> index eefdb518fe64..8dc9225a5353 100644
> --- a/fs/xfs/libxfs/xfs_ialloc.c
> +++ b/fs/xfs/libxfs/xfs_ialloc.c
> @@ -10,7 +10,6 @@
>  #include "xfs_log_format.h"
>  #include "xfs_trans_resv.h"
>  #include "xfs_bit.h"
> -#include "xfs_sb.h"
>  #include "xfs_mount.h"
>  #include "xfs_inode.h"
>  #include "xfs_btree.h"
> @@ -27,6 +26,7 @@
>  #include "xfs_trace.h"
>  #include "xfs_log.h"
>  #include "xfs_rmap.h"
> +#include "xfs_ag.h"
>  
>  /*
>   * Lookup a record by ino in the btree given by cur.
> diff --git a/fs/xfs/libxfs/xfs_refcount_btree.c b/fs/xfs/libxfs/xfs_refcount_btree.c
> index a6ac60ae9421..b281f0c674f5 100644
> --- a/fs/xfs/libxfs/xfs_refcount_btree.c
> +++ b/fs/xfs/libxfs/xfs_refcount_btree.c
> @@ -9,7 +9,6 @@
>  #include "xfs_format.h"
>  #include "xfs_log_format.h"
>  #include "xfs_trans_resv.h"
> -#include "xfs_sb.h"
>  #include "xfs_mount.h"
>  #include "xfs_btree.h"
>  #include "xfs_btree_staging.h"
> @@ -20,6 +19,7 @@
>  #include "xfs_trans.h"
>  #include "xfs_bit.h"
>  #include "xfs_rmap.h"
> +#include "xfs_ag.h"
>  
>  static struct xfs_btree_cur *
>  xfs_refcountbt_dup_cursor(
> diff --git a/fs/xfs/libxfs/xfs_rmap.c b/fs/xfs/libxfs/xfs_rmap.c
> index 10e0cf9949a2..61e8f10436ac 100644
> --- a/fs/xfs/libxfs/xfs_rmap.c
> +++ b/fs/xfs/libxfs/xfs_rmap.c
> @@ -21,6 +21,7 @@
>  #include "xfs_errortag.h"
>  #include "xfs_error.h"
>  #include "xfs_inode.h"
> +#include "xfs_ag.h"
>  
>  /*
>   * Lookup the first record less than or equal to [bno, len, owner, offset]
> diff --git a/fs/xfs/libxfs/xfs_rmap_btree.c b/fs/xfs/libxfs/xfs_rmap_btree.c
> index 9f5bcbd834c3..f1fee42dda2d 100644
> --- a/fs/xfs/libxfs/xfs_rmap_btree.c
> +++ b/fs/xfs/libxfs/xfs_rmap_btree.c
> @@ -9,7 +9,6 @@
>  #include "xfs_format.h"
>  #include "xfs_log_format.h"
>  #include "xfs_trans_resv.h"
> -#include "xfs_sb.h"
>  #include "xfs_mount.h"
>  #include "xfs_trans.h"
>  #include "xfs_alloc.h"
> @@ -20,6 +19,7 @@
>  #include "xfs_trace.h"
>  #include "xfs_error.h"
>  #include "xfs_extent_busy.h"
> +#include "xfs_ag.h"
>  #include "xfs_ag_resv.h"
>  
>  /*
> diff --git a/fs/xfs/libxfs/xfs_sb.c b/fs/xfs/libxfs/xfs_sb.c
> index dfbbcbd448c1..cbcfce8cebf1 100644
> --- a/fs/xfs/libxfs/xfs_sb.c
> +++ b/fs/xfs/libxfs/xfs_sb.c
> @@ -30,67 +30,6 @@
>   * Physical superblock buffer manipulations. Shared with libxfs in userspace.
>   */
>  
> -/*
> - * Reference counting access wrappers to the perag structures.
> - * Because we never free per-ag structures, the only thing we
> - * have to protect against changes is the tree structure itself.
> - */
> -struct xfs_perag *
> -xfs_perag_get(
> -	struct xfs_mount	*mp,
> -	xfs_agnumber_t		agno)
> -{
> -	struct xfs_perag	*pag;
> -	int			ref = 0;
> -
> -	rcu_read_lock();
> -	pag = radix_tree_lookup(&mp->m_perag_tree, agno);
> -	if (pag) {
> -		ASSERT(atomic_read(&pag->pag_ref) >= 0);
> -		ref = atomic_inc_return(&pag->pag_ref);
> -	}
> -	rcu_read_unlock();
> -	trace_xfs_perag_get(mp, agno, ref, _RET_IP_);
> -	return pag;
> -}
> -
> -/*
> - * search from @first to find the next perag with the given tag set.
> - */
> -struct xfs_perag *
> -xfs_perag_get_tag(
> -	struct xfs_mount	*mp,
> -	xfs_agnumber_t		first,
> -	int			tag)
> -{
> -	struct xfs_perag	*pag;
> -	int			found;
> -	int			ref;
> -
> -	rcu_read_lock();
> -	found = radix_tree_gang_lookup_tag(&mp->m_perag_tree,
> -					(void **)&pag, first, 1, tag);
> -	if (found <= 0) {
> -		rcu_read_unlock();
> -		return NULL;
> -	}
> -	ref = atomic_inc_return(&pag->pag_ref);
> -	rcu_read_unlock();
> -	trace_xfs_perag_get_tag(mp, pag->pag_agno, ref, _RET_IP_);
> -	return pag;
> -}
> -
> -void
> -xfs_perag_put(
> -	struct xfs_perag	*pag)
> -{
> -	int	ref;
> -
> -	ASSERT(atomic_read(&pag->pag_ref) > 0);
> -	ref = atomic_dec_return(&pag->pag_ref);
> -	trace_xfs_perag_put(pag->pag_mount, pag->pag_agno, ref, _RET_IP_);
> -}
> -
>  /* Check all the superblock fields we care about when reading one in. */
>  STATIC int
>  xfs_validate_sb_read(
> @@ -841,78 +780,6 @@ xfs_sb_mount_common(
>  	mp->m_ag_max_usable = xfs_alloc_ag_max_usable(mp);
>  }
>  
> -/*
> - * xfs_initialize_perag_data
> - *
> - * Read in each per-ag structure so we can count up the number of
> - * allocated inodes, free inodes and used filesystem blocks as this
> - * information is no longer persistent in the superblock. Once we have
> - * this information, write it into the in-core superblock structure.
> - */
> -int
> -xfs_initialize_perag_data(
> -	struct xfs_mount *mp,
> -	xfs_agnumber_t	agcount)
> -{
> -	xfs_agnumber_t	index;
> -	xfs_perag_t	*pag;
> -	xfs_sb_t	*sbp = &mp->m_sb;
> -	uint64_t	ifree = 0;
> -	uint64_t	ialloc = 0;
> -	uint64_t	bfree = 0;
> -	uint64_t	bfreelst = 0;
> -	uint64_t	btree = 0;
> -	uint64_t	fdblocks;
> -	int		error = 0;
> -
> -	for (index = 0; index < agcount; index++) {
> -		/*
> -		 * read the agf, then the agi. This gets us
> -		 * all the information we need and populates the
> -		 * per-ag structures for us.
> -		 */
> -		error = xfs_alloc_pagf_init(mp, NULL, index, 0);
> -		if (error)
> -			return error;
> -
> -		error = xfs_ialloc_pagi_init(mp, NULL, index);
> -		if (error)
> -			return error;
> -		pag = xfs_perag_get(mp, index);
> -		ifree += pag->pagi_freecount;
> -		ialloc += pag->pagi_count;
> -		bfree += pag->pagf_freeblks;
> -		bfreelst += pag->pagf_flcount;
> -		btree += pag->pagf_btreeblks;
> -		xfs_perag_put(pag);
> -	}
> -	fdblocks = bfree + bfreelst + btree;
> -
> -	/*
> -	 * If the new summary counts are obviously incorrect, fail the
> -	 * mount operation because that implies the AGFs are also corrupt.
> -	 * Clear FS_COUNTERS so that we don't unmount with a dirty log, which
> -	 * will prevent xfs_repair from fixing anything.
> -	 */
> -	if (fdblocks > sbp->sb_dblocks || ifree > ialloc) {
> -		xfs_alert(mp, "AGF corruption. Please run xfs_repair.");
> -		error = -EFSCORRUPTED;
> -		goto out;
> -	}
> -
> -	/* Overwrite incore superblock counters with just-read data */
> -	spin_lock(&mp->m_sb_lock);
> -	sbp->sb_ifree = ifree;
> -	sbp->sb_icount = ialloc;
> -	sbp->sb_fdblocks = fdblocks;
> -	spin_unlock(&mp->m_sb_lock);
> -
> -	xfs_reinit_percpu_counters(mp);
> -out:
> -	xfs_fs_mark_healthy(mp, XFS_SICK_FS_COUNTERS);
> -	return error;
> -}
> -
>  /*
>   * xfs_log_sb() can be used to copy arbitrary changes to the in-core superblock
>   * into the superblock buffer to be logged.  It does not provide the higher
> diff --git a/fs/xfs/libxfs/xfs_sb.h b/fs/xfs/libxfs/xfs_sb.h
> index f79f9dc632b6..0c1602d9b53d 100644
> --- a/fs/xfs/libxfs/xfs_sb.h
> +++ b/fs/xfs/libxfs/xfs_sb.h
> @@ -13,15 +13,6 @@ struct xfs_trans;
>  struct xfs_fsop_geom;
>  struct xfs_perag;
>  
> -/*
> - * perag get/put wrappers for ref counting
> - */
> -extern struct xfs_perag *xfs_perag_get(struct xfs_mount *, xfs_agnumber_t);
> -extern struct xfs_perag *xfs_perag_get_tag(struct xfs_mount *, xfs_agnumber_t,
> -					   int tag);
> -extern void	xfs_perag_put(struct xfs_perag *pag);
> -extern int	xfs_initialize_perag_data(struct xfs_mount *, xfs_agnumber_t);
> -
>  extern void	xfs_log_sb(struct xfs_trans *tp);
>  extern int	xfs_sync_sb(struct xfs_mount *mp, bool wait);
>  extern int	xfs_sync_sb_buf(struct xfs_mount *mp);
> diff --git a/fs/xfs/scrub/agheader.c b/fs/xfs/scrub/agheader.c
> index 7a2f9b5f2db5..64a7a30f4ac0 100644
> --- a/fs/xfs/scrub/agheader.c
> +++ b/fs/xfs/scrub/agheader.c
> @@ -14,6 +14,7 @@
>  #include "xfs_alloc.h"
>  #include "xfs_ialloc.h"
>  #include "xfs_rmap.h"
> +#include "xfs_ag.h"
>  #include "scrub/scrub.h"
>  #include "scrub/common.h"
>  
> diff --git a/fs/xfs/scrub/agheader_repair.c b/fs/xfs/scrub/agheader_repair.c
> index 23690f824ffa..1cdfbd57f36b 100644
> --- a/fs/xfs/scrub/agheader_repair.c
> +++ b/fs/xfs/scrub/agheader_repair.c
> @@ -20,6 +20,7 @@
>  #include "xfs_rmap.h"
>  #include "xfs_rmap_btree.h"
>  #include "xfs_refcount_btree.h"
> +#include "xfs_ag.h"
>  #include "scrub/scrub.h"
>  #include "scrub/common.h"
>  #include "scrub/trace.h"
> diff --git a/fs/xfs/scrub/common.c b/fs/xfs/scrub/common.c
> index aa874607618a..c8da976b50fc 100644
> --- a/fs/xfs/scrub/common.c
> +++ b/fs/xfs/scrub/common.c
> @@ -12,7 +12,6 @@
>  #include "xfs_btree.h"
>  #include "xfs_log_format.h"
>  #include "xfs_trans.h"
> -#include "xfs_sb.h"
>  #include "xfs_inode.h"
>  #include "xfs_icache.h"
>  #include "xfs_alloc.h"
> @@ -26,6 +25,7 @@
>  #include "xfs_trans_priv.h"
>  #include "xfs_attr.h"
>  #include "xfs_reflink.h"
> +#include "xfs_ag.h"
>  #include "scrub/scrub.h"
>  #include "scrub/common.h"
>  #include "scrub/trace.h"
> diff --git a/fs/xfs/scrub/fscounters.c b/fs/xfs/scrub/fscounters.c
> index f1d1a8c58853..453ae9adf94c 100644
> --- a/fs/xfs/scrub/fscounters.c
> +++ b/fs/xfs/scrub/fscounters.c
> @@ -9,11 +9,11 @@
>  #include "xfs_format.h"
>  #include "xfs_trans_resv.h"
>  #include "xfs_mount.h"
> -#include "xfs_sb.h"
>  #include "xfs_alloc.h"
>  #include "xfs_ialloc.h"
>  #include "xfs_health.h"
>  #include "xfs_btree.h"
> +#include "xfs_ag.h"
>  #include "scrub/scrub.h"
>  #include "scrub/common.h"
>  #include "scrub/trace.h"
> diff --git a/fs/xfs/scrub/health.c b/fs/xfs/scrub/health.c
> index 3de59b5c2ce6..2e61df3bca83 100644
> --- a/fs/xfs/scrub/health.c
> +++ b/fs/xfs/scrub/health.c
> @@ -8,7 +8,7 @@
>  #include "xfs_shared.h"
>  #include "xfs_format.h"
>  #include "xfs_btree.h"
> -#include "xfs_sb.h"
> +#include "xfs_ag.h"
>  #include "xfs_health.h"
>  #include "scrub/scrub.h"
>  #include "scrub/health.h"
> diff --git a/fs/xfs/scrub/repair.c b/fs/xfs/scrub/repair.c
> index c2857d854c83..1308b62a8170 100644
> --- a/fs/xfs/scrub/repair.c
> +++ b/fs/xfs/scrub/repair.c
> @@ -22,6 +22,7 @@
>  #include "xfs_rmap_btree.h"
>  #include "xfs_refcount_btree.h"
>  #include "xfs_extent_busy.h"
> +#include "xfs_ag.h"
>  #include "xfs_ag_resv.h"
>  #include "xfs_quota.h"
>  #include "scrub/scrub.h"
> diff --git a/fs/xfs/xfs_buf.c b/fs/xfs/xfs_buf.c
> index 37a1d12762d8..38245c49b1b6 100644
> --- a/fs/xfs/xfs_buf.c
> +++ b/fs/xfs/xfs_buf.c
> @@ -10,7 +10,6 @@
>  #include "xfs_format.h"
>  #include "xfs_log_format.h"
>  #include "xfs_trans_resv.h"
> -#include "xfs_sb.h"
>  #include "xfs_mount.h"
>  #include "xfs_trace.h"
>  #include "xfs_log.h"
> @@ -19,6 +18,7 @@
>  #include "xfs_buf_item.h"
>  #include "xfs_errortag.h"
>  #include "xfs_error.h"
> +#include "xfs_ag.h"
>  
>  static kmem_zone_t *xfs_buf_zone;
>  
> diff --git a/fs/xfs/xfs_discard.c b/fs/xfs/xfs_discard.c
> index f979d0d7e6cd..3bf6dba1a040 100644
> --- a/fs/xfs/xfs_discard.c
> +++ b/fs/xfs/xfs_discard.c
> @@ -8,7 +8,6 @@
>  #include "xfs_format.h"
>  #include "xfs_log_format.h"
>  #include "xfs_trans_resv.h"
> -#include "xfs_sb.h"
>  #include "xfs_mount.h"
>  #include "xfs_btree.h"
>  #include "xfs_alloc_btree.h"
> @@ -18,6 +17,7 @@
>  #include "xfs_extent_busy.h"
>  #include "xfs_trace.h"
>  #include "xfs_log.h"
> +#include "xfs_ag.h"
>  
>  STATIC int
>  xfs_trim_extents(
> diff --git a/fs/xfs/xfs_extent_busy.c b/fs/xfs/xfs_extent_busy.c
> index ef17c1f6db32..184732aa8674 100644
> --- a/fs/xfs/xfs_extent_busy.c
> +++ b/fs/xfs/xfs_extent_busy.c
> @@ -11,13 +11,13 @@
>  #include "xfs_log_format.h"
>  #include "xfs_shared.h"
>  #include "xfs_trans_resv.h"
> -#include "xfs_sb.h"
>  #include "xfs_mount.h"
>  #include "xfs_alloc.h"
>  #include "xfs_extent_busy.h"
>  #include "xfs_trace.h"
>  #include "xfs_trans.h"
>  #include "xfs_log.h"
> +#include "xfs_ag.h"
>  
>  void
>  xfs_extent_busy_insert(
> diff --git a/fs/xfs/xfs_filestream.c b/fs/xfs/xfs_filestream.c
> index db23e455eb91..eed6ca5f8f91 100644
> --- a/fs/xfs/xfs_filestream.c
> +++ b/fs/xfs/xfs_filestream.c
> @@ -9,13 +9,13 @@
>  #include "xfs_format.h"
>  #include "xfs_log_format.h"
>  #include "xfs_trans_resv.h"
> -#include "xfs_sb.h"
>  #include "xfs_mount.h"
>  #include "xfs_inode.h"
>  #include "xfs_bmap.h"
>  #include "xfs_alloc.h"
>  #include "xfs_mru_cache.h"
>  #include "xfs_trace.h"
> +#include "xfs_ag.h"
>  #include "xfs_ag_resv.h"
>  #include "xfs_trans.h"
>  #include "xfs_filestream.h"
> diff --git a/fs/xfs/xfs_health.c b/fs/xfs/xfs_health.c
> index 8e0cb05a7142..b79475ea3dbd 100644
> --- a/fs/xfs/xfs_health.c
> +++ b/fs/xfs/xfs_health.c
> @@ -9,11 +9,11 @@
>  #include "xfs_format.h"
>  #include "xfs_log_format.h"
>  #include "xfs_trans_resv.h"
> -#include "xfs_sb.h"
>  #include "xfs_mount.h"
>  #include "xfs_inode.h"
>  #include "xfs_trace.h"
>  #include "xfs_health.h"
> +#include "xfs_ag.h"
>  
>  /*
>   * Warn about metadata corruption that we detected but haven't fixed, and
> diff --git a/fs/xfs/xfs_icache.c b/fs/xfs/xfs_icache.c
> index 3c81daca0e9a..588ea2bf88bb 100644
> --- a/fs/xfs/xfs_icache.c
> +++ b/fs/xfs/xfs_icache.c
> @@ -9,7 +9,6 @@
>  #include "xfs_format.h"
>  #include "xfs_log_format.h"
>  #include "xfs_trans_resv.h"
> -#include "xfs_sb.h"
>  #include "xfs_mount.h"
>  #include "xfs_inode.h"
>  #include "xfs_trans.h"
> @@ -23,6 +22,7 @@
>  #include "xfs_dquot.h"
>  #include "xfs_reflink.h"
>  #include "xfs_ialloc.h"
> +#include "xfs_ag.h"
>  
>  #include <linux/iversion.h>
>  
> diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
> index 17c2d8b18283..25910b145d70 100644
> --- a/fs/xfs/xfs_inode.c
> +++ b/fs/xfs/xfs_inode.c
> @@ -11,7 +11,6 @@
>  #include "xfs_format.h"
>  #include "xfs_log_format.h"
>  #include "xfs_trans_resv.h"
> -#include "xfs_sb.h"
>  #include "xfs_mount.h"
>  #include "xfs_defer.h"
>  #include "xfs_inode.h"
> @@ -35,6 +34,7 @@
>  #include "xfs_log.h"
>  #include "xfs_bmap_btree.h"
>  #include "xfs_reflink.h"
> +#include "xfs_ag.h"
>  
>  kmem_zone_t *xfs_inode_zone;
>  
> diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c
> index e5dd1c0c2f03..fee2a4e80241 100644
> --- a/fs/xfs/xfs_log_recover.c
> +++ b/fs/xfs/xfs_log_recover.c
> @@ -25,6 +25,7 @@
>  #include "xfs_icache.h"
>  #include "xfs_error.h"
>  #include "xfs_buf_item.h"
> +#include "xfs_ag.h"
>  
>  #define BLK_AVG(blk1, blk2)	((blk1+blk2) >> 1)
>  
> diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c
> index bdfee1943796..21c630dde476 100644
> --- a/fs/xfs/xfs_mount.c
> +++ b/fs/xfs/xfs_mount.c
> @@ -32,6 +32,7 @@
>  #include "xfs_extent_busy.h"
>  #include "xfs_health.h"
>  #include "xfs_trace.h"
> +#include "xfs_ag.h"
>  
>  static DEFINE_MUTEX(xfs_uuid_table_mutex);
>  static int xfs_uuid_table_size;
> diff --git a/fs/xfs/xfs_qm.c b/fs/xfs/xfs_qm.c
> index 4bf949a89d0d..f7baf4dc2554 100644
> --- a/fs/xfs/xfs_qm.c
> +++ b/fs/xfs/xfs_qm.c
> @@ -23,6 +23,7 @@
>  #include "xfs_trace.h"
>  #include "xfs_icache.h"
>  #include "xfs_error.h"
> +#include "xfs_ag.h"
>  
>  /*
>   * The global quota manager. There is only one of these for the entire
> diff --git a/fs/xfs/xfs_reflink.c b/fs/xfs/xfs_reflink.c
> index 060695d6d56a..f297d68a931b 100644
> --- a/fs/xfs/xfs_reflink.c
> +++ b/fs/xfs/xfs_reflink.c
> @@ -27,7 +27,7 @@
>  #include "xfs_quota.h"
>  #include "xfs_reflink.h"
>  #include "xfs_iomap.h"
> -#include "xfs_sb.h"
> +#include "xfs_ag.h"
>  #include "xfs_ag_resv.h"
>  
>  /*
> diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c
> index a2dab05332ac..688309dbe18b 100644
> --- a/fs/xfs/xfs_super.c
> +++ b/fs/xfs/xfs_super.c
> @@ -36,6 +36,7 @@
>  #include "xfs_bmap_item.h"
>  #include "xfs_reflink.h"
>  #include "xfs_pwork.h"
> +#include "xfs_ag.h"
>  
>  #include <linux/magic.h>
>  #include <linux/fs_context.h>
> -- 
> 2.31.1
> 


^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 02/22] xfs: prepare for moving perag definitions and support to libxfs
  2021-05-06  7:20 ` [PATCH 02/22] xfs: prepare for moving perag definitions and support to libxfs Dave Chinner
@ 2021-05-10 12:53   ` Brian Foster
  2021-05-11  7:19     ` Dave Chinner
  0 siblings, 1 reply; 87+ messages in thread
From: Brian Foster @ 2021-05-10 12:53 UTC (permalink / raw)
  To: Dave Chinner; +Cc: linux-xfs

On Thu, May 06, 2021 at 05:20:34PM +1000, Dave Chinner wrote:
> From: Dave Chinner <dchinner@redhat.com>
> 
> The perag structures really need to be defined with the rest of the
> AG support infrastructure. The struct xfs_perag and init/teardown
> has been placed in xfs_mount.[ch] because there are differences in
> the structure between kernel and userspace. Mainly that userspace
> doesn't have a lot of the internal stuff that the kernel has for
> caches and discard and other such structures.
> 
> However, it makes more sense to move this to libxfs than to keep
> this separation because we are now moving to use struct perags
> everywhere in the code instead of passing raw agnumber_t values
> about. Hence we shoudl really move the support infrastructure to
> libxfs/xfs_ag.[ch].
> 
> To do this without breaking userspace, first we need to rearrange
> the structures and code so that all the kernel specific code is
> located together. This makes it simple for userspace to ifdef out
> the all the parts it does not need, minimising the code differences
> between kernel and userspace. The next commit will do the move...
> 
> Signed-off-by: Dave Chinner <dchinner@redhat.com>
> ---
>  fs/xfs/xfs_mount.c | 50 ++++++++++++++++++++++++++--------------------
>  fs/xfs/xfs_mount.h | 19 +++++++++---------
>  2 files changed, 38 insertions(+), 31 deletions(-)
> 
> diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c
> index 21c630dde476..2e6d42014346 100644
> --- a/fs/xfs/xfs_mount.c
> +++ b/fs/xfs/xfs_mount.c
...
> @@ -229,13 +220,27 @@ xfs_initialize_perag(
>  		}
>  		spin_unlock(&mp->m_perag_lock);
>  		radix_tree_preload_end();
> -		/* first new pag is fully initialized */
> -		if (first_initialised == NULLAGNUMBER)
> -			first_initialised = index;
> +
> +		spin_lock_init(&pag->pag_ici_lock);
> +		spin_lock_init(&pag->pagb_lock);
> +		spin_lock_init(&pag->pag_state_lock);
> +		INIT_DELAYED_WORK(&pag->pag_blockgc_work, xfs_blockgc_worker);
> +		INIT_RADIX_TREE(&pag->pag_ici_root, GFP_ATOMIC);
> +		init_waitqueue_head(&pag->pagb_wait);
> +		pag->pagb_count = 0;
> +		pag->pagb_tree = RB_ROOT;
> +
> +		error = xfs_buf_hash_init(pag);
> +		if (error)
> +			goto out_free_pag;
> +

There's error handling code earlier up in this function that still lands
in out_hash_destroy, which is now before we get to the _hash_init()
call.

>  		error = xfs_iunlink_init(pag);
>  		if (error)
>  			goto out_hash_destroy;
> -		spin_lock_init(&pag->pag_state_lock);
> +
> +		/* first new pag is fully initialized */
> +		if (first_initialised == NULLAGNUMBER)
> +			first_initialised = index;
>  	}
>  
>  	index = xfs_set_inode_alloc(mp, agcount);
> @@ -249,6 +254,7 @@ xfs_initialize_perag(
>  out_hash_destroy:
>  	xfs_buf_hash_destroy(pag);
>  out_free_pag:
> +	pag = radix_tree_delete(&mp->m_perag_tree, index);

Now if we get here with an allocated pag that hasn't been inserted to
the tree, I suspect this call would assign pag = NULL..

Brian

>  	kmem_free(pag);
>  out_unwind_new_pags:
>  	/* unwind any prior newly initialized pags */
> diff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h
> index bb67274ee23f..6e534be5eea8 100644
> --- a/fs/xfs/xfs_mount.h
> +++ b/fs/xfs/xfs_mount.h
> @@ -338,6 +338,16 @@ typedef struct xfs_perag {
>  	xfs_agino_t	pagl_leftrec;
>  	xfs_agino_t	pagl_rightrec;
>  
> +	int		pagb_count;	/* pagb slots in use */
> +	uint8_t		pagf_refcount_level; /* recount btree height */
> +
> +	/* Blocks reserved for all kinds of metadata. */
> +	struct xfs_ag_resv	pag_meta_resv;
> +	/* Blocks reserved for the reverse mapping btree. */
> +	struct xfs_ag_resv	pag_rmapbt_resv;
> +
> +	/* -- kernel only structures below this line -- */
> +
>  	/*
>  	 * Bitsets of per-ag metadata that have been checked and/or are sick.
>  	 * Callers should hold pag_state_lock before accessing this field.
> @@ -364,19 +374,10 @@ typedef struct xfs_perag {
>  
>  	/* for rcu-safe freeing */
>  	struct rcu_head	rcu_head;
> -	int		pagb_count;	/* pagb slots in use */
> -
> -	/* Blocks reserved for all kinds of metadata. */
> -	struct xfs_ag_resv	pag_meta_resv;
> -	/* Blocks reserved for the reverse mapping btree. */
> -	struct xfs_ag_resv	pag_rmapbt_resv;
>  
>  	/* background prealloc block trimming */
>  	struct delayed_work	pag_blockgc_work;
>  
> -	/* reference count */
> -	uint8_t			pagf_refcount_level;
> -
>  	/*
>  	 * Unlinked inode information.  This incore information reflects
>  	 * data stored in the AGI, so callers must hold the AGI buffer lock
> -- 
> 2.31.1
> 


^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 04/22] xfs: make for_each_perag... a first class citizen
  2021-05-06  7:20 ` [PATCH 04/22] xfs: make for_each_perag... a first class citizen Dave Chinner
@ 2021-05-10 12:53   ` Brian Foster
  2021-05-11  7:35     ` Dave Chinner
  0 siblings, 1 reply; 87+ messages in thread
From: Brian Foster @ 2021-05-10 12:53 UTC (permalink / raw)
  To: Dave Chinner; +Cc: linux-xfs

On Thu, May 06, 2021 at 05:20:36PM +1000, Dave Chinner wrote:
> From: Dave Chinner <dchinner@redhat.com>
> 
> for_each_perag_tag() is defined in xfs_icache.c for local use.
> Promote this to xfs_ag.h and define equivalent iteration functions
> so that we can use them to iterate AGs instead to replace open coded
> perag walks and perag lookups.
> 
> We also convert as many of the straight forward open coded AG walks
> to use these iterators as possible. Anything that is not a direct
> conversion to an iterator is ignored and will be updated in future
> commits.
> 
> Signed-off-by: Dave Chinner <dchinner@redhat.com>
> ---
>  fs/xfs/libxfs/xfs_ag.h    | 17 +++++++++++++++++
>  fs/xfs/scrub/fscounters.c | 36 ++++++++++++++----------------------
>  fs/xfs/xfs_extent_busy.c  |  7 ++-----
>  fs/xfs/xfs_fsops.c        |  8 ++------
>  fs/xfs/xfs_health.c       |  4 +---
>  fs/xfs/xfs_icache.c       | 15 ++-------------
>  6 files changed, 38 insertions(+), 49 deletions(-)
> 
...
> diff --git a/fs/xfs/scrub/fscounters.c b/fs/xfs/scrub/fscounters.c
> index 453ae9adf94c..2dfdac566399 100644
> --- a/fs/xfs/scrub/fscounters.c
> +++ b/fs/xfs/scrub/fscounters.c
...
> @@ -229,12 +224,9 @@ xchk_fscount_aggregate_agcounts(
>  		fsc->fdblocks -= pag->pag_meta_resv.ar_reserved;
>  		fsc->fdblocks -= pag->pag_rmapbt_resv.ar_orig_reserved;
>  
> -		xfs_perag_put(pag);
> -
> -		if (xchk_should_terminate(sc, &error))
> -			break;
>  	}
> -
> +	if (pag)
> +		xfs_perag_put(pag);

It's not shown in the diff, but there is still an exit path out of the
above loop that calls xfs_perag_put(). The rest of the patch LGTM.

Brian

>  	if (error)
>  		return error;
>  
> diff --git a/fs/xfs/xfs_extent_busy.c b/fs/xfs/xfs_extent_busy.c
> index 184732aa8674..6af0b5a1c7b0 100644
> --- a/fs/xfs/xfs_extent_busy.c
> +++ b/fs/xfs/xfs_extent_busy.c
> @@ -605,12 +605,11 @@ void
>  xfs_extent_busy_wait_all(
>  	struct xfs_mount	*mp)
>  {
> +	struct xfs_perag	*pag;
>  	DEFINE_WAIT		(wait);
>  	xfs_agnumber_t		agno;
>  
> -	for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) {
> -		struct xfs_perag *pag = xfs_perag_get(mp, agno);
> -
> +	for_each_perag(mp, agno, pag) {
>  		do {
>  			prepare_to_wait(&pag->pagb_wait, &wait, TASK_KILLABLE);
>  			if  (RB_EMPTY_ROOT(&pag->pagb_tree))
> @@ -618,8 +617,6 @@ xfs_extent_busy_wait_all(
>  			schedule();
>  		} while (1);
>  		finish_wait(&pag->pagb_wait, &wait);
> -
> -		xfs_perag_put(pag);
>  	}
>  }
>  
> diff --git a/fs/xfs/xfs_fsops.c b/fs/xfs/xfs_fsops.c
> index be9cf88d2ad7..07c745cd483e 100644
> --- a/fs/xfs/xfs_fsops.c
> +++ b/fs/xfs/xfs_fsops.c
> @@ -576,10 +576,8 @@ xfs_fs_reserve_ag_blocks(
>  	int			err2;
>  
>  	mp->m_finobt_nores = false;
> -	for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) {
> -		pag = xfs_perag_get(mp, agno);
> +	for_each_perag(mp, agno, pag) {
>  		err2 = xfs_ag_resv_init(pag, NULL);
> -		xfs_perag_put(pag);
>  		if (err2 && !error)
>  			error = err2;
>  	}
> @@ -605,10 +603,8 @@ xfs_fs_unreserve_ag_blocks(
>  	int			error = 0;
>  	int			err2;
>  
> -	for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) {
> -		pag = xfs_perag_get(mp, agno);
> +	for_each_perag(mp, agno, pag) {
>  		err2 = xfs_ag_resv_free(pag);
> -		xfs_perag_put(pag);
>  		if (err2 && !error)
>  			error = err2;
>  	}
> diff --git a/fs/xfs/xfs_health.c b/fs/xfs/xfs_health.c
> index b79475ea3dbd..5de3195f6cb2 100644
> --- a/fs/xfs/xfs_health.c
> +++ b/fs/xfs/xfs_health.c
> @@ -34,14 +34,12 @@ xfs_health_unmount(
>  		return;
>  
>  	/* Measure AG corruption levels. */
> -	for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) {
> -		pag = xfs_perag_get(mp, agno);
> +	for_each_perag(mp, agno, pag) {
>  		xfs_ag_measure_sickness(pag, &sick, &checked);
>  		if (sick) {
>  			trace_xfs_ag_unfixed_corruption(mp, agno, sick);
>  			warn = true;
>  		}
> -		xfs_perag_put(pag);
>  	}
>  
>  	/* Measure realtime volume corruption levels. */
> diff --git a/fs/xfs/xfs_icache.c b/fs/xfs/xfs_icache.c
> index 588ea2bf88bb..7dad83a6f586 100644
> --- a/fs/xfs/xfs_icache.c
> +++ b/fs/xfs/xfs_icache.c
> @@ -1061,15 +1061,13 @@ xfs_reclaim_inodes_ag(
>  	int			*nr_to_scan)
>  {
>  	struct xfs_perag	*pag;
> -	xfs_agnumber_t		ag = 0;
> +	xfs_agnumber_t		agno;
>  
> -	while ((pag = xfs_perag_get_tag(mp, ag, XFS_ICI_RECLAIM_TAG))) {
> +	for_each_perag_tag(mp, agno, pag, XFS_ICI_RECLAIM_TAG) {
>  		unsigned long	first_index = 0;
>  		int		done = 0;
>  		int		nr_found = 0;
>  
> -		ag = pag->pag_agno + 1;
> -
>  		first_index = READ_ONCE(pag->pag_ici_reclaim_cursor);
>  		do {
>  			struct xfs_inode *batch[XFS_LOOKUP_BATCH];
> @@ -1134,7 +1132,6 @@ xfs_reclaim_inodes_ag(
>  		if (done)
>  			first_index = 0;
>  		WRITE_ONCE(pag->pag_ici_reclaim_cursor, first_index);
> -		xfs_perag_put(pag);
>  	}
>  }
>  
> @@ -1554,14 +1551,6 @@ xfs_inode_clear_cowblocks_tag(
>  	return xfs_blockgc_clear_iflag(ip, XFS_ICOWBLOCKS);
>  }
>  
> -#define for_each_perag_tag(mp, next_agno, pag, tag) \
> -	for ((next_agno) = 0, (pag) = xfs_perag_get_tag((mp), 0, (tag)); \
> -		(pag) != NULL; \
> -		(next_agno) = (pag)->pag_agno + 1, \
> -		xfs_perag_put(pag), \
> -		(pag) = xfs_perag_get_tag((mp), (next_agno), (tag)))
> -
> -
>  /* Disable post-EOF and CoW block auto-reclamation. */
>  void
>  xfs_blockgc_stop(
> -- 
> 2.31.1
> 


^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 05/22] xfs: convert raw ag walks to use for_each_perag
  2021-05-06  7:20 ` [PATCH 05/22] xfs: convert raw ag walks to use for_each_perag Dave Chinner
@ 2021-05-10 12:54   ` Brian Foster
  0 siblings, 0 replies; 87+ messages in thread
From: Brian Foster @ 2021-05-10 12:54 UTC (permalink / raw)
  To: Dave Chinner; +Cc: linux-xfs

On Thu, May 06, 2021 at 05:20:37PM +1000, Dave Chinner wrote:
> From: Dave Chinner <dchinner@redhat.com>
> 
> Convert the raw walks to an iterator, pulling the current AG out of
> pag->pag_agno instead of the loop iterator variable.
> 
> Signed-off-by: Dave Chinner <dchinner@redhat.com>
> ---
>  fs/xfs/libxfs/xfs_types.c |  4 ++-
>  fs/xfs/scrub/bmap.c       |  6 +++--
>  fs/xfs/xfs_log_recover.c  | 55 ++++++++++++++++++---------------------
>  fs/xfs/xfs_reflink.c      |  9 ++++---
>  4 files changed, 39 insertions(+), 35 deletions(-)
> 
...
> diff --git a/fs/xfs/scrub/bmap.c b/fs/xfs/scrub/bmap.c
> index b5ebf1d1b4db..c60a1990d629 100644
> --- a/fs/xfs/scrub/bmap.c
> +++ b/fs/xfs/scrub/bmap.c
...
> @@ -607,8 +609,8 @@ xchk_bmap_check_rmaps(
>  	    (zero_size || ifp->if_nextents > 0))
>  		return 0;
>  
> -	for (agno = 0; agno < sc->mp->m_sb.sb_agcount; agno++) {
> -		error = xchk_bmap_check_ag_rmaps(sc, whichfork, agno);
> +	for_each_perag(sc->mp, agno, pag) {
> +		error = xchk_bmap_check_ag_rmaps(sc, whichfork, pag->pag_agno);
>  		if (error)
>  			return error;

It looks like this loop is missing xfs_perag_put() early breakout
treatment. The rest of the patch LGTM.

Brian

>  		if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
> diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c
> index fee2a4e80241..1227503d2246 100644
> --- a/fs/xfs/xfs_log_recover.c
> +++ b/fs/xfs/xfs_log_recover.c
> @@ -2742,21 +2742,17 @@ STATIC void
>  xlog_recover_process_iunlinks(
>  	struct xlog	*log)
>  {
> -	xfs_mount_t	*mp;
> -	xfs_agnumber_t	agno;
> -	xfs_agi_t	*agi;
> -	struct xfs_buf	*agibp;
> -	xfs_agino_t	agino;
> -	int		bucket;
> -	int		error;
> -
> -	mp = log->l_mp;
> +	struct xfs_mount	*mp = log->l_mp;
> +	struct xfs_perag	*pag;
> +	xfs_agnumber_t		agno;
> +	struct xfs_agi		*agi;
> +	struct xfs_buf		*agibp;
> +	xfs_agino_t		agino;
> +	int			bucket;
> +	int			error;
>  
> -	for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) {
> -		/*
> -		 * Find the agi for this ag.
> -		 */
> -		error = xfs_read_agi(mp, NULL, agno, &agibp);
> +	for_each_perag(mp, agno, pag) {
> +		error = xfs_read_agi(mp, NULL, pag->pag_agno, &agibp);
>  		if (error) {
>  			/*
>  			 * AGI is b0rked. Don't process it.
> @@ -2782,7 +2778,7 @@ xlog_recover_process_iunlinks(
>  			agino = be32_to_cpu(agi->agi_unlinked[bucket]);
>  			while (agino != NULLAGINO) {
>  				agino = xlog_recover_process_one_iunlink(mp,
> -							agno, agino, bucket);
> +						pag->pag_agno, agino, bucket);
>  				cond_resched();
>  			}
>  		}
> @@ -3494,27 +3490,28 @@ xlog_recover_cancel(
>   */
>  STATIC void
>  xlog_recover_check_summary(
> -	struct xlog	*log)
> +	struct xlog		*log)
>  {
> -	xfs_mount_t	*mp;
> -	struct xfs_buf	*agfbp;
> -	struct xfs_buf	*agibp;
> -	xfs_agnumber_t	agno;
> -	uint64_t	freeblks;
> -	uint64_t	itotal;
> -	uint64_t	ifree;
> -	int		error;
> +	struct xfs_mount	*mp = log->l_mp;
> +	struct xfs_perag	*pag;
> +	struct xfs_buf		*agfbp;
> +	struct xfs_buf		*agibp;
> +	xfs_agnumber_t		agno;
> +	uint64_t		freeblks;
> +	uint64_t		itotal;
> +	uint64_t		ifree;
> +	int			error;
>  
>  	mp = log->l_mp;
>  
>  	freeblks = 0LL;
>  	itotal = 0LL;
>  	ifree = 0LL;
> -	for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) {
> -		error = xfs_read_agf(mp, NULL, agno, 0, &agfbp);
> +	for_each_perag(mp, agno, pag) {
> +		error = xfs_read_agf(mp, NULL, pag->pag_agno, 0, &agfbp);
>  		if (error) {
>  			xfs_alert(mp, "%s agf read failed agno %d error %d",
> -						__func__, agno, error);
> +						__func__, pag->pag_agno, error);
>  		} else {
>  			struct xfs_agf	*agfp = agfbp->b_addr;
>  
> @@ -3523,10 +3520,10 @@ xlog_recover_check_summary(
>  			xfs_buf_relse(agfbp);
>  		}
>  
> -		error = xfs_read_agi(mp, NULL, agno, &agibp);
> +		error = xfs_read_agi(mp, NULL, pag->pag_agno, &agibp);
>  		if (error) {
>  			xfs_alert(mp, "%s agi read failed agno %d error %d",
> -						__func__, agno, error);
> +						__func__, pag->pag_agno, error);
>  		} else {
>  			struct xfs_agi	*agi = agibp->b_addr;
>  
> diff --git a/fs/xfs/xfs_reflink.c b/fs/xfs/xfs_reflink.c
> index f297d68a931b..0e430b0c1b16 100644
> --- a/fs/xfs/xfs_reflink.c
> +++ b/fs/xfs/xfs_reflink.c
> @@ -755,16 +755,19 @@ int
>  xfs_reflink_recover_cow(
>  	struct xfs_mount	*mp)
>  {
> +	struct xfs_perag	*pag;
>  	xfs_agnumber_t		agno;
>  	int			error = 0;
>  
>  	if (!xfs_sb_version_hasreflink(&mp->m_sb))
>  		return 0;
>  
> -	for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) {
> -		error = xfs_refcount_recover_cow_leftovers(mp, agno);
> -		if (error)
> +	for_each_perag(mp, agno, pag) {
> +		error = xfs_refcount_recover_cow_leftovers(mp, pag->pag_agno);
> +		if (error) {
> +			xfs_perag_put(pag);
>  			break;
> +		}
>  	}
>  
>  	return error;
> -- 
> 2.31.1
> 


^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 06/22] xfs: convert xfs_iwalk to use perag references
  2021-05-06  7:20 ` [PATCH 06/22] xfs: convert xfs_iwalk to use perag references Dave Chinner
@ 2021-05-10 13:41   ` Brian Foster
  2021-05-12 22:08   ` Darrick J. Wong
  1 sibling, 0 replies; 87+ messages in thread
From: Brian Foster @ 2021-05-10 13:41 UTC (permalink / raw)
  To: Dave Chinner; +Cc: linux-xfs

On Thu, May 06, 2021 at 05:20:38PM +1000, Dave Chinner wrote:
> From: Dave Chinner <dchinner@redhat.com>
> 
> Rather than manually walking the ags and passing agnunbers around,
> pass the perag for the AG we are currently working on around in the
> iwalk structure.
> 
> Signed-off-by: Dave Chinner <dchinner@redhat.com>
> ---

LGTM:

Reviewed-by: Brian Foster <bfoster@redhat.com>

>  fs/xfs/libxfs/xfs_ag.h |  8 +++-
>  fs/xfs/xfs_iwalk.c     | 86 ++++++++++++++++++++++++++----------------
>  2 files changed, 60 insertions(+), 34 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_ag.h b/fs/xfs/libxfs/xfs_ag.h
> index 33783120263c..3fa88222dacd 100644
> --- a/fs/xfs/libxfs/xfs_ag.h
> +++ b/fs/xfs/libxfs/xfs_ag.h
> @@ -117,13 +117,17 @@ void	xfs_perag_put(struct xfs_perag *pag);
>  /*
>   * Perag iteration APIs
>   */
> -#define for_each_perag(mp, next_agno, pag) \
> -	for ((next_agno) = 0, (pag) = xfs_perag_get((mp), 0); \
> +#define for_each_perag_from(mp, next_agno, pag) \
> +	for ((pag) = xfs_perag_get((mp), (next_agno)); \
>  		(pag) != NULL; \
>  		(next_agno) = (pag)->pag_agno + 1, \
>  		xfs_perag_put(pag), \
>  		(pag) = xfs_perag_get((mp), (next_agno)))
>  
> +#define for_each_perag(mp, next_agno, pag) \
> +	(next_agno) = 0; \
> +	for_each_perag_from((mp), (next_agno), (pag))
> +
>  #define for_each_perag_tag(mp, next_agno, pag, tag) \
>  	for ((next_agno) = 0, (pag) = xfs_perag_get_tag((mp), 0, (tag)); \
>  		(pag) != NULL; \
> diff --git a/fs/xfs/xfs_iwalk.c b/fs/xfs/xfs_iwalk.c
> index c4a340f1f1e1..c7e8f48a3ec4 100644
> --- a/fs/xfs/xfs_iwalk.c
> +++ b/fs/xfs/xfs_iwalk.c
> @@ -21,6 +21,7 @@
>  #include "xfs_health.h"
>  #include "xfs_trans.h"
>  #include "xfs_pwork.h"
> +#include "xfs_ag.h"
>  
>  /*
>   * Walking Inodes in the Filesystem
> @@ -51,6 +52,7 @@ struct xfs_iwalk_ag {
>  
>  	struct xfs_mount		*mp;
>  	struct xfs_trans		*tp;
> +	struct xfs_perag		*pag;
>  
>  	/* Where do we start the traversal? */
>  	xfs_ino_t			startino;
> @@ -90,7 +92,7 @@ struct xfs_iwalk_ag {
>  STATIC void
>  xfs_iwalk_ichunk_ra(
>  	struct xfs_mount		*mp,
> -	xfs_agnumber_t			agno,
> +	struct xfs_perag		*pag,
>  	struct xfs_inobt_rec_incore	*irec)
>  {
>  	struct xfs_ino_geometry		*igeo = M_IGEO(mp);
> @@ -106,7 +108,7 @@ xfs_iwalk_ichunk_ra(
>  
>  		imask = xfs_inobt_maskn(i, igeo->inodes_per_cluster);
>  		if (imask & ~irec->ir_free) {
> -			xfs_btree_reada_bufs(mp, agno, agbno,
> +			xfs_btree_reada_bufs(mp, pag->pag_agno, agbno,
>  					igeo->blocks_per_cluster,
>  					&xfs_inode_buf_ops);
>  		}
> @@ -174,26 +176,25 @@ xfs_iwalk_free(
>  /* For each inuse inode in each cached inobt record, call our function. */
>  STATIC int
>  xfs_iwalk_ag_recs(
> -	struct xfs_iwalk_ag		*iwag)
> +	struct xfs_iwalk_ag	*iwag)
>  {
> -	struct xfs_mount		*mp = iwag->mp;
> -	struct xfs_trans		*tp = iwag->tp;
> -	xfs_ino_t			ino;
> -	unsigned int			i, j;
> -	xfs_agnumber_t			agno;
> -	int				error;
> +	struct xfs_mount	*mp = iwag->mp;
> +	struct xfs_trans	*tp = iwag->tp;
> +	struct xfs_perag	*pag = iwag->pag;
> +	xfs_ino_t		ino;
> +	unsigned int		i, j;
> +	int			error;
>  
> -	agno = XFS_INO_TO_AGNO(mp, iwag->startino);
>  	for (i = 0; i < iwag->nr_recs; i++) {
>  		struct xfs_inobt_rec_incore	*irec = &iwag->recs[i];
>  
> -		trace_xfs_iwalk_ag_rec(mp, agno, irec);
> +		trace_xfs_iwalk_ag_rec(mp, pag->pag_agno, irec);
>  
>  		if (xfs_pwork_want_abort(&iwag->pwork))
>  			return 0;
>  
>  		if (iwag->inobt_walk_fn) {
> -			error = iwag->inobt_walk_fn(mp, tp, agno, irec,
> +			error = iwag->inobt_walk_fn(mp, tp, pag->pag_agno, irec,
>  					iwag->data);
>  			if (error)
>  				return error;
> @@ -211,7 +212,8 @@ xfs_iwalk_ag_recs(
>  				continue;
>  
>  			/* Otherwise call our function. */
> -			ino = XFS_AGINO_TO_INO(mp, agno, irec->ir_startino + j);
> +			ino = XFS_AGINO_TO_INO(mp, pag->pag_agno,
> +						irec->ir_startino + j);
>  			error = iwag->iwalk_fn(mp, tp, ino, iwag->data);
>  			if (error)
>  				return error;
> @@ -257,7 +259,6 @@ xfs_iwalk_del_inobt(
>  STATIC int
>  xfs_iwalk_ag_start(
>  	struct xfs_iwalk_ag	*iwag,
> -	xfs_agnumber_t		agno,
>  	xfs_agino_t		agino,
>  	struct xfs_btree_cur	**curpp,
>  	struct xfs_buf		**agi_bpp,
> @@ -265,12 +266,14 @@ xfs_iwalk_ag_start(
>  {
>  	struct xfs_mount	*mp = iwag->mp;
>  	struct xfs_trans	*tp = iwag->tp;
> +	struct xfs_perag	*pag = iwag->pag;
>  	struct xfs_inobt_rec_incore *irec;
>  	int			error;
>  
>  	/* Set up a fresh cursor and empty the inobt cache. */
>  	iwag->nr_recs = 0;
> -	error = xfs_inobt_cur(mp, tp, agno, XFS_BTNUM_INO, curpp, agi_bpp);
> +	error = xfs_inobt_cur(mp, tp, pag->pag_agno, XFS_BTNUM_INO,
> +				curpp, agi_bpp);
>  	if (error)
>  		return error;
>  
> @@ -304,7 +307,7 @@ xfs_iwalk_ag_start(
>  	if (XFS_IS_CORRUPT(mp, *has_more != 1))
>  		return -EFSCORRUPTED;
>  
> -	iwag->lastino = XFS_AGINO_TO_INO(mp, agno,
> +	iwag->lastino = XFS_AGINO_TO_INO(mp, pag->pag_agno,
>  				irec->ir_startino + XFS_INODES_PER_CHUNK - 1);
>  
>  	/*
> @@ -345,7 +348,6 @@ xfs_iwalk_ag_start(
>  STATIC int
>  xfs_iwalk_run_callbacks(
>  	struct xfs_iwalk_ag		*iwag,
> -	xfs_agnumber_t			agno,
>  	struct xfs_btree_cur		**curpp,
>  	struct xfs_buf			**agi_bpp,
>  	int				*has_more)
> @@ -376,7 +378,8 @@ xfs_iwalk_run_callbacks(
>  		return 0;
>  
>  	/* ...and recreate the cursor just past where we left off. */
> -	error = xfs_inobt_cur(mp, tp, agno, XFS_BTNUM_INO, curpp, agi_bpp);
> +	error = xfs_inobt_cur(mp, tp, iwag->pag->pag_agno, XFS_BTNUM_INO,
> +				curpp, agi_bpp);
>  	if (error)
>  		return error;
>  
> @@ -390,17 +393,17 @@ xfs_iwalk_ag(
>  {
>  	struct xfs_mount		*mp = iwag->mp;
>  	struct xfs_trans		*tp = iwag->tp;
> +	struct xfs_perag		*pag = iwag->pag;
>  	struct xfs_buf			*agi_bp = NULL;
>  	struct xfs_btree_cur		*cur = NULL;
> -	xfs_agnumber_t			agno;
>  	xfs_agino_t			agino;
>  	int				has_more;
>  	int				error = 0;
>  
>  	/* Set up our cursor at the right place in the inode btree. */
> -	agno = XFS_INO_TO_AGNO(mp, iwag->startino);
> +	ASSERT(pag->pag_agno == XFS_INO_TO_AGNO(mp, iwag->startino));
>  	agino = XFS_INO_TO_AGINO(mp, iwag->startino);
> -	error = xfs_iwalk_ag_start(iwag, agno, agino, &cur, &agi_bp, &has_more);
> +	error = xfs_iwalk_ag_start(iwag, agino, &cur, &agi_bp, &has_more);
>  
>  	while (!error && has_more) {
>  		struct xfs_inobt_rec_incore	*irec;
> @@ -417,7 +420,7 @@ xfs_iwalk_ag(
>  			break;
>  
>  		/* Make sure that we always move forward. */
> -		rec_fsino = XFS_AGINO_TO_INO(mp, agno, irec->ir_startino);
> +		rec_fsino = XFS_AGINO_TO_INO(mp, pag->pag_agno, irec->ir_startino);
>  		if (iwag->lastino != NULLFSINO &&
>  		    XFS_IS_CORRUPT(mp, iwag->lastino >= rec_fsino)) {
>  			error = -EFSCORRUPTED;
> @@ -438,7 +441,7 @@ xfs_iwalk_ag(
>  		 * walking the inodes.
>  		 */
>  		if (iwag->iwalk_fn)
> -			xfs_iwalk_ichunk_ra(mp, agno, irec);
> +			xfs_iwalk_ichunk_ra(mp, pag, irec);
>  
>  		/*
>  		 * If there's space in the buffer for more records, increment
> @@ -458,15 +461,14 @@ xfs_iwalk_ag(
>  		 * we would be if we had been able to increment like above.
>  		 */
>  		ASSERT(has_more);
> -		error = xfs_iwalk_run_callbacks(iwag, agno, &cur, &agi_bp,
> -				&has_more);
> +		error = xfs_iwalk_run_callbacks(iwag, &cur, &agi_bp, &has_more);
>  	}
>  
>  	if (iwag->nr_recs == 0 || error)
>  		goto out;
>  
>  	/* Walk the unprocessed records in the cache. */
> -	error = xfs_iwalk_run_callbacks(iwag, agno, &cur, &agi_bp, &has_more);
> +	error = xfs_iwalk_run_callbacks(iwag, &cur, &agi_bp, &has_more);
>  
>  out:
>  	xfs_iwalk_del_inobt(tp, &cur, &agi_bp, error);
> @@ -555,6 +557,7 @@ xfs_iwalk(
>  		.pwork		= XFS_PWORK_SINGLE_THREADED,
>  		.lastino	= NULLFSINO,
>  	};
> +	struct xfs_perag	*pag;
>  	xfs_agnumber_t		agno = XFS_INO_TO_AGNO(mp, startino);
>  	int			error;
>  
> @@ -565,15 +568,19 @@ xfs_iwalk(
>  	if (error)
>  		return error;
>  
> -	for (; agno < mp->m_sb.sb_agcount; agno++) {
> +	for_each_perag_from(mp, agno, pag) {
> +		iwag.pag = pag;
>  		error = xfs_iwalk_ag(&iwag);
>  		if (error)
>  			break;
>  		iwag.startino = XFS_AGINO_TO_INO(mp, agno + 1, 0);
>  		if (flags & XFS_INOBT_WALK_SAME_AG)
>  			break;
> +		iwag.pag = NULL;
>  	}
>  
> +	if (iwag.pag)
> +		xfs_perag_put(pag);
>  	xfs_iwalk_free(&iwag);
>  	return error;
>  }
> @@ -598,6 +605,7 @@ xfs_iwalk_ag_work(
>  	error = xfs_iwalk_ag(iwag);
>  	xfs_iwalk_free(iwag);
>  out:
> +	xfs_perag_put(iwag->pag);
>  	kmem_free(iwag);
>  	return error;
>  }
> @@ -617,6 +625,7 @@ xfs_iwalk_threaded(
>  	void			*data)
>  {
>  	struct xfs_pwork_ctl	pctl;
> +	struct xfs_perag	*pag;
>  	xfs_agnumber_t		agno = XFS_INO_TO_AGNO(mp, startino);
>  	int			error;
>  
> @@ -627,7 +636,7 @@ xfs_iwalk_threaded(
>  	if (error)
>  		return error;
>  
> -	for (; agno < mp->m_sb.sb_agcount; agno++) {
> +	for_each_perag_from(mp, agno, pag) {
>  		struct xfs_iwalk_ag	*iwag;
>  
>  		if (xfs_pwork_ctl_want_abort(&pctl))
> @@ -635,17 +644,25 @@ xfs_iwalk_threaded(
>  
>  		iwag = kmem_zalloc(sizeof(struct xfs_iwalk_ag), 0);
>  		iwag->mp = mp;
> +
> +		/*
> +		 * perag is being handed off to async work, so take another
> +		 * reference for the async work to release.
> +		 */
> +		atomic_inc(&pag->pag_ref);
> +		iwag->pag = pag;
>  		iwag->iwalk_fn = iwalk_fn;
>  		iwag->data = data;
>  		iwag->startino = startino;
>  		iwag->sz_recs = xfs_iwalk_prefetch(inode_records);
>  		iwag->lastino = NULLFSINO;
>  		xfs_pwork_queue(&pctl, &iwag->pwork);
> -		startino = XFS_AGINO_TO_INO(mp, agno + 1, 0);
> +		startino = XFS_AGINO_TO_INO(mp, pag->pag_agno + 1, 0);
>  		if (flags & XFS_INOBT_WALK_SAME_AG)
>  			break;
>  	}
> -
> +	if (pag)
> +		xfs_perag_put(pag);
>  	if (polled)
>  		xfs_pwork_poll(&pctl);
>  	return xfs_pwork_destroy(&pctl);
> @@ -715,6 +732,7 @@ xfs_inobt_walk(
>  		.pwork		= XFS_PWORK_SINGLE_THREADED,
>  		.lastino	= NULLFSINO,
>  	};
> +	struct xfs_perag	*pag;
>  	xfs_agnumber_t		agno = XFS_INO_TO_AGNO(mp, startino);
>  	int			error;
>  
> @@ -725,15 +743,19 @@ xfs_inobt_walk(
>  	if (error)
>  		return error;
>  
> -	for (; agno < mp->m_sb.sb_agcount; agno++) {
> +	for_each_perag_from(mp, agno, pag) {
> +		iwag.pag = pag;
>  		error = xfs_iwalk_ag(&iwag);
>  		if (error)
>  			break;
> -		iwag.startino = XFS_AGINO_TO_INO(mp, agno + 1, 0);
> +		iwag.startino = XFS_AGINO_TO_INO(mp, pag->pag_agno + 1, 0);
>  		if (flags & XFS_INOBT_WALK_SAME_AG)
>  			break;
> +		iwag.pag = NULL;
>  	}
>  
> +	if (iwag.pag)
> +		xfs_perag_put(pag);
>  	xfs_iwalk_free(&iwag);
>  	return error;
>  }
> -- 
> 2.31.1
> 


^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 07/22] xfs: convert secondary superblock walk to use perags
  2021-05-06  7:20 ` [PATCH 07/22] xfs: convert secondary superblock walk to use perags Dave Chinner
@ 2021-05-10 13:41   ` Brian Foster
  2021-05-12 22:09   ` Darrick J. Wong
  1 sibling, 0 replies; 87+ messages in thread
From: Brian Foster @ 2021-05-10 13:41 UTC (permalink / raw)
  To: Dave Chinner; +Cc: linux-xfs

On Thu, May 06, 2021 at 05:20:39PM +1000, Dave Chinner wrote:
> From: Dave Chinner <dchinner@redhat.com>
> 
> Clean up the last external manual AG walk.
> 
> Signed-off-by: Dave Chinner <dchinner@redhat.com>
> ---

Reviewed-by: Brian Foster <bfoster@redhat.com>

>  fs/xfs/libxfs/xfs_sb.c | 12 +++++++-----
>  1 file changed, 7 insertions(+), 5 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_sb.c b/fs/xfs/libxfs/xfs_sb.c
> index cbcfce8cebf1..7d4c238540d4 100644
> --- a/fs/xfs/libxfs/xfs_sb.c
> +++ b/fs/xfs/libxfs/xfs_sb.c
> @@ -25,6 +25,7 @@
>  #include "xfs_refcount_btree.h"
>  #include "xfs_da_format.h"
>  #include "xfs_health.h"
> +#include "xfs_ag.h"
>  
>  /*
>   * Physical superblock buffer manipulations. Shared with libxfs in userspace.
> @@ -856,17 +857,18 @@ int
>  xfs_update_secondary_sbs(
>  	struct xfs_mount	*mp)
>  {
> -	xfs_agnumber_t		agno;
> +	struct xfs_perag	*pag;
> +	xfs_agnumber_t		agno = 1;
>  	int			saved_error = 0;
>  	int			error = 0;
>  	LIST_HEAD		(buffer_list);
>  
>  	/* update secondary superblocks. */
> -	for (agno = 1; agno < mp->m_sb.sb_agcount; agno++) {
> +	for_each_perag_from(mp, agno, pag) {
>  		struct xfs_buf		*bp;
>  
>  		error = xfs_buf_get(mp->m_ddev_targp,
> -				 XFS_AG_DADDR(mp, agno, XFS_SB_DADDR),
> +				 XFS_AG_DADDR(mp, pag->pag_agno, XFS_SB_DADDR),
>  				 XFS_FSS_TO_BB(mp, 1), &bp);
>  		/*
>  		 * If we get an error reading or writing alternate superblocks,
> @@ -878,7 +880,7 @@ xfs_update_secondary_sbs(
>  		if (error) {
>  			xfs_warn(mp,
>  		"error allocating secondary superblock for ag %d",
> -				agno);
> +				pag->pag_agno);
>  			if (!saved_error)
>  				saved_error = error;
>  			continue;
> @@ -899,7 +901,7 @@ xfs_update_secondary_sbs(
>  		if (error) {
>  			xfs_warn(mp,
>  		"write error %d updating a secondary superblock near ag %d",
> -				error, agno);
> +				error, pag->pag_agno);
>  			if (!saved_error)
>  				saved_error = error;
>  			continue;
> -- 
> 2.31.1
> 


^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 03/22] xfs: move perag structure and setup to libxfs/xfs_ag.[ch]
  2021-05-06  7:20 ` [PATCH 03/22] xfs: move perag structure and setup to libxfs/xfs_ag.[ch] Dave Chinner
@ 2021-05-10 22:26   ` Darrick J. Wong
  2021-05-10 23:38     ` Dave Chinner
  0 siblings, 1 reply; 87+ messages in thread
From: Darrick J. Wong @ 2021-05-10 22:26 UTC (permalink / raw)
  To: Dave Chinner; +Cc: linux-xfs

On Thu, May 06, 2021 at 05:20:35PM +1000, Dave Chinner wrote:
> From: Dave Chinner <dchinner@redhat.com>
> 
> Move the xfs_perag infrastructure to the libxfs files that contain
> all the per AG infrastructure. This helps set up for passing perags
> around all the code instead of bare agnos with minimal extra
> includes for existing files.
> 
> Signed-off-by: Dave Chinner <dchinner@redhat.com>
> ---
>  fs/xfs/libxfs/xfs_ag.c      | 133 ++++++++++++++++++++++++++++++++++++
>  fs/xfs/libxfs/xfs_ag.h      |  98 +++++++++++++++++++++++++-
>  fs/xfs/libxfs/xfs_ag_resv.h |  15 ++++
>  fs/xfs/libxfs/xfs_btree.c   |   1 +
>  fs/xfs/xfs_mount.c          | 131 -----------------------------------
>  fs/xfs/xfs_mount.h          | 111 +-----------------------------
>  fs/xfs/xfs_trace.c          |   2 +
>  7 files changed, 250 insertions(+), 241 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_ag.c b/fs/xfs/libxfs/xfs_ag.c
> index 2ca31dc46fe8..14d8b866dc6d 100644
> --- a/fs/xfs/libxfs/xfs_ag.c
> +++ b/fs/xfs/libxfs/xfs_ag.c
> @@ -28,6 +28,9 @@
>  #include "xfs_log_format.h"
>  #include "xfs_trans.h"
>  #include "xfs_trace.h"
> +#include "xfs_inode.h"
> +#include "xfs_icache.h"
> +
>  
>  /*
>   * Passive reference counting access wrappers to the perag structures.  If the
> @@ -163,6 +166,136 @@ xfs_initialize_perag_data(
>  	return error;
>  }
>  
> +STATIC void
> +__xfs_free_perag(
> +	struct rcu_head	*head)
> +{
> +	struct xfs_perag *pag = container_of(head, struct xfs_perag, rcu_head);
> +
> +	ASSERT(!delayed_work_pending(&pag->pag_blockgc_work));
> +	ASSERT(atomic_read(&pag->pag_ref) == 0);
> +	kmem_free(pag);
> +}
> +
> +/*
> + * Free up the per-ag resources associated with the mount structure.
> + */
> +void
> +xfs_free_perag(
> +	struct xfs_mount	*mp)
> +{
> +	struct xfs_perag	*pag;
> +	xfs_agnumber_t		agno;
> +
> +	for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) {
> +		spin_lock(&mp->m_perag_lock);
> +		pag = radix_tree_delete(&mp->m_perag_tree, agno);
> +		spin_unlock(&mp->m_perag_lock);
> +		ASSERT(pag);
> +		ASSERT(atomic_read(&pag->pag_ref) == 0);
> +
> +		cancel_delayed_work_sync(&pag->pag_blockgc_work);
> +		xfs_iunlink_destroy(pag);
> +		xfs_buf_hash_destroy(pag);
> +
> +		call_rcu(&pag->rcu_head, __xfs_free_perag);
> +	}
> +}
> +
> +int
> +xfs_initialize_perag(
> +	struct xfs_mount	*mp,
> +	xfs_agnumber_t		agcount,
> +	xfs_agnumber_t		*maxagi)
> +{
> +	struct xfs_perag	*pag;
> +	xfs_agnumber_t		index;
> +	xfs_agnumber_t		first_initialised = NULLAGNUMBER;
> +	int			error;
> +
> +	/*
> +	 * Walk the current per-ag tree so we don't try to initialise AGs
> +	 * that already exist (growfs case). Allocate and insert all the
> +	 * AGs we don't find ready for initialisation.
> +	 */
> +	for (index = 0; index < agcount; index++) {
> +		pag = xfs_perag_get(mp, index);
> +		if (pag) {
> +			xfs_perag_put(pag);
> +			continue;
> +		}
> +
> +		pag = kmem_zalloc(sizeof(*pag), KM_MAYFAIL);
> +		if (!pag) {
> +			error = -ENOMEM;
> +			goto out_unwind_new_pags;
> +		}
> +		pag->pag_agno = index;
> +		pag->pag_mount = mp;
> +
> +		error = radix_tree_preload(GFP_NOFS);
> +		if (error)
> +			goto out_hash_destroy;
> +
> +		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_hash_destroy;
> +		}
> +		spin_unlock(&mp->m_perag_lock);
> +		radix_tree_preload_end();
> +
> +		spin_lock_init(&pag->pag_ici_lock);
> +		spin_lock_init(&pag->pagb_lock);
> +		spin_lock_init(&pag->pag_state_lock);
> +		INIT_DELAYED_WORK(&pag->pag_blockgc_work, xfs_blockgc_worker);
> +		INIT_RADIX_TREE(&pag->pag_ici_root, GFP_ATOMIC);
> +		init_waitqueue_head(&pag->pagb_wait);
> +		pag->pagb_count = 0;
> +		pag->pagb_tree = RB_ROOT;
> +
> +		error = xfs_buf_hash_init(pag);
> +		if (error)
> +			goto out_free_pag;
> +
> +		error = xfs_iunlink_init(pag);
> +		if (error)
> +			goto out_hash_destroy;
> +
> +		/* first new pag is fully initialized */
> +		if (first_initialised == NULLAGNUMBER)
> +			first_initialised = index;
> +	}
> +
> +	index = xfs_set_inode_alloc(mp, agcount);
> +
> +	if (maxagi)
> +		*maxagi = index;
> +
> +	mp->m_ag_prealloc_blocks = xfs_prealloc_blocks(mp);
> +	return 0;
> +
> +out_hash_destroy:
> +	xfs_buf_hash_destroy(pag);
> +out_free_pag:
> +	pag = radix_tree_delete(&mp->m_perag_tree, index);
> +	kmem_free(pag);
> +out_unwind_new_pags:
> +	/* unwind any prior newly initialized pags */
> +	for (index = first_initialised; index < agcount; index++) {
> +		pag = radix_tree_delete(&mp->m_perag_tree, index);
> +		if (!pag)
> +			break;
> +		xfs_buf_hash_destroy(pag);
> +		xfs_iunlink_destroy(pag);
> +		kmem_free(pag);
> +	}
> +	return error;
> +}
> +
>  static int
>  xfs_get_aghdr_buf(
>  	struct xfs_mount	*mp,
> diff --git a/fs/xfs/libxfs/xfs_ag.h b/fs/xfs/libxfs/xfs_ag.h
> index cb1bd1c03cd7..ec37f9d9f310 100644
> --- a/fs/xfs/libxfs/xfs_ag.h
> +++ b/fs/xfs/libxfs/xfs_ag.h
> @@ -12,9 +12,103 @@ struct xfs_trans;
>  struct xfs_perag;
>  
>  /*
> - * perag get/put wrappers for ref counting
> + * Per-ag infrastructure
>   */
> -int	xfs_initialize_perag_data(struct xfs_mount *, xfs_agnumber_t);
> +
> +/* per-AG block reservation data structures*/
> +struct xfs_ag_resv {
> +	/* number of blocks originally reserved here */
> +	xfs_extlen_t			ar_orig_reserved;
> +	/* number of blocks reserved here */
> +	xfs_extlen_t			ar_reserved;
> +	/* number of blocks originally asked for */
> +	xfs_extlen_t			ar_asked;
> +};
> +
> +/*
> + * Per-ag incore structure, copies of information in agf and agi, to improve the
> + * performance of allocation group selection.
> + */
> +typedef struct xfs_perag {
> +	struct xfs_mount *pag_mount;	/* owner filesystem */
> +	xfs_agnumber_t	pag_agno;	/* AG this structure belongs to */
> +	atomic_t	pag_ref;	/* perag reference count */
> +	char		pagf_init;	/* this agf's entry is initialized */
> +	char		pagi_init;	/* this agi's entry is initialized */
> +	char		pagf_metadata;	/* the agf is preferred to be metadata */
> +	char		pagi_inodeok;	/* The agi is ok for inodes */
> +	uint8_t		pagf_levels[XFS_BTNUM_AGF];
> +					/* # of levels in bno & cnt btree */
> +	bool		pagf_agflreset; /* agfl requires reset before use */
> +	uint32_t	pagf_flcount;	/* count of blocks in freelist */
> +	xfs_extlen_t	pagf_freeblks;	/* total free blocks */
> +	xfs_extlen_t	pagf_longest;	/* longest free space */
> +	uint32_t	pagf_btreeblks;	/* # of blocks held in AGF btrees */
> +	xfs_agino_t	pagi_freecount;	/* number of free inodes */
> +	xfs_agino_t	pagi_count;	/* number of allocated inodes */
> +
> +	/*
> +	 * Inode allocation search lookup optimisation.
> +	 * If the pagino matches, the search for new inodes
> +	 * doesn't need to search the near ones again straight away
> +	 */
> +	xfs_agino_t	pagl_pagino;
> +	xfs_agino_t	pagl_leftrec;
> +	xfs_agino_t	pagl_rightrec;
> +
> +	int		pagb_count;	/* pagb slots in use */
> +	uint8_t		pagf_refcount_level; /* recount btree height */
> +
> +	/* Blocks reserved for all kinds of metadata. */
> +	struct xfs_ag_resv	pag_meta_resv;
> +	/* Blocks reserved for the reverse mapping btree. */
> +	struct xfs_ag_resv	pag_rmapbt_resv;
> +
> +	/* -- kernel only structures below this line -- */
> +
> +	/*
> +	 * Bitsets of per-ag metadata that have been checked and/or are sick.
> +	 * Callers should hold pag_state_lock before accessing this field.
> +	 */
> +	uint16_t	pag_checked;
> +	uint16_t	pag_sick;
> +	spinlock_t	pag_state_lock;
> +
> +	spinlock_t	pagb_lock;	/* lock for pagb_tree */
> +	struct rb_root	pagb_tree;	/* ordered tree of busy extents */
> +	unsigned int	pagb_gen;	/* generation count for pagb_tree */
> +	wait_queue_head_t pagb_wait;	/* woken when pagb_gen changes */
> +
> +	atomic_t        pagf_fstrms;    /* # of filestreams active in this AG */
> +
> +	spinlock_t	pag_ici_lock;	/* incore inode cache lock */
> +	struct radix_tree_root pag_ici_root;	/* incore inode cache root */
> +	int		pag_ici_reclaimable;	/* reclaimable inodes */
> +	unsigned long	pag_ici_reclaim_cursor;	/* reclaim restart point */
> +
> +	/* buffer cache index */
> +	spinlock_t	pag_buf_lock;	/* lock for pag_buf_hash */
> +	struct rhashtable pag_buf_hash;
> +
> +	/* for rcu-safe freeing */
> +	struct rcu_head	rcu_head;
> +
> +	/* background prealloc block trimming */
> +	struct delayed_work	pag_blockgc_work;
> +
> +	/*
> +	 * Unlinked inode information.  This incore information reflects
> +	 * data stored in the AGI, so callers must hold the AGI buffer lock
> +	 * or have some other means to control concurrency.
> +	 */
> +	struct rhashtable	pagi_unlinked_hash;
> +} xfs_perag_t;

I wonder, have you ported this to xfsprogs yet?  How much of a mess is
this going to create for things like libxfs-diff?

(Also would be nice to kill off xfs_perag_t, but maybe you did that at
the end of the series already <shrug>)

--D

> +
> +int xfs_initialize_perag(struct xfs_mount *mp, xfs_agnumber_t agcount,
> +			xfs_agnumber_t *maxagi);
> +int xfs_initialize_perag_data(struct xfs_mount *, xfs_agnumber_t);
> +void xfs_free_perag(struct xfs_mount *mp);
> +
>  struct xfs_perag *xfs_perag_get(struct xfs_mount *, xfs_agnumber_t);
>  struct xfs_perag *xfs_perag_get_tag(struct xfs_mount *, xfs_agnumber_t,
>  				   int tag);
> diff --git a/fs/xfs/libxfs/xfs_ag_resv.h b/fs/xfs/libxfs/xfs_ag_resv.h
> index 8a8eb4bc48bb..b74b210008ea 100644
> --- a/fs/xfs/libxfs/xfs_ag_resv.h
> +++ b/fs/xfs/libxfs/xfs_ag_resv.h
> @@ -18,6 +18,21 @@ void xfs_ag_resv_alloc_extent(struct xfs_perag *pag, enum xfs_ag_resv_type type,
>  void xfs_ag_resv_free_extent(struct xfs_perag *pag, enum xfs_ag_resv_type type,
>  		struct xfs_trans *tp, xfs_extlen_t len);
>  
> +static inline struct xfs_ag_resv *
> +xfs_perag_resv(
> +	struct xfs_perag	*pag,
> +	enum xfs_ag_resv_type	type)
> +{
> +	switch (type) {
> +	case XFS_AG_RESV_METADATA:
> +		return &pag->pag_meta_resv;
> +	case XFS_AG_RESV_RMAPBT:
> +		return &pag->pag_rmapbt_resv;
> +	default:
> +		return NULL;
> +	}
> +}
> +
>  /*
>   * RMAPBT reservation accounting wrappers. Since rmapbt blocks are sourced from
>   * the AGFL, they are allocated one at a time and the reservation updates don't
> diff --git a/fs/xfs/libxfs/xfs_btree.c b/fs/xfs/libxfs/xfs_btree.c
> index 5b6fcb9b44e2..0f12b885600d 100644
> --- a/fs/xfs/libxfs/xfs_btree.c
> +++ b/fs/xfs/libxfs/xfs_btree.c
> @@ -21,6 +21,7 @@
>  #include "xfs_alloc.h"
>  #include "xfs_log.h"
>  #include "xfs_btree_staging.h"
> +#include "xfs_ag.h"
>  
>  /*
>   * Cursor allocation zone.
> diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c
> index 2e6d42014346..c3a96fb3ad80 100644
> --- a/fs/xfs/xfs_mount.c
> +++ b/fs/xfs/xfs_mount.c
> @@ -120,43 +120,6 @@ xfs_uuid_unmount(
>  	mutex_unlock(&xfs_uuid_table_mutex);
>  }
>  
> -
> -STATIC void
> -__xfs_free_perag(
> -	struct rcu_head	*head)
> -{
> -	struct xfs_perag *pag = container_of(head, struct xfs_perag, rcu_head);
> -
> -	ASSERT(!delayed_work_pending(&pag->pag_blockgc_work));
> -	ASSERT(atomic_read(&pag->pag_ref) == 0);
> -	kmem_free(pag);
> -}
> -
> -/*
> - * Free up the per-ag resources associated with the mount structure.
> - */
> -STATIC void
> -xfs_free_perag(
> -	xfs_mount_t	*mp)
> -{
> -	xfs_agnumber_t	agno;
> -	struct xfs_perag *pag;
> -
> -	for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) {
> -		spin_lock(&mp->m_perag_lock);
> -		pag = radix_tree_delete(&mp->m_perag_tree, agno);
> -		spin_unlock(&mp->m_perag_lock);
> -		ASSERT(pag);
> -		ASSERT(atomic_read(&pag->pag_ref) == 0);
> -
> -		cancel_delayed_work_sync(&pag->pag_blockgc_work);
> -		xfs_iunlink_destroy(pag);
> -		xfs_buf_hash_destroy(pag);
> -
> -		call_rcu(&pag->rcu_head, __xfs_free_perag);
> -	}
> -}
> -
>  /*
>   * Check size of device based on the (data/realtime) block count.
>   * Note: this check is used by the growfs code as well as mount.
> @@ -175,100 +138,6 @@ xfs_sb_validate_fsb_count(
>  	return 0;
>  }
>  
> -int
> -xfs_initialize_perag(
> -	struct xfs_mount	*mp,
> -	xfs_agnumber_t		agcount,
> -	xfs_agnumber_t		*maxagi)
> -{
> -	struct xfs_perag	*pag;
> -	xfs_agnumber_t		index;
> -	xfs_agnumber_t		first_initialised = NULLAGNUMBER;
> -	int			error;
> -
> -	/*
> -	 * Walk the current per-ag tree so we don't try to initialise AGs
> -	 * that already exist (growfs case). Allocate and insert all the
> -	 * AGs we don't find ready for initialisation.
> -	 */
> -	for (index = 0; index < agcount; index++) {
> -		pag = xfs_perag_get(mp, index);
> -		if (pag) {
> -			xfs_perag_put(pag);
> -			continue;
> -		}
> -
> -		pag = kmem_zalloc(sizeof(*pag), KM_MAYFAIL);
> -		if (!pag) {
> -			error = -ENOMEM;
> -			goto out_unwind_new_pags;
> -		}
> -		pag->pag_agno = index;
> -		pag->pag_mount = mp;
> -
> -		error = radix_tree_preload(GFP_NOFS);
> -		if (error)
> -			goto out_hash_destroy;
> -
> -		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_hash_destroy;
> -		}
> -		spin_unlock(&mp->m_perag_lock);
> -		radix_tree_preload_end();
> -
> -		spin_lock_init(&pag->pag_ici_lock);
> -		spin_lock_init(&pag->pagb_lock);
> -		spin_lock_init(&pag->pag_state_lock);
> -		INIT_DELAYED_WORK(&pag->pag_blockgc_work, xfs_blockgc_worker);
> -		INIT_RADIX_TREE(&pag->pag_ici_root, GFP_ATOMIC);
> -		init_waitqueue_head(&pag->pagb_wait);
> -		pag->pagb_count = 0;
> -		pag->pagb_tree = RB_ROOT;
> -
> -		error = xfs_buf_hash_init(pag);
> -		if (error)
> -			goto out_free_pag;
> -
> -		error = xfs_iunlink_init(pag);
> -		if (error)
> -			goto out_hash_destroy;
> -
> -		/* first new pag is fully initialized */
> -		if (first_initialised == NULLAGNUMBER)
> -			first_initialised = index;
> -	}
> -
> -	index = xfs_set_inode_alloc(mp, agcount);
> -
> -	if (maxagi)
> -		*maxagi = index;
> -
> -	mp->m_ag_prealloc_blocks = xfs_prealloc_blocks(mp);
> -	return 0;
> -
> -out_hash_destroy:
> -	xfs_buf_hash_destroy(pag);
> -out_free_pag:
> -	pag = radix_tree_delete(&mp->m_perag_tree, index);
> -	kmem_free(pag);
> -out_unwind_new_pags:
> -	/* unwind any prior newly initialized pags */
> -	for (index = first_initialised; index < agcount; index++) {
> -		pag = radix_tree_delete(&mp->m_perag_tree, index);
> -		if (!pag)
> -			break;
> -		xfs_buf_hash_destroy(pag);
> -		xfs_iunlink_destroy(pag);
> -		kmem_free(pag);
> -	}
> -	return error;
> -}
> -
>  /*
>   * xfs_readsb
>   *
> diff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h
> index 6e534be5eea8..c78b63fe779a 100644
> --- a/fs/xfs/xfs_mount.h
> +++ b/fs/xfs/xfs_mount.h
> @@ -12,6 +12,7 @@ struct xfs_mru_cache;
>  struct xfs_ail;
>  struct xfs_quotainfo;
>  struct xfs_da_geometry;
> +struct xfs_perag;
>  
>  /* dynamic preallocation free space thresholds, 5% down to 1% */
>  enum {
> @@ -297,118 +298,12 @@ xfs_daddr_to_agbno(struct xfs_mount *mp, xfs_daddr_t d)
>  	return (xfs_agblock_t) do_div(ld, mp->m_sb.sb_agblocks);
>  }
>  
> -/* per-AG block reservation data structures*/
> -struct xfs_ag_resv {
> -	/* number of blocks originally reserved here */
> -	xfs_extlen_t			ar_orig_reserved;
> -	/* number of blocks reserved here */
> -	xfs_extlen_t			ar_reserved;
> -	/* number of blocks originally asked for */
> -	xfs_extlen_t			ar_asked;
> -};
> -
> -/*
> - * Per-ag incore structure, copies of information in agf and agi, to improve the
> - * performance of allocation group selection.
> - */
> -typedef struct xfs_perag {
> -	struct xfs_mount *pag_mount;	/* owner filesystem */
> -	xfs_agnumber_t	pag_agno;	/* AG this structure belongs to */
> -	atomic_t	pag_ref;	/* perag reference count */
> -	char		pagf_init;	/* this agf's entry is initialized */
> -	char		pagi_init;	/* this agi's entry is initialized */
> -	char		pagf_metadata;	/* the agf is preferred to be metadata */
> -	char		pagi_inodeok;	/* The agi is ok for inodes */
> -	uint8_t		pagf_levels[XFS_BTNUM_AGF];
> -					/* # of levels in bno & cnt btree */
> -	bool		pagf_agflreset; /* agfl requires reset before use */
> -	uint32_t	pagf_flcount;	/* count of blocks in freelist */
> -	xfs_extlen_t	pagf_freeblks;	/* total free blocks */
> -	xfs_extlen_t	pagf_longest;	/* longest free space */
> -	uint32_t	pagf_btreeblks;	/* # of blocks held in AGF btrees */
> -	xfs_agino_t	pagi_freecount;	/* number of free inodes */
> -	xfs_agino_t	pagi_count;	/* number of allocated inodes */
> -
> -	/*
> -	 * Inode allocation search lookup optimisation.
> -	 * If the pagino matches, the search for new inodes
> -	 * doesn't need to search the near ones again straight away
> -	 */
> -	xfs_agino_t	pagl_pagino;
> -	xfs_agino_t	pagl_leftrec;
> -	xfs_agino_t	pagl_rightrec;
> -
> -	int		pagb_count;	/* pagb slots in use */
> -	uint8_t		pagf_refcount_level; /* recount btree height */
> -
> -	/* Blocks reserved for all kinds of metadata. */
> -	struct xfs_ag_resv	pag_meta_resv;
> -	/* Blocks reserved for the reverse mapping btree. */
> -	struct xfs_ag_resv	pag_rmapbt_resv;
> -
> -	/* -- kernel only structures below this line -- */
> -
> -	/*
> -	 * Bitsets of per-ag metadata that have been checked and/or are sick.
> -	 * Callers should hold pag_state_lock before accessing this field.
> -	 */
> -	uint16_t	pag_checked;
> -	uint16_t	pag_sick;
> -	spinlock_t	pag_state_lock;
> -
> -	spinlock_t	pagb_lock;	/* lock for pagb_tree */
> -	struct rb_root	pagb_tree;	/* ordered tree of busy extents */
> -	unsigned int	pagb_gen;	/* generation count for pagb_tree */
> -	wait_queue_head_t pagb_wait;	/* woken when pagb_gen changes */
> -
> -	atomic_t        pagf_fstrms;    /* # of filestreams active in this AG */
> -
> -	spinlock_t	pag_ici_lock;	/* incore inode cache lock */
> -	struct radix_tree_root pag_ici_root;	/* incore inode cache root */
> -	int		pag_ici_reclaimable;	/* reclaimable inodes */
> -	unsigned long	pag_ici_reclaim_cursor;	/* reclaim restart point */
> -
> -	/* buffer cache index */
> -	spinlock_t	pag_buf_lock;	/* lock for pag_buf_hash */
> -	struct rhashtable pag_buf_hash;
> -
> -	/* for rcu-safe freeing */
> -	struct rcu_head	rcu_head;
> -
> -	/* background prealloc block trimming */
> -	struct delayed_work	pag_blockgc_work;
> -
> -	/*
> -	 * Unlinked inode information.  This incore information reflects
> -	 * data stored in the AGI, so callers must hold the AGI buffer lock
> -	 * or have some other means to control concurrency.
> -	 */
> -	struct rhashtable	pagi_unlinked_hash;
> -} xfs_perag_t;
> -
> -static inline struct xfs_ag_resv *
> -xfs_perag_resv(
> -	struct xfs_perag	*pag,
> -	enum xfs_ag_resv_type	type)
> -{
> -	switch (type) {
> -	case XFS_AG_RESV_METADATA:
> -		return &pag->pag_meta_resv;
> -	case XFS_AG_RESV_RMAPBT:
> -		return &pag->pag_rmapbt_resv;
> -	default:
> -		return NULL;
> -	}
> -}
> -
> -int xfs_buf_hash_init(xfs_perag_t *pag);
> -void xfs_buf_hash_destroy(xfs_perag_t *pag);
> +int xfs_buf_hash_init(struct xfs_perag *pag);
> +void xfs_buf_hash_destroy(struct xfs_perag *pag);
>  
>  extern void	xfs_uuid_table_free(void);
>  extern uint64_t xfs_default_resblks(xfs_mount_t *mp);
>  extern int	xfs_mountfs(xfs_mount_t *mp);
> -extern int	xfs_initialize_perag(xfs_mount_t *mp, xfs_agnumber_t agcount,
> -				     xfs_agnumber_t *maxagi);
>  extern void	xfs_unmountfs(xfs_mount_t *);
>  
>  extern int	xfs_mod_fdblocks(struct xfs_mount *mp, int64_t delta,
> diff --git a/fs/xfs/xfs_trace.c b/fs/xfs/xfs_trace.c
> index 9b8d703dc9fd..7e01e00550ac 100644
> --- a/fs/xfs/xfs_trace.c
> +++ b/fs/xfs/xfs_trace.c
> @@ -30,6 +30,8 @@
>  #include "xfs_fsmap.h"
>  #include "xfs_btree_staging.h"
>  #include "xfs_icache.h"
> +#include "xfs_ag.h"
> +#include "xfs_ag_resv.h"
>  
>  /*
>   * We include this last to have the helpers above available for the trace
> -- 
> 2.31.1
> 

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 01/22] xfs: move xfs_perag_get/put to xfs_ag.[ch]
  2021-05-06  7:20 ` [PATCH 01/22] xfs: move xfs_perag_get/put to xfs_ag.[ch] Dave Chinner
  2021-05-10 12:52   ` Brian Foster
@ 2021-05-10 22:28   ` Darrick J. Wong
  1 sibling, 0 replies; 87+ messages in thread
From: Darrick J. Wong @ 2021-05-10 22:28 UTC (permalink / raw)
  To: Dave Chinner; +Cc: linux-xfs

On Thu, May 06, 2021 at 05:20:33PM +1000, Dave Chinner wrote:
> From: Dave Chinner <dchinner@redhat.com>
> 
> They are AG functions, not superblock functions, so move them to the
> appropriate location.
> 
> Signed-off-by: Dave Chinner <dchinner@redhat.com>

Looks decent to me, so long as this doesn't make a porting mess in
userspace...

Reviewed-by: Darrick J. Wong <djwong@kernel.org>

--D

> ---
>  fs/xfs/libxfs/xfs_ag.c             | 135 +++++++++++++++++++++++++++++
>  fs/xfs/libxfs/xfs_ag.h             |  10 +++
>  fs/xfs/libxfs/xfs_ag_resv.c        |   2 +-
>  fs/xfs/libxfs/xfs_alloc.c          |   2 +-
>  fs/xfs/libxfs/xfs_alloc_btree.c    |   2 +-
>  fs/xfs/libxfs/xfs_attr_leaf.c      |   1 +
>  fs/xfs/libxfs/xfs_bmap.c           |   1 +
>  fs/xfs/libxfs/xfs_ialloc.c         |   2 +-
>  fs/xfs/libxfs/xfs_refcount_btree.c |   2 +-
>  fs/xfs/libxfs/xfs_rmap.c           |   1 +
>  fs/xfs/libxfs/xfs_rmap_btree.c     |   2 +-
>  fs/xfs/libxfs/xfs_sb.c             | 133 ----------------------------
>  fs/xfs/libxfs/xfs_sb.h             |   9 --
>  fs/xfs/scrub/agheader.c            |   1 +
>  fs/xfs/scrub/agheader_repair.c     |   1 +
>  fs/xfs/scrub/common.c              |   2 +-
>  fs/xfs/scrub/fscounters.c          |   2 +-
>  fs/xfs/scrub/health.c              |   2 +-
>  fs/xfs/scrub/repair.c              |   1 +
>  fs/xfs/xfs_buf.c                   |   2 +-
>  fs/xfs/xfs_discard.c               |   2 +-
>  fs/xfs/xfs_extent_busy.c           |   2 +-
>  fs/xfs/xfs_filestream.c            |   2 +-
>  fs/xfs/xfs_health.c                |   2 +-
>  fs/xfs/xfs_icache.c                |   2 +-
>  fs/xfs/xfs_inode.c                 |   2 +-
>  fs/xfs/xfs_log_recover.c           |   1 +
>  fs/xfs/xfs_mount.c                 |   1 +
>  fs/xfs/xfs_qm.c                    |   1 +
>  fs/xfs/xfs_reflink.c               |   2 +-
>  fs/xfs/xfs_super.c                 |   1 +
>  31 files changed, 172 insertions(+), 159 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_ag.c b/fs/xfs/libxfs/xfs_ag.c
> index c68a36688474..2ca31dc46fe8 100644
> --- a/fs/xfs/libxfs/xfs_ag.c
> +++ b/fs/xfs/libxfs/xfs_ag.c
> @@ -27,6 +27,141 @@
>  #include "xfs_defer.h"
>  #include "xfs_log_format.h"
>  #include "xfs_trans.h"
> +#include "xfs_trace.h"
> +
> +/*
> + * Passive reference counting access wrappers to the perag structures.  If the
> + * per-ag structure is to be freed, the freeing code is responsible for cleaning
> + * up objects with passive references before freeing the structure. This is
> + * things like cached buffers.
> + */
> +struct xfs_perag *
> +xfs_perag_get(
> +	struct xfs_mount	*mp,
> +	xfs_agnumber_t		agno)
> +{
> +	struct xfs_perag	*pag;
> +	int			ref = 0;
> +
> +	rcu_read_lock();
> +	pag = radix_tree_lookup(&mp->m_perag_tree, agno);
> +	if (pag) {
> +		ASSERT(atomic_read(&pag->pag_ref) >= 0);
> +		ref = atomic_inc_return(&pag->pag_ref);
> +	}
> +	rcu_read_unlock();
> +	trace_xfs_perag_get(mp, agno, ref, _RET_IP_);
> +	return pag;
> +}
> +
> +/*
> + * search from @first to find the next perag with the given tag set.
> + */
> +struct xfs_perag *
> +xfs_perag_get_tag(
> +	struct xfs_mount	*mp,
> +	xfs_agnumber_t		first,
> +	int			tag)
> +{
> +	struct xfs_perag	*pag;
> +	int			found;
> +	int			ref;
> +
> +	rcu_read_lock();
> +	found = radix_tree_gang_lookup_tag(&mp->m_perag_tree,
> +					(void **)&pag, first, 1, tag);
> +	if (found <= 0) {
> +		rcu_read_unlock();
> +		return NULL;
> +	}
> +	ref = atomic_inc_return(&pag->pag_ref);
> +	rcu_read_unlock();
> +	trace_xfs_perag_get_tag(mp, pag->pag_agno, ref, _RET_IP_);
> +	return pag;
> +}
> +
> +void
> +xfs_perag_put(
> +	struct xfs_perag	*pag)
> +{
> +	int	ref;
> +
> +	ASSERT(atomic_read(&pag->pag_ref) > 0);
> +	ref = atomic_dec_return(&pag->pag_ref);
> +	trace_xfs_perag_put(pag->pag_mount, pag->pag_agno, ref, _RET_IP_);
> +}
> +
> +/*
> + * xfs_initialize_perag_data
> + *
> + * Read in each per-ag structure so we can count up the number of
> + * allocated inodes, free inodes and used filesystem blocks as this
> + * information is no longer persistent in the superblock. Once we have
> + * this information, write it into the in-core superblock structure.
> + */
> +int
> +xfs_initialize_perag_data(
> +	struct xfs_mount *mp,
> +	xfs_agnumber_t	agcount)
> +{
> +	xfs_agnumber_t	index;
> +	xfs_perag_t	*pag;
> +	xfs_sb_t	*sbp = &mp->m_sb;
> +	uint64_t	ifree = 0;
> +	uint64_t	ialloc = 0;
> +	uint64_t	bfree = 0;
> +	uint64_t	bfreelst = 0;
> +	uint64_t	btree = 0;
> +	uint64_t	fdblocks;
> +	int		error = 0;
> +
> +	for (index = 0; index < agcount; index++) {
> +		/*
> +		 * read the agf, then the agi. This gets us
> +		 * all the information we need and populates the
> +		 * per-ag structures for us.
> +		 */
> +		error = xfs_alloc_pagf_init(mp, NULL, index, 0);
> +		if (error)
> +			return error;
> +
> +		error = xfs_ialloc_pagi_init(mp, NULL, index);
> +		if (error)
> +			return error;
> +		pag = xfs_perag_get(mp, index);
> +		ifree += pag->pagi_freecount;
> +		ialloc += pag->pagi_count;
> +		bfree += pag->pagf_freeblks;
> +		bfreelst += pag->pagf_flcount;
> +		btree += pag->pagf_btreeblks;
> +		xfs_perag_put(pag);
> +	}
> +	fdblocks = bfree + bfreelst + btree;
> +
> +	/*
> +	 * If the new summary counts are obviously incorrect, fail the
> +	 * mount operation because that implies the AGFs are also corrupt.
> +	 * Clear FS_COUNTERS so that we don't unmount with a dirty log, which
> +	 * will prevent xfs_repair from fixing anything.
> +	 */
> +	if (fdblocks > sbp->sb_dblocks || ifree > ialloc) {
> +		xfs_alert(mp, "AGF corruption. Please run xfs_repair.");
> +		error = -EFSCORRUPTED;
> +		goto out;
> +	}
> +
> +	/* Overwrite incore superblock counters with just-read data */
> +	spin_lock(&mp->m_sb_lock);
> +	sbp->sb_ifree = ifree;
> +	sbp->sb_icount = ialloc;
> +	sbp->sb_fdblocks = fdblocks;
> +	spin_unlock(&mp->m_sb_lock);
> +
> +	xfs_reinit_percpu_counters(mp);
> +out:
> +	xfs_fs_mark_healthy(mp, XFS_SICK_FS_COUNTERS);
> +	return error;
> +}
>  
>  static int
>  xfs_get_aghdr_buf(
> diff --git a/fs/xfs/libxfs/xfs_ag.h b/fs/xfs/libxfs/xfs_ag.h
> index 4535de1d88ea..cb1bd1c03cd7 100644
> --- a/fs/xfs/libxfs/xfs_ag.h
> +++ b/fs/xfs/libxfs/xfs_ag.h
> @@ -9,6 +9,16 @@
>  
>  struct xfs_mount;
>  struct xfs_trans;
> +struct xfs_perag;
> +
> +/*
> + * perag get/put wrappers for ref counting
> + */
> +int	xfs_initialize_perag_data(struct xfs_mount *, xfs_agnumber_t);
> +struct xfs_perag *xfs_perag_get(struct xfs_mount *, xfs_agnumber_t);
> +struct xfs_perag *xfs_perag_get_tag(struct xfs_mount *, xfs_agnumber_t,
> +				   int tag);
> +void	xfs_perag_put(struct xfs_perag *pag);
>  
>  struct aghdr_init_data {
>  	/* per ag data */
> diff --git a/fs/xfs/libxfs/xfs_ag_resv.c b/fs/xfs/libxfs/xfs_ag_resv.c
> index e32a1833d523..2e3dcdfd4984 100644
> --- a/fs/xfs/libxfs/xfs_ag_resv.c
> +++ b/fs/xfs/libxfs/xfs_ag_resv.c
> @@ -19,7 +19,7 @@
>  #include "xfs_btree.h"
>  #include "xfs_refcount_btree.h"
>  #include "xfs_ialloc_btree.h"
> -#include "xfs_sb.h"
> +#include "xfs_ag.h"
>  #include "xfs_ag_resv.h"
>  
>  /*
> diff --git a/fs/xfs/libxfs/xfs_alloc.c b/fs/xfs/libxfs/xfs_alloc.c
> index 82b7cbb1f24f..dc2b77829915 100644
> --- a/fs/xfs/libxfs/xfs_alloc.c
> +++ b/fs/xfs/libxfs/xfs_alloc.c
> @@ -10,7 +10,6 @@
>  #include "xfs_shared.h"
>  #include "xfs_trans_resv.h"
>  #include "xfs_bit.h"
> -#include "xfs_sb.h"
>  #include "xfs_mount.h"
>  #include "xfs_defer.h"
>  #include "xfs_btree.h"
> @@ -24,6 +23,7 @@
>  #include "xfs_trans.h"
>  #include "xfs_buf_item.h"
>  #include "xfs_log.h"
> +#include "xfs_ag.h"
>  #include "xfs_ag_resv.h"
>  #include "xfs_bmap.h"
>  
> diff --git a/fs/xfs/libxfs/xfs_alloc_btree.c b/fs/xfs/libxfs/xfs_alloc_btree.c
> index a43e4c50e69b..a540b6e799e0 100644
> --- a/fs/xfs/libxfs/xfs_alloc_btree.c
> +++ b/fs/xfs/libxfs/xfs_alloc_btree.c
> @@ -9,7 +9,6 @@
>  #include "xfs_format.h"
>  #include "xfs_log_format.h"
>  #include "xfs_trans_resv.h"
> -#include "xfs_sb.h"
>  #include "xfs_mount.h"
>  #include "xfs_btree.h"
>  #include "xfs_btree_staging.h"
> @@ -19,6 +18,7 @@
>  #include "xfs_error.h"
>  #include "xfs_trace.h"
>  #include "xfs_trans.h"
> +#include "xfs_ag.h"
>  
>  
>  STATIC struct xfs_btree_cur *
> diff --git a/fs/xfs/libxfs/xfs_attr_leaf.c b/fs/xfs/libxfs/xfs_attr_leaf.c
> index 556184b63061..aa371d005131 100644
> --- a/fs/xfs/libxfs/xfs_attr_leaf.c
> +++ b/fs/xfs/libxfs/xfs_attr_leaf.c
> @@ -27,6 +27,7 @@
>  #include "xfs_buf_item.h"
>  #include "xfs_dir2.h"
>  #include "xfs_log.h"
> +#include "xfs_ag.h"
>  
>  
>  /*
> diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c
> index 7e3b9b01431e..2086c55b67bd 100644
> --- a/fs/xfs/libxfs/xfs_bmap.c
> +++ b/fs/xfs/libxfs/xfs_bmap.c
> @@ -31,6 +31,7 @@
>  #include "xfs_attr_leaf.h"
>  #include "xfs_filestream.h"
>  #include "xfs_rmap.h"
> +#include "xfs_ag.h"
>  #include "xfs_ag_resv.h"
>  #include "xfs_refcount.h"
>  #include "xfs_icache.h"
> diff --git a/fs/xfs/libxfs/xfs_ialloc.c b/fs/xfs/libxfs/xfs_ialloc.c
> index eefdb518fe64..8dc9225a5353 100644
> --- a/fs/xfs/libxfs/xfs_ialloc.c
> +++ b/fs/xfs/libxfs/xfs_ialloc.c
> @@ -10,7 +10,6 @@
>  #include "xfs_log_format.h"
>  #include "xfs_trans_resv.h"
>  #include "xfs_bit.h"
> -#include "xfs_sb.h"
>  #include "xfs_mount.h"
>  #include "xfs_inode.h"
>  #include "xfs_btree.h"
> @@ -27,6 +26,7 @@
>  #include "xfs_trace.h"
>  #include "xfs_log.h"
>  #include "xfs_rmap.h"
> +#include "xfs_ag.h"
>  
>  /*
>   * Lookup a record by ino in the btree given by cur.
> diff --git a/fs/xfs/libxfs/xfs_refcount_btree.c b/fs/xfs/libxfs/xfs_refcount_btree.c
> index a6ac60ae9421..b281f0c674f5 100644
> --- a/fs/xfs/libxfs/xfs_refcount_btree.c
> +++ b/fs/xfs/libxfs/xfs_refcount_btree.c
> @@ -9,7 +9,6 @@
>  #include "xfs_format.h"
>  #include "xfs_log_format.h"
>  #include "xfs_trans_resv.h"
> -#include "xfs_sb.h"
>  #include "xfs_mount.h"
>  #include "xfs_btree.h"
>  #include "xfs_btree_staging.h"
> @@ -20,6 +19,7 @@
>  #include "xfs_trans.h"
>  #include "xfs_bit.h"
>  #include "xfs_rmap.h"
> +#include "xfs_ag.h"
>  
>  static struct xfs_btree_cur *
>  xfs_refcountbt_dup_cursor(
> diff --git a/fs/xfs/libxfs/xfs_rmap.c b/fs/xfs/libxfs/xfs_rmap.c
> index 10e0cf9949a2..61e8f10436ac 100644
> --- a/fs/xfs/libxfs/xfs_rmap.c
> +++ b/fs/xfs/libxfs/xfs_rmap.c
> @@ -21,6 +21,7 @@
>  #include "xfs_errortag.h"
>  #include "xfs_error.h"
>  #include "xfs_inode.h"
> +#include "xfs_ag.h"
>  
>  /*
>   * Lookup the first record less than or equal to [bno, len, owner, offset]
> diff --git a/fs/xfs/libxfs/xfs_rmap_btree.c b/fs/xfs/libxfs/xfs_rmap_btree.c
> index 9f5bcbd834c3..f1fee42dda2d 100644
> --- a/fs/xfs/libxfs/xfs_rmap_btree.c
> +++ b/fs/xfs/libxfs/xfs_rmap_btree.c
> @@ -9,7 +9,6 @@
>  #include "xfs_format.h"
>  #include "xfs_log_format.h"
>  #include "xfs_trans_resv.h"
> -#include "xfs_sb.h"
>  #include "xfs_mount.h"
>  #include "xfs_trans.h"
>  #include "xfs_alloc.h"
> @@ -20,6 +19,7 @@
>  #include "xfs_trace.h"
>  #include "xfs_error.h"
>  #include "xfs_extent_busy.h"
> +#include "xfs_ag.h"
>  #include "xfs_ag_resv.h"
>  
>  /*
> diff --git a/fs/xfs/libxfs/xfs_sb.c b/fs/xfs/libxfs/xfs_sb.c
> index dfbbcbd448c1..cbcfce8cebf1 100644
> --- a/fs/xfs/libxfs/xfs_sb.c
> +++ b/fs/xfs/libxfs/xfs_sb.c
> @@ -30,67 +30,6 @@
>   * Physical superblock buffer manipulations. Shared with libxfs in userspace.
>   */
>  
> -/*
> - * Reference counting access wrappers to the perag structures.
> - * Because we never free per-ag structures, the only thing we
> - * have to protect against changes is the tree structure itself.
> - */
> -struct xfs_perag *
> -xfs_perag_get(
> -	struct xfs_mount	*mp,
> -	xfs_agnumber_t		agno)
> -{
> -	struct xfs_perag	*pag;
> -	int			ref = 0;
> -
> -	rcu_read_lock();
> -	pag = radix_tree_lookup(&mp->m_perag_tree, agno);
> -	if (pag) {
> -		ASSERT(atomic_read(&pag->pag_ref) >= 0);
> -		ref = atomic_inc_return(&pag->pag_ref);
> -	}
> -	rcu_read_unlock();
> -	trace_xfs_perag_get(mp, agno, ref, _RET_IP_);
> -	return pag;
> -}
> -
> -/*
> - * search from @first to find the next perag with the given tag set.
> - */
> -struct xfs_perag *
> -xfs_perag_get_tag(
> -	struct xfs_mount	*mp,
> -	xfs_agnumber_t		first,
> -	int			tag)
> -{
> -	struct xfs_perag	*pag;
> -	int			found;
> -	int			ref;
> -
> -	rcu_read_lock();
> -	found = radix_tree_gang_lookup_tag(&mp->m_perag_tree,
> -					(void **)&pag, first, 1, tag);
> -	if (found <= 0) {
> -		rcu_read_unlock();
> -		return NULL;
> -	}
> -	ref = atomic_inc_return(&pag->pag_ref);
> -	rcu_read_unlock();
> -	trace_xfs_perag_get_tag(mp, pag->pag_agno, ref, _RET_IP_);
> -	return pag;
> -}
> -
> -void
> -xfs_perag_put(
> -	struct xfs_perag	*pag)
> -{
> -	int	ref;
> -
> -	ASSERT(atomic_read(&pag->pag_ref) > 0);
> -	ref = atomic_dec_return(&pag->pag_ref);
> -	trace_xfs_perag_put(pag->pag_mount, pag->pag_agno, ref, _RET_IP_);
> -}
> -
>  /* Check all the superblock fields we care about when reading one in. */
>  STATIC int
>  xfs_validate_sb_read(
> @@ -841,78 +780,6 @@ xfs_sb_mount_common(
>  	mp->m_ag_max_usable = xfs_alloc_ag_max_usable(mp);
>  }
>  
> -/*
> - * xfs_initialize_perag_data
> - *
> - * Read in each per-ag structure so we can count up the number of
> - * allocated inodes, free inodes and used filesystem blocks as this
> - * information is no longer persistent in the superblock. Once we have
> - * this information, write it into the in-core superblock structure.
> - */
> -int
> -xfs_initialize_perag_data(
> -	struct xfs_mount *mp,
> -	xfs_agnumber_t	agcount)
> -{
> -	xfs_agnumber_t	index;
> -	xfs_perag_t	*pag;
> -	xfs_sb_t	*sbp = &mp->m_sb;
> -	uint64_t	ifree = 0;
> -	uint64_t	ialloc = 0;
> -	uint64_t	bfree = 0;
> -	uint64_t	bfreelst = 0;
> -	uint64_t	btree = 0;
> -	uint64_t	fdblocks;
> -	int		error = 0;
> -
> -	for (index = 0; index < agcount; index++) {
> -		/*
> -		 * read the agf, then the agi. This gets us
> -		 * all the information we need and populates the
> -		 * per-ag structures for us.
> -		 */
> -		error = xfs_alloc_pagf_init(mp, NULL, index, 0);
> -		if (error)
> -			return error;
> -
> -		error = xfs_ialloc_pagi_init(mp, NULL, index);
> -		if (error)
> -			return error;
> -		pag = xfs_perag_get(mp, index);
> -		ifree += pag->pagi_freecount;
> -		ialloc += pag->pagi_count;
> -		bfree += pag->pagf_freeblks;
> -		bfreelst += pag->pagf_flcount;
> -		btree += pag->pagf_btreeblks;
> -		xfs_perag_put(pag);
> -	}
> -	fdblocks = bfree + bfreelst + btree;
> -
> -	/*
> -	 * If the new summary counts are obviously incorrect, fail the
> -	 * mount operation because that implies the AGFs are also corrupt.
> -	 * Clear FS_COUNTERS so that we don't unmount with a dirty log, which
> -	 * will prevent xfs_repair from fixing anything.
> -	 */
> -	if (fdblocks > sbp->sb_dblocks || ifree > ialloc) {
> -		xfs_alert(mp, "AGF corruption. Please run xfs_repair.");
> -		error = -EFSCORRUPTED;
> -		goto out;
> -	}
> -
> -	/* Overwrite incore superblock counters with just-read data */
> -	spin_lock(&mp->m_sb_lock);
> -	sbp->sb_ifree = ifree;
> -	sbp->sb_icount = ialloc;
> -	sbp->sb_fdblocks = fdblocks;
> -	spin_unlock(&mp->m_sb_lock);
> -
> -	xfs_reinit_percpu_counters(mp);
> -out:
> -	xfs_fs_mark_healthy(mp, XFS_SICK_FS_COUNTERS);
> -	return error;
> -}
> -
>  /*
>   * xfs_log_sb() can be used to copy arbitrary changes to the in-core superblock
>   * into the superblock buffer to be logged.  It does not provide the higher
> diff --git a/fs/xfs/libxfs/xfs_sb.h b/fs/xfs/libxfs/xfs_sb.h
> index f79f9dc632b6..0c1602d9b53d 100644
> --- a/fs/xfs/libxfs/xfs_sb.h
> +++ b/fs/xfs/libxfs/xfs_sb.h
> @@ -13,15 +13,6 @@ struct xfs_trans;
>  struct xfs_fsop_geom;
>  struct xfs_perag;
>  
> -/*
> - * perag get/put wrappers for ref counting
> - */
> -extern struct xfs_perag *xfs_perag_get(struct xfs_mount *, xfs_agnumber_t);
> -extern struct xfs_perag *xfs_perag_get_tag(struct xfs_mount *, xfs_agnumber_t,
> -					   int tag);
> -extern void	xfs_perag_put(struct xfs_perag *pag);
> -extern int	xfs_initialize_perag_data(struct xfs_mount *, xfs_agnumber_t);
> -
>  extern void	xfs_log_sb(struct xfs_trans *tp);
>  extern int	xfs_sync_sb(struct xfs_mount *mp, bool wait);
>  extern int	xfs_sync_sb_buf(struct xfs_mount *mp);
> diff --git a/fs/xfs/scrub/agheader.c b/fs/xfs/scrub/agheader.c
> index 7a2f9b5f2db5..64a7a30f4ac0 100644
> --- a/fs/xfs/scrub/agheader.c
> +++ b/fs/xfs/scrub/agheader.c
> @@ -14,6 +14,7 @@
>  #include "xfs_alloc.h"
>  #include "xfs_ialloc.h"
>  #include "xfs_rmap.h"
> +#include "xfs_ag.h"
>  #include "scrub/scrub.h"
>  #include "scrub/common.h"
>  
> diff --git a/fs/xfs/scrub/agheader_repair.c b/fs/xfs/scrub/agheader_repair.c
> index 23690f824ffa..1cdfbd57f36b 100644
> --- a/fs/xfs/scrub/agheader_repair.c
> +++ b/fs/xfs/scrub/agheader_repair.c
> @@ -20,6 +20,7 @@
>  #include "xfs_rmap.h"
>  #include "xfs_rmap_btree.h"
>  #include "xfs_refcount_btree.h"
> +#include "xfs_ag.h"
>  #include "scrub/scrub.h"
>  #include "scrub/common.h"
>  #include "scrub/trace.h"
> diff --git a/fs/xfs/scrub/common.c b/fs/xfs/scrub/common.c
> index aa874607618a..c8da976b50fc 100644
> --- a/fs/xfs/scrub/common.c
> +++ b/fs/xfs/scrub/common.c
> @@ -12,7 +12,6 @@
>  #include "xfs_btree.h"
>  #include "xfs_log_format.h"
>  #include "xfs_trans.h"
> -#include "xfs_sb.h"
>  #include "xfs_inode.h"
>  #include "xfs_icache.h"
>  #include "xfs_alloc.h"
> @@ -26,6 +25,7 @@
>  #include "xfs_trans_priv.h"
>  #include "xfs_attr.h"
>  #include "xfs_reflink.h"
> +#include "xfs_ag.h"
>  #include "scrub/scrub.h"
>  #include "scrub/common.h"
>  #include "scrub/trace.h"
> diff --git a/fs/xfs/scrub/fscounters.c b/fs/xfs/scrub/fscounters.c
> index f1d1a8c58853..453ae9adf94c 100644
> --- a/fs/xfs/scrub/fscounters.c
> +++ b/fs/xfs/scrub/fscounters.c
> @@ -9,11 +9,11 @@
>  #include "xfs_format.h"
>  #include "xfs_trans_resv.h"
>  #include "xfs_mount.h"
> -#include "xfs_sb.h"
>  #include "xfs_alloc.h"
>  #include "xfs_ialloc.h"
>  #include "xfs_health.h"
>  #include "xfs_btree.h"
> +#include "xfs_ag.h"
>  #include "scrub/scrub.h"
>  #include "scrub/common.h"
>  #include "scrub/trace.h"
> diff --git a/fs/xfs/scrub/health.c b/fs/xfs/scrub/health.c
> index 3de59b5c2ce6..2e61df3bca83 100644
> --- a/fs/xfs/scrub/health.c
> +++ b/fs/xfs/scrub/health.c
> @@ -8,7 +8,7 @@
>  #include "xfs_shared.h"
>  #include "xfs_format.h"
>  #include "xfs_btree.h"
> -#include "xfs_sb.h"
> +#include "xfs_ag.h"
>  #include "xfs_health.h"
>  #include "scrub/scrub.h"
>  #include "scrub/health.h"
> diff --git a/fs/xfs/scrub/repair.c b/fs/xfs/scrub/repair.c
> index c2857d854c83..1308b62a8170 100644
> --- a/fs/xfs/scrub/repair.c
> +++ b/fs/xfs/scrub/repair.c
> @@ -22,6 +22,7 @@
>  #include "xfs_rmap_btree.h"
>  #include "xfs_refcount_btree.h"
>  #include "xfs_extent_busy.h"
> +#include "xfs_ag.h"
>  #include "xfs_ag_resv.h"
>  #include "xfs_quota.h"
>  #include "scrub/scrub.h"
> diff --git a/fs/xfs/xfs_buf.c b/fs/xfs/xfs_buf.c
> index 37a1d12762d8..38245c49b1b6 100644
> --- a/fs/xfs/xfs_buf.c
> +++ b/fs/xfs/xfs_buf.c
> @@ -10,7 +10,6 @@
>  #include "xfs_format.h"
>  #include "xfs_log_format.h"
>  #include "xfs_trans_resv.h"
> -#include "xfs_sb.h"
>  #include "xfs_mount.h"
>  #include "xfs_trace.h"
>  #include "xfs_log.h"
> @@ -19,6 +18,7 @@
>  #include "xfs_buf_item.h"
>  #include "xfs_errortag.h"
>  #include "xfs_error.h"
> +#include "xfs_ag.h"
>  
>  static kmem_zone_t *xfs_buf_zone;
>  
> diff --git a/fs/xfs/xfs_discard.c b/fs/xfs/xfs_discard.c
> index f979d0d7e6cd..3bf6dba1a040 100644
> --- a/fs/xfs/xfs_discard.c
> +++ b/fs/xfs/xfs_discard.c
> @@ -8,7 +8,6 @@
>  #include "xfs_format.h"
>  #include "xfs_log_format.h"
>  #include "xfs_trans_resv.h"
> -#include "xfs_sb.h"
>  #include "xfs_mount.h"
>  #include "xfs_btree.h"
>  #include "xfs_alloc_btree.h"
> @@ -18,6 +17,7 @@
>  #include "xfs_extent_busy.h"
>  #include "xfs_trace.h"
>  #include "xfs_log.h"
> +#include "xfs_ag.h"
>  
>  STATIC int
>  xfs_trim_extents(
> diff --git a/fs/xfs/xfs_extent_busy.c b/fs/xfs/xfs_extent_busy.c
> index ef17c1f6db32..184732aa8674 100644
> --- a/fs/xfs/xfs_extent_busy.c
> +++ b/fs/xfs/xfs_extent_busy.c
> @@ -11,13 +11,13 @@
>  #include "xfs_log_format.h"
>  #include "xfs_shared.h"
>  #include "xfs_trans_resv.h"
> -#include "xfs_sb.h"
>  #include "xfs_mount.h"
>  #include "xfs_alloc.h"
>  #include "xfs_extent_busy.h"
>  #include "xfs_trace.h"
>  #include "xfs_trans.h"
>  #include "xfs_log.h"
> +#include "xfs_ag.h"
>  
>  void
>  xfs_extent_busy_insert(
> diff --git a/fs/xfs/xfs_filestream.c b/fs/xfs/xfs_filestream.c
> index db23e455eb91..eed6ca5f8f91 100644
> --- a/fs/xfs/xfs_filestream.c
> +++ b/fs/xfs/xfs_filestream.c
> @@ -9,13 +9,13 @@
>  #include "xfs_format.h"
>  #include "xfs_log_format.h"
>  #include "xfs_trans_resv.h"
> -#include "xfs_sb.h"
>  #include "xfs_mount.h"
>  #include "xfs_inode.h"
>  #include "xfs_bmap.h"
>  #include "xfs_alloc.h"
>  #include "xfs_mru_cache.h"
>  #include "xfs_trace.h"
> +#include "xfs_ag.h"
>  #include "xfs_ag_resv.h"
>  #include "xfs_trans.h"
>  #include "xfs_filestream.h"
> diff --git a/fs/xfs/xfs_health.c b/fs/xfs/xfs_health.c
> index 8e0cb05a7142..b79475ea3dbd 100644
> --- a/fs/xfs/xfs_health.c
> +++ b/fs/xfs/xfs_health.c
> @@ -9,11 +9,11 @@
>  #include "xfs_format.h"
>  #include "xfs_log_format.h"
>  #include "xfs_trans_resv.h"
> -#include "xfs_sb.h"
>  #include "xfs_mount.h"
>  #include "xfs_inode.h"
>  #include "xfs_trace.h"
>  #include "xfs_health.h"
> +#include "xfs_ag.h"
>  
>  /*
>   * Warn about metadata corruption that we detected but haven't fixed, and
> diff --git a/fs/xfs/xfs_icache.c b/fs/xfs/xfs_icache.c
> index 3c81daca0e9a..588ea2bf88bb 100644
> --- a/fs/xfs/xfs_icache.c
> +++ b/fs/xfs/xfs_icache.c
> @@ -9,7 +9,6 @@
>  #include "xfs_format.h"
>  #include "xfs_log_format.h"
>  #include "xfs_trans_resv.h"
> -#include "xfs_sb.h"
>  #include "xfs_mount.h"
>  #include "xfs_inode.h"
>  #include "xfs_trans.h"
> @@ -23,6 +22,7 @@
>  #include "xfs_dquot.h"
>  #include "xfs_reflink.h"
>  #include "xfs_ialloc.h"
> +#include "xfs_ag.h"
>  
>  #include <linux/iversion.h>
>  
> diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
> index 17c2d8b18283..25910b145d70 100644
> --- a/fs/xfs/xfs_inode.c
> +++ b/fs/xfs/xfs_inode.c
> @@ -11,7 +11,6 @@
>  #include "xfs_format.h"
>  #include "xfs_log_format.h"
>  #include "xfs_trans_resv.h"
> -#include "xfs_sb.h"
>  #include "xfs_mount.h"
>  #include "xfs_defer.h"
>  #include "xfs_inode.h"
> @@ -35,6 +34,7 @@
>  #include "xfs_log.h"
>  #include "xfs_bmap_btree.h"
>  #include "xfs_reflink.h"
> +#include "xfs_ag.h"
>  
>  kmem_zone_t *xfs_inode_zone;
>  
> diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c
> index e5dd1c0c2f03..fee2a4e80241 100644
> --- a/fs/xfs/xfs_log_recover.c
> +++ b/fs/xfs/xfs_log_recover.c
> @@ -25,6 +25,7 @@
>  #include "xfs_icache.h"
>  #include "xfs_error.h"
>  #include "xfs_buf_item.h"
> +#include "xfs_ag.h"
>  
>  #define BLK_AVG(blk1, blk2)	((blk1+blk2) >> 1)
>  
> diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c
> index bdfee1943796..21c630dde476 100644
> --- a/fs/xfs/xfs_mount.c
> +++ b/fs/xfs/xfs_mount.c
> @@ -32,6 +32,7 @@
>  #include "xfs_extent_busy.h"
>  #include "xfs_health.h"
>  #include "xfs_trace.h"
> +#include "xfs_ag.h"
>  
>  static DEFINE_MUTEX(xfs_uuid_table_mutex);
>  static int xfs_uuid_table_size;
> diff --git a/fs/xfs/xfs_qm.c b/fs/xfs/xfs_qm.c
> index 4bf949a89d0d..f7baf4dc2554 100644
> --- a/fs/xfs/xfs_qm.c
> +++ b/fs/xfs/xfs_qm.c
> @@ -23,6 +23,7 @@
>  #include "xfs_trace.h"
>  #include "xfs_icache.h"
>  #include "xfs_error.h"
> +#include "xfs_ag.h"
>  
>  /*
>   * The global quota manager. There is only one of these for the entire
> diff --git a/fs/xfs/xfs_reflink.c b/fs/xfs/xfs_reflink.c
> index 060695d6d56a..f297d68a931b 100644
> --- a/fs/xfs/xfs_reflink.c
> +++ b/fs/xfs/xfs_reflink.c
> @@ -27,7 +27,7 @@
>  #include "xfs_quota.h"
>  #include "xfs_reflink.h"
>  #include "xfs_iomap.h"
> -#include "xfs_sb.h"
> +#include "xfs_ag.h"
>  #include "xfs_ag_resv.h"
>  
>  /*
> diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c
> index a2dab05332ac..688309dbe18b 100644
> --- a/fs/xfs/xfs_super.c
> +++ b/fs/xfs/xfs_super.c
> @@ -36,6 +36,7 @@
>  #include "xfs_bmap_item.h"
>  #include "xfs_reflink.h"
>  #include "xfs_pwork.h"
> +#include "xfs_ag.h"
>  
>  #include <linux/magic.h>
>  #include <linux/fs_context.h>
> -- 
> 2.31.1
> 

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 03/22] xfs: move perag structure and setup to libxfs/xfs_ag.[ch]
  2021-05-10 22:26   ` Darrick J. Wong
@ 2021-05-10 23:38     ` Dave Chinner
  0 siblings, 0 replies; 87+ messages in thread
From: Dave Chinner @ 2021-05-10 23:38 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs

On Mon, May 10, 2021 at 03:26:55PM -0700, Darrick J. Wong wrote:
> On Thu, May 06, 2021 at 05:20:35PM +1000, Dave Chinner wrote:
> > From: Dave Chinner <dchinner@redhat.com>
> > 
> > Move the xfs_perag infrastructure to the libxfs files that contain
> > all the per AG infrastructure. This helps set up for passing perags
> > around all the code instead of bare agnos with minimal extra
> > includes for existing files.
.....
> > -int	xfs_initialize_perag_data(struct xfs_mount *, xfs_agnumber_t);
> > +
> > +/* per-AG block reservation data structures*/
> > +struct xfs_ag_resv {
> > +	/* number of blocks originally reserved here */
> > +	xfs_extlen_t			ar_orig_reserved;
> > +	/* number of blocks reserved here */
> > +	xfs_extlen_t			ar_reserved;
> > +	/* number of blocks originally asked for */
> > +	xfs_extlen_t			ar_asked;
> > +};
> > +
> > +/*
> > + * Per-ag incore structure, copies of information in agf and agi, to improve the
> > + * performance of allocation group selection.
> > + */
> > +typedef struct xfs_perag {
> > +	struct xfs_mount *pag_mount;	/* owner filesystem */
> > +	xfs_agnumber_t	pag_agno;	/* AG this structure belongs to */
> > +	atomic_t	pag_ref;	/* perag reference count */
> > +	char		pagf_init;	/* this agf's entry is initialized */
> > +	char		pagi_init;	/* this agi's entry is initialized */
> > +	char		pagf_metadata;	/* the agf is preferred to be metadata */
> > +	char		pagi_inodeok;	/* The agi is ok for inodes */
> > +	uint8_t		pagf_levels[XFS_BTNUM_AGF];
> > +					/* # of levels in bno & cnt btree */
> > +	bool		pagf_agflreset; /* agfl requires reset before use */
> > +	uint32_t	pagf_flcount;	/* count of blocks in freelist */
> > +	xfs_extlen_t	pagf_freeblks;	/* total free blocks */
> > +	xfs_extlen_t	pagf_longest;	/* longest free space */
> > +	uint32_t	pagf_btreeblks;	/* # of blocks held in AGF btrees */
> > +	xfs_agino_t	pagi_freecount;	/* number of free inodes */
> > +	xfs_agino_t	pagi_count;	/* number of allocated inodes */
> > +
> > +	/*
> > +	 * Inode allocation search lookup optimisation.
> > +	 * If the pagino matches, the search for new inodes
> > +	 * doesn't need to search the near ones again straight away
> > +	 */
> > +	xfs_agino_t	pagl_pagino;
> > +	xfs_agino_t	pagl_leftrec;
> > +	xfs_agino_t	pagl_rightrec;
> > +
> > +	int		pagb_count;	/* pagb slots in use */
> > +	uint8_t		pagf_refcount_level; /* recount btree height */
> > +
> > +	/* Blocks reserved for all kinds of metadata. */
> > +	struct xfs_ag_resv	pag_meta_resv;
> > +	/* Blocks reserved for the reverse mapping btree. */
> > +	struct xfs_ag_resv	pag_rmapbt_resv;
> > +
> > +	/* -- kernel only structures below this line -- */
> > +
> > +	/*
> > +	 * Bitsets of per-ag metadata that have been checked and/or are sick.
> > +	 * Callers should hold pag_state_lock before accessing this field.
> > +	 */
> > +	uint16_t	pag_checked;
> > +	uint16_t	pag_sick;
> > +	spinlock_t	pag_state_lock;
> > +
> > +	spinlock_t	pagb_lock;	/* lock for pagb_tree */
> > +	struct rb_root	pagb_tree;	/* ordered tree of busy extents */
> > +	unsigned int	pagb_gen;	/* generation count for pagb_tree */
> > +	wait_queue_head_t pagb_wait;	/* woken when pagb_gen changes */
> > +
> > +	atomic_t        pagf_fstrms;    /* # of filestreams active in this AG */
> > +
> > +	spinlock_t	pag_ici_lock;	/* incore inode cache lock */
> > +	struct radix_tree_root pag_ici_root;	/* incore inode cache root */
> > +	int		pag_ici_reclaimable;	/* reclaimable inodes */
> > +	unsigned long	pag_ici_reclaim_cursor;	/* reclaim restart point */
> > +
> > +	/* buffer cache index */
> > +	spinlock_t	pag_buf_lock;	/* lock for pag_buf_hash */
> > +	struct rhashtable pag_buf_hash;
> > +
> > +	/* for rcu-safe freeing */
> > +	struct rcu_head	rcu_head;
> > +
> > +	/* background prealloc block trimming */
> > +	struct delayed_work	pag_blockgc_work;
> > +
> > +	/*
> > +	 * Unlinked inode information.  This incore information reflects
> > +	 * data stored in the AGI, so callers must hold the AGI buffer lock
> > +	 * or have some other means to control concurrency.
> > +	 */
> > +	struct rhashtable	pagi_unlinked_hash;
> > +} xfs_perag_t;
> 
> I wonder, have you ported this to xfsprogs yet?  How much of a mess is
> this going to create for things like libxfs-diff?

I've looked at it, not yet ported. I structured the code so that
userspace should just need to add a couple of "#ifdef
KERNEL"/"#endif /* KERNEL */" pairs around the structure definition
and the init function, and then all userspace sees is the common
parts of the structure. Then the custom code to initialise the
perags in libxfs/init.c in userspace can go away....

IOWs, I think the xfs-diff should only show up a couple of ifdefs
and nothing else.

> (Also would be nice to kill off xfs_perag_t, but maybe you did that at
> the end of the series already <shrug>)

No, I don't think I did. Should be trivial to do, there's only 4 or
5 of them in use. I'll do it as a separate patch.

Cheers,

Dave.
-- 
Dave Chinner
david@fromorbit.com

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 01/22] xfs: move xfs_perag_get/put to xfs_ag.[ch]
  2021-05-10 12:52   ` Brian Foster
@ 2021-05-11  7:18     ` Dave Chinner
  0 siblings, 0 replies; 87+ messages in thread
From: Dave Chinner @ 2021-05-11  7:18 UTC (permalink / raw)
  To: Brian Foster; +Cc: linux-xfs

On Mon, May 10, 2021 at 08:52:56AM -0400, Brian Foster wrote:
> On Thu, May 06, 2021 at 05:20:33PM +1000, Dave Chinner wrote:
> > From: Dave Chinner <dchinner@redhat.com>
> > 
> > They are AG functions, not superblock functions, so move them to the
> > appropriate location.
> > 
> > Signed-off-by: Dave Chinner <dchinner@redhat.com>
> > ---
> ...
> > 
> > diff --git a/fs/xfs/libxfs/xfs_ag.c b/fs/xfs/libxfs/xfs_ag.c
> > index c68a36688474..2ca31dc46fe8 100644
> > --- a/fs/xfs/libxfs/xfs_ag.c
> > +++ b/fs/xfs/libxfs/xfs_ag.c
> > @@ -27,6 +27,141 @@
> >  #include "xfs_defer.h"
> >  #include "xfs_log_format.h"
> >  #include "xfs_trans.h"
> > +#include "xfs_trace.h"
> 
> The corresponding xfs_trace.h include can now be removed from
> libxfs/xfs_sb.c. Otherwise looks like a straightforward move:

fixed.
-- 
Dave Chinner
david@fromorbit.com

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 02/22] xfs: prepare for moving perag definitions and support to libxfs
  2021-05-10 12:53   ` Brian Foster
@ 2021-05-11  7:19     ` Dave Chinner
  0 siblings, 0 replies; 87+ messages in thread
From: Dave Chinner @ 2021-05-11  7:19 UTC (permalink / raw)
  To: Brian Foster; +Cc: linux-xfs

On Mon, May 10, 2021 at 08:53:28AM -0400, Brian Foster wrote:
> On Thu, May 06, 2021 at 05:20:34PM +1000, Dave Chinner wrote:
> > From: Dave Chinner <dchinner@redhat.com>
> > 
> > The perag structures really need to be defined with the rest of the
> > AG support infrastructure. The struct xfs_perag and init/teardown
> > has been placed in xfs_mount.[ch] because there are differences in
> > the structure between kernel and userspace. Mainly that userspace
> > doesn't have a lot of the internal stuff that the kernel has for
> > caches and discard and other such structures.
> > 
> > However, it makes more sense to move this to libxfs than to keep
> > this separation because we are now moving to use struct perags
> > everywhere in the code instead of passing raw agnumber_t values
> > about. Hence we shoudl really move the support infrastructure to
> > libxfs/xfs_ag.[ch].
> > 
> > To do this without breaking userspace, first we need to rearrange
> > the structures and code so that all the kernel specific code is
> > located together. This makes it simple for userspace to ifdef out
> > the all the parts it does not need, minimising the code differences
> > between kernel and userspace. The next commit will do the move...
> > 
> > Signed-off-by: Dave Chinner <dchinner@redhat.com>
> > ---
> >  fs/xfs/xfs_mount.c | 50 ++++++++++++++++++++++++++--------------------
> >  fs/xfs/xfs_mount.h | 19 +++++++++---------
> >  2 files changed, 38 insertions(+), 31 deletions(-)
> > 
> > diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c
> > index 21c630dde476..2e6d42014346 100644
> > --- a/fs/xfs/xfs_mount.c
> > +++ b/fs/xfs/xfs_mount.c
> ...
> > @@ -229,13 +220,27 @@ xfs_initialize_perag(
> >  		}
> >  		spin_unlock(&mp->m_perag_lock);
> >  		radix_tree_preload_end();
> > -		/* first new pag is fully initialized */
> > -		if (first_initialised == NULLAGNUMBER)
> > -			first_initialised = index;
> > +
> > +		spin_lock_init(&pag->pag_ici_lock);
> > +		spin_lock_init(&pag->pagb_lock);
> > +		spin_lock_init(&pag->pag_state_lock);
> > +		INIT_DELAYED_WORK(&pag->pag_blockgc_work, xfs_blockgc_worker);
> > +		INIT_RADIX_TREE(&pag->pag_ici_root, GFP_ATOMIC);
> > +		init_waitqueue_head(&pag->pagb_wait);
> > +		pag->pagb_count = 0;
> > +		pag->pagb_tree = RB_ROOT;
> > +
> > +		error = xfs_buf_hash_init(pag);
> > +		if (error)
> > +			goto out_free_pag;
> > +
> 
> There's error handling code earlier up in this function that still lands
> in out_hash_destroy, which is now before we get to the _hash_init()
> call.
> 
> >  		error = xfs_iunlink_init(pag);
> >  		if (error)
> >  			goto out_hash_destroy;
> > -		spin_lock_init(&pag->pag_state_lock);
> > +
> > +		/* first new pag is fully initialized */
> > +		if (first_initialised == NULLAGNUMBER)
> > +			first_initialised = index;
> >  	}
> >  
> >  	index = xfs_set_inode_alloc(mp, agcount);
> > @@ -249,6 +254,7 @@ xfs_initialize_perag(
> >  out_hash_destroy:
> >  	xfs_buf_hash_destroy(pag);
> >  out_free_pag:
> > +	pag = radix_tree_delete(&mp->m_perag_tree, index);
> 
> Now if we get here with an allocated pag that hasn't been inserted to
> the tree, I suspect this call would assign pag = NULL..

Yup, error handling was fubar. Fixed now.

-- 
Dave Chinner
david@fromorbit.com

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 04/22] xfs: make for_each_perag... a first class citizen
  2021-05-10 12:53   ` Brian Foster
@ 2021-05-11  7:35     ` Dave Chinner
  2021-05-11 12:29       ` Brian Foster
  0 siblings, 1 reply; 87+ messages in thread
From: Dave Chinner @ 2021-05-11  7:35 UTC (permalink / raw)
  To: Brian Foster; +Cc: linux-xfs

On Mon, May 10, 2021 at 08:53:56AM -0400, Brian Foster wrote:
> On Thu, May 06, 2021 at 05:20:36PM +1000, Dave Chinner wrote:
> > From: Dave Chinner <dchinner@redhat.com>
> > 
> > for_each_perag_tag() is defined in xfs_icache.c for local use.
> > Promote this to xfs_ag.h and define equivalent iteration functions
> > so that we can use them to iterate AGs instead to replace open coded
> > perag walks and perag lookups.
> > 
> > We also convert as many of the straight forward open coded AG walks
> > to use these iterators as possible. Anything that is not a direct
> > conversion to an iterator is ignored and will be updated in future
> > commits.
> > 
> > Signed-off-by: Dave Chinner <dchinner@redhat.com>
> > ---
> >  fs/xfs/libxfs/xfs_ag.h    | 17 +++++++++++++++++
> >  fs/xfs/scrub/fscounters.c | 36 ++++++++++++++----------------------
> >  fs/xfs/xfs_extent_busy.c  |  7 ++-----
> >  fs/xfs/xfs_fsops.c        |  8 ++------
> >  fs/xfs/xfs_health.c       |  4 +---
> >  fs/xfs/xfs_icache.c       | 15 ++-------------
> >  6 files changed, 38 insertions(+), 49 deletions(-)
> > 
> ...
> > diff --git a/fs/xfs/scrub/fscounters.c b/fs/xfs/scrub/fscounters.c
> > index 453ae9adf94c..2dfdac566399 100644
> > --- a/fs/xfs/scrub/fscounters.c
> > +++ b/fs/xfs/scrub/fscounters.c
> ...
> > @@ -229,12 +224,9 @@ xchk_fscount_aggregate_agcounts(
> >  		fsc->fdblocks -= pag->pag_meta_resv.ar_reserved;
> >  		fsc->fdblocks -= pag->pag_rmapbt_resv.ar_orig_reserved;
> >  
> > -		xfs_perag_put(pag);
> > -
> > -		if (xchk_should_terminate(sc, &error))
> > -			break;
> >  	}
> > -
> > +	if (pag)
> > +		xfs_perag_put(pag);
> 
> It's not shown in the diff, but there is still an exit path out of the
> above loop that calls xfs_perag_put(). The rest of the patch LGTM.

Good spot. Fixed.

FWIW, I'm not entirely happy with the way the iterator can break and
require conditional cleanup. I'm thinking that I'll come back to
these and convert them to a iterator structure that will turn this
into the pattern:

	perag_iter_init(&iter, start_agno, end_agno);
	for_each_perag(pag, iter) {
		....
	}
	perag_iter_done(&iter);

and so the code doesn't need to care about whether it exits the loop
via a break or running out of perags to iterate. I haven't fully
thought this through, though, so I'm leaving it alone for now...

-Dave.

PS - ain't english great? thought, through, though: look the same,
sound completely different...
-- 
Dave Chinner
david@fromorbit.com

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 04/22] xfs: make for_each_perag... a first class citizen
  2021-05-11  7:35     ` Dave Chinner
@ 2021-05-11 12:29       ` Brian Foster
  2021-05-11 21:33         ` Dave Chinner
  0 siblings, 1 reply; 87+ messages in thread
From: Brian Foster @ 2021-05-11 12:29 UTC (permalink / raw)
  To: Dave Chinner; +Cc: linux-xfs

On Tue, May 11, 2021 at 05:35:19PM +1000, Dave Chinner wrote:
> On Mon, May 10, 2021 at 08:53:56AM -0400, Brian Foster wrote:
> > On Thu, May 06, 2021 at 05:20:36PM +1000, Dave Chinner wrote:
> > > From: Dave Chinner <dchinner@redhat.com>
> > > 
> > > for_each_perag_tag() is defined in xfs_icache.c for local use.
> > > Promote this to xfs_ag.h and define equivalent iteration functions
> > > so that we can use them to iterate AGs instead to replace open coded
> > > perag walks and perag lookups.
> > > 
> > > We also convert as many of the straight forward open coded AG walks
> > > to use these iterators as possible. Anything that is not a direct
> > > conversion to an iterator is ignored and will be updated in future
> > > commits.
> > > 
> > > Signed-off-by: Dave Chinner <dchinner@redhat.com>
> > > ---
> > >  fs/xfs/libxfs/xfs_ag.h    | 17 +++++++++++++++++
> > >  fs/xfs/scrub/fscounters.c | 36 ++++++++++++++----------------------
> > >  fs/xfs/xfs_extent_busy.c  |  7 ++-----
> > >  fs/xfs/xfs_fsops.c        |  8 ++------
> > >  fs/xfs/xfs_health.c       |  4 +---
> > >  fs/xfs/xfs_icache.c       | 15 ++-------------
> > >  6 files changed, 38 insertions(+), 49 deletions(-)
> > > 
> > ...
> > > diff --git a/fs/xfs/scrub/fscounters.c b/fs/xfs/scrub/fscounters.c
> > > index 453ae9adf94c..2dfdac566399 100644
> > > --- a/fs/xfs/scrub/fscounters.c
> > > +++ b/fs/xfs/scrub/fscounters.c
> > ...
> > > @@ -229,12 +224,9 @@ xchk_fscount_aggregate_agcounts(
> > >  		fsc->fdblocks -= pag->pag_meta_resv.ar_reserved;
> > >  		fsc->fdblocks -= pag->pag_rmapbt_resv.ar_orig_reserved;
> > >  
> > > -		xfs_perag_put(pag);
> > > -
> > > -		if (xchk_should_terminate(sc, &error))
> > > -			break;
> > >  	}
> > > -
> > > +	if (pag)
> > > +		xfs_perag_put(pag);
> > 
> > It's not shown in the diff, but there is still an exit path out of the
> > above loop that calls xfs_perag_put(). The rest of the patch LGTM.
> 
> Good spot. Fixed.
> 
> FWIW, I'm not entirely happy with the way the iterator can break and
> require conditional cleanup. I'm thinking that I'll come back to
> these and convert them to a iterator structure that will turn this
> into the pattern:
> 
> 	perag_iter_init(&iter, start_agno, end_agno);
> 	for_each_perag(pag, iter) {
> 		....
> 	}
> 	perag_iter_done(&iter);
> 
> and so the code doesn't need to care about whether it exits the loop
> via a break or running out of perags to iterate. I haven't fully
> thought this through, though, so I'm leaving it alone for now...
> 

I think something like that would be an improvement. It's
straightforward enough to follow through these changes with the loop
break quirk in mind, but I suspect that somebody modifying (and/or
reviewing) related code farther in the future might very easily miss
something like an external put being required if a loop is modified to
break out early.

Brian

> -Dave.
> 
> PS - ain't english great? thought, through, though: look the same,
> sound completely different...
> -- 
> Dave Chinner
> david@fromorbit.com
> 


^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 08/22] xfs: pass perags through to the busy extent code
  2021-05-06  7:20 ` [PATCH 08/22] xfs: pass perags through to the busy extent code Dave Chinner
@ 2021-05-11 12:29   ` Brian Foster
  2021-05-12 22:13   ` Darrick J. Wong
  1 sibling, 0 replies; 87+ messages in thread
From: Brian Foster @ 2021-05-11 12:29 UTC (permalink / raw)
  To: Dave Chinner; +Cc: linux-xfs

On Thu, May 06, 2021 at 05:20:40PM +1000, Dave Chinner wrote:
> From: Dave Chinner <dchinner@redhat.com>
> 
> All of the callers of the busy extent API either have perag
> references available to use so we can pass a perag to the busy
> extent functions rather than having them have to do unnecessary
> lookups.
> 
> Signed-off-by: Dave Chinner <dchinner@redhat.com>
> ---

Reviewed-by: Brian Foster <bfoster@redhat.com>

>  fs/xfs/libxfs/xfs_alloc.c       | 37 +++++++++++++++++----------------
>  fs/xfs/libxfs/xfs_alloc.h       |  2 +-
>  fs/xfs/libxfs/xfs_alloc_btree.c |  5 ++---
>  fs/xfs/libxfs/xfs_rmap.c        | 32 ++++++++++++++++------------
>  fs/xfs/libxfs/xfs_rmap_btree.c  |  7 +++----
>  fs/xfs/scrub/repair.c           |  4 ++--
>  fs/xfs/xfs_discard.c            |  2 +-
>  fs/xfs/xfs_extent_busy.c        | 24 ++++++---------------
>  fs/xfs/xfs_extent_busy.h        |  7 ++++---
>  9 files changed, 57 insertions(+), 63 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_alloc.c b/fs/xfs/libxfs/xfs_alloc.c
> index dc2b77829915..ce31c00dbf6f 100644
> --- a/fs/xfs/libxfs/xfs_alloc.c
> +++ b/fs/xfs/libxfs/xfs_alloc.c
> @@ -1063,7 +1063,7 @@ xfs_alloc_ag_vextent_small(
>  	if (fbno == NULLAGBLOCK)
>  		goto out;
>  
> -	xfs_extent_busy_reuse(args->mp, args->agno, fbno, 1,
> +	xfs_extent_busy_reuse(args->mp, args->pag, fbno, 1,
>  			      (args->datatype & XFS_ALLOC_NOBUSY));
>  
>  	if (args->datatype & XFS_ALLOC_USERDATA) {
> @@ -1178,7 +1178,7 @@ xfs_alloc_ag_vextent(
>  		if (error)
>  			return error;
>  
> -		ASSERT(!xfs_extent_busy_search(args->mp, args->agno,
> +		ASSERT(!xfs_extent_busy_search(args->mp, args->pag,
>  					      args->agbno, args->len));
>  	}
>  
> @@ -3292,7 +3292,7 @@ xfs_alloc_vextent(
>  int
>  xfs_free_extent_fix_freelist(
>  	struct xfs_trans	*tp,
> -	xfs_agnumber_t		agno,
> +	struct xfs_perag	*pag,
>  	struct xfs_buf		**agbp)
>  {
>  	struct xfs_alloc_arg	args;
> @@ -3301,7 +3301,8 @@ xfs_free_extent_fix_freelist(
>  	memset(&args, 0, sizeof(struct xfs_alloc_arg));
>  	args.tp = tp;
>  	args.mp = tp->t_mountp;
> -	args.agno = agno;
> +	args.agno = pag->pag_agno;
> +	args.pag = pag;
>  
>  	/*
>  	 * validate that the block number is legal - the enables us to detect
> @@ -3310,17 +3311,12 @@ xfs_free_extent_fix_freelist(
>  	if (args.agno >= args.mp->m_sb.sb_agcount)
>  		return -EFSCORRUPTED;
>  
> -	args.pag = xfs_perag_get(args.mp, args.agno);
> -	ASSERT(args.pag);
> -
>  	error = xfs_alloc_fix_freelist(&args, XFS_ALLOC_FLAG_FREEING);
>  	if (error)
> -		goto out;
> +		return error;
>  
>  	*agbp = args.agbp;
> -out:
> -	xfs_perag_put(args.pag);
> -	return error;
> +	return 0;
>  }
>  
>  /*
> @@ -3344,6 +3340,7 @@ __xfs_free_extent(
>  	struct xfs_agf			*agf;
>  	int				error;
>  	unsigned int			busy_flags = 0;
> +	struct xfs_perag		*pag;
>  
>  	ASSERT(len != 0);
>  	ASSERT(type != XFS_AG_RESV_AGFL);
> @@ -3352,33 +3349,37 @@ __xfs_free_extent(
>  			XFS_ERRTAG_FREE_EXTENT))
>  		return -EIO;
>  
> -	error = xfs_free_extent_fix_freelist(tp, agno, &agbp);
> +	pag = xfs_perag_get(mp, agno);
> +	error = xfs_free_extent_fix_freelist(tp, pag, &agbp);
>  	if (error)
> -		return error;
> +		goto err;
>  	agf = agbp->b_addr;
>  
>  	if (XFS_IS_CORRUPT(mp, agbno >= mp->m_sb.sb_agblocks)) {
>  		error = -EFSCORRUPTED;
> -		goto err;
> +		goto err_release;
>  	}
>  
>  	/* validate the extent size is legal now we have the agf locked */
>  	if (XFS_IS_CORRUPT(mp, agbno + len > be32_to_cpu(agf->agf_length))) {
>  		error = -EFSCORRUPTED;
> -		goto err;
> +		goto err_release;
>  	}
>  
>  	error = xfs_free_ag_extent(tp, agbp, agno, agbno, len, oinfo, type);
>  	if (error)
> -		goto err;
> +		goto err_release;
>  
>  	if (skip_discard)
>  		busy_flags |= XFS_EXTENT_BUSY_SKIP_DISCARD;
> -	xfs_extent_busy_insert(tp, agno, agbno, len, busy_flags);
> +	xfs_extent_busy_insert(tp, pag, agbno, len, busy_flags);
> +	xfs_perag_put(pag);
>  	return 0;
>  
> -err:
> +err_release:
>  	xfs_trans_brelse(tp, agbp);
> +err:
> +	xfs_perag_put(pag);
>  	return error;
>  }
>  
> diff --git a/fs/xfs/libxfs/xfs_alloc.h b/fs/xfs/libxfs/xfs_alloc.h
> index a4427c5775c2..e30900b6f8ba 100644
> --- a/fs/xfs/libxfs/xfs_alloc.h
> +++ b/fs/xfs/libxfs/xfs_alloc.h
> @@ -214,7 +214,7 @@ int xfs_alloc_read_agfl(struct xfs_mount *mp, struct xfs_trans *tp,
>  int xfs_free_agfl_block(struct xfs_trans *, xfs_agnumber_t, xfs_agblock_t,
>  			struct xfs_buf *, struct xfs_owner_info *);
>  int xfs_alloc_fix_freelist(struct xfs_alloc_arg *args, int flags);
> -int xfs_free_extent_fix_freelist(struct xfs_trans *tp, xfs_agnumber_t agno,
> +int xfs_free_extent_fix_freelist(struct xfs_trans *tp, struct xfs_perag *pag,
>  		struct xfs_buf **agbp);
>  
>  xfs_extlen_t xfs_prealloc_blocks(struct xfs_mount *mp);
> diff --git a/fs/xfs/libxfs/xfs_alloc_btree.c b/fs/xfs/libxfs/xfs_alloc_btree.c
> index a540b6e799e0..19fdf87e86b9 100644
> --- a/fs/xfs/libxfs/xfs_alloc_btree.c
> +++ b/fs/xfs/libxfs/xfs_alloc_btree.c
> @@ -72,7 +72,7 @@ xfs_allocbt_alloc_block(
>  	}
>  
>  	atomic64_inc(&cur->bc_mp->m_allocbt_blks);
> -	xfs_extent_busy_reuse(cur->bc_mp, cur->bc_ag.agno, bno, 1, false);
> +	xfs_extent_busy_reuse(cur->bc_mp, cur->bc_ag.agbp->b_pag, bno, 1, false);
>  
>  	new->s = cpu_to_be32(bno);
>  
> @@ -86,7 +86,6 @@ xfs_allocbt_free_block(
>  	struct xfs_buf		*bp)
>  {
>  	struct xfs_buf		*agbp = cur->bc_ag.agbp;
> -	struct xfs_agf		*agf = agbp->b_addr;
>  	xfs_agblock_t		bno;
>  	int			error;
>  
> @@ -96,7 +95,7 @@ xfs_allocbt_free_block(
>  		return error;
>  
>  	atomic64_dec(&cur->bc_mp->m_allocbt_blks);
> -	xfs_extent_busy_insert(cur->bc_tp, be32_to_cpu(agf->agf_seqno), bno, 1,
> +	xfs_extent_busy_insert(cur->bc_tp, agbp->b_pag, bno, 1,
>  			      XFS_EXTENT_BUSY_SKIP_DISCARD);
>  	return 0;
>  }
> diff --git a/fs/xfs/libxfs/xfs_rmap.c b/fs/xfs/libxfs/xfs_rmap.c
> index 61e8f10436ac..1d0a6b686eea 100644
> --- a/fs/xfs/libxfs/xfs_rmap.c
> +++ b/fs/xfs/libxfs/xfs_rmap.c
> @@ -11,6 +11,7 @@
>  #include "xfs_trans_resv.h"
>  #include "xfs_bit.h"
>  #include "xfs_mount.h"
> +#include "xfs_sb.h"
>  #include "xfs_defer.h"
>  #include "xfs_btree.h"
>  #include "xfs_trans.h"
> @@ -2363,31 +2364,32 @@ xfs_rmap_finish_one(
>  	struct xfs_btree_cur		**pcur)
>  {
>  	struct xfs_mount		*mp = tp->t_mountp;
> +	struct xfs_perag		*pag;
>  	struct xfs_btree_cur		*rcur;
>  	struct xfs_buf			*agbp = NULL;
>  	int				error = 0;
> -	xfs_agnumber_t			agno;
>  	struct xfs_owner_info		oinfo;
>  	xfs_agblock_t			bno;
>  	bool				unwritten;
>  
> -	agno = XFS_FSB_TO_AGNO(mp, startblock);
> -	ASSERT(agno != NULLAGNUMBER);
> +	pag = xfs_perag_get(mp, XFS_FSB_TO_AGNO(mp, startblock));
>  	bno = XFS_FSB_TO_AGBNO(mp, startblock);
>  
> -	trace_xfs_rmap_deferred(mp, agno, type, bno, owner, whichfork,
> +	trace_xfs_rmap_deferred(mp, pag->pag_agno, type, bno, owner, whichfork,
>  			startoff, blockcount, state);
>  
> -	if (XFS_TEST_ERROR(false, mp,
> -			XFS_ERRTAG_RMAP_FINISH_ONE))
> -		return -EIO;
> +	if (XFS_TEST_ERROR(false, mp, XFS_ERRTAG_RMAP_FINISH_ONE)) {
> +		error = -EIO;
> +		goto out_drop;
> +	}
> +
>  
>  	/*
>  	 * If we haven't gotten a cursor or the cursor AG doesn't match
>  	 * the startblock, get one now.
>  	 */
>  	rcur = *pcur;
> -	if (rcur != NULL && rcur->bc_ag.agno != agno) {
> +	if (rcur != NULL && rcur->bc_ag.agno != pag->pag_agno) {
>  		xfs_rmap_finish_one_cleanup(tp, rcur, 0);
>  		rcur = NULL;
>  		*pcur = NULL;
> @@ -2398,13 +2400,15 @@ xfs_rmap_finish_one(
>  		 * rmapbt, because a shape change could cause us to
>  		 * allocate blocks.
>  		 */
> -		error = xfs_free_extent_fix_freelist(tp, agno, &agbp);
> +		error = xfs_free_extent_fix_freelist(tp, pag, &agbp);
>  		if (error)
> -			return error;
> -		if (XFS_IS_CORRUPT(tp->t_mountp, !agbp))
> -			return -EFSCORRUPTED;
> +			goto out_drop;
> +		if (XFS_IS_CORRUPT(tp->t_mountp, !agbp)) {
> +			error = -EFSCORRUPTED;
> +			goto out_drop;
> +		}
>  
> -		rcur = xfs_rmapbt_init_cursor(mp, tp, agbp, agno);
> +		rcur = xfs_rmapbt_init_cursor(mp, tp, agbp, pag->pag_agno);
>  	}
>  	*pcur = rcur;
>  
> @@ -2442,6 +2446,8 @@ xfs_rmap_finish_one(
>  		ASSERT(0);
>  		error = -EFSCORRUPTED;
>  	}
> +out_drop:
> +	xfs_perag_put(pag);
>  	return error;
>  }
>  
> diff --git a/fs/xfs/libxfs/xfs_rmap_btree.c b/fs/xfs/libxfs/xfs_rmap_btree.c
> index f1fee42dda2d..46a5295ecf35 100644
> --- a/fs/xfs/libxfs/xfs_rmap_btree.c
> +++ b/fs/xfs/libxfs/xfs_rmap_btree.c
> @@ -100,8 +100,7 @@ xfs_rmapbt_alloc_block(
>  		return 0;
>  	}
>  
> -	xfs_extent_busy_reuse(cur->bc_mp, cur->bc_ag.agno, bno, 1,
> -			false);
> +	xfs_extent_busy_reuse(cur->bc_mp, agbp->b_pag, bno, 1, false);
>  
>  	new->s = cpu_to_be32(bno);
>  	be32_add_cpu(&agf->agf_rmap_blocks, 1);
> @@ -133,10 +132,10 @@ xfs_rmapbt_free_block(
>  	if (error)
>  		return error;
>  
> -	xfs_extent_busy_insert(cur->bc_tp, be32_to_cpu(agf->agf_seqno), bno, 1,
> +	pag = cur->bc_ag.agbp->b_pag;
> +	xfs_extent_busy_insert(cur->bc_tp, pag, bno, 1,
>  			      XFS_EXTENT_BUSY_SKIP_DISCARD);
>  
> -	pag = cur->bc_ag.agbp->b_pag;
>  	xfs_ag_resv_free_extent(pag, XFS_AG_RESV_RMAPBT, NULL, 1);
>  	return 0;
>  }
> diff --git a/fs/xfs/scrub/repair.c b/fs/xfs/scrub/repair.c
> index 1308b62a8170..6b62872c4d10 100644
> --- a/fs/xfs/scrub/repair.c
> +++ b/fs/xfs/scrub/repair.c
> @@ -304,7 +304,7 @@ xrep_alloc_ag_block(
>  			return error;
>  		if (bno == NULLAGBLOCK)
>  			return -ENOSPC;
> -		xfs_extent_busy_reuse(sc->mp, sc->sa.agno, bno,
> +		xfs_extent_busy_reuse(sc->mp, sc->sa.pag, bno,
>  				1, false);
>  		*fsbno = XFS_AGB_TO_FSB(sc->mp, sc->sa.agno, bno);
>  		if (resv == XFS_AG_RESV_RMAPBT)
> @@ -519,7 +519,7 @@ xrep_put_freelist(
>  			agbno, 0);
>  	if (error)
>  		return error;
> -	xfs_extent_busy_insert(sc->tp, sc->sa.agno, agbno, 1,
> +	xfs_extent_busy_insert(sc->tp, sc->sa.pag, agbno, 1,
>  			XFS_EXTENT_BUSY_SKIP_DISCARD);
>  
>  	return 0;
> diff --git a/fs/xfs/xfs_discard.c b/fs/xfs/xfs_discard.c
> index 3bf6dba1a040..972864250bd2 100644
> --- a/fs/xfs/xfs_discard.c
> +++ b/fs/xfs/xfs_discard.c
> @@ -108,7 +108,7 @@ xfs_trim_extents(
>  		 * If any blocks in the range are still busy, skip the
>  		 * discard and try again the next time.
>  		 */
> -		if (xfs_extent_busy_search(mp, agno, fbno, flen)) {
> +		if (xfs_extent_busy_search(mp, pag, fbno, flen)) {
>  			trace_xfs_discard_busy(mp, agno, fbno, flen);
>  			goto next_extent;
>  		}
> diff --git a/fs/xfs/xfs_extent_busy.c b/fs/xfs/xfs_extent_busy.c
> index 6af0b5a1c7b0..a0ea63fcc50d 100644
> --- a/fs/xfs/xfs_extent_busy.c
> +++ b/fs/xfs/xfs_extent_busy.c
> @@ -22,28 +22,26 @@
>  void
>  xfs_extent_busy_insert(
>  	struct xfs_trans	*tp,
> -	xfs_agnumber_t		agno,
> +	struct xfs_perag	*pag,
>  	xfs_agblock_t		bno,
>  	xfs_extlen_t		len,
>  	unsigned int		flags)
>  {
>  	struct xfs_extent_busy	*new;
>  	struct xfs_extent_busy	*busyp;
> -	struct xfs_perag	*pag;
>  	struct rb_node		**rbp;
>  	struct rb_node		*parent = NULL;
>  
>  	new = kmem_zalloc(sizeof(struct xfs_extent_busy), 0);
> -	new->agno = agno;
> +	new->agno = pag->pag_agno;
>  	new->bno = bno;
>  	new->length = len;
>  	INIT_LIST_HEAD(&new->list);
>  	new->flags = flags;
>  
>  	/* trace before insert to be able to see failed inserts */
> -	trace_xfs_extent_busy(tp->t_mountp, agno, bno, len);
> +	trace_xfs_extent_busy(tp->t_mountp, pag->pag_agno, bno, len);
>  
> -	pag = xfs_perag_get(tp->t_mountp, new->agno);
>  	spin_lock(&pag->pagb_lock);
>  	rbp = &pag->pagb_tree.rb_node;
>  	while (*rbp) {
> @@ -66,7 +64,6 @@ xfs_extent_busy_insert(
>  
>  	list_add(&new->list, &tp->t_busy);
>  	spin_unlock(&pag->pagb_lock);
> -	xfs_perag_put(pag);
>  }
>  
>  /*
> @@ -81,21 +78,17 @@ xfs_extent_busy_insert(
>  int
>  xfs_extent_busy_search(
>  	struct xfs_mount	*mp,
> -	xfs_agnumber_t		agno,
> +	struct xfs_perag	*pag,
>  	xfs_agblock_t		bno,
>  	xfs_extlen_t		len)
>  {
> -	struct xfs_perag	*pag;
>  	struct rb_node		*rbp;
>  	struct xfs_extent_busy	*busyp;
>  	int			match = 0;
>  
> -	pag = xfs_perag_get(mp, agno);
> +	/* find closest start bno overlap */
>  	spin_lock(&pag->pagb_lock);
> -
>  	rbp = pag->pagb_tree.rb_node;
> -
> -	/* find closest start bno overlap */
>  	while (rbp) {
>  		busyp = rb_entry(rbp, struct xfs_extent_busy, rb_node);
>  		if (bno < busyp->bno) {
> @@ -115,7 +108,6 @@ xfs_extent_busy_search(
>  		}
>  	}
>  	spin_unlock(&pag->pagb_lock);
> -	xfs_perag_put(pag);
>  	return match;
>  }
>  
> @@ -281,17 +273,14 @@ xfs_extent_busy_update_extent(
>  void
>  xfs_extent_busy_reuse(
>  	struct xfs_mount	*mp,
> -	xfs_agnumber_t		agno,
> +	struct xfs_perag	*pag,
>  	xfs_agblock_t		fbno,
>  	xfs_extlen_t		flen,
>  	bool			userdata)
>  {
> -	struct xfs_perag	*pag;
>  	struct rb_node		*rbp;
>  
>  	ASSERT(flen > 0);
> -
> -	pag = xfs_perag_get(mp, agno);
>  	spin_lock(&pag->pagb_lock);
>  restart:
>  	rbp = pag->pagb_tree.rb_node;
> @@ -314,7 +303,6 @@ xfs_extent_busy_reuse(
>  			goto restart;
>  	}
>  	spin_unlock(&pag->pagb_lock);
> -	xfs_perag_put(pag);
>  }
>  
>  /*
> diff --git a/fs/xfs/xfs_extent_busy.h b/fs/xfs/xfs_extent_busy.h
> index 990ab3891971..8031617bb6ef 100644
> --- a/fs/xfs/xfs_extent_busy.h
> +++ b/fs/xfs/xfs_extent_busy.h
> @@ -9,6 +9,7 @@
>  #define	__XFS_EXTENT_BUSY_H__
>  
>  struct xfs_mount;
> +struct xfs_perag;
>  struct xfs_trans;
>  struct xfs_alloc_arg;
>  
> @@ -31,7 +32,7 @@ struct xfs_extent_busy {
>  };
>  
>  void
> -xfs_extent_busy_insert(struct xfs_trans *tp, xfs_agnumber_t agno,
> +xfs_extent_busy_insert(struct xfs_trans *tp, struct xfs_perag *pag,
>  	xfs_agblock_t bno, xfs_extlen_t len, unsigned int flags);
>  
>  void
> @@ -39,11 +40,11 @@ xfs_extent_busy_clear(struct xfs_mount *mp, struct list_head *list,
>  	bool do_discard);
>  
>  int
> -xfs_extent_busy_search(struct xfs_mount *mp, xfs_agnumber_t agno,
> +xfs_extent_busy_search(struct xfs_mount *mp, struct xfs_perag *pag,
>  	xfs_agblock_t bno, xfs_extlen_t len);
>  
>  void
> -xfs_extent_busy_reuse(struct xfs_mount *mp, xfs_agnumber_t agno,
> +xfs_extent_busy_reuse(struct xfs_mount *mp, struct xfs_perag *pag,
>  	xfs_agblock_t fbno, xfs_extlen_t flen, bool userdata);
>  
>  bool
> -- 
> 2.31.1
> 


^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 09/22] xfs: push perags through the ag reservation callouts
  2021-05-06  7:20 ` [PATCH 09/22] xfs: push perags through the ag reservation callouts Dave Chinner
@ 2021-05-11 12:29   ` Brian Foster
  2021-05-13  0:29     ` Dave Chinner
  2021-05-12 22:16   ` Darrick J. Wong
  1 sibling, 1 reply; 87+ messages in thread
From: Brian Foster @ 2021-05-11 12:29 UTC (permalink / raw)
  To: Dave Chinner; +Cc: linux-xfs

On Thu, May 06, 2021 at 05:20:41PM +1000, Dave Chinner wrote:
> From: Dave Chinner <dchinner@redhat.com>
> 
> We currently pass an agno from the AG reservation functions to the
> individual feature accounting functions, which then may have to do
> perag lookups to access per-AG state. Plumb the perag through from
> the highest AG reservation layer to the feature callouts so they
> don't have to look it up again.
> 
> Signed-off-by: Dave Chinner <dchinner@redhat.com>
> ---

The changes look fine, but the commit log implies we're relieving some
lower level functions of the need to re-look up perag structs. I don't
see one perag get/put cycle being removed here, so I suppose either that
comes later or the commit log is a bit misleading..? Either way, with a
minor reword of the commit log to clarify that, this otherwise looks
fine to me.

Brian

>  fs/xfs/libxfs/xfs_ag_resv.c        |  9 ++++-----
>  fs/xfs/libxfs/xfs_ialloc_btree.c   | 17 +++++++++--------
>  fs/xfs/libxfs/xfs_ialloc_btree.h   |  2 +-
>  fs/xfs/libxfs/xfs_refcount_btree.c |  7 +++----
>  fs/xfs/libxfs/xfs_refcount_btree.h |  3 ++-
>  fs/xfs/libxfs/xfs_rmap_btree.c     |  6 +++---
>  fs/xfs/libxfs/xfs_rmap_btree.h     |  2 +-
>  7 files changed, 23 insertions(+), 23 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_ag_resv.c b/fs/xfs/libxfs/xfs_ag_resv.c
> index 2e3dcdfd4984..f7394a8ecf6b 100644
> --- a/fs/xfs/libxfs/xfs_ag_resv.c
> +++ b/fs/xfs/libxfs/xfs_ag_resv.c
> @@ -250,7 +250,6 @@ xfs_ag_resv_init(
>  	struct xfs_trans		*tp)
>  {
>  	struct xfs_mount		*mp = pag->pag_mount;
> -	xfs_agnumber_t			agno = pag->pag_agno;
>  	xfs_extlen_t			ask;
>  	xfs_extlen_t			used;
>  	int				error = 0, error2;
> @@ -260,11 +259,11 @@ xfs_ag_resv_init(
>  	if (pag->pag_meta_resv.ar_asked == 0) {
>  		ask = used = 0;
>  
> -		error = xfs_refcountbt_calc_reserves(mp, tp, agno, &ask, &used);
> +		error = xfs_refcountbt_calc_reserves(mp, tp, pag, &ask, &used);
>  		if (error)
>  			goto out;
>  
> -		error = xfs_finobt_calc_reserves(mp, tp, agno, &ask, &used);
> +		error = xfs_finobt_calc_reserves(mp, tp, pag, &ask, &used);
>  		if (error)
>  			goto out;
>  
> @@ -282,7 +281,7 @@ xfs_ag_resv_init(
>  
>  			mp->m_finobt_nores = true;
>  
> -			error = xfs_refcountbt_calc_reserves(mp, tp, agno, &ask,
> +			error = xfs_refcountbt_calc_reserves(mp, tp, pag, &ask,
>  					&used);
>  			if (error)
>  				goto out;
> @@ -300,7 +299,7 @@ xfs_ag_resv_init(
>  	if (pag->pag_rmapbt_resv.ar_asked == 0) {
>  		ask = used = 0;
>  
> -		error = xfs_rmapbt_calc_reserves(mp, tp, agno, &ask, &used);
> +		error = xfs_rmapbt_calc_reserves(mp, tp, pag, &ask, &used);
>  		if (error)
>  			goto out;
>  
> diff --git a/fs/xfs/libxfs/xfs_ialloc_btree.c b/fs/xfs/libxfs/xfs_ialloc_btree.c
> index 4c5831646bd9..4ec8ea1331a5 100644
> --- a/fs/xfs/libxfs/xfs_ialloc_btree.c
> +++ b/fs/xfs/libxfs/xfs_ialloc_btree.c
> @@ -20,6 +20,7 @@
>  #include "xfs_trace.h"
>  #include "xfs_trans.h"
>  #include "xfs_rmap.h"
> +#include "xfs_ag.h"
>  
>  STATIC int
>  xfs_inobt_get_minrecs(
> @@ -680,7 +681,7 @@ static int
>  xfs_inobt_count_blocks(
>  	struct xfs_mount	*mp,
>  	struct xfs_trans	*tp,
> -	xfs_agnumber_t		agno,
> +	struct xfs_perag	*pag,
>  	xfs_btnum_t		btnum,
>  	xfs_extlen_t		*tree_blocks)
>  {
> @@ -688,7 +689,7 @@ xfs_inobt_count_blocks(
>  	struct xfs_btree_cur	*cur = NULL;
>  	int			error;
>  
> -	error = xfs_inobt_cur(mp, tp, agno, btnum, &cur, &agbp);
> +	error = xfs_inobt_cur(mp, tp, pag->pag_agno, btnum, &cur, &agbp);
>  	if (error)
>  		return error;
>  
> @@ -704,14 +705,14 @@ static int
>  xfs_finobt_read_blocks(
>  	struct xfs_mount	*mp,
>  	struct xfs_trans	*tp,
> -	xfs_agnumber_t		agno,
> +	struct xfs_perag	*pag,
>  	xfs_extlen_t		*tree_blocks)
>  {
>  	struct xfs_buf		*agbp;
>  	struct xfs_agi		*agi;
>  	int			error;
>  
> -	error = xfs_ialloc_read_agi(mp, tp, agno, &agbp);
> +	error = xfs_ialloc_read_agi(mp, tp, pag->pag_agno, &agbp);
>  	if (error)
>  		return error;
>  
> @@ -728,7 +729,7 @@ int
>  xfs_finobt_calc_reserves(
>  	struct xfs_mount	*mp,
>  	struct xfs_trans	*tp,
> -	xfs_agnumber_t		agno,
> +	struct xfs_perag	*pag,
>  	xfs_extlen_t		*ask,
>  	xfs_extlen_t		*used)
>  {
> @@ -739,14 +740,14 @@ xfs_finobt_calc_reserves(
>  		return 0;
>  
>  	if (xfs_sb_version_hasinobtcounts(&mp->m_sb))
> -		error = xfs_finobt_read_blocks(mp, tp, agno, &tree_len);
> +		error = xfs_finobt_read_blocks(mp, tp, pag, &tree_len);
>  	else
> -		error = xfs_inobt_count_blocks(mp, tp, agno, XFS_BTNUM_FINO,
> +		error = xfs_inobt_count_blocks(mp, tp, pag, XFS_BTNUM_FINO,
>  				&tree_len);
>  	if (error)
>  		return error;
>  
> -	*ask += xfs_inobt_max_size(mp, agno);
> +	*ask += xfs_inobt_max_size(mp, pag->pag_agno);
>  	*used += tree_len;
>  	return 0;
>  }
> diff --git a/fs/xfs/libxfs/xfs_ialloc_btree.h b/fs/xfs/libxfs/xfs_ialloc_btree.h
> index 35bbd978c272..d5afe01fb2de 100644
> --- a/fs/xfs/libxfs/xfs_ialloc_btree.h
> +++ b/fs/xfs/libxfs/xfs_ialloc_btree.h
> @@ -64,7 +64,7 @@ int xfs_inobt_rec_check_count(struct xfs_mount *,
>  #endif	/* DEBUG */
>  
>  int xfs_finobt_calc_reserves(struct xfs_mount *mp, struct xfs_trans *tp,
> -		xfs_agnumber_t agno, xfs_extlen_t *ask, xfs_extlen_t *used);
> +		struct xfs_perag *pag, xfs_extlen_t *ask, xfs_extlen_t *used);
>  extern xfs_extlen_t xfs_iallocbt_calc_size(struct xfs_mount *mp,
>  		unsigned long long len);
>  int xfs_inobt_cur(struct xfs_mount *mp, struct xfs_trans *tp,
> diff --git a/fs/xfs/libxfs/xfs_refcount_btree.c b/fs/xfs/libxfs/xfs_refcount_btree.c
> index b281f0c674f5..c4ddf9ded00b 100644
> --- a/fs/xfs/libxfs/xfs_refcount_btree.c
> +++ b/fs/xfs/libxfs/xfs_refcount_btree.c
> @@ -450,7 +450,7 @@ int
>  xfs_refcountbt_calc_reserves(
>  	struct xfs_mount	*mp,
>  	struct xfs_trans	*tp,
> -	xfs_agnumber_t		agno,
> +	struct xfs_perag	*pag,
>  	xfs_extlen_t		*ask,
>  	xfs_extlen_t		*used)
>  {
> @@ -463,8 +463,7 @@ xfs_refcountbt_calc_reserves(
>  	if (!xfs_sb_version_hasreflink(&mp->m_sb))
>  		return 0;
>  
> -
> -	error = xfs_alloc_read_agf(mp, tp, agno, 0, &agbp);
> +	error = xfs_alloc_read_agf(mp, tp, pag->pag_agno, 0, &agbp);
>  	if (error)
>  		return error;
>  
> @@ -479,7 +478,7 @@ xfs_refcountbt_calc_reserves(
>  	 * expansion.  We therefore can pretend the space isn't there.
>  	 */
>  	if (mp->m_sb.sb_logstart &&
> -	    XFS_FSB_TO_AGNO(mp, mp->m_sb.sb_logstart) == agno)
> +	    XFS_FSB_TO_AGNO(mp, mp->m_sb.sb_logstart) == pag->pag_agno)
>  		agblocks -= mp->m_sb.sb_logblocks;
>  
>  	*ask += xfs_refcountbt_max_size(mp, agblocks);
> diff --git a/fs/xfs/libxfs/xfs_refcount_btree.h b/fs/xfs/libxfs/xfs_refcount_btree.h
> index 69dc515db671..eab1b0c672c0 100644
> --- a/fs/xfs/libxfs/xfs_refcount_btree.h
> +++ b/fs/xfs/libxfs/xfs_refcount_btree.h
> @@ -13,6 +13,7 @@
>  struct xfs_buf;
>  struct xfs_btree_cur;
>  struct xfs_mount;
> +struct xfs_perag;
>  struct xbtree_afakeroot;
>  
>  /*
> @@ -58,7 +59,7 @@ extern xfs_extlen_t xfs_refcountbt_max_size(struct xfs_mount *mp,
>  		xfs_agblock_t agblocks);
>  
>  extern int xfs_refcountbt_calc_reserves(struct xfs_mount *mp,
> -		struct xfs_trans *tp, xfs_agnumber_t agno, xfs_extlen_t *ask,
> +		struct xfs_trans *tp, struct xfs_perag *pag, xfs_extlen_t *ask,
>  		xfs_extlen_t *used);
>  
>  void xfs_refcountbt_commit_staged_btree(struct xfs_btree_cur *cur,
> diff --git a/fs/xfs/libxfs/xfs_rmap_btree.c b/fs/xfs/libxfs/xfs_rmap_btree.c
> index 46a5295ecf35..ba2f7064451b 100644
> --- a/fs/xfs/libxfs/xfs_rmap_btree.c
> +++ b/fs/xfs/libxfs/xfs_rmap_btree.c
> @@ -595,7 +595,7 @@ int
>  xfs_rmapbt_calc_reserves(
>  	struct xfs_mount	*mp,
>  	struct xfs_trans	*tp,
> -	xfs_agnumber_t		agno,
> +	struct xfs_perag	*pag,
>  	xfs_extlen_t		*ask,
>  	xfs_extlen_t		*used)
>  {
> @@ -608,7 +608,7 @@ xfs_rmapbt_calc_reserves(
>  	if (!xfs_sb_version_hasrmapbt(&mp->m_sb))
>  		return 0;
>  
> -	error = xfs_alloc_read_agf(mp, tp, agno, 0, &agbp);
> +	error = xfs_alloc_read_agf(mp, tp, pag->pag_agno, 0, &agbp);
>  	if (error)
>  		return error;
>  
> @@ -623,7 +623,7 @@ xfs_rmapbt_calc_reserves(
>  	 * expansion.  We therefore can pretend the space isn't there.
>  	 */
>  	if (mp->m_sb.sb_logstart &&
> -	    XFS_FSB_TO_AGNO(mp, mp->m_sb.sb_logstart) == agno)
> +	    XFS_FSB_TO_AGNO(mp, mp->m_sb.sb_logstart) == pag->pag_agno)
>  		agblocks -= mp->m_sb.sb_logblocks;
>  
>  	/* Reserve 1% of the AG or enough for 1 block per record. */
> diff --git a/fs/xfs/libxfs/xfs_rmap_btree.h b/fs/xfs/libxfs/xfs_rmap_btree.h
> index 115c3455a734..57fab72e26ad 100644
> --- a/fs/xfs/libxfs/xfs_rmap_btree.h
> +++ b/fs/xfs/libxfs/xfs_rmap_btree.h
> @@ -57,6 +57,6 @@ extern xfs_extlen_t xfs_rmapbt_max_size(struct xfs_mount *mp,
>  		xfs_agblock_t agblocks);
>  
>  extern int xfs_rmapbt_calc_reserves(struct xfs_mount *mp, struct xfs_trans *tp,
> -		xfs_agnumber_t agno, xfs_extlen_t *ask, xfs_extlen_t *used);
> +		struct xfs_perag *pag, xfs_extlen_t *ask, xfs_extlen_t *used);
>  
>  #endif	/* __XFS_RMAP_BTREE_H__ */
> -- 
> 2.31.1
> 


^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 10/22] xfs: pass perags around in fsmap data dev functions
  2021-05-06  7:20 ` [PATCH 10/22] xfs: pass perags around in fsmap data dev functions Dave Chinner
@ 2021-05-11 12:30   ` Brian Foster
  2021-05-12 22:23   ` Darrick J. Wong
  1 sibling, 0 replies; 87+ messages in thread
From: Brian Foster @ 2021-05-11 12:30 UTC (permalink / raw)
  To: Dave Chinner; +Cc: linux-xfs

On Thu, May 06, 2021 at 05:20:42PM +1000, Dave Chinner wrote:
> From: Dave Chinner <dchinner@redhat.com>
> 
> Needs a [from, to] ranged AG walk, and the perag to be stuffed into
> the info structure for callouts to use.
> 
> Signed-off-by: Dave Chinner <dchinner@redhat.com>
> ---
>  fs/xfs/libxfs/xfs_ag.h | 14 ++++++--
>  fs/xfs/xfs_fsmap.c     | 75 ++++++++++++++++++++++++++----------------
>  2 files changed, 58 insertions(+), 31 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_ag.h b/fs/xfs/libxfs/xfs_ag.h
> index 3fa88222dacd..bebbe1bfce27 100644
> --- a/fs/xfs/libxfs/xfs_ag.h
> +++ b/fs/xfs/libxfs/xfs_ag.h
> @@ -116,14 +116,24 @@ void	xfs_perag_put(struct xfs_perag *pag);
>  
>  /*
>   * Perag iteration APIs
> + *
> + * XXX: for_each_perag_range() usage really needs an iterator to clean up when
> + * we terminate at end_agno because we may have taken a reference to the perag
> + * beyond end_agno. RIght now callers have to be careful to catch and clean that
> + * up themselves. This is not necessary for the callers of for_each_perag() and
> + * for_each_perag_from() because they terminate at sb_agcount where there are
> + * no perag structures in tree beyond end_agno.
>   */
> -#define for_each_perag_from(mp, next_agno, pag) \
> +#define for_each_perag_range(mp, next_agno, end_agno, pag) \
>  	for ((pag) = xfs_perag_get((mp), (next_agno)); \
> -		(pag) != NULL; \
> +		(pag) != NULL && (next_agno) <= (end_agno); \
>  		(next_agno) = (pag)->pag_agno + 1, \
>  		xfs_perag_put(pag), \
>  		(pag) = xfs_perag_get((mp), (next_agno)))
>  
> +#define for_each_perag_from(mp, next_agno, pag) \
> +	for_each_perag_range((mp), (next_agno), (mp)->m_sb.sb_agcount, (pag))
> +

It definitely would be nice to have some kind of abstraction for the
proper setup/teardown of these iterators, as described in the earlier
patch. Otherwise this looks fine to me for now:

Reviewed-by: Brian Foster <bfoster@redhat.com>

>  #define for_each_perag(mp, next_agno, pag) \
>  	(next_agno) = 0; \
>  	for_each_perag_from((mp), (next_agno), (pag))
> diff --git a/fs/xfs/xfs_fsmap.c b/fs/xfs/xfs_fsmap.c
> index 34f2b971ce43..835dd6e3819b 100644
> --- a/fs/xfs/xfs_fsmap.c
> +++ b/fs/xfs/xfs_fsmap.c
> @@ -24,6 +24,7 @@
>  #include "xfs_refcount_btree.h"
>  #include "xfs_alloc_btree.h"
>  #include "xfs_rtalloc.h"
> +#include "xfs_ag.h"
>  
>  /* Convert an xfs_fsmap to an fsmap. */
>  static void
> @@ -157,10 +158,10 @@ struct xfs_getfsmap_info {
>  	struct xfs_fsmap_head	*head;
>  	struct fsmap		*fsmap_recs;	/* mapping records */
>  	struct xfs_buf		*agf_bp;	/* AGF, for refcount queries */
> +	struct xfs_perag	*pag;		/* AG info, if applicable */
>  	xfs_daddr_t		next_daddr;	/* next daddr we expect */
>  	u64			missing_owner;	/* owner of holes */
>  	u32			dev;		/* device id */
> -	xfs_agnumber_t		agno;		/* AG number, if applicable */
>  	struct xfs_rmap_irec	low;		/* low rmap key */
>  	struct xfs_rmap_irec	high;		/* high rmap key */
>  	bool			last;		/* last extent? */
> @@ -203,14 +204,14 @@ xfs_getfsmap_is_shared(
>  	*stat = false;
>  	if (!xfs_sb_version_hasreflink(&mp->m_sb))
>  		return 0;
> -	/* rt files will have agno set to NULLAGNUMBER */
> -	if (info->agno == NULLAGNUMBER)
> +	/* rt files will have no perag structure */
> +	if (!info->pag)
>  		return 0;
>  
>  	/* Are there any shared blocks here? */
>  	flen = 0;
>  	cur = xfs_refcountbt_init_cursor(mp, tp, info->agf_bp,
> -			info->agno);
> +			info->pag->pag_agno);
>  
>  	error = xfs_refcount_find_shared(cur, rec->rm_startblock,
>  			rec->rm_blockcount, &fbno, &flen, false);
> @@ -311,7 +312,8 @@ xfs_getfsmap_helper(
>  	if (info->head->fmh_entries >= info->head->fmh_count)
>  		return -ECANCELED;
>  
> -	trace_xfs_fsmap_mapping(mp, info->dev, info->agno, rec);
> +	trace_xfs_fsmap_mapping(mp, info->dev,
> +			info->pag ? info->pag->pag_agno : NULLAGNUMBER, rec);
>  
>  	fmr.fmr_device = info->dev;
>  	fmr.fmr_physical = rec_daddr;
> @@ -429,8 +431,8 @@ xfs_getfsmap_logdev(
>  	info->high.rm_flags = XFS_RMAP_KEY_FLAGS | XFS_RMAP_REC_FLAGS;
>  	info->missing_owner = XFS_FMR_OWN_FREE;
>  
> -	trace_xfs_fsmap_low_key(mp, info->dev, info->agno, &info->low);
> -	trace_xfs_fsmap_high_key(mp, info->dev, info->agno, &info->high);
> +	trace_xfs_fsmap_low_key(mp, info->dev, NULLAGNUMBER, &info->low);
> +	trace_xfs_fsmap_high_key(mp, info->dev, NULLAGNUMBER, &info->high);
>  
>  	if (keys[0].fmr_physical > 0)
>  		return 0;
> @@ -508,8 +510,8 @@ __xfs_getfsmap_rtdev(
>  	info->high.rm_blockcount = 0;
>  	xfs_getfsmap_set_irec_flags(&info->high, &keys[1]);
>  
> -	trace_xfs_fsmap_low_key(mp, info->dev, info->agno, &info->low);
> -	trace_xfs_fsmap_high_key(mp, info->dev, info->agno, &info->high);
> +	trace_xfs_fsmap_low_key(mp, info->dev, NULLAGNUMBER, &info->low);
> +	trace_xfs_fsmap_high_key(mp, info->dev, NULLAGNUMBER, &info->high);
>  
>  	return query_fn(tp, info);
>  }
> @@ -572,6 +574,7 @@ __xfs_getfsmap_datadev(
>  	void				*priv)
>  {
>  	struct xfs_mount		*mp = tp->t_mountp;
> +	struct xfs_perag		*pag;
>  	struct xfs_btree_cur		*bt_cur = NULL;
>  	xfs_fsblock_t			start_fsb;
>  	xfs_fsblock_t			end_fsb;
> @@ -610,20 +613,20 @@ __xfs_getfsmap_datadev(
>  	start_ag = XFS_FSB_TO_AGNO(mp, start_fsb);
>  	end_ag = XFS_FSB_TO_AGNO(mp, end_fsb);
>  
> -	/* Query each AG */
> -	for (info->agno = start_ag; info->agno <= end_ag; info->agno++) {
> +	for_each_perag_range(mp, start_ag, end_ag, pag) {
>  		/*
>  		 * Set the AG high key from the fsmap high key if this
>  		 * is the last AG that we're querying.
>  		 */
> -		if (info->agno == end_ag) {
> +		info->pag = pag;
> +		if (pag->pag_agno == end_ag) {
>  			info->high.rm_startblock = XFS_FSB_TO_AGBNO(mp,
>  					end_fsb);
>  			info->high.rm_offset = XFS_BB_TO_FSBT(mp,
>  					keys[1].fmr_offset);
>  			error = xfs_fsmap_owner_to_rmap(&info->high, &keys[1]);
>  			if (error)
> -				goto err;
> +				break;
>  			xfs_getfsmap_set_irec_flags(&info->high, &keys[1]);
>  		}
>  
> @@ -634,38 +637,45 @@ __xfs_getfsmap_datadev(
>  			info->agf_bp = NULL;
>  		}
>  
> -		error = xfs_alloc_read_agf(mp, tp, info->agno, 0,
> +		error = xfs_alloc_read_agf(mp, tp, pag->pag_agno, 0,
>  				&info->agf_bp);
>  		if (error)
> -			goto err;
> +			break;
>  
> -		trace_xfs_fsmap_low_key(mp, info->dev, info->agno, &info->low);
> -		trace_xfs_fsmap_high_key(mp, info->dev, info->agno,
> +		trace_xfs_fsmap_low_key(mp, info->dev, pag->pag_agno,
> +				&info->low);
> +		trace_xfs_fsmap_high_key(mp, info->dev, pag->pag_agno,
>  				&info->high);
>  
>  		error = query_fn(tp, info, &bt_cur, priv);
>  		if (error)
> -			goto err;
> +			break;
>  
>  		/*
>  		 * Set the AG low key to the start of the AG prior to
>  		 * moving on to the next AG.
>  		 */
> -		if (info->agno == start_ag) {
> +		if (pag->pag_agno == start_ag) {
>  			info->low.rm_startblock = 0;
>  			info->low.rm_owner = 0;
>  			info->low.rm_offset = 0;
>  			info->low.rm_flags = 0;
>  		}
> -	}
>  
> -	/* Report any gap at the end of the AG */
> -	info->last = true;
> -	error = query_fn(tp, info, &bt_cur, priv);
> -	if (error)
> -		goto err;
> +		/*
> +		 * If this is the last AG, report any gap at the end of it
> +		 * before we drop the reference to the perag when the loop
> +		 * terminates.
> +		 */
> +		if (pag->pag_agno == end_ag) {
> +			info->last = true;
> +			error = query_fn(tp, info, &bt_cur, priv);
> +			if (error)
> +				break;
> +		}
> +		info->pag = NULL;
> +	}
>  
> -err:
>  	if (bt_cur)
>  		xfs_btree_del_cursor(bt_cur, error < 0 ? XFS_BTREE_ERROR :
>  							 XFS_BTREE_NOERROR);
> @@ -673,6 +683,13 @@ __xfs_getfsmap_datadev(
>  		xfs_trans_brelse(tp, info->agf_bp);
>  		info->agf_bp = NULL;
>  	}
> +	if (info->pag) {
> +		xfs_perag_put(info->pag);
> +		info->pag = NULL;
> +	} else if (pag) {
> +		/* loop termination case */
> +		xfs_perag_put(pag);
> +	}
>  
>  	return error;
>  }
> @@ -691,7 +708,7 @@ xfs_getfsmap_datadev_rmapbt_query(
>  
>  	/* Allocate cursor for this AG and query_range it. */
>  	*curpp = xfs_rmapbt_init_cursor(tp->t_mountp, tp, info->agf_bp,
> -			info->agno);
> +			info->pag->pag_agno);
>  	return xfs_rmap_query_range(*curpp, &info->low, &info->high,
>  			xfs_getfsmap_datadev_helper, info);
>  }
> @@ -724,7 +741,7 @@ xfs_getfsmap_datadev_bnobt_query(
>  
>  	/* Allocate cursor for this AG and query_range it. */
>  	*curpp = xfs_allocbt_init_cursor(tp->t_mountp, tp, info->agf_bp,
> -			info->agno, XFS_BTNUM_BNO);
> +			info->pag->pag_agno, XFS_BTNUM_BNO);
>  	key->ar_startblock = info->low.rm_startblock;
>  	key[1].ar_startblock = info->high.rm_startblock;
>  	return xfs_alloc_query_range(*curpp, key, &key[1],
> @@ -937,7 +954,7 @@ xfs_getfsmap(
>  
>  		info.dev = handlers[i].dev;
>  		info.last = false;
> -		info.agno = NULLAGNUMBER;
> +		info.pag = NULL;
>  		error = handlers[i].fn(tp, dkeys, &info);
>  		if (error)
>  			break;
> -- 
> 2.31.1
> 


^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 11/22] xfs: add a perag to the btree cursor
  2021-05-06  7:20 ` [PATCH 11/22] xfs: add a perag to the btree cursor Dave Chinner
@ 2021-05-11 12:30   ` Brian Foster
  2021-05-11 20:51     ` Darrick J. Wong
  2021-05-12 22:40   ` Darrick J. Wong
  1 sibling, 1 reply; 87+ messages in thread
From: Brian Foster @ 2021-05-11 12:30 UTC (permalink / raw)
  To: Dave Chinner; +Cc: linux-xfs

On Thu, May 06, 2021 at 05:20:43PM +1000, Dave Chinner wrote:
> From: Dave Chinner <dchinner@redhat.com>
> 
> Which will eventually completely replace the agno in it.
> 
> Signed-off-by: Dave Chinner <dchinner@redhat.com>
> ---
>  fs/xfs/libxfs/xfs_alloc.c          | 25 +++++++++++++++----------
>  fs/xfs/libxfs/xfs_alloc_btree.c    | 13 ++++++++++---
>  fs/xfs/libxfs/xfs_alloc_btree.h    |  3 ++-
>  fs/xfs/libxfs/xfs_btree.c          |  2 ++
>  fs/xfs/libxfs/xfs_btree.h          |  4 +++-
>  fs/xfs/libxfs/xfs_ialloc.c         | 16 ++++++++--------
>  fs/xfs/libxfs/xfs_ialloc_btree.c   | 15 +++++++++++----
>  fs/xfs/libxfs/xfs_ialloc_btree.h   |  7 ++++---
>  fs/xfs/libxfs/xfs_refcount.c       |  4 ++--
>  fs/xfs/libxfs/xfs_refcount_btree.c | 17 ++++++++++++-----
>  fs/xfs/libxfs/xfs_refcount_btree.h |  2 +-
>  fs/xfs/libxfs/xfs_rmap.c           |  6 +++---
>  fs/xfs/libxfs/xfs_rmap_btree.c     | 17 ++++++++++++-----
>  fs/xfs/libxfs/xfs_rmap_btree.h     |  2 +-
>  fs/xfs/scrub/agheader_repair.c     | 20 +++++++++++---------
>  fs/xfs/scrub/bmap.c                |  2 +-
>  fs/xfs/scrub/common.c              | 12 ++++++------
>  fs/xfs/scrub/repair.c              |  5 +++--
>  fs/xfs/xfs_discard.c               |  2 +-
>  fs/xfs/xfs_fsmap.c                 |  6 +++---
>  fs/xfs/xfs_reflink.c               |  2 +-
>  21 files changed, 112 insertions(+), 70 deletions(-)
> 
...
> diff --git a/fs/xfs/libxfs/xfs_btree.c b/fs/xfs/libxfs/xfs_btree.c
> index 0f12b885600d..44044317c0fb 100644
> --- a/fs/xfs/libxfs/xfs_btree.c
> +++ b/fs/xfs/libxfs/xfs_btree.c
> @@ -377,6 +377,8 @@ xfs_btree_del_cursor(
>  	       XFS_FORCED_SHUTDOWN(cur->bc_mp));
>  	if (unlikely(cur->bc_flags & XFS_BTREE_STAGING))
>  		kmem_free(cur->bc_ops);
> +	if (!(cur->bc_flags & XFS_BTREE_LONG_PTRS) && cur->bc_ag.pag)
> +		xfs_perag_put(cur->bc_ag.pag);

What's the correlation with BTREE_LONG_PTRS?

Brian

>  	kmem_cache_free(xfs_btree_cur_zone, cur);
>  }
>  
> diff --git a/fs/xfs/libxfs/xfs_btree.h b/fs/xfs/libxfs/xfs_btree.h
> index 10e50cbacacf..8233f8679ba9 100644
> --- a/fs/xfs/libxfs/xfs_btree.h
> +++ b/fs/xfs/libxfs/xfs_btree.h
> @@ -11,6 +11,7 @@ struct xfs_inode;
>  struct xfs_mount;
>  struct xfs_trans;
>  struct xfs_ifork;
> +struct xfs_perag;
>  
>  extern kmem_zone_t	*xfs_btree_cur_zone;
>  
> @@ -180,11 +181,12 @@ union xfs_btree_irec {
>  
>  /* Per-AG btree information. */
>  struct xfs_btree_cur_ag {
> +	xfs_agnumber_t		agno;
> +	struct xfs_perag	*pag;
>  	union {
>  		struct xfs_buf		*agbp;
>  		struct xbtree_afakeroot	*afake;	/* for staging cursor */
>  	};
> -	xfs_agnumber_t		agno;
>  	union {
>  		struct {
>  			unsigned long nr_ops;	/* # record updates */
> diff --git a/fs/xfs/libxfs/xfs_ialloc.c b/fs/xfs/libxfs/xfs_ialloc.c
> index 8dc9225a5353..905872bab426 100644
> --- a/fs/xfs/libxfs/xfs_ialloc.c
> +++ b/fs/xfs/libxfs/xfs_ialloc.c
> @@ -183,7 +183,7 @@ xfs_inobt_insert(
>  	int			i;
>  	int			error;
>  
> -	cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, btnum);
> +	cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, NULL, btnum);
>  
>  	for (thisino = newino;
>  	     thisino < newino + newlen;
> @@ -531,7 +531,7 @@ xfs_inobt_insert_sprec(
>  	int				i;
>  	struct xfs_inobt_rec_incore	rec;
>  
> -	cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, btnum);
> +	cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, NULL, btnum);
>  
>  	/* the new record is pre-aligned so we know where to look */
>  	error = xfs_inobt_lookup(cur, nrec->ir_startino, XFS_LOOKUP_EQ, &i);
> @@ -1145,7 +1145,7 @@ xfs_dialloc_ag_inobt(
>  	ASSERT(pag->pagi_freecount > 0);
>  
>   restart_pagno:
> -	cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_INO);
> +	cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, NULL, XFS_BTNUM_INO);
>  	/*
>  	 * If pagino is 0 (this is the root inode allocation) use newino.
>  	 * This must work because we've just allocated some.
> @@ -1598,7 +1598,7 @@ xfs_dialloc_ag(
>  	if (!pagino)
>  		pagino = be32_to_cpu(agi->agi_newino);
>  
> -	cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_FINO);
> +	cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, NULL, XFS_BTNUM_FINO);
>  
>  	error = xfs_check_agi_freecount(cur, agi);
>  	if (error)
> @@ -1641,7 +1641,7 @@ xfs_dialloc_ag(
>  	 * the original freecount. If all is well, make the equivalent update to
>  	 * the inobt using the finobt record and offset information.
>  	 */
> -	icur = xfs_inobt_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_INO);
> +	icur = xfs_inobt_init_cursor(mp, tp, agbp, agno, NULL, XFS_BTNUM_INO);
>  
>  	error = xfs_check_agi_freecount(icur, agi);
>  	if (error)
> @@ -1954,7 +1954,7 @@ xfs_difree_inobt(
>  	/*
>  	 * Initialize the cursor.
>  	 */
> -	cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_INO);
> +	cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, NULL, XFS_BTNUM_INO);
>  
>  	error = xfs_check_agi_freecount(cur, agi);
>  	if (error)
> @@ -2080,7 +2080,7 @@ xfs_difree_finobt(
>  	int				error;
>  	int				i;
>  
> -	cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_FINO);
> +	cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, NULL, XFS_BTNUM_FINO);
>  
>  	error = xfs_inobt_lookup(cur, ibtrec->ir_startino, XFS_LOOKUP_EQ, &i);
>  	if (error)
> @@ -2281,7 +2281,7 @@ xfs_imap_lookup(
>  	 * we have a record, we need to ensure it contains the inode number
>  	 * we are looking up.
>  	 */
> -	cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_INO);
> +	cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, NULL, XFS_BTNUM_INO);
>  	error = xfs_inobt_lookup(cur, agino, XFS_LOOKUP_LE, &i);
>  	if (!error) {
>  		if (i)
> diff --git a/fs/xfs/libxfs/xfs_ialloc_btree.c b/fs/xfs/libxfs/xfs_ialloc_btree.c
> index 4ec8ea1331a5..6c4efdf01674 100644
> --- a/fs/xfs/libxfs/xfs_ialloc_btree.c
> +++ b/fs/xfs/libxfs/xfs_ialloc_btree.c
> @@ -36,7 +36,7 @@ xfs_inobt_dup_cursor(
>  {
>  	return xfs_inobt_init_cursor(cur->bc_mp, cur->bc_tp,
>  			cur->bc_ag.agbp, cur->bc_ag.agno,
> -			cur->bc_btnum);
> +			cur->bc_ag.pag, cur->bc_btnum);
>  }
>  
>  STATIC void
> @@ -429,6 +429,7 @@ xfs_inobt_init_common(
>  	struct xfs_mount	*mp,		/* file system mount point */
>  	struct xfs_trans	*tp,		/* transaction pointer */
>  	xfs_agnumber_t		agno,		/* allocation group number */
> +	struct xfs_perag	*pag,
>  	xfs_btnum_t		btnum)		/* ialloc or free ino btree */
>  {
>  	struct xfs_btree_cur	*cur;
> @@ -451,6 +452,11 @@ xfs_inobt_init_common(
>  		cur->bc_flags |= XFS_BTREE_CRC_BLOCKS;
>  
>  	cur->bc_ag.agno = agno;
> +	if (pag) {
> +		/* take a reference for the cursor */
> +		atomic_inc(&pag->pag_ref);
> +	}
> +	cur->bc_ag.pag = pag;
>  	return cur;
>  }
>  
> @@ -461,12 +467,13 @@ xfs_inobt_init_cursor(
>  	struct xfs_trans	*tp,
>  	struct xfs_buf		*agbp,
>  	xfs_agnumber_t		agno,
> +	struct xfs_perag	*pag,
>  	xfs_btnum_t		btnum)
>  {
>  	struct xfs_btree_cur	*cur;
>  	struct xfs_agi		*agi = agbp->b_addr;
>  
> -	cur = xfs_inobt_init_common(mp, tp, agno, btnum);
> +	cur = xfs_inobt_init_common(mp, tp, agno, pag, btnum);
>  	if (btnum == XFS_BTNUM_INO)
>  		cur->bc_nlevels = be32_to_cpu(agi->agi_level);
>  	else
> @@ -485,7 +492,7 @@ xfs_inobt_stage_cursor(
>  {
>  	struct xfs_btree_cur	*cur;
>  
> -	cur = xfs_inobt_init_common(mp, NULL, agno, btnum);
> +	cur = xfs_inobt_init_common(mp, NULL, agno, NULL, btnum);
>  	xfs_btree_stage_afakeroot(cur, afake);
>  	return cur;
>  }
> @@ -672,7 +679,7 @@ xfs_inobt_cur(
>  	if (error)
>  		return error;
>  
> -	cur = xfs_inobt_init_cursor(mp, tp, *agi_bpp, agno, which);
> +	cur = xfs_inobt_init_cursor(mp, tp, *agi_bpp, agno, NULL, which);
>  	*curpp = cur;
>  	return 0;
>  }
> diff --git a/fs/xfs/libxfs/xfs_ialloc_btree.h b/fs/xfs/libxfs/xfs_ialloc_btree.h
> index d5afe01fb2de..04dfa7eee81f 100644
> --- a/fs/xfs/libxfs/xfs_ialloc_btree.h
> +++ b/fs/xfs/libxfs/xfs_ialloc_btree.h
> @@ -13,6 +13,7 @@
>  struct xfs_buf;
>  struct xfs_btree_cur;
>  struct xfs_mount;
> +struct xfs_perag;
>  
>  /*
>   * Btree block header size depends on a superblock flag.
> @@ -45,9 +46,9 @@ struct xfs_mount;
>  		 (maxrecs) * sizeof(xfs_inobt_key_t) + \
>  		 ((index) - 1) * sizeof(xfs_inobt_ptr_t)))
>  
> -extern struct xfs_btree_cur *xfs_inobt_init_cursor(struct xfs_mount *,
> -		struct xfs_trans *, struct xfs_buf *, xfs_agnumber_t,
> -		xfs_btnum_t);
> +extern struct xfs_btree_cur *xfs_inobt_init_cursor(struct xfs_mount *mp,
> +		struct xfs_trans *tp, struct xfs_buf *agbp, xfs_agnumber_t agno,
> +		struct xfs_perag *pag, xfs_btnum_t btnum);
>  struct xfs_btree_cur *xfs_inobt_stage_cursor(struct xfs_mount *mp,
>  		struct xbtree_afakeroot *afake, xfs_agnumber_t agno,
>  		xfs_btnum_t btnum);
> diff --git a/fs/xfs/libxfs/xfs_refcount.c b/fs/xfs/libxfs/xfs_refcount.c
> index 2037b9f23069..1c2bd2949d7d 100644
> --- a/fs/xfs/libxfs/xfs_refcount.c
> +++ b/fs/xfs/libxfs/xfs_refcount.c
> @@ -1178,7 +1178,7 @@ xfs_refcount_finish_one(
>  		if (error)
>  			return error;
>  
> -		rcur = xfs_refcountbt_init_cursor(mp, tp, agbp, agno);
> +		rcur = xfs_refcountbt_init_cursor(mp, tp, agbp, agno, NULL);
>  		rcur->bc_ag.refc.nr_ops = nr_ops;
>  		rcur->bc_ag.refc.shape_changes = shape_changes;
>  	}
> @@ -1707,7 +1707,7 @@ xfs_refcount_recover_cow_leftovers(
>  	error = xfs_alloc_read_agf(mp, tp, agno, 0, &agbp);
>  	if (error)
>  		goto out_trans;
> -	cur = xfs_refcountbt_init_cursor(mp, tp, agbp, agno);
> +	cur = xfs_refcountbt_init_cursor(mp, tp, agbp, agno, NULL);
>  
>  	/* Find all the leftover CoW staging extents. */
>  	memset(&low, 0, sizeof(low));
> diff --git a/fs/xfs/libxfs/xfs_refcount_btree.c b/fs/xfs/libxfs/xfs_refcount_btree.c
> index c4ddf9ded00b..74f8ac0209f1 100644
> --- a/fs/xfs/libxfs/xfs_refcount_btree.c
> +++ b/fs/xfs/libxfs/xfs_refcount_btree.c
> @@ -26,7 +26,7 @@ xfs_refcountbt_dup_cursor(
>  	struct xfs_btree_cur	*cur)
>  {
>  	return xfs_refcountbt_init_cursor(cur->bc_mp, cur->bc_tp,
> -			cur->bc_ag.agbp, cur->bc_ag.agno);
> +			cur->bc_ag.agbp, cur->bc_ag.agno, cur->bc_ag.pag);
>  }
>  
>  STATIC void
> @@ -316,7 +316,8 @@ static struct xfs_btree_cur *
>  xfs_refcountbt_init_common(
>  	struct xfs_mount	*mp,
>  	struct xfs_trans	*tp,
> -	xfs_agnumber_t		agno)
> +	xfs_agnumber_t		agno,
> +	struct xfs_perag	*pag)
>  {
>  	struct xfs_btree_cur	*cur;
>  
> @@ -332,6 +333,11 @@ xfs_refcountbt_init_common(
>  
>  	cur->bc_ag.agno = agno;
>  	cur->bc_flags |= XFS_BTREE_CRC_BLOCKS;
> +	if (pag) {
> +		/* take a reference for the cursor */
> +		atomic_inc(&pag->pag_ref);
> +	}
> +	cur->bc_ag.pag = pag;
>  
>  	cur->bc_ag.refc.nr_ops = 0;
>  	cur->bc_ag.refc.shape_changes = 0;
> @@ -345,12 +351,13 @@ xfs_refcountbt_init_cursor(
>  	struct xfs_mount	*mp,
>  	struct xfs_trans	*tp,
>  	struct xfs_buf		*agbp,
> -	xfs_agnumber_t		agno)
> +	xfs_agnumber_t		agno,
> +	struct xfs_perag	*pag)
>  {
>  	struct xfs_agf		*agf = agbp->b_addr;
>  	struct xfs_btree_cur	*cur;
>  
> -	cur = xfs_refcountbt_init_common(mp, tp, agno);
> +	cur = xfs_refcountbt_init_common(mp, tp, agno, pag);
>  	cur->bc_nlevels = be32_to_cpu(agf->agf_refcount_level);
>  	cur->bc_ag.agbp = agbp;
>  	return cur;
> @@ -365,7 +372,7 @@ xfs_refcountbt_stage_cursor(
>  {
>  	struct xfs_btree_cur	*cur;
>  
> -	cur = xfs_refcountbt_init_common(mp, NULL, agno);
> +	cur = xfs_refcountbt_init_common(mp, NULL, agno, NULL);
>  	xfs_btree_stage_afakeroot(cur, afake);
>  	return cur;
>  }
> diff --git a/fs/xfs/libxfs/xfs_refcount_btree.h b/fs/xfs/libxfs/xfs_refcount_btree.h
> index eab1b0c672c0..8b82a39f104a 100644
> --- a/fs/xfs/libxfs/xfs_refcount_btree.h
> +++ b/fs/xfs/libxfs/xfs_refcount_btree.h
> @@ -47,7 +47,7 @@ struct xbtree_afakeroot;
>  
>  extern struct xfs_btree_cur *xfs_refcountbt_init_cursor(struct xfs_mount *mp,
>  		struct xfs_trans *tp, struct xfs_buf *agbp,
> -		xfs_agnumber_t agno);
> +		xfs_agnumber_t agno, struct xfs_perag *pag);
>  struct xfs_btree_cur *xfs_refcountbt_stage_cursor(struct xfs_mount *mp,
>  		struct xbtree_afakeroot *afake, xfs_agnumber_t agno);
>  extern int xfs_refcountbt_maxrecs(int blocklen, bool leaf);
> diff --git a/fs/xfs/libxfs/xfs_rmap.c b/fs/xfs/libxfs/xfs_rmap.c
> index 1d0a6b686eea..0d7a6997120c 100644
> --- a/fs/xfs/libxfs/xfs_rmap.c
> +++ b/fs/xfs/libxfs/xfs_rmap.c
> @@ -708,7 +708,7 @@ xfs_rmap_free(
>  	if (!xfs_sb_version_hasrmapbt(&mp->m_sb))
>  		return 0;
>  
> -	cur = xfs_rmapbt_init_cursor(mp, tp, agbp, agno);
> +	cur = xfs_rmapbt_init_cursor(mp, tp, agbp, agno, NULL);
>  
>  	error = xfs_rmap_unmap(cur, bno, len, false, oinfo);
>  
> @@ -962,7 +962,7 @@ xfs_rmap_alloc(
>  	if (!xfs_sb_version_hasrmapbt(&mp->m_sb))
>  		return 0;
>  
> -	cur = xfs_rmapbt_init_cursor(mp, tp, agbp, agno);
> +	cur = xfs_rmapbt_init_cursor(mp, tp, agbp, agno, NULL);
>  	error = xfs_rmap_map(cur, bno, len, false, oinfo);
>  
>  	xfs_btree_del_cursor(cur, error);
> @@ -2408,7 +2408,7 @@ xfs_rmap_finish_one(
>  			goto out_drop;
>  		}
>  
> -		rcur = xfs_rmapbt_init_cursor(mp, tp, agbp, pag->pag_agno);
> +		rcur = xfs_rmapbt_init_cursor(mp, tp, agbp, pag->pag_agno, pag);
>  	}
>  	*pcur = rcur;
>  
> diff --git a/fs/xfs/libxfs/xfs_rmap_btree.c b/fs/xfs/libxfs/xfs_rmap_btree.c
> index ba2f7064451b..7bef8feeded1 100644
> --- a/fs/xfs/libxfs/xfs_rmap_btree.c
> +++ b/fs/xfs/libxfs/xfs_rmap_btree.c
> @@ -52,7 +52,7 @@ xfs_rmapbt_dup_cursor(
>  	struct xfs_btree_cur	*cur)
>  {
>  	return xfs_rmapbt_init_cursor(cur->bc_mp, cur->bc_tp,
> -			cur->bc_ag.agbp, cur->bc_ag.agno);
> +			cur->bc_ag.agbp, cur->bc_ag.agno, cur->bc_ag.pag);
>  }
>  
>  STATIC void
> @@ -449,7 +449,8 @@ static struct xfs_btree_cur *
>  xfs_rmapbt_init_common(
>  	struct xfs_mount	*mp,
>  	struct xfs_trans	*tp,
> -	xfs_agnumber_t		agno)
> +	xfs_agnumber_t		agno,
> +	struct xfs_perag	*pag)
>  {
>  	struct xfs_btree_cur	*cur;
>  
> @@ -463,6 +464,11 @@ xfs_rmapbt_init_common(
>  	cur->bc_statoff = XFS_STATS_CALC_INDEX(xs_rmap_2);
>  	cur->bc_ag.agno = agno;
>  	cur->bc_ops = &xfs_rmapbt_ops;
> +	if (pag) {
> +		/* take a reference for the cursor */
> +		atomic_inc(&pag->pag_ref);
> +	}
> +	cur->bc_ag.pag = pag;
>  
>  	return cur;
>  }
> @@ -473,12 +479,13 @@ xfs_rmapbt_init_cursor(
>  	struct xfs_mount	*mp,
>  	struct xfs_trans	*tp,
>  	struct xfs_buf		*agbp,
> -	xfs_agnumber_t		agno)
> +	xfs_agnumber_t		agno,
> +	struct xfs_perag	*pag)
>  {
>  	struct xfs_agf		*agf = agbp->b_addr;
>  	struct xfs_btree_cur	*cur;
>  
> -	cur = xfs_rmapbt_init_common(mp, tp, agno);
> +	cur = xfs_rmapbt_init_common(mp, tp, agno, pag);
>  	cur->bc_nlevels = be32_to_cpu(agf->agf_levels[XFS_BTNUM_RMAP]);
>  	cur->bc_ag.agbp = agbp;
>  	return cur;
> @@ -493,7 +500,7 @@ xfs_rmapbt_stage_cursor(
>  {
>  	struct xfs_btree_cur	*cur;
>  
> -	cur = xfs_rmapbt_init_common(mp, NULL, agno);
> +	cur = xfs_rmapbt_init_common(mp, NULL, agno, NULL);
>  	xfs_btree_stage_afakeroot(cur, afake);
>  	return cur;
>  }
> diff --git a/fs/xfs/libxfs/xfs_rmap_btree.h b/fs/xfs/libxfs/xfs_rmap_btree.h
> index 57fab72e26ad..c94f418cc06b 100644
> --- a/fs/xfs/libxfs/xfs_rmap_btree.h
> +++ b/fs/xfs/libxfs/xfs_rmap_btree.h
> @@ -43,7 +43,7 @@ struct xbtree_afakeroot;
>  
>  struct xfs_btree_cur *xfs_rmapbt_init_cursor(struct xfs_mount *mp,
>  				struct xfs_trans *tp, struct xfs_buf *bp,
> -				xfs_agnumber_t agno);
> +				xfs_agnumber_t agno, struct xfs_perag *pag);
>  struct xfs_btree_cur *xfs_rmapbt_stage_cursor(struct xfs_mount *mp,
>  		struct xbtree_afakeroot *afake, xfs_agnumber_t agno);
>  void xfs_rmapbt_commit_staged_btree(struct xfs_btree_cur *cur,
> diff --git a/fs/xfs/scrub/agheader_repair.c b/fs/xfs/scrub/agheader_repair.c
> index 1cdfbd57f36b..5dd91bf04c18 100644
> --- a/fs/xfs/scrub/agheader_repair.c
> +++ b/fs/xfs/scrub/agheader_repair.c
> @@ -247,7 +247,7 @@ xrep_agf_calc_from_btrees(
>  
>  	/* Update the AGF counters from the bnobt. */
>  	cur = xfs_allocbt_init_cursor(mp, sc->tp, agf_bp, sc->sa.agno,
> -			XFS_BTNUM_BNO);
> +			sc->sa.pag, XFS_BTNUM_BNO);
>  	error = xfs_alloc_query_all(cur, xrep_agf_walk_allocbt, &raa);
>  	if (error)
>  		goto err;
> @@ -261,7 +261,7 @@ xrep_agf_calc_from_btrees(
>  
>  	/* Update the AGF counters from the cntbt. */
>  	cur = xfs_allocbt_init_cursor(mp, sc->tp, agf_bp, sc->sa.agno,
> -			XFS_BTNUM_CNT);
> +			sc->sa.pag, XFS_BTNUM_CNT);
>  	error = xfs_btree_count_blocks(cur, &blocks);
>  	if (error)
>  		goto err;
> @@ -269,7 +269,8 @@ xrep_agf_calc_from_btrees(
>  	btreeblks += blocks - 1;
>  
>  	/* Update the AGF counters from the rmapbt. */
> -	cur = xfs_rmapbt_init_cursor(mp, sc->tp, agf_bp, sc->sa.agno);
> +	cur = xfs_rmapbt_init_cursor(mp, sc->tp, agf_bp, sc->sa.agno,
> +			sc->sa.pag);
>  	error = xfs_btree_count_blocks(cur, &blocks);
>  	if (error)
>  		goto err;
> @@ -282,7 +283,7 @@ xrep_agf_calc_from_btrees(
>  	/* Update the AGF counters from the refcountbt. */
>  	if (xfs_sb_version_hasreflink(&mp->m_sb)) {
>  		cur = xfs_refcountbt_init_cursor(mp, sc->tp, agf_bp,
> -				sc->sa.agno);
> +				sc->sa.agno, sc->sa.pag);
>  		error = xfs_btree_count_blocks(cur, &blocks);
>  		if (error)
>  			goto err;
> @@ -490,7 +491,8 @@ xrep_agfl_collect_blocks(
>  	xbitmap_init(&ra.agmetablocks);
>  
>  	/* Find all space used by the free space btrees & rmapbt. */
> -	cur = xfs_rmapbt_init_cursor(mp, sc->tp, agf_bp, sc->sa.agno);
> +	cur = xfs_rmapbt_init_cursor(mp, sc->tp, agf_bp, sc->sa.agno,
> +			sc->sa.pag);
>  	error = xfs_rmap_query_all(cur, xrep_agfl_walk_rmap, &ra);
>  	if (error)
>  		goto err;
> @@ -498,7 +500,7 @@ xrep_agfl_collect_blocks(
>  
>  	/* Find all blocks currently being used by the bnobt. */
>  	cur = xfs_allocbt_init_cursor(mp, sc->tp, agf_bp, sc->sa.agno,
> -			XFS_BTNUM_BNO);
> +			sc->sa.pag, XFS_BTNUM_BNO);
>  	error = xbitmap_set_btblocks(&ra.agmetablocks, cur);
>  	if (error)
>  		goto err;
> @@ -506,7 +508,7 @@ xrep_agfl_collect_blocks(
>  
>  	/* Find all blocks currently being used by the cntbt. */
>  	cur = xfs_allocbt_init_cursor(mp, sc->tp, agf_bp, sc->sa.agno,
> -			XFS_BTNUM_CNT);
> +			sc->sa.pag, XFS_BTNUM_CNT);
>  	error = xbitmap_set_btblocks(&ra.agmetablocks, cur);
>  	if (error)
>  		goto err;
> @@ -807,7 +809,7 @@ xrep_agi_calc_from_btrees(
>  	int			error;
>  
>  	cur = xfs_inobt_init_cursor(mp, sc->tp, agi_bp, sc->sa.agno,
> -			XFS_BTNUM_INO);
> +			sc->sa.pag, XFS_BTNUM_INO);
>  	error = xfs_ialloc_count_inodes(cur, &count, &freecount);
>  	if (error)
>  		goto err;
> @@ -829,7 +831,7 @@ xrep_agi_calc_from_btrees(
>  		xfs_agblock_t	blocks;
>  
>  		cur = xfs_inobt_init_cursor(mp, sc->tp, agi_bp, sc->sa.agno,
> -				XFS_BTNUM_FINO);
> +				sc->sa.pag, XFS_BTNUM_FINO);
>  		error = xfs_btree_count_blocks(cur, &blocks);
>  		if (error)
>  			goto err;
> diff --git a/fs/xfs/scrub/bmap.c b/fs/xfs/scrub/bmap.c
> index c60a1990d629..a792d9ffd61e 100644
> --- a/fs/xfs/scrub/bmap.c
> +++ b/fs/xfs/scrub/bmap.c
> @@ -556,7 +556,7 @@ xchk_bmap_check_ag_rmaps(
>  	if (error)
>  		return error;
>  
> -	cur = xfs_rmapbt_init_cursor(sc->mp, sc->tp, agf, agno);
> +	cur = xfs_rmapbt_init_cursor(sc->mp, sc->tp, agf, agno, NULL);
>  
>  	sbcri.sc = sc;
>  	sbcri.whichfork = whichfork;
> diff --git a/fs/xfs/scrub/common.c b/fs/xfs/scrub/common.c
> index c8da976b50fc..50768559fb60 100644
> --- a/fs/xfs/scrub/common.c
> +++ b/fs/xfs/scrub/common.c
> @@ -465,42 +465,42 @@ xchk_ag_btcur_init(
>  	    xchk_ag_btree_healthy_enough(sc, sa->pag, XFS_BTNUM_BNO)) {
>  		/* Set up a bnobt cursor for cross-referencing. */
>  		sa->bno_cur = xfs_allocbt_init_cursor(mp, sc->tp, sa->agf_bp,
> -				agno, XFS_BTNUM_BNO);
> +				agno, sa->pag, XFS_BTNUM_BNO);
>  	}
>  
>  	if (sa->agf_bp &&
>  	    xchk_ag_btree_healthy_enough(sc, sa->pag, XFS_BTNUM_CNT)) {
>  		/* Set up a cntbt cursor for cross-referencing. */
>  		sa->cnt_cur = xfs_allocbt_init_cursor(mp, sc->tp, sa->agf_bp,
> -				agno, XFS_BTNUM_CNT);
> +				agno, sa->pag, XFS_BTNUM_CNT);
>  	}
>  
>  	/* Set up a inobt cursor for cross-referencing. */
>  	if (sa->agi_bp &&
>  	    xchk_ag_btree_healthy_enough(sc, sa->pag, XFS_BTNUM_INO)) {
>  		sa->ino_cur = xfs_inobt_init_cursor(mp, sc->tp, sa->agi_bp,
> -					agno, XFS_BTNUM_INO);
> +				agno, sa->pag, XFS_BTNUM_INO);
>  	}
>  
>  	/* Set up a finobt cursor for cross-referencing. */
>  	if (sa->agi_bp && xfs_sb_version_hasfinobt(&mp->m_sb) &&
>  	    xchk_ag_btree_healthy_enough(sc, sa->pag, XFS_BTNUM_FINO)) {
>  		sa->fino_cur = xfs_inobt_init_cursor(mp, sc->tp, sa->agi_bp,
> -				agno, XFS_BTNUM_FINO);
> +				agno, sa->pag, XFS_BTNUM_FINO);
>  	}
>  
>  	/* Set up a rmapbt cursor for cross-referencing. */
>  	if (sa->agf_bp && xfs_sb_version_hasrmapbt(&mp->m_sb) &&
>  	    xchk_ag_btree_healthy_enough(sc, sa->pag, XFS_BTNUM_RMAP)) {
>  		sa->rmap_cur = xfs_rmapbt_init_cursor(mp, sc->tp, sa->agf_bp,
> -				agno);
> +				agno, sa->pag);
>  	}
>  
>  	/* Set up a refcountbt cursor for cross-referencing. */
>  	if (sa->agf_bp && xfs_sb_version_hasreflink(&mp->m_sb) &&
>  	    xchk_ag_btree_healthy_enough(sc, sa->pag, XFS_BTNUM_REFC)) {
>  		sa->refc_cur = xfs_refcountbt_init_cursor(mp, sc->tp,
> -				sa->agf_bp, agno);
> +				sa->agf_bp, agno, sa->pag);
>  	}
>  }
>  
> diff --git a/fs/xfs/scrub/repair.c b/fs/xfs/scrub/repair.c
> index 6b62872c4d10..862dc56fd8cd 100644
> --- a/fs/xfs/scrub/repair.c
> +++ b/fs/xfs/scrub/repair.c
> @@ -555,7 +555,7 @@ xrep_reap_block(
>  	} else {
>  		agf_bp = sc->sa.agf_bp;
>  	}
> -	cur = xfs_rmapbt_init_cursor(sc->mp, sc->tp, agf_bp, agno);
> +	cur = xfs_rmapbt_init_cursor(sc->mp, sc->tp, agf_bp, agno, sc->sa.pag);
>  
>  	/* Can we find any other rmappings? */
>  	error = xfs_rmap_has_other_keys(cur, agbno, 1, oinfo, &has_other_rmap);
> @@ -892,7 +892,8 @@ xrep_find_ag_btree_roots(
>  		fab->height = 0;
>  	}
>  
> -	cur = xfs_rmapbt_init_cursor(mp, sc->tp, agf_bp, sc->sa.agno);
> +	cur = xfs_rmapbt_init_cursor(mp, sc->tp, agf_bp, sc->sa.agno,
> +			sc->sa.pag);
>  	error = xfs_rmap_query_all(cur, xrep_findroot_rmap, &ri);
>  	xfs_btree_del_cursor(cur, error);
>  
> diff --git a/fs/xfs/xfs_discard.c b/fs/xfs/xfs_discard.c
> index 972864250bd2..311ebaad4f5a 100644
> --- a/fs/xfs/xfs_discard.c
> +++ b/fs/xfs/xfs_discard.c
> @@ -50,7 +50,7 @@ xfs_trim_extents(
>  		goto out_put_perag;
>  	agf = agbp->b_addr;
>  
> -	cur = xfs_allocbt_init_cursor(mp, NULL, agbp, agno, XFS_BTNUM_CNT);
> +	cur = xfs_allocbt_init_cursor(mp, NULL, agbp, agno, pag, XFS_BTNUM_CNT);
>  
>  	/*
>  	 * Look up the longest btree in the AGF and start with it.
> diff --git a/fs/xfs/xfs_fsmap.c b/fs/xfs/xfs_fsmap.c
> index 835dd6e3819b..b654a2bf9a9f 100644
> --- a/fs/xfs/xfs_fsmap.c
> +++ b/fs/xfs/xfs_fsmap.c
> @@ -211,7 +211,7 @@ xfs_getfsmap_is_shared(
>  	/* Are there any shared blocks here? */
>  	flen = 0;
>  	cur = xfs_refcountbt_init_cursor(mp, tp, info->agf_bp,
> -			info->pag->pag_agno);
> +			info->pag->pag_agno, info->pag);
>  
>  	error = xfs_refcount_find_shared(cur, rec->rm_startblock,
>  			rec->rm_blockcount, &fbno, &flen, false);
> @@ -708,7 +708,7 @@ xfs_getfsmap_datadev_rmapbt_query(
>  
>  	/* Allocate cursor for this AG and query_range it. */
>  	*curpp = xfs_rmapbt_init_cursor(tp->t_mountp, tp, info->agf_bp,
> -			info->pag->pag_agno);
> +			info->pag->pag_agno, info->pag);
>  	return xfs_rmap_query_range(*curpp, &info->low, &info->high,
>  			xfs_getfsmap_datadev_helper, info);
>  }
> @@ -741,7 +741,7 @@ xfs_getfsmap_datadev_bnobt_query(
>  
>  	/* Allocate cursor for this AG and query_range it. */
>  	*curpp = xfs_allocbt_init_cursor(tp->t_mountp, tp, info->agf_bp,
> -			info->pag->pag_agno, XFS_BTNUM_BNO);
> +			info->pag->pag_agno, info->pag, XFS_BTNUM_BNO);
>  	key->ar_startblock = info->low.rm_startblock;
>  	key[1].ar_startblock = info->high.rm_startblock;
>  	return xfs_alloc_query_range(*curpp, key, &key[1],
> diff --git a/fs/xfs/xfs_reflink.c b/fs/xfs/xfs_reflink.c
> index 0e430b0c1b16..28ffe1817f9b 100644
> --- a/fs/xfs/xfs_reflink.c
> +++ b/fs/xfs/xfs_reflink.c
> @@ -144,7 +144,7 @@ xfs_reflink_find_shared(
>  	if (error)
>  		return error;
>  
> -	cur = xfs_refcountbt_init_cursor(mp, tp, agbp, agno);
> +	cur = xfs_refcountbt_init_cursor(mp, tp, agbp, agno, NULL);
>  
>  	error = xfs_refcount_find_shared(cur, agbno, aglen, fbno, flen,
>  			find_end_of_shared);
> -- 
> 2.31.1
> 


^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 12/22] xfs: convert rmap btree cursor to using a perag
  2021-05-06  7:20 ` [PATCH 12/22] xfs: convert rmap btree cursor to using a perag Dave Chinner
@ 2021-05-11 12:30   ` Brian Foster
  2021-05-12 22:45   ` Darrick J. Wong
  1 sibling, 0 replies; 87+ messages in thread
From: Brian Foster @ 2021-05-11 12:30 UTC (permalink / raw)
  To: Dave Chinner; +Cc: linux-xfs

On Thu, May 06, 2021 at 05:20:44PM +1000, Dave Chinner wrote:
> From: Dave Chinner <dchinner@redhat.com>
> 
> Signed-off-by: Dave Chinner <dchinner@redhat.com>
> ---

Reviewed-by: Brian Foster <bfoster@redhat.com>

>  fs/xfs/libxfs/xfs_ag.c         |  2 +-
>  fs/xfs/libxfs/xfs_alloc.c      |  7 ++++---
>  fs/xfs/libxfs/xfs_rmap.c       | 10 ++++-----
>  fs/xfs/libxfs/xfs_rmap.h       |  6 ++++--
>  fs/xfs/libxfs/xfs_rmap_btree.c | 37 +++++++++++++++-------------------
>  fs/xfs/libxfs/xfs_rmap_btree.h |  4 ++--
>  fs/xfs/scrub/agheader_repair.c |  6 ++----
>  fs/xfs/scrub/bmap.c            |  2 +-
>  fs/xfs/scrub/common.c          |  2 +-
>  fs/xfs/scrub/repair.c          | 10 ++++-----
>  fs/xfs/xfs_fsmap.c             |  2 +-
>  11 files changed, 42 insertions(+), 46 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_ag.c b/fs/xfs/libxfs/xfs_ag.c
> index 14d8b866dc6d..44f2787f3556 100644
> --- a/fs/xfs/libxfs/xfs_ag.c
> +++ b/fs/xfs/libxfs/xfs_ag.c
> @@ -914,7 +914,7 @@ xfs_ag_extend_space(
>  	 * XFS_RMAP_OINFO_SKIP_UPDATE is used here to tell the rmap btree that
>  	 * this doesn't actually exist in the rmap btree.
>  	 */
> -	error = xfs_rmap_free(tp, bp, id->agno,
> +	error = xfs_rmap_free(tp, bp, bp->b_pag,
>  				be32_to_cpu(agf->agf_length) - len,
>  				len, &XFS_RMAP_OINFO_SKIP_UPDATE);
>  	if (error)
> diff --git a/fs/xfs/libxfs/xfs_alloc.c b/fs/xfs/libxfs/xfs_alloc.c
> index 7ec4af6bf494..10747cc4d8f6 100644
> --- a/fs/xfs/libxfs/xfs_alloc.c
> +++ b/fs/xfs/libxfs/xfs_alloc.c
> @@ -1092,7 +1092,7 @@ xfs_alloc_ag_vextent_small(
>  	 * If we're feeding an AGFL block to something that doesn't live in the
>  	 * free space, we need to clear out the OWN_AG rmap.
>  	 */
> -	error = xfs_rmap_free(args->tp, args->agbp, args->agno, fbno, 1,
> +	error = xfs_rmap_free(args->tp, args->agbp, args->pag, fbno, 1,
>  			      &XFS_RMAP_OINFO_AG);
>  	if (error)
>  		goto error;
> @@ -1169,7 +1169,7 @@ xfs_alloc_ag_vextent(
>  
>  	/* if not file data, insert new block into the reverse map btree */
>  	if (!xfs_rmap_should_skip_owner_update(&args->oinfo)) {
> -		error = xfs_rmap_alloc(args->tp, args->agbp, args->agno,
> +		error = xfs_rmap_alloc(args->tp, args->agbp, args->pag,
>  				       args->agbno, args->len, &args->oinfo);
>  		if (error)
>  			return error;
> @@ -1899,12 +1899,13 @@ xfs_free_ag_extent(
>  	int				haveright; /* have a right neighbor */
>  	int				i;
>  	int				error;
> +	struct xfs_perag		*pag = agbp->b_pag;
>  
>  	bno_cur = cnt_cur = NULL;
>  	mp = tp->t_mountp;
>  
>  	if (!xfs_rmap_should_skip_owner_update(oinfo)) {
> -		error = xfs_rmap_free(tp, agbp, agno, bno, len, oinfo);
> +		error = xfs_rmap_free(tp, agbp, pag, bno, len, oinfo);
>  		if (error)
>  			goto error0;
>  	}
> diff --git a/fs/xfs/libxfs/xfs_rmap.c b/fs/xfs/libxfs/xfs_rmap.c
> index 0d7a6997120c..b23f949ee15c 100644
> --- a/fs/xfs/libxfs/xfs_rmap.c
> +++ b/fs/xfs/libxfs/xfs_rmap.c
> @@ -696,7 +696,7 @@ int
>  xfs_rmap_free(
>  	struct xfs_trans		*tp,
>  	struct xfs_buf			*agbp,
> -	xfs_agnumber_t			agno,
> +	struct xfs_perag		*pag,
>  	xfs_agblock_t			bno,
>  	xfs_extlen_t			len,
>  	const struct xfs_owner_info	*oinfo)
> @@ -708,7 +708,7 @@ xfs_rmap_free(
>  	if (!xfs_sb_version_hasrmapbt(&mp->m_sb))
>  		return 0;
>  
> -	cur = xfs_rmapbt_init_cursor(mp, tp, agbp, agno, NULL);
> +	cur = xfs_rmapbt_init_cursor(mp, tp, agbp, pag);
>  
>  	error = xfs_rmap_unmap(cur, bno, len, false, oinfo);
>  
> @@ -950,7 +950,7 @@ int
>  xfs_rmap_alloc(
>  	struct xfs_trans		*tp,
>  	struct xfs_buf			*agbp,
> -	xfs_agnumber_t			agno,
> +	struct xfs_perag		*pag,
>  	xfs_agblock_t			bno,
>  	xfs_extlen_t			len,
>  	const struct xfs_owner_info	*oinfo)
> @@ -962,7 +962,7 @@ xfs_rmap_alloc(
>  	if (!xfs_sb_version_hasrmapbt(&mp->m_sb))
>  		return 0;
>  
> -	cur = xfs_rmapbt_init_cursor(mp, tp, agbp, agno, NULL);
> +	cur = xfs_rmapbt_init_cursor(mp, tp, agbp, pag);
>  	error = xfs_rmap_map(cur, bno, len, false, oinfo);
>  
>  	xfs_btree_del_cursor(cur, error);
> @@ -2408,7 +2408,7 @@ xfs_rmap_finish_one(
>  			goto out_drop;
>  		}
>  
> -		rcur = xfs_rmapbt_init_cursor(mp, tp, agbp, pag->pag_agno, pag);
> +		rcur = xfs_rmapbt_init_cursor(mp, tp, agbp, pag);
>  	}
>  	*pcur = rcur;
>  
> diff --git a/fs/xfs/libxfs/xfs_rmap.h b/fs/xfs/libxfs/xfs_rmap.h
> index abe633403fd1..f2423cf7f1e2 100644
> --- a/fs/xfs/libxfs/xfs_rmap.h
> +++ b/fs/xfs/libxfs/xfs_rmap.h
> @@ -6,6 +6,8 @@
>  #ifndef __XFS_RMAP_H__
>  #define __XFS_RMAP_H__
>  
> +struct xfs_perag;
> +
>  static inline void
>  xfs_rmap_ino_bmbt_owner(
>  	struct xfs_owner_info	*oi,
> @@ -113,10 +115,10 @@ xfs_owner_info_pack(
>  }
>  
>  int xfs_rmap_alloc(struct xfs_trans *tp, struct xfs_buf *agbp,
> -		   xfs_agnumber_t agno, xfs_agblock_t bno, xfs_extlen_t len,
> +		   struct xfs_perag *pag, xfs_agblock_t bno, xfs_extlen_t len,
>  		   const struct xfs_owner_info *oinfo);
>  int xfs_rmap_free(struct xfs_trans *tp, struct xfs_buf *agbp,
> -		  xfs_agnumber_t agno, xfs_agblock_t bno, xfs_extlen_t len,
> +		  struct xfs_perag *pag, xfs_agblock_t bno, xfs_extlen_t len,
>  		  const struct xfs_owner_info *oinfo);
>  
>  int xfs_rmap_lookup_le(struct xfs_btree_cur *cur, xfs_agblock_t bno,
> diff --git a/fs/xfs/libxfs/xfs_rmap_btree.c b/fs/xfs/libxfs/xfs_rmap_btree.c
> index 7bef8feeded1..cafe181bc92d 100644
> --- a/fs/xfs/libxfs/xfs_rmap_btree.c
> +++ b/fs/xfs/libxfs/xfs_rmap_btree.c
> @@ -52,7 +52,7 @@ xfs_rmapbt_dup_cursor(
>  	struct xfs_btree_cur	*cur)
>  {
>  	return xfs_rmapbt_init_cursor(cur->bc_mp, cur->bc_tp,
> -			cur->bc_ag.agbp, cur->bc_ag.agno, cur->bc_ag.pag);
> +				cur->bc_ag.agbp, cur->bc_ag.pag);
>  }
>  
>  STATIC void
> @@ -64,13 +64,12 @@ xfs_rmapbt_set_root(
>  	struct xfs_buf		*agbp = cur->bc_ag.agbp;
>  	struct xfs_agf		*agf = agbp->b_addr;
>  	int			btnum = cur->bc_btnum;
> -	struct xfs_perag	*pag = agbp->b_pag;
>  
>  	ASSERT(ptr->s != 0);
>  
>  	agf->agf_roots[btnum] = ptr->s;
>  	be32_add_cpu(&agf->agf_levels[btnum], inc);
> -	pag->pagf_levels[btnum] += inc;
> +	cur->bc_ag.pag->pagf_levels[btnum] += inc;
>  
>  	xfs_alloc_log_agf(cur->bc_tp, agbp, XFS_AGF_ROOTS | XFS_AGF_LEVELS);
>  }
> @@ -84,6 +83,7 @@ xfs_rmapbt_alloc_block(
>  {
>  	struct xfs_buf		*agbp = cur->bc_ag.agbp;
>  	struct xfs_agf		*agf = agbp->b_addr;
> +	struct xfs_perag	*pag = cur->bc_ag.pag;
>  	int			error;
>  	xfs_agblock_t		bno;
>  
> @@ -93,20 +93,19 @@ xfs_rmapbt_alloc_block(
>  	if (error)
>  		return error;
>  
> -	trace_xfs_rmapbt_alloc_block(cur->bc_mp, cur->bc_ag.agno,
> -			bno, 1);
> +	trace_xfs_rmapbt_alloc_block(cur->bc_mp, pag->pag_agno, bno, 1);
>  	if (bno == NULLAGBLOCK) {
>  		*stat = 0;
>  		return 0;
>  	}
>  
> -	xfs_extent_busy_reuse(cur->bc_mp, agbp->b_pag, bno, 1, false);
> +	xfs_extent_busy_reuse(cur->bc_mp, pag, bno, 1, false);
>  
>  	new->s = cpu_to_be32(bno);
>  	be32_add_cpu(&agf->agf_rmap_blocks, 1);
>  	xfs_alloc_log_agf(cur->bc_tp, agbp, XFS_AGF_RMAP_BLOCKS);
>  
> -	xfs_ag_resv_rmapbt_alloc(cur->bc_mp, cur->bc_ag.agno);
> +	xfs_ag_resv_rmapbt_alloc(cur->bc_mp, pag->pag_agno);
>  
>  	*stat = 1;
>  	return 0;
> @@ -119,12 +118,12 @@ xfs_rmapbt_free_block(
>  {
>  	struct xfs_buf		*agbp = cur->bc_ag.agbp;
>  	struct xfs_agf		*agf = agbp->b_addr;
> -	struct xfs_perag	*pag;
> +	struct xfs_perag	*pag = cur->bc_ag.pag;
>  	xfs_agblock_t		bno;
>  	int			error;
>  
>  	bno = xfs_daddr_to_agbno(cur->bc_mp, XFS_BUF_ADDR(bp));
> -	trace_xfs_rmapbt_free_block(cur->bc_mp, cur->bc_ag.agno,
> +	trace_xfs_rmapbt_free_block(cur->bc_mp, pag->pag_agno,
>  			bno, 1);
>  	be32_add_cpu(&agf->agf_rmap_blocks, -1);
>  	xfs_alloc_log_agf(cur->bc_tp, agbp, XFS_AGF_RMAP_BLOCKS);
> @@ -132,7 +131,6 @@ xfs_rmapbt_free_block(
>  	if (error)
>  		return error;
>  
> -	pag = cur->bc_ag.agbp->b_pag;
>  	xfs_extent_busy_insert(cur->bc_tp, pag, bno, 1,
>  			      XFS_EXTENT_BUSY_SKIP_DISCARD);
>  
> @@ -214,7 +212,7 @@ xfs_rmapbt_init_ptr_from_cur(
>  {
>  	struct xfs_agf		*agf = cur->bc_ag.agbp->b_addr;
>  
> -	ASSERT(cur->bc_ag.agno == be32_to_cpu(agf->agf_seqno));
> +	ASSERT(cur->bc_ag.pag->pag_agno == be32_to_cpu(agf->agf_seqno));
>  
>  	ptr->s = agf->agf_roots[cur->bc_btnum];
>  }
> @@ -449,7 +447,6 @@ static struct xfs_btree_cur *
>  xfs_rmapbt_init_common(
>  	struct xfs_mount	*mp,
>  	struct xfs_trans	*tp,
> -	xfs_agnumber_t		agno,
>  	struct xfs_perag	*pag)
>  {
>  	struct xfs_btree_cur	*cur;
> @@ -462,13 +459,12 @@ xfs_rmapbt_init_common(
>  	cur->bc_flags = XFS_BTREE_CRC_BLOCKS | XFS_BTREE_OVERLAPPING;
>  	cur->bc_blocklog = mp->m_sb.sb_blocklog;
>  	cur->bc_statoff = XFS_STATS_CALC_INDEX(xs_rmap_2);
> -	cur->bc_ag.agno = agno;
>  	cur->bc_ops = &xfs_rmapbt_ops;
> -	if (pag) {
> -		/* take a reference for the cursor */
> -		atomic_inc(&pag->pag_ref);
> -	}
> +
> +	/* take a reference for the cursor */
> +	atomic_inc(&pag->pag_ref);
>  	cur->bc_ag.pag = pag;
> +	cur->bc_ag.agno = pag->pag_agno;
>  
>  	return cur;
>  }
> @@ -479,13 +475,12 @@ xfs_rmapbt_init_cursor(
>  	struct xfs_mount	*mp,
>  	struct xfs_trans	*tp,
>  	struct xfs_buf		*agbp,
> -	xfs_agnumber_t		agno,
>  	struct xfs_perag	*pag)
>  {
>  	struct xfs_agf		*agf = agbp->b_addr;
>  	struct xfs_btree_cur	*cur;
>  
> -	cur = xfs_rmapbt_init_common(mp, tp, agno, pag);
> +	cur = xfs_rmapbt_init_common(mp, tp, pag);
>  	cur->bc_nlevels = be32_to_cpu(agf->agf_levels[XFS_BTNUM_RMAP]);
>  	cur->bc_ag.agbp = agbp;
>  	return cur;
> @@ -496,11 +491,11 @@ struct xfs_btree_cur *
>  xfs_rmapbt_stage_cursor(
>  	struct xfs_mount	*mp,
>  	struct xbtree_afakeroot	*afake,
> -	xfs_agnumber_t		agno)
> +	struct xfs_perag	*pag)
>  {
>  	struct xfs_btree_cur	*cur;
>  
> -	cur = xfs_rmapbt_init_common(mp, NULL, agno, NULL);
> +	cur = xfs_rmapbt_init_common(mp, NULL, pag);
>  	xfs_btree_stage_afakeroot(cur, afake);
>  	return cur;
>  }
> diff --git a/fs/xfs/libxfs/xfs_rmap_btree.h b/fs/xfs/libxfs/xfs_rmap_btree.h
> index c94f418cc06b..88d8d18788a2 100644
> --- a/fs/xfs/libxfs/xfs_rmap_btree.h
> +++ b/fs/xfs/libxfs/xfs_rmap_btree.h
> @@ -43,9 +43,9 @@ struct xbtree_afakeroot;
>  
>  struct xfs_btree_cur *xfs_rmapbt_init_cursor(struct xfs_mount *mp,
>  				struct xfs_trans *tp, struct xfs_buf *bp,
> -				xfs_agnumber_t agno, struct xfs_perag *pag);
> +				struct xfs_perag *pag);
>  struct xfs_btree_cur *xfs_rmapbt_stage_cursor(struct xfs_mount *mp,
> -		struct xbtree_afakeroot *afake, xfs_agnumber_t agno);
> +		struct xbtree_afakeroot *afake, struct xfs_perag *pag);
>  void xfs_rmapbt_commit_staged_btree(struct xfs_btree_cur *cur,
>  		struct xfs_trans *tp, struct xfs_buf *agbp);
>  int xfs_rmapbt_maxrecs(int blocklen, int leaf);
> diff --git a/fs/xfs/scrub/agheader_repair.c b/fs/xfs/scrub/agheader_repair.c
> index 5dd91bf04c18..981c689e3d95 100644
> --- a/fs/xfs/scrub/agheader_repair.c
> +++ b/fs/xfs/scrub/agheader_repair.c
> @@ -269,8 +269,7 @@ xrep_agf_calc_from_btrees(
>  	btreeblks += blocks - 1;
>  
>  	/* Update the AGF counters from the rmapbt. */
> -	cur = xfs_rmapbt_init_cursor(mp, sc->tp, agf_bp, sc->sa.agno,
> -			sc->sa.pag);
> +	cur = xfs_rmapbt_init_cursor(mp, sc->tp, agf_bp, sc->sa.pag);
>  	error = xfs_btree_count_blocks(cur, &blocks);
>  	if (error)
>  		goto err;
> @@ -491,8 +490,7 @@ xrep_agfl_collect_blocks(
>  	xbitmap_init(&ra.agmetablocks);
>  
>  	/* Find all space used by the free space btrees & rmapbt. */
> -	cur = xfs_rmapbt_init_cursor(mp, sc->tp, agf_bp, sc->sa.agno,
> -			sc->sa.pag);
> +	cur = xfs_rmapbt_init_cursor(mp, sc->tp, agf_bp, sc->sa.pag);
>  	error = xfs_rmap_query_all(cur, xrep_agfl_walk_rmap, &ra);
>  	if (error)
>  		goto err;
> diff --git a/fs/xfs/scrub/bmap.c b/fs/xfs/scrub/bmap.c
> index a792d9ffd61e..b20c3f03b3c5 100644
> --- a/fs/xfs/scrub/bmap.c
> +++ b/fs/xfs/scrub/bmap.c
> @@ -556,7 +556,7 @@ xchk_bmap_check_ag_rmaps(
>  	if (error)
>  		return error;
>  
> -	cur = xfs_rmapbt_init_cursor(sc->mp, sc->tp, agf, agno, NULL);
> +	cur = xfs_rmapbt_init_cursor(sc->mp, sc->tp, agf, sc->sa.pag);
>  
>  	sbcri.sc = sc;
>  	sbcri.whichfork = whichfork;
> diff --git a/fs/xfs/scrub/common.c b/fs/xfs/scrub/common.c
> index 50768559fb60..48381c1adeed 100644
> --- a/fs/xfs/scrub/common.c
> +++ b/fs/xfs/scrub/common.c
> @@ -493,7 +493,7 @@ xchk_ag_btcur_init(
>  	if (sa->agf_bp && xfs_sb_version_hasrmapbt(&mp->m_sb) &&
>  	    xchk_ag_btree_healthy_enough(sc, sa->pag, XFS_BTNUM_RMAP)) {
>  		sa->rmap_cur = xfs_rmapbt_init_cursor(mp, sc->tp, sa->agf_bp,
> -				agno, sa->pag);
> +				sa->pag);
>  	}
>  
>  	/* Set up a refcountbt cursor for cross-referencing. */
> diff --git a/fs/xfs/scrub/repair.c b/fs/xfs/scrub/repair.c
> index 862dc56fd8cd..5cf1c3707b6a 100644
> --- a/fs/xfs/scrub/repair.c
> +++ b/fs/xfs/scrub/repair.c
> @@ -509,7 +509,7 @@ xrep_put_freelist(
>  	 * create an rmap for the block prior to merging it or else other
>  	 * parts will break.
>  	 */
> -	error = xfs_rmap_alloc(sc->tp, sc->sa.agf_bp, sc->sa.agno, agbno, 1,
> +	error = xfs_rmap_alloc(sc->tp, sc->sa.agf_bp, sc->sa.pag, agbno, 1,
>  			&XFS_RMAP_OINFO_AG);
>  	if (error)
>  		return error;
> @@ -555,7 +555,7 @@ xrep_reap_block(
>  	} else {
>  		agf_bp = sc->sa.agf_bp;
>  	}
> -	cur = xfs_rmapbt_init_cursor(sc->mp, sc->tp, agf_bp, agno, sc->sa.pag);
> +	cur = xfs_rmapbt_init_cursor(sc->mp, sc->tp, agf_bp, sc->sa.pag);
>  
>  	/* Can we find any other rmappings? */
>  	error = xfs_rmap_has_other_keys(cur, agbno, 1, oinfo, &has_other_rmap);
> @@ -577,7 +577,8 @@ xrep_reap_block(
>  	 * to run xfs_repair.
>  	 */
>  	if (has_other_rmap)
> -		error = xfs_rmap_free(sc->tp, agf_bp, agno, agbno, 1, oinfo);
> +		error = xfs_rmap_free(sc->tp, agf_bp, sc->sa.pag, agbno,
> +					1, oinfo);
>  	else if (resv == XFS_AG_RESV_AGFL)
>  		error = xrep_put_freelist(sc, agbno);
>  	else
> @@ -892,8 +893,7 @@ xrep_find_ag_btree_roots(
>  		fab->height = 0;
>  	}
>  
> -	cur = xfs_rmapbt_init_cursor(mp, sc->tp, agf_bp, sc->sa.agno,
> -			sc->sa.pag);
> +	cur = xfs_rmapbt_init_cursor(mp, sc->tp, agf_bp, sc->sa.pag);
>  	error = xfs_rmap_query_all(cur, xrep_findroot_rmap, &ri);
>  	xfs_btree_del_cursor(cur, error);
>  
> diff --git a/fs/xfs/xfs_fsmap.c b/fs/xfs/xfs_fsmap.c
> index b654a2bf9a9f..7bfe9ea35de0 100644
> --- a/fs/xfs/xfs_fsmap.c
> +++ b/fs/xfs/xfs_fsmap.c
> @@ -708,7 +708,7 @@ xfs_getfsmap_datadev_rmapbt_query(
>  
>  	/* Allocate cursor for this AG and query_range it. */
>  	*curpp = xfs_rmapbt_init_cursor(tp->t_mountp, tp, info->agf_bp,
> -			info->pag->pag_agno, info->pag);
> +			info->pag);
>  	return xfs_rmap_query_range(*curpp, &info->low, &info->high,
>  			xfs_getfsmap_datadev_helper, info);
>  }
> -- 
> 2.31.1
> 


^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 13/22] xfs: convert refcount btree cursor to use perags
  2021-05-06  7:20 ` [PATCH 13/22] xfs: convert refcount btree cursor to use perags Dave Chinner
@ 2021-05-11 12:30   ` Brian Foster
  2021-05-12 22:47   ` Darrick J. Wong
  1 sibling, 0 replies; 87+ messages in thread
From: Brian Foster @ 2021-05-11 12:30 UTC (permalink / raw)
  To: Dave Chinner; +Cc: linux-xfs

On Thu, May 06, 2021 at 05:20:45PM +1000, Dave Chinner wrote:
> From: Dave Chinner <dchinner@redhat.com>
> 
> Signed-off-by: Dave Chinner <dchinner@redhat.com>
> ---

Reviewed-by: Brian Foster <bfoster@redhat.com>

>  fs/xfs/libxfs/xfs_refcount.c       | 39 +++++++++++++++++-------------
>  fs/xfs/libxfs/xfs_refcount.h       |  9 ++++++-
>  fs/xfs/libxfs/xfs_refcount_btree.c | 22 +++++++----------
>  fs/xfs/libxfs/xfs_refcount_btree.h |  4 +--
>  fs/xfs/scrub/agheader_repair.c     |  2 +-
>  fs/xfs/scrub/bmap.c                |  8 +++---
>  fs/xfs/scrub/common.c              |  2 +-
>  fs/xfs/xfs_fsmap.c                 |  3 +--
>  fs/xfs/xfs_reflink.c               |  4 +--
>  9 files changed, 50 insertions(+), 43 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_refcount.c b/fs/xfs/libxfs/xfs_refcount.c
> index 1c2bd2949d7d..3c2b99cbd57d 100644
> --- a/fs/xfs/libxfs/xfs_refcount.c
> +++ b/fs/xfs/libxfs/xfs_refcount.c
> @@ -22,6 +22,7 @@
>  #include "xfs_bit.h"
>  #include "xfs_refcount.h"
>  #include "xfs_rmap.h"
> +#include "xfs_ag.h"
>  
>  /* Allowable refcount adjustment amounts. */
>  enum xfs_refc_adjust_op {
> @@ -1142,14 +1143,13 @@ xfs_refcount_finish_one(
>  	struct xfs_btree_cur		*rcur;
>  	struct xfs_buf			*agbp = NULL;
>  	int				error = 0;
> -	xfs_agnumber_t			agno;
>  	xfs_agblock_t			bno;
>  	xfs_agblock_t			new_agbno;
>  	unsigned long			nr_ops = 0;
>  	int				shape_changes = 0;
> +	struct xfs_perag		*pag;
>  
> -	agno = XFS_FSB_TO_AGNO(mp, startblock);
> -	ASSERT(agno != NULLAGNUMBER);
> +	pag = xfs_perag_get(mp, XFS_FSB_TO_AGNO(mp, startblock));
>  	bno = XFS_FSB_TO_AGBNO(mp, startblock);
>  
>  	trace_xfs_refcount_deferred(mp, XFS_FSB_TO_AGNO(mp, startblock),
> @@ -1157,15 +1157,17 @@ xfs_refcount_finish_one(
>  			blockcount);
>  
>  	if (XFS_TEST_ERROR(false, mp,
> -			XFS_ERRTAG_REFCOUNT_FINISH_ONE))
> -		return -EIO;
> +			XFS_ERRTAG_REFCOUNT_FINISH_ONE)) {
> +		error = -EIO;
> +		goto out_drop;
> +	}
>  
>  	/*
>  	 * If we haven't gotten a cursor or the cursor AG doesn't match
>  	 * the startblock, get one now.
>  	 */
>  	rcur = *pcur;
> -	if (rcur != NULL && rcur->bc_ag.agno != agno) {
> +	if (rcur != NULL && rcur->bc_ag.pag != pag) {
>  		nr_ops = rcur->bc_ag.refc.nr_ops;
>  		shape_changes = rcur->bc_ag.refc.shape_changes;
>  		xfs_refcount_finish_one_cleanup(tp, rcur, 0);
> @@ -1173,12 +1175,12 @@ xfs_refcount_finish_one(
>  		*pcur = NULL;
>  	}
>  	if (rcur == NULL) {
> -		error = xfs_alloc_read_agf(tp->t_mountp, tp, agno,
> +		error = xfs_alloc_read_agf(tp->t_mountp, tp, pag->pag_agno,
>  				XFS_ALLOC_FLAG_FREEING, &agbp);
>  		if (error)
> -			return error;
> +			goto out_drop;
>  
> -		rcur = xfs_refcountbt_init_cursor(mp, tp, agbp, agno, NULL);
> +		rcur = xfs_refcountbt_init_cursor(mp, tp, agbp, pag);
>  		rcur->bc_ag.refc.nr_ops = nr_ops;
>  		rcur->bc_ag.refc.shape_changes = shape_changes;
>  	}
> @@ -1188,12 +1190,12 @@ xfs_refcount_finish_one(
>  	case XFS_REFCOUNT_INCREASE:
>  		error = xfs_refcount_adjust(rcur, bno, blockcount, &new_agbno,
>  			new_len, XFS_REFCOUNT_ADJUST_INCREASE, NULL);
> -		*new_fsb = XFS_AGB_TO_FSB(mp, agno, new_agbno);
> +		*new_fsb = XFS_AGB_TO_FSB(mp, pag->pag_agno, new_agbno);
>  		break;
>  	case XFS_REFCOUNT_DECREASE:
>  		error = xfs_refcount_adjust(rcur, bno, blockcount, &new_agbno,
>  			new_len, XFS_REFCOUNT_ADJUST_DECREASE, NULL);
> -		*new_fsb = XFS_AGB_TO_FSB(mp, agno, new_agbno);
> +		*new_fsb = XFS_AGB_TO_FSB(mp, pag->pag_agno, new_agbno);
>  		break;
>  	case XFS_REFCOUNT_ALLOC_COW:
>  		*new_fsb = startblock + blockcount;
> @@ -1210,8 +1212,10 @@ xfs_refcount_finish_one(
>  		error = -EFSCORRUPTED;
>  	}
>  	if (!error && *new_len > 0)
> -		trace_xfs_refcount_finish_one_leftover(mp, agno, type,
> +		trace_xfs_refcount_finish_one_leftover(mp, pag->pag_agno, type,
>  				bno, blockcount, new_agbno, *new_len);
> +out_drop:
> +	xfs_perag_put(pag);
>  	return error;
>  }
>  
> @@ -1672,7 +1676,7 @@ xfs_refcount_recover_extent(
>  int
>  xfs_refcount_recover_cow_leftovers(
>  	struct xfs_mount		*mp,
> -	xfs_agnumber_t			agno)
> +	struct xfs_perag		*pag)
>  {
>  	struct xfs_trans		*tp;
>  	struct xfs_btree_cur		*cur;
> @@ -1704,10 +1708,10 @@ xfs_refcount_recover_cow_leftovers(
>  	if (error)
>  		return error;
>  
> -	error = xfs_alloc_read_agf(mp, tp, agno, 0, &agbp);
> +	error = xfs_alloc_read_agf(mp, tp, pag->pag_agno, 0, &agbp);
>  	if (error)
>  		goto out_trans;
> -	cur = xfs_refcountbt_init_cursor(mp, tp, agbp, agno, NULL);
> +	cur = xfs_refcountbt_init_cursor(mp, tp, agbp, pag);
>  
>  	/* Find all the leftover CoW staging extents. */
>  	memset(&low, 0, sizeof(low));
> @@ -1729,11 +1733,12 @@ xfs_refcount_recover_cow_leftovers(
>  		if (error)
>  			goto out_free;
>  
> -		trace_xfs_refcount_recover_extent(mp, agno, &rr->rr_rrec);
> +		trace_xfs_refcount_recover_extent(mp, pag->pag_agno,
> +				&rr->rr_rrec);
>  
>  		/* Free the orphan record */
>  		agbno = rr->rr_rrec.rc_startblock - XFS_REFC_COW_START;
> -		fsb = XFS_AGB_TO_FSB(mp, agno, agbno);
> +		fsb = XFS_AGB_TO_FSB(mp, pag->pag_agno, agbno);
>  		xfs_refcount_free_cow_extent(tp, fsb,
>  				rr->rr_rrec.rc_blockcount);
>  
> diff --git a/fs/xfs/libxfs/xfs_refcount.h b/fs/xfs/libxfs/xfs_refcount.h
> index 209795539c8d..9f6e9aae4da0 100644
> --- a/fs/xfs/libxfs/xfs_refcount.h
> +++ b/fs/xfs/libxfs/xfs_refcount.h
> @@ -6,6 +6,13 @@
>  #ifndef __XFS_REFCOUNT_H__
>  #define __XFS_REFCOUNT_H__
>  
> +struct xfs_trans;
> +struct xfs_mount;
> +struct xfs_perag;
> +struct xfs_btree_cur;
> +struct xfs_bmbt_irec;
> +struct xfs_refcount_irec;
> +
>  extern int xfs_refcount_lookup_le(struct xfs_btree_cur *cur,
>  		xfs_agblock_t bno, int *stat);
>  extern int xfs_refcount_lookup_ge(struct xfs_btree_cur *cur,
> @@ -50,7 +57,7 @@ void xfs_refcount_alloc_cow_extent(struct xfs_trans *tp, xfs_fsblock_t fsb,
>  void xfs_refcount_free_cow_extent(struct xfs_trans *tp, xfs_fsblock_t fsb,
>  		xfs_extlen_t len);
>  extern int xfs_refcount_recover_cow_leftovers(struct xfs_mount *mp,
> -		xfs_agnumber_t agno);
> +		struct xfs_perag *pag);
>  
>  /*
>   * While we're adjusting the refcounts records of an extent, we have
> diff --git a/fs/xfs/libxfs/xfs_refcount_btree.c b/fs/xfs/libxfs/xfs_refcount_btree.c
> index 74f8ac0209f1..8f6577cb3475 100644
> --- a/fs/xfs/libxfs/xfs_refcount_btree.c
> +++ b/fs/xfs/libxfs/xfs_refcount_btree.c
> @@ -26,7 +26,7 @@ xfs_refcountbt_dup_cursor(
>  	struct xfs_btree_cur	*cur)
>  {
>  	return xfs_refcountbt_init_cursor(cur->bc_mp, cur->bc_tp,
> -			cur->bc_ag.agbp, cur->bc_ag.agno, cur->bc_ag.pag);
> +			cur->bc_ag.agbp, cur->bc_ag.pag);
>  }
>  
>  STATIC void
> @@ -316,13 +316,11 @@ static struct xfs_btree_cur *
>  xfs_refcountbt_init_common(
>  	struct xfs_mount	*mp,
>  	struct xfs_trans	*tp,
> -	xfs_agnumber_t		agno,
>  	struct xfs_perag	*pag)
>  {
>  	struct xfs_btree_cur	*cur;
>  
> -	ASSERT(agno != NULLAGNUMBER);
> -	ASSERT(agno < mp->m_sb.sb_agcount);
> +	ASSERT(pag->pag_agno < mp->m_sb.sb_agcount);
>  
>  	cur = kmem_cache_zalloc(xfs_btree_cur_zone, GFP_NOFS | __GFP_NOFAIL);
>  	cur->bc_tp = tp;
> @@ -331,13 +329,12 @@ xfs_refcountbt_init_common(
>  	cur->bc_blocklog = mp->m_sb.sb_blocklog;
>  	cur->bc_statoff = XFS_STATS_CALC_INDEX(xs_refcbt_2);
>  
> -	cur->bc_ag.agno = agno;
>  	cur->bc_flags |= XFS_BTREE_CRC_BLOCKS;
> -	if (pag) {
> -		/* take a reference for the cursor */
> -		atomic_inc(&pag->pag_ref);
> -	}
> +
> +	/* take a reference for the cursor */
> +	atomic_inc(&pag->pag_ref);
>  	cur->bc_ag.pag = pag;
> +	cur->bc_ag.agno = pag->pag_agno;
>  
>  	cur->bc_ag.refc.nr_ops = 0;
>  	cur->bc_ag.refc.shape_changes = 0;
> @@ -351,13 +348,12 @@ xfs_refcountbt_init_cursor(
>  	struct xfs_mount	*mp,
>  	struct xfs_trans	*tp,
>  	struct xfs_buf		*agbp,
> -	xfs_agnumber_t		agno,
>  	struct xfs_perag	*pag)
>  {
>  	struct xfs_agf		*agf = agbp->b_addr;
>  	struct xfs_btree_cur	*cur;
>  
> -	cur = xfs_refcountbt_init_common(mp, tp, agno, pag);
> +	cur = xfs_refcountbt_init_common(mp, tp, pag);
>  	cur->bc_nlevels = be32_to_cpu(agf->agf_refcount_level);
>  	cur->bc_ag.agbp = agbp;
>  	return cur;
> @@ -368,11 +364,11 @@ struct xfs_btree_cur *
>  xfs_refcountbt_stage_cursor(
>  	struct xfs_mount	*mp,
>  	struct xbtree_afakeroot	*afake,
> -	xfs_agnumber_t		agno)
> +	struct xfs_perag	*pag)
>  {
>  	struct xfs_btree_cur	*cur;
>  
> -	cur = xfs_refcountbt_init_common(mp, NULL, agno, NULL);
> +	cur = xfs_refcountbt_init_common(mp, NULL, pag);
>  	xfs_btree_stage_afakeroot(cur, afake);
>  	return cur;
>  }
> diff --git a/fs/xfs/libxfs/xfs_refcount_btree.h b/fs/xfs/libxfs/xfs_refcount_btree.h
> index 8b82a39f104a..bd9ed9e1e41f 100644
> --- a/fs/xfs/libxfs/xfs_refcount_btree.h
> +++ b/fs/xfs/libxfs/xfs_refcount_btree.h
> @@ -47,9 +47,9 @@ struct xbtree_afakeroot;
>  
>  extern struct xfs_btree_cur *xfs_refcountbt_init_cursor(struct xfs_mount *mp,
>  		struct xfs_trans *tp, struct xfs_buf *agbp,
> -		xfs_agnumber_t agno, struct xfs_perag *pag);
> +		struct xfs_perag *pag);
>  struct xfs_btree_cur *xfs_refcountbt_stage_cursor(struct xfs_mount *mp,
> -		struct xbtree_afakeroot *afake, xfs_agnumber_t agno);
> +		struct xbtree_afakeroot *afake, struct xfs_perag *pag);
>  extern int xfs_refcountbt_maxrecs(int blocklen, bool leaf);
>  extern void xfs_refcountbt_compute_maxlevels(struct xfs_mount *mp);
>  
> diff --git a/fs/xfs/scrub/agheader_repair.c b/fs/xfs/scrub/agheader_repair.c
> index 981c689e3d95..251410c19198 100644
> --- a/fs/xfs/scrub/agheader_repair.c
> +++ b/fs/xfs/scrub/agheader_repair.c
> @@ -282,7 +282,7 @@ xrep_agf_calc_from_btrees(
>  	/* Update the AGF counters from the refcountbt. */
>  	if (xfs_sb_version_hasreflink(&mp->m_sb)) {
>  		cur = xfs_refcountbt_init_cursor(mp, sc->tp, agf_bp,
> -				sc->sa.agno, sc->sa.pag);
> +				sc->sa.pag);
>  		error = xfs_btree_count_blocks(cur, &blocks);
>  		if (error)
>  			goto err;
> diff --git a/fs/xfs/scrub/bmap.c b/fs/xfs/scrub/bmap.c
> index b20c3f03b3c5..5adef162115d 100644
> --- a/fs/xfs/scrub/bmap.c
> +++ b/fs/xfs/scrub/bmap.c
> @@ -545,18 +545,18 @@ STATIC int
>  xchk_bmap_check_ag_rmaps(
>  	struct xfs_scrub		*sc,
>  	int				whichfork,
> -	xfs_agnumber_t			agno)
> +	struct xfs_perag		*pag)
>  {
>  	struct xchk_bmap_check_rmap_info	sbcri;
>  	struct xfs_btree_cur		*cur;
>  	struct xfs_buf			*agf;
>  	int				error;
>  
> -	error = xfs_alloc_read_agf(sc->mp, sc->tp, agno, 0, &agf);
> +	error = xfs_alloc_read_agf(sc->mp, sc->tp, pag->pag_agno, 0, &agf);
>  	if (error)
>  		return error;
>  
> -	cur = xfs_rmapbt_init_cursor(sc->mp, sc->tp, agf, sc->sa.pag);
> +	cur = xfs_rmapbt_init_cursor(sc->mp, sc->tp, agf, pag);
>  
>  	sbcri.sc = sc;
>  	sbcri.whichfork = whichfork;
> @@ -610,7 +610,7 @@ xchk_bmap_check_rmaps(
>  		return 0;
>  
>  	for_each_perag(sc->mp, agno, pag) {
> -		error = xchk_bmap_check_ag_rmaps(sc, whichfork, pag->pag_agno);
> +		error = xchk_bmap_check_ag_rmaps(sc, whichfork, pag);
>  		if (error)
>  			return error;
>  		if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
> diff --git a/fs/xfs/scrub/common.c b/fs/xfs/scrub/common.c
> index 48381c1adeed..cc7688ce79b2 100644
> --- a/fs/xfs/scrub/common.c
> +++ b/fs/xfs/scrub/common.c
> @@ -500,7 +500,7 @@ xchk_ag_btcur_init(
>  	if (sa->agf_bp && xfs_sb_version_hasreflink(&mp->m_sb) &&
>  	    xchk_ag_btree_healthy_enough(sc, sa->pag, XFS_BTNUM_REFC)) {
>  		sa->refc_cur = xfs_refcountbt_init_cursor(mp, sc->tp,
> -				sa->agf_bp, agno, sa->pag);
> +				sa->agf_bp, sa->pag);
>  	}
>  }
>  
> diff --git a/fs/xfs/xfs_fsmap.c b/fs/xfs/xfs_fsmap.c
> index 7bfe9ea35de0..623cabaeafee 100644
> --- a/fs/xfs/xfs_fsmap.c
> +++ b/fs/xfs/xfs_fsmap.c
> @@ -210,8 +210,7 @@ xfs_getfsmap_is_shared(
>  
>  	/* Are there any shared blocks here? */
>  	flen = 0;
> -	cur = xfs_refcountbt_init_cursor(mp, tp, info->agf_bp,
> -			info->pag->pag_agno, info->pag);
> +	cur = xfs_refcountbt_init_cursor(mp, tp, info->agf_bp, info->pag);
>  
>  	error = xfs_refcount_find_shared(cur, rec->rm_startblock,
>  			rec->rm_blockcount, &fbno, &flen, false);
> diff --git a/fs/xfs/xfs_reflink.c b/fs/xfs/xfs_reflink.c
> index 28ffe1817f9b..c256104772cb 100644
> --- a/fs/xfs/xfs_reflink.c
> +++ b/fs/xfs/xfs_reflink.c
> @@ -144,7 +144,7 @@ xfs_reflink_find_shared(
>  	if (error)
>  		return error;
>  
> -	cur = xfs_refcountbt_init_cursor(mp, tp, agbp, agno, NULL);
> +	cur = xfs_refcountbt_init_cursor(mp, tp, agbp, agbp->b_pag);
>  
>  	error = xfs_refcount_find_shared(cur, agbno, aglen, fbno, flen,
>  			find_end_of_shared);
> @@ -763,7 +763,7 @@ xfs_reflink_recover_cow(
>  		return 0;
>  
>  	for_each_perag(mp, agno, pag) {
> -		error = xfs_refcount_recover_cow_leftovers(mp, pag->pag_agno);
> +		error = xfs_refcount_recover_cow_leftovers(mp, pag);
>  		if (error) {
>  			xfs_perag_put(pag);
>  			break;
> -- 
> 2.31.1
> 


^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 14/22] xfs: convert allocbt cursors to use perags
  2021-05-06  7:20 ` [PATCH 14/22] xfs: convert allocbt cursors " Dave Chinner
@ 2021-05-11 12:30   ` Brian Foster
  2021-05-13  3:55   ` Darrick J. Wong
  1 sibling, 0 replies; 87+ messages in thread
From: Brian Foster @ 2021-05-11 12:30 UTC (permalink / raw)
  To: Dave Chinner; +Cc: linux-xfs

On Thu, May 06, 2021 at 05:20:46PM +1000, Dave Chinner wrote:
> From: Dave Chinner <dchinner@redhat.com>
> 
> Signed-off-by: Dave Chinner <dchinner@redhat.com>
> ---

Reviewed-by: Brian Foster <bfoster@redhat.com>

>  fs/xfs/libxfs/xfs_alloc.c       | 25 ++++++++++---------------
>  fs/xfs/libxfs/xfs_alloc_btree.c | 26 ++++++++++----------------
>  fs/xfs/libxfs/xfs_alloc_btree.h |  8 ++++----
>  fs/xfs/scrub/agheader_repair.c  |  8 ++++----
>  fs/xfs/scrub/common.c           |  4 ++--
>  fs/xfs/xfs_discard.c            |  2 +-
>  fs/xfs/xfs_fsmap.c              |  2 +-
>  7 files changed, 32 insertions(+), 43 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_alloc.c b/fs/xfs/libxfs/xfs_alloc.c
> index 10747cc4d8f6..c99a80286efa 100644
> --- a/fs/xfs/libxfs/xfs_alloc.c
> +++ b/fs/xfs/libxfs/xfs_alloc.c
> @@ -776,8 +776,7 @@ xfs_alloc_cur_setup(
>  	 */
>  	if (!acur->cnt)
>  		acur->cnt = xfs_allocbt_init_cursor(args->mp, args->tp,
> -						args->agbp, args->agno,
> -						args->pag, XFS_BTNUM_CNT);
> +					args->agbp, args->pag, XFS_BTNUM_CNT);
>  	error = xfs_alloc_lookup_ge(acur->cnt, 0, args->maxlen, &i);
>  	if (error)
>  		return error;
> @@ -787,12 +786,10 @@ xfs_alloc_cur_setup(
>  	 */
>  	if (!acur->bnolt)
>  		acur->bnolt = xfs_allocbt_init_cursor(args->mp, args->tp,
> -						args->agbp, args->agno,
> -						args->pag, XFS_BTNUM_BNO);
> +					args->agbp, args->pag, XFS_BTNUM_BNO);
>  	if (!acur->bnogt)
>  		acur->bnogt = xfs_allocbt_init_cursor(args->mp, args->tp,
> -						args->agbp, args->agno,
> -						args->pag, XFS_BTNUM_BNO);
> +					args->agbp, args->pag, XFS_BTNUM_BNO);
>  	return i == 1 ? 0 : -ENOSPC;
>  }
>  
> @@ -1220,7 +1217,7 @@ xfs_alloc_ag_vextent_exact(
>  	 * Allocate/initialize a cursor for the by-number freespace btree.
>  	 */
>  	bno_cur = xfs_allocbt_init_cursor(args->mp, args->tp, args->agbp,
> -					  args->agno, args->pag, XFS_BTNUM_BNO);
> +					  args->pag, XFS_BTNUM_BNO);
>  
>  	/*
>  	 * Lookup bno and minlen in the btree (minlen is irrelevant, really).
> @@ -1280,7 +1277,7 @@ xfs_alloc_ag_vextent_exact(
>  	 * Allocate/initialize a cursor for the by-size btree.
>  	 */
>  	cnt_cur = xfs_allocbt_init_cursor(args->mp, args->tp, args->agbp,
> -					args->agno, args->pag, XFS_BTNUM_CNT);
> +					args->pag, XFS_BTNUM_CNT);
>  	ASSERT(args->agbno + args->len <= be32_to_cpu(agf->agf_length));
>  	error = xfs_alloc_fixup_trees(cnt_cur, bno_cur, fbno, flen, args->agbno,
>  				      args->len, XFSA_FIXUP_BNO_OK);
> @@ -1677,7 +1674,7 @@ xfs_alloc_ag_vextent_size(
>  	 * Allocate and initialize a cursor for the by-size btree.
>  	 */
>  	cnt_cur = xfs_allocbt_init_cursor(args->mp, args->tp, args->agbp,
> -					args->agno, args->pag, XFS_BTNUM_CNT);
> +					args->pag, XFS_BTNUM_CNT);
>  	bno_cur = NULL;
>  	busy = false;
>  
> @@ -1840,7 +1837,7 @@ xfs_alloc_ag_vextent_size(
>  	 * Allocate and initialize a cursor for the by-block tree.
>  	 */
>  	bno_cur = xfs_allocbt_init_cursor(args->mp, args->tp, args->agbp,
> -					args->agno, args->pag, XFS_BTNUM_BNO);
> +					args->pag, XFS_BTNUM_BNO);
>  	if ((error = xfs_alloc_fixup_trees(cnt_cur, bno_cur, fbno, flen,
>  			rbno, rlen, XFSA_FIXUP_CNT_OK)))
>  		goto error0;
> @@ -1913,8 +1910,7 @@ xfs_free_ag_extent(
>  	/*
>  	 * Allocate and initialize a cursor for the by-block btree.
>  	 */
> -	bno_cur = xfs_allocbt_init_cursor(mp, tp, agbp, agno,
> -					NULL, XFS_BTNUM_BNO);
> +	bno_cur = xfs_allocbt_init_cursor(mp, tp, agbp, pag, XFS_BTNUM_BNO);
>  	/*
>  	 * Look for a neighboring block on the left (lower block numbers)
>  	 * that is contiguous with this space.
> @@ -1984,8 +1980,7 @@ xfs_free_ag_extent(
>  	/*
>  	 * Now allocate and initialize a cursor for the by-size tree.
>  	 */
> -	cnt_cur = xfs_allocbt_init_cursor(mp, tp, agbp, agno,
> -					NULL, XFS_BTNUM_CNT);
> +	cnt_cur = xfs_allocbt_init_cursor(mp, tp, agbp, pag, XFS_BTNUM_CNT);
>  	/*
>  	 * Have both left and right contiguous neighbors.
>  	 * Merge all three into a single free block.
> @@ -2496,7 +2491,7 @@ xfs_exact_minlen_extent_available(
>  	int			error = 0;
>  
>  	cnt_cur = xfs_allocbt_init_cursor(args->mp, args->tp, agbp,
> -					args->agno, args->pag, XFS_BTNUM_CNT);
> +					args->pag, XFS_BTNUM_CNT);
>  	error = xfs_alloc_lookup_ge(cnt_cur, 0, args->minlen, stat);
>  	if (error)
>  		goto out;
> diff --git a/fs/xfs/libxfs/xfs_alloc_btree.c b/fs/xfs/libxfs/xfs_alloc_btree.c
> index a52ab25bbf0b..0c2e4cff4ee3 100644
> --- a/fs/xfs/libxfs/xfs_alloc_btree.c
> +++ b/fs/xfs/libxfs/xfs_alloc_btree.c
> @@ -26,8 +26,7 @@ xfs_allocbt_dup_cursor(
>  	struct xfs_btree_cur	*cur)
>  {
>  	return xfs_allocbt_init_cursor(cur->bc_mp, cur->bc_tp,
> -			cur->bc_ag.agbp, cur->bc_ag.agno,
> -			cur->bc_ag.pag, cur->bc_btnum);
> +			cur->bc_ag.agbp, cur->bc_ag.pag, cur->bc_btnum);
>  }
>  
>  STATIC void
> @@ -39,13 +38,12 @@ xfs_allocbt_set_root(
>  	struct xfs_buf		*agbp = cur->bc_ag.agbp;
>  	struct xfs_agf		*agf = agbp->b_addr;
>  	int			btnum = cur->bc_btnum;
> -	struct xfs_perag	*pag = agbp->b_pag;
>  
>  	ASSERT(ptr->s != 0);
>  
>  	agf->agf_roots[btnum] = ptr->s;
>  	be32_add_cpu(&agf->agf_levels[btnum], inc);
> -	pag->pagf_levels[btnum] += inc;
> +	cur->bc_ag.pag->pagf_levels[btnum] += inc;
>  
>  	xfs_alloc_log_agf(cur->bc_tp, agbp, XFS_AGF_ROOTS | XFS_AGF_LEVELS);
>  }
> @@ -224,7 +222,7 @@ xfs_allocbt_init_ptr_from_cur(
>  {
>  	struct xfs_agf		*agf = cur->bc_ag.agbp->b_addr;
>  
> -	ASSERT(cur->bc_ag.agno == be32_to_cpu(agf->agf_seqno));
> +	ASSERT(cur->bc_ag.pag->pag_agno == be32_to_cpu(agf->agf_seqno));
>  
>  	ptr->s = agf->agf_roots[cur->bc_btnum];
>  }
> @@ -472,7 +470,6 @@ STATIC struct xfs_btree_cur *
>  xfs_allocbt_init_common(
>  	struct xfs_mount	*mp,
>  	struct xfs_trans	*tp,
> -	xfs_agnumber_t		agno,
>  	struct xfs_perag	*pag,
>  	xfs_btnum_t		btnum)
>  {
> @@ -486,6 +483,7 @@ xfs_allocbt_init_common(
>  	cur->bc_mp = mp;
>  	cur->bc_btnum = btnum;
>  	cur->bc_blocklog = mp->m_sb.sb_blocklog;
> +	cur->bc_ag.abt.active = false;
>  
>  	if (btnum == XFS_BTNUM_CNT) {
>  		cur->bc_ops = &xfs_cntbt_ops;
> @@ -496,13 +494,10 @@ xfs_allocbt_init_common(
>  		cur->bc_statoff = XFS_STATS_CALC_INDEX(xs_abtb_2);
>  	}
>  
> -	cur->bc_ag.agno = agno;
> -	cur->bc_ag.abt.active = false;
> -	if (pag) {
> -		/* take a reference for the cursor */
> -		atomic_inc(&pag->pag_ref);
> -	}
> +	/* take a reference for the cursor */
> +	atomic_inc(&pag->pag_ref);
>  	cur->bc_ag.pag = pag;
> +	cur->bc_ag.agno = pag->pag_agno;
>  
>  	if (xfs_sb_version_hascrc(&mp->m_sb))
>  		cur->bc_flags |= XFS_BTREE_CRC_BLOCKS;
> @@ -518,14 +513,13 @@ xfs_allocbt_init_cursor(
>  	struct xfs_mount	*mp,		/* file system mount point */
>  	struct xfs_trans	*tp,		/* transaction pointer */
>  	struct xfs_buf		*agbp,		/* buffer for agf structure */
> -	xfs_agnumber_t		agno,		/* allocation group number */
>  	struct xfs_perag	*pag,
>  	xfs_btnum_t		btnum)		/* btree identifier */
>  {
>  	struct xfs_agf		*agf = agbp->b_addr;
>  	struct xfs_btree_cur	*cur;
>  
> -	cur = xfs_allocbt_init_common(mp, tp, agno, pag, btnum);
> +	cur = xfs_allocbt_init_common(mp, tp, pag, btnum);
>  	if (btnum == XFS_BTNUM_CNT)
>  		cur->bc_nlevels = be32_to_cpu(agf->agf_levels[XFS_BTNUM_CNT]);
>  	else
> @@ -541,12 +535,12 @@ struct xfs_btree_cur *
>  xfs_allocbt_stage_cursor(
>  	struct xfs_mount	*mp,
>  	struct xbtree_afakeroot	*afake,
> -	xfs_agnumber_t		agno,
> +	struct xfs_perag	*pag,
>  	xfs_btnum_t		btnum)
>  {
>  	struct xfs_btree_cur	*cur;
>  
> -	cur = xfs_allocbt_init_common(mp, NULL, agno, NULL, btnum);
> +	cur = xfs_allocbt_init_common(mp, NULL, pag, btnum);
>  	xfs_btree_stage_afakeroot(cur, afake);
>  	return cur;
>  }
> diff --git a/fs/xfs/libxfs/xfs_alloc_btree.h b/fs/xfs/libxfs/xfs_alloc_btree.h
> index a10cedba18d8..9eb4c667a6b8 100644
> --- a/fs/xfs/libxfs/xfs_alloc_btree.h
> +++ b/fs/xfs/libxfs/xfs_alloc_btree.h
> @@ -47,11 +47,11 @@ struct xbtree_afakeroot;
>  		 (maxrecs) * sizeof(xfs_alloc_key_t) + \
>  		 ((index) - 1) * sizeof(xfs_alloc_ptr_t)))
>  
> -extern struct xfs_btree_cur *xfs_allocbt_init_cursor(struct xfs_mount *,
> -		struct xfs_trans *, struct xfs_buf *,
> -		xfs_agnumber_t, struct xfs_perag *pag, xfs_btnum_t);
> +extern struct xfs_btree_cur *xfs_allocbt_init_cursor(struct xfs_mount *mp,
> +		struct xfs_trans *tp, struct xfs_buf *bp,
> +		struct xfs_perag *pag, xfs_btnum_t btnum);
>  struct xfs_btree_cur *xfs_allocbt_stage_cursor(struct xfs_mount *mp,
> -		struct xbtree_afakeroot *afake, xfs_agnumber_t agno,
> +		struct xbtree_afakeroot *afake, struct xfs_perag *pag,
>  		xfs_btnum_t btnum);
>  extern int xfs_allocbt_maxrecs(struct xfs_mount *, int, int);
>  extern xfs_extlen_t xfs_allocbt_calc_size(struct xfs_mount *mp,
> diff --git a/fs/xfs/scrub/agheader_repair.c b/fs/xfs/scrub/agheader_repair.c
> index 251410c19198..ee2d85e3fd4a 100644
> --- a/fs/xfs/scrub/agheader_repair.c
> +++ b/fs/xfs/scrub/agheader_repair.c
> @@ -246,7 +246,7 @@ xrep_agf_calc_from_btrees(
>  	int			error;
>  
>  	/* Update the AGF counters from the bnobt. */
> -	cur = xfs_allocbt_init_cursor(mp, sc->tp, agf_bp, sc->sa.agno,
> +	cur = xfs_allocbt_init_cursor(mp, sc->tp, agf_bp,
>  			sc->sa.pag, XFS_BTNUM_BNO);
>  	error = xfs_alloc_query_all(cur, xrep_agf_walk_allocbt, &raa);
>  	if (error)
> @@ -260,7 +260,7 @@ xrep_agf_calc_from_btrees(
>  	agf->agf_longest = cpu_to_be32(raa.longest);
>  
>  	/* Update the AGF counters from the cntbt. */
> -	cur = xfs_allocbt_init_cursor(mp, sc->tp, agf_bp, sc->sa.agno,
> +	cur = xfs_allocbt_init_cursor(mp, sc->tp, agf_bp,
>  			sc->sa.pag, XFS_BTNUM_CNT);
>  	error = xfs_btree_count_blocks(cur, &blocks);
>  	if (error)
> @@ -497,7 +497,7 @@ xrep_agfl_collect_blocks(
>  	xfs_btree_del_cursor(cur, error);
>  
>  	/* Find all blocks currently being used by the bnobt. */
> -	cur = xfs_allocbt_init_cursor(mp, sc->tp, agf_bp, sc->sa.agno,
> +	cur = xfs_allocbt_init_cursor(mp, sc->tp, agf_bp,
>  			sc->sa.pag, XFS_BTNUM_BNO);
>  	error = xbitmap_set_btblocks(&ra.agmetablocks, cur);
>  	if (error)
> @@ -505,7 +505,7 @@ xrep_agfl_collect_blocks(
>  	xfs_btree_del_cursor(cur, error);
>  
>  	/* Find all blocks currently being used by the cntbt. */
> -	cur = xfs_allocbt_init_cursor(mp, sc->tp, agf_bp, sc->sa.agno,
> +	cur = xfs_allocbt_init_cursor(mp, sc->tp, agf_bp,
>  			sc->sa.pag, XFS_BTNUM_CNT);
>  	error = xbitmap_set_btblocks(&ra.agmetablocks, cur);
>  	if (error)
> diff --git a/fs/xfs/scrub/common.c b/fs/xfs/scrub/common.c
> index cc7688ce79b2..3035f8cee6f6 100644
> --- a/fs/xfs/scrub/common.c
> +++ b/fs/xfs/scrub/common.c
> @@ -465,14 +465,14 @@ xchk_ag_btcur_init(
>  	    xchk_ag_btree_healthy_enough(sc, sa->pag, XFS_BTNUM_BNO)) {
>  		/* Set up a bnobt cursor for cross-referencing. */
>  		sa->bno_cur = xfs_allocbt_init_cursor(mp, sc->tp, sa->agf_bp,
> -				agno, sa->pag, XFS_BTNUM_BNO);
> +				sa->pag, XFS_BTNUM_BNO);
>  	}
>  
>  	if (sa->agf_bp &&
>  	    xchk_ag_btree_healthy_enough(sc, sa->pag, XFS_BTNUM_CNT)) {
>  		/* Set up a cntbt cursor for cross-referencing. */
>  		sa->cnt_cur = xfs_allocbt_init_cursor(mp, sc->tp, sa->agf_bp,
> -				agno, sa->pag, XFS_BTNUM_CNT);
> +				sa->pag, XFS_BTNUM_CNT);
>  	}
>  
>  	/* Set up a inobt cursor for cross-referencing. */
> diff --git a/fs/xfs/xfs_discard.c b/fs/xfs/xfs_discard.c
> index 311ebaad4f5a..736df5660f1f 100644
> --- a/fs/xfs/xfs_discard.c
> +++ b/fs/xfs/xfs_discard.c
> @@ -50,7 +50,7 @@ xfs_trim_extents(
>  		goto out_put_perag;
>  	agf = agbp->b_addr;
>  
> -	cur = xfs_allocbt_init_cursor(mp, NULL, agbp, agno, pag, XFS_BTNUM_CNT);
> +	cur = xfs_allocbt_init_cursor(mp, NULL, agbp, pag, XFS_BTNUM_CNT);
>  
>  	/*
>  	 * Look up the longest btree in the AGF and start with it.
> diff --git a/fs/xfs/xfs_fsmap.c b/fs/xfs/xfs_fsmap.c
> index 623cabaeafee..7501dd941a63 100644
> --- a/fs/xfs/xfs_fsmap.c
> +++ b/fs/xfs/xfs_fsmap.c
> @@ -740,7 +740,7 @@ xfs_getfsmap_datadev_bnobt_query(
>  
>  	/* Allocate cursor for this AG and query_range it. */
>  	*curpp = xfs_allocbt_init_cursor(tp->t_mountp, tp, info->agf_bp,
> -			info->pag->pag_agno, info->pag, XFS_BTNUM_BNO);
> +			info->pag, XFS_BTNUM_BNO);
>  	key->ar_startblock = info->low.rm_startblock;
>  	key[1].ar_startblock = info->high.rm_startblock;
>  	return xfs_alloc_query_range(*curpp, key, &key[1],
> -- 
> 2.31.1
> 


^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 15/22] xfs: use perag for ialloc btree cursors
  2021-05-06  7:20 ` [PATCH 15/22] xfs: use perag for ialloc btree cursors Dave Chinner
@ 2021-05-11 12:30   ` Brian Foster
  2021-05-13  3:55   ` Darrick J. Wong
  1 sibling, 0 replies; 87+ messages in thread
From: Brian Foster @ 2021-05-11 12:30 UTC (permalink / raw)
  To: Dave Chinner; +Cc: linux-xfs

On Thu, May 06, 2021 at 05:20:47PM +1000, Dave Chinner wrote:
> From: Dave Chinner <dchinner@redhat.com>
> 
> Signed-off-by: Dave Chinner <dchinner@redhat.com>
> ---

Reviewed-by: Brian Foster <bfoster@redhat.com>

>  fs/xfs/libxfs/xfs_ialloc.c       | 177 ++++++++++++++++---------------
>  fs/xfs/libxfs/xfs_ialloc_btree.c |  27 ++---
>  fs/xfs/libxfs/xfs_ialloc_btree.h |   6 +-
>  fs/xfs/scrub/agheader_repair.c   |   4 +-
>  fs/xfs/scrub/common.c            |   5 +-
>  fs/xfs/xfs_iwalk.c               |   6 +-
>  6 files changed, 109 insertions(+), 116 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_ialloc.c b/fs/xfs/libxfs/xfs_ialloc.c
> index 905872bab426..e6f64d41e208 100644
> --- a/fs/xfs/libxfs/xfs_ialloc.c
> +++ b/fs/xfs/libxfs/xfs_ialloc.c
> @@ -172,18 +172,17 @@ xfs_inobt_insert(
>  	struct xfs_mount	*mp,
>  	struct xfs_trans	*tp,
>  	struct xfs_buf		*agbp,
> +	struct xfs_perag	*pag,
>  	xfs_agino_t		newino,
>  	xfs_agino_t		newlen,
>  	xfs_btnum_t		btnum)
>  {
>  	struct xfs_btree_cur	*cur;
> -	struct xfs_agi		*agi = agbp->b_addr;
> -	xfs_agnumber_t		agno = be32_to_cpu(agi->agi_seqno);
>  	xfs_agino_t		thisino;
>  	int			i;
>  	int			error;
>  
> -	cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, NULL, btnum);
> +	cur = xfs_inobt_init_cursor(mp, tp, agbp, pag, btnum);
>  
>  	for (thisino = newino;
>  	     thisino < newino + newlen;
> @@ -520,18 +519,17 @@ xfs_inobt_insert_sprec(
>  	struct xfs_mount		*mp,
>  	struct xfs_trans		*tp,
>  	struct xfs_buf			*agbp,
> +	struct xfs_perag		*pag,
>  	int				btnum,
>  	struct xfs_inobt_rec_incore	*nrec,	/* in/out: new/merged rec. */
>  	bool				merge)	/* merge or replace */
>  {
>  	struct xfs_btree_cur		*cur;
> -	struct xfs_agi			*agi = agbp->b_addr;
> -	xfs_agnumber_t			agno = be32_to_cpu(agi->agi_seqno);
>  	int				error;
>  	int				i;
>  	struct xfs_inobt_rec_incore	rec;
>  
> -	cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, NULL, btnum);
> +	cur = xfs_inobt_init_cursor(mp, tp, agbp, pag, btnum);
>  
>  	/* the new record is pre-aligned so we know where to look */
>  	error = xfs_inobt_lookup(cur, nrec->ir_startino, XFS_LOOKUP_EQ, &i);
> @@ -578,14 +576,14 @@ xfs_inobt_insert_sprec(
>  			goto error;
>  		}
>  
> -		trace_xfs_irec_merge_pre(mp, agno, rec.ir_startino,
> +		trace_xfs_irec_merge_pre(mp, pag->pag_agno, rec.ir_startino,
>  					 rec.ir_holemask, nrec->ir_startino,
>  					 nrec->ir_holemask);
>  
>  		/* merge to nrec to output the updated record */
>  		__xfs_inobt_rec_merge(nrec, &rec);
>  
> -		trace_xfs_irec_merge_post(mp, agno, nrec->ir_startino,
> +		trace_xfs_irec_merge_post(mp, pag->pag_agno, nrec->ir_startino,
>  					  nrec->ir_holemask);
>  
>  		error = xfs_inobt_rec_check_count(mp, nrec);
> @@ -613,21 +611,20 @@ xfs_inobt_insert_sprec(
>  STATIC int
>  xfs_ialloc_ag_alloc(
>  	struct xfs_trans	*tp,
> -	struct xfs_buf		*agbp)
> +	struct xfs_buf		*agbp,
> +	struct xfs_perag	*pag)
>  {
>  	struct xfs_agi		*agi;
>  	struct xfs_alloc_arg	args;
> -	xfs_agnumber_t		agno;
>  	int			error;
>  	xfs_agino_t		newino;		/* new first inode's number */
>  	xfs_agino_t		newlen;		/* new number of inodes */
>  	int			isaligned = 0;	/* inode allocation at stripe */
>  						/* unit boundary */
>  	/* init. to full chunk */
> -	uint16_t		allocmask = (uint16_t) -1;
>  	struct xfs_inobt_rec_incore rec;
> -	struct xfs_perag	*pag;
>  	struct xfs_ino_geometry	*igeo = M_IGEO(tp->t_mountp);
> +	uint16_t		allocmask = (uint16_t) -1;
>  	int			do_sparse = 0;
>  
>  	memset(&args, 0, sizeof(args));
> @@ -660,14 +657,13 @@ xfs_ialloc_ag_alloc(
>  	 */
>  	agi = agbp->b_addr;
>  	newino = be32_to_cpu(agi->agi_newino);
> -	agno = be32_to_cpu(agi->agi_seqno);
>  	args.agbno = XFS_AGINO_TO_AGBNO(args.mp, newino) +
>  		     igeo->ialloc_blks;
>  	if (do_sparse)
>  		goto sparse_alloc;
>  	if (likely(newino != NULLAGINO &&
>  		  (args.agbno < be32_to_cpu(agi->agi_length)))) {
> -		args.fsbno = XFS_AGB_TO_FSB(args.mp, agno, args.agbno);
> +		args.fsbno = XFS_AGB_TO_FSB(args.mp, pag->pag_agno, args.agbno);
>  		args.type = XFS_ALLOCTYPE_THIS_BNO;
>  		args.prod = 1;
>  
> @@ -727,7 +723,7 @@ xfs_ialloc_ag_alloc(
>  		 * For now, just allocate blocks up front.
>  		 */
>  		args.agbno = be32_to_cpu(agi->agi_root);
> -		args.fsbno = XFS_AGB_TO_FSB(args.mp, agno, args.agbno);
> +		args.fsbno = XFS_AGB_TO_FSB(args.mp, pag->pag_agno, args.agbno);
>  		/*
>  		 * Allocate a fixed-size extent of inodes.
>  		 */
> @@ -748,7 +744,7 @@ xfs_ialloc_ag_alloc(
>  	if (isaligned && args.fsbno == NULLFSBLOCK) {
>  		args.type = XFS_ALLOCTYPE_NEAR_BNO;
>  		args.agbno = be32_to_cpu(agi->agi_root);
> -		args.fsbno = XFS_AGB_TO_FSB(args.mp, agno, args.agbno);
> +		args.fsbno = XFS_AGB_TO_FSB(args.mp, pag->pag_agno, args.agbno);
>  		args.alignment = igeo->cluster_align;
>  		if ((error = xfs_alloc_vextent(&args)))
>  			return error;
> @@ -764,7 +760,7 @@ xfs_ialloc_ag_alloc(
>  sparse_alloc:
>  		args.type = XFS_ALLOCTYPE_NEAR_BNO;
>  		args.agbno = be32_to_cpu(agi->agi_root);
> -		args.fsbno = XFS_AGB_TO_FSB(args.mp, agno, args.agbno);
> +		args.fsbno = XFS_AGB_TO_FSB(args.mp, pag->pag_agno, args.agbno);
>  		args.alignment = args.mp->m_sb.sb_spino_align;
>  		args.prod = 1;
>  
> @@ -809,7 +805,7 @@ xfs_ialloc_ag_alloc(
>  	 * rather than a linear progression to prevent the next generation
>  	 * number from being easily guessable.
>  	 */
> -	error = xfs_ialloc_inode_init(args.mp, tp, NULL, newlen, agno,
> +	error = xfs_ialloc_inode_init(args.mp, tp, NULL, newlen, pag->pag_agno,
>  			args.agbno, args.len, prandom_u32());
>  
>  	if (error)
> @@ -836,12 +832,12 @@ xfs_ialloc_ag_alloc(
>  		 * if necessary. If a merge does occur, rec is updated to the
>  		 * merged record.
>  		 */
> -		error = xfs_inobt_insert_sprec(args.mp, tp, agbp, XFS_BTNUM_INO,
> -					       &rec, true);
> +		error = xfs_inobt_insert_sprec(args.mp, tp, agbp, pag,
> +				XFS_BTNUM_INO, &rec, true);
>  		if (error == -EFSCORRUPTED) {
>  			xfs_alert(args.mp,
>  	"invalid sparse inode record: ino 0x%llx holemask 0x%x count %u",
> -				  XFS_AGINO_TO_INO(args.mp, agno,
> +				  XFS_AGINO_TO_INO(args.mp, pag->pag_agno,
>  						   rec.ir_startino),
>  				  rec.ir_holemask, rec.ir_count);
>  			xfs_force_shutdown(args.mp, SHUTDOWN_CORRUPT_INCORE);
> @@ -861,21 +857,20 @@ xfs_ialloc_ag_alloc(
>  		 * existing record with this one.
>  		 */
>  		if (xfs_sb_version_hasfinobt(&args.mp->m_sb)) {
> -			error = xfs_inobt_insert_sprec(args.mp, tp, agbp,
> -						       XFS_BTNUM_FINO, &rec,
> -						       false);
> +			error = xfs_inobt_insert_sprec(args.mp, tp, agbp, pag,
> +				       XFS_BTNUM_FINO, &rec, false);
>  			if (error)
>  				return error;
>  		}
>  	} else {
>  		/* full chunk - insert new records to both btrees */
> -		error = xfs_inobt_insert(args.mp, tp, agbp, newino, newlen,
> +		error = xfs_inobt_insert(args.mp, tp, agbp, pag, newino, newlen,
>  					 XFS_BTNUM_INO);
>  		if (error)
>  			return error;
>  
>  		if (xfs_sb_version_hasfinobt(&args.mp->m_sb)) {
> -			error = xfs_inobt_insert(args.mp, tp, agbp, newino,
> +			error = xfs_inobt_insert(args.mp, tp, agbp, pag, newino,
>  						 newlen, XFS_BTNUM_FINO);
>  			if (error)
>  				return error;
> @@ -887,7 +882,6 @@ xfs_ialloc_ag_alloc(
>  	 */
>  	be32_add_cpu(&agi->agi_count, newlen);
>  	be32_add_cpu(&agi->agi_freecount, newlen);
> -	pag = agbp->b_pag;
>  	pag->pagi_freecount += newlen;
>  	pag->pagi_count += newlen;
>  	agi->agi_newino = cpu_to_be32(newino);
> @@ -1123,15 +1117,14 @@ STATIC int
>  xfs_dialloc_ag_inobt(
>  	struct xfs_trans	*tp,
>  	struct xfs_buf		*agbp,
> +	struct xfs_perag	*pag,
>  	xfs_ino_t		parent,
>  	xfs_ino_t		*inop)
>  {
>  	struct xfs_mount	*mp = tp->t_mountp;
>  	struct xfs_agi		*agi = agbp->b_addr;
> -	xfs_agnumber_t		agno = be32_to_cpu(agi->agi_seqno);
>  	xfs_agnumber_t		pagno = XFS_INO_TO_AGNO(mp, parent);
>  	xfs_agino_t		pagino = XFS_INO_TO_AGINO(mp, parent);
> -	struct xfs_perag	*pag = agbp->b_pag;
>  	struct xfs_btree_cur	*cur, *tcur;
>  	struct xfs_inobt_rec_incore rec, trec;
>  	xfs_ino_t		ino;
> @@ -1145,7 +1138,7 @@ xfs_dialloc_ag_inobt(
>  	ASSERT(pag->pagi_freecount > 0);
>  
>   restart_pagno:
> -	cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, NULL, XFS_BTNUM_INO);
> +	cur = xfs_inobt_init_cursor(mp, tp, agbp, pag, XFS_BTNUM_INO);
>  	/*
>  	 * If pagino is 0 (this is the root inode allocation) use newino.
>  	 * This must work because we've just allocated some.
> @@ -1160,7 +1153,7 @@ xfs_dialloc_ag_inobt(
>  	/*
>  	 * If in the same AG as the parent, try to get near the parent.
>  	 */
> -	if (pagno == agno) {
> +	if (pagno == pag->pag_agno) {
>  		int		doneleft;	/* done, to the left */
>  		int		doneright;	/* done, to the right */
>  
> @@ -1363,7 +1356,7 @@ xfs_dialloc_ag_inobt(
>  	ASSERT(offset < XFS_INODES_PER_CHUNK);
>  	ASSERT((XFS_AGINO_TO_OFFSET(mp, rec.ir_startino) %
>  				   XFS_INODES_PER_CHUNK) == 0);
> -	ino = XFS_AGINO_TO_INO(mp, agno, rec.ir_startino + offset);
> +	ino = XFS_AGINO_TO_INO(mp, pag->pag_agno, rec.ir_startino + offset);
>  	rec.ir_free &= ~XFS_INOBT_MASK(offset);
>  	rec.ir_freecount--;
>  	error = xfs_inobt_update(cur, &rec);
> @@ -1577,7 +1570,6 @@ xfs_dialloc_ag(
>  {
>  	struct xfs_mount		*mp = tp->t_mountp;
>  	struct xfs_agi			*agi = agbp->b_addr;
> -	xfs_agnumber_t			agno = be32_to_cpu(agi->agi_seqno);
>  	xfs_agnumber_t			pagno = XFS_INO_TO_AGNO(mp, parent);
>  	xfs_agino_t			pagino = XFS_INO_TO_AGINO(mp, parent);
>  	struct xfs_btree_cur		*cur;	/* finobt cursor */
> @@ -1587,9 +1579,10 @@ xfs_dialloc_ag(
>  	int				error;
>  	int				offset;
>  	int				i;
> +	struct xfs_perag		*pag = agbp->b_pag;
>  
>  	if (!xfs_sb_version_hasfinobt(&mp->m_sb))
> -		return xfs_dialloc_ag_inobt(tp, agbp, parent, inop);
> +		return xfs_dialloc_ag_inobt(tp, agbp, pag, parent, inop);
>  
>  	/*
>  	 * If pagino is 0 (this is the root inode allocation) use newino.
> @@ -1598,7 +1591,7 @@ xfs_dialloc_ag(
>  	if (!pagino)
>  		pagino = be32_to_cpu(agi->agi_newino);
>  
> -	cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, NULL, XFS_BTNUM_FINO);
> +	cur = xfs_inobt_init_cursor(mp, tp, agbp, pag, XFS_BTNUM_FINO);
>  
>  	error = xfs_check_agi_freecount(cur, agi);
>  	if (error)
> @@ -1609,7 +1602,7 @@ xfs_dialloc_ag(
>  	 * parent. If so, find the closest available inode to the parent. If
>  	 * not, consider the agi hint or find the first free inode in the AG.
>  	 */
> -	if (agno == pagno)
> +	if (pag->pag_agno == pagno)
>  		error = xfs_dialloc_ag_finobt_near(pagino, &cur, &rec);
>  	else
>  		error = xfs_dialloc_ag_finobt_newino(agi, cur, &rec);
> @@ -1621,7 +1614,7 @@ xfs_dialloc_ag(
>  	ASSERT(offset < XFS_INODES_PER_CHUNK);
>  	ASSERT((XFS_AGINO_TO_OFFSET(mp, rec.ir_startino) %
>  				   XFS_INODES_PER_CHUNK) == 0);
> -	ino = XFS_AGINO_TO_INO(mp, agno, rec.ir_startino + offset);
> +	ino = XFS_AGINO_TO_INO(mp, pag->pag_agno, rec.ir_startino + offset);
>  
>  	/*
>  	 * Modify or remove the finobt record.
> @@ -1641,7 +1634,7 @@ xfs_dialloc_ag(
>  	 * the original freecount. If all is well, make the equivalent update to
>  	 * the inobt using the finobt record and offset information.
>  	 */
> -	icur = xfs_inobt_init_cursor(mp, tp, agbp, agno, NULL, XFS_BTNUM_INO);
> +	icur = xfs_inobt_init_cursor(mp, tp, agbp, pag, XFS_BTNUM_INO);
>  
>  	error = xfs_check_agi_freecount(icur, agi);
>  	if (error)
> @@ -1657,7 +1650,7 @@ xfs_dialloc_ag(
>  	 */
>  	be32_add_cpu(&agi->agi_freecount, -1);
>  	xfs_ialloc_log_agi(tp, agbp, XFS_AGI_FREECOUNT);
> -	agbp->b_pag->pagi_freecount--;
> +	pag->pagi_freecount--;
>  
>  	xfs_trans_mod_sb(tp, XFS_TRANS_SB_IFREE, -1);
>  
> @@ -1809,7 +1802,7 @@ xfs_dialloc_select_ag(
>  		if (!okalloc)
>  			goto nextag_relse_buffer;
>  
> -		error = xfs_ialloc_ag_alloc(*tpp, agbp);
> +		error = xfs_ialloc_ag_alloc(*tpp, agbp, pag);
>  		if (error < 0) {
>  			xfs_trans_brelse(*tpp, agbp);
>  
> @@ -1935,12 +1928,12 @@ xfs_difree_inobt(
>  	struct xfs_mount		*mp,
>  	struct xfs_trans		*tp,
>  	struct xfs_buf			*agbp,
> +	struct xfs_perag		*pag,
>  	xfs_agino_t			agino,
>  	struct xfs_icluster		*xic,
>  	struct xfs_inobt_rec_incore	*orec)
>  {
>  	struct xfs_agi			*agi = agbp->b_addr;
> -	xfs_agnumber_t			agno = be32_to_cpu(agi->agi_seqno);
>  	struct xfs_btree_cur		*cur;
>  	struct xfs_inobt_rec_incore	rec;
>  	int				ilen;
> @@ -1954,7 +1947,7 @@ xfs_difree_inobt(
>  	/*
>  	 * Initialize the cursor.
>  	 */
> -	cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, NULL, XFS_BTNUM_INO);
> +	cur = xfs_inobt_init_cursor(mp, tp, agbp, pag, XFS_BTNUM_INO);
>  
>  	error = xfs_check_agi_freecount(cur, agi);
>  	if (error)
> @@ -2005,7 +1998,8 @@ xfs_difree_inobt(
>  		struct xfs_perag	*pag = agbp->b_pag;
>  
>  		xic->deleted = true;
> -		xic->first_ino = XFS_AGINO_TO_INO(mp, agno, rec.ir_startino);
> +		xic->first_ino = XFS_AGINO_TO_INO(mp, pag->pag_agno,
> +				rec.ir_startino);
>  		xic->alloc = xfs_inobt_irec_to_allocmask(&rec);
>  
>  		/*
> @@ -2028,7 +2022,7 @@ xfs_difree_inobt(
>  			goto error0;
>  		}
>  
> -		xfs_difree_inode_chunk(tp, agno, &rec);
> +		xfs_difree_inode_chunk(tp, pag->pag_agno, &rec);
>  	} else {
>  		xic->deleted = false;
>  
> @@ -2044,7 +2038,7 @@ xfs_difree_inobt(
>  		 */
>  		be32_add_cpu(&agi->agi_freecount, 1);
>  		xfs_ialloc_log_agi(tp, agbp, XFS_AGI_FREECOUNT);
> -		agbp->b_pag->pagi_freecount++;
> +		pag->pagi_freecount++;
>  		xfs_trans_mod_sb(tp, XFS_TRANS_SB_IFREE, 1);
>  	}
>  
> @@ -2069,18 +2063,18 @@ xfs_difree_finobt(
>  	struct xfs_mount		*mp,
>  	struct xfs_trans		*tp,
>  	struct xfs_buf			*agbp,
> +	struct xfs_perag		*pag,
>  	xfs_agino_t			agino,
>  	struct xfs_inobt_rec_incore	*ibtrec) /* inobt record */
>  {
>  	struct xfs_agi			*agi = agbp->b_addr;
> -	xfs_agnumber_t			agno = be32_to_cpu(agi->agi_seqno);
>  	struct xfs_btree_cur		*cur;
>  	struct xfs_inobt_rec_incore	rec;
>  	int				offset = agino - ibtrec->ir_startino;
>  	int				error;
>  	int				i;
>  
> -	cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, NULL, XFS_BTNUM_FINO);
> +	cur = xfs_inobt_init_cursor(mp, tp, agbp, pag, XFS_BTNUM_FINO);
>  
>  	error = xfs_inobt_lookup(cur, ibtrec->ir_startino, XFS_LOOKUP_EQ, &i);
>  	if (error)
> @@ -2188,16 +2182,15 @@ xfs_difree(
>  	xfs_agino_t		agino;	/* allocation group inode number */
>  	xfs_agnumber_t		agno;	/* allocation group number */
>  	int			error;	/* error return value */
> -	struct xfs_mount	*mp;	/* mount structure for filesystem */
> +	struct xfs_mount	*mp = tp->t_mountp;
>  	struct xfs_inobt_rec_incore rec;/* btree record */
> -
> -	mp = tp->t_mountp;
> +	struct xfs_perag	*pag;
>  
>  	/*
>  	 * Break up inode number into its components.
>  	 */
>  	agno = XFS_INO_TO_AGNO(mp, inode);
> -	if (agno >= mp->m_sb.sb_agcount)  {
> +	if (agno >= mp->m_sb.sb_agcount) {
>  		xfs_warn(mp, "%s: agno >= mp->m_sb.sb_agcount (%d >= %d).",
>  			__func__, agno, mp->m_sb.sb_agcount);
>  		ASSERT(0);
> @@ -2231,7 +2224,8 @@ xfs_difree(
>  	/*
>  	 * Fix up the inode allocation btree.
>  	 */
> -	error = xfs_difree_inobt(mp, tp, agbp, agino, xic, &rec);
> +	pag = agbp->b_pag;
> +	error = xfs_difree_inobt(mp, tp, agbp, pag, agino, xic, &rec);
>  	if (error)
>  		goto error0;
>  
> @@ -2239,7 +2233,7 @@ xfs_difree(
>  	 * Fix up the free inode btree.
>  	 */
>  	if (xfs_sb_version_hasfinobt(&mp->m_sb)) {
> -		error = xfs_difree_finobt(mp, tp, agbp, agino, &rec);
> +		error = xfs_difree_finobt(mp, tp, agbp, pag, agino, &rec);
>  		if (error)
>  			goto error0;
>  	}
> @@ -2254,7 +2248,7 @@ STATIC int
>  xfs_imap_lookup(
>  	struct xfs_mount	*mp,
>  	struct xfs_trans	*tp,
> -	xfs_agnumber_t		agno,
> +	struct xfs_perag	*pag,
>  	xfs_agino_t		agino,
>  	xfs_agblock_t		agbno,
>  	xfs_agblock_t		*chunk_agbno,
> @@ -2267,11 +2261,11 @@ xfs_imap_lookup(
>  	int			error;
>  	int			i;
>  
> -	error = xfs_ialloc_read_agi(mp, tp, agno, &agbp);
> +	error = xfs_ialloc_read_agi(mp, tp, pag->pag_agno, &agbp);
>  	if (error) {
>  		xfs_alert(mp,
>  			"%s: xfs_ialloc_read_agi() returned error %d, agno %d",
> -			__func__, error, agno);
> +			__func__, error, pag->pag_agno);
>  		return error;
>  	}
>  
> @@ -2281,7 +2275,7 @@ xfs_imap_lookup(
>  	 * we have a record, we need to ensure it contains the inode number
>  	 * we are looking up.
>  	 */
> -	cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, NULL, XFS_BTNUM_INO);
> +	cur = xfs_inobt_init_cursor(mp, tp, agbp, pag, XFS_BTNUM_INO);
>  	error = xfs_inobt_lookup(cur, agino, XFS_LOOKUP_LE, &i);
>  	if (!error) {
>  		if (i)
> @@ -2315,42 +2309,44 @@ xfs_imap_lookup(
>   */
>  int
>  xfs_imap(
> -	xfs_mount_t	 *mp,	/* file system mount structure */
> -	xfs_trans_t	 *tp,	/* transaction pointer */
> -	xfs_ino_t	ino,	/* inode to locate */
> -	struct xfs_imap	*imap,	/* location map structure */
> -	uint		flags)	/* flags for inode btree lookup */
> +	struct xfs_mount	 *mp,	/* file system mount structure */
> +	struct xfs_trans	 *tp,	/* transaction pointer */
> +	xfs_ino_t		ino,	/* inode to locate */
> +	struct xfs_imap		*imap,	/* location map structure */
> +	uint			flags)	/* flags for inode btree lookup */
>  {
> -	xfs_agblock_t	agbno;	/* block number of inode in the alloc group */
> -	xfs_agino_t	agino;	/* inode number within alloc group */
> -	xfs_agnumber_t	agno;	/* allocation group number */
> -	xfs_agblock_t	chunk_agbno;	/* first block in inode chunk */
> -	xfs_agblock_t	cluster_agbno;	/* first block in inode cluster */
> -	int		error;	/* error code */
> -	int		offset;	/* index of inode in its buffer */
> -	xfs_agblock_t	offset_agbno;	/* blks from chunk start to inode */
> +	xfs_agblock_t		agbno;	/* block number of inode in the alloc group */
> +	xfs_agino_t		agino;	/* inode number within alloc group */
> +	xfs_agblock_t		chunk_agbno;	/* first block in inode chunk */
> +	xfs_agblock_t		cluster_agbno;	/* first block in inode cluster */
> +	int			error;	/* error code */
> +	int			offset;	/* index of inode in its buffer */
> +	xfs_agblock_t		offset_agbno;	/* blks from chunk start to inode */
> +	struct xfs_perag	*pag;
>  
>  	ASSERT(ino != NULLFSINO);
>  
>  	/*
>  	 * Split up the inode number into its parts.
>  	 */
> -	agno = XFS_INO_TO_AGNO(mp, ino);
> +	pag = xfs_perag_get(mp, XFS_INO_TO_AGNO(mp, ino));
>  	agino = XFS_INO_TO_AGINO(mp, ino);
>  	agbno = XFS_AGINO_TO_AGBNO(mp, agino);
> -	if (agno >= mp->m_sb.sb_agcount || agbno >= mp->m_sb.sb_agblocks ||
> -	    ino != XFS_AGINO_TO_INO(mp, agno, agino)) {
> +	if (!pag || agbno >= mp->m_sb.sb_agblocks ||
> +	    ino != XFS_AGINO_TO_INO(mp, pag->pag_agno, agino)) {
> +		error = -EINVAL;
>  #ifdef DEBUG
>  		/*
>  		 * Don't output diagnostic information for untrusted inodes
>  		 * as they can be invalid without implying corruption.
>  		 */
>  		if (flags & XFS_IGET_UNTRUSTED)
> -			return -EINVAL;
> -		if (agno >= mp->m_sb.sb_agcount) {
> +			goto out_drop;
> +		if (!pag) {
>  			xfs_alert(mp,
>  				"%s: agno (%d) >= mp->m_sb.sb_agcount (%d)",
> -				__func__, agno, mp->m_sb.sb_agcount);
> +				__func__, XFS_INO_TO_AGNO(mp, ino),
> +				mp->m_sb.sb_agcount);
>  		}
>  		if (agbno >= mp->m_sb.sb_agblocks) {
>  			xfs_alert(mp,
> @@ -2358,15 +2354,15 @@ xfs_imap(
>  				__func__, (unsigned long long)agbno,
>  				(unsigned long)mp->m_sb.sb_agblocks);
>  		}
> -		if (ino != XFS_AGINO_TO_INO(mp, agno, agino)) {
> +		if (pag && ino != XFS_AGINO_TO_INO(mp, pag->pag_agno, agino)) {
>  			xfs_alert(mp,
>  		"%s: ino (0x%llx) != XFS_AGINO_TO_INO() (0x%llx)",
>  				__func__, ino,
> -				XFS_AGINO_TO_INO(mp, agno, agino));
> +				XFS_AGINO_TO_INO(mp, pag->pag_agno, agino));
>  		}
>  		xfs_stack_trace();
>  #endif /* DEBUG */
> -		return -EINVAL;
> +		goto out_drop;
>  	}
>  
>  	/*
> @@ -2377,10 +2373,10 @@ xfs_imap(
>  	 * in all cases where an untrusted inode number is passed.
>  	 */
>  	if (flags & XFS_IGET_UNTRUSTED) {
> -		error = xfs_imap_lookup(mp, tp, agno, agino, agbno,
> +		error = xfs_imap_lookup(mp, tp, pag, agino, agbno,
>  					&chunk_agbno, &offset_agbno, flags);
>  		if (error)
> -			return error;
> +			goto out_drop;
>  		goto out_map;
>  	}
>  
> @@ -2392,11 +2388,12 @@ xfs_imap(
>  		offset = XFS_INO_TO_OFFSET(mp, ino);
>  		ASSERT(offset < mp->m_sb.sb_inopblock);
>  
> -		imap->im_blkno = XFS_AGB_TO_DADDR(mp, agno, agbno);
> +		imap->im_blkno = XFS_AGB_TO_DADDR(mp, pag->pag_agno, agbno);
>  		imap->im_len = XFS_FSB_TO_BB(mp, 1);
>  		imap->im_boffset = (unsigned short)(offset <<
>  							mp->m_sb.sb_inodelog);
> -		return 0;
> +		error = 0;
> +		goto out_drop;
>  	}
>  
>  	/*
> @@ -2408,10 +2405,10 @@ xfs_imap(
>  		offset_agbno = agbno & M_IGEO(mp)->inoalign_mask;
>  		chunk_agbno = agbno - offset_agbno;
>  	} else {
> -		error = xfs_imap_lookup(mp, tp, agno, agino, agbno,
> +		error = xfs_imap_lookup(mp, tp, pag, agino, agbno,
>  					&chunk_agbno, &offset_agbno, flags);
>  		if (error)
> -			return error;
> +			goto out_drop;
>  	}
>  
>  out_map:
> @@ -2422,7 +2419,7 @@ xfs_imap(
>  	offset = ((agbno - cluster_agbno) * mp->m_sb.sb_inopblock) +
>  		XFS_INO_TO_OFFSET(mp, ino);
>  
> -	imap->im_blkno = XFS_AGB_TO_DADDR(mp, agno, cluster_agbno);
> +	imap->im_blkno = XFS_AGB_TO_DADDR(mp, pag->pag_agno, cluster_agbno);
>  	imap->im_len = XFS_FSB_TO_BB(mp, M_IGEO(mp)->blocks_per_cluster);
>  	imap->im_boffset = (unsigned short)(offset << mp->m_sb.sb_inodelog);
>  
> @@ -2439,9 +2436,13 @@ xfs_imap(
>  			__func__, (unsigned long long) imap->im_blkno,
>  			(unsigned long long) imap->im_len,
>  			XFS_FSB_TO_BB(mp, mp->m_sb.sb_dblocks));
> -		return -EINVAL;
> +		error = -EINVAL;
> +		goto out_drop;
>  	}
> -	return 0;
> +	error = 0;
> +out_drop:
> +	xfs_perag_put(pag);
> +	return error;
>  }
>  
>  /*
> diff --git a/fs/xfs/libxfs/xfs_ialloc_btree.c b/fs/xfs/libxfs/xfs_ialloc_btree.c
> index 6c4efdf01674..450161b53648 100644
> --- a/fs/xfs/libxfs/xfs_ialloc_btree.c
> +++ b/fs/xfs/libxfs/xfs_ialloc_btree.c
> @@ -35,8 +35,7 @@ xfs_inobt_dup_cursor(
>  	struct xfs_btree_cur	*cur)
>  {
>  	return xfs_inobt_init_cursor(cur->bc_mp, cur->bc_tp,
> -			cur->bc_ag.agbp, cur->bc_ag.agno,
> -			cur->bc_ag.pag, cur->bc_btnum);
> +			cur->bc_ag.agbp, cur->bc_ag.pag, cur->bc_btnum);
>  }
>  
>  STATIC void
> @@ -428,7 +427,6 @@ static struct xfs_btree_cur *
>  xfs_inobt_init_common(
>  	struct xfs_mount	*mp,		/* file system mount point */
>  	struct xfs_trans	*tp,		/* transaction pointer */
> -	xfs_agnumber_t		agno,		/* allocation group number */
>  	struct xfs_perag	*pag,
>  	xfs_btnum_t		btnum)		/* ialloc or free ino btree */
>  {
> @@ -451,12 +449,10 @@ xfs_inobt_init_common(
>  	if (xfs_sb_version_hascrc(&mp->m_sb))
>  		cur->bc_flags |= XFS_BTREE_CRC_BLOCKS;
>  
> -	cur->bc_ag.agno = agno;
> -	if (pag) {
> -		/* take a reference for the cursor */
> -		atomic_inc(&pag->pag_ref);
> -	}
> +	/* take a reference for the cursor */
> +	atomic_inc(&pag->pag_ref);
>  	cur->bc_ag.pag = pag;
> +	cur->bc_ag.agno = pag->pag_agno;
>  	return cur;
>  }
>  
> @@ -466,14 +462,13 @@ xfs_inobt_init_cursor(
>  	struct xfs_mount	*mp,
>  	struct xfs_trans	*tp,
>  	struct xfs_buf		*agbp,
> -	xfs_agnumber_t		agno,
>  	struct xfs_perag	*pag,
>  	xfs_btnum_t		btnum)
>  {
>  	struct xfs_btree_cur	*cur;
>  	struct xfs_agi		*agi = agbp->b_addr;
>  
> -	cur = xfs_inobt_init_common(mp, tp, agno, pag, btnum);
> +	cur = xfs_inobt_init_common(mp, tp, pag, btnum);
>  	if (btnum == XFS_BTNUM_INO)
>  		cur->bc_nlevels = be32_to_cpu(agi->agi_level);
>  	else
> @@ -487,12 +482,12 @@ struct xfs_btree_cur *
>  xfs_inobt_stage_cursor(
>  	struct xfs_mount	*mp,
>  	struct xbtree_afakeroot	*afake,
> -	xfs_agnumber_t		agno,
> +	struct xfs_perag	*pag,
>  	xfs_btnum_t		btnum)
>  {
>  	struct xfs_btree_cur	*cur;
>  
> -	cur = xfs_inobt_init_common(mp, NULL, agno, NULL, btnum);
> +	cur = xfs_inobt_init_common(mp, NULL, pag, btnum);
>  	xfs_btree_stage_afakeroot(cur, afake);
>  	return cur;
>  }
> @@ -664,7 +659,7 @@ int
>  xfs_inobt_cur(
>  	struct xfs_mount	*mp,
>  	struct xfs_trans	*tp,
> -	xfs_agnumber_t		agno,
> +	struct xfs_perag	*pag,
>  	xfs_btnum_t		which,
>  	struct xfs_btree_cur	**curpp,
>  	struct xfs_buf		**agi_bpp)
> @@ -675,11 +670,11 @@ xfs_inobt_cur(
>  	ASSERT(*agi_bpp == NULL);
>  	ASSERT(*curpp == NULL);
>  
> -	error = xfs_ialloc_read_agi(mp, tp, agno, agi_bpp);
> +	error = xfs_ialloc_read_agi(mp, tp, pag->pag_agno, agi_bpp);
>  	if (error)
>  		return error;
>  
> -	cur = xfs_inobt_init_cursor(mp, tp, *agi_bpp, agno, NULL, which);
> +	cur = xfs_inobt_init_cursor(mp, tp, *agi_bpp, pag, which);
>  	*curpp = cur;
>  	return 0;
>  }
> @@ -696,7 +691,7 @@ xfs_inobt_count_blocks(
>  	struct xfs_btree_cur	*cur = NULL;
>  	int			error;
>  
> -	error = xfs_inobt_cur(mp, tp, pag->pag_agno, btnum, &cur, &agbp);
> +	error = xfs_inobt_cur(mp, tp, pag, btnum, &cur, &agbp);
>  	if (error)
>  		return error;
>  
> diff --git a/fs/xfs/libxfs/xfs_ialloc_btree.h b/fs/xfs/libxfs/xfs_ialloc_btree.h
> index 04dfa7eee81f..e530c82b2217 100644
> --- a/fs/xfs/libxfs/xfs_ialloc_btree.h
> +++ b/fs/xfs/libxfs/xfs_ialloc_btree.h
> @@ -47,10 +47,10 @@ struct xfs_perag;
>  		 ((index) - 1) * sizeof(xfs_inobt_ptr_t)))
>  
>  extern struct xfs_btree_cur *xfs_inobt_init_cursor(struct xfs_mount *mp,
> -		struct xfs_trans *tp, struct xfs_buf *agbp, xfs_agnumber_t agno,
> +		struct xfs_trans *tp, struct xfs_buf *agbp,
>  		struct xfs_perag *pag, xfs_btnum_t btnum);
>  struct xfs_btree_cur *xfs_inobt_stage_cursor(struct xfs_mount *mp,
> -		struct xbtree_afakeroot *afake, xfs_agnumber_t agno,
> +		struct xbtree_afakeroot *afake, struct xfs_perag *pag,
>  		xfs_btnum_t btnum);
>  extern int xfs_inobt_maxrecs(struct xfs_mount *, int, int);
>  
> @@ -69,7 +69,7 @@ int xfs_finobt_calc_reserves(struct xfs_mount *mp, struct xfs_trans *tp,
>  extern xfs_extlen_t xfs_iallocbt_calc_size(struct xfs_mount *mp,
>  		unsigned long long len);
>  int xfs_inobt_cur(struct xfs_mount *mp, struct xfs_trans *tp,
> -		xfs_agnumber_t agno, xfs_btnum_t btnum,
> +		struct xfs_perag *pag, xfs_btnum_t btnum,
>  		struct xfs_btree_cur **curpp, struct xfs_buf **agi_bpp);
>  
>  void xfs_inobt_commit_staged_btree(struct xfs_btree_cur *cur,
> diff --git a/fs/xfs/scrub/agheader_repair.c b/fs/xfs/scrub/agheader_repair.c
> index ee2d85e3fd4a..ecc9146647ba 100644
> --- a/fs/xfs/scrub/agheader_repair.c
> +++ b/fs/xfs/scrub/agheader_repair.c
> @@ -806,7 +806,7 @@ xrep_agi_calc_from_btrees(
>  	xfs_agino_t		freecount;
>  	int			error;
>  
> -	cur = xfs_inobt_init_cursor(mp, sc->tp, agi_bp, sc->sa.agno,
> +	cur = xfs_inobt_init_cursor(mp, sc->tp, agi_bp,
>  			sc->sa.pag, XFS_BTNUM_INO);
>  	error = xfs_ialloc_count_inodes(cur, &count, &freecount);
>  	if (error)
> @@ -828,7 +828,7 @@ xrep_agi_calc_from_btrees(
>  	    xfs_sb_version_hasinobtcounts(&mp->m_sb)) {
>  		xfs_agblock_t	blocks;
>  
> -		cur = xfs_inobt_init_cursor(mp, sc->tp, agi_bp, sc->sa.agno,
> +		cur = xfs_inobt_init_cursor(mp, sc->tp, agi_bp,
>  				sc->sa.pag, XFS_BTNUM_FINO);
>  		error = xfs_btree_count_blocks(cur, &blocks);
>  		if (error)
> diff --git a/fs/xfs/scrub/common.c b/fs/xfs/scrub/common.c
> index 3035f8cee6f6..64c3b9b78d0d 100644
> --- a/fs/xfs/scrub/common.c
> +++ b/fs/xfs/scrub/common.c
> @@ -458,7 +458,6 @@ xchk_ag_btcur_init(
>  	struct xchk_ag		*sa)
>  {
>  	struct xfs_mount	*mp = sc->mp;
> -	xfs_agnumber_t		agno = sa->agno;
>  
>  	xchk_perag_get(sc->mp, sa);
>  	if (sa->agf_bp &&
> @@ -479,14 +478,14 @@ xchk_ag_btcur_init(
>  	if (sa->agi_bp &&
>  	    xchk_ag_btree_healthy_enough(sc, sa->pag, XFS_BTNUM_INO)) {
>  		sa->ino_cur = xfs_inobt_init_cursor(mp, sc->tp, sa->agi_bp,
> -				agno, sa->pag, XFS_BTNUM_INO);
> +				sa->pag, XFS_BTNUM_INO);
>  	}
>  
>  	/* Set up a finobt cursor for cross-referencing. */
>  	if (sa->agi_bp && xfs_sb_version_hasfinobt(&mp->m_sb) &&
>  	    xchk_ag_btree_healthy_enough(sc, sa->pag, XFS_BTNUM_FINO)) {
>  		sa->fino_cur = xfs_inobt_init_cursor(mp, sc->tp, sa->agi_bp,
> -				agno, sa->pag, XFS_BTNUM_FINO);
> +				sa->pag, XFS_BTNUM_FINO);
>  	}
>  
>  	/* Set up a rmapbt cursor for cross-referencing. */
> diff --git a/fs/xfs/xfs_iwalk.c b/fs/xfs/xfs_iwalk.c
> index c7e8f48a3ec4..917d51eefee3 100644
> --- a/fs/xfs/xfs_iwalk.c
> +++ b/fs/xfs/xfs_iwalk.c
> @@ -272,8 +272,7 @@ xfs_iwalk_ag_start(
>  
>  	/* Set up a fresh cursor and empty the inobt cache. */
>  	iwag->nr_recs = 0;
> -	error = xfs_inobt_cur(mp, tp, pag->pag_agno, XFS_BTNUM_INO,
> -				curpp, agi_bpp);
> +	error = xfs_inobt_cur(mp, tp, pag, XFS_BTNUM_INO, curpp, agi_bpp);
>  	if (error)
>  		return error;
>  
> @@ -378,8 +377,7 @@ xfs_iwalk_run_callbacks(
>  		return 0;
>  
>  	/* ...and recreate the cursor just past where we left off. */
> -	error = xfs_inobt_cur(mp, tp, iwag->pag->pag_agno, XFS_BTNUM_INO,
> -				curpp, agi_bpp);
> +	error = xfs_inobt_cur(mp, tp, iwag->pag, XFS_BTNUM_INO, curpp, agi_bpp);
>  	if (error)
>  		return error;
>  
> -- 
> 2.31.1
> 


^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 16/22] xfs: remove agno from btree cursor
  2021-05-06  7:20 ` [PATCH 16/22] xfs: remove agno from btree cursor Dave Chinner
@ 2021-05-11 12:34   ` Brian Foster
  2021-05-11 22:02     ` Dave Chinner
  2021-05-12 22:52   ` Darrick J. Wong
  1 sibling, 1 reply; 87+ messages in thread
From: Brian Foster @ 2021-05-11 12:34 UTC (permalink / raw)
  To: Dave Chinner; +Cc: linux-xfs

On Thu, May 06, 2021 at 05:20:48PM +1000, Dave Chinner wrote:
> From: Dave Chinner <dchinner@redhat.com>
> 
> Now that everything passes a perag, the agno is not needed anymore.
> Convert all the users to use pag->pag_agno instead and remove the
> agno from the cursor. This was largely done as an automated search
> and replace.
> 
> Signed-off-by: Dave Chinner <dchinner@redhat.com>
> ---
>  fs/xfs/libxfs/xfs_alloc.c          |   2 +-
>  fs/xfs/libxfs/xfs_alloc_btree.c    |   1 -
>  fs/xfs/libxfs/xfs_btree.c          |  12 ++--
>  fs/xfs/libxfs/xfs_btree.h          |   1 -
>  fs/xfs/libxfs/xfs_ialloc.c         |   2 +-
>  fs/xfs/libxfs/xfs_ialloc_btree.c   |   7 +-
>  fs/xfs/libxfs/xfs_refcount.c       |  82 +++++++++++-----------
>  fs/xfs/libxfs/xfs_refcount_btree.c |  11 ++-
>  fs/xfs/libxfs/xfs_rmap.c           | 108 ++++++++++++++---------------
>  fs/xfs/libxfs/xfs_rmap_btree.c     |   1 -
>  fs/xfs/scrub/agheader_repair.c     |   2 +-
>  fs/xfs/scrub/alloc.c               |   3 +-
>  fs/xfs/scrub/bmap.c                |   2 +-
>  fs/xfs/scrub/ialloc.c              |   9 +--
>  fs/xfs/scrub/refcount.c            |   3 +-
>  fs/xfs/scrub/rmap.c                |   3 +-
>  fs/xfs/scrub/trace.c               |   3 +-
>  fs/xfs/xfs_fsmap.c                 |   4 +-
>  fs/xfs/xfs_trace.h                 |   4 +-
>  19 files changed, 130 insertions(+), 130 deletions(-)
> 
...
> diff --git a/fs/xfs/libxfs/xfs_rmap.c b/fs/xfs/libxfs/xfs_rmap.c
> index b23f949ee15c..d1dfad0204e3 100644
> --- a/fs/xfs/libxfs/xfs_rmap.c
> +++ b/fs/xfs/libxfs/xfs_rmap.c
...
> @@ -2389,7 +2389,7 @@ xfs_rmap_finish_one(
>  	 * the startblock, get one now.
>  	 */
>  	rcur = *pcur;
> -	if (rcur != NULL && rcur->bc_ag.agno != pag->pag_agno) {
> +	if (rcur != NULL && rcur->bc_ag.pag != pag) {

I wonder a bit about this sort of logic if the goal is to ultimately
allow for dynamic instantiation of perag structures, though it's
probably not an issue here.

>  		xfs_rmap_finish_one_cleanup(tp, rcur, 0);
>  		rcur = NULL;
>  		*pcur = NULL;
...
> diff --git a/fs/xfs/xfs_trace.h b/fs/xfs/xfs_trace.h
> index 808ae337b222..5ba9c6396dcb 100644
> --- a/fs/xfs/xfs_trace.h
> +++ b/fs/xfs/xfs_trace.h
> @@ -3730,7 +3730,7 @@ TRACE_EVENT(xfs_btree_commit_afakeroot,
>  	TP_fast_assign(
>  		__entry->dev = cur->bc_mp->m_super->s_dev;
>  		__entry->btnum = cur->bc_btnum;
> -		__entry->agno = cur->bc_ag.agno;
> +		__entry->agno = cur->bc_ag.pag->pag_agno;

It would be nice if we did this with some of the other tracepoints
rather than pulling ->pag_agno out at every callsite, but that's
probably something for another patch. All in all this looks fine to me:

Reviewed-by: Brian Foster <bfoster@redhat.com>

>  		__entry->agbno = cur->bc_ag.afake->af_root;
>  		__entry->levels = cur->bc_ag.afake->af_levels;
>  		__entry->blocks = cur->bc_ag.afake->af_blocks;
> @@ -3845,7 +3845,7 @@ TRACE_EVENT(xfs_btree_bload_block,
>  			__entry->agno = XFS_FSB_TO_AGNO(cur->bc_mp, fsb);
>  			__entry->agbno = XFS_FSB_TO_AGBNO(cur->bc_mp, fsb);
>  		} else {
> -			__entry->agno = cur->bc_ag.agno;
> +			__entry->agno = cur->bc_ag.pag->pag_agno;
>  			__entry->agbno = be32_to_cpu(ptr->s);
>  		}
>  		__entry->nr_records = nr_records;
> -- 
> 2.31.1
> 


^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 11/22] xfs: add a perag to the btree cursor
  2021-05-11 12:30   ` Brian Foster
@ 2021-05-11 20:51     ` Darrick J. Wong
  2021-05-11 21:52       ` Dave Chinner
  0 siblings, 1 reply; 87+ messages in thread
From: Darrick J. Wong @ 2021-05-11 20:51 UTC (permalink / raw)
  To: Brian Foster; +Cc: Dave Chinner, linux-xfs

On Tue, May 11, 2021 at 08:30:22AM -0400, Brian Foster wrote:
> On Thu, May 06, 2021 at 05:20:43PM +1000, Dave Chinner wrote:
> > From: Dave Chinner <dchinner@redhat.com>
> > 
> > Which will eventually completely replace the agno in it.
> > 
> > Signed-off-by: Dave Chinner <dchinner@redhat.com>
> > ---
> >  fs/xfs/libxfs/xfs_alloc.c          | 25 +++++++++++++++----------
> >  fs/xfs/libxfs/xfs_alloc_btree.c    | 13 ++++++++++---
> >  fs/xfs/libxfs/xfs_alloc_btree.h    |  3 ++-
> >  fs/xfs/libxfs/xfs_btree.c          |  2 ++
> >  fs/xfs/libxfs/xfs_btree.h          |  4 +++-
> >  fs/xfs/libxfs/xfs_ialloc.c         | 16 ++++++++--------
> >  fs/xfs/libxfs/xfs_ialloc_btree.c   | 15 +++++++++++----
> >  fs/xfs/libxfs/xfs_ialloc_btree.h   |  7 ++++---
> >  fs/xfs/libxfs/xfs_refcount.c       |  4 ++--
> >  fs/xfs/libxfs/xfs_refcount_btree.c | 17 ++++++++++++-----
> >  fs/xfs/libxfs/xfs_refcount_btree.h |  2 +-
> >  fs/xfs/libxfs/xfs_rmap.c           |  6 +++---
> >  fs/xfs/libxfs/xfs_rmap_btree.c     | 17 ++++++++++++-----
> >  fs/xfs/libxfs/xfs_rmap_btree.h     |  2 +-
> >  fs/xfs/scrub/agheader_repair.c     | 20 +++++++++++---------
> >  fs/xfs/scrub/bmap.c                |  2 +-
> >  fs/xfs/scrub/common.c              | 12 ++++++------
> >  fs/xfs/scrub/repair.c              |  5 +++--
> >  fs/xfs/xfs_discard.c               |  2 +-
> >  fs/xfs/xfs_fsmap.c                 |  6 +++---
> >  fs/xfs/xfs_reflink.c               |  2 +-
> >  21 files changed, 112 insertions(+), 70 deletions(-)
> > 
> ...
> > diff --git a/fs/xfs/libxfs/xfs_btree.c b/fs/xfs/libxfs/xfs_btree.c
> > index 0f12b885600d..44044317c0fb 100644
> > --- a/fs/xfs/libxfs/xfs_btree.c
> > +++ b/fs/xfs/libxfs/xfs_btree.c
> > @@ -377,6 +377,8 @@ xfs_btree_del_cursor(
> >  	       XFS_FORCED_SHUTDOWN(cur->bc_mp));
> >  	if (unlikely(cur->bc_flags & XFS_BTREE_STAGING))
> >  		kmem_free(cur->bc_ops);
> > +	if (!(cur->bc_flags & XFS_BTREE_LONG_PTRS) && cur->bc_ag.pag)
> > +		xfs_perag_put(cur->bc_ag.pag);
> 
> What's the correlation with BTREE_LONG_PTRS?

maybe this should be:

	if (!(cur->bc_flags & XFS_BTREE_ROOT_IN_INODE))
		xfs_perag_put(cur->bc_ag.pag);

?

--D

> Brian
> 
> >  	kmem_cache_free(xfs_btree_cur_zone, cur);
> >  }
> >  
> > diff --git a/fs/xfs/libxfs/xfs_btree.h b/fs/xfs/libxfs/xfs_btree.h
> > index 10e50cbacacf..8233f8679ba9 100644
> > --- a/fs/xfs/libxfs/xfs_btree.h
> > +++ b/fs/xfs/libxfs/xfs_btree.h
> > @@ -11,6 +11,7 @@ struct xfs_inode;
> >  struct xfs_mount;
> >  struct xfs_trans;
> >  struct xfs_ifork;
> > +struct xfs_perag;
> >  
> >  extern kmem_zone_t	*xfs_btree_cur_zone;
> >  
> > @@ -180,11 +181,12 @@ union xfs_btree_irec {
> >  
> >  /* Per-AG btree information. */
> >  struct xfs_btree_cur_ag {
> > +	xfs_agnumber_t		agno;
> > +	struct xfs_perag	*pag;
> >  	union {
> >  		struct xfs_buf		*agbp;
> >  		struct xbtree_afakeroot	*afake;	/* for staging cursor */
> >  	};
> > -	xfs_agnumber_t		agno;
> >  	union {
> >  		struct {
> >  			unsigned long nr_ops;	/* # record updates */
> > diff --git a/fs/xfs/libxfs/xfs_ialloc.c b/fs/xfs/libxfs/xfs_ialloc.c
> > index 8dc9225a5353..905872bab426 100644
> > --- a/fs/xfs/libxfs/xfs_ialloc.c
> > +++ b/fs/xfs/libxfs/xfs_ialloc.c
> > @@ -183,7 +183,7 @@ xfs_inobt_insert(
> >  	int			i;
> >  	int			error;
> >  
> > -	cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, btnum);
> > +	cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, NULL, btnum);
> >  
> >  	for (thisino = newino;
> >  	     thisino < newino + newlen;
> > @@ -531,7 +531,7 @@ xfs_inobt_insert_sprec(
> >  	int				i;
> >  	struct xfs_inobt_rec_incore	rec;
> >  
> > -	cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, btnum);
> > +	cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, NULL, btnum);
> >  
> >  	/* the new record is pre-aligned so we know where to look */
> >  	error = xfs_inobt_lookup(cur, nrec->ir_startino, XFS_LOOKUP_EQ, &i);
> > @@ -1145,7 +1145,7 @@ xfs_dialloc_ag_inobt(
> >  	ASSERT(pag->pagi_freecount > 0);
> >  
> >   restart_pagno:
> > -	cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_INO);
> > +	cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, NULL, XFS_BTNUM_INO);
> >  	/*
> >  	 * If pagino is 0 (this is the root inode allocation) use newino.
> >  	 * This must work because we've just allocated some.
> > @@ -1598,7 +1598,7 @@ xfs_dialloc_ag(
> >  	if (!pagino)
> >  		pagino = be32_to_cpu(agi->agi_newino);
> >  
> > -	cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_FINO);
> > +	cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, NULL, XFS_BTNUM_FINO);
> >  
> >  	error = xfs_check_agi_freecount(cur, agi);
> >  	if (error)
> > @@ -1641,7 +1641,7 @@ xfs_dialloc_ag(
> >  	 * the original freecount. If all is well, make the equivalent update to
> >  	 * the inobt using the finobt record and offset information.
> >  	 */
> > -	icur = xfs_inobt_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_INO);
> > +	icur = xfs_inobt_init_cursor(mp, tp, agbp, agno, NULL, XFS_BTNUM_INO);
> >  
> >  	error = xfs_check_agi_freecount(icur, agi);
> >  	if (error)
> > @@ -1954,7 +1954,7 @@ xfs_difree_inobt(
> >  	/*
> >  	 * Initialize the cursor.
> >  	 */
> > -	cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_INO);
> > +	cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, NULL, XFS_BTNUM_INO);
> >  
> >  	error = xfs_check_agi_freecount(cur, agi);
> >  	if (error)
> > @@ -2080,7 +2080,7 @@ xfs_difree_finobt(
> >  	int				error;
> >  	int				i;
> >  
> > -	cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_FINO);
> > +	cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, NULL, XFS_BTNUM_FINO);
> >  
> >  	error = xfs_inobt_lookup(cur, ibtrec->ir_startino, XFS_LOOKUP_EQ, &i);
> >  	if (error)
> > @@ -2281,7 +2281,7 @@ xfs_imap_lookup(
> >  	 * we have a record, we need to ensure it contains the inode number
> >  	 * we are looking up.
> >  	 */
> > -	cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_INO);
> > +	cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, NULL, XFS_BTNUM_INO);
> >  	error = xfs_inobt_lookup(cur, agino, XFS_LOOKUP_LE, &i);
> >  	if (!error) {
> >  		if (i)
> > diff --git a/fs/xfs/libxfs/xfs_ialloc_btree.c b/fs/xfs/libxfs/xfs_ialloc_btree.c
> > index 4ec8ea1331a5..6c4efdf01674 100644
> > --- a/fs/xfs/libxfs/xfs_ialloc_btree.c
> > +++ b/fs/xfs/libxfs/xfs_ialloc_btree.c
> > @@ -36,7 +36,7 @@ xfs_inobt_dup_cursor(
> >  {
> >  	return xfs_inobt_init_cursor(cur->bc_mp, cur->bc_tp,
> >  			cur->bc_ag.agbp, cur->bc_ag.agno,
> > -			cur->bc_btnum);
> > +			cur->bc_ag.pag, cur->bc_btnum);
> >  }
> >  
> >  STATIC void
> > @@ -429,6 +429,7 @@ xfs_inobt_init_common(
> >  	struct xfs_mount	*mp,		/* file system mount point */
> >  	struct xfs_trans	*tp,		/* transaction pointer */
> >  	xfs_agnumber_t		agno,		/* allocation group number */
> > +	struct xfs_perag	*pag,
> >  	xfs_btnum_t		btnum)		/* ialloc or free ino btree */
> >  {
> >  	struct xfs_btree_cur	*cur;
> > @@ -451,6 +452,11 @@ xfs_inobt_init_common(
> >  		cur->bc_flags |= XFS_BTREE_CRC_BLOCKS;
> >  
> >  	cur->bc_ag.agno = agno;
> > +	if (pag) {
> > +		/* take a reference for the cursor */
> > +		atomic_inc(&pag->pag_ref);
> > +	}
> > +	cur->bc_ag.pag = pag;
> >  	return cur;
> >  }
> >  
> > @@ -461,12 +467,13 @@ xfs_inobt_init_cursor(
> >  	struct xfs_trans	*tp,
> >  	struct xfs_buf		*agbp,
> >  	xfs_agnumber_t		agno,
> > +	struct xfs_perag	*pag,
> >  	xfs_btnum_t		btnum)
> >  {
> >  	struct xfs_btree_cur	*cur;
> >  	struct xfs_agi		*agi = agbp->b_addr;
> >  
> > -	cur = xfs_inobt_init_common(mp, tp, agno, btnum);
> > +	cur = xfs_inobt_init_common(mp, tp, agno, pag, btnum);
> >  	if (btnum == XFS_BTNUM_INO)
> >  		cur->bc_nlevels = be32_to_cpu(agi->agi_level);
> >  	else
> > @@ -485,7 +492,7 @@ xfs_inobt_stage_cursor(
> >  {
> >  	struct xfs_btree_cur	*cur;
> >  
> > -	cur = xfs_inobt_init_common(mp, NULL, agno, btnum);
> > +	cur = xfs_inobt_init_common(mp, NULL, agno, NULL, btnum);
> >  	xfs_btree_stage_afakeroot(cur, afake);
> >  	return cur;
> >  }
> > @@ -672,7 +679,7 @@ xfs_inobt_cur(
> >  	if (error)
> >  		return error;
> >  
> > -	cur = xfs_inobt_init_cursor(mp, tp, *agi_bpp, agno, which);
> > +	cur = xfs_inobt_init_cursor(mp, tp, *agi_bpp, agno, NULL, which);
> >  	*curpp = cur;
> >  	return 0;
> >  }
> > diff --git a/fs/xfs/libxfs/xfs_ialloc_btree.h b/fs/xfs/libxfs/xfs_ialloc_btree.h
> > index d5afe01fb2de..04dfa7eee81f 100644
> > --- a/fs/xfs/libxfs/xfs_ialloc_btree.h
> > +++ b/fs/xfs/libxfs/xfs_ialloc_btree.h
> > @@ -13,6 +13,7 @@
> >  struct xfs_buf;
> >  struct xfs_btree_cur;
> >  struct xfs_mount;
> > +struct xfs_perag;
> >  
> >  /*
> >   * Btree block header size depends on a superblock flag.
> > @@ -45,9 +46,9 @@ struct xfs_mount;
> >  		 (maxrecs) * sizeof(xfs_inobt_key_t) + \
> >  		 ((index) - 1) * sizeof(xfs_inobt_ptr_t)))
> >  
> > -extern struct xfs_btree_cur *xfs_inobt_init_cursor(struct xfs_mount *,
> > -		struct xfs_trans *, struct xfs_buf *, xfs_agnumber_t,
> > -		xfs_btnum_t);
> > +extern struct xfs_btree_cur *xfs_inobt_init_cursor(struct xfs_mount *mp,
> > +		struct xfs_trans *tp, struct xfs_buf *agbp, xfs_agnumber_t agno,
> > +		struct xfs_perag *pag, xfs_btnum_t btnum);
> >  struct xfs_btree_cur *xfs_inobt_stage_cursor(struct xfs_mount *mp,
> >  		struct xbtree_afakeroot *afake, xfs_agnumber_t agno,
> >  		xfs_btnum_t btnum);
> > diff --git a/fs/xfs/libxfs/xfs_refcount.c b/fs/xfs/libxfs/xfs_refcount.c
> > index 2037b9f23069..1c2bd2949d7d 100644
> > --- a/fs/xfs/libxfs/xfs_refcount.c
> > +++ b/fs/xfs/libxfs/xfs_refcount.c
> > @@ -1178,7 +1178,7 @@ xfs_refcount_finish_one(
> >  		if (error)
> >  			return error;
> >  
> > -		rcur = xfs_refcountbt_init_cursor(mp, tp, agbp, agno);
> > +		rcur = xfs_refcountbt_init_cursor(mp, tp, agbp, agno, NULL);
> >  		rcur->bc_ag.refc.nr_ops = nr_ops;
> >  		rcur->bc_ag.refc.shape_changes = shape_changes;
> >  	}
> > @@ -1707,7 +1707,7 @@ xfs_refcount_recover_cow_leftovers(
> >  	error = xfs_alloc_read_agf(mp, tp, agno, 0, &agbp);
> >  	if (error)
> >  		goto out_trans;
> > -	cur = xfs_refcountbt_init_cursor(mp, tp, agbp, agno);
> > +	cur = xfs_refcountbt_init_cursor(mp, tp, agbp, agno, NULL);
> >  
> >  	/* Find all the leftover CoW staging extents. */
> >  	memset(&low, 0, sizeof(low));
> > diff --git a/fs/xfs/libxfs/xfs_refcount_btree.c b/fs/xfs/libxfs/xfs_refcount_btree.c
> > index c4ddf9ded00b..74f8ac0209f1 100644
> > --- a/fs/xfs/libxfs/xfs_refcount_btree.c
> > +++ b/fs/xfs/libxfs/xfs_refcount_btree.c
> > @@ -26,7 +26,7 @@ xfs_refcountbt_dup_cursor(
> >  	struct xfs_btree_cur	*cur)
> >  {
> >  	return xfs_refcountbt_init_cursor(cur->bc_mp, cur->bc_tp,
> > -			cur->bc_ag.agbp, cur->bc_ag.agno);
> > +			cur->bc_ag.agbp, cur->bc_ag.agno, cur->bc_ag.pag);
> >  }
> >  
> >  STATIC void
> > @@ -316,7 +316,8 @@ static struct xfs_btree_cur *
> >  xfs_refcountbt_init_common(
> >  	struct xfs_mount	*mp,
> >  	struct xfs_trans	*tp,
> > -	xfs_agnumber_t		agno)
> > +	xfs_agnumber_t		agno,
> > +	struct xfs_perag	*pag)
> >  {
> >  	struct xfs_btree_cur	*cur;
> >  
> > @@ -332,6 +333,11 @@ xfs_refcountbt_init_common(
> >  
> >  	cur->bc_ag.agno = agno;
> >  	cur->bc_flags |= XFS_BTREE_CRC_BLOCKS;
> > +	if (pag) {
> > +		/* take a reference for the cursor */
> > +		atomic_inc(&pag->pag_ref);
> > +	}
> > +	cur->bc_ag.pag = pag;
> >  
> >  	cur->bc_ag.refc.nr_ops = 0;
> >  	cur->bc_ag.refc.shape_changes = 0;
> > @@ -345,12 +351,13 @@ xfs_refcountbt_init_cursor(
> >  	struct xfs_mount	*mp,
> >  	struct xfs_trans	*tp,
> >  	struct xfs_buf		*agbp,
> > -	xfs_agnumber_t		agno)
> > +	xfs_agnumber_t		agno,
> > +	struct xfs_perag	*pag)
> >  {
> >  	struct xfs_agf		*agf = agbp->b_addr;
> >  	struct xfs_btree_cur	*cur;
> >  
> > -	cur = xfs_refcountbt_init_common(mp, tp, agno);
> > +	cur = xfs_refcountbt_init_common(mp, tp, agno, pag);
> >  	cur->bc_nlevels = be32_to_cpu(agf->agf_refcount_level);
> >  	cur->bc_ag.agbp = agbp;
> >  	return cur;
> > @@ -365,7 +372,7 @@ xfs_refcountbt_stage_cursor(
> >  {
> >  	struct xfs_btree_cur	*cur;
> >  
> > -	cur = xfs_refcountbt_init_common(mp, NULL, agno);
> > +	cur = xfs_refcountbt_init_common(mp, NULL, agno, NULL);
> >  	xfs_btree_stage_afakeroot(cur, afake);
> >  	return cur;
> >  }
> > diff --git a/fs/xfs/libxfs/xfs_refcount_btree.h b/fs/xfs/libxfs/xfs_refcount_btree.h
> > index eab1b0c672c0..8b82a39f104a 100644
> > --- a/fs/xfs/libxfs/xfs_refcount_btree.h
> > +++ b/fs/xfs/libxfs/xfs_refcount_btree.h
> > @@ -47,7 +47,7 @@ struct xbtree_afakeroot;
> >  
> >  extern struct xfs_btree_cur *xfs_refcountbt_init_cursor(struct xfs_mount *mp,
> >  		struct xfs_trans *tp, struct xfs_buf *agbp,
> > -		xfs_agnumber_t agno);
> > +		xfs_agnumber_t agno, struct xfs_perag *pag);
> >  struct xfs_btree_cur *xfs_refcountbt_stage_cursor(struct xfs_mount *mp,
> >  		struct xbtree_afakeroot *afake, xfs_agnumber_t agno);
> >  extern int xfs_refcountbt_maxrecs(int blocklen, bool leaf);
> > diff --git a/fs/xfs/libxfs/xfs_rmap.c b/fs/xfs/libxfs/xfs_rmap.c
> > index 1d0a6b686eea..0d7a6997120c 100644
> > --- a/fs/xfs/libxfs/xfs_rmap.c
> > +++ b/fs/xfs/libxfs/xfs_rmap.c
> > @@ -708,7 +708,7 @@ xfs_rmap_free(
> >  	if (!xfs_sb_version_hasrmapbt(&mp->m_sb))
> >  		return 0;
> >  
> > -	cur = xfs_rmapbt_init_cursor(mp, tp, agbp, agno);
> > +	cur = xfs_rmapbt_init_cursor(mp, tp, agbp, agno, NULL);
> >  
> >  	error = xfs_rmap_unmap(cur, bno, len, false, oinfo);
> >  
> > @@ -962,7 +962,7 @@ xfs_rmap_alloc(
> >  	if (!xfs_sb_version_hasrmapbt(&mp->m_sb))
> >  		return 0;
> >  
> > -	cur = xfs_rmapbt_init_cursor(mp, tp, agbp, agno);
> > +	cur = xfs_rmapbt_init_cursor(mp, tp, agbp, agno, NULL);
> >  	error = xfs_rmap_map(cur, bno, len, false, oinfo);
> >  
> >  	xfs_btree_del_cursor(cur, error);
> > @@ -2408,7 +2408,7 @@ xfs_rmap_finish_one(
> >  			goto out_drop;
> >  		}
> >  
> > -		rcur = xfs_rmapbt_init_cursor(mp, tp, agbp, pag->pag_agno);
> > +		rcur = xfs_rmapbt_init_cursor(mp, tp, agbp, pag->pag_agno, pag);
> >  	}
> >  	*pcur = rcur;
> >  
> > diff --git a/fs/xfs/libxfs/xfs_rmap_btree.c b/fs/xfs/libxfs/xfs_rmap_btree.c
> > index ba2f7064451b..7bef8feeded1 100644
> > --- a/fs/xfs/libxfs/xfs_rmap_btree.c
> > +++ b/fs/xfs/libxfs/xfs_rmap_btree.c
> > @@ -52,7 +52,7 @@ xfs_rmapbt_dup_cursor(
> >  	struct xfs_btree_cur	*cur)
> >  {
> >  	return xfs_rmapbt_init_cursor(cur->bc_mp, cur->bc_tp,
> > -			cur->bc_ag.agbp, cur->bc_ag.agno);
> > +			cur->bc_ag.agbp, cur->bc_ag.agno, cur->bc_ag.pag);
> >  }
> >  
> >  STATIC void
> > @@ -449,7 +449,8 @@ static struct xfs_btree_cur *
> >  xfs_rmapbt_init_common(
> >  	struct xfs_mount	*mp,
> >  	struct xfs_trans	*tp,
> > -	xfs_agnumber_t		agno)
> > +	xfs_agnumber_t		agno,
> > +	struct xfs_perag	*pag)
> >  {
> >  	struct xfs_btree_cur	*cur;
> >  
> > @@ -463,6 +464,11 @@ xfs_rmapbt_init_common(
> >  	cur->bc_statoff = XFS_STATS_CALC_INDEX(xs_rmap_2);
> >  	cur->bc_ag.agno = agno;
> >  	cur->bc_ops = &xfs_rmapbt_ops;
> > +	if (pag) {
> > +		/* take a reference for the cursor */
> > +		atomic_inc(&pag->pag_ref);
> > +	}
> > +	cur->bc_ag.pag = pag;
> >  
> >  	return cur;
> >  }
> > @@ -473,12 +479,13 @@ xfs_rmapbt_init_cursor(
> >  	struct xfs_mount	*mp,
> >  	struct xfs_trans	*tp,
> >  	struct xfs_buf		*agbp,
> > -	xfs_agnumber_t		agno)
> > +	xfs_agnumber_t		agno,
> > +	struct xfs_perag	*pag)
> >  {
> >  	struct xfs_agf		*agf = agbp->b_addr;
> >  	struct xfs_btree_cur	*cur;
> >  
> > -	cur = xfs_rmapbt_init_common(mp, tp, agno);
> > +	cur = xfs_rmapbt_init_common(mp, tp, agno, pag);
> >  	cur->bc_nlevels = be32_to_cpu(agf->agf_levels[XFS_BTNUM_RMAP]);
> >  	cur->bc_ag.agbp = agbp;
> >  	return cur;
> > @@ -493,7 +500,7 @@ xfs_rmapbt_stage_cursor(
> >  {
> >  	struct xfs_btree_cur	*cur;
> >  
> > -	cur = xfs_rmapbt_init_common(mp, NULL, agno);
> > +	cur = xfs_rmapbt_init_common(mp, NULL, agno, NULL);
> >  	xfs_btree_stage_afakeroot(cur, afake);
> >  	return cur;
> >  }
> > diff --git a/fs/xfs/libxfs/xfs_rmap_btree.h b/fs/xfs/libxfs/xfs_rmap_btree.h
> > index 57fab72e26ad..c94f418cc06b 100644
> > --- a/fs/xfs/libxfs/xfs_rmap_btree.h
> > +++ b/fs/xfs/libxfs/xfs_rmap_btree.h
> > @@ -43,7 +43,7 @@ struct xbtree_afakeroot;
> >  
> >  struct xfs_btree_cur *xfs_rmapbt_init_cursor(struct xfs_mount *mp,
> >  				struct xfs_trans *tp, struct xfs_buf *bp,
> > -				xfs_agnumber_t agno);
> > +				xfs_agnumber_t agno, struct xfs_perag *pag);
> >  struct xfs_btree_cur *xfs_rmapbt_stage_cursor(struct xfs_mount *mp,
> >  		struct xbtree_afakeroot *afake, xfs_agnumber_t agno);
> >  void xfs_rmapbt_commit_staged_btree(struct xfs_btree_cur *cur,
> > diff --git a/fs/xfs/scrub/agheader_repair.c b/fs/xfs/scrub/agheader_repair.c
> > index 1cdfbd57f36b..5dd91bf04c18 100644
> > --- a/fs/xfs/scrub/agheader_repair.c
> > +++ b/fs/xfs/scrub/agheader_repair.c
> > @@ -247,7 +247,7 @@ xrep_agf_calc_from_btrees(
> >  
> >  	/* Update the AGF counters from the bnobt. */
> >  	cur = xfs_allocbt_init_cursor(mp, sc->tp, agf_bp, sc->sa.agno,
> > -			XFS_BTNUM_BNO);
> > +			sc->sa.pag, XFS_BTNUM_BNO);
> >  	error = xfs_alloc_query_all(cur, xrep_agf_walk_allocbt, &raa);
> >  	if (error)
> >  		goto err;
> > @@ -261,7 +261,7 @@ xrep_agf_calc_from_btrees(
> >  
> >  	/* Update the AGF counters from the cntbt. */
> >  	cur = xfs_allocbt_init_cursor(mp, sc->tp, agf_bp, sc->sa.agno,
> > -			XFS_BTNUM_CNT);
> > +			sc->sa.pag, XFS_BTNUM_CNT);
> >  	error = xfs_btree_count_blocks(cur, &blocks);
> >  	if (error)
> >  		goto err;
> > @@ -269,7 +269,8 @@ xrep_agf_calc_from_btrees(
> >  	btreeblks += blocks - 1;
> >  
> >  	/* Update the AGF counters from the rmapbt. */
> > -	cur = xfs_rmapbt_init_cursor(mp, sc->tp, agf_bp, sc->sa.agno);
> > +	cur = xfs_rmapbt_init_cursor(mp, sc->tp, agf_bp, sc->sa.agno,
> > +			sc->sa.pag);
> >  	error = xfs_btree_count_blocks(cur, &blocks);
> >  	if (error)
> >  		goto err;
> > @@ -282,7 +283,7 @@ xrep_agf_calc_from_btrees(
> >  	/* Update the AGF counters from the refcountbt. */
> >  	if (xfs_sb_version_hasreflink(&mp->m_sb)) {
> >  		cur = xfs_refcountbt_init_cursor(mp, sc->tp, agf_bp,
> > -				sc->sa.agno);
> > +				sc->sa.agno, sc->sa.pag);
> >  		error = xfs_btree_count_blocks(cur, &blocks);
> >  		if (error)
> >  			goto err;
> > @@ -490,7 +491,8 @@ xrep_agfl_collect_blocks(
> >  	xbitmap_init(&ra.agmetablocks);
> >  
> >  	/* Find all space used by the free space btrees & rmapbt. */
> > -	cur = xfs_rmapbt_init_cursor(mp, sc->tp, agf_bp, sc->sa.agno);
> > +	cur = xfs_rmapbt_init_cursor(mp, sc->tp, agf_bp, sc->sa.agno,
> > +			sc->sa.pag);
> >  	error = xfs_rmap_query_all(cur, xrep_agfl_walk_rmap, &ra);
> >  	if (error)
> >  		goto err;
> > @@ -498,7 +500,7 @@ xrep_agfl_collect_blocks(
> >  
> >  	/* Find all blocks currently being used by the bnobt. */
> >  	cur = xfs_allocbt_init_cursor(mp, sc->tp, agf_bp, sc->sa.agno,
> > -			XFS_BTNUM_BNO);
> > +			sc->sa.pag, XFS_BTNUM_BNO);
> >  	error = xbitmap_set_btblocks(&ra.agmetablocks, cur);
> >  	if (error)
> >  		goto err;
> > @@ -506,7 +508,7 @@ xrep_agfl_collect_blocks(
> >  
> >  	/* Find all blocks currently being used by the cntbt. */
> >  	cur = xfs_allocbt_init_cursor(mp, sc->tp, agf_bp, sc->sa.agno,
> > -			XFS_BTNUM_CNT);
> > +			sc->sa.pag, XFS_BTNUM_CNT);
> >  	error = xbitmap_set_btblocks(&ra.agmetablocks, cur);
> >  	if (error)
> >  		goto err;
> > @@ -807,7 +809,7 @@ xrep_agi_calc_from_btrees(
> >  	int			error;
> >  
> >  	cur = xfs_inobt_init_cursor(mp, sc->tp, agi_bp, sc->sa.agno,
> > -			XFS_BTNUM_INO);
> > +			sc->sa.pag, XFS_BTNUM_INO);
> >  	error = xfs_ialloc_count_inodes(cur, &count, &freecount);
> >  	if (error)
> >  		goto err;
> > @@ -829,7 +831,7 @@ xrep_agi_calc_from_btrees(
> >  		xfs_agblock_t	blocks;
> >  
> >  		cur = xfs_inobt_init_cursor(mp, sc->tp, agi_bp, sc->sa.agno,
> > -				XFS_BTNUM_FINO);
> > +				sc->sa.pag, XFS_BTNUM_FINO);
> >  		error = xfs_btree_count_blocks(cur, &blocks);
> >  		if (error)
> >  			goto err;
> > diff --git a/fs/xfs/scrub/bmap.c b/fs/xfs/scrub/bmap.c
> > index c60a1990d629..a792d9ffd61e 100644
> > --- a/fs/xfs/scrub/bmap.c
> > +++ b/fs/xfs/scrub/bmap.c
> > @@ -556,7 +556,7 @@ xchk_bmap_check_ag_rmaps(
> >  	if (error)
> >  		return error;
> >  
> > -	cur = xfs_rmapbt_init_cursor(sc->mp, sc->tp, agf, agno);
> > +	cur = xfs_rmapbt_init_cursor(sc->mp, sc->tp, agf, agno, NULL);
> >  
> >  	sbcri.sc = sc;
> >  	sbcri.whichfork = whichfork;
> > diff --git a/fs/xfs/scrub/common.c b/fs/xfs/scrub/common.c
> > index c8da976b50fc..50768559fb60 100644
> > --- a/fs/xfs/scrub/common.c
> > +++ b/fs/xfs/scrub/common.c
> > @@ -465,42 +465,42 @@ xchk_ag_btcur_init(
> >  	    xchk_ag_btree_healthy_enough(sc, sa->pag, XFS_BTNUM_BNO)) {
> >  		/* Set up a bnobt cursor for cross-referencing. */
> >  		sa->bno_cur = xfs_allocbt_init_cursor(mp, sc->tp, sa->agf_bp,
> > -				agno, XFS_BTNUM_BNO);
> > +				agno, sa->pag, XFS_BTNUM_BNO);
> >  	}
> >  
> >  	if (sa->agf_bp &&
> >  	    xchk_ag_btree_healthy_enough(sc, sa->pag, XFS_BTNUM_CNT)) {
> >  		/* Set up a cntbt cursor for cross-referencing. */
> >  		sa->cnt_cur = xfs_allocbt_init_cursor(mp, sc->tp, sa->agf_bp,
> > -				agno, XFS_BTNUM_CNT);
> > +				agno, sa->pag, XFS_BTNUM_CNT);
> >  	}
> >  
> >  	/* Set up a inobt cursor for cross-referencing. */
> >  	if (sa->agi_bp &&
> >  	    xchk_ag_btree_healthy_enough(sc, sa->pag, XFS_BTNUM_INO)) {
> >  		sa->ino_cur = xfs_inobt_init_cursor(mp, sc->tp, sa->agi_bp,
> > -					agno, XFS_BTNUM_INO);
> > +				agno, sa->pag, XFS_BTNUM_INO);
> >  	}
> >  
> >  	/* Set up a finobt cursor for cross-referencing. */
> >  	if (sa->agi_bp && xfs_sb_version_hasfinobt(&mp->m_sb) &&
> >  	    xchk_ag_btree_healthy_enough(sc, sa->pag, XFS_BTNUM_FINO)) {
> >  		sa->fino_cur = xfs_inobt_init_cursor(mp, sc->tp, sa->agi_bp,
> > -				agno, XFS_BTNUM_FINO);
> > +				agno, sa->pag, XFS_BTNUM_FINO);
> >  	}
> >  
> >  	/* Set up a rmapbt cursor for cross-referencing. */
> >  	if (sa->agf_bp && xfs_sb_version_hasrmapbt(&mp->m_sb) &&
> >  	    xchk_ag_btree_healthy_enough(sc, sa->pag, XFS_BTNUM_RMAP)) {
> >  		sa->rmap_cur = xfs_rmapbt_init_cursor(mp, sc->tp, sa->agf_bp,
> > -				agno);
> > +				agno, sa->pag);
> >  	}
> >  
> >  	/* Set up a refcountbt cursor for cross-referencing. */
> >  	if (sa->agf_bp && xfs_sb_version_hasreflink(&mp->m_sb) &&
> >  	    xchk_ag_btree_healthy_enough(sc, sa->pag, XFS_BTNUM_REFC)) {
> >  		sa->refc_cur = xfs_refcountbt_init_cursor(mp, sc->tp,
> > -				sa->agf_bp, agno);
> > +				sa->agf_bp, agno, sa->pag);
> >  	}
> >  }
> >  
> > diff --git a/fs/xfs/scrub/repair.c b/fs/xfs/scrub/repair.c
> > index 6b62872c4d10..862dc56fd8cd 100644
> > --- a/fs/xfs/scrub/repair.c
> > +++ b/fs/xfs/scrub/repair.c
> > @@ -555,7 +555,7 @@ xrep_reap_block(
> >  	} else {
> >  		agf_bp = sc->sa.agf_bp;
> >  	}
> > -	cur = xfs_rmapbt_init_cursor(sc->mp, sc->tp, agf_bp, agno);
> > +	cur = xfs_rmapbt_init_cursor(sc->mp, sc->tp, agf_bp, agno, sc->sa.pag);
> >  
> >  	/* Can we find any other rmappings? */
> >  	error = xfs_rmap_has_other_keys(cur, agbno, 1, oinfo, &has_other_rmap);
> > @@ -892,7 +892,8 @@ xrep_find_ag_btree_roots(
> >  		fab->height = 0;
> >  	}
> >  
> > -	cur = xfs_rmapbt_init_cursor(mp, sc->tp, agf_bp, sc->sa.agno);
> > +	cur = xfs_rmapbt_init_cursor(mp, sc->tp, agf_bp, sc->sa.agno,
> > +			sc->sa.pag);
> >  	error = xfs_rmap_query_all(cur, xrep_findroot_rmap, &ri);
> >  	xfs_btree_del_cursor(cur, error);
> >  
> > diff --git a/fs/xfs/xfs_discard.c b/fs/xfs/xfs_discard.c
> > index 972864250bd2..311ebaad4f5a 100644
> > --- a/fs/xfs/xfs_discard.c
> > +++ b/fs/xfs/xfs_discard.c
> > @@ -50,7 +50,7 @@ xfs_trim_extents(
> >  		goto out_put_perag;
> >  	agf = agbp->b_addr;
> >  
> > -	cur = xfs_allocbt_init_cursor(mp, NULL, agbp, agno, XFS_BTNUM_CNT);
> > +	cur = xfs_allocbt_init_cursor(mp, NULL, agbp, agno, pag, XFS_BTNUM_CNT);
> >  
> >  	/*
> >  	 * Look up the longest btree in the AGF and start with it.
> > diff --git a/fs/xfs/xfs_fsmap.c b/fs/xfs/xfs_fsmap.c
> > index 835dd6e3819b..b654a2bf9a9f 100644
> > --- a/fs/xfs/xfs_fsmap.c
> > +++ b/fs/xfs/xfs_fsmap.c
> > @@ -211,7 +211,7 @@ xfs_getfsmap_is_shared(
> >  	/* Are there any shared blocks here? */
> >  	flen = 0;
> >  	cur = xfs_refcountbt_init_cursor(mp, tp, info->agf_bp,
> > -			info->pag->pag_agno);
> > +			info->pag->pag_agno, info->pag);
> >  
> >  	error = xfs_refcount_find_shared(cur, rec->rm_startblock,
> >  			rec->rm_blockcount, &fbno, &flen, false);
> > @@ -708,7 +708,7 @@ xfs_getfsmap_datadev_rmapbt_query(
> >  
> >  	/* Allocate cursor for this AG and query_range it. */
> >  	*curpp = xfs_rmapbt_init_cursor(tp->t_mountp, tp, info->agf_bp,
> > -			info->pag->pag_agno);
> > +			info->pag->pag_agno, info->pag);
> >  	return xfs_rmap_query_range(*curpp, &info->low, &info->high,
> >  			xfs_getfsmap_datadev_helper, info);
> >  }
> > @@ -741,7 +741,7 @@ xfs_getfsmap_datadev_bnobt_query(
> >  
> >  	/* Allocate cursor for this AG and query_range it. */
> >  	*curpp = xfs_allocbt_init_cursor(tp->t_mountp, tp, info->agf_bp,
> > -			info->pag->pag_agno, XFS_BTNUM_BNO);
> > +			info->pag->pag_agno, info->pag, XFS_BTNUM_BNO);
> >  	key->ar_startblock = info->low.rm_startblock;
> >  	key[1].ar_startblock = info->high.rm_startblock;
> >  	return xfs_alloc_query_range(*curpp, key, &key[1],
> > diff --git a/fs/xfs/xfs_reflink.c b/fs/xfs/xfs_reflink.c
> > index 0e430b0c1b16..28ffe1817f9b 100644
> > --- a/fs/xfs/xfs_reflink.c
> > +++ b/fs/xfs/xfs_reflink.c
> > @@ -144,7 +144,7 @@ xfs_reflink_find_shared(
> >  	if (error)
> >  		return error;
> >  
> > -	cur = xfs_refcountbt_init_cursor(mp, tp, agbp, agno);
> > +	cur = xfs_refcountbt_init_cursor(mp, tp, agbp, agno, NULL);
> >  
> >  	error = xfs_refcount_find_shared(cur, agbno, aglen, fbno, flen,
> >  			find_end_of_shared);
> > -- 
> > 2.31.1
> > 
> 

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 04/22] xfs: make for_each_perag... a first class citizen
  2021-05-11 12:29       ` Brian Foster
@ 2021-05-11 21:33         ` Dave Chinner
  2021-05-12 21:58           ` Darrick J. Wong
  0 siblings, 1 reply; 87+ messages in thread
From: Dave Chinner @ 2021-05-11 21:33 UTC (permalink / raw)
  To: Brian Foster; +Cc: linux-xfs

On Tue, May 11, 2021 at 08:29:38AM -0400, Brian Foster wrote:
> On Tue, May 11, 2021 at 05:35:19PM +1000, Dave Chinner wrote:
> > On Mon, May 10, 2021 at 08:53:56AM -0400, Brian Foster wrote:
> > > On Thu, May 06, 2021 at 05:20:36PM +1000, Dave Chinner wrote:
> > > > From: Dave Chinner <dchinner@redhat.com>
> > > > 
> > > > for_each_perag_tag() is defined in xfs_icache.c for local use.
> > > > Promote this to xfs_ag.h and define equivalent iteration functions
> > > > so that we can use them to iterate AGs instead to replace open coded
> > > > perag walks and perag lookups.
> > > > 
> > > > We also convert as many of the straight forward open coded AG walks
> > > > to use these iterators as possible. Anything that is not a direct
> > > > conversion to an iterator is ignored and will be updated in future
> > > > commits.
> > > > 
> > > > Signed-off-by: Dave Chinner <dchinner@redhat.com>
> > > > ---
> > > >  fs/xfs/libxfs/xfs_ag.h    | 17 +++++++++++++++++
> > > >  fs/xfs/scrub/fscounters.c | 36 ++++++++++++++----------------------
> > > >  fs/xfs/xfs_extent_busy.c  |  7 ++-----
> > > >  fs/xfs/xfs_fsops.c        |  8 ++------
> > > >  fs/xfs/xfs_health.c       |  4 +---
> > > >  fs/xfs/xfs_icache.c       | 15 ++-------------
> > > >  6 files changed, 38 insertions(+), 49 deletions(-)
> > > > 
> > > ...
> > > > diff --git a/fs/xfs/scrub/fscounters.c b/fs/xfs/scrub/fscounters.c
> > > > index 453ae9adf94c..2dfdac566399 100644
> > > > --- a/fs/xfs/scrub/fscounters.c
> > > > +++ b/fs/xfs/scrub/fscounters.c
> > > ...
> > > > @@ -229,12 +224,9 @@ xchk_fscount_aggregate_agcounts(
> > > >  		fsc->fdblocks -= pag->pag_meta_resv.ar_reserved;
> > > >  		fsc->fdblocks -= pag->pag_rmapbt_resv.ar_orig_reserved;
> > > >  
> > > > -		xfs_perag_put(pag);
> > > > -
> > > > -		if (xchk_should_terminate(sc, &error))
> > > > -			break;
> > > >  	}
> > > > -
> > > > +	if (pag)
> > > > +		xfs_perag_put(pag);
> > > 
> > > It's not shown in the diff, but there is still an exit path out of the
> > > above loop that calls xfs_perag_put(). The rest of the patch LGTM.
> > 
> > Good spot. Fixed.
> > 
> > FWIW, I'm not entirely happy with the way the iterator can break and
> > require conditional cleanup. I'm thinking that I'll come back to
> > these and convert them to a iterator structure that will turn this
> > into the pattern:
> > 
> > 	perag_iter_init(&iter, start_agno, end_agno);
> > 	for_each_perag(pag, iter) {
> > 		....
> > 	}
> > 	perag_iter_done(&iter);
> > 
> > and so the code doesn't need to care about whether it exits the loop
> > via a break or running out of perags to iterate. I haven't fully
> > thought this through, though, so I'm leaving it alone for now...
> > 
> 
> I think something like that would be an improvement. It's
> straightforward enough to follow through these changes with the loop
> break quirk in mind, but I suspect that somebody modifying (and/or
> reviewing) related code farther in the future might very easily miss
> something like an external put being required if a loop is modified to
> break out early.

*nod*

I think I'll need to address this when I do the conversion of these
iterators to use active references to pin or skip perags that are
being torn down. The iterators becomes slightly more complex at this
point, so that's probably the best point to address this.

Cheers,

Dave.
-- 
Dave Chinner
david@fromorbit.com

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 11/22] xfs: add a perag to the btree cursor
  2021-05-11 20:51     ` Darrick J. Wong
@ 2021-05-11 21:52       ` Dave Chinner
  2021-05-12 12:49         ` Brian Foster
  0 siblings, 1 reply; 87+ messages in thread
From: Dave Chinner @ 2021-05-11 21:52 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: Brian Foster, linux-xfs

On Tue, May 11, 2021 at 01:51:52PM -0700, Darrick J. Wong wrote:
> On Tue, May 11, 2021 at 08:30:22AM -0400, Brian Foster wrote:
> > On Thu, May 06, 2021 at 05:20:43PM +1000, Dave Chinner wrote:
> > > From: Dave Chinner <dchinner@redhat.com>
> > > 
> > > Which will eventually completely replace the agno in it.
> > > 
> > > Signed-off-by: Dave Chinner <dchinner@redhat.com>
> > > ---
> > >  fs/xfs/libxfs/xfs_alloc.c          | 25 +++++++++++++++----------
> > >  fs/xfs/libxfs/xfs_alloc_btree.c    | 13 ++++++++++---
> > >  fs/xfs/libxfs/xfs_alloc_btree.h    |  3 ++-
> > >  fs/xfs/libxfs/xfs_btree.c          |  2 ++
> > >  fs/xfs/libxfs/xfs_btree.h          |  4 +++-
> > >  fs/xfs/libxfs/xfs_ialloc.c         | 16 ++++++++--------
> > >  fs/xfs/libxfs/xfs_ialloc_btree.c   | 15 +++++++++++----
> > >  fs/xfs/libxfs/xfs_ialloc_btree.h   |  7 ++++---
> > >  fs/xfs/libxfs/xfs_refcount.c       |  4 ++--
> > >  fs/xfs/libxfs/xfs_refcount_btree.c | 17 ++++++++++++-----
> > >  fs/xfs/libxfs/xfs_refcount_btree.h |  2 +-
> > >  fs/xfs/libxfs/xfs_rmap.c           |  6 +++---
> > >  fs/xfs/libxfs/xfs_rmap_btree.c     | 17 ++++++++++++-----
> > >  fs/xfs/libxfs/xfs_rmap_btree.h     |  2 +-
> > >  fs/xfs/scrub/agheader_repair.c     | 20 +++++++++++---------
> > >  fs/xfs/scrub/bmap.c                |  2 +-
> > >  fs/xfs/scrub/common.c              | 12 ++++++------
> > >  fs/xfs/scrub/repair.c              |  5 +++--
> > >  fs/xfs/xfs_discard.c               |  2 +-
> > >  fs/xfs/xfs_fsmap.c                 |  6 +++---
> > >  fs/xfs/xfs_reflink.c               |  2 +-
> > >  21 files changed, 112 insertions(+), 70 deletions(-)
> > > 
> > ...
> > > diff --git a/fs/xfs/libxfs/xfs_btree.c b/fs/xfs/libxfs/xfs_btree.c
> > > index 0f12b885600d..44044317c0fb 100644
> > > --- a/fs/xfs/libxfs/xfs_btree.c
> > > +++ b/fs/xfs/libxfs/xfs_btree.c
> > > @@ -377,6 +377,8 @@ xfs_btree_del_cursor(
> > >  	       XFS_FORCED_SHUTDOWN(cur->bc_mp));
> > >  	if (unlikely(cur->bc_flags & XFS_BTREE_STAGING))
> > >  		kmem_free(cur->bc_ops);
> > > +	if (!(cur->bc_flags & XFS_BTREE_LONG_PTRS) && cur->bc_ag.pag)
> > > +		xfs_perag_put(cur->bc_ag.pag);
> > 
> > What's the correlation with BTREE_LONG_PTRS?

Only the btrees that index agbnos within a specific AG use the
cur->bc_ag structure to store the agno the btree is rooted in.
These are all btrees that use short pointers.

IOWs, we need an agno to turn the agbno into a full fsbno, daddr,
inum or anything else with global scope. Translation of short
pointers to physical location is necessary just to walk the tree,
while long pointer trees already record physical location of the
blocks within the tree and hence do not need an agno for
translation.

Hence needing the agno is specific, at this point in
time, to a btree containing short pointers.

> maybe this should be:
> 
> 	if (!(cur->bc_flags & XFS_BTREE_ROOT_IN_INODE))
> 		xfs_perag_put(cur->bc_ag.pag);

Given that the only long pointer btree we have is also the only
btree we have rooted in an inode, this is just another way of saying
!BTREE_LONG_PTRS. But "root in inode" is less obvious, because then we
lose the context taht "short pointers need translation via agno to
calculate their physical location in the wider filesystem"...

If we are going to put short ptrs in an inode, then at that point
we need to change the btree cursor, anyway, because then we are
going to need both an inode pointer and something else to turn those
short pointers into global scope pointers for IO....

Cheers,

Dave.
-- 
Dave Chinner
david@fromorbit.com

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 16/22] xfs: remove agno from btree cursor
  2021-05-11 12:34   ` Brian Foster
@ 2021-05-11 22:02     ` Dave Chinner
  0 siblings, 0 replies; 87+ messages in thread
From: Dave Chinner @ 2021-05-11 22:02 UTC (permalink / raw)
  To: Brian Foster; +Cc: linux-xfs

On Tue, May 11, 2021 at 08:34:40AM -0400, Brian Foster wrote:
> On Thu, May 06, 2021 at 05:20:48PM +1000, Dave Chinner wrote:
> > From: Dave Chinner <dchinner@redhat.com>
> > 
> > Now that everything passes a perag, the agno is not needed anymore.
> > Convert all the users to use pag->pag_agno instead and remove the
> > agno from the cursor. This was largely done as an automated search
> > and replace.
> > 
> > Signed-off-by: Dave Chinner <dchinner@redhat.com>
> > ---
> >  fs/xfs/libxfs/xfs_alloc.c          |   2 +-
> >  fs/xfs/libxfs/xfs_alloc_btree.c    |   1 -
> >  fs/xfs/libxfs/xfs_btree.c          |  12 ++--
> >  fs/xfs/libxfs/xfs_btree.h          |   1 -
> >  fs/xfs/libxfs/xfs_ialloc.c         |   2 +-
> >  fs/xfs/libxfs/xfs_ialloc_btree.c   |   7 +-
> >  fs/xfs/libxfs/xfs_refcount.c       |  82 +++++++++++-----------
> >  fs/xfs/libxfs/xfs_refcount_btree.c |  11 ++-
> >  fs/xfs/libxfs/xfs_rmap.c           | 108 ++++++++++++++---------------
> >  fs/xfs/libxfs/xfs_rmap_btree.c     |   1 -
> >  fs/xfs/scrub/agheader_repair.c     |   2 +-
> >  fs/xfs/scrub/alloc.c               |   3 +-
> >  fs/xfs/scrub/bmap.c                |   2 +-
> >  fs/xfs/scrub/ialloc.c              |   9 +--
> >  fs/xfs/scrub/refcount.c            |   3 +-
> >  fs/xfs/scrub/rmap.c                |   3 +-
> >  fs/xfs/scrub/trace.c               |   3 +-
> >  fs/xfs/xfs_fsmap.c                 |   4 +-
> >  fs/xfs/xfs_trace.h                 |   4 +-
> >  19 files changed, 130 insertions(+), 130 deletions(-)
> > 
> ...
> > diff --git a/fs/xfs/libxfs/xfs_rmap.c b/fs/xfs/libxfs/xfs_rmap.c
> > index b23f949ee15c..d1dfad0204e3 100644
> > --- a/fs/xfs/libxfs/xfs_rmap.c
> > +++ b/fs/xfs/libxfs/xfs_rmap.c
> ...
> > @@ -2389,7 +2389,7 @@ xfs_rmap_finish_one(
> >  	 * the startblock, get one now.
> >  	 */
> >  	rcur = *pcur;
> > -	if (rcur != NULL && rcur->bc_ag.agno != pag->pag_agno) {
> > +	if (rcur != NULL && rcur->bc_ag.pag != pag) {
> 
> I wonder a bit about this sort of logic if the goal is to ultimately
> allow for dynamic instantiation of perag structures, though it's
> probably not an issue here.

The cursor will have an active reference, hence the perag it holds
cannot be reclaimed until it drops it's reference. THis is the
reason for pushing the perag into the cursor - we can guarantee the
existence of the perag for as long as a btree cursor chain (i.e. the
original cursor + all it's children that were duplicated from it).

Hence I think that checks that the pag is the same memory
address indicate that the perag is still the same. 

> >  		xfs_rmap_finish_one_cleanup(tp, rcur, 0);
> >  		rcur = NULL;
> >  		*pcur = NULL;
> ...
> > diff --git a/fs/xfs/xfs_trace.h b/fs/xfs/xfs_trace.h
> > index 808ae337b222..5ba9c6396dcb 100644
> > --- a/fs/xfs/xfs_trace.h
> > +++ b/fs/xfs/xfs_trace.h
> > @@ -3730,7 +3730,7 @@ TRACE_EVENT(xfs_btree_commit_afakeroot,
> >  	TP_fast_assign(
> >  		__entry->dev = cur->bc_mp->m_super->s_dev;
> >  		__entry->btnum = cur->bc_btnum;
> > -		__entry->agno = cur->bc_ag.agno;
> > +		__entry->agno = cur->bc_ag.pag->pag_agno;
> 
> It would be nice if we did this with some of the other tracepoints
> rather than pulling ->pag_agno out at every callsite, but that's
> probably something for another patch. All in all this looks fine to me:

Yeah, that's something to clean up down the track. Cleaning up
tracepoints have been low on my priority list - just retaining what
they capture is sufficient for the initial conversion....

> Reviewed-by: Brian Foster <bfoster@redhat.com>

Ta.

Cheers,

Dave.
-- 
Dave Chinner
david@fromorbit.com

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 11/22] xfs: add a perag to the btree cursor
  2021-05-11 21:52       ` Dave Chinner
@ 2021-05-12 12:49         ` Brian Foster
  2021-05-12 22:41           ` Darrick J. Wong
  0 siblings, 1 reply; 87+ messages in thread
From: Brian Foster @ 2021-05-12 12:49 UTC (permalink / raw)
  To: Dave Chinner; +Cc: Darrick J. Wong, linux-xfs

On Wed, May 12, 2021 at 07:52:50AM +1000, Dave Chinner wrote:
> On Tue, May 11, 2021 at 01:51:52PM -0700, Darrick J. Wong wrote:
> > On Tue, May 11, 2021 at 08:30:22AM -0400, Brian Foster wrote:
> > > On Thu, May 06, 2021 at 05:20:43PM +1000, Dave Chinner wrote:
> > > > From: Dave Chinner <dchinner@redhat.com>
> > > > 
> > > > Which will eventually completely replace the agno in it.
> > > > 
> > > > Signed-off-by: Dave Chinner <dchinner@redhat.com>
> > > > ---
> > > >  fs/xfs/libxfs/xfs_alloc.c          | 25 +++++++++++++++----------
> > > >  fs/xfs/libxfs/xfs_alloc_btree.c    | 13 ++++++++++---
> > > >  fs/xfs/libxfs/xfs_alloc_btree.h    |  3 ++-
> > > >  fs/xfs/libxfs/xfs_btree.c          |  2 ++
> > > >  fs/xfs/libxfs/xfs_btree.h          |  4 +++-
> > > >  fs/xfs/libxfs/xfs_ialloc.c         | 16 ++++++++--------
> > > >  fs/xfs/libxfs/xfs_ialloc_btree.c   | 15 +++++++++++----
> > > >  fs/xfs/libxfs/xfs_ialloc_btree.h   |  7 ++++---
> > > >  fs/xfs/libxfs/xfs_refcount.c       |  4 ++--
> > > >  fs/xfs/libxfs/xfs_refcount_btree.c | 17 ++++++++++++-----
> > > >  fs/xfs/libxfs/xfs_refcount_btree.h |  2 +-
> > > >  fs/xfs/libxfs/xfs_rmap.c           |  6 +++---
> > > >  fs/xfs/libxfs/xfs_rmap_btree.c     | 17 ++++++++++++-----
> > > >  fs/xfs/libxfs/xfs_rmap_btree.h     |  2 +-
> > > >  fs/xfs/scrub/agheader_repair.c     | 20 +++++++++++---------
> > > >  fs/xfs/scrub/bmap.c                |  2 +-
> > > >  fs/xfs/scrub/common.c              | 12 ++++++------
> > > >  fs/xfs/scrub/repair.c              |  5 +++--
> > > >  fs/xfs/xfs_discard.c               |  2 +-
> > > >  fs/xfs/xfs_fsmap.c                 |  6 +++---
> > > >  fs/xfs/xfs_reflink.c               |  2 +-
> > > >  21 files changed, 112 insertions(+), 70 deletions(-)
> > > > 
> > > ...
> > > > diff --git a/fs/xfs/libxfs/xfs_btree.c b/fs/xfs/libxfs/xfs_btree.c
> > > > index 0f12b885600d..44044317c0fb 100644
> > > > --- a/fs/xfs/libxfs/xfs_btree.c
> > > > +++ b/fs/xfs/libxfs/xfs_btree.c
> > > > @@ -377,6 +377,8 @@ xfs_btree_del_cursor(
> > > >  	       XFS_FORCED_SHUTDOWN(cur->bc_mp));
> > > >  	if (unlikely(cur->bc_flags & XFS_BTREE_STAGING))
> > > >  		kmem_free(cur->bc_ops);
> > > > +	if (!(cur->bc_flags & XFS_BTREE_LONG_PTRS) && cur->bc_ag.pag)
> > > > +		xfs_perag_put(cur->bc_ag.pag);
> > > 
> > > What's the correlation with BTREE_LONG_PTRS?
> 
> Only the btrees that index agbnos within a specific AG use the
> cur->bc_ag structure to store the agno the btree is rooted in.
> These are all btrees that use short pointers.
> 
> IOWs, we need an agno to turn the agbno into a full fsbno, daddr,
> inum or anything else with global scope. Translation of short
> pointers to physical location is necessary just to walk the tree,
> while long pointer trees already record physical location of the
> blocks within the tree and hence do not need an agno for
> translation.
> 
> Hence needing the agno is specific, at this point in
> time, to a btree containing short pointers.
> 
> > maybe this should be:
> > 
> > 	if (!(cur->bc_flags & XFS_BTREE_ROOT_IN_INODE))
> > 		xfs_perag_put(cur->bc_ag.pag);
> 
> Given that the only long pointer btree we have is also the only
> btree we have rooted in an inode, this is just another way of saying
> !BTREE_LONG_PTRS. But "root in inode" is less obvious, because then we
> lose the context taht "short pointers need translation via agno to
> calculate their physical location in the wider filesystem"...
> 

Got it, thanks. The bc_ag field is unioned with bc_ino, the latter of
which is used by XFS_BTREE_ROOT_IN_INODE trees to track inode
information rather than AG information. I think the flag usage just
threw me off at a glance. With that cleared up:

Reviewed-by: Brian Foster <bfoster@redhat.com>

> If we are going to put short ptrs in an inode, then at that point
> we need to change the btree cursor, anyway, because then we are
> going to need both an inode pointer and something else to turn those
> short pointers into global scope pointers for IO....
> 
> Cheers,
> 
> Dave.
> -- 
> Dave Chinner
> david@fromorbit.com
> 


^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 17/22] xfs: simplify xfs_dialloc_select_ag() return values
  2021-05-06  7:20 ` [PATCH 17/22] xfs: simplify xfs_dialloc_select_ag() return values Dave Chinner
@ 2021-05-12 12:49   ` Brian Foster
  2021-05-12 22:55   ` Darrick J. Wong
  1 sibling, 0 replies; 87+ messages in thread
From: Brian Foster @ 2021-05-12 12:49 UTC (permalink / raw)
  To: Dave Chinner; +Cc: linux-xfs

On Thu, May 06, 2021 at 05:20:49PM +1000, Dave Chinner wrote:
> From: Dave Chinner <dchinner@redhat.com>
> 
> The only caller of xfs_dialloc_select_ag() will always return
> -ENOSPC to it's caller if the agbp returned from
> xfs_dialloc_select_ag() is NULL. IOWs, failure to find a candidate
> AGI we can allocate inodes from is always an ENOSPC condition, so
> move this logic up into xfs_dialloc_select_ag() so we can simplify
> the return logic in this function.
> 
> xfs_dialloc_select_ag() now only ever returns 0 with a locked
> agbp, or an error with no agbp.
> 
> Signed-off-by: Dave Chinner <dchinner@redhat.com>
> ---

Reviewed-by: Brian Foster <bfoster@redhat.com>

>  fs/xfs/libxfs/xfs_ialloc.c | 23 ++++++++---------------
>  fs/xfs/xfs_inode.c         |  3 ---
>  2 files changed, 8 insertions(+), 18 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_ialloc.c b/fs/xfs/libxfs/xfs_ialloc.c
> index 4540fbcd68a3..872591e8f5cb 100644
> --- a/fs/xfs/libxfs/xfs_ialloc.c
> +++ b/fs/xfs/libxfs/xfs_ialloc.c
> @@ -1717,7 +1717,7 @@ xfs_dialloc_roll(
>   * This function will ensure that the selected AG has free inodes available to
>   * allocate from. The selected AGI will be returned locked to the caller, and it
>   * will allocate more free inodes if required. If no free inodes are found or
> - * can be allocated, no AGI will be returned.
> + * can be allocated, -ENOSPC be returned.
>   */
>  int
>  xfs_dialloc_select_ag(
> @@ -1730,7 +1730,6 @@ xfs_dialloc_select_ag(
>  	struct xfs_buf		*agbp;
>  	xfs_agnumber_t		agno;
>  	int			error;
> -	bool			noroom = false;
>  	xfs_agnumber_t		start_agno;
>  	struct xfs_perag	*pag;
>  	struct xfs_ino_geometry	*igeo = M_IGEO(mp);
> @@ -1744,7 +1743,7 @@ xfs_dialloc_select_ag(
>  	 */
>  	start_agno = xfs_ialloc_ag_select(*tpp, parent, mode);
>  	if (start_agno == NULLAGNUMBER)
> -		return 0;
> +		return -ENOSPC;
>  
>  	/*
>  	 * If we have already hit the ceiling of inode blocks then clear
> @@ -1757,7 +1756,6 @@ xfs_dialloc_select_ag(
>  	if (igeo->maxicount &&
>  	    percpu_counter_read_positive(&mp->m_icount) + igeo->ialloc_inos
>  							> igeo->maxicount) {
> -		noroom = true;
>  		okalloc = false;
>  	}
>  
> @@ -1794,10 +1792,8 @@ xfs_dialloc_select_ag(
>  		if (error)
>  			break;
>  
> -		if (pag->pagi_freecount) {
> -			xfs_perag_put(pag);
> +		if (pag->pagi_freecount)
>  			goto found_ag;
> -		}
>  
>  		if (!okalloc)
>  			goto nextag_relse_buffer;
> @@ -1805,9 +1801,6 @@ xfs_dialloc_select_ag(
>  		error = xfs_ialloc_ag_alloc(*tpp, agbp, pag);
>  		if (error < 0) {
>  			xfs_trans_brelse(*tpp, agbp);
> -
> -			if (error == -ENOSPC)
> -				error = 0;
>  			break;
>  		}
>  
> @@ -1818,12 +1811,11 @@ xfs_dialloc_select_ag(
>  			 * allocate one of the new inodes.
>  			 */
>  			ASSERT(pag->pagi_freecount > 0);
> -			xfs_perag_put(pag);
>  
>  			error = xfs_dialloc_roll(tpp, agbp);
>  			if (error) {
>  				xfs_buf_relse(agbp);
> -				return error;
> +				break;
>  			}
>  			goto found_ag;
>  		}
> @@ -1831,16 +1823,17 @@ xfs_dialloc_select_ag(
>  nextag_relse_buffer:
>  		xfs_trans_brelse(*tpp, agbp);
>  nextag:
> -		xfs_perag_put(pag);
>  		if (++agno == mp->m_sb.sb_agcount)
>  			agno = 0;
>  		if (agno == start_agno)
> -			return noroom ? -ENOSPC : 0;
> +			break;
> +		xfs_perag_put(pag);
>  	}
>  
>  	xfs_perag_put(pag);
> -	return error;
> +	return error ? error : -ENOSPC;
>  found_ag:
> +	xfs_perag_put(pag);
>  	*IO_agbp = agbp;
>  	return 0;
>  }
> diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
> index 25910b145d70..3918c99fa95b 100644
> --- a/fs/xfs/xfs_inode.c
> +++ b/fs/xfs/xfs_inode.c
> @@ -923,9 +923,6 @@ xfs_dir_ialloc(
>  	if (error)
>  		return error;
>  
> -	if (!agibp)
> -		return -ENOSPC;
> -
>  	/* Allocate an inode from the selected AG */
>  	error = xfs_dialloc_ag(*tpp, agibp, parent_ino, &ino);
>  	if (error)
> -- 
> 2.31.1
> 


^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 18/22] xfs: collapse AG selection for inode allocation
  2021-05-06  7:20 ` [PATCH 18/22] xfs: collapse AG selection for inode allocation Dave Chinner
@ 2021-05-12 12:52   ` Brian Foster
  2021-05-18  1:21     ` Dave Chinner
  2021-05-12 23:11   ` Darrick J. Wong
  1 sibling, 1 reply; 87+ messages in thread
From: Brian Foster @ 2021-05-12 12:52 UTC (permalink / raw)
  To: Dave Chinner; +Cc: linux-xfs

On Thu, May 06, 2021 at 05:20:50PM +1000, Dave Chinner wrote:
> From: Dave Chinner <dchinner@redhat.com>
> 
> xfs_dialloc_select_ag() does a lot of repetitive work. It first
> calls xfs_ialloc_ag_select() to select the AG to start allocation
> attempts in, which can do up to two entire loops across the perags
> that inodes can be allocated in. This is simply checking if there is
> spce available to allocate inodes in an AG, and it returns when it
> finds the first candidate AG.
> 
> xfs_dialloc_select_ag() then does it's own iterative walk across
> all the perags locking the AGIs and trying to allocate inodes from
> the locked AG. It also doesn't limit the search to mp->m_maxagi,
> so it will walk all AGs whether they can allocate inodes or not.
> 
> Hence if we are really low on inodes, we could do almost 3 entire
> walks across the whole perag range before we find an allocation
> group we can allocate inodes in or report ENOSPC.
> 
> Because xfs_ialloc_ag_select() returns on the first candidate AG it
> finds, we can simply do these checks directly in
> xfs_dialloc_select_ag() before we lock and try to allocate inodes.
> This reduces the inode allocation pass down to 2 perag sweeps at
> most - one for aligned inode cluster allocation and if we can't
> allocate full, aligned inode clusters anywhere we'll do another pass
> trying to do sparse inode cluster allocation.
> 
> This also removes a big chunk of duplicate code.
> 
> Signed-off-by: Dave Chinner <dchinner@redhat.com>
> ---
>  fs/xfs/libxfs/xfs_ialloc.c | 221 +++++++++++++------------------------
>  1 file changed, 75 insertions(+), 146 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_ialloc.c b/fs/xfs/libxfs/xfs_ialloc.c
> index 872591e8f5cb..b22556556bba 100644
> --- a/fs/xfs/libxfs/xfs_ialloc.c
> +++ b/fs/xfs/libxfs/xfs_ialloc.c
...
> @@ -1778,10 +1669,41 @@ xfs_dialloc_select_ag(
>  				break;
>  		}
>  
> +		if (!pag->pagi_freecount)
> +			goto nextag;

It looks like this would never allow for allocation of new inode
chunks..?

> +		if (!okalloc)
> +			goto nextag;
> +
> +		if (!pag->pagf_init) {
> +			error = xfs_alloc_pagf_init(mp, *tpp, agno, flags);
> +			if (error)
> +				goto nextag;
> +		}
> +
>  		/*
> -		 * Do a first racy fast path check if this AG is usable.
> +		 * Check that there is enough free space for the file plus a
> +		 * chunk of inodes if we need to allocate some. If this is the
> +		 * first pass across the AGs, take into account the potential
> +		 * space needed for alignment of inode chunks when checking the
> +		 * longest contiguous free space in the AG - this prevents us
> +		 * from getting ENOSPC because we have free space larger than
> +		 * ialloc_blks but alignment constraints prevent us from using
> +		 * it.
> +		 *
> +		 * If we can't find an AG with space for full alignment slack to
> +		 * be taken into account, we must be near ENOSPC in all AGs.
> +		 * Hence we don't include alignment for the second pass and so
> +		 * if we fail allocation due to alignment issues then it is most
> +		 * likely a real ENOSPC condition.
>  		 */
> -		if (!pag->pagi_freecount && !okalloc)
> +		ineed = M_IGEO(mp)->ialloc_min_blks;
> +		if (flags && ineed > 1)
> +			ineed += M_IGEO(mp)->cluster_align;
> +		longest = pag->pagf_longest;
> +		if (!longest)
> +			longest = pag->pagf_flcount > 0;
> +
> +		if (pag->pagf_freeblks < needspace + ineed || longest < ineed)
>  			goto nextag;

... and here we check for enough free space in the AG for chunk
allocation purposes. The pagi_freecount check is further down, however,
so it looks like we can skip the AG even if pagi_freecount > 0 and
allocation is not necessary.

Brian

>  
>  		/*
> @@ -1823,10 +1745,17 @@ xfs_dialloc_select_ag(
>  nextag_relse_buffer:
>  		xfs_trans_brelse(*tpp, agbp);
>  nextag:
> -		if (++agno == mp->m_sb.sb_agcount)
> -			agno = 0;
> -		if (agno == start_agno)
> +		if (XFS_FORCED_SHUTDOWN(mp)) {
> +			error = -EFSCORRUPTED;
>  			break;
> +		}
> +		if (++agno == mp->m_maxagi)
> +			agno = 0;
> +		if (agno == start_agno) {
> +			if (!flags)
> +				break;
> +			flags = 0;
> +		}
>  		xfs_perag_put(pag);
>  	}
>  
> -- 
> 2.31.1
> 


^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 19/22] xfs: get rid of xfs_dir_ialloc()
  2021-05-06  7:20 ` [PATCH 19/22] xfs: get rid of xfs_dir_ialloc() Dave Chinner
  2021-05-06 11:26     ` kernel test robot
  2021-05-06 11:26     ` kernel test robot
@ 2021-05-12 12:52   ` Brian Foster
  2021-05-12 23:19   ` Darrick J. Wong
  3 siblings, 0 replies; 87+ messages in thread
From: Brian Foster @ 2021-05-12 12:52 UTC (permalink / raw)
  To: Dave Chinner; +Cc: linux-xfs

On Thu, May 06, 2021 at 05:20:51PM +1000, Dave Chinner wrote:
> From: Dave Chinner <dchinner@redhat.com>
> 
> This is just a simple wrapper around the per-ag inode allocation
> that doesn't need to exist. The internal mechanism to select and
> allocate within an AG does not need to be exposed outside
> xfs_ialloc.c, and it being exposed simply makes it harder to follow
> the code and simplify it.
> 
> This is simplified by internalising xf_dialloc_select_ag() and
> xfs_dialloc_ag() into a single xfs_dialloc() function and then
> xfs_dir_ialloc() can go away.
> 
> Signed-off-by: Dave Chinner <dchinner@redhat.com>
> ---

Looks fine to me modulo the kernel robot thing:

Reviewed-by: Brian Foster <bfoster@redhat.com>

>  fs/xfs/libxfs/xfs_ialloc.c | 15 +++++----
>  fs/xfs/libxfs/xfs_ialloc.h | 27 +++-------------
>  fs/xfs/xfs_inode.c         | 66 +++++++-------------------------------
>  fs/xfs/xfs_inode.h         |  9 +++---
>  fs/xfs/xfs_qm.c            |  9 ++++--
>  fs/xfs/xfs_symlink.c       |  9 ++++--
>  6 files changed, 43 insertions(+), 92 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_ialloc.c b/fs/xfs/libxfs/xfs_ialloc.c
> index b22556556bba..2c0ef2dd46d9 100644
> --- a/fs/xfs/libxfs/xfs_ialloc.c
> +++ b/fs/xfs/libxfs/xfs_ialloc.c
> @@ -1602,24 +1602,23 @@ xfs_ialloc_next_ag(
>   * can be allocated, -ENOSPC be returned.
>   */
>  int
> -xfs_dialloc_select_ag(
> +xfs_dialloc(
>  	struct xfs_trans	**tpp,
>  	xfs_ino_t		parent,
>  	umode_t			mode,
> -	struct xfs_buf		**IO_agbp)
> +	xfs_ino_t		*new_ino)
>  {
>  	struct xfs_mount	*mp = (*tpp)->t_mountp;
>  	struct xfs_buf		*agbp;
>  	xfs_agnumber_t		agno;
> -	int			error;
> +	int			error = 0;
>  	xfs_agnumber_t		start_agno;
>  	struct xfs_perag	*pag;
>  	struct xfs_ino_geometry	*igeo = M_IGEO(mp);
>  	bool			okalloc = true;
>  	int			needspace;
>  	int			flags;
> -
> -	*IO_agbp = NULL;
> +	xfs_ino_t		ino;
>  
>  	/*
>  	 * Files of these types need at least one block if length > 0
> @@ -1763,7 +1762,11 @@ xfs_dialloc_select_ag(
>  	return error ? error : -ENOSPC;
>  found_ag:
>  	xfs_perag_put(pag);
> -	*IO_agbp = agbp;
> +	/* Allocate an inode in the found AG */
> +	error = xfs_dialloc_ag(*tpp, agbp, parent, &ino);
> +	if (error)
> +		return error;
> +	*new_ino = ino;
>  	return 0;
>  }
>  
> diff --git a/fs/xfs/libxfs/xfs_ialloc.h b/fs/xfs/libxfs/xfs_ialloc.h
> index 3511086a7ae1..886f6748fb22 100644
> --- a/fs/xfs/libxfs/xfs_ialloc.h
> +++ b/fs/xfs/libxfs/xfs_ialloc.h
> @@ -33,30 +33,11 @@ xfs_make_iptr(struct xfs_mount *mp, struct xfs_buf *b, int o)
>  }
>  
>  /*
> - * Allocate an inode on disk.
> - * Mode is used to tell whether the new inode will need space, and whether
> - * it is a directory.
> - *
> - * There are two phases to inode allocation: selecting an AG and ensuring
> - * that it contains free inodes, followed by allocating one of the free
> - * inodes. xfs_dialloc_select_ag() does the former and returns a locked AGI
> - * to the caller, ensuring that followup call to xfs_dialloc_ag() will
> - * have free inodes to allocate from. xfs_dialloc_ag() will return the inode
> - * number of the free inode we allocated.
> + * Allocate an inode on disk.  Mode is used to tell whether the new inode will
> + * need space, and whether it is a directory.
>   */
> -int					/* error */
> -xfs_dialloc_select_ag(
> -	struct xfs_trans **tpp,		/* double pointer of transaction */
> -	xfs_ino_t	parent,		/* parent inode (directory) */
> -	umode_t		mode,		/* mode bits for new inode */
> -	struct xfs_buf	**IO_agbp);
> -
> -int
> -xfs_dialloc_ag(
> -	struct xfs_trans	*tp,
> -	struct xfs_buf		*agbp,
> -	xfs_ino_t		parent,
> -	xfs_ino_t		*inop);
> +int xfs_dialloc(struct xfs_trans **tpp, xfs_ino_t parent, umode_t mode,
> +		xfs_ino_t *new_ino);
>  
>  /*
>   * Free disk inode.  Carefully avoids touching the incore inode, all
> diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
> index 3918c99fa95b..26668b6846e2 100644
> --- a/fs/xfs/xfs_inode.c
> +++ b/fs/xfs/xfs_inode.c
> @@ -749,7 +749,7 @@ xfs_inode_inherit_flags2(
>   * Initialise a newly allocated inode and return the in-core inode to the
>   * caller locked exclusively.
>   */
> -static int
> +int
>  xfs_init_new_inode(
>  	struct user_namespace	*mnt_userns,
>  	struct xfs_trans	*tp,
> @@ -885,54 +885,6 @@ xfs_init_new_inode(
>  	return 0;
>  }
>  
> -/*
> - * Allocates a new inode from disk and return a pointer to the incore copy. This
> - * routine will internally commit the current transaction and allocate a new one
> - * if we needed to allocate more on-disk free inodes to perform the requested
> - * operation.
> - *
> - * If we are allocating quota inodes, we do not have a parent inode to attach to
> - * or associate with (i.e. dp == NULL) because they are not linked into the
> - * directory structure - they are attached directly to the superblock - and so
> - * have no parent.
> - */
> -int
> -xfs_dir_ialloc(
> -	struct user_namespace	*mnt_userns,
> -	struct xfs_trans	**tpp,
> -	struct xfs_inode	*dp,
> -	umode_t			mode,
> -	xfs_nlink_t		nlink,
> -	dev_t			rdev,
> -	prid_t			prid,
> -	bool			init_xattrs,
> -	struct xfs_inode	**ipp)
> -{
> -	struct xfs_buf		*agibp;
> -	xfs_ino_t		parent_ino = dp ? dp->i_ino : 0;
> -	xfs_ino_t		ino;
> -	int			error;
> -
> -	ASSERT((*tpp)->t_flags & XFS_TRANS_PERM_LOG_RES);
> -
> -	/*
> -	 * Call the space management code to pick the on-disk inode to be
> -	 * allocated.
> -	 */
> -	error = xfs_dialloc_select_ag(tpp, parent_ino, mode, &agibp);
> -	if (error)
> -		return error;
> -
> -	/* Allocate an inode from the selected AG */
> -	error = xfs_dialloc_ag(*tpp, agibp, parent_ino, &ino);
> -	if (error)
> -		return error;
> -	ASSERT(ino != NULLFSINO);
> -
> -	return xfs_init_new_inode(mnt_userns, *tpp, dp, ino, mode, nlink, rdev,
> -				  prid, init_xattrs, ipp);
> -}
> -
>  /*
>   * Decrement the link count on an inode & log the change.  If this causes the
>   * link count to go to zero, move the inode to AGI unlinked list so that it can
> @@ -990,6 +942,7 @@ xfs_create(
>  	struct xfs_dquot	*pdqp = NULL;
>  	struct xfs_trans_res	*tres;
>  	uint			resblks;
> +	xfs_ino_t		ino;
>  
>  	trace_xfs_create(dp, name);
>  
> @@ -1046,14 +999,16 @@ xfs_create(
>  	 * entry pointing to them, but a directory also the "." entry
>  	 * pointing to itself.
>  	 */
> -	error = xfs_dir_ialloc(mnt_userns, &tp, dp, mode, is_dir ? 2 : 1, rdev,
> -			       prid, init_xattrs, &ip);
> +	error = xfs_dialloc(&tp, dp->i_ino, mode, &ino);
> +	if (!error)
> +		error = xfs_init_new_inode(mnt_userns, tp, dp, ino, mode,
> +				is_dir ? 2 : 1, rdev, prid, init_xattrs, &ip);
>  	if (error)
>  		goto out_trans_cancel;
>  
>  	/*
>  	 * Now we join the directory inode to the transaction.  We do not do it
> -	 * earlier because xfs_dir_ialloc might commit the previous transaction
> +	 * earlier because xfs_dialloc might commit the previous transaction
>  	 * (and release all the locks).  An error from here on will result in
>  	 * the transaction cancel unlocking dp so don't do it explicitly in the
>  	 * error path.
> @@ -1143,6 +1098,7 @@ xfs_create_tmpfile(
>  	struct xfs_dquot	*pdqp = NULL;
>  	struct xfs_trans_res	*tres;
>  	uint			resblks;
> +	xfs_ino_t		ino;
>  
>  	if (XFS_FORCED_SHUTDOWN(mp))
>  		return -EIO;
> @@ -1167,8 +1123,10 @@ xfs_create_tmpfile(
>  	if (error)
>  		goto out_release_dquots;
>  
> -	error = xfs_dir_ialloc(mnt_userns, &tp, dp, mode, 0, 0, prid,
> -				false, &ip);
> +	error = xfs_dialloc(&tp, dp->i_ino, mode, &ino);
> +	if (!error)
> +		error = xfs_init_new_inode(mnt_userns, tp, dp, ino, mode,
> +				0, 0, prid, false, &ip);
>  	if (error)
>  		goto out_trans_cancel;
>  
> diff --git a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h
> index ca826cfba91c..4b6703dbffb8 100644
> --- a/fs/xfs/xfs_inode.h
> +++ b/fs/xfs/xfs_inode.h
> @@ -431,11 +431,10 @@ void		xfs_lock_two_inodes(struct xfs_inode *ip0, uint ip0_mode,
>  xfs_extlen_t	xfs_get_extsz_hint(struct xfs_inode *ip);
>  xfs_extlen_t	xfs_get_cowextsz_hint(struct xfs_inode *ip);
>  
> -int		xfs_dir_ialloc(struct user_namespace *mnt_userns,
> -			       struct xfs_trans **tpp, struct xfs_inode *dp,
> -			       umode_t mode, xfs_nlink_t nlink, dev_t dev,
> -			       prid_t prid, bool need_xattr,
> -			       struct xfs_inode **ipp);
> +int xfs_init_new_inode(struct user_namespace *mnt_userns, struct xfs_trans *tp,
> +		struct xfs_inode *pip, xfs_ino_t ino, umode_t mode,
> +		xfs_nlink_t nlink, dev_t rdev, prid_t prid, bool init_xattrs,
> +		struct xfs_inode **ipp);
>  
>  static inline int
>  xfs_itruncate_extents(
> diff --git a/fs/xfs/xfs_qm.c b/fs/xfs/xfs_qm.c
> index f7baf4dc2554..fe341f3fd419 100644
> --- a/fs/xfs/xfs_qm.c
> +++ b/fs/xfs/xfs_qm.c
> @@ -24,6 +24,7 @@
>  #include "xfs_icache.h"
>  #include "xfs_error.h"
>  #include "xfs_ag.h"
> +#include "xfs_ialloc.h"
>  
>  /*
>   * The global quota manager. There is only one of these for the entire
> @@ -788,8 +789,12 @@ xfs_qm_qino_alloc(
>  		return error;
>  
>  	if (need_alloc) {
> -		error = xfs_dir_ialloc(&init_user_ns, &tp, NULL, S_IFREG, 1, 0,
> -				       0, false, ipp);
> +		xfs_ino_t	ino;
> +
> +		error = xfs_dialloc(&tp, 0, S_IFREG, &ino);
> +		if (!error)
> +			error = xfs_init_new_inode(&init_user_ns, tp, NULL, ino,
> +					S_IFREG, 1, 0, 0, false, ipp);
>  		if (error) {
>  			xfs_trans_cancel(tp);
>  			return error;
> diff --git a/fs/xfs/xfs_symlink.c b/fs/xfs/xfs_symlink.c
> index b4fa70282383..44596c31f4c9 100644
> --- a/fs/xfs/xfs_symlink.c
> +++ b/fs/xfs/xfs_symlink.c
> @@ -21,6 +21,7 @@
>  #include "xfs_trans_space.h"
>  #include "xfs_trace.h"
>  #include "xfs_trans.h"
> +#include "xfs_ialloc.h"
>  
>  /* ----- Kernel only functions below ----- */
>  int
> @@ -161,6 +162,7 @@ xfs_symlink(
>  	struct xfs_dquot	*gdqp = NULL;
>  	struct xfs_dquot	*pdqp = NULL;
>  	uint			resblks;
> +	xfs_ino_t		ino;
>  
>  	*ipp = NULL;
>  
> @@ -223,8 +225,11 @@ xfs_symlink(
>  	/*
>  	 * Allocate an inode for the symlink.
>  	 */
> -	error = xfs_dir_ialloc(mnt_userns, &tp, dp, S_IFLNK | (mode & ~S_IFMT),
> -			       1, 0, prid, false, &ip);
> +	error = xfs_dialloc(&tp, dp->i_ino, S_IFLNK, &ino);
> +	if (!error)
> +		error = xfs_init_new_inode(mnt_userns, tp, dp, ino,
> +				S_IFLNK | (mode & ~S_IFMT), 1, 0, prid,
> +				false, &ip);
>  	if (error)
>  		goto out_trans_cancel;
>  
> -- 
> 2.31.1
> 


^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 20/22] xfs: inode allocation can use a single perag instance
  2021-05-06  7:20 ` [PATCH 20/22] xfs: inode allocation can use a single perag instance Dave Chinner
@ 2021-05-12 12:52   ` Brian Foster
  2021-05-12 23:19   ` Darrick J. Wong
  1 sibling, 0 replies; 87+ messages in thread
From: Brian Foster @ 2021-05-12 12:52 UTC (permalink / raw)
  To: Dave Chinner; +Cc: linux-xfs

On Thu, May 06, 2021 at 05:20:52PM +1000, Dave Chinner wrote:
> From: Dave Chinner <dchinner@redhat.com>
> 
> Now that we've internalised the two-phase inode allocation, we can
> now easily make the AG selection and allocation atomic from the
> perspective of a single perag context. This will ensure AGs going
> offline/away cannot occur between the selection and allocation
> steps.
> 
> Signed-off-by: Dave Chinner <dchinner@redhat.com>
> ---

Reviewed-by: Brian Foster <bfoster@redhat.com>

>  fs/xfs/libxfs/xfs_ialloc.c | 6 +++---
>  1 file changed, 3 insertions(+), 3 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_ialloc.c b/fs/xfs/libxfs/xfs_ialloc.c
> index 2c0ef2dd46d9..d749bb7c7a69 100644
> --- a/fs/xfs/libxfs/xfs_ialloc.c
> +++ b/fs/xfs/libxfs/xfs_ialloc.c
> @@ -1432,6 +1432,7 @@ int
>  xfs_dialloc_ag(
>  	struct xfs_trans	*tp,
>  	struct xfs_buf		*agbp,
> +	struct xfs_perag	*pag,
>  	xfs_ino_t		parent,
>  	xfs_ino_t		*inop)
>  {
> @@ -1446,7 +1447,6 @@ xfs_dialloc_ag(
>  	int				error;
>  	int				offset;
>  	int				i;
> -	struct xfs_perag		*pag = agbp->b_pag;
>  
>  	if (!xfs_sb_version_hasfinobt(&mp->m_sb))
>  		return xfs_dialloc_ag_inobt(tp, agbp, pag, parent, inop);
> @@ -1761,9 +1761,9 @@ xfs_dialloc(
>  	xfs_perag_put(pag);
>  	return error ? error : -ENOSPC;
>  found_ag:
> -	xfs_perag_put(pag);
>  	/* Allocate an inode in the found AG */
> -	error = xfs_dialloc_ag(*tpp, agbp, parent, &ino);
> +	error = xfs_dialloc_ag(*tpp, agbp, pag, parent, &ino);
> +	xfs_perag_put(pag);
>  	if (error)
>  		return error;
>  	*new_ino = ino;
> -- 
> 2.31.1
> 


^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 22/22] xfs: use perag through unlink processing
  2021-05-06  7:20 ` [PATCH 22/22] xfs: use perag through unlink processing Dave Chinner
@ 2021-05-12 21:37   ` Darrick J. Wong
  0 siblings, 0 replies; 87+ messages in thread
From: Darrick J. Wong @ 2021-05-12 21:37 UTC (permalink / raw)
  To: Dave Chinner; +Cc: linux-xfs

On Thu, May 06, 2021 at 05:20:54PM +1000, Dave Chinner wrote:
> From: Dave Chinner <dchinner@redhat.com>
> 
> Unlinked lists are held in the perag, and freeing of inodes needs to
> be passed a perag, too, so look up the perag early in the unlink
> processing and use it throughout.
> 
> Signed-off-by: Dave Chinner <dchinner@redhat.com>

Looks like a fairly straightforward conversion...
Reviewed-by: Darrick J. Wong <djwong@kernel.org>

--D

> ---
>  fs/xfs/libxfs/xfs_ialloc.c |  23 +++----
>  fs/xfs/libxfs/xfs_ialloc.h |  13 +---
>  fs/xfs/xfs_inode.c         | 131 +++++++++++++++++++++----------------
>  3 files changed, 87 insertions(+), 80 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_ialloc.c b/fs/xfs/libxfs/xfs_ialloc.c
> index 340bb95d7bc1..be84820588c6 100644
> --- a/fs/xfs/libxfs/xfs_ialloc.c
> +++ b/fs/xfs/libxfs/xfs_ialloc.c
> @@ -2133,35 +2133,33 @@ xfs_difree_finobt(
>   */
>  int
>  xfs_difree(
> -	struct xfs_trans	*tp,		/* transaction pointer */
> -	xfs_ino_t		inode,		/* inode to be freed */
> -	struct xfs_icluster	*xic)	/* cluster info if deleted */
> +	struct xfs_trans	*tp,
> +	struct xfs_perag	*pag,
> +	xfs_ino_t		inode,
> +	struct xfs_icluster	*xic)
>  {
>  	/* REFERENCED */
>  	xfs_agblock_t		agbno;	/* block number containing inode */
>  	struct xfs_buf		*agbp;	/* buffer for allocation group header */
>  	xfs_agino_t		agino;	/* allocation group inode number */
> -	xfs_agnumber_t		agno;	/* allocation group number */
>  	int			error;	/* error return value */
>  	struct xfs_mount	*mp = tp->t_mountp;
>  	struct xfs_inobt_rec_incore rec;/* btree record */
> -	struct xfs_perag	*pag;
>  
>  	/*
>  	 * Break up inode number into its components.
>  	 */
> -	agno = XFS_INO_TO_AGNO(mp, inode);
> -	if (agno >= mp->m_sb.sb_agcount) {
> -		xfs_warn(mp, "%s: agno >= mp->m_sb.sb_agcount (%d >= %d).",
> -			__func__, agno, mp->m_sb.sb_agcount);
> +	if (pag->pag_agno != XFS_INO_TO_AGNO(mp, inode)) {
> +		xfs_warn(mp, "%s: agno != pag->pag_agno (%d != %d).",
> +			__func__, XFS_INO_TO_AGNO(mp, inode), pag->pag_agno);
>  		ASSERT(0);
>  		return -EINVAL;
>  	}
>  	agino = XFS_INO_TO_AGINO(mp, inode);
> -	if (inode != XFS_AGINO_TO_INO(mp, agno, agino))  {
> +	if (inode != XFS_AGINO_TO_INO(mp, pag->pag_agno, agino))  {
>  		xfs_warn(mp, "%s: inode != XFS_AGINO_TO_INO() (%llu != %llu).",
>  			__func__, (unsigned long long)inode,
> -			(unsigned long long)XFS_AGINO_TO_INO(mp, agno, agino));
> +			(unsigned long long)XFS_AGINO_TO_INO(mp, pag->pag_agno, agino));
>  		ASSERT(0);
>  		return -EINVAL;
>  	}
> @@ -2175,7 +2173,7 @@ xfs_difree(
>  	/*
>  	 * Get the allocation group header.
>  	 */
> -	error = xfs_ialloc_read_agi(mp, tp, agno, &agbp);
> +	error = xfs_ialloc_read_agi(mp, tp, pag->pag_agno, &agbp);
>  	if (error) {
>  		xfs_warn(mp, "%s: xfs_ialloc_read_agi() returned error %d.",
>  			__func__, error);
> @@ -2185,7 +2183,6 @@ xfs_difree(
>  	/*
>  	 * Fix up the inode allocation btree.
>  	 */
> -	pag = agbp->b_pag;
>  	error = xfs_difree_inobt(mp, tp, agbp, pag, agino, xic, &rec);
>  	if (error)
>  		goto error0;
> diff --git a/fs/xfs/libxfs/xfs_ialloc.h b/fs/xfs/libxfs/xfs_ialloc.h
> index 886f6748fb22..9df7c80408ff 100644
> --- a/fs/xfs/libxfs/xfs_ialloc.h
> +++ b/fs/xfs/libxfs/xfs_ialloc.h
> @@ -39,17 +39,8 @@ xfs_make_iptr(struct xfs_mount *mp, struct xfs_buf *b, int o)
>  int xfs_dialloc(struct xfs_trans **tpp, xfs_ino_t parent, umode_t mode,
>  		xfs_ino_t *new_ino);
>  
> -/*
> - * Free disk inode.  Carefully avoids touching the incore inode, all
> - * manipulations incore are the caller's responsibility.
> - * The on-disk inode is not changed by this operation, only the
> - * btree (free inode mask) is changed.
> - */
> -int					/* error */
> -xfs_difree(
> -	struct xfs_trans *tp,		/* transaction pointer */
> -	xfs_ino_t	inode,		/* inode to be freed */
> -	struct xfs_icluster *ifree);	/* cluster info if deleted */
> +int xfs_difree(struct xfs_trans *tp, struct xfs_perag *pag,
> +		xfs_ino_t ino, struct xfs_icluster *ifree);
>  
>  /*
>   * Return the location of the inode in imap, for mapping it into a buffer.
> diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
> index 26668b6846e2..aad98a982382 100644
> --- a/fs/xfs/xfs_inode.c
> +++ b/fs/xfs/xfs_inode.c
> @@ -45,7 +45,8 @@ kmem_zone_t *xfs_inode_zone;
>  #define	XFS_ITRUNC_MAX_EXTENTS	2
>  
>  STATIC int xfs_iunlink(struct xfs_trans *, struct xfs_inode *);
> -STATIC int xfs_iunlink_remove(struct xfs_trans *, struct xfs_inode *);
> +STATIC int xfs_iunlink_remove(struct xfs_trans *tp, struct xfs_perag *pag,
> +	struct xfs_inode *);
>  
>  /*
>   * helper function to extract extent size hint from inode
> @@ -1241,7 +1242,11 @@ xfs_link(
>  	 * Handle initial link state of O_TMPFILE inode
>  	 */
>  	if (VFS_I(sip)->i_nlink == 0) {
> -		error = xfs_iunlink_remove(tp, sip);
> +		struct xfs_perag	*pag;
> +
> +		pag = xfs_perag_get(mp, XFS_INO_TO_AGNO(mp, sip->i_ino));
> +		error = xfs_iunlink_remove(tp, pag, sip);
> +		xfs_perag_put(pag);
>  		if (error)
>  			goto error_return;
>  	}
> @@ -1934,7 +1939,7 @@ xfs_iunlink_destroy(
>  STATIC int
>  xfs_iunlink_update_bucket(
>  	struct xfs_trans	*tp,
> -	xfs_agnumber_t		agno,
> +	struct xfs_perag	*pag,
>  	struct xfs_buf		*agibp,
>  	unsigned int		bucket_index,
>  	xfs_agino_t		new_agino)
> @@ -1943,10 +1948,10 @@ xfs_iunlink_update_bucket(
>  	xfs_agino_t		old_value;
>  	int			offset;
>  
> -	ASSERT(xfs_verify_agino_or_null(tp->t_mountp, agno, new_agino));
> +	ASSERT(xfs_verify_agino_or_null(tp->t_mountp, pag->pag_agno, new_agino));
>  
>  	old_value = be32_to_cpu(agi->agi_unlinked[bucket_index]);
> -	trace_xfs_iunlink_update_bucket(tp->t_mountp, agno, bucket_index,
> +	trace_xfs_iunlink_update_bucket(tp->t_mountp, pag->pag_agno, bucket_index,
>  			old_value, new_agino);
>  
>  	/*
> @@ -1970,7 +1975,7 @@ xfs_iunlink_update_bucket(
>  STATIC void
>  xfs_iunlink_update_dinode(
>  	struct xfs_trans	*tp,
> -	xfs_agnumber_t		agno,
> +	struct xfs_perag	*pag,
>  	xfs_agino_t		agino,
>  	struct xfs_buf		*ibp,
>  	struct xfs_dinode	*dip,
> @@ -1980,9 +1985,9 @@ xfs_iunlink_update_dinode(
>  	struct xfs_mount	*mp = tp->t_mountp;
>  	int			offset;
>  
> -	ASSERT(xfs_verify_agino_or_null(mp, agno, next_agino));
> +	ASSERT(xfs_verify_agino_or_null(mp, pag->pag_agno, next_agino));
>  
> -	trace_xfs_iunlink_update_dinode(mp, agno, agino,
> +	trace_xfs_iunlink_update_dinode(mp, pag->pag_agno, agino,
>  			be32_to_cpu(dip->di_next_unlinked), next_agino);
>  
>  	dip->di_next_unlinked = cpu_to_be32(next_agino);
> @@ -2000,7 +2005,7 @@ STATIC int
>  xfs_iunlink_update_inode(
>  	struct xfs_trans	*tp,
>  	struct xfs_inode	*ip,
> -	xfs_agnumber_t		agno,
> +	struct xfs_perag	*pag,
>  	xfs_agino_t		next_agino,
>  	xfs_agino_t		*old_next_agino)
>  {
> @@ -2010,7 +2015,7 @@ xfs_iunlink_update_inode(
>  	xfs_agino_t		old_value;
>  	int			error;
>  
> -	ASSERT(xfs_verify_agino_or_null(mp, agno, next_agino));
> +	ASSERT(xfs_verify_agino_or_null(mp, pag->pag_agno, next_agino));
>  
>  	error = xfs_imap_to_bp(mp, tp, &ip->i_imap, &ibp);
>  	if (error)
> @@ -2019,7 +2024,7 @@ xfs_iunlink_update_inode(
>  
>  	/* Make sure the old pointer isn't garbage. */
>  	old_value = be32_to_cpu(dip->di_next_unlinked);
> -	if (!xfs_verify_agino_or_null(mp, agno, old_value)) {
> +	if (!xfs_verify_agino_or_null(mp, pag->pag_agno, old_value)) {
>  		xfs_inode_verifier_error(ip, -EFSCORRUPTED, __func__, dip,
>  				sizeof(*dip), __this_address);
>  		error = -EFSCORRUPTED;
> @@ -2042,7 +2047,7 @@ xfs_iunlink_update_inode(
>  	}
>  
>  	/* Ok, update the new pointer. */
> -	xfs_iunlink_update_dinode(tp, agno, XFS_INO_TO_AGINO(mp, ip->i_ino),
> +	xfs_iunlink_update_dinode(tp, pag, XFS_INO_TO_AGINO(mp, ip->i_ino),
>  			ibp, dip, &ip->i_imap, next_agino);
>  	return 0;
>  out:
> @@ -2063,10 +2068,10 @@ xfs_iunlink(
>  	struct xfs_inode	*ip)
>  {
>  	struct xfs_mount	*mp = tp->t_mountp;
> +	struct xfs_perag	*pag;
>  	struct xfs_agi		*agi;
>  	struct xfs_buf		*agibp;
>  	xfs_agino_t		next_agino;
> -	xfs_agnumber_t		agno = XFS_INO_TO_AGNO(mp, ip->i_ino);
>  	xfs_agino_t		agino = XFS_INO_TO_AGINO(mp, ip->i_ino);
>  	short			bucket_index = agino % XFS_AGI_UNLINKED_BUCKETS;
>  	int			error;
> @@ -2075,10 +2080,12 @@ xfs_iunlink(
>  	ASSERT(VFS_I(ip)->i_mode != 0);
>  	trace_xfs_iunlink(ip);
>  
> +	pag = xfs_perag_get(mp, XFS_INO_TO_AGNO(mp, ip->i_ino));
> +
>  	/* Get the agi buffer first.  It ensures lock ordering on the list. */
> -	error = xfs_read_agi(mp, tp, agno, &agibp);
> +	error = xfs_read_agi(mp, tp, pag->pag_agno, &agibp);
>  	if (error)
> -		return error;
> +		goto out;
>  	agi = agibp->b_addr;
>  
>  	/*
> @@ -2088,9 +2095,10 @@ xfs_iunlink(
>  	 */
>  	next_agino = be32_to_cpu(agi->agi_unlinked[bucket_index]);
>  	if (next_agino == agino ||
> -	    !xfs_verify_agino_or_null(mp, agno, next_agino)) {
> +	    !xfs_verify_agino_or_null(mp, pag->pag_agno, next_agino)) {
>  		xfs_buf_mark_corrupt(agibp);
> -		return -EFSCORRUPTED;
> +		error = -EFSCORRUPTED;
> +		goto out;
>  	}
>  
>  	if (next_agino != NULLAGINO) {
> @@ -2100,23 +2108,26 @@ xfs_iunlink(
>  		 * There is already another inode in the bucket, so point this
>  		 * inode to the current head of the list.
>  		 */
> -		error = xfs_iunlink_update_inode(tp, ip, agno, next_agino,
> +		error = xfs_iunlink_update_inode(tp, ip, pag, next_agino,
>  				&old_agino);
>  		if (error)
> -			return error;
> +			goto out;
>  		ASSERT(old_agino == NULLAGINO);
>  
>  		/*
>  		 * agino has been unlinked, add a backref from the next inode
>  		 * back to agino.
>  		 */
> -		error = xfs_iunlink_add_backref(agibp->b_pag, agino, next_agino);
> +		error = xfs_iunlink_add_backref(pag, agino, next_agino);
>  		if (error)
> -			return error;
> +			goto out;
>  	}
>  
>  	/* Point the head of the list to point to this inode. */
> -	return xfs_iunlink_update_bucket(tp, agno, agibp, bucket_index, agino);
> +	error = xfs_iunlink_update_bucket(tp, pag, agibp, bucket_index, agino);
> +out:
> +	xfs_perag_put(pag);
> +	return error;
>  }
>  
>  /* Return the imap, dinode pointer, and buffer for an inode. */
> @@ -2164,14 +2175,13 @@ xfs_iunlink_map_ino(
>  STATIC int
>  xfs_iunlink_map_prev(
>  	struct xfs_trans	*tp,
> -	xfs_agnumber_t		agno,
> +	struct xfs_perag	*pag,
>  	xfs_agino_t		head_agino,
>  	xfs_agino_t		target_agino,
>  	xfs_agino_t		*agino,
>  	struct xfs_imap		*imap,
>  	struct xfs_dinode	**dipp,
> -	struct xfs_buf		**bpp,
> -	struct xfs_perag	*pag)
> +	struct xfs_buf		**bpp)
>  {
>  	struct xfs_mount	*mp = tp->t_mountp;
>  	xfs_agino_t		next_agino;
> @@ -2183,7 +2193,8 @@ xfs_iunlink_map_prev(
>  	/* See if our backref cache can find it faster. */
>  	*agino = xfs_iunlink_lookup_backref(pag, target_agino);
>  	if (*agino != NULLAGINO) {
> -		error = xfs_iunlink_map_ino(tp, agno, *agino, imap, dipp, bpp);
> +		error = xfs_iunlink_map_ino(tp, pag->pag_agno, *agino, imap,
> +				dipp, bpp);
>  		if (error)
>  			return error;
>  
> @@ -2199,7 +2210,7 @@ xfs_iunlink_map_prev(
>  		WARN_ON_ONCE(1);
>  	}
>  
> -	trace_xfs_iunlink_map_prev_fallback(mp, agno);
> +	trace_xfs_iunlink_map_prev_fallback(mp, pag->pag_agno);
>  
>  	/* Otherwise, walk the entire bucket until we find it. */
>  	next_agino = head_agino;
> @@ -2210,8 +2221,8 @@ xfs_iunlink_map_prev(
>  			xfs_trans_brelse(tp, *bpp);
>  
>  		*agino = next_agino;
> -		error = xfs_iunlink_map_ino(tp, agno, next_agino, imap, dipp,
> -				bpp);
> +		error = xfs_iunlink_map_ino(tp, pag->pag_agno, next_agino, imap,
> +				dipp, bpp);
>  		if (error)
>  			return error;
>  
> @@ -2220,7 +2231,7 @@ xfs_iunlink_map_prev(
>  		 * Make sure this pointer is valid and isn't an obvious
>  		 * infinite loop.
>  		 */
> -		if (!xfs_verify_agino(mp, agno, unlinked_agino) ||
> +		if (!xfs_verify_agino(mp, pag->pag_agno, unlinked_agino) ||
>  		    next_agino == unlinked_agino) {
>  			XFS_CORRUPTION_ERROR(__func__,
>  					XFS_ERRLEVEL_LOW, mp,
> @@ -2240,6 +2251,7 @@ xfs_iunlink_map_prev(
>  STATIC int
>  xfs_iunlink_remove(
>  	struct xfs_trans	*tp,
> +	struct xfs_perag	*pag,
>  	struct xfs_inode	*ip)
>  {
>  	struct xfs_mount	*mp = tp->t_mountp;
> @@ -2247,7 +2259,6 @@ xfs_iunlink_remove(
>  	struct xfs_buf		*agibp;
>  	struct xfs_buf		*last_ibp;
>  	struct xfs_dinode	*last_dip = NULL;
> -	xfs_agnumber_t		agno = XFS_INO_TO_AGNO(mp, ip->i_ino);
>  	xfs_agino_t		agino = XFS_INO_TO_AGINO(mp, ip->i_ino);
>  	xfs_agino_t		next_agino;
>  	xfs_agino_t		head_agino;
> @@ -2257,7 +2268,7 @@ xfs_iunlink_remove(
>  	trace_xfs_iunlink_remove(ip);
>  
>  	/* Get the agi buffer first.  It ensures lock ordering on the list. */
> -	error = xfs_read_agi(mp, tp, agno, &agibp);
> +	error = xfs_read_agi(mp, tp, pag->pag_agno, &agibp);
>  	if (error)
>  		return error;
>  	agi = agibp->b_addr;
> @@ -2267,7 +2278,7 @@ xfs_iunlink_remove(
>  	 * go on.  Make sure the head pointer isn't garbage.
>  	 */
>  	head_agino = be32_to_cpu(agi->agi_unlinked[bucket_index]);
> -	if (!xfs_verify_agino(mp, agno, head_agino)) {
> +	if (!xfs_verify_agino(mp, pag->pag_agno, head_agino)) {
>  		XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,
>  				agi, sizeof(*agi));
>  		return -EFSCORRUPTED;
> @@ -2278,7 +2289,7 @@ xfs_iunlink_remove(
>  	 * the old pointer value so that we can update whatever was previous
>  	 * to us in the list to point to whatever was next in the list.
>  	 */
> -	error = xfs_iunlink_update_inode(tp, ip, agno, NULLAGINO, &next_agino);
> +	error = xfs_iunlink_update_inode(tp, ip, pag, NULLAGINO, &next_agino);
>  	if (error)
>  		return error;
>  
> @@ -2290,8 +2301,7 @@ xfs_iunlink_remove(
>  	 * this inode's backref to point from the next inode.
>  	 */
>  	if (next_agino != NULLAGINO) {
> -		error = xfs_iunlink_change_backref(agibp->b_pag, next_agino,
> -				NULLAGINO);
> +		error = xfs_iunlink_change_backref(pag, next_agino, NULLAGINO);
>  		if (error)
>  			return error;
>  	}
> @@ -2301,14 +2311,13 @@ xfs_iunlink_remove(
>  		xfs_agino_t	prev_agino;
>  
>  		/* We need to search the list for the inode being freed. */
> -		error = xfs_iunlink_map_prev(tp, agno, head_agino, agino,
> -				&prev_agino, &imap, &last_dip, &last_ibp,
> -				agibp->b_pag);
> +		error = xfs_iunlink_map_prev(tp, pag, head_agino, agino,
> +				&prev_agino, &imap, &last_dip, &last_ibp);
>  		if (error)
>  			return error;
>  
>  		/* Point the previous inode on the list to the next inode. */
> -		xfs_iunlink_update_dinode(tp, agno, prev_agino, last_ibp,
> +		xfs_iunlink_update_dinode(tp, pag, prev_agino, last_ibp,
>  				last_dip, &imap, next_agino);
>  
>  		/*
> @@ -2324,7 +2333,7 @@ xfs_iunlink_remove(
>  	}
>  
>  	/* Point the head of the list to the next unlinked inode. */
> -	return xfs_iunlink_update_bucket(tp, agno, agibp, bucket_index,
> +	return xfs_iunlink_update_bucket(tp, pag, agibp, bucket_index,
>  			next_agino);
>  }
>  
> @@ -2335,12 +2344,11 @@ xfs_iunlink_remove(
>   */
>  static void
>  xfs_ifree_mark_inode_stale(
> -	struct xfs_buf		*bp,
> +	struct xfs_perag	*pag,
>  	struct xfs_inode	*free_ip,
>  	xfs_ino_t		inum)
>  {
> -	struct xfs_mount	*mp = bp->b_mount;
> -	struct xfs_perag	*pag = bp->b_pag;
> +	struct xfs_mount	*mp = pag->pag_mount;
>  	struct xfs_inode_log_item *iip;
>  	struct xfs_inode	*ip;
>  
> @@ -2430,10 +2438,11 @@ xfs_ifree_mark_inode_stale(
>   * inodes that are in memory - they all must be marked stale and attached to
>   * the cluster buffer.
>   */
> -STATIC int
> +static int
>  xfs_ifree_cluster(
> -	struct xfs_inode	*free_ip,
>  	struct xfs_trans	*tp,
> +	struct xfs_perag	*pag,
> +	struct xfs_inode	*free_ip,
>  	struct xfs_icluster	*xic)
>  {
>  	struct xfs_mount	*mp = free_ip->i_mount;
> @@ -2495,7 +2504,7 @@ xfs_ifree_cluster(
>  		 * already marked XFS_ISTALE.
>  		 */
>  		for (i = 0; i < igeo->inodes_per_cluster; i++)
> -			xfs_ifree_mark_inode_stale(bp, free_ip, inum + i);
> +			xfs_ifree_mark_inode_stale(pag, free_ip, inum + i);
>  
>  		xfs_trans_stale_inode_buf(tp, bp);
>  		xfs_trans_binval(tp, bp);
> @@ -2518,9 +2527,11 @@ xfs_ifree(
>  	struct xfs_trans	*tp,
>  	struct xfs_inode	*ip)
>  {
> -	int			error;
> +	struct xfs_mount	*mp = ip->i_mount;
> +	struct xfs_perag	*pag;
>  	struct xfs_icluster	xic = { 0 };
>  	struct xfs_inode_log_item *iip = ip->i_itemp;
> +	int			error;
>  
>  	ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
>  	ASSERT(VFS_I(ip)->i_nlink == 0);
> @@ -2528,16 +2539,18 @@ xfs_ifree(
>  	ASSERT(ip->i_disk_size == 0 || !S_ISREG(VFS_I(ip)->i_mode));
>  	ASSERT(ip->i_nblocks == 0);
>  
> +	pag = xfs_perag_get(mp, XFS_INO_TO_AGNO(mp, ip->i_ino));
> +
>  	/*
>  	 * Pull the on-disk inode from the AGI unlinked list.
>  	 */
> -	error = xfs_iunlink_remove(tp, ip);
> +	error = xfs_iunlink_remove(tp, pag, ip);
>  	if (error)
> -		return error;
> +		goto out;
>  
> -	error = xfs_difree(tp, ip->i_ino, &xic);
> +	error = xfs_difree(tp, pag, ip->i_ino, &xic);
>  	if (error)
> -		return error;
> +		goto out;
>  
>  	/*
>  	 * Free any local-format data sitting around before we reset the
> @@ -2552,7 +2565,7 @@ xfs_ifree(
>  
>  	VFS_I(ip)->i_mode = 0;		/* mark incore inode as free */
>  	ip->i_diflags = 0;
> -	ip->i_diflags2 = ip->i_mount->m_ino_geo.new_diflags2;
> +	ip->i_diflags2 = mp->m_ino_geo.new_diflags2;
>  	ip->i_forkoff = 0;		/* mark the attr fork not in use */
>  	ip->i_df.if_format = XFS_DINODE_FMT_EXTENTS;
>  	if (xfs_iflags_test(ip, XFS_IPRESERVE_DM_FIELDS))
> @@ -2571,8 +2584,9 @@ xfs_ifree(
>  	xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
>  
>  	if (xic.deleted)
> -		error = xfs_ifree_cluster(ip, tp, &xic);
> -
> +		error = xfs_ifree_cluster(tp, pag, ip, &xic);
> +out:
> +	xfs_perag_put(pag);
>  	return error;
>  }
>  
> @@ -3176,8 +3190,13 @@ xfs_rename(
>  	 * in future.
>  	 */
>  	if (wip) {
> +		struct xfs_perag	*pag;
> +
>  		ASSERT(VFS_I(wip)->i_nlink == 0);
> -		error = xfs_iunlink_remove(tp, wip);
> +
> +		pag = xfs_perag_get(mp, XFS_INO_TO_AGNO(mp, wip->i_ino));
> +		error = xfs_iunlink_remove(tp, pag, wip);
> +		xfs_perag_put(pag);
>  		if (error)
>  			goto out_trans_cancel;
>  
> -- 
> 2.31.1
> 

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 21/22] xfs: clean up and simplify xfs_dialloc()
  2021-05-06  7:20 ` [PATCH 21/22] xfs: clean up and simplify xfs_dialloc() Dave Chinner
@ 2021-05-12 21:49   ` Darrick J. Wong
  2021-05-18  1:46     ` Dave Chinner
  0 siblings, 1 reply; 87+ messages in thread
From: Darrick J. Wong @ 2021-05-12 21:49 UTC (permalink / raw)
  To: Dave Chinner; +Cc: linux-xfs

On Thu, May 06, 2021 at 05:20:53PM +1000, Dave Chinner wrote:
> From: Dave Chinner <dchinner@redhat.com>
> 
> Because it's a mess.
> 
> Signed-off-by: Dave Chinner <dchinner@redhat.com>
> ---
>  fs/xfs/libxfs/xfs_ialloc.c | 270 +++++++++++++++++++++----------------
>  1 file changed, 153 insertions(+), 117 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_ialloc.c b/fs/xfs/libxfs/xfs_ialloc.c
> index d749bb7c7a69..340bb95d7bc1 100644
> --- a/fs/xfs/libxfs/xfs_ialloc.c
> +++ b/fs/xfs/libxfs/xfs_ialloc.c
> @@ -604,9 +604,10 @@ xfs_inobt_insert_sprec(
>  }
>  
>  /*
> - * Allocate new inodes in the allocation group specified by agbp.
> - * Returns 0 if inodes were allocated in this AG; 1 if there was no space
> - * in this AG; or the usual negative error code.
> + * Allocate new inodes in the allocation group specified by agbp.  Returns 0 if
> + * inodes were allocated in this AG; -EAGAIN if there was no space in this AG so
> + * the caller knows it can try another AG, a hard -ENOSPC when over the maximum
> + * inode count threshold, or the usual negative error code for other errors.
>   */
>  STATIC int
>  xfs_ialloc_ag_alloc(
> @@ -792,7 +793,7 @@ xfs_ialloc_ag_alloc(
>  	}
>  
>  	if (args.fsbno == NULLFSBLOCK)
> -		return 1;
> +		return -EAGAIN;
>  
>  	ASSERT(args.len == args.minlen);
>  
> @@ -1568,14 +1569,17 @@ xfs_dialloc_roll(
>  	/* Re-attach the quota info that we detached from prev trx. */
>  	tp->t_dqinfo = dqinfo;
>  
> -	*tpp = tp;
> -	if (error)
> -		return error;
> +	/*
> +	 * Join the buffer even on commit error so that the buffer is released
> +	 * when the caller cancels the transaction and doesn't have to handle
> +	 * this error case specially.
> +	 */
>  	xfs_trans_bjoin(tp, agibp);
> -	return 0;
> +	*tpp = tp;
> +	return error;
>  }
>  
> -STATIC xfs_agnumber_t
> +static xfs_agnumber_t
>  xfs_ialloc_next_ag(
>  	xfs_mount_t	*mp)
>  {
> @@ -1590,16 +1594,136 @@ xfs_ialloc_next_ag(
>  	return agno;
>  }
>  
> +static bool
> +xfs_dialloc_good_ag(
> +	struct xfs_trans	*tp,
> +	struct xfs_perag	*pag,
> +	umode_t			mode,
> +	int			flags,
> +	bool			ok_alloc)
> +{
> +	struct xfs_mount	*mp = tp->t_mountp;
> +	xfs_extlen_t		ineed;
> +	xfs_extlen_t		longest = 0;
> +	int			needspace;
> +	int			error;
> +
> +	if (!pag->pagi_inodeok)
> +		return false;
> +
> +	if (!pag->pagi_init) {
> +		error = xfs_ialloc_pagi_init(mp, tp, pag->pag_agno);
> +		if (error)
> +			return false;
> +	}
> +
> +	if (pag->pagi_freecount)
> +		return true;
> +	if (!ok_alloc)
> +		return false;
> +
> +	if (!pag->pagf_init) {
> +		error = xfs_alloc_pagf_init(mp, tp, pag->pag_agno, flags);
> +		if (error)
> +			return false;
> +	}
> +
> +	/*
> +	 * Check that there is enough free space for the file plus a chunk of
> +	 * inodes if we need to allocate some. If this is the first pass across
> +	 * the AGs, take into account the potential space needed for alignment
> +	 * of inode chunks when checking the longest contiguous free space in
> +	 * the AG - this prevents us from getting ENOSPC because we have free
> +	 * space larger than ialloc_blks but alignment constraints prevent us
> +	 * from using it.
> +	 *
> +	 * If we can't find an AG with space for full alignment slack to be
> +	 * taken into account, we must be near ENOSPC in all AGs.  Hence we
> +	 * don't include alignment for the second pass and so if we fail
> +	 * allocation due to alignment issues then it is most likely a real
> +	 * ENOSPC condition.
> +	 *
> +	 * XXX(dgc): this calculation is now bogus thanks to the per-ag
> +	 * reservations that xfs_alloc_fix_freelist() now does via
> +	 * xfs_alloc_space_available(). When the AG fills up, pagf_freeblks will
> +	 * be more than large enough for the check below to succeed, but
> +	 * xfs_alloc_space_available() will fail because of the non-zero
> +	 * metadata reservation and hence we won't actually be able to allocate
> +	 * more inodes in this AG. We do soooo much unnecessary work near ENOSPC
> +	 * because of this.

Yuck.  Can this be fixed by doing:

	really_free = pag->pagf_freeblks -
				xfs_ag_resv_needed(pag, XFS_AG_RESV_NONE);
	return really_free >= needspace + ineed && longest >= ineed)

to account for those reservations, perhaps?

> +	 */
> +	ineed = M_IGEO(mp)->ialloc_min_blks;
> +	if (flags && ineed > 1)
> +		ineed += M_IGEO(mp)->cluster_align;
> +	longest = pag->pagf_longest;
> +	if (!longest)
> +		longest = pag->pagf_flcount > 0;
> +	needspace = S_ISDIR(mode) || S_ISREG(mode) || S_ISLNK(mode);
> +
> +	if (pag->pagf_freeblks < needspace + ineed || longest < ineed)
> +		return false;
> +	return true;
> +}
> +
> +static int
> +xfs_dialloc_try_ag(
> +	struct xfs_trans	**tpp,
> +	struct xfs_perag	*pag,
> +	xfs_ino_t		parent,
> +	xfs_ino_t		*new_ino,
> +	bool			ok_alloc)
> +{
> +	struct xfs_buf		*agbp;
> +	xfs_ino_t		ino;
> +	int			error;
> +
> +	/*
> +	 * Then read in the AGI buffer and recheck with the AGI buffer
> +	 * lock held.
> +	 */
> +	error = xfs_ialloc_read_agi(pag->pag_mount, *tpp, pag->pag_agno, &agbp);
> +	if (error)
> +		return error;
> +
> +	if (!pag->pagi_freecount) {
> +		if (!ok_alloc) {
> +			error = -EAGAIN;
> +			goto out_release;
> +		}
> +
> +		error = xfs_ialloc_ag_alloc(*tpp, agbp, pag);
> +		if (error < 0)
> +			goto out_release;
> +
> +		/*
> +		 * We successfully allocated space for an inode cluster in this
> +		 * AG.  Roll the transaction so that we can allocate one of the
> +		 * new inodes.
> +		 */
> +		ASSERT(pag->pagi_freecount > 0);
> +		error = xfs_dialloc_roll(tpp, agbp);
> +		if (error)
> +			goto out_release;
> +	}
> +
> +	/* Allocate an inode in the found AG */
> +	error = xfs_dialloc_ag(*tpp, agbp, pag, parent, &ino);
> +	if (!error)
> +		*new_ino = ino;
> +	return error;
> +
> +out_release:
> +	xfs_trans_brelse(*tpp, agbp);
> +	return error;
> +}
> +
>  /*
> - * Select and prepare an AG for inode allocation.
> + * Allocate an on-disk inode.
>   *
>   * Mode is used to tell whether the new inode is a directory and hence where to
> - * locate it.
> - *
> - * This function will ensure that the selected AG has free inodes available to
> - * allocate from. The selected AGI will be returned locked to the caller, and it
> - * will allocate more free inodes if required. If no free inodes are found or
> - * can be allocated, -ENOSPC be returned.
> + * locate it. The on-disk inode that is allocated will be returned in @new_ino
> + * on success, otherwise an error will be set to indicate the failure (e.g.
> + * -ENOSPC).
>   */
>  int
>  xfs_dialloc(
> @@ -1609,14 +1733,12 @@ xfs_dialloc(
>  	xfs_ino_t		*new_ino)
>  {
>  	struct xfs_mount	*mp = (*tpp)->t_mountp;
> -	struct xfs_buf		*agbp;
>  	xfs_agnumber_t		agno;
>  	int			error = 0;
>  	xfs_agnumber_t		start_agno;
>  	struct xfs_perag	*pag;
>  	struct xfs_ino_geometry	*igeo = M_IGEO(mp);
> -	bool			okalloc = true;
> -	int			needspace;
> +	bool			ok_alloc = true;
>  	int			flags;
>  	xfs_ino_t		ino;
>  
> @@ -1624,7 +1746,6 @@ xfs_dialloc(
>  	 * Files of these types need at least one block if length > 0
>  	 * (and they won't fit in the inode, but that's hard to figure out).
>  	 */
> -	needspace = S_ISDIR(mode) || S_ISREG(mode) || S_ISLNK(mode);
>  	if (S_ISDIR(mode))
>  		start_agno = xfs_ialloc_next_ag(mp);
>  	else {
> @@ -1635,7 +1756,7 @@ xfs_dialloc(
>  
>  	/*
>  	 * If we have already hit the ceiling of inode blocks then clear
> -	 * okalloc so we scan all available agi structures for a free
> +	 * ok_alloc so we scan all available agi structures for a free
>  	 * inode.
>  	 *
>  	 * Read rough value of mp->m_icount by percpu_counter_read_positive,
> @@ -1644,7 +1765,7 @@ xfs_dialloc(

Er... didn't this logic get split into xfs_dialloc_select_ag in 5.11?

Nice cleanup, at least...

--D

>  	if (igeo->maxicount &&
>  	    percpu_counter_read_positive(&mp->m_icount) + igeo->ialloc_inos
>  							> igeo->maxicount) {
> -		okalloc = false;
> +		ok_alloc = false;
>  	}
>  
>  	/*
> @@ -1655,95 +1776,14 @@ xfs_dialloc(
>  	agno = start_agno;
>  	flags = XFS_ALLOC_FLAG_TRYLOCK;
>  	for (;;) {
> -		xfs_extlen_t	ineed;
> -		xfs_extlen_t	longest = 0;
> -
>  		pag = xfs_perag_get(mp, agno);
> -		if (!pag->pagi_inodeok)
> -			goto nextag;
> -
> -		if (!pag->pagi_init) {
> -			error = xfs_ialloc_pagi_init(mp, *tpp, agno);
> -			if (error)
> -				break;
> -		}
> -
> -		if (!pag->pagi_freecount)
> -			goto nextag;
> -		if (!okalloc)
> -			goto nextag;
> -
> -		if (!pag->pagf_init) {
> -			error = xfs_alloc_pagf_init(mp, *tpp, agno, flags);
> -			if (error)
> -				goto nextag;
> -		}
> -
> -		/*
> -		 * Check that there is enough free space for the file plus a
> -		 * chunk of inodes if we need to allocate some. If this is the
> -		 * first pass across the AGs, take into account the potential
> -		 * space needed for alignment of inode chunks when checking the
> -		 * longest contiguous free space in the AG - this prevents us
> -		 * from getting ENOSPC because we have free space larger than
> -		 * ialloc_blks but alignment constraints prevent us from using
> -		 * it.
> -		 *
> -		 * If we can't find an AG with space for full alignment slack to
> -		 * be taken into account, we must be near ENOSPC in all AGs.
> -		 * Hence we don't include alignment for the second pass and so
> -		 * if we fail allocation due to alignment issues then it is most
> -		 * likely a real ENOSPC condition.
> -		 */
> -		ineed = M_IGEO(mp)->ialloc_min_blks;
> -		if (flags && ineed > 1)
> -			ineed += M_IGEO(mp)->cluster_align;
> -		longest = pag->pagf_longest;
> -		if (!longest)
> -			longest = pag->pagf_flcount > 0;
> -
> -		if (pag->pagf_freeblks < needspace + ineed || longest < ineed)
> -			goto nextag;
> -
> -		/*
> -		 * Then read in the AGI buffer and recheck with the AGI buffer
> -		 * lock held.
> -		 */
> -		error = xfs_ialloc_read_agi(mp, *tpp, agno, &agbp);
> -		if (error)
> -			break;
> -
> -		if (pag->pagi_freecount)
> -			goto found_ag;
> -
> -		if (!okalloc)
> -			goto nextag_relse_buffer;
> -
> -		error = xfs_ialloc_ag_alloc(*tpp, agbp, pag);
> -		if (error < 0) {
> -			xfs_trans_brelse(*tpp, agbp);
> -			break;
> -		}
> -
> -		if (error == 0) {
> -			/*
> -			 * We successfully allocated space for an inode cluster
> -			 * in this AG.  Roll the transaction so that we can
> -			 * allocate one of the new inodes.
> -			 */
> -			ASSERT(pag->pagi_freecount > 0);
> -
> -			error = xfs_dialloc_roll(tpp, agbp);
> -			if (error) {
> -				xfs_buf_relse(agbp);
> +		if (xfs_dialloc_good_ag(*tpp, pag, mode, flags, ok_alloc)) {
> +			error = xfs_dialloc_try_ag(tpp, pag, parent,
> +					&ino, ok_alloc);
> +			if (error != -EAGAIN)
>  				break;
> -			}
> -			goto found_ag;
>  		}
>  
> -nextag_relse_buffer:
> -		xfs_trans_brelse(*tpp, agbp);
> -nextag:
>  		if (XFS_FORCED_SHUTDOWN(mp)) {
>  			error = -EFSCORRUPTED;
>  			break;
> @@ -1751,23 +1791,19 @@ xfs_dialloc(
>  		if (++agno == mp->m_maxagi)
>  			agno = 0;
>  		if (agno == start_agno) {
> -			if (!flags)
> +			if (!flags) {
> +				error = -ENOSPC;
>  				break;
> +			}
>  			flags = 0;
>  		}
>  		xfs_perag_put(pag);
>  	}
>  
> +	if (!error)
> +		*new_ino = ino;
>  	xfs_perag_put(pag);
> -	return error ? error : -ENOSPC;
> -found_ag:
> -	/* Allocate an inode in the found AG */
> -	error = xfs_dialloc_ag(*tpp, agbp, pag, parent, &ino);
> -	xfs_perag_put(pag);
> -	if (error)
> -		return error;
> -	*new_ino = ino;
> -	return 0;
> +	return error;
>  }
>  
>  /*
> -- 
> 2.31.1
> 

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 04/22] xfs: make for_each_perag... a first class citizen
  2021-05-11 21:33         ` Dave Chinner
@ 2021-05-12 21:58           ` Darrick J. Wong
  0 siblings, 0 replies; 87+ messages in thread
From: Darrick J. Wong @ 2021-05-12 21:58 UTC (permalink / raw)
  To: Dave Chinner; +Cc: Brian Foster, linux-xfs

On Wed, May 12, 2021 at 07:33:12AM +1000, Dave Chinner wrote:
> On Tue, May 11, 2021 at 08:29:38AM -0400, Brian Foster wrote:
> > On Tue, May 11, 2021 at 05:35:19PM +1000, Dave Chinner wrote:
> > > On Mon, May 10, 2021 at 08:53:56AM -0400, Brian Foster wrote:
> > > > On Thu, May 06, 2021 at 05:20:36PM +1000, Dave Chinner wrote:
> > > > > From: Dave Chinner <dchinner@redhat.com>
> > > > > 
> > > > > for_each_perag_tag() is defined in xfs_icache.c for local use.
> > > > > Promote this to xfs_ag.h and define equivalent iteration functions
> > > > > so that we can use them to iterate AGs instead to replace open coded
> > > > > perag walks and perag lookups.
> > > > > 
> > > > > We also convert as many of the straight forward open coded AG walks
> > > > > to use these iterators as possible. Anything that is not a direct
> > > > > conversion to an iterator is ignored and will be updated in future
> > > > > commits.
> > > > > 
> > > > > Signed-off-by: Dave Chinner <dchinner@redhat.com>
> > > > > ---
> > > > >  fs/xfs/libxfs/xfs_ag.h    | 17 +++++++++++++++++
> > > > >  fs/xfs/scrub/fscounters.c | 36 ++++++++++++++----------------------
> > > > >  fs/xfs/xfs_extent_busy.c  |  7 ++-----
> > > > >  fs/xfs/xfs_fsops.c        |  8 ++------
> > > > >  fs/xfs/xfs_health.c       |  4 +---
> > > > >  fs/xfs/xfs_icache.c       | 15 ++-------------
> > > > >  6 files changed, 38 insertions(+), 49 deletions(-)
> > > > > 
> > > > ...
> > > > > diff --git a/fs/xfs/scrub/fscounters.c b/fs/xfs/scrub/fscounters.c
> > > > > index 453ae9adf94c..2dfdac566399 100644
> > > > > --- a/fs/xfs/scrub/fscounters.c
> > > > > +++ b/fs/xfs/scrub/fscounters.c
> > > > ...
> > > > > @@ -229,12 +224,9 @@ xchk_fscount_aggregate_agcounts(
> > > > >  		fsc->fdblocks -= pag->pag_meta_resv.ar_reserved;
> > > > >  		fsc->fdblocks -= pag->pag_rmapbt_resv.ar_orig_reserved;
> > > > >  
> > > > > -		xfs_perag_put(pag);
> > > > > -
> > > > > -		if (xchk_should_terminate(sc, &error))
> > > > > -			break;
> > > > >  	}
> > > > > -
> > > > > +	if (pag)
> > > > > +		xfs_perag_put(pag);
> > > > 
> > > > It's not shown in the diff, but there is still an exit path out of the
> > > > above loop that calls xfs_perag_put(). The rest of the patch LGTM.
> > > 
> > > Good spot. Fixed.
> > > 
> > > FWIW, I'm not entirely happy with the way the iterator can break and
> > > require conditional cleanup. I'm thinking that I'll come back to
> > > these and convert them to a iterator structure that will turn this
> > > into the pattern:
> > > 
> > > 	perag_iter_init(&iter, start_agno, end_agno);
> > > 	for_each_perag(pag, iter) {
> > > 		....
> > > 	}
> > > 	perag_iter_done(&iter);
> > > 
> > > and so the code doesn't need to care about whether it exits the loop
> > > via a break or running out of perags to iterate. I haven't fully
> > > thought this through, though, so I'm leaving it alone for now...
> > > 
> > 
> > I think something like that would be an improvement. It's
> > straightforward enough to follow through these changes with the loop
> > break quirk in mind, but I suspect that somebody modifying (and/or
> > reviewing) related code farther in the future might very easily miss
> > something like an external put being required if a loop is modified to
> > break out early.
> 
> *nod*
> 
> I think I'll need to address this when I do the conversion of these
> iterators to use active references to pin or skip perags that are
> being torn down. The iterators becomes slightly more complex at this
> point, so that's probably the best point to address this.

This sounds like a good change to me. :)

--D

> Cheers,
> 
> Dave.
> -- 
> Dave Chinner
> david@fromorbit.com

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 06/22] xfs: convert xfs_iwalk to use perag references
  2021-05-06  7:20 ` [PATCH 06/22] xfs: convert xfs_iwalk to use perag references Dave Chinner
  2021-05-10 13:41   ` Brian Foster
@ 2021-05-12 22:08   ` Darrick J. Wong
  1 sibling, 0 replies; 87+ messages in thread
From: Darrick J. Wong @ 2021-05-12 22:08 UTC (permalink / raw)
  To: Dave Chinner; +Cc: linux-xfs

On Thu, May 06, 2021 at 05:20:38PM +1000, Dave Chinner wrote:
> From: Dave Chinner <dchinner@redhat.com>
> 
> Rather than manually walking the ags and passing agnunbers around,
> pass the perag for the AG we are currently working on around in the
> iwalk structure.
> 
> Signed-off-by: Dave Chinner <dchinner@redhat.com>
> ---
>  fs/xfs/libxfs/xfs_ag.h |  8 +++-
>  fs/xfs/xfs_iwalk.c     | 86 ++++++++++++++++++++++++++----------------
>  2 files changed, 60 insertions(+), 34 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_ag.h b/fs/xfs/libxfs/xfs_ag.h
> index 33783120263c..3fa88222dacd 100644
> --- a/fs/xfs/libxfs/xfs_ag.h
> +++ b/fs/xfs/libxfs/xfs_ag.h
> @@ -117,13 +117,17 @@ void	xfs_perag_put(struct xfs_perag *pag);
>  /*
>   * Perag iteration APIs
>   */
> -#define for_each_perag(mp, next_agno, pag) \
> -	for ((next_agno) = 0, (pag) = xfs_perag_get((mp), 0); \
> +#define for_each_perag_from(mp, next_agno, pag) \

Maybe just put these in patch 4, even if the ranged iteration doesn't
get used for a patch or two?

> +	for ((pag) = xfs_perag_get((mp), (next_agno)); \
>  		(pag) != NULL; \
>  		(next_agno) = (pag)->pag_agno + 1, \
>  		xfs_perag_put(pag), \
>  		(pag) = xfs_perag_get((mp), (next_agno)))
>  
> +#define for_each_perag(mp, next_agno, pag) \

On the off chance this macro survives into the next revision of the
patch set, the "next_agno" parameters should just be "agno" because
otherwise it sounds like I'm supposed to initialize next_agno to the
next (or first) AG that I want.

Iterator format issues aside, the rest of the conversion looks good to
me.  I'll wait to see the next version before RVBing though.

--D

> +	(next_agno) = 0; \
> +	for_each_perag_from((mp), (next_agno), (pag))
> +
>  #define for_each_perag_tag(mp, next_agno, pag, tag) \
>  	for ((next_agno) = 0, (pag) = xfs_perag_get_tag((mp), 0, (tag)); \
>  		(pag) != NULL; \
> diff --git a/fs/xfs/xfs_iwalk.c b/fs/xfs/xfs_iwalk.c
> index c4a340f1f1e1..c7e8f48a3ec4 100644
> --- a/fs/xfs/xfs_iwalk.c
> +++ b/fs/xfs/xfs_iwalk.c
> @@ -21,6 +21,7 @@
>  #include "xfs_health.h"
>  #include "xfs_trans.h"
>  #include "xfs_pwork.h"
> +#include "xfs_ag.h"
>  
>  /*
>   * Walking Inodes in the Filesystem
> @@ -51,6 +52,7 @@ struct xfs_iwalk_ag {
>  
>  	struct xfs_mount		*mp;
>  	struct xfs_trans		*tp;
> +	struct xfs_perag		*pag;
>  
>  	/* Where do we start the traversal? */
>  	xfs_ino_t			startino;
> @@ -90,7 +92,7 @@ struct xfs_iwalk_ag {
>  STATIC void
>  xfs_iwalk_ichunk_ra(
>  	struct xfs_mount		*mp,
> -	xfs_agnumber_t			agno,
> +	struct xfs_perag		*pag,
>  	struct xfs_inobt_rec_incore	*irec)
>  {
>  	struct xfs_ino_geometry		*igeo = M_IGEO(mp);
> @@ -106,7 +108,7 @@ xfs_iwalk_ichunk_ra(
>  
>  		imask = xfs_inobt_maskn(i, igeo->inodes_per_cluster);
>  		if (imask & ~irec->ir_free) {
> -			xfs_btree_reada_bufs(mp, agno, agbno,
> +			xfs_btree_reada_bufs(mp, pag->pag_agno, agbno,
>  					igeo->blocks_per_cluster,
>  					&xfs_inode_buf_ops);
>  		}
> @@ -174,26 +176,25 @@ xfs_iwalk_free(
>  /* For each inuse inode in each cached inobt record, call our function. */
>  STATIC int
>  xfs_iwalk_ag_recs(
> -	struct xfs_iwalk_ag		*iwag)
> +	struct xfs_iwalk_ag	*iwag)
>  {
> -	struct xfs_mount		*mp = iwag->mp;
> -	struct xfs_trans		*tp = iwag->tp;
> -	xfs_ino_t			ino;
> -	unsigned int			i, j;
> -	xfs_agnumber_t			agno;
> -	int				error;
> +	struct xfs_mount	*mp = iwag->mp;
> +	struct xfs_trans	*tp = iwag->tp;
> +	struct xfs_perag	*pag = iwag->pag;
> +	xfs_ino_t		ino;
> +	unsigned int		i, j;
> +	int			error;
>  
> -	agno = XFS_INO_TO_AGNO(mp, iwag->startino);
>  	for (i = 0; i < iwag->nr_recs; i++) {
>  		struct xfs_inobt_rec_incore	*irec = &iwag->recs[i];
>  
> -		trace_xfs_iwalk_ag_rec(mp, agno, irec);
> +		trace_xfs_iwalk_ag_rec(mp, pag->pag_agno, irec);
>  
>  		if (xfs_pwork_want_abort(&iwag->pwork))
>  			return 0;
>  
>  		if (iwag->inobt_walk_fn) {
> -			error = iwag->inobt_walk_fn(mp, tp, agno, irec,
> +			error = iwag->inobt_walk_fn(mp, tp, pag->pag_agno, irec,
>  					iwag->data);
>  			if (error)
>  				return error;
> @@ -211,7 +212,8 @@ xfs_iwalk_ag_recs(
>  				continue;
>  
>  			/* Otherwise call our function. */
> -			ino = XFS_AGINO_TO_INO(mp, agno, irec->ir_startino + j);
> +			ino = XFS_AGINO_TO_INO(mp, pag->pag_agno,
> +						irec->ir_startino + j);
>  			error = iwag->iwalk_fn(mp, tp, ino, iwag->data);
>  			if (error)
>  				return error;
> @@ -257,7 +259,6 @@ xfs_iwalk_del_inobt(
>  STATIC int
>  xfs_iwalk_ag_start(
>  	struct xfs_iwalk_ag	*iwag,
> -	xfs_agnumber_t		agno,
>  	xfs_agino_t		agino,
>  	struct xfs_btree_cur	**curpp,
>  	struct xfs_buf		**agi_bpp,
> @@ -265,12 +266,14 @@ xfs_iwalk_ag_start(
>  {
>  	struct xfs_mount	*mp = iwag->mp;
>  	struct xfs_trans	*tp = iwag->tp;
> +	struct xfs_perag	*pag = iwag->pag;
>  	struct xfs_inobt_rec_incore *irec;
>  	int			error;
>  
>  	/* Set up a fresh cursor and empty the inobt cache. */
>  	iwag->nr_recs = 0;
> -	error = xfs_inobt_cur(mp, tp, agno, XFS_BTNUM_INO, curpp, agi_bpp);
> +	error = xfs_inobt_cur(mp, tp, pag->pag_agno, XFS_BTNUM_INO,
> +				curpp, agi_bpp);
>  	if (error)
>  		return error;
>  
> @@ -304,7 +307,7 @@ xfs_iwalk_ag_start(
>  	if (XFS_IS_CORRUPT(mp, *has_more != 1))
>  		return -EFSCORRUPTED;
>  
> -	iwag->lastino = XFS_AGINO_TO_INO(mp, agno,
> +	iwag->lastino = XFS_AGINO_TO_INO(mp, pag->pag_agno,
>  				irec->ir_startino + XFS_INODES_PER_CHUNK - 1);
>  
>  	/*
> @@ -345,7 +348,6 @@ xfs_iwalk_ag_start(
>  STATIC int
>  xfs_iwalk_run_callbacks(
>  	struct xfs_iwalk_ag		*iwag,
> -	xfs_agnumber_t			agno,
>  	struct xfs_btree_cur		**curpp,
>  	struct xfs_buf			**agi_bpp,
>  	int				*has_more)
> @@ -376,7 +378,8 @@ xfs_iwalk_run_callbacks(
>  		return 0;
>  
>  	/* ...and recreate the cursor just past where we left off. */
> -	error = xfs_inobt_cur(mp, tp, agno, XFS_BTNUM_INO, curpp, agi_bpp);
> +	error = xfs_inobt_cur(mp, tp, iwag->pag->pag_agno, XFS_BTNUM_INO,
> +				curpp, agi_bpp);
>  	if (error)
>  		return error;
>  
> @@ -390,17 +393,17 @@ xfs_iwalk_ag(
>  {
>  	struct xfs_mount		*mp = iwag->mp;
>  	struct xfs_trans		*tp = iwag->tp;
> +	struct xfs_perag		*pag = iwag->pag;
>  	struct xfs_buf			*agi_bp = NULL;
>  	struct xfs_btree_cur		*cur = NULL;
> -	xfs_agnumber_t			agno;
>  	xfs_agino_t			agino;
>  	int				has_more;
>  	int				error = 0;
>  
>  	/* Set up our cursor at the right place in the inode btree. */
> -	agno = XFS_INO_TO_AGNO(mp, iwag->startino);
> +	ASSERT(pag->pag_agno == XFS_INO_TO_AGNO(mp, iwag->startino));
>  	agino = XFS_INO_TO_AGINO(mp, iwag->startino);
> -	error = xfs_iwalk_ag_start(iwag, agno, agino, &cur, &agi_bp, &has_more);
> +	error = xfs_iwalk_ag_start(iwag, agino, &cur, &agi_bp, &has_more);
>  
>  	while (!error && has_more) {
>  		struct xfs_inobt_rec_incore	*irec;
> @@ -417,7 +420,7 @@ xfs_iwalk_ag(
>  			break;
>  
>  		/* Make sure that we always move forward. */
> -		rec_fsino = XFS_AGINO_TO_INO(mp, agno, irec->ir_startino);
> +		rec_fsino = XFS_AGINO_TO_INO(mp, pag->pag_agno, irec->ir_startino);
>  		if (iwag->lastino != NULLFSINO &&
>  		    XFS_IS_CORRUPT(mp, iwag->lastino >= rec_fsino)) {
>  			error = -EFSCORRUPTED;
> @@ -438,7 +441,7 @@ xfs_iwalk_ag(
>  		 * walking the inodes.
>  		 */
>  		if (iwag->iwalk_fn)
> -			xfs_iwalk_ichunk_ra(mp, agno, irec);
> +			xfs_iwalk_ichunk_ra(mp, pag, irec);
>  
>  		/*
>  		 * If there's space in the buffer for more records, increment
> @@ -458,15 +461,14 @@ xfs_iwalk_ag(
>  		 * we would be if we had been able to increment like above.
>  		 */
>  		ASSERT(has_more);
> -		error = xfs_iwalk_run_callbacks(iwag, agno, &cur, &agi_bp,
> -				&has_more);
> +		error = xfs_iwalk_run_callbacks(iwag, &cur, &agi_bp, &has_more);
>  	}
>  
>  	if (iwag->nr_recs == 0 || error)
>  		goto out;
>  
>  	/* Walk the unprocessed records in the cache. */
> -	error = xfs_iwalk_run_callbacks(iwag, agno, &cur, &agi_bp, &has_more);
> +	error = xfs_iwalk_run_callbacks(iwag, &cur, &agi_bp, &has_more);
>  
>  out:
>  	xfs_iwalk_del_inobt(tp, &cur, &agi_bp, error);
> @@ -555,6 +557,7 @@ xfs_iwalk(
>  		.pwork		= XFS_PWORK_SINGLE_THREADED,
>  		.lastino	= NULLFSINO,
>  	};
> +	struct xfs_perag	*pag;
>  	xfs_agnumber_t		agno = XFS_INO_TO_AGNO(mp, startino);
>  	int			error;
>  
> @@ -565,15 +568,19 @@ xfs_iwalk(
>  	if (error)
>  		return error;
>  
> -	for (; agno < mp->m_sb.sb_agcount; agno++) {
> +	for_each_perag_from(mp, agno, pag) {
> +		iwag.pag = pag;
>  		error = xfs_iwalk_ag(&iwag);
>  		if (error)
>  			break;
>  		iwag.startino = XFS_AGINO_TO_INO(mp, agno + 1, 0);
>  		if (flags & XFS_INOBT_WALK_SAME_AG)
>  			break;
> +		iwag.pag = NULL;
>  	}
>  
> +	if (iwag.pag)
> +		xfs_perag_put(pag);
>  	xfs_iwalk_free(&iwag);
>  	return error;
>  }
> @@ -598,6 +605,7 @@ xfs_iwalk_ag_work(
>  	error = xfs_iwalk_ag(iwag);
>  	xfs_iwalk_free(iwag);
>  out:
> +	xfs_perag_put(iwag->pag);
>  	kmem_free(iwag);
>  	return error;
>  }
> @@ -617,6 +625,7 @@ xfs_iwalk_threaded(
>  	void			*data)
>  {
>  	struct xfs_pwork_ctl	pctl;
> +	struct xfs_perag	*pag;
>  	xfs_agnumber_t		agno = XFS_INO_TO_AGNO(mp, startino);
>  	int			error;
>  
> @@ -627,7 +636,7 @@ xfs_iwalk_threaded(
>  	if (error)
>  		return error;
>  
> -	for (; agno < mp->m_sb.sb_agcount; agno++) {
> +	for_each_perag_from(mp, agno, pag) {
>  		struct xfs_iwalk_ag	*iwag;
>  
>  		if (xfs_pwork_ctl_want_abort(&pctl))
> @@ -635,17 +644,25 @@ xfs_iwalk_threaded(
>  
>  		iwag = kmem_zalloc(sizeof(struct xfs_iwalk_ag), 0);
>  		iwag->mp = mp;
> +
> +		/*
> +		 * perag is being handed off to async work, so take another
> +		 * reference for the async work to release.
> +		 */
> +		atomic_inc(&pag->pag_ref);
> +		iwag->pag = pag;
>  		iwag->iwalk_fn = iwalk_fn;
>  		iwag->data = data;
>  		iwag->startino = startino;
>  		iwag->sz_recs = xfs_iwalk_prefetch(inode_records);
>  		iwag->lastino = NULLFSINO;
>  		xfs_pwork_queue(&pctl, &iwag->pwork);
> -		startino = XFS_AGINO_TO_INO(mp, agno + 1, 0);
> +		startino = XFS_AGINO_TO_INO(mp, pag->pag_agno + 1, 0);
>  		if (flags & XFS_INOBT_WALK_SAME_AG)
>  			break;
>  	}
> -
> +	if (pag)
> +		xfs_perag_put(pag);
>  	if (polled)
>  		xfs_pwork_poll(&pctl);
>  	return xfs_pwork_destroy(&pctl);
> @@ -715,6 +732,7 @@ xfs_inobt_walk(
>  		.pwork		= XFS_PWORK_SINGLE_THREADED,
>  		.lastino	= NULLFSINO,
>  	};
> +	struct xfs_perag	*pag;
>  	xfs_agnumber_t		agno = XFS_INO_TO_AGNO(mp, startino);
>  	int			error;
>  
> @@ -725,15 +743,19 @@ xfs_inobt_walk(
>  	if (error)
>  		return error;
>  
> -	for (; agno < mp->m_sb.sb_agcount; agno++) {
> +	for_each_perag_from(mp, agno, pag) {
> +		iwag.pag = pag;
>  		error = xfs_iwalk_ag(&iwag);
>  		if (error)
>  			break;
> -		iwag.startino = XFS_AGINO_TO_INO(mp, agno + 1, 0);
> +		iwag.startino = XFS_AGINO_TO_INO(mp, pag->pag_agno + 1, 0);
>  		if (flags & XFS_INOBT_WALK_SAME_AG)
>  			break;
> +		iwag.pag = NULL;
>  	}
>  
> +	if (iwag.pag)
> +		xfs_perag_put(pag);
>  	xfs_iwalk_free(&iwag);
>  	return error;
>  }
> -- 
> 2.31.1
> 

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 07/22] xfs: convert secondary superblock walk to use perags
  2021-05-06  7:20 ` [PATCH 07/22] xfs: convert secondary superblock walk to use perags Dave Chinner
  2021-05-10 13:41   ` Brian Foster
@ 2021-05-12 22:09   ` Darrick J. Wong
  1 sibling, 0 replies; 87+ messages in thread
From: Darrick J. Wong @ 2021-05-12 22:09 UTC (permalink / raw)
  To: Dave Chinner; +Cc: linux-xfs

On Thu, May 06, 2021 at 05:20:39PM +1000, Dave Chinner wrote:
> From: Dave Chinner <dchinner@redhat.com>
> 
> Clean up the last external manual AG walk.
> 
> Signed-off-by: Dave Chinner <dchinner@redhat.com>

Simple enough conversion I don't mind RVBing before we settle the exact
iterator idioms...

Reviewed-by: Darrick J. Wong <djwong@kernel.org>

--D

> ---
>  fs/xfs/libxfs/xfs_sb.c | 12 +++++++-----
>  1 file changed, 7 insertions(+), 5 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_sb.c b/fs/xfs/libxfs/xfs_sb.c
> index cbcfce8cebf1..7d4c238540d4 100644
> --- a/fs/xfs/libxfs/xfs_sb.c
> +++ b/fs/xfs/libxfs/xfs_sb.c
> @@ -25,6 +25,7 @@
>  #include "xfs_refcount_btree.h"
>  #include "xfs_da_format.h"
>  #include "xfs_health.h"
> +#include "xfs_ag.h"
>  
>  /*
>   * Physical superblock buffer manipulations. Shared with libxfs in userspace.
> @@ -856,17 +857,18 @@ int
>  xfs_update_secondary_sbs(
>  	struct xfs_mount	*mp)
>  {
> -	xfs_agnumber_t		agno;
> +	struct xfs_perag	*pag;
> +	xfs_agnumber_t		agno = 1;
>  	int			saved_error = 0;
>  	int			error = 0;
>  	LIST_HEAD		(buffer_list);
>  
>  	/* update secondary superblocks. */
> -	for (agno = 1; agno < mp->m_sb.sb_agcount; agno++) {
> +	for_each_perag_from(mp, agno, pag) {
>  		struct xfs_buf		*bp;
>  
>  		error = xfs_buf_get(mp->m_ddev_targp,
> -				 XFS_AG_DADDR(mp, agno, XFS_SB_DADDR),
> +				 XFS_AG_DADDR(mp, pag->pag_agno, XFS_SB_DADDR),
>  				 XFS_FSS_TO_BB(mp, 1), &bp);
>  		/*
>  		 * If we get an error reading or writing alternate superblocks,
> @@ -878,7 +880,7 @@ xfs_update_secondary_sbs(
>  		if (error) {
>  			xfs_warn(mp,
>  		"error allocating secondary superblock for ag %d",
> -				agno);
> +				pag->pag_agno);
>  			if (!saved_error)
>  				saved_error = error;
>  			continue;
> @@ -899,7 +901,7 @@ xfs_update_secondary_sbs(
>  		if (error) {
>  			xfs_warn(mp,
>  		"write error %d updating a secondary superblock near ag %d",
> -				error, agno);
> +				error, pag->pag_agno);
>  			if (!saved_error)
>  				saved_error = error;
>  			continue;
> -- 
> 2.31.1
> 

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 08/22] xfs: pass perags through to the busy extent code
  2021-05-06  7:20 ` [PATCH 08/22] xfs: pass perags through to the busy extent code Dave Chinner
  2021-05-11 12:29   ` Brian Foster
@ 2021-05-12 22:13   ` Darrick J. Wong
  1 sibling, 0 replies; 87+ messages in thread
From: Darrick J. Wong @ 2021-05-12 22:13 UTC (permalink / raw)
  To: Dave Chinner; +Cc: linux-xfs

On Thu, May 06, 2021 at 05:20:40PM +1000, Dave Chinner wrote:
> From: Dave Chinner <dchinner@redhat.com>
> 
> All of the callers of the busy extent API either have perag
> references available to use so we can pass a perag to the busy
> extent functions rather than having them have to do unnecessary
> lookups.
> 
> Signed-off-by: Dave Chinner <dchinner@redhat.com>

I began to wonder during this patch if the cur->bc_ag ought to hold a
reference to the perag struct instead of the agno, but I guess that
makes little difference since we still have to attach the AG header
buffer to the cursor.

Just thought I'd mention that in case anyone else was thinking along the
same lines, but I don't expect to see such a ch{ange,urn} in this
series, so:

Reviewed-by: Darrick J. Wong <djwong@kernel.org>

--D

> ---
>  fs/xfs/libxfs/xfs_alloc.c       | 37 +++++++++++++++++----------------
>  fs/xfs/libxfs/xfs_alloc.h       |  2 +-
>  fs/xfs/libxfs/xfs_alloc_btree.c |  5 ++---
>  fs/xfs/libxfs/xfs_rmap.c        | 32 ++++++++++++++++------------
>  fs/xfs/libxfs/xfs_rmap_btree.c  |  7 +++----
>  fs/xfs/scrub/repair.c           |  4 ++--
>  fs/xfs/xfs_discard.c            |  2 +-
>  fs/xfs/xfs_extent_busy.c        | 24 ++++++---------------
>  fs/xfs/xfs_extent_busy.h        |  7 ++++---
>  9 files changed, 57 insertions(+), 63 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_alloc.c b/fs/xfs/libxfs/xfs_alloc.c
> index dc2b77829915..ce31c00dbf6f 100644
> --- a/fs/xfs/libxfs/xfs_alloc.c
> +++ b/fs/xfs/libxfs/xfs_alloc.c
> @@ -1063,7 +1063,7 @@ xfs_alloc_ag_vextent_small(
>  	if (fbno == NULLAGBLOCK)
>  		goto out;
>  
> -	xfs_extent_busy_reuse(args->mp, args->agno, fbno, 1,
> +	xfs_extent_busy_reuse(args->mp, args->pag, fbno, 1,
>  			      (args->datatype & XFS_ALLOC_NOBUSY));
>  
>  	if (args->datatype & XFS_ALLOC_USERDATA) {
> @@ -1178,7 +1178,7 @@ xfs_alloc_ag_vextent(
>  		if (error)
>  			return error;
>  
> -		ASSERT(!xfs_extent_busy_search(args->mp, args->agno,
> +		ASSERT(!xfs_extent_busy_search(args->mp, args->pag,
>  					      args->agbno, args->len));
>  	}
>  
> @@ -3292,7 +3292,7 @@ xfs_alloc_vextent(
>  int
>  xfs_free_extent_fix_freelist(
>  	struct xfs_trans	*tp,
> -	xfs_agnumber_t		agno,
> +	struct xfs_perag	*pag,
>  	struct xfs_buf		**agbp)
>  {
>  	struct xfs_alloc_arg	args;
> @@ -3301,7 +3301,8 @@ xfs_free_extent_fix_freelist(
>  	memset(&args, 0, sizeof(struct xfs_alloc_arg));
>  	args.tp = tp;
>  	args.mp = tp->t_mountp;
> -	args.agno = agno;
> +	args.agno = pag->pag_agno;
> +	args.pag = pag;
>  
>  	/*
>  	 * validate that the block number is legal - the enables us to detect
> @@ -3310,17 +3311,12 @@ xfs_free_extent_fix_freelist(
>  	if (args.agno >= args.mp->m_sb.sb_agcount)
>  		return -EFSCORRUPTED;
>  
> -	args.pag = xfs_perag_get(args.mp, args.agno);
> -	ASSERT(args.pag);
> -
>  	error = xfs_alloc_fix_freelist(&args, XFS_ALLOC_FLAG_FREEING);
>  	if (error)
> -		goto out;
> +		return error;
>  
>  	*agbp = args.agbp;
> -out:
> -	xfs_perag_put(args.pag);
> -	return error;
> +	return 0;
>  }
>  
>  /*
> @@ -3344,6 +3340,7 @@ __xfs_free_extent(
>  	struct xfs_agf			*agf;
>  	int				error;
>  	unsigned int			busy_flags = 0;
> +	struct xfs_perag		*pag;
>  
>  	ASSERT(len != 0);
>  	ASSERT(type != XFS_AG_RESV_AGFL);
> @@ -3352,33 +3349,37 @@ __xfs_free_extent(
>  			XFS_ERRTAG_FREE_EXTENT))
>  		return -EIO;
>  
> -	error = xfs_free_extent_fix_freelist(tp, agno, &agbp);
> +	pag = xfs_perag_get(mp, agno);
> +	error = xfs_free_extent_fix_freelist(tp, pag, &agbp);
>  	if (error)
> -		return error;
> +		goto err;
>  	agf = agbp->b_addr;
>  
>  	if (XFS_IS_CORRUPT(mp, agbno >= mp->m_sb.sb_agblocks)) {
>  		error = -EFSCORRUPTED;
> -		goto err;
> +		goto err_release;
>  	}
>  
>  	/* validate the extent size is legal now we have the agf locked */
>  	if (XFS_IS_CORRUPT(mp, agbno + len > be32_to_cpu(agf->agf_length))) {
>  		error = -EFSCORRUPTED;
> -		goto err;
> +		goto err_release;
>  	}
>  
>  	error = xfs_free_ag_extent(tp, agbp, agno, agbno, len, oinfo, type);
>  	if (error)
> -		goto err;
> +		goto err_release;
>  
>  	if (skip_discard)
>  		busy_flags |= XFS_EXTENT_BUSY_SKIP_DISCARD;
> -	xfs_extent_busy_insert(tp, agno, agbno, len, busy_flags);
> +	xfs_extent_busy_insert(tp, pag, agbno, len, busy_flags);
> +	xfs_perag_put(pag);
>  	return 0;
>  
> -err:
> +err_release:
>  	xfs_trans_brelse(tp, agbp);
> +err:
> +	xfs_perag_put(pag);
>  	return error;
>  }
>  
> diff --git a/fs/xfs/libxfs/xfs_alloc.h b/fs/xfs/libxfs/xfs_alloc.h
> index a4427c5775c2..e30900b6f8ba 100644
> --- a/fs/xfs/libxfs/xfs_alloc.h
> +++ b/fs/xfs/libxfs/xfs_alloc.h
> @@ -214,7 +214,7 @@ int xfs_alloc_read_agfl(struct xfs_mount *mp, struct xfs_trans *tp,
>  int xfs_free_agfl_block(struct xfs_trans *, xfs_agnumber_t, xfs_agblock_t,
>  			struct xfs_buf *, struct xfs_owner_info *);
>  int xfs_alloc_fix_freelist(struct xfs_alloc_arg *args, int flags);
> -int xfs_free_extent_fix_freelist(struct xfs_trans *tp, xfs_agnumber_t agno,
> +int xfs_free_extent_fix_freelist(struct xfs_trans *tp, struct xfs_perag *pag,
>  		struct xfs_buf **agbp);
>  
>  xfs_extlen_t xfs_prealloc_blocks(struct xfs_mount *mp);
> diff --git a/fs/xfs/libxfs/xfs_alloc_btree.c b/fs/xfs/libxfs/xfs_alloc_btree.c
> index a540b6e799e0..19fdf87e86b9 100644
> --- a/fs/xfs/libxfs/xfs_alloc_btree.c
> +++ b/fs/xfs/libxfs/xfs_alloc_btree.c
> @@ -72,7 +72,7 @@ xfs_allocbt_alloc_block(
>  	}
>  
>  	atomic64_inc(&cur->bc_mp->m_allocbt_blks);
> -	xfs_extent_busy_reuse(cur->bc_mp, cur->bc_ag.agno, bno, 1, false);
> +	xfs_extent_busy_reuse(cur->bc_mp, cur->bc_ag.agbp->b_pag, bno, 1, false);
>  
>  	new->s = cpu_to_be32(bno);
>  
> @@ -86,7 +86,6 @@ xfs_allocbt_free_block(
>  	struct xfs_buf		*bp)
>  {
>  	struct xfs_buf		*agbp = cur->bc_ag.agbp;
> -	struct xfs_agf		*agf = agbp->b_addr;
>  	xfs_agblock_t		bno;
>  	int			error;
>  
> @@ -96,7 +95,7 @@ xfs_allocbt_free_block(
>  		return error;
>  
>  	atomic64_dec(&cur->bc_mp->m_allocbt_blks);
> -	xfs_extent_busy_insert(cur->bc_tp, be32_to_cpu(agf->agf_seqno), bno, 1,
> +	xfs_extent_busy_insert(cur->bc_tp, agbp->b_pag, bno, 1,
>  			      XFS_EXTENT_BUSY_SKIP_DISCARD);
>  	return 0;
>  }
> diff --git a/fs/xfs/libxfs/xfs_rmap.c b/fs/xfs/libxfs/xfs_rmap.c
> index 61e8f10436ac..1d0a6b686eea 100644
> --- a/fs/xfs/libxfs/xfs_rmap.c
> +++ b/fs/xfs/libxfs/xfs_rmap.c
> @@ -11,6 +11,7 @@
>  #include "xfs_trans_resv.h"
>  #include "xfs_bit.h"
>  #include "xfs_mount.h"
> +#include "xfs_sb.h"
>  #include "xfs_defer.h"
>  #include "xfs_btree.h"
>  #include "xfs_trans.h"
> @@ -2363,31 +2364,32 @@ xfs_rmap_finish_one(
>  	struct xfs_btree_cur		**pcur)
>  {
>  	struct xfs_mount		*mp = tp->t_mountp;
> +	struct xfs_perag		*pag;
>  	struct xfs_btree_cur		*rcur;
>  	struct xfs_buf			*agbp = NULL;
>  	int				error = 0;
> -	xfs_agnumber_t			agno;
>  	struct xfs_owner_info		oinfo;
>  	xfs_agblock_t			bno;
>  	bool				unwritten;
>  
> -	agno = XFS_FSB_TO_AGNO(mp, startblock);
> -	ASSERT(agno != NULLAGNUMBER);
> +	pag = xfs_perag_get(mp, XFS_FSB_TO_AGNO(mp, startblock));
>  	bno = XFS_FSB_TO_AGBNO(mp, startblock);
>  
> -	trace_xfs_rmap_deferred(mp, agno, type, bno, owner, whichfork,
> +	trace_xfs_rmap_deferred(mp, pag->pag_agno, type, bno, owner, whichfork,
>  			startoff, blockcount, state);
>  
> -	if (XFS_TEST_ERROR(false, mp,
> -			XFS_ERRTAG_RMAP_FINISH_ONE))
> -		return -EIO;
> +	if (XFS_TEST_ERROR(false, mp, XFS_ERRTAG_RMAP_FINISH_ONE)) {
> +		error = -EIO;
> +		goto out_drop;
> +	}
> +
>  
>  	/*
>  	 * If we haven't gotten a cursor or the cursor AG doesn't match
>  	 * the startblock, get one now.
>  	 */
>  	rcur = *pcur;
> -	if (rcur != NULL && rcur->bc_ag.agno != agno) {
> +	if (rcur != NULL && rcur->bc_ag.agno != pag->pag_agno) {
>  		xfs_rmap_finish_one_cleanup(tp, rcur, 0);
>  		rcur = NULL;
>  		*pcur = NULL;
> @@ -2398,13 +2400,15 @@ xfs_rmap_finish_one(
>  		 * rmapbt, because a shape change could cause us to
>  		 * allocate blocks.
>  		 */
> -		error = xfs_free_extent_fix_freelist(tp, agno, &agbp);
> +		error = xfs_free_extent_fix_freelist(tp, pag, &agbp);
>  		if (error)
> -			return error;
> -		if (XFS_IS_CORRUPT(tp->t_mountp, !agbp))
> -			return -EFSCORRUPTED;
> +			goto out_drop;
> +		if (XFS_IS_CORRUPT(tp->t_mountp, !agbp)) {
> +			error = -EFSCORRUPTED;
> +			goto out_drop;
> +		}
>  
> -		rcur = xfs_rmapbt_init_cursor(mp, tp, agbp, agno);
> +		rcur = xfs_rmapbt_init_cursor(mp, tp, agbp, pag->pag_agno);
>  	}
>  	*pcur = rcur;
>  
> @@ -2442,6 +2446,8 @@ xfs_rmap_finish_one(
>  		ASSERT(0);
>  		error = -EFSCORRUPTED;
>  	}
> +out_drop:
> +	xfs_perag_put(pag);
>  	return error;
>  }
>  
> diff --git a/fs/xfs/libxfs/xfs_rmap_btree.c b/fs/xfs/libxfs/xfs_rmap_btree.c
> index f1fee42dda2d..46a5295ecf35 100644
> --- a/fs/xfs/libxfs/xfs_rmap_btree.c
> +++ b/fs/xfs/libxfs/xfs_rmap_btree.c
> @@ -100,8 +100,7 @@ xfs_rmapbt_alloc_block(
>  		return 0;
>  	}
>  
> -	xfs_extent_busy_reuse(cur->bc_mp, cur->bc_ag.agno, bno, 1,
> -			false);
> +	xfs_extent_busy_reuse(cur->bc_mp, agbp->b_pag, bno, 1, false);
>  
>  	new->s = cpu_to_be32(bno);
>  	be32_add_cpu(&agf->agf_rmap_blocks, 1);
> @@ -133,10 +132,10 @@ xfs_rmapbt_free_block(
>  	if (error)
>  		return error;
>  
> -	xfs_extent_busy_insert(cur->bc_tp, be32_to_cpu(agf->agf_seqno), bno, 1,
> +	pag = cur->bc_ag.agbp->b_pag;
> +	xfs_extent_busy_insert(cur->bc_tp, pag, bno, 1,
>  			      XFS_EXTENT_BUSY_SKIP_DISCARD);
>  
> -	pag = cur->bc_ag.agbp->b_pag;
>  	xfs_ag_resv_free_extent(pag, XFS_AG_RESV_RMAPBT, NULL, 1);
>  	return 0;
>  }
> diff --git a/fs/xfs/scrub/repair.c b/fs/xfs/scrub/repair.c
> index 1308b62a8170..6b62872c4d10 100644
> --- a/fs/xfs/scrub/repair.c
> +++ b/fs/xfs/scrub/repair.c
> @@ -304,7 +304,7 @@ xrep_alloc_ag_block(
>  			return error;
>  		if (bno == NULLAGBLOCK)
>  			return -ENOSPC;
> -		xfs_extent_busy_reuse(sc->mp, sc->sa.agno, bno,
> +		xfs_extent_busy_reuse(sc->mp, sc->sa.pag, bno,
>  				1, false);
>  		*fsbno = XFS_AGB_TO_FSB(sc->mp, sc->sa.agno, bno);
>  		if (resv == XFS_AG_RESV_RMAPBT)
> @@ -519,7 +519,7 @@ xrep_put_freelist(
>  			agbno, 0);
>  	if (error)
>  		return error;
> -	xfs_extent_busy_insert(sc->tp, sc->sa.agno, agbno, 1,
> +	xfs_extent_busy_insert(sc->tp, sc->sa.pag, agbno, 1,
>  			XFS_EXTENT_BUSY_SKIP_DISCARD);
>  
>  	return 0;
> diff --git a/fs/xfs/xfs_discard.c b/fs/xfs/xfs_discard.c
> index 3bf6dba1a040..972864250bd2 100644
> --- a/fs/xfs/xfs_discard.c
> +++ b/fs/xfs/xfs_discard.c
> @@ -108,7 +108,7 @@ xfs_trim_extents(
>  		 * If any blocks in the range are still busy, skip the
>  		 * discard and try again the next time.
>  		 */
> -		if (xfs_extent_busy_search(mp, agno, fbno, flen)) {
> +		if (xfs_extent_busy_search(mp, pag, fbno, flen)) {
>  			trace_xfs_discard_busy(mp, agno, fbno, flen);
>  			goto next_extent;
>  		}
> diff --git a/fs/xfs/xfs_extent_busy.c b/fs/xfs/xfs_extent_busy.c
> index 6af0b5a1c7b0..a0ea63fcc50d 100644
> --- a/fs/xfs/xfs_extent_busy.c
> +++ b/fs/xfs/xfs_extent_busy.c
> @@ -22,28 +22,26 @@
>  void
>  xfs_extent_busy_insert(
>  	struct xfs_trans	*tp,
> -	xfs_agnumber_t		agno,
> +	struct xfs_perag	*pag,
>  	xfs_agblock_t		bno,
>  	xfs_extlen_t		len,
>  	unsigned int		flags)
>  {
>  	struct xfs_extent_busy	*new;
>  	struct xfs_extent_busy	*busyp;
> -	struct xfs_perag	*pag;
>  	struct rb_node		**rbp;
>  	struct rb_node		*parent = NULL;
>  
>  	new = kmem_zalloc(sizeof(struct xfs_extent_busy), 0);
> -	new->agno = agno;
> +	new->agno = pag->pag_agno;
>  	new->bno = bno;
>  	new->length = len;
>  	INIT_LIST_HEAD(&new->list);
>  	new->flags = flags;
>  
>  	/* trace before insert to be able to see failed inserts */
> -	trace_xfs_extent_busy(tp->t_mountp, agno, bno, len);
> +	trace_xfs_extent_busy(tp->t_mountp, pag->pag_agno, bno, len);
>  
> -	pag = xfs_perag_get(tp->t_mountp, new->agno);
>  	spin_lock(&pag->pagb_lock);
>  	rbp = &pag->pagb_tree.rb_node;
>  	while (*rbp) {
> @@ -66,7 +64,6 @@ xfs_extent_busy_insert(
>  
>  	list_add(&new->list, &tp->t_busy);
>  	spin_unlock(&pag->pagb_lock);
> -	xfs_perag_put(pag);
>  }
>  
>  /*
> @@ -81,21 +78,17 @@ xfs_extent_busy_insert(
>  int
>  xfs_extent_busy_search(
>  	struct xfs_mount	*mp,
> -	xfs_agnumber_t		agno,
> +	struct xfs_perag	*pag,
>  	xfs_agblock_t		bno,
>  	xfs_extlen_t		len)
>  {
> -	struct xfs_perag	*pag;
>  	struct rb_node		*rbp;
>  	struct xfs_extent_busy	*busyp;
>  	int			match = 0;
>  
> -	pag = xfs_perag_get(mp, agno);
> +	/* find closest start bno overlap */
>  	spin_lock(&pag->pagb_lock);
> -
>  	rbp = pag->pagb_tree.rb_node;
> -
> -	/* find closest start bno overlap */
>  	while (rbp) {
>  		busyp = rb_entry(rbp, struct xfs_extent_busy, rb_node);
>  		if (bno < busyp->bno) {
> @@ -115,7 +108,6 @@ xfs_extent_busy_search(
>  		}
>  	}
>  	spin_unlock(&pag->pagb_lock);
> -	xfs_perag_put(pag);
>  	return match;
>  }
>  
> @@ -281,17 +273,14 @@ xfs_extent_busy_update_extent(
>  void
>  xfs_extent_busy_reuse(
>  	struct xfs_mount	*mp,
> -	xfs_agnumber_t		agno,
> +	struct xfs_perag	*pag,
>  	xfs_agblock_t		fbno,
>  	xfs_extlen_t		flen,
>  	bool			userdata)
>  {
> -	struct xfs_perag	*pag;
>  	struct rb_node		*rbp;
>  
>  	ASSERT(flen > 0);
> -
> -	pag = xfs_perag_get(mp, agno);
>  	spin_lock(&pag->pagb_lock);
>  restart:
>  	rbp = pag->pagb_tree.rb_node;
> @@ -314,7 +303,6 @@ xfs_extent_busy_reuse(
>  			goto restart;
>  	}
>  	spin_unlock(&pag->pagb_lock);
> -	xfs_perag_put(pag);
>  }
>  
>  /*
> diff --git a/fs/xfs/xfs_extent_busy.h b/fs/xfs/xfs_extent_busy.h
> index 990ab3891971..8031617bb6ef 100644
> --- a/fs/xfs/xfs_extent_busy.h
> +++ b/fs/xfs/xfs_extent_busy.h
> @@ -9,6 +9,7 @@
>  #define	__XFS_EXTENT_BUSY_H__
>  
>  struct xfs_mount;
> +struct xfs_perag;
>  struct xfs_trans;
>  struct xfs_alloc_arg;
>  
> @@ -31,7 +32,7 @@ struct xfs_extent_busy {
>  };
>  
>  void
> -xfs_extent_busy_insert(struct xfs_trans *tp, xfs_agnumber_t agno,
> +xfs_extent_busy_insert(struct xfs_trans *tp, struct xfs_perag *pag,
>  	xfs_agblock_t bno, xfs_extlen_t len, unsigned int flags);
>  
>  void
> @@ -39,11 +40,11 @@ xfs_extent_busy_clear(struct xfs_mount *mp, struct list_head *list,
>  	bool do_discard);
>  
>  int
> -xfs_extent_busy_search(struct xfs_mount *mp, xfs_agnumber_t agno,
> +xfs_extent_busy_search(struct xfs_mount *mp, struct xfs_perag *pag,
>  	xfs_agblock_t bno, xfs_extlen_t len);
>  
>  void
> -xfs_extent_busy_reuse(struct xfs_mount *mp, xfs_agnumber_t agno,
> +xfs_extent_busy_reuse(struct xfs_mount *mp, struct xfs_perag *pag,
>  	xfs_agblock_t fbno, xfs_extlen_t flen, bool userdata);
>  
>  bool
> -- 
> 2.31.1
> 

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 09/22] xfs: push perags through the ag reservation callouts
  2021-05-06  7:20 ` [PATCH 09/22] xfs: push perags through the ag reservation callouts Dave Chinner
  2021-05-11 12:29   ` Brian Foster
@ 2021-05-12 22:16   ` Darrick J. Wong
  1 sibling, 0 replies; 87+ messages in thread
From: Darrick J. Wong @ 2021-05-12 22:16 UTC (permalink / raw)
  To: Dave Chinner; +Cc: linux-xfs

On Thu, May 06, 2021 at 05:20:41PM +1000, Dave Chinner wrote:
> From: Dave Chinner <dchinner@redhat.com>
> 
> We currently pass an agno from the AG reservation functions to the
> individual feature accounting functions, which then may have to do
> perag lookups to access per-AG state. Plumb the perag through from
> the highest AG reservation layer to the feature callouts so they
> don't have to look it up again.

Like Brian, I don't see where this patch removes xfs_perag_get lookups.
Did that fall off this patch (I started at the front, tried to look at
the end, got tripped up, and resumed the start-to-finish iteration) or
should that last sentence be shortened to read:

"Plumb the perag through the entire call stack because perag structures
are now first class citizens." ?

If it's just the commit message change needed here, then:
Reviewed-by: Darrick J. Wong <djwong@kernel.org>

--D

> 
> Signed-off-by: Dave Chinner <dchinner@redhat.com>
> ---
>  fs/xfs/libxfs/xfs_ag_resv.c        |  9 ++++-----
>  fs/xfs/libxfs/xfs_ialloc_btree.c   | 17 +++++++++--------
>  fs/xfs/libxfs/xfs_ialloc_btree.h   |  2 +-
>  fs/xfs/libxfs/xfs_refcount_btree.c |  7 +++----
>  fs/xfs/libxfs/xfs_refcount_btree.h |  3 ++-
>  fs/xfs/libxfs/xfs_rmap_btree.c     |  6 +++---
>  fs/xfs/libxfs/xfs_rmap_btree.h     |  2 +-
>  7 files changed, 23 insertions(+), 23 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_ag_resv.c b/fs/xfs/libxfs/xfs_ag_resv.c
> index 2e3dcdfd4984..f7394a8ecf6b 100644
> --- a/fs/xfs/libxfs/xfs_ag_resv.c
> +++ b/fs/xfs/libxfs/xfs_ag_resv.c
> @@ -250,7 +250,6 @@ xfs_ag_resv_init(
>  	struct xfs_trans		*tp)
>  {
>  	struct xfs_mount		*mp = pag->pag_mount;
> -	xfs_agnumber_t			agno = pag->pag_agno;
>  	xfs_extlen_t			ask;
>  	xfs_extlen_t			used;
>  	int				error = 0, error2;
> @@ -260,11 +259,11 @@ xfs_ag_resv_init(
>  	if (pag->pag_meta_resv.ar_asked == 0) {
>  		ask = used = 0;
>  
> -		error = xfs_refcountbt_calc_reserves(mp, tp, agno, &ask, &used);
> +		error = xfs_refcountbt_calc_reserves(mp, tp, pag, &ask, &used);
>  		if (error)
>  			goto out;
>  
> -		error = xfs_finobt_calc_reserves(mp, tp, agno, &ask, &used);
> +		error = xfs_finobt_calc_reserves(mp, tp, pag, &ask, &used);
>  		if (error)
>  			goto out;
>  
> @@ -282,7 +281,7 @@ xfs_ag_resv_init(
>  
>  			mp->m_finobt_nores = true;
>  
> -			error = xfs_refcountbt_calc_reserves(mp, tp, agno, &ask,
> +			error = xfs_refcountbt_calc_reserves(mp, tp, pag, &ask,
>  					&used);
>  			if (error)
>  				goto out;
> @@ -300,7 +299,7 @@ xfs_ag_resv_init(
>  	if (pag->pag_rmapbt_resv.ar_asked == 0) {
>  		ask = used = 0;
>  
> -		error = xfs_rmapbt_calc_reserves(mp, tp, agno, &ask, &used);
> +		error = xfs_rmapbt_calc_reserves(mp, tp, pag, &ask, &used);
>  		if (error)
>  			goto out;
>  
> diff --git a/fs/xfs/libxfs/xfs_ialloc_btree.c b/fs/xfs/libxfs/xfs_ialloc_btree.c
> index 4c5831646bd9..4ec8ea1331a5 100644
> --- a/fs/xfs/libxfs/xfs_ialloc_btree.c
> +++ b/fs/xfs/libxfs/xfs_ialloc_btree.c
> @@ -20,6 +20,7 @@
>  #include "xfs_trace.h"
>  #include "xfs_trans.h"
>  #include "xfs_rmap.h"
> +#include "xfs_ag.h"
>  
>  STATIC int
>  xfs_inobt_get_minrecs(
> @@ -680,7 +681,7 @@ static int
>  xfs_inobt_count_blocks(
>  	struct xfs_mount	*mp,
>  	struct xfs_trans	*tp,
> -	xfs_agnumber_t		agno,
> +	struct xfs_perag	*pag,
>  	xfs_btnum_t		btnum,
>  	xfs_extlen_t		*tree_blocks)
>  {
> @@ -688,7 +689,7 @@ xfs_inobt_count_blocks(
>  	struct xfs_btree_cur	*cur = NULL;
>  	int			error;
>  
> -	error = xfs_inobt_cur(mp, tp, agno, btnum, &cur, &agbp);
> +	error = xfs_inobt_cur(mp, tp, pag->pag_agno, btnum, &cur, &agbp);
>  	if (error)
>  		return error;
>  
> @@ -704,14 +705,14 @@ static int
>  xfs_finobt_read_blocks(
>  	struct xfs_mount	*mp,
>  	struct xfs_trans	*tp,
> -	xfs_agnumber_t		agno,
> +	struct xfs_perag	*pag,
>  	xfs_extlen_t		*tree_blocks)
>  {
>  	struct xfs_buf		*agbp;
>  	struct xfs_agi		*agi;
>  	int			error;
>  
> -	error = xfs_ialloc_read_agi(mp, tp, agno, &agbp);
> +	error = xfs_ialloc_read_agi(mp, tp, pag->pag_agno, &agbp);
>  	if (error)
>  		return error;
>  
> @@ -728,7 +729,7 @@ int
>  xfs_finobt_calc_reserves(
>  	struct xfs_mount	*mp,
>  	struct xfs_trans	*tp,
> -	xfs_agnumber_t		agno,
> +	struct xfs_perag	*pag,
>  	xfs_extlen_t		*ask,
>  	xfs_extlen_t		*used)
>  {
> @@ -739,14 +740,14 @@ xfs_finobt_calc_reserves(
>  		return 0;
>  
>  	if (xfs_sb_version_hasinobtcounts(&mp->m_sb))
> -		error = xfs_finobt_read_blocks(mp, tp, agno, &tree_len);
> +		error = xfs_finobt_read_blocks(mp, tp, pag, &tree_len);
>  	else
> -		error = xfs_inobt_count_blocks(mp, tp, agno, XFS_BTNUM_FINO,
> +		error = xfs_inobt_count_blocks(mp, tp, pag, XFS_BTNUM_FINO,
>  				&tree_len);
>  	if (error)
>  		return error;
>  
> -	*ask += xfs_inobt_max_size(mp, agno);
> +	*ask += xfs_inobt_max_size(mp, pag->pag_agno);
>  	*used += tree_len;
>  	return 0;
>  }
> diff --git a/fs/xfs/libxfs/xfs_ialloc_btree.h b/fs/xfs/libxfs/xfs_ialloc_btree.h
> index 35bbd978c272..d5afe01fb2de 100644
> --- a/fs/xfs/libxfs/xfs_ialloc_btree.h
> +++ b/fs/xfs/libxfs/xfs_ialloc_btree.h
> @@ -64,7 +64,7 @@ int xfs_inobt_rec_check_count(struct xfs_mount *,
>  #endif	/* DEBUG */
>  
>  int xfs_finobt_calc_reserves(struct xfs_mount *mp, struct xfs_trans *tp,
> -		xfs_agnumber_t agno, xfs_extlen_t *ask, xfs_extlen_t *used);
> +		struct xfs_perag *pag, xfs_extlen_t *ask, xfs_extlen_t *used);
>  extern xfs_extlen_t xfs_iallocbt_calc_size(struct xfs_mount *mp,
>  		unsigned long long len);
>  int xfs_inobt_cur(struct xfs_mount *mp, struct xfs_trans *tp,
> diff --git a/fs/xfs/libxfs/xfs_refcount_btree.c b/fs/xfs/libxfs/xfs_refcount_btree.c
> index b281f0c674f5..c4ddf9ded00b 100644
> --- a/fs/xfs/libxfs/xfs_refcount_btree.c
> +++ b/fs/xfs/libxfs/xfs_refcount_btree.c
> @@ -450,7 +450,7 @@ int
>  xfs_refcountbt_calc_reserves(
>  	struct xfs_mount	*mp,
>  	struct xfs_trans	*tp,
> -	xfs_agnumber_t		agno,
> +	struct xfs_perag	*pag,
>  	xfs_extlen_t		*ask,
>  	xfs_extlen_t		*used)
>  {
> @@ -463,8 +463,7 @@ xfs_refcountbt_calc_reserves(
>  	if (!xfs_sb_version_hasreflink(&mp->m_sb))
>  		return 0;
>  
> -
> -	error = xfs_alloc_read_agf(mp, tp, agno, 0, &agbp);
> +	error = xfs_alloc_read_agf(mp, tp, pag->pag_agno, 0, &agbp);
>  	if (error)
>  		return error;
>  
> @@ -479,7 +478,7 @@ xfs_refcountbt_calc_reserves(
>  	 * expansion.  We therefore can pretend the space isn't there.
>  	 */
>  	if (mp->m_sb.sb_logstart &&
> -	    XFS_FSB_TO_AGNO(mp, mp->m_sb.sb_logstart) == agno)
> +	    XFS_FSB_TO_AGNO(mp, mp->m_sb.sb_logstart) == pag->pag_agno)
>  		agblocks -= mp->m_sb.sb_logblocks;
>  
>  	*ask += xfs_refcountbt_max_size(mp, agblocks);
> diff --git a/fs/xfs/libxfs/xfs_refcount_btree.h b/fs/xfs/libxfs/xfs_refcount_btree.h
> index 69dc515db671..eab1b0c672c0 100644
> --- a/fs/xfs/libxfs/xfs_refcount_btree.h
> +++ b/fs/xfs/libxfs/xfs_refcount_btree.h
> @@ -13,6 +13,7 @@
>  struct xfs_buf;
>  struct xfs_btree_cur;
>  struct xfs_mount;
> +struct xfs_perag;
>  struct xbtree_afakeroot;
>  
>  /*
> @@ -58,7 +59,7 @@ extern xfs_extlen_t xfs_refcountbt_max_size(struct xfs_mount *mp,
>  		xfs_agblock_t agblocks);
>  
>  extern int xfs_refcountbt_calc_reserves(struct xfs_mount *mp,
> -		struct xfs_trans *tp, xfs_agnumber_t agno, xfs_extlen_t *ask,
> +		struct xfs_trans *tp, struct xfs_perag *pag, xfs_extlen_t *ask,
>  		xfs_extlen_t *used);
>  
>  void xfs_refcountbt_commit_staged_btree(struct xfs_btree_cur *cur,
> diff --git a/fs/xfs/libxfs/xfs_rmap_btree.c b/fs/xfs/libxfs/xfs_rmap_btree.c
> index 46a5295ecf35..ba2f7064451b 100644
> --- a/fs/xfs/libxfs/xfs_rmap_btree.c
> +++ b/fs/xfs/libxfs/xfs_rmap_btree.c
> @@ -595,7 +595,7 @@ int
>  xfs_rmapbt_calc_reserves(
>  	struct xfs_mount	*mp,
>  	struct xfs_trans	*tp,
> -	xfs_agnumber_t		agno,
> +	struct xfs_perag	*pag,
>  	xfs_extlen_t		*ask,
>  	xfs_extlen_t		*used)
>  {
> @@ -608,7 +608,7 @@ xfs_rmapbt_calc_reserves(
>  	if (!xfs_sb_version_hasrmapbt(&mp->m_sb))
>  		return 0;
>  
> -	error = xfs_alloc_read_agf(mp, tp, agno, 0, &agbp);
> +	error = xfs_alloc_read_agf(mp, tp, pag->pag_agno, 0, &agbp);
>  	if (error)
>  		return error;
>  
> @@ -623,7 +623,7 @@ xfs_rmapbt_calc_reserves(
>  	 * expansion.  We therefore can pretend the space isn't there.
>  	 */
>  	if (mp->m_sb.sb_logstart &&
> -	    XFS_FSB_TO_AGNO(mp, mp->m_sb.sb_logstart) == agno)
> +	    XFS_FSB_TO_AGNO(mp, mp->m_sb.sb_logstart) == pag->pag_agno)
>  		agblocks -= mp->m_sb.sb_logblocks;
>  
>  	/* Reserve 1% of the AG or enough for 1 block per record. */
> diff --git a/fs/xfs/libxfs/xfs_rmap_btree.h b/fs/xfs/libxfs/xfs_rmap_btree.h
> index 115c3455a734..57fab72e26ad 100644
> --- a/fs/xfs/libxfs/xfs_rmap_btree.h
> +++ b/fs/xfs/libxfs/xfs_rmap_btree.h
> @@ -57,6 +57,6 @@ extern xfs_extlen_t xfs_rmapbt_max_size(struct xfs_mount *mp,
>  		xfs_agblock_t agblocks);
>  
>  extern int xfs_rmapbt_calc_reserves(struct xfs_mount *mp, struct xfs_trans *tp,
> -		xfs_agnumber_t agno, xfs_extlen_t *ask, xfs_extlen_t *used);
> +		struct xfs_perag *pag, xfs_extlen_t *ask, xfs_extlen_t *used);
>  
>  #endif	/* __XFS_RMAP_BTREE_H__ */
> -- 
> 2.31.1
> 

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 10/22] xfs: pass perags around in fsmap data dev functions
  2021-05-06  7:20 ` [PATCH 10/22] xfs: pass perags around in fsmap data dev functions Dave Chinner
  2021-05-11 12:30   ` Brian Foster
@ 2021-05-12 22:23   ` Darrick J. Wong
  2021-05-18  1:00     ` Dave Chinner
  1 sibling, 1 reply; 87+ messages in thread
From: Darrick J. Wong @ 2021-05-12 22:23 UTC (permalink / raw)
  To: Dave Chinner; +Cc: linux-xfs

On Thu, May 06, 2021 at 05:20:42PM +1000, Dave Chinner wrote:
> From: Dave Chinner <dchinner@redhat.com>
> 
> Needs a [from, to] ranged AG walk, and the perag to be stuffed into
> the info structure for callouts to use.
> 
> Signed-off-by: Dave Chinner <dchinner@redhat.com>
> ---
>  fs/xfs/libxfs/xfs_ag.h | 14 ++++++--
>  fs/xfs/xfs_fsmap.c     | 75 ++++++++++++++++++++++++++----------------
>  2 files changed, 58 insertions(+), 31 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_ag.h b/fs/xfs/libxfs/xfs_ag.h
> index 3fa88222dacd..bebbe1bfce27 100644
> --- a/fs/xfs/libxfs/xfs_ag.h
> +++ b/fs/xfs/libxfs/xfs_ag.h
> @@ -116,14 +116,24 @@ void	xfs_perag_put(struct xfs_perag *pag);
>  
>  /*
>   * Perag iteration APIs
> + *
> + * XXX: for_each_perag_range() usage really needs an iterator to clean up when
> + * we terminate at end_agno because we may have taken a reference to the perag
> + * beyond end_agno. RIght now callers have to be careful to catch and clean that
> + * up themselves. This is not necessary for the callers of for_each_perag() and
> + * for_each_perag_from() because they terminate at sb_agcount where there are
> + * no perag structures in tree beyond end_agno.

I think I'll wait and see what this becomes with the next iteration
before RVBing things.  The conversions look correct in this patch.

>   */
> -#define for_each_perag_from(mp, next_agno, pag) \
> +#define for_each_perag_range(mp, next_agno, end_agno, pag) \
>  	for ((pag) = xfs_perag_get((mp), (next_agno)); \
> -		(pag) != NULL; \
> +		(pag) != NULL && (next_agno) <= (end_agno); \
>  		(next_agno) = (pag)->pag_agno + 1, \
>  		xfs_perag_put(pag), \
>  		(pag) = xfs_perag_get((mp), (next_agno)))
>  
> +#define for_each_perag_from(mp, next_agno, pag) \
> +	for_each_perag_range((mp), (next_agno), (mp)->m_sb.sb_agcount, (pag))
> +
>  #define for_each_perag(mp, next_agno, pag) \
>  	(next_agno) = 0; \
>  	for_each_perag_from((mp), (next_agno), (pag))
> diff --git a/fs/xfs/xfs_fsmap.c b/fs/xfs/xfs_fsmap.c
> index 34f2b971ce43..835dd6e3819b 100644
> --- a/fs/xfs/xfs_fsmap.c
> +++ b/fs/xfs/xfs_fsmap.c
> @@ -24,6 +24,7 @@
>  #include "xfs_refcount_btree.h"
>  #include "xfs_alloc_btree.h"
>  #include "xfs_rtalloc.h"
> +#include "xfs_ag.h"
>  
>  /* Convert an xfs_fsmap to an fsmap. */
>  static void
> @@ -157,10 +158,10 @@ struct xfs_getfsmap_info {
>  	struct xfs_fsmap_head	*head;
>  	struct fsmap		*fsmap_recs;	/* mapping records */
>  	struct xfs_buf		*agf_bp;	/* AGF, for refcount queries */
> +	struct xfs_perag	*pag;		/* AG info, if applicable */
>  	xfs_daddr_t		next_daddr;	/* next daddr we expect */
>  	u64			missing_owner;	/* owner of holes */
>  	u32			dev;		/* device id */
> -	xfs_agnumber_t		agno;		/* AG number, if applicable */
>  	struct xfs_rmap_irec	low;		/* low rmap key */
>  	struct xfs_rmap_irec	high;		/* high rmap key */
>  	bool			last;		/* last extent? */
> @@ -203,14 +204,14 @@ xfs_getfsmap_is_shared(
>  	*stat = false;
>  	if (!xfs_sb_version_hasreflink(&mp->m_sb))
>  		return 0;
> -	/* rt files will have agno set to NULLAGNUMBER */
> -	if (info->agno == NULLAGNUMBER)
> +	/* rt files will have no perag structure */
> +	if (!info->pag)
>  		return 0;

FWIW on my realtime rmap and reflink patchsets, I've been using the
convention of agno==NULLAGNUMBER and pag==NULL to indicate that we're
targeting the realtime device, so this dovetails with that nicely.

If we ever want to support multiple rt devices I guess we'd have to
figure out an appropriate "shard" structure to pass around, but seeing
as I've barely gotten rt reflink to work properly with non-unit extent
sizes, that's a fair ways off...

--D

>  
>  	/* Are there any shared blocks here? */
>  	flen = 0;
>  	cur = xfs_refcountbt_init_cursor(mp, tp, info->agf_bp,
> -			info->agno);
> +			info->pag->pag_agno);
>  
>  	error = xfs_refcount_find_shared(cur, rec->rm_startblock,
>  			rec->rm_blockcount, &fbno, &flen, false);
> @@ -311,7 +312,8 @@ xfs_getfsmap_helper(
>  	if (info->head->fmh_entries >= info->head->fmh_count)
>  		return -ECANCELED;
>  
> -	trace_xfs_fsmap_mapping(mp, info->dev, info->agno, rec);
> +	trace_xfs_fsmap_mapping(mp, info->dev,
> +			info->pag ? info->pag->pag_agno : NULLAGNUMBER, rec);
>  
>  	fmr.fmr_device = info->dev;
>  	fmr.fmr_physical = rec_daddr;
> @@ -429,8 +431,8 @@ xfs_getfsmap_logdev(
>  	info->high.rm_flags = XFS_RMAP_KEY_FLAGS | XFS_RMAP_REC_FLAGS;
>  	info->missing_owner = XFS_FMR_OWN_FREE;
>  
> -	trace_xfs_fsmap_low_key(mp, info->dev, info->agno, &info->low);
> -	trace_xfs_fsmap_high_key(mp, info->dev, info->agno, &info->high);
> +	trace_xfs_fsmap_low_key(mp, info->dev, NULLAGNUMBER, &info->low);
> +	trace_xfs_fsmap_high_key(mp, info->dev, NULLAGNUMBER, &info->high);
>  
>  	if (keys[0].fmr_physical > 0)
>  		return 0;
> @@ -508,8 +510,8 @@ __xfs_getfsmap_rtdev(
>  	info->high.rm_blockcount = 0;
>  	xfs_getfsmap_set_irec_flags(&info->high, &keys[1]);
>  
> -	trace_xfs_fsmap_low_key(mp, info->dev, info->agno, &info->low);
> -	trace_xfs_fsmap_high_key(mp, info->dev, info->agno, &info->high);
> +	trace_xfs_fsmap_low_key(mp, info->dev, NULLAGNUMBER, &info->low);
> +	trace_xfs_fsmap_high_key(mp, info->dev, NULLAGNUMBER, &info->high);
>  
>  	return query_fn(tp, info);
>  }
> @@ -572,6 +574,7 @@ __xfs_getfsmap_datadev(
>  	void				*priv)
>  {
>  	struct xfs_mount		*mp = tp->t_mountp;
> +	struct xfs_perag		*pag;
>  	struct xfs_btree_cur		*bt_cur = NULL;
>  	xfs_fsblock_t			start_fsb;
>  	xfs_fsblock_t			end_fsb;
> @@ -610,20 +613,20 @@ __xfs_getfsmap_datadev(
>  	start_ag = XFS_FSB_TO_AGNO(mp, start_fsb);
>  	end_ag = XFS_FSB_TO_AGNO(mp, end_fsb);
>  
> -	/* Query each AG */
> -	for (info->agno = start_ag; info->agno <= end_ag; info->agno++) {
> +	for_each_perag_range(mp, start_ag, end_ag, pag) {
>  		/*
>  		 * Set the AG high key from the fsmap high key if this
>  		 * is the last AG that we're querying.
>  		 */
> -		if (info->agno == end_ag) {
> +		info->pag = pag;
> +		if (pag->pag_agno == end_ag) {
>  			info->high.rm_startblock = XFS_FSB_TO_AGBNO(mp,
>  					end_fsb);
>  			info->high.rm_offset = XFS_BB_TO_FSBT(mp,
>  					keys[1].fmr_offset);
>  			error = xfs_fsmap_owner_to_rmap(&info->high, &keys[1]);
>  			if (error)
> -				goto err;
> +				break;
>  			xfs_getfsmap_set_irec_flags(&info->high, &keys[1]);
>  		}
>  
> @@ -634,38 +637,45 @@ __xfs_getfsmap_datadev(
>  			info->agf_bp = NULL;
>  		}
>  
> -		error = xfs_alloc_read_agf(mp, tp, info->agno, 0,
> +		error = xfs_alloc_read_agf(mp, tp, pag->pag_agno, 0,
>  				&info->agf_bp);
>  		if (error)
> -			goto err;
> +			break;
>  
> -		trace_xfs_fsmap_low_key(mp, info->dev, info->agno, &info->low);
> -		trace_xfs_fsmap_high_key(mp, info->dev, info->agno,
> +		trace_xfs_fsmap_low_key(mp, info->dev, pag->pag_agno,
> +				&info->low);
> +		trace_xfs_fsmap_high_key(mp, info->dev, pag->pag_agno,
>  				&info->high);
>  
>  		error = query_fn(tp, info, &bt_cur, priv);
>  		if (error)
> -			goto err;
> +			break;
>  
>  		/*
>  		 * Set the AG low key to the start of the AG prior to
>  		 * moving on to the next AG.
>  		 */
> -		if (info->agno == start_ag) {
> +		if (pag->pag_agno == start_ag) {
>  			info->low.rm_startblock = 0;
>  			info->low.rm_owner = 0;
>  			info->low.rm_offset = 0;
>  			info->low.rm_flags = 0;
>  		}
> -	}
>  
> -	/* Report any gap at the end of the AG */
> -	info->last = true;
> -	error = query_fn(tp, info, &bt_cur, priv);
> -	if (error)
> -		goto err;
> +		/*
> +		 * If this is the last AG, report any gap at the end of it
> +		 * before we drop the reference to the perag when the loop
> +		 * terminates.
> +		 */
> +		if (pag->pag_agno == end_ag) {
> +			info->last = true;
> +			error = query_fn(tp, info, &bt_cur, priv);
> +			if (error)
> +				break;
> +		}
> +		info->pag = NULL;
> +	}
>  
> -err:
>  	if (bt_cur)
>  		xfs_btree_del_cursor(bt_cur, error < 0 ? XFS_BTREE_ERROR :
>  							 XFS_BTREE_NOERROR);
> @@ -673,6 +683,13 @@ __xfs_getfsmap_datadev(
>  		xfs_trans_brelse(tp, info->agf_bp);
>  		info->agf_bp = NULL;
>  	}
> +	if (info->pag) {
> +		xfs_perag_put(info->pag);
> +		info->pag = NULL;
> +	} else if (pag) {
> +		/* loop termination case */
> +		xfs_perag_put(pag);
> +	}
>  
>  	return error;
>  }
> @@ -691,7 +708,7 @@ xfs_getfsmap_datadev_rmapbt_query(
>  
>  	/* Allocate cursor for this AG and query_range it. */
>  	*curpp = xfs_rmapbt_init_cursor(tp->t_mountp, tp, info->agf_bp,
> -			info->agno);
> +			info->pag->pag_agno);
>  	return xfs_rmap_query_range(*curpp, &info->low, &info->high,
>  			xfs_getfsmap_datadev_helper, info);
>  }
> @@ -724,7 +741,7 @@ xfs_getfsmap_datadev_bnobt_query(
>  
>  	/* Allocate cursor for this AG and query_range it. */
>  	*curpp = xfs_allocbt_init_cursor(tp->t_mountp, tp, info->agf_bp,
> -			info->agno, XFS_BTNUM_BNO);
> +			info->pag->pag_agno, XFS_BTNUM_BNO);
>  	key->ar_startblock = info->low.rm_startblock;
>  	key[1].ar_startblock = info->high.rm_startblock;
>  	return xfs_alloc_query_range(*curpp, key, &key[1],
> @@ -937,7 +954,7 @@ xfs_getfsmap(
>  
>  		info.dev = handlers[i].dev;
>  		info.last = false;
> -		info.agno = NULLAGNUMBER;
> +		info.pag = NULL;
>  		error = handlers[i].fn(tp, dkeys, &info);
>  		if (error)
>  			break;
> -- 
> 2.31.1
> 

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 11/22] xfs: add a perag to the btree cursor
  2021-05-06  7:20 ` [PATCH 11/22] xfs: add a perag to the btree cursor Dave Chinner
  2021-05-11 12:30   ` Brian Foster
@ 2021-05-12 22:40   ` Darrick J. Wong
  2021-05-13  0:12     ` Dave Chinner
  1 sibling, 1 reply; 87+ messages in thread
From: Darrick J. Wong @ 2021-05-12 22:40 UTC (permalink / raw)
  To: Dave Chinner; +Cc: linux-xfs

On Thu, May 06, 2021 at 05:20:43PM +1000, Dave Chinner wrote:
> From: Dave Chinner <dchinner@redhat.com>
> 
> Which will eventually completely replace the agno in it.
> 
> Signed-off-by: Dave Chinner <dchinner@redhat.com>
> ---
>  fs/xfs/libxfs/xfs_alloc.c          | 25 +++++++++++++++----------
>  fs/xfs/libxfs/xfs_alloc_btree.c    | 13 ++++++++++---
>  fs/xfs/libxfs/xfs_alloc_btree.h    |  3 ++-
>  fs/xfs/libxfs/xfs_btree.c          |  2 ++
>  fs/xfs/libxfs/xfs_btree.h          |  4 +++-
>  fs/xfs/libxfs/xfs_ialloc.c         | 16 ++++++++--------
>  fs/xfs/libxfs/xfs_ialloc_btree.c   | 15 +++++++++++----
>  fs/xfs/libxfs/xfs_ialloc_btree.h   |  7 ++++---
>  fs/xfs/libxfs/xfs_refcount.c       |  4 ++--
>  fs/xfs/libxfs/xfs_refcount_btree.c | 17 ++++++++++++-----
>  fs/xfs/libxfs/xfs_refcount_btree.h |  2 +-
>  fs/xfs/libxfs/xfs_rmap.c           |  6 +++---
>  fs/xfs/libxfs/xfs_rmap_btree.c     | 17 ++++++++++++-----
>  fs/xfs/libxfs/xfs_rmap_btree.h     |  2 +-
>  fs/xfs/scrub/agheader_repair.c     | 20 +++++++++++---------
>  fs/xfs/scrub/bmap.c                |  2 +-
>  fs/xfs/scrub/common.c              | 12 ++++++------
>  fs/xfs/scrub/repair.c              |  5 +++--
>  fs/xfs/xfs_discard.c               |  2 +-
>  fs/xfs/xfs_fsmap.c                 |  6 +++---
>  fs/xfs/xfs_reflink.c               |  2 +-
>  21 files changed, 112 insertions(+), 70 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_alloc.c b/fs/xfs/libxfs/xfs_alloc.c
> index ce31c00dbf6f..7ec4af6bf494 100644
> --- a/fs/xfs/libxfs/xfs_alloc.c
> +++ b/fs/xfs/libxfs/xfs_alloc.c
> @@ -776,7 +776,8 @@ xfs_alloc_cur_setup(
>  	 */
>  	if (!acur->cnt)
>  		acur->cnt = xfs_allocbt_init_cursor(args->mp, args->tp,
> -					args->agbp, args->agno, XFS_BTNUM_CNT);
> +						args->agbp, args->agno,
> +						args->pag, XFS_BTNUM_CNT);

If we still have to pass the AG[FI] buffer into the _init_cursor
functions, why not get the perag reference from the xfs_buf and
eliminate the agno/pag parameter?  It looks like cursors get their own
active reference to the perag, so I think only the _stage_cursor
function needs to be passed a perag structure, right?

The mechanical conversion stuff in the rest of this patch look fine to
me.

--D

>  	error = xfs_alloc_lookup_ge(acur->cnt, 0, args->maxlen, &i);
>  	if (error)
>  		return error;
> @@ -786,10 +787,12 @@ xfs_alloc_cur_setup(
>  	 */
>  	if (!acur->bnolt)
>  		acur->bnolt = xfs_allocbt_init_cursor(args->mp, args->tp,
> -					args->agbp, args->agno, XFS_BTNUM_BNO);
> +						args->agbp, args->agno,
> +						args->pag, XFS_BTNUM_BNO);
>  	if (!acur->bnogt)
>  		acur->bnogt = xfs_allocbt_init_cursor(args->mp, args->tp,
> -					args->agbp, args->agno, XFS_BTNUM_BNO);
> +						args->agbp, args->agno,
> +						args->pag, XFS_BTNUM_BNO);
>  	return i == 1 ? 0 : -ENOSPC;
>  }
>  
> @@ -1217,7 +1220,7 @@ xfs_alloc_ag_vextent_exact(
>  	 * Allocate/initialize a cursor for the by-number freespace btree.
>  	 */
>  	bno_cur = xfs_allocbt_init_cursor(args->mp, args->tp, args->agbp,
> -					  args->agno, XFS_BTNUM_BNO);
> +					  args->agno, args->pag, XFS_BTNUM_BNO);
>  
>  	/*
>  	 * Lookup bno and minlen in the btree (minlen is irrelevant, really).
> @@ -1277,7 +1280,7 @@ xfs_alloc_ag_vextent_exact(
>  	 * Allocate/initialize a cursor for the by-size btree.
>  	 */
>  	cnt_cur = xfs_allocbt_init_cursor(args->mp, args->tp, args->agbp,
> -		args->agno, XFS_BTNUM_CNT);
> +					args->agno, args->pag, XFS_BTNUM_CNT);
>  	ASSERT(args->agbno + args->len <= be32_to_cpu(agf->agf_length));
>  	error = xfs_alloc_fixup_trees(cnt_cur, bno_cur, fbno, flen, args->agbno,
>  				      args->len, XFSA_FIXUP_BNO_OK);
> @@ -1674,7 +1677,7 @@ xfs_alloc_ag_vextent_size(
>  	 * Allocate and initialize a cursor for the by-size btree.
>  	 */
>  	cnt_cur = xfs_allocbt_init_cursor(args->mp, args->tp, args->agbp,
> -		args->agno, XFS_BTNUM_CNT);
> +					args->agno, args->pag, XFS_BTNUM_CNT);
>  	bno_cur = NULL;
>  	busy = false;
>  
> @@ -1837,7 +1840,7 @@ xfs_alloc_ag_vextent_size(
>  	 * Allocate and initialize a cursor for the by-block tree.
>  	 */
>  	bno_cur = xfs_allocbt_init_cursor(args->mp, args->tp, args->agbp,
> -		args->agno, XFS_BTNUM_BNO);
> +					args->agno, args->pag, XFS_BTNUM_BNO);
>  	if ((error = xfs_alloc_fixup_trees(cnt_cur, bno_cur, fbno, flen,
>  			rbno, rlen, XFSA_FIXUP_CNT_OK)))
>  		goto error0;
> @@ -1909,7 +1912,8 @@ xfs_free_ag_extent(
>  	/*
>  	 * Allocate and initialize a cursor for the by-block btree.
>  	 */
> -	bno_cur = xfs_allocbt_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_BNO);
> +	bno_cur = xfs_allocbt_init_cursor(mp, tp, agbp, agno,
> +					NULL, XFS_BTNUM_BNO);
>  	/*
>  	 * Look for a neighboring block on the left (lower block numbers)
>  	 * that is contiguous with this space.
> @@ -1979,7 +1983,8 @@ xfs_free_ag_extent(
>  	/*
>  	 * Now allocate and initialize a cursor for the by-size tree.
>  	 */
> -	cnt_cur = xfs_allocbt_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_CNT);
> +	cnt_cur = xfs_allocbt_init_cursor(mp, tp, agbp, agno,
> +					NULL, XFS_BTNUM_CNT);
>  	/*
>  	 * Have both left and right contiguous neighbors.
>  	 * Merge all three into a single free block.
> @@ -2490,7 +2495,7 @@ xfs_exact_minlen_extent_available(
>  	int			error = 0;
>  
>  	cnt_cur = xfs_allocbt_init_cursor(args->mp, args->tp, agbp,
> -			args->agno, XFS_BTNUM_CNT);
> +					args->agno, args->pag, XFS_BTNUM_CNT);
>  	error = xfs_alloc_lookup_ge(cnt_cur, 0, args->minlen, stat);
>  	if (error)
>  		goto out;
> diff --git a/fs/xfs/libxfs/xfs_alloc_btree.c b/fs/xfs/libxfs/xfs_alloc_btree.c
> index 19fdf87e86b9..a52ab25bbf0b 100644
> --- a/fs/xfs/libxfs/xfs_alloc_btree.c
> +++ b/fs/xfs/libxfs/xfs_alloc_btree.c
> @@ -27,7 +27,7 @@ xfs_allocbt_dup_cursor(
>  {
>  	return xfs_allocbt_init_cursor(cur->bc_mp, cur->bc_tp,
>  			cur->bc_ag.agbp, cur->bc_ag.agno,
> -			cur->bc_btnum);
> +			cur->bc_ag.pag, cur->bc_btnum);
>  }
>  
>  STATIC void
> @@ -473,6 +473,7 @@ xfs_allocbt_init_common(
>  	struct xfs_mount	*mp,
>  	struct xfs_trans	*tp,
>  	xfs_agnumber_t		agno,
> +	struct xfs_perag	*pag,
>  	xfs_btnum_t		btnum)
>  {
>  	struct xfs_btree_cur	*cur;
> @@ -497,6 +498,11 @@ xfs_allocbt_init_common(
>  
>  	cur->bc_ag.agno = agno;
>  	cur->bc_ag.abt.active = false;
> +	if (pag) {
> +		/* take a reference for the cursor */
> +		atomic_inc(&pag->pag_ref);
> +	}
> +	cur->bc_ag.pag = pag;
>  
>  	if (xfs_sb_version_hascrc(&mp->m_sb))
>  		cur->bc_flags |= XFS_BTREE_CRC_BLOCKS;
> @@ -513,12 +519,13 @@ xfs_allocbt_init_cursor(
>  	struct xfs_trans	*tp,		/* transaction pointer */
>  	struct xfs_buf		*agbp,		/* buffer for agf structure */
>  	xfs_agnumber_t		agno,		/* allocation group number */
> +	struct xfs_perag	*pag,
>  	xfs_btnum_t		btnum)		/* btree identifier */
>  {
>  	struct xfs_agf		*agf = agbp->b_addr;
>  	struct xfs_btree_cur	*cur;
>  
> -	cur = xfs_allocbt_init_common(mp, tp, agno, btnum);
> +	cur = xfs_allocbt_init_common(mp, tp, agno, pag, btnum);
>  	if (btnum == XFS_BTNUM_CNT)
>  		cur->bc_nlevels = be32_to_cpu(agf->agf_levels[XFS_BTNUM_CNT]);
>  	else
> @@ -539,7 +546,7 @@ xfs_allocbt_stage_cursor(
>  {
>  	struct xfs_btree_cur	*cur;
>  
> -	cur = xfs_allocbt_init_common(mp, NULL, agno, btnum);
> +	cur = xfs_allocbt_init_common(mp, NULL, agno, NULL, btnum);
>  	xfs_btree_stage_afakeroot(cur, afake);
>  	return cur;
>  }
> diff --git a/fs/xfs/libxfs/xfs_alloc_btree.h b/fs/xfs/libxfs/xfs_alloc_btree.h
> index a5b998e950fe..a10cedba18d8 100644
> --- a/fs/xfs/libxfs/xfs_alloc_btree.h
> +++ b/fs/xfs/libxfs/xfs_alloc_btree.h
> @@ -13,6 +13,7 @@
>  struct xfs_buf;
>  struct xfs_btree_cur;
>  struct xfs_mount;
> +struct xfs_perag;
>  struct xbtree_afakeroot;
>  
>  /*
> @@ -48,7 +49,7 @@ struct xbtree_afakeroot;
>  
>  extern struct xfs_btree_cur *xfs_allocbt_init_cursor(struct xfs_mount *,
>  		struct xfs_trans *, struct xfs_buf *,
> -		xfs_agnumber_t, xfs_btnum_t);
> +		xfs_agnumber_t, struct xfs_perag *pag, xfs_btnum_t);
>  struct xfs_btree_cur *xfs_allocbt_stage_cursor(struct xfs_mount *mp,
>  		struct xbtree_afakeroot *afake, xfs_agnumber_t agno,
>  		xfs_btnum_t btnum);
> diff --git a/fs/xfs/libxfs/xfs_btree.c b/fs/xfs/libxfs/xfs_btree.c
> index 0f12b885600d..44044317c0fb 100644
> --- a/fs/xfs/libxfs/xfs_btree.c
> +++ b/fs/xfs/libxfs/xfs_btree.c
> @@ -377,6 +377,8 @@ xfs_btree_del_cursor(
>  	       XFS_FORCED_SHUTDOWN(cur->bc_mp));
>  	if (unlikely(cur->bc_flags & XFS_BTREE_STAGING))
>  		kmem_free(cur->bc_ops);
> +	if (!(cur->bc_flags & XFS_BTREE_LONG_PTRS) && cur->bc_ag.pag)
> +		xfs_perag_put(cur->bc_ag.pag);
>  	kmem_cache_free(xfs_btree_cur_zone, cur);
>  }
>  
> diff --git a/fs/xfs/libxfs/xfs_btree.h b/fs/xfs/libxfs/xfs_btree.h
> index 10e50cbacacf..8233f8679ba9 100644
> --- a/fs/xfs/libxfs/xfs_btree.h
> +++ b/fs/xfs/libxfs/xfs_btree.h
> @@ -11,6 +11,7 @@ struct xfs_inode;
>  struct xfs_mount;
>  struct xfs_trans;
>  struct xfs_ifork;
> +struct xfs_perag;
>  
>  extern kmem_zone_t	*xfs_btree_cur_zone;
>  
> @@ -180,11 +181,12 @@ union xfs_btree_irec {
>  
>  /* Per-AG btree information. */
>  struct xfs_btree_cur_ag {
> +	xfs_agnumber_t		agno;
> +	struct xfs_perag	*pag;
>  	union {
>  		struct xfs_buf		*agbp;
>  		struct xbtree_afakeroot	*afake;	/* for staging cursor */
>  	};
> -	xfs_agnumber_t		agno;
>  	union {
>  		struct {
>  			unsigned long nr_ops;	/* # record updates */
> diff --git a/fs/xfs/libxfs/xfs_ialloc.c b/fs/xfs/libxfs/xfs_ialloc.c
> index 8dc9225a5353..905872bab426 100644
> --- a/fs/xfs/libxfs/xfs_ialloc.c
> +++ b/fs/xfs/libxfs/xfs_ialloc.c
> @@ -183,7 +183,7 @@ xfs_inobt_insert(
>  	int			i;
>  	int			error;
>  
> -	cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, btnum);
> +	cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, NULL, btnum);
>  
>  	for (thisino = newino;
>  	     thisino < newino + newlen;
> @@ -531,7 +531,7 @@ xfs_inobt_insert_sprec(
>  	int				i;
>  	struct xfs_inobt_rec_incore	rec;
>  
> -	cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, btnum);
> +	cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, NULL, btnum);
>  
>  	/* the new record is pre-aligned so we know where to look */
>  	error = xfs_inobt_lookup(cur, nrec->ir_startino, XFS_LOOKUP_EQ, &i);
> @@ -1145,7 +1145,7 @@ xfs_dialloc_ag_inobt(
>  	ASSERT(pag->pagi_freecount > 0);
>  
>   restart_pagno:
> -	cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_INO);
> +	cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, NULL, XFS_BTNUM_INO);
>  	/*
>  	 * If pagino is 0 (this is the root inode allocation) use newino.
>  	 * This must work because we've just allocated some.
> @@ -1598,7 +1598,7 @@ xfs_dialloc_ag(
>  	if (!pagino)
>  		pagino = be32_to_cpu(agi->agi_newino);
>  
> -	cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_FINO);
> +	cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, NULL, XFS_BTNUM_FINO);
>  
>  	error = xfs_check_agi_freecount(cur, agi);
>  	if (error)
> @@ -1641,7 +1641,7 @@ xfs_dialloc_ag(
>  	 * the original freecount. If all is well, make the equivalent update to
>  	 * the inobt using the finobt record and offset information.
>  	 */
> -	icur = xfs_inobt_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_INO);
> +	icur = xfs_inobt_init_cursor(mp, tp, agbp, agno, NULL, XFS_BTNUM_INO);
>  
>  	error = xfs_check_agi_freecount(icur, agi);
>  	if (error)
> @@ -1954,7 +1954,7 @@ xfs_difree_inobt(
>  	/*
>  	 * Initialize the cursor.
>  	 */
> -	cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_INO);
> +	cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, NULL, XFS_BTNUM_INO);
>  
>  	error = xfs_check_agi_freecount(cur, agi);
>  	if (error)
> @@ -2080,7 +2080,7 @@ xfs_difree_finobt(
>  	int				error;
>  	int				i;
>  
> -	cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_FINO);
> +	cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, NULL, XFS_BTNUM_FINO);
>  
>  	error = xfs_inobt_lookup(cur, ibtrec->ir_startino, XFS_LOOKUP_EQ, &i);
>  	if (error)
> @@ -2281,7 +2281,7 @@ xfs_imap_lookup(
>  	 * we have a record, we need to ensure it contains the inode number
>  	 * we are looking up.
>  	 */
> -	cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_INO);
> +	cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, NULL, XFS_BTNUM_INO);
>  	error = xfs_inobt_lookup(cur, agino, XFS_LOOKUP_LE, &i);
>  	if (!error) {
>  		if (i)
> diff --git a/fs/xfs/libxfs/xfs_ialloc_btree.c b/fs/xfs/libxfs/xfs_ialloc_btree.c
> index 4ec8ea1331a5..6c4efdf01674 100644
> --- a/fs/xfs/libxfs/xfs_ialloc_btree.c
> +++ b/fs/xfs/libxfs/xfs_ialloc_btree.c
> @@ -36,7 +36,7 @@ xfs_inobt_dup_cursor(
>  {
>  	return xfs_inobt_init_cursor(cur->bc_mp, cur->bc_tp,
>  			cur->bc_ag.agbp, cur->bc_ag.agno,
> -			cur->bc_btnum);
> +			cur->bc_ag.pag, cur->bc_btnum);
>  }
>  
>  STATIC void
> @@ -429,6 +429,7 @@ xfs_inobt_init_common(
>  	struct xfs_mount	*mp,		/* file system mount point */
>  	struct xfs_trans	*tp,		/* transaction pointer */
>  	xfs_agnumber_t		agno,		/* allocation group number */
> +	struct xfs_perag	*pag,
>  	xfs_btnum_t		btnum)		/* ialloc or free ino btree */
>  {
>  	struct xfs_btree_cur	*cur;
> @@ -451,6 +452,11 @@ xfs_inobt_init_common(
>  		cur->bc_flags |= XFS_BTREE_CRC_BLOCKS;
>  
>  	cur->bc_ag.agno = agno;
> +	if (pag) {
> +		/* take a reference for the cursor */
> +		atomic_inc(&pag->pag_ref);
> +	}
> +	cur->bc_ag.pag = pag;
>  	return cur;
>  }
>  
> @@ -461,12 +467,13 @@ xfs_inobt_init_cursor(
>  	struct xfs_trans	*tp,
>  	struct xfs_buf		*agbp,
>  	xfs_agnumber_t		agno,
> +	struct xfs_perag	*pag,
>  	xfs_btnum_t		btnum)
>  {
>  	struct xfs_btree_cur	*cur;
>  	struct xfs_agi		*agi = agbp->b_addr;
>  
> -	cur = xfs_inobt_init_common(mp, tp, agno, btnum);
> +	cur = xfs_inobt_init_common(mp, tp, agno, pag, btnum);
>  	if (btnum == XFS_BTNUM_INO)
>  		cur->bc_nlevels = be32_to_cpu(agi->agi_level);
>  	else
> @@ -485,7 +492,7 @@ xfs_inobt_stage_cursor(
>  {
>  	struct xfs_btree_cur	*cur;
>  
> -	cur = xfs_inobt_init_common(mp, NULL, agno, btnum);
> +	cur = xfs_inobt_init_common(mp, NULL, agno, NULL, btnum);
>  	xfs_btree_stage_afakeroot(cur, afake);
>  	return cur;
>  }
> @@ -672,7 +679,7 @@ xfs_inobt_cur(
>  	if (error)
>  		return error;
>  
> -	cur = xfs_inobt_init_cursor(mp, tp, *agi_bpp, agno, which);
> +	cur = xfs_inobt_init_cursor(mp, tp, *agi_bpp, agno, NULL, which);
>  	*curpp = cur;
>  	return 0;
>  }
> diff --git a/fs/xfs/libxfs/xfs_ialloc_btree.h b/fs/xfs/libxfs/xfs_ialloc_btree.h
> index d5afe01fb2de..04dfa7eee81f 100644
> --- a/fs/xfs/libxfs/xfs_ialloc_btree.h
> +++ b/fs/xfs/libxfs/xfs_ialloc_btree.h
> @@ -13,6 +13,7 @@
>  struct xfs_buf;
>  struct xfs_btree_cur;
>  struct xfs_mount;
> +struct xfs_perag;
>  
>  /*
>   * Btree block header size depends on a superblock flag.
> @@ -45,9 +46,9 @@ struct xfs_mount;
>  		 (maxrecs) * sizeof(xfs_inobt_key_t) + \
>  		 ((index) - 1) * sizeof(xfs_inobt_ptr_t)))
>  
> -extern struct xfs_btree_cur *xfs_inobt_init_cursor(struct xfs_mount *,
> -		struct xfs_trans *, struct xfs_buf *, xfs_agnumber_t,
> -		xfs_btnum_t);
> +extern struct xfs_btree_cur *xfs_inobt_init_cursor(struct xfs_mount *mp,
> +		struct xfs_trans *tp, struct xfs_buf *agbp, xfs_agnumber_t agno,
> +		struct xfs_perag *pag, xfs_btnum_t btnum);
>  struct xfs_btree_cur *xfs_inobt_stage_cursor(struct xfs_mount *mp,
>  		struct xbtree_afakeroot *afake, xfs_agnumber_t agno,
>  		xfs_btnum_t btnum);
> diff --git a/fs/xfs/libxfs/xfs_refcount.c b/fs/xfs/libxfs/xfs_refcount.c
> index 2037b9f23069..1c2bd2949d7d 100644
> --- a/fs/xfs/libxfs/xfs_refcount.c
> +++ b/fs/xfs/libxfs/xfs_refcount.c
> @@ -1178,7 +1178,7 @@ xfs_refcount_finish_one(
>  		if (error)
>  			return error;
>  
> -		rcur = xfs_refcountbt_init_cursor(mp, tp, agbp, agno);
> +		rcur = xfs_refcountbt_init_cursor(mp, tp, agbp, agno, NULL);
>  		rcur->bc_ag.refc.nr_ops = nr_ops;
>  		rcur->bc_ag.refc.shape_changes = shape_changes;
>  	}
> @@ -1707,7 +1707,7 @@ xfs_refcount_recover_cow_leftovers(
>  	error = xfs_alloc_read_agf(mp, tp, agno, 0, &agbp);
>  	if (error)
>  		goto out_trans;
> -	cur = xfs_refcountbt_init_cursor(mp, tp, agbp, agno);
> +	cur = xfs_refcountbt_init_cursor(mp, tp, agbp, agno, NULL);
>  
>  	/* Find all the leftover CoW staging extents. */
>  	memset(&low, 0, sizeof(low));
> diff --git a/fs/xfs/libxfs/xfs_refcount_btree.c b/fs/xfs/libxfs/xfs_refcount_btree.c
> index c4ddf9ded00b..74f8ac0209f1 100644
> --- a/fs/xfs/libxfs/xfs_refcount_btree.c
> +++ b/fs/xfs/libxfs/xfs_refcount_btree.c
> @@ -26,7 +26,7 @@ xfs_refcountbt_dup_cursor(
>  	struct xfs_btree_cur	*cur)
>  {
>  	return xfs_refcountbt_init_cursor(cur->bc_mp, cur->bc_tp,
> -			cur->bc_ag.agbp, cur->bc_ag.agno);
> +			cur->bc_ag.agbp, cur->bc_ag.agno, cur->bc_ag.pag);
>  }
>  
>  STATIC void
> @@ -316,7 +316,8 @@ static struct xfs_btree_cur *
>  xfs_refcountbt_init_common(
>  	struct xfs_mount	*mp,
>  	struct xfs_trans	*tp,
> -	xfs_agnumber_t		agno)
> +	xfs_agnumber_t		agno,
> +	struct xfs_perag	*pag)
>  {
>  	struct xfs_btree_cur	*cur;
>  
> @@ -332,6 +333,11 @@ xfs_refcountbt_init_common(
>  
>  	cur->bc_ag.agno = agno;
>  	cur->bc_flags |= XFS_BTREE_CRC_BLOCKS;
> +	if (pag) {
> +		/* take a reference for the cursor */
> +		atomic_inc(&pag->pag_ref);
> +	}
> +	cur->bc_ag.pag = pag;
>  
>  	cur->bc_ag.refc.nr_ops = 0;
>  	cur->bc_ag.refc.shape_changes = 0;
> @@ -345,12 +351,13 @@ xfs_refcountbt_init_cursor(
>  	struct xfs_mount	*mp,
>  	struct xfs_trans	*tp,
>  	struct xfs_buf		*agbp,
> -	xfs_agnumber_t		agno)
> +	xfs_agnumber_t		agno,
> +	struct xfs_perag	*pag)
>  {
>  	struct xfs_agf		*agf = agbp->b_addr;
>  	struct xfs_btree_cur	*cur;
>  
> -	cur = xfs_refcountbt_init_common(mp, tp, agno);
> +	cur = xfs_refcountbt_init_common(mp, tp, agno, pag);
>  	cur->bc_nlevels = be32_to_cpu(agf->agf_refcount_level);
>  	cur->bc_ag.agbp = agbp;
>  	return cur;
> @@ -365,7 +372,7 @@ xfs_refcountbt_stage_cursor(
>  {
>  	struct xfs_btree_cur	*cur;
>  
> -	cur = xfs_refcountbt_init_common(mp, NULL, agno);
> +	cur = xfs_refcountbt_init_common(mp, NULL, agno, NULL);
>  	xfs_btree_stage_afakeroot(cur, afake);
>  	return cur;
>  }
> diff --git a/fs/xfs/libxfs/xfs_refcount_btree.h b/fs/xfs/libxfs/xfs_refcount_btree.h
> index eab1b0c672c0..8b82a39f104a 100644
> --- a/fs/xfs/libxfs/xfs_refcount_btree.h
> +++ b/fs/xfs/libxfs/xfs_refcount_btree.h
> @@ -47,7 +47,7 @@ struct xbtree_afakeroot;
>  
>  extern struct xfs_btree_cur *xfs_refcountbt_init_cursor(struct xfs_mount *mp,
>  		struct xfs_trans *tp, struct xfs_buf *agbp,
> -		xfs_agnumber_t agno);
> +		xfs_agnumber_t agno, struct xfs_perag *pag);
>  struct xfs_btree_cur *xfs_refcountbt_stage_cursor(struct xfs_mount *mp,
>  		struct xbtree_afakeroot *afake, xfs_agnumber_t agno);
>  extern int xfs_refcountbt_maxrecs(int blocklen, bool leaf);
> diff --git a/fs/xfs/libxfs/xfs_rmap.c b/fs/xfs/libxfs/xfs_rmap.c
> index 1d0a6b686eea..0d7a6997120c 100644
> --- a/fs/xfs/libxfs/xfs_rmap.c
> +++ b/fs/xfs/libxfs/xfs_rmap.c
> @@ -708,7 +708,7 @@ xfs_rmap_free(
>  	if (!xfs_sb_version_hasrmapbt(&mp->m_sb))
>  		return 0;
>  
> -	cur = xfs_rmapbt_init_cursor(mp, tp, agbp, agno);
> +	cur = xfs_rmapbt_init_cursor(mp, tp, agbp, agno, NULL);
>  
>  	error = xfs_rmap_unmap(cur, bno, len, false, oinfo);
>  
> @@ -962,7 +962,7 @@ xfs_rmap_alloc(
>  	if (!xfs_sb_version_hasrmapbt(&mp->m_sb))
>  		return 0;
>  
> -	cur = xfs_rmapbt_init_cursor(mp, tp, agbp, agno);
> +	cur = xfs_rmapbt_init_cursor(mp, tp, agbp, agno, NULL);
>  	error = xfs_rmap_map(cur, bno, len, false, oinfo);
>  
>  	xfs_btree_del_cursor(cur, error);
> @@ -2408,7 +2408,7 @@ xfs_rmap_finish_one(
>  			goto out_drop;
>  		}
>  
> -		rcur = xfs_rmapbt_init_cursor(mp, tp, agbp, pag->pag_agno);
> +		rcur = xfs_rmapbt_init_cursor(mp, tp, agbp, pag->pag_agno, pag);
>  	}
>  	*pcur = rcur;
>  
> diff --git a/fs/xfs/libxfs/xfs_rmap_btree.c b/fs/xfs/libxfs/xfs_rmap_btree.c
> index ba2f7064451b..7bef8feeded1 100644
> --- a/fs/xfs/libxfs/xfs_rmap_btree.c
> +++ b/fs/xfs/libxfs/xfs_rmap_btree.c
> @@ -52,7 +52,7 @@ xfs_rmapbt_dup_cursor(
>  	struct xfs_btree_cur	*cur)
>  {
>  	return xfs_rmapbt_init_cursor(cur->bc_mp, cur->bc_tp,
> -			cur->bc_ag.agbp, cur->bc_ag.agno);
> +			cur->bc_ag.agbp, cur->bc_ag.agno, cur->bc_ag.pag);
>  }
>  
>  STATIC void
> @@ -449,7 +449,8 @@ static struct xfs_btree_cur *
>  xfs_rmapbt_init_common(
>  	struct xfs_mount	*mp,
>  	struct xfs_trans	*tp,
> -	xfs_agnumber_t		agno)
> +	xfs_agnumber_t		agno,
> +	struct xfs_perag	*pag)
>  {
>  	struct xfs_btree_cur	*cur;
>  
> @@ -463,6 +464,11 @@ xfs_rmapbt_init_common(
>  	cur->bc_statoff = XFS_STATS_CALC_INDEX(xs_rmap_2);
>  	cur->bc_ag.agno = agno;
>  	cur->bc_ops = &xfs_rmapbt_ops;
> +	if (pag) {
> +		/* take a reference for the cursor */
> +		atomic_inc(&pag->pag_ref);
> +	}
> +	cur->bc_ag.pag = pag;
>  
>  	return cur;
>  }
> @@ -473,12 +479,13 @@ xfs_rmapbt_init_cursor(
>  	struct xfs_mount	*mp,
>  	struct xfs_trans	*tp,
>  	struct xfs_buf		*agbp,
> -	xfs_agnumber_t		agno)
> +	xfs_agnumber_t		agno,
> +	struct xfs_perag	*pag)
>  {
>  	struct xfs_agf		*agf = agbp->b_addr;
>  	struct xfs_btree_cur	*cur;
>  
> -	cur = xfs_rmapbt_init_common(mp, tp, agno);
> +	cur = xfs_rmapbt_init_common(mp, tp, agno, pag);
>  	cur->bc_nlevels = be32_to_cpu(agf->agf_levels[XFS_BTNUM_RMAP]);
>  	cur->bc_ag.agbp = agbp;
>  	return cur;
> @@ -493,7 +500,7 @@ xfs_rmapbt_stage_cursor(
>  {
>  	struct xfs_btree_cur	*cur;
>  
> -	cur = xfs_rmapbt_init_common(mp, NULL, agno);
> +	cur = xfs_rmapbt_init_common(mp, NULL, agno, NULL);
>  	xfs_btree_stage_afakeroot(cur, afake);
>  	return cur;
>  }
> diff --git a/fs/xfs/libxfs/xfs_rmap_btree.h b/fs/xfs/libxfs/xfs_rmap_btree.h
> index 57fab72e26ad..c94f418cc06b 100644
> --- a/fs/xfs/libxfs/xfs_rmap_btree.h
> +++ b/fs/xfs/libxfs/xfs_rmap_btree.h
> @@ -43,7 +43,7 @@ struct xbtree_afakeroot;
>  
>  struct xfs_btree_cur *xfs_rmapbt_init_cursor(struct xfs_mount *mp,
>  				struct xfs_trans *tp, struct xfs_buf *bp,
> -				xfs_agnumber_t agno);
> +				xfs_agnumber_t agno, struct xfs_perag *pag);
>  struct xfs_btree_cur *xfs_rmapbt_stage_cursor(struct xfs_mount *mp,
>  		struct xbtree_afakeroot *afake, xfs_agnumber_t agno);
>  void xfs_rmapbt_commit_staged_btree(struct xfs_btree_cur *cur,
> diff --git a/fs/xfs/scrub/agheader_repair.c b/fs/xfs/scrub/agheader_repair.c
> index 1cdfbd57f36b..5dd91bf04c18 100644
> --- a/fs/xfs/scrub/agheader_repair.c
> +++ b/fs/xfs/scrub/agheader_repair.c
> @@ -247,7 +247,7 @@ xrep_agf_calc_from_btrees(
>  
>  	/* Update the AGF counters from the bnobt. */
>  	cur = xfs_allocbt_init_cursor(mp, sc->tp, agf_bp, sc->sa.agno,
> -			XFS_BTNUM_BNO);
> +			sc->sa.pag, XFS_BTNUM_BNO);
>  	error = xfs_alloc_query_all(cur, xrep_agf_walk_allocbt, &raa);
>  	if (error)
>  		goto err;
> @@ -261,7 +261,7 @@ xrep_agf_calc_from_btrees(
>  
>  	/* Update the AGF counters from the cntbt. */
>  	cur = xfs_allocbt_init_cursor(mp, sc->tp, agf_bp, sc->sa.agno,
> -			XFS_BTNUM_CNT);
> +			sc->sa.pag, XFS_BTNUM_CNT);
>  	error = xfs_btree_count_blocks(cur, &blocks);
>  	if (error)
>  		goto err;
> @@ -269,7 +269,8 @@ xrep_agf_calc_from_btrees(
>  	btreeblks += blocks - 1;
>  
>  	/* Update the AGF counters from the rmapbt. */
> -	cur = xfs_rmapbt_init_cursor(mp, sc->tp, agf_bp, sc->sa.agno);
> +	cur = xfs_rmapbt_init_cursor(mp, sc->tp, agf_bp, sc->sa.agno,
> +			sc->sa.pag);
>  	error = xfs_btree_count_blocks(cur, &blocks);
>  	if (error)
>  		goto err;
> @@ -282,7 +283,7 @@ xrep_agf_calc_from_btrees(
>  	/* Update the AGF counters from the refcountbt. */
>  	if (xfs_sb_version_hasreflink(&mp->m_sb)) {
>  		cur = xfs_refcountbt_init_cursor(mp, sc->tp, agf_bp,
> -				sc->sa.agno);
> +				sc->sa.agno, sc->sa.pag);
>  		error = xfs_btree_count_blocks(cur, &blocks);
>  		if (error)
>  			goto err;
> @@ -490,7 +491,8 @@ xrep_agfl_collect_blocks(
>  	xbitmap_init(&ra.agmetablocks);
>  
>  	/* Find all space used by the free space btrees & rmapbt. */
> -	cur = xfs_rmapbt_init_cursor(mp, sc->tp, agf_bp, sc->sa.agno);
> +	cur = xfs_rmapbt_init_cursor(mp, sc->tp, agf_bp, sc->sa.agno,
> +			sc->sa.pag);
>  	error = xfs_rmap_query_all(cur, xrep_agfl_walk_rmap, &ra);
>  	if (error)
>  		goto err;
> @@ -498,7 +500,7 @@ xrep_agfl_collect_blocks(
>  
>  	/* Find all blocks currently being used by the bnobt. */
>  	cur = xfs_allocbt_init_cursor(mp, sc->tp, agf_bp, sc->sa.agno,
> -			XFS_BTNUM_BNO);
> +			sc->sa.pag, XFS_BTNUM_BNO);
>  	error = xbitmap_set_btblocks(&ra.agmetablocks, cur);
>  	if (error)
>  		goto err;
> @@ -506,7 +508,7 @@ xrep_agfl_collect_blocks(
>  
>  	/* Find all blocks currently being used by the cntbt. */
>  	cur = xfs_allocbt_init_cursor(mp, sc->tp, agf_bp, sc->sa.agno,
> -			XFS_BTNUM_CNT);
> +			sc->sa.pag, XFS_BTNUM_CNT);
>  	error = xbitmap_set_btblocks(&ra.agmetablocks, cur);
>  	if (error)
>  		goto err;
> @@ -807,7 +809,7 @@ xrep_agi_calc_from_btrees(
>  	int			error;
>  
>  	cur = xfs_inobt_init_cursor(mp, sc->tp, agi_bp, sc->sa.agno,
> -			XFS_BTNUM_INO);
> +			sc->sa.pag, XFS_BTNUM_INO);
>  	error = xfs_ialloc_count_inodes(cur, &count, &freecount);
>  	if (error)
>  		goto err;
> @@ -829,7 +831,7 @@ xrep_agi_calc_from_btrees(
>  		xfs_agblock_t	blocks;
>  
>  		cur = xfs_inobt_init_cursor(mp, sc->tp, agi_bp, sc->sa.agno,
> -				XFS_BTNUM_FINO);
> +				sc->sa.pag, XFS_BTNUM_FINO);
>  		error = xfs_btree_count_blocks(cur, &blocks);
>  		if (error)
>  			goto err;
> diff --git a/fs/xfs/scrub/bmap.c b/fs/xfs/scrub/bmap.c
> index c60a1990d629..a792d9ffd61e 100644
> --- a/fs/xfs/scrub/bmap.c
> +++ b/fs/xfs/scrub/bmap.c
> @@ -556,7 +556,7 @@ xchk_bmap_check_ag_rmaps(
>  	if (error)
>  		return error;
>  
> -	cur = xfs_rmapbt_init_cursor(sc->mp, sc->tp, agf, agno);
> +	cur = xfs_rmapbt_init_cursor(sc->mp, sc->tp, agf, agno, NULL);
>  
>  	sbcri.sc = sc;
>  	sbcri.whichfork = whichfork;
> diff --git a/fs/xfs/scrub/common.c b/fs/xfs/scrub/common.c
> index c8da976b50fc..50768559fb60 100644
> --- a/fs/xfs/scrub/common.c
> +++ b/fs/xfs/scrub/common.c
> @@ -465,42 +465,42 @@ xchk_ag_btcur_init(
>  	    xchk_ag_btree_healthy_enough(sc, sa->pag, XFS_BTNUM_BNO)) {
>  		/* Set up a bnobt cursor for cross-referencing. */
>  		sa->bno_cur = xfs_allocbt_init_cursor(mp, sc->tp, sa->agf_bp,
> -				agno, XFS_BTNUM_BNO);
> +				agno, sa->pag, XFS_BTNUM_BNO);
>  	}
>  
>  	if (sa->agf_bp &&
>  	    xchk_ag_btree_healthy_enough(sc, sa->pag, XFS_BTNUM_CNT)) {
>  		/* Set up a cntbt cursor for cross-referencing. */
>  		sa->cnt_cur = xfs_allocbt_init_cursor(mp, sc->tp, sa->agf_bp,
> -				agno, XFS_BTNUM_CNT);
> +				agno, sa->pag, XFS_BTNUM_CNT);
>  	}
>  
>  	/* Set up a inobt cursor for cross-referencing. */
>  	if (sa->agi_bp &&
>  	    xchk_ag_btree_healthy_enough(sc, sa->pag, XFS_BTNUM_INO)) {
>  		sa->ino_cur = xfs_inobt_init_cursor(mp, sc->tp, sa->agi_bp,
> -					agno, XFS_BTNUM_INO);
> +				agno, sa->pag, XFS_BTNUM_INO);
>  	}
>  
>  	/* Set up a finobt cursor for cross-referencing. */
>  	if (sa->agi_bp && xfs_sb_version_hasfinobt(&mp->m_sb) &&
>  	    xchk_ag_btree_healthy_enough(sc, sa->pag, XFS_BTNUM_FINO)) {
>  		sa->fino_cur = xfs_inobt_init_cursor(mp, sc->tp, sa->agi_bp,
> -				agno, XFS_BTNUM_FINO);
> +				agno, sa->pag, XFS_BTNUM_FINO);
>  	}
>  
>  	/* Set up a rmapbt cursor for cross-referencing. */
>  	if (sa->agf_bp && xfs_sb_version_hasrmapbt(&mp->m_sb) &&
>  	    xchk_ag_btree_healthy_enough(sc, sa->pag, XFS_BTNUM_RMAP)) {
>  		sa->rmap_cur = xfs_rmapbt_init_cursor(mp, sc->tp, sa->agf_bp,
> -				agno);
> +				agno, sa->pag);
>  	}
>  
>  	/* Set up a refcountbt cursor for cross-referencing. */
>  	if (sa->agf_bp && xfs_sb_version_hasreflink(&mp->m_sb) &&
>  	    xchk_ag_btree_healthy_enough(sc, sa->pag, XFS_BTNUM_REFC)) {
>  		sa->refc_cur = xfs_refcountbt_init_cursor(mp, sc->tp,
> -				sa->agf_bp, agno);
> +				sa->agf_bp, agno, sa->pag);
>  	}
>  }
>  
> diff --git a/fs/xfs/scrub/repair.c b/fs/xfs/scrub/repair.c
> index 6b62872c4d10..862dc56fd8cd 100644
> --- a/fs/xfs/scrub/repair.c
> +++ b/fs/xfs/scrub/repair.c
> @@ -555,7 +555,7 @@ xrep_reap_block(
>  	} else {
>  		agf_bp = sc->sa.agf_bp;
>  	}
> -	cur = xfs_rmapbt_init_cursor(sc->mp, sc->tp, agf_bp, agno);
> +	cur = xfs_rmapbt_init_cursor(sc->mp, sc->tp, agf_bp, agno, sc->sa.pag);
>  
>  	/* Can we find any other rmappings? */
>  	error = xfs_rmap_has_other_keys(cur, agbno, 1, oinfo, &has_other_rmap);
> @@ -892,7 +892,8 @@ xrep_find_ag_btree_roots(
>  		fab->height = 0;
>  	}
>  
> -	cur = xfs_rmapbt_init_cursor(mp, sc->tp, agf_bp, sc->sa.agno);
> +	cur = xfs_rmapbt_init_cursor(mp, sc->tp, agf_bp, sc->sa.agno,
> +			sc->sa.pag);
>  	error = xfs_rmap_query_all(cur, xrep_findroot_rmap, &ri);
>  	xfs_btree_del_cursor(cur, error);
>  
> diff --git a/fs/xfs/xfs_discard.c b/fs/xfs/xfs_discard.c
> index 972864250bd2..311ebaad4f5a 100644
> --- a/fs/xfs/xfs_discard.c
> +++ b/fs/xfs/xfs_discard.c
> @@ -50,7 +50,7 @@ xfs_trim_extents(
>  		goto out_put_perag;
>  	agf = agbp->b_addr;
>  
> -	cur = xfs_allocbt_init_cursor(mp, NULL, agbp, agno, XFS_BTNUM_CNT);
> +	cur = xfs_allocbt_init_cursor(mp, NULL, agbp, agno, pag, XFS_BTNUM_CNT);
>  
>  	/*
>  	 * Look up the longest btree in the AGF and start with it.
> diff --git a/fs/xfs/xfs_fsmap.c b/fs/xfs/xfs_fsmap.c
> index 835dd6e3819b..b654a2bf9a9f 100644
> --- a/fs/xfs/xfs_fsmap.c
> +++ b/fs/xfs/xfs_fsmap.c
> @@ -211,7 +211,7 @@ xfs_getfsmap_is_shared(
>  	/* Are there any shared blocks here? */
>  	flen = 0;
>  	cur = xfs_refcountbt_init_cursor(mp, tp, info->agf_bp,
> -			info->pag->pag_agno);
> +			info->pag->pag_agno, info->pag);
>  
>  	error = xfs_refcount_find_shared(cur, rec->rm_startblock,
>  			rec->rm_blockcount, &fbno, &flen, false);
> @@ -708,7 +708,7 @@ xfs_getfsmap_datadev_rmapbt_query(
>  
>  	/* Allocate cursor for this AG and query_range it. */
>  	*curpp = xfs_rmapbt_init_cursor(tp->t_mountp, tp, info->agf_bp,
> -			info->pag->pag_agno);
> +			info->pag->pag_agno, info->pag);
>  	return xfs_rmap_query_range(*curpp, &info->low, &info->high,
>  			xfs_getfsmap_datadev_helper, info);
>  }
> @@ -741,7 +741,7 @@ xfs_getfsmap_datadev_bnobt_query(
>  
>  	/* Allocate cursor for this AG and query_range it. */
>  	*curpp = xfs_allocbt_init_cursor(tp->t_mountp, tp, info->agf_bp,
> -			info->pag->pag_agno, XFS_BTNUM_BNO);
> +			info->pag->pag_agno, info->pag, XFS_BTNUM_BNO);
>  	key->ar_startblock = info->low.rm_startblock;
>  	key[1].ar_startblock = info->high.rm_startblock;
>  	return xfs_alloc_query_range(*curpp, key, &key[1],
> diff --git a/fs/xfs/xfs_reflink.c b/fs/xfs/xfs_reflink.c
> index 0e430b0c1b16..28ffe1817f9b 100644
> --- a/fs/xfs/xfs_reflink.c
> +++ b/fs/xfs/xfs_reflink.c
> @@ -144,7 +144,7 @@ xfs_reflink_find_shared(
>  	if (error)
>  		return error;
>  
> -	cur = xfs_refcountbt_init_cursor(mp, tp, agbp, agno);
> +	cur = xfs_refcountbt_init_cursor(mp, tp, agbp, agno, NULL);
>  
>  	error = xfs_refcount_find_shared(cur, agbno, aglen, fbno, flen,
>  			find_end_of_shared);
> -- 
> 2.31.1
> 

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 11/22] xfs: add a perag to the btree cursor
  2021-05-12 12:49         ` Brian Foster
@ 2021-05-12 22:41           ` Darrick J. Wong
  0 siblings, 0 replies; 87+ messages in thread
From: Darrick J. Wong @ 2021-05-12 22:41 UTC (permalink / raw)
  To: Brian Foster; +Cc: Dave Chinner, linux-xfs

On Wed, May 12, 2021 at 08:49:28AM -0400, Brian Foster wrote:
> On Wed, May 12, 2021 at 07:52:50AM +1000, Dave Chinner wrote:
> > On Tue, May 11, 2021 at 01:51:52PM -0700, Darrick J. Wong wrote:
> > > On Tue, May 11, 2021 at 08:30:22AM -0400, Brian Foster wrote:
> > > > On Thu, May 06, 2021 at 05:20:43PM +1000, Dave Chinner wrote:
> > > > > From: Dave Chinner <dchinner@redhat.com>
> > > > > 
> > > > > Which will eventually completely replace the agno in it.
> > > > > 
> > > > > Signed-off-by: Dave Chinner <dchinner@redhat.com>
> > > > > ---
> > > > >  fs/xfs/libxfs/xfs_alloc.c          | 25 +++++++++++++++----------
> > > > >  fs/xfs/libxfs/xfs_alloc_btree.c    | 13 ++++++++++---
> > > > >  fs/xfs/libxfs/xfs_alloc_btree.h    |  3 ++-
> > > > >  fs/xfs/libxfs/xfs_btree.c          |  2 ++
> > > > >  fs/xfs/libxfs/xfs_btree.h          |  4 +++-
> > > > >  fs/xfs/libxfs/xfs_ialloc.c         | 16 ++++++++--------
> > > > >  fs/xfs/libxfs/xfs_ialloc_btree.c   | 15 +++++++++++----
> > > > >  fs/xfs/libxfs/xfs_ialloc_btree.h   |  7 ++++---
> > > > >  fs/xfs/libxfs/xfs_refcount.c       |  4 ++--
> > > > >  fs/xfs/libxfs/xfs_refcount_btree.c | 17 ++++++++++++-----
> > > > >  fs/xfs/libxfs/xfs_refcount_btree.h |  2 +-
> > > > >  fs/xfs/libxfs/xfs_rmap.c           |  6 +++---
> > > > >  fs/xfs/libxfs/xfs_rmap_btree.c     | 17 ++++++++++++-----
> > > > >  fs/xfs/libxfs/xfs_rmap_btree.h     |  2 +-
> > > > >  fs/xfs/scrub/agheader_repair.c     | 20 +++++++++++---------
> > > > >  fs/xfs/scrub/bmap.c                |  2 +-
> > > > >  fs/xfs/scrub/common.c              | 12 ++++++------
> > > > >  fs/xfs/scrub/repair.c              |  5 +++--
> > > > >  fs/xfs/xfs_discard.c               |  2 +-
> > > > >  fs/xfs/xfs_fsmap.c                 |  6 +++---
> > > > >  fs/xfs/xfs_reflink.c               |  2 +-
> > > > >  21 files changed, 112 insertions(+), 70 deletions(-)
> > > > > 
> > > > ...
> > > > > diff --git a/fs/xfs/libxfs/xfs_btree.c b/fs/xfs/libxfs/xfs_btree.c
> > > > > index 0f12b885600d..44044317c0fb 100644
> > > > > --- a/fs/xfs/libxfs/xfs_btree.c
> > > > > +++ b/fs/xfs/libxfs/xfs_btree.c
> > > > > @@ -377,6 +377,8 @@ xfs_btree_del_cursor(
> > > > >  	       XFS_FORCED_SHUTDOWN(cur->bc_mp));
> > > > >  	if (unlikely(cur->bc_flags & XFS_BTREE_STAGING))
> > > > >  		kmem_free(cur->bc_ops);
> > > > > +	if (!(cur->bc_flags & XFS_BTREE_LONG_PTRS) && cur->bc_ag.pag)
> > > > > +		xfs_perag_put(cur->bc_ag.pag);
> > > > 
> > > > What's the correlation with BTREE_LONG_PTRS?
> > 
> > Only the btrees that index agbnos within a specific AG use the
> > cur->bc_ag structure to store the agno the btree is rooted in.
> > These are all btrees that use short pointers.
> > 
> > IOWs, we need an agno to turn the agbno into a full fsbno, daddr,
> > inum or anything else with global scope. Translation of short
> > pointers to physical location is necessary just to walk the tree,
> > while long pointer trees already record physical location of the
> > blocks within the tree and hence do not need an agno for
> > translation.
> > 
> > Hence needing the agno is specific, at this point in
> > time, to a btree containing short pointers.
> > 
> > > maybe this should be:
> > > 
> > > 	if (!(cur->bc_flags & XFS_BTREE_ROOT_IN_INODE))
> > > 		xfs_perag_put(cur->bc_ag.pag);
> > 
> > Given that the only long pointer btree we have is also the only
> > btree we have rooted in an inode, this is just another way of saying
> > !BTREE_LONG_PTRS. But "root in inode" is less obvious, because then we
> > lose the context taht "short pointers need translation via agno to
> > calculate their physical location in the wider filesystem"...

Ok.  Can you add a comment to xfs_btree.h somewhere noting that
LONG_PTRS is what we use to switch betwen bc_ag and bc_ino, please?

--D

> > 
> 
> Got it, thanks. The bc_ag field is unioned with bc_ino, the latter of
> which is used by XFS_BTREE_ROOT_IN_INODE trees to track inode
> information rather than AG information. I think the flag usage just
> threw me off at a glance. With that cleared up:
> 
> Reviewed-by: Brian Foster <bfoster@redhat.com>
> 
> > If we are going to put short ptrs in an inode, then at that point
> > we need to change the btree cursor, anyway, because then we are
> > going to need both an inode pointer and something else to turn those
> > short pointers into global scope pointers for IO....
> > 
> > Cheers,
> > 
> > Dave.
> > -- 
> > Dave Chinner
> > david@fromorbit.com
> > 
> 

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 12/22] xfs: convert rmap btree cursor to using a perag
  2021-05-06  7:20 ` [PATCH 12/22] xfs: convert rmap btree cursor to using a perag Dave Chinner
  2021-05-11 12:30   ` Brian Foster
@ 2021-05-12 22:45   ` Darrick J. Wong
  2021-05-13  3:54     ` Darrick J. Wong
  1 sibling, 1 reply; 87+ messages in thread
From: Darrick J. Wong @ 2021-05-12 22:45 UTC (permalink / raw)
  To: Dave Chinner; +Cc: linux-xfs

On Thu, May 06, 2021 at 05:20:44PM +1000, Dave Chinner wrote:
> From: Dave Chinner <dchinner@redhat.com>
> 
> Signed-off-by: Dave Chinner <dchinner@redhat.com>
> ---
>  fs/xfs/libxfs/xfs_ag.c         |  2 +-
>  fs/xfs/libxfs/xfs_alloc.c      |  7 ++++---
>  fs/xfs/libxfs/xfs_rmap.c       | 10 ++++-----
>  fs/xfs/libxfs/xfs_rmap.h       |  6 ++++--
>  fs/xfs/libxfs/xfs_rmap_btree.c | 37 +++++++++++++++-------------------
>  fs/xfs/libxfs/xfs_rmap_btree.h |  4 ++--
>  fs/xfs/scrub/agheader_repair.c |  6 ++----
>  fs/xfs/scrub/bmap.c            |  2 +-
>  fs/xfs/scrub/common.c          |  2 +-
>  fs/xfs/scrub/repair.c          | 10 ++++-----
>  fs/xfs/xfs_fsmap.c             |  2 +-
>  11 files changed, 42 insertions(+), 46 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_ag.c b/fs/xfs/libxfs/xfs_ag.c
> index 14d8b866dc6d..44f2787f3556 100644
> --- a/fs/xfs/libxfs/xfs_ag.c
> +++ b/fs/xfs/libxfs/xfs_ag.c
> @@ -914,7 +914,7 @@ xfs_ag_extend_space(
>  	 * XFS_RMAP_OINFO_SKIP_UPDATE is used here to tell the rmap btree that
>  	 * this doesn't actually exist in the rmap btree.
>  	 */
> -	error = xfs_rmap_free(tp, bp, id->agno,
> +	error = xfs_rmap_free(tp, bp, bp->b_pag,

Same question here as in the last patch -- so long as we have to pass
the AGF buffer pointer into the xfs_rmap functions, why is it even
necessary to pass both the AGF and the perag when we could get the
second from the first?

I suspect I'm going to whine about this for the next three patches, but
the mechanical conversion looks correct to me.

--D

>  				be32_to_cpu(agf->agf_length) - len,
>  				len, &XFS_RMAP_OINFO_SKIP_UPDATE);
>  	if (error)
> diff --git a/fs/xfs/libxfs/xfs_alloc.c b/fs/xfs/libxfs/xfs_alloc.c
> index 7ec4af6bf494..10747cc4d8f6 100644
> --- a/fs/xfs/libxfs/xfs_alloc.c
> +++ b/fs/xfs/libxfs/xfs_alloc.c
> @@ -1092,7 +1092,7 @@ xfs_alloc_ag_vextent_small(
>  	 * If we're feeding an AGFL block to something that doesn't live in the
>  	 * free space, we need to clear out the OWN_AG rmap.
>  	 */
> -	error = xfs_rmap_free(args->tp, args->agbp, args->agno, fbno, 1,
> +	error = xfs_rmap_free(args->tp, args->agbp, args->pag, fbno, 1,
>  			      &XFS_RMAP_OINFO_AG);
>  	if (error)
>  		goto error;
> @@ -1169,7 +1169,7 @@ xfs_alloc_ag_vextent(
>  
>  	/* if not file data, insert new block into the reverse map btree */
>  	if (!xfs_rmap_should_skip_owner_update(&args->oinfo)) {
> -		error = xfs_rmap_alloc(args->tp, args->agbp, args->agno,
> +		error = xfs_rmap_alloc(args->tp, args->agbp, args->pag,
>  				       args->agbno, args->len, &args->oinfo);
>  		if (error)
>  			return error;
> @@ -1899,12 +1899,13 @@ xfs_free_ag_extent(
>  	int				haveright; /* have a right neighbor */
>  	int				i;
>  	int				error;
> +	struct xfs_perag		*pag = agbp->b_pag;
>  
>  	bno_cur = cnt_cur = NULL;
>  	mp = tp->t_mountp;
>  
>  	if (!xfs_rmap_should_skip_owner_update(oinfo)) {
> -		error = xfs_rmap_free(tp, agbp, agno, bno, len, oinfo);
> +		error = xfs_rmap_free(tp, agbp, pag, bno, len, oinfo);
>  		if (error)
>  			goto error0;
>  	}
> diff --git a/fs/xfs/libxfs/xfs_rmap.c b/fs/xfs/libxfs/xfs_rmap.c
> index 0d7a6997120c..b23f949ee15c 100644
> --- a/fs/xfs/libxfs/xfs_rmap.c
> +++ b/fs/xfs/libxfs/xfs_rmap.c
> @@ -696,7 +696,7 @@ int
>  xfs_rmap_free(
>  	struct xfs_trans		*tp,
>  	struct xfs_buf			*agbp,
> -	xfs_agnumber_t			agno,
> +	struct xfs_perag		*pag,
>  	xfs_agblock_t			bno,
>  	xfs_extlen_t			len,
>  	const struct xfs_owner_info	*oinfo)
> @@ -708,7 +708,7 @@ xfs_rmap_free(
>  	if (!xfs_sb_version_hasrmapbt(&mp->m_sb))
>  		return 0;
>  
> -	cur = xfs_rmapbt_init_cursor(mp, tp, agbp, agno, NULL);
> +	cur = xfs_rmapbt_init_cursor(mp, tp, agbp, pag);
>  
>  	error = xfs_rmap_unmap(cur, bno, len, false, oinfo);
>  
> @@ -950,7 +950,7 @@ int
>  xfs_rmap_alloc(
>  	struct xfs_trans		*tp,
>  	struct xfs_buf			*agbp,
> -	xfs_agnumber_t			agno,
> +	struct xfs_perag		*pag,
>  	xfs_agblock_t			bno,
>  	xfs_extlen_t			len,
>  	const struct xfs_owner_info	*oinfo)
> @@ -962,7 +962,7 @@ xfs_rmap_alloc(
>  	if (!xfs_sb_version_hasrmapbt(&mp->m_sb))
>  		return 0;
>  
> -	cur = xfs_rmapbt_init_cursor(mp, tp, agbp, agno, NULL);
> +	cur = xfs_rmapbt_init_cursor(mp, tp, agbp, pag);
>  	error = xfs_rmap_map(cur, bno, len, false, oinfo);
>  
>  	xfs_btree_del_cursor(cur, error);
> @@ -2408,7 +2408,7 @@ xfs_rmap_finish_one(
>  			goto out_drop;
>  		}
>  
> -		rcur = xfs_rmapbt_init_cursor(mp, tp, agbp, pag->pag_agno, pag);
> +		rcur = xfs_rmapbt_init_cursor(mp, tp, agbp, pag);
>  	}
>  	*pcur = rcur;
>  
> diff --git a/fs/xfs/libxfs/xfs_rmap.h b/fs/xfs/libxfs/xfs_rmap.h
> index abe633403fd1..f2423cf7f1e2 100644
> --- a/fs/xfs/libxfs/xfs_rmap.h
> +++ b/fs/xfs/libxfs/xfs_rmap.h
> @@ -6,6 +6,8 @@
>  #ifndef __XFS_RMAP_H__
>  #define __XFS_RMAP_H__
>  
> +struct xfs_perag;
> +
>  static inline void
>  xfs_rmap_ino_bmbt_owner(
>  	struct xfs_owner_info	*oi,
> @@ -113,10 +115,10 @@ xfs_owner_info_pack(
>  }
>  
>  int xfs_rmap_alloc(struct xfs_trans *tp, struct xfs_buf *agbp,
> -		   xfs_agnumber_t agno, xfs_agblock_t bno, xfs_extlen_t len,
> +		   struct xfs_perag *pag, xfs_agblock_t bno, xfs_extlen_t len,
>  		   const struct xfs_owner_info *oinfo);
>  int xfs_rmap_free(struct xfs_trans *tp, struct xfs_buf *agbp,
> -		  xfs_agnumber_t agno, xfs_agblock_t bno, xfs_extlen_t len,
> +		  struct xfs_perag *pag, xfs_agblock_t bno, xfs_extlen_t len,
>  		  const struct xfs_owner_info *oinfo);
>  
>  int xfs_rmap_lookup_le(struct xfs_btree_cur *cur, xfs_agblock_t bno,
> diff --git a/fs/xfs/libxfs/xfs_rmap_btree.c b/fs/xfs/libxfs/xfs_rmap_btree.c
> index 7bef8feeded1..cafe181bc92d 100644
> --- a/fs/xfs/libxfs/xfs_rmap_btree.c
> +++ b/fs/xfs/libxfs/xfs_rmap_btree.c
> @@ -52,7 +52,7 @@ xfs_rmapbt_dup_cursor(
>  	struct xfs_btree_cur	*cur)
>  {
>  	return xfs_rmapbt_init_cursor(cur->bc_mp, cur->bc_tp,
> -			cur->bc_ag.agbp, cur->bc_ag.agno, cur->bc_ag.pag);
> +				cur->bc_ag.agbp, cur->bc_ag.pag);
>  }
>  
>  STATIC void
> @@ -64,13 +64,12 @@ xfs_rmapbt_set_root(
>  	struct xfs_buf		*agbp = cur->bc_ag.agbp;
>  	struct xfs_agf		*agf = agbp->b_addr;
>  	int			btnum = cur->bc_btnum;
> -	struct xfs_perag	*pag = agbp->b_pag;
>  
>  	ASSERT(ptr->s != 0);
>  
>  	agf->agf_roots[btnum] = ptr->s;
>  	be32_add_cpu(&agf->agf_levels[btnum], inc);
> -	pag->pagf_levels[btnum] += inc;
> +	cur->bc_ag.pag->pagf_levels[btnum] += inc;
>  
>  	xfs_alloc_log_agf(cur->bc_tp, agbp, XFS_AGF_ROOTS | XFS_AGF_LEVELS);
>  }
> @@ -84,6 +83,7 @@ xfs_rmapbt_alloc_block(
>  {
>  	struct xfs_buf		*agbp = cur->bc_ag.agbp;
>  	struct xfs_agf		*agf = agbp->b_addr;
> +	struct xfs_perag	*pag = cur->bc_ag.pag;
>  	int			error;
>  	xfs_agblock_t		bno;
>  
> @@ -93,20 +93,19 @@ xfs_rmapbt_alloc_block(
>  	if (error)
>  		return error;
>  
> -	trace_xfs_rmapbt_alloc_block(cur->bc_mp, cur->bc_ag.agno,
> -			bno, 1);
> +	trace_xfs_rmapbt_alloc_block(cur->bc_mp, pag->pag_agno, bno, 1);
>  	if (bno == NULLAGBLOCK) {
>  		*stat = 0;
>  		return 0;
>  	}
>  
> -	xfs_extent_busy_reuse(cur->bc_mp, agbp->b_pag, bno, 1, false);
> +	xfs_extent_busy_reuse(cur->bc_mp, pag, bno, 1, false);
>  
>  	new->s = cpu_to_be32(bno);
>  	be32_add_cpu(&agf->agf_rmap_blocks, 1);
>  	xfs_alloc_log_agf(cur->bc_tp, agbp, XFS_AGF_RMAP_BLOCKS);
>  
> -	xfs_ag_resv_rmapbt_alloc(cur->bc_mp, cur->bc_ag.agno);
> +	xfs_ag_resv_rmapbt_alloc(cur->bc_mp, pag->pag_agno);
>  
>  	*stat = 1;
>  	return 0;
> @@ -119,12 +118,12 @@ xfs_rmapbt_free_block(
>  {
>  	struct xfs_buf		*agbp = cur->bc_ag.agbp;
>  	struct xfs_agf		*agf = agbp->b_addr;
> -	struct xfs_perag	*pag;
> +	struct xfs_perag	*pag = cur->bc_ag.pag;
>  	xfs_agblock_t		bno;
>  	int			error;
>  
>  	bno = xfs_daddr_to_agbno(cur->bc_mp, XFS_BUF_ADDR(bp));
> -	trace_xfs_rmapbt_free_block(cur->bc_mp, cur->bc_ag.agno,
> +	trace_xfs_rmapbt_free_block(cur->bc_mp, pag->pag_agno,
>  			bno, 1);
>  	be32_add_cpu(&agf->agf_rmap_blocks, -1);
>  	xfs_alloc_log_agf(cur->bc_tp, agbp, XFS_AGF_RMAP_BLOCKS);
> @@ -132,7 +131,6 @@ xfs_rmapbt_free_block(
>  	if (error)
>  		return error;
>  
> -	pag = cur->bc_ag.agbp->b_pag;
>  	xfs_extent_busy_insert(cur->bc_tp, pag, bno, 1,
>  			      XFS_EXTENT_BUSY_SKIP_DISCARD);
>  
> @@ -214,7 +212,7 @@ xfs_rmapbt_init_ptr_from_cur(
>  {
>  	struct xfs_agf		*agf = cur->bc_ag.agbp->b_addr;
>  
> -	ASSERT(cur->bc_ag.agno == be32_to_cpu(agf->agf_seqno));
> +	ASSERT(cur->bc_ag.pag->pag_agno == be32_to_cpu(agf->agf_seqno));
>  
>  	ptr->s = agf->agf_roots[cur->bc_btnum];
>  }
> @@ -449,7 +447,6 @@ static struct xfs_btree_cur *
>  xfs_rmapbt_init_common(
>  	struct xfs_mount	*mp,
>  	struct xfs_trans	*tp,
> -	xfs_agnumber_t		agno,
>  	struct xfs_perag	*pag)
>  {
>  	struct xfs_btree_cur	*cur;
> @@ -462,13 +459,12 @@ xfs_rmapbt_init_common(
>  	cur->bc_flags = XFS_BTREE_CRC_BLOCKS | XFS_BTREE_OVERLAPPING;
>  	cur->bc_blocklog = mp->m_sb.sb_blocklog;
>  	cur->bc_statoff = XFS_STATS_CALC_INDEX(xs_rmap_2);
> -	cur->bc_ag.agno = agno;
>  	cur->bc_ops = &xfs_rmapbt_ops;
> -	if (pag) {
> -		/* take a reference for the cursor */
> -		atomic_inc(&pag->pag_ref);
> -	}
> +
> +	/* take a reference for the cursor */
> +	atomic_inc(&pag->pag_ref);
>  	cur->bc_ag.pag = pag;
> +	cur->bc_ag.agno = pag->pag_agno;
>  
>  	return cur;
>  }
> @@ -479,13 +475,12 @@ xfs_rmapbt_init_cursor(
>  	struct xfs_mount	*mp,
>  	struct xfs_trans	*tp,
>  	struct xfs_buf		*agbp,
> -	xfs_agnumber_t		agno,
>  	struct xfs_perag	*pag)
>  {
>  	struct xfs_agf		*agf = agbp->b_addr;
>  	struct xfs_btree_cur	*cur;
>  
> -	cur = xfs_rmapbt_init_common(mp, tp, agno, pag);
> +	cur = xfs_rmapbt_init_common(mp, tp, pag);
>  	cur->bc_nlevels = be32_to_cpu(agf->agf_levels[XFS_BTNUM_RMAP]);
>  	cur->bc_ag.agbp = agbp;
>  	return cur;
> @@ -496,11 +491,11 @@ struct xfs_btree_cur *
>  xfs_rmapbt_stage_cursor(
>  	struct xfs_mount	*mp,
>  	struct xbtree_afakeroot	*afake,
> -	xfs_agnumber_t		agno)
> +	struct xfs_perag	*pag)
>  {
>  	struct xfs_btree_cur	*cur;
>  
> -	cur = xfs_rmapbt_init_common(mp, NULL, agno, NULL);
> +	cur = xfs_rmapbt_init_common(mp, NULL, pag);
>  	xfs_btree_stage_afakeroot(cur, afake);
>  	return cur;
>  }
> diff --git a/fs/xfs/libxfs/xfs_rmap_btree.h b/fs/xfs/libxfs/xfs_rmap_btree.h
> index c94f418cc06b..88d8d18788a2 100644
> --- a/fs/xfs/libxfs/xfs_rmap_btree.h
> +++ b/fs/xfs/libxfs/xfs_rmap_btree.h
> @@ -43,9 +43,9 @@ struct xbtree_afakeroot;
>  
>  struct xfs_btree_cur *xfs_rmapbt_init_cursor(struct xfs_mount *mp,
>  				struct xfs_trans *tp, struct xfs_buf *bp,
> -				xfs_agnumber_t agno, struct xfs_perag *pag);
> +				struct xfs_perag *pag);
>  struct xfs_btree_cur *xfs_rmapbt_stage_cursor(struct xfs_mount *mp,
> -		struct xbtree_afakeroot *afake, xfs_agnumber_t agno);
> +		struct xbtree_afakeroot *afake, struct xfs_perag *pag);
>  void xfs_rmapbt_commit_staged_btree(struct xfs_btree_cur *cur,
>  		struct xfs_trans *tp, struct xfs_buf *agbp);
>  int xfs_rmapbt_maxrecs(int blocklen, int leaf);
> diff --git a/fs/xfs/scrub/agheader_repair.c b/fs/xfs/scrub/agheader_repair.c
> index 5dd91bf04c18..981c689e3d95 100644
> --- a/fs/xfs/scrub/agheader_repair.c
> +++ b/fs/xfs/scrub/agheader_repair.c
> @@ -269,8 +269,7 @@ xrep_agf_calc_from_btrees(
>  	btreeblks += blocks - 1;
>  
>  	/* Update the AGF counters from the rmapbt. */
> -	cur = xfs_rmapbt_init_cursor(mp, sc->tp, agf_bp, sc->sa.agno,
> -			sc->sa.pag);
> +	cur = xfs_rmapbt_init_cursor(mp, sc->tp, agf_bp, sc->sa.pag);
>  	error = xfs_btree_count_blocks(cur, &blocks);
>  	if (error)
>  		goto err;
> @@ -491,8 +490,7 @@ xrep_agfl_collect_blocks(
>  	xbitmap_init(&ra.agmetablocks);
>  
>  	/* Find all space used by the free space btrees & rmapbt. */
> -	cur = xfs_rmapbt_init_cursor(mp, sc->tp, agf_bp, sc->sa.agno,
> -			sc->sa.pag);
> +	cur = xfs_rmapbt_init_cursor(mp, sc->tp, agf_bp, sc->sa.pag);
>  	error = xfs_rmap_query_all(cur, xrep_agfl_walk_rmap, &ra);
>  	if (error)
>  		goto err;
> diff --git a/fs/xfs/scrub/bmap.c b/fs/xfs/scrub/bmap.c
> index a792d9ffd61e..b20c3f03b3c5 100644
> --- a/fs/xfs/scrub/bmap.c
> +++ b/fs/xfs/scrub/bmap.c
> @@ -556,7 +556,7 @@ xchk_bmap_check_ag_rmaps(
>  	if (error)
>  		return error;
>  
> -	cur = xfs_rmapbt_init_cursor(sc->mp, sc->tp, agf, agno, NULL);
> +	cur = xfs_rmapbt_init_cursor(sc->mp, sc->tp, agf, sc->sa.pag);
>  
>  	sbcri.sc = sc;
>  	sbcri.whichfork = whichfork;
> diff --git a/fs/xfs/scrub/common.c b/fs/xfs/scrub/common.c
> index 50768559fb60..48381c1adeed 100644
> --- a/fs/xfs/scrub/common.c
> +++ b/fs/xfs/scrub/common.c
> @@ -493,7 +493,7 @@ xchk_ag_btcur_init(
>  	if (sa->agf_bp && xfs_sb_version_hasrmapbt(&mp->m_sb) &&
>  	    xchk_ag_btree_healthy_enough(sc, sa->pag, XFS_BTNUM_RMAP)) {
>  		sa->rmap_cur = xfs_rmapbt_init_cursor(mp, sc->tp, sa->agf_bp,
> -				agno, sa->pag);
> +				sa->pag);
>  	}
>  
>  	/* Set up a refcountbt cursor for cross-referencing. */
> diff --git a/fs/xfs/scrub/repair.c b/fs/xfs/scrub/repair.c
> index 862dc56fd8cd..5cf1c3707b6a 100644
> --- a/fs/xfs/scrub/repair.c
> +++ b/fs/xfs/scrub/repair.c
> @@ -509,7 +509,7 @@ xrep_put_freelist(
>  	 * create an rmap for the block prior to merging it or else other
>  	 * parts will break.
>  	 */
> -	error = xfs_rmap_alloc(sc->tp, sc->sa.agf_bp, sc->sa.agno, agbno, 1,
> +	error = xfs_rmap_alloc(sc->tp, sc->sa.agf_bp, sc->sa.pag, agbno, 1,
>  			&XFS_RMAP_OINFO_AG);
>  	if (error)
>  		return error;
> @@ -555,7 +555,7 @@ xrep_reap_block(
>  	} else {
>  		agf_bp = sc->sa.agf_bp;
>  	}
> -	cur = xfs_rmapbt_init_cursor(sc->mp, sc->tp, agf_bp, agno, sc->sa.pag);
> +	cur = xfs_rmapbt_init_cursor(sc->mp, sc->tp, agf_bp, sc->sa.pag);
>  
>  	/* Can we find any other rmappings? */
>  	error = xfs_rmap_has_other_keys(cur, agbno, 1, oinfo, &has_other_rmap);
> @@ -577,7 +577,8 @@ xrep_reap_block(
>  	 * to run xfs_repair.
>  	 */
>  	if (has_other_rmap)
> -		error = xfs_rmap_free(sc->tp, agf_bp, agno, agbno, 1, oinfo);
> +		error = xfs_rmap_free(sc->tp, agf_bp, sc->sa.pag, agbno,
> +					1, oinfo);
>  	else if (resv == XFS_AG_RESV_AGFL)
>  		error = xrep_put_freelist(sc, agbno);
>  	else
> @@ -892,8 +893,7 @@ xrep_find_ag_btree_roots(
>  		fab->height = 0;
>  	}
>  
> -	cur = xfs_rmapbt_init_cursor(mp, sc->tp, agf_bp, sc->sa.agno,
> -			sc->sa.pag);
> +	cur = xfs_rmapbt_init_cursor(mp, sc->tp, agf_bp, sc->sa.pag);
>  	error = xfs_rmap_query_all(cur, xrep_findroot_rmap, &ri);
>  	xfs_btree_del_cursor(cur, error);
>  
> diff --git a/fs/xfs/xfs_fsmap.c b/fs/xfs/xfs_fsmap.c
> index b654a2bf9a9f..7bfe9ea35de0 100644
> --- a/fs/xfs/xfs_fsmap.c
> +++ b/fs/xfs/xfs_fsmap.c
> @@ -708,7 +708,7 @@ xfs_getfsmap_datadev_rmapbt_query(
>  
>  	/* Allocate cursor for this AG and query_range it. */
>  	*curpp = xfs_rmapbt_init_cursor(tp->t_mountp, tp, info->agf_bp,
> -			info->pag->pag_agno, info->pag);
> +			info->pag);
>  	return xfs_rmap_query_range(*curpp, &info->low, &info->high,
>  			xfs_getfsmap_datadev_helper, info);
>  }
> -- 
> 2.31.1
> 

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 13/22] xfs: convert refcount btree cursor to use perags
  2021-05-06  7:20 ` [PATCH 13/22] xfs: convert refcount btree cursor to use perags Dave Chinner
  2021-05-11 12:30   ` Brian Foster
@ 2021-05-12 22:47   ` Darrick J. Wong
  1 sibling, 0 replies; 87+ messages in thread
From: Darrick J. Wong @ 2021-05-12 22:47 UTC (permalink / raw)
  To: Dave Chinner; +Cc: linux-xfs

On Thu, May 06, 2021 at 05:20:45PM +1000, Dave Chinner wrote:
> From: Dave Chinner <dchinner@redhat.com>
> 
> Signed-off-by: Dave Chinner <dchinner@redhat.com>
> ---
>  fs/xfs/libxfs/xfs_refcount.c       | 39 +++++++++++++++++-------------
>  fs/xfs/libxfs/xfs_refcount.h       |  9 ++++++-
>  fs/xfs/libxfs/xfs_refcount_btree.c | 22 +++++++----------
>  fs/xfs/libxfs/xfs_refcount_btree.h |  4 +--
>  fs/xfs/scrub/agheader_repair.c     |  2 +-
>  fs/xfs/scrub/bmap.c                |  8 +++---
>  fs/xfs/scrub/common.c              |  2 +-
>  fs/xfs/xfs_fsmap.c                 |  3 +--
>  fs/xfs/xfs_reflink.c               |  4 +--
>  9 files changed, 50 insertions(+), 43 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_refcount.c b/fs/xfs/libxfs/xfs_refcount.c
> index 1c2bd2949d7d..3c2b99cbd57d 100644
> --- a/fs/xfs/libxfs/xfs_refcount.c
> +++ b/fs/xfs/libxfs/xfs_refcount.c
> @@ -22,6 +22,7 @@
>  #include "xfs_bit.h"
>  #include "xfs_refcount.h"
>  #include "xfs_rmap.h"
> +#include "xfs_ag.h"
>  
>  /* Allowable refcount adjustment amounts. */
>  enum xfs_refc_adjust_op {
> @@ -1142,14 +1143,13 @@ xfs_refcount_finish_one(
>  	struct xfs_btree_cur		*rcur;
>  	struct xfs_buf			*agbp = NULL;
>  	int				error = 0;
> -	xfs_agnumber_t			agno;
>  	xfs_agblock_t			bno;
>  	xfs_agblock_t			new_agbno;
>  	unsigned long			nr_ops = 0;
>  	int				shape_changes = 0;
> +	struct xfs_perag		*pag;
>  
> -	agno = XFS_FSB_TO_AGNO(mp, startblock);
> -	ASSERT(agno != NULLAGNUMBER);
> +	pag = xfs_perag_get(mp, XFS_FSB_TO_AGNO(mp, startblock));
>  	bno = XFS_FSB_TO_AGBNO(mp, startblock);
>  
>  	trace_xfs_refcount_deferred(mp, XFS_FSB_TO_AGNO(mp, startblock),
> @@ -1157,15 +1157,17 @@ xfs_refcount_finish_one(
>  			blockcount);
>  
>  	if (XFS_TEST_ERROR(false, mp,
> -			XFS_ERRTAG_REFCOUNT_FINISH_ONE))
> -		return -EIO;
> +			XFS_ERRTAG_REFCOUNT_FINISH_ONE)) {

Might as well shorten this into a single line while you're at it.

Same whinging as the last patch about passing agfbp and pag through the
xfs_refcount.c functions into the cursor constructor.

--D

> +		error = -EIO;
> +		goto out_drop;
> +	}
>  
>  	/*
>  	 * If we haven't gotten a cursor or the cursor AG doesn't match
>  	 * the startblock, get one now.
>  	 */
>  	rcur = *pcur;
> -	if (rcur != NULL && rcur->bc_ag.agno != agno) {
> +	if (rcur != NULL && rcur->bc_ag.pag != pag) {
>  		nr_ops = rcur->bc_ag.refc.nr_ops;
>  		shape_changes = rcur->bc_ag.refc.shape_changes;
>  		xfs_refcount_finish_one_cleanup(tp, rcur, 0);
> @@ -1173,12 +1175,12 @@ xfs_refcount_finish_one(
>  		*pcur = NULL;
>  	}
>  	if (rcur == NULL) {
> -		error = xfs_alloc_read_agf(tp->t_mountp, tp, agno,
> +		error = xfs_alloc_read_agf(tp->t_mountp, tp, pag->pag_agno,
>  				XFS_ALLOC_FLAG_FREEING, &agbp);
>  		if (error)
> -			return error;
> +			goto out_drop;
>  
> -		rcur = xfs_refcountbt_init_cursor(mp, tp, agbp, agno, NULL);
> +		rcur = xfs_refcountbt_init_cursor(mp, tp, agbp, pag);
>  		rcur->bc_ag.refc.nr_ops = nr_ops;
>  		rcur->bc_ag.refc.shape_changes = shape_changes;
>  	}
> @@ -1188,12 +1190,12 @@ xfs_refcount_finish_one(
>  	case XFS_REFCOUNT_INCREASE:
>  		error = xfs_refcount_adjust(rcur, bno, blockcount, &new_agbno,
>  			new_len, XFS_REFCOUNT_ADJUST_INCREASE, NULL);
> -		*new_fsb = XFS_AGB_TO_FSB(mp, agno, new_agbno);
> +		*new_fsb = XFS_AGB_TO_FSB(mp, pag->pag_agno, new_agbno);
>  		break;
>  	case XFS_REFCOUNT_DECREASE:
>  		error = xfs_refcount_adjust(rcur, bno, blockcount, &new_agbno,
>  			new_len, XFS_REFCOUNT_ADJUST_DECREASE, NULL);
> -		*new_fsb = XFS_AGB_TO_FSB(mp, agno, new_agbno);
> +		*new_fsb = XFS_AGB_TO_FSB(mp, pag->pag_agno, new_agbno);
>  		break;
>  	case XFS_REFCOUNT_ALLOC_COW:
>  		*new_fsb = startblock + blockcount;
> @@ -1210,8 +1212,10 @@ xfs_refcount_finish_one(
>  		error = -EFSCORRUPTED;
>  	}
>  	if (!error && *new_len > 0)
> -		trace_xfs_refcount_finish_one_leftover(mp, agno, type,
> +		trace_xfs_refcount_finish_one_leftover(mp, pag->pag_agno, type,
>  				bno, blockcount, new_agbno, *new_len);
> +out_drop:
> +	xfs_perag_put(pag);
>  	return error;
>  }
>  
> @@ -1672,7 +1676,7 @@ xfs_refcount_recover_extent(
>  int
>  xfs_refcount_recover_cow_leftovers(
>  	struct xfs_mount		*mp,
> -	xfs_agnumber_t			agno)
> +	struct xfs_perag		*pag)
>  {
>  	struct xfs_trans		*tp;
>  	struct xfs_btree_cur		*cur;
> @@ -1704,10 +1708,10 @@ xfs_refcount_recover_cow_leftovers(
>  	if (error)
>  		return error;
>  
> -	error = xfs_alloc_read_agf(mp, tp, agno, 0, &agbp);
> +	error = xfs_alloc_read_agf(mp, tp, pag->pag_agno, 0, &agbp);
>  	if (error)
>  		goto out_trans;
> -	cur = xfs_refcountbt_init_cursor(mp, tp, agbp, agno, NULL);
> +	cur = xfs_refcountbt_init_cursor(mp, tp, agbp, pag);
>  
>  	/* Find all the leftover CoW staging extents. */
>  	memset(&low, 0, sizeof(low));
> @@ -1729,11 +1733,12 @@ xfs_refcount_recover_cow_leftovers(
>  		if (error)
>  			goto out_free;
>  
> -		trace_xfs_refcount_recover_extent(mp, agno, &rr->rr_rrec);
> +		trace_xfs_refcount_recover_extent(mp, pag->pag_agno,
> +				&rr->rr_rrec);
>  
>  		/* Free the orphan record */
>  		agbno = rr->rr_rrec.rc_startblock - XFS_REFC_COW_START;
> -		fsb = XFS_AGB_TO_FSB(mp, agno, agbno);
> +		fsb = XFS_AGB_TO_FSB(mp, pag->pag_agno, agbno);
>  		xfs_refcount_free_cow_extent(tp, fsb,
>  				rr->rr_rrec.rc_blockcount);
>  
> diff --git a/fs/xfs/libxfs/xfs_refcount.h b/fs/xfs/libxfs/xfs_refcount.h
> index 209795539c8d..9f6e9aae4da0 100644
> --- a/fs/xfs/libxfs/xfs_refcount.h
> +++ b/fs/xfs/libxfs/xfs_refcount.h
> @@ -6,6 +6,13 @@
>  #ifndef __XFS_REFCOUNT_H__
>  #define __XFS_REFCOUNT_H__
>  
> +struct xfs_trans;
> +struct xfs_mount;
> +struct xfs_perag;
> +struct xfs_btree_cur;
> +struct xfs_bmbt_irec;
> +struct xfs_refcount_irec;
> +
>  extern int xfs_refcount_lookup_le(struct xfs_btree_cur *cur,
>  		xfs_agblock_t bno, int *stat);
>  extern int xfs_refcount_lookup_ge(struct xfs_btree_cur *cur,
> @@ -50,7 +57,7 @@ void xfs_refcount_alloc_cow_extent(struct xfs_trans *tp, xfs_fsblock_t fsb,
>  void xfs_refcount_free_cow_extent(struct xfs_trans *tp, xfs_fsblock_t fsb,
>  		xfs_extlen_t len);
>  extern int xfs_refcount_recover_cow_leftovers(struct xfs_mount *mp,
> -		xfs_agnumber_t agno);
> +		struct xfs_perag *pag);
>  
>  /*
>   * While we're adjusting the refcounts records of an extent, we have
> diff --git a/fs/xfs/libxfs/xfs_refcount_btree.c b/fs/xfs/libxfs/xfs_refcount_btree.c
> index 74f8ac0209f1..8f6577cb3475 100644
> --- a/fs/xfs/libxfs/xfs_refcount_btree.c
> +++ b/fs/xfs/libxfs/xfs_refcount_btree.c
> @@ -26,7 +26,7 @@ xfs_refcountbt_dup_cursor(
>  	struct xfs_btree_cur	*cur)
>  {
>  	return xfs_refcountbt_init_cursor(cur->bc_mp, cur->bc_tp,
> -			cur->bc_ag.agbp, cur->bc_ag.agno, cur->bc_ag.pag);
> +			cur->bc_ag.agbp, cur->bc_ag.pag);
>  }
>  
>  STATIC void
> @@ -316,13 +316,11 @@ static struct xfs_btree_cur *
>  xfs_refcountbt_init_common(
>  	struct xfs_mount	*mp,
>  	struct xfs_trans	*tp,
> -	xfs_agnumber_t		agno,
>  	struct xfs_perag	*pag)
>  {
>  	struct xfs_btree_cur	*cur;
>  
> -	ASSERT(agno != NULLAGNUMBER);
> -	ASSERT(agno < mp->m_sb.sb_agcount);
> +	ASSERT(pag->pag_agno < mp->m_sb.sb_agcount);
>  
>  	cur = kmem_cache_zalloc(xfs_btree_cur_zone, GFP_NOFS | __GFP_NOFAIL);
>  	cur->bc_tp = tp;
> @@ -331,13 +329,12 @@ xfs_refcountbt_init_common(
>  	cur->bc_blocklog = mp->m_sb.sb_blocklog;
>  	cur->bc_statoff = XFS_STATS_CALC_INDEX(xs_refcbt_2);
>  
> -	cur->bc_ag.agno = agno;
>  	cur->bc_flags |= XFS_BTREE_CRC_BLOCKS;
> -	if (pag) {
> -		/* take a reference for the cursor */
> -		atomic_inc(&pag->pag_ref);
> -	}
> +
> +	/* take a reference for the cursor */
> +	atomic_inc(&pag->pag_ref);
>  	cur->bc_ag.pag = pag;
> +	cur->bc_ag.agno = pag->pag_agno;
>  
>  	cur->bc_ag.refc.nr_ops = 0;
>  	cur->bc_ag.refc.shape_changes = 0;
> @@ -351,13 +348,12 @@ xfs_refcountbt_init_cursor(
>  	struct xfs_mount	*mp,
>  	struct xfs_trans	*tp,
>  	struct xfs_buf		*agbp,
> -	xfs_agnumber_t		agno,
>  	struct xfs_perag	*pag)
>  {
>  	struct xfs_agf		*agf = agbp->b_addr;
>  	struct xfs_btree_cur	*cur;
>  
> -	cur = xfs_refcountbt_init_common(mp, tp, agno, pag);
> +	cur = xfs_refcountbt_init_common(mp, tp, pag);
>  	cur->bc_nlevels = be32_to_cpu(agf->agf_refcount_level);
>  	cur->bc_ag.agbp = agbp;
>  	return cur;
> @@ -368,11 +364,11 @@ struct xfs_btree_cur *
>  xfs_refcountbt_stage_cursor(
>  	struct xfs_mount	*mp,
>  	struct xbtree_afakeroot	*afake,
> -	xfs_agnumber_t		agno)
> +	struct xfs_perag	*pag)
>  {
>  	struct xfs_btree_cur	*cur;
>  
> -	cur = xfs_refcountbt_init_common(mp, NULL, agno, NULL);
> +	cur = xfs_refcountbt_init_common(mp, NULL, pag);
>  	xfs_btree_stage_afakeroot(cur, afake);
>  	return cur;
>  }
> diff --git a/fs/xfs/libxfs/xfs_refcount_btree.h b/fs/xfs/libxfs/xfs_refcount_btree.h
> index 8b82a39f104a..bd9ed9e1e41f 100644
> --- a/fs/xfs/libxfs/xfs_refcount_btree.h
> +++ b/fs/xfs/libxfs/xfs_refcount_btree.h
> @@ -47,9 +47,9 @@ struct xbtree_afakeroot;
>  
>  extern struct xfs_btree_cur *xfs_refcountbt_init_cursor(struct xfs_mount *mp,
>  		struct xfs_trans *tp, struct xfs_buf *agbp,
> -		xfs_agnumber_t agno, struct xfs_perag *pag);
> +		struct xfs_perag *pag);
>  struct xfs_btree_cur *xfs_refcountbt_stage_cursor(struct xfs_mount *mp,
> -		struct xbtree_afakeroot *afake, xfs_agnumber_t agno);
> +		struct xbtree_afakeroot *afake, struct xfs_perag *pag);
>  extern int xfs_refcountbt_maxrecs(int blocklen, bool leaf);
>  extern void xfs_refcountbt_compute_maxlevels(struct xfs_mount *mp);
>  
> diff --git a/fs/xfs/scrub/agheader_repair.c b/fs/xfs/scrub/agheader_repair.c
> index 981c689e3d95..251410c19198 100644
> --- a/fs/xfs/scrub/agheader_repair.c
> +++ b/fs/xfs/scrub/agheader_repair.c
> @@ -282,7 +282,7 @@ xrep_agf_calc_from_btrees(
>  	/* Update the AGF counters from the refcountbt. */
>  	if (xfs_sb_version_hasreflink(&mp->m_sb)) {
>  		cur = xfs_refcountbt_init_cursor(mp, sc->tp, agf_bp,
> -				sc->sa.agno, sc->sa.pag);
> +				sc->sa.pag);
>  		error = xfs_btree_count_blocks(cur, &blocks);
>  		if (error)
>  			goto err;
> diff --git a/fs/xfs/scrub/bmap.c b/fs/xfs/scrub/bmap.c
> index b20c3f03b3c5..5adef162115d 100644
> --- a/fs/xfs/scrub/bmap.c
> +++ b/fs/xfs/scrub/bmap.c
> @@ -545,18 +545,18 @@ STATIC int
>  xchk_bmap_check_ag_rmaps(
>  	struct xfs_scrub		*sc,
>  	int				whichfork,
> -	xfs_agnumber_t			agno)
> +	struct xfs_perag		*pag)
>  {
>  	struct xchk_bmap_check_rmap_info	sbcri;
>  	struct xfs_btree_cur		*cur;
>  	struct xfs_buf			*agf;
>  	int				error;
>  
> -	error = xfs_alloc_read_agf(sc->mp, sc->tp, agno, 0, &agf);
> +	error = xfs_alloc_read_agf(sc->mp, sc->tp, pag->pag_agno, 0, &agf);
>  	if (error)
>  		return error;
>  
> -	cur = xfs_rmapbt_init_cursor(sc->mp, sc->tp, agf, sc->sa.pag);
> +	cur = xfs_rmapbt_init_cursor(sc->mp, sc->tp, agf, pag);
>  
>  	sbcri.sc = sc;
>  	sbcri.whichfork = whichfork;
> @@ -610,7 +610,7 @@ xchk_bmap_check_rmaps(
>  		return 0;
>  
>  	for_each_perag(sc->mp, agno, pag) {
> -		error = xchk_bmap_check_ag_rmaps(sc, whichfork, pag->pag_agno);
> +		error = xchk_bmap_check_ag_rmaps(sc, whichfork, pag);
>  		if (error)
>  			return error;
>  		if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
> diff --git a/fs/xfs/scrub/common.c b/fs/xfs/scrub/common.c
> index 48381c1adeed..cc7688ce79b2 100644
> --- a/fs/xfs/scrub/common.c
> +++ b/fs/xfs/scrub/common.c
> @@ -500,7 +500,7 @@ xchk_ag_btcur_init(
>  	if (sa->agf_bp && xfs_sb_version_hasreflink(&mp->m_sb) &&
>  	    xchk_ag_btree_healthy_enough(sc, sa->pag, XFS_BTNUM_REFC)) {
>  		sa->refc_cur = xfs_refcountbt_init_cursor(mp, sc->tp,
> -				sa->agf_bp, agno, sa->pag);
> +				sa->agf_bp, sa->pag);
>  	}
>  }
>  
> diff --git a/fs/xfs/xfs_fsmap.c b/fs/xfs/xfs_fsmap.c
> index 7bfe9ea35de0..623cabaeafee 100644
> --- a/fs/xfs/xfs_fsmap.c
> +++ b/fs/xfs/xfs_fsmap.c
> @@ -210,8 +210,7 @@ xfs_getfsmap_is_shared(
>  
>  	/* Are there any shared blocks here? */
>  	flen = 0;
> -	cur = xfs_refcountbt_init_cursor(mp, tp, info->agf_bp,
> -			info->pag->pag_agno, info->pag);
> +	cur = xfs_refcountbt_init_cursor(mp, tp, info->agf_bp, info->pag);
>  
>  	error = xfs_refcount_find_shared(cur, rec->rm_startblock,
>  			rec->rm_blockcount, &fbno, &flen, false);
> diff --git a/fs/xfs/xfs_reflink.c b/fs/xfs/xfs_reflink.c
> index 28ffe1817f9b..c256104772cb 100644
> --- a/fs/xfs/xfs_reflink.c
> +++ b/fs/xfs/xfs_reflink.c
> @@ -144,7 +144,7 @@ xfs_reflink_find_shared(
>  	if (error)
>  		return error;
>  
> -	cur = xfs_refcountbt_init_cursor(mp, tp, agbp, agno, NULL);
> +	cur = xfs_refcountbt_init_cursor(mp, tp, agbp, agbp->b_pag);
>  
>  	error = xfs_refcount_find_shared(cur, agbno, aglen, fbno, flen,
>  			find_end_of_shared);
> @@ -763,7 +763,7 @@ xfs_reflink_recover_cow(
>  		return 0;
>  
>  	for_each_perag(mp, agno, pag) {
> -		error = xfs_refcount_recover_cow_leftovers(mp, pag->pag_agno);
> +		error = xfs_refcount_recover_cow_leftovers(mp, pag);
>  		if (error) {
>  			xfs_perag_put(pag);
>  			break;
> -- 
> 2.31.1
> 

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 16/22] xfs: remove agno from btree cursor
  2021-05-06  7:20 ` [PATCH 16/22] xfs: remove agno from btree cursor Dave Chinner
  2021-05-11 12:34   ` Brian Foster
@ 2021-05-12 22:52   ` Darrick J. Wong
  1 sibling, 0 replies; 87+ messages in thread
From: Darrick J. Wong @ 2021-05-12 22:52 UTC (permalink / raw)
  To: Dave Chinner; +Cc: linux-xfs

On Thu, May 06, 2021 at 05:20:48PM +1000, Dave Chinner wrote:
> From: Dave Chinner <dchinner@redhat.com>
> 
> Now that everything passes a perag, the agno is not needed anymore.
> Convert all the users to use pag->pag_agno instead and remove the
> agno from the cursor. This was largely done as an automated search
> and replace.
> 
> Signed-off-by: Dave Chinner <dchinner@redhat.com>

Yippeeeee!
Reviewed-by: Darrick J. Wong <djwong@kernel.org>

--D

> ---
>  fs/xfs/libxfs/xfs_alloc.c          |   2 +-
>  fs/xfs/libxfs/xfs_alloc_btree.c    |   1 -
>  fs/xfs/libxfs/xfs_btree.c          |  12 ++--
>  fs/xfs/libxfs/xfs_btree.h          |   1 -
>  fs/xfs/libxfs/xfs_ialloc.c         |   2 +-
>  fs/xfs/libxfs/xfs_ialloc_btree.c   |   7 +-
>  fs/xfs/libxfs/xfs_refcount.c       |  82 +++++++++++-----------
>  fs/xfs/libxfs/xfs_refcount_btree.c |  11 ++-
>  fs/xfs/libxfs/xfs_rmap.c           | 108 ++++++++++++++---------------
>  fs/xfs/libxfs/xfs_rmap_btree.c     |   1 -
>  fs/xfs/scrub/agheader_repair.c     |   2 +-
>  fs/xfs/scrub/alloc.c               |   3 +-
>  fs/xfs/scrub/bmap.c                |   2 +-
>  fs/xfs/scrub/ialloc.c              |   9 +--
>  fs/xfs/scrub/refcount.c            |   3 +-
>  fs/xfs/scrub/rmap.c                |   3 +-
>  fs/xfs/scrub/trace.c               |   3 +-
>  fs/xfs/xfs_fsmap.c                 |   4 +-
>  fs/xfs/xfs_trace.h                 |   4 +-
>  19 files changed, 130 insertions(+), 130 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_alloc.c b/fs/xfs/libxfs/xfs_alloc.c
> index c99a80286efa..f7864f33c1f0 100644
> --- a/fs/xfs/libxfs/xfs_alloc.c
> +++ b/fs/xfs/libxfs/xfs_alloc.c
> @@ -230,7 +230,7 @@ xfs_alloc_get_rec(
>  	int			*stat)	/* output: success/failure */
>  {
>  	struct xfs_mount	*mp = cur->bc_mp;
> -	xfs_agnumber_t		agno = cur->bc_ag.agno;
> +	xfs_agnumber_t		agno = cur->bc_ag.pag->pag_agno;
>  	union xfs_btree_rec	*rec;
>  	int			error;
>  
> diff --git a/fs/xfs/libxfs/xfs_alloc_btree.c b/fs/xfs/libxfs/xfs_alloc_btree.c
> index 0c2e4cff4ee3..6b363f78cfa2 100644
> --- a/fs/xfs/libxfs/xfs_alloc_btree.c
> +++ b/fs/xfs/libxfs/xfs_alloc_btree.c
> @@ -497,7 +497,6 @@ xfs_allocbt_init_common(
>  	/* take a reference for the cursor */
>  	atomic_inc(&pag->pag_ref);
>  	cur->bc_ag.pag = pag;
> -	cur->bc_ag.agno = pag->pag_agno;
>  
>  	if (xfs_sb_version_hascrc(&mp->m_sb))
>  		cur->bc_flags |= XFS_BTREE_CRC_BLOCKS;
> diff --git a/fs/xfs/libxfs/xfs_btree.c b/fs/xfs/libxfs/xfs_btree.c
> index 44044317c0fb..be74a6b53689 100644
> --- a/fs/xfs/libxfs/xfs_btree.c
> +++ b/fs/xfs/libxfs/xfs_btree.c
> @@ -216,7 +216,7 @@ xfs_btree_check_sptr(
>  {
>  	if (level <= 0)
>  		return false;
> -	return xfs_verify_agbno(cur->bc_mp, cur->bc_ag.agno, agbno);
> +	return xfs_verify_agbno(cur->bc_mp, cur->bc_ag.pag->pag_agno, agbno);
>  }
>  
>  /*
> @@ -245,7 +245,7 @@ xfs_btree_check_ptr(
>  			return 0;
>  		xfs_err(cur->bc_mp,
>  "AG %u: Corrupt btree %d pointer at level %d index %d.",
> -				cur->bc_ag.agno, cur->bc_btnum,
> +				cur->bc_ag.pag->pag_agno, cur->bc_btnum,
>  				level, index);
>  	}
>  
> @@ -888,13 +888,13 @@ xfs_btree_readahead_sblock(
>  
>  
>  	if ((lr & XFS_BTCUR_LEFTRA) && left != NULLAGBLOCK) {
> -		xfs_btree_reada_bufs(cur->bc_mp, cur->bc_ag.agno,
> +		xfs_btree_reada_bufs(cur->bc_mp, cur->bc_ag.pag->pag_agno,
>  				     left, 1, cur->bc_ops->buf_ops);
>  		rval++;
>  	}
>  
>  	if ((lr & XFS_BTCUR_RIGHTRA) && right != NULLAGBLOCK) {
> -		xfs_btree_reada_bufs(cur->bc_mp, cur->bc_ag.agno,
> +		xfs_btree_reada_bufs(cur->bc_mp, cur->bc_ag.pag->pag_agno,
>  				     right, 1, cur->bc_ops->buf_ops);
>  		rval++;
>  	}
> @@ -952,7 +952,7 @@ xfs_btree_ptr_to_daddr(
>  		*daddr = XFS_FSB_TO_DADDR(cur->bc_mp, fsbno);
>  	} else {
>  		agbno = be32_to_cpu(ptr->s);
> -		*daddr = XFS_AGB_TO_DADDR(cur->bc_mp, cur->bc_ag.agno,
> +		*daddr = XFS_AGB_TO_DADDR(cur->bc_mp, cur->bc_ag.pag->pag_agno,
>  				agbno);
>  	}
>  
> @@ -1153,7 +1153,7 @@ xfs_btree_init_block_cur(
>  	if (cur->bc_flags & XFS_BTREE_LONG_PTRS)
>  		owner = cur->bc_ino.ip->i_ino;
>  	else
> -		owner = cur->bc_ag.agno;
> +		owner = cur->bc_ag.pag->pag_agno;
>  
>  	xfs_btree_init_block_int(cur->bc_mp, XFS_BUF_TO_BLOCK(bp), bp->b_bn,
>  				 cur->bc_btnum, level, numrecs,
> diff --git a/fs/xfs/libxfs/xfs_btree.h b/fs/xfs/libxfs/xfs_btree.h
> index 8233f8679ba9..13bbcf107e5d 100644
> --- a/fs/xfs/libxfs/xfs_btree.h
> +++ b/fs/xfs/libxfs/xfs_btree.h
> @@ -181,7 +181,6 @@ union xfs_btree_irec {
>  
>  /* Per-AG btree information. */
>  struct xfs_btree_cur_ag {
> -	xfs_agnumber_t		agno;
>  	struct xfs_perag	*pag;
>  	union {
>  		struct xfs_buf		*agbp;
> diff --git a/fs/xfs/libxfs/xfs_ialloc.c b/fs/xfs/libxfs/xfs_ialloc.c
> index e6f64d41e208..4540fbcd68a3 100644
> --- a/fs/xfs/libxfs/xfs_ialloc.c
> +++ b/fs/xfs/libxfs/xfs_ialloc.c
> @@ -105,7 +105,7 @@ xfs_inobt_get_rec(
>  	int				*stat)
>  {
>  	struct xfs_mount		*mp = cur->bc_mp;
> -	xfs_agnumber_t			agno = cur->bc_ag.agno;
> +	xfs_agnumber_t			agno = cur->bc_ag.pag->pag_agno;
>  	union xfs_btree_rec		*rec;
>  	int				error;
>  	uint64_t			realfree;
> diff --git a/fs/xfs/libxfs/xfs_ialloc_btree.c b/fs/xfs/libxfs/xfs_ialloc_btree.c
> index 450161b53648..823a038939f8 100644
> --- a/fs/xfs/libxfs/xfs_ialloc_btree.c
> +++ b/fs/xfs/libxfs/xfs_ialloc_btree.c
> @@ -102,7 +102,7 @@ __xfs_inobt_alloc_block(
>  	args.tp = cur->bc_tp;
>  	args.mp = cur->bc_mp;
>  	args.oinfo = XFS_RMAP_OINFO_INOBT;
> -	args.fsbno = XFS_AGB_TO_FSB(args.mp, cur->bc_ag.agno, sbno);
> +	args.fsbno = XFS_AGB_TO_FSB(args.mp, cur->bc_ag.pag->pag_agno, sbno);
>  	args.minlen = 1;
>  	args.maxlen = 1;
>  	args.prod = 1;
> @@ -235,7 +235,7 @@ xfs_inobt_init_ptr_from_cur(
>  {
>  	struct xfs_agi		*agi = cur->bc_ag.agbp->b_addr;
>  
> -	ASSERT(cur->bc_ag.agno == be32_to_cpu(agi->agi_seqno));
> +	ASSERT(cur->bc_ag.pag->pag_agno == be32_to_cpu(agi->agi_seqno));
>  
>  	ptr->s = agi->agi_root;
>  }
> @@ -247,7 +247,7 @@ xfs_finobt_init_ptr_from_cur(
>  {
>  	struct xfs_agi		*agi = cur->bc_ag.agbp->b_addr;
>  
> -	ASSERT(cur->bc_ag.agno == be32_to_cpu(agi->agi_seqno));
> +	ASSERT(cur->bc_ag.pag->pag_agno == be32_to_cpu(agi->agi_seqno));
>  	ptr->s = agi->agi_free_root;
>  }
>  
> @@ -452,7 +452,6 @@ xfs_inobt_init_common(
>  	/* take a reference for the cursor */
>  	atomic_inc(&pag->pag_ref);
>  	cur->bc_ag.pag = pag;
> -	cur->bc_ag.agno = pag->pag_agno;
>  	return cur;
>  }
>  
> diff --git a/fs/xfs/libxfs/xfs_refcount.c b/fs/xfs/libxfs/xfs_refcount.c
> index 3c2b99cbd57d..82b2810d85a6 100644
> --- a/fs/xfs/libxfs/xfs_refcount.c
> +++ b/fs/xfs/libxfs/xfs_refcount.c
> @@ -47,7 +47,7 @@ xfs_refcount_lookup_le(
>  	xfs_agblock_t		bno,
>  	int			*stat)
>  {
> -	trace_xfs_refcount_lookup(cur->bc_mp, cur->bc_ag.agno, bno,
> +	trace_xfs_refcount_lookup(cur->bc_mp, cur->bc_ag.pag->pag_agno, bno,
>  			XFS_LOOKUP_LE);
>  	cur->bc_rec.rc.rc_startblock = bno;
>  	cur->bc_rec.rc.rc_blockcount = 0;
> @@ -64,7 +64,7 @@ xfs_refcount_lookup_ge(
>  	xfs_agblock_t		bno,
>  	int			*stat)
>  {
> -	trace_xfs_refcount_lookup(cur->bc_mp, cur->bc_ag.agno, bno,
> +	trace_xfs_refcount_lookup(cur->bc_mp, cur->bc_ag.pag->pag_agno, bno,
>  			XFS_LOOKUP_GE);
>  	cur->bc_rec.rc.rc_startblock = bno;
>  	cur->bc_rec.rc.rc_blockcount = 0;
> @@ -81,7 +81,7 @@ xfs_refcount_lookup_eq(
>  	xfs_agblock_t		bno,
>  	int			*stat)
>  {
> -	trace_xfs_refcount_lookup(cur->bc_mp, cur->bc_ag.agno, bno,
> +	trace_xfs_refcount_lookup(cur->bc_mp, cur->bc_ag.pag->pag_agno, bno,
>  			XFS_LOOKUP_LE);
>  	cur->bc_rec.rc.rc_startblock = bno;
>  	cur->bc_rec.rc.rc_blockcount = 0;
> @@ -109,7 +109,7 @@ xfs_refcount_get_rec(
>  	int				*stat)
>  {
>  	struct xfs_mount		*mp = cur->bc_mp;
> -	xfs_agnumber_t			agno = cur->bc_ag.agno;
> +	xfs_agnumber_t			agno = cur->bc_ag.pag->pag_agno;
>  	union xfs_btree_rec		*rec;
>  	int				error;
>  	xfs_agblock_t			realstart;
> @@ -120,7 +120,7 @@ xfs_refcount_get_rec(
>  
>  	xfs_refcount_btrec_to_irec(rec, irec);
>  
> -	agno = cur->bc_ag.agno;
> +	agno = cur->bc_ag.pag->pag_agno;
>  	if (irec->rc_blockcount == 0 || irec->rc_blockcount > MAXREFCEXTLEN)
>  		goto out_bad_rec;
>  
> @@ -145,7 +145,7 @@ xfs_refcount_get_rec(
>  	if (irec->rc_refcount == 0 || irec->rc_refcount > MAXREFCOUNT)
>  		goto out_bad_rec;
>  
> -	trace_xfs_refcount_get(cur->bc_mp, cur->bc_ag.agno, irec);
> +	trace_xfs_refcount_get(cur->bc_mp, cur->bc_ag.pag->pag_agno, irec);
>  	return 0;
>  
>  out_bad_rec:
> @@ -170,14 +170,14 @@ xfs_refcount_update(
>  	union xfs_btree_rec	rec;
>  	int			error;
>  
> -	trace_xfs_refcount_update(cur->bc_mp, cur->bc_ag.agno, irec);
> +	trace_xfs_refcount_update(cur->bc_mp, cur->bc_ag.pag->pag_agno, irec);
>  	rec.refc.rc_startblock = cpu_to_be32(irec->rc_startblock);
>  	rec.refc.rc_blockcount = cpu_to_be32(irec->rc_blockcount);
>  	rec.refc.rc_refcount = cpu_to_be32(irec->rc_refcount);
>  	error = xfs_btree_update(cur, &rec);
>  	if (error)
>  		trace_xfs_refcount_update_error(cur->bc_mp,
> -				cur->bc_ag.agno, error, _RET_IP_);
> +				cur->bc_ag.pag->pag_agno, error, _RET_IP_);
>  	return error;
>  }
>  
> @@ -194,7 +194,7 @@ xfs_refcount_insert(
>  {
>  	int				error;
>  
> -	trace_xfs_refcount_insert(cur->bc_mp, cur->bc_ag.agno, irec);
> +	trace_xfs_refcount_insert(cur->bc_mp, cur->bc_ag.pag->pag_agno, irec);
>  	cur->bc_rec.rc.rc_startblock = irec->rc_startblock;
>  	cur->bc_rec.rc.rc_blockcount = irec->rc_blockcount;
>  	cur->bc_rec.rc.rc_refcount = irec->rc_refcount;
> @@ -209,7 +209,7 @@ xfs_refcount_insert(
>  out_error:
>  	if (error)
>  		trace_xfs_refcount_insert_error(cur->bc_mp,
> -				cur->bc_ag.agno, error, _RET_IP_);
> +				cur->bc_ag.pag->pag_agno, error, _RET_IP_);
>  	return error;
>  }
>  
> @@ -235,7 +235,7 @@ xfs_refcount_delete(
>  		error = -EFSCORRUPTED;
>  		goto out_error;
>  	}
> -	trace_xfs_refcount_delete(cur->bc_mp, cur->bc_ag.agno, &irec);
> +	trace_xfs_refcount_delete(cur->bc_mp, cur->bc_ag.pag->pag_agno, &irec);
>  	error = xfs_btree_delete(cur, i);
>  	if (XFS_IS_CORRUPT(cur->bc_mp, *i != 1)) {
>  		error = -EFSCORRUPTED;
> @@ -247,7 +247,7 @@ xfs_refcount_delete(
>  out_error:
>  	if (error)
>  		trace_xfs_refcount_delete_error(cur->bc_mp,
> -				cur->bc_ag.agno, error, _RET_IP_);
> +				cur->bc_ag.pag->pag_agno, error, _RET_IP_);
>  	return error;
>  }
>  
> @@ -367,7 +367,7 @@ xfs_refcount_split_extent(
>  		return 0;
>  
>  	*shape_changed = true;
> -	trace_xfs_refcount_split_extent(cur->bc_mp, cur->bc_ag.agno,
> +	trace_xfs_refcount_split_extent(cur->bc_mp, cur->bc_ag.pag->pag_agno,
>  			&rcext, agbno);
>  
>  	/* Establish the right extent. */
> @@ -392,7 +392,7 @@ xfs_refcount_split_extent(
>  
>  out_error:
>  	trace_xfs_refcount_split_extent_error(cur->bc_mp,
> -			cur->bc_ag.agno, error, _RET_IP_);
> +			cur->bc_ag.pag->pag_agno, error, _RET_IP_);
>  	return error;
>  }
>  
> @@ -412,7 +412,7 @@ xfs_refcount_merge_center_extents(
>  	int				found_rec;
>  
>  	trace_xfs_refcount_merge_center_extents(cur->bc_mp,
> -			cur->bc_ag.agno, left, center, right);
> +			cur->bc_ag.pag->pag_agno, left, center, right);
>  
>  	/*
>  	 * Make sure the center and right extents are not in the btree.
> @@ -469,7 +469,7 @@ xfs_refcount_merge_center_extents(
>  
>  out_error:
>  	trace_xfs_refcount_merge_center_extents_error(cur->bc_mp,
> -			cur->bc_ag.agno, error, _RET_IP_);
> +			cur->bc_ag.pag->pag_agno, error, _RET_IP_);
>  	return error;
>  }
>  
> @@ -488,7 +488,7 @@ xfs_refcount_merge_left_extent(
>  	int				found_rec;
>  
>  	trace_xfs_refcount_merge_left_extent(cur->bc_mp,
> -			cur->bc_ag.agno, left, cleft);
> +			cur->bc_ag.pag->pag_agno, left, cleft);
>  
>  	/* If the extent at agbno (cleft) wasn't synthesized, remove it. */
>  	if (cleft->rc_refcount > 1) {
> @@ -531,7 +531,7 @@ xfs_refcount_merge_left_extent(
>  
>  out_error:
>  	trace_xfs_refcount_merge_left_extent_error(cur->bc_mp,
> -			cur->bc_ag.agno, error, _RET_IP_);
> +			cur->bc_ag.pag->pag_agno, error, _RET_IP_);
>  	return error;
>  }
>  
> @@ -549,7 +549,7 @@ xfs_refcount_merge_right_extent(
>  	int				found_rec;
>  
>  	trace_xfs_refcount_merge_right_extent(cur->bc_mp,
> -			cur->bc_ag.agno, cright, right);
> +			cur->bc_ag.pag->pag_agno, cright, right);
>  
>  	/*
>  	 * If the extent ending at agbno+aglen (cright) wasn't synthesized,
> @@ -595,7 +595,7 @@ xfs_refcount_merge_right_extent(
>  
>  out_error:
>  	trace_xfs_refcount_merge_right_extent_error(cur->bc_mp,
> -			cur->bc_ag.agno, error, _RET_IP_);
> +			cur->bc_ag.pag->pag_agno, error, _RET_IP_);
>  	return error;
>  }
>  
> @@ -680,13 +680,13 @@ xfs_refcount_find_left_extents(
>  		cleft->rc_blockcount = aglen;
>  		cleft->rc_refcount = 1;
>  	}
> -	trace_xfs_refcount_find_left_extent(cur->bc_mp, cur->bc_ag.agno,
> +	trace_xfs_refcount_find_left_extent(cur->bc_mp, cur->bc_ag.pag->pag_agno,
>  			left, cleft, agbno);
>  	return error;
>  
>  out_error:
>  	trace_xfs_refcount_find_left_extent_error(cur->bc_mp,
> -			cur->bc_ag.agno, error, _RET_IP_);
> +			cur->bc_ag.pag->pag_agno, error, _RET_IP_);
>  	return error;
>  }
>  
> @@ -769,13 +769,13 @@ xfs_refcount_find_right_extents(
>  		cright->rc_blockcount = aglen;
>  		cright->rc_refcount = 1;
>  	}
> -	trace_xfs_refcount_find_right_extent(cur->bc_mp, cur->bc_ag.agno,
> +	trace_xfs_refcount_find_right_extent(cur->bc_mp, cur->bc_ag.pag->pag_agno,
>  			cright, right, agbno + aglen);
>  	return error;
>  
>  out_error:
>  	trace_xfs_refcount_find_right_extent_error(cur->bc_mp,
> -			cur->bc_ag.agno, error, _RET_IP_);
> +			cur->bc_ag.pag->pag_agno, error, _RET_IP_);
>  	return error;
>  }
>  
> @@ -953,7 +953,7 @@ xfs_refcount_adjust_extents(
>  					ext.rc_startblock - *agbno);
>  			tmp.rc_refcount = 1 + adj;
>  			trace_xfs_refcount_modify_extent(cur->bc_mp,
> -					cur->bc_ag.agno, &tmp);
> +					cur->bc_ag.pag->pag_agno, &tmp);
>  
>  			/*
>  			 * Either cover the hole (increment) or
> @@ -972,7 +972,7 @@ xfs_refcount_adjust_extents(
>  				cur->bc_ag.refc.nr_ops++;
>  			} else {
>  				fsbno = XFS_AGB_TO_FSB(cur->bc_mp,
> -						cur->bc_ag.agno,
> +						cur->bc_ag.pag->pag_agno,
>  						tmp.rc_startblock);
>  				xfs_bmap_add_free(cur->bc_tp, fsbno,
>  						  tmp.rc_blockcount, oinfo);
> @@ -999,7 +999,7 @@ xfs_refcount_adjust_extents(
>  			goto skip;
>  		ext.rc_refcount += adj;
>  		trace_xfs_refcount_modify_extent(cur->bc_mp,
> -				cur->bc_ag.agno, &ext);
> +				cur->bc_ag.pag->pag_agno, &ext);
>  		if (ext.rc_refcount > 1) {
>  			error = xfs_refcount_update(cur, &ext);
>  			if (error)
> @@ -1017,7 +1017,7 @@ xfs_refcount_adjust_extents(
>  			goto advloop;
>  		} else {
>  			fsbno = XFS_AGB_TO_FSB(cur->bc_mp,
> -					cur->bc_ag.agno,
> +					cur->bc_ag.pag->pag_agno,
>  					ext.rc_startblock);
>  			xfs_bmap_add_free(cur->bc_tp, fsbno, ext.rc_blockcount,
>  					  oinfo);
> @@ -1036,7 +1036,7 @@ xfs_refcount_adjust_extents(
>  	return error;
>  out_error:
>  	trace_xfs_refcount_modify_extent_error(cur->bc_mp,
> -			cur->bc_ag.agno, error, _RET_IP_);
> +			cur->bc_ag.pag->pag_agno, error, _RET_IP_);
>  	return error;
>  }
>  
> @@ -1058,10 +1058,10 @@ xfs_refcount_adjust(
>  	*new_agbno = agbno;
>  	*new_aglen = aglen;
>  	if (adj == XFS_REFCOUNT_ADJUST_INCREASE)
> -		trace_xfs_refcount_increase(cur->bc_mp, cur->bc_ag.agno,
> +		trace_xfs_refcount_increase(cur->bc_mp, cur->bc_ag.pag->pag_agno,
>  				agbno, aglen);
>  	else
> -		trace_xfs_refcount_decrease(cur->bc_mp, cur->bc_ag.agno,
> +		trace_xfs_refcount_decrease(cur->bc_mp, cur->bc_ag.pag->pag_agno,
>  				agbno, aglen);
>  
>  	/*
> @@ -1100,7 +1100,7 @@ xfs_refcount_adjust(
>  	return 0;
>  
>  out_error:
> -	trace_xfs_refcount_adjust_error(cur->bc_mp, cur->bc_ag.agno,
> +	trace_xfs_refcount_adjust_error(cur->bc_mp, cur->bc_ag.pag->pag_agno,
>  			error, _RET_IP_);
>  	return error;
>  }
> @@ -1298,7 +1298,7 @@ xfs_refcount_find_shared(
>  	int				have;
>  	int				error;
>  
> -	trace_xfs_refcount_find_shared(cur->bc_mp, cur->bc_ag.agno,
> +	trace_xfs_refcount_find_shared(cur->bc_mp, cur->bc_ag.pag->pag_agno,
>  			agbno, aglen);
>  
>  	/* By default, skip the whole range */
> @@ -1378,12 +1378,12 @@ xfs_refcount_find_shared(
>  
>  done:
>  	trace_xfs_refcount_find_shared_result(cur->bc_mp,
> -			cur->bc_ag.agno, *fbno, *flen);
> +			cur->bc_ag.pag->pag_agno, *fbno, *flen);
>  
>  out_error:
>  	if (error)
>  		trace_xfs_refcount_find_shared_error(cur->bc_mp,
> -				cur->bc_ag.agno, error, _RET_IP_);
> +				cur->bc_ag.pag->pag_agno, error, _RET_IP_);
>  	return error;
>  }
>  
> @@ -1480,7 +1480,7 @@ xfs_refcount_adjust_cow_extents(
>  		tmp.rc_blockcount = aglen;
>  		tmp.rc_refcount = 1;
>  		trace_xfs_refcount_modify_extent(cur->bc_mp,
> -				cur->bc_ag.agno, &tmp);
> +				cur->bc_ag.pag->pag_agno, &tmp);
>  
>  		error = xfs_refcount_insert(cur, &tmp,
>  				&found_tmp);
> @@ -1508,7 +1508,7 @@ xfs_refcount_adjust_cow_extents(
>  
>  		ext.rc_refcount = 0;
>  		trace_xfs_refcount_modify_extent(cur->bc_mp,
> -				cur->bc_ag.agno, &ext);
> +				cur->bc_ag.pag->pag_agno, &ext);
>  		error = xfs_refcount_delete(cur, &found_rec);
>  		if (error)
>  			goto out_error;
> @@ -1524,7 +1524,7 @@ xfs_refcount_adjust_cow_extents(
>  	return error;
>  out_error:
>  	trace_xfs_refcount_modify_extent_error(cur->bc_mp,
> -			cur->bc_ag.agno, error, _RET_IP_);
> +			cur->bc_ag.pag->pag_agno, error, _RET_IP_);
>  	return error;
>  }
>  
> @@ -1570,7 +1570,7 @@ xfs_refcount_adjust_cow(
>  	return 0;
>  
>  out_error:
> -	trace_xfs_refcount_adjust_cow_error(cur->bc_mp, cur->bc_ag.agno,
> +	trace_xfs_refcount_adjust_cow_error(cur->bc_mp, cur->bc_ag.pag->pag_agno,
>  			error, _RET_IP_);
>  	return error;
>  }
> @@ -1584,7 +1584,7 @@ __xfs_refcount_cow_alloc(
>  	xfs_agblock_t		agbno,
>  	xfs_extlen_t		aglen)
>  {
> -	trace_xfs_refcount_cow_increase(rcur->bc_mp, rcur->bc_ag.agno,
> +	trace_xfs_refcount_cow_increase(rcur->bc_mp, rcur->bc_ag.pag->pag_agno,
>  			agbno, aglen);
>  
>  	/* Add refcount btree reservation */
> @@ -1601,7 +1601,7 @@ __xfs_refcount_cow_free(
>  	xfs_agblock_t		agbno,
>  	xfs_extlen_t		aglen)
>  {
> -	trace_xfs_refcount_cow_decrease(rcur->bc_mp, rcur->bc_ag.agno,
> +	trace_xfs_refcount_cow_decrease(rcur->bc_mp, rcur->bc_ag.pag->pag_agno,
>  			agbno, aglen);
>  
>  	/* Remove refcount btree reservation */
> diff --git a/fs/xfs/libxfs/xfs_refcount_btree.c b/fs/xfs/libxfs/xfs_refcount_btree.c
> index 8f6577cb3475..92d336c17e83 100644
> --- a/fs/xfs/libxfs/xfs_refcount_btree.c
> +++ b/fs/xfs/libxfs/xfs_refcount_btree.c
> @@ -65,7 +65,7 @@ xfs_refcountbt_alloc_block(
>  	args.tp = cur->bc_tp;
>  	args.mp = cur->bc_mp;
>  	args.type = XFS_ALLOCTYPE_NEAR_BNO;
> -	args.fsbno = XFS_AGB_TO_FSB(cur->bc_mp, cur->bc_ag.agno,
> +	args.fsbno = XFS_AGB_TO_FSB(cur->bc_mp, cur->bc_ag.pag->pag_agno,
>  			xfs_refc_block(args.mp));
>  	args.oinfo = XFS_RMAP_OINFO_REFC;
>  	args.minlen = args.maxlen = args.prod = 1;
> @@ -74,13 +74,13 @@ xfs_refcountbt_alloc_block(
>  	error = xfs_alloc_vextent(&args);
>  	if (error)
>  		goto out_error;
> -	trace_xfs_refcountbt_alloc_block(cur->bc_mp, cur->bc_ag.agno,
> +	trace_xfs_refcountbt_alloc_block(cur->bc_mp, cur->bc_ag.pag->pag_agno,
>  			args.agbno, 1);
>  	if (args.fsbno == NULLFSBLOCK) {
>  		*stat = 0;
>  		return 0;
>  	}
> -	ASSERT(args.agno == cur->bc_ag.agno);
> +	ASSERT(args.agno == cur->bc_ag.pag->pag_agno);
>  	ASSERT(args.len == 1);
>  
>  	new->s = cpu_to_be32(args.agbno);
> @@ -105,7 +105,7 @@ xfs_refcountbt_free_block(
>  	xfs_fsblock_t		fsbno = XFS_DADDR_TO_FSB(mp, XFS_BUF_ADDR(bp));
>  	int			error;
>  
> -	trace_xfs_refcountbt_free_block(cur->bc_mp, cur->bc_ag.agno,
> +	trace_xfs_refcountbt_free_block(cur->bc_mp, cur->bc_ag.pag->pag_agno,
>  			XFS_FSB_TO_AGBNO(cur->bc_mp, fsbno), 1);
>  	be32_add_cpu(&agf->agf_refcount_blocks, -1);
>  	xfs_alloc_log_agf(cur->bc_tp, agbp, XFS_AGF_REFCOUNT_BLOCKS);
> @@ -170,7 +170,7 @@ xfs_refcountbt_init_ptr_from_cur(
>  {
>  	struct xfs_agf		*agf = cur->bc_ag.agbp->b_addr;
>  
> -	ASSERT(cur->bc_ag.agno == be32_to_cpu(agf->agf_seqno));
> +	ASSERT(cur->bc_ag.pag->pag_agno == be32_to_cpu(agf->agf_seqno));
>  
>  	ptr->s = agf->agf_refcount_root;
>  }
> @@ -334,7 +334,6 @@ xfs_refcountbt_init_common(
>  	/* take a reference for the cursor */
>  	atomic_inc(&pag->pag_ref);
>  	cur->bc_ag.pag = pag;
> -	cur->bc_ag.agno = pag->pag_agno;
>  
>  	cur->bc_ag.refc.nr_ops = 0;
>  	cur->bc_ag.refc.shape_changes = 0;
> diff --git a/fs/xfs/libxfs/xfs_rmap.c b/fs/xfs/libxfs/xfs_rmap.c
> index b23f949ee15c..d1dfad0204e3 100644
> --- a/fs/xfs/libxfs/xfs_rmap.c
> +++ b/fs/xfs/libxfs/xfs_rmap.c
> @@ -81,7 +81,7 @@ xfs_rmap_update(
>  	union xfs_btree_rec	rec;
>  	int			error;
>  
> -	trace_xfs_rmap_update(cur->bc_mp, cur->bc_ag.agno,
> +	trace_xfs_rmap_update(cur->bc_mp, cur->bc_ag.pag->pag_agno,
>  			irec->rm_startblock, irec->rm_blockcount,
>  			irec->rm_owner, irec->rm_offset, irec->rm_flags);
>  
> @@ -93,7 +93,7 @@ xfs_rmap_update(
>  	error = xfs_btree_update(cur, &rec);
>  	if (error)
>  		trace_xfs_rmap_update_error(cur->bc_mp,
> -				cur->bc_ag.agno, error, _RET_IP_);
> +				cur->bc_ag.pag->pag_agno, error, _RET_IP_);
>  	return error;
>  }
>  
> @@ -109,7 +109,7 @@ xfs_rmap_insert(
>  	int			i;
>  	int			error;
>  
> -	trace_xfs_rmap_insert(rcur->bc_mp, rcur->bc_ag.agno, agbno,
> +	trace_xfs_rmap_insert(rcur->bc_mp, rcur->bc_ag.pag->pag_agno, agbno,
>  			len, owner, offset, flags);
>  
>  	error = xfs_rmap_lookup_eq(rcur, agbno, len, owner, offset, flags, &i);
> @@ -135,7 +135,7 @@ xfs_rmap_insert(
>  done:
>  	if (error)
>  		trace_xfs_rmap_insert_error(rcur->bc_mp,
> -				rcur->bc_ag.agno, error, _RET_IP_);
> +				rcur->bc_ag.pag->pag_agno, error, _RET_IP_);
>  	return error;
>  }
>  
> @@ -151,7 +151,7 @@ xfs_rmap_delete(
>  	int			i;
>  	int			error;
>  
> -	trace_xfs_rmap_delete(rcur->bc_mp, rcur->bc_ag.agno, agbno,
> +	trace_xfs_rmap_delete(rcur->bc_mp, rcur->bc_ag.pag->pag_agno, agbno,
>  			len, owner, offset, flags);
>  
>  	error = xfs_rmap_lookup_eq(rcur, agbno, len, owner, offset, flags, &i);
> @@ -172,7 +172,7 @@ xfs_rmap_delete(
>  done:
>  	if (error)
>  		trace_xfs_rmap_delete_error(rcur->bc_mp,
> -				rcur->bc_ag.agno, error, _RET_IP_);
> +				rcur->bc_ag.pag->pag_agno, error, _RET_IP_);
>  	return error;
>  }
>  
> @@ -199,7 +199,7 @@ xfs_rmap_get_rec(
>  	int			*stat)
>  {
>  	struct xfs_mount	*mp = cur->bc_mp;
> -	xfs_agnumber_t		agno = cur->bc_ag.agno;
> +	xfs_agnumber_t		agno = cur->bc_ag.pag->pag_agno;
>  	union xfs_btree_rec	*rec;
>  	int			error;
>  
> @@ -262,7 +262,7 @@ xfs_rmap_find_left_neighbor_helper(
>  	struct xfs_find_left_neighbor_info	*info = priv;
>  
>  	trace_xfs_rmap_find_left_neighbor_candidate(cur->bc_mp,
> -			cur->bc_ag.agno, rec->rm_startblock,
> +			cur->bc_ag.pag->pag_agno, rec->rm_startblock,
>  			rec->rm_blockcount, rec->rm_owner, rec->rm_offset,
>  			rec->rm_flags);
>  
> @@ -314,7 +314,7 @@ xfs_rmap_find_left_neighbor(
>  	info.stat = stat;
>  
>  	trace_xfs_rmap_find_left_neighbor_query(cur->bc_mp,
> -			cur->bc_ag.agno, bno, 0, owner, offset, flags);
> +			cur->bc_ag.pag->pag_agno, bno, 0, owner, offset, flags);
>  
>  	error = xfs_rmap_query_range(cur, &info.high, &info.high,
>  			xfs_rmap_find_left_neighbor_helper, &info);
> @@ -322,7 +322,7 @@ xfs_rmap_find_left_neighbor(
>  		error = 0;
>  	if (*stat)
>  		trace_xfs_rmap_find_left_neighbor_result(cur->bc_mp,
> -				cur->bc_ag.agno, irec->rm_startblock,
> +				cur->bc_ag.pag->pag_agno, irec->rm_startblock,
>  				irec->rm_blockcount, irec->rm_owner,
>  				irec->rm_offset, irec->rm_flags);
>  	return error;
> @@ -338,7 +338,7 @@ xfs_rmap_lookup_le_range_helper(
>  	struct xfs_find_left_neighbor_info	*info = priv;
>  
>  	trace_xfs_rmap_lookup_le_range_candidate(cur->bc_mp,
> -			cur->bc_ag.agno, rec->rm_startblock,
> +			cur->bc_ag.pag->pag_agno, rec->rm_startblock,
>  			rec->rm_blockcount, rec->rm_owner, rec->rm_offset,
>  			rec->rm_flags);
>  
> @@ -387,14 +387,14 @@ xfs_rmap_lookup_le_range(
>  	info.stat = stat;
>  
>  	trace_xfs_rmap_lookup_le_range(cur->bc_mp,
> -			cur->bc_ag.agno, bno, 0, owner, offset, flags);
> +			cur->bc_ag.pag->pag_agno, bno, 0, owner, offset, flags);
>  	error = xfs_rmap_query_range(cur, &info.high, &info.high,
>  			xfs_rmap_lookup_le_range_helper, &info);
>  	if (error == -ECANCELED)
>  		error = 0;
>  	if (*stat)
>  		trace_xfs_rmap_lookup_le_range_result(cur->bc_mp,
> -				cur->bc_ag.agno, irec->rm_startblock,
> +				cur->bc_ag.pag->pag_agno, irec->rm_startblock,
>  				irec->rm_blockcount, irec->rm_owner,
>  				irec->rm_offset, irec->rm_flags);
>  	return error;
> @@ -500,7 +500,7 @@ xfs_rmap_unmap(
>  			(flags & XFS_RMAP_BMBT_BLOCK);
>  	if (unwritten)
>  		flags |= XFS_RMAP_UNWRITTEN;
> -	trace_xfs_rmap_unmap(mp, cur->bc_ag.agno, bno, len,
> +	trace_xfs_rmap_unmap(mp, cur->bc_ag.pag->pag_agno, bno, len,
>  			unwritten, oinfo);
>  
>  	/*
> @@ -524,7 +524,7 @@ xfs_rmap_unmap(
>  		goto out_error;
>  	}
>  	trace_xfs_rmap_lookup_le_range_result(cur->bc_mp,
> -			cur->bc_ag.agno, ltrec.rm_startblock,
> +			cur->bc_ag.pag->pag_agno, ltrec.rm_startblock,
>  			ltrec.rm_blockcount, ltrec.rm_owner,
>  			ltrec.rm_offset, ltrec.rm_flags);
>  	ltoff = ltrec.rm_offset;
> @@ -590,7 +590,7 @@ xfs_rmap_unmap(
>  
>  	if (ltrec.rm_startblock == bno && ltrec.rm_blockcount == len) {
>  		/* exact match, simply remove the record from rmap tree */
> -		trace_xfs_rmap_delete(mp, cur->bc_ag.agno,
> +		trace_xfs_rmap_delete(mp, cur->bc_ag.pag->pag_agno,
>  				ltrec.rm_startblock, ltrec.rm_blockcount,
>  				ltrec.rm_owner, ltrec.rm_offset,
>  				ltrec.rm_flags);
> @@ -668,7 +668,7 @@ xfs_rmap_unmap(
>  		else
>  			cur->bc_rec.r.rm_offset = offset + len;
>  		cur->bc_rec.r.rm_flags = flags;
> -		trace_xfs_rmap_insert(mp, cur->bc_ag.agno,
> +		trace_xfs_rmap_insert(mp, cur->bc_ag.pag->pag_agno,
>  				cur->bc_rec.r.rm_startblock,
>  				cur->bc_rec.r.rm_blockcount,
>  				cur->bc_rec.r.rm_owner,
> @@ -680,11 +680,11 @@ xfs_rmap_unmap(
>  	}
>  
>  out_done:
> -	trace_xfs_rmap_unmap_done(mp, cur->bc_ag.agno, bno, len,
> +	trace_xfs_rmap_unmap_done(mp, cur->bc_ag.pag->pag_agno, bno, len,
>  			unwritten, oinfo);
>  out_error:
>  	if (error)
> -		trace_xfs_rmap_unmap_error(mp, cur->bc_ag.agno,
> +		trace_xfs_rmap_unmap_error(mp, cur->bc_ag.pag->pag_agno,
>  				error, _RET_IP_);
>  	return error;
>  }
> @@ -775,7 +775,7 @@ xfs_rmap_map(
>  			(flags & XFS_RMAP_BMBT_BLOCK);
>  	if (unwritten)
>  		flags |= XFS_RMAP_UNWRITTEN;
> -	trace_xfs_rmap_map(mp, cur->bc_ag.agno, bno, len,
> +	trace_xfs_rmap_map(mp, cur->bc_ag.pag->pag_agno, bno, len,
>  			unwritten, oinfo);
>  	ASSERT(!xfs_rmap_should_skip_owner_update(oinfo));
>  
> @@ -797,7 +797,7 @@ xfs_rmap_map(
>  			goto out_error;
>  		}
>  		trace_xfs_rmap_lookup_le_range_result(cur->bc_mp,
> -				cur->bc_ag.agno, ltrec.rm_startblock,
> +				cur->bc_ag.pag->pag_agno, ltrec.rm_startblock,
>  				ltrec.rm_blockcount, ltrec.rm_owner,
>  				ltrec.rm_offset, ltrec.rm_flags);
>  
> @@ -833,7 +833,7 @@ xfs_rmap_map(
>  			goto out_error;
>  		}
>  		trace_xfs_rmap_find_right_neighbor_result(cur->bc_mp,
> -			cur->bc_ag.agno, gtrec.rm_startblock,
> +			cur->bc_ag.pag->pag_agno, gtrec.rm_startblock,
>  			gtrec.rm_blockcount, gtrec.rm_owner,
>  			gtrec.rm_offset, gtrec.rm_flags);
>  		if (!xfs_rmap_is_mergeable(&gtrec, owner, flags))
> @@ -872,7 +872,7 @@ xfs_rmap_map(
>  			 * result: |rrrrrrrrrrrrrrrrrrrrrrrrrrrrr|
>  			 */
>  			ltrec.rm_blockcount += gtrec.rm_blockcount;
> -			trace_xfs_rmap_delete(mp, cur->bc_ag.agno,
> +			trace_xfs_rmap_delete(mp, cur->bc_ag.pag->pag_agno,
>  					gtrec.rm_startblock,
>  					gtrec.rm_blockcount,
>  					gtrec.rm_owner,
> @@ -923,7 +923,7 @@ xfs_rmap_map(
>  		cur->bc_rec.r.rm_owner = owner;
>  		cur->bc_rec.r.rm_offset = offset;
>  		cur->bc_rec.r.rm_flags = flags;
> -		trace_xfs_rmap_insert(mp, cur->bc_ag.agno, bno, len,
> +		trace_xfs_rmap_insert(mp, cur->bc_ag.pag->pag_agno, bno, len,
>  			owner, offset, flags);
>  		error = xfs_btree_insert(cur, &i);
>  		if (error)
> @@ -934,11 +934,11 @@ xfs_rmap_map(
>  		}
>  	}
>  
> -	trace_xfs_rmap_map_done(mp, cur->bc_ag.agno, bno, len,
> +	trace_xfs_rmap_map_done(mp, cur->bc_ag.pag->pag_agno, bno, len,
>  			unwritten, oinfo);
>  out_error:
>  	if (error)
> -		trace_xfs_rmap_map_error(mp, cur->bc_ag.agno,
> +		trace_xfs_rmap_map_error(mp, cur->bc_ag.pag->pag_agno,
>  				error, _RET_IP_);
>  	return error;
>  }
> @@ -1012,7 +1012,7 @@ xfs_rmap_convert(
>  			(flags & (XFS_RMAP_ATTR_FORK | XFS_RMAP_BMBT_BLOCK))));
>  	oldext = unwritten ? XFS_RMAP_UNWRITTEN : 0;
>  	new_endoff = offset + len;
> -	trace_xfs_rmap_convert(mp, cur->bc_ag.agno, bno, len,
> +	trace_xfs_rmap_convert(mp, cur->bc_ag.pag->pag_agno, bno, len,
>  			unwritten, oinfo);
>  
>  	/*
> @@ -1036,7 +1036,7 @@ xfs_rmap_convert(
>  		goto done;
>  	}
>  	trace_xfs_rmap_lookup_le_range_result(cur->bc_mp,
> -			cur->bc_ag.agno, PREV.rm_startblock,
> +			cur->bc_ag.pag->pag_agno, PREV.rm_startblock,
>  			PREV.rm_blockcount, PREV.rm_owner,
>  			PREV.rm_offset, PREV.rm_flags);
>  
> @@ -1078,7 +1078,7 @@ xfs_rmap_convert(
>  			goto done;
>  		}
>  		trace_xfs_rmap_find_left_neighbor_result(cur->bc_mp,
> -				cur->bc_ag.agno, LEFT.rm_startblock,
> +				cur->bc_ag.pag->pag_agno, LEFT.rm_startblock,
>  				LEFT.rm_blockcount, LEFT.rm_owner,
>  				LEFT.rm_offset, LEFT.rm_flags);
>  		if (LEFT.rm_startblock + LEFT.rm_blockcount == bno &&
> @@ -1116,7 +1116,7 @@ xfs_rmap_convert(
>  			goto done;
>  		}
>  		trace_xfs_rmap_find_right_neighbor_result(cur->bc_mp,
> -				cur->bc_ag.agno, RIGHT.rm_startblock,
> +				cur->bc_ag.pag->pag_agno, RIGHT.rm_startblock,
>  				RIGHT.rm_blockcount, RIGHT.rm_owner,
>  				RIGHT.rm_offset, RIGHT.rm_flags);
>  		if (bno + len == RIGHT.rm_startblock &&
> @@ -1134,7 +1134,7 @@ xfs_rmap_convert(
>  	     RIGHT.rm_blockcount > XFS_RMAP_LEN_MAX)
>  		state &= ~RMAP_RIGHT_CONTIG;
>  
> -	trace_xfs_rmap_convert_state(mp, cur->bc_ag.agno, state,
> +	trace_xfs_rmap_convert_state(mp, cur->bc_ag.pag->pag_agno, state,
>  			_RET_IP_);
>  
>  	/* reset the cursor back to PREV */
> @@ -1164,7 +1164,7 @@ xfs_rmap_convert(
>  			error = -EFSCORRUPTED;
>  			goto done;
>  		}
> -		trace_xfs_rmap_delete(mp, cur->bc_ag.agno,
> +		trace_xfs_rmap_delete(mp, cur->bc_ag.pag->pag_agno,
>  				RIGHT.rm_startblock, RIGHT.rm_blockcount,
>  				RIGHT.rm_owner, RIGHT.rm_offset,
>  				RIGHT.rm_flags);
> @@ -1182,7 +1182,7 @@ xfs_rmap_convert(
>  			error = -EFSCORRUPTED;
>  			goto done;
>  		}
> -		trace_xfs_rmap_delete(mp, cur->bc_ag.agno,
> +		trace_xfs_rmap_delete(mp, cur->bc_ag.pag->pag_agno,
>  				PREV.rm_startblock, PREV.rm_blockcount,
>  				PREV.rm_owner, PREV.rm_offset,
>  				PREV.rm_flags);
> @@ -1212,7 +1212,7 @@ xfs_rmap_convert(
>  		 * Setting all of a previous oldext extent to newext.
>  		 * The left neighbor is contiguous, the right is not.
>  		 */
> -		trace_xfs_rmap_delete(mp, cur->bc_ag.agno,
> +		trace_xfs_rmap_delete(mp, cur->bc_ag.pag->pag_agno,
>  				PREV.rm_startblock, PREV.rm_blockcount,
>  				PREV.rm_owner, PREV.rm_offset,
>  				PREV.rm_flags);
> @@ -1249,7 +1249,7 @@ xfs_rmap_convert(
>  			error = -EFSCORRUPTED;
>  			goto done;
>  		}
> -		trace_xfs_rmap_delete(mp, cur->bc_ag.agno,
> +		trace_xfs_rmap_delete(mp, cur->bc_ag.pag->pag_agno,
>  				RIGHT.rm_startblock, RIGHT.rm_blockcount,
>  				RIGHT.rm_owner, RIGHT.rm_offset,
>  				RIGHT.rm_flags);
> @@ -1328,7 +1328,7 @@ xfs_rmap_convert(
>  		NEW.rm_blockcount = len;
>  		NEW.rm_flags = newext;
>  		cur->bc_rec.r = NEW;
> -		trace_xfs_rmap_insert(mp, cur->bc_ag.agno, bno,
> +		trace_xfs_rmap_insert(mp, cur->bc_ag.pag->pag_agno, bno,
>  				len, owner, offset, newext);
>  		error = xfs_btree_insert(cur, &i);
>  		if (error)
> @@ -1385,7 +1385,7 @@ xfs_rmap_convert(
>  		NEW.rm_blockcount = len;
>  		NEW.rm_flags = newext;
>  		cur->bc_rec.r = NEW;
> -		trace_xfs_rmap_insert(mp, cur->bc_ag.agno, bno,
> +		trace_xfs_rmap_insert(mp, cur->bc_ag.pag->pag_agno, bno,
>  				len, owner, offset, newext);
>  		error = xfs_btree_insert(cur, &i);
>  		if (error)
> @@ -1416,7 +1416,7 @@ xfs_rmap_convert(
>  		NEW = PREV;
>  		NEW.rm_blockcount = offset - PREV.rm_offset;
>  		cur->bc_rec.r = NEW;
> -		trace_xfs_rmap_insert(mp, cur->bc_ag.agno,
> +		trace_xfs_rmap_insert(mp, cur->bc_ag.pag->pag_agno,
>  				NEW.rm_startblock, NEW.rm_blockcount,
>  				NEW.rm_owner, NEW.rm_offset,
>  				NEW.rm_flags);
> @@ -1443,7 +1443,7 @@ xfs_rmap_convert(
>  		/* new middle extent - newext */
>  		cur->bc_rec.r.rm_flags &= ~XFS_RMAP_UNWRITTEN;
>  		cur->bc_rec.r.rm_flags |= newext;
> -		trace_xfs_rmap_insert(mp, cur->bc_ag.agno, bno, len,
> +		trace_xfs_rmap_insert(mp, cur->bc_ag.pag->pag_agno, bno, len,
>  				owner, offset, newext);
>  		error = xfs_btree_insert(cur, &i);
>  		if (error)
> @@ -1467,12 +1467,12 @@ xfs_rmap_convert(
>  		ASSERT(0);
>  	}
>  
> -	trace_xfs_rmap_convert_done(mp, cur->bc_ag.agno, bno, len,
> +	trace_xfs_rmap_convert_done(mp, cur->bc_ag.pag->pag_agno, bno, len,
>  			unwritten, oinfo);
>  done:
>  	if (error)
>  		trace_xfs_rmap_convert_error(cur->bc_mp,
> -				cur->bc_ag.agno, error, _RET_IP_);
> +				cur->bc_ag.pag->pag_agno, error, _RET_IP_);
>  	return error;
>  }
>  
> @@ -1508,7 +1508,7 @@ xfs_rmap_convert_shared(
>  			(flags & (XFS_RMAP_ATTR_FORK | XFS_RMAP_BMBT_BLOCK))));
>  	oldext = unwritten ? XFS_RMAP_UNWRITTEN : 0;
>  	new_endoff = offset + len;
> -	trace_xfs_rmap_convert(mp, cur->bc_ag.agno, bno, len,
> +	trace_xfs_rmap_convert(mp, cur->bc_ag.pag->pag_agno, bno, len,
>  			unwritten, oinfo);
>  
>  	/*
> @@ -1575,7 +1575,7 @@ xfs_rmap_convert_shared(
>  			goto done;
>  		}
>  		trace_xfs_rmap_find_right_neighbor_result(cur->bc_mp,
> -				cur->bc_ag.agno, RIGHT.rm_startblock,
> +				cur->bc_ag.pag->pag_agno, RIGHT.rm_startblock,
>  				RIGHT.rm_blockcount, RIGHT.rm_owner,
>  				RIGHT.rm_offset, RIGHT.rm_flags);
>  		if (xfs_rmap_is_mergeable(&RIGHT, owner, newext))
> @@ -1591,7 +1591,7 @@ xfs_rmap_convert_shared(
>  	     RIGHT.rm_blockcount > XFS_RMAP_LEN_MAX)
>  		state &= ~RMAP_RIGHT_CONTIG;
>  
> -	trace_xfs_rmap_convert_state(mp, cur->bc_ag.agno, state,
> +	trace_xfs_rmap_convert_state(mp, cur->bc_ag.pag->pag_agno, state,
>  			_RET_IP_);
>  	/*
>  	 * Switch out based on the FILLING and CONTIG state bits.
> @@ -1882,12 +1882,12 @@ xfs_rmap_convert_shared(
>  		ASSERT(0);
>  	}
>  
> -	trace_xfs_rmap_convert_done(mp, cur->bc_ag.agno, bno, len,
> +	trace_xfs_rmap_convert_done(mp, cur->bc_ag.pag->pag_agno, bno, len,
>  			unwritten, oinfo);
>  done:
>  	if (error)
>  		trace_xfs_rmap_convert_error(cur->bc_mp,
> -				cur->bc_ag.agno, error, _RET_IP_);
> +				cur->bc_ag.pag->pag_agno, error, _RET_IP_);
>  	return error;
>  }
>  
> @@ -1925,7 +1925,7 @@ xfs_rmap_unmap_shared(
>  	xfs_owner_info_unpack(oinfo, &owner, &offset, &flags);
>  	if (unwritten)
>  		flags |= XFS_RMAP_UNWRITTEN;
> -	trace_xfs_rmap_unmap(mp, cur->bc_ag.agno, bno, len,
> +	trace_xfs_rmap_unmap(mp, cur->bc_ag.pag->pag_agno, bno, len,
>  			unwritten, oinfo);
>  
>  	/*
> @@ -2074,12 +2074,12 @@ xfs_rmap_unmap_shared(
>  			goto out_error;
>  	}
>  
> -	trace_xfs_rmap_unmap_done(mp, cur->bc_ag.agno, bno, len,
> +	trace_xfs_rmap_unmap_done(mp, cur->bc_ag.pag->pag_agno, bno, len,
>  			unwritten, oinfo);
>  out_error:
>  	if (error)
>  		trace_xfs_rmap_unmap_error(cur->bc_mp,
> -				cur->bc_ag.agno, error, _RET_IP_);
> +				cur->bc_ag.pag->pag_agno, error, _RET_IP_);
>  	return error;
>  }
>  
> @@ -2114,7 +2114,7 @@ xfs_rmap_map_shared(
>  	xfs_owner_info_unpack(oinfo, &owner, &offset, &flags);
>  	if (unwritten)
>  		flags |= XFS_RMAP_UNWRITTEN;
> -	trace_xfs_rmap_map(mp, cur->bc_ag.agno, bno, len,
> +	trace_xfs_rmap_map(mp, cur->bc_ag.pag->pag_agno, bno, len,
>  			unwritten, oinfo);
>  
>  	/* Is there a left record that abuts our range? */
> @@ -2140,7 +2140,7 @@ xfs_rmap_map_shared(
>  			goto out_error;
>  		}
>  		trace_xfs_rmap_find_right_neighbor_result(cur->bc_mp,
> -			cur->bc_ag.agno, gtrec.rm_startblock,
> +			cur->bc_ag.pag->pag_agno, gtrec.rm_startblock,
>  			gtrec.rm_blockcount, gtrec.rm_owner,
>  			gtrec.rm_offset, gtrec.rm_flags);
>  
> @@ -2233,12 +2233,12 @@ xfs_rmap_map_shared(
>  			goto out_error;
>  	}
>  
> -	trace_xfs_rmap_map_done(mp, cur->bc_ag.agno, bno, len,
> +	trace_xfs_rmap_map_done(mp, cur->bc_ag.pag->pag_agno, bno, len,
>  			unwritten, oinfo);
>  out_error:
>  	if (error)
>  		trace_xfs_rmap_map_error(cur->bc_mp,
> -				cur->bc_ag.agno, error, _RET_IP_);
> +				cur->bc_ag.pag->pag_agno, error, _RET_IP_);
>  	return error;
>  }
>  
> @@ -2389,7 +2389,7 @@ xfs_rmap_finish_one(
>  	 * the startblock, get one now.
>  	 */
>  	rcur = *pcur;
> -	if (rcur != NULL && rcur->bc_ag.agno != pag->pag_agno) {
> +	if (rcur != NULL && rcur->bc_ag.pag != pag) {
>  		xfs_rmap_finish_one_cleanup(tp, rcur, 0);
>  		rcur = NULL;
>  		*pcur = NULL;
> diff --git a/fs/xfs/libxfs/xfs_rmap_btree.c b/fs/xfs/libxfs/xfs_rmap_btree.c
> index cafe181bc92d..f29bc71b9950 100644
> --- a/fs/xfs/libxfs/xfs_rmap_btree.c
> +++ b/fs/xfs/libxfs/xfs_rmap_btree.c
> @@ -464,7 +464,6 @@ xfs_rmapbt_init_common(
>  	/* take a reference for the cursor */
>  	atomic_inc(&pag->pag_ref);
>  	cur->bc_ag.pag = pag;
> -	cur->bc_ag.agno = pag->pag_agno;
>  
>  	return cur;
>  }
> diff --git a/fs/xfs/scrub/agheader_repair.c b/fs/xfs/scrub/agheader_repair.c
> index ecc9146647ba..e95f8c98f0f7 100644
> --- a/fs/xfs/scrub/agheader_repair.c
> +++ b/fs/xfs/scrub/agheader_repair.c
> @@ -454,7 +454,7 @@ xrep_agfl_walk_rmap(
>  
>  	/* Record all the OWN_AG blocks. */
>  	if (rec->rm_owner == XFS_RMAP_OWN_AG) {
> -		fsb = XFS_AGB_TO_FSB(cur->bc_mp, cur->bc_ag.agno,
> +		fsb = XFS_AGB_TO_FSB(cur->bc_mp, cur->bc_ag.pag->pag_agno,
>  				rec->rm_startblock);
>  		error = xbitmap_set(ra->freesp, fsb, rec->rm_blockcount);
>  		if (error)
> diff --git a/fs/xfs/scrub/alloc.c b/fs/xfs/scrub/alloc.c
> index 2720bd7fe53b..d5741980094a 100644
> --- a/fs/xfs/scrub/alloc.c
> +++ b/fs/xfs/scrub/alloc.c
> @@ -15,6 +15,7 @@
>  #include "scrub/scrub.h"
>  #include "scrub/common.h"
>  #include "scrub/btree.h"
> +#include "xfs_ag.h"
>  
>  /*
>   * Set us up to scrub free space btrees.
> @@ -93,7 +94,7 @@ xchk_allocbt_rec(
>  	union xfs_btree_rec	*rec)
>  {
>  	struct xfs_mount	*mp = bs->cur->bc_mp;
> -	xfs_agnumber_t		agno = bs->cur->bc_ag.agno;
> +	xfs_agnumber_t		agno = bs->cur->bc_ag.pag->pag_agno;
>  	xfs_agblock_t		bno;
>  	xfs_extlen_t		len;
>  
> diff --git a/fs/xfs/scrub/bmap.c b/fs/xfs/scrub/bmap.c
> index 5adef162115d..b9c205a2fede 100644
> --- a/fs/xfs/scrub/bmap.c
> +++ b/fs/xfs/scrub/bmap.c
> @@ -515,7 +515,7 @@ xchk_bmap_check_rmap(
>  			xchk_fblock_set_corrupt(sc, sbcri->whichfork,
>  					rec->rm_offset);
>  		if (irec.br_startblock != XFS_AGB_TO_FSB(sc->mp,
> -				cur->bc_ag.agno, rec->rm_startblock))
> +				cur->bc_ag.pag->pag_agno, rec->rm_startblock))
>  			xchk_fblock_set_corrupt(sc, sbcri->whichfork,
>  					rec->rm_offset);
>  		if (irec.br_blockcount > rec->rm_blockcount)
> diff --git a/fs/xfs/scrub/ialloc.c b/fs/xfs/scrub/ialloc.c
> index 8d9f3fb0cd22..30e568596b79 100644
> --- a/fs/xfs/scrub/ialloc.c
> +++ b/fs/xfs/scrub/ialloc.c
> @@ -21,6 +21,7 @@
>  #include "scrub/common.h"
>  #include "scrub/btree.h"
>  #include "scrub/trace.h"
> +#include "xfs_ag.h"
>  
>  /*
>   * Set us up to scrub inode btrees.
> @@ -103,7 +104,7 @@ xchk_iallocbt_chunk(
>  	xfs_extlen_t			len)
>  {
>  	struct xfs_mount		*mp = bs->cur->bc_mp;
> -	xfs_agnumber_t			agno = bs->cur->bc_ag.agno;
> +	xfs_agnumber_t			agno = bs->cur->bc_ag.pag->pag_agno;
>  	xfs_agblock_t			bno;
>  
>  	bno = XFS_AGINO_TO_AGBNO(mp, agino);
> @@ -163,7 +164,7 @@ xchk_iallocbt_check_cluster_ifree(
>  	 * the record, compute which fs inode we're talking about.
>  	 */
>  	agino = irec->ir_startino + irec_ino;
> -	fsino = XFS_AGINO_TO_INO(mp, bs->cur->bc_ag.agno, agino);
> +	fsino = XFS_AGINO_TO_INO(mp, bs->cur->bc_ag.pag->pag_agno, agino);
>  	irec_free = (irec->ir_free & XFS_INOBT_MASK(irec_ino));
>  
>  	if (be16_to_cpu(dip->di_magic) != XFS_DINODE_MAGIC ||
> @@ -213,7 +214,7 @@ xchk_iallocbt_check_cluster(
>  	struct xfs_mount		*mp = bs->cur->bc_mp;
>  	struct xfs_buf			*cluster_bp;
>  	unsigned int			nr_inodes;
> -	xfs_agnumber_t			agno = bs->cur->bc_ag.agno;
> +	xfs_agnumber_t			agno = bs->cur->bc_ag.pag->pag_agno;
>  	xfs_agblock_t			agbno;
>  	unsigned int			cluster_index;
>  	uint16_t			cluster_mask = 0;
> @@ -423,7 +424,7 @@ xchk_iallocbt_rec(
>  	struct xchk_iallocbt		*iabt = bs->private;
>  	struct xfs_inobt_rec_incore	irec;
>  	uint64_t			holes;
> -	xfs_agnumber_t			agno = bs->cur->bc_ag.agno;
> +	xfs_agnumber_t			agno = bs->cur->bc_ag.pag->pag_agno;
>  	xfs_agino_t			agino;
>  	xfs_extlen_t			len;
>  	int				holecount;
> diff --git a/fs/xfs/scrub/refcount.c b/fs/xfs/scrub/refcount.c
> index 744530a66c0c..7014b7408bad 100644
> --- a/fs/xfs/scrub/refcount.c
> +++ b/fs/xfs/scrub/refcount.c
> @@ -13,6 +13,7 @@
>  #include "scrub/scrub.h"
>  #include "scrub/common.h"
>  #include "scrub/btree.h"
> +#include "xfs_ag.h"
>  
>  /*
>   * Set us up to scrub reference count btrees.
> @@ -333,7 +334,7 @@ xchk_refcountbt_rec(
>  {
>  	struct xfs_mount	*mp = bs->cur->bc_mp;
>  	xfs_agblock_t		*cow_blocks = bs->private;
> -	xfs_agnumber_t		agno = bs->cur->bc_ag.agno;
> +	xfs_agnumber_t		agno = bs->cur->bc_ag.pag->pag_agno;
>  	xfs_agblock_t		bno;
>  	xfs_extlen_t		len;
>  	xfs_nlink_t		refcount;
> diff --git a/fs/xfs/scrub/rmap.c b/fs/xfs/scrub/rmap.c
> index a4f17477c5d1..fc306573f0ac 100644
> --- a/fs/xfs/scrub/rmap.c
> +++ b/fs/xfs/scrub/rmap.c
> @@ -15,6 +15,7 @@
>  #include "scrub/scrub.h"
>  #include "scrub/common.h"
>  #include "scrub/btree.h"
> +#include "xfs_ag.h"
>  
>  /*
>   * Set us up to scrub reverse mapping btrees.
> @@ -91,7 +92,7 @@ xchk_rmapbt_rec(
>  {
>  	struct xfs_mount	*mp = bs->cur->bc_mp;
>  	struct xfs_rmap_irec	irec;
> -	xfs_agnumber_t		agno = bs->cur->bc_ag.agno;
> +	xfs_agnumber_t		agno = bs->cur->bc_ag.pag->pag_agno;
>  	bool			non_inode;
>  	bool			is_unwritten;
>  	bool			is_bmbt;
> diff --git a/fs/xfs/scrub/trace.c b/fs/xfs/scrub/trace.c
> index 2c6c248be823..03882a605a3c 100644
> --- a/fs/xfs/scrub/trace.c
> +++ b/fs/xfs/scrub/trace.c
> @@ -13,6 +13,7 @@
>  #include "xfs_inode.h"
>  #include "xfs_btree.h"
>  #include "scrub/scrub.h"
> +#include "xfs_ag.h"
>  
>  /* Figure out which block the btree cursor was pointing to. */
>  static inline xfs_fsblock_t
> @@ -26,7 +27,7 @@ xchk_btree_cur_fsbno(
>  		 cur->bc_flags & XFS_BTREE_LONG_PTRS)
>  		return XFS_INO_TO_FSB(cur->bc_mp, cur->bc_ino.ip->i_ino);
>  	else if (!(cur->bc_flags & XFS_BTREE_LONG_PTRS))
> -		return XFS_AGB_TO_FSB(cur->bc_mp, cur->bc_ag.agno, 0);
> +		return XFS_AGB_TO_FSB(cur->bc_mp, cur->bc_ag.pag->pag_agno, 0);
>  	return NULLFSBLOCK;
>  }
>  
> diff --git a/fs/xfs/xfs_fsmap.c b/fs/xfs/xfs_fsmap.c
> index 7501dd941a63..7d0b09c1366e 100644
> --- a/fs/xfs/xfs_fsmap.c
> +++ b/fs/xfs/xfs_fsmap.c
> @@ -355,7 +355,7 @@ xfs_getfsmap_datadev_helper(
>  	xfs_fsblock_t			fsb;
>  	xfs_daddr_t			rec_daddr;
>  
> -	fsb = XFS_AGB_TO_FSB(mp, cur->bc_ag.agno, rec->rm_startblock);
> +	fsb = XFS_AGB_TO_FSB(mp, cur->bc_ag.pag->pag_agno, rec->rm_startblock);
>  	rec_daddr = XFS_FSB_TO_DADDR(mp, fsb);
>  
>  	return xfs_getfsmap_helper(cur->bc_tp, info, rec, rec_daddr);
> @@ -373,7 +373,7 @@ xfs_getfsmap_datadev_bnobt_helper(
>  	struct xfs_rmap_irec		irec;
>  	xfs_daddr_t			rec_daddr;
>  
> -	rec_daddr = XFS_AGB_TO_DADDR(mp, cur->bc_ag.agno,
> +	rec_daddr = XFS_AGB_TO_DADDR(mp, cur->bc_ag.pag->pag_agno,
>  			rec->ar_startblock);
>  
>  	irec.rm_startblock = rec->ar_startblock;
> diff --git a/fs/xfs/xfs_trace.h b/fs/xfs/xfs_trace.h
> index 808ae337b222..5ba9c6396dcb 100644
> --- a/fs/xfs/xfs_trace.h
> +++ b/fs/xfs/xfs_trace.h
> @@ -3730,7 +3730,7 @@ TRACE_EVENT(xfs_btree_commit_afakeroot,
>  	TP_fast_assign(
>  		__entry->dev = cur->bc_mp->m_super->s_dev;
>  		__entry->btnum = cur->bc_btnum;
> -		__entry->agno = cur->bc_ag.agno;
> +		__entry->agno = cur->bc_ag.pag->pag_agno;
>  		__entry->agbno = cur->bc_ag.afake->af_root;
>  		__entry->levels = cur->bc_ag.afake->af_levels;
>  		__entry->blocks = cur->bc_ag.afake->af_blocks;
> @@ -3845,7 +3845,7 @@ TRACE_EVENT(xfs_btree_bload_block,
>  			__entry->agno = XFS_FSB_TO_AGNO(cur->bc_mp, fsb);
>  			__entry->agbno = XFS_FSB_TO_AGBNO(cur->bc_mp, fsb);
>  		} else {
> -			__entry->agno = cur->bc_ag.agno;
> +			__entry->agno = cur->bc_ag.pag->pag_agno;
>  			__entry->agbno = be32_to_cpu(ptr->s);
>  		}
>  		__entry->nr_records = nr_records;
> -- 
> 2.31.1
> 

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 17/22] xfs: simplify xfs_dialloc_select_ag() return values
  2021-05-06  7:20 ` [PATCH 17/22] xfs: simplify xfs_dialloc_select_ag() return values Dave Chinner
  2021-05-12 12:49   ` Brian Foster
@ 2021-05-12 22:55   ` Darrick J. Wong
  1 sibling, 0 replies; 87+ messages in thread
From: Darrick J. Wong @ 2021-05-12 22:55 UTC (permalink / raw)
  To: Dave Chinner; +Cc: linux-xfs

On Thu, May 06, 2021 at 05:20:49PM +1000, Dave Chinner wrote:
> From: Dave Chinner <dchinner@redhat.com>
> 
> The only caller of xfs_dialloc_select_ag() will always return
> -ENOSPC to it's caller if the agbp returned from
> xfs_dialloc_select_ag() is NULL. IOWs, failure to find a candidate
> AGI we can allocate inodes from is always an ENOSPC condition, so
> move this logic up into xfs_dialloc_select_ag() so we can simplify
> the return logic in this function.
> 
> xfs_dialloc_select_ag() now only ever returns 0 with a locked
> agbp, or an error with no agbp.
> 
> Signed-off-by: Dave Chinner <dchinner@redhat.com>

Woo nice cleanup!
Reviewed-by: Darrick J. Wong <djwong@kernel.org>

--D

> ---
>  fs/xfs/libxfs/xfs_ialloc.c | 23 ++++++++---------------
>  fs/xfs/xfs_inode.c         |  3 ---
>  2 files changed, 8 insertions(+), 18 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_ialloc.c b/fs/xfs/libxfs/xfs_ialloc.c
> index 4540fbcd68a3..872591e8f5cb 100644
> --- a/fs/xfs/libxfs/xfs_ialloc.c
> +++ b/fs/xfs/libxfs/xfs_ialloc.c
> @@ -1717,7 +1717,7 @@ xfs_dialloc_roll(
>   * This function will ensure that the selected AG has free inodes available to
>   * allocate from. The selected AGI will be returned locked to the caller, and it
>   * will allocate more free inodes if required. If no free inodes are found or
> - * can be allocated, no AGI will be returned.
> + * can be allocated, -ENOSPC be returned.
>   */
>  int
>  xfs_dialloc_select_ag(
> @@ -1730,7 +1730,6 @@ xfs_dialloc_select_ag(
>  	struct xfs_buf		*agbp;
>  	xfs_agnumber_t		agno;
>  	int			error;
> -	bool			noroom = false;
>  	xfs_agnumber_t		start_agno;
>  	struct xfs_perag	*pag;
>  	struct xfs_ino_geometry	*igeo = M_IGEO(mp);
> @@ -1744,7 +1743,7 @@ xfs_dialloc_select_ag(
>  	 */
>  	start_agno = xfs_ialloc_ag_select(*tpp, parent, mode);
>  	if (start_agno == NULLAGNUMBER)
> -		return 0;
> +		return -ENOSPC;
>  
>  	/*
>  	 * If we have already hit the ceiling of inode blocks then clear
> @@ -1757,7 +1756,6 @@ xfs_dialloc_select_ag(
>  	if (igeo->maxicount &&
>  	    percpu_counter_read_positive(&mp->m_icount) + igeo->ialloc_inos
>  							> igeo->maxicount) {
> -		noroom = true;
>  		okalloc = false;
>  	}
>  
> @@ -1794,10 +1792,8 @@ xfs_dialloc_select_ag(
>  		if (error)
>  			break;
>  
> -		if (pag->pagi_freecount) {
> -			xfs_perag_put(pag);
> +		if (pag->pagi_freecount)
>  			goto found_ag;
> -		}
>  
>  		if (!okalloc)
>  			goto nextag_relse_buffer;
> @@ -1805,9 +1801,6 @@ xfs_dialloc_select_ag(
>  		error = xfs_ialloc_ag_alloc(*tpp, agbp, pag);
>  		if (error < 0) {
>  			xfs_trans_brelse(*tpp, agbp);
> -
> -			if (error == -ENOSPC)
> -				error = 0;
>  			break;
>  		}
>  
> @@ -1818,12 +1811,11 @@ xfs_dialloc_select_ag(
>  			 * allocate one of the new inodes.
>  			 */
>  			ASSERT(pag->pagi_freecount > 0);
> -			xfs_perag_put(pag);
>  
>  			error = xfs_dialloc_roll(tpp, agbp);
>  			if (error) {
>  				xfs_buf_relse(agbp);
> -				return error;
> +				break;
>  			}
>  			goto found_ag;
>  		}
> @@ -1831,16 +1823,17 @@ xfs_dialloc_select_ag(
>  nextag_relse_buffer:
>  		xfs_trans_brelse(*tpp, agbp);
>  nextag:
> -		xfs_perag_put(pag);
>  		if (++agno == mp->m_sb.sb_agcount)
>  			agno = 0;
>  		if (agno == start_agno)
> -			return noroom ? -ENOSPC : 0;
> +			break;
> +		xfs_perag_put(pag);
>  	}
>  
>  	xfs_perag_put(pag);
> -	return error;
> +	return error ? error : -ENOSPC;
>  found_ag:
> +	xfs_perag_put(pag);
>  	*IO_agbp = agbp;
>  	return 0;
>  }
> diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
> index 25910b145d70..3918c99fa95b 100644
> --- a/fs/xfs/xfs_inode.c
> +++ b/fs/xfs/xfs_inode.c
> @@ -923,9 +923,6 @@ xfs_dir_ialloc(
>  	if (error)
>  		return error;
>  
> -	if (!agibp)
> -		return -ENOSPC;
> -
>  	/* Allocate an inode from the selected AG */
>  	error = xfs_dialloc_ag(*tpp, agibp, parent_ino, &ino);
>  	if (error)
> -- 
> 2.31.1
> 

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 18/22] xfs: collapse AG selection for inode allocation
  2021-05-06  7:20 ` [PATCH 18/22] xfs: collapse AG selection for inode allocation Dave Chinner
  2021-05-12 12:52   ` Brian Foster
@ 2021-05-12 23:11   ` Darrick J. Wong
  2021-05-18  1:29     ` Dave Chinner
  1 sibling, 1 reply; 87+ messages in thread
From: Darrick J. Wong @ 2021-05-12 23:11 UTC (permalink / raw)
  To: Dave Chinner; +Cc: linux-xfs

On Thu, May 06, 2021 at 05:20:50PM +1000, Dave Chinner wrote:
> From: Dave Chinner <dchinner@redhat.com>
> 
> xfs_dialloc_select_ag() does a lot of repetitive work. It first
> calls xfs_ialloc_ag_select() to select the AG to start allocation
> attempts in, which can do up to two entire loops across the perags
> that inodes can be allocated in. This is simply checking if there is
> spce available to allocate inodes in an AG, and it returns when it
> finds the first candidate AG.
> 
> xfs_dialloc_select_ag() then does it's own iterative walk across
> all the perags locking the AGIs and trying to allocate inodes from
> the locked AG. It also doesn't limit the search to mp->m_maxagi,
> so it will walk all AGs whether they can allocate inodes or not.
> 
> Hence if we are really low on inodes, we could do almost 3 entire
> walks across the whole perag range before we find an allocation
> group we can allocate inodes in or report ENOSPC.
> 
> Because xfs_ialloc_ag_select() returns on the first candidate AG it
> finds, we can simply do these checks directly in
> xfs_dialloc_select_ag() before we lock and try to allocate inodes.
> This reduces the inode allocation pass down to 2 perag sweeps at
> most - one for aligned inode cluster allocation and if we can't
> allocate full, aligned inode clusters anywhere we'll do another pass
> trying to do sparse inode cluster allocation.
> 
> This also removes a big chunk of duplicate code.

Soooooo... we did an AG walk to pick the optimal starting point of an AG
walk?  Heh.

> 
> Signed-off-by: Dave Chinner <dchinner@redhat.com>
> ---
>  fs/xfs/libxfs/xfs_ialloc.c | 221 +++++++++++++------------------------
>  1 file changed, 75 insertions(+), 146 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_ialloc.c b/fs/xfs/libxfs/xfs_ialloc.c
> index 872591e8f5cb..b22556556bba 100644
> --- a/fs/xfs/libxfs/xfs_ialloc.c
> +++ b/fs/xfs/libxfs/xfs_ialloc.c
> @@ -899,139 +899,6 @@ xfs_ialloc_ag_alloc(
>  	return 0;
>  }
>  
> -STATIC xfs_agnumber_t
> -xfs_ialloc_next_ag(
> -	xfs_mount_t	*mp)
> -{
> -	xfs_agnumber_t	agno;
> -
> -	spin_lock(&mp->m_agirotor_lock);
> -	agno = mp->m_agirotor;
> -	if (++mp->m_agirotor >= mp->m_maxagi)
> -		mp->m_agirotor = 0;
> -	spin_unlock(&mp->m_agirotor_lock);
> -
> -	return agno;
> -}
> -
> -/*
> - * Select an allocation group to look for a free inode in, based on the parent
> - * inode and the mode.  Return the allocation group buffer.
> - */
> -STATIC xfs_agnumber_t
> -xfs_ialloc_ag_select(
> -	xfs_trans_t	*tp,		/* transaction pointer */
> -	xfs_ino_t	parent,		/* parent directory inode number */
> -	umode_t		mode)		/* bits set to indicate file type */
> -{
> -	xfs_agnumber_t	agcount;	/* number of ag's in the filesystem */
> -	xfs_agnumber_t	agno;		/* current ag number */
> -	int		flags;		/* alloc buffer locking flags */
> -	xfs_extlen_t	ineed;		/* blocks needed for inode allocation */
> -	xfs_extlen_t	longest = 0;	/* longest extent available */
> -	xfs_mount_t	*mp;		/* mount point structure */
> -	int		needspace;	/* file mode implies space allocated */
> -	xfs_perag_t	*pag;		/* per allocation group data */
> -	xfs_agnumber_t	pagno;		/* parent (starting) ag number */
> -	int		error;
> -
> -	/*
> -	 * Files of these types need at least one block if length > 0
> -	 * (and they won't fit in the inode, but that's hard to figure out).
> -	 */
> -	needspace = S_ISDIR(mode) || S_ISREG(mode) || S_ISLNK(mode);
> -	mp = tp->t_mountp;
> -	agcount = mp->m_maxagi;
> -	if (S_ISDIR(mode))
> -		pagno = xfs_ialloc_next_ag(mp);
> -	else {
> -		pagno = XFS_INO_TO_AGNO(mp, parent);
> -		if (pagno >= agcount)
> -			pagno = 0;
> -	}
> -
> -	ASSERT(pagno < agcount);
> -
> -	/*
> -	 * Loop through allocation groups, looking for one with a little
> -	 * free space in it.  Note we don't look for free inodes, exactly.
> -	 * Instead, we include whether there is a need to allocate inodes
> -	 * to mean that blocks must be allocated for them,
> -	 * if none are currently free.
> -	 */
> -	agno = pagno;
> -	flags = XFS_ALLOC_FLAG_TRYLOCK;
> -	for (;;) {
> -		pag = xfs_perag_get(mp, agno);
> -		if (!pag->pagi_inodeok) {
> -			xfs_ialloc_next_ag(mp);
> -			goto nextag;
> -		}
> -
> -		if (!pag->pagi_init) {
> -			error = xfs_ialloc_pagi_init(mp, tp, agno);
> -			if (error)
> -				goto nextag;
> -		}
> -
> -		if (pag->pagi_freecount) {
> -			xfs_perag_put(pag);
> -			return agno;
> -		}
> -
> -		if (!pag->pagf_init) {
> -			error = xfs_alloc_pagf_init(mp, tp, agno, flags);
> -			if (error)
> -				goto nextag;
> -		}
> -
> -		/*
> -		 * Check that there is enough free space for the file plus a
> -		 * chunk of inodes if we need to allocate some. If this is the
> -		 * first pass across the AGs, take into account the potential
> -		 * space needed for alignment of inode chunks when checking the
> -		 * longest contiguous free space in the AG - this prevents us
> -		 * from getting ENOSPC because we have free space larger than
> -		 * ialloc_blks but alignment constraints prevent us from using
> -		 * it.
> -		 *
> -		 * If we can't find an AG with space for full alignment slack to
> -		 * be taken into account, we must be near ENOSPC in all AGs.
> -		 * Hence we don't include alignment for the second pass and so
> -		 * if we fail allocation due to alignment issues then it is most
> -		 * likely a real ENOSPC condition.
> -		 */
> -		ineed = M_IGEO(mp)->ialloc_min_blks;
> -		if (flags && ineed > 1)
> -			ineed += M_IGEO(mp)->cluster_align;
> -		longest = pag->pagf_longest;
> -		if (!longest)
> -			longest = pag->pagf_flcount > 0;
> -
> -		if (pag->pagf_freeblks >= needspace + ineed &&
> -		    longest >= ineed) {
> -			xfs_perag_put(pag);
> -			return agno;
> -		}
> -nextag:
> -		xfs_perag_put(pag);
> -		/*
> -		 * No point in iterating over the rest, if we're shutting
> -		 * down.
> -		 */
> -		if (XFS_FORCED_SHUTDOWN(mp))
> -			return NULLAGNUMBER;
> -		agno++;
> -		if (agno >= agcount)
> -			agno = 0;
> -		if (agno == pagno) {
> -			if (flags == 0)
> -				return NULLAGNUMBER;
> -			flags = 0;
> -		}
> -	}
> -}
> -
>  /*
>   * Try to retrieve the next record to the left/right from the current one.
>   */
> @@ -1708,6 +1575,21 @@ xfs_dialloc_roll(
>  	return 0;
>  }
>  
> +STATIC xfs_agnumber_t
> +xfs_ialloc_next_ag(
> +	xfs_mount_t	*mp)
> +{
> +	xfs_agnumber_t	agno;
> +
> +	spin_lock(&mp->m_agirotor_lock);
> +	agno = mp->m_agirotor;
> +	if (++mp->m_agirotor >= mp->m_maxagi)
> +		mp->m_agirotor = 0;
> +	spin_unlock(&mp->m_agirotor_lock);
> +
> +	return agno;
> +}
> +
>  /*
>   * Select and prepare an AG for inode allocation.
>   *
> @@ -1734,16 +1616,23 @@ xfs_dialloc_select_ag(
>  	struct xfs_perag	*pag;
>  	struct xfs_ino_geometry	*igeo = M_IGEO(mp);
>  	bool			okalloc = true;
> +	int			needspace;
> +	int			flags;
>  
>  	*IO_agbp = NULL;
>  
>  	/*
> -	 * We do not have an agbp, so select an initial allocation
> -	 * group for inode allocation.
> +	 * Files of these types need at least one block if length > 0
> +	 * (and they won't fit in the inode, but that's hard to figure out).

Uh, what is length here?  Seeing as most directories and symlinks
probably end up in local format, is this needspace computation really
true?

I guess it doesn't hurt to be cautious and assume that directories can
expand and that people are aggressively symlinking.  But maybe this
comment could be rephrased to something like:

	/*
	 * Directories, symlinks, and regular files frequently allocate
	 * at least one block, so factor that potential expansion when
	 * we examine whether an AG has enough space for file creation.
	 */
	needspace = S_ISDIR(mode)...;

With that clarified,
Reviewed-by: Darrick J. Wong <djwong@kernel.org>

--D

>  	 */
> -	start_agno = xfs_ialloc_ag_select(*tpp, parent, mode);
> -	if (start_agno == NULLAGNUMBER)
> -		return -ENOSPC;
> +	needspace = S_ISDIR(mode) || S_ISREG(mode) || S_ISLNK(mode);
> +	if (S_ISDIR(mode))
> +		start_agno = xfs_ialloc_next_ag(mp);
> +	else {
> +		start_agno = XFS_INO_TO_AGNO(mp, parent);
> +		if (start_agno >= mp->m_maxagi)
> +			start_agno = 0;
> +	}
>  
>  	/*
>  	 * If we have already hit the ceiling of inode blocks then clear
> @@ -1765,12 +1654,14 @@ xfs_dialloc_select_ag(
>  	 * allocation groups upward, wrapping at the end.
>  	 */
>  	agno = start_agno;
> +	flags = XFS_ALLOC_FLAG_TRYLOCK;
>  	for (;;) {
> +		xfs_extlen_t	ineed;
> +		xfs_extlen_t	longest = 0;
> +
>  		pag = xfs_perag_get(mp, agno);
> -		if (!pag->pagi_inodeok) {
> -			xfs_ialloc_next_ag(mp);
> +		if (!pag->pagi_inodeok)
>  			goto nextag;
> -		}
>  
>  		if (!pag->pagi_init) {
>  			error = xfs_ialloc_pagi_init(mp, *tpp, agno);
> @@ -1778,10 +1669,41 @@ xfs_dialloc_select_ag(
>  				break;
>  		}
>  
> +		if (!pag->pagi_freecount)
> +			goto nextag;
> +		if (!okalloc)
> +			goto nextag;
> +
> +		if (!pag->pagf_init) {
> +			error = xfs_alloc_pagf_init(mp, *tpp, agno, flags);
> +			if (error)
> +				goto nextag;
> +		}
> +
>  		/*
> -		 * Do a first racy fast path check if this AG is usable.
> +		 * Check that there is enough free space for the file plus a
> +		 * chunk of inodes if we need to allocate some. If this is the
> +		 * first pass across the AGs, take into account the potential
> +		 * space needed for alignment of inode chunks when checking the
> +		 * longest contiguous free space in the AG - this prevents us
> +		 * from getting ENOSPC because we have free space larger than
> +		 * ialloc_blks but alignment constraints prevent us from using
> +		 * it.
> +		 *
> +		 * If we can't find an AG with space for full alignment slack to
> +		 * be taken into account, we must be near ENOSPC in all AGs.
> +		 * Hence we don't include alignment for the second pass and so
> +		 * if we fail allocation due to alignment issues then it is most
> +		 * likely a real ENOSPC condition.
>  		 */
> -		if (!pag->pagi_freecount && !okalloc)
> +		ineed = M_IGEO(mp)->ialloc_min_blks;
> +		if (flags && ineed > 1)
> +			ineed += M_IGEO(mp)->cluster_align;
> +		longest = pag->pagf_longest;
> +		if (!longest)
> +			longest = pag->pagf_flcount > 0;
> +
> +		if (pag->pagf_freeblks < needspace + ineed || longest < ineed)
>  			goto nextag;
>  
>  		/*
> @@ -1823,10 +1745,17 @@ xfs_dialloc_select_ag(
>  nextag_relse_buffer:
>  		xfs_trans_brelse(*tpp, agbp);
>  nextag:
> -		if (++agno == mp->m_sb.sb_agcount)
> -			agno = 0;
> -		if (agno == start_agno)
> +		if (XFS_FORCED_SHUTDOWN(mp)) {
> +			error = -EFSCORRUPTED;
>  			break;
> +		}
> +		if (++agno == mp->m_maxagi)
> +			agno = 0;
> +		if (agno == start_agno) {
> +			if (!flags)
> +				break;
> +			flags = 0;
> +		}
>  		xfs_perag_put(pag);
>  	}
>  
> -- 
> 2.31.1
> 

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 19/22] xfs: get rid of xfs_dir_ialloc()
  2021-05-06  7:20 ` [PATCH 19/22] xfs: get rid of xfs_dir_ialloc() Dave Chinner
                     ` (2 preceding siblings ...)
  2021-05-12 12:52   ` [PATCH 19/22] xfs: get rid of xfs_dir_ialloc() Brian Foster
@ 2021-05-12 23:19   ` Darrick J. Wong
  3 siblings, 0 replies; 87+ messages in thread
From: Darrick J. Wong @ 2021-05-12 23:19 UTC (permalink / raw)
  To: Dave Chinner; +Cc: linux-xfs

On Thu, May 06, 2021 at 05:20:51PM +1000, Dave Chinner wrote:
> From: Dave Chinner <dchinner@redhat.com>
> 
> This is just a simple wrapper around the per-ag inode allocation
> that doesn't need to exist. The internal mechanism to select and
> allocate within an AG does not need to be exposed outside
> xfs_ialloc.c, and it being exposed simply makes it harder to follow
> the code and simplify it.
> 
> This is simplified by internalising xf_dialloc_select_ag() and
> xfs_dialloc_ag() into a single xfs_dialloc() function and then
> xfs_dir_ialloc() can go away.
> 
> Signed-off-by: Dave Chinner <dchinner@redhat.com>

Aha, I see what you did here with disappearing xfs_dialloc_select_ag.
Ignore my later comments about 5.11 and whatnot.

This'll cause some churn in the metadata directory tree patchset, but
it's not like that hasn't happened 5x before. :P

Reviewed-by: Darrick J. Wong <djwong@kernel.org>

--D

> ---
>  fs/xfs/libxfs/xfs_ialloc.c | 15 +++++----
>  fs/xfs/libxfs/xfs_ialloc.h | 27 +++-------------
>  fs/xfs/xfs_inode.c         | 66 +++++++-------------------------------
>  fs/xfs/xfs_inode.h         |  9 +++---
>  fs/xfs/xfs_qm.c            |  9 ++++--
>  fs/xfs/xfs_symlink.c       |  9 ++++--
>  6 files changed, 43 insertions(+), 92 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_ialloc.c b/fs/xfs/libxfs/xfs_ialloc.c
> index b22556556bba..2c0ef2dd46d9 100644
> --- a/fs/xfs/libxfs/xfs_ialloc.c
> +++ b/fs/xfs/libxfs/xfs_ialloc.c
> @@ -1602,24 +1602,23 @@ xfs_ialloc_next_ag(
>   * can be allocated, -ENOSPC be returned.
>   */
>  int
> -xfs_dialloc_select_ag(
> +xfs_dialloc(
>  	struct xfs_trans	**tpp,
>  	xfs_ino_t		parent,
>  	umode_t			mode,
> -	struct xfs_buf		**IO_agbp)
> +	xfs_ino_t		*new_ino)
>  {
>  	struct xfs_mount	*mp = (*tpp)->t_mountp;
>  	struct xfs_buf		*agbp;
>  	xfs_agnumber_t		agno;
> -	int			error;
> +	int			error = 0;
>  	xfs_agnumber_t		start_agno;
>  	struct xfs_perag	*pag;
>  	struct xfs_ino_geometry	*igeo = M_IGEO(mp);
>  	bool			okalloc = true;
>  	int			needspace;
>  	int			flags;
> -
> -	*IO_agbp = NULL;
> +	xfs_ino_t		ino;
>  
>  	/*
>  	 * Files of these types need at least one block if length > 0
> @@ -1763,7 +1762,11 @@ xfs_dialloc_select_ag(
>  	return error ? error : -ENOSPC;
>  found_ag:
>  	xfs_perag_put(pag);
> -	*IO_agbp = agbp;
> +	/* Allocate an inode in the found AG */
> +	error = xfs_dialloc_ag(*tpp, agbp, parent, &ino);
> +	if (error)
> +		return error;
> +	*new_ino = ino;
>  	return 0;
>  }
>  
> diff --git a/fs/xfs/libxfs/xfs_ialloc.h b/fs/xfs/libxfs/xfs_ialloc.h
> index 3511086a7ae1..886f6748fb22 100644
> --- a/fs/xfs/libxfs/xfs_ialloc.h
> +++ b/fs/xfs/libxfs/xfs_ialloc.h
> @@ -33,30 +33,11 @@ xfs_make_iptr(struct xfs_mount *mp, struct xfs_buf *b, int o)
>  }
>  
>  /*
> - * Allocate an inode on disk.
> - * Mode is used to tell whether the new inode will need space, and whether
> - * it is a directory.
> - *
> - * There are two phases to inode allocation: selecting an AG and ensuring
> - * that it contains free inodes, followed by allocating one of the free
> - * inodes. xfs_dialloc_select_ag() does the former and returns a locked AGI
> - * to the caller, ensuring that followup call to xfs_dialloc_ag() will
> - * have free inodes to allocate from. xfs_dialloc_ag() will return the inode
> - * number of the free inode we allocated.
> + * Allocate an inode on disk.  Mode is used to tell whether the new inode will
> + * need space, and whether it is a directory.
>   */
> -int					/* error */
> -xfs_dialloc_select_ag(
> -	struct xfs_trans **tpp,		/* double pointer of transaction */
> -	xfs_ino_t	parent,		/* parent inode (directory) */
> -	umode_t		mode,		/* mode bits for new inode */
> -	struct xfs_buf	**IO_agbp);
> -
> -int
> -xfs_dialloc_ag(
> -	struct xfs_trans	*tp,
> -	struct xfs_buf		*agbp,
> -	xfs_ino_t		parent,
> -	xfs_ino_t		*inop);
> +int xfs_dialloc(struct xfs_trans **tpp, xfs_ino_t parent, umode_t mode,
> +		xfs_ino_t *new_ino);
>  
>  /*
>   * Free disk inode.  Carefully avoids touching the incore inode, all
> diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
> index 3918c99fa95b..26668b6846e2 100644
> --- a/fs/xfs/xfs_inode.c
> +++ b/fs/xfs/xfs_inode.c
> @@ -749,7 +749,7 @@ xfs_inode_inherit_flags2(
>   * Initialise a newly allocated inode and return the in-core inode to the
>   * caller locked exclusively.
>   */
> -static int
> +int
>  xfs_init_new_inode(
>  	struct user_namespace	*mnt_userns,
>  	struct xfs_trans	*tp,
> @@ -885,54 +885,6 @@ xfs_init_new_inode(
>  	return 0;
>  }
>  
> -/*
> - * Allocates a new inode from disk and return a pointer to the incore copy. This
> - * routine will internally commit the current transaction and allocate a new one
> - * if we needed to allocate more on-disk free inodes to perform the requested
> - * operation.
> - *
> - * If we are allocating quota inodes, we do not have a parent inode to attach to
> - * or associate with (i.e. dp == NULL) because they are not linked into the
> - * directory structure - they are attached directly to the superblock - and so
> - * have no parent.
> - */
> -int
> -xfs_dir_ialloc(
> -	struct user_namespace	*mnt_userns,
> -	struct xfs_trans	**tpp,
> -	struct xfs_inode	*dp,
> -	umode_t			mode,
> -	xfs_nlink_t		nlink,
> -	dev_t			rdev,
> -	prid_t			prid,
> -	bool			init_xattrs,
> -	struct xfs_inode	**ipp)
> -{
> -	struct xfs_buf		*agibp;
> -	xfs_ino_t		parent_ino = dp ? dp->i_ino : 0;
> -	xfs_ino_t		ino;
> -	int			error;
> -
> -	ASSERT((*tpp)->t_flags & XFS_TRANS_PERM_LOG_RES);
> -
> -	/*
> -	 * Call the space management code to pick the on-disk inode to be
> -	 * allocated.
> -	 */
> -	error = xfs_dialloc_select_ag(tpp, parent_ino, mode, &agibp);
> -	if (error)
> -		return error;
> -
> -	/* Allocate an inode from the selected AG */
> -	error = xfs_dialloc_ag(*tpp, agibp, parent_ino, &ino);
> -	if (error)
> -		return error;
> -	ASSERT(ino != NULLFSINO);
> -
> -	return xfs_init_new_inode(mnt_userns, *tpp, dp, ino, mode, nlink, rdev,
> -				  prid, init_xattrs, ipp);
> -}
> -
>  /*
>   * Decrement the link count on an inode & log the change.  If this causes the
>   * link count to go to zero, move the inode to AGI unlinked list so that it can
> @@ -990,6 +942,7 @@ xfs_create(
>  	struct xfs_dquot	*pdqp = NULL;
>  	struct xfs_trans_res	*tres;
>  	uint			resblks;
> +	xfs_ino_t		ino;
>  
>  	trace_xfs_create(dp, name);
>  
> @@ -1046,14 +999,16 @@ xfs_create(
>  	 * entry pointing to them, but a directory also the "." entry
>  	 * pointing to itself.
>  	 */
> -	error = xfs_dir_ialloc(mnt_userns, &tp, dp, mode, is_dir ? 2 : 1, rdev,
> -			       prid, init_xattrs, &ip);
> +	error = xfs_dialloc(&tp, dp->i_ino, mode, &ino);
> +	if (!error)
> +		error = xfs_init_new_inode(mnt_userns, tp, dp, ino, mode,
> +				is_dir ? 2 : 1, rdev, prid, init_xattrs, &ip);
>  	if (error)
>  		goto out_trans_cancel;
>  
>  	/*
>  	 * Now we join the directory inode to the transaction.  We do not do it
> -	 * earlier because xfs_dir_ialloc might commit the previous transaction
> +	 * earlier because xfs_dialloc might commit the previous transaction
>  	 * (and release all the locks).  An error from here on will result in
>  	 * the transaction cancel unlocking dp so don't do it explicitly in the
>  	 * error path.
> @@ -1143,6 +1098,7 @@ xfs_create_tmpfile(
>  	struct xfs_dquot	*pdqp = NULL;
>  	struct xfs_trans_res	*tres;
>  	uint			resblks;
> +	xfs_ino_t		ino;
>  
>  	if (XFS_FORCED_SHUTDOWN(mp))
>  		return -EIO;
> @@ -1167,8 +1123,10 @@ xfs_create_tmpfile(
>  	if (error)
>  		goto out_release_dquots;
>  
> -	error = xfs_dir_ialloc(mnt_userns, &tp, dp, mode, 0, 0, prid,
> -				false, &ip);
> +	error = xfs_dialloc(&tp, dp->i_ino, mode, &ino);
> +	if (!error)
> +		error = xfs_init_new_inode(mnt_userns, tp, dp, ino, mode,
> +				0, 0, prid, false, &ip);
>  	if (error)
>  		goto out_trans_cancel;
>  
> diff --git a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h
> index ca826cfba91c..4b6703dbffb8 100644
> --- a/fs/xfs/xfs_inode.h
> +++ b/fs/xfs/xfs_inode.h
> @@ -431,11 +431,10 @@ void		xfs_lock_two_inodes(struct xfs_inode *ip0, uint ip0_mode,
>  xfs_extlen_t	xfs_get_extsz_hint(struct xfs_inode *ip);
>  xfs_extlen_t	xfs_get_cowextsz_hint(struct xfs_inode *ip);
>  
> -int		xfs_dir_ialloc(struct user_namespace *mnt_userns,
> -			       struct xfs_trans **tpp, struct xfs_inode *dp,
> -			       umode_t mode, xfs_nlink_t nlink, dev_t dev,
> -			       prid_t prid, bool need_xattr,
> -			       struct xfs_inode **ipp);
> +int xfs_init_new_inode(struct user_namespace *mnt_userns, struct xfs_trans *tp,
> +		struct xfs_inode *pip, xfs_ino_t ino, umode_t mode,
> +		xfs_nlink_t nlink, dev_t rdev, prid_t prid, bool init_xattrs,
> +		struct xfs_inode **ipp);
>  
>  static inline int
>  xfs_itruncate_extents(
> diff --git a/fs/xfs/xfs_qm.c b/fs/xfs/xfs_qm.c
> index f7baf4dc2554..fe341f3fd419 100644
> --- a/fs/xfs/xfs_qm.c
> +++ b/fs/xfs/xfs_qm.c
> @@ -24,6 +24,7 @@
>  #include "xfs_icache.h"
>  #include "xfs_error.h"
>  #include "xfs_ag.h"
> +#include "xfs_ialloc.h"
>  
>  /*
>   * The global quota manager. There is only one of these for the entire
> @@ -788,8 +789,12 @@ xfs_qm_qino_alloc(
>  		return error;
>  
>  	if (need_alloc) {
> -		error = xfs_dir_ialloc(&init_user_ns, &tp, NULL, S_IFREG, 1, 0,
> -				       0, false, ipp);
> +		xfs_ino_t	ino;
> +
> +		error = xfs_dialloc(&tp, 0, S_IFREG, &ino);
> +		if (!error)
> +			error = xfs_init_new_inode(&init_user_ns, tp, NULL, ino,
> +					S_IFREG, 1, 0, 0, false, ipp);
>  		if (error) {
>  			xfs_trans_cancel(tp);
>  			return error;
> diff --git a/fs/xfs/xfs_symlink.c b/fs/xfs/xfs_symlink.c
> index b4fa70282383..44596c31f4c9 100644
> --- a/fs/xfs/xfs_symlink.c
> +++ b/fs/xfs/xfs_symlink.c
> @@ -21,6 +21,7 @@
>  #include "xfs_trans_space.h"
>  #include "xfs_trace.h"
>  #include "xfs_trans.h"
> +#include "xfs_ialloc.h"
>  
>  /* ----- Kernel only functions below ----- */
>  int
> @@ -161,6 +162,7 @@ xfs_symlink(
>  	struct xfs_dquot	*gdqp = NULL;
>  	struct xfs_dquot	*pdqp = NULL;
>  	uint			resblks;
> +	xfs_ino_t		ino;
>  
>  	*ipp = NULL;
>  
> @@ -223,8 +225,11 @@ xfs_symlink(
>  	/*
>  	 * Allocate an inode for the symlink.
>  	 */
> -	error = xfs_dir_ialloc(mnt_userns, &tp, dp, S_IFLNK | (mode & ~S_IFMT),
> -			       1, 0, prid, false, &ip);
> +	error = xfs_dialloc(&tp, dp->i_ino, S_IFLNK, &ino);
> +	if (!error)
> +		error = xfs_init_new_inode(mnt_userns, tp, dp, ino,
> +				S_IFLNK | (mode & ~S_IFMT), 1, 0, prid,
> +				false, &ip);
>  	if (error)
>  		goto out_trans_cancel;
>  
> -- 
> 2.31.1
> 

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 20/22] xfs: inode allocation can use a single perag instance
  2021-05-06  7:20 ` [PATCH 20/22] xfs: inode allocation can use a single perag instance Dave Chinner
  2021-05-12 12:52   ` Brian Foster
@ 2021-05-12 23:19   ` Darrick J. Wong
  1 sibling, 0 replies; 87+ messages in thread
From: Darrick J. Wong @ 2021-05-12 23:19 UTC (permalink / raw)
  To: Dave Chinner; +Cc: linux-xfs

On Thu, May 06, 2021 at 05:20:52PM +1000, Dave Chinner wrote:
> From: Dave Chinner <dchinner@redhat.com>
> 
> Now that we've internalised the two-phase inode allocation, we can
> now easily make the AG selection and allocation atomic from the
> perspective of a single perag context. This will ensure AGs going
> offline/away cannot occur between the selection and allocation
> steps.
> 
> Signed-off-by: Dave Chinner <dchinner@redhat.com>

Make sense.
Reviewed-by: Darrick J. Wong <djwong@kernel.org>

--D

> ---
>  fs/xfs/libxfs/xfs_ialloc.c | 6 +++---
>  1 file changed, 3 insertions(+), 3 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_ialloc.c b/fs/xfs/libxfs/xfs_ialloc.c
> index 2c0ef2dd46d9..d749bb7c7a69 100644
> --- a/fs/xfs/libxfs/xfs_ialloc.c
> +++ b/fs/xfs/libxfs/xfs_ialloc.c
> @@ -1432,6 +1432,7 @@ int
>  xfs_dialloc_ag(
>  	struct xfs_trans	*tp,
>  	struct xfs_buf		*agbp,
> +	struct xfs_perag	*pag,
>  	xfs_ino_t		parent,
>  	xfs_ino_t		*inop)
>  {
> @@ -1446,7 +1447,6 @@ xfs_dialloc_ag(
>  	int				error;
>  	int				offset;
>  	int				i;
> -	struct xfs_perag		*pag = agbp->b_pag;
>  
>  	if (!xfs_sb_version_hasfinobt(&mp->m_sb))
>  		return xfs_dialloc_ag_inobt(tp, agbp, pag, parent, inop);
> @@ -1761,9 +1761,9 @@ xfs_dialloc(
>  	xfs_perag_put(pag);
>  	return error ? error : -ENOSPC;
>  found_ag:
> -	xfs_perag_put(pag);
>  	/* Allocate an inode in the found AG */
> -	error = xfs_dialloc_ag(*tpp, agbp, parent, &ino);
> +	error = xfs_dialloc_ag(*tpp, agbp, pag, parent, &ino);
> +	xfs_perag_put(pag);
>  	if (error)
>  		return error;
>  	*new_ino = ino;
> -- 
> 2.31.1
> 

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 11/22] xfs: add a perag to the btree cursor
  2021-05-12 22:40   ` Darrick J. Wong
@ 2021-05-13  0:12     ` Dave Chinner
  2021-05-13  0:55       ` Darrick J. Wong
  0 siblings, 1 reply; 87+ messages in thread
From: Dave Chinner @ 2021-05-13  0:12 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs

On Wed, May 12, 2021 at 03:40:06PM -0700, Darrick J. Wong wrote:
> On Thu, May 06, 2021 at 05:20:43PM +1000, Dave Chinner wrote:
> > From: Dave Chinner <dchinner@redhat.com>
> > 
> > Which will eventually completely replace the agno in it.
> > 
> > Signed-off-by: Dave Chinner <dchinner@redhat.com>
> > ---
> >  fs/xfs/libxfs/xfs_alloc.c          | 25 +++++++++++++++----------
> >  fs/xfs/libxfs/xfs_alloc_btree.c    | 13 ++++++++++---
> >  fs/xfs/libxfs/xfs_alloc_btree.h    |  3 ++-
> >  fs/xfs/libxfs/xfs_btree.c          |  2 ++
> >  fs/xfs/libxfs/xfs_btree.h          |  4 +++-
> >  fs/xfs/libxfs/xfs_ialloc.c         | 16 ++++++++--------
> >  fs/xfs/libxfs/xfs_ialloc_btree.c   | 15 +++++++++++----
> >  fs/xfs/libxfs/xfs_ialloc_btree.h   |  7 ++++---
> >  fs/xfs/libxfs/xfs_refcount.c       |  4 ++--
> >  fs/xfs/libxfs/xfs_refcount_btree.c | 17 ++++++++++++-----
> >  fs/xfs/libxfs/xfs_refcount_btree.h |  2 +-
> >  fs/xfs/libxfs/xfs_rmap.c           |  6 +++---
> >  fs/xfs/libxfs/xfs_rmap_btree.c     | 17 ++++++++++++-----
> >  fs/xfs/libxfs/xfs_rmap_btree.h     |  2 +-
> >  fs/xfs/scrub/agheader_repair.c     | 20 +++++++++++---------
> >  fs/xfs/scrub/bmap.c                |  2 +-
> >  fs/xfs/scrub/common.c              | 12 ++++++------
> >  fs/xfs/scrub/repair.c              |  5 +++--
> >  fs/xfs/xfs_discard.c               |  2 +-
> >  fs/xfs/xfs_fsmap.c                 |  6 +++---
> >  fs/xfs/xfs_reflink.c               |  2 +-
> >  21 files changed, 112 insertions(+), 70 deletions(-)
> > 
> > diff --git a/fs/xfs/libxfs/xfs_alloc.c b/fs/xfs/libxfs/xfs_alloc.c
> > index ce31c00dbf6f..7ec4af6bf494 100644
> > --- a/fs/xfs/libxfs/xfs_alloc.c
> > +++ b/fs/xfs/libxfs/xfs_alloc.c
> > @@ -776,7 +776,8 @@ xfs_alloc_cur_setup(
> >  	 */
> >  	if (!acur->cnt)
> >  		acur->cnt = xfs_allocbt_init_cursor(args->mp, args->tp,
> > -					args->agbp, args->agno, XFS_BTNUM_CNT);
> > +						args->agbp, args->agno,
> > +						args->pag, XFS_BTNUM_CNT);
> 
> If we still have to pass the AG[FI] buffer into the _init_cursor
> functions, why not get the perag reference from the xfs_buf and
> eliminate the agno/pag parameter?  It looks like cursors get their own
> active reference to the perag, so I think only the _stage_cursor
> function needs to be passed a perag structure, right?

Because when I convert this to active/passive perag references, the
buffers only have a passive reference and they can't be converted to
active references.

Active references provide the barrier that prevents high
level code from accessing/entering the AG while a shrink (or other
offline type event) is in the process of tearing down that AG. The
process of tearing down the AG still may require the ability to
read/write to the AG metadata (e.g. checking the AG is fully
empty), so we still need the buffer cache to work while in this
transient offline state. Hence we need passive reference counts for
the buffers, because having cached buffers should not impact on the
functioning of the high level "don't use this AG anymore" barrier.

And when we finally got to tear down the perag, we have to tear down
the buffer cache for that AG, which means we have to wait until all
the buffers have been reclaimed. Which will release all the
references the buffers have on the perag, and so we know it is safe
to tear down the perag because both the active reference count and
the passive reference counts are zero.

IOWs, high level code needs an active reference for part of it's
operation, it needs an active reference that covers the entire
operation and this active reference has to be gained at a place
where it can fail safely (e.g. where AGs are iterated). If we try to
take an active reference from a buffer at random points in time,
we'll end up with failures to get active references in spots were we
cannot cleanly fail.

The example of xfs_allocbt_init_cursor() is that if could fail to
get an active reference from the agbp inside a transaction that has
already dirtied the AGFL. That then leads to an allocation failure
with a dirty transaction and a shutdown.....

Basically, we take an active reference when we start the high level
operation in an AG to protect it, and every other active reference
that the operation takes must be derived from that same perag
instance. Pulling the perag from the bp->b_pag pointer in high level
code is a layering vioaltion - the only time this should ever happen
is in IO verifiers where the passive buffer reference guarantees the
validity of the perag for the buffer cache callouts.

Cheers,

Dave.
-- 
Dave Chinner
david@fromorbit.com

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 09/22] xfs: push perags through the ag reservation callouts
  2021-05-11 12:29   ` Brian Foster
@ 2021-05-13  0:29     ` Dave Chinner
  0 siblings, 0 replies; 87+ messages in thread
From: Dave Chinner @ 2021-05-13  0:29 UTC (permalink / raw)
  To: Brian Foster; +Cc: linux-xfs

On Tue, May 11, 2021 at 08:29:54AM -0400, Brian Foster wrote:
> On Thu, May 06, 2021 at 05:20:41PM +1000, Dave Chinner wrote:
> > From: Dave Chinner <dchinner@redhat.com>
> > 
> > We currently pass an agno from the AG reservation functions to the
> > individual feature accounting functions, which then may have to do
> > perag lookups to access per-AG state. Plumb the perag through from
> > the highest AG reservation layer to the feature callouts so they
> > don't have to look it up again.
> > 
> > Signed-off-by: Dave Chinner <dchinner@redhat.com>
> > ---
> 
> The changes look fine, but the commit log implies we're relieving some
> lower level functions of the need to re-look up perag structs. I don't
> see one perag get/put cycle being removed here, so I suppose either that
> comes later or the commit log is a bit misleading..? Either way, with a
> minor reword of the commit log to clarify that, this otherwise looks
> fine to me.

Future patches use the the perag that is passed down through these
functions. e.g. the next series of patches that pass a perag to the
btree cursor init functions rather than the plain AG. Passing the
pag down the stack ehre means that the lower layers modified in this
patch don't need to look up the perag again.

i.e. read this "don't have to add lookups in future", not as "will
remove existing lookups right now".

Cheers,

Dave.
-- 
Dave Chinner
david@fromorbit.com

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 11/22] xfs: add a perag to the btree cursor
  2021-05-13  0:12     ` Dave Chinner
@ 2021-05-13  0:55       ` Darrick J. Wong
  2021-05-13  1:07         ` Dave Chinner
  0 siblings, 1 reply; 87+ messages in thread
From: Darrick J. Wong @ 2021-05-13  0:55 UTC (permalink / raw)
  To: Dave Chinner; +Cc: linux-xfs

On Thu, May 13, 2021 at 10:12:16AM +1000, Dave Chinner wrote:
> On Wed, May 12, 2021 at 03:40:06PM -0700, Darrick J. Wong wrote:
> > On Thu, May 06, 2021 at 05:20:43PM +1000, Dave Chinner wrote:
> > > From: Dave Chinner <dchinner@redhat.com>
> > > 
> > > Which will eventually completely replace the agno in it.
> > > 
> > > Signed-off-by: Dave Chinner <dchinner@redhat.com>
> > > ---
> > >  fs/xfs/libxfs/xfs_alloc.c          | 25 +++++++++++++++----------
> > >  fs/xfs/libxfs/xfs_alloc_btree.c    | 13 ++++++++++---
> > >  fs/xfs/libxfs/xfs_alloc_btree.h    |  3 ++-
> > >  fs/xfs/libxfs/xfs_btree.c          |  2 ++
> > >  fs/xfs/libxfs/xfs_btree.h          |  4 +++-
> > >  fs/xfs/libxfs/xfs_ialloc.c         | 16 ++++++++--------
> > >  fs/xfs/libxfs/xfs_ialloc_btree.c   | 15 +++++++++++----
> > >  fs/xfs/libxfs/xfs_ialloc_btree.h   |  7 ++++---
> > >  fs/xfs/libxfs/xfs_refcount.c       |  4 ++--
> > >  fs/xfs/libxfs/xfs_refcount_btree.c | 17 ++++++++++++-----
> > >  fs/xfs/libxfs/xfs_refcount_btree.h |  2 +-
> > >  fs/xfs/libxfs/xfs_rmap.c           |  6 +++---
> > >  fs/xfs/libxfs/xfs_rmap_btree.c     | 17 ++++++++++++-----
> > >  fs/xfs/libxfs/xfs_rmap_btree.h     |  2 +-
> > >  fs/xfs/scrub/agheader_repair.c     | 20 +++++++++++---------
> > >  fs/xfs/scrub/bmap.c                |  2 +-
> > >  fs/xfs/scrub/common.c              | 12 ++++++------
> > >  fs/xfs/scrub/repair.c              |  5 +++--
> > >  fs/xfs/xfs_discard.c               |  2 +-
> > >  fs/xfs/xfs_fsmap.c                 |  6 +++---
> > >  fs/xfs/xfs_reflink.c               |  2 +-
> > >  21 files changed, 112 insertions(+), 70 deletions(-)
> > > 
> > > diff --git a/fs/xfs/libxfs/xfs_alloc.c b/fs/xfs/libxfs/xfs_alloc.c
> > > index ce31c00dbf6f..7ec4af6bf494 100644
> > > --- a/fs/xfs/libxfs/xfs_alloc.c
> > > +++ b/fs/xfs/libxfs/xfs_alloc.c
> > > @@ -776,7 +776,8 @@ xfs_alloc_cur_setup(
> > >  	 */
> > >  	if (!acur->cnt)
> > >  		acur->cnt = xfs_allocbt_init_cursor(args->mp, args->tp,
> > > -					args->agbp, args->agno, XFS_BTNUM_CNT);
> > > +						args->agbp, args->agno,
> > > +						args->pag, XFS_BTNUM_CNT);
> > 
> > If we still have to pass the AG[FI] buffer into the _init_cursor
> > functions, why not get the perag reference from the xfs_buf and
> > eliminate the agno/pag parameter?  It looks like cursors get their own
> > active reference to the perag, so I think only the _stage_cursor
> > function needs to be passed a perag structure, right?
> 
> Because when I convert this to active/passive perag references, the
> buffers only have a passive reference and they can't be converted to
> active references.
>
> Active references provide the barrier that prevents high
> level code from accessing/entering the AG while a shrink (or other
> offline type event) is in the process of tearing down that AG. The
> process of tearing down the AG still may require the ability to
> read/write to the AG metadata (e.g. checking the AG is fully
> empty), so we still need the buffer cache to work while in this
> transient offline state. Hence we need passive reference counts for
> the buffers, because having cached buffers should not impact on the
> functioning of the high level "don't use this AG anymore" barrier.

Agreed; it's past time to shift the world towards the idea that one
grabs the incore object and only then starts grabbing buffers.  But even
if you've done it correctly:

	pag = xfs_perag_get_active(agno);
	xfs_alloc_read_agf(tp, ..., &agfbp);

Why not pass in just the buffer?

	cur = xfs_rmapbt_init_cursor(tp, agfbp, pag);

Is the idea here simply that we don't want to give people the idea that
they can just read the agf and pass it to xfs_rmapbt_init_cursor?  In
other words, the third parameter is there to give the people the
impression that pag and agfbp are both equally important tokens, and
that callers must obtain both and pass them in?  No monkeying around
with the buffer's passive reference by higher level code, at all, ever?
I guess I can live with that.  I might just be micro-optimising function
call parameter counts.  :P

--D

> And when we finally got to tear down the perag, we have to tear down
> the buffer cache for that AG, which means we have to wait until all
> the buffers have been reclaimed. Which will release all the
> references the buffers have on the perag, and so we know it is safe
> to tear down the perag because both the active reference count and
> the passive reference counts are zero.
> 
> IOWs, high level code needs an active reference for part of it's
> operation, it needs an active reference that covers the entire
> operation and this active reference has to be gained at a place
> where it can fail safely (e.g. where AGs are iterated). If we try to
> take an active reference from a buffer at random points in time,
> we'll end up with failures to get active references in spots were we
> cannot cleanly fail.
> 
> The example of xfs_allocbt_init_cursor() is that if could fail to
> get an active reference from the agbp inside a transaction that has
> already dirtied the AGFL. That then leads to an allocation failure
> with a dirty transaction and a shutdown.....
> 
> Basically, we take an active reference when we start the high level
> operation in an AG to protect it, and every other active reference
> that the operation takes must be derived from that same perag
> instance. Pulling the perag from the bp->b_pag pointer in high level
> code is a layering vioaltion - the only time this should ever happen
> is in IO verifiers where the passive buffer reference guarantees the
> validity of the perag for the buffer cache callouts.
> 
> Cheers,
> 
> Dave.
> -- 
> Dave Chinner
> david@fromorbit.com

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 11/22] xfs: add a perag to the btree cursor
  2021-05-13  0:55       ` Darrick J. Wong
@ 2021-05-13  1:07         ` Dave Chinner
  2021-05-13  3:49           ` Darrick J. Wong
  0 siblings, 1 reply; 87+ messages in thread
From: Dave Chinner @ 2021-05-13  1:07 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs

On Wed, May 12, 2021 at 05:55:08PM -0700, Darrick J. Wong wrote:
> On Thu, May 13, 2021 at 10:12:16AM +1000, Dave Chinner wrote:
> > On Wed, May 12, 2021 at 03:40:06PM -0700, Darrick J. Wong wrote:
> > > On Thu, May 06, 2021 at 05:20:43PM +1000, Dave Chinner wrote:
> > > > From: Dave Chinner <dchinner@redhat.com>
> > > > 
> > > > Which will eventually completely replace the agno in it.
> > > > 
> > > > Signed-off-by: Dave Chinner <dchinner@redhat.com>
> > > > ---
> > > >  fs/xfs/libxfs/xfs_alloc.c          | 25 +++++++++++++++----------
> > > >  fs/xfs/libxfs/xfs_alloc_btree.c    | 13 ++++++++++---
> > > >  fs/xfs/libxfs/xfs_alloc_btree.h    |  3 ++-
> > > >  fs/xfs/libxfs/xfs_btree.c          |  2 ++
> > > >  fs/xfs/libxfs/xfs_btree.h          |  4 +++-
> > > >  fs/xfs/libxfs/xfs_ialloc.c         | 16 ++++++++--------
> > > >  fs/xfs/libxfs/xfs_ialloc_btree.c   | 15 +++++++++++----
> > > >  fs/xfs/libxfs/xfs_ialloc_btree.h   |  7 ++++---
> > > >  fs/xfs/libxfs/xfs_refcount.c       |  4 ++--
> > > >  fs/xfs/libxfs/xfs_refcount_btree.c | 17 ++++++++++++-----
> > > >  fs/xfs/libxfs/xfs_refcount_btree.h |  2 +-
> > > >  fs/xfs/libxfs/xfs_rmap.c           |  6 +++---
> > > >  fs/xfs/libxfs/xfs_rmap_btree.c     | 17 ++++++++++++-----
> > > >  fs/xfs/libxfs/xfs_rmap_btree.h     |  2 +-
> > > >  fs/xfs/scrub/agheader_repair.c     | 20 +++++++++++---------
> > > >  fs/xfs/scrub/bmap.c                |  2 +-
> > > >  fs/xfs/scrub/common.c              | 12 ++++++------
> > > >  fs/xfs/scrub/repair.c              |  5 +++--
> > > >  fs/xfs/xfs_discard.c               |  2 +-
> > > >  fs/xfs/xfs_fsmap.c                 |  6 +++---
> > > >  fs/xfs/xfs_reflink.c               |  2 +-
> > > >  21 files changed, 112 insertions(+), 70 deletions(-)
> > > > 
> > > > diff --git a/fs/xfs/libxfs/xfs_alloc.c b/fs/xfs/libxfs/xfs_alloc.c
> > > > index ce31c00dbf6f..7ec4af6bf494 100644
> > > > --- a/fs/xfs/libxfs/xfs_alloc.c
> > > > +++ b/fs/xfs/libxfs/xfs_alloc.c
> > > > @@ -776,7 +776,8 @@ xfs_alloc_cur_setup(
> > > >  	 */
> > > >  	if (!acur->cnt)
> > > >  		acur->cnt = xfs_allocbt_init_cursor(args->mp, args->tp,
> > > > -					args->agbp, args->agno, XFS_BTNUM_CNT);
> > > > +						args->agbp, args->agno,
> > > > +						args->pag, XFS_BTNUM_CNT);
> > > 
> > > If we still have to pass the AG[FI] buffer into the _init_cursor
> > > functions, why not get the perag reference from the xfs_buf and
> > > eliminate the agno/pag parameter?  It looks like cursors get their own
> > > active reference to the perag, so I think only the _stage_cursor
> > > function needs to be passed a perag structure, right?
> > 
> > Because when I convert this to active/passive perag references, the
> > buffers only have a passive reference and they can't be converted to
> > active references.
> >
> > Active references provide the barrier that prevents high
> > level code from accessing/entering the AG while a shrink (or other
> > offline type event) is in the process of tearing down that AG. The
> > process of tearing down the AG still may require the ability to
> > read/write to the AG metadata (e.g. checking the AG is fully
> > empty), so we still need the buffer cache to work while in this
> > transient offline state. Hence we need passive reference counts for
> > the buffers, because having cached buffers should not impact on the
> > functioning of the high level "don't use this AG anymore" barrier.
> 
> Agreed; it's past time to shift the world towards the idea that one
> grabs the incore object and only then starts grabbing buffers.  But even
> if you've done it correctly:
> 
> 	pag = xfs_perag_get_active(agno);
> 	xfs_alloc_read_agf(tp, ..., &agfbp);
> 
> Why not pass in just the buffer?
> 
> 	cur = xfs_rmapbt_init_cursor(tp, agfbp, pag);
> 
> Is the idea here simply that we don't want to give people the idea that
> they can just read the agf and pass it to xfs_rmapbt_init_cursor?  In
> other words, the third parameter is there to give the people the
> impression that pag and agfbp are both equally important tokens, and
> that callers must obtain both and pass them in?

I'm angling to hide the agfbp entirely here - move the allocation
serialisation to the perag using a mutex rwsem, not the AGF buffer.
We don't actually need the AGF until we have to modify it, so it's
lock hold time during allocation can be cut way down if it is not
used to serialise the entire allocation operation. This would also
get us lockdep coverage for agi/agf locking, etc.

Also, I'm intending that the perag init functions which currently
take a agno and then do a lookup for the perag to initialise it will
take a perag, not a agno. We almost always already have the perag
when we do a buffer read to initialise the perag...

> No monkeying around
> with the buffer's passive reference by higher level code, at all, ever?

Except in the buffer cache itself or callouts directly from the
buffer cache that operation under the buffer's existence guarantee
for the perag.

> I guess I can live with that.  I might just be micro-optimising function
> call parameter counts.  :P

Oh, I'm planning on chopping them down, but going the other way.
Cache the ag bps in the perag so we don't ahve to do buffer cache
lookups to find them, nor do we have to pass them around anywhere
that we pass a perag....

Cheers,

Dave.
-- 
Dave Chinner
david@fromorbit.com

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 11/22] xfs: add a perag to the btree cursor
  2021-05-13  1:07         ` Dave Chinner
@ 2021-05-13  3:49           ` Darrick J. Wong
  0 siblings, 0 replies; 87+ messages in thread
From: Darrick J. Wong @ 2021-05-13  3:49 UTC (permalink / raw)
  To: Dave Chinner; +Cc: linux-xfs

On Thu, May 13, 2021 at 11:07:50AM +1000, Dave Chinner wrote:
> On Wed, May 12, 2021 at 05:55:08PM -0700, Darrick J. Wong wrote:
> > On Thu, May 13, 2021 at 10:12:16AM +1000, Dave Chinner wrote:
> > > On Wed, May 12, 2021 at 03:40:06PM -0700, Darrick J. Wong wrote:
> > > > On Thu, May 06, 2021 at 05:20:43PM +1000, Dave Chinner wrote:
> > > > > From: Dave Chinner <dchinner@redhat.com>
> > > > > 
> > > > > Which will eventually completely replace the agno in it.
> > > > > 
> > > > > Signed-off-by: Dave Chinner <dchinner@redhat.com>
> > > > > ---
> > > > >  fs/xfs/libxfs/xfs_alloc.c          | 25 +++++++++++++++----------
> > > > >  fs/xfs/libxfs/xfs_alloc_btree.c    | 13 ++++++++++---
> > > > >  fs/xfs/libxfs/xfs_alloc_btree.h    |  3 ++-
> > > > >  fs/xfs/libxfs/xfs_btree.c          |  2 ++
> > > > >  fs/xfs/libxfs/xfs_btree.h          |  4 +++-
> > > > >  fs/xfs/libxfs/xfs_ialloc.c         | 16 ++++++++--------
> > > > >  fs/xfs/libxfs/xfs_ialloc_btree.c   | 15 +++++++++++----
> > > > >  fs/xfs/libxfs/xfs_ialloc_btree.h   |  7 ++++---
> > > > >  fs/xfs/libxfs/xfs_refcount.c       |  4 ++--
> > > > >  fs/xfs/libxfs/xfs_refcount_btree.c | 17 ++++++++++++-----
> > > > >  fs/xfs/libxfs/xfs_refcount_btree.h |  2 +-
> > > > >  fs/xfs/libxfs/xfs_rmap.c           |  6 +++---
> > > > >  fs/xfs/libxfs/xfs_rmap_btree.c     | 17 ++++++++++++-----
> > > > >  fs/xfs/libxfs/xfs_rmap_btree.h     |  2 +-
> > > > >  fs/xfs/scrub/agheader_repair.c     | 20 +++++++++++---------
> > > > >  fs/xfs/scrub/bmap.c                |  2 +-
> > > > >  fs/xfs/scrub/common.c              | 12 ++++++------
> > > > >  fs/xfs/scrub/repair.c              |  5 +++--
> > > > >  fs/xfs/xfs_discard.c               |  2 +-
> > > > >  fs/xfs/xfs_fsmap.c                 |  6 +++---
> > > > >  fs/xfs/xfs_reflink.c               |  2 +-
> > > > >  21 files changed, 112 insertions(+), 70 deletions(-)
> > > > > 
> > > > > diff --git a/fs/xfs/libxfs/xfs_alloc.c b/fs/xfs/libxfs/xfs_alloc.c
> > > > > index ce31c00dbf6f..7ec4af6bf494 100644
> > > > > --- a/fs/xfs/libxfs/xfs_alloc.c
> > > > > +++ b/fs/xfs/libxfs/xfs_alloc.c
> > > > > @@ -776,7 +776,8 @@ xfs_alloc_cur_setup(
> > > > >  	 */
> > > > >  	if (!acur->cnt)
> > > > >  		acur->cnt = xfs_allocbt_init_cursor(args->mp, args->tp,
> > > > > -					args->agbp, args->agno, XFS_BTNUM_CNT);
> > > > > +						args->agbp, args->agno,
> > > > > +						args->pag, XFS_BTNUM_CNT);
> > > > 
> > > > If we still have to pass the AG[FI] buffer into the _init_cursor
> > > > functions, why not get the perag reference from the xfs_buf and
> > > > eliminate the agno/pag parameter?  It looks like cursors get their own
> > > > active reference to the perag, so I think only the _stage_cursor
> > > > function needs to be passed a perag structure, right?
> > > 
> > > Because when I convert this to active/passive perag references, the
> > > buffers only have a passive reference and they can't be converted to
> > > active references.
> > >
> > > Active references provide the barrier that prevents high
> > > level code from accessing/entering the AG while a shrink (or other
> > > offline type event) is in the process of tearing down that AG. The
> > > process of tearing down the AG still may require the ability to
> > > read/write to the AG metadata (e.g. checking the AG is fully
> > > empty), so we still need the buffer cache to work while in this
> > > transient offline state. Hence we need passive reference counts for
> > > the buffers, because having cached buffers should not impact on the
> > > functioning of the high level "don't use this AG anymore" barrier.
> > 
> > Agreed; it's past time to shift the world towards the idea that one
> > grabs the incore object and only then starts grabbing buffers.  But even
> > if you've done it correctly:
> > 
> > 	pag = xfs_perag_get_active(agno);
> > 	xfs_alloc_read_agf(tp, ..., &agfbp);
> > 
> > Why not pass in just the buffer?
> > 
> > 	cur = xfs_rmapbt_init_cursor(tp, agfbp, pag);
> > 
> > Is the idea here simply that we don't want to give people the idea that
> > they can just read the agf and pass it to xfs_rmapbt_init_cursor?  In
> > other words, the third parameter is there to give the people the
> > impression that pag and agfbp are both equally important tokens, and
> > that callers must obtain both and pass them in?
> 
> I'm angling to hide the agfbp entirely here - move the allocation
> serialisation to the perag using a mutex rwsem, not the AGF buffer.
> We don't actually need the AGF until we have to modify it, so it's
> lock hold time during allocation can be cut way down if it is not
> used to serialise the entire allocation operation. This would also
> get us lockdep coverage for agi/agf locking, etc.

Hmmm.  Recently I've been wrangling with a concurrency problem between
scrub and io threads running a series of different AG btree updates
(e.g. bunmap, which runs a deferred rmap-delete and then a deferred
refcount-decrease).  Because the only way we serialize access to the AGs
is through the AG buffer locks and we don't maintain that lock across
the transaction roll between defer items, it's possible that scrub can
step in and grab the buffer lock between items, which it then marks as
cross-reference corruption because the number of rmaps for a given block
doesn't match the number of references in the refcount btree.  The log
intent items guarantee consistency (and the defer items are queue in the
correct order to avoid accidental freeing) but this is suboptimal.

Right now I've "fixed" it by adding a per-ag counter of pending intents
and adapting scrub to lock the AG buffers, check the counter, and if
it's nonzero, it'll cycle the buffers and try again.  This works, but
it's a little silly.  Depending on how the AG mutex works, this could
fix that problem for scrub.

> Also, I'm intending that the perag init functions which currently
> take a agno and then do a lookup for the perag to initialise it will
> take a perag, not a agno. We almost always already have the perag
> when we do a buffer read to initialise the perag...

<nod>

> > No monkeying around
> > with the buffer's passive reference by higher level code, at all, ever?
> 
> Except in the buffer cache itself or callouts directly from the
> buffer cache that operation under the buffer's existence guarantee
> for the perag.

Got it.

> > I guess I can live with that.  I might just be micro-optimising function
> > call parameter counts.  :P
> 
> Oh, I'm planning on chopping them down, but going the other way.
> Cache the ag bps in the perag so we don't ahve to do buffer cache
> lookups to find them, nor do we have to pass them around anywhere
> that we pass a perag....

That's gonna hurt on explodefs filesystems with a million AGs... ;)

Ok, I'm satisfied.
Reviewed-by: Darrick J. Wong <djwong@kernel.org>

--D

> 
> Cheers,
> 
> Dave.
> -- 
> Dave Chinner
> david@fromorbit.com

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 12/22] xfs: convert rmap btree cursor to using a perag
  2021-05-12 22:45   ` Darrick J. Wong
@ 2021-05-13  3:54     ` Darrick J. Wong
  0 siblings, 0 replies; 87+ messages in thread
From: Darrick J. Wong @ 2021-05-13  3:54 UTC (permalink / raw)
  To: Dave Chinner; +Cc: linux-xfs

On Wed, May 12, 2021 at 03:45:12PM -0700, Darrick J. Wong wrote:
> On Thu, May 06, 2021 at 05:20:44PM +1000, Dave Chinner wrote:
> > From: Dave Chinner <dchinner@redhat.com>
> > 
> > Signed-off-by: Dave Chinner <dchinner@redhat.com>
> > ---
> >  fs/xfs/libxfs/xfs_ag.c         |  2 +-
> >  fs/xfs/libxfs/xfs_alloc.c      |  7 ++++---
> >  fs/xfs/libxfs/xfs_rmap.c       | 10 ++++-----
> >  fs/xfs/libxfs/xfs_rmap.h       |  6 ++++--
> >  fs/xfs/libxfs/xfs_rmap_btree.c | 37 +++++++++++++++-------------------
> >  fs/xfs/libxfs/xfs_rmap_btree.h |  4 ++--
> >  fs/xfs/scrub/agheader_repair.c |  6 ++----
> >  fs/xfs/scrub/bmap.c            |  2 +-
> >  fs/xfs/scrub/common.c          |  2 +-
> >  fs/xfs/scrub/repair.c          | 10 ++++-----
> >  fs/xfs/xfs_fsmap.c             |  2 +-
> >  11 files changed, 42 insertions(+), 46 deletions(-)
> > 
> > diff --git a/fs/xfs/libxfs/xfs_ag.c b/fs/xfs/libxfs/xfs_ag.c
> > index 14d8b866dc6d..44f2787f3556 100644
> > --- a/fs/xfs/libxfs/xfs_ag.c
> > +++ b/fs/xfs/libxfs/xfs_ag.c
> > @@ -914,7 +914,7 @@ xfs_ag_extend_space(
> >  	 * XFS_RMAP_OINFO_SKIP_UPDATE is used here to tell the rmap btree that
> >  	 * this doesn't actually exist in the rmap btree.
> >  	 */
> > -	error = xfs_rmap_free(tp, bp, id->agno,
> > +	error = xfs_rmap_free(tp, bp, bp->b_pag,
> 
> Same question here as in the last patch -- so long as we have to pass
> the AGF buffer pointer into the xfs_rmap functions, why is it even
> necessary to pass both the AGF and the perag when we could get the
> second from the first?
> 
> I suspect I'm going to whine about this for the next three patches, but
> the mechanical conversion looks correct to me.

/me changes his mind and 
Reviewed-by: Darrick J. Wong <djwong@kernel.org>

--D

> 
> --D
> 
> >  				be32_to_cpu(agf->agf_length) - len,
> >  				len, &XFS_RMAP_OINFO_SKIP_UPDATE);
> >  	if (error)
> > diff --git a/fs/xfs/libxfs/xfs_alloc.c b/fs/xfs/libxfs/xfs_alloc.c
> > index 7ec4af6bf494..10747cc4d8f6 100644
> > --- a/fs/xfs/libxfs/xfs_alloc.c
> > +++ b/fs/xfs/libxfs/xfs_alloc.c
> > @@ -1092,7 +1092,7 @@ xfs_alloc_ag_vextent_small(
> >  	 * If we're feeding an AGFL block to something that doesn't live in the
> >  	 * free space, we need to clear out the OWN_AG rmap.
> >  	 */
> > -	error = xfs_rmap_free(args->tp, args->agbp, args->agno, fbno, 1,
> > +	error = xfs_rmap_free(args->tp, args->agbp, args->pag, fbno, 1,
> >  			      &XFS_RMAP_OINFO_AG);
> >  	if (error)
> >  		goto error;
> > @@ -1169,7 +1169,7 @@ xfs_alloc_ag_vextent(
> >  
> >  	/* if not file data, insert new block into the reverse map btree */
> >  	if (!xfs_rmap_should_skip_owner_update(&args->oinfo)) {
> > -		error = xfs_rmap_alloc(args->tp, args->agbp, args->agno,
> > +		error = xfs_rmap_alloc(args->tp, args->agbp, args->pag,
> >  				       args->agbno, args->len, &args->oinfo);
> >  		if (error)
> >  			return error;
> > @@ -1899,12 +1899,13 @@ xfs_free_ag_extent(
> >  	int				haveright; /* have a right neighbor */
> >  	int				i;
> >  	int				error;
> > +	struct xfs_perag		*pag = agbp->b_pag;
> >  
> >  	bno_cur = cnt_cur = NULL;
> >  	mp = tp->t_mountp;
> >  
> >  	if (!xfs_rmap_should_skip_owner_update(oinfo)) {
> > -		error = xfs_rmap_free(tp, agbp, agno, bno, len, oinfo);
> > +		error = xfs_rmap_free(tp, agbp, pag, bno, len, oinfo);
> >  		if (error)
> >  			goto error0;
> >  	}
> > diff --git a/fs/xfs/libxfs/xfs_rmap.c b/fs/xfs/libxfs/xfs_rmap.c
> > index 0d7a6997120c..b23f949ee15c 100644
> > --- a/fs/xfs/libxfs/xfs_rmap.c
> > +++ b/fs/xfs/libxfs/xfs_rmap.c
> > @@ -696,7 +696,7 @@ int
> >  xfs_rmap_free(
> >  	struct xfs_trans		*tp,
> >  	struct xfs_buf			*agbp,
> > -	xfs_agnumber_t			agno,
> > +	struct xfs_perag		*pag,
> >  	xfs_agblock_t			bno,
> >  	xfs_extlen_t			len,
> >  	const struct xfs_owner_info	*oinfo)
> > @@ -708,7 +708,7 @@ xfs_rmap_free(
> >  	if (!xfs_sb_version_hasrmapbt(&mp->m_sb))
> >  		return 0;
> >  
> > -	cur = xfs_rmapbt_init_cursor(mp, tp, agbp, agno, NULL);
> > +	cur = xfs_rmapbt_init_cursor(mp, tp, agbp, pag);
> >  
> >  	error = xfs_rmap_unmap(cur, bno, len, false, oinfo);
> >  
> > @@ -950,7 +950,7 @@ int
> >  xfs_rmap_alloc(
> >  	struct xfs_trans		*tp,
> >  	struct xfs_buf			*agbp,
> > -	xfs_agnumber_t			agno,
> > +	struct xfs_perag		*pag,
> >  	xfs_agblock_t			bno,
> >  	xfs_extlen_t			len,
> >  	const struct xfs_owner_info	*oinfo)
> > @@ -962,7 +962,7 @@ xfs_rmap_alloc(
> >  	if (!xfs_sb_version_hasrmapbt(&mp->m_sb))
> >  		return 0;
> >  
> > -	cur = xfs_rmapbt_init_cursor(mp, tp, agbp, agno, NULL);
> > +	cur = xfs_rmapbt_init_cursor(mp, tp, agbp, pag);
> >  	error = xfs_rmap_map(cur, bno, len, false, oinfo);
> >  
> >  	xfs_btree_del_cursor(cur, error);
> > @@ -2408,7 +2408,7 @@ xfs_rmap_finish_one(
> >  			goto out_drop;
> >  		}
> >  
> > -		rcur = xfs_rmapbt_init_cursor(mp, tp, agbp, pag->pag_agno, pag);
> > +		rcur = xfs_rmapbt_init_cursor(mp, tp, agbp, pag);
> >  	}
> >  	*pcur = rcur;
> >  
> > diff --git a/fs/xfs/libxfs/xfs_rmap.h b/fs/xfs/libxfs/xfs_rmap.h
> > index abe633403fd1..f2423cf7f1e2 100644
> > --- a/fs/xfs/libxfs/xfs_rmap.h
> > +++ b/fs/xfs/libxfs/xfs_rmap.h
> > @@ -6,6 +6,8 @@
> >  #ifndef __XFS_RMAP_H__
> >  #define __XFS_RMAP_H__
> >  
> > +struct xfs_perag;
> > +
> >  static inline void
> >  xfs_rmap_ino_bmbt_owner(
> >  	struct xfs_owner_info	*oi,
> > @@ -113,10 +115,10 @@ xfs_owner_info_pack(
> >  }
> >  
> >  int xfs_rmap_alloc(struct xfs_trans *tp, struct xfs_buf *agbp,
> > -		   xfs_agnumber_t agno, xfs_agblock_t bno, xfs_extlen_t len,
> > +		   struct xfs_perag *pag, xfs_agblock_t bno, xfs_extlen_t len,
> >  		   const struct xfs_owner_info *oinfo);
> >  int xfs_rmap_free(struct xfs_trans *tp, struct xfs_buf *agbp,
> > -		  xfs_agnumber_t agno, xfs_agblock_t bno, xfs_extlen_t len,
> > +		  struct xfs_perag *pag, xfs_agblock_t bno, xfs_extlen_t len,
> >  		  const struct xfs_owner_info *oinfo);
> >  
> >  int xfs_rmap_lookup_le(struct xfs_btree_cur *cur, xfs_agblock_t bno,
> > diff --git a/fs/xfs/libxfs/xfs_rmap_btree.c b/fs/xfs/libxfs/xfs_rmap_btree.c
> > index 7bef8feeded1..cafe181bc92d 100644
> > --- a/fs/xfs/libxfs/xfs_rmap_btree.c
> > +++ b/fs/xfs/libxfs/xfs_rmap_btree.c
> > @@ -52,7 +52,7 @@ xfs_rmapbt_dup_cursor(
> >  	struct xfs_btree_cur	*cur)
> >  {
> >  	return xfs_rmapbt_init_cursor(cur->bc_mp, cur->bc_tp,
> > -			cur->bc_ag.agbp, cur->bc_ag.agno, cur->bc_ag.pag);
> > +				cur->bc_ag.agbp, cur->bc_ag.pag);
> >  }
> >  
> >  STATIC void
> > @@ -64,13 +64,12 @@ xfs_rmapbt_set_root(
> >  	struct xfs_buf		*agbp = cur->bc_ag.agbp;
> >  	struct xfs_agf		*agf = agbp->b_addr;
> >  	int			btnum = cur->bc_btnum;
> > -	struct xfs_perag	*pag = agbp->b_pag;
> >  
> >  	ASSERT(ptr->s != 0);
> >  
> >  	agf->agf_roots[btnum] = ptr->s;
> >  	be32_add_cpu(&agf->agf_levels[btnum], inc);
> > -	pag->pagf_levels[btnum] += inc;
> > +	cur->bc_ag.pag->pagf_levels[btnum] += inc;
> >  
> >  	xfs_alloc_log_agf(cur->bc_tp, agbp, XFS_AGF_ROOTS | XFS_AGF_LEVELS);
> >  }
> > @@ -84,6 +83,7 @@ xfs_rmapbt_alloc_block(
> >  {
> >  	struct xfs_buf		*agbp = cur->bc_ag.agbp;
> >  	struct xfs_agf		*agf = agbp->b_addr;
> > +	struct xfs_perag	*pag = cur->bc_ag.pag;
> >  	int			error;
> >  	xfs_agblock_t		bno;
> >  
> > @@ -93,20 +93,19 @@ xfs_rmapbt_alloc_block(
> >  	if (error)
> >  		return error;
> >  
> > -	trace_xfs_rmapbt_alloc_block(cur->bc_mp, cur->bc_ag.agno,
> > -			bno, 1);
> > +	trace_xfs_rmapbt_alloc_block(cur->bc_mp, pag->pag_agno, bno, 1);
> >  	if (bno == NULLAGBLOCK) {
> >  		*stat = 0;
> >  		return 0;
> >  	}
> >  
> > -	xfs_extent_busy_reuse(cur->bc_mp, agbp->b_pag, bno, 1, false);
> > +	xfs_extent_busy_reuse(cur->bc_mp, pag, bno, 1, false);
> >  
> >  	new->s = cpu_to_be32(bno);
> >  	be32_add_cpu(&agf->agf_rmap_blocks, 1);
> >  	xfs_alloc_log_agf(cur->bc_tp, agbp, XFS_AGF_RMAP_BLOCKS);
> >  
> > -	xfs_ag_resv_rmapbt_alloc(cur->bc_mp, cur->bc_ag.agno);
> > +	xfs_ag_resv_rmapbt_alloc(cur->bc_mp, pag->pag_agno);
> >  
> >  	*stat = 1;
> >  	return 0;
> > @@ -119,12 +118,12 @@ xfs_rmapbt_free_block(
> >  {
> >  	struct xfs_buf		*agbp = cur->bc_ag.agbp;
> >  	struct xfs_agf		*agf = agbp->b_addr;
> > -	struct xfs_perag	*pag;
> > +	struct xfs_perag	*pag = cur->bc_ag.pag;
> >  	xfs_agblock_t		bno;
> >  	int			error;
> >  
> >  	bno = xfs_daddr_to_agbno(cur->bc_mp, XFS_BUF_ADDR(bp));
> > -	trace_xfs_rmapbt_free_block(cur->bc_mp, cur->bc_ag.agno,
> > +	trace_xfs_rmapbt_free_block(cur->bc_mp, pag->pag_agno,
> >  			bno, 1);
> >  	be32_add_cpu(&agf->agf_rmap_blocks, -1);
> >  	xfs_alloc_log_agf(cur->bc_tp, agbp, XFS_AGF_RMAP_BLOCKS);
> > @@ -132,7 +131,6 @@ xfs_rmapbt_free_block(
> >  	if (error)
> >  		return error;
> >  
> > -	pag = cur->bc_ag.agbp->b_pag;
> >  	xfs_extent_busy_insert(cur->bc_tp, pag, bno, 1,
> >  			      XFS_EXTENT_BUSY_SKIP_DISCARD);
> >  
> > @@ -214,7 +212,7 @@ xfs_rmapbt_init_ptr_from_cur(
> >  {
> >  	struct xfs_agf		*agf = cur->bc_ag.agbp->b_addr;
> >  
> > -	ASSERT(cur->bc_ag.agno == be32_to_cpu(agf->agf_seqno));
> > +	ASSERT(cur->bc_ag.pag->pag_agno == be32_to_cpu(agf->agf_seqno));
> >  
> >  	ptr->s = agf->agf_roots[cur->bc_btnum];
> >  }
> > @@ -449,7 +447,6 @@ static struct xfs_btree_cur *
> >  xfs_rmapbt_init_common(
> >  	struct xfs_mount	*mp,
> >  	struct xfs_trans	*tp,
> > -	xfs_agnumber_t		agno,
> >  	struct xfs_perag	*pag)
> >  {
> >  	struct xfs_btree_cur	*cur;
> > @@ -462,13 +459,12 @@ xfs_rmapbt_init_common(
> >  	cur->bc_flags = XFS_BTREE_CRC_BLOCKS | XFS_BTREE_OVERLAPPING;
> >  	cur->bc_blocklog = mp->m_sb.sb_blocklog;
> >  	cur->bc_statoff = XFS_STATS_CALC_INDEX(xs_rmap_2);
> > -	cur->bc_ag.agno = agno;
> >  	cur->bc_ops = &xfs_rmapbt_ops;
> > -	if (pag) {
> > -		/* take a reference for the cursor */
> > -		atomic_inc(&pag->pag_ref);
> > -	}
> > +
> > +	/* take a reference for the cursor */
> > +	atomic_inc(&pag->pag_ref);
> >  	cur->bc_ag.pag = pag;
> > +	cur->bc_ag.agno = pag->pag_agno;
> >  
> >  	return cur;
> >  }
> > @@ -479,13 +475,12 @@ xfs_rmapbt_init_cursor(
> >  	struct xfs_mount	*mp,
> >  	struct xfs_trans	*tp,
> >  	struct xfs_buf		*agbp,
> > -	xfs_agnumber_t		agno,
> >  	struct xfs_perag	*pag)
> >  {
> >  	struct xfs_agf		*agf = agbp->b_addr;
> >  	struct xfs_btree_cur	*cur;
> >  
> > -	cur = xfs_rmapbt_init_common(mp, tp, agno, pag);
> > +	cur = xfs_rmapbt_init_common(mp, tp, pag);
> >  	cur->bc_nlevels = be32_to_cpu(agf->agf_levels[XFS_BTNUM_RMAP]);
> >  	cur->bc_ag.agbp = agbp;
> >  	return cur;
> > @@ -496,11 +491,11 @@ struct xfs_btree_cur *
> >  xfs_rmapbt_stage_cursor(
> >  	struct xfs_mount	*mp,
> >  	struct xbtree_afakeroot	*afake,
> > -	xfs_agnumber_t		agno)
> > +	struct xfs_perag	*pag)
> >  {
> >  	struct xfs_btree_cur	*cur;
> >  
> > -	cur = xfs_rmapbt_init_common(mp, NULL, agno, NULL);
> > +	cur = xfs_rmapbt_init_common(mp, NULL, pag);
> >  	xfs_btree_stage_afakeroot(cur, afake);
> >  	return cur;
> >  }
> > diff --git a/fs/xfs/libxfs/xfs_rmap_btree.h b/fs/xfs/libxfs/xfs_rmap_btree.h
> > index c94f418cc06b..88d8d18788a2 100644
> > --- a/fs/xfs/libxfs/xfs_rmap_btree.h
> > +++ b/fs/xfs/libxfs/xfs_rmap_btree.h
> > @@ -43,9 +43,9 @@ struct xbtree_afakeroot;
> >  
> >  struct xfs_btree_cur *xfs_rmapbt_init_cursor(struct xfs_mount *mp,
> >  				struct xfs_trans *tp, struct xfs_buf *bp,
> > -				xfs_agnumber_t agno, struct xfs_perag *pag);
> > +				struct xfs_perag *pag);
> >  struct xfs_btree_cur *xfs_rmapbt_stage_cursor(struct xfs_mount *mp,
> > -		struct xbtree_afakeroot *afake, xfs_agnumber_t agno);
> > +		struct xbtree_afakeroot *afake, struct xfs_perag *pag);
> >  void xfs_rmapbt_commit_staged_btree(struct xfs_btree_cur *cur,
> >  		struct xfs_trans *tp, struct xfs_buf *agbp);
> >  int xfs_rmapbt_maxrecs(int blocklen, int leaf);
> > diff --git a/fs/xfs/scrub/agheader_repair.c b/fs/xfs/scrub/agheader_repair.c
> > index 5dd91bf04c18..981c689e3d95 100644
> > --- a/fs/xfs/scrub/agheader_repair.c
> > +++ b/fs/xfs/scrub/agheader_repair.c
> > @@ -269,8 +269,7 @@ xrep_agf_calc_from_btrees(
> >  	btreeblks += blocks - 1;
> >  
> >  	/* Update the AGF counters from the rmapbt. */
> > -	cur = xfs_rmapbt_init_cursor(mp, sc->tp, agf_bp, sc->sa.agno,
> > -			sc->sa.pag);
> > +	cur = xfs_rmapbt_init_cursor(mp, sc->tp, agf_bp, sc->sa.pag);
> >  	error = xfs_btree_count_blocks(cur, &blocks);
> >  	if (error)
> >  		goto err;
> > @@ -491,8 +490,7 @@ xrep_agfl_collect_blocks(
> >  	xbitmap_init(&ra.agmetablocks);
> >  
> >  	/* Find all space used by the free space btrees & rmapbt. */
> > -	cur = xfs_rmapbt_init_cursor(mp, sc->tp, agf_bp, sc->sa.agno,
> > -			sc->sa.pag);
> > +	cur = xfs_rmapbt_init_cursor(mp, sc->tp, agf_bp, sc->sa.pag);
> >  	error = xfs_rmap_query_all(cur, xrep_agfl_walk_rmap, &ra);
> >  	if (error)
> >  		goto err;
> > diff --git a/fs/xfs/scrub/bmap.c b/fs/xfs/scrub/bmap.c
> > index a792d9ffd61e..b20c3f03b3c5 100644
> > --- a/fs/xfs/scrub/bmap.c
> > +++ b/fs/xfs/scrub/bmap.c
> > @@ -556,7 +556,7 @@ xchk_bmap_check_ag_rmaps(
> >  	if (error)
> >  		return error;
> >  
> > -	cur = xfs_rmapbt_init_cursor(sc->mp, sc->tp, agf, agno, NULL);
> > +	cur = xfs_rmapbt_init_cursor(sc->mp, sc->tp, agf, sc->sa.pag);
> >  
> >  	sbcri.sc = sc;
> >  	sbcri.whichfork = whichfork;
> > diff --git a/fs/xfs/scrub/common.c b/fs/xfs/scrub/common.c
> > index 50768559fb60..48381c1adeed 100644
> > --- a/fs/xfs/scrub/common.c
> > +++ b/fs/xfs/scrub/common.c
> > @@ -493,7 +493,7 @@ xchk_ag_btcur_init(
> >  	if (sa->agf_bp && xfs_sb_version_hasrmapbt(&mp->m_sb) &&
> >  	    xchk_ag_btree_healthy_enough(sc, sa->pag, XFS_BTNUM_RMAP)) {
> >  		sa->rmap_cur = xfs_rmapbt_init_cursor(mp, sc->tp, sa->agf_bp,
> > -				agno, sa->pag);
> > +				sa->pag);
> >  	}
> >  
> >  	/* Set up a refcountbt cursor for cross-referencing. */
> > diff --git a/fs/xfs/scrub/repair.c b/fs/xfs/scrub/repair.c
> > index 862dc56fd8cd..5cf1c3707b6a 100644
> > --- a/fs/xfs/scrub/repair.c
> > +++ b/fs/xfs/scrub/repair.c
> > @@ -509,7 +509,7 @@ xrep_put_freelist(
> >  	 * create an rmap for the block prior to merging it or else other
> >  	 * parts will break.
> >  	 */
> > -	error = xfs_rmap_alloc(sc->tp, sc->sa.agf_bp, sc->sa.agno, agbno, 1,
> > +	error = xfs_rmap_alloc(sc->tp, sc->sa.agf_bp, sc->sa.pag, agbno, 1,
> >  			&XFS_RMAP_OINFO_AG);
> >  	if (error)
> >  		return error;
> > @@ -555,7 +555,7 @@ xrep_reap_block(
> >  	} else {
> >  		agf_bp = sc->sa.agf_bp;
> >  	}
> > -	cur = xfs_rmapbt_init_cursor(sc->mp, sc->tp, agf_bp, agno, sc->sa.pag);
> > +	cur = xfs_rmapbt_init_cursor(sc->mp, sc->tp, agf_bp, sc->sa.pag);
> >  
> >  	/* Can we find any other rmappings? */
> >  	error = xfs_rmap_has_other_keys(cur, agbno, 1, oinfo, &has_other_rmap);
> > @@ -577,7 +577,8 @@ xrep_reap_block(
> >  	 * to run xfs_repair.
> >  	 */
> >  	if (has_other_rmap)
> > -		error = xfs_rmap_free(sc->tp, agf_bp, agno, agbno, 1, oinfo);
> > +		error = xfs_rmap_free(sc->tp, agf_bp, sc->sa.pag, agbno,
> > +					1, oinfo);
> >  	else if (resv == XFS_AG_RESV_AGFL)
> >  		error = xrep_put_freelist(sc, agbno);
> >  	else
> > @@ -892,8 +893,7 @@ xrep_find_ag_btree_roots(
> >  		fab->height = 0;
> >  	}
> >  
> > -	cur = xfs_rmapbt_init_cursor(mp, sc->tp, agf_bp, sc->sa.agno,
> > -			sc->sa.pag);
> > +	cur = xfs_rmapbt_init_cursor(mp, sc->tp, agf_bp, sc->sa.pag);
> >  	error = xfs_rmap_query_all(cur, xrep_findroot_rmap, &ri);
> >  	xfs_btree_del_cursor(cur, error);
> >  
> > diff --git a/fs/xfs/xfs_fsmap.c b/fs/xfs/xfs_fsmap.c
> > index b654a2bf9a9f..7bfe9ea35de0 100644
> > --- a/fs/xfs/xfs_fsmap.c
> > +++ b/fs/xfs/xfs_fsmap.c
> > @@ -708,7 +708,7 @@ xfs_getfsmap_datadev_rmapbt_query(
> >  
> >  	/* Allocate cursor for this AG and query_range it. */
> >  	*curpp = xfs_rmapbt_init_cursor(tp->t_mountp, tp, info->agf_bp,
> > -			info->pag->pag_agno, info->pag);
> > +			info->pag);
> >  	return xfs_rmap_query_range(*curpp, &info->low, &info->high,
> >  			xfs_getfsmap_datadev_helper, info);
> >  }
> > -- 
> > 2.31.1
> > 

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 14/22] xfs: convert allocbt cursors to use perags
  2021-05-06  7:20 ` [PATCH 14/22] xfs: convert allocbt cursors " Dave Chinner
  2021-05-11 12:30   ` Brian Foster
@ 2021-05-13  3:55   ` Darrick J. Wong
  1 sibling, 0 replies; 87+ messages in thread
From: Darrick J. Wong @ 2021-05-13  3:55 UTC (permalink / raw)
  To: Dave Chinner; +Cc: linux-xfs

On Thu, May 06, 2021 at 05:20:46PM +1000, Dave Chinner wrote:
> From: Dave Chinner <dchinner@redhat.com>
> 
> Signed-off-by: Dave Chinner <dchinner@redhat.com>

Fairly simple mechanical change...
Reviewed-by: Darrick J. Wong <djwong@kernel.org>

--D

> ---
>  fs/xfs/libxfs/xfs_alloc.c       | 25 ++++++++++---------------
>  fs/xfs/libxfs/xfs_alloc_btree.c | 26 ++++++++++----------------
>  fs/xfs/libxfs/xfs_alloc_btree.h |  8 ++++----
>  fs/xfs/scrub/agheader_repair.c  |  8 ++++----
>  fs/xfs/scrub/common.c           |  4 ++--
>  fs/xfs/xfs_discard.c            |  2 +-
>  fs/xfs/xfs_fsmap.c              |  2 +-
>  7 files changed, 32 insertions(+), 43 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_alloc.c b/fs/xfs/libxfs/xfs_alloc.c
> index 10747cc4d8f6..c99a80286efa 100644
> --- a/fs/xfs/libxfs/xfs_alloc.c
> +++ b/fs/xfs/libxfs/xfs_alloc.c
> @@ -776,8 +776,7 @@ xfs_alloc_cur_setup(
>  	 */
>  	if (!acur->cnt)
>  		acur->cnt = xfs_allocbt_init_cursor(args->mp, args->tp,
> -						args->agbp, args->agno,
> -						args->pag, XFS_BTNUM_CNT);
> +					args->agbp, args->pag, XFS_BTNUM_CNT);
>  	error = xfs_alloc_lookup_ge(acur->cnt, 0, args->maxlen, &i);
>  	if (error)
>  		return error;
> @@ -787,12 +786,10 @@ xfs_alloc_cur_setup(
>  	 */
>  	if (!acur->bnolt)
>  		acur->bnolt = xfs_allocbt_init_cursor(args->mp, args->tp,
> -						args->agbp, args->agno,
> -						args->pag, XFS_BTNUM_BNO);
> +					args->agbp, args->pag, XFS_BTNUM_BNO);
>  	if (!acur->bnogt)
>  		acur->bnogt = xfs_allocbt_init_cursor(args->mp, args->tp,
> -						args->agbp, args->agno,
> -						args->pag, XFS_BTNUM_BNO);
> +					args->agbp, args->pag, XFS_BTNUM_BNO);
>  	return i == 1 ? 0 : -ENOSPC;
>  }
>  
> @@ -1220,7 +1217,7 @@ xfs_alloc_ag_vextent_exact(
>  	 * Allocate/initialize a cursor for the by-number freespace btree.
>  	 */
>  	bno_cur = xfs_allocbt_init_cursor(args->mp, args->tp, args->agbp,
> -					  args->agno, args->pag, XFS_BTNUM_BNO);
> +					  args->pag, XFS_BTNUM_BNO);
>  
>  	/*
>  	 * Lookup bno and minlen in the btree (minlen is irrelevant, really).
> @@ -1280,7 +1277,7 @@ xfs_alloc_ag_vextent_exact(
>  	 * Allocate/initialize a cursor for the by-size btree.
>  	 */
>  	cnt_cur = xfs_allocbt_init_cursor(args->mp, args->tp, args->agbp,
> -					args->agno, args->pag, XFS_BTNUM_CNT);
> +					args->pag, XFS_BTNUM_CNT);
>  	ASSERT(args->agbno + args->len <= be32_to_cpu(agf->agf_length));
>  	error = xfs_alloc_fixup_trees(cnt_cur, bno_cur, fbno, flen, args->agbno,
>  				      args->len, XFSA_FIXUP_BNO_OK);
> @@ -1677,7 +1674,7 @@ xfs_alloc_ag_vextent_size(
>  	 * Allocate and initialize a cursor for the by-size btree.
>  	 */
>  	cnt_cur = xfs_allocbt_init_cursor(args->mp, args->tp, args->agbp,
> -					args->agno, args->pag, XFS_BTNUM_CNT);
> +					args->pag, XFS_BTNUM_CNT);
>  	bno_cur = NULL;
>  	busy = false;
>  
> @@ -1840,7 +1837,7 @@ xfs_alloc_ag_vextent_size(
>  	 * Allocate and initialize a cursor for the by-block tree.
>  	 */
>  	bno_cur = xfs_allocbt_init_cursor(args->mp, args->tp, args->agbp,
> -					args->agno, args->pag, XFS_BTNUM_BNO);
> +					args->pag, XFS_BTNUM_BNO);
>  	if ((error = xfs_alloc_fixup_trees(cnt_cur, bno_cur, fbno, flen,
>  			rbno, rlen, XFSA_FIXUP_CNT_OK)))
>  		goto error0;
> @@ -1913,8 +1910,7 @@ xfs_free_ag_extent(
>  	/*
>  	 * Allocate and initialize a cursor for the by-block btree.
>  	 */
> -	bno_cur = xfs_allocbt_init_cursor(mp, tp, agbp, agno,
> -					NULL, XFS_BTNUM_BNO);
> +	bno_cur = xfs_allocbt_init_cursor(mp, tp, agbp, pag, XFS_BTNUM_BNO);
>  	/*
>  	 * Look for a neighboring block on the left (lower block numbers)
>  	 * that is contiguous with this space.
> @@ -1984,8 +1980,7 @@ xfs_free_ag_extent(
>  	/*
>  	 * Now allocate and initialize a cursor for the by-size tree.
>  	 */
> -	cnt_cur = xfs_allocbt_init_cursor(mp, tp, agbp, agno,
> -					NULL, XFS_BTNUM_CNT);
> +	cnt_cur = xfs_allocbt_init_cursor(mp, tp, agbp, pag, XFS_BTNUM_CNT);
>  	/*
>  	 * Have both left and right contiguous neighbors.
>  	 * Merge all three into a single free block.
> @@ -2496,7 +2491,7 @@ xfs_exact_minlen_extent_available(
>  	int			error = 0;
>  
>  	cnt_cur = xfs_allocbt_init_cursor(args->mp, args->tp, agbp,
> -					args->agno, args->pag, XFS_BTNUM_CNT);
> +					args->pag, XFS_BTNUM_CNT);
>  	error = xfs_alloc_lookup_ge(cnt_cur, 0, args->minlen, stat);
>  	if (error)
>  		goto out;
> diff --git a/fs/xfs/libxfs/xfs_alloc_btree.c b/fs/xfs/libxfs/xfs_alloc_btree.c
> index a52ab25bbf0b..0c2e4cff4ee3 100644
> --- a/fs/xfs/libxfs/xfs_alloc_btree.c
> +++ b/fs/xfs/libxfs/xfs_alloc_btree.c
> @@ -26,8 +26,7 @@ xfs_allocbt_dup_cursor(
>  	struct xfs_btree_cur	*cur)
>  {
>  	return xfs_allocbt_init_cursor(cur->bc_mp, cur->bc_tp,
> -			cur->bc_ag.agbp, cur->bc_ag.agno,
> -			cur->bc_ag.pag, cur->bc_btnum);
> +			cur->bc_ag.agbp, cur->bc_ag.pag, cur->bc_btnum);
>  }
>  
>  STATIC void
> @@ -39,13 +38,12 @@ xfs_allocbt_set_root(
>  	struct xfs_buf		*agbp = cur->bc_ag.agbp;
>  	struct xfs_agf		*agf = agbp->b_addr;
>  	int			btnum = cur->bc_btnum;
> -	struct xfs_perag	*pag = agbp->b_pag;
>  
>  	ASSERT(ptr->s != 0);
>  
>  	agf->agf_roots[btnum] = ptr->s;
>  	be32_add_cpu(&agf->agf_levels[btnum], inc);
> -	pag->pagf_levels[btnum] += inc;
> +	cur->bc_ag.pag->pagf_levels[btnum] += inc;
>  
>  	xfs_alloc_log_agf(cur->bc_tp, agbp, XFS_AGF_ROOTS | XFS_AGF_LEVELS);
>  }
> @@ -224,7 +222,7 @@ xfs_allocbt_init_ptr_from_cur(
>  {
>  	struct xfs_agf		*agf = cur->bc_ag.agbp->b_addr;
>  
> -	ASSERT(cur->bc_ag.agno == be32_to_cpu(agf->agf_seqno));
> +	ASSERT(cur->bc_ag.pag->pag_agno == be32_to_cpu(agf->agf_seqno));
>  
>  	ptr->s = agf->agf_roots[cur->bc_btnum];
>  }
> @@ -472,7 +470,6 @@ STATIC struct xfs_btree_cur *
>  xfs_allocbt_init_common(
>  	struct xfs_mount	*mp,
>  	struct xfs_trans	*tp,
> -	xfs_agnumber_t		agno,
>  	struct xfs_perag	*pag,
>  	xfs_btnum_t		btnum)
>  {
> @@ -486,6 +483,7 @@ xfs_allocbt_init_common(
>  	cur->bc_mp = mp;
>  	cur->bc_btnum = btnum;
>  	cur->bc_blocklog = mp->m_sb.sb_blocklog;
> +	cur->bc_ag.abt.active = false;
>  
>  	if (btnum == XFS_BTNUM_CNT) {
>  		cur->bc_ops = &xfs_cntbt_ops;
> @@ -496,13 +494,10 @@ xfs_allocbt_init_common(
>  		cur->bc_statoff = XFS_STATS_CALC_INDEX(xs_abtb_2);
>  	}
>  
> -	cur->bc_ag.agno = agno;
> -	cur->bc_ag.abt.active = false;
> -	if (pag) {
> -		/* take a reference for the cursor */
> -		atomic_inc(&pag->pag_ref);
> -	}
> +	/* take a reference for the cursor */
> +	atomic_inc(&pag->pag_ref);
>  	cur->bc_ag.pag = pag;
> +	cur->bc_ag.agno = pag->pag_agno;
>  
>  	if (xfs_sb_version_hascrc(&mp->m_sb))
>  		cur->bc_flags |= XFS_BTREE_CRC_BLOCKS;
> @@ -518,14 +513,13 @@ xfs_allocbt_init_cursor(
>  	struct xfs_mount	*mp,		/* file system mount point */
>  	struct xfs_trans	*tp,		/* transaction pointer */
>  	struct xfs_buf		*agbp,		/* buffer for agf structure */
> -	xfs_agnumber_t		agno,		/* allocation group number */
>  	struct xfs_perag	*pag,
>  	xfs_btnum_t		btnum)		/* btree identifier */
>  {
>  	struct xfs_agf		*agf = agbp->b_addr;
>  	struct xfs_btree_cur	*cur;
>  
> -	cur = xfs_allocbt_init_common(mp, tp, agno, pag, btnum);
> +	cur = xfs_allocbt_init_common(mp, tp, pag, btnum);
>  	if (btnum == XFS_BTNUM_CNT)
>  		cur->bc_nlevels = be32_to_cpu(agf->agf_levels[XFS_BTNUM_CNT]);
>  	else
> @@ -541,12 +535,12 @@ struct xfs_btree_cur *
>  xfs_allocbt_stage_cursor(
>  	struct xfs_mount	*mp,
>  	struct xbtree_afakeroot	*afake,
> -	xfs_agnumber_t		agno,
> +	struct xfs_perag	*pag,
>  	xfs_btnum_t		btnum)
>  {
>  	struct xfs_btree_cur	*cur;
>  
> -	cur = xfs_allocbt_init_common(mp, NULL, agno, NULL, btnum);
> +	cur = xfs_allocbt_init_common(mp, NULL, pag, btnum);
>  	xfs_btree_stage_afakeroot(cur, afake);
>  	return cur;
>  }
> diff --git a/fs/xfs/libxfs/xfs_alloc_btree.h b/fs/xfs/libxfs/xfs_alloc_btree.h
> index a10cedba18d8..9eb4c667a6b8 100644
> --- a/fs/xfs/libxfs/xfs_alloc_btree.h
> +++ b/fs/xfs/libxfs/xfs_alloc_btree.h
> @@ -47,11 +47,11 @@ struct xbtree_afakeroot;
>  		 (maxrecs) * sizeof(xfs_alloc_key_t) + \
>  		 ((index) - 1) * sizeof(xfs_alloc_ptr_t)))
>  
> -extern struct xfs_btree_cur *xfs_allocbt_init_cursor(struct xfs_mount *,
> -		struct xfs_trans *, struct xfs_buf *,
> -		xfs_agnumber_t, struct xfs_perag *pag, xfs_btnum_t);
> +extern struct xfs_btree_cur *xfs_allocbt_init_cursor(struct xfs_mount *mp,
> +		struct xfs_trans *tp, struct xfs_buf *bp,
> +		struct xfs_perag *pag, xfs_btnum_t btnum);
>  struct xfs_btree_cur *xfs_allocbt_stage_cursor(struct xfs_mount *mp,
> -		struct xbtree_afakeroot *afake, xfs_agnumber_t agno,
> +		struct xbtree_afakeroot *afake, struct xfs_perag *pag,
>  		xfs_btnum_t btnum);
>  extern int xfs_allocbt_maxrecs(struct xfs_mount *, int, int);
>  extern xfs_extlen_t xfs_allocbt_calc_size(struct xfs_mount *mp,
> diff --git a/fs/xfs/scrub/agheader_repair.c b/fs/xfs/scrub/agheader_repair.c
> index 251410c19198..ee2d85e3fd4a 100644
> --- a/fs/xfs/scrub/agheader_repair.c
> +++ b/fs/xfs/scrub/agheader_repair.c
> @@ -246,7 +246,7 @@ xrep_agf_calc_from_btrees(
>  	int			error;
>  
>  	/* Update the AGF counters from the bnobt. */
> -	cur = xfs_allocbt_init_cursor(mp, sc->tp, agf_bp, sc->sa.agno,
> +	cur = xfs_allocbt_init_cursor(mp, sc->tp, agf_bp,
>  			sc->sa.pag, XFS_BTNUM_BNO);
>  	error = xfs_alloc_query_all(cur, xrep_agf_walk_allocbt, &raa);
>  	if (error)
> @@ -260,7 +260,7 @@ xrep_agf_calc_from_btrees(
>  	agf->agf_longest = cpu_to_be32(raa.longest);
>  
>  	/* Update the AGF counters from the cntbt. */
> -	cur = xfs_allocbt_init_cursor(mp, sc->tp, agf_bp, sc->sa.agno,
> +	cur = xfs_allocbt_init_cursor(mp, sc->tp, agf_bp,
>  			sc->sa.pag, XFS_BTNUM_CNT);
>  	error = xfs_btree_count_blocks(cur, &blocks);
>  	if (error)
> @@ -497,7 +497,7 @@ xrep_agfl_collect_blocks(
>  	xfs_btree_del_cursor(cur, error);
>  
>  	/* Find all blocks currently being used by the bnobt. */
> -	cur = xfs_allocbt_init_cursor(mp, sc->tp, agf_bp, sc->sa.agno,
> +	cur = xfs_allocbt_init_cursor(mp, sc->tp, agf_bp,
>  			sc->sa.pag, XFS_BTNUM_BNO);
>  	error = xbitmap_set_btblocks(&ra.agmetablocks, cur);
>  	if (error)
> @@ -505,7 +505,7 @@ xrep_agfl_collect_blocks(
>  	xfs_btree_del_cursor(cur, error);
>  
>  	/* Find all blocks currently being used by the cntbt. */
> -	cur = xfs_allocbt_init_cursor(mp, sc->tp, agf_bp, sc->sa.agno,
> +	cur = xfs_allocbt_init_cursor(mp, sc->tp, agf_bp,
>  			sc->sa.pag, XFS_BTNUM_CNT);
>  	error = xbitmap_set_btblocks(&ra.agmetablocks, cur);
>  	if (error)
> diff --git a/fs/xfs/scrub/common.c b/fs/xfs/scrub/common.c
> index cc7688ce79b2..3035f8cee6f6 100644
> --- a/fs/xfs/scrub/common.c
> +++ b/fs/xfs/scrub/common.c
> @@ -465,14 +465,14 @@ xchk_ag_btcur_init(
>  	    xchk_ag_btree_healthy_enough(sc, sa->pag, XFS_BTNUM_BNO)) {
>  		/* Set up a bnobt cursor for cross-referencing. */
>  		sa->bno_cur = xfs_allocbt_init_cursor(mp, sc->tp, sa->agf_bp,
> -				agno, sa->pag, XFS_BTNUM_BNO);
> +				sa->pag, XFS_BTNUM_BNO);
>  	}
>  
>  	if (sa->agf_bp &&
>  	    xchk_ag_btree_healthy_enough(sc, sa->pag, XFS_BTNUM_CNT)) {
>  		/* Set up a cntbt cursor for cross-referencing. */
>  		sa->cnt_cur = xfs_allocbt_init_cursor(mp, sc->tp, sa->agf_bp,
> -				agno, sa->pag, XFS_BTNUM_CNT);
> +				sa->pag, XFS_BTNUM_CNT);
>  	}
>  
>  	/* Set up a inobt cursor for cross-referencing. */
> diff --git a/fs/xfs/xfs_discard.c b/fs/xfs/xfs_discard.c
> index 311ebaad4f5a..736df5660f1f 100644
> --- a/fs/xfs/xfs_discard.c
> +++ b/fs/xfs/xfs_discard.c
> @@ -50,7 +50,7 @@ xfs_trim_extents(
>  		goto out_put_perag;
>  	agf = agbp->b_addr;
>  
> -	cur = xfs_allocbt_init_cursor(mp, NULL, agbp, agno, pag, XFS_BTNUM_CNT);
> +	cur = xfs_allocbt_init_cursor(mp, NULL, agbp, pag, XFS_BTNUM_CNT);
>  
>  	/*
>  	 * Look up the longest btree in the AGF and start with it.
> diff --git a/fs/xfs/xfs_fsmap.c b/fs/xfs/xfs_fsmap.c
> index 623cabaeafee..7501dd941a63 100644
> --- a/fs/xfs/xfs_fsmap.c
> +++ b/fs/xfs/xfs_fsmap.c
> @@ -740,7 +740,7 @@ xfs_getfsmap_datadev_bnobt_query(
>  
>  	/* Allocate cursor for this AG and query_range it. */
>  	*curpp = xfs_allocbt_init_cursor(tp->t_mountp, tp, info->agf_bp,
> -			info->pag->pag_agno, info->pag, XFS_BTNUM_BNO);
> +			info->pag, XFS_BTNUM_BNO);
>  	key->ar_startblock = info->low.rm_startblock;
>  	key[1].ar_startblock = info->high.rm_startblock;
>  	return xfs_alloc_query_range(*curpp, key, &key[1],
> -- 
> 2.31.1
> 

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 15/22] xfs: use perag for ialloc btree cursors
  2021-05-06  7:20 ` [PATCH 15/22] xfs: use perag for ialloc btree cursors Dave Chinner
  2021-05-11 12:30   ` Brian Foster
@ 2021-05-13  3:55   ` Darrick J. Wong
  1 sibling, 0 replies; 87+ messages in thread
From: Darrick J. Wong @ 2021-05-13  3:55 UTC (permalink / raw)
  To: Dave Chinner; +Cc: linux-xfs

On Thu, May 06, 2021 at 05:20:47PM +1000, Dave Chinner wrote:
> From: Dave Chinner <dchinner@redhat.com>
> 
> Signed-off-by: Dave Chinner <dchinner@redhat.com>

Looks good...
Reviewed-by: Darrick J. Wong <djwong@kernel.org>

--D

> ---
>  fs/xfs/libxfs/xfs_ialloc.c       | 177 ++++++++++++++++---------------
>  fs/xfs/libxfs/xfs_ialloc_btree.c |  27 ++---
>  fs/xfs/libxfs/xfs_ialloc_btree.h |   6 +-
>  fs/xfs/scrub/agheader_repair.c   |   4 +-
>  fs/xfs/scrub/common.c            |   5 +-
>  fs/xfs/xfs_iwalk.c               |   6 +-
>  6 files changed, 109 insertions(+), 116 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_ialloc.c b/fs/xfs/libxfs/xfs_ialloc.c
> index 905872bab426..e6f64d41e208 100644
> --- a/fs/xfs/libxfs/xfs_ialloc.c
> +++ b/fs/xfs/libxfs/xfs_ialloc.c
> @@ -172,18 +172,17 @@ xfs_inobt_insert(
>  	struct xfs_mount	*mp,
>  	struct xfs_trans	*tp,
>  	struct xfs_buf		*agbp,
> +	struct xfs_perag	*pag,
>  	xfs_agino_t		newino,
>  	xfs_agino_t		newlen,
>  	xfs_btnum_t		btnum)
>  {
>  	struct xfs_btree_cur	*cur;
> -	struct xfs_agi		*agi = agbp->b_addr;
> -	xfs_agnumber_t		agno = be32_to_cpu(agi->agi_seqno);
>  	xfs_agino_t		thisino;
>  	int			i;
>  	int			error;
>  
> -	cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, NULL, btnum);
> +	cur = xfs_inobt_init_cursor(mp, tp, agbp, pag, btnum);
>  
>  	for (thisino = newino;
>  	     thisino < newino + newlen;
> @@ -520,18 +519,17 @@ xfs_inobt_insert_sprec(
>  	struct xfs_mount		*mp,
>  	struct xfs_trans		*tp,
>  	struct xfs_buf			*agbp,
> +	struct xfs_perag		*pag,
>  	int				btnum,
>  	struct xfs_inobt_rec_incore	*nrec,	/* in/out: new/merged rec. */
>  	bool				merge)	/* merge or replace */
>  {
>  	struct xfs_btree_cur		*cur;
> -	struct xfs_agi			*agi = agbp->b_addr;
> -	xfs_agnumber_t			agno = be32_to_cpu(agi->agi_seqno);
>  	int				error;
>  	int				i;
>  	struct xfs_inobt_rec_incore	rec;
>  
> -	cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, NULL, btnum);
> +	cur = xfs_inobt_init_cursor(mp, tp, agbp, pag, btnum);
>  
>  	/* the new record is pre-aligned so we know where to look */
>  	error = xfs_inobt_lookup(cur, nrec->ir_startino, XFS_LOOKUP_EQ, &i);
> @@ -578,14 +576,14 @@ xfs_inobt_insert_sprec(
>  			goto error;
>  		}
>  
> -		trace_xfs_irec_merge_pre(mp, agno, rec.ir_startino,
> +		trace_xfs_irec_merge_pre(mp, pag->pag_agno, rec.ir_startino,
>  					 rec.ir_holemask, nrec->ir_startino,
>  					 nrec->ir_holemask);
>  
>  		/* merge to nrec to output the updated record */
>  		__xfs_inobt_rec_merge(nrec, &rec);
>  
> -		trace_xfs_irec_merge_post(mp, agno, nrec->ir_startino,
> +		trace_xfs_irec_merge_post(mp, pag->pag_agno, nrec->ir_startino,
>  					  nrec->ir_holemask);
>  
>  		error = xfs_inobt_rec_check_count(mp, nrec);
> @@ -613,21 +611,20 @@ xfs_inobt_insert_sprec(
>  STATIC int
>  xfs_ialloc_ag_alloc(
>  	struct xfs_trans	*tp,
> -	struct xfs_buf		*agbp)
> +	struct xfs_buf		*agbp,
> +	struct xfs_perag	*pag)
>  {
>  	struct xfs_agi		*agi;
>  	struct xfs_alloc_arg	args;
> -	xfs_agnumber_t		agno;
>  	int			error;
>  	xfs_agino_t		newino;		/* new first inode's number */
>  	xfs_agino_t		newlen;		/* new number of inodes */
>  	int			isaligned = 0;	/* inode allocation at stripe */
>  						/* unit boundary */
>  	/* init. to full chunk */
> -	uint16_t		allocmask = (uint16_t) -1;
>  	struct xfs_inobt_rec_incore rec;
> -	struct xfs_perag	*pag;
>  	struct xfs_ino_geometry	*igeo = M_IGEO(tp->t_mountp);
> +	uint16_t		allocmask = (uint16_t) -1;
>  	int			do_sparse = 0;
>  
>  	memset(&args, 0, sizeof(args));
> @@ -660,14 +657,13 @@ xfs_ialloc_ag_alloc(
>  	 */
>  	agi = agbp->b_addr;
>  	newino = be32_to_cpu(agi->agi_newino);
> -	agno = be32_to_cpu(agi->agi_seqno);
>  	args.agbno = XFS_AGINO_TO_AGBNO(args.mp, newino) +
>  		     igeo->ialloc_blks;
>  	if (do_sparse)
>  		goto sparse_alloc;
>  	if (likely(newino != NULLAGINO &&
>  		  (args.agbno < be32_to_cpu(agi->agi_length)))) {
> -		args.fsbno = XFS_AGB_TO_FSB(args.mp, agno, args.agbno);
> +		args.fsbno = XFS_AGB_TO_FSB(args.mp, pag->pag_agno, args.agbno);
>  		args.type = XFS_ALLOCTYPE_THIS_BNO;
>  		args.prod = 1;
>  
> @@ -727,7 +723,7 @@ xfs_ialloc_ag_alloc(
>  		 * For now, just allocate blocks up front.
>  		 */
>  		args.agbno = be32_to_cpu(agi->agi_root);
> -		args.fsbno = XFS_AGB_TO_FSB(args.mp, agno, args.agbno);
> +		args.fsbno = XFS_AGB_TO_FSB(args.mp, pag->pag_agno, args.agbno);
>  		/*
>  		 * Allocate a fixed-size extent of inodes.
>  		 */
> @@ -748,7 +744,7 @@ xfs_ialloc_ag_alloc(
>  	if (isaligned && args.fsbno == NULLFSBLOCK) {
>  		args.type = XFS_ALLOCTYPE_NEAR_BNO;
>  		args.agbno = be32_to_cpu(agi->agi_root);
> -		args.fsbno = XFS_AGB_TO_FSB(args.mp, agno, args.agbno);
> +		args.fsbno = XFS_AGB_TO_FSB(args.mp, pag->pag_agno, args.agbno);
>  		args.alignment = igeo->cluster_align;
>  		if ((error = xfs_alloc_vextent(&args)))
>  			return error;
> @@ -764,7 +760,7 @@ xfs_ialloc_ag_alloc(
>  sparse_alloc:
>  		args.type = XFS_ALLOCTYPE_NEAR_BNO;
>  		args.agbno = be32_to_cpu(agi->agi_root);
> -		args.fsbno = XFS_AGB_TO_FSB(args.mp, agno, args.agbno);
> +		args.fsbno = XFS_AGB_TO_FSB(args.mp, pag->pag_agno, args.agbno);
>  		args.alignment = args.mp->m_sb.sb_spino_align;
>  		args.prod = 1;
>  
> @@ -809,7 +805,7 @@ xfs_ialloc_ag_alloc(
>  	 * rather than a linear progression to prevent the next generation
>  	 * number from being easily guessable.
>  	 */
> -	error = xfs_ialloc_inode_init(args.mp, tp, NULL, newlen, agno,
> +	error = xfs_ialloc_inode_init(args.mp, tp, NULL, newlen, pag->pag_agno,
>  			args.agbno, args.len, prandom_u32());
>  
>  	if (error)
> @@ -836,12 +832,12 @@ xfs_ialloc_ag_alloc(
>  		 * if necessary. If a merge does occur, rec is updated to the
>  		 * merged record.
>  		 */
> -		error = xfs_inobt_insert_sprec(args.mp, tp, agbp, XFS_BTNUM_INO,
> -					       &rec, true);
> +		error = xfs_inobt_insert_sprec(args.mp, tp, agbp, pag,
> +				XFS_BTNUM_INO, &rec, true);
>  		if (error == -EFSCORRUPTED) {
>  			xfs_alert(args.mp,
>  	"invalid sparse inode record: ino 0x%llx holemask 0x%x count %u",
> -				  XFS_AGINO_TO_INO(args.mp, agno,
> +				  XFS_AGINO_TO_INO(args.mp, pag->pag_agno,
>  						   rec.ir_startino),
>  				  rec.ir_holemask, rec.ir_count);
>  			xfs_force_shutdown(args.mp, SHUTDOWN_CORRUPT_INCORE);
> @@ -861,21 +857,20 @@ xfs_ialloc_ag_alloc(
>  		 * existing record with this one.
>  		 */
>  		if (xfs_sb_version_hasfinobt(&args.mp->m_sb)) {
> -			error = xfs_inobt_insert_sprec(args.mp, tp, agbp,
> -						       XFS_BTNUM_FINO, &rec,
> -						       false);
> +			error = xfs_inobt_insert_sprec(args.mp, tp, agbp, pag,
> +				       XFS_BTNUM_FINO, &rec, false);
>  			if (error)
>  				return error;
>  		}
>  	} else {
>  		/* full chunk - insert new records to both btrees */
> -		error = xfs_inobt_insert(args.mp, tp, agbp, newino, newlen,
> +		error = xfs_inobt_insert(args.mp, tp, agbp, pag, newino, newlen,
>  					 XFS_BTNUM_INO);
>  		if (error)
>  			return error;
>  
>  		if (xfs_sb_version_hasfinobt(&args.mp->m_sb)) {
> -			error = xfs_inobt_insert(args.mp, tp, agbp, newino,
> +			error = xfs_inobt_insert(args.mp, tp, agbp, pag, newino,
>  						 newlen, XFS_BTNUM_FINO);
>  			if (error)
>  				return error;
> @@ -887,7 +882,6 @@ xfs_ialloc_ag_alloc(
>  	 */
>  	be32_add_cpu(&agi->agi_count, newlen);
>  	be32_add_cpu(&agi->agi_freecount, newlen);
> -	pag = agbp->b_pag;
>  	pag->pagi_freecount += newlen;
>  	pag->pagi_count += newlen;
>  	agi->agi_newino = cpu_to_be32(newino);
> @@ -1123,15 +1117,14 @@ STATIC int
>  xfs_dialloc_ag_inobt(
>  	struct xfs_trans	*tp,
>  	struct xfs_buf		*agbp,
> +	struct xfs_perag	*pag,
>  	xfs_ino_t		parent,
>  	xfs_ino_t		*inop)
>  {
>  	struct xfs_mount	*mp = tp->t_mountp;
>  	struct xfs_agi		*agi = agbp->b_addr;
> -	xfs_agnumber_t		agno = be32_to_cpu(agi->agi_seqno);
>  	xfs_agnumber_t		pagno = XFS_INO_TO_AGNO(mp, parent);
>  	xfs_agino_t		pagino = XFS_INO_TO_AGINO(mp, parent);
> -	struct xfs_perag	*pag = agbp->b_pag;
>  	struct xfs_btree_cur	*cur, *tcur;
>  	struct xfs_inobt_rec_incore rec, trec;
>  	xfs_ino_t		ino;
> @@ -1145,7 +1138,7 @@ xfs_dialloc_ag_inobt(
>  	ASSERT(pag->pagi_freecount > 0);
>  
>   restart_pagno:
> -	cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, NULL, XFS_BTNUM_INO);
> +	cur = xfs_inobt_init_cursor(mp, tp, agbp, pag, XFS_BTNUM_INO);
>  	/*
>  	 * If pagino is 0 (this is the root inode allocation) use newino.
>  	 * This must work because we've just allocated some.
> @@ -1160,7 +1153,7 @@ xfs_dialloc_ag_inobt(
>  	/*
>  	 * If in the same AG as the parent, try to get near the parent.
>  	 */
> -	if (pagno == agno) {
> +	if (pagno == pag->pag_agno) {
>  		int		doneleft;	/* done, to the left */
>  		int		doneright;	/* done, to the right */
>  
> @@ -1363,7 +1356,7 @@ xfs_dialloc_ag_inobt(
>  	ASSERT(offset < XFS_INODES_PER_CHUNK);
>  	ASSERT((XFS_AGINO_TO_OFFSET(mp, rec.ir_startino) %
>  				   XFS_INODES_PER_CHUNK) == 0);
> -	ino = XFS_AGINO_TO_INO(mp, agno, rec.ir_startino + offset);
> +	ino = XFS_AGINO_TO_INO(mp, pag->pag_agno, rec.ir_startino + offset);
>  	rec.ir_free &= ~XFS_INOBT_MASK(offset);
>  	rec.ir_freecount--;
>  	error = xfs_inobt_update(cur, &rec);
> @@ -1577,7 +1570,6 @@ xfs_dialloc_ag(
>  {
>  	struct xfs_mount		*mp = tp->t_mountp;
>  	struct xfs_agi			*agi = agbp->b_addr;
> -	xfs_agnumber_t			agno = be32_to_cpu(agi->agi_seqno);
>  	xfs_agnumber_t			pagno = XFS_INO_TO_AGNO(mp, parent);
>  	xfs_agino_t			pagino = XFS_INO_TO_AGINO(mp, parent);
>  	struct xfs_btree_cur		*cur;	/* finobt cursor */
> @@ -1587,9 +1579,10 @@ xfs_dialloc_ag(
>  	int				error;
>  	int				offset;
>  	int				i;
> +	struct xfs_perag		*pag = agbp->b_pag;
>  
>  	if (!xfs_sb_version_hasfinobt(&mp->m_sb))
> -		return xfs_dialloc_ag_inobt(tp, agbp, parent, inop);
> +		return xfs_dialloc_ag_inobt(tp, agbp, pag, parent, inop);
>  
>  	/*
>  	 * If pagino is 0 (this is the root inode allocation) use newino.
> @@ -1598,7 +1591,7 @@ xfs_dialloc_ag(
>  	if (!pagino)
>  		pagino = be32_to_cpu(agi->agi_newino);
>  
> -	cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, NULL, XFS_BTNUM_FINO);
> +	cur = xfs_inobt_init_cursor(mp, tp, agbp, pag, XFS_BTNUM_FINO);
>  
>  	error = xfs_check_agi_freecount(cur, agi);
>  	if (error)
> @@ -1609,7 +1602,7 @@ xfs_dialloc_ag(
>  	 * parent. If so, find the closest available inode to the parent. If
>  	 * not, consider the agi hint or find the first free inode in the AG.
>  	 */
> -	if (agno == pagno)
> +	if (pag->pag_agno == pagno)
>  		error = xfs_dialloc_ag_finobt_near(pagino, &cur, &rec);
>  	else
>  		error = xfs_dialloc_ag_finobt_newino(agi, cur, &rec);
> @@ -1621,7 +1614,7 @@ xfs_dialloc_ag(
>  	ASSERT(offset < XFS_INODES_PER_CHUNK);
>  	ASSERT((XFS_AGINO_TO_OFFSET(mp, rec.ir_startino) %
>  				   XFS_INODES_PER_CHUNK) == 0);
> -	ino = XFS_AGINO_TO_INO(mp, agno, rec.ir_startino + offset);
> +	ino = XFS_AGINO_TO_INO(mp, pag->pag_agno, rec.ir_startino + offset);
>  
>  	/*
>  	 * Modify or remove the finobt record.
> @@ -1641,7 +1634,7 @@ xfs_dialloc_ag(
>  	 * the original freecount. If all is well, make the equivalent update to
>  	 * the inobt using the finobt record and offset information.
>  	 */
> -	icur = xfs_inobt_init_cursor(mp, tp, agbp, agno, NULL, XFS_BTNUM_INO);
> +	icur = xfs_inobt_init_cursor(mp, tp, agbp, pag, XFS_BTNUM_INO);
>  
>  	error = xfs_check_agi_freecount(icur, agi);
>  	if (error)
> @@ -1657,7 +1650,7 @@ xfs_dialloc_ag(
>  	 */
>  	be32_add_cpu(&agi->agi_freecount, -1);
>  	xfs_ialloc_log_agi(tp, agbp, XFS_AGI_FREECOUNT);
> -	agbp->b_pag->pagi_freecount--;
> +	pag->pagi_freecount--;
>  
>  	xfs_trans_mod_sb(tp, XFS_TRANS_SB_IFREE, -1);
>  
> @@ -1809,7 +1802,7 @@ xfs_dialloc_select_ag(
>  		if (!okalloc)
>  			goto nextag_relse_buffer;
>  
> -		error = xfs_ialloc_ag_alloc(*tpp, agbp);
> +		error = xfs_ialloc_ag_alloc(*tpp, agbp, pag);
>  		if (error < 0) {
>  			xfs_trans_brelse(*tpp, agbp);
>  
> @@ -1935,12 +1928,12 @@ xfs_difree_inobt(
>  	struct xfs_mount		*mp,
>  	struct xfs_trans		*tp,
>  	struct xfs_buf			*agbp,
> +	struct xfs_perag		*pag,
>  	xfs_agino_t			agino,
>  	struct xfs_icluster		*xic,
>  	struct xfs_inobt_rec_incore	*orec)
>  {
>  	struct xfs_agi			*agi = agbp->b_addr;
> -	xfs_agnumber_t			agno = be32_to_cpu(agi->agi_seqno);
>  	struct xfs_btree_cur		*cur;
>  	struct xfs_inobt_rec_incore	rec;
>  	int				ilen;
> @@ -1954,7 +1947,7 @@ xfs_difree_inobt(
>  	/*
>  	 * Initialize the cursor.
>  	 */
> -	cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, NULL, XFS_BTNUM_INO);
> +	cur = xfs_inobt_init_cursor(mp, tp, agbp, pag, XFS_BTNUM_INO);
>  
>  	error = xfs_check_agi_freecount(cur, agi);
>  	if (error)
> @@ -2005,7 +1998,8 @@ xfs_difree_inobt(
>  		struct xfs_perag	*pag = agbp->b_pag;
>  
>  		xic->deleted = true;
> -		xic->first_ino = XFS_AGINO_TO_INO(mp, agno, rec.ir_startino);
> +		xic->first_ino = XFS_AGINO_TO_INO(mp, pag->pag_agno,
> +				rec.ir_startino);
>  		xic->alloc = xfs_inobt_irec_to_allocmask(&rec);
>  
>  		/*
> @@ -2028,7 +2022,7 @@ xfs_difree_inobt(
>  			goto error0;
>  		}
>  
> -		xfs_difree_inode_chunk(tp, agno, &rec);
> +		xfs_difree_inode_chunk(tp, pag->pag_agno, &rec);
>  	} else {
>  		xic->deleted = false;
>  
> @@ -2044,7 +2038,7 @@ xfs_difree_inobt(
>  		 */
>  		be32_add_cpu(&agi->agi_freecount, 1);
>  		xfs_ialloc_log_agi(tp, agbp, XFS_AGI_FREECOUNT);
> -		agbp->b_pag->pagi_freecount++;
> +		pag->pagi_freecount++;
>  		xfs_trans_mod_sb(tp, XFS_TRANS_SB_IFREE, 1);
>  	}
>  
> @@ -2069,18 +2063,18 @@ xfs_difree_finobt(
>  	struct xfs_mount		*mp,
>  	struct xfs_trans		*tp,
>  	struct xfs_buf			*agbp,
> +	struct xfs_perag		*pag,
>  	xfs_agino_t			agino,
>  	struct xfs_inobt_rec_incore	*ibtrec) /* inobt record */
>  {
>  	struct xfs_agi			*agi = agbp->b_addr;
> -	xfs_agnumber_t			agno = be32_to_cpu(agi->agi_seqno);
>  	struct xfs_btree_cur		*cur;
>  	struct xfs_inobt_rec_incore	rec;
>  	int				offset = agino - ibtrec->ir_startino;
>  	int				error;
>  	int				i;
>  
> -	cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, NULL, XFS_BTNUM_FINO);
> +	cur = xfs_inobt_init_cursor(mp, tp, agbp, pag, XFS_BTNUM_FINO);
>  
>  	error = xfs_inobt_lookup(cur, ibtrec->ir_startino, XFS_LOOKUP_EQ, &i);
>  	if (error)
> @@ -2188,16 +2182,15 @@ xfs_difree(
>  	xfs_agino_t		agino;	/* allocation group inode number */
>  	xfs_agnumber_t		agno;	/* allocation group number */
>  	int			error;	/* error return value */
> -	struct xfs_mount	*mp;	/* mount structure for filesystem */
> +	struct xfs_mount	*mp = tp->t_mountp;
>  	struct xfs_inobt_rec_incore rec;/* btree record */
> -
> -	mp = tp->t_mountp;
> +	struct xfs_perag	*pag;
>  
>  	/*
>  	 * Break up inode number into its components.
>  	 */
>  	agno = XFS_INO_TO_AGNO(mp, inode);
> -	if (agno >= mp->m_sb.sb_agcount)  {
> +	if (agno >= mp->m_sb.sb_agcount) {
>  		xfs_warn(mp, "%s: agno >= mp->m_sb.sb_agcount (%d >= %d).",
>  			__func__, agno, mp->m_sb.sb_agcount);
>  		ASSERT(0);
> @@ -2231,7 +2224,8 @@ xfs_difree(
>  	/*
>  	 * Fix up the inode allocation btree.
>  	 */
> -	error = xfs_difree_inobt(mp, tp, agbp, agino, xic, &rec);
> +	pag = agbp->b_pag;
> +	error = xfs_difree_inobt(mp, tp, agbp, pag, agino, xic, &rec);
>  	if (error)
>  		goto error0;
>  
> @@ -2239,7 +2233,7 @@ xfs_difree(
>  	 * Fix up the free inode btree.
>  	 */
>  	if (xfs_sb_version_hasfinobt(&mp->m_sb)) {
> -		error = xfs_difree_finobt(mp, tp, agbp, agino, &rec);
> +		error = xfs_difree_finobt(mp, tp, agbp, pag, agino, &rec);
>  		if (error)
>  			goto error0;
>  	}
> @@ -2254,7 +2248,7 @@ STATIC int
>  xfs_imap_lookup(
>  	struct xfs_mount	*mp,
>  	struct xfs_trans	*tp,
> -	xfs_agnumber_t		agno,
> +	struct xfs_perag	*pag,
>  	xfs_agino_t		agino,
>  	xfs_agblock_t		agbno,
>  	xfs_agblock_t		*chunk_agbno,
> @@ -2267,11 +2261,11 @@ xfs_imap_lookup(
>  	int			error;
>  	int			i;
>  
> -	error = xfs_ialloc_read_agi(mp, tp, agno, &agbp);
> +	error = xfs_ialloc_read_agi(mp, tp, pag->pag_agno, &agbp);
>  	if (error) {
>  		xfs_alert(mp,
>  			"%s: xfs_ialloc_read_agi() returned error %d, agno %d",
> -			__func__, error, agno);
> +			__func__, error, pag->pag_agno);
>  		return error;
>  	}
>  
> @@ -2281,7 +2275,7 @@ xfs_imap_lookup(
>  	 * we have a record, we need to ensure it contains the inode number
>  	 * we are looking up.
>  	 */
> -	cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, NULL, XFS_BTNUM_INO);
> +	cur = xfs_inobt_init_cursor(mp, tp, agbp, pag, XFS_BTNUM_INO);
>  	error = xfs_inobt_lookup(cur, agino, XFS_LOOKUP_LE, &i);
>  	if (!error) {
>  		if (i)
> @@ -2315,42 +2309,44 @@ xfs_imap_lookup(
>   */
>  int
>  xfs_imap(
> -	xfs_mount_t	 *mp,	/* file system mount structure */
> -	xfs_trans_t	 *tp,	/* transaction pointer */
> -	xfs_ino_t	ino,	/* inode to locate */
> -	struct xfs_imap	*imap,	/* location map structure */
> -	uint		flags)	/* flags for inode btree lookup */
> +	struct xfs_mount	 *mp,	/* file system mount structure */
> +	struct xfs_trans	 *tp,	/* transaction pointer */
> +	xfs_ino_t		ino,	/* inode to locate */
> +	struct xfs_imap		*imap,	/* location map structure */
> +	uint			flags)	/* flags for inode btree lookup */
>  {
> -	xfs_agblock_t	agbno;	/* block number of inode in the alloc group */
> -	xfs_agino_t	agino;	/* inode number within alloc group */
> -	xfs_agnumber_t	agno;	/* allocation group number */
> -	xfs_agblock_t	chunk_agbno;	/* first block in inode chunk */
> -	xfs_agblock_t	cluster_agbno;	/* first block in inode cluster */
> -	int		error;	/* error code */
> -	int		offset;	/* index of inode in its buffer */
> -	xfs_agblock_t	offset_agbno;	/* blks from chunk start to inode */
> +	xfs_agblock_t		agbno;	/* block number of inode in the alloc group */
> +	xfs_agino_t		agino;	/* inode number within alloc group */
> +	xfs_agblock_t		chunk_agbno;	/* first block in inode chunk */
> +	xfs_agblock_t		cluster_agbno;	/* first block in inode cluster */
> +	int			error;	/* error code */
> +	int			offset;	/* index of inode in its buffer */
> +	xfs_agblock_t		offset_agbno;	/* blks from chunk start to inode */
> +	struct xfs_perag	*pag;
>  
>  	ASSERT(ino != NULLFSINO);
>  
>  	/*
>  	 * Split up the inode number into its parts.
>  	 */
> -	agno = XFS_INO_TO_AGNO(mp, ino);
> +	pag = xfs_perag_get(mp, XFS_INO_TO_AGNO(mp, ino));
>  	agino = XFS_INO_TO_AGINO(mp, ino);
>  	agbno = XFS_AGINO_TO_AGBNO(mp, agino);
> -	if (agno >= mp->m_sb.sb_agcount || agbno >= mp->m_sb.sb_agblocks ||
> -	    ino != XFS_AGINO_TO_INO(mp, agno, agino)) {
> +	if (!pag || agbno >= mp->m_sb.sb_agblocks ||
> +	    ino != XFS_AGINO_TO_INO(mp, pag->pag_agno, agino)) {
> +		error = -EINVAL;
>  #ifdef DEBUG
>  		/*
>  		 * Don't output diagnostic information for untrusted inodes
>  		 * as they can be invalid without implying corruption.
>  		 */
>  		if (flags & XFS_IGET_UNTRUSTED)
> -			return -EINVAL;
> -		if (agno >= mp->m_sb.sb_agcount) {
> +			goto out_drop;
> +		if (!pag) {
>  			xfs_alert(mp,
>  				"%s: agno (%d) >= mp->m_sb.sb_agcount (%d)",
> -				__func__, agno, mp->m_sb.sb_agcount);
> +				__func__, XFS_INO_TO_AGNO(mp, ino),
> +				mp->m_sb.sb_agcount);
>  		}
>  		if (agbno >= mp->m_sb.sb_agblocks) {
>  			xfs_alert(mp,
> @@ -2358,15 +2354,15 @@ xfs_imap(
>  				__func__, (unsigned long long)agbno,
>  				(unsigned long)mp->m_sb.sb_agblocks);
>  		}
> -		if (ino != XFS_AGINO_TO_INO(mp, agno, agino)) {
> +		if (pag && ino != XFS_AGINO_TO_INO(mp, pag->pag_agno, agino)) {
>  			xfs_alert(mp,
>  		"%s: ino (0x%llx) != XFS_AGINO_TO_INO() (0x%llx)",
>  				__func__, ino,
> -				XFS_AGINO_TO_INO(mp, agno, agino));
> +				XFS_AGINO_TO_INO(mp, pag->pag_agno, agino));
>  		}
>  		xfs_stack_trace();
>  #endif /* DEBUG */
> -		return -EINVAL;
> +		goto out_drop;
>  	}
>  
>  	/*
> @@ -2377,10 +2373,10 @@ xfs_imap(
>  	 * in all cases where an untrusted inode number is passed.
>  	 */
>  	if (flags & XFS_IGET_UNTRUSTED) {
> -		error = xfs_imap_lookup(mp, tp, agno, agino, agbno,
> +		error = xfs_imap_lookup(mp, tp, pag, agino, agbno,
>  					&chunk_agbno, &offset_agbno, flags);
>  		if (error)
> -			return error;
> +			goto out_drop;
>  		goto out_map;
>  	}
>  
> @@ -2392,11 +2388,12 @@ xfs_imap(
>  		offset = XFS_INO_TO_OFFSET(mp, ino);
>  		ASSERT(offset < mp->m_sb.sb_inopblock);
>  
> -		imap->im_blkno = XFS_AGB_TO_DADDR(mp, agno, agbno);
> +		imap->im_blkno = XFS_AGB_TO_DADDR(mp, pag->pag_agno, agbno);
>  		imap->im_len = XFS_FSB_TO_BB(mp, 1);
>  		imap->im_boffset = (unsigned short)(offset <<
>  							mp->m_sb.sb_inodelog);
> -		return 0;
> +		error = 0;
> +		goto out_drop;
>  	}
>  
>  	/*
> @@ -2408,10 +2405,10 @@ xfs_imap(
>  		offset_agbno = agbno & M_IGEO(mp)->inoalign_mask;
>  		chunk_agbno = agbno - offset_agbno;
>  	} else {
> -		error = xfs_imap_lookup(mp, tp, agno, agino, agbno,
> +		error = xfs_imap_lookup(mp, tp, pag, agino, agbno,
>  					&chunk_agbno, &offset_agbno, flags);
>  		if (error)
> -			return error;
> +			goto out_drop;
>  	}
>  
>  out_map:
> @@ -2422,7 +2419,7 @@ xfs_imap(
>  	offset = ((agbno - cluster_agbno) * mp->m_sb.sb_inopblock) +
>  		XFS_INO_TO_OFFSET(mp, ino);
>  
> -	imap->im_blkno = XFS_AGB_TO_DADDR(mp, agno, cluster_agbno);
> +	imap->im_blkno = XFS_AGB_TO_DADDR(mp, pag->pag_agno, cluster_agbno);
>  	imap->im_len = XFS_FSB_TO_BB(mp, M_IGEO(mp)->blocks_per_cluster);
>  	imap->im_boffset = (unsigned short)(offset << mp->m_sb.sb_inodelog);
>  
> @@ -2439,9 +2436,13 @@ xfs_imap(
>  			__func__, (unsigned long long) imap->im_blkno,
>  			(unsigned long long) imap->im_len,
>  			XFS_FSB_TO_BB(mp, mp->m_sb.sb_dblocks));
> -		return -EINVAL;
> +		error = -EINVAL;
> +		goto out_drop;
>  	}
> -	return 0;
> +	error = 0;
> +out_drop:
> +	xfs_perag_put(pag);
> +	return error;
>  }
>  
>  /*
> diff --git a/fs/xfs/libxfs/xfs_ialloc_btree.c b/fs/xfs/libxfs/xfs_ialloc_btree.c
> index 6c4efdf01674..450161b53648 100644
> --- a/fs/xfs/libxfs/xfs_ialloc_btree.c
> +++ b/fs/xfs/libxfs/xfs_ialloc_btree.c
> @@ -35,8 +35,7 @@ xfs_inobt_dup_cursor(
>  	struct xfs_btree_cur	*cur)
>  {
>  	return xfs_inobt_init_cursor(cur->bc_mp, cur->bc_tp,
> -			cur->bc_ag.agbp, cur->bc_ag.agno,
> -			cur->bc_ag.pag, cur->bc_btnum);
> +			cur->bc_ag.agbp, cur->bc_ag.pag, cur->bc_btnum);
>  }
>  
>  STATIC void
> @@ -428,7 +427,6 @@ static struct xfs_btree_cur *
>  xfs_inobt_init_common(
>  	struct xfs_mount	*mp,		/* file system mount point */
>  	struct xfs_trans	*tp,		/* transaction pointer */
> -	xfs_agnumber_t		agno,		/* allocation group number */
>  	struct xfs_perag	*pag,
>  	xfs_btnum_t		btnum)		/* ialloc or free ino btree */
>  {
> @@ -451,12 +449,10 @@ xfs_inobt_init_common(
>  	if (xfs_sb_version_hascrc(&mp->m_sb))
>  		cur->bc_flags |= XFS_BTREE_CRC_BLOCKS;
>  
> -	cur->bc_ag.agno = agno;
> -	if (pag) {
> -		/* take a reference for the cursor */
> -		atomic_inc(&pag->pag_ref);
> -	}
> +	/* take a reference for the cursor */
> +	atomic_inc(&pag->pag_ref);
>  	cur->bc_ag.pag = pag;
> +	cur->bc_ag.agno = pag->pag_agno;
>  	return cur;
>  }
>  
> @@ -466,14 +462,13 @@ xfs_inobt_init_cursor(
>  	struct xfs_mount	*mp,
>  	struct xfs_trans	*tp,
>  	struct xfs_buf		*agbp,
> -	xfs_agnumber_t		agno,
>  	struct xfs_perag	*pag,
>  	xfs_btnum_t		btnum)
>  {
>  	struct xfs_btree_cur	*cur;
>  	struct xfs_agi		*agi = agbp->b_addr;
>  
> -	cur = xfs_inobt_init_common(mp, tp, agno, pag, btnum);
> +	cur = xfs_inobt_init_common(mp, tp, pag, btnum);
>  	if (btnum == XFS_BTNUM_INO)
>  		cur->bc_nlevels = be32_to_cpu(agi->agi_level);
>  	else
> @@ -487,12 +482,12 @@ struct xfs_btree_cur *
>  xfs_inobt_stage_cursor(
>  	struct xfs_mount	*mp,
>  	struct xbtree_afakeroot	*afake,
> -	xfs_agnumber_t		agno,
> +	struct xfs_perag	*pag,
>  	xfs_btnum_t		btnum)
>  {
>  	struct xfs_btree_cur	*cur;
>  
> -	cur = xfs_inobt_init_common(mp, NULL, agno, NULL, btnum);
> +	cur = xfs_inobt_init_common(mp, NULL, pag, btnum);
>  	xfs_btree_stage_afakeroot(cur, afake);
>  	return cur;
>  }
> @@ -664,7 +659,7 @@ int
>  xfs_inobt_cur(
>  	struct xfs_mount	*mp,
>  	struct xfs_trans	*tp,
> -	xfs_agnumber_t		agno,
> +	struct xfs_perag	*pag,
>  	xfs_btnum_t		which,
>  	struct xfs_btree_cur	**curpp,
>  	struct xfs_buf		**agi_bpp)
> @@ -675,11 +670,11 @@ xfs_inobt_cur(
>  	ASSERT(*agi_bpp == NULL);
>  	ASSERT(*curpp == NULL);
>  
> -	error = xfs_ialloc_read_agi(mp, tp, agno, agi_bpp);
> +	error = xfs_ialloc_read_agi(mp, tp, pag->pag_agno, agi_bpp);
>  	if (error)
>  		return error;
>  
> -	cur = xfs_inobt_init_cursor(mp, tp, *agi_bpp, agno, NULL, which);
> +	cur = xfs_inobt_init_cursor(mp, tp, *agi_bpp, pag, which);
>  	*curpp = cur;
>  	return 0;
>  }
> @@ -696,7 +691,7 @@ xfs_inobt_count_blocks(
>  	struct xfs_btree_cur	*cur = NULL;
>  	int			error;
>  
> -	error = xfs_inobt_cur(mp, tp, pag->pag_agno, btnum, &cur, &agbp);
> +	error = xfs_inobt_cur(mp, tp, pag, btnum, &cur, &agbp);
>  	if (error)
>  		return error;
>  
> diff --git a/fs/xfs/libxfs/xfs_ialloc_btree.h b/fs/xfs/libxfs/xfs_ialloc_btree.h
> index 04dfa7eee81f..e530c82b2217 100644
> --- a/fs/xfs/libxfs/xfs_ialloc_btree.h
> +++ b/fs/xfs/libxfs/xfs_ialloc_btree.h
> @@ -47,10 +47,10 @@ struct xfs_perag;
>  		 ((index) - 1) * sizeof(xfs_inobt_ptr_t)))
>  
>  extern struct xfs_btree_cur *xfs_inobt_init_cursor(struct xfs_mount *mp,
> -		struct xfs_trans *tp, struct xfs_buf *agbp, xfs_agnumber_t agno,
> +		struct xfs_trans *tp, struct xfs_buf *agbp,
>  		struct xfs_perag *pag, xfs_btnum_t btnum);
>  struct xfs_btree_cur *xfs_inobt_stage_cursor(struct xfs_mount *mp,
> -		struct xbtree_afakeroot *afake, xfs_agnumber_t agno,
> +		struct xbtree_afakeroot *afake, struct xfs_perag *pag,
>  		xfs_btnum_t btnum);
>  extern int xfs_inobt_maxrecs(struct xfs_mount *, int, int);
>  
> @@ -69,7 +69,7 @@ int xfs_finobt_calc_reserves(struct xfs_mount *mp, struct xfs_trans *tp,
>  extern xfs_extlen_t xfs_iallocbt_calc_size(struct xfs_mount *mp,
>  		unsigned long long len);
>  int xfs_inobt_cur(struct xfs_mount *mp, struct xfs_trans *tp,
> -		xfs_agnumber_t agno, xfs_btnum_t btnum,
> +		struct xfs_perag *pag, xfs_btnum_t btnum,
>  		struct xfs_btree_cur **curpp, struct xfs_buf **agi_bpp);
>  
>  void xfs_inobt_commit_staged_btree(struct xfs_btree_cur *cur,
> diff --git a/fs/xfs/scrub/agheader_repair.c b/fs/xfs/scrub/agheader_repair.c
> index ee2d85e3fd4a..ecc9146647ba 100644
> --- a/fs/xfs/scrub/agheader_repair.c
> +++ b/fs/xfs/scrub/agheader_repair.c
> @@ -806,7 +806,7 @@ xrep_agi_calc_from_btrees(
>  	xfs_agino_t		freecount;
>  	int			error;
>  
> -	cur = xfs_inobt_init_cursor(mp, sc->tp, agi_bp, sc->sa.agno,
> +	cur = xfs_inobt_init_cursor(mp, sc->tp, agi_bp,
>  			sc->sa.pag, XFS_BTNUM_INO);
>  	error = xfs_ialloc_count_inodes(cur, &count, &freecount);
>  	if (error)
> @@ -828,7 +828,7 @@ xrep_agi_calc_from_btrees(
>  	    xfs_sb_version_hasinobtcounts(&mp->m_sb)) {
>  		xfs_agblock_t	blocks;
>  
> -		cur = xfs_inobt_init_cursor(mp, sc->tp, agi_bp, sc->sa.agno,
> +		cur = xfs_inobt_init_cursor(mp, sc->tp, agi_bp,
>  				sc->sa.pag, XFS_BTNUM_FINO);
>  		error = xfs_btree_count_blocks(cur, &blocks);
>  		if (error)
> diff --git a/fs/xfs/scrub/common.c b/fs/xfs/scrub/common.c
> index 3035f8cee6f6..64c3b9b78d0d 100644
> --- a/fs/xfs/scrub/common.c
> +++ b/fs/xfs/scrub/common.c
> @@ -458,7 +458,6 @@ xchk_ag_btcur_init(
>  	struct xchk_ag		*sa)
>  {
>  	struct xfs_mount	*mp = sc->mp;
> -	xfs_agnumber_t		agno = sa->agno;
>  
>  	xchk_perag_get(sc->mp, sa);
>  	if (sa->agf_bp &&
> @@ -479,14 +478,14 @@ xchk_ag_btcur_init(
>  	if (sa->agi_bp &&
>  	    xchk_ag_btree_healthy_enough(sc, sa->pag, XFS_BTNUM_INO)) {
>  		sa->ino_cur = xfs_inobt_init_cursor(mp, sc->tp, sa->agi_bp,
> -				agno, sa->pag, XFS_BTNUM_INO);
> +				sa->pag, XFS_BTNUM_INO);
>  	}
>  
>  	/* Set up a finobt cursor for cross-referencing. */
>  	if (sa->agi_bp && xfs_sb_version_hasfinobt(&mp->m_sb) &&
>  	    xchk_ag_btree_healthy_enough(sc, sa->pag, XFS_BTNUM_FINO)) {
>  		sa->fino_cur = xfs_inobt_init_cursor(mp, sc->tp, sa->agi_bp,
> -				agno, sa->pag, XFS_BTNUM_FINO);
> +				sa->pag, XFS_BTNUM_FINO);
>  	}
>  
>  	/* Set up a rmapbt cursor for cross-referencing. */
> diff --git a/fs/xfs/xfs_iwalk.c b/fs/xfs/xfs_iwalk.c
> index c7e8f48a3ec4..917d51eefee3 100644
> --- a/fs/xfs/xfs_iwalk.c
> +++ b/fs/xfs/xfs_iwalk.c
> @@ -272,8 +272,7 @@ xfs_iwalk_ag_start(
>  
>  	/* Set up a fresh cursor and empty the inobt cache. */
>  	iwag->nr_recs = 0;
> -	error = xfs_inobt_cur(mp, tp, pag->pag_agno, XFS_BTNUM_INO,
> -				curpp, agi_bpp);
> +	error = xfs_inobt_cur(mp, tp, pag, XFS_BTNUM_INO, curpp, agi_bpp);
>  	if (error)
>  		return error;
>  
> @@ -378,8 +377,7 @@ xfs_iwalk_run_callbacks(
>  		return 0;
>  
>  	/* ...and recreate the cursor just past where we left off. */
> -	error = xfs_inobt_cur(mp, tp, iwag->pag->pag_agno, XFS_BTNUM_INO,
> -				curpp, agi_bpp);
> +	error = xfs_inobt_cur(mp, tp, iwag->pag, XFS_BTNUM_INO, curpp, agi_bpp);
>  	if (error)
>  		return error;
>  
> -- 
> 2.31.1
> 

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 10/22] xfs: pass perags around in fsmap data dev functions
  2021-05-12 22:23   ` Darrick J. Wong
@ 2021-05-18  1:00     ` Dave Chinner
  0 siblings, 0 replies; 87+ messages in thread
From: Dave Chinner @ 2021-05-18  1:00 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs

On Wed, May 12, 2021 at 03:23:23PM -0700, Darrick J. Wong wrote:
> On Thu, May 06, 2021 at 05:20:42PM +1000, Dave Chinner wrote:
> > From: Dave Chinner <dchinner@redhat.com>
> > 
> > Needs a [from, to] ranged AG walk, and the perag to be stuffed into
> > the info structure for callouts to use.
> > 
> > Signed-off-by: Dave Chinner <dchinner@redhat.com>
> > ---
> >  fs/xfs/libxfs/xfs_ag.h | 14 ++++++--
> >  fs/xfs/xfs_fsmap.c     | 75 ++++++++++++++++++++++++++----------------
> >  2 files changed, 58 insertions(+), 31 deletions(-)
> > 
> > diff --git a/fs/xfs/libxfs/xfs_ag.h b/fs/xfs/libxfs/xfs_ag.h
> > index 3fa88222dacd..bebbe1bfce27 100644
> > --- a/fs/xfs/libxfs/xfs_ag.h
> > +++ b/fs/xfs/libxfs/xfs_ag.h
> > @@ -116,14 +116,24 @@ void	xfs_perag_put(struct xfs_perag *pag);
> >  
> >  /*
> >   * Perag iteration APIs
> > + *
> > + * XXX: for_each_perag_range() usage really needs an iterator to clean up when
> > + * we terminate at end_agno because we may have taken a reference to the perag
> > + * beyond end_agno. RIght now callers have to be careful to catch and clean that
> > + * up themselves. This is not necessary for the callers of for_each_perag() and
> > + * for_each_perag_from() because they terminate at sb_agcount where there are
> > + * no perag structures in tree beyond end_agno.
> 
> I think I'll wait and see what this becomes with the next iteration
> before RVBing things.  The conversions look correct in this patch.

I wasn't planning on addressing this immediately (i.e. in this patch
set), so it's not actually going to change yet. I'll do this as a
standalone conversion in the next series of changes leading up to
active references...

-Dave.

-- 
Dave Chinner
david@fromorbit.com

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 18/22] xfs: collapse AG selection for inode allocation
  2021-05-12 12:52   ` Brian Foster
@ 2021-05-18  1:21     ` Dave Chinner
  0 siblings, 0 replies; 87+ messages in thread
From: Dave Chinner @ 2021-05-18  1:21 UTC (permalink / raw)
  To: Brian Foster; +Cc: linux-xfs

On Wed, May 12, 2021 at 08:52:25AM -0400, Brian Foster wrote:
> On Thu, May 06, 2021 at 05:20:50PM +1000, Dave Chinner wrote:
> > From: Dave Chinner <dchinner@redhat.com>
> > 
> > xfs_dialloc_select_ag() does a lot of repetitive work. It first
> > calls xfs_ialloc_ag_select() to select the AG to start allocation
> > attempts in, which can do up to two entire loops across the perags
> > that inodes can be allocated in. This is simply checking if there is
> > spce available to allocate inodes in an AG, and it returns when it
> > finds the first candidate AG.
> > 
> > xfs_dialloc_select_ag() then does it's own iterative walk across
> > all the perags locking the AGIs and trying to allocate inodes from
> > the locked AG. It also doesn't limit the search to mp->m_maxagi,
> > so it will walk all AGs whether they can allocate inodes or not.
> > 
> > Hence if we are really low on inodes, we could do almost 3 entire
> > walks across the whole perag range before we find an allocation
> > group we can allocate inodes in or report ENOSPC.
> > 
> > Because xfs_ialloc_ag_select() returns on the first candidate AG it
> > finds, we can simply do these checks directly in
> > xfs_dialloc_select_ag() before we lock and try to allocate inodes.
> > This reduces the inode allocation pass down to 2 perag sweeps at
> > most - one for aligned inode cluster allocation and if we can't
> > allocate full, aligned inode clusters anywhere we'll do another pass
> > trying to do sparse inode cluster allocation.
> > 
> > This also removes a big chunk of duplicate code.
> > 
> > Signed-off-by: Dave Chinner <dchinner@redhat.com>
> > ---
> >  fs/xfs/libxfs/xfs_ialloc.c | 221 +++++++++++++------------------------
> >  1 file changed, 75 insertions(+), 146 deletions(-)
> > 
> > diff --git a/fs/xfs/libxfs/xfs_ialloc.c b/fs/xfs/libxfs/xfs_ialloc.c
> > index 872591e8f5cb..b22556556bba 100644
> > --- a/fs/xfs/libxfs/xfs_ialloc.c
> > +++ b/fs/xfs/libxfs/xfs_ialloc.c
> ...
> > @@ -1778,10 +1669,41 @@ xfs_dialloc_select_ag(
> >  				break;
> >  		}
> >  
> > +		if (!pag->pagi_freecount)
> > +			goto nextag;
> 
> It looks like this would never allow for allocation of new inode
> chunks..?
> 
> > +		if (!okalloc)
> > +			goto nextag;

I guess I never tested this patch in isolation, and I fixed the bug
in one of the following patches. This should be:

		if (!pag->pagi_freecount && !okalloc)
			goto nextag;

Fixed.

-Dave.
-- 
Dave Chinner
david@fromorbit.com

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 18/22] xfs: collapse AG selection for inode allocation
  2021-05-12 23:11   ` Darrick J. Wong
@ 2021-05-18  1:29     ` Dave Chinner
  0 siblings, 0 replies; 87+ messages in thread
From: Dave Chinner @ 2021-05-18  1:29 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs

On Wed, May 12, 2021 at 04:11:14PM -0700, Darrick J. Wong wrote:
> On Thu, May 06, 2021 at 05:20:50PM +1000, Dave Chinner wrote:
> > From: Dave Chinner <dchinner@redhat.com>
> > 
> > xfs_dialloc_select_ag() does a lot of repetitive work. It first
> > calls xfs_ialloc_ag_select() to select the AG to start allocation
> > attempts in, which can do up to two entire loops across the perags
> > that inodes can be allocated in. This is simply checking if there is
> > spce available to allocate inodes in an AG, and it returns when it
> > finds the first candidate AG.
> > 
> > xfs_dialloc_select_ag() then does it's own iterative walk across
> > all the perags locking the AGIs and trying to allocate inodes from
> > the locked AG. It also doesn't limit the search to mp->m_maxagi,
> > so it will walk all AGs whether they can allocate inodes or not.
> > 
> > Hence if we are really low on inodes, we could do almost 3 entire
> > walks across the whole perag range before we find an allocation
> > group we can allocate inodes in or report ENOSPC.
> > 
> > Because xfs_ialloc_ag_select() returns on the first candidate AG it
> > finds, we can simply do these checks directly in
> > xfs_dialloc_select_ag() before we lock and try to allocate inodes.
> > This reduces the inode allocation pass down to 2 perag sweeps at
> > most - one for aligned inode cluster allocation and if we can't
> > allocate full, aligned inode clusters anywhere we'll do another pass
> > trying to do sparse inode cluster allocation.
> > 
> > This also removes a big chunk of duplicate code.
> 
> Soooooo... we did an AG walk to pick the optimal starting point of an AG
> walk?  Heh.

yup.

> > @@ -1734,16 +1616,23 @@ xfs_dialloc_select_ag(
> >  	struct xfs_perag	*pag;
> >  	struct xfs_ino_geometry	*igeo = M_IGEO(mp);
> >  	bool			okalloc = true;
> > +	int			needspace;
> > +	int			flags;
> >  
> >  	*IO_agbp = NULL;
> >  
> >  	/*
> > -	 * We do not have an agbp, so select an initial allocation
> > -	 * group for inode allocation.
> > +	 * Files of these types need at least one block if length > 0
> > +	 * (and they won't fit in the inode, but that's hard to figure out).
> 
> Uh, what is length here?  Seeing as most directories and symlinks
> probably end up in local format, is this needspace computation really
> true?

Ah, that's the exact text from the comment in
xfs_ialloc_ag_select() above the needspace calculation - I didn't
actually change it at all. :/

> I guess it doesn't hurt to be cautious and assume that directories can
> expand and that people are aggressively symlinking.  But maybe this
> comment could be rephrased to something like:
> 
> 	/*
> 	 * Directories, symlinks, and regular files frequently allocate
> 	 * at least one block, so factor that potential expansion when
> 	 * we examine whether an AG has enough space for file creation.
> 	 */
> 	needspace = S_ISDIR(mode)...;
> 
> With that clarified,
> Reviewed-by: Darrick J. Wong <djwong@kernel.org>

Changed.

-Dave.
-- 
Dave Chinner
david@fromorbit.com

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [PATCH 21/22] xfs: clean up and simplify xfs_dialloc()
  2021-05-12 21:49   ` Darrick J. Wong
@ 2021-05-18  1:46     ` Dave Chinner
  0 siblings, 0 replies; 87+ messages in thread
From: Dave Chinner @ 2021-05-18  1:46 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs

On Wed, May 12, 2021 at 02:49:30PM -0700, Darrick J. Wong wrote:
> On Thu, May 06, 2021 at 05:20:53PM +1000, Dave Chinner wrote:
> > From: Dave Chinner <dchinner@redhat.com>
> > 
> > Because it's a mess.
> > 
> > Signed-off-by: Dave Chinner <dchinner@redhat.com>
.....
> > +	/*
> > +	 * Check that there is enough free space for the file plus a chunk of
> > +	 * inodes if we need to allocate some. If this is the first pass across
> > +	 * the AGs, take into account the potential space needed for alignment
> > +	 * of inode chunks when checking the longest contiguous free space in
> > +	 * the AG - this prevents us from getting ENOSPC because we have free
> > +	 * space larger than ialloc_blks but alignment constraints prevent us
> > +	 * from using it.
> > +	 *
> > +	 * If we can't find an AG with space for full alignment slack to be
> > +	 * taken into account, we must be near ENOSPC in all AGs.  Hence we
> > +	 * don't include alignment for the second pass and so if we fail
> > +	 * allocation due to alignment issues then it is most likely a real
> > +	 * ENOSPC condition.
> > +	 *
> > +	 * XXX(dgc): this calculation is now bogus thanks to the per-ag
> > +	 * reservations that xfs_alloc_fix_freelist() now does via
> > +	 * xfs_alloc_space_available(). When the AG fills up, pagf_freeblks will
> > +	 * be more than large enough for the check below to succeed, but
> > +	 * xfs_alloc_space_available() will fail because of the non-zero
> > +	 * metadata reservation and hence we won't actually be able to allocate
> > +	 * more inodes in this AG. We do soooo much unnecessary work near ENOSPC
> > +	 * because of this.
> 
> Yuck.  Can this be fixed by doing:
> 
> 	really_free = pag->pagf_freeblks -
> 				xfs_ag_resv_needed(pag, XFS_AG_RESV_NONE);
> 	return really_free >= needspace + ineed && longest >= ineed)
> 
> to account for those reservations, perhaps?

Something like that, though I'd much prefer to factor the freelist
fixup calculations and use them here so we have a single set of
"is there enough space in this AG for allocating X blocks"
functions.

It's somewhat outside the scope of this patchset, so I wrote the
comment rather than trying to address it here and complicate this
patchset....

> > @@ -1624,7 +1746,6 @@ xfs_dialloc(
> >  	 * Files of these types need at least one block if length > 0
> >  	 * (and they won't fit in the inode, but that's hard to figure out).
> >  	 */
> > -	needspace = S_ISDIR(mode) || S_ISREG(mode) || S_ISLNK(mode);
> >  	if (S_ISDIR(mode))
> >  		start_agno = xfs_ialloc_next_ag(mp);
> >  	else {
> > @@ -1635,7 +1756,7 @@ xfs_dialloc(
> >  
> >  	/*
> >  	 * If we have already hit the ceiling of inode blocks then clear
> > -	 * okalloc so we scan all available agi structures for a free
> > +	 * ok_alloc so we scan all available agi structures for a free
> >  	 * inode.
> >  	 *
> >  	 * Read rough value of mp->m_icount by percpu_counter_read_positive,
> > @@ -1644,7 +1765,7 @@ xfs_dialloc(
> 
> Er... didn't this logic get split into xfs_dialloc_select_ag in 5.11?

Yeah, but that was more about cleaning up the code in xfs_inode.c
by separating out the inode initialisation from the physical inode
allocation. That cleanup and separation is what allows this series
to simplify and clean up the inode allocation because it is no
longer commingled with the inode initialisation after allocation...

> Nice cleanup, at least...
>
>  :)

Yup, along with the 5.11 mods, we've chopped a lot of unnecessary
code out of the inode allocation path... :)

-Dave.
-- 
Dave Chinner
david@fromorbit.com

^ permalink raw reply	[flat|nested] 87+ messages in thread

end of thread, other threads:[~2021-05-18  1:46 UTC | newest]

Thread overview: 87+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-05-06  7:20 [RFC 00/22] xfs: initial agnumber -> perag conversions for shrink Dave Chinner
2021-05-06  7:20 ` [PATCH 01/22] xfs: move xfs_perag_get/put to xfs_ag.[ch] Dave Chinner
2021-05-10 12:52   ` Brian Foster
2021-05-11  7:18     ` Dave Chinner
2021-05-10 22:28   ` Darrick J. Wong
2021-05-06  7:20 ` [PATCH 02/22] xfs: prepare for moving perag definitions and support to libxfs Dave Chinner
2021-05-10 12:53   ` Brian Foster
2021-05-11  7:19     ` Dave Chinner
2021-05-06  7:20 ` [PATCH 03/22] xfs: move perag structure and setup to libxfs/xfs_ag.[ch] Dave Chinner
2021-05-10 22:26   ` Darrick J. Wong
2021-05-10 23:38     ` Dave Chinner
2021-05-06  7:20 ` [PATCH 04/22] xfs: make for_each_perag... a first class citizen Dave Chinner
2021-05-10 12:53   ` Brian Foster
2021-05-11  7:35     ` Dave Chinner
2021-05-11 12:29       ` Brian Foster
2021-05-11 21:33         ` Dave Chinner
2021-05-12 21:58           ` Darrick J. Wong
2021-05-06  7:20 ` [PATCH 05/22] xfs: convert raw ag walks to use for_each_perag Dave Chinner
2021-05-10 12:54   ` Brian Foster
2021-05-06  7:20 ` [PATCH 06/22] xfs: convert xfs_iwalk to use perag references Dave Chinner
2021-05-10 13:41   ` Brian Foster
2021-05-12 22:08   ` Darrick J. Wong
2021-05-06  7:20 ` [PATCH 07/22] xfs: convert secondary superblock walk to use perags Dave Chinner
2021-05-10 13:41   ` Brian Foster
2021-05-12 22:09   ` Darrick J. Wong
2021-05-06  7:20 ` [PATCH 08/22] xfs: pass perags through to the busy extent code Dave Chinner
2021-05-11 12:29   ` Brian Foster
2021-05-12 22:13   ` Darrick J. Wong
2021-05-06  7:20 ` [PATCH 09/22] xfs: push perags through the ag reservation callouts Dave Chinner
2021-05-11 12:29   ` Brian Foster
2021-05-13  0:29     ` Dave Chinner
2021-05-12 22:16   ` Darrick J. Wong
2021-05-06  7:20 ` [PATCH 10/22] xfs: pass perags around in fsmap data dev functions Dave Chinner
2021-05-11 12:30   ` Brian Foster
2021-05-12 22:23   ` Darrick J. Wong
2021-05-18  1:00     ` Dave Chinner
2021-05-06  7:20 ` [PATCH 11/22] xfs: add a perag to the btree cursor Dave Chinner
2021-05-11 12:30   ` Brian Foster
2021-05-11 20:51     ` Darrick J. Wong
2021-05-11 21:52       ` Dave Chinner
2021-05-12 12:49         ` Brian Foster
2021-05-12 22:41           ` Darrick J. Wong
2021-05-12 22:40   ` Darrick J. Wong
2021-05-13  0:12     ` Dave Chinner
2021-05-13  0:55       ` Darrick J. Wong
2021-05-13  1:07         ` Dave Chinner
2021-05-13  3:49           ` Darrick J. Wong
2021-05-06  7:20 ` [PATCH 12/22] xfs: convert rmap btree cursor to using a perag Dave Chinner
2021-05-11 12:30   ` Brian Foster
2021-05-12 22:45   ` Darrick J. Wong
2021-05-13  3:54     ` Darrick J. Wong
2021-05-06  7:20 ` [PATCH 13/22] xfs: convert refcount btree cursor to use perags Dave Chinner
2021-05-11 12:30   ` Brian Foster
2021-05-12 22:47   ` Darrick J. Wong
2021-05-06  7:20 ` [PATCH 14/22] xfs: convert allocbt cursors " Dave Chinner
2021-05-11 12:30   ` Brian Foster
2021-05-13  3:55   ` Darrick J. Wong
2021-05-06  7:20 ` [PATCH 15/22] xfs: use perag for ialloc btree cursors Dave Chinner
2021-05-11 12:30   ` Brian Foster
2021-05-13  3:55   ` Darrick J. Wong
2021-05-06  7:20 ` [PATCH 16/22] xfs: remove agno from btree cursor Dave Chinner
2021-05-11 12:34   ` Brian Foster
2021-05-11 22:02     ` Dave Chinner
2021-05-12 22:52   ` Darrick J. Wong
2021-05-06  7:20 ` [PATCH 17/22] xfs: simplify xfs_dialloc_select_ag() return values Dave Chinner
2021-05-12 12:49   ` Brian Foster
2021-05-12 22:55   ` Darrick J. Wong
2021-05-06  7:20 ` [PATCH 18/22] xfs: collapse AG selection for inode allocation Dave Chinner
2021-05-12 12:52   ` Brian Foster
2021-05-18  1:21     ` Dave Chinner
2021-05-12 23:11   ` Darrick J. Wong
2021-05-18  1:29     ` Dave Chinner
2021-05-06  7:20 ` [PATCH 19/22] xfs: get rid of xfs_dir_ialloc() Dave Chinner
2021-05-06 11:26   ` kernel test robot
2021-05-06 11:26     ` kernel test robot
2021-05-06 11:26   ` [RFC PATCH] xfs: xfs_dialloc_ag can be static kernel test robot
2021-05-06 11:26     ` kernel test robot
2021-05-12 12:52   ` [PATCH 19/22] xfs: get rid of xfs_dir_ialloc() Brian Foster
2021-05-12 23:19   ` Darrick J. Wong
2021-05-06  7:20 ` [PATCH 20/22] xfs: inode allocation can use a single perag instance Dave Chinner
2021-05-12 12:52   ` Brian Foster
2021-05-12 23:19   ` Darrick J. Wong
2021-05-06  7:20 ` [PATCH 21/22] xfs: clean up and simplify xfs_dialloc() Dave Chinner
2021-05-12 21:49   ` Darrick J. Wong
2021-05-18  1:46     ` Dave Chinner
2021-05-06  7:20 ` [PATCH 22/22] xfs: use perag through unlink processing Dave Chinner
2021-05-12 21:37   ` Darrick J. Wong

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.