Skip to main content

starnix_modules_zram/
lib.rs

1// Copyright 2023 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#![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        // This value isn't entirely correct because we're still counting metadata and other
111        // non-fragmentation usage.
112        let compr_data_size = compressed_storage_bytes - compressed_fragmentation_bytes;
113        let mem_used_total = compressed_storage_bytes;
114        // The remaining values are not yet available from Zircon.
115        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}