|
@@ -5,23 +5,23 @@ use btlib::{
|
|
|
accessor::Accessor,
|
|
|
bterr,
|
|
|
crypto::{Creds, Decrypter, Signer},
|
|
|
- error::{BtErr, DisplayErr},
|
|
|
+ error::BtErr,
|
|
|
AuthzAttrs, BlockAccessor, BlockError, BlockMeta, BlockMetaSecrets, BlockOpenOptions,
|
|
|
BlockPath, BlockReader, DirEntry, Directory, Epoch, FileBlock, FlushMeta, IssuedProcRec,
|
|
|
MetaAccess, MetaReader, Positioned, Principal, Principaled, ProcRec, Result, Split, TrySeek,
|
|
|
- WriteDual, ZeroExtendable,
|
|
|
+ ZeroExtendable,
|
|
|
};
|
|
|
use btserde::{read_from, write_to};
|
|
|
-use core::future::{ready, Ready};
|
|
|
+use core::future::Ready;
|
|
|
use log::{debug, error, warn};
|
|
|
-use positioned_io::Size;
|
|
|
+use positioned_io::{ReadAt, Size};
|
|
|
use serde::{Deserialize, Serialize};
|
|
|
use std::{
|
|
|
collections::hash_map::{self, HashMap},
|
|
|
fmt::{Display, Formatter},
|
|
|
fs::File,
|
|
|
future::Future,
|
|
|
- io::{self, Read as IoRead, Seek, SeekFrom, Write as IoWrite},
|
|
|
+ io::{self, Seek, SeekFrom, Write as IoWrite},
|
|
|
net::{IpAddr, Ipv6Addr},
|
|
|
ops::{Deref, DerefMut},
|
|
|
path::{Path, PathBuf},
|
|
@@ -31,17 +31,11 @@ use std::{
|
|
|
},
|
|
|
time::Duration,
|
|
|
};
|
|
|
-use tokio::sync::{
|
|
|
- Mutex, MutexGuard, RwLock, RwLockReadGuard, RwLockWriteGuard,
|
|
|
-};
|
|
|
+use tokio::sync::{Mutex, OwnedMutexGuard, OwnedRwLockReadGuard, OwnedRwLockWriteGuard, RwLock};
|
|
|
|
|
|
pub use private::{Authorizer, AuthzContext, Error, LocalFs, ModeAuthorizer};
|
|
|
|
|
|
mod private {
|
|
|
- use btlib::DropTrigger;
|
|
|
-
|
|
|
- use crate::server::{ReadGuard, ReadingGuard, WriteGuard};
|
|
|
-
|
|
|
use super::*;
|
|
|
|
|
|
type Inode = u64;
|
|
@@ -173,21 +167,21 @@ mod private {
|
|
|
}
|
|
|
|
|
|
type HandleValueParts<'a> = (
|
|
|
- &'a Mutex<Option<Accessor<&'static [u8]>>>,
|
|
|
+ &'a Arc<Mutex<Option<Accessor<&'static [u8]>>>>,
|
|
|
&'a Arc<BlockPath>,
|
|
|
Flags,
|
|
|
);
|
|
|
|
|
|
- struct HandleGuard<'a, B: Size> {
|
|
|
- guard: MutexGuard<'a, Option<Accessor<&'static [u8]>>>,
|
|
|
+ struct HandleGuard<B: Size> {
|
|
|
+ guard: OwnedMutexGuard<Option<Accessor<&'static [u8]>>>,
|
|
|
accessor: Option<Accessor<B>>,
|
|
|
flags: Flags,
|
|
|
}
|
|
|
|
|
|
- impl<'a, B: Size> HandleGuard<'a, B> {
|
|
|
+ impl<B: Size> HandleGuard<B> {
|
|
|
fn new(
|
|
|
flags: Flags,
|
|
|
- mut guard: MutexGuard<'a, Option<Accessor<&'static [u8]>>>,
|
|
|
+ mut guard: OwnedMutexGuard<Option<Accessor<&'static [u8]>>>,
|
|
|
block: B,
|
|
|
) -> Self {
|
|
|
let accessor = guard
|
|
@@ -201,7 +195,7 @@ mod private {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- impl<'a, B: Size> Drop for HandleGuard<'a, B> {
|
|
|
+ impl<B: Size> Drop for HandleGuard<B> {
|
|
|
fn drop(&mut self) {
|
|
|
*self.guard = self.accessor.take().map(|accessor| {
|
|
|
let (accessor, _) = accessor.split();
|
|
@@ -210,14 +204,14 @@ mod private {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- impl<'a, B: Size> Deref for HandleGuard<'a, B> {
|
|
|
+ impl<B: Size> Deref for HandleGuard<B> {
|
|
|
type Target = Accessor<B>;
|
|
|
fn deref(&self) -> &Self::Target {
|
|
|
self.accessor.as_ref().unwrap()
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- impl<'a, B: Size> DerefMut for HandleGuard<'a, B> {
|
|
|
+ impl<B: Size> DerefMut for HandleGuard<B> {
|
|
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
|
|
self.accessor.as_mut().unwrap()
|
|
|
}
|
|
@@ -225,12 +219,12 @@ mod private {
|
|
|
|
|
|
enum HandleValue {
|
|
|
File {
|
|
|
- accessor: Mutex<Option<Accessor<&'static [u8]>>>,
|
|
|
+ accessor: Arc<Mutex<Option<Accessor<&'static [u8]>>>>,
|
|
|
owner: Arc<BlockPath>,
|
|
|
flags: Flags,
|
|
|
},
|
|
|
Directory {
|
|
|
- accessor: Mutex<Option<Accessor<&'static [u8]>>>,
|
|
|
+ accessor: Arc<Mutex<Option<Accessor<&'static [u8]>>>>,
|
|
|
owner: Arc<BlockPath>,
|
|
|
flags: Flags,
|
|
|
dir: Directory,
|
|
@@ -241,7 +235,7 @@ mod private {
|
|
|
fn new<T: Size>(accessor: Accessor<T>, owner: Arc<BlockPath>, flags: Flags) -> HandleValue {
|
|
|
let (accessor, ..) = accessor.split();
|
|
|
HandleValue::File {
|
|
|
- accessor: Mutex::new(Some(accessor)),
|
|
|
+ accessor: Arc::new(Mutex::new(Some(accessor))),
|
|
|
owner,
|
|
|
flags,
|
|
|
}
|
|
@@ -273,7 +267,7 @@ mod private {
|
|
|
fn convert_to_dir<C: Signer + Principaled + Decrypter>(
|
|
|
self,
|
|
|
block: &mut FileBlock<C>,
|
|
|
- ) -> io::Result<HandleValue> {
|
|
|
+ ) -> Result<HandleValue> {
|
|
|
let (accessor, owner, flags) = match self {
|
|
|
Self::File {
|
|
|
accessor,
|
|
@@ -287,15 +281,18 @@ mod private {
|
|
|
..
|
|
|
} => (accessor, owner, flags),
|
|
|
};
|
|
|
+ let accessor = Arc::try_unwrap(accessor).map_err(|_| {
|
|
|
+ bterr!("LOGIC ERROR: accessor was still in use even though convert_to_dir owns it")
|
|
|
+ })?;
|
|
|
let accessor = accessor
|
|
|
.into_inner()
|
|
|
- .ok_or_else(|| bterr!("a thread paniced while it held the accessor lock"))?;
|
|
|
+ .ok_or_else(|| bterr!("LOGIC ERROR: accessor was not returned to mutex"))?;
|
|
|
let mut accessor = Accessor::combine(accessor, block);
|
|
|
let dir = accessor.read_dir()?;
|
|
|
let (accessor, ..) = accessor.split();
|
|
|
Ok(HandleValue::Directory {
|
|
|
dir,
|
|
|
- accessor: Mutex::new(Some(accessor)),
|
|
|
+ accessor: Arc::new(Mutex::new(Some(accessor))),
|
|
|
owner,
|
|
|
flags,
|
|
|
})
|
|
@@ -311,10 +308,21 @@ mod private {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- async fn guard<'a, B: Size>(&'a self, from: &BlockPath, block: B) -> Result<HandleGuard<'a, B>> {
|
|
|
+ async fn lock(
|
|
|
+ &self,
|
|
|
+ from: &BlockPath,
|
|
|
+ ) -> Result<(Flags, OwnedMutexGuard<Option<Accessor<&'static [u8]>>>)> {
|
|
|
let (mutex, owner, flags) = self.parts();
|
|
|
owner.assert_eq(from)?;
|
|
|
- let guard = mutex.lock().await;
|
|
|
+ Ok((flags, mutex.clone().lock_owned().await))
|
|
|
+ }
|
|
|
+
|
|
|
+ async fn guard<'a, B: Size>(
|
|
|
+ &'a self,
|
|
|
+ from: &BlockPath,
|
|
|
+ block: B,
|
|
|
+ ) -> Result<HandleGuard<B>> {
|
|
|
+ let (flags, guard) = self.lock(from).await?;
|
|
|
Ok(HandleGuard::new(flags, guard, block))
|
|
|
}
|
|
|
|
|
@@ -326,6 +334,47 @@ mod private {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ struct BlockGuard<B> {
|
|
|
+ inner: B,
|
|
|
+ }
|
|
|
+
|
|
|
+ impl<B> BlockGuard<B> {
|
|
|
+ fn new(inner: B) -> Self {
|
|
|
+ Self { inner }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ impl<C, B: Deref<Target = InodeTableValue<C>>> Deref for BlockGuard<B> {
|
|
|
+ type Target = FileBlock<C>;
|
|
|
+ fn deref(&self) -> &Self::Target {
|
|
|
+ self.inner.block.get_ref()
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ impl<C, B: DerefMut<Target = InodeTableValue<C>>> DerefMut for BlockGuard<B> {
|
|
|
+ fn deref_mut(&mut self) -> &mut Self::Target {
|
|
|
+ self.inner.block.get_mut()
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ impl<C, B: Deref<Target = InodeTableValue<C>>> Size for BlockGuard<B> {
|
|
|
+ fn size(&self) -> io::Result<Option<u64>> {
|
|
|
+ self.inner.block.size()
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ impl<C, B: Deref<Target = InodeTableValue<C>>> ReadAt for BlockGuard<B> {
|
|
|
+ fn read_at(&self, pos: u64, buf: &mut [u8]) -> io::Result<usize> {
|
|
|
+ self.inner.block.get_ref().read_at(pos, buf)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ impl<C: 'static, B: Deref<Target = InodeTableValue<C>>> AsRef<BlockMeta> for BlockGuard<B> {
|
|
|
+ fn as_ref(&self) -> &BlockMeta {
|
|
|
+ self.inner.block.as_ref()
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
pub struct InodeTableValue<C> {
|
|
|
block: Accessor<FileBlock<C>>,
|
|
|
handle_values: HashMap<Handle, HandleValue>,
|
|
@@ -380,17 +429,28 @@ mod private {
|
|
|
&'a self,
|
|
|
from: &BlockPath,
|
|
|
handle: Handle,
|
|
|
- ) -> Result<HandleGuard<'a, &FileBlock<C>>> {
|
|
|
+ ) -> Result<HandleGuard<&FileBlock<C>>> {
|
|
|
let value = self.value(handle)?;
|
|
|
let block = self.block();
|
|
|
value.guard(from, block).await
|
|
|
}
|
|
|
|
|
|
+ async fn handle_guard_owned(
|
|
|
+ guard: OwnedRwLockReadGuard<Self>,
|
|
|
+ from: &BlockPath,
|
|
|
+ handle: Handle,
|
|
|
+ ) -> Result<HandleGuard<BlockGuard<OwnedRwLockReadGuard<Self>>>> {
|
|
|
+ let value = guard.value(handle)?;
|
|
|
+ let (flags, mutex_guard) = value.lock(from).await?;
|
|
|
+ let guard = BlockGuard::new(guard);
|
|
|
+ Ok(HandleGuard::new(flags, mutex_guard, guard))
|
|
|
+ }
|
|
|
+
|
|
|
async fn handle_guard_mut<'a>(
|
|
|
&'a mut self,
|
|
|
from: &BlockPath,
|
|
|
handle: Handle,
|
|
|
- ) -> Result<HandleGuard<'a, &mut FileBlock<C>>> {
|
|
|
+ ) -> Result<HandleGuard<&mut FileBlock<C>>> {
|
|
|
let value = self
|
|
|
.handle_values
|
|
|
.get(&handle)
|
|
@@ -469,32 +529,32 @@ mod private {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- type InodeTable<C> = HashMap<Inode, RwLock<InodeTableValue<C>>>;
|
|
|
+ type InodeTable<C> = HashMap<Inode, Arc<RwLock<InodeTableValue<C>>>>;
|
|
|
|
|
|
- struct TableGuard<'a, C> {
|
|
|
- table_guard: RwLockReadGuard<'a, InodeTable<C>>,
|
|
|
+ struct TableGuard<C> {
|
|
|
+ table_guard: OwnedRwLockReadGuard<InodeTable<C>>,
|
|
|
}
|
|
|
|
|
|
- impl<'a, C> TableGuard<'a, C> {
|
|
|
- async fn new(table: &'a RwLock<InodeTable<C>>) -> TableGuard<'a, C> {
|
|
|
- let table_guard = table.read().await;
|
|
|
+ impl<C> TableGuard<C> {
|
|
|
+ async fn new(table: Arc<RwLock<InodeTable<C>>>) -> TableGuard<C> {
|
|
|
+ let table_guard = table.read_owned().await;
|
|
|
TableGuard { table_guard }
|
|
|
}
|
|
|
|
|
|
- async fn read(&'a self, inode: Inode) -> Result<RwLockReadGuard<'a, InodeTableValue<C>>> {
|
|
|
+ async fn read(&self, inode: Inode) -> Result<OwnedRwLockReadGuard<InodeTableValue<C>>> {
|
|
|
let value = self
|
|
|
.table_guard
|
|
|
.get(&inode)
|
|
|
.ok_or_else(|| bterr!(Error::NotOpen(inode)))?;
|
|
|
- Ok(value.read().await)
|
|
|
+ Ok(value.clone().read_owned().await)
|
|
|
}
|
|
|
|
|
|
- async fn write(&'a self, inode: Inode) -> Result<RwLockWriteGuard<'a, InodeTableValue<C>>> {
|
|
|
+ async fn write(&self, inode: Inode) -> Result<OwnedRwLockWriteGuard<InodeTableValue<C>>> {
|
|
|
let value = self
|
|
|
.table_guard
|
|
|
.get(&inode)
|
|
|
.ok_or_else(|| bterr!(Error::NotOpen(inode)))?;
|
|
|
- Ok(value.write().await)
|
|
|
+ Ok(value.clone().write_owned().await)
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -512,7 +572,7 @@ mod private {
|
|
|
/// The path to the directory in the local filesystem where this blocktree is located.
|
|
|
path: PathBuf,
|
|
|
/// A map from inode numbers to their reference counts.
|
|
|
- inodes: RwLock<InodeTable<C>>,
|
|
|
+ inodes: Arc<RwLock<InodeTable<C>>>,
|
|
|
/// The next inode that will be assigned to a new block.
|
|
|
next_inode: AtomicU64,
|
|
|
/// The generation number of this filesystem. This is the same for every other server in
|
|
@@ -531,7 +591,7 @@ mod private {
|
|
|
|
|
|
impl<C: Creds + 'static, A: Authorizer> LocalFs<C, A> {
|
|
|
/// Creates a new empty blocktree at the given path.
|
|
|
- pub fn new_empty(
|
|
|
+ pub async fn new_empty(
|
|
|
btdir: PathBuf,
|
|
|
generation: u64,
|
|
|
creds: C,
|
|
@@ -599,12 +659,12 @@ mod private {
|
|
|
},
|
|
|
};
|
|
|
root_block_path.push_component(root_principal.to_string());
|
|
|
- todo!()
|
|
|
- //fs.grant_access_to(
|
|
|
- // &Arc::new(root_block_path),
|
|
|
- // SpecInodes::RootDir.into(),
|
|
|
- // proc_rec,
|
|
|
- //).await?;
|
|
|
+ fs.grant_access_to(
|
|
|
+ &Arc::new(root_block_path),
|
|
|
+ SpecInodes::RootDir.into(),
|
|
|
+ proc_rec,
|
|
|
+ )
|
|
|
+ .await?;
|
|
|
}
|
|
|
Ok(fs)
|
|
|
}
|
|
@@ -643,15 +703,18 @@ mod private {
|
|
|
let empty_path = Arc::new(BlockPath::default());
|
|
|
inodes.insert(
|
|
|
SpecInodes::Sb.into(),
|
|
|
- RwLock::new(InodeTableValue::new(sb_block, empty_path.clone())),
|
|
|
+ Arc::new(RwLock::new(InodeTableValue::new(
|
|
|
+ sb_block,
|
|
|
+ empty_path.clone(),
|
|
|
+ ))),
|
|
|
);
|
|
|
inodes.insert(
|
|
|
SpecInodes::RootDir.into(),
|
|
|
- RwLock::new(InodeTableValue::new(root_block, empty_path)),
|
|
|
+ Arc::new(RwLock::new(InodeTableValue::new(root_block, empty_path))),
|
|
|
);
|
|
|
Ok(LocalFs {
|
|
|
path: btdir,
|
|
|
- inodes: RwLock::new(inodes),
|
|
|
+ inodes: Arc::new(RwLock::new(inodes)),
|
|
|
next_inode: AtomicU64::new(sb.next_inode),
|
|
|
generation: sb.generation,
|
|
|
creds,
|
|
@@ -705,8 +768,8 @@ mod private {
|
|
|
Ok(block)
|
|
|
}
|
|
|
|
|
|
- async fn table_guard(&self) -> TableGuard<'_, C> {
|
|
|
- TableGuard::new(&self.inodes).await
|
|
|
+ async fn table_guard(&self) -> TableGuard<C> {
|
|
|
+ TableGuard::new(self.inodes.clone()).await
|
|
|
}
|
|
|
|
|
|
async fn open_value(
|
|
@@ -716,9 +779,9 @@ mod private {
|
|
|
block_path: BlockPath,
|
|
|
) -> Result<()> {
|
|
|
let block = Self::open_block(&self.path, inode, self.creds.clone(), block_path)?;
|
|
|
- let value = RwLock::new(InodeTableValue::new(block, from.clone()));
|
|
|
+ let value = Arc::new(RwLock::new(InodeTableValue::new(block, from.clone())));
|
|
|
let mut inodes = self.inodes.write().await;
|
|
|
- if let Some(_) = inodes.insert(inode, value) {
|
|
|
+ if inodes.insert(inode, value).is_some() {
|
|
|
error!(
|
|
|
"LOGIC ERROR: open_value was called with inode {inode}, which is already open"
|
|
|
);
|
|
@@ -731,9 +794,9 @@ mod private {
|
|
|
from: &Arc<BlockPath>,
|
|
|
inode: Inode,
|
|
|
block_path: BlockPath,
|
|
|
- ) -> Result<TableGuard<'a, C>> {
|
|
|
+ ) -> Result<TableGuard<C>> {
|
|
|
{
|
|
|
- let inodes = self.inodes.read().await;
|
|
|
+ let inodes = self.inodes.clone().read_owned().await;
|
|
|
if inodes.contains_key(&inode) {
|
|
|
return Ok(TableGuard {
|
|
|
table_guard: inodes,
|
|
@@ -741,7 +804,7 @@ mod private {
|
|
|
}
|
|
|
}
|
|
|
self.open_value(from, inode, block_path).await?;
|
|
|
- Ok(TableGuard::new(&self.inodes).await)
|
|
|
+ Ok(TableGuard::new(self.inodes.clone()).await)
|
|
|
}
|
|
|
|
|
|
async fn inode_forget<'a>(
|
|
@@ -764,11 +827,9 @@ mod private {
|
|
|
value.total_lookup_count()
|
|
|
};
|
|
|
if 0 == lookup_count {
|
|
|
- let delete = inodes
|
|
|
- .remove(&inode)
|
|
|
- .unwrap()
|
|
|
- .into_inner()
|
|
|
- .delete;
|
|
|
+ let entry = Arc::try_unwrap(inodes.remove(&inode).unwrap())
|
|
|
+ .map_err(|_| bterr!("LOGIC ERROR: entry for inode {inode} was still in use while it was being forgotten"))?;
|
|
|
+ let delete = entry.into_inner().delete;
|
|
|
if delete {
|
|
|
let path = Self::block_path(&self.path, inode);
|
|
|
std::fs::remove_file(path)?;
|
|
@@ -881,7 +942,8 @@ mod private {
|
|
|
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, next_inode, bind_path)
|
|
|
+ .await?;
|
|
|
{
|
|
|
let table_guard = self.table_guard().await;
|
|
|
let mut value_guard = table_guard.write(next_inode).await?;
|
|
@@ -910,7 +972,10 @@ mod private {
|
|
|
.map(|e| e.inode())
|
|
|
}
|
|
|
|
|
|
- async fn lookup_inode<'a, I: Iterator<Item = &'a str>>(&self, components: I) -> Result<Inode> {
|
|
|
+ async fn lookup_inode<'a, I: Iterator<Item = &'a str>>(
|
|
|
+ &self,
|
|
|
+ components: I,
|
|
|
+ ) -> Result<Inode> {
|
|
|
const ROOT: Inode = SpecInodes::RootDir as Inode;
|
|
|
let mut inode = ROOT;
|
|
|
for component in components {
|
|
@@ -948,7 +1013,9 @@ mod private {
|
|
|
let relative = from.relative_to(local_root)?;
|
|
|
let inode = self.lookup_inode(relative.components()).await?;
|
|
|
let proc_rec = {
|
|
|
- let table_guard = self.ensure_open(from, inode, from.as_ref().to_owned()).await?;
|
|
|
+ let table_guard = self
|
|
|
+ .ensure_open(from, inode, from.as_ref().to_owned())
|
|
|
+ .await?;
|
|
|
let mut value_guard = table_guard.write(inode).await?;
|
|
|
value_guard.block.read_proc_rec()?
|
|
|
};
|
|
@@ -959,99 +1026,73 @@ mod private {
|
|
|
|
|
|
unsafe impl<C: Sync, A: Sync> Sync for LocalFs<C, A> {}
|
|
|
|
|
|
- pub struct TopGuard<'a, C> {
|
|
|
- guard: TableGuard<'a, C>,
|
|
|
- inode: Inode,
|
|
|
- handle: Handle,
|
|
|
- from: &'a Arc<BlockPath>,
|
|
|
- offset: u64,
|
|
|
- size: u64,
|
|
|
- }
|
|
|
-
|
|
|
- impl<'a, C: 'a + Send + Sync + Principaled + Decrypter + Signer> ReadingGuard<'a> for TopGuard<'a, C> {
|
|
|
- type ReadGuard<'b> = InodeGuard<'b, RwLockReadGuard<'b, InodeTableValue<C>>> where C: 'b, Self: 'b;
|
|
|
- type ReadFut<'b> = impl 'b + Send + Future<Output = Result<Self::ReadGuard<'b>>> where Self: 'b;
|
|
|
- fn read(&self) -> Self::ReadFut<'_> {
|
|
|
- async move {
|
|
|
- let guard = self.guard.read(self.inode).await?;
|
|
|
- Ok(InodeGuard {
|
|
|
- guard,
|
|
|
- handle: self.handle,
|
|
|
- from: self.from,
|
|
|
- offset: self.offset,
|
|
|
- size: self.size,
|
|
|
- })
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- type WriteGuard = InodeGuard<'a, RwLockWriteGuard<'a, InodeTableValue<C>>>;
|
|
|
- type WriteFut = impl 'a + Send + Future<Output = Result<Self::WriteGuard>>;
|
|
|
- fn write(&'a self) -> Self::WriteFut {
|
|
|
- async move {
|
|
|
- let guard = self.guard.write(self.inode).await?;
|
|
|
- Ok(InodeGuard {
|
|
|
- guard,
|
|
|
- handle: self.handle,
|
|
|
- from: self.from,
|
|
|
- offset: self.offset,
|
|
|
- size: self.size,
|
|
|
- })
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- pub struct InodeGuard<'a, T> {
|
|
|
- guard: T,
|
|
|
- handle: Handle,
|
|
|
- from: &'a Arc<BlockPath>,
|
|
|
+ /// An owned guard which allows read access to file data.
|
|
|
+ pub struct BufGuard<C> {
|
|
|
offset: u64,
|
|
|
size: u64,
|
|
|
+ // Note that handle must come before _table to ensure the guards are dropped in the correct
|
|
|
+ // order.
|
|
|
+ handle: HandleGuard<BlockGuard<OwnedRwLockReadGuard<InodeTableValue<C>>>>,
|
|
|
+ _table: OwnedRwLockReadGuard<InodeTable<C>>,
|
|
|
}
|
|
|
|
|
|
- impl<'a, C: 'a + Sync + Principaled + Decrypter + Signer, T: 'a + Send + Sync + Deref<Target = InodeTableValue<C>>> ReadGuard<'a> for InodeGuard<'a, T> {
|
|
|
- type BufGuard<'b> = BufferGuard<'b, C> where Self: 'b;
|
|
|
- type BufFut<'b> = impl 'b + Send + Future<Output = Result<Option<Self::BufGuard<'b>>>> where Self: 'b;
|
|
|
- fn get_buf(&self) -> Self::BufFut<'_>
|
|
|
- {
|
|
|
- async move {
|
|
|
- let mut block = self.guard.handle_guard(&self.from, self.handle).await?;
|
|
|
- block.flags.assert_readable()?;
|
|
|
- let pos = block.pos() as u64;
|
|
|
- if self.offset != pos {
|
|
|
- if let Err(err) = block.try_seek(SeekFrom::Start(self.offset)) {
|
|
|
+ impl<C: 'static + Principaled + Signer + Decrypter> BufGuard<C> {
|
|
|
+ async fn new(
|
|
|
+ table: Arc<RwLock<InodeTable<C>>>,
|
|
|
+ from: &BlockPath,
|
|
|
+ inode: Inode,
|
|
|
+ handle: Handle,
|
|
|
+ offset: u64,
|
|
|
+ size: u64,
|
|
|
+ ) -> Result<BufGuard<C>> {
|
|
|
+ let table = table.clone().read_owned().await;
|
|
|
+ let entry = table.get(&inode).ok_or(Error::NotOpen(inode))?;
|
|
|
+ let inode_guard = {
|
|
|
+ let inode_guard = entry.clone().read_owned().await;
|
|
|
+ let mut handle_guard = inode_guard.handle_guard(from, handle).await?;
|
|
|
+ handle_guard.flags.assert_readable()?;
|
|
|
+ let pos = handle_guard.pos() as u64;
|
|
|
+ if offset != pos {
|
|
|
+ if let Err(err) = handle_guard.try_seek(SeekFrom::Start(offset)) {
|
|
|
// An error with `ErrorKind::Unsupported` means that the `SectoredBuf`
|
|
|
// has unflushed data and it needs exclusive access to the block to
|
|
|
// perform this seek because this data needs to be written.
|
|
|
if let io::ErrorKind::Unsupported = err.kind() {
|
|
|
- return Ok::<_, btlib::Error>(None);
|
|
|
+ None
|
|
|
} else {
|
|
|
return Err(err.into());
|
|
|
}
|
|
|
+ } else {
|
|
|
+ drop(handle_guard);
|
|
|
+ Some(inode_guard)
|
|
|
}
|
|
|
+ } else {
|
|
|
+ drop(handle_guard);
|
|
|
+ Some(inode_guard)
|
|
|
}
|
|
|
- Ok(Some(BufferGuard { handle: block, offset: self.offset, size: self.size }))
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- impl<'a, C: Send + Principaled + Decrypter + Signer, T: 'a + Send + DerefMut<Target = InodeTableValue<C>>> WriteGuard<'a> for InodeGuard<'a, T> {
|
|
|
- type SeekFut = impl 'a + Send + Future<Output = Result<()>>;
|
|
|
- fn seek(&'a mut self) -> Self::SeekFut {
|
|
|
- async move {
|
|
|
- let mut block = self.guard.handle_guard_mut(self.from, self.handle).await?;
|
|
|
- block.seek(SeekFrom::Start(self.offset))?;
|
|
|
- Ok(())
|
|
|
- }
|
|
|
+ };
|
|
|
+ let inode_guard = match inode_guard {
|
|
|
+ Some(inode_guard) => inode_guard,
|
|
|
+ None => {
|
|
|
+ {
|
|
|
+ let mut inode_guard = entry.write().await;
|
|
|
+ let mut handle_guard = inode_guard.handle_guard_mut(from, handle).await?;
|
|
|
+ handle_guard.seek(SeekFrom::Start(offset))?;
|
|
|
+ }
|
|
|
+ entry.clone().read_owned().await
|
|
|
+ }
|
|
|
+ };
|
|
|
+ let handle = InodeTableValue::handle_guard_owned(inode_guard, from, handle).await?;
|
|
|
+ Ok(BufGuard {
|
|
|
+ handle,
|
|
|
+ _table: table,
|
|
|
+ offset,
|
|
|
+ size,
|
|
|
+ })
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- pub struct BufferGuard<'a, C> {
|
|
|
- handle: HandleGuard<'a, &'a FileBlock<C>>,
|
|
|
- offset: u64,
|
|
|
- size: u64,
|
|
|
- }
|
|
|
-
|
|
|
- impl<'a, C> Deref for BufferGuard<'a, C> {
|
|
|
+ impl<C: 'static + Principaled + Decrypter + Signer> Deref for BufGuard<C> {
|
|
|
type Target = [u8];
|
|
|
fn deref(&self) -> &Self::Target {
|
|
|
self.handle.get_buf(self.offset, self.size).unwrap()
|
|
@@ -1147,7 +1188,8 @@ mod private {
|
|
|
let (handle, stat) = {
|
|
|
let table_guard = self.ensure_open(from, inode, block_path).await?;
|
|
|
let mut value_guard = table_guard.write(inode).await?;
|
|
|
- let handle = value_guard.new_handle(from.clone(), FlagValue::ReadWrite.into())?;
|
|
|
+ let handle =
|
|
|
+ value_guard.new_handle(from.clone(), FlagValue::ReadWrite.into())?;
|
|
|
let stat = {
|
|
|
let mut block = value_guard.handle_guard_mut(from, handle).await?;
|
|
|
let stat = block.mut_meta_body().access_secrets(|secrets| {
|
|
@@ -1218,7 +1260,7 @@ mod private {
|
|
|
drop(result);
|
|
|
value.forget_handle(handle);
|
|
|
return Err(bterr!(message));
|
|
|
- },
|
|
|
+ }
|
|
|
}
|
|
|
};
|
|
|
let ctx = AuthzContext::new(from, &authz_attrs, block.meta());
|
|
@@ -1253,84 +1295,33 @@ mod private {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- type ReadingGuard<'a> = TopGuard<'a, C> where Self: 'a;
|
|
|
- type ReadFut<'c> = impl 'c + Send + Future<Output = Result<Self::ReadingGuard<'c>>>;
|
|
|
- fn read2<'c>(&'c self, from: &'c Arc<BlockPath>, msg: Read) -> Self::ReadFut<'c> {
|
|
|
+ type ReadGuard = BufGuard<C>;
|
|
|
+ type ReadFut<'c> = impl 'c + Send + Future<Output = Result<Self::ReadGuard>>;
|
|
|
+ fn read<'c>(&'c self, from: &'c Arc<BlockPath>, msg: Read) -> Self::ReadFut<'c> {
|
|
|
async move {
|
|
|
- let Read { inode, handle, offset, size } = msg;
|
|
|
- let guard = self.table_guard().await;
|
|
|
- Ok(TopGuard {
|
|
|
- guard,
|
|
|
- from,
|
|
|
+ let Read {
|
|
|
inode,
|
|
|
handle,
|
|
|
offset,
|
|
|
size,
|
|
|
- })
|
|
|
+ } = msg;
|
|
|
+ BufGuard::new(self.inodes.clone(), from, inode, handle, offset, size).await
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- fn read<'c, R, F>(&'c self, from: &'c Arc<BlockPath>, msg: Read, callback: F) -> Result<R>
|
|
|
- where
|
|
|
- F: 'c + FnOnce(&[u8]) -> R,
|
|
|
- {
|
|
|
- todo!()
|
|
|
- //let Read {
|
|
|
- // inode,
|
|
|
- // handle,
|
|
|
- // offset,
|
|
|
- // size,
|
|
|
- //} = msg;
|
|
|
- //debug!("read: inode {inode}, handle {handle}, offset {offset}, size {size}");
|
|
|
- //let mut callback = Some(callback);
|
|
|
- //let table_guard = self.table_guard();
|
|
|
- //let output = (|| {
|
|
|
- // let value_guard = table_guard.read(inode)?;
|
|
|
- // let mut block = value_guard.handle_guard(from, handle)?;
|
|
|
- // block.flags.assert_readable()?;
|
|
|
- // let pos = block.pos() as u64;
|
|
|
- // if offset != pos {
|
|
|
- // if let Err(err) = block.try_seek(SeekFrom::Start(offset)) {
|
|
|
- // // An error with `ErrorKind::Unsupported` means that the `SectoredBuf`
|
|
|
- // // has unflushed data and it needs exclusive access to the block to
|
|
|
- // // perform this seek because this data needs to be written.
|
|
|
- // if let io::ErrorKind::Unsupported = err.kind() {
|
|
|
- // return Ok::<_, btlib::Error>(None);
|
|
|
- // } else {
|
|
|
- // return Err(err.into());
|
|
|
- // }
|
|
|
- // }
|
|
|
- // }
|
|
|
- // let buf = block.get_buf(offset, size)?;
|
|
|
- // let callback = callback.take().unwrap();
|
|
|
- // Ok(Some(callback(buf)))
|
|
|
- //})()?;
|
|
|
- //let output = match output {
|
|
|
- // Some(output) => output,
|
|
|
- // None => {
|
|
|
- // // The offset of this read requires us to flush data buffered from a previous
|
|
|
- // // write before seeking to a different sector, so we have to access the block
|
|
|
- // // mutably.
|
|
|
- // let mut value_guard = table_guard.write(inode)?;
|
|
|
- // let mut block = value_guard.handle_guard_mut(from, handle)?;
|
|
|
- // block.seek(SeekFrom::Start(offset))?;
|
|
|
- // let buf = block.get_buf(offset, size)?;
|
|
|
- // let callback = callback.take().unwrap();
|
|
|
- // callback(buf)
|
|
|
- // }
|
|
|
- //};
|
|
|
- //Ok(output)
|
|
|
- }
|
|
|
-
|
|
|
type WriteFut<'r> = impl 'r + Send + Future<Output = Result<WriteReply>>;
|
|
|
fn write<'c>(
|
|
|
&'c self,
|
|
|
from: &'c Arc<BlockPath>,
|
|
|
write: Write<&'c [u8]>,
|
|
|
- ) -> Self::WriteFut<'c>
|
|
|
- {
|
|
|
+ ) -> Self::WriteFut<'c> {
|
|
|
async move {
|
|
|
- let Write { inode, handle, offset, mut data } = write;
|
|
|
+ let Write {
|
|
|
+ inode,
|
|
|
+ handle,
|
|
|
+ offset,
|
|
|
+ mut data,
|
|
|
+ } = write;
|
|
|
debug!("write: inode {inode}, handle {handle}, offset {offset}");
|
|
|
let table_guard = self.table_guard().await;
|
|
|
let mut value_guard = table_guard.write(inode).await?;
|
|
@@ -1341,9 +1332,7 @@ mod private {
|
|
|
block.seek(SeekFrom::Start(offset))?;
|
|
|
}
|
|
|
let written = std::io::copy(&mut data, block.deref_mut())?;
|
|
|
- Ok(WriteReply {
|
|
|
- written: written as u64,
|
|
|
- })
|
|
|
+ Ok(WriteReply { written })
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -1355,15 +1344,8 @@ mod private {
|
|
|
let table_guard = self.table_guard().await;
|
|
|
let mut value_guard = table_guard.write(inode).await?;
|
|
|
let mut block = value_guard.handle_guard_mut(from, handle).await?;
|
|
|
- block.flags.assert_writeable()?;
|
|
|
- match block.flush().bterr() {
|
|
|
- Ok(value) => Ok(value),
|
|
|
- Err(err) => match err.downcast_ref::<Error>() {
|
|
|
- // If the handle is read-only we just return Ok.
|
|
|
- Some(Error::ReadOnlyHandle(..)) => Ok(()),
|
|
|
- _ => Err(err),
|
|
|
- },
|
|
|
- }
|
|
|
+ block.flush()?;
|
|
|
+ Ok(())
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -1637,7 +1619,7 @@ mod private {
|
|
|
Ok(mut block) => {
|
|
|
block.flush()?;
|
|
|
block.flush_meta()?;
|
|
|
- },
|
|
|
+ }
|
|
|
Err(err) => match err.downcast_ref::<Error>() {
|
|
|
// If the cause of the error is that the handle is read-only, then it is
|
|
|
// not actually an error.
|