From f56ea2d031ef81cc461450f37b3251953a49d3a0 Mon Sep 17 00:00:00 2001 From: Joe Thornber Date: Mon, 3 Aug 2020 16:22:08 +0100 Subject: [PATCH] [thin_check (rust)] walk devices tree. --- src/pdata/btree.rs | 40 ++++++++-------- src/thin/check.rs | 104 ++++++++++++++++++++++++++++++++--------- src/thin/superblock.rs | 2 +- 3 files changed, 105 insertions(+), 41 deletions(-) diff --git a/src/pdata/btree.rs b/src/pdata/btree.rs index 90d9733..1069eb3 100644 --- a/src/pdata/btree.rs +++ b/src/pdata/btree.rs @@ -9,10 +9,11 @@ use crate::checksum; //------------------------------------------ pub trait ValueType { - type Value; // The size of the value when on disk. fn disk_size() -> u32; - fn unpack(data: &[u8]) -> IResult<&[u8], Self::Value>; + fn unpack(data: &[u8]) -> IResult<&[u8], Self> + where + Self: std::marker::Sized; } const NODE_HEADER_SIZE: usize = 32; @@ -59,7 +60,7 @@ pub enum Node { Leaf { header: NodeHeader, keys: Vec, - values: Vec, + values: Vec, }, } @@ -85,8 +86,7 @@ pub fn unpack_node( let (i, header) = to_any(unpack_node_header(data))?; - // FIXME: lift checks to own fn - if header.value_size != V::disk_size() { + if header.is_leaf && header.value_size != V::disk_size() { return node_err(format!( "value_size mismatch: expected {}, was {}", V::disk_size(), @@ -94,7 +94,7 @@ pub fn unpack_node( )); } - let elt_size = V::disk_size() + 8; + let elt_size = header.value_size + 8; if elt_size as usize * header.max_entries as usize + NODE_HEADER_SIZE > BLOCK_SIZE { return node_err(format!("max_entries is too large ({})", header.max_entries)); } @@ -152,11 +152,7 @@ pub fn unpack_node( //------------------------------------------ -pub struct ValueU64; - -impl ValueType for ValueU64 { - type Value = u64; - +impl ValueType for u64 { fn disk_size() -> u32 { 8 } @@ -180,10 +176,10 @@ pub struct BTreeWalker { } impl BTreeWalker { - pub fn new(engine: AsyncIoEngine, ignore_non_fatal: bool) -> BTreeWalker { + pub fn new(engine: Arc, ignore_non_fatal: bool) -> BTreeWalker { let nr_blocks = engine.get_nr_blocks() as usize; let r: BTreeWalker = BTreeWalker { - engine: Arc::new(engine), + engine: engine, seen: Arc::new(Mutex::new(FixedBitSet::with_capacity(nr_blocks))), ignore_non_fatal, }; @@ -242,16 +238,22 @@ impl BTreeWalker { Ok(()) } - pub fn walk( - &mut self, - visitor: &mut NV, - root: &Block, - ) -> Result<()> + pub fn walk_b(&mut self, visitor: &mut NV, root: &Block) -> Result<()> where NV: NodeVisitor, V: ValueType, { - self.walk_node(visitor, &root, true) + self.walk_node(visitor, &root, true) + } + + pub fn walk(&mut self, visitor: &mut NV, root: u64) -> Result<()> + where + NV: NodeVisitor, + V: ValueType, + { + let mut root = Block::new(root); + self.engine.read(&mut root)?; + self.walk_node(visitor, &root, true) } } diff --git a/src/thin/check.rs b/src/thin/check.rs index 4946c30..3717a73 100644 --- a/src/thin/check.rs +++ b/src/thin/check.rs @@ -1,12 +1,13 @@ use anyhow::{anyhow, Result}; use nom::{number::complete::*, IResult}; +use std::collections::HashMap; use std::path::Path; use std::sync::{Arc, Mutex}; use std::time::Instant; use threadpool::ThreadPool; use crate::block_manager::{AsyncIoEngine, Block, IoEngine}; -use crate::pdata::btree::{BTreeWalker, Node, NodeVisitor, ValueType, ValueU64}; +use crate::pdata::btree::{BTreeWalker, Node, NodeVisitor, ValueType}; use crate::thin::superblock::*; //------------------------------------------ @@ -17,11 +18,7 @@ struct BlockTime { time: u32, } -struct ValueBlockTime; - -impl ValueType for ValueBlockTime { - type Value = BlockTime; - +impl ValueType for BlockTime { fn disk_size() -> u32 { 8 } @@ -43,8 +40,8 @@ impl ValueType for ValueBlockTime { struct TopLevelVisitor {} -impl NodeVisitor for TopLevelVisitor { - fn visit(&mut self, w: &BTreeWalker, _b: &Block, node: &Node) -> Result<()> { +impl NodeVisitor for TopLevelVisitor { + fn visit(&mut self, w: &BTreeWalker, _b: &Block, node: &Node) -> Result<()> { if let Node::Leaf { header: _h, keys, @@ -77,7 +74,7 @@ impl NodeVisitor for TopLevelVisitor { let mut w = w.clone(); pool.execute(move || { let mut v = BottomLevelVisitor {}; - let result = w.walk(&mut v, &b).expect("walk failed"); // FIXME: return error + let result = w.walk_b(&mut v, &b).expect("walk failed"); // FIXME: return error eprintln!("checked thin_dev {} -> {:?}", thin_id, result); }); } @@ -91,8 +88,67 @@ impl NodeVisitor for TopLevelVisitor { struct BottomLevelVisitor {} -impl NodeVisitor for BottomLevelVisitor { - fn visit(&mut self, _w: &BTreeWalker, _b: &Block, _node: &Node) -> Result<()> { +impl NodeVisitor for BottomLevelVisitor { + fn visit(&mut self, _w: &BTreeWalker, _b: &Block, _node: &Node) -> Result<()> { + Ok(()) + } +} + +//------------------------------------------ + +#[derive(Clone)] +struct DeviceDetail { + mapped_blocks: u64, + transaction_id: u64, + creation_time: u32, + snapshotted_time: u32, +} + +impl ValueType for DeviceDetail { + fn disk_size() -> u32 { + 24 + } + + fn unpack(i: &[u8]) -> IResult<&[u8], DeviceDetail> { + let (i, mapped_blocks) = le_u64(i)?; + let (i, transaction_id) = le_u64(i)?; + let (i, creation_time) = le_u32(i)?; + let (i, snapshotted_time) = le_u32(i)?; + + Ok(( + i, + DeviceDetail { + mapped_blocks, + transaction_id, + creation_time, + snapshotted_time, + }, + )) + } +} + +struct DeviceVisitor { + devs: HashMap, +} + +impl DeviceVisitor { + pub fn new() -> DeviceVisitor { + DeviceVisitor { + devs: HashMap::new(), + } + } +} + +impl NodeVisitor for DeviceVisitor { + fn visit(&mut self, _w: &BTreeWalker, _b: &Block, node: &Node) -> Result<()> { + if let Node::Leaf {header: _h, keys, values} = node { + for n in 0..keys.len() { + let k = keys[n] as u32; + let v = values[n].clone(); + self.devs.insert(k, v.clone()); + } + } + Ok(()) } } @@ -101,19 +157,25 @@ impl NodeVisitor for BottomLevelVisitor { pub fn check(dev: &Path) -> Result<()> { //let mut engine = SyncIoEngine::new(dev)?; - let mut engine = AsyncIoEngine::new(dev, 256)?; + let mut engine = Arc::new(AsyncIoEngine::new(dev, 256)?); let now = Instant::now(); - let sb = read_superblock(&mut engine, SUPERBLOCK_LOCATION)?; + let sb = read_superblock(engine.as_ref(), SUPERBLOCK_LOCATION)?; eprintln!("{:?}", sb); - - let mut root = Block::new(sb.mapping_root); - engine.read(&mut root)?; - - let mut visitor = TopLevelVisitor {}; - let mut w = BTreeWalker::new(engine, false); - let _result = w.walk(&mut visitor, &root)?; - println!("read mapping tree in {} ms", now.elapsed().as_millis()); + + { + let mut visitor = DeviceVisitor::new(); + let mut w = BTreeWalker::new(engine.clone(), false); + w.walk(&mut visitor, sb.details_root)?; + println!("found {} devices", visitor.devs.len()); + } + + { + let mut visitor = TopLevelVisitor {}; + let mut w = BTreeWalker::new(engine.clone(), false); + let _result = w.walk(&mut visitor, sb.mapping_root)?; + println!("read mapping tree in {} ms", now.elapsed().as_millis()); + } Ok(()) } diff --git a/src/thin/superblock.rs b/src/thin/superblock.rs index e52d7f2..5001eb6 100644 --- a/src/thin/superblock.rs +++ b/src/thin/superblock.rs @@ -85,7 +85,7 @@ fn unpack(data: &[u8]) -> IResult<&[u8], Superblock> { )) } -pub fn read_superblock(engine: &mut E, loc: u64) -> Result { +pub fn read_superblock(engine: &E, loc: u64) -> Result { let mut b = Block::new(loc); engine.read(&mut b)?;