Преглед изворни кода

Added a crate for the blocktree file server.

Matthew Carr пре 2 година
родитељ
комит
bc80d18027
6 измењених фајлова са 168 додато и 22 уклоњено
  1. 10 0
      Cargo.lock
  2. 1 0
      Cargo.toml
  3. 12 0
      crates/btfs/Cargo.toml
  4. 78 0
      crates/btfs/src/main.rs
  5. 4 3
      crates/btlib/src/blocktree.rs
  6. 63 19
      crates/btmsg/src/lib.rs

+ 10 - 0
Cargo.lock

@@ -183,6 +183,16 @@ dependencies = [
  "alloc-stdlib",
 ]
 
+[[package]]
+name = "btfs"
+version = "0.1.0"
+dependencies = [
+ "btlib",
+ "btmsg",
+ "log",
+ "tss-esapi",
+]
+
 [[package]]
 name = "btfuse"
 version = "0.1.0"

+ 1 - 0
Cargo.toml

@@ -8,6 +8,7 @@ members = [
     "crates/test-harness",
     "crates/btfuse",
     "crates/swtpm-harness",
+    "crates/btfs",
 ]
 
 [profile.bench]

+ 12 - 0
crates/btfs/Cargo.toml

@@ -0,0 +1,12 @@
+[package]
+name = "btfs"
+version = "0.1.0"
+edition = "2021"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+btlib = { path = "../btlib" }
+btmsg = { path = "../btmsg" }
+tss-esapi = { version = "7.1.0", features = ["generate-bindings"] }
+log = "0.4.17"

+ 78 - 0
crates/btfs/src/main.rs

@@ -0,0 +1,78 @@
+use log::info;
+use std::{
+    env::{self, VarError},
+    fs, io,
+    path::Path,
+    path::PathBuf,
+    str::FromStr,
+};
+use tss_esapi::{tcti_ldr::TabrmdConfig, Context};
+
+use btlib::{
+    blocktree::{Blocktree, ModeAuthorizer},
+    crypto::{
+        tpm::{TpmCredStore, TpmCreds},
+        CredStore,
+    },
+};
+
+const PATH_ENV: &str = "BT_DIR";
+const TABRMD_ENV: &str = "BT_TABRMD";
+const TABRMD_CONFIG: &str = "bus_type=session,bus_name=com.intel.tss2.Tabrmd";
+const STATE_FILE: &str = "tpm_state";
+const BLOCK_DIR: &str = "blocks";
+
+fn btdir() -> PathBuf {
+    env::var(PATH_ENV).map(PathBuf::from).unwrap_or_else(|err| {
+        if let VarError::NotPresent = err {
+            let mut path_buf: PathBuf = env::var("HOME").unwrap().into();
+            path_buf.push(".config");
+            path_buf.push("blocktree");
+            path_buf
+        } else {
+            panic!("invalid value of the '{PATH_ENV}' environment variable");
+        }
+    })
+}
+
+fn tabrmd_config() -> String {
+    env::var(TABRMD_ENV).unwrap_or_else(|err| {
+        if let VarError::NotPresent = err {
+            TABRMD_CONFIG.to_string()
+        } else {
+            panic!("invalid value of the '{TABRMD_ENV}' environment variable");
+        }
+    })
+}
+
+fn make_blocktree(btdir: &Path, creds: TpmCreds) -> Blocktree<TpmCreds, ModeAuthorizer> {
+    let block_dir = btdir.join(BLOCK_DIR);
+    let exists = match fs::read_dir(&block_dir) {
+        Ok(_) => true,
+        Err(err) => {
+            if let io::ErrorKind::NotFound = err.kind() {
+                false
+            } else {
+                panic!("unexpected error occurred when checking if block dir exists: {err}");
+            }
+        }
+    };
+    if exists {
+        Blocktree::new_existing(block_dir, creds, ModeAuthorizer {}).unwrap()
+    } else {
+        Blocktree::new_empty(block_dir, 0, creds, ModeAuthorizer {}).unwrap()
+    }
+}
+
+fn main() {
+    let btdir = btdir();
+    info!("using btdir= '{}'", btdir.display());
+    fs::create_dir_all(&btdir).unwrap();
+    let tabrmd_config = tabrmd_config();
+    info!("using tabrmd_config = '{tabrmd_config}'");
+    let context =
+        Context::new_with_tabrmd(TabrmdConfig::from_str(&tabrmd_config).unwrap()).unwrap();
+    let cred_store = TpmCredStore::new(context, btdir.join(STATE_FILE)).unwrap();
+    let node_creds = cred_store.node_creds().unwrap();
+    let _bt = make_blocktree(&btdir, node_creds);
+}

+ 4 - 3
crates/btlib/src/blocktree.rs

