1use delivery_blob::compression::{ChunkedArchiveError, DataBuffer};
6use fuchsia_sync::Mutex;
7use mapping::{
8 DeliveryCommand, DeliveryHandler, PENDING_DELIVERY_COMMANDS_CAPACITY, PageRequest,
9 RawDeliveryCommand,
10};
11use std::ops::Range;
12use std::sync::Arc;
13use storage_ptr_slice::MutPtrByteSlice;
14use vmo_fifo::SyncSender;
15
16pub struct Verifier {
18 sender: Mutex<Option<SyncSender<RawDeliveryCommand>>>,
19}
20
21impl Verifier {
22 pub fn new(delivery_queue: zx::Vmo) -> Self {
23 let sender = if delivery_queue.get_size().unwrap_or(0) > 0 {
24 SyncSender::<RawDeliveryCommand>::new(
28 delivery_queue,
29 zx::system_get_page_size() as usize,
30 PENDING_DELIVERY_COMMANDS_CAPACITY,
31 )
32 .ok()
33 } else {
34 None
35 };
36 Self { sender: Mutex::new(sender) }
37 }
38}
39
40impl DeliveryHandler for Verifier {
41 type Request = Buffer;
42
43 fn get_page_request(self: &Arc<Self>, key: u64, original_range: Range<u64>) -> Buffer {
45 Buffer {
46 verifier: Arc::clone(self),
47 key,
48 read_range: original_range,
49 read_alignment: 0,
50 committed_len: 0,
51 delivered_len: 0,
52 data: Vec::new(),
53 child_target: None,
54 }
55 }
56
57 fn get_child_page_request(
60 self: &Arc<Self>,
61 child_key: u64,
62 child_target_offset: u64,
63 parent_byte_range: Range<u64>,
64 ) -> Buffer {
65 Buffer {
66 verifier: Arc::clone(self),
67 key: child_key,
68 read_range: parent_byte_range.clone(),
69 read_alignment: 0,
70 committed_len: 0,
71 delivered_len: 0,
72 data: Vec::new(),
73 child_target: Some(ChildTarget { child_target_offset, parent_byte_range }),
74 }
75 }
76
77 fn deliver_child_inline_tail(
80 self: &Arc<Self>,
81 parent_byte_offset: u64,
82 child_key: u64,
83 child_target_offset: u64,
84 tail_length: u32,
85 ) {
86 let mut sender = self.sender.lock();
87 if let Some(sender) = sender.as_mut() {
88 let cmd = DeliveryCommand::ChildInlineTail {
89 parent_byte_offset,
90 child_key,
91 child_target_offset,
92 tail_length,
93 };
94 let _ = sender.push(cmd.into());
95 }
96 }
97
98 fn deliver_child_sparse(
101 &self,
102 child_key: u64,
103 child_target_offset: u64,
104 child_length: u64,
105 ) -> Result<(), anyhow::Error> {
106 let mut sender = self.sender.lock();
107 if let Some(sender) = sender.as_mut() {
108 let cmd = DeliveryCommand::ChildData {
109 parent_offset: 0,
110 offset: 0,
111 length: 0,
112 child_key,
113 child_target_offset,
114 in_chunk_offset: 0,
115 child_length: child_length as u32,
116 };
117 sender.push(cmd.into())?;
118 }
119 Ok(())
120 }
121
122 fn register_blob(
124 &self,
125 key: u64,
126 merkle_leaves: &[[u8; 32]],
127 read_alignment: usize,
128 ) -> Result<(), anyhow::Error> {
129 let mut sender = self.sender.lock();
130 if let Some(sender) = sender.as_mut() {
131 let leaf_bytes: &[u8] = merkle_leaves.as_flattened();
132 let mut payload = sender.reserve_payload(leaf_bytes.len())?;
133 payload.data().copy_from_slice(leaf_bytes);
134 let cmd = DeliveryCommand::RegisterBlob {
135 key,
136 offset: payload.offset(),
137 length: leaf_bytes.len() as u32,
138 read_alignment: read_alignment as u32,
139 };
140 payload.commit(cmd.into())?;
141 }
142 Ok(())
143 }
144}
145
146struct ChildTarget {
149 child_target_offset: u64,
151 parent_byte_range: Range<u64>,
153}
154
155pub struct Buffer {
158 verifier: Arc<Verifier>,
159 key: u64,
160 read_range: Range<u64>,
161 read_alignment: usize,
164 committed_len: usize,
166 delivered_len: usize,
168 data: Vec<u8>,
169 child_target: Option<ChildTarget>,
170}
171
172impl Buffer {
173 fn deliver_chunk(&mut self, size: usize) -> Result<(), ChunkedArchiveError> {
174 let chunk_data = &self.data[self.delivered_len..self.delivered_len + size];
176 let offset = self.read_range.start + self.delivered_len as u64;
177
178 let mut sender = self.verifier.sender.lock();
179 if let Some(sender) = sender.as_mut() {
180 let page_size = zx::system_get_page_size() as usize;
181 let aligned_size = size.next_multiple_of(page_size);
182 let mut payload = sender.reserve_payload(aligned_size).map_err(|e| {
183 log::error!(e:?; "Verifier::deliver_chunk: reserve_payload failed");
184 ChunkedArchiveError::IntegrityError
185 })?;
186
187 let payload_data = payload.data();
188 payload_data.subslice_mut(0..size).copy_from_slice(chunk_data);
189 payload_data.subslice_mut(size..aligned_size).fill(0);
190 let cmd = if let Some(target) = &self.child_target {
191 let chunk_end = offset + aligned_size as u64;
192 let slice_start = std::cmp::max(offset, target.parent_byte_range.start);
193 let slice_end = std::cmp::min(chunk_end, target.parent_byte_range.end);
194 let in_chunk_offset = (slice_start - offset) as u32;
195 let child_target_offset =
196 target.child_target_offset + (slice_start - target.parent_byte_range.start);
197 let child_length = (slice_end.saturating_sub(slice_start)) as u32;
198 DeliveryCommand::ChildData {
199 parent_offset: offset,
200 offset: payload.offset(),
201 length: aligned_size as u32,
202 child_key: self.key,
203 child_target_offset,
204 in_chunk_offset,
205 child_length,
206 }
207 } else {
208 DeliveryCommand::Data {
209 key: self.key,
210 target_offset: offset,
211 length: aligned_size as u32,
212 offset: payload.offset(),
213 }
214 };
215 payload.commit(cmd.into()).map_err(|_| ChunkedArchiveError::IntegrityError)?;
216 }
217
218 self.delivered_len += size;
219 Ok(())
220 }
221}
222
223impl DataBuffer for Buffer {
224 fn range(&self) -> Range<u64> {
225 self.read_range.clone()
226 }
227
228 fn mut_ptr_slice(&mut self) -> MutPtrByteSlice<'_> {
234 assert!(!self.data.is_empty(), "prepare must be called before accessing mut_ptr_slice");
235 MutPtrByteSlice::from(&mut self.data[self.committed_len..])
236 }
237
238 fn commit(&mut self, size: usize) -> Result<(), ChunkedArchiveError> {
239 const VERIFICATION_FLUSH_THRESHOLD: usize = 96 * 1024;
240
241 self.committed_len += size;
242
243 if self.committed_len < self.data.len() {
244 let flush_threshold =
248 (VERIFICATION_FLUSH_THRESHOLD / self.read_alignment).max(1) * self.read_alignment;
249 if self.committed_len - self.delivered_len >= flush_threshold {
250 let to_deliver = ((self.committed_len - self.delivered_len) / self.read_alignment)
251 * self.read_alignment;
252 self.deliver_chunk(to_deliver)?;
253 }
254 } else if self.delivered_len < self.committed_len {
255 self.deliver_chunk(self.committed_len - self.delivered_len)?;
257 }
258
259 Ok(())
260 }
261}
262
263impl PageRequest for Buffer {
264 fn prepare(
265 &mut self,
266 read_range: Range<u64>,
267 read_alignment: usize,
268 ) -> Result<(), ChunkedArchiveError> {
269 assert!(self.data.is_empty(), "prepare must only be called once");
270 assert!(read_alignment > 0, "read_alignment must be non-zero");
271 self.read_range = read_range;
272 self.read_alignment = read_alignment;
273 let len = (self.read_range.end - self.read_range.start) as usize;
274 self.data = vec![0u8; len];
275 Ok(())
276 }
277}
278
279#[cfg(test)]
280mod tests {
281 use super::*;
282 use mapping::{DELIVERY_DATA_COMMAND, TARGET_READ_AHEAD_SIZE};
283 use test_case::test_case;
284
285 #[fuchsia::test]
286 fn test_verifier_buffer_incremental_commit() {
287 let delivery_queue = zx::Vmo::create(65536).unwrap();
288 let mut receiver = vmo_fifo::Receiver::<RawDeliveryCommand>::new(
289 delivery_queue.duplicate_handle(zx::Rights::SAME_RIGHTS).unwrap(),
290 PENDING_DELIVERY_COMMANDS_CAPACITY,
291 )
292 .unwrap();
293
294 let verifier = Arc::new(Verifier::new(delivery_queue));
295 let key = 42u64;
296
297 let mut request = verifier.get_page_request(key, 0..8192);
298 request.prepare(0..8192, TARGET_READ_AHEAD_SIZE as usize).expect("prepare");
299
300 let page1_data = vec![0xAAu8; 4096];
302 request.mut_ptr_slice().subslice_mut(0..4096).copy_from_slice(&page1_data);
303 request.commit(4096).expect("commit page 1");
304
305 assert_eq!(request.mut_ptr_slice().len(), 4096);
307 assert!(receiver.is_empty());
309
310 let page2_data = vec![0xBBu8; 4096];
312 request.mut_ptr_slice().subslice_mut(0..4096).copy_from_slice(&page2_data);
313 request.commit(4096).expect("commit page 2");
314
315 assert_eq!(request.mut_ptr_slice().len(), 0);
317
318 let msg = receiver.peek().expect("msg");
320 assert_eq!(msg.opcode, DELIVERY_DATA_COMMAND);
321 assert_eq!(msg.key, key);
322 assert_eq!(msg.length, 8192);
323 assert_eq!(msg.target_offset, 0);
324 let mut buf = vec![0u8; 8192];
325 msg.payload_slice(msg.offset, msg.length).copy_to_slice(&mut buf);
326 assert_eq!(&buf[..4096], &page1_data[..]);
327 assert_eq!(&buf[4096..], &page2_data[..]);
328 msg.pop().expect("pop msg");
329 }
330
331 #[fuchsia::test]
332 fn test_verifier_buffer_page_aligned_commits() {
333 let delivery_queue = zx::Vmo::create(65536).unwrap();
334 let mut receiver = vmo_fifo::Receiver::<RawDeliveryCommand>::new(
335 delivery_queue.duplicate_handle(zx::Rights::SAME_RIGHTS).unwrap(),
336 PENDING_DELIVERY_COMMANDS_CAPACITY,
337 )
338 .unwrap();
339
340 let verifier = Arc::new(Verifier::new(delivery_queue));
341 let key = 43u64;
342
343 let mut request = verifier.get_page_request(key, 0..5000);
344 request.prepare(0..5000, TARGET_READ_AHEAD_SIZE as usize).expect("prepare");
345
346 let data = vec![0xCCu8; 5000];
347
348 request.mut_ptr_slice().subslice_mut(0..4096).copy_from_slice(&data[..4096]);
350 request.commit(4096).expect("commit 4096 bytes");
351 assert!(receiver.is_empty());
352
353 request.mut_ptr_slice().subslice_mut(0..904).copy_from_slice(&data[4096..5000]);
355 request.commit(904).expect("commit 904 bytes");
356
357 let msg = receiver.peek().expect("msg");
359 assert_eq!(msg.target_offset, 0);
360 assert_eq!(msg.length, 8192);
361 let mut buf = vec![0u8; 8192];
362 msg.payload_slice(msg.offset, msg.length).copy_to_slice(&mut buf);
363 assert_eq!(&buf[..5000], &data[..]);
364 assert_eq!(&buf[5000..], &[0u8; 3192]);
365 msg.pop().expect("pop msg");
366 }
367
368 #[test_case(32 * 1024, 128 * 1024; "zstd_32k_read_128k")]
369 #[test_case(48 * 1024, 96 * 1024; "zstd_48k_read_96k")]
370 #[test_case(152 * 1024, 152 * 1024; "zstd_152k_read_152k")]
371 #[fuchsia::test]
372 fn test_verifier_buffer_delivery_data_size_chunking(
373 zstd_chunk_size: usize,
374 read_alignment: usize,
375 ) {
376 let total_size = read_alignment * 2;
377 let delivery_queue = zx::Vmo::create(total_size as u64 + 65536).unwrap();
378 let mut receiver = vmo_fifo::Receiver::<RawDeliveryCommand>::new(
379 delivery_queue.duplicate_handle(zx::Rights::SAME_RIGHTS).unwrap(),
380 PENDING_DELIVERY_COMMANDS_CAPACITY,
381 )
382 .unwrap();
383
384 let verifier = Arc::new(Verifier::new(delivery_queue));
385 let key = 44u64;
386
387 let mut request = verifier.get_page_request(key, 0..total_size as u64);
388 request.prepare(0..total_size as u64, read_alignment).expect("prepare");
389
390 let chunk = vec![0x55u8; zstd_chunk_size];
391 let chunks_per_read = read_alignment / zstd_chunk_size;
392
393 for _ in 0..(chunks_per_read - 1) {
395 request.mut_ptr_slice().subslice_mut(0..zstd_chunk_size).copy_from_slice(&chunk);
396 request.commit(zstd_chunk_size).expect("commit");
397 }
398 assert!(receiver.is_empty());
399
400 request.mut_ptr_slice().subslice_mut(0..zstd_chunk_size).copy_from_slice(&chunk);
402 request.commit(zstd_chunk_size).expect("commit");
403
404 let msg1 = receiver.peek().expect("msg1");
406 assert_eq!(msg1.target_offset, 0);
407 assert_eq!(msg1.length, read_alignment as u32);
408 msg1.pop().expect("pop msg1");
409
410 for _ in 0..chunks_per_read {
412 request.mut_ptr_slice().subslice_mut(0..zstd_chunk_size).copy_from_slice(&chunk);
413 request.commit(zstd_chunk_size).expect("commit");
414 }
415
416 let msg2 = receiver.peek().expect("msg2");
418 assert_eq!(msg2.target_offset, read_alignment as u64);
419 assert_eq!(msg2.length, read_alignment as u32);
420 msg2.pop().expect("pop msg2");
421 }
422
423 #[fuchsia::test]
424 #[should_panic(expected = "prepare must only be called once")]
425 fn test_verifier_buffer_prepare_multiple_times_panics() {
426 let delivery_queue = zx::Vmo::create(4096).unwrap();
427 let verifier = Arc::new(Verifier::new(delivery_queue));
428
429 let key = 46u64;
430 let mut request = verifier.get_page_request(key, 0..8192);
431 request.prepare(0..4096, TARGET_READ_AHEAD_SIZE as usize).expect("first prepare");
432 let _ = request.prepare(0..8192, TARGET_READ_AHEAD_SIZE as usize);
433 }
434
435 #[fuchsia::test]
436 fn test_verifier_buffer_supplies_pages_via_delivery_receiver() {
437 let pager = Arc::new(zx::Pager::create(zx::PagerOptions::empty()).unwrap());
438 let port = zx::Port::create();
439 let key = 44u64;
440 let paged_vmo = pager.create_vmo(zx::VmoOptions::empty(), &port, key, 8192).unwrap();
441
442 let delivery_queue = zx::Vmo::create(65536).unwrap();
443 let vmo_provider = Arc::new(blob_pager_and_verifier::TestVmoProvider::new(
444 pager.clone(),
445 delivery_queue.duplicate_handle(zx::Rights::SAME_RIGHTS).unwrap(),
446 ));
447 vmo_provider
448 .register_vmo(key, paged_vmo.duplicate_handle(zx::Rights::SAME_RIGHTS).unwrap());
449 let receiver = vmo_fifo::Receiver::<RawDeliveryCommand>::new(
450 delivery_queue.duplicate_handle(zx::Rights::SAME_RIGHTS).unwrap(),
451 PENDING_DELIVERY_COMMANDS_CAPACITY,
452 )
453 .unwrap();
454 let _processor = blob_pager_and_verifier::DeliveryQueueProcessor::spawn(
455 receiver,
456 vmo_provider,
457 delivery_queue.duplicate_handle(zx::Rights::SAME_RIGHTS).unwrap(),
458 )
459 .unwrap();
460
461 let verifier = Arc::new(Verifier::new(delivery_queue));
462 let mut request = verifier.get_page_request(key, 0..8192);
463 request.prepare(0..8192, TARGET_READ_AHEAD_SIZE as usize).expect("prepare");
464
465 let page1_data = vec![0xAAu8; 4096];
466 request.mut_ptr_slice().subslice_mut(0..4096).copy_from_slice(&page1_data);
467 request.commit(4096).expect("commit page 1");
468
469 let page2_data = vec![0xBBu8; 4096];
470 request.mut_ptr_slice().subslice_mut(0..4096).copy_from_slice(&page2_data);
471 request.commit(4096).expect("commit page 2");
472
473 let mut read_buf = vec![0u8; 8192];
474 paged_vmo.read(&mut read_buf, 0).expect("read paged_vmo");
475 assert_eq!(&read_buf[..4096], &page1_data[..]);
476 assert_eq!(&read_buf[4096..8192], &page2_data[..]);
477 }
478
479 #[fuchsia::test]
480 fn test_verifier_register_blob() {
481 let delivery_queue = zx::Vmo::create(65536).unwrap();
482 let mut receiver = vmo_fifo::Receiver::<RawDeliveryCommand>::new(
483 delivery_queue.duplicate_handle(zx::Rights::SAME_RIGHTS).unwrap(),
484 PENDING_DELIVERY_COMMANDS_CAPACITY,
485 )
486 .unwrap();
487
488 let verifier = Arc::new(Verifier::new(delivery_queue));
489 let key = 42u64;
490 let leaves = [[0xABu8; 32], [0xCDu8; 32]];
491
492 verifier.register_blob(key, &leaves, 96 * 1024).expect("register_blob failed");
493
494 let msg = receiver.peek().expect("peek msg");
495 assert_eq!(msg.opcode, mapping::DELIVERY_REGISTER_BLOB_COMMAND);
496 assert_eq!(msg.key, key);
497 assert_eq!(msg.length, 64);
498 assert_eq!(msg.read_alignment, 96 * 1024);
499 let mut buf = vec![0u8; 64];
500 msg.payload_slice(msg.offset, msg.length).copy_to_slice(&mut buf);
501 assert_eq!(&buf[..32], &[0xABu8; 32]);
502 assert_eq!(&buf[32..], &[0xCDu8; 32]);
503 msg.pop().expect("pop msg failed");
504 }
505
506 #[fuchsia::test]
507 fn test_verifier_buffer_96k_overlap() {
508 let total_size = 128 * 1024;
509 let chunk_size = 32 * 1024;
510 let delivery_queue = zx::Vmo::create(total_size as u64 * 2 + 65536).unwrap();
511 let mut receiver = vmo_fifo::Receiver::<RawDeliveryCommand>::new(
512 delivery_queue.duplicate_handle(zx::Rights::SAME_RIGHTS).unwrap(),
513 PENDING_DELIVERY_COMMANDS_CAPACITY,
514 )
515 .unwrap();
516
517 let verifier = Arc::new(Verifier::new(delivery_queue));
518 let key = 45u64;
519
520 let mut request = verifier.get_page_request(key, 0..total_size as u64);
521 request.prepare(0..total_size as u64, chunk_size).expect("prepare");
522
523 let chunk = vec![0x55u8; chunk_size];
524
525 for _ in 0..2 {
527 request.mut_ptr_slice().subslice_mut(0..chunk_size).copy_from_slice(&chunk);
528 request.commit(chunk_size).expect("commit");
529 }
530 assert!(receiver.is_empty());
531
532 request.mut_ptr_slice().subslice_mut(0..chunk_size).copy_from_slice(&chunk);
535 request.commit(chunk_size).expect("commit");
536
537 let msg1 = receiver.peek().expect("msg1");
538 assert_eq!(msg1.target_offset, 0);
539 assert_eq!(msg1.length, 96 * 1024);
540 msg1.pop().expect("pop msg1");
541
542 request.mut_ptr_slice().subslice_mut(0..chunk_size).copy_from_slice(&chunk);
544 request.commit(chunk_size).expect("commit");
545
546 let msg2 = receiver.peek().expect("msg2");
547 assert_eq!(msg2.target_offset, 96 * 1024);
548 assert_eq!(msg2.length, 32 * 1024);
549 msg2.pop().expect("pop msg2");
550 }
551}