Description
In the Linux kernel, the following vulnerability has been resolved:

btrfs: do not strictly require dirty metadata threshold for metadata writepages

[BUG]
There is an internal report that over 1000 processes are
waiting at the io_schedule_timeout() of balance_dirty_pages(), causing
a system hang and trigger a kernel coredump.

The kernel is v6.4 kernel based, but the root problem still applies to
any upstream kernel before v6.18.

[CAUSE]
From Jan Kara for his wisdom on the dirty page balance behavior first.

This cgroup dirty limit was what was actually playing the role here
because the cgroup had only a small amount of memory and so the dirty
limit for it was something like 16MB.

Dirty throttling is responsible for enforcing that nobody can dirty
(significantly) more dirty memory than there's dirty limit. Thus when
a task is dirtying pages it periodically enters into balance_dirty_pages()
and we let it sleep there to slow down the dirtying.

When the system is over dirty limit already (either globally or within
a cgroup of the running task), we will not let the task exit from
balance_dirty_pages() until the number of dirty pages drops below the
limit.

So in this particular case, as I already mentioned, there was a cgroup
with relatively small amount of memory and as a result with dirty limit
set at 16MB. A task from that cgroup has dirtied about 28MB worth of
pages in btrfs btree inode and these were practically the only dirty
pages in that cgroup.

So that means the only way to reduce the dirty pages of that cgroup is
to writeback the dirty pages of btrfs btree inode, and only after that
those processes can exit balance_dirty_pages().

Now back to the btrfs part, btree_writepages() is responsible for
writing back dirty btree inode pages.

The problem here is, there is a btrfs internal threshold that if the
btree inode's dirty bytes are below the 32M threshold, it will not
do any writeback.

This behavior is to batch as much metadata as possible so we won't write
back those tree blocks and then later re-COW them again for another
modification.

This internal 32MiB is higher than the existing dirty page size (28MiB),
meaning no writeback will happen, causing a deadlock between btrfs and
cgroup:

- Btrfs doesn't want to write back btree inode until more dirty pages

- Cgroup/MM doesn't want more dirty pages for btrfs btree inode
Thus any process touching that btree inode is put into sleep until
the number of dirty pages is reduced.

Thanks Jan Kara a lot for the analysis of the root cause.