@@ -9,7 +9,10 @@ use log::{debug, error, warn};
 use positioned_io::Size;
 use serde::{Deserialize, Serialize};
 use std::{
-    collections::hash_map::{self, HashMap},
+    collections::{
+        hash_map::{self, HashMap},
+        BTreeMap,
+    },
     ffi::CStr,
     fmt::{Display, Formatter},
     fs::File,
@@ -35,8 +38,6 @@ use crate::{
 pub use private::{Blocktree, ModeAuthorizer, SpecInodes};
 
 mod private {
-    use std::collections::BTreeMap;
-
     use super::*;
 
     type Inode = u64;

+ 63 - 19
crates/btmsg/src/lib.rs

@@ -14,7 +14,14 @@ use futures::{
 };
 use lazy_static::lazy_static;
 use serde::{Deserialize, Serialize};
-use std::{io, marker::PhantomData, net::Shutdown, path::PathBuf};
+use std::{
+    io,
+    marker::PhantomData,
+    net::Shutdown,
+    path::PathBuf,
+    collections::hash_map::DefaultHasher,
+    hash::{Hash, Hasher},
+};
 use tokio::{
     io::{AsyncRead, AsyncWrite, ReadBuf},
     net::UnixDatagram,
@@ -39,23 +46,56 @@ mod private {
 
     /// Appends the given Blocktree path to the path of the given directory.
     fn socket_path(fs_path: &mut PathBuf, addr: &BlockAddr) {
-        fs_path.push(addr.inode.to_string());
+        fs_path.push(addr.num.value().to_string());
+    }
+
+    /// An identifier for a block. Persistent blocks (files, directories, and servers) are
+    /// identified by the `Inode` variant and transient blocks (processes) are identified by the
+    /// PID variant.
+    #[derive(Serialize, Deserialize, PartialEq, Eq, Hash, Clone, Debug)]
+    pub enum BlockNum {
+        Inode(u64),
+        Pid(u64),
+    }
+
+    impl BlockNum {
+        pub fn value(&self) -> u64 {
+            match self {
+                BlockNum::Inode(value) => *value,
+                BlockNum::Pid(value) => *value,
+            }
+        }
+    }
+
+    impl From<BlockNum> for u64 {
+        fn from(value: BlockNum) -> Self {
+            value.value()
+        }
     }
 
-    #[derive(Serialize, Deserialize, PartialEq, Eq, Default, Hash, Clone, Debug)]
+    #[derive(Serialize, Deserialize, PartialEq, Eq, Hash, Clone, Debug)]
     pub struct BlockAddr {
+        /// The root principal of the blocktree this block is part of.
         pub root: Principal,
-        pub generation: u64,
-        pub inode: u64,
+        /// The cluster ID this block is served by.
+        pub cluster: u64,
+        /// The number of this block.
+        pub num: BlockNum,
     }
 
     impl BlockAddr {
-        pub fn new(root: Principal, generation: u64, inode: u64) -> Self {
-            Self {
-                root,
-                generation,
-                inode,
-            }
+        pub fn new(root: Principal, cluster: u64, num: BlockNum) -> Self {
+            Self { root, cluster, num }
+        }
+
+        pub fn port(&self) -> u16 {
+            let mut hasher = DefaultHasher::new();
+            self.hash(&mut hasher);
+            let hash = hasher.finish();
+            // We compute a port in the dynamic range [49152, 65535] as defined by RFC 6335.
+            const NUM_RES_PORTS: u16 = 49153;
+            const PORTS_AVAIL: u64 = (u16::MAX - NUM_RES_PORTS) as u64;
+            NUM_RES_PORTS + (hash % PORTS_AVAIL) as u16
         }
     }
 
@@ -91,11 +131,6 @@ mod private {
         }
     }
 
-    #[derive(Serialize, Deserialize)]
-    enum VerMsg<T> {
-        V0(Msg<T>),
-    }
-
     /// A type which can be used to send messages.
     pub trait Sender {
         type SendFut<'a, T>: 'a + Future<Output = Result<()>> + core::marker::Send
@@ -135,7 +170,7 @@ mod private {
             const U64_LEN: usize = std::mem::size_of::<u64>();
             let payload = dst.split_off(U64_LEN);
             let mut writer = payload.writer();
-            write_to(&VerMsg::V0(item), &mut writer)?;
+            write_to(&item, &mut writer)?;
             let payload = writer.into_inner();
             let payload_len = payload.len() as u64;
             let mut writer = dst.writer();
@@ -168,7 +203,7 @@ mod private {
                 src.reserve(payload_len - slice.len());
                 return Ok(None);
             }
-            let VerMsg::V0(msg) = read_from(&mut slice)?;
+            let msg = read_from(&mut slice)?;
             // Consume all the bytes that have been read out of the buffer.
             let _ = src.split_to(std::mem::size_of::<u64>() + payload_len);
             Ok(Some(msg))
@@ -365,7 +400,7 @@ mod tests {
     }
 
     fn block_addr(generation: u64, inode: u64) -> BlockAddr {
-        BlockAddr::new(ROOT_PRINCIPAL.clone(), generation, inode)
+        BlockAddr::new(ROOT_PRINCIPAL.clone(), generation, BlockNum::Inode(inode))
     }
 
     #[derive(Serialize, Deserialize)]
@@ -411,6 +446,15 @@ mod tests {
         }
     }
 
+    /// This tests just server to ensure that changes to the port hashing algorithm are made
+    /// deliberately.
+    #[test]
+    fn hash_block_addr() {
+        let block_addr = BlockAddr::new(ROOT_PRINCIPAL.clone(), 1, BlockNum::Inode(1));
+        let port = block_addr.port();
+        assert_eq!(64984, port);
+    }
+
     #[tokio::test]
     async fn message_received_is_message_sent() {
         let case = TestCase::new();