WARNING in ext4_journalled_invalidate_folio

Status: upstream: reported C repro on 2026/11/12 04:57
Subsystems: ext4
Labels: prio:low
[Documentation on labels]
Reported-by: syzbot+f111db4cb2acd44eb2f4@syzkaller.appspotmail.com
First crash: 1d08h, last: 16h28m
✨ AI-generated root cause summary:

When a buffered write fails partially (e.g. short copy due to user page fault) on an ext4 inode in data=journal mode with blocksize < PAGE_SIZE, ext4_journalled_write_end() invokes ext4_truncate_failed_write() to discard blocks allocated past inode->i_size. In data=journal mode, buffers attached to a folio straddling inode->i_size that are undergoing transaction commit cannot be invalidated immediately by jbd2_journal_invalidate_folio() and return -EBUSY. While the normal truncate path (ext4_truncate_down()) calls ext4_wait_for_tail_page_commit() to wait for the committing transaction before truncating the page cache, ext4_truncate_failed_write() directly calls truncate_inode_pages(), causing ext4_journalled_invalidate_folio() to encounter -EBUSY and trigger a WARN_ON.

▶ ▼ ✨ Full AI root cause analysis
Based on kernel commit 067c5c24cef2:

Root Cause Analysis

1. Relevant Functions, Structs, and Files

  • Files:
    • fs/ext4/truncate.h: Defines ext4_truncate_failed_write().
    • fs/ext4/inode.c: Defines ext4_journalled_write_end(), ext4_journalled_invalidate_folio(), __ext4_journalled_invalidate_folio(), and ext4_wait_for_tail_page_commit().
    • fs/jbd2/transaction.c: Defines jbd2_journal_invalidate_folio() and journal_unmap_buffer().
    • mm/truncate.c: Implements truncate_inode_pages_range(), truncate_inode_partial_folio(), and folio_invalidate().
  • Structures and Fields:
    • struct folio: Folio straddling EOF / inode->i_size.
    • struct buffer_head & struct journal_head: Buffer and journal metadata heads attached to the folio.
    • journal_t: JBD2 journal (journal->j_committing_transaction, journal->j_running_transaction).
    • transaction_t: Current committing transaction (jh->b_transaction == journal->j_committing_transaction).
    • struct address_space_operations: ext4_journalled_aops.invalidate_folio.

2. Triggering Mechanism and Invariant Violation

  1. Triggering Sequence:

    • A file on an ext4 filesystem configured in data=journal mode (ext4_should_journal_data(inode) == true) with a sub-page block size (blocksize < PAGE_SIZE, e.g., 1KB blocks with 4KB pages) undergoes an extending buffered write (pwritev -> generic_perform_write()).
    • ext4_write_begin() instantiates and allocates new disk blocks beyond the existing inode->i_size.
    • The user-space copy operation then experiences a fault or short copy (copied < len, e.g., page fault at CR2 = 0x20000000d000).
    • Execution reaches ext4_journalled_write_end() (fs/ext4/inode.c):
      • The journalled buffers are zeroed and marked dirty via write_end_fn() -> ext4_dirty_journalled_data().
      • The inode size is updated to pos + copied via ext4_update_inode_size(), leaving inode->i_size unaligned with the page boundary (straddling the folio).
      • The inode is added to the orphan list (ext4_orphan_add()), and the transaction handle is stopped via ext4_journal_stop(handle).
      • Because blocks were allocated past the new inode->i_size (pos + len > inode->i_size), ext4_journalled_write_end() calls ext4_truncate_failed_write(inode) to clean up unwritten blocks.
  2. The Invariant Violation:

    • In JBD2, when invalidating a partial folio (partial_page == (offset || length < folio_size(folio))), any buffer_head undergoing commit (jh->b_transaction == journal->j_committing_transaction) cannot be discarded or unmapped immediately because its contents are actively being written to the journal.
    • journal_unmap_buffer() (fs/jbd2/transaction.c:2406-2415) explicitly enforces this rule:
      if (partial_page) {
          ...
          return -EBUSY;
      }
      
      Callers invalidating partial folios in data=journal mode must wait for the committing transaction to complete and then retry.
    • Because VFS a_ops->invalidate_folio() returns void, the page cache truncation code (truncate_inode_partial_folio()) cannot handle or retry -EBUSY.
    • In the standard truncate path (ext4_truncate_down(), fs/ext4/inode.c:6974), ext4 explicitly satisfies this requirement before calling truncate_pagecache():
      if (ext4_should_journal_data(inode))
          ext4_wait_for_tail_page_commit(inode);
      
    • However, ext4_truncate_failed_write() (fs/ext4/truncate.h:12-24) lacks this check:
      static inline void ext4_truncate_failed_write(struct inode *inode)
      {
          struct address_space *mapping = inode->i_mapping;
      
          filemap_invalidate_lock(mapping);
          truncate_inode_pages(mapping, inode->i_size);
          ext4_truncate(inode);
          filemap_invalidate_unlock(mapping);
      }
      
      It directly calls truncate_inode_pages(mapping, inode->i_size) without calling ext4_wait_for_tail_page_commit(inode).
  3. Manifestation:

    • truncate_inode_pages() calls truncate_inode_partial_folio(), which calls folio_invalidate(folio, offset, length), invoking ext4_journalled_invalidate_folio().
    • __ext4_journalled_invalidate_folio() calls jbd2_journal_invalidate_folio().
    • Because the buffer is still tied to journal->j_committing_transaction and partial_page is true, journal_unmap_buffer() returns -EBUSY (RBX = 0xfffffff0).
    • ext4_journalled_invalidate_folio() checks the return code and encounters -EBUSY < 0, triggering the warning at line 3561:
      WARN_ON(__ext4_journalled_invalidate_folio(folio, offset, length) < 0);
      
