From 84c24bfff67ba80a85868f9be534a21a69f560c4 Mon Sep 17 00:00:00 2001 From: Michael-F-Bryan Date: Fri, 17 Mar 2023 05:13:35 +0800 Subject: [PATCH] Use external knowledge when preopening dirs instead of traversing the fs --- lib/wasi/src/runners/container.rs | 14 +++++++--- lib/wasi/src/runners/wasi.rs | 38 +++++++++++++--------------- lib/wasi/src/runners/wcgi/handler.rs | 14 +++++----- lib/wasi/src/runners/wcgi/runner.rs | 5 ---- 4 files changed, 36 insertions(+), 35 deletions(-) diff --git a/lib/wasi/src/runners/container.rs b/lib/wasi/src/runners/container.rs index a41830b7ddf..c05be2663c1 100644 --- a/lib/wasi/src/runners/container.rs +++ b/lib/wasi/src/runners/container.rs @@ -111,10 +111,18 @@ impl WapmContainer { /// Get the entire container as a single filesystem and a list of suggested /// directories to preopen. - pub(crate) fn container_fs(&self) -> Box { + pub(crate) fn container_fs(&self) -> (Box, Vec) { match &self.repr { - Repr::V1Mmap(mapped) => Box::new(WebcFileSystem::init_all(Arc::clone(mapped))), - Repr::V1Owned(owned) => Box::new(WebcFileSystem::init_all(Arc::clone(owned))), + Repr::V1Mmap(mapped) => { + let fs = WebcFileSystem::init_all(Arc::clone(mapped)); + let top_level_dirs = fs.top_level_dirs().clone(); + (Box::new(fs), top_level_dirs) + } + Repr::V1Owned(owned) => { + let fs = WebcFileSystem::init_all(Arc::clone(owned)); + let top_level_dirs = fs.top_level_dirs().clone(); + (Box::new(fs), top_level_dirs) + } } } } diff --git a/lib/wasi/src/runners/wasi.rs b/lib/wasi/src/runners/wasi.rs index 7fc186536b3..0b9cebbf5e4 100644 --- a/lib/wasi/src/runners/wasi.rs +++ b/lib/wasi/src/runners/wasi.rs @@ -132,14 +132,13 @@ impl WasiRunner { container: &WapmContainer, command: &str, ) -> Result { - let fs = unioned_filesystem(&self.mapped_dirs, container)?; - let fs = container.container_fs(); + let (fs, preopen_dirs) = unioned_filesystem(&self.mapped_dirs, container)?; - let mut builder = WasiEnv::builder(command) - .args(&self.args) - .preopen_dir("/")?; + let mut builder = WasiEnv::builder(command).args(&self.args); - preopen(&fs, "/".as_ref(), &mut builder)?; + for dir in preopen_dirs { + builder.add_preopen_dir(dir)?; + } builder.set_fs(Box::new(fs)); @@ -199,10 +198,12 @@ impl crate::runners::Runner for WasiRunner { pub(crate) fn unioned_filesystem( mapped_dirs: &[MappedDirectory], container: &WapmContainer, -) -> Result { +) -> Result<(impl FileSystem, Vec), Error> { // We start with the root filesystem so we get things like "/dev/" let primary = RootFileSystemBuilder::new().build(); + let mut preopen_dirs = Vec::new(); + // Now, let's merge in the host volumes. if !mapped_dirs.is_empty() { let host_fs: Arc = @@ -232,25 +233,20 @@ pub(crate) fn unioned_filesystem( guest.display() ) })?; + + preopen_dirs.push(guest); } } - // Once we've set up the primary filesystem, make sure it is overlayed with - // the WEBC container's files - Ok(OverlayFileSystem::new(primary, [container.container_fs()])) -} + let (container_fs, top_level_dirs) = container.container_fs(); -fn preopen(fs: &dyn FileSystem, path: &Path, builder: &mut WasiEnvBuilder) -> Result<(), Error> { - for result in fs.read_dir(path)? { - let entry = result?; + preopen_dirs.extend(top_level_dirs.into_iter().map(|p| Path::new("/").join(p))); - if entry.file_type()?.is_dir() { - builder.add_preopen_dir(&entry.path)?; - preopen(fs, &entry.path, builder)?; - } - } + // Once we've set up the primary filesystem, make sure it is overlayed with + // the WEBC container's files + let fs = OverlayFileSystem::new(primary, [container_fs]); - Ok(()) + Ok((fs, preopen_dirs)) } fn create_dir_all(fs: &(impl FileSystem + ?Sized), path: &Path) -> Result<(), Error> { @@ -307,7 +303,7 @@ mod tests { host: temp.path().to_path_buf(), }]; - let fs = unioned_filesystem(&mapped_dirs, &container).unwrap(); + let (fs, _) = unioned_filesystem(&mapped_dirs, &container).unwrap(); // Files that were mounted on the host let path_contents = read_dir(&fs, "/path/to/"); diff --git a/lib/wasi/src/runners/wcgi/handler.rs b/lib/wasi/src/runners/wcgi/handler.rs index 10e45f4cad1..2ab523686e8 100644 --- a/lib/wasi/src/runners/wcgi/handler.rs +++ b/lib/wasi/src/runners/wcgi/handler.rs @@ -7,7 +7,7 @@ use std::{ task::Poll, }; -use anyhow::{Context, Error}; +use anyhow::Error; use futures::{Future, FutureExt, StreamExt, TryFutureExt}; use http::{Request, Response}; use hyper::{service::Service, Body}; @@ -17,7 +17,7 @@ use tokio::{ }; use tracing::Instrument; use wasmer::Module; -use wasmer_vfs::{FileSystem, PassthruFileSystem, RootFileSystemBuilder, TmpFileSystem}; +use wasmer_vfs::FileSystem; use wcgi_host::CgiDialect; use crate::{ @@ -54,6 +54,8 @@ impl Handler { self.dialect .prepare_environment_variables(parts, &mut request_specific_env); + let (fs, preopen_dirs) = self.fs()?; + let rt = PluggableRuntimeImplementation::new(Arc::clone(&self.task_manager)); let mut builder = builder .envs(self.env.iter()) @@ -68,11 +70,11 @@ impl Handler { threading: Default::default(), }) .runtime(Arc::new(rt)) - .fs(Box::new(self.fs()?)) + .fs(Box::new(fs)) .preopen_dir(Path::new("/"))?; - for dir in &self.mapped_dirs { - builder.add_preopen_dir(&dir.guest)?; + for dir in preopen_dirs { + builder.add_preopen_dir(dir)?; } let module = self.module.clone(); @@ -134,7 +136,7 @@ impl Handler { Ok(response) } - fn fs(&self) -> Result { + fn fs(&self) -> Result<(impl FileSystem, Vec), Error> { crate::runners::wasi::unioned_filesystem(&self.mapped_dirs, &self.container) } } diff --git a/lib/wasi/src/runners/wcgi/runner.rs b/lib/wasi/src/runners/wcgi/runner.rs index aa14d519305..ed6dd3bfde8 100644 --- a/lib/wasi/src/runners/wcgi/runner.rs +++ b/lib/wasi/src/runners/wcgi/runner.rs @@ -8,7 +8,6 @@ use tower::{make::Shared, ServiceBuilder}; use tower_http::{catch_panic::CatchPanicLayer, cors::CorsLayer, trace::TraceLayer}; use tracing::Span; use wasmer::{Engine, Module, Store}; -use wasmer_vfs::FileSystem; use wcgi_host::CgiDialect; use webc::metadata::{ annotations::{Wasi, Wcgi}, @@ -226,10 +225,6 @@ impl RunnerContext<'_> { &self.store } - fn container_fs(&self) -> Box { - self.container.container_fs() - } - fn get_atom(&self, name: &str) -> Option<&[u8]> { self.container.get_atom(name) }