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};
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        // This value isn't entirely correct because we're still counting metadata and other
109        // non-fragmentation usage.
110        let compr_data_size = compressed_storage_bytes - compressed_fragmentation_bytes;
111        let mem_used_total = compressed_storage_bytes;
112        // The remaining values are not yet available from Zircon.
113        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}