1use crate::file::ErofsFile;
6use fuchsia_async as fasync;
7use std::ops::Range;
8use std::sync::{Arc, Mutex, Weak};
9use zx::sys::zx_page_request_command_t::{ZX_PAGER_VMO_COMPLETE, ZX_PAGER_VMO_READ};
10
11const READAHEAD_ALIGNMENT: u64 = 128 * 1024;
12
13pub enum FileHolder {
21 Strong(Arc<ErofsFile>),
22 Weak(Weak<ErofsFile>),
23}
24
25pub struct ErofsPager {
27 pager: Arc<zx::Pager>,
28}
29
30impl ErofsPager {
31 pub fn new() -> Result<Self, zx::Status> {
33 let pager = Arc::new(zx::Pager::create(zx::PagerOptions::empty())?);
34 Ok(Self { pager })
35 }
36
37 pub fn create_vmo(
39 &self,
40 file: Weak<ErofsFile>,
41 initial_size: u64,
42 ) -> Result<(zx::Vmo, fasync::ReceiverRegistration<ErofsPacketReceiver>), zx::Status> {
43 let receiver = ErofsPacketReceiver {
44 file: Mutex::new(FileHolder::Weak(file)),
45 pager: self.pager.clone(),
46 };
47
48 let registration = fasync::EHandle::local().register_receiver(receiver);
49
50 let vmo = self
51 .pager
52 .create_vmo(
53 zx::VmoOptions::empty(),
54 fasync::EHandle::local().port(),
55 registration.key(),
56 initial_size,
57 )
58 .map_err(|e| {
59 log::error!("self.pager.create_vmo failed: {:?}", e);
60 e
61 })?;
62
63 Ok((vmo, registration))
64 }
65}
66
67pub struct ErofsPacketReceiver {
69 pub(crate) file: Mutex<FileHolder>,
70 pager: Arc<zx::Pager>,
71}
72
73impl ErofsPacketReceiver {
74 fn get_file(&self) -> Result<Arc<ErofsFile>, zx::Status> {
75 let holder = self.file.lock().unwrap();
76 match &*holder {
77 FileHolder::Strong(strong) => Ok(strong.clone()),
78 FileHolder::Weak(weak) => weak.upgrade().ok_or(zx::Status::BAD_STATE),
79 }
80 }
81
82 fn page_in(&self, range: Range<u64>) -> Result<(), zx::Status> {
83 let file = self.get_file()?;
84
85 let readahead_start = (range.start / READAHEAD_ALIGNMENT) * READAHEAD_ALIGNMENT;
87 let mut readahead_end =
88 ((range.end + READAHEAD_ALIGNMENT - 1) / READAHEAD_ALIGNMENT) * READAHEAD_ALIGNMENT;
89
90 let vmo_size = file.vmo().get_size()?;
92 readahead_end = std::cmp::min(readahead_end, vmo_size);
93
94 if readahead_end <= readahead_start {
95 return Ok(());
96 }
97
98 let len = readahead_end - readahead_start;
99
100 let mut buf = vec![0u8; len as usize];
103 let read_bytes =
104 file.fs().read_file_range(file.node(), readahead_start, &mut buf).map_err(|e| {
105 log::error!("Read EROFS file range failed: {:?}", e);
106 e.to_status()
107 })?;
108
109 if read_bytes < buf.len() {
110 buf[read_bytes..].fill(0);
111 }
112
113 let aux_vmo = zx::Vmo::create(len)?;
114 aux_vmo.write(&buf, 0)?;
115
116 self.pager.supply_pages(file.vmo(), readahead_start..readahead_end, &aux_vmo, 0)?;
117 Ok(())
118 }
119
120 fn receive_signal_packet(&self, signals: zx::SignalPacket) {
127 assert!(signals.observed().contains(zx::Signals::VMO_ZERO_CHILDREN));
128
129 let mut file_holder = self.file.lock().unwrap();
130 let strong = match &*file_holder {
131 FileHolder::Strong(strong) => strong.clone(),
132 FileHolder::Weak(_) => return,
133 };
134
135 match strong.vmo().info() {
136 Ok(info) => {
137 if info.num_children == 0 {
138 let weak = FileHolder::Weak(Arc::downgrade(&strong));
139 *file_holder = weak;
140 } else {
141 if let Err(e) = strong.register_zero_children_wait() {
143 log::error!("Failed to re-register VMO_ZERO_CHILDREN wait: {:?}", e);
144 }
145 }
146 }
147 Err(e) => {
148 log::error!("Failed to query VMO info: {:?}", e);
149 }
150 }
151 }
152
153 fn receive_pager_packet(&self, contents: zx::PagerPacket) {
154 let command = contents.command();
155 if command == ZX_PAGER_VMO_COMPLETE {
156 return;
157 }
158
159 let range = contents.range();
160 if command != ZX_PAGER_VMO_READ {
162 if let Ok(file) = self.get_file() {
163 let _ = self.pager.op_range(
164 zx::PagerOp::Fail(zx::Status::NOT_SUPPORTED),
165 file.vmo(),
166 range,
167 );
168 }
169 return;
170 }
171
172 if let Err(e) = self.page_in(range.clone()) {
173 log::error!("Page fault handler failed: {:?}", e);
174 if let Ok(file) = self.get_file() {
175 let _ = self.pager.op_range(zx::PagerOp::Fail(e), file.vmo(), range);
176 }
177 }
178 }
179}
180
181impl fasync::PacketReceiver for ErofsPacketReceiver {
182 fn receive_packet(&self, packet: zx::Packet) {
183 match packet.contents() {
184 zx::PacketContents::Pager(contents) => {
185 self.receive_pager_packet(contents);
186 }
187 zx::PacketContents::SignalOne(signals) => {
188 self.receive_signal_packet(signals);
189 }
190 _ => {}
191 }
192 }
193}