linux/fs/xfs/libxfs
Darrick J. Wong 43f3b18679 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:15 -05:00
..
xfs_ag.c xfs: remove the flags argument to xfs_buf_get_uncached 2025-03-18 14:47:45 +01:00
xfs_ag.h xfs: move the min and max group block numbers to xfs_group 2024-11-05 13:38:44 -08:00
xfs_ag_resv.c xfs: remove the expr argument to XFS_TEST_ERROR 2025-09-18 17:32:02 +02:00
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: remove the expr argument to XFS_TEST_ERROR 2025-09-18 17:32:02 +02:00
xfs_alloc.h xfs: support logging EFIs for realtime extents 2024-11-05 13:38:42 -08:00
xfs_alloc_btree.c xfs: refactor cmp_key_with_cur routines to take advantage of cmp_int() 2025-07-24 17:30:13 +02: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:11 -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:15 -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-08-26 11:00:33 +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: remove the expr argument to XFS_TEST_ERROR 2025-09-18 17:32:02 +02:00
xfs_bmap.h xfs: allow block allocator to take an alignment hint 2025-05-07 14:25:31 -07:00
xfs_bmap_btree.c xfs: refactor cmp_key_with_cur routines to take advantage of cmp_int() 2025-07-24 17:30:13 +02:00
xfs_bmap_btree.h xfs: make xfs_iroot_realloc a bmap btree function 2024-12-23 13:06:02 -08:00
xfs_btree.c xfs: remove the expr argument to XFS_TEST_ERROR 2025-09-18 17:32:02 +02:00
xfs_btree.h xfs: refactor xfs_btree_diff_two_ptrs() to take advantage of cmp_int() 2025-07-24 17:30:13 +02:00
xfs_btree_mem.c xfs: create a shadow rmap btree during realtime rmap repair 2024-12-23 13:06:09 -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: online repair of the realtime rmap btree 2024-12-23 13:06:09 -08:00
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: remove the expr argument to XFS_TEST_ERROR 2025-09-18 17:32:02 +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: support logging EFIs for realtime extents 2024-11-05 13:38:42 -08:00
xfs_defer.h xfs: add a realtime flag to the refcount update log redo items 2024-12-23 13:06:11 -08:00
xfs_dir2.c xfs: remove the expr argument to XFS_TEST_ERROR 2025-09-18 17:32:02 +02:00
xfs_dir2.h xfs: mark xfs_dir_isempty static 2025-01-13 14:55:06 +01: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: use metadir for quota inodes 2024-11-05 13:38:45 -08:00
xfs_errortag.h xfs: centralize error tag definitions 2025-09-18 17:32:02 +02:00
xfs_exchmaps.c xfs: remove the expr argument to XFS_TEST_ERROR 2025-09-18 17:32:02 +02:00
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 fs/xfs: replace strncpy with memtostr_pad() 2025-07-24 17:30:14 +02:00
xfs_fs.h xfs: enable fsmap reporting for internal RT devices 2025-03-03 08:17:08 -07:00
xfs_group.c xfs: improve the xg_active_ref check in xfs_group_free 2025-07-24 17:30:14 +02:00
xfs_group.h xfs: support zone gaps 2025-03-03 08:17:09 -07:00
xfs_health.h xfs: report realtime refcount btree corruption errors to the health system 2024-12-23 13:06:14 -08:00
xfs_ialloc.c xfs: set max_agbno to allow sparse alloc of last full inode chunk 2026-01-23 11:21:25 +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: refactor cmp_key_with_cur routines to take advantage of cmp_int() 2025-07-24 17:30:13 +02: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: remove the expr argument to XFS_TEST_ERROR 2025-09-18 17:32:02 +02:00
xfs_inode_buf.h xfs: enforce metadata inode flag 2024-11-05 13:38:31 -08:00
xfs_inode_fork.c xfs: remove the expr argument to XFS_TEST_ERROR 2025-09-18 17:32:02 +02:00
xfs_inode_fork.h xfs: make xfs_iroot_realloc a bmap btree function 2024-12-23 13:06:02 -08:00
xfs_inode_util.c xfs: remove deprecated sysctl knobs 2025-09-05 08:48:23 -07:00
xfs_inode_util.h xfs: hoist inode free function to libxfs 2024-07-02 11:36:59 -07:00
xfs_log_format.h xfs: move the XLOG_REG_ constants out of xfs_log_format.h 2025-09-16 14:08:47 +02:00
xfs_log_recover.h xfs: remove the xfs_trans_header_t typedef 2025-09-16 12:25:05 +02:00
xfs_log_rlimit.c xfs: commit CoW-based atomic writes atomically 2025-05-07 14:25:32 -07:00
xfs_metadir.c xfs: allow inode-based btrees to reserve space in the data device 2024-12-23 13:06:03 -08:00
xfs_metadir.h xfs: read and write metadata inode directory tree 2024-11-05 13:38:31 -08:00
xfs_metafile.c xfs: remove the expr argument to XFS_TEST_ERROR 2025-09-18 17:32:02 +02:00
xfs_metafile.h xfs: make metabtree reservations global 2025-03-03 08:16:43 -07:00
xfs_ondisk.h xfs: fix log CRC mismatches between i386 and other architectures 2025-09-16 12:27:41 +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: use metadir for quota inodes 2024-11-05 13:38:45 -08:00
xfs_refcount.c xfs: remove the expr argument to XFS_TEST_ERROR 2025-09-18 17:32:02 +02:00
xfs_refcount.h xfs: recover CoW leftovers in the realtime volume 2024-12-23 13:06:13 -08:00
xfs_refcount_btree.c xfs: refactor cmp_key_with_cur routines to take advantage of cmp_int() 2025-07-24 17:30:13 +02:00
xfs_refcount_btree.h xfs: standardize the btree maxrecs function parameters 2024-09-01 08:58:20 -07:00
xfs_rmap.c xfs: remove the expr argument to XFS_TEST_ERROR 2025-09-18 17:32:02 +02:00
xfs_rmap.h xfs: add a realtime flag to the rmap update log redo items 2024-12-23 13:06:04 -08:00
xfs_rmap_btree.c xfs: refactor cmp_key_with_cur routines to take advantage of cmp_int() 2025-07-24 17:30:13 +02:00
xfs_rmap_btree.h xfs: standardize the btree maxrecs function parameters 2024-09-01 08:58:20 -07:00
xfs_rtbitmap.c xfs: remove the expr argument to XFS_TEST_ERROR 2025-09-18 17:32:02 +02:00
xfs_rtbitmap.h xfs: online repair of realtime bitmaps for a realtime group 2024-12-23 13:06:08 -08:00
xfs_rtgroup.c xfs: define the zoned on-disk format 2025-03-03 08:16:45 -07:00
xfs_rtgroup.h xfs: prevent gc from picking the same zone twice 2025-10-31 12:06:03 +01:00
xfs_rtrefcount_btree.c xfs: refactor cmp_key_with_cur routines to take advantage of cmp_int() 2025-07-24 17:30:13 +02:00
xfs_rtrefcount_btree.h xfs: create routine to allocate and initialize a realtime refcount btree inode 2024-12-23 13:06:12 -08:00
xfs_rtrmap_btree.c xfs: refactor cmp_key_with_cur routines to take advantage of cmp_int() 2025-07-24 17:30:13 +02:00
xfs_rtrmap_btree.h xfs: add a xfs_rtrmap_highest_rgbno helper 2025-03-03 08:16:45 -07:00
xfs_sb.c xfs: validate that zoned RT devices are zone aligned 2026-01-02 12:57:22 +01:00
xfs_sb.h xfs: make xfs_rtblock_t a segmented address like xfs_fsblock_t 2024-11-05 13:38:44 -08:00
xfs_shared.h xfs: introduce realtime refcount btree ondisk definitions 2024-12-23 13:06:10 -08:00
xfs_symlink_remote.c xfs: return from xfs_symlink_verify early on V4 filesystems 2024-12-12 17:45:13 -08: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: switch to multigrain timestamps 2024-10-10 10:20:52 +02:00
xfs_trans_resv.c xfs: allow sysadmins to specify a maximum atomic write limit at mount time 2025-05-07 14:25:33 -07:00
xfs_trans_resv.h xfs: allow sysadmins to specify a maximum atomic write limit at mount time 2025-05-07 14:25:33 -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: realtime rmap btree transaction reservations 2024-12-23 13:06:04 -08:00
xfs_types.c xfs: make xfs_rtblock_t a segmented address like xfs_fsblock_t 2024-11-05 13:38:44 -08:00
xfs_types.h xfs: add support for zoned space reservations 2025-03-03 08:17:07 -07:00
xfs_zones.c xfs: support zone gaps 2025-03-03 08:17:09 -07:00
xfs_zones.h xfs: improve default maximum number of open zones 2025-09-18 17:32:39 +02:00