linux/fs/xfs/libxfs
Darrick J. Wong ef42a8766f xfs: fix freemap adjustments when adding xattrs to leaf blocks
[ Upstream commit 3eefc0c2b7 ]

xfs/592 and xfs/794 both trip this assertion in the leaf block freemap
adjustment code after ~20 minutes of running on my test VMs:

 ASSERT(ichdr->firstused >= ichdr->count * sizeof(xfs_attr_leaf_entry_t)
					+ xfs_attr3_leaf_hdr_size(leaf));

Upon enabling quite a lot more debugging code, I narrowed this down to
fsstress trying to set a local extended attribute with namelen=3 and
valuelen=71.  This results in an entry size of 80 bytes.

At the start of xfs_attr3_leaf_add_work, the freemap looks like this:

i 0 base 448 size 0 rhs 448 count 46
i 1 base 388 size 132 rhs 448 count 46
i 2 base 2120 size 4 rhs 448 count 46
firstused = 520

where "rhs" is the first byte past the end of the leaf entry array.
This is inconsistent -- the entries array ends at byte 448, but
freemap[1] says there's free space starting at byte 388!

By the end of the function, the freemap is in worse shape:

i 0 base 456 size 0 rhs 456 count 47
i 1 base 388 size 52 rhs 456 count 47
i 2 base 2120 size 4 rhs 456 count 47
firstused = 440

Important note: 388 is not aligned with the entries array element size
of 8 bytes.

Based on the incorrect freemap, the name area starts at byte 440, which
is below the end of the entries array!  That's why the assertion
triggers and the filesystem shuts down.

How did we end up here?  First, recall from the previous patch that the
freemap array in an xattr leaf block is not intended to be a
comprehensive map of all free space in the leaf block.  In other words,
it's perfectly legal to have a leaf block with:

 * 376 bytes in use by the entries array
 * freemap[0] has [base = 376, size = 8]
 * freemap[1] has [base = 388, size = 1500]
 * the space between 376 and 388 is free, but the freemap stopped
   tracking that some time ago

If we add one xattr, the entries array grows to 384 bytes, and
freemap[0] becomes [base = 384, size = 0].  So far, so good.  But if we
add a second xattr, the entries array grows to 392 bytes, and freemap[0]
gets pushed up to [base = 392, size = 0].  This is bad, because
freemap[1] hasn't been updated, and now the entries array and the free
space claim the same space.

The fix here is to adjust all freemap entries so that none of them
collide with the entries array.  Note that this fix relies on commit
2a2b5932db ("xfs: fix attr leaf header freemap.size underflow") and
the previous patch that resets zero length freemap entries to have
base = 0.

