starnix_modules_zram/
lib.rs1#![recursion_limit = "256"]
6
7use starnix_core::device::kobject::{Device, DeviceMetadata};
8use starnix_core::device::{DeviceMode, DeviceOps};
9use starnix_core::fs::sysfs::{BlockDeviceInfo, build_block_device_directory};
10use starnix_core::task::{CurrentTask, Kernel, KernelStats};
11use starnix_core::vfs::pseudo::dynamic_file::{DynamicFile, DynamicFileBuf, DynamicFileSource};
12use starnix_core::vfs::pseudo::simple_directory::SimpleDirectoryMutator;
13use starnix_core::vfs::pseudo::stub_empty_file::StubEmptyFile;
14use starnix_core::vfs::{
15 FileOps, FsNodeOps, NamespaceNode, fileops_impl_dataless, fileops_impl_noop_sync,
16 fileops_impl_seekless,
17};
18use starnix_logging::{bug_ref, log_error};
19
20use starnix_uapi::device_id::{DeviceId, ZRAM_MAJOR};
21use starnix_uapi::errno;
22use starnix_uapi::errors::Errno;
23use starnix_uapi::file_mode::mode;
24use starnix_uapi::open_flags::OpenFlags;
25use std::sync::{Arc, Weak};
26
27#[derive(Default, Clone)]
28pub struct ZramDevice {
29 kernel_stats: Arc<KernelStatsWrapper>,
30}
31
32impl ZramDevice {
33 fn get_stats(&self) -> Result<fidl_fuchsia_kernel::MemoryStatsCompression, Errno> {
34 self.kernel_stats.get_stats()
35 }
36}
37
38impl DeviceOps for ZramDevice {
39 fn open(
40 &self,
41 _current_task: &CurrentTask,
42 _id: DeviceId,
43 _node: &NamespaceNode,
44 _flags: OpenFlags,
45 ) -> Result<Box<dyn FileOps>, Errno> {
46 Ok(Box::new(self.clone()))
47 }
48}
49
50impl FileOps for ZramDevice {
51 fileops_impl_seekless!();
52 fileops_impl_dataless!();
53 fileops_impl_noop_sync!();
54}
55
56pub fn zram_device_init(kernel: &Kernel) -> Result<(), Errno> {
57 let zram_device = ZramDevice::default();
58 let zram_device_clone = zram_device.clone();
59 let registry = &kernel.device_registry;
60 registry.add_device_with_dir(
61 kernel,
62 "zram0".into(),
63 DeviceMetadata::new("zram0".into(), DeviceId::new(ZRAM_MAJOR, 0), DeviceMode::Block),
64 None,
65 registry.objects.block_class(),
66 |device, dir| build_zram_device_directory(device, zram_device_clone, dir),
67 zram_device,
68 );
69 Ok(())
70}
71
72fn build_zram_device_directory(
73 device: &Device,
74 zram_device: ZramDevice,
75 dir: &SimpleDirectoryMutator,
76) {
77 let block_info = Arc::downgrade(&zram_device.kernel_stats) as Weak<dyn BlockDeviceInfo>;
78 build_block_device_directory(device, block_info, dir);
79 dir.entry(
80 "idle",
81 StubEmptyFile::new_node(bug_ref!("https://fxbug.dev/322892951")),
82 mode!(IFREG, 0o664),
83 );
84 for name in ["backing_dev", "recomp_algorithm", "recompress"] {
85 dir.entry(
86 name,
87 StubEmptyFile::new_node(bug_ref!("https://fxbug.dev/452096300")),
88 mode!(IFREG, 0o444),
89 );
90 }
91 dir.entry("mm_stat", MmStatFile::new_node(zram_device), mode!(IFREG, 0o444));
92}
93
94#[derive(Clone)]
95struct MmStatFile {
96 device: ZramDevice,
97}
98impl MmStatFile {
99 pub fn new_node(device: ZramDevice) -> impl FsNodeOps {
100 DynamicFile::new_node(Self { device })
101 }
102}
103impl DynamicFileSource for MmStatFile {
104 fn generate(
105 &self,
106 _current_task: &CurrentTask,
107 sink: &mut DynamicFileBuf,
108 ) -> Result<(), Errno> {
109 let stats = self.device.get_stats()?;
110
111 let compressed_storage_bytes = stats.compressed_storage_bytes.unwrap_or_default();
112 let compressed_fragmentation_bytes =
113 stats.compressed_fragmentation_bytes.unwrap_or_default();
114
115 let orig_data_size = stats.uncompressed_storage_bytes.unwrap_or_default();
116 let compr_data_size = compressed_storage_bytes - compressed_fragmentation_bytes;
119 let mem_used_total = compressed_storage_bytes;
120 let mem_limit = 0;
122 let mem_used_max = 0;
123 let same_pages = 0;
124 let pages_compacted = 0;
125 let huge_pages = 0;
126
127 writeln!(
128 sink,
129 "{orig_data_size} {compr_data_size} {mem_used_total} {mem_limit} \
130 {mem_used_max} {same_pages} {pages_compacted} {huge_pages}"
131 )?;
132 Ok(())
133 }
134}
135
136#[derive(Default)]
137struct KernelStatsWrapper(KernelStats);
138
139impl KernelStatsWrapper {
140 fn get_stats(&self) -> Result<fidl_fuchsia_kernel::MemoryStatsCompression, Errno> {
141 self.0.get().get_memory_stats_compression(zx::MonotonicInstant::INFINITE).map_err(|e| {
142 log_error!("FIDL error getting memory compression stats: {e}");
143 errno!(EIO)
144 })
145 }
146}
147
148impl BlockDeviceInfo for KernelStatsWrapper {
149 fn size(&self) -> Result<usize, Errno> {
150 Ok(self.get_stats()?.uncompressed_storage_bytes.unwrap_or_default() as usize)
151 }
152}