Nothing to see here, move along meow
1use crate::block_io::BlockIo;
2use crate::btree;
3use crate::bulkfree::{BulkfreePhase, BulkfreeState};
4use crate::cache::BlockCache;
5use crate::cap::FsRights;
6use crate::commit;
7use crate::dir;
8use crate::dispatch::{FsState, dispatch_request};
9use crate::error::FsError;
10use crate::file;
11use crate::integrity;
12use crate::ipc_proto::{FsRequest, FsResponse};
13use crate::mkfs;
14use crate::ops;
15use crate::pool::NodePool;
16use crate::snapshot;
17use crate::transaction;
18use lancer_core::fs::{
19 BLOCK_SIZE_MIN, BLOCK_SIZE_MIN_LOG2, BlockRef, BlockType, Compression, FREEMAP_BITS_PER_LEAF,
20 FreemapLeaf, INODE_SIZE, Inode, InodeType,
21};
22use zerocopy::IntoBytes;
23
24const LZ4_HASH_SIZE: usize = 1 << 12;
25
26pub fn make_bio(num_blocks: u64) -> BlockIo {
27 BlockIo::new_memory(num_blocks)
28}
29
30pub fn make_cache() -> Box<BlockCache> {
31 unsafe {
32 let layout = std::alloc::Layout::new::<BlockCache>();
33 let ptr = std::alloc::alloc_zeroed(layout) as *mut BlockCache;
34 assert!(!ptr.is_null());
35 (*ptr).reset_lru();
36 Box::from_raw(ptr)
37 }
38}
39
40pub fn make_pool() -> Box<NodePool> {
41 unsafe {
42 let layout = std::alloc::Layout::new::<NodePool>();
43 let ptr = std::alloc::alloc_zeroed(layout) as *mut NodePool;
44 assert!(!ptr.is_null());
45 (*ptr).clear_all();
46 Box::from_raw(ptr)
47 }
48}
49
50pub struct TestFs {
51 pub bio: BlockIo,
52 pub cache: Box<BlockCache>,
53 pub pool: Box<NodePool>,
54 pub state: FsState,
55 pub scratch: Vec<u8>,
56 pub hash_table: Vec<u16>,
57 pub pending_tree_root: Option<BlockRef>,
58}
59
60fn mount_from_bio(bio: &mut BlockIo) -> FsState {
61 let sb_pair = commit::load_validated_superblock_pair(bio).unwrap();
62 let tree_root = sb_pair.active().tree_root;
63
64 let mut cache = make_cache();
65 let mut pool = make_pool();
66
67 let root_ref = btree::btree_lookup(&mut pool, &mut cache, bio, &tree_root, 1, None)
68 .unwrap()
69 .expect("metadata tree must contain root inode (key=1)");
70
71 let root_inode_block = crate::blockref_block_num(&root_ref);
72 let root_inode = file::read_inode(&mut cache, bio, root_inode_block).unwrap();
73
74 drop(pool);
75 drop(cache);
76
77 FsState::from_superblock_pair(
78 sb_pair,
79 root_inode_block,
80 root_inode.object_id,
81 root_inode.generation,
82 )
83}
84
85pub fn setup_fs(num_blocks: u64) -> TestFs {
86 let mut bio = make_bio(num_blocks);
87 mkfs::mkfs(&mut bio, num_blocks).unwrap();
88
89 let state = mount_from_bio(&mut bio);
90
91 TestFs {
92 bio,
93 cache: make_cache(),
94 pool: make_pool(),
95 state,
96 scratch: vec![0u8; 8192],
97 hash_table: vec![0u16; LZ4_HASH_SIZE],
98 pending_tree_root: None,
99 }
100}
101
102pub fn with_fs<R>(num_blocks: u64, f: impl FnOnce(&mut TestFs) -> R) -> R {
103 let mut fs = setup_fs(num_blocks);
104 f(&mut fs)
105}
106
107impl TestFs {
108 pub fn next_txn(&self) -> u64 {
109 self.state.sb_pair.active().transaction_id.wrapping_add(1)
110 }
111
112 pub fn alloc_object_id(&mut self) -> u64 {
113 let id = self.state.next_object_id;
114 self.state.next_object_id += 1;
115 id
116 }
117
118 pub fn root_inode(&mut self) -> Inode {
119 file::read_inode(&mut self.cache, &mut self.bio, self.state.root_inode_block).unwrap()
120 }
121
122 pub fn read_inode(&mut self, block: u64) -> Inode {
123 file::read_inode(&mut self.cache, &mut self.bio, block).unwrap()
124 }
125
126 pub fn save_inode(&mut self, block: u64, inode: &Inode) {
127 file::write_inode_to_cache(&mut self.cache, &mut self.bio, block, inode).unwrap()
128 }
129
130 pub fn create_file(&mut self, parent_block: u64, name: &[u8]) -> (Inode, u64) {
131 let parent = self.read_inode(parent_block);
132 let txn = self.next_txn();
133 let obj_id = self.alloc_object_id();
134 let (updated_parent, child, child_block) = ops::file_create(
135 &mut self.pool,
136 &mut self.cache,
137 &mut self.bio,
138 &mut self.state.freemap,
139 &parent,
140 name,
141 InodeType::File,
142 txn,
143 obj_id,
144 )
145 .unwrap();
146 self.save_inode(parent_block, &updated_parent);
147 (child, child_block)
148 }
149
150 pub fn create_file_result(
151 &mut self,
152 parent_block: u64,
153 name: &[u8],
154 ) -> Result<(Inode, u64), FsError> {
155 let parent = self.read_inode(parent_block);
156 let txn = self.next_txn();
157 let obj_id = self.alloc_object_id();
158 let (updated_parent, child, child_block) = ops::file_create(
159 &mut self.pool,
160 &mut self.cache,
161 &mut self.bio,
162 &mut self.state.freemap,
163 &parent,
164 name,
165 InodeType::File,
166 txn,
167 obj_id,
168 )?;
169 self.save_inode(parent_block, &updated_parent);
170 Ok((child, child_block))
171 }
172
173 pub fn write_file(&mut self, block: u64, offset: u64, data: &[u8]) -> Inode {
174 self.write_file_compressed(block, offset, data, Compression::None)
175 }
176
177 pub fn write_file_compressed(
178 &mut self,
179 block: u64,
180 offset: u64,
181 data: &[u8],
182 compression: Compression,
183 ) -> Inode {
184 let inode = self.read_inode(block);
185 let txn = self.next_txn();
186 let dedup_roots = self.state.dedup_roots;
187 let ht: &mut [u16; LZ4_HASH_SIZE] = self.hash_table.as_mut_slice().try_into().unwrap();
188 let (updated, _written, new_dedups) = file::file_write(
189 &mut self.pool,
190 &mut self.cache,
191 &mut self.bio,
192 &mut self.state.freemap,
193 &dedup_roots,
194 &inode,
195 offset,
196 data,
197 txn,
198 compression,
199 &mut self.scratch,
200 ht,
201 )
202 .unwrap();
203 self.state.dedup_roots = new_dedups;
204 self.save_inode(block, &updated);
205 updated
206 }
207
208 pub fn read_file(&mut self, block: u64, offset: u64, len: usize) -> Vec<u8> {
209 let inode = self.read_inode(block);
210 let mut buf = vec![0u8; len];
211 let n = file::file_read(
212 &mut self.pool,
213 &mut self.cache,
214 &mut self.bio,
215 &inode,
216 offset,
217 &mut buf,
218 )
219 .unwrap();
220 buf.truncate(n);
221 buf
222 }
223
224 pub fn read_file_result(
225 &mut self,
226 block: u64,
227 offset: u64,
228 len: usize,
229 ) -> Result<Vec<u8>, FsError> {
230 let inode = self.read_inode(block);
231 let mut buf = vec![0u8; len];
232 let n = file::file_read(
233 &mut self.pool,
234 &mut self.cache,
235 &mut self.bio,
236 &inode,
237 offset,
238 &mut buf,
239 )?;
240 buf.truncate(n);
241 Ok(buf)
242 }
243
244 pub fn mkdir(&mut self, parent_block: u64, name: &[u8]) -> (Inode, u64) {
245 let parent = self.read_inode(parent_block);
246 let txn = self.next_txn();
247 let obj_id = self.alloc_object_id();
248 let (updated_parent, child, child_block) = ops::mkdir(
249 &mut self.pool,
250 &mut self.cache,
251 &mut self.bio,
252 &mut self.state.freemap,
253 &parent,
254 name,
255 txn,
256 obj_id,
257 )
258 .unwrap();
259 self.save_inode(parent_block, &updated_parent);
260 (child, child_block)
261 }
262
263 pub fn rmdir(&mut self, parent_block: u64, name: &[u8]) -> Result<(), FsError> {
264 let parent = self.read_inode(parent_block);
265 let txn = self.next_txn();
266 let updated_parent = ops::rmdir(
267 &mut self.pool,
268 &mut self.cache,
269 &mut self.bio,
270 &parent,
271 name,
272 txn,
273 )?;
274 self.save_inode(parent_block, &updated_parent);
275 Ok(())
276 }
277
278 pub fn delete_file(&mut self, parent_block: u64, name: &[u8]) -> Result<(), FsError> {
279 let parent = self.read_inode(parent_block);
280 let txn = self.next_txn();
281 let updated_parent = ops::file_delete(
282 &mut self.pool,
283 &mut self.cache,
284 &mut self.bio,
285 &parent,
286 name,
287 txn,
288 )?;
289 self.save_inode(parent_block, &updated_parent);
290 Ok(())
291 }
292
293 pub fn commit(&mut self) {
294 let tree_root = self
295 .pending_tree_root
296 .take()
297 .unwrap_or_else(|| self.state.sb_pair.active().tree_root);
298 let dedup_roots = self.state.dedup_roots;
299 let snapshot_root = self.state.sb_pair.active().snapshot_root;
300 let scrub_cursor = self.state.scrub.cursor();
301 let next_obj = self.state.next_object_id;
302 transaction::transaction_commit(
303 &mut self.pool,
304 &mut self.cache,
305 &mut self.bio,
306 &mut self.state.freemap,
307 &mut self.state.reserved,
308 &mut self.state.sb_pair,
309 &tree_root,
310 &dedup_roots,
311 &snapshot_root,
312 Some(&self.state.ditto),
313 scrub_cursor,
314 next_obj,
315 )
316 .unwrap();
317 self.state.dedup_roots = self.state.sb_pair.active().dedup_roots;
318 }
319
320 pub fn create_snapshot(&mut self, name: &[u8]) {
321 let tree_root = self.state.sb_pair.active().tree_root;
322 let dedup_roots = self.state.dedup_roots;
323 let snapshot_root = self.state.sb_pair.active().snapshot_root;
324 let scrub_cursor = self.state.scrub.cursor();
325 let next_obj = self.state.next_object_id;
326 snapshot::create_snapshot(
327 &mut self.pool,
328 &mut self.cache,
329 &mut self.bio,
330 &mut self.state.freemap,
331 &mut self.state.reserved,
332 &mut self.state.sb_pair,
333 &tree_root,
334 &dedup_roots,
335 &snapshot_root,
336 name,
337 Some(&self.state.ditto),
338 scrub_cursor,
339 next_obj,
340 )
341 .unwrap();
342 self.state.dedup_roots = self.state.sb_pair.active().dedup_roots;
343 }
344
345 pub fn snapshot_lookup(&mut self, name: &[u8]) -> Option<snapshot::SnapshotRef> {
346 let snapshot_root = self.state.sb_pair.active().snapshot_root;
347 snapshot::snapshot_lookup(
348 &mut self.pool,
349 &mut self.cache,
350 &mut self.bio,
351 &snapshot_root,
352 name,
353 )
354 .unwrap()
355 }
356
357 pub fn delete_snapshot(&mut self, name: &[u8]) {
358 let snapshot_root = self.state.sb_pair.active().snapshot_root;
359 let scrub_cursor = self.state.scrub.cursor();
360 let next_obj = self.state.next_object_id;
361 snapshot::delete_snapshot(
362 &mut self.pool,
363 &mut self.cache,
364 &mut self.bio,
365 &mut self.state.freemap,
366 &mut self.state.reserved,
367 &mut self.state.sb_pair,
368 &snapshot_root,
369 name,
370 Some(&self.state.ditto),
371 scrub_cursor,
372 next_obj,
373 )
374 .unwrap();
375 }
376
377 pub fn root_block(&self) -> u64 {
378 self.state.root_inode_block
379 }
380
381 pub fn lookup_file(&mut self, parent_block: u64, name: &[u8]) -> Option<u64> {
382 let parent = self.read_inode(parent_block);
383 dir::dir_lookup(
384 &mut self.pool,
385 &mut self.cache,
386 &mut self.bio,
387 &parent,
388 name,
389 None,
390 )
391 .ok()
392 .flatten()
393 .map(|br| crate::blockref_block_num(&br))
394 }
395
396 pub fn resolve_path(&mut self, names: &[&[u8]]) -> Option<u64> {
397 names.iter().try_fold(self.root_block(), |block, name| {
398 self.lookup_file(block, name)
399 })
400 }
401
402 pub fn count_allocated_blocks(&mut self) -> u64 {
403 let total_data = self.state.freemap.total_data_blocks();
404 let total_leaves = total_data.div_ceil(FREEMAP_BITS_PER_LEAF as u64);
405 (0..total_leaves).fold(0u64, |acc, leaf_key| {
406 let leaf_block = crate::freemap::find_freemap_leaf_pub(
407 &mut self.cache,
408 &mut self.bio,
409 &self.state.freemap.root(),
410 leaf_key,
411 )
412 .unwrap();
413 let leaf_data = self.cache.cache_read(&mut self.bio, leaf_block).unwrap();
414 let leaf = unsafe { &*(leaf_data.as_ptr() as *const FreemapLeaf) };
415 let bits_in_leaf = {
416 let leaf_base = leaf_key * FREEMAP_BITS_PER_LEAF as u64;
417 let remaining = total_data.saturating_sub(leaf_base);
418 remaining.min(FREEMAP_BITS_PER_LEAF as u64) as usize
419 };
420 let full_bytes = bits_in_leaf / 8;
421 let tail_bits = bits_in_leaf % 8;
422 let byte_count: u32 = leaf.bits[..full_bytes].iter().map(|b| b.count_ones()).sum();
423 let tail_count = match tail_bits > 0 {
424 true => (leaf.bits[full_bytes] & ((1u8 << tail_bits) - 1)).count_ones(),
425 false => 0,
426 };
427 acc + (byte_count + tail_count) as u64
428 })
429 }
430
431 pub fn run_bulkfree(&mut self) {
432 let mut bf = BulkfreeState::new();
433 let active = self.state.sb_pair.active();
434 let roots: Vec<BlockRef> = [active.tree_root, active.snapshot_root]
435 .iter()
436 .copied()
437 .chain(active.dedup_roots.iter().copied())
438 .filter(|r| !r.is_null())
439 .collect();
440 bf.start(&roots, active.transaction_id, 0);
441 while matches!(bf.phase(), BulkfreePhase::Marking) {
442 bf.mark_step(&mut self.cache, &mut self.bio).unwrap();
443 }
444 while !bf.is_done() {
445 bf.sweep_step(&mut self.cache, &mut self.bio, &mut self.state.freemap)
446 .unwrap();
447 }
448 }
449
450 pub fn commit_result(&mut self) -> Result<(), FsError> {
451 let tree_root = self
452 .pending_tree_root
453 .take()
454 .unwrap_or_else(|| self.state.sb_pair.active().tree_root);
455 let dedup_roots = self.state.dedup_roots;
456 let snapshot_root = self.state.sb_pair.active().snapshot_root;
457 let scrub_cursor = self.state.scrub.cursor();
458 let next_obj = self.state.next_object_id;
459 let result = transaction::transaction_commit(
460 &mut self.pool,
461 &mut self.cache,
462 &mut self.bio,
463 &mut self.state.freemap,
464 &mut self.state.reserved,
465 &mut self.state.sb_pair,
466 &tree_root,
467 &dedup_roots,
468 &snapshot_root,
469 Some(&self.state.ditto),
470 scrub_cursor,
471 next_obj,
472 );
473 match &result {
474 Ok(()) => self.state.dedup_roots = self.state.sb_pair.active().dedup_roots,
475 Err(_) => {}
476 }
477 result
478 }
479
480 pub fn remount(&mut self) {
481 self.cache = make_cache();
482 self.pool = make_pool();
483 self.state = mount_from_bio(&mut self.bio);
484 self.pending_tree_root = None;
485 }
486
487 pub fn write_file_cow(&mut self, name: &[u8], offset: u64, data: &[u8]) -> (Inode, u64) {
488 let txn = self.next_txn();
489 let root_dir = self.read_inode(self.state.root_inode_block);
490 let file_ref = dir::dir_lookup(
491 &mut self.pool,
492 &mut self.cache,
493 &mut self.bio,
494 &root_dir,
495 name,
496 None,
497 )
498 .unwrap()
499 .expect("file must exist for write_file_cow");
500 let file_block = crate::blockref_block_num(&file_ref);
501
502 let file_inode = self.read_inode(file_block);
503 let dedup_roots = self.state.dedup_roots;
504 let ht: &mut [u16; LZ4_HASH_SIZE] = self.hash_table.as_mut_slice().try_into().unwrap();
505 let (updated_file, _written, new_dedups) = file::file_write(
506 &mut self.pool,
507 &mut self.cache,
508 &mut self.bio,
509 &mut self.state.freemap,
510 &dedup_roots,
511 &file_inode,
512 offset,
513 data,
514 txn,
515 Compression::None,
516 &mut self.scratch,
517 ht,
518 )
519 .unwrap();
520 self.state.dedup_roots = new_dedups;
521
522 let new_file_block = file::cow_inode(
523 &mut self.cache,
524 &mut self.bio,
525 &mut self.state.freemap,
526 &updated_file,
527 )
528 .unwrap();
529
530 let new_file_phys = crate::block_num_to_phys(new_file_block);
531 let after_remove = dir::dir_remove(
532 &mut self.pool,
533 &mut self.cache,
534 &mut self.bio,
535 &root_dir,
536 name,
537 txn,
538 )
539 .unwrap();
540 let after_insert = dir::dir_insert(
541 &mut self.pool,
542 &mut self.cache,
543 &mut self.bio,
544 &after_remove,
545 name,
546 new_file_phys,
547 txn,
548 )
549 .unwrap();
550
551 let new_root_block = file::cow_inode(
552 &mut self.cache,
553 &mut self.bio,
554 &mut self.state.freemap,
555 &after_insert,
556 )
557 .unwrap();
558 self.state.root_inode_block = new_root_block;
559
560 self.update_metadata_tree(self.state.root_object_id, new_root_block);
561
562 (updated_file, new_file_block)
563 }
564
565 pub fn update_metadata_tree(&mut self, object_id: u64, new_inode_block: u64) {
566 let txn = self.next_txn();
567 let tree_root = self
568 .pending_tree_root
569 .unwrap_or_else(|| self.state.sb_pair.active().tree_root);
570
571 let after_delete = btree::btree_delete(
572 &mut self.pool,
573 &mut self.cache,
574 &mut self.bio,
575 &tree_root,
576 object_id,
577 txn,
578 )
579 .unwrap()
580 .unwrap_or(BlockRef::ZERO);
581
582 let mut inode_block_data = [0u8; BLOCK_SIZE_MIN as usize];
583 let inode = self.read_inode(new_inode_block);
584 inode_block_data[..INODE_SIZE].copy_from_slice(inode.as_bytes());
585 let hashes = integrity::compute_block_hashes(&inode_block_data);
586
587 let new_ref = BlockRef::new(
588 crate::block_num_to_phys(new_inode_block),
589 BLOCK_SIZE_MIN_LOG2,
590 object_id,
591 txn,
592 hashes.content_hash,
593 hashes.integrity_crc,
594 BlockType::Inode,
595 Compression::None,
596 0,
597 0,
598 );
599
600 let new_tree_root = btree::btree_insert(
601 &mut self.pool,
602 &mut self.cache,
603 &mut self.bio,
604 &after_delete,
605 object_id,
606 new_ref,
607 txn,
608 )
609 .unwrap();
610
611 self.pending_tree_root = Some(new_tree_root);
612 }
613
614 pub fn writable_snapshot_commit(
615 &mut self,
616 name: &[u8],
617 new_snap_tree_root: &BlockRef,
618 snap_txn: u64,
619 ) {
620 let snapshot_root = self.state.sb_pair.active().snapshot_root;
621 let scrub_cursor = self.state.scrub.cursor();
622 let next_obj = self.state.next_object_id;
623 snapshot::writable_snapshot_commit(
624 &mut self.pool,
625 &mut self.cache,
626 &mut self.bio,
627 &mut self.state.freemap,
628 &mut self.state.reserved,
629 &mut self.state.sb_pair,
630 &snapshot_root,
631 name,
632 new_snap_tree_root,
633 snap_txn,
634 Some(&self.state.ditto),
635 scrub_cursor,
636 next_obj,
637 )
638 .unwrap();
639 }
640
641 pub fn snapshot_create_file(&mut self, snap: &snapshot::SnapshotRef, name: &[u8]) -> BlockRef {
642 let txn = snap.snapshot_txn_id;
643
644 let root_entry = btree::btree_lookup(
645 &mut self.pool,
646 &mut self.cache,
647 &mut self.bio,
648 &snap.root_blockref,
649 self.state.root_object_id,
650 snap.txn_filter(),
651 )
652 .unwrap()
653 .expect("snapshot must contain root inode");
654
655 let root_block = crate::blockref_block_num(&root_entry);
656 let root_inode = self.read_inode(root_block);
657
658 let obj_id = self.alloc_object_id();
659 let (updated_parent, _child, _child_block) = ops::file_create(
660 &mut self.pool,
661 &mut self.cache,
662 &mut self.bio,
663 &mut self.state.freemap,
664 &root_inode,
665 name,
666 InodeType::File,
667 txn,
668 obj_id,
669 )
670 .unwrap();
671
672 let new_root_block = file::cow_inode(
673 &mut self.cache,
674 &mut self.bio,
675 &mut self.state.freemap,
676 &updated_parent,
677 )
678 .unwrap();
679
680 let mut inode_block_data = [0u8; BLOCK_SIZE_MIN as usize];
681 let new_root_inode = self.read_inode(new_root_block);
682 inode_block_data[..INODE_SIZE].copy_from_slice(new_root_inode.as_bytes());
683 let hashes = integrity::compute_block_hashes(&inode_block_data);
684
685 let new_root_ref = BlockRef::new(
686 crate::block_num_to_phys(new_root_block),
687 BLOCK_SIZE_MIN_LOG2,
688 self.state.root_object_id,
689 txn,
690 hashes.content_hash,
691 hashes.integrity_crc,
692 BlockType::Inode,
693 Compression::None,
694 0,
695 0,
696 );
697
698 let after_delete = btree::btree_delete(
699 &mut self.pool,
700 &mut self.cache,
701 &mut self.bio,
702 &snap.root_blockref,
703 self.state.root_object_id,
704 txn,
705 )
706 .unwrap()
707 .unwrap_or(BlockRef::ZERO);
708
709 btree::btree_insert(
710 &mut self.pool,
711 &mut self.cache,
712 &mut self.bio,
713 &after_delete,
714 self.state.root_object_id,
715 new_root_ref,
716 txn,
717 )
718 .unwrap()
719 }
720}
721
722pub struct DispatchTestFs {
723 pub fs: TestFs,
724 pub data_area: Vec<u8>,
725 pub client_pid: u16,
726 pub root_handle: u8,
727}
728
729pub fn setup_dispatch_fs(num_blocks: u64) -> DispatchTestFs {
730 let mut fs = setup_fs(num_blocks);
731 let root_handle = fs
732 .state
733 .handles
734 .install_root_handle(
735 0,
736 fs.state.root_object_id,
737 fs.state.root_generation,
738 fs.state.root_inode_block,
739 )
740 .unwrap();
741
742 DispatchTestFs {
743 fs,
744 data_area: vec![0u8; 8192],
745 client_pid: 0,
746 root_handle,
747 }
748}
749
750impl DispatchTestFs {
751 pub fn dispatch(&mut self, req: &FsRequest) -> FsResponse {
752 let hash_table: &mut [u16; LZ4_HASH_SIZE] =
753 self.fs.hash_table.as_mut_slice().try_into().unwrap();
754 dispatch_request(
755 req,
756 &mut self.fs.pool,
757 &mut self.fs.cache,
758 &mut self.fs.bio,
759 &mut self.fs.state,
760 self.data_area.as_mut_ptr(),
761 self.data_area.len(),
762 self.client_pid,
763 &mut self.fs.scratch,
764 hash_table,
765 )
766 }
767
768 pub fn dispatch_as(&mut self, client_pid: u16, req: &FsRequest) -> FsResponse {
769 let hash_table: &mut [u16; LZ4_HASH_SIZE] =
770 self.fs.hash_table.as_mut_slice().try_into().unwrap();
771 dispatch_request(
772 req,
773 &mut self.fs.pool,
774 &mut self.fs.cache,
775 &mut self.fs.bio,
776 &mut self.fs.state,
777 self.data_area.as_mut_ptr(),
778 self.data_area.len(),
779 client_pid,
780 &mut self.fs.scratch,
781 hash_table,
782 )
783 }
784
785 pub fn install_client(&mut self, pid: u16) -> u8 {
786 self.fs
787 .state
788 .handles
789 .install_root_handle(
790 pid,
791 self.fs.state.root_object_id,
792 self.fs.state.root_generation,
793 self.fs.state.root_inode_block,
794 )
795 .unwrap()
796 }
797
798 pub fn dispatch_open(&mut self, dir_handle: u8, name: &[u8], mode: FsRights) -> FsResponse {
799 self.data_area[..name.len()].copy_from_slice(name);
800 let req = FsRequest::open(1, dir_handle, mode, 0, name.len() as u64);
801 self.dispatch(&req)
802 }
803
804 pub fn dispatch_mkdir(&mut self, dir_handle: u8, name: &[u8]) -> FsResponse {
805 self.data_area[..name.len()].copy_from_slice(name);
806 let req = FsRequest::mkdir(1, dir_handle, 0, name.len() as u64);
807 self.dispatch(&req)
808 }
809
810 pub fn dispatch_write(&mut self, handle: u8, offset: u64, data: &[u8]) -> FsResponse {
811 self.data_area[..data.len()].copy_from_slice(data);
812 let req = FsRequest::write(1, handle, offset, data.len() as u32, 0);
813 self.dispatch(&req)
814 }
815
816 pub fn dispatch_read(&mut self, handle: u8, offset: u64, len: u32) -> (FsResponse, Vec<u8>) {
817 self.data_area
818 .iter_mut()
819 .take(len as usize)
820 .for_each(|b| *b = 0);
821 let req = FsRequest::read(1, handle, offset, len, 0);
822 let resp = self.dispatch(&req);
823 let bytes_read = match resp.status {
824 0 => resp.val0 as usize,
825 _ => 0,
826 };
827 let data = self.data_area[..bytes_read].to_vec();
828 (resp, data)
829 }
830
831 pub fn dispatch_stat(&mut self, handle: u8) -> FsResponse {
832 let req = FsRequest::stat(1, handle);
833 self.dispatch(&req)
834 }
835
836 pub fn dispatch_close(&mut self, handle: u8) -> FsResponse {
837 let req = FsRequest::close(1, handle);
838 self.dispatch(&req)
839 }
840
841 pub fn dispatch_unlink(&mut self, dir_handle: u8, name: &[u8]) -> FsResponse {
842 self.data_area[..name.len()].copy_from_slice(name);
843 let req = FsRequest::unlink(1, dir_handle, 0, name.len() as u64);
844 self.dispatch(&req)
845 }
846
847 pub fn dispatch_readdir(&mut self, dir_handle: u8, cursor: u64, buf_len: usize) -> FsResponse {
848 let req = FsRequest::readdir(1, dir_handle, cursor, 0, buf_len as u64);
849 self.dispatch(&req)
850 }
851
852 pub fn dispatch_create_snapshot(&mut self, handle: u8, name: &[u8]) -> FsResponse {
853 self.data_area[..name.len()].copy_from_slice(name);
854 let req = FsRequest {
855 opcode: 9,
856 handle,
857 flags: 0,
858 _pad: 0,
859 tag: 1,
860 arg0: 0,
861 arg1: name.len() as u64,
862 arg2: 0,
863 };
864 self.dispatch(&req)
865 }
866
867 pub fn dispatch_delete_snapshot(&mut self, handle: u8, name: &[u8]) -> FsResponse {
868 self.data_area[..name.len()].copy_from_slice(name);
869 let req = FsRequest {
870 opcode: 10,
871 handle,
872 flags: 0,
873 _pad: 0,
874 tag: 1,
875 arg0: 0,
876 arg1: name.len() as u64,
877 arg2: 0,
878 };
879 self.dispatch(&req)
880 }
881
882 pub fn dispatch_sync(&mut self) -> FsResponse {
883 let req = FsRequest::sync(1);
884 self.dispatch(&req)
885 }
886
887 pub fn remount(&mut self) {
888 self.fs.remount();
889 self.root_handle = self
890 .fs
891 .state
892 .handles
893 .install_root_handle(
894 self.client_pid,
895 self.fs.state.root_object_id,
896 self.fs.state.root_generation,
897 self.fs.state.root_inode_block,
898 )
899 .unwrap();
900 }
901}