summaryrefslogtreecommitdiff
path: root/fs/ocfs2
AgeCommit message (Collapse)Author
3 daysMerge branch 'fs-next' of linux-nextMark Brown
3 daysocfs2: cluster: fix o2hb_dependent_users leak on pin failureJoseph Qi
In o2hb_region_inc_user(), o2hb_dependent_users is incremented unconditionally before calling o2hb_region_pin(). If the pin fails, the counter is never decremented and any partially-pinned regions are never unpinned, since the caller does not call o2hb_region_dec_user() on error. The leaked counter causes subsequent o2hb_region_inc_user() calls to skip pinning entirely (the > 1 check), leaving heartbeat regions unprotected. Fix by rolling back on failure: call o2hb_region_unpin(NULL) to release any partially-pinned regions and decrement o2hb_dependent_users to restore the pre-increment state. Link: https://lore.kernel.org/20260722124933.430554-4-joseph.qi@linux.alibaba.com Fixes: 58a3158a5d17 ("ocfs2/cluster: Pin/unpin o2hb regions") Signed-off-by: Joseph Qi <joseph.qi@linux.alibaba.com> Cc: Mark Fasheh <mark@fasheh.com> Cc: Joel Becker <jlbec@evilplan.org> Cc: Junxiao Bi <junxiao.bi@oracle.com> Cc: Changwei Ge <gechangwei@live.cn> Cc: Jun Piao <piaojun@huawei.com> Cc: Heming Zhao <heming.zhao@suse.com> Cc: <stable@vger.kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
3 daysocfs2: cluster: avoid lock order inversion in o2hb_region_pin() from drop_itemJoseph Qi
o2hb_heartbeat_group_drop_item() is called from configfs rmdir with the parent directory's inode_lock held. It calls o2hb_region_pin() -> o2nm_depend_item() -> configfs_depend_item(), which acquires the configfs root inode_lock. This creates a parent -> root inode_lock nesting that could deadlock against paths taking root -> parent (e.g. subsystem unregistration). Fix this by using configfs_depend_item_unlocked() when o2hb_region_pin() is called from a configfs callback context. This variant skips the root inode_lock when caller and target are in the same subsystem, which is safe because VFS already holds a lock preventing unregistration. Add o2nm_depend_item_unlocked() wrapper and a from_callback parameter to o2hb_region_pin() to select the appropriate variant. Link: https://lore.kernel.org/20260722124933.430554-3-joseph.qi@linux.alibaba.com Fixes: 58a3158a5d17 ("ocfs2/cluster: Pin/unpin o2hb regions") Signed-off-by: Joseph Qi <joseph.qi@linux.alibaba.com> Cc: Changwei Ge <gechangwei@live.cn> Cc: Heming Zhao <heming.zhao@suse.com> Cc: Joel Becker <jlbec@evilplan.org> Cc: Jun Piao <piaojun@huawei.com> Cc: Junxiao Bi <junxiao.bi@oracle.com> Cc: Mark Fasheh <mark@fasheh.com> Cc: <stable@vger.kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
3 daysocfs2: cluster: don't sleep while holding o2hb_live_lock in o2hb_region_pin()Joseph Qi
Patch series "ocfs2: cluster: o2hb_region_pin() fixes", v2. This series fixes three related issues in o2hb_region_pin(), all are from the original implementation in commit: 58a3158a5d17 ("ocfs2/cluster: Pin/unpin o2hb regions"): 1) It is called with o2hb_live_lock (a spinlock) held, but the underlying configfs_depend_item() sleeps (takes inode rwsem and pins the filesystem). This triggers BUG under CONFIG_DEBUG_ATOMIC_SLEEP. 2) When called from the configfs drop_item callback, it creates a lock order inversion: parent inode_lock -> configfs root inode_lock, which can deadlock against subsystem unregistration paths taking root -> parent. 3) If pinning fails partway through o2hb_region_inc_user(), the o2hb_dependent_users counter is leaked and partially-pinned regions are never released, leaving heartbeat regions unprotected on subsequent mounts. Patch 1 reworks o2hb_region_pin() to drop o2hb_live_lock across each sleeping configfs_depend_item() call, using a config_item reference to keep the region alive while unlocked. Patch 2 adds a from_callback parameter to select configfs_depend_item_unlocked() when called from configfs context, avoiding the inode_lock nesting. Patch 3 fixes the error path in o2hb_region_inc_user() to unpin and decrement the counter on failure. This patch (of 3): o2hb_region_pin() is always called with the o2hb_live_lock spinlock held (from o2hb_region_inc_user() and o2hb_heartbeat_group_drop_item()), but it calls o2nm_depend_item() -> configfs_depend_item(), which sleeps: it pins the configfs filesystem and takes the configfs root inode rwsem. Under CONFIG_DEBUG_ATOMIC_SLEEP this triggers: BUG: sleeping function called from invalid context at kernel/locking/rwsem.c in_atomic(): 1, ... name: mount.ocfs2 down_write configfs_depend_item o2hb_region_pin o2hb_region_inc_user o2hb_register_callback dlm_register_domain_handlers ... ocfs2_dlm_init ocfs2_mount_volume ocfs2_fill_super Rework o2hb_region_pin() to pin one region at a time with the lock dropped across the sleeping call: under o2hb_live_lock find the next eligible region and take a config_item reference to keep it alive, drop the lock, call o2nm_depend_item(), then retake the lock and record the pin. The config_item_put() is done with the lock released as well, since o2hb_region_release() also acquires o2hb_live_lock and can sleep. The region list may change while unlocked, so the scan restarts from the top after each pin. Local heartbeat still pins only the matching region; global heartbeat pins all eligible regions. The unpin path is unaffected: configfs_undepend_item() only takes a spinlock and does not sleep. Link: https://lore.kernel.org/20260722124933.430554-1-joseph.qi@linux.alibaba.com Link: https://lore.kernel.org/20260722124933.430554-2-joseph.qi@linux.alibaba.com Fixes: 58a3158a5d17 ("ocfs2/cluster: Pin/unpin o2hb regions") Signed-off-by: Joseph Qi <joseph.qi@linux.alibaba.com> Cc: Changwei Ge <gechangwei@live.cn> Cc: Heming Zhao <heming.zhao@suse.com> Cc: Joel Becker <jlbec@evilplan.org> Cc: Jun Piao <piaojun@huawei.com> Cc: Junxiao Bi <junxiao.bi@oracle.com> Cc: Mark Fasheh <mark@fasheh.com> Cc: <stable@vger.kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
3 daysocfs2: always run deallocs on copy-on-write completionDmitry Antipov
Local fuzzing of 6.12.94 has found the following memory leak caused by doing 'copy_file_range()' within the same filesystem: unreferenced object 0xffff88812192c980 (size 32): comm "syz.0.49", pid 12095, jiffies 4294964143 hex dump (first 32 bytes): 00 00 00 00 00 00 00 00 08 00 00 00 00 00 00 00 ................ c0 c5 92 21 81 88 ff ff 00 02 00 00 00 06 00 00 ...!............ backtrace (crc 7068d63f): kmemleak_alloc_recursive include/linux/kmemleak.h:42 [inline] slab_post_alloc_hook mm/slub.c:4152 [inline] slab_alloc_node mm/slub.c:4197 [inline] __kmalloc_cache_noprof+0x168/0x2c0 mm/slub.c:4358 kmalloc_noprof include/linux/slab.h:878 [inline] ocfs2_find_per_slot_free_list fs/ocfs2/alloc.c:6618 [inline] ocfs2_cache_block_dealloc+0x155/0x4b0 fs/ocfs2/alloc.c:6786 ocfs2_cache_extent_block_free fs/ocfs2/alloc.c:6819 [inline] ocfs2_unlink_path+0x286/0x450 fs/ocfs2/alloc.c:2613 ocfs2_rotate_subtree_left fs/ocfs2/alloc.c:2779 [inline] __ocfs2_rotate_tree_left+0x1f6f/0x2da0 fs/ocfs2/alloc.c:2985 ocfs2_rotate_tree_left+0x283/0xe00 fs/ocfs2/alloc.c:3237 ocfs2_try_to_merge_extent+0xf56/0x1a20 fs/ocfs2/alloc.c:3825 ocfs2_split_extent+0x15f4/0x2940 fs/ocfs2/alloc.c:5138 ocfs2_clear_ext_refcount+0x2f6/0x550 fs/ocfs2/refcounttree.c:3098 ocfs2_replace_clusters fs/ocfs2/refcounttree.c:3131 [inline] ocfs2_make_clusters_writable fs/ocfs2/refcounttree.c:3255 [inline] ocfs2_replace_cow+0x991/0x1660 fs/ocfs2/refcounttree.c:3349 ocfs2_refcount_cow_hunk fs/ocfs2/refcounttree.c:3427 [inline] ocfs2_refcount_cow+0x5e1/0x9f0 fs/ocfs2/refcounttree.c:3470 ocfs2_prepare_inode_for_write fs/ocfs2/file.c:2340 [inline] ocfs2_file_write_iter+0xbda/0x1880 fs/ocfs2/file.c:2451 iter_file_splice_write+0x890/0xf60 fs/splice.c:743 do_splice_from fs/splice.c:944 [inline] direct_splice_actor+0x232/0x480 fs/splice.c:1167 splice_direct_to_actor+0x4b4/0xb60 fs/splice.c:1111 do_splice_direct_actor fs/splice.c:1210 [inline] do_splice_direct+0x10f/0x1c0 fs/splice.c:1236 do_sendfile+0x430/0xbf0 fs/read_write.c:1388 unreferenced object 0xffff88812192c5c0 (size 32): comm "syz.0.49", pid 12095, jiffies 4294964143 hex dump (first 32 bytes): 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 29 70 00 00 00 00 00 00 19 00 00 00 00 00 00 00 )p.............. backtrace (crc afec850f): kmemleak_alloc_recursive include/linux/kmemleak.h:42 [inline] slab_post_alloc_hook mm/slub.c:4152 [inline] slab_alloc_node mm/slub.c:4197 [inline] __kmalloc_cache_noprof+0x168/0x2c0 mm/slub.c:4358 kmalloc_noprof include/linux/slab.h:878 [inline] kzalloc_noprof include/linux/slab.h:1014 [inline] ocfs2_cache_block_dealloc+0x25c/0x4b0 fs/ocfs2/alloc.c:6793 ocfs2_cache_extent_block_free fs/ocfs2/alloc.c:6819 [inline] ocfs2_unlink_path+0x286/0x450 fs/ocfs2/alloc.c:2613 ocfs2_rotate_subtree_left fs/ocfs2/alloc.c:2779 [inline] __ocfs2_rotate_tree_left+0x1f6f/0x2da0 fs/ocfs2/alloc.c:2985 ocfs2_rotate_tree_left+0x283/0xe00 fs/ocfs2/alloc.c:3237 ocfs2_try_to_merge_extent+0xf56/0x1a20 fs/ocfs2/alloc.c:3825 ocfs2_split_extent+0x15f4/0x2940 fs/ocfs2/alloc.c:5138 ocfs2_clear_ext_refcount+0x2f6/0x550 fs/ocfs2/refcounttree.c:3098 ocfs2_replace_clusters fs/ocfs2/refcounttree.c:3131 [inline] ocfs2_make_clusters_writable fs/ocfs2/refcounttree.c:3255 [inline] ocfs2_replace_cow+0x991/0x1660 fs/ocfs2/refcounttree.c:3349 ocfs2_refcount_cow_hunk fs/ocfs2/refcounttree.c:3427 [inline] ocfs2_refcount_cow+0x5e1/0x9f0 fs/ocfs2/refcounttree.c:3470 ocfs2_prepare_inode_for_write fs/ocfs2/file.c:2340 [inline] ocfs2_file_write_iter+0xbda/0x1880 fs/ocfs2/file.c:2451 iter_file_splice_write+0x890/0xf60 fs/splice.c:743 do_splice_from fs/splice.c:944 [inline] direct_splice_actor+0x232/0x480 fs/splice.c:1167 splice_direct_to_actor+0x4b4/0xb60 fs/splice.c:1111 do_splice_direct_actor fs/splice.c:1210 [inline] do_splice_direct+0x10f/0x1c0 fs/splice.c:1236 do_sendfile+0x430/0xbf0 fs/read_write.c:1388 This happens when 'ocfs2_cache_block_dealloc()' called from 'ocfs2_cache_extent_block_free()' uses the suballocator to schedule extent removal, so 'ocfs2_run_deallocs()' should be run unconditionally to complete the removal with 'ocfs2_free_cached_blocks()'. An extra semi-automated static analysis [1] suspects that the same scenario looks possible in 'ocfs2_attach_refcount_tree()' and 'ocfs2_reflink_remap_blocks()' as well, but, since 'ocfs2_run_deallocs()' is a safe no-op for an empty dealloc context, 'ocfs2_create_reflink_node()' and 'ocfs2_reflink_xattrs()' may be adjusted in the same way too, thus keeping the code pattern consistent. Link: https://lore.kernel.org/20260721102840.387663-1-dmantipov@yandex.ru Link: https://lore.kernel.org/ocfs2-devel/f1d7e266-4b44-41b9-98c0-5b3868a8d9c3@yandex.ru [1] Fixes: 6f70fa519976 ("ocfs2: Add CoW support.") Signed-off-by: Dmitry Antipov <dmantipov@yandex.ru> Suggested-by: Joseph Qi <joseph.qi@linux.alibaba.com> Reviewed-by: Joseph Qi <joseph.qi@linux.alibaba.com> Cc: Mark Fasheh <mark@fasheh.com> Cc: Joel Becker <jlbec@evilplan.org> Cc: Junxiao Bi <junxiao.bi@oracle.com> Cc: Changwei Ge <gechangwei@live.cn> Cc: Jun Piao <piaojun@huawei.com> Cc: Heming Zhao <heming.zhao@suse.com> Cc: <stable@vger.kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
3 daysocfs2: validate directory-index entry counts when reading metadataDoruk Tan Ozturk
ocfs2_validate_dx_leaf() and ocfs2_validate_dx_root() check the ECC and signature of an indexed-directory block before it reaches higher-level callers, but neither validator bounds the ocfs2_dx_entry_list counts against the capacity of the block that holds them. ocfs2_dx_dir_search() then walks for (i = 0; i < le16_to_cpu(entry_list->de_num_used); i++) dx_entry = &entry_list->de_entries[i]; over de_num_used entries with no bounds check. entry_list is either dx_leaf->dl_list (from ocfs2_read_dx_leaf) or, for an inline root, dx_root->dr_entries. A crafted on-disk image can set de_num_used (and de_count, which is the __counted_by_le() bound of de_entries) to 0xffff and make the walk read far past the end of the 4KB metadata block, giving a slab out-of-bounds read reachable from any path lookup, stat() or open() on an indexed directory once the image is mounted. Commit 775c17386a6f ("ocfs2: validate dx_root extent list fields during block read") already bounds dr_list for the non-inline dx_root, but left the inline dr_entries path and the dx_leaf dl_list unchecked. Add the same read-time validation for both entry lists: de_count must equal the capacity of the block (ocfs2_dx_entries_per_leaf()/per_root()) and de_num_used must not exceed de_count, rejecting corrupted metadata with -EFSCORRUPTED before ocfs2_dx_dir_search() can walk an out-of-range entry array. de_count is always written as exactly the block capacity when a leaf or inline root is formatted, so the equality check does not reject any valid image. Found by 0sec automated security-research tooling (https://0sec.ai). Link: https://lore.kernel.org/20260713205625.92391-1-doruk@0sec.ai Fixes: 9b7895efac90 ("ocfs2: Add a name indexed b-tree to directory inodes") Fixes: 4ed8a6bb083b ("ocfs2: Store dir index records inline") Assisted-by: 0sec:claude-opus-4-8 Signed-off-by: Doruk Tan Ozturk <doruk@0sec.ai> Reviewed-by: Joseph Qi <joseph.qi@linux.alibaba.com> Cc: Joel Becker <jlbec@evilplan.org> Cc: Kees Cook <kees@kernel.org> Cc: Mark Fasheh <mark@fasheh.com> Cc: Junxiao Bi <junxiao.bi@oracle.com> Cc: Changwei Ge <gechangwei@live.cn> Cc: Jun Piao <piaojun@huawei.com> Cc: Heming Zhao <heming.zhao@suse.com> Cc: <stable@vger.kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
3 daysocfs2: cluster: use an on-stack bio for the heartbeat writeJoseph Qi
The disk heartbeat write always covers this node's own single slot, i.e. one heartbeat block that lives within a single page. It is submitted by o2hb_issue_node_write() and waited on by the caller before the ctxt goes out of scope, so its lifetime is well bounded. Turn it into an on-stack bio embedded in struct o2hb_bio_wait_ctxt rather than allocating one from the mempool. This removes any allocation from the fence-critical write path entirely: a delayed or blocked heartbeat write is what leads to the local node being fenced, so it should not depend on the state of a shared bio pool. Because the bio is embedded rather than allocated, add a dedicated o2hb_write_bio_end_io() that does not call bio_put(), and tear the bio down with bio_uninit() once the caller has waited on the I/O. The read path still allocates via o2hb_setup_one_bio() with GFP_NOFS, since it issues a variable number of bios in a loop. Link: https://lore.kernel.org/20260710071756.3586797-2-joseph.qi@linux.alibaba.com Signed-off-by: Joseph Qi <joseph.qi@linux.alibaba.com> Cc: Mark Fasheh <mark@fasheh.com> Cc: Joel Becker <jlbec@evilplan.org> Cc: Junxiao Bi <junxiao.bi@oracle.com> Cc: Changwei Ge <gechangwei@live.cn> Cc: Jun Piao <piaojun@huawei.com> Cc: Heming Zhao <heming.zhao@suse.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
3 daysocfs2: cluster: use GFP_NOFS for heartbeat bio allocationJoseph Qi
o2hb_setup_one_bio() allocates the heartbeat bio with GFP_ATOMIC. The disk heartbeat runs in the o2hb kernel thread (o2hb_do_disk_heartbeat), which is process context and can sleep, so there is no atomicity requirement here. GFP_ATOMIC lacks __GFP_DIRECT_RECLAIM, so the allocation is not served from the fs_bio_set mempool reserve and can return NULL under memory pressure. A failed heartbeat allocation aborts the heartbeat and can lead to the local node being fenced, which is exactly what the old comment worried about. Use GFP_NOFS instead. It keeps __GFP_DIRECT_RECLAIM so the allocation is backed by the fs_bio_set mempool and cannot fail, while avoiding recursion back into the filesystem during heartbeat I/O. As the allocation can no longer fail, drop the dead ERR_PTR(-ENOMEM) path in o2hb_setup_one_bio() and the now-redundant IS_ERR() handling in its callers. Link: https://lore.kernel.org/20260710071756.3586797-1-joseph.qi@linux.alibaba.com Signed-off-by: Joseph Qi <joseph.qi@linux.alibaba.com> Cc: Mark Fasheh <mark@fasheh.com> Cc: Joel Becker <jlbec@evilplan.org> Cc: Junxiao Bi <junxiao.bi@oracle.com> Cc: Changwei Ge <gechangwei@live.cn> Cc: Jun Piao <piaojun@huawei.com> Cc: Heming Zhao <heming.zhao@suse.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
3 daysocfs2: validate rl_used against rl_count in refcount block validatorIbrahim Hashimov
ocfs2_find_refcount_rec_in_rl() walks the on-disk refcount record array with: for (; i < le16_to_cpu(rb->rf_records.rl_used); i++) { rec = &rb->rf_records.rl_recs[i]; ... rl_recs[] lives in a single metadata block (4096 bytes on the common configuration), so its real capacity is fixed by ocfs2_refcount_recs_per_rb(sb) (247 records for a 4K block with the 16-byte ocfs2_refcount_rec). rl_used and rl_count are both read directly off disk by ocfs2_validate_refcount_block() and are never checked against that capacity, nor against each other, before any refcount/reflink/CoW operation walks the array. A crafted (or corrupted) refcount block with rl_used == 0xffff makes the loop above walk far past the end of the block, dereferencing rl_recs[i] for i up to 65534. The resulting index is then handed to the sibling ocfs2_insert_refcount_rec(), whose insert-shift does: if (index < le16_to_cpu(rf_list->rl_used)) memmove(&rf_list->rl_recs[index + 1], &rf_list->rl_recs[index], (le16_to_cpu(rf_list->rl_used) - index) * sizeof(struct ocfs2_refcount_rec)); i.e. a memmove() of up to (0xffff - index) * 16 bytes (~1 MiB) from an offset already past the block. This is reachable from an ordinary reflink (FICLONE) against a crafted/corrupted ocfs2 image: attaching an extent whose cpos sorts past every real record in the leaf forces the lookup to run off the end instead of returning early on a match. The attacker model is local: CAP_SYS_ADMIN mounting a crafted or corrupted ocfs2 image, or a raw write to the block device backing an already-mounted ocfs2 filesystem. ocfs2_validate_refcount_block() already validates the block's ECC, signature, rf_blkno and rf_fs_generation, but never rl_count/rl_used against the block's actual on-disk capacity. This is the same class of gap that ocfs2_validate_extent_block() (fs/ocfs2/alloc.c) already closes for the sibling extent-list header, which checks both the record capacity and the "used" bound before any code walks h_list.l_recs[]: if (le16_to_cpu(eb->h_list.l_count) != ocfs2_extent_recs_per_eb(sb)) { rc = ocfs2_error(...); goto bail; } if (le16_to_cpu(eb->h_list.l_next_free_rec) > le16_to_cpu(eb->h_list.l_count)) { rc = ocfs2_error(...); goto bail; } Add the equivalent pair of checks to ocfs2_validate_refcount_block(): reject a refcount block whose rl_count does not match the fixed per-block capacity returned by ocfs2_refcount_recs_per_rb(), and reject rl_used > rl_count. Both checks are skipped when OCFS2_REFCOUNT_TREE_FL is set, because in that case the same union bytes hold an ocfs2_extent_list (rf_list), not the refcount record list (rf_records) -- that layout is already validated separately by ocfs2_validate_extent_block() when the referenced extent block is read. This mirrors the existing "!(rb->rf_flags & OCFS2_REFCOUNT_TREE_FL)" guard used elsewhere in this file (e.g. ocfs2_get_refcount_rec()) to decide whether rf_records or rf_list is the live member of the union. With this in place, a forged rl_used/rl_count is caught at block validation time (ocfs2_error()), consistent with every other corruption check in this function, instead of driving an out-of-bounds read in ocfs2_find_refcount_rec_in_rl() and a subsequent out-of-bounds memmove() in ocfs2_insert_refcount_rec(). Verified against a crafted image on a v6.19 KASAN (KASAN_GENERIC) build: replaying the same reflink (FICLONE) reliably hit a KASAN report in __ocfs2_increase_refcount()/ocfs2_insert_refcount_rec() before this patch, and triggers no report once ocfs2_validate_refcount_block() rejects the forged rl_used/rl_count. Link: https://lore.kernel.org/20260709132609.44233-1-security@auditcode.ai Fixes: f2c870e3b12e ("ocfs2: Add ocfs2_read_refcount_block.") Signed-off-by: Ibrahim Hashimov <security@auditcode.ai> Reviewed-by: Joseph Qi <joseph.qi@linux.alibaba.com> Cc: Mark Fasheh <mark@fasheh.com> Cc: Joel Becker <jlbec@evilplan.org> Cc: Junxiao Bi <junxiao.bi@oracle.com> Cc: Changwei Ge <gechangwei@live.cn> Cc: Jun Piao <piaojun@huawei.com> Cc: Heming Zhao <heming.zhao@suse.com> Assisted-by: AuditCode-AI:2026.07 Cc: <stable@vger.kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
3 daysocfs2: do not use make_bad_inode() in ocfs2_read_inode_block_full()Dmitry Antipov
This reverts commit 58b6fcd2ab34 ("ocfs2: mark inode bad upon validation failure during read"). Since 'make_bad_inode()' resets inode type to S_IFREG, doing this for directory inode during active VFS lookup is likely to confuse the latter, including VFS_BUG_ON_INODE() triggered in this case. Link: https://lore.kernel.org/20260709060101.207262-1-dmantipov@yandex.ru Fixes: 58b6fcd2ab34 ("ocfs2: mark inode bad upon validation failure during read") Signed-off-by: Dmitry Antipov <dmantipov@yandex.ru> Suggested-by: Al Viro <viro@zeniv.linux.org.uk> Reported-by: syzbot+d222f4b7129379c3d5bc@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=d222f4b7129379c3d5bc Reviewed-by: Joseph Qi <joseph.qi@linux.alibaba.com> Cc: Mark Fasheh <mark@fasheh.com> Cc: Joel Becker <jlbec@evilplan.org> Cc: Junxiao Bi <junxiao.bi@oracle.com> Cc: Changwei Ge <gechangwei@live.cn> Cc: Jun Piao <piaojun@huawei.com> Cc: Heming Zhao <heming.zhao@suse.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
3 daysocfs2: validate external xattr entries when reading metadataCen Zhang
ocfs2_validate_xattr_block() checks the xattr block header before the block reaches higher-level xattr users, but it does not verify that a non-indexed block's xh_count and entry offsets fit inside the block. Indexed buckets likewise reach list/get consumers after ECC without an entry-bounds check. Use the flat xattr entry validator for non-indexed external xattr blocks, and use a bucket-specific validator for indexed buckets at metadata read time. The bucket validator keeps the entry array bounded by the first bucket block while checking name/value offsets against the bucket block they target. Reject corrupted external xattr metadata before listxattr() or getxattr() can walk out-of-range entry arrays or name/value offsets. Validation reproduced this kernel report: BUG: KASAN: use-after-free in ocfs2_xattr_list_entries+0xd7/0x190 Read of size 1 at addr ffff88810a654007 by task ocfs2_xattr_lis/630 Call Trace: dump_stack_lvl+0x66/0xa0 print_report+0xce/0x630 kasan_report+0xe0/0x110 ocfs2_xattr_list_entries+0xd7/0x190 ocfs2_listxattr+0x3f6/0x610 listxattr+0x90/0xe0 path_listxattrat+0xed/0x220 do_syscall_64+0x115/0x6a0 entry_SYSCALL_64_after_hwframe+0x77/0x7f Link: https://lore.kernel.org/20260705025311.3429854-3-zzzccc427@gmail.com Fixes: cf1d6c763fbc ("ocfs2: Add extended attribute support") Fixes: 0c044f0b24b9 ("ocfs2: Add xattr bucket iteration for large numbers of EAs") Signed-off-by: Cen Zhang <zzzccc427@gmail.com> Assisted-by: Codex:gpt-5.5 Reviewed-by: Joseph Qi <joseph.qi@linux.alibaba.com> Cc: Mark Fasheh <mark@fasheh.com> Cc: Joel Becker <jlbec@evilplan.org> Cc: Junxiao Bi <junxiao.bi@oracle.com> Cc: Changwei Ge <gechangwei@live.cn> Cc: Jun Piao <piaojun@huawei.com> Cc: Heming Zhao <heming.zhao@suse.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
3 daysocfs2: validate inline xattrs during inode block validationCen Zhang
Patch series "ocfs2: validate xattr entry bounds", v7. This series validates OCFS2 xattr entry name/value bounds when xattr metadata is read and validated, before getxattr() or listxattr() can walk out-of-range entry arrays or offsets from corrupted metadata. This patch (of 2): ocfs2_validate_inode_block() verifies a dinode before OCFS2 users walk metadata from it, but inline xattr metadata is still checked only in operation-specific consumers. The existing ibody lookup helper validates inline header placement and entry count, but inode block validation does not reject entry name/value bounds. Add a flat xattr entry validator and call it from inode block validation for inline xattrs. Keep the operation paths on their existing header/count lookup checks; the full entry bounds check now runs when the inode block is validated at read time. Reject corrupted inline xattr metadata before ocfs2_xattr_ibody_get() or listxattr() can walk past the inline storage. Validation reproduced this kernel report: BUG: KASAN: use-after-free in ocfs2_xattr_find_entry+0x5a/0x170 Read of size 2 at addr ffff8881242a2000 by task python3/529 Call Trace: dump_stack_lvl+0x66/0xa0 print_report+0xce/0x630 kasan_report+0xe0/0x110 ocfs2_xattr_find_entry+0x5a/0x170 ocfs2_xattr_get_nolock+0x20a/0x820 ocfs2_xattr_get+0x10c/0x1e0 __vfs_getxattr+0xe2/0x130 vfs_getxattr+0x185/0x1b0 Link: https://lore.kernel.org/20260705025311.3429854-1-zzzccc427@gmail.com Link: https://lore.kernel.org/20260705025311.3429854-2-zzzccc427@gmail.com Fixes: cf1d6c763fbc ("ocfs2: Add extended attribute support") Signed-off-by: Cen Zhang <zzzccc427@gmail.com> Assisted-by: Codex:gpt-5.5 Reviewed-by: Joseph Qi <joseph.qi@linux.alibaba.com> Cc: Changwei Ge <gechangwei@live.cn> Cc: Heming Zhao <heming.zhao@suse.com> Cc: Joel Becker <jlbec@evilplan.org> Cc: Jun Piao <piaojun@huawei.com> Cc: Junxiao Bi <junxiao.bi@oracle.com> Cc: Mark Fasheh <mark@fasheh.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
3 daysocfs2: fix hung task in orphan recoveryJiaming Zhang
A crafted OCFS2 image with corrupted orphan-directory extent metadata can make umount hang. During unmount, ocfs2_recovery_disable() waits for the ocfs2_complete_recovery work item to finish. The worker scans the orphan directory through ocfs2_queue_orphans() and ocfs2_dir_foreach(). If ocfs2_read_dir_block() fails on a corrupted directory block, ocfs2_dir_foreach_blk_el() skips the block and continues walking. On a badly corrupted directory this can keep orphan recovery busy for a long time, leaving umount blocked while flushing osb->ocfs2_wq. Return the read error immediately for full directory scans and propagate the error from ocfs2_dir_foreach(). When ocfs2_empty_dir() receives such an error, report the directory as non-empty so unlink/rmdir does not proceed on an unreadable directory. Link: https://lore.kernel.org/20260702090507.446517-1-r772577952@gmail.com Closes: https://lore.kernel.org/lkml/CANypQFbWH76Y6LWHEwAvTP7aQL04uMJ=dDyL6YDmxa3fv3Tyjg@mail.gmail.com/ Assisted-by: Codex:gpt-5.5-xhigh Signed-off-by: Jiaming Zhang <r772577952@gmail.com> Reviewed-by: Joseph Qi <joseph.qi@linux.alibaba.com> Cc: Mark Fasheh <mark@fasheh.com> Cc: Joel Becker <jlbec@evilplan.org> Cc: Junxiao Bi <junxiao.bi@oracle.com> Cc: Changwei Ge <gechangwei@live.cn> Cc: Jun Piao <piaojun@huawei.com> Cc: Heming Zhao <heming.zhao@suse.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
3 daysocfs2: validate lengths in dlm_mig_lockres_handlerBryam Vargas
A node receiving a DLM_MIG_LOCKRES message trusts several fields of the peer-supplied dlm_migratable_lockres without validation. num_locks and lockname_len are bounded only on the sending side, and the message is never checked to actually carry num_locks migratable_lock entries. As a result dlm_process_recovery_data() walks mres->ml[0..num_locks) past the kmalloc(data_len) copy of the message (an out-of-bounds read that ends in a BUG_ON panic), and dlm_init_lockres() copies lockname_len bytes into the fixed 32-byte o2dlm_lockname slab object (a heap out-of-bounds write). Both are reachable by any node in the domain. Validate these fields right after dlm_grab(), before anything uses them -- including the not-joined error path, which already prints mres->lockname with the unbounded lockname_len as a %.*s precision. Reject the message unless lockname_len <= DLM_LOCKID_NAME_MAX, num_locks <= DLM_MAX_MIGRATABLE_LOCKS (the bound the sender already asserts), and the payload is large enough to hold the claimed locks. Conforming recovery and migration messages are unaffected. Link: https://lore.kernel.org/20260629-b4-disp-94fb6521-v1-2-6953bcc0421f@proton.me Fixes: 6714d8e86bf4 ("[PATCH] OCFS2: The Second Oracle Cluster Filesystem") Signed-off-by: Bryam Vargas <hexlabsecurity@proton.me> Reviewed-by: Joseph Qi <joseph.qi@linux.alibaba.com> Cc: Mark Fasheh <mark@fasheh.com> Cc: Joel Becker <jlbec@evilplan.org> Cc: Junxiao Bi <junxiao.bi@oracle.com> Cc: Changwei Ge <gechangwei@live.cn> Cc: Jun Piao <piaojun@huawei.com> Cc: Heming Zhao <heming.zhao@suse.com> Cc: <stable@vger.kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
3 daysocfs2: bound namelen in dlm_migrate_request_handlerBryam Vargas
Patch series "ocfs2/dlm: bound peer-controlled lengths in the o2dlm". The o2dlm receive handlers trust u8 length and count fields from the wire without bounding them, so a node in a DLM domain can corrupt or panic any other node with a malformed message. Three defects: - dlm_migrate_request_handler() passes migrate->namelen unchecked to dlm_init_mle(), which memcpy()s it into the 32-byte mname[] of an o2dlm_mle slab object: a heap out-of-bounds write of up to ~215 attacker-controlled bytes. - dlm_mig_lockres_handler() passes mres->lockname_len unchecked to dlm_init_lockres(), which memcpy()s it into the 32-byte o2dlm_lockname slab object: a heap out-of-bounds write of up to ~223 bytes. - the same handler trusts mres->num_locks without checking that the message is large enough to hold that many entries, so dlm_process_recovery_data() walks mres->ml[] past the kmalloc(data_len) copy and trips a BUG_ON (an out-of-bounds read ending in a panic). The other o2dlm receive handlers already reject an oversized name; the migration and recovery handlers have omitted it since the DLM was added (see the Fixes tags). Patch 1 bounds namelen; patch 2 validates lockname_len, num_locks, and the payload size. Conforming recovery and migration traffic is unaffected. o2net authenticates peers only by the DLM domain key, so any node that has joined the domain -- including a compromised or malicious member -- can send these messages. There is no local trigger; the attacker must already be a member of the cluster. Each sink was confirmed under KASAN with an out-of-tree module mirroring it exactly -- a kmem_cache/kmalloc of the real destination size, then the same unclamped memcpy/loop: slab-out-of-bounds Write for the two writes, Read for the recovery walk, and a panic. A userspace AddressSanitizer build faults identically under -m32 and -m64. Scrubbed logs are available on request. I reported this privately to security@kernel.org and the ocfs2 maintainers on 2026-06-20; with no response after the standard embargo period I am posting the fix publicly. I have no embargo requirement. This patch (of 2): A node receiving a DLM_MIGRATE_REQUEST message trusts the peer-supplied name length (migrate->namelen) without bounding it. dlm_init_mle() then copies that many bytes into the fixed DLM_LOCKID_NAME_MAX-byte mname[] array of an o2dlm_mle slab object, so a malformed message from a cluster peer overflows the slab object by up to ~215 bytes: a heap out-of-bounds write of attacker-controlled data, reachable by any node in the domain. Reject an oversized name, the way dlm_master_request_handler() and the other o2dlm receive handlers already do; the migration handler omits the check entirely. Conforming messages are unaffected. Link: https://lore.kernel.org/20260629-b4-disp-94fb6521-v1-0-6953bcc0421f@proton.me Link: https://lore.kernel.org/20260629-b4-disp-94fb6521-v1-1-6953bcc0421f@proton.me Fixes: 6714d8e86bf4 ("[PATCH] OCFS2: The Second Oracle Cluster Filesystem") Signed-off-by: Bryam Vargas <hexlabsecurity@proton.me> Reviewed-by: Joseph Qi <joseph.qi@linux.alibaba.com> Cc: Changwei Ge <gechangwei@live.cn> Cc: Heming Zhao <heming.zhao@suse.com> Cc: Joel Becker <jlbec@evilplan.org> Cc: Jun Piao <piaojun@huawei.com> Cc: Junxiao Bi <junxiao.bi@oracle.com> Cc: Mark Fasheh <mark@fasheh.com> Cc: <stable@vger.kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
3 daysocfs2: use inode_lock_nested() for orphan dir lockingDeepanshu Kartikey
PREEMPT_RT's rtmutex PI chain walker warns about a lock dependency cycle when inode_lock(orphan_dir_inode) is called while holding inode_lock(file_inode): ocfs2_file_write_iter() inode_lock(file_inode) [class 0] ocfs2_dio_end_io_write() ocfs2_del_inode_from_orphan() inode_lock(orphan_dir_inode) [class 0] <- warning! However this is a false positive. write_iter() is never called on a directory, and orphan_dir is always a directory, so these two locks can never actually conflict in practice. Fix by using inode_lock_nested(orphan_dir_inode, I_MUTEX_NONDIR2) in all three places where orphan_dir_inode is locked in namei.c, placing it in a separate lock class so the rtmutex PI chain walker understands these locks have distinct roles and does not warn about their ordering. Link: https://lore.kernel.org/20260620231223.46588-1-kartikey406@gmail.com Signed-off-by: Deepanshu Kartikey <kartikey406@gmail.com> Suggested-by: Matthew Wilcox <willy@infradead.org> Reported-by: syzbot+ce129763ce7d7e914739@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=ce129763ce7d7e914739 Reviewed-by: Joseph Qi <joseph.qi@linux.alibaba.com> Cc: Mark Fasheh <mark@fasheh.com> Cc: Joel Becker <jlbec@evilplan.org> Cc: Junxiao Bi <junxiao.bi@oracle.com> Cc: Changwei Ge <gechangwei@live.cn> Cc: Jun Piao <piaojun@huawei.com> Cc: Heming Zhao <heming.zhao@suse.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
3 daysocfs2/cluster: keep heartbeat local node stableCen Zhang
o2nm_node_local_store() handles local=0 by stopping o2net and setting cl_local_node to O2NM_INVALID_NODE_NUM, but it leaves cl_has_local set. That stale state makes o2nm_this_node() return 255, blocks a later local=1 attempt with -EBUSY, and can feed 255 to heartbeat users that call o2nm_this_node() dynamically. Clearing cl_has_local is required when the local node is reset. But heartbeat threads can still be running at that point. They pin the local node config item at startup, yet o2hb_do_disk_heartbeat() and thread teardown re-read o2nm_this_node() for the local slot and for o2nm_undepend_this_node(). Once local=0 has cleared the live local-node state, those dynamic reads return O2NM_MAX_NODES, which is also the invalid node number 255. Store the local node number in the heartbeat region when the region starts. Use that stable node for heartbeat slot writes/checks, negotiation messages, and the final configfs undepend. Stop the heartbeat loop when the current local node no longer matches the stored node, and clear cl_has_local together with cl_local_node in the local=0 path so nodemanager state matches node removal. Validation reproduced this kernel report: KASAN slab-out-of-bounds in o2hb_do_disk_heartbeat+0x372/0xb30 RIP: 0010:memset+0xf/0x20 Read of size 8 Call trace: dump_stack_lvl+0x66/0xa0 print_report+0xd0/0x630 o2hb_do_disk_heartbeat+0x372/0xb30 (fs/ocfs2/cluster/heartbeat.c:1079) srso_alias_return_thunk+0x5/0xfbef5 __virt_addr_valid+0x188/0x2f0 kasan_report+0xe4/0x120 o2hb_do_disk_heartbeat+0x5/0xb30 (fs/ocfs2/cluster/heartbeat.c:1079) o2hb_thread+0x14e/0x770 kthread_affine_node+0x139/0x180 lockdep_hardirqs_on_prepare+0xda/0x190 trace_hardirqs_on+0x18/0x130 kthread+0x19d/0x1e0 ret_from_fork+0x37a/0x4d0 __switch_to+0x2d5/0x6f0 ret_from_fork_asm+0x1a/0x30 Link: https://lore.kernel.org/20260616074931.3774929-1-zzzccc427@gmail.com Fixes: a7f6a5fb4bde ("[PATCH] OCFS2: The Second Oracle Cluster Filesystem") Assisted-by: Codex:gpt-5.5 Signed-off-by: Cen Zhang <zzzccc427@gmail.com> Suggested-by: Joseph Qi <joseph.qi@linux.alibaba.com> Reviewed-by: Joseph Qi <joseph.qi@linux.alibaba.com> Cc: Mark Fasheh <mark@fasheh.com> Cc: Joel Becker <jlbec@evilplan.org> Cc: Junxiao Bi <junxiao.bi@oracle.com> Cc: Changwei Ge <gechangwei@live.cn> Cc: Jun Piao <piaojun@huawei.com> Cc: Heming Zhao <heming.zhao@suse.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
5 daysMerge branch 'vfs-7.3.super' into vfs.allChristian Brauner
5 daysocfs2: fix boundary check in ocfs2_check_dir_entry() to use buffer offsetJoseph Qi
Commit 390ac56cf0f6 ("ocfs2: add boundary check to ocfs2_check_dir_entry()") added an out-of-bounds guard using the caller-supplied 'offset' argument: if (offset > size - OCFS2_DIR_REC_LEN(1)) return 0; However, 'offset' and 'size' are not measured against the same base for all callers. In the block-based lookup path, ocfs2_find_entry_el() passes 'offset' as an absolute offset into the whole directory: i = ocfs2_search_dirblock(bh, dir, name, namelen, block << sb->s_blocksize_bits, bh->b_data, sb->s_blocksize, res_dir); while 'size' is a single block size (sb->s_blocksize). For any directory entry located in the second or later block, 'offset' is >= sb->s_blocksize, so the guard rejects every such entry even though it is perfectly valid and lies entirely within its block buffer. This makes mounting fail for filesystems whose system directory spans more than one block, e.g. a volume formatted with a small block size: mkfs.ocfs2 -b 512 -C 4096 -N 2 -T datafiles --fs-features=usrquota,grpquota ocfs2_check_dir_entry:314 ERROR: directory entry (#18: offset=512) too close to end or out-of-bounds ocfs2_init_local_system_inodes:496 ERROR: status=-22, sysfile=12, slot=0 ocfs2_mount_volume:1757 ERROR: status = -22 The dirent's position within the buffer being validated is ((char *)de - buf), which is what the rest of the function already uses (via next_offset) and what must be bounds-checked against 'size'. Compute that buffer-relative offset and use it for the guard. The subtraction is reordered to size - buf_offset < OCFS2_DIR_REC_LEN(1) to avoid an unsigned underflow when size is smaller than the minimal record length. Link: https://lore.kernel.org/20260710040512.3310736-1-joseph.qi@linux.alibaba.com Fixes: 390ac56cf0f6 ("ocfs2: add boundary check to ocfs2_check_dir_entry()") Signed-off-by: Joseph Qi <joseph.qi@linux.alibaba.com> Reviewed-by: Dmitry Antipov <dmantipov@yandex.ru> Tested-by: Dmitry Antipov <dmantipov@yandex.ru> Cc: Mark Fasheh <mark@fasheh.com> Cc: Joel Becker <jlbec@evilplan.org> Cc: Junxiao Bi <junxiao.bi@oracle.com> Cc: Changwei Ge <gechangwei@live.cn> Cc: Jun Piao <piaojun@huawei.com> Cc: Heming Zhao <heming.zhao@suse.com> Cc: <stable@vger.kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
2026-07-02Remove excl arg to ->create inode_operationNeilBrown
The only time that 'false' is passed as the 'excl' arg to the ->create inode_operation is in lookup_open() when ->atomic_open is not provided by the parent directory. *all* directory inode_operations which do not have ->atomic_open completely ignore the 'excl' arg. Therefore we don't need the 'excl' arg. Those few ->create operations which pay attention to the arg are only ever called with a value of 'true'. We remove that arg and change all ->create operations to behave as those thhe arg were 'true'. Signed-off-by: NeilBrown <neil@brown.name> Link: https://patch.msgid.link/178290671516.27465.15984496764174914338@noble.neil.brown.name Reviewed-by: Jori Koolstra <jkoolstra@xs4all.nl> Reviewed-by: Jan Kara <jack@suse.cz> Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
2026-07-01ocfs2: dlmfs: drop redundant S_IFDIR from mkdirJori Koolstra
vfs_mkdir() now sets the S_IFDIR type bit in the mode it passes to ->mkdir(), so OR-ing S_IFDIR into the mode again in dlmfs_mkdir() is redundant. Drop it. Assisted-by: LLM Signed-off-by: Jori Koolstra <jkoolstra@xs4all.nl> Link: https://patch.msgid.link/20260630105400.68459-23-jkoolstra@xs4all.nl Reviewed-by: NeilBrown <neil@brown.name> Reviewed-by: Jan Kara <jack@suse.cz> Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
2026-07-01ocfs2: drop redundant S_IFDIR from mkdirJori Koolstra
vfs_mkdir() now sets the S_IFDIR type bit in the mode it passes to ->mkdir(), so OR-ing S_IFDIR into the mode again in ocfs2_mkdir() is redundant. Drop it. Assisted-by: LLM Signed-off-by: Jori Koolstra <jkoolstra@xs4all.nl> Link: https://patch.msgid.link/20260630105400.68459-22-jkoolstra@xs4all.nl Reviewed-by: NeilBrown <neil@brown.name> Reviewed-by: Jan Kara <jack@suse.cz> Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
2026-06-29ocfs2: don't reset s_dev on dismountChristian Brauner
ocfs2_dismount_volume() has reset sb->s_dev to zero since the original merge in ccd979bdbce9 ("[PATCH] OCFS2: The Second Oracle Cluster Filesystem") as part of scrubbing the super_block. Nothing reads the field afterwards: all ocfs2-internal uses are mount-time log and trace prints, and dev_t-keyed superblock lookups skip a dying superblock anyway - s_root is gone before ->put_super runs and super_lock() refuses SB_DYING superblocks. The upcoming device-to-superblock table registers every superblock under its s_dev. Drop the reset instead of leaving a superblock around whose s_dev contradicts its registration. Link: https://patch.msgid.link/20260616-work-super-bdev_holder_global-v2-6-7df6b864028e@kernel.org Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
2026-06-21Merge tag 'mm-nonmm-stable-2026-06-21-10-22' of ↵Linus Torvalds
git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm Pull non-MM updates from Andrew Morton: - "taskstats: fix TGID dead-thread stat retention" (Yiyang Chen) Fix a taskstats TGID aggregation bug where fields added in the TGID query path were not preserved after thread exit, and adds a kselftest covering the regression. - "lib/tests: string_helpers: Slight improvements" (Andy Shevchenko) Improve lib/tests/string_helpers_kunit.c a little - "lib/base64: decode fixes" (Josh Law) Address minor issues in lib/base64.c - "selftests/filelock: Make output more kselftestish" (Mark Brown) Make the output from the ofdlocks test a bit easier for tooling to work with. Also ignore the generated file - "uaccess: unify inline vs outline copy_{from,to}_user() selection" (Yury Norov) Simplify the usercopy code by removing the selectability of inlining copy_{from,to}_user(). - "ocfs2: validate inline xattr header consumers" (ZhengYuan Huang) Fix a number of possible issues in the ocfs2 xattr code - "lib and lib/cmdline enhancements" (Dmitry Antipov) Provide additional robustness checking in the cmdline handling code and its in-kernel testing and selftests - "cleanup the RAID6 P/Q library" (Christoph Hellwig) Clean up the RAID6 P/Q library to match the recent updates to the RAID 5 XOR library and other CRC/crypto libraries - "ocfs2: harden inode validators against forged metadata" (Michael Bommarito) Add three structural checks to OCFS2 dinode validation so malformed on-disk fields are rejected before ocfs2_populate_inode() copies them into the in-core inode - "lib/raid: replace __get_free_pages() call with kmalloc()" (Mike Rapoport) Clean up the lib/raid code by using kmalloc() in more places * tag 'mm-nonmm-stable-2026-06-21-10-22' of git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm: (108 commits) ocfs2: fix circular locking dependency in ocfs2_dio_end_io_write ocfs2: fix NULL h_transaction deref in ocfs2_assure_trans_credits lib: interval_tree_test: validate benchmark parameters ocfs2: avoid moving extents to occupied clusters treewide: fix transposed "sign" typos and update spelling.txt ocfs2: fix UBSAN array-index-out-of-bounds in ocfs2_sum_rightmost_rec fat: reject BPB volumes whose data area starts beyond total sectors selftests/uevent: increase __UEVENT_BUFFER_SIZE to avoid ENOBUFS on busy systems lib/test_firmware: allocate the configured into_buf size fs: efs: remove unneeded debug prints checkpatch: cuppress warnings when Reported-by: is followed by Link: MAINTAINERS: add Alexander as a kcov reviewer mailmap: update Alexander Sverdlin's Email addresses fs: fat: inode: replace sprintf() with scnprintf() ocfs2: fix out-of-bounds write in ocfs2_remove_refcount_extent ocfs2: fix race between ocfs2_control_install_private() and ocfs2_control_release() ocfs2/dlm: require a ref for locking_state debugfs open ocfs2: reject FITRIM ranges shorter than a cluster ocfs2: validate fast symlink target during inode read ocfs2: add journal NULL check in ocfs2_checkpoint_inode() ...
2026-06-17ocfs2: fix circular locking dependency in ocfs2_dio_end_io_writeAleksandr Nogikh
A circular locking dependency involves INODE_ALLOC_SYSTEM_INODE, EXTENT_ALLOC_SYSTEM_INODE, and ORPHAN_DIR_SYSTEM_INODE. 1. ocfs2_mknod() acquires INODE_ALLOC then EXTENT_ALLOC. 2. ocfs2_dio_end_io_write() acquires EXTENT_ALLOC for unwritten extents, then ORPHAN_DIR via ocfs2_del_inode_from_orphan() while still holding EXTENT_ALLOC. 3. ocfs2_wipe_inode() acquires ORPHAN_DIR then INODE_ALLOC via ocfs2_remove_inode. Break the cycle in ocfs2_dio_end_io_write() by freeing the allocation contexts (releasing EXTENT_ALLOC) before acquiring ORPHAN_DIR. WARNING: possible circular locking dependency detected ------------------------------------------------------ is trying to acquire lock: ffff8881e78b33a0 (&ocfs2_sysfile_lock_key[INODE_ALLOC_SYSTEM_INODE]){+.+.}-{4:4}, at: ocfs2_evict_inode+0x1539/0x43b0 fs/ocfs2/inode.c:1299 but task is already holding lock: ffff8881e78b4fa0 (&ocfs2_sysfile_lock_key[ORPHAN_DIR_SYSTEM_INODE]){+.+.}-{4:4}, at: ocfs2_evict_inode+0xe97/0x43b0 fs/ocfs2/inode.c:1299 the existing dependency chain (in reverse order) is: -> #2 (&ocfs2_sysfile_lock_key[ORPHAN_DIR_SYSTEM_INODE]){+.+.}-{4:4}: inode_lock include/linux/fs.h:1029 [inline] ocfs2_del_inode_from_orphan+0x12e/0x7a0 fs/ocfs2/namei.c:2728 ocfs2_dio_end_io+0xf9c/0x1370 fs/ocfs2/aops.c:2418 dio_complete+0x25b/0x790 fs/direct-io.c:281 -> #1 (&ocfs2_sysfile_lock_key[EXTENT_ALLOC_SYSTEM_INODE]){+.+.}-{4:4}: inode_lock include/linux/fs.h:1029 [inline] ocfs2_reserve_suballoc_bits+0x16d/0x4840 fs/ocfs2/suballoc.c:882 ocfs2_reserve_new_metadata_blocks+0x415/0x9a0 fs/ocfs2/suballoc.c:1078 ocfs2_mknod+0x10f3/0x2260 fs/ocfs2/namei.c:351 -> #0 (&ocfs2_sysfile_lock_key[INODE_ALLOC_SYSTEM_INODE]){+.+.}-{4:4}: __lock_acquire+0x15a5/0x2cf0 kernel/locking/lockdep.c:5237 lock_acquire+0x106/0x350 kernel/locking/lockdep.c:5868 down_write+0x96/0x200 kernel/locking/rwsem.c:1625 inode_lock include/linux/fs.h:1029 [inline] ocfs2_remove_inode fs/ocfs2/inode.c:733 [inline] ocfs2_wipe_inode fs/ocfs2/inode.c:896 [inline] ocfs2_delete_inode fs/ocfs2/inode.c:1157 [inline] ocfs2_evict_inode+0x1539/0x43b0 fs/ocfs2/inode.c:1299 Chain exists of: &ocfs2_sysfile_lock_key[INODE_ALLOC_SYSTEM_INODE] --> &ocfs2_sysfile_lock_key[EXTENT_ALLOC_SYSTEM_INODE] --> &ocfs2_sysfile_lock_key[ORPHAN_DIR_SYSTEM_INODE] Possible unsafe locking scenario: CPU0 CPU1 ---- ---- lock(&ocfs2_sysfile_lock_key[ORPHAN_DIR_SYSTEM_INODE]); lock(&ocfs2_sysfile_lock_key[EXTENT_ALLOC_SYSTEM_INODE]); lock(&ocfs2_sysfile_lock_key[ORPHAN_DIR_SYSTEM_INODE]); lock(&ocfs2_sysfile_lock_key[INODE_ALLOC_SYSTEM_INODE]); *** DEADLOCK *** Link: https://lore.kernel.org/97c902a6-3bcf-43ea-9b70-f1f136a6c3f2@mail.kernel.org Fixes: d647c5b2fbf8 ("ocfs2: split transactions in dio completion to avoid credit exhaustion") Assisted-by: Gemini:gemini-3.1-pro-preview Gemini:gemini-3-flash-preview syzbot Reported-by: syzbot+b225d4dfce6219600c42@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=b225d4dfce6219600c42 Link: https://syzkaller.appspot.com/ai_job?id=0b53ce1e-2972-4192-aa85-8097a702762c Signed-off-by: Aleksandr Nogikh <nogikh@google.com> Reviewed-by: Heming Zhao <heming.zhao@suse.com> Cc: Mark Fasheh <mark@fasheh.com> Cc: Joel Becker <jlbec@evilplan.org> Cc: Junxiao Bi <junxiao.bi@oracle.com> Cc: Joseph Qi <jiangqi903@gmail.com> Cc: Changwei Ge <gechangwei@live.cn> Cc: Jun Piao <piaojun@huawei.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
2026-06-17ocfs2: fix NULL h_transaction deref in ocfs2_assure_trans_creditsIan Bridges
[BUG] A direct write over unwritten extents can panic the kernel in ocfs2_assure_trans_credits() when the journal aborts during DIO completion. The crash is a general protection fault from a NULL pointer dereference. [CAUSE] ocfs2_dio_end_io_write() loops over a direct write's unwritten extents, marking each written under a single journal handle. If the journal aborts (for example after an I/O error) while the extent tree is being updated, the handle is left aborted with its transaction pointer cleared. The extent merge treats that failure as not critical and reports success, so the loop keeps using the handle. ocfs2_assure_trans_credits() reads the handle's remaining credits without first checking whether the handle is aborted, and that read dereferences the cleared transaction pointer. [FIX] A journal abort is recorded in the handle itself, so callers are expected to test the handle rather than rely on a returned error. Make ocfs2_assure_trans_credits() do that, as the other ocfs2 journal helpers already do, and return -EROFS when the handle is aborted. Link: https://lore.kernel.org/airKTsM1fRVN-Wj7@dev Fixes: be346c1a6eeb ("ocfs2: fix DIO failure due to insufficient transaction credits") Signed-off-by: Ian Bridges <icb@fastmail.org> Reported-by: syzbot+e9c15ff790cea6a0cfae@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=e9c15ff790cea6a0cfae Reviewed-by: Joseph Qi <joseph.qi@linux.alibaba.com> Cc: Mark Fasheh <mark@fasheh.com> Cc: Joel Becker <jlbec@evilplan.org> Cc: Junxiao Bi <junxiao.bi@oracle.com> Cc: Changwei Ge <gechangwei@live.cn> Cc: Jun Piao <piaojun@huawei.com> Cc: Heming Zhao <heming.zhao@suse.com> Cc: <stable@vger.kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
2026-06-17ocfs2: avoid moving extents to occupied clustersKyle Zeng
For non-auto OCFS2_IOC_MOVE_EXT operations, userspace supplies a physical me_goal. ocfs2_move_extent() initializes new_phys_cpos from that goal and expects ocfs2_probe_alloc_group() to replace it with a free run in the target block group. The probe currently leaves *phys_cpos unchanged if the scan reaches the end of the group without finding a free run. An occupied goal at the last bit can therefore survive the probe and be passed to __ocfs2_move_extent(), which copies file data into a cluster still owned by another inode before the bitmap is updated. When the probe does find a free run, it also subtracts move_len from the ending bit. The start of an N-bit run ending at i is i - N + 1, so the current calculation can report the bit immediately before the free run. Clear *phys_cpos before scanning and use the correct free-run start. Callers already treat a zero result as -ENOSPC, so failed probes no longer continue with an occupied caller-controlled goal. Link: https://lore.kernel.org/20260611213510.16956-1-kylebot@openai.com Fixes: e6b5859cccfa ("Ocfs2/move_extents: helper to probe a proper region to move in an alloc group.") Fixes: 236b9254f8d1 ("ocfs2: fix non-auto defrag path not working issue") Assisted-by: Codex:gpt-5.5 Signed-off-by: Kyle Zeng <kylebot@openai.com> Reviewed-by: Joseph Qi <joseph.qi@linux.alibaba.com> Cc: Mark Fasheh <mark@fasheh.com> Cc: Joel Becker <jlbec@evilplan.org> Cc: Junxiao Bi <junxiao.bi@oracle.com> Cc: Changwei Ge <gechangwei@live.cn> Cc: Jun Piao <piaojun@huawei.com> Cc: Heming Zhao <heming.zhao@suse.com> Cc: <stable@vger.kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
2026-06-17ocfs2: fix UBSAN array-index-out-of-bounds in ocfs2_sum_rightmost_recIan Bridges
[BUG] On-disk corruption setting l_next_free_rec to 0 in an inode's embedded extent list triggers a UBSAN panic on the next write to that file. [CAUSE] ocfs2_sum_rightmost_rec() computes i = le16_to_cpu(el->l_next_free_rec) - 1 and accesses el->l_recs[i] without validating i. When l_next_free_rec is 0, i becomes -1; when l_next_free_rec exceeds l_count, i falls past the end of the array. Either case violates the __counted_by_le(l_count) annotation on l_recs[] and triggers UBSAN. [FIX] Validate the inode's embedded extent list when the inode is read, in ocfs2_validate_inode_block(): l_count must be non-zero and no larger than the inode block can hold, and l_next_free_rec must not exceed l_count. A corrupt list is rejected at read time, before the b-tree code can index l_recs[] out of bounds. Link: https://lore.kernel.org/ain_780qc0P4ypNd@dev Signed-off-by: Ian Bridges <icb@fastmail.org> Reported-by: syzbot+be16e33db01e6644db7a@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=be16e33db01e6644db7a Reviewed-by: Joseph Qi <joseph.qi@linux.alibaba.com> Cc: Mark Fasheh <mark@fasheh.com> Cc: Joel Becker <jlbec@evilplan.org> Cc: Junxiao Bi <junxiao.bi@oracle.com> Cc: Changwei Ge <gechangwei@live.cn> Cc: Jun Piao <piaojun@huawei.com> Cc: Heming Zhao <heming.zhao@suse.com> Cc: <stable@vger.kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
2026-06-15Merge tag 'vfs-7.2-rc1.procfs' of ↵Linus Torvalds
git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs Pull procfs updates from Christian Brauner: - Revamp fs/filesystems.c The file was a mess with a hand-rolled linked list in desperate need of a cleanup. The filesystems list is now RCU-ified, /proc files can be marked permanent from outside fs/proc/, and the string emitted when reading /proc/filesystems is pre-generated and cached instead of pointer-chasing and printfing entry by entry on every read. The file is read frequently because libselinux reads it and is linked into numerous frequently used programs (even ones you would not suspect, like sed!). Scalability also improves since reference maintenance on open/close is bypassed. open+read+close cycle single-threaded (ops/s): before: 442732 after: 1063462 (+140%) open+read+close cycle with 20 processes (ops/s): before: 606177 after: 3300576 (+444%) A follow-up patch adds missing unlocks in some corner cases and tidies things up. - Relax the mount visibility check for subset=pid mounts When procfs is mounted with subset=pid, all static files become unavailable and only the dynamic pid information is accessible. In that case there is no point in imposing the full mount visibility restrictions on the mounter - everything that can be hidden in procfs is already inaccessible. These restrictions prevented procfs from being mounted inside rootless containers since almost all container implementations overmount parts of procfs to hide certain directories. As part of this /proc/self/net is only shown in subset=pid mounts for CAP_NET_ADMIN, reconfiguring subset=pid is rejected, the SB_I_USERNS_VISIBLE superblock flag is replaced with an FS_USERNS_MOUNT_RESTRICTED filesystem flag, fully visible mounts are recorded in a list, and the mount restrictions are finally documented. - Protect ptrace_may_access() with exec_update_lock in procfs Most uses of ptrace_may_access() in procfs should hold exec_update_lock to avoid TOCTOU issues with concurrent privileged execve() (like setuid binary execution). This fixes the easy cases - the owner and visibility checks and the FD link permission checks - with the gnarlier ones to follow later. * tag 'vfs-7.2-rc1.procfs' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs: fs: fix ups and tidy ups to /proc/filesystems caching proc: protect ptrace_may_access() with exec_update_lock (FD links) proc: protect ptrace_may_access() with exec_update_lock (part 1) docs: proc: add documentation about mount restrictions proc: handle subset=pid separately in userns visibility checks proc: prevent reconfiguring subset=pid proc: subset=pid: Show /proc/self/net only for CAP_NET_ADMIN fs: cache the string generated by reading /proc/filesystems sysfs: remove trivial sysfs_get_tree() wrapper fs: RCU-ify filesystems list fs: move SB_I_USERNS_VISIBLE to FS_USERNS_MOUNT_RESTRICTED proc: allow to mark /proc files permanent outside of fs/proc/ namespace: record fully visible mounts in list
2026-06-15Merge tag 'vfs-7.2-rc1.misc' of ↵Linus Torvalds
git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs Pull misc vfs updates from Christian Brauner: "Features: - Reduce pipe->mutex contention by pre-allocating pages outside the lock in anon_pipe_write(). anon_pipe_write() called alloc_page() once per page while holding pipe->mutex. The allocation can sleep doing direct reclaim and runs memcg charging, which extends the critical section and stalls any concurrent reader on the same mutex. Now up to 8 pages are pre-allocated before the mutex is taken, leftovers are recycled into the per-pipe tmp_page[] cache before unlock, and any remainder is released after unlock, keeping the allocator out of the critical section on both sides. On a writers x readers sweep with 64KB writes against a 1 MB pipe throughput improves 6-28% and average write latency drops 5-22%; under memory pressure - when the cost of holding the mutex across reclaim is highest - throughput improves 21-48% and latency drops 17-33%. The microbenchmark is added to selftests. - uaccess/sockptr: fix the ignored_trailing logic in copy_struct_to_user() to behave as documented and the usize check in copy_struct_from_sockptr() for user pointers, and add copy_struct_{from,to}_bounce_buffer() and copy_struct_to_sockptr() helpers for upcoming users (IPPROTO_SMBDIRECT, IPPROTO_QUIC). - bpf: add a sleepable bpf_real_inode() kfunc that resolves the real inode backing a dentry via d_real_inode(). On overlayfs the inode attached to the dentry doesn't carry the underlying device information; this is used by the filesystem restriction BPF program that was merged into systemd. - docs: add guidelines for submitting new filesystems, motivated by the maintenance burden abandoned and untestable filesystems impose on VFS developers, blocking infrastructure work like folio conversions and iomap migration. Fixes: - libfs: set SB_I_NOEXEC and SB_I_NODEV by default in init_pseudo() and drop the now-redundant assignments in callers. This began as a one-line dma-buf fix for a path_noexec() warning; a pseudo filesystem has no reason not to set SB_I_NOEXEC. All init_pseudo() callers were audited: the only visible effect is on dma-buf where SB_I_NOEXEC silences the warning. - Handle set_blocksize() failures in legacy filesystems (bfs, hpfs, qnx4, jfs, befs, affs, isofs, minix, ntfs3, omfs). Mounting a device with a sector size > PAGE_SIZE crashed roughly half of them; the rest had the same missing error handling pattern. Plus a follow-up releasing the superblock buffer_head when setting the minix v3 block size fails. - mount: honour SB_NOUSER in the new mount API. - fs/fcntl: fix a SOFTIRQ-unsafe lock order in fasync signaling by switching the process-group paths of send_sigio() and send_sigurg() from read_lock(&tasklist_lock) to RCU, matching the single-PID path. - vfs: add an FS_USERNS_DELEGATABLE flag and set it for NFS, fixing delegated NFS mounts (fsopen() in a container with the mount performed by a privileged daemon) that broke when non-init s_user_ns was tied to FS_USERNS_MOUNT. - selftests/namespaces: fix a hang in nsid_test where an unreaped grandchild kept the TAP pipe write-end open, a waitpid(-1) race in listns_efault_test, and a false FAIL on kernels without listns() where the tests should SKIP. - filelock: fix the break_lease() stub signature for CONFIG_FILE_LOCKING=n. - init/initramfs_test: wait for the async initramfs unpacking before running; the test and do_populate_rootfs() share the parser state. - fs/coredump: reduce redundant log noise in validate_coredump_safety(). - iomap: pass the correct length to fserror_report_io() in __iomap_write_begin(). - backing-file: fix the backing_file_open() kerneldoc. Cleanups: - initramfs: refactor the cpio hex header parsing to use hex2bin() instead of the hand-rolled simple_strntoul() which is reverted, and extend the initramfs KUnit tests to cover header fields with 0x prefixes. - Replace __get_free_pages() and friends with kmalloc()/kzalloc() across quota, proc, ocfs2/dlm, nilfs2, nfs, nfsd, libfs, jfs, jbd2, isofs, fuse, select, namespace, configfs, binfmt_misc, bfs, and the do_mounts init code - part of the larger work of replacing page allocator calls with kmalloc(). - Use clear_and_wake_up_bit() in unlock_buffer() and journal_end_buffer_io_sync() instead of open-coding the sequence. - Drop unused VFS exports: unexport drop_super_exclusive(), remove start_removing_user_path_at(), and fold __start_removing_path() into start_removing_path(). - fs/read_write: narrow the __kernel_write() export with EXPORT_SYMBOL_FOR_MODULES(). - vfs: uapi: retire octal and hex constants in favor of (1 << n) for the O_ flags. Finding a free bit for a new flag across the architectures was needlessly hard with the mixed bases. - dcache: add extra sanity checks of dead dentries in dentry_free() via a new DENTRY_WARN_ONCE() that also prints d_flags. - iov_iter: use kmemdup_array() in dup_iter() to harden the allocation against multiplication overflow. - fs/pipe: write to ->poll_usage only once. - vfs: remove an always-taken if-branch in find_next_fd(). - dcache: use kmalloc_flex() for struct external_name in __d_alloc(). - namei: use QSTR() instead of QSTR_INIT() in path_pts(). - sync_file_range: delete dead S_ISLNK code. - Comment fixes: retire a stale comment in fget_task_next() and fix assorted spelling mistakes" * tag 'vfs-7.2-rc1.misc' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs: (73 commits) backing-file: fix backing_file_open() kerneldoc parameter iomap: pass the correct len to fserror_report_io in __iomap_write_begin vfs: add FS_USERNS_DELEGATABLE flag and set it for NFS filelock: fix break_lease() stub signature for CONFIG_FILE_LOCKING=n vfs: uapi: retire octal and hex numbers in favor of (1 << n) for O_ flags bpf: add bpf_real_inode() kfunc fs/read_write: Do not export __kernel_write() to the entire world libfs: drop redundant SB_I_NOEXEC/SB_I_NODEV in init_pseudo() callers libfs: set SB_I_NOEXEC and SB_I_NODEV by default in init_pseudo() mount: honour SB_NOUSER in the new mount API fs/fcntl: fix SOFTIRQ-unsafe lock order in fasync signaling selftests/pipe: add pipe_bench microbenchmark fs/pipe: pre-allocate pages outside pipe->mutex in anon_pipe_write fs: retire stale comment in fget_task_next() fs: fix spelling mistakes in comment bfs: replace get_zeroed_page() with kzalloc() binfmt_misc: replace __get_free_page() with kmalloc() configfs: replace __get_free_pages() with kzalloc() fs/namespace: use __getname() to allocate mntpath buffer fs/select: replace __get_free_page() with kmalloc() ...
2026-06-04ocfs2: fix out-of-bounds write in ocfs2_remove_refcount_extentIan Bridges
[BUG] Unlinking a refcounted file whose refcount tree has leaf blocks triggers a fortify panic due to an out-of-bounds write. [CAUSE] When the last leaf block is removed from a refcount tree, ocfs2_remove_refcount_extent() converts the root back to leaf mode with a bulk memset on &rb->rf_records. rf_records sits in an anonymous union with rf_list. rf_list.l_tree_depth aliases rf_records.rl_count, and is 0 for a single-level tree. With rl_count equal to 0, the memset writes past the 16-byte declared size of rf_records, which the fortify checker catches. [FIX] Replace the bulk memset on &rb->rf_records with a correctly-bounded memset on rl_recs[] alone, after setting rl_count to the correct value. Link: https://lore.kernel.org/ah3TESOsEO9j_JLU@dev Fixes: 2f26f58df041 ("ocfs2: annotate flexible array members with __counted_by_le()") Signed-off-by: Ian Bridges <icb@fastmail.org> Reported-by: syzbot+3ef989aae096b30f1663@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=3ef989aae096b30f1663 Reviewed-by: Joseph Qi <joseph.qi@linux.alibaba.com> Cc: Mark Fasheh <mark@fasheh.com> Cc: Joel Becker <jlbec@evilplan.org> Cc: Junxiao Bi <junxiao.bi@oracle.com> Cc: Changwei Ge <gechangwei@live.cn> Cc: Jun Piao <piaojun@huawei.com> Cc: Heming Zhao <heming.zhao@suse.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
2026-06-04ocfs2: fix race between ocfs2_control_install_private() and ↵Joseph Qi
ocfs2_control_release() Move atomic_inc(&ocfs2_control_opened) and the handshake state update inside ocfs2_control_lock to close a race window where ocfs2_control_release() can observe ocfs2_control_opened dropping to zero (resetting ocfs2_control_this_node and running_proto) while ocfs2_control_install_private() is about to bump the counter and mark the connection valid. Link: https://lore.kernel.org/20260601121618.1263346-1-joseph.qi@linux.alibaba.com Fixes: 3cfd4ab6b6b4 ("ocfs2: Add the local node id to the handshake.") Signed-off-by: Joseph Qi <joseph.qi@linux.alibaba.com> Reported-by: Ginger <ginger.jzllee@gmail.com> Cc: Mark Fasheh <mark@fasheh.com> Cc: Joel Becker <jlbec@evilplan.org> Cc: Junxiao Bi <junxiao.bi@oracle.com> Cc: Changwei Ge <gechangwei@live.cn> Cc: Jun Piao <piaojun@huawei.com> Cc: Heming Zhao <heming.zhao@suse.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
2026-06-04ocfs2/dlm: require a ref for locking_state debugfs openZhang Cen
debug_lockres_open() copies inode->i_private into struct debug_lockres and debug_lockres_release() later drops that pointer with dlm_put(). That only works if open successfully pins the struct dlm_ctxt. Today open calls dlm_grab(dlm) but ignores its return value. Once the last domain unregister has removed the context from dlm_domains, dlm_grab() returns NULL, yet open still stores the raw pointer and returns success. The later release path is outside the debugfs removal barrier, so it can call dlm_put() after dlm_free_ctxt_mem() has freed the context. KASAN reports this as a slab-use-after-free in dlm_put() called from debug_lockres_release(). Fail the open when dlm_grab() cannot acquire the reference and unwind the seq_file private state before returning. That keeps locking_state from handing out a file descriptor whose release path does not own the dlm_ctxt. The buggy scenario involves two paths, with each column showing the order within that path: locking_state debugfs open: last domain unregister: 1. debug_lockres_open() reads 1. dlm_unregister_domain() calls inode->i_private. dlm_complete_dlm_shutdown(). 2. debug_lockres_open() calls 2. shutdown removes the dlm_ctxt from dlm_grab(dlm) and gets NULL. dlm_domains. 3. open still stores the raw dlm 3. final teardown reaches pointer in dl->dl_ctxt and dlm_free_ctxt_mem() and frees it. returns success. 4. debug_lockres_release() later calls dlm_put(dl->dl_ctxt). Validation reproduced this kernel report: KASAN slab-use-after-free in dlm_put+0x82/0x200 RIP: 0033:0x7f4d349bc9e0 The buggy address belongs to the object at ffff888103a3c000 which belongs to the cache kmalloc-2k of size 2048 The buggy address is located 816 bytes inside of freed 2048-byte region [ffff888103a3c000, ffff888103a3c800) Write of size 4 Call trace: dump_stack_lvl+0x66/0xa0 (?:?) print_report+0xd0/0x630 (?:?) dlm_put+0x82/0x200 (?:?) srso_alias_return_thunk+0x5/0xfbef5 (?:?) __virt_addr_valid+0x188/0x2f0 (?:?) kasan_report+0xe4/0x120 (?:?) kasan_check_range+0x105/0x1b0 (?:?) debug_lockres_release+0x53/0x80 (fs/ocfs2/dlm/dlmdebug.c:587) dlm_put+0x9/0x200 (?:?) debug_lockres_release+0x5c/0x80 (fs/ocfs2/dlm/dlmdebug.c:587) full_proxy_release+0x67/0x90 (?:?) __fput+0x1df/0x4b0 (?:?) do_raw_spin_lock+0x10f/0x1b0 (?:?) fput_close_sync+0xd2/0x170 (?:?) __x64_sys_close+0x55/0x90 (?:?) do_syscall_64+0x10c/0x640 (arch/x86/entry/syscall_64.c:87) irqentry_exit+0xac/0x6e0 (?:?) entry_SYSCALL_64_after_hwframe+0x77/0x7f (?:?) Freed by task stack: kasan_save_stack+0x33/0x60 (?:?) kasan_save_track+0x14/0x30 (?:?) kasan_save_free_info+0x3b/0x60 (?:?) __kasan_slab_free+0x5f/0x80 (?:?) kfree+0x30f/0x580 (?:?) dlm_put+0x1ce/0x200 (?:?) dlm_unregister_domain+0xf6/0xb30 (?:?) o2cb_cluster_disconnect+0x6b/0x90 (?:?) ocfs2_cluster_disconnect+0x41/0x70 (?:?) ocfs2_dlm_shutdown+0x1c4/0x220 (?:?) ocfs2_dismount_volume+0x38a/0x550 (?:?) generic_shutdown_super+0xc3/0x220 (?:?) kill_block_super+0x29/0x60 (?:?) deactivate_locked_super+0x66/0xe0 (?:?) cleanup_mnt+0x13d/0x210 (?:?) task_work_run+0xfa/0x170 (?:?) exit_to_user_mode_loop+0xd6/0x430 (?:?) do_syscall_64+0x3cb/0x640 (arch/x86/entry/syscall_64.c:87) entry_SYSCALL_64_after_hwframe+0x77/0x7f (?:?) Link: https://lore.kernel.org/20260531044714.1640172-1-rollkingzzc@gmail.com Fixes: 4e3d24ed1a12 ("ocfs2/dlm: Dumps the lockres' into a debugfs file") Assisted-by: Codex:gpt-5.5 Signed-off-by: Zhang Cen <rollkingzzc@gmail.com> Reviewed-by: Joseph Qi <joseph.qi@linux.alibaba.com> Cc: Mark Fasheh <mark@fasheh.com> Cc: Joel Becker <jlbec@evilplan.org> Cc: Junxiao Bi <junxiao.bi@oracle.com> Cc: Changwei Ge <gechangwei@live.cn> Cc: Jun Piao <piaojun@huawei.com> Cc: Heming Zhao <heming.zhao@suse.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
2026-06-04ocfs2: reject FITRIM ranges shorter than a clusterZhang Cen
ocfs2_trim_mainbm() trims the global bitmap in cluster units, but its too-short range validation only checks sb->s_blocksize. On filesystems with a cluster size larger than the block size, a FITRIM range that is at least one block but shorter than one cluster is accepted and shifted down to len == 0. The later start + len - 1 and len -= ... arithmetic then underflows and can drive trimming past the requested range. Reject ranges shorter than s_clustersize instead. That preserves the existing -EINVAL behavior for requests that cannot discard even one allocation unit and keeps zero-cluster trims out of the group walk. Link: https://lore.kernel.org/20260528151247.361854-1-rollkingzzc@gmail.com Fixes: aa89762c5480 ("ocfs2: return EINVAL if the given range to discard is less than block size") Assisted-by: Codex:gpt-5.5 Signed-off-by: Zhang Cen <rollkingzzc@gmail.com> Reviewed-by: Joseph Qi <joseph.qi@linux.alibaba.com> Cc: Mark Fasheh <mark@fasheh.com> Cc: Joel Becker <jlbec@evilplan.org> Cc: Junxiao Bi <junxiao.bi@oracle.com> Cc: Changwei Ge <gechangwei@live.cn> Cc: Jun Piao <piaojun@huawei.com> Cc: Heming Zhao <heming.zhao@suse.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
2026-06-04ocfs2: validate fast symlink target during inode readZhang Cen
ocfs2_validate_inode_block() already rejects several inconsistent self-contained dinodes before they are exposed to the rest of the filesystem. Fast symlinks need the same treatment. A zero-cluster symlink is treated as a fast symlink and later read through page_get_link() and ocfs2_fast_symlink_read_folio(). That path uses strnlen() on the inline payload and then copies len + 1 bytes into the folio. If a corrupt dinode stores an i_size that does not fit the inline area or omits the terminating NUL at i_size, that copy reads past the end of the inode block buffer. Reject zero-cluster symlink dinodes whose i_size exceeds the inline fast-symlink capacity or whose inline payload is not NUL-terminated exactly at i_size when the inode block is validated. This keeps malformed fast symlinks from reaching the read path. Validation reproduced this kernel report: KASAN use-after-free in ocfs2_fast_symlink_read_folio+0x12c/0x1f0 RIP: 0033:0x7f5c6d859aa7 Read of size 3905 Call trace: dump_stack_lvl+0x66/0xa0 (?:?) print_report+0xce/0x630 (?:?) ocfs2_fast_symlink_read_folio+0x12c/0x1f0 (fs/ocfs2/inode.c:?) srso_alias_return_thunk+0x5/0xfbef5 (?:?) __virt_addr_valid+0x19f/0x330 (?:?) kasan_report+0xe0/0x110 (?:?) kasan_check_range+0x105/0x1b0 (?:?) __asan_memcpy+0x23/0x60 (?:?) filemap_read_folio+0x27/0xe0 (?:?) filemap_read_folio+0x35/0xe0 (?:?) do_read_cache_folio+0x138/0x230 (?:?) __page_get_link+0x26/0x110 (?:?) page_get_link+0x2e/0x70 (?:?) vfs_readlink+0x15e/0x250 (?:?) touch_atime+0x4d/0x370 (?:?) do_readlinkat+0x186/0x200 (?:?) do_user_addr_fault+0x65a/0x890 (?:?) __x64_sys_readlink+0x46/0x60 (?:?) do_syscall_64+0x115/0x6a0 (arch/x86/entry/syscall_64.c:87) entry_SYSCALL_64_after_hwframe+0x77/0x7f (?:?) Link: https://lore.kernel.org/20260528151230.361127-1-rollkingzzc@gmail.com Fixes: ea022dfb3c2a ("ocfs: simplify symlink handling") Assisted-by: Codex:gpt-5.5 Signed-off-by: Zhang Cen <rollkingzzc@gmail.com> Reviewed-by: Joseph Qi <joseph.qi@linux.alibaba.com> Cc: Gui-Dong Han <2045gemini@gmail.com> Cc: Mark Fasheh <mark@fasheh.com> Cc: Joel Becker <jlbec@evilplan.org> Cc: Junxiao Bi <junxiao.bi@oracle.com> Cc: Changwei Ge <gechangwei@live.cn> Cc: Jun Piao <piaojun@huawei.com> Cc: Heming Zhao <heming.zhao@suse.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
2026-06-04ocfs2: add journal NULL check in ocfs2_checkpoint_inode()Joseph Qi
During unmount, ocfs2_journal_shutdown() frees the journal and sets osb->journal to NULL. Later, when VFS evicts remaining cached inodes, ocfs2_evict_inode() -> ocfs2_clear_inode() -> ocfs2_checkpoint_inode() -> ocfs2_ci_fully_checkpointed() dereferences osb->journal, causing a NULL pointer dereference. Fix this by adding a NULL check for osb->journal in ocfs2_checkpoint_inode(). If the journal is NULL, it has already been fully flushed and destroyed during shutdown, so there is nothing to checkpoint. Link: https://lore.kernel.org/20260531131645.3650299-1-joseph.qi@linux.alibaba.com Reported-by: Farhad Alemi <farhad.alemi@berkeley.edu> Fixes: da5e7c87827e ("ocfs2: cleanup journal init and shutdown") Signed-off-by: Joseph Qi <joseph.qi@linux.alibaba.com> Tested-by: Farhad Alemi <farhad.alemi@berkeley.edu> Reviewed-by: Heming Zhao <heming.zhao@suse.com> Cc: Mark Fasheh <mark@fasheh.com> Cc: Joel Becker <jlbec@evilplan.org> Cc: Junxiao Bi <junxiao.bi@oracle.com> Cc: Changwei Ge <gechangwei@live.cn> Cc: Jun Piao <piaojun@huawei.com> Cc: <stable@vger.kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
2026-06-04ocfs2: fix buffer head management in ocfs2_read_blocks()Dmitry Antipov
In ocfs2_read_blocks(), caller should't assume that buffer head returned by 'sb_getblk()' is exclusively owned and so 'put_bh()' always drops b_count from 1 to 0. If it is not so, buffer head remains on hold and likely to be returned by the next call to 'sb_getblk()' unchanged - that is, with BH_Uptodate bit set even if it has failed validation previously, thus allowing to insert that buffer head into OCFS2 metadata cache and submit it to upper layers. To avoid such a scenario, BH_Uptodate should be cleared immediately after 'validate()' callback has detected some data inconsistency. Link: https://lore.kernel.org/20260529094128.494293-1-dmantipov@yandex.ru Fixes: cf76c78595ca ("ocfs2: don't put and assigning null to bh allocated outside") Signed-off-by: Dmitry Antipov <dmantipov@yandex.ru> Reported-by: syzbot+caacd220635a9cc3bac9@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=caacd220635a9cc3bac9 Reviewed-by: Joseph Qi <joseph.qi@linux.alibaba.com> Cc: Mark Fasheh <mark@fasheh.com> Cc: Joel Becker <jlbec@evilplan.org> Cc: Junxiao Bi <junxiao.bi@oracle.com> Cc: Changwei Ge <gechangwei@live.cn> Cc: Jun Piao <piaojun@huawei.com> Cc: Heming Zhao <heming.zhao@suse.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
2026-06-04ocfs2: reject oversized group bitmap descriptorsZhang Cen
ocfs2_validate_gd_parent() only bounds bg_bits against the parent allocator's chain geometry. A malicious descriptor can still claim a bg_size/bg_bits pair that exceeds the bitmap bytes that physically fit in the group descriptor block, so later bitmap scans and bit updates can run past bg_bitmap. Add a physical-cap check based on ocfs2_group_bitmap_size() for the parent allocator type and reject descriptors whose bg_size or bg_bits exceed that capacity. Keep the existing chain geometry check so both the on-disk bitmap layout and the allocator metadata must agree before the descriptor is used. Validation reproduced this kernel report: KASAN use-after-free in _find_next_bit+0x7f/0xc0 Read of size 8 Call trace: dump_stack_lvl+0x66/0xa0 (?:?) print_report+0xd0/0x630 (?:?) _find_next_bit+0x7f/0xc0 (?:?) srso_alias_return_thunk+0x5/0xfbef5 (?:?) __virt_addr_valid+0x188/0x2f0 (?:?) kasan_report+0xe4/0x120 (?:?) ocfs2_find_max_contig_free_bits+0x35/0x70 (fs/ocfs2/suballoc.c:1375) ocfs2_block_group_set_bits+0x472/0x4b0 (fs/ocfs2/suballoc.c:1457) ocfs2_cluster_group_search+0x16b/0x440 (fs/ocfs2/suballoc.c:86) ocfs2_bg_discontig_fix_result+0x1ef/0x230 (fs/ocfs2/suballoc.c:1786) ocfs2_search_chain+0x8f8/0x10a0 (fs/ocfs2/suballoc.c:1886) get_page_from_freelist+0x70e/0x2370 (?:?) lock_release+0xc6/0x290 (?:?) do_raw_spin_unlock+0x9a/0x100 (?:?) kasan_unpoison+0x27/0x60 (?:?) __bfs+0x147/0x240 (?:?) get_page_from_freelist+0x83d/0x2370 (?:?) ocfs2_claim_suballoc_bits+0x38c/0xe70 (fs/ocfs2/suballoc.c:96) sched_domains_numa_masks_clear+0x70/0xd0 (?:?) check_irq_usage+0xe8/0xb70 (?:?) __ocfs2_claim_clusters+0x18d/0x4c0 (fs/ocfs2/suballoc.c:2497) check_path+0x24/0x50 (?:?) rcu_is_watching+0x20/0x50 (?:?) check_prev_add+0xfd/0xd00 (?:?) ocfs2_add_clusters_in_btree+0x17d/0x810 (fs/ocfs2/suballoc.c:?) __folio_batch_add_and_move+0x1f5/0x3d0 (?:?) ocfs2_add_inode_data+0xd9/0x120 (fs/ocfs2/suballoc.c:?) filemap_add_folio+0x105/0x1f0 (?:?) ocfs2_write_begin_nolock+0x29f7/0x2f80 (fs/ocfs2/suballoc.c:3043) ocfs2_read_inode_block+0xb5/0x110 (fs/ocfs2/suballoc.c:?) down_write+0xf5/0x180 (?:?) ocfs2_write_begin+0x180/0x240 (fs/ocfs2/suballoc.c:?) __mark_inode_dirty+0x758/0x9a0 (?:?) inode_to_bdi+0x41/0x90 (?:?) balance_dirty_pages_ratelimited_flags+0xf8/0x1d0 (?:?) generic_perform_write+0x252/0x440 (?:?) mnt_put_write_access_file+0x16/0x70 (?:?) file_update_time_flags+0xe4/0x200 (?:?) ocfs2_file_write_iter+0x80a/0x1320 (fs/ocfs2/suballoc.c:?) lock_acquire+0x184/0x2f0 (?:?) ksys_write+0xd2/0x170 (?:?) apparmor_file_permission+0xf5/0x310 (?:?) read_zero+0x8d/0x140 (?:?) lock_is_held_type+0x8f/0x100 (?:?) Link: https://lore.kernel.org/20260524111248.1429884-1-rollkingzzc@gmail.com Fixes: ccd979bdbce9 ("[PATCH] OCFS2: The Second Oracle Cluster Filesystem") Assisted-by: Codex:gpt-5.5 Signed-off-by: Zhang Cen <rollkingzzc@gmail.com> Reviewed-by: Joseph Qi <joseph.qi@linux.alibaba.com> Cc: Mark Fasheh <mark@fasheh.com> Cc: Joel Becker <jlbec@evilplan.org> Cc: Junxiao Bi <junxiao.bi@oracle.com> Cc: Changwei Ge <gechangwei@live.cn> Cc: Jun Piao <piaojun@huawei.com> Cc: Heming Zhao <heming.zhao@suse.com> Cc: <stable@vger.kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
2026-06-04ocfs2: rebase copied fsdlm LVB pointers in locking_stateZhang Cen
The locking_state debugfs iterator snapshots struct ocfs2_lock_res by value under ocfs2_dlm_tracking_lock and later formats that copy in ocfs2_dlm_seq_show(). That is fine for the inline fields, but the userspace fsdlm stack stores the LVB through lksb_fsdlm.sb_lvbptr. Once the iterator drops the tracking lock, a copied non-NULL sb_lvbptr still points into the original lockres owner, so teardown can free that container before the debugfs dump walks the raw LVB bytes. Rebase the copied sb_lvbptr to the copied l_lksb before dumping the raw LVB. The seq snapshot already carries the inline LVB storage reserved in struct ocfs2_dlm_lksb, so the debugfs reader can dump the copied bytes without borrowing the original lockres lifetime. The buggy scenario involves two paths, with each column showing the order within that path: locking_state reader: lockres teardown: 1. ocfs2_dlm_seq_start()/next() 1. file release or another owner copies struct ocfs2_lock_res teardown reaches 2. ocfs2_dlm_seq_show() formats ocfs2_lock_res_free() the copied row 2. the lockres is removed from the 3. ocfs2_dlm_lvb() follows the tracking list copied sb_lvbptr 3. the owner frees the original lockres container Validation reproduced this kernel report: KASAN slab-use-after-free in ocfs2_dlm_seq_show+0x1bd/0x430 RIP: 0033:0x7f8ec4b1e29d The buggy address belongs to the object at ffff88810a1e0800 which belongs to the cache kmalloc-1k of size 1024 The buggy address is located 368 bytes inside of freed 1024-byte region [ffff88810a1e0800, ffff88810a1e0c00) Read of size 1 Call trace: dump_stack_lvl+0x66/0xa0 print_report+0xce/0x630 ocfs2_dlm_seq_show+0x1bd/0x430 (fs/ocfs2/dlmglue.c:3137) srso_alias_return_thunk+0x5/0xfbef5 __virt_addr_valid+0x19f/0x330 kasan_report+0xe0/0x110 seq_read_iter+0x29d/0x790 seq_read+0x20a/0x280 find_held_lock+0x2b/0x80 rcu_read_unlock+0x18/0x70 full_proxy_read+0x9e/0xd0 vfs_read+0x12c/0x590 ksys_read+0xd2/0x170 do_user_addr_fault+0x65a/0x890 do_syscall_64+0x115/0x6a0 (arch/x86/entry/syscall_64.c:87) entry_SYSCALL_64_after_hwframe+0x77/0x7f Allocated by task stack: kasan_save_stack+0x33/0x60 kasan_save_track+0x14/0x30 __kasan_kmalloc+0xaa/0xb0 ocfs2_file_open+0x13e/0x300 do_dentry_open+0x233/0x7f0 vfs_open+0x5a/0x1b0 path_openat+0x66d/0x1540 do_file_open+0x186/0x2b0 do_sys_openat2+0xce/0x150 __x64_sys_openat+0xd0/0x140 do_syscall_64+0x115/0x6a0 (arch/x86/entry/syscall_64.c:87) entry_SYSCALL_64_after_hwframe+0x77/0x7f Freed by task stack: kasan_save_stack+0x33/0x60 kasan_save_track+0x14/0x30 kasan_save_free_info+0x3b/0x60 __kasan_slab_free+0x5f/0x80 kfree+0x313/0x590 ocfs2_file_release+0x138/0x260 __fput+0x1df/0x4b0 fput_close_sync+0xd2/0x170 __x64_sys_close+0x55/0x90 do_syscall_64+0x115/0x6a0 (arch/x86/entry/syscall_64.c:87) entry_SYSCALL_64_after_hwframe+0x77/0x7f Link: https://lore.kernel.org/20260525041726.4112882-1-rollkingzzc@gmail.com Fixes: cf4d8d75d8ab ("ocfs2: add fsdlm to stackglue") Assisted-by: Codex:gpt-5.5 Signed-off-by: Zhang Cen <rollkingzzc@gmail.com> Reviewed-by: Joseph Qi <joseph.qi@linux.alibaba.com> Cc: Mark Fasheh <mark@fasheh.com> Cc: Joel Becker <jlbec@evilplan.org> Cc: Junxiao Bi <junxiao.bi@oracle.com> Cc: Changwei Ge <gechangwei@live.cn> Cc: Jun Piao <piaojun@huawei.com> Cc: Heming Zhao <heming.zhao@suse.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
2026-06-04ocfs2: Convert ocfs2_write_super_or_backup to bh_submit()Matthew Wilcox (Oracle)
Avoid an extra indirect function call and changing the buffer refcount by using bh_submit() instead of submit_bh(). Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org> Link: https://patch.msgid.link/20260528173150.1093780-22-willy@infradead.org Reviewed-by: Joseph Qi <joseph.qi@linux.alibaba.com> Reviewed-by: Jan Kara <jack@suse.cz> Cc: ocfs2-devel@lists.linux.dev Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
2026-06-04ocfs2: Convert ocfs2_read_blocks to bh_submit()Matthew Wilcox (Oracle)
Avoid an extra indirect function call and changing the buffer refcount by using bh_submit() instead of submit_bh(). Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org> Link: https://patch.msgid.link/20260528173150.1093780-21-willy@infradead.org Reviewed-by: Joseph Qi <joseph.qi@linux.alibaba.com> Reviewed-by: Jan Kara <jack@suse.cz> Cc: ocfs2-devel@lists.linux.dev Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
2026-06-04ocfs2: Convert ocfs2_read_block to bh_submit()Matthew Wilcox (Oracle)
Avoid an extra indirect function call and changing the buffer refcount by using bh_submit() instead of submit_bh(). Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org> Link: https://patch.msgid.link/20260528173150.1093780-20-willy@infradead.org Reviewed-by: Joseph Qi <joseph.qi@linux.alibaba.com> Reviewed-by: Jan Kara <jack@suse.cz> Cc: ocfs2-devel@lists.linux.dev Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
2026-06-04ocfs2: Convert ocfs2_write_block to bh_submit()Matthew Wilcox (Oracle)
Avoid an extra indirect function call and changing the buffer refcount by using bh_submit() instead of submit_bh(). Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org> Link: https://patch.msgid.link/20260528173150.1093780-19-willy@infradead.org Reviewed-by: Joseph Qi <joseph.qi@linux.alibaba.com> Reviewed-by: Jan Kara <jack@suse.cz> Cc: ocfs2-devel@lists.linux.dev Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
2026-05-28ocfs2: reject non-inline dinodes with i_size and zero i_clustersMichael Bommarito
On a volume mounted without OCFS2_FEATURE_INCOMPAT_SPARSE_ALLOC, a non-inline regular file with non-zero i_size and zero i_clusters is structurally malformed: the extent map declares no allocated clusters yet the size header claims content exists. Keep rejecting that shape, but express it through a shared predicate so the same invariant is available to normal inode reads and online filecheck. The same zero-cluster shape is also malformed for non-inline directories. ocfs2 directory growth allocates backing storage before advancing i_size, and ocfs2_dir_foreach_blk_el() later walks until ctx->pos reaches i_size_read(inode). A forged directory dinode with a huge i_size and no clusters would repeatedly fail on holes while advancing through the claimed size. Sparse regular files remain exempt: on sparse-alloc volumes, truncate can legitimately grow i_size without allocating clusters. System inodes and inline-data dinodes also retain their separate storage rules. Mirror the check in ocfs2_filecheck_validate_inode_block() as well. filecheck reports through its own error namespace, so malformed size/cluster state is logged as a filecheck invalid-inode result rather than via ocfs2_error(), but it must not proceed into ocfs2_populate_inode(). Link: https://lore.kernel.org/20260519110404.1803902-4-michael.bommarito@gmail.com Fixes: b657c95c1108 ("ocfs2: Wrap inode block reads in a dedicated function.") Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com> Link: https://sashiko.dev/#/patchset/20260517111015.3187935-1-michael.bommarito%40gmail.com Assisted-by: Claude:claude-opus-4-7 Reviewed-by: Joseph Qi <joseph.qi@linux.alibaba.com> Cc: Mark Fasheh <mark@fasheh.com> Cc: Joel Becker <jlbec@evilplan.org> Cc: Junxiao Bi <junxiao.bi@oracle.com> Cc: Changwei Ge <gechangwei@live.cn> Cc: Jun Piao <piaojun@huawei.com> Cc: Heming Zhao <heming.zhao@suse.com> Cc: <stable@vger.kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
2026-05-28ocfs2: reject dinodes whose i_rdev disagrees with the file typeMichael Bommarito
id1.dev1.i_rdev is the device-number arm of the ocfs2_dinode id1 union. It is only meaningful for character and block device inodes. For any other user-visible file type the on-disk value must be zero. ocfs2_populate_inode() currently copies id1.dev1.i_rdev into inode->i_rdev before the S_IFMT switch decides whether the inode is a special file. A non-device inode with a non-zero i_rdev can therefore publish stale or attacker-controlled device state into the in-core inode. System inodes legitimately use other arms of the same union, so keep the cross-check restricted to non-system inodes. Factor that predicate into a helper and use it in both the normal validator and online filecheck path; filecheck reports the malformed dinode through OCFS2_FILECHECK_ERR_INVALIDINO instead of ocfs2_error(). Link: https://lore.kernel.org/20260519110404.1803902-3-michael.bommarito@gmail.com Fixes: b657c95c1108 ("ocfs2: Wrap inode block reads in a dedicated function.") Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com> Assisted-by: Claude:claude-opus-4-7 Reviewed-by: Joseph Qi <joseph.qi@linux.alibaba.com> Cc: Changwei Ge <gechangwei@live.cn> Cc: Heming Zhao <heming.zhao@suse.com> Cc: Joel Becker <jlbec@evilplan.org> Cc: Jun Piao <piaojun@huawei.com> Cc: Junxiao Bi <junxiao.bi@oracle.com> Cc: Mark Fasheh <mark@fasheh.com> Cc: <stable@vger.kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
2026-05-28ocfs2: reject dinodes with non-canonical i_mode typeMichael Bommarito
Patch series "ocfs2: harden inode validators against forged metadata", v2. This series adds three structural checks to OCFS2 dinode validation so malformed on-disk fields are rejected before ocfs2_populate_inode() copies them into the in-core inode. The checks cover: - i_mode values whose type bits do not name a canonical POSIX file type; - non-device dinodes whose id1.dev1.i_rdev field is non-zero; and - non-inline dinodes that claim non-zero i_size while i_clusters is zero, covering directories unconditionally and regular files on non-sparse volumes. The normal read path reports these through ocfs2_error(), matching the existing suballoc-slot, inline-data, chain-list, and refcount checks. The online filecheck path uses the same structural predicates but keeps its own reporting contract, returning OCFS2_FILECHECK_ERR_INVALIDINO instead of calling ocfs2_error(). This patch (of 3): ocfs2_validate_inode_block() currently accepts any non-zero i_mode value. ocfs2_populate_inode() then copies that mode verbatim into inode->i_mode and dispatches on i_mode & S_IFMT to the file/dir/symlink/special_file iops; an unrecognised type falls through to ocfs2_special_file_iops and init_special_inode(). Reject dinodes whose type bits do not name one of the seven canonical POSIX file types. Use fs_umode_to_ftype(), the same generic file-type conversion helper OCFS2 already uses for directory entries, so the accepted inode type set matches the kernel file-type vocabulary instead of open-coding a local switch. Apply the same structural check to the online filecheck read path. filecheck keeps its own error namespace, so it reports malformed i_mode through the filecheck logger and OCFS2_FILECHECK_ERR_INVALIDINO instead of calling ocfs2_error(), but it must not allow a malformed dinode to proceed into ocfs2_populate_inode(). Link: https://lore.kernel.org/20260519110404.1803902-1-michael.bommarito@gmail.com Link: https://lore.kernel.org/20260519110404.1803902-2-michael.bommarito@gmail.com Fixes: b657c95c1108 ("ocfs2: Wrap inode block reads in a dedicated function.") Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com> Link: https://sashiko.dev/#/patchset/20260517111015.3187935-1-michael.bommarito%40gmail.com Assisted-by: Claude:claude-opus-4-7 Reviewed-by: Joseph Qi <joseph.qi@linux.alibaba.com> Cc: Changwei Ge <gechangwei@live.cn> Cc: Heming Zhao <heming.zhao@suse.com> Cc: Joel Becker <jlbec@evilplan.org> Cc: Jun Piao <piaojun@huawei.com> Cc: Junxiao Bi <junxiao.bi@oracle.com> Cc: Mark Fasheh <mark@fasheh.com> Cc: <stable@vger.kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
2026-05-28ocfs2: kill osb->system_file_mutex lockTetsuo Handa
Commit 43b10a20372d ("ocfs2: avoid system inode ref confusion by adding mutex lock") tried to avoid a refcount leak caused by allowing multiple threads to call igrab(inode). But addition of osb->system_file_mutex made locking dependency complicated and is causing lockdep to warn about possibility of AB-BA deadlock. Since _ocfs2_get_system_file_inode() returns the same inode for the same input arguments, we don't need to serialize _ocfs2_get_system_file_inode(). What we need to make sure is that igrab(inode) is called for only once(). Therefore, replace osb->system_file_mutex with cmpxchg()-based locking. Link: https://lore.kernel.org/fea8d1fd-afb0-4302-a560-c202e2ef7afd@I-love.SAKURA.ne.jp Fixes: 43b10a20372d ("ocfs2: avoid system inode ref confusion by adding mutex lock") Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> Reviewed-by: Heming Zhao <heming.zhao@suse.com> Acked-by: Joseph Qi <joseph.qi@linux.alibaba.com> Cc: Mark Fasheh <mark@fasheh.com> Cc: Joel Becker <jlbec@evilplan.org> Cc: Junxiao Bi <junxiao.bi@oracle.com> Cc: Changwei Ge <gechangwei@live.cn> Cc: Jun Piao <piaojun@huawei.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
2026-05-28ocfs2: validate inline xattr header before reflinking inline xattrsZhengYuan Huang
[BUG] A corrupt inline xattr header can make ocfs2_reflink_xattr_inline() lock, copy, and reflink xattr state from an unchecked ibody xattr header. [CAUSE] The inline reflink path still trusted di->i_xattr_inline_size to compute header_off, xh, and new_xh before handing the source header to the reflink allocator and copy logic. [FIX] Validate the source inode's inline xattr header with the shared helper first, then derive the reflink copy offsets from the validated inline size/header. This keeps the reflink path from traversing corrupt ibody xattr geometry. Link: https://lore.kernel.org/20260508085914.61647-6-gality369@gmail.com Signed-off-by: ZhengYuan Huang <gality369@gmail.com> Reviewed-by: Joseph Qi <joseph.qi@linux.alibaba.com> Cc: Changwei Ge <gechangwei@live.cn> Cc: Heming Zhao <heming.zhao@suse.com> Cc: Jia-Ju Bai <baijiaju1990@gmail.com> Cc: Joel Becker <jlbec@evilplan.org> Cc: Jun Piao <piaojun@huawei.com> Cc: Junxiao Bi <junxiao.bi@oracle.com> Cc: Mark Fasheh <mark@fasheh.com> Cc: Zixuan Fu <r33s3n6@gmail.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
2026-05-28ocfs2: validate inline xattr header before inline refcount attachZhengYuan Huang
[BUG] A corrupt inline xattr header can make ocfs2_xattr_inline_attach_refcount() feed an unchecked header into the refcount-attachment walk for inline xattr values. [CAUSE] The inline refcount-attach path still derived the header directly from di->i_xattr_inline_size and then passed it to code that iterates xh_count and xattr entries. [FIX] Use the shared ibody header helper before attaching refcounts to inline xattr values so corrupt header geometry is rejected with -EFSCORRUPTED instead of being traversed. Link: https://lore.kernel.org/20260508085914.61647-5-gality369@gmail.com Signed-off-by: ZhengYuan Huang <gality369@gmail.com> Reviewed-by: Joseph Qi <joseph.qi@linux.alibaba.com> Cc: Changwei Ge <gechangwei@live.cn> Cc: Heming Zhao <heming.zhao@suse.com> Cc: Jia-Ju Bai <baijiaju1990@gmail.com> Cc: Joel Becker <jlbec@evilplan.org> Cc: Jun Piao <piaojun@huawei.com> Cc: Junxiao Bi <junxiao.bi@oracle.com> Cc: Mark Fasheh <mark@fasheh.com> Cc: Zixuan Fu <r33s3n6@gmail.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
2026-05-28ocfs2: validate inline xattr header before ibody removeZhengYuan Huang
[BUG] A corrupt inline xattr header can make ocfs2_xattr_ibody_remove() pass an unchecked header into ocfs2_remove_value_outside() during inode xattr teardown. [CAUSE] ocfs2_xattr_ibody_remove() still rebuilt the ibody xattr header directly from di->i_xattr_inline_size and then handed it to code that iterates xh_count and entry geometry. [FIX] Validate the inline xattr header with the shared helper before handing it to the outside-value removal path, and propagate -EFSCORRUPTED on bad metadata instead of traversing the unchecked header. Link: https://lore.kernel.org/20260508085914.61647-4-gality369@gmail.com Signed-off-by: ZhengYuan Huang <gality369@gmail.com> Reviewed-by: Joseph Qi <joseph.qi@linux.alibaba.com> Cc: Changwei Ge <gechangwei@live.cn> Cc: Heming Zhao <heming.zhao@suse.com> Cc: Jia-Ju Bai <baijiaju1990@gmail.com> Cc: Joel Becker <jlbec@evilplan.org> Cc: Jun Piao <piaojun@huawei.com> Cc: Junxiao Bi <junxiao.bi@oracle.com> Cc: Mark Fasheh <mark@fasheh.com> Cc: Zixuan Fu <r33s3n6@gmail.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>