77 lines
2.8 KiB
Diff
77 lines
2.8 KiB
Diff
From 26933a27fa749433c4a11034c9fb77971fc65049 Mon Sep 17 00:00:00 2001
|
|
From: Dave Chinner <dchinner@redhat.com>
|
|
Date: Wed, 18 Dec 2024 11:50:36 -0800
|
|
Subject: xfs: fix sparse inode limits on runt AG
|
|
|
|
The runt AG at the end of a filesystem is almost always smaller than
|
|
the mp->m_sb.sb_agblocks. Unfortunately, when setting the max_agbno
|
|
limit for the inode chunk allocation, we do not take this into
|
|
account. This means we can allocate a sparse inode chunk that
|
|
overlaps beyond the end of an AG. When we go to allocate an inode
|
|
from that sparse chunk, the irec fails validation because the
|
|
agbno of the start of the irec is beyond valid limits for the runt
|
|
AG.
|
|
|
|
Prevent this from happening by taking into account the size of the
|
|
runt AG when allocating inode chunks. Also convert the various
|
|
checks for valid inode chunk agbnos to use xfs_ag_block_count()
|
|
so that they will also catch such issues in the future.
|
|
|
|
Fixes: 56d1115c9bc7 ("xfs: allocate sparse inode chunks on full chunk allocation failure")
|
|
Signed-off-by: Dave Chinner <dchinner@redhat.com>
|
|
Reviewed-by: Darrick J. Wong <djwong@kernel.org>
|
|
Signed-off-by: Carlos Maiolino <cem@kernel.org>
|
|
---
|
|
fs/xfs/libxfs/xfs_ialloc.c | 16 +++++++++-------
|
|
1 file changed, 9 insertions(+), 7 deletions(-)
|
|
|
|
--- a/fs/xfs/libxfs/xfs_ialloc.c
|
|
+++ b/fs/xfs/libxfs/xfs_ialloc.c
|
|
@@ -855,7 +855,8 @@ sparse_alloc:
|
|
* the end of the AG.
|
|
*/
|
|
args.min_agbno = args.mp->m_sb.sb_inoalignmt;
|
|
- args.max_agbno = round_down(args.mp->m_sb.sb_agblocks,
|
|
+ args.max_agbno = round_down(xfs_ag_block_count(args.mp,
|
|
+ pag->pag_agno),
|
|
args.mp->m_sb.sb_inoalignmt) -
|
|
igeo->ialloc_blks;
|
|
|
|
@@ -2332,9 +2333,9 @@ xfs_difree(
|
|
return -EINVAL;
|
|
}
|
|
agbno = XFS_AGINO_TO_AGBNO(mp, agino);
|
|
- if (agbno >= mp->m_sb.sb_agblocks) {
|
|
- xfs_warn(mp, "%s: agbno >= mp->m_sb.sb_agblocks (%d >= %d).",
|
|
- __func__, agbno, mp->m_sb.sb_agblocks);
|
|
+ if (agbno >= xfs_ag_block_count(mp, pag->pag_agno)) {
|
|
+ xfs_warn(mp, "%s: agbno >= xfs_ag_block_count (%d >= %d).",
|
|
+ __func__, agbno, xfs_ag_block_count(mp, pag->pag_agno));
|
|
ASSERT(0);
|
|
return -EINVAL;
|
|
}
|
|
@@ -2457,7 +2458,7 @@ xfs_imap(
|
|
*/
|
|
agino = XFS_INO_TO_AGINO(mp, ino);
|
|
agbno = XFS_AGINO_TO_AGBNO(mp, agino);
|
|
- if (agbno >= mp->m_sb.sb_agblocks ||
|
|
+ if (agbno >= xfs_ag_block_count(mp, pag->pag_agno) ||
|
|
ino != XFS_AGINO_TO_INO(mp, pag->pag_agno, agino)) {
|
|
error = -EINVAL;
|
|
#ifdef DEBUG
|
|
@@ -2467,11 +2468,12 @@ xfs_imap(
|
|
*/
|
|
if (flags & XFS_IGET_UNTRUSTED)
|
|
return error;
|
|
- if (agbno >= mp->m_sb.sb_agblocks) {
|
|
+ if (agbno >= xfs_ag_block_count(mp, pag->pag_agno)) {
|
|
xfs_alert(mp,
|
|
"%s: agbno (0x%llx) >= mp->m_sb.sb_agblocks (0x%lx)",
|
|
__func__, (unsigned long long)agbno,
|
|
- (unsigned long)mp->m_sb.sb_agblocks);
|
|
+ (unsigned long)xfs_ag_block_count(mp,
|
|
+ pag->pag_agno));
|
|
}
|
|
if (ino != XFS_AGINO_TO_INO(mp, pag->pag_agno, agino)) {
|
|
xfs_alert(mp,
|