From 13bd4aedffda005a08fb0bb5496a9035efd9de11 Mon Sep 17 00:00:00 2001 From: Luxian Date: Sat, 9 Nov 2024 12:23:48 +0800 Subject: [PATCH] [scorpio]: Improve Mounting Interface. v1.0 Signed-off-by: Luxian --- scorpio/README.md | 9 + scorpio/config.toml | 11 +- scorpio/src/deamon/mod.rs | 74 +++--- scorpio/src/fuse/mod.rs | 344 +-------------------------- scorpio/src/overlayfs/inode_store.rs | 4 +- scorpio/src/overlayfs/mod.rs | 5 +- 6 files changed, 57 insertions(+), 390 deletions(-) diff --git a/scorpio/README.md b/scorpio/README.md index b78a2087..9b61158b 100644 --- a/scorpio/README.md +++ b/scorpio/README.md @@ -46,7 +46,16 @@ The structure of Sapling is achieved through a multi-layered architecture, with ### How to Use? +1. run the mono server in `localhost:8000`. +2. config the `mount_path` and `store_path` in the `config.toml` +3. `cargo run ` in the `scorpio` dictionary. + +The following interfaces are currently available: +```bash +curl -X POST http://localhost:2725/api/fs/mount -H "Content-Type: application/json" -d '{"path": "third-part/mega/scorpio"}' +curl -X GET http://localhost:2725/api/fs/mpoint +``` ### How to Contribute? diff --git a/scorpio/config.toml b/scorpio/config.toml index 6e8b1f91..e34dbbb9 100644 --- a/scorpio/config.toml +++ b/scorpio/config.toml @@ -1,13 +1,10 @@ url = "http://localhost:8000" -mount_path = "/home/luxian/megadir/mount" -store_path = "/home/luxian/megadir/store" - -[[works]] -path = "third-part/mega/libra" -node = 35 -hash = "47a90e9262bcd023bbff32f9f4c328b43b62813a" +mount_path = "~/megadir/mount" +store_path = "~/megadir/store" [[works]] path = "third-part/mega/scorpio" node = 44 hash = "87c37b198c0a83e57afeaf2228c8a3a39769afc7" + + diff --git a/scorpio/src/deamon/mod.rs b/scorpio/src/deamon/mod.rs index 5e760315..aaac6501 100644 --- a/scorpio/src/deamon/mod.rs +++ b/scorpio/src/deamon/mod.rs @@ -1,12 +1,16 @@ +use std::path::PathBuf; use std::sync::Arc; use axum::extract::State; use axum::Router; use axum::routing::{post, get}; +use fuse3::raw::{Filesystem, Request}; use serde::{Deserialize, Serialize}; use tokio::sync::Mutex; use crate::fuse::MegaFuse; +use crate::manager::fetch::fetch; use crate::manager::ScorpioManager; +use crate::util::GPath; #[derive(Debug, Deserialize, Serialize)] @@ -67,9 +71,7 @@ struct ConfigRequest { } #[derive(Clone)] struct ScoState{ - #[allow(unused)] fuse:Arc, - #[allow(unused)] manager:Arc>, } #[allow(unused)] @@ -90,25 +92,24 @@ pub async fn deamon_main(fuse:Arc,manager:ScorpioManager) { } async fn mount_handler( - State(_state): State, // 注入共享状态 - _req: axum::Json, + State(state): State, // 注入共享状态 + req: axum::Json, ) -> axum::Json { - // let mono_path = req.path.clone(); - // let inode = state.fuse.get_inode(&mono_path); - // let mut ml = state.manager.lock().await; - // let store_path = ml.store_path.clone(); - // let work_dir = fetch(&mut ml,inode, mono_path).await; - // let store_path = PathBuf::from(store_path).join(&work_dir.hash); - // state.fuse.overlay_mount(inode, store_path); - // state.fuse.async_init(fuse_backend_rs::abi::fuse_abi::FsOptions::empty()).await; - //let _ = state.fuse.init(fuse_backend_rs::abi::fuse_abi::FsOptions::empty()); + let mono_path = GPath::from(req.path.clone()).to_string(); + let inode = state.fuse.get_inode(&mono_path).await; + let mut ml = state.manager.lock().await; + let store_path = ml.store_path.clone(); + let work_dir = fetch(&mut ml,inode, mono_path).await; + let store_path = PathBuf::from(store_path).join(&work_dir.hash); + state.fuse.overlay_mount(inode, store_path).await; + let _ = state.fuse.init(Request::default()).await; + // 在这里可以访问 state.fuse 或 state.manager let mount_info = MountInfo{ - hash: "hash".to_string(), - path: "path".to_string(), - inode: 0, + hash:work_dir.hash, + path: work_dir.path, + inode, }; - axum::Json(MountResponse { status: "success".to_string(), mount: mount_info, @@ -116,29 +117,18 @@ async fn mount_handler( }) } -async fn mounts_handler(State(_state): State) -> axum::Json { - // 你可以在这里使用 state.fuse 或 state.manager 来获取挂载点信息 - let mounts = vec![ - MountInfo { - hash: "abc123".to_string(), - path: "/mnt/dir1".to_string(), - inode: 1001, - }, - MountInfo { - hash: "def456".to_string(), - path: "/mnt/dir2".to_string(), - inode: 1002, - }, - MountInfo { - hash: "ghi789".to_string(), - path: "/mnt/dir3".to_string(), - inode: 1003, - }, - ]; +async fn mounts_handler(State(state): State) -> axum::Json { + let manager = state.manager.lock().await; + let re = manager.works.iter().map(|word_dir| MountInfo{ + hash: word_dir.hash.clone(), + path: word_dir.path.clone(), + inode: word_dir.node, + }).collect(); + axum::Json(MountsResponse { status: "success".to_string(), - mounts, + mounts: re, }) } @@ -153,13 +143,15 @@ async fn umount_handler( }) } -async fn config_handler(State(_state): State) -> axum::Json { +async fn config_handler(State(state): State) -> axum::Json { + let t = state.manager.lock().await; // 使用 state 访问配置逻辑 let config_info = ConfigInfo { - mega_url: "http://localhost:8000".to_string(), - mount_path: "/home/luxian/megadir/mount".to_string(), - store_path: "/home/luxian/megadir/store".to_string(), + mega_url: t.url.clone(), + mount_path: t.mount_path.clone(), + store_path: t.store_path.clone(), }; + drop(t); axum::Json(ConfigResponse { status: "success".to_string(), diff --git a/scorpio/src/fuse/mod.rs b/scorpio/src/fuse/mod.rs index 4e8db87d..5fba85fb 100644 --- a/scorpio/src/fuse/mod.rs +++ b/scorpio/src/fuse/mod.rs @@ -38,7 +38,7 @@ impl MegaFuse{ } // TODO: add pass parameter: lower-dir and upper-dir. - pub async fn overlay_mount>(&self, inode: u64, store_path: P) { + pub async fn overlay_mount>(&self, inode: u64, store_path: P){ let lower = store_path.as_ref().join("lower"); let upper = store_path.as_ref().join("upper"); @@ -83,6 +83,10 @@ impl MegaFuse{ self.overlayfs.lock().await.insert(inode, Arc::new(overlayfs)); } + pub async fn overlay_un_mount>(&self, store_path: P) -> std::io::Result<()>{ + + Ok(()) + } pub async fn get_inode(&self,path:&str) -> u64{ let item = self.dic.store.get_by_path(path).await; @@ -99,341 +103,3 @@ impl MegaFuse{ } } - - -// impl FileSystem for MegaFuse{ -// type Inode = u64; -// type Handle = u64; -// fn init(&self, capable: FsOptions) -> Result { -// self.dic.init(capable).unwrap(); -// let map_lock = &self.overlayfs.lock().unwrap(); -// for (inode,ovl_fs) in map_lock.iter(){ -// let inode_batch = self.inodes_alloc.alloc_inode(*inode); -// ovl_fs.extend_inode_alloc(inode_batch).await; -// ovl_fs.init(capable).unwrap(); -// } -// Ok(fuse_backend_rs::abi::fuse_abi::FsOptions::empty()) -// } - -// // fn destroy(&self) {} - -// fn statfs(&self, ctx: &Context, inode: Self::Inode) -> Result { - -// let a:Arc> = select_filesystem!(self,inode ); -// a.statfs(ctx, inode) -// } - -// fn lookup(&self, ctx: &Context, parent: Self::Inode, name: &CStr) -> Result { -// let a:Arc> = select_filesystem!(self,parent ); -// a.lookup(ctx, parent, name) -// } - -// fn opendir( -// &self, -// ctx: &Context, -// inode: Self::Inode, -// flags: u32, -// ) -> Result<(Option, OpenOptions)> { -// let a:Arc> = select_filesystem!(self,inode ); -// a.opendir(ctx, inode, flags) -// } - -// fn releasedir(&self, ctx: &Context, inode: Self::Inode, flags: u32, handle: Self::Handle) -> Result<()> { -// let a:Arc> = select_filesystem!(self,inode ); -// a.releasedir(ctx, inode, flags, handle) -// } - -// // for mkdir or create file -// // 1. lookup name, if exists and not whiteout, return EEXIST -// // 2. not exists and no whiteout, copy up parent node, ususally a mkdir on upper layer would do the work -// // 3. find whiteout, if whiteout in upper layer, should set opaque. if in lower layer, just mkdir? -// fn mkdir( -// &self, -// ctx: &Context, -// parent: Self::Inode, -// name: &CStr, -// mode: u32, -// umask: u32, -// ) -> Result { -// println!("top mkdir : parent:{}, name :{:?}, mode:{},umask:{}",parent,name,mode,umask); -// let a:Arc> = select_filesystem!(self,parent ); -// a.mkdir(ctx, parent, name, mode, umask) -// } - -// fn rmdir(&self, ctx: &Context, parent: Self::Inode, name: &CStr) -> Result<()> { -// let a:Arc> = select_filesystem!(self,parent ); -// a.rmdir(ctx, parent, name) -// } - -// fn readdir( -// &self, -// ctx: &Context, -// inode: Self::Inode, -// handle: Self::Handle, -// size: u32, -// offset: u64, -// add_entry: &mut dyn FnMut(DirEntry) -> Result, -// ) -> Result<()> { -// let a:Arc> = select_filesystem!(self,inode ); -// a.readdir(ctx, inode, handle, size, offset, add_entry) -// } - -// fn readdirplus( -// &self, -// ctx: &Context, -// inode: Self::Inode, -// handle: Self::Handle, -// size: u32, -// offset: u64, -// add_entry: &mut dyn FnMut(DirEntry, Entry) -> Result, -// ) -> Result<()> { -// let a:Arc> = select_filesystem!(self,inode ); -// a.readdirplus(ctx, inode, handle, size, offset, add_entry) -// } - -// fn open( -// &self, -// ctx: &Context, -// inode: Self::Inode, -// flags: u32, -// fuse_flags: u32, -// ) -> Result<(Option, OpenOptions, Option)> { -// let a:Arc> = select_filesystem!(self,inode ); -// a.open(ctx, inode, flags, fuse_flags) -// } - -// fn release( -// &self, -// ctx: &Context, -// inode: Self::Inode, -// flags: u32, -// handle: Self::Handle, -// flush: bool, -// flock_release: bool, -// lock_owner: Option, -// ) -> Result<()> { -// let a:Arc> = select_filesystem!(self,inode ); -// a.release(ctx, inode, flags, handle, flush, flock_release, lock_owner) -// } - -// fn create( -// &self, -// ctx: &Context, -// parent: Self::Inode, -// name: &CStr, -// args: CreateIn, -// ) -> Result<(Entry, Option, OpenOptions, Option)> { -// let a:Arc> = select_filesystem!(self,parent ); -// a.create(ctx, parent, name, args) -// } - -// fn unlink(&self, ctx: &Context, parent: Self::Inode, name: &CStr) -> Result<()> { -// let a:Arc> = select_filesystem!(self,parent ); -// a.unlink(ctx, parent, name) -// } - -// fn read( -// &self, -// ctx: &Context, -// inode: Self::Inode, -// handle: Self::Handle, -// w: &mut dyn ZeroCopyWriter, -// size: u32, -// offset: u64, -// lock_owner: Option, -// flags: u32, -// ) -> Result { -// let a:Arc> = select_filesystem!(self,inode ); -// a.read(ctx, inode, handle, w, size, offset, lock_owner, flags) -// } - -// fn write( -// &self, -// ctx: &Context, -// inode: Self::Inode, -// handle: Self::Handle, -// r: &mut dyn ZeroCopyReader, -// size: u32, -// offset: u64, -// lock_owner: Option, -// delayed_write: bool, -// flags: u32, -// fuse_flags: u32, -// ) -> Result { -// let a:Arc> = select_filesystem!(self,inode ); -// a.write(ctx, inode, handle, r, size, offset, lock_owner, delayed_write, flags, fuse_flags) -// } - -// fn getattr( -// &self, -// ctx: &Context, -// inode: Self::Inode, -// handle: Option, -// ) -> Result<(stat64, Duration)> { -// let a:Arc> = select_filesystem!(self,inode ); -// a.getattr(ctx, inode, handle) -// } - -// fn setattr( -// &self, -// ctx: &Context, -// inode: Self::Inode, -// attr: stat64, -// handle: Option, -// valid: SetattrValid, -// ) -> Result<(stat64, Duration)> { -// let a:Arc> = select_filesystem!(self,inode ); -// a.setattr(ctx, inode, attr, handle, valid) -// } - - - -// fn mknod( -// &self, -// ctx: &Context, -// inode: Self::Inode, -// name: &CStr, -// mode: u32, -// rdev: u32, -// umask: u32, -// ) -> Result { -// let a:Arc> = select_filesystem!(self,inode ); -// a.mknod(ctx, inode, name, mode, rdev, umask) -// } - -// fn link(&self, ctx: &Context, inode: Self::Inode, newparent: Self::Inode, name: &CStr) -> Result { -// let a:Arc> = select_filesystem!(self,inode ); -// a.link(ctx, inode, newparent, name) -// } - -// fn symlink(&self, ctx: &Context, linkname: &CStr, parent: Self::Inode, name: &CStr) -> Result { -// let a:Arc> = select_filesystem!(self,parent ); -// a.symlink(ctx, linkname, parent, name) -// } - -// fn readlink(&self, ctx: &Context, inode: Self::Inode) -> Result> { -// let a:Arc> = select_filesystem!(self,inode ); -// a.readlink(ctx, inode) -// } - -// fn flush(&self, ctx: &Context, inode: Self::Inode, handle: Self::Handle, lock_owner: u64) -> Result<()> { -// let a:Arc> = select_filesystem!(self,inode ); -// a.flush(ctx, inode, handle, lock_owner) -// } - -// fn fsync(&self, ctx: &Context, inode: Self::Inode, datasync: bool, handle: Self::Handle) -> Result<()> { -// let a:Arc> = select_filesystem!(self,inode ); -// a.fsync(ctx, inode, datasync, handle) -// } - -// fn fsyncdir(&self, ctx: &Context, inode: Self::Inode, datasync: bool, handle: Self::Handle) -> Result<()> { -// let a:Arc> = select_filesystem!(self,inode ); -// a.fsyncdir(ctx, inode, datasync, handle) -// } - -// fn access(&self, ctx: &Context, inode: Self::Inode, mask: u32) -> Result<()> { -// let a:Arc> = select_filesystem!(self,inode ); -// a.access(ctx, inode, mask) -// } - -// fn setxattr( -// &self, -// ctx: &Context, -// inode: Self::Inode, -// name: &CStr, -// value: &[u8], -// flags: u32, -// ) -> Result<()> { -// let a:Arc> = select_filesystem!(self,inode ); -// a.setxattr(ctx, inode, name, value, flags) -// } - -// fn getxattr( -// &self, -// ctx: &Context, -// inode: Self::Inode, -// name: &CStr, -// size: u32, -// ) -> Result { -// let a:Arc> = select_filesystem!(self,inode ); -// a.getxattr(ctx, inode, name, size) -// } - -// fn listxattr(&self, ctx: &Context, inode: Self::Inode, size: u32) -> Result { -// let a:Arc> = select_filesystem!(self,inode ); -// a.listxattr(ctx, inode, size) -// } - -// fn removexattr(&self, ctx: &Context, inode: Self::Inode, name: &CStr) -> Result<()> { -// let a:Arc> = select_filesystem!(self,inode ); -// a.removexattr(ctx, inode, name) -// } - -// fn fallocate( -// &self, -// ctx: &Context, -// inode: Self::Inode, -// handle: Self::Handle, -// mode: u32, -// offset: u64, -// length: u64, -// ) -> Result<()> { -// let a:Arc> = select_filesystem!(self,inode ); -// a.fallocate(ctx, inode, handle, mode, offset, length) -// } - -// fn lseek( -// &self, -// ctx: &Context, -// inode: Self::Inode, -// handle: Self::Handle, -// offset: u64, -// whence: u32, -// ) -> Result { -// let a:Arc> = select_filesystem!(self,inode ); -// a.lseek(ctx, inode, handle, offset, whence) -// } -// } - - - -// #[cfg(test)] -// mod tests{ -// use std::{path::Path, thread}; - -// use crate::server::FuseServer; - -// use super::*; -// use fuse_backend_rs::{api::server::Server, transport::{FuseChannel, FuseSession}}; -// use signal_hook::{consts::TERM_SIGNALS, iterator::Signals}; - -// #[test] -// pub fn test_dic_ovlfs(){ -// let megafuse = Arc::new(MegaFuse::new()); -// // dicfuse.init(FsOptions::empty()).unwrap(); -// // Create fuse session -// let mut se = FuseSession::new(Path::new(&"/home/luxian/megatest/dictest"), "dic", "", false).unwrap(); -// se.mount().unwrap(); -// let ch: FuseChannel = se.new_channel().unwrap(); -// println!("start fs servers"); -// let server = Arc::new(Server::new(megafuse.clone())); - -// let mut fuse_server = FuseServer { server, ch }; - -// // Spawn server thread -// let handle = thread::spawn(move || { -// let _ = fuse_server.svc_loop(); -// }); -// // Wait for termination signal -// let mut signals = Signals::new(TERM_SIGNALS).unwrap(); -// println!("Signals start"); -// if let Some(_sig) = signals.forever().next() { -// //pass -// } -// // Unmount and wake up -// se.umount().unwrap(); -// se.wake().unwrap(); -// // Join server thread -// let _ = handle.join(); -// } -// } \ No newline at end of file diff --git a/scorpio/src/overlayfs/inode_store.rs b/scorpio/src/overlayfs/inode_store.rs index 4b56d0c5..ea1b917e 100644 --- a/scorpio/src/overlayfs/inode_store.rs +++ b/scorpio/src/overlayfs/inode_store.rs @@ -8,7 +8,9 @@ use std::{ sync::Arc, }; -use super::{Inode, OverlayInode, VFS_MAX_INO}; +use crate::passthrough::VFS_MAX_INO; + +use super::{Inode, OverlayInode}; use futures::future::join_all; use radix_trie::Trie; diff --git a/scorpio/src/overlayfs/mod.rs b/scorpio/src/overlayfs/mod.rs index 30dc9ea3..58073b4d 100644 --- a/scorpio/src/overlayfs/mod.rs +++ b/scorpio/src/overlayfs/mod.rs @@ -24,9 +24,10 @@ use fuse3::raw::{Filesystem, Request}; use fuse3::{mode_from_kind_and_perm, Errno, FileType}; -use fuse_backend_rs::api::{SLASH_ASCII, VFS_MAX_INO}; +const SLASH_ASCII: char = '/'; use futures::future::join_all; use futures::stream::iter; + use futures::StreamExt; use inode_store::InodeStore; use layer::Layer; @@ -944,7 +945,7 @@ impl OverlayFs { // If name is empty, return parent itself. // Parent dir will be loaded, but returned OverlayInode won't. async fn lookup_node(&self, ctx: Request, parent: Inode, name: &str) -> Result> { - if name.contains([SLASH_ASCII as char]) { + if name.contains(SLASH_ASCII) { return Err(Error::from_raw_os_error(libc::EINVAL)); }