Cc: <stable@vger.kernel.org> # v2.6.12
Fixes: 1da177e4c3 ("Linux-2.6.12-rc2")
Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Sasha Levin <sashal@kernel.org>
History 2026-03-04 07:21:48 -05:00
..
xfs_ag.c xfs: update the pag for the last AG at recovery time 2024-10-22 13:37:19 +02:00
xfs_ag.h xfs: update the pag for the last AG at recovery time 2024-10-22 13:37:19 +02:00
xfs_ag_resv.c xfs: split xfs_mod_freecounter 2024-04-22 18:00:47 +05:30
xfs_ag_resv.h xfs: get rid of xfs_ag_resv_rmapbt_alloc 2024-07-04 14:36:13 +05:30
xfs_alloc.c xfs: Reduce unnecessary searches when searching for the best extents 2024-10-30 11:27:18 +01:00
xfs_alloc.h xfs: don't ifdef around the exact minlen allocations 2024-10-07 08:00:11 +02:00
xfs_alloc_btree.c xfs: standardize the btree maxrecs function parameters 2024-09-01 08:58:20 -07:00
xfs_alloc_btree.h xfs: standardize the btree maxrecs function parameters 2024-09-01 08:58:20 -07:00
xfs_attr.c xfs: remove xfs_attr_leaf_hasname 2026-03-04 07:21:47 -05:00
xfs_attr.h xfs: fix xfs_init_attr_trans not handling explicit operation codes 2024-05-27 15:55:52 +05:30
xfs_attr_leaf.c xfs: fix freemap adjustments when adding xattrs to leaf blocks 2026-03-04 07:21:48 -05:00
xfs_attr_leaf.h xfs: return bool from xfs_attr3_leaf_add 2024-10-07 08:00:11 +02:00
xfs_attr_remote.c xfs: do not propagate ENODATA disk errors into xattr code 2025-09-04 15:31:54 +02:00
xfs_attr_remote.h xfs: create a helper to compute the blockcount of a max sized remote value 2024-05-02 07:48:36 -07:00
xfs_attr_sf.h xfs: pass the attr value to put_listent when possible 2024-04-23 07:47:00 -07:00
xfs_bit.c xfs: fix missing header includes 2019-11-07 13:00:53 -08:00
xfs_bit.h xfs: Use the correct style for SPDX License Identifier 2020-05-13 15:32:45 -07:00
xfs_bmap.c xfs: support lowmode allocations in xfs_bmap_exact_minlen_extent_alloc 2024-10-07 08:00:12 +02:00
xfs_bmap.h xfs: hoist extent size helpers to libxfs 2024-07-02 11:36:55 -07:00
xfs_bmap_btree.c xfs: standardize the btree maxrecs function parameters 2024-09-01 08:58:20 -07:00
xfs_bmap_btree.h xfs: standardize the btree maxrecs function parameters 2024-09-01 08:58:20 -07:00
xfs_btree.c xfs: return a 64-bit block count from xfs_btree_count_blocks 2024-12-19 18:13:08 +01:00
xfs_btree.h xfs: return a 64-bit block count from xfs_btree_count_blocks 2024-12-19 18:13:08 +01:00
xfs_btree_mem.c xfs: launder in-memory btree buffers before transaction commit 2024-02-22 12:43:36 -08:00
xfs_btree_mem.h xfs: launder in-memory btree buffers before transaction commit 2024-02-22 12:43:36 -08:00
xfs_btree_staging.c xfs: xfs_btree_bload_prep_block() should use __GFP_NOFAIL 2024-02-28 14:04:30 +05:30
xfs_btree_staging.h xfs: don't override bc_ops for staging btrees 2024-02-22 12:37:35 -08:00
xfs_cksum.h License cleanup: add SPDX GPL-2.0 license identifier to files with no license 2017-11-02 11:10:55 +01:00
xfs_da_btree.c xfs: do not propagate ENODATA disk errors into xattr code 2025-09-04 15:31:54 +02:00
xfs_da_btree.h xfs: create attr log item opcodes and formats for parent pointers 2024-04-23 07:46:57 -07:00
xfs_da_format.h xfs: turn XFS_ATTR3_RMT_BUF_SPACE into a function 2024-05-02 07:48:36 -07:00
xfs_defer.c xfs: Remove duplicate xfs_trans_priv.h header 2024-09-03 10:07:41 +05:30
xfs_defer.h xfs: Increase XFS_DEFER_OPS_NR_INODES to 5 2024-04-15 14:59:01 -07:00
xfs_dir2.c xfs: move dirent update hooks to xfs_dir2.c 2024-07-02 11:37:00 -07:00
xfs_dir2.h xfs: move dirent update hooks to xfs_dir2.c 2024-07-02 11:37:00 -07:00
xfs_dir2_block.c xfs: validate explicit directory block buffer owners 2024-04-15 14:58:52 -07:00
xfs_dir2_data.c xfs: don't walk off the end of a directory data block 2024-07-01 09:32:29 +05:30
xfs_dir2_leaf.c xfs: validate explicit directory free block owners 2024-04-15 14:58:52 -07:00
xfs_dir2_node.c xfs: validate explicit directory free block owners 2024-04-15 14:58:52 -07:00
xfs_dir2_priv.h xfs: don't walk off the end of a directory data block 2024-07-01 09:32:29 +05:30
xfs_dir2_sf.c xfs: convert remaining kmem_free() to kfree() 2024-02-13 18:07:34 +05:30
xfs_dquot_buf.c xfs: remove the xfs_dqblk_t typedef 2021-10-14 09:19:33 -07:00
xfs_errortag.h xfs: add error injection to test file mapping exchange recovery 2024-04-15 14:54:19 -07:00
xfs_exchmaps.c xfs: refactor dir format helpers 2024-04-26 11:21:46 +05:30
xfs_exchmaps.h xfs: use atomic extent swapping to fix user file fork data 2024-04-15 14:58:53 -07:00
xfs_format.h xfs: don't use the incore struct xfs_sb for offsets into struct xfs_dsb 2024-07-02 11:37:00 -07:00
xfs_fs.h xfs: fix C++ compilation errors in xfs_fs.h 2024-09-01 08:58:20 -07:00
xfs_health.h xfs: report directory tree corruption in the health information 2024-04-23 16:55:17 -07:00
xfs_ialloc.c xfs: set max_agbno to allow sparse alloc of last full inode chunk 2026-01-23 11:18:50 +01:00
xfs_ialloc.h xfs: pass the icreate args object to xfs_dialloc 2024-09-01 08:58:19 -07:00
xfs_ialloc_btree.c xfs: return a 64-bit block count from xfs_btree_count_blocks 2024-12-19 18:13:08 +01:00
xfs_ialloc_btree.h xfs: standardize the btree maxrecs function parameters 2024-09-01 08:58:20 -07:00
xfs_iext_tree.c xfs: use __GFP_NOLOCKDEP instead of GFP_NOFS 2024-02-13 18:07:34 +05:30
xfs_inode_buf.c xfs: fix di_onlink checking for V1/V2 inodes 2024-08-26 09:50:41 +05:30
xfs_inode_buf.h xfs: kill xfs_sb_version_has_v3inode() 2021-08-19 10:07:14 -07:00
xfs_inode_fork.c xfs: standardize the btree maxrecs function parameters 2024-09-01 08:58:20 -07:00
xfs_inode_fork.h xfs: simplify iext overflow checking and upgrade 2024-05-03 11:20:06 +05:30
xfs_inode_util.c xfs: remove unnecessary check 2024-09-03 10:07:40 +05:30
xfs_inode_util.h xfs: hoist inode free function to libxfs 2024-07-02 11:36:59 -07:00
xfs_log_format.h xfs: fix log CRC mismatches between i386 and other architectures 2025-10-23 16:20:38 +02:00
xfs_log_recover.h xfs: capture inode generation numbers in the ondisk exchmaps log item 2024-04-15 14:54:24 -07:00
xfs_log_rlimit.c xfs: drop compatibility minimum log size computations for reflink 2024-04-23 07:47:01 -07:00
xfs_ondisk.h xfs: fix log CRC mismatches between i386 and other architectures 2025-10-23 16:20:38 +02:00
xfs_parent.c xfs: add raw parent pointer apis to support repair 2024-04-23 07:47:04 -07:00
xfs_parent.h xfs: add raw parent pointer apis to support repair 2024-04-23 07:47:04 -07:00
xfs_quota_defs.h xfs: remove unused parameter in macro XFS_DQUOT_LOGRES 2024-07-29 09:29:31 +05:30
xfs_refcount.c xfs: move xfs_refcount_update_defer_add to xfs_refcount_item.c 2024-07-02 11:37:07 -07:00
xfs_refcount.h xfs: move xfs_refcount_update_defer_add to xfs_refcount_item.c 2024-07-02 11:37:07 -07:00
xfs_refcount_btree.c xfs: standardize the btree maxrecs function parameters 2024-09-01 08:58:20 -07:00
xfs_refcount_btree.h xfs: standardize the btree maxrecs function parameters 2024-09-01 08:58:20 -07:00
xfs_rmap.c xfs: move xfs_rmap_update_defer_add to xfs_rmap_item.c 2024-07-02 11:37:05 -07:00
xfs_rmap.h xfs: move xfs_rmap_update_defer_add to xfs_rmap_item.c 2024-07-02 11:37:05 -07:00
xfs_rmap_btree.c xfs: standardize the btree maxrecs function parameters 2024-09-01 08:58:20 -07:00
xfs_rmap_btree.h xfs: standardize the btree maxrecs function parameters 2024-09-01 08:58:20 -07:00
xfs_rtbitmap.c xfs: replace m_rsumsize with m_rsumblocks 2024-09-01 08:58:19 -07:00
xfs_rtbitmap.h xfs: remove xfs_{rtbitmap,rtsummary}_wordcount 2024-09-01 08:58:19 -07:00
xfs_sb.c xfs: fix sb_spino_align checks for large fsblock sizes 2024-12-27 14:02:01 +01:00
xfs_sb.h xfs: ensure rtx mask/shift are correct after growfs 2024-09-01 08:58:19 -07:00
xfs_shared.h xfs: enable block size larger than page size support 2024-09-03 15:00:52 +02:00
xfs_symlink_remote.c xfs: return from xfs_symlink_verify early on V4 filesystems 2024-12-19 18:13:08 +01:00
xfs_symlink_remote.h xfs: pass the owner to xfs_symlink_write_target 2024-04-15 14:58:57 -07:00
xfs_trans_inode.c xfs: implement atime updates in xfs_trans_ichgtime 2024-07-02 11:36:56 -07:00
xfs_trans_resv.c xfs: replace shouty XFS_BM{BT,DR} macros 2024-09-01 08:58:20 -07:00
xfs_trans_resv.h xfs: rename xfs_*alloc*_log_count to _block_count 2022-04-28 10:25:59 -07:00
xfs_trans_space.c xfs: Add parent pointers to rename 2024-04-23 07:46:59 -07:00
xfs_trans_space.h xfs: Add parent pointers to rename 2024-04-23 07:46:59 -07:00
xfs_types.c xfs: rename xfs_verify_rtext to xfs_verify_rtbext 2023-10-17 16:24:22 -07:00
xfs_types.h xfs: remove xfs_validate_rtextents 2024-09-01 08:58:19 -07:00