Skip to content

Commit c6808a8

Browse files
authored
fix(mm): balance page cache membership accounting (#2131)
* fix(mm): balance page cache membership accounting Track immutable file and shmem membership on each page-cache entry so removal and final cache teardown can update VM counters exactly once without upgrading an owner that is already being destroyed. Keep dirty, writeback, and unevictable accounting tied to the currently mapped entry. Revalidate entry identity across truncate and writeback completion, and require the legacy reclaimer to claim the expected physical page before submitting stale snapshots. Preserve the existing PageEntry layout, use vacant-only insertion, and align tmpfs construction with immutable shmem classification. Add a debugfs accounting selftest and dunitest coverage for membership, inflight teardown, late completion, aggregate VM wiring, and layout stability. Validated with make fmt, make kernel, the page-cache accounting dunitest, FUSE core and extended suites, repeated non-DAX VirtioFS mount/read/unmount beyond guest RAM, and CubeSandbox master/candidate performance checks. Signed-off-by: longjin <longjin@dragonos.org>
1 parent 56acd9b commit c6808a8

6 files changed

Lines changed: 661 additions & 101 deletions

File tree

kernel/src/debug/page_cache.rs

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ use crate::{
1414
#[derive(Debug)]
1515
struct PageCacheCompletionSelftestCallback;
1616

17+
#[derive(Debug)]
18+
struct PageCacheAccountingSelftestCallback;
19+
1720
impl KernFSCallback for PageCacheCompletionSelftestCallback {
1821
fn open(&self, mut data: KernCallbackData) -> Result<(), SystemError> {
1922
let report = crate::filesystem::page_cache::run_completion_domain_debug_selftest()?;
@@ -55,6 +58,47 @@ impl KernFSCallback for PageCacheCompletionSelftestCallback {
5558
}
5659
}
5760

61+
impl KernFSCallback for PageCacheAccountingSelftestCallback {
62+
fn open(&self, mut data: KernCallbackData) -> Result<(), SystemError> {
63+
let report = crate::filesystem::page_cache::run_accounting_debug_selftest()?;
64+
data.file_private_data_mut()
65+
.replace(KernFilePrivateData::DebugTextSnapshot(report));
66+
Ok(())
67+
}
68+
69+
fn read(
70+
&self,
71+
data: KernCallbackData,
72+
buf: &mut [u8],
73+
offset: usize,
74+
) -> Result<usize, SystemError> {
75+
let report: &String = match data.file_private_data() {
76+
Some(KernFilePrivateData::DebugTextSnapshot(report)) => report,
77+
_ => return Err(SystemError::EINVAL),
78+
};
79+
let bytes = report.as_bytes();
80+
if offset >= bytes.len() {
81+
return Ok(0);
82+
}
83+
let len = buf.len().min(bytes.len() - offset);
84+
buf[..len].copy_from_slice(&bytes[offset..offset + len]);
85+
Ok(len)
86+
}
87+
88+
fn write(
89+
&self,
90+
_data: KernCallbackData,
91+
_buf: &[u8],
92+
_offset: usize,
93+
) -> Result<usize, SystemError> {
94+
Err(SystemError::EPERM)
95+
}
96+
97+
fn poll(&self, _data: KernCallbackData) -> Result<PollStatus, SystemError> {
98+
Ok(PollStatus::READ)
99+
}
100+
}
101+
58102
pub fn init_debugfs_page_cache() -> Result<(), SystemError> {
59103
let debugfs = debugfs_kobj();
60104
let root = debugfs.inode().ok_or(SystemError::ENOENT)?;
@@ -71,5 +115,12 @@ pub fn init_debugfs_page_cache() -> Result<(), SystemError> {
71115
None,
72116
Some(&PageCacheCompletionSelftestCallback),
73117
)?;
118+
page_cache.add_file(
119+
"accounting_selftest".to_string(),
120+
InodeMode::S_IRUSR,
121+
Some(4096),
122+
None,
123+
Some(&PageCacheAccountingSelftestCallback),
124+
)?;
74125
Ok(())
75126
}

0 commit comments

Comments
 (0)