[ENHANCEMENT]
Since kernel commit b55102826d7d ("btrfs: set AS_KERNEL_FILE on the
btree_inode"), btrfs btree inode pages will only be charged to the root
cgroup which should have a much larger limit than btrfs' 32MiB
threshold.
So it should not affect newer kernels.

But for all current LTS kernels, they are all affected by this problem,
and backporting the whole AS_KERNEL_FILE may not be a good idea.

Even for newer kernels I still think it's a good idea to get
rid of the internal threshold at btree_writepages(), since for most cases
cgroup/MM has a better view of full system memory usage than btrfs' fixed
threshold.

For internal callers using btrfs_btree_balance_dirty() since that
function is already doing internal threshold check, we don't need to
bother them.

But for external callers of btree_writepages(), just respect their
requests and write back whatever they want, ignoring the internal
btrfs threshold to avoid such deadlock on btree inode dirty page
balancing.
Published: 2026-02-14
Score: 5.5 Medium
EPSS: < 1% Very Low
KEV: No
Impact: Denial of Service
Action: Patch
AI Analysis

Impact

The vulnerability originates in the Btrfs filesystem’s handling of dirty metadata. An internal threshold of 32 MiB prevents Btrfs from writing back dirty btree inode pages until that limit is exceeded, while the cgroup memory controller throttles tasks to a much lower limit for small cgroups. When a task dirties more than the cgroup allows – for example 28 MiB of btree pages – the task is forced to sleep in balance_dirty_pages() awaiting a writeback that cannot occur. This deadlock causes the process to wait indefinitely, eventually leading to a kernel core dump and a system hang. The impact is a denial of service at the system level, where normal operations can be halted by a local or privileged process that triggers excessive Btrfs metadata writes.

Affected Systems

Vulnerable Linux kernels include all upstream releases from 6.4 up to but excluding 6.18, including the 6.19 release candidate series (6.19rc1 through 6.19rc7). Any system running these kernels on a filesystem using the Btrfs filesystem is affected. The issue is tied to the Linux:Linux vendor.

Risk and Exploitability

The CVSS score is 5.5, indicating moderate severity, and the EPSS score is reported as less than 1 %, implying a very low probability of exploitation under normal circumstances. The vulnerability is not listed in the CISA Known Exploited Vulnerabilities catalog. The attack vector is most likely local or privileged, as the deadlock requires a process capable of creating large Btrfs metadata writes within a constrained cgroup. No public exploit has been demonstrated, but any process that can trigger the btree_writepages() path on a small‑memory cgroup could reproduce the hang.

Generated by OpenCVE AI on April 16, 2026 at 06:48 UTC.

Remediation

No vendor fix or workaround currently provided.

OpenCVE Recommended Actions

  • Upgrade the kernel to a version that includes the patch removing the internal 32 MiB threshold (any release after 6.18 will be safe).
  • If a newer kernel cannot be installed, reduce the memory limit for the offending cgroup or move the process to a cgroup with a larger memory ceiling. This mitigates the throttling that leads to the deadlock.
  • If an immediate kernel upgrade is not possible, apply the upstream patch that replaces the internal threshold with the AS_KERNEL_FILE flag (commit b55102826d7d) or backport the relevant changes to the current kernel branch.

Generated by OpenCVE AI on April 16, 2026 at 06:48 UTC.

Tracking

Sign in to view the affected projects.

Advisories

No advisories yet.

History

Wed, 25 Mar 2026 10:45:00 +0000


Wed, 18 Mar 2026 14:30:00 +0000

Type Values Removed Values Added
Weaknesses CWE-667
CPEs cpe:2.3:o:linux:linux_kernel:6.19:rc1:*:*:*:*:*:*
cpe:2.3:o:linux:linux_kernel:6.19:rc2:*:*:*:*:*:*
cpe:2.3:o:linux:linux_kernel:6.19:rc3:*:*:*:*:*:*
cpe:2.3:o:linux:linux_kernel:6.19:rc4:*:*:*:*:*:*
cpe:2.3:o:linux:linux_kernel:6.19:rc5:*:*:*:*:*:*
cpe:2.3:o:linux:linux_kernel:6.19:rc6:*:*:*:*:*:*
cpe:2.3:o:linux:linux_kernel:6.19:rc7:*:*:*:*:*:*
Metrics cvssV3_1

{'score': 7.0, 'vector': 'CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:H'}

cvssV3_1

{'score': 5.5, 'vector': 'CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H'}


Tue, 17 Feb 2026 00:15:00 +0000

Type Values Removed Values Added
References
Metrics threat_severity

None

cvssV3_1

{'score': 7.0, 'vector': 'CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:H'}

threat_severity

Important


Sat, 14 Feb 2026 16:15:00 +0000

Type Values Removed Values Added
Description In the Linux kernel, the following vulnerability has been resolved: btrfs: do not strictly require dirty metadata threshold for metadata writepages [BUG] There is an internal report that over 1000 processes are waiting at the io_schedule_timeout() of balance_dirty_pages(), causing a system hang and trigger a kernel coredump. The kernel is v6.4 kernel based, but the root problem still applies to any upstream kernel before v6.18. [CAUSE] From Jan Kara for his wisdom on the dirty page balance behavior first. This cgroup dirty limit was what was actually playing the role here because the cgroup had only a small amount of memory and so the dirty limit for it was something like 16MB. Dirty throttling is responsible for enforcing that nobody can dirty (significantly) more dirty memory than there's dirty limit. Thus when a task is dirtying pages it periodically enters into balance_dirty_pages() and we let it sleep there to slow down the dirtying. When the system is over dirty limit already (either globally or within a cgroup of the running task), we will not let the task exit from balance_dirty_pages() until the number of dirty pages drops below the limit. So in this particular case, as I already mentioned, there was a cgroup with relatively small amount of memory and as a result with dirty limit set at 16MB. A task from that cgroup has dirtied about 28MB worth of pages in btrfs btree inode and these were practically the only dirty pages in that cgroup. So that means the only way to reduce the dirty pages of that cgroup is to writeback the dirty pages of btrfs btree inode, and only after that those processes can exit balance_dirty_pages(). Now back to the btrfs part, btree_writepages() is responsible for writing back dirty btree inode pages. The problem here is, there is a btrfs internal threshold that if the btree inode's dirty bytes are below the 32M threshold, it will not do any writeback. This behavior is to batch as much metadata as possible so we won't write back those tree blocks and then later re-COW them again for another modification. This internal 32MiB is higher than the existing dirty page size (28MiB), meaning no writeback will happen, causing a deadlock between btrfs and cgroup: - Btrfs doesn't want to write back btree inode until more dirty pages - Cgroup/MM doesn't want more dirty pages for btrfs btree inode Thus any process touching that btree inode is put into sleep until the number of dirty pages is reduced. Thanks Jan Kara a lot for the analysis of the root cause. [ENHANCEMENT] Since kernel commit b55102826d7d ("btrfs: set AS_KERNEL_FILE on the btree_inode"), btrfs btree inode pages will only be charged to the root cgroup which should have a much larger limit than btrfs' 32MiB threshold. So it should not affect newer kernels. But for all current LTS kernels, they are all affected by this problem, and backporting the whole AS_KERNEL_FILE may not be a good idea. Even for newer kernels I still think it's a good idea to get rid of the internal threshold at btree_writepages(), since for most cases cgroup/MM has a better view of full system memory usage than btrfs' fixed threshold. For internal callers using btrfs_btree_balance_dirty() since that function is already doing internal threshold check, we don't need to bother them. But for external callers of btree_writepages(), just respect their requests and write back whatever they want, ignoring the internal btrfs threshold to avoid such deadlock on btree inode dirty page balancing.
Title btrfs: do not strictly require dirty metadata threshold for metadata writepages
First Time appeared Linux
Linux linux Kernel
CPEs cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*
Vendors & Products Linux
Linux linux Kernel
References

Subscriptions

Linux Linux Kernel
cve-icon MITRE

Status: PUBLISHED

Assigner: Linux

Published:

Updated: 2026-03-25T10:20:27.832Z

Reserved: 2026-01-13T15:37:45.978Z

Link: CVE-2026-23157

cve-icon Vulnrichment

No data.

cve-icon NVD

Status : Modified

Published: 2026-02-14T16:15:55.863

Modified: 2026-03-25T11:16:19.570

Link: CVE-2026-23157

cve-icon Redhat

Severity : Important

Publid Date: 2026-02-14T00:00:00Z

Links: CVE-2026-23157 - Bugzilla

cve-icon OpenCVE Enrichment

Updated: 2026-04-16T07:00:10Z

Weaknesses