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};
19use starnix_sync::{FileOpsCore, Locked, Unlocked};
20use starnix_uapi::device_type::{DeviceType, 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 _locked: &mut Locked<FileOpsCore>,
42 _current_task: &CurrentTask,
43 _id: DeviceType,
44 _node: &NamespaceNode,
45 _flags: OpenFlags,
46 ) -> Result<Box<dyn FileOps>, Errno> {
47 Ok(Box::new(self.clone()))
48 }
49}
50
51impl FileOps for ZramDevice {
52 fileops_impl_seekless!();
53 fileops_impl_dataless!();
54 fileops_impl_noop_sync!();
55}
56
57pub fn zram_device_init(locked: &mut Locked<Unlocked>, kernel: &Kernel) -> Result<(), Errno> {
58 let zram_device = ZramDevice::default();
59 let zram_device_clone = zram_device.clone();
60 let registry = &kernel.device_registry;
61 registry.register_device_with_dir(
62 locked,
63 kernel,
64 "zram0".into(),
65 DeviceMetadata::new("zram0".into(), DeviceType::new(ZRAM_MAJOR, 0), DeviceMode::Block),
66 registry.objects.virtual_block_class(),
67 |device, dir| build_zram_device_directory(device, zram_device_clone, dir),
68 zram_device,
69 )?;
70 Ok(())
71}
72
73fn build_zram_device_directory(
74 device: &Device,
75 zram_device: ZramDevice,
76 dir: &SimpleDirectoryMutator,
77) {
78 let block_info = Arc::downgrade(&zram_device.kernel_stats) as Weak<dyn BlockDeviceInfo>;
79 build_block_device_directory(device, block_info, dir);
80 dir.entry(
81 "idle",
82 StubEmptyFile::new_node(bug_ref!("https://fxbug.dev/322892951")),
83 mode!(IFREG, 0o664),
84 );
85 dir.entry("mm_stat", MmStatFile::new_node(zram_device), mode!(IFREG, 0o444));
86}
87
88#[derive(Clone)]
89struct MmStatFile {
90 device: ZramDevice,
91}
92impl MmStatFile {
93 pub fn new_node(device: ZramDevice) -> impl FsNodeOps {
94 DynamicFile::new_node(Self { device })
95 }
96}
97impl DynamicFileSource for MmStatFile {
98 fn generate(
99 &self,
100 _current_task: &CurrentTask,
101 sink: &mut DynamicFileBuf,
102 ) -> Result<(), Errno> {
103 let stats = self.device.get_stats()?;
104
105 let compressed_storage_bytes = stats.compressed_storage_bytes.unwrap_or_default();
106 let compressed_fragmentation_bytes =
107 stats.compressed_fragmentation_bytes.unwrap_or_default();
108
109 let orig_data_size = stats.uncompressed_storage_bytes.unwrap_or_default();
110 let compr_data_size = compressed_storage_bytes - compressed_fragmentation_bytes;
113 let mem_used_total = compressed_storage_bytes;
114 let mem_limit = 0;
116 let mem_used_max = 0;
117 let same_pages = 0;
118 let pages_compacted = 0;
119 let huge_pages = 0;
120
121 writeln!(
122 sink,
123 "{orig_data_size} {compr_data_size} {mem_used_total} {mem_limit} \
124 {mem_used_max} {same_pages} {pages_compacted} {huge_pages}"
125 )?;
126 Ok(())
127 }
128}
129
130#[derive(Default)]
131struct KernelStatsWrapper(KernelStats);
132
133impl KernelStatsWrapper {
134 fn get_stats(&self) -> Result<fidl_fuchsia_kernel::MemoryStatsCompression, Errno> {
135 self.0.get().get_memory_stats_compression(zx::MonotonicInstant::INFINITE).map_err(|e| {
136 log_error!("FIDL error getting memory compression stats: {e}");
137 errno!(EIO)
138 })
139 }
140}
141
142impl BlockDeviceInfo for KernelStatsWrapper {
143 fn size(&self) -> Result<usize, Errno> {
144 Ok(self.get_stats()?.uncompressed_storage_bytes.unwrap_or_default() as usize)
145 }
146}