▶ ▼ ✨ AI Jobs (1)
ID Workflow Result Correct Bug Created Started Finished Revision
3d0d86ea assessment-security DenialOfService: ✅ Exploitable: ❌ FilesystemTrigger: ❌ FuzzingArtifact: ❌ MemoryCorruption: ❌ NetworkNeedsSetup: ❌ NetworkTrigger: ❌ PeripheralTrigger: ❌ RemoteTrigger: ❌ Unprivileged: ❌ UserNamespace: ❌ VMGuestTrigger: ❌ VMHostTrigger: ❌ ❓ WARNING in ext4_journalled_invalidate_folio 2026/11/11 21:19 2026/11/11 21:19 2026/11/11 22:01 8d68b303
▶ ▼ Discussions (3)
Title Replies (including bot) Last reply
[PATCH] ext4: wait for tail page commit in ext4_truncate_failed_write() 2 (2) 2026/11/12 13:02
[PATCH] ext4: wait for tail page commit before truncating a failed write 2 (3) 2026/11/12 12:11
[syzbot] [ext4?] WARNING in ext4_journalled_invalidate_folio 0 (1) 2026/11/12 04:57

Sample crash report:
------------[ cut here ]------------
__ext4_journalled_invalidate_folio(folio, offset, length) < 0
WARNING: fs/ext4/inode.c:3561 at ext4_journalled_invalidate_folio+0x4a/0x50 fs/ext4/inode.c:3561, CPU#0: syz.0.17/5572
Modules linked in:
CPU: 0 UID: 0 PID: 5572 Comm: syz.0.17 Not tainted syzkaller #0 PREEMPT(full) 
Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.3-debian-1.16.3-2 04/01/2014
RIP: 0010:ext4_journalled_invalidate_folio+0x4a/0x50 fs/ext4/inode.c:3561
Code: e8 3b 06 00 00 89 c3 31 ff 89 c6 e8 00 70 2a ff 85 db 78 10 e8 e7 6a 2a ff 5b 41 5e 41 5f e9 0d 23 6d 09 cc e8 d7 6a 2a ff 90 <0f> 0b 90 eb ea 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90
RSP: 0018:ffffc900021f7240 EFLAGS: 00010293
RAX: ffffffff829ec759 RBX: 00000000fffffff0 RCX: ffff888033d3cb00
RDX: 0000000000000000 RSI: 00000000fffffff0 RDI: 0000000000000000
RBP: 000000000006d300 R08: ffff888013b5a467 R09: 1ffff1100276b48c
R10: dffffc0000000000 R11: ffffed100276b48d R12: ffffea00011f6798
R13: dffffc0000000000 R14: 0000000000000300 R15: ffffea00011f6780
FS:  00007f91140b36c0(0000) GS:ffff88808a9f9000(0000) knlGS:0000000000000000
CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 0000200000076000 CR3: 000000004039c000 CR4: 0000000000352ef0
Call Trace:
 <TASK>
 folio_invalidate mm/truncate.c:140 [inline]
 truncate_inode_partial_folio+0x70b/0xec0 mm/truncate.c:261
 truncate_inode_pages_range+0x5f0/0xc10 mm/truncate.c:460
 ext4_truncate_failed_write fs/ext4/truncate.h:21 [inline]
 ext4_journalled_write_end+0x99f/0xd20 fs/ext4/inode.c:1726
 generic_perform_write+0x612/0x8e0 mm/filemap.c:4413
 ext4_buffered_write_iter+0x139/0x540 fs/ext4/file.c:372
 ext4_file_write_iter+0xae4/0x1cd0 fs/ext4/file.c:-1
 aio_write+0x5cc/0x870 fs/aio.c:1697
 __io_submit_one fs/aio.c:-1 [inline]
 io_submit_one+0x798/0x13d0 fs/aio.c:2121
 __do_sys_io_submit fs/aio.c:2180 [inline]
 __se_sys_io_submit+0x195/0x340 fs/aio.c:2150
 do_syscall_x64 arch/x86/entry/syscall_64.c:61 [inline]
 do_syscall_64+0x16a/0x530 arch/x86/entry/syscall_64.c:89
 entry_SYSCALL_64_after_hwframe+0x77/0x7f
