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@xxxxxxxxxxxxxxxxxx> --- 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 --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; -- 2.25.1