diff mbox series

[1/5] xfs: count the number of blocks in a per-ag reservation

Message ID aa97ca3662b008c5319f636f1520dfe680c20041.1723688622.git.kjlx@templeofstupid.com (mailing list archive)
State Accepted, archived
Headers show
Series xfstests: fstests for agfl reservation | expand

Commit Message

Krister Johansen Aug. 15, 2024, 7:31 p.m. UTC
In order to get the AGFL reservation, alloc_set_aside, and ag_max_usable
calculations correct in the face of per-AG reservations, we need to
understand the number of blocks that a per-AG reservation can leave free
in a worst-case scenario.

Compute the number of blocks used for a per-ag reservation by using AG
0's reservation.  Other code already assumes AG 0's reservation is as
large or larger than the other AG's.  Subsequent patches will used the
block count to construct a more accurate set of parameters.

The reservation is counted after log_mount_finish because reservations
are temporarily enabled for this operation.  An updated alloc_set_aside
and ag_max_usable need to be computed before enabling reservations at
the end of a RW mount.

Signed-off-by: Krister Johansen <kjlx@templeofstupid.com>
---
 fs/xfs/xfs_fsops.c | 21 +++++++++++++++++++++
 fs/xfs/xfs_fsops.h |  1 +
 fs/xfs/xfs_mount.c |  7 +++++++
 fs/xfs/xfs_mount.h |  7 +++++++
 4 files changed, 36 insertions(+)
diff mbox series

Patch

diff --git a/fs/xfs/xfs_fsops.c b/fs/xfs/xfs_fsops.c
index c211ea2b63c4..fefc20df8a2e 100644
--- a/fs/xfs/xfs_fsops.c
+++ b/fs/xfs/xfs_fsops.c
@@ -551,6 +551,27 @@  xfs_fs_reserve_ag_blocks(
 	return error;
 }
 
+/*
+ * Count the number of reserved blocks that an AG has requested.
+ */
+uint
+xfs_fs_count_reserved_ag_blocks(
+	struct xfs_mount	*mp,
+	xfs_agnumber_t		agno)
+{
+
+	struct xfs_perag	*pag;
+	uint			blocks = 0;
+
+	pag = xfs_perag_grab(mp, agno);
+	if (!pag)
+		return blocks;
+
+	blocks = pag->pag_meta_resv.ar_asked + pag->pag_rmapbt_resv.ar_asked;
+	xfs_perag_rele(pag);
+	return blocks;
+}
+
 /*
  * Free space reserved for per-AG metadata.
  */
diff --git a/fs/xfs/xfs_fsops.h b/fs/xfs/xfs_fsops.h
index 3e2f73bcf831..75f5fa1a38f4 100644
--- a/fs/xfs/xfs_fsops.h
+++ b/fs/xfs/xfs_fsops.h
@@ -12,6 +12,7 @@  int xfs_reserve_blocks(struct xfs_mount *mp, uint64_t request);
 int xfs_fs_goingdown(struct xfs_mount *mp, uint32_t inflags);
 
 int xfs_fs_reserve_ag_blocks(struct xfs_mount *mp);
+uint xfs_fs_count_reserved_ag_blocks(struct xfs_mount *mp, xfs_agnumber_t agno);
 void xfs_fs_unreserve_ag_blocks(struct xfs_mount *mp);
 
 #endif	/* __XFS_FSOPS_H__ */
diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c
index 09eef1721ef4..d6ba67a29e3a 100644
--- a/fs/xfs/xfs_mount.c
+++ b/fs/xfs/xfs_mount.c
@@ -952,6 +952,13 @@  xfs_mountfs(
 		xfs_warn(mp,
 	"ENOSPC reserving per-AG metadata pool, log recovery may fail.");
 	error = xfs_log_mount_finish(mp);
+	/*
+	 * Before disabling the temporary per-ag reservation, count up the
+	 * reserved blocks in AG 0.  This will be used to determine how to
+	 * re-size the AGFL reserve and alloc_set_aside prior to enabling
+	 * reservations if the mount is RW.
+	 */
+	mp->m_ag_resblk_count = xfs_fs_count_reserved_ag_blocks(mp, 0);
 	xfs_fs_unreserve_ag_blocks(mp);
 	if (error) {
 		xfs_warn(mp, "log mount finish failed");
diff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h
index d0567dfbc036..800788043ca6 100644
--- a/fs/xfs/xfs_mount.h
+++ b/fs/xfs/xfs_mount.h
@@ -213,6 +213,13 @@  typedef struct xfs_mount {
 	uint64_t		m_resblks;	/* total reserved blocks */
 	uint64_t		m_resblks_avail;/* available reserved blocks */
 	uint64_t		m_resblks_save;	/* reserved blks @ remount,ro */
+
+	/*
+	 * Number of per-ag resv blocks for a single AG. Derived from AG 0
+	 * under the assumption no per-AG reservations will be larger than that
+	 * one.
+	 */
+	uint			m_ag_resblk_count;
 	struct delayed_work	m_reclaim_work;	/* background inode reclaim */
 	struct dentry		*m_debugfs;	/* debugfs parent */
 	struct xfs_kobj		m_kobj;