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.register_device_with_dir(
61 kernel,
62 "zram0".into(),
63 DeviceMetadata::new("zram0".into(), DeviceId::new(ZRAM_MAJOR, 0), DeviceMode::Block),
64 registry.objects.virtual_block_class(),
65 |device, dir| build_zram_device_directory(device, zram_device_clone, dir),
66 zram_device,
67 )?;
68 Ok(())
69}
70
71fn build_zram_device_directory(
72 device: &Device,
73 zram_device: ZramDevice,
74 dir: &SimpleDirectoryMutator,
75) {
76 let block_info = Arc::downgrade(&zram_device.kernel_stats) as Weak<dyn BlockDeviceInfo>;
77 build_block_device_directory(device, block_info, dir);
78 dir.entry(
79 "idle",
80 StubEmptyFile::new_node(bug_ref!("https://fxbug.dev/322892951")),
81 mode!(IFREG, 0o664),
82 );
83 dir.entry("mm_stat", MmStatFile::new_node(zram_device), mode!(IFREG, 0o444));
84}
85
86#[derive(Clone)]
87struct MmStatFile {
88 device: ZramDevice,
89}
90impl MmStatFile {
91 pub fn new_node(device: ZramDevice) -> impl FsNodeOps {
92 DynamicFile::new_node(Self { device })
93 }
94}
95impl DynamicFileSource for MmStatFile {
96 fn generate(
97 &self,
98 _current_task: &CurrentTask,
99 sink: &mut DynamicFileBuf,
100 ) -> Result<(), Errno> {
101 let stats = self.device.get_stats()?;
102
103 let compressed_storage_bytes = stats.compressed_storage_bytes.unwrap_or_default();
104 let compressed_fragmentation_bytes =
105 stats.compressed_fragmentation_bytes.unwrap_or_default();
106
107 let orig_data_size = stats.uncompressed_storage_bytes.unwrap_or_default();
108 let compr_data_size = compressed_storage_bytes - compressed_fragmentation_bytes;
111 let mem_used_total = compressed_storage_bytes;
112 let mem_limit = 0;
114 let mem_used_max = 0;
115 let same_pages = 0;
116 let pages_compacted = 0;
117 let huge_pages = 0;
118
119 writeln!(
120 sink,
121 "{orig_data_size} {compr_data_size} {mem_used_total} {mem_limit} \
122 {mem_used_max} {same_pages} {pages_compacted} {huge_pages}"
123 )?;
124 Ok(())
125 }
126}
127
128#[derive(Default)]
129struct KernelStatsWrapper(KernelStats);
130
131impl KernelStatsWrapper {
132 fn get_stats(&self) -> Result<fidl_fuchsia_kernel::MemoryStatsCompression, Errno> {
133 self.0.get().get_memory_stats_compression(zx::MonotonicInstant::INFINITE).map_err(|e| {
134 log_error!("FIDL error getting memory compression stats: {e}");
135 errno!(EIO)
136 })
137 }
138}
139
140impl BlockDeviceInfo for KernelStatsWrapper {
141 fn size(&self) -> Result<usize, Errno> {
142 Ok(self.get_stats()?.uncompressed_storage_bytes.unwrap_or_default() as usize)
143 }
144}