[fxfs] Convert FxNode to a trait.
Also fixes a bug where the root node was never added to the cache on
initializing a volume.
Change-Id: I36d74f0309e41efaebd5feb96981899d68a23874
Tested: unit.
Reviewed-on: https://fuchsia-review.googlesource.com/c/fuchsia/+/513727
Commit-Queue: James Sullivan <jfsulliv@google.com>
Reviewed-by: Chris Suter <csuter@google.com>
diff --git a/src/storage/fxfs/src/server.rs b/src/storage/fxfs/src/server.rs
index 80f86ad..343429d 100644
--- a/src/storage/fxfs/src/server.rs
+++ b/src/storage/fxfs/src/server.rs
@@ -52,7 +52,8 @@
.open_or_create_volume(volume_name)
.await
.expect("Open or create volume failed"),
- );
+ )
+ .await;
Ok(Self { fs, volume })
}
diff --git a/src/storage/fxfs/src/server/directory.rs b/src/storage/fxfs/src/server/directory.rs
index e367d99..fa648cb 100644
--- a/src/storage/fxfs/src/server/directory.rs
+++ b/src/storage/fxfs/src/server/directory.rs
@@ -30,6 +30,7 @@
dirents_sink::{self, Sink},
entry::{DirectoryEntry, EntryInfo},
entry_container::{AsyncGetEntry, Directory, MutableDirectory},
+ mutable::connection::io1::MutableConnection,
traversal_position::TraversalPosition,
},
execution_scope::ExecutionScope,
@@ -53,19 +54,17 @@
flags: u32,
mode: u32,
mut path: Path,
- ) -> Result<FxNode, Error> {
+ ) -> Result<Arc<dyn FxNode>, Error> {
// TODO(csuter): There are races to fix here where a direectory or file could be removed
// whilst a lookup is taking place. The transaction locks only protect against multiple
// writers, but the readers don't have any locks, so there needs to be checks that nodes
// still exist at some point.
- let mut current_node = FxNode::Dir(self.clone());
let fs = self.volume.store().filesystem();
+ let mut current_node = self.clone() as Arc<dyn FxNode>;
while !path.is_empty() {
let last_segment = path.is_single_component();
- let current_dir = match current_node {
- FxNode::Dir(dir) => dir.clone(),
- FxNode::File(_file) => bail!(FxfsError::NotDir),
- };
+ let current_dir =
+ current_node.into_any().downcast::<FxDirectory>().map_err(|_| FxfsError::NotDir)?;
let name = path.next().unwrap();
// Create the transaction here if we might need to create the object so that we have a
// lock in place.
@@ -126,25 +125,34 @@
dir: &Arc<FxDirectory>,
name: &str,
mode: u32,
- ) -> Result<FxNode, Error> {
+ ) -> Result<Arc<dyn FxNode>, Error> {
let (object_id, node) = if mode & MODE_TYPE_DIRECTORY != 0 {
let dir = dir.directory.create_child_dir(&mut transaction, name).await?;
let object_id = dir.object_id();
- let node =
- FxNode::Dir(Arc::new(FxDirectory { volume: self.volume.clone(), directory: dir }));
+ let node = Arc::new(FxDirectory { volume: self.volume.clone(), directory: dir })
+ as Arc<dyn FxNode>;
(object_id, node)
} else {
let handle = dir.directory.create_child_file(&mut transaction, name).await?;
let object_id = handle.object_id();
- let node = FxNode::File(Arc::new(FxFile::new(handle)));
+ let node = Arc::new(FxFile::new(handle)) as Arc<dyn FxNode>;
(object_id, node)
};
- transaction.commit().await;
- self.volume.add_node(object_id, node.downgrade()).await;
+ self.volume.store().filesystem().commit_transaction(transaction).await;
+ self.volume.add_node(object_id, Arc::downgrade(&node)).await;
Ok(node)
}
}
+impl FxNode for FxDirectory {
+ fn object_id(&self) -> u64 {
+ self.directory.object_id()
+ }
+ fn into_any(self: Arc<Self>) -> Arc<dyn Any + Send + Sync + 'static> {
+ self
+ }
+}
+
#[async_trait]
impl MutableDirectory for FxDirectory {
async fn link(&self, _name: String, _entry: Arc<dyn DirectoryEntry>) -> Result<(), Status> {
@@ -187,19 +195,24 @@
) {
let cloned_scope = scope.clone();
scope.spawn(async move {
+ // TODO(jfsulliv): Factor this out into a visitor-pattern style method for FxNode, e.g.
+ // FxNode::visit(FileFn, DirFn).
match self.lookup(flags, mode, path).await {
Err(e) => send_on_open_with_error(flags, server_end, map_to_status(e)),
- Ok(FxNode::Dir(dir)) => {
- vfs::directory::mutable::connection::io1::MutableConnection::create_connection(
- cloned_scope,
- OpenDirectory::new(dir),
- flags,
- mode,
- server_end,
- );
- }
- Ok(FxNode::File(file)) => {
- file.clone().open(cloned_scope, flags, mode, Path::empty(), server_end);
+ Ok(node) => {
+ if let Ok(dir) = node.clone().into_any().downcast::<FxDirectory>() {
+ MutableConnection::create_connection(
+ cloned_scope,
+ OpenDirectory::new(dir),
+ flags,
+ mode,
+ server_end,
+ );
+ } else if let Ok(file) = node.into_any().downcast::<FxFile>() {
+ file.clone().open(cloned_scope, flags, mode, Path::empty(), server_end);
+ } else {
+ panic!("Unknown node type")
+ }
}
};
});
@@ -285,7 +298,7 @@
let device = Arc::new(FakeDevice::new(2048, 512));
let filesystem = FxFilesystem::new_empty(device.clone()).await?;
let volume_directory = volume_directory(&filesystem).await?;
- let vol = FxVolumeAndRoot::new(volume_directory.new_volume("vol").await?);
+ let vol = FxVolumeAndRoot::new(volume_directory.new_volume("vol").await?).await;
{
let (dir_proxy, dir_server_end) = fidl::endpoints::create_proxy::<DirectoryMarker>()
.expect("Create proxy to succeed");
@@ -331,7 +344,7 @@
let device = Arc::new(FakeDevice::new(2048, 512));
let filesystem = FxFilesystem::new_empty(device.clone()).await?;
let volume_directory = volume_directory(&filesystem).await?;
- let vol = FxVolumeAndRoot::new(volume_directory.new_volume("vol").await?);
+ let vol = FxVolumeAndRoot::new(volume_directory.new_volume("vol").await?).await;
let dir = vol.root().clone();
let (dir_proxy, dir_server_end) =
@@ -357,12 +370,12 @@
let (filesystem, vol) = if i == 0 {
let filesystem = FxFilesystem::new_empty(device.clone()).await?;
let volume_directory = volume_directory(&filesystem).await?;
- let vol = FxVolumeAndRoot::new(volume_directory.new_volume("vol").await?);
+ let vol = FxVolumeAndRoot::new(volume_directory.new_volume("vol").await?).await;
(filesystem, vol)
} else {
let filesystem = FxFilesystem::open(device.clone()).await?;
let volume_directory = volume_directory(&filesystem).await?;
- let vol = FxVolumeAndRoot::new(volume_directory.volume("vol").await?);
+ let vol = FxVolumeAndRoot::new(volume_directory.volume("vol").await?).await;
(filesystem, vol)
};
let dir = vol.root().clone();
@@ -394,7 +407,7 @@
let device = Arc::new(FakeDevice::new(2048, 512));
let filesystem = FxFilesystem::new_empty(device.clone()).await?;
let volume_directory = volume_directory(&filesystem).await?;
- let vol = FxVolumeAndRoot::new(volume_directory.new_volume("vol").await?);
+ let vol = FxVolumeAndRoot::new(volume_directory.new_volume("vol").await?).await;
let dir = vol.root().clone();
let (dir_proxy, dir_server_end) =
@@ -428,7 +441,7 @@
let device = Arc::new(FakeDevice::new(2048, 512));
let filesystem = FxFilesystem::new_empty(device.clone()).await?;
let volume_directory = volume_directory(&filesystem).await?;
- let vol = FxVolumeAndRoot::new(volume_directory.new_volume("vol").await?);
+ let vol = FxVolumeAndRoot::new(volume_directory.new_volume("vol").await?).await;
let dir = vol.root().clone();
let (dir_proxy, dir_server_end) =
@@ -463,7 +476,7 @@
let device = Arc::new(FakeDevice::new(2048, 512));
let filesystem = FxFilesystem::new_empty(device.clone()).await?;
let volume_directory = volume_directory(&filesystem).await?;
- let vol = FxVolumeAndRoot::new(volume_directory.new_volume("vol").await?);
+ let vol = FxVolumeAndRoot::new(volume_directory.new_volume("vol").await?).await;
let dir = vol.root().clone();
let (dir_proxy, dir_server_end) =
@@ -508,7 +521,7 @@
let device = Arc::new(FakeDevice::new(2048, 512));
let filesystem = FxFilesystem::new_empty(device.clone()).await?;
let volume_directory = volume_directory(&filesystem).await?;
- let vol = FxVolumeAndRoot::new(volume_directory.new_volume("vol").await?);
+ let vol = FxVolumeAndRoot::new(volume_directory.new_volume("vol").await?).await;
let dir = vol.root().clone();
let (dir_proxy, dir_server_end) =
diff --git a/src/storage/fxfs/src/server/file.rs b/src/storage/fxfs/src/server/file.rs
index 15e0947..c492eb3 100644
--- a/src/storage/fxfs/src/server/file.rs
+++ b/src/storage/fxfs/src/server/file.rs
@@ -6,14 +6,14 @@
crate::{
object_handle::{ObjectHandle, ObjectHandleExt},
object_store::StoreObjectHandle,
- server::errors::map_to_status,
+ server::{errors::map_to_status, node::FxNode},
},
async_trait::async_trait,
fidl::endpoints::ServerEnd,
fidl_fuchsia_io::{self as fio, NodeAttributes, NodeMarker},
fidl_fuchsia_mem::Buffer,
fuchsia_zircon::Status,
- std::sync::Arc,
+ std::{any::Any, sync::Arc},
vfs::{
common::send_on_open_with_error,
directory::entry::{DirectoryEntry, EntryInfo},
@@ -37,6 +37,15 @@
}
}
+impl FxNode for FxFile {
+ fn object_id(&self) -> u64 {
+ self.handle.object_id()
+ }
+ fn into_any(self: Arc<Self>) -> Arc<dyn Any + Send + Sync + 'static> {
+ self
+ }
+}
+
impl DirectoryEntry for FxFile {
fn open(
self: Arc<Self>,
@@ -164,7 +173,7 @@
let device = Arc::new(FakeDevice::new(2048, 512));
let filesystem = FxFilesystem::new_empty(device.clone()).await?;
let volume_directory = volume_directory(&filesystem).await?;
- let vol = FxVolumeAndRoot::new(volume_directory.new_volume("vol").await?);
+ let vol = FxVolumeAndRoot::new(volume_directory.new_volume("vol").await?).await;
let dir = vol.root().clone();
let (dir_proxy, dir_server_end) =
@@ -199,7 +208,7 @@
let device = Arc::new(FakeDevice::new(2048, 512));
let filesystem = FxFilesystem::new_empty(device.clone()).await?;
let volume_directory = volume_directory(&filesystem).await?;
- let vol = FxVolumeAndRoot::new(volume_directory.new_volume("vol").await?);
+ let vol = FxVolumeAndRoot::new(volume_directory.new_volume("vol").await?).await;
let dir = vol.root().clone();
let (dir_proxy, dir_server_end) =
@@ -245,12 +254,12 @@
let (filesystem, vol) = if i == 0 {
let filesystem = FxFilesystem::new_empty(device.clone()).await?;
let volume_directory = volume_directory(&filesystem).await?;
- let vol = FxVolumeAndRoot::new(volume_directory.new_volume("vol").await?);
+ let vol = FxVolumeAndRoot::new(volume_directory.new_volume("vol").await?).await;
(filesystem, vol)
} else {
let filesystem = FxFilesystem::open(device.clone()).await?;
let volume_directory = volume_directory(&filesystem).await?;
- let vol = FxVolumeAndRoot::new(volume_directory.volume("vol").await?);
+ let vol = FxVolumeAndRoot::new(volume_directory.volume("vol").await?).await;
(filesystem, vol)
};
let dir = vol.root().clone();
@@ -294,7 +303,7 @@
let device = Arc::new(FakeDevice::new(2048, 512));
let filesystem = FxFilesystem::new_empty(device.clone()).await?;
let volume_directory = volume_directory(&filesystem).await?;
- let vol = FxVolumeAndRoot::new(volume_directory.new_volume("vol").await?);
+ let vol = FxVolumeAndRoot::new(volume_directory.new_volume("vol").await?).await;
let dir = vol.root().clone();
let (dir_proxy, dir_server_end) =
@@ -342,7 +351,7 @@
let device = Arc::new(FakeDevice::new(2048, 512));
let filesystem = FxFilesystem::new_empty(device.clone()).await?;
let volume_directory = volume_directory(&filesystem).await?;
- let vol = FxVolumeAndRoot::new(volume_directory.new_volume("vol").await?);
+ let vol = FxVolumeAndRoot::new(volume_directory.new_volume("vol").await?).await;
let dir = vol.root().clone();
let (dir_proxy, dir_server_end) =
@@ -410,7 +419,7 @@
let device = Arc::new(FakeDevice::new(2048, 512));
let filesystem = FxFilesystem::new_empty(device.clone()).await?;
let volume_directory = volume_directory(&filesystem).await?;
- let vol = FxVolumeAndRoot::new(volume_directory.new_volume("vol").await?);
+ let vol = FxVolumeAndRoot::new(volume_directory.new_volume("vol").await?).await;
let dir = vol.root().clone();
let (dir_proxy, dir_server_end) =
@@ -476,7 +485,7 @@
let device = Arc::new(FakeDevice::new(2048, 512));
let filesystem = FxFilesystem::new_empty(device.clone()).await?;
let volume_directory = volume_directory(&filesystem).await?;
- let vol = FxVolumeAndRoot::new(volume_directory.new_volume("vol").await?);
+ let vol = FxVolumeAndRoot::new(volume_directory.new_volume("vol").await?).await;
let dir = vol.root().clone();
let (dir_proxy, dir_server_end) =
@@ -548,7 +557,7 @@
let device = Arc::new(FakeDevice::new(2048, 512));
let filesystem = FxFilesystem::new_empty(device.clone()).await?;
let volume_directory = volume_directory(&filesystem).await?;
- let vol = FxVolumeAndRoot::new(volume_directory.new_volume("vol").await?);
+ let vol = FxVolumeAndRoot::new(volume_directory.new_volume("vol").await?).await;
let dir = vol.root().clone();
let (dir_proxy, dir_server_end) =
diff --git a/src/storage/fxfs/src/server/node.rs b/src/storage/fxfs/src/server/node.rs
index 1657836..9b4c1f4 100644
--- a/src/storage/fxfs/src/server/node.rs
+++ b/src/storage/fxfs/src/server/node.rs
@@ -2,45 +2,10 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-use {
- crate::server::{directory::FxDirectory, file::FxFile},
- std::sync::{Arc, Weak},
-};
+use {std::any::Any, std::sync::Arc};
-// TODO(jfsulliv): Should FxNode be a trait object instead of an enum, so that we can have common
-// functionality shared between directories and files?
-
-#[derive(Clone)]
-// FxNode is a strong reference to a node in the filesystem hierarchy (either a file or directory).
-pub enum FxNode {
- Dir(Arc<FxDirectory>),
- File(Arc<FxFile>),
-}
-
-impl FxNode {
- /// Creates a weak copy of self.
- pub fn downgrade(&self) -> WeakFxNode {
- match self {
- FxNode::Dir(dir) => WeakFxNode::Dir(Arc::downgrade(dir)),
- FxNode::File(file) => WeakFxNode::File(Arc::downgrade(file)),
- }
- }
-}
-
-#[derive(Clone)]
-// WeakFxNode is a weak version of FxNode.
-pub enum WeakFxNode {
- Dir(Weak<FxDirectory>),
- File(Weak<FxFile>),
-}
-
-impl WeakFxNode {
- /// Attempts to create a strong copy of self. If the underlying node has been deleted, returns
- /// None.
- pub fn upgrade(&self) -> Option<FxNode> {
- match self {
- WeakFxNode::Dir(dir) => Weak::upgrade(dir).map(|dir| FxNode::Dir(dir)),
- WeakFxNode::File(file) => Weak::upgrade(file).map(|file| FxNode::File(file)),
- }
- }
+// FxNode is a node in the filesystem hierarchy (either a file or directory).
+pub trait FxNode: Any + Send + Sync + 'static {
+ fn object_id(&self) -> u64;
+ fn into_any(self: Arc<Self>) -> Arc<dyn Any + Send + Sync + 'static>;
}
diff --git a/src/storage/fxfs/src/server/volume.rs b/src/storage/fxfs/src/server/volume.rs
index 1515eec..bfd34d4 100644
--- a/src/storage/fxfs/src/server/volume.rs
+++ b/src/storage/fxfs/src/server/volume.rs
@@ -6,32 +6,32 @@
crate::{
errors::FxfsError,
object_store::{directory::ObjectDescriptor, HandleOptions, ObjectStore},
- server::{
- directory::FxDirectory,
- file::FxFile,
- node::{FxNode, WeakFxNode},
- },
+ server::{directory::FxDirectory, file::FxFile, node::FxNode},
volume::Volume,
},
anyhow::{anyhow, bail, Error},
fuchsia_zircon::Status,
- std::{any::Any, collections::HashMap, sync::Arc},
+ std::{
+ any::Any,
+ collections::HashMap,
+ sync::{Arc, Weak},
+ },
vfs::{
filesystem::{Filesystem, FilesystemRename},
path::Path,
},
};
-struct NodeCache(HashMap<u64, WeakFxNode>);
+struct NodeCache(HashMap<u64, Weak<dyn FxNode>>);
impl NodeCache {
- fn add(&mut self, object_id: u64, node: WeakFxNode) {
+ fn add(&mut self, object_id: u64, node: Weak<dyn FxNode>) {
// This is a programming error, so panic here.
assert!(!self.0.contains_key(&object_id), "Duplicate node for {}", object_id);
self.0.insert(object_id, node);
}
- fn get(&mut self, object_id: u64) -> Result<FxNode, Error> {
+ fn get(&mut self, object_id: u64) -> Result<Arc<dyn FxNode>, Error> {
if let Some(node) = self.0.get(&object_id) {
if let Some(node) = node.upgrade() {
Ok(node)
@@ -62,19 +62,22 @@
&self.store
}
- pub async fn add_node(&self, object_id: u64, node: WeakFxNode) {
+ pub async fn add_node(&self, object_id: u64, node: Weak<dyn FxNode>) {
self.nodes.lock().await.add(object_id, node)
}
- pub async fn open_node(&self, object_id: u64) -> Result<FxNode, Error> {
+ pub async fn open_node(&self, object_id: u64) -> Result<Arc<dyn FxNode>, Error> {
self.nodes.lock().await.get(object_id)
}
+ /// Attempts to open a node in the node cache. If the node wasn't present in the cache, loads
+ /// the object from the object store, installing the returned node into the cache and returns
+ /// the newly created FxNode backed by the loaded object.
pub async fn open_or_load_node(
self: &Arc<Self>,
object_id: u64,
object_descriptor: ObjectDescriptor,
- ) -> Result<FxNode, Error> {
+ ) -> Result<Arc<dyn FxNode>, Error> {
let mut nodes = self.nodes.lock().await;
match nodes.get(object_id) {
Ok(node) => Ok(node),
@@ -83,15 +86,15 @@
ObjectDescriptor::File => {
let file =
self.store.open_object(object_id, HandleOptions::default()).await?;
- FxNode::File(Arc::new(FxFile::new(file)))
+ Arc::new(FxFile::new(file)) as Arc<dyn FxNode>
}
ObjectDescriptor::Directory => {
let directory = self.store.open_directory(object_id).await?;
- FxNode::Dir(Arc::new(FxDirectory::new(self.clone(), directory)))
+ Arc::new(FxDirectory::new(self.clone(), directory)) as Arc<dyn FxNode>
}
_ => bail!(FxfsError::Inconsistent),
};
- nodes.add(object_id, node.downgrade());
+ nodes.add(object_id, Arc::downgrade(&node));
Ok(node)
}
Err(e) => return Err(e),
@@ -115,17 +118,19 @@
pub struct FxVolumeAndRoot {
volume: Arc<FxVolume>,
- root: FxNode,
+ root: Arc<dyn FxNode>,
}
impl FxVolumeAndRoot {
- pub fn new(volume: Volume) -> Self {
+ pub async fn new(volume: Volume) -> Self {
let (store, root_directory) = volume.into();
+ let root_object_id = root_directory.object_id();
let volume = Arc::new(FxVolume {
nodes: futures::lock::Mutex::new(NodeCache(HashMap::new())),
store,
});
- let root = FxNode::Dir(Arc::new(FxDirectory::new(volume.clone(), root_directory)));
+ let root: Arc<dyn FxNode> = Arc::new(FxDirectory::new(volume.clone(), root_directory));
+ volume.add_node(root_object_id, Arc::downgrade(&root)).await;
Self { volume, root }
}
@@ -133,12 +138,8 @@
&self.volume
}
- pub fn root(&self) -> &Arc<FxDirectory> {
- if let FxNode::Dir(dir) = &self.root {
- dir
- } else {
- panic!("Invalid type for root");
- }
+ pub fn root(&self) -> Arc<FxDirectory> {
+ self.root.clone().into_any().downcast::<FxDirectory>().expect("Invalid type for root")
}
pub(super) fn into_volume(self) -> Arc<FxVolume> {