1use crate::{
8 chunk::{
9 self, ChunkTreeCache, ParityKind, ParityPlan, ParityRow,
10 StripePlacement, WritePlan,
11 },
12 raid56, raw,
13 superblock::{self, Superblock},
14 tree::{KeyType, TreeBlock},
15};
16use bytes::Buf;
17use std::{
18 collections::BTreeMap,
19 io::{self, Read, Seek, SeekFrom, Write},
20 mem,
21 sync::Arc,
22};
23
24pub trait TreeBlockCache: Send + Sync {
38 fn get(&self, addr: u64) -> Option<Arc<TreeBlock>>;
40
41 fn put(&self, addr: u64, block: Arc<TreeBlock>);
44
45 fn invalidate(&self, addr: u64);
48}
49
50pub struct BlockReader<R> {
57 devices: BTreeMap<u64, R>,
58 nodesize: u32,
59 chunk_cache: ChunkTreeCache,
60 cache: Option<Arc<dyn TreeBlockCache>>,
64}
65
66impl<R> BlockReader<R> {
67 pub fn new(
73 handle: R,
74 devid: u64,
75 nodesize: u32,
76 chunk_cache: ChunkTreeCache,
77 ) -> Self {
78 let mut devices = BTreeMap::new();
79 devices.insert(devid, handle);
80 Self {
81 devices,
82 nodesize,
83 chunk_cache,
84 cache: None,
85 }
86 }
87
88 pub fn set_cache(&mut self, cache: Option<Arc<dyn TreeBlockCache>>) {
95 self.cache = cache;
96 }
97
98 #[must_use]
100 pub fn with_cache(mut self, cache: Arc<dyn TreeBlockCache>) -> Self {
101 self.cache = Some(cache);
102 self
103 }
104
105 #[must_use]
110 pub fn new_multi(
111 devices: BTreeMap<u64, R>,
112 nodesize: u32,
113 chunk_cache: ChunkTreeCache,
114 ) -> Self {
115 Self {
116 devices,
117 nodesize,
118 chunk_cache,
119 cache: None,
120 }
121 }
122
123 #[must_use]
125 pub fn devices(&self) -> &BTreeMap<u64, R> {
126 &self.devices
127 }
128
129 pub fn devices_mut(&mut self) -> &mut BTreeMap<u64, R> {
137 &mut self.devices
138 }
139
140 pub fn single_device_mut(&mut self) -> &mut R {
153 assert_eq!(
154 self.devices.len(),
155 1,
156 "single_device_mut: filesystem has {} devices, not 1",
157 self.devices.len(),
158 );
159 self.devices.values_mut().next().unwrap()
160 }
161}
162
163impl<R: Read + Seek> BlockReader<R> {
164 pub fn read_block(&mut self, logical: u64) -> io::Result<Vec<u8>> {
171 self.read_data(logical, self.nodesize as usize)
177 }
178
179 pub fn read_tree_block(
190 &mut self,
191 logical: u64,
192 ) -> io::Result<Arc<TreeBlock>> {
193 if let Some(cache) = self.cache.as_ref() {
194 if let Some(hit) = cache.get(logical) {
195 return Ok(hit);
196 }
197 }
198 let buf = self.read_block(logical)?;
199 let block = Arc::new(TreeBlock::parse(&buf));
200 if let Some(cache) = self.cache.as_ref() {
201 cache.put(logical, Arc::clone(&block));
202 }
203 Ok(block)
204 }
205
206 #[must_use]
208 pub fn chunk_cache(&self) -> &ChunkTreeCache {
209 &self.chunk_cache
210 }
211
212 pub fn chunk_cache_mut(&mut self) -> &mut ChunkTreeCache {
214 &mut self.chunk_cache
215 }
216
217 #[must_use]
219 pub fn nodesize(&self) -> u32 {
220 self.nodesize
221 }
222
223 pub fn read_data(
240 &mut self,
241 logical: u64,
242 len: usize,
243 ) -> io::Result<Vec<u8>> {
244 let placements =
245 self.chunk_cache.plan_read(logical, len).ok_or_else(|| {
246 io::Error::new(
247 io::ErrorKind::NotFound,
248 format!(
249 "logical address {logical} not mapped or unsupported profile"
250 ),
251 )
252 })?;
253 let mut buf = vec![0u8; len];
254 for p in placements {
255 let dev = self.device_handle_mut(p.devid)?;
256 dev.seek(SeekFrom::Start(p.physical))?;
257 dev.read_exact(&mut buf[p.buf_offset..p.buf_offset + p.len])?;
258 }
259 Ok(buf)
260 }
261
262 fn device_handle_mut(&mut self, devid: u64) -> io::Result<&mut R> {
265 self.devices.get_mut(&devid).ok_or_else(|| {
266 io::Error::new(
267 io::ErrorKind::NotFound,
268 format!(
269 "device {devid} not open (referenced by the chunk cache)"
270 ),
271 )
272 })
273 }
274}
275
276impl<R: Read + Write + Seek> BlockReader<R> {
277 pub fn write_block(&mut self, logical: u64, buf: &[u8]) -> io::Result<()> {
295 let plan = self.chunk_cache.plan_write(logical, buf.len()).ok_or_else(
296 || {
297 io::Error::new(
298 io::ErrorKind::NotFound,
299 format!(
300 "logical address {logical} not mapped or unsupported profile"
301 ),
302 )
303 },
304 )?;
305 match plan {
306 WritePlan::Plain(placements) => {
307 self.execute_plain_plan(buf, &placements)
308 }
309 WritePlan::Parity(plan) => self.execute_parity_plan(buf, &plan),
310 }
311 }
312
313 fn execute_plain_plan(
314 &mut self,
315 buf: &[u8],
316 placements: &[StripePlacement],
317 ) -> io::Result<()> {
318 for p in placements {
319 let dev = self.device_handle_mut(p.devid)?;
320 dev.seek(SeekFrom::Start(p.physical))?;
321 dev.write_all(&buf[p.buf_offset..p.buf_offset + p.len])?;
322 }
323 Ok(())
324 }
325
326 fn execute_parity_plan(
334 &mut self,
335 buf: &[u8],
336 plan: &ParityPlan,
337 ) -> io::Result<()> {
338 let stripe_len = plan.stripe_len as usize;
339 for row in &plan.rows {
340 self.execute_parity_row(buf, stripe_len, row)?;
341 }
342 Ok(())
343 }
344
345 fn execute_parity_row(
346 &mut self,
347 buf: &[u8],
348 stripe_len: usize,
349 row: &ParityRow,
350 ) -> io::Result<()> {
351 let mut scratch: Vec<Vec<u8>> =
353 Vec::with_capacity(row.data_columns.len());
354 for col in &row.data_columns {
355 let mut slot = vec![0u8; stripe_len];
356 let dev = self.device_handle_mut(col.devid)?;
357 dev.seek(SeekFrom::Start(col.physical))?;
358 dev.read_exact(&mut slot)?;
359 scratch.push(slot);
360 }
361 for (col, slot) in row.data_columns.iter().zip(scratch.iter_mut()) {
363 if let Some(ov) = &col.overlay {
364 let dst_start = ov.slot_offset as usize;
365 let dst_end = dst_start + ov.len as usize;
366 let src_start = ov.buf_offset;
367 let src_end = src_start + ov.len as usize;
368 slot[dst_start..dst_end]
369 .copy_from_slice(&buf[src_start..src_end]);
370 }
371 }
372 let stripe_refs: Vec<&[u8]> =
374 scratch.iter().map(Vec::as_slice).collect();
375 let want_q = row.parity_targets.iter().any(|t| t.kind == ParityKind::Q);
376 let (p_buf, q_buf) = if want_q {
377 let (p, q) = raid56::compute_p_q(&stripe_refs);
378 (p, Some(q))
379 } else {
380 (raid56::compute_p(&stripe_refs), None)
381 };
382 for col in &row.data_columns {
384 let Some(ov) = &col.overlay else { continue };
385 let dev = self.device_handle_mut(col.devid)?;
386 dev.seek(SeekFrom::Start(
387 col.physical + u64::from(ov.slot_offset),
388 ))?;
389 let src_start = ov.buf_offset;
390 let src_end = src_start + ov.len as usize;
391 dev.write_all(&buf[src_start..src_end])?;
392 }
393 for target in &row.parity_targets {
395 let bytes = match target.kind {
396 ParityKind::P => &p_buf,
397 ParityKind::Q => {
398 q_buf.as_ref().expect("Q target without Q computation")
399 }
400 };
401 let dev = self.device_handle_mut(target.devid)?;
402 dev.seek(SeekFrom::Start(target.physical))?;
403 dev.write_all(bytes)?;
404 }
405 Ok(())
406 }
407}
408
409pub struct OpenFilesystem<R> {
411 pub reader: BlockReader<R>,
413 pub superblock: Superblock,
415 pub tree_roots: BTreeMap<u64, (u64, u64)>,
417 pub per_device_dev_items: BTreeMap<u64, crate::items::DeviceItem>,
424}
425
426pub fn filesystem_open<R: Read + Seek>(
438 reader: R,
439) -> io::Result<OpenFilesystem<R>> {
440 filesystem_open_mirror(reader, 0)
441}
442
443pub fn filesystem_open_mirror<R: Read + Seek>(
449 reader: R,
450 mirror: u32,
451) -> io::Result<OpenFilesystem<R>> {
452 let mut reader = reader;
453
454 let sb = superblock::read_superblock(&mut reader, mirror)?;
456 let primary_devid = sb.dev_item.devid;
457 let mut per_device_dev_items = BTreeMap::new();
458 per_device_dev_items.insert(primary_devid, sb.dev_item.clone());
459
460 let chunk_cache = chunk::seed_from_sys_chunk_array(
462 &sb.sys_chunk_array,
463 sb.sys_chunk_array_size,
464 );
465
466 let mut block_reader =
467 BlockReader::new(reader, primary_devid, sb.nodesize, chunk_cache);
468
469 read_chunk_tree(&mut block_reader, sb.chunk_root)?;
471
472 let tree_roots = read_root_tree(&mut block_reader, sb.root)?;
474
475 Ok(OpenFilesystem {
476 reader: block_reader,
477 superblock: sb,
478 tree_roots,
479 per_device_dev_items,
480 })
481}
482
483pub fn filesystem_open_multi<R: Read + Seek>(
506 devices: BTreeMap<u64, R>,
507) -> io::Result<OpenFilesystem<R>> {
508 if devices.is_empty() {
509 return Err(io::Error::other(
510 "filesystem_open_multi: device map is empty",
511 ));
512 }
513 let mut devices = devices;
514
515 let mut per_device_dev_items: BTreeMap<u64, crate::items::DeviceItem> =
517 BTreeMap::new();
518 let mut superblocks: BTreeMap<u64, Superblock> = BTreeMap::new();
519 for (&devid, dev) in &mut devices {
520 let sb = superblock::read_superblock(dev, 0)?;
521 if sb.dev_item.devid != devid {
522 return Err(io::Error::other(format!(
523 "device map key {devid} doesn't match superblock dev_item.devid {}",
524 sb.dev_item.devid,
525 )));
526 }
527 per_device_dev_items.insert(devid, sb.dev_item.clone());
528 superblocks.insert(devid, sb);
529 }
530
531 let primary_sb = superblocks.values().next().unwrap().clone();
534 for (devid, sb) in &superblocks {
535 if sb.fsid != primary_sb.fsid {
536 return Err(io::Error::other(format!(
537 "device {devid} fsid {} differs from primary fsid {}",
538 sb.fsid, primary_sb.fsid,
539 )));
540 }
541 }
542
543 let chunk_cache = chunk::seed_from_sys_chunk_array(
545 &primary_sb.sys_chunk_array,
546 primary_sb.sys_chunk_array_size,
547 );
548
549 let mut block_reader =
550 BlockReader::new_multi(devices, primary_sb.nodesize, chunk_cache);
551
552 read_chunk_tree(&mut block_reader, primary_sb.chunk_root)?;
554
555 let mut referenced: std::collections::BTreeSet<u64> =
557 std::collections::BTreeSet::new();
558 for mapping in block_reader.chunk_cache().iter() {
559 for stripe in &mapping.stripes {
560 referenced.insert(stripe.devid);
561 }
562 }
563 for devid in &referenced {
564 if !block_reader.devices().contains_key(devid) {
565 return Err(io::Error::other(format!(
566 "chunk tree references devid {devid} but no handle was provided"
567 )));
568 }
569 }
570
571 let tree_roots = read_root_tree(&mut block_reader, primary_sb.root)?;
573
574 Ok(OpenFilesystem {
575 reader: block_reader,
576 superblock: primary_sb,
577 tree_roots,
578 per_device_dev_items,
579 })
580}
581
582pub fn filesystem_open_with_cache<R: Read + Seek>(
596 reader: R,
597 mirror: u32,
598 chunk_cache: ChunkTreeCache,
599) -> io::Result<OpenFilesystem<R>> {
600 let mut reader = reader;
601 let sb = superblock::read_superblock(&mut reader, mirror)?;
602 let primary_devid = sb.dev_item.devid;
603 let mut per_device_dev_items = BTreeMap::new();
604 per_device_dev_items.insert(primary_devid, sb.dev_item.clone());
605 let mut block_reader =
606 BlockReader::new(reader, primary_devid, sb.nodesize, chunk_cache);
607 let tree_roots = read_root_tree(&mut block_reader, sb.root)?;
608
609 Ok(OpenFilesystem {
610 reader: block_reader,
611 superblock: sb,
612 tree_roots,
613 per_device_dev_items,
614 })
615}
616
617pub fn read_chunk_tree<R: Read + Seek>(
626 reader: &mut BlockReader<R>,
627 root_logical: u64,
628) -> io::Result<()> {
629 let block = reader.read_tree_block(root_logical)?;
630
631 match &*block {
632 TreeBlock::Leaf { items, data, .. } => {
633 for item in items {
634 if item.key.key_type != KeyType::ChunkItem {
635 continue;
636 }
637 let item_data = &data[mem::size_of::<raw::btrfs_header>()
638 + item.offset as usize..];
639 if let Some((mapping, _)) =
640 chunk::parse_chunk_item(item_data, item.key.offset)
641 {
642 if reader.chunk_cache.lookup(mapping.logical).is_none() {
645 reader.chunk_cache.insert(mapping);
646 }
647 }
648 }
649 }
650 TreeBlock::Node { ptrs, .. } => {
651 for ptr in ptrs {
652 read_chunk_tree(reader, ptr.blockptr)?;
653 }
654 }
655 }
656
657 Ok(())
658}
659
660pub fn read_root_tree<R: Read + Seek>(
668 reader: &mut BlockReader<R>,
669 root_logical: u64,
670) -> io::Result<BTreeMap<u64, (u64, u64)>> {
671 let mut tree_roots = BTreeMap::new();
672 collect_root_items(reader, root_logical, &mut tree_roots)?;
673 Ok(tree_roots)
674}
675
676#[derive(Debug, Clone, Copy, PartialEq, Eq)]
678pub enum Traversal {
679 Bfs,
681 Dfs,
683}
684
685pub fn tree_walk<R: Read + Seek>(
691 reader: &mut BlockReader<R>,
692 root_logical: u64,
693 traversal: Traversal,
694 visitor: &mut dyn FnMut(&TreeBlock),
695) -> io::Result<()> {
696 match traversal {
697 Traversal::Bfs => tree_walk_bfs(reader, root_logical, visitor),
698 Traversal::Dfs => tree_walk_dfs(reader, root_logical, visitor),
699 }
700}
701
702fn tree_walk_dfs<R: Read + Seek>(
703 reader: &mut BlockReader<R>,
704 logical: u64,
705 visitor: &mut dyn FnMut(&TreeBlock),
706) -> io::Result<()> {
707 let block = reader.read_tree_block(logical)?;
708 visitor(&block);
709
710 if let TreeBlock::Node { ptrs, .. } = &*block {
711 for ptr in ptrs {
712 tree_walk_dfs(reader, ptr.blockptr, visitor)?;
713 }
714 }
715
716 Ok(())
717}
718
719fn tree_walk_bfs<R: Read + Seek>(
720 reader: &mut BlockReader<R>,
721 root_logical: u64,
722 visitor: &mut dyn FnMut(&TreeBlock),
723) -> io::Result<()> {
724 let root_block = reader.read_tree_block(root_logical)?;
725 let root_level = root_block.header().level;
726 visitor(&root_block);
727
728 let mut current_level_ptrs: Vec<u64> = match &*root_block {
729 TreeBlock::Node { ptrs, .. } => {
730 ptrs.iter().map(|p| p.blockptr).collect()
731 }
732 TreeBlock::Leaf { .. } => return Ok(()),
733 };
734
735 for _level in (0..root_level).rev() {
736 let mut next_level_ptrs = Vec::new();
737
738 for logical in ¤t_level_ptrs {
739 let block = reader.read_tree_block(*logical)?;
740 visitor(&block);
741
742 if let TreeBlock::Node { ptrs, .. } = &*block {
743 next_level_ptrs.extend(ptrs.iter().map(|p| p.blockptr));
744 }
745 }
746
747 current_level_ptrs = next_level_ptrs;
748 }
749
750 Ok(())
751}
752
753pub fn tree_walk_tolerant<R: Read + Seek>(
764 reader: &mut BlockReader<R>,
765 root_logical: u64,
766 visitor: &mut dyn FnMut(&[u8], &TreeBlock),
767 on_error: &mut dyn FnMut(u64, &io::Error),
768) -> io::Result<()> {
769 let buf = reader.read_block(root_logical)?;
770 let block = TreeBlock::parse(&buf);
771 visitor(&buf, &block);
772
773 if let TreeBlock::Node { ptrs, .. } = &block {
774 for ptr in ptrs {
775 tree_walk_tolerant_dfs(reader, ptr.blockptr, visitor, on_error);
776 }
777 }
778
779 Ok(())
780}
781
782fn tree_walk_tolerant_dfs<R: Read + Seek>(
783 reader: &mut BlockReader<R>,
784 logical: u64,
785 visitor: &mut dyn FnMut(&[u8], &TreeBlock),
786 on_error: &mut dyn FnMut(u64, &io::Error),
787) {
788 let buf = match reader.read_block(logical) {
789 Ok(b) => b,
790 Err(e) => {
791 on_error(logical, &e);
792 return;
793 }
794 };
795 let block = TreeBlock::parse(&buf);
796 visitor(&buf, &block);
797
798 if let TreeBlock::Node { ptrs, .. } = &block {
799 for ptr in ptrs {
800 tree_walk_tolerant_dfs(reader, ptr.blockptr, visitor, on_error);
801 }
802 }
803}
804
805pub fn tree_walk_mut<R: Read + Write + Seek>(
816 reader: &mut BlockReader<R>,
817 root_logical: u64,
818 csum_type: superblock::ChecksumType,
819 visitor: &mut dyn FnMut(&mut Vec<u8>, &TreeBlock) -> bool,
820) -> io::Result<()> {
821 let mut buf = reader.read_block(root_logical)?;
822 let block = TreeBlock::parse(&buf);
823
824 let child_ptrs: Vec<u64> = if let TreeBlock::Node { ptrs, .. } = &block {
825 ptrs.iter().map(|p| p.blockptr).collect()
826 } else {
827 Vec::new()
828 };
829
830 if visitor(&mut buf, &block) {
831 crate::util::csum_tree_block(&mut buf, csum_type);
832 reader.write_block(root_logical, &buf)?;
833 }
834
835 for ptr in child_ptrs {
836 tree_walk_mut(reader, ptr, csum_type, visitor)?;
837 }
838
839 Ok(())
840}
841
842pub fn block_visit<R: Read + Seek>(
848 reader: &mut BlockReader<R>,
849 logical: u64,
850 follow: bool,
851 traversal: Traversal,
852 visitor: &mut dyn FnMut(&TreeBlock),
853) -> io::Result<()> {
854 if follow {
855 tree_walk(reader, logical, traversal, visitor)
856 } else {
857 let block = reader.read_tree_block(logical)?;
858 visitor(&block);
859 Ok(())
860 }
861}
862
863#[derive(Debug, Clone)]
865pub struct TreeStats {
866 pub total_nodes: u64,
868 pub total_bytes: u64,
870 pub total_inline: u64,
872 pub total_seeks: u64,
874 pub forward_seeks: u64,
876 pub backward_seeks: u64,
878 pub total_seek_len: u64,
880 pub max_seek_len: u64,
882 pub total_clusters: u64,
884 pub total_cluster_size: u64,
886 pub min_cluster_size: u64,
888 pub max_cluster_size: u64,
890 pub lowest_bytenr: u64,
892 pub highest_bytenr: u64,
894 pub node_counts: Vec<u64>,
896 pub levels: u8,
898}
899
900pub fn tree_stats_collect<R: Read + Seek>(
909 reader: &mut BlockReader<R>,
910 root_logical: u64,
911 find_inline: bool,
912) -> io::Result<TreeStats> {
913 let root_block = reader.read_tree_block(root_logical)?;
914 let nodesize = u64::from(reader.nodesize());
915 let root_level = root_block.header().level;
916 let root_bytenr = root_block.header().bytenr;
917
918 let mut stats = TreeStats {
919 total_nodes: 0,
920 total_bytes: 0,
921 total_inline: 0,
922 total_seeks: 0,
923 forward_seeks: 0,
924 backward_seeks: 0,
925 total_seek_len: 0,
926 max_seek_len: 0,
927 total_clusters: 0,
928 total_cluster_size: 0,
929 min_cluster_size: u64::MAX,
930 max_cluster_size: nodesize,
931 lowest_bytenr: root_bytenr,
932 highest_bytenr: root_bytenr,
933 node_counts: vec![0u64; root_level as usize + 1],
934 levels: root_level + 1,
935 };
936
937 walk_stats(reader, &root_block, &mut stats, find_inline, nodesize)?;
938 Ok(stats)
939}
940
941fn walk_stats<R: Read + Seek>(
943 reader: &mut BlockReader<R>,
944 block: &TreeBlock,
945 stats: &mut TreeStats,
946 find_inline: bool,
947 nodesize: u64,
948) -> io::Result<()> {
949 let level = block.header().level;
950 let bytenr = block.header().bytenr;
951
952 stats.total_nodes += 1;
953 stats.total_bytes += nodesize;
954 if (level as usize) < stats.node_counts.len() {
955 stats.node_counts[level as usize] += 1;
956 }
957 if bytenr < stats.lowest_bytenr {
958 stats.lowest_bytenr = bytenr;
959 }
960 if bytenr > stats.highest_bytenr {
961 stats.highest_bytenr = bytenr;
962 }
963
964 match block {
965 TreeBlock::Leaf { items, data, .. } => {
966 if find_inline {
967 let type_off =
968 mem::offset_of!(raw::btrfs_file_extent_item, type_);
969 let inline_hdr_size =
970 mem::offset_of!(raw::btrfs_file_extent_item, disk_bytenr);
971 let header_size = mem::size_of::<raw::btrfs_header>();
972 for item in items {
973 if item.key.key_type != KeyType::ExtentData {
974 continue;
975 }
976 let start = header_size + item.offset as usize;
977 if start + type_off >= data.len() {
978 continue;
979 }
980 if data[start + type_off] == 0
982 && item.size as usize > inline_hdr_size
983 {
984 stats.total_inline +=
985 u64::from(item.size) - inline_hdr_size as u64;
986 }
987 }
988 }
989 }
990 TreeBlock::Node { ptrs, .. } => {
991 let mut last_block = bytenr;
992 let mut cluster_size = nodesize;
993
994 for ptr in ptrs {
995 let child = reader.read_tree_block(ptr.blockptr)?;
996 walk_stats(reader, &child, stats, find_inline, nodesize)?;
997
998 let cur = ptr.blockptr;
999 if last_block + nodesize == cur {
1000 cluster_size += nodesize;
1001 } else {
1002 let distance = cur.abs_diff(last_block + nodesize);
1003 stats.total_seeks += 1;
1004 stats.total_seek_len += distance;
1005 if distance > stats.max_seek_len {
1006 stats.max_seek_len = distance;
1007 }
1008 if cur > last_block + nodesize {
1009 stats.forward_seeks += 1;
1010 } else {
1011 stats.backward_seeks += 1;
1012 }
1013 if cluster_size != nodesize {
1014 stats.total_clusters += 1;
1015 stats.total_cluster_size += cluster_size;
1016 if cluster_size < stats.min_cluster_size {
1017 stats.min_cluster_size = cluster_size;
1018 }
1019 if cluster_size > stats.max_cluster_size {
1020 stats.max_cluster_size = cluster_size;
1021 }
1022 }
1023 cluster_size = nodesize;
1024 }
1025 last_block = cur;
1026 }
1027 }
1028 }
1029
1030 Ok(())
1031}
1032
1033fn collect_root_items<R: Read + Seek>(
1034 reader: &mut BlockReader<R>,
1035 logical: u64,
1036 tree_roots: &mut BTreeMap<u64, (u64, u64)>,
1037) -> io::Result<()> {
1038 let block = reader.read_tree_block(logical)?;
1039
1040 match &*block {
1041 TreeBlock::Leaf { items, data, .. } => {
1042 let header_size = mem::size_of::<raw::btrfs_header>();
1045 let root_item_bytenr_offset = {
1046 mem::offset_of!(raw::btrfs_root_item, bytenr)
1049 };
1050
1051 for item in items {
1052 if item.key.key_type != KeyType::RootItem {
1053 continue;
1054 }
1055 let item_start = header_size + item.offset as usize;
1056 if item_start + root_item_bytenr_offset + 8 > data.len() {
1057 continue;
1058 }
1059 let mut buf = &data[item_start + root_item_bytenr_offset..];
1060 let bytenr = buf.get_u64_le();
1061 if bytenr != 0 {
1062 tree_roots
1063 .insert(item.key.objectid, (bytenr, item.key.offset));
1064 }
1065 }
1066 }
1067 TreeBlock::Node { ptrs, .. } => {
1068 for ptr in ptrs {
1069 collect_root_items(reader, ptr.blockptr, tree_roots)?;
1070 }
1071 }
1072 }
1073
1074 Ok(())
1075}
1076
1077#[cfg(test)]
1078mod tests {
1079 use super::*;
1080 use crate::chunk::{ChunkMapping, Stripe};
1081 use std::io::Cursor;
1082 use uuid::Uuid;
1083
1084 fn make_device(len: usize) -> Cursor<Vec<u8>> {
1087 Cursor::new(vec![0u8; len])
1088 }
1089
1090 fn make_mapping(
1095 logical: u64,
1096 length: u64,
1097 stripes: &[(u64, u64)],
1098 ) -> ChunkMapping {
1099 let chunk_type = if stripes.len() == 1 {
1100 0 } else {
1102 let same_devid = stripes.iter().all(|s| s.0 == stripes[0].0);
1106 if same_devid {
1107 u64::from(raw::BTRFS_BLOCK_GROUP_DUP)
1108 } else {
1109 u64::from(match stripes.len() {
1110 3 => raw::BTRFS_BLOCK_GROUP_RAID1C3,
1111 4 => raw::BTRFS_BLOCK_GROUP_RAID1C4,
1112 _ => raw::BTRFS_BLOCK_GROUP_RAID1,
1115 })
1116 }
1117 };
1118 ChunkMapping {
1119 logical,
1120 length,
1121 stripe_len: 65536,
1122 chunk_type,
1123 num_stripes: stripes.len() as u16,
1124 sub_stripes: 0,
1125 stripes: stripes
1126 .iter()
1127 .map(|&(devid, offset)| Stripe {
1128 devid,
1129 offset,
1130 dev_uuid: Uuid::nil(),
1131 })
1132 .collect(),
1133 }
1134 }
1135
1136 fn make_reader(
1139 devices: &[(u64, usize)],
1140 mappings: &[ChunkMapping],
1141 ) -> BlockReader<Cursor<Vec<u8>>> {
1142 let mut handles = BTreeMap::new();
1143 for &(devid, len) in devices {
1144 handles.insert(devid, make_device(len));
1145 }
1146 let mut cache = ChunkTreeCache::default();
1147 for m in mappings {
1148 cache.insert(m.clone());
1149 }
1150 BlockReader::new_multi(handles, 4096, cache)
1151 }
1152
1153 #[test]
1154 fn read_block_routes_to_correct_devid() {
1155 let mapping =
1161 make_mapping(1_000_000, 4096, &[(2, 50_000), (1, 20_000)]);
1162 let mut reader = make_reader(&[(1, 100_000), (2, 100_000)], &[mapping]);
1163
1164 reader.devices_mut().get_mut(&1).unwrap().get_mut()
1167 [20_000..20_000 + 4096]
1168 .fill(0xAA);
1169 reader.devices_mut().get_mut(&2).unwrap().get_mut()
1170 [50_000..50_000 + 4096]
1171 .fill(0xBB);
1172
1173 let buf = reader.read_block(1_000_000).expect("read_block");
1176 assert_eq!(buf.len(), 4096);
1177 assert!(buf.iter().all(|&b| b == 0xBB), "expected all 0xBB");
1178 }
1179
1180 #[test]
1181 fn read_data_routes_to_correct_devid() {
1182 let mapping = make_mapping(1_000_000, 4096, &[(5, 8000)]);
1183 let mut reader = make_reader(&[(5, 100_000)], &[mapping]);
1184 reader.devices_mut().get_mut(&5).unwrap().get_mut()[8000..8000 + 100]
1185 .fill(0xCC);
1186
1187 let buf = reader.read_data(1_000_000, 100).expect("read_data");
1188 assert_eq!(buf, vec![0xCC; 100]);
1189 }
1190
1191 #[test]
1192 fn write_block_fans_out_to_all_stripes() {
1193 let mapping = make_mapping(2_000_000, 4096, &[(1, 1000), (2, 7000)]);
1196 let mut reader = make_reader(&[(1, 100_000), (2, 100_000)], &[mapping]);
1197
1198 let payload = vec![0xDDu8; 4096];
1199 reader
1200 .write_block(2_000_000, &payload)
1201 .expect("write_block");
1202
1203 let dev1 = reader.devices().get(&1).unwrap().get_ref();
1204 let dev2 = reader.devices().get(&2).unwrap().get_ref();
1205 assert_eq!(&dev1[1000..1000 + 4096], &payload[..]);
1206 assert_eq!(&dev2[7000..7000 + 4096], &payload[..]);
1207 assert!(dev1[..1000].iter().all(|&b| b == 0));
1209 assert!(dev1[1000 + 4096..].iter().all(|&b| b == 0));
1210 assert!(dev2[..7000].iter().all(|&b| b == 0));
1211 assert!(dev2[7000 + 4096..].iter().all(|&b| b == 0));
1212 }
1213
1214 #[test]
1215 fn write_block_fans_out_to_dup_same_devid() {
1216 let mapping = make_mapping(3_000_000, 4096, &[(1, 1000), (1, 50_000)]);
1219 let mut reader = make_reader(&[(1, 100_000)], &[mapping]);
1220
1221 let payload = vec![0xEEu8; 4096];
1222 reader
1223 .write_block(3_000_000, &payload)
1224 .expect("write_block");
1225
1226 let dev = reader.devices().get(&1).unwrap().get_ref();
1227 assert_eq!(&dev[1000..1000 + 4096], &payload[..]);
1228 assert_eq!(&dev[50_000..50_000 + 4096], &payload[..]);
1229 }
1230
1231 #[test]
1232 fn write_block_three_devices_raid1c3() {
1233 let mapping = make_mapping(4_000_000, 4096, &[(1, 0), (2, 0), (3, 0)]);
1234 let mut reader =
1235 make_reader(&[(1, 8192), (2, 8192), (3, 8192)], &[mapping]);
1236
1237 let payload = vec![0xFFu8; 4096];
1238 reader
1239 .write_block(4_000_000, &payload)
1240 .expect("write_block");
1241
1242 for &devid in &[1u64, 2, 3] {
1243 let dev = reader.devices().get(&devid).unwrap().get_ref();
1244 assert_eq!(
1245 &dev[..4096],
1246 &payload[..],
1247 "devid {devid} mirror missing"
1248 );
1249 }
1250 }
1251
1252 #[test]
1253 fn read_block_missing_devid_errors() {
1254 let mapping = make_mapping(5_000_000, 4096, &[(9, 0)]);
1258 let mut reader = make_reader(&[(1, 8192), (2, 8192)], &[mapping]);
1259
1260 let err = reader.read_block(5_000_000).unwrap_err();
1261 assert_eq!(err.kind(), io::ErrorKind::NotFound);
1262 assert!(
1263 err.to_string().contains("device 9"),
1264 "expected error to mention devid 9, got: {err}"
1265 );
1266 }
1267
1268 #[test]
1269 fn write_block_missing_devid_errors() {
1270 let mapping = make_mapping(5_000_000, 4096, &[(1, 0), (9, 0)]);
1271 let mut reader = make_reader(&[(1, 8192)], &[mapping]);
1272
1273 let err = reader.write_block(5_000_000, &[0u8; 4096]).unwrap_err();
1274 assert_eq!(err.kind(), io::ErrorKind::NotFound);
1275 assert!(err.to_string().contains("device 9"));
1276 }
1277
1278 #[test]
1279 fn read_block_unmapped_logical_errors() {
1280 let mut reader = make_reader(&[(1, 8192)], &[]);
1282 let err = reader.read_block(1_000_000).unwrap_err();
1283 assert_eq!(err.kind(), io::ErrorKind::NotFound);
1284 assert!(err.to_string().contains("not mapped"));
1285 }
1286
1287 #[test]
1288 fn new_single_inserts_under_supplied_devid() {
1289 let cursor = make_device(8192);
1292 let cache = ChunkTreeCache::default();
1293 let reader = BlockReader::new(cursor, 7, 4096, cache);
1294 assert_eq!(reader.devices().len(), 1);
1295 assert!(reader.devices().contains_key(&7));
1296 }
1297
1298 #[test]
1299 fn new_multi_with_disjoint_devids() {
1300 let mapping = make_mapping(0, 4096, &[(1, 100), (5, 200)]);
1303 let mut reader = make_reader(&[(1, 8192), (5, 8192)], &[mapping]);
1304
1305 let payload = vec![0x77u8; 4096];
1306 reader.write_block(0, &payload).expect("write_block");
1307 let dev1 = reader.devices().get(&1).unwrap().get_ref();
1308 let dev5 = reader.devices().get(&5).unwrap().get_ref();
1309 assert_eq!(&dev1[100..100 + 4096], &payload[..]);
1310 assert_eq!(&dev5[200..200 + 4096], &payload[..]);
1311 }
1312
1313 #[test]
1314 #[should_panic(expected = "filesystem has 2 devices")]
1315 fn single_device_mut_panics_on_multi_device() {
1316 let mapping = make_mapping(0, 4096, &[(1, 0), (2, 0)]);
1317 let mut reader = make_reader(&[(1, 4096), (2, 4096)], &[mapping]);
1318 let _ = reader.single_device_mut();
1319 }
1320
1321 #[test]
1322 fn single_device_mut_returns_handle_for_single_device() {
1323 let mapping = make_mapping(0, 4096, &[(1, 0)]);
1324 let mut reader = make_reader(&[(1, 8192)], &[mapping]);
1325 reader.single_device_mut().get_mut()[42] = 0x99;
1328 assert_eq!(reader.devices().get(&1).unwrap().get_ref()[42], 0x99);
1329 }
1330}