@@ -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.
*/
@@ -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__ */
@@ -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");
@@ -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;
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(+)