RIP: 0033:0x7f91131a8fd9
Code: ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 c7 c1 e8 ff ff ff f7 d8 64 89 01 48
RSP: 002b:00007f91140b3028 EFLAGS: 00000246 ORIG_RAX: 00000000000000d1
RAX: ffffffffffffffda RBX: 00007f9113425fa0 RCX: 00007f91131a8fd9
RDX: 0000200000008c80 RSI: 000000000000003b RDI: 00007f911408a000
RBP: 00007f9113237fed R08: 0000000000000000 R09: 0000000000000000
R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000
R13: 00007f9113426038 R14: 00007f9113425fa0 R15: 00007ffe99a17598
 </TASK>

Crashes (14):
Time Kernel Commit Syzkaller Config Log Report Syz repro C repro VM info Assets (help?) Manager Title
2026/11/12 08:47 upstream 79eb6679ef6a 8d68b303 .config console log report syz / log C [disk image (non-bootable)] [vmlinux] [kernel image] [mounted in repro (clean fs)] ci-snapshot-upstream-root WARNING in ext4_journalled_invalidate_folio
2026/11/12 04:56 git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux.git for-kernelci 58c1eb84e977 8d68b303 .config console log report syz / log C [disk image] [vmlinux] [kernel image] [mounted in repro (clean fs)] ci-upstream-gce-arm64 WARNING in ext4_journalled_invalidate_folio
2026/11/12 07:05 upstream 79eb6679ef6a 8d68b303 .config console log report info [disk image] [vmlinux] [kernel image] ci-upstream-kasan-gce-root WARNING in ext4_journalled_invalidate_folio
2026/11/12 13:46 upstream 9d66f26fefac 5c462c66 .config console log report [disk image (non-bootable)] [vmlinux] [kernel image] ci-snapshot-upstream-root WARNING in ext4_journalled_invalidate_folio
2026/11/12 05:36 upstream 79eb6679ef6a 8d68b303 .config console log report [disk image (non-bootable)] [vmlinux] [kernel image] ci-snapshot-upstream-root WARNING in ext4_journalled_invalidate_folio
2026/11/12 05:36 upstream 79eb6679ef6a 8d68b303 .config console log report [disk image (non-bootable)] [vmlinux] [kernel image] ci-snapshot-upstream-root WARNING in ext4_journalled_invalidate_folio
2026/11/12 04:50 upstream 79eb6679ef6a 8d68b303 .config console log report [disk image (non-bootable)] [vmlinux] [kernel image] ci-snapshot-upstream-root WARNING in ext4_journalled_invalidate_folio
2026/11/12 02:55 upstream 79eb6679ef6a 8d68b303 .config console log report [disk image (non-bootable)] [vmlinux] [kernel image] ci-snapshot-upstream-root WARNING in ext4_journalled_invalidate_folio
2026/11/11 21:26 upstream 067c5c24cef2 e56a968c .config console log report [disk image (non-bootable)] [vmlinux] [kernel image] ci-snapshot-upstream-root WARNING in ext4_journalled_invalidate_folio
2026/11/11 21:25 upstream 067c5c24cef2 e56a968c .config console log report [disk image (non-bootable)] [vmlinux] [kernel image] ci-snapshot-upstream-root WARNING in ext4_journalled_invalidate_folio
2026/11/11 21:23 upstream 067c5c24cef2 e56a968c .config console log report [disk image (non-bootable)] [vmlinux] [kernel image] ci-snapshot-upstream-root WARNING in ext4_journalled_invalidate_folio
2026/11/11 21:22 upstream 067c5c24cef2 e56a968c .config console log report [disk image (non-bootable)] [vmlinux] [kernel image] ci-snapshot-upstream-root WARNING in ext4_journalled_invalidate_folio
2026/11/11 21:19 upstream 067c5c24cef2 e56a968c .config console log report [disk image (non-bootable)] [vmlinux] [kernel image] ci-snapshot-upstream-root WARNING in ext4_journalled_invalidate_folio
2026/11/12 02:50 git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux.git for-kernelci 58c1eb84e977 8d68b303 .config console log report info [disk image] [vmlinux] [kernel image] ci-upstream-gce-arm64 WARNING in ext4_journalled_invalidate_folio
* Struck through repros no longer work on HEAD.