|
@@ -36,6 +36,8 @@ use tokio::sync::{Mutex, OwnedMutexGuard, OwnedRwLockReadGuard, OwnedRwLockWrite
|
|
|
pub use private::{Authorizer, AuthzContext, Error, LocalFs, ModeAuthorizer};
|
|
|
|
|
|
mod private {
|
|
|
+ use btlib::crypto::SymKey;
|
|
|
+
|
|
|
use super::*;
|
|
|
|
|
|
type Inode = u64;
|
|
@@ -510,8 +512,8 @@ mod private {
|
|
|
}
|
|
|
|
|
|
/// Decrements the lookup count from the given path by the given amount.
|
|
|
- fn decr_lookup_count(&mut self, from: &Arc<BlockPath>, decr: u64) {
|
|
|
- match self.lookup_counts.entry(from.clone()) {
|
|
|
+ fn decr_lookup_count(&mut self, from: Arc<BlockPath>, decr: u64) {
|
|
|
+ match self.lookup_counts.entry(from) {
|
|
|
hash_map::Entry::Occupied(mut entry) => {
|
|
|
let new_count = entry.get().saturating_sub(decr);
|
|
|
if new_count > 0 {
|
|
@@ -608,6 +610,7 @@ mod private {
|
|
|
SpecInodes::Sb.into(),
|
|
|
creds.clone(),
|
|
|
root_block_path.clone(),
|
|
|
+ None,
|
|
|
)?;
|
|
|
let sb = Superblock {
|
|
|
generation,
|
|
@@ -631,6 +634,7 @@ mod private {
|
|
|
SpecInodes::RootDir.into(),
|
|
|
creds.clone(),
|
|
|
root_block_path.clone(),
|
|
|
+ None,
|
|
|
)?;
|
|
|
write_to(&Directory::new(), &mut root_block)?;
|
|
|
root_block.mut_meta_body().access_secrets(|secrets| {
|
|
@@ -680,6 +684,7 @@ mod private {
|
|
|
SpecInodes::Sb.into(),
|
|
|
creds.clone(),
|
|
|
root_block_path.to_owned(),
|
|
|
+ None,
|
|
|
)?;
|
|
|
let sb = read_from(&mut sb_block)?;
|
|
|
let root_block = Self::open_block(
|
|
@@ -687,6 +692,7 @@ mod private {
|
|
|
SpecInodes::RootDir.into(),
|
|
|
creds.clone(),
|
|
|
root_block_path,
|
|
|
+ None,
|
|
|
)?;
|
|
|
Self::new(btdir, sb, sb_block, root_block, creds, authorizer)
|
|
|
}
|
|
@@ -737,6 +743,7 @@ mod private {
|
|
|
inode: Inode,
|
|
|
creds: C,
|
|
|
block_path: BlockPath,
|
|
|
+ parent_key: Option<SymKey>,
|
|
|
) -> Result<Accessor<FileBlock<C>>> {
|
|
|
let path = Self::block_path(&btdir, inode);
|
|
|
let dir = path.ancestors().nth(1).unwrap();
|
|
@@ -751,18 +758,20 @@ mod private {
|
|
|
.write(true)
|
|
|
.create(true)
|
|
|
.open(path)?;
|
|
|
- Self::open_block_file(file, creds, block_path)
|
|
|
+ Self::open_block_file(file, creds, block_path, parent_key)
|
|
|
}
|
|
|
|
|
|
fn open_block_file(
|
|
|
file: File,
|
|
|
creds: C,
|
|
|
block_path: BlockPath,
|
|
|
+ parent_key: Option<SymKey>,
|
|
|
) -> Result<Accessor<FileBlock<C>>> {
|
|
|
let block = BlockOpenOptions::new()
|
|
|
.with_creds(creds)
|
|
|
.with_encrypt(true)
|
|
|
.with_inner(file)
|
|
|
+ .with_parent_key(parent_key)
|
|
|
.with_block_path(block_path)
|
|
|
.open()?;
|
|
|
Ok(block)
|
|
@@ -774,12 +783,19 @@ mod private {
|
|
|
|
|
|
async fn open_value(
|
|
|
&self,
|
|
|
- from: &Arc<BlockPath>,
|
|
|
+ from: Arc<BlockPath>,
|
|
|
inode: Inode,
|
|
|
block_path: BlockPath,
|
|
|
+ parent_key: Option<SymKey>,
|
|
|
) -> Result<()> {
|
|
|
- let block = Self::open_block(&self.path, inode, self.creds.clone(), block_path)?;
|
|
|
- let value = Arc::new(RwLock::new(InodeTableValue::new(block, from.clone())));
|
|
|
+ let block = Self::open_block(
|
|
|
+ &self.path,
|
|
|
+ inode,
|
|
|
+ self.creds.clone(),
|
|
|
+ block_path,
|
|
|
+ parent_key,
|
|
|
+ )?;
|
|
|
+ let value = Arc::new(RwLock::new(InodeTableValue::new(block, from)));
|
|
|
let mut inodes = self.inodes.write().await;
|
|
|
if inodes.insert(inode, value).is_some() {
|
|
|
error!(
|
|
@@ -789,27 +805,33 @@ mod private {
|
|
|
Ok(())
|
|
|
}
|
|
|
|
|
|
+ /// Ensures that the given inode is open. If the inode is already open, then this method
|
|
|
+ /// does nothing and returns the table guard which was used to check the status of the
|
|
|
+ /// inode.
|
|
|
+ /// ## Warning
|
|
|
+ /// Because this method creates new table guards, no table guard must be alive when it's
|
|
|
+ /// called. Otherwise a deadlock will occur.
|
|
|
async fn ensure_open<'a>(
|
|
|
&'a self,
|
|
|
from: &Arc<BlockPath>,
|
|
|
inode: Inode,
|
|
|
block_path: BlockPath,
|
|
|
+ parent_key: Option<SymKey>,
|
|
|
) -> Result<TableGuard<C>> {
|
|
|
{
|
|
|
- let inodes = self.inodes.clone().read_owned().await;
|
|
|
- if inodes.contains_key(&inode) {
|
|
|
- return Ok(TableGuard {
|
|
|
- table_guard: inodes,
|
|
|
- });
|
|
|
+ let table_guard = self.inodes.clone().read_owned().await;
|
|
|
+ if table_guard.contains_key(&inode) {
|
|
|
+ return Ok(TableGuard { table_guard });
|
|
|
}
|
|
|
}
|
|
|
- self.open_value(from, inode, block_path).await?;
|
|
|
+ self.open_value(from.clone(), inode, block_path, parent_key)
|
|
|
+ .await?;
|
|
|
Ok(TableGuard::new(self.inodes.clone()).await)
|
|
|
}
|
|
|
|
|
|
async fn inode_forget<'a>(
|
|
|
&self,
|
|
|
- from: &Arc<BlockPath>,
|
|
|
+ from: Arc<BlockPath>,
|
|
|
inode: Inode,
|
|
|
count: u64,
|
|
|
) -> io::Result<()> {
|
|
@@ -880,7 +902,7 @@ mod private {
|
|
|
|
|
|
/// Grants the given credentials access to the directory this instance is responsible for.
|
|
|
///
|
|
|
- /// # Warning
|
|
|
+ /// ## Warning
|
|
|
/// This method calls `self.authz_attrs`, so the same consideration for avoiding deadlock
|
|
|
/// apply to this method as well. See the documentation of `self.authz_attrs` for details.
|
|
|
async fn grant_access_to(
|
|
@@ -891,12 +913,12 @@ mod private {
|
|
|
) -> Result<()> {
|
|
|
let authz_attrs = self.authz_attrs(from).await?;
|
|
|
let principal = proc_rec.pub_creds.principal();
|
|
|
- let next_inode = {
|
|
|
+ let (next_inode, parent_key) = {
|
|
|
let table_guard = self.table_guard().await;
|
|
|
|
|
|
let next_inode = if inode == SpecInodes::RootDir.value() {
|
|
|
// If the inode is for the root directory we need to add a readcap for the
|
|
|
- // superblock when we access it.
|
|
|
+ // superblock.
|
|
|
let mut value_guard = table_guard.write(SpecInodes::Sb.into()).await?;
|
|
|
let mut block = &mut value_guard.block;
|
|
|
let next_inode = self.next_inode.fetch_add(1, Ordering::Relaxed);
|
|
@@ -916,7 +938,7 @@ mod private {
|
|
|
self.next_inode().await
|
|
|
}?;
|
|
|
|
|
|
- {
|
|
|
+ let parent_key = {
|
|
|
let mut value_guard = table_guard.write(inode).await?;
|
|
|
let block = &mut value_guard.block;
|
|
|
self.authorizer.can_write(&AuthzContext::new(
|
|
@@ -934,37 +956,40 @@ mod private {
|
|
|
// Note that write_dir calls flush, which also ensures metadata is written to
|
|
|
// disk.
|
|
|
block.write_dir(&dir)?;
|
|
|
- }
|
|
|
|
|
|
- next_inode
|
|
|
+ block.meta_body().block_key()?.clone()
|
|
|
+ };
|
|
|
+
|
|
|
+ (next_inode, parent_key)
|
|
|
};
|
|
|
|
|
|
let self_writecap = self.creds.writecap().ok_or(BlockError::MissingWritecap)?;
|
|
|
let self_bind_path = Arc::new(self_writecap.bind_path());
|
|
|
let bind_path = proc_rec.writecap.bind_path();
|
|
|
- self.open_value(&self_bind_path, next_inode, bind_path)
|
|
|
- .await?;
|
|
|
+ self.open_value(
|
|
|
+ self_bind_path.clone(),
|
|
|
+ next_inode,
|
|
|
+ bind_path,
|
|
|
+ Some(parent_key),
|
|
|
+ )
|
|
|
+ .await?;
|
|
|
{
|
|
|
let table_guard = self.table_guard().await;
|
|
|
let mut value_guard = table_guard.write(next_inode).await?;
|
|
|
let block = &mut value_guard.block;
|
|
|
- // TODO: Adding a readcap should not be necessary because the principal has been
|
|
|
- // given access to the root directory.
|
|
|
- // Once proper inherited readcaps are implemented we will
|
|
|
- // no longer need to add a readcap to this block.
|
|
|
- block
|
|
|
- .mut_meta_body()
|
|
|
- .add_readcap_for(principal, &proc_rec.pub_creds.enc)?;
|
|
|
block.write_proc_rec(&ProcRec::Valid(proc_rec))?;
|
|
|
};
|
|
|
// We must ensure the reference count for the inode is decremented, otherwise the table
|
|
|
// entry will never be freed.
|
|
|
- self.inode_forget(&self_bind_path, next_inode, 1).await?;
|
|
|
+ self.inode_forget(self_bind_path, next_inode, 1).await?;
|
|
|
Ok(())
|
|
|
}
|
|
|
|
|
|
- async fn lookup_inode_in(&self, parent: Inode, name: &str) -> Result<Inode> {
|
|
|
- let table_guard = self.table_guard().await;
|
|
|
+ async fn lookup_inode_in(
|
|
|
+ table_guard: &TableGuard<C>,
|
|
|
+ parent: Inode,
|
|
|
+ name: &str,
|
|
|
+ ) -> Result<Inode> {
|
|
|
let mut value_guard = table_guard.write(parent).await?;
|
|
|
let dir = value_guard.block.read_dir()?;
|
|
|
dir.entry(name)
|
|
@@ -972,20 +997,20 @@ mod private {
|
|
|
.map(|e| e.inode())
|
|
|
}
|
|
|
|
|
|
+ /// Returns a pair of inodes, where the first inode is the inode referred to by the given
|
|
|
+ /// path, and the second is the parent inode.
|
|
|
async fn lookup_inode<'a, I: Iterator<Item = &'a str>>(
|
|
|
- &self,
|
|
|
+ table_guard: &TableGuard<C>,
|
|
|
components: I,
|
|
|
- ) -> Result<Inode> {
|
|
|
+ ) -> Result<(Inode, Option<Inode>)> {
|
|
|
const ROOT: Inode = SpecInodes::RootDir as Inode;
|
|
|
+ let mut parent = None;
|
|
|
let mut inode = ROOT;
|
|
|
for component in components {
|
|
|
- inode = self.lookup_inode_in(inode, component).await?;
|
|
|
- }
|
|
|
- if inode == ROOT {
|
|
|
- Err(io::Error::from_raw_os_error(libc::ENOENT).into())
|
|
|
- } else {
|
|
|
- Ok(inode)
|
|
|
+ parent = Some(inode);
|
|
|
+ inode = Self::lookup_inode_in(table_guard, inode, component).await?;
|
|
|
}
|
|
|
+ Ok((inode, parent))
|
|
|
}
|
|
|
|
|
|
/// Retrieves the authorization attributes for the principal identified by the given path.
|
|
@@ -1011,10 +1036,21 @@ mod private {
|
|
|
}
|
|
|
let local_root = writecap.path();
|
|
|
let relative = from.relative_to(local_root)?;
|
|
|
- let inode = self.lookup_inode(relative.components()).await?;
|
|
|
+ let (inode, parent_key) = {
|
|
|
+ let table_guard = self.table_guard().await;
|
|
|
+ let (inode, parent) =
|
|
|
+ Self::lookup_inode(&table_guard, relative.components()).await?;
|
|
|
+ let parent_key = if let Some(parent) = parent {
|
|
|
+ let value_guard = table_guard.read(parent).await?;
|
|
|
+ Some(value_guard.block.meta_body().block_key()?.clone())
|
|
|
+ } else {
|
|
|
+ None
|
|
|
+ };
|
|
|
+ (inode, parent_key)
|
|
|
+ };
|
|
|
let proc_rec = {
|
|
|
let table_guard = self
|
|
|
- .ensure_open(from, inode, from.as_ref().to_owned())
|
|
|
+ .ensure_open(from, inode, from.as_ref().to_owned(), parent_key)
|
|
|
.await?;
|
|
|
let mut value_guard = table_guard.write(inode).await?;
|
|
|
value_guard.block.read_proc_rec()?
|
|
@@ -1109,18 +1145,20 @@ mod private {
|
|
|
debug!("lookup: parent {parent}, {:?}", name);
|
|
|
let authz_attrs = self.authz_attrs(from).await?;
|
|
|
|
|
|
- let (dir, block_path) = {
|
|
|
+ let (dir, block_path, parent_key) = {
|
|
|
let table_guard = self.table_guard().await;
|
|
|
- let mut parent_value = table_guard.write(parent).await?;
|
|
|
- let parent_block = &mut parent_value.block;
|
|
|
+ let mut value_guard = table_guard.write(parent).await?;
|
|
|
+ let parent_block = &mut value_guard.block;
|
|
|
self.authorizer.can_exec(&AuthzContext::new(
|
|
|
from,
|
|
|
&authz_attrs,
|
|
|
parent_block.meta(),
|
|
|
))?;
|
|
|
let dir = parent_block.read_dir()?;
|
|
|
- let block_path = parent_block.meta_body().path().to_owned();
|
|
|
- (dir, block_path)
|
|
|
+ let meta_body = parent_block.meta_body();
|
|
|
+ let block_path = meta_body.path().to_owned();
|
|
|
+ let parent_key = meta_body.block_key()?.clone();
|
|
|
+ (dir, block_path, parent_key)
|
|
|
};
|
|
|
|
|
|
let entry = dir
|
|
@@ -1128,7 +1166,9 @@ mod private {
|
|
|
.ok_or_else(|| io::Error::from_raw_os_error(libc::ENOENT))?;
|
|
|
let inode = entry.inode();
|
|
|
let stat = {
|
|
|
- let table_guard = self.ensure_open(from, inode, block_path).await?;
|
|
|
+ let table_guard = self
|
|
|
+ .ensure_open(from, inode, block_path, Some(parent_key))
|
|
|
+ .await?;
|
|
|
let mut value_guard = table_guard.write(inode).await?;
|
|
|
let stat = value_guard.block.meta_body().secrets()?.to_owned();
|
|
|
value_guard.incr_lookup_count(from);
|
|
@@ -1160,7 +1200,7 @@ mod private {
|
|
|
let name = msg.name.to_owned();
|
|
|
|
|
|
// Add a directory entry to the parent for the new inode.
|
|
|
- let (inode, mut block_path) = {
|
|
|
+ let (inode, mut block_path, parent_key) = {
|
|
|
let table_guard = self.table_guard().await;
|
|
|
let mut value_guard = table_guard.write(parent).await?;
|
|
|
let block = &mut value_guard.block;
|
|
@@ -1181,12 +1221,18 @@ mod private {
|
|
|
dir.add_file(name.clone(), inode)?;
|
|
|
block.write_dir(&dir)?;
|
|
|
|
|
|
- (inode, block.meta_body().path().clone())
|
|
|
+ let meta_body = block.meta_body();
|
|
|
+ let block_path = meta_body.path().clone();
|
|
|
+ let parent_key = meta_body.block_key()?.clone();
|
|
|
+
|
|
|
+ (inode, block_path, parent_key)
|
|
|
};
|
|
|
block_path.push_component(name);
|
|
|
|
|
|
let (handle, stat) = {
|
|
|
- let table_guard = self.ensure_open(from, inode, block_path).await?;
|
|
|
+ let table_guard = self
|
|
|
+ .ensure_open(from, inode, block_path, Some(parent_key))
|
|
|
+ .await?;
|
|
|
let mut value_guard = table_guard.write(inode).await?;
|
|
|
let handle =
|
|
|
value_guard.new_handle(from.clone(), FlagValue::ReadWrite.into())?;
|
|
@@ -1444,7 +1490,7 @@ mod private {
|
|
|
let Unlink { parent, name } = msg;
|
|
|
debug!("unlink: parent {parent}, name {name}");
|
|
|
let authz_attrs = self.authz_attrs(from).await?;
|
|
|
- let (block_path, inode) = {
|
|
|
+ let (block_path, inode, parent_key) = {
|
|
|
let table_guard = self.table_guard().await;
|
|
|
let mut value_guard = table_guard.write(parent).await?;
|
|
|
let parent_block = &mut value_guard.block;
|
|
@@ -1463,12 +1509,16 @@ mod private {
|
|
|
let inode = entry.inode();
|
|
|
parent_block.write_dir(&dir)?;
|
|
|
|
|
|
- let mut block_path = parent_block.meta_body().path().clone();
|
|
|
+ let meta_body = parent_block.meta_body();
|
|
|
+ let mut block_path = meta_body.path().clone();
|
|
|
block_path.push_component(name.to_owned());
|
|
|
- (block_path, inode)
|
|
|
+ let parent_key = meta_body.block_key()?.clone();
|
|
|
+ (block_path, inode, parent_key)
|
|
|
};
|
|
|
|
|
|
- let table_guard = self.ensure_open(from, inode, block_path).await?;
|
|
|
+ let table_guard = self
|
|
|
+ .ensure_open(from, inode, block_path, Some(parent_key))
|
|
|
+ .await?;
|
|
|
let mut value = table_guard.write(inode).await?;
|
|
|
// We mark the block for deletion if `nlink` drops to zero.
|
|
|
let block = value.block_mut();
|
|
@@ -1637,7 +1687,7 @@ mod private {
|
|
|
async move {
|
|
|
let Forget { inode, count } = msg;
|
|
|
debug!("forget: inode {inode}, count {count}");
|
|
|
- self.inode_forget(from, inode, count).await.bterr()
|
|
|
+ self.inode_forget(from.clone(), inode, count).await.bterr()
|
|
|
}
|
|
|
}
|
|
|
|