Re: [PATCH/RFC] btrfs: fix folio lock leak in writepage_delalloc() for folios dirtied behind btrfs' back
Qu Wenruo <[email protected]> Wed, 22 Jul 2026 06:37:49 +0930
| Newsgroups | org.kernel.vger.linux-btrfs,org.kernel.vger.kvm,org.kernel.vger.linux-kernel,org.kernel.vger.linux-s390 |
|---|---|
| Message-ID | <[email protected]> |
在 2026/7/22 04:41, Christian Borntraeger 写道:
> A folio can carry the folio-level dirty flag while its btrfs subpage
> dirty bitmap is empty: btrfs data mappings use filemap_dirty_folio(),
> so a generic folio_mark_dirty() call sets only the folio flag and the
> xarray tag, without setting any subpage dirty bit and without a
> delalloc reservation. The typical source is set_page_dirty_lock() on
> a GUP pin,
Shouldn't such folio got its ->page_mkwrite() callback get called first?
> e.g. the s390 KVM irq adapter path
> (adapter_indicators_set()) which pins guest indicator pages living in
> a file-backed guest RAM file, sets a bit and marks the page dirty.
Thus I think this is a bigger problem for S390.
>
> When writeback then picks up such a folio, writepage_delalloc()
> copies the empty subpage dirty bitmap into
> bio_ctrl->submit_bitmap, sets up no range locks (nr_locked stays 0),
> finds no delalloc range, and finally hits
>
> if (bitmap_empty(bio_ctrl->submit_bitmap, blocks_per_folio)) {
> wbc->nr_to_write -= delalloc_to_write;
> return 1;
> }
>
> which is meant for "all dirty ranges were submitted asynchronously,
> the async paths own the folio unlock". But nothing was submitted at
> all, so extent_writepage() returns without anybody ever unlocking the
> folio. The folio stays locked forever and every subsequent locker
> (page faults through btrfs_page_mkwrite(), other flushers, delalloc
> space reclaim which then parks holding fs_info->delalloc_root_mutex,
> syncfs, ...) blocks in D state.
>
> This was debugged from a crash dump of a hung s390 KVM host: a KVM
> guest with its RAM backed by a file on btrfs (zstd compression),
> where a 64-page (256K) large data folio of the guest RAM file was
> found locked and dirty, with an empty subpage dirty bitmap,
> nr_locked == 0, no PG_writeback set and no outstanding block I/O,
> with two vCPU threads, the irqfd worker, two flusher workers,
> khugepaged and syncfs all queued behind it.
>
> Small folios are not affected because
> btrfs_copy_subpage_dirty_bitmap() unconditionally reports bit 0 set
> for single-block folios.
Unfortunately this means btrfs can get a dirty folio that is dirtied
without notifying the fs.
This will trigger a lot of other warnings, e.g. space reservation problems.
Furthermore, such dirtying folio without notifying the fs behavior can
also lead to problems in other fses.
IIRC ext4 will give warning for such cases too.
So I do not think this is the correct fix, but something went totally
wrong in the S390 GUP behavior that allows a fs folio to be marked dirty
without calling page_mkwrite().
Thanks,
Qu