diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4b31f85..bd9ace8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -40,7 +40,7 @@ jobs: run: | mkdir -p /data/action/_work/sealfs/sealfs/target if [ -d /data/backup/debug ]; then - mv /data/backup/debug w/data/action/_work/sealfs/sealfs/target + mv /data/backup/debug /data/action/_work/sealfs/sealfs/target fi - name: Build diff --git a/docker/client/Dockerfile b/docker/client/Dockerfile index f4b1b6a..d5d48ae 100644 --- a/docker/client/Dockerfile +++ b/docker/client/Dockerfile @@ -1,7 +1,7 @@ FROM debian:bullseye-20221205 RUN apt update && apt upgrade -y && apt-mark unhold libcap2 && \ - apt install -y libfuse3-3 libfuse2 libibverbs1 && \ + apt install -y fuse3 libfuse3-3 libfuse2 libibverbs1 && \ apt clean && \ rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* diff --git a/src/client/daemon.rs b/src/client/daemon.rs index 3617a1d..b082796 100644 --- a/src/client/daemon.rs +++ b/src/client/daemon.rs @@ -13,7 +13,9 @@ use fuser::{BackgroundSession, MountOption}; use log::{error, info}; use crate::{ - common::{errors::CONNECTION_ERROR, sender::REQUEST_TIMEOUT}, + common::{ + errors::CONNECTION_ERROR, sender::REQUEST_TIMEOUT, serialization::MountVolumeSendMetaData, + }, rpc::{ client::{RpcClient, UnixStreamCreator}, server::Handler, @@ -28,7 +30,7 @@ const LIST_MOUNTPOINTS: u32 = 4; pub struct SealfsFused { pub client: Arc, - pub mount_points: DashMap, + pub mount_points: DashMap, pub index_file: String, } @@ -47,8 +49,18 @@ impl SealfsFused { } } - pub async fn mount(&self, mountpoint: String, volume_name: String) -> Result<(), i32> { - let mut options = vec![MountOption::RW, MountOption::FSName("seal".to_string())]; + pub async fn mount( + &self, + mountpoint: String, + volume_name: String, + read_only: bool, + ) -> Result<(), i32> { + let mount_mode = if read_only { + MountOption::RO + } else { + MountOption::RW + }; + let mut options = vec![mount_mode, MountOption::FSName("seal".to_string())]; options.push(MountOption::AutoUnmount); options.push(MountOption::AllowRoot); let result = self.client.init_volume(&volume_name).await; @@ -62,7 +74,8 @@ impl SealfsFused { ) { Ok(session) => { info!("mount success"); - self.mount_points.insert(mountpoint, (volume_name, session)); + self.mount_points + .insert(mountpoint, (volume_name, read_only, session)); Ok(()) } Err(e) => { @@ -101,7 +114,7 @@ impl SealfsFused { std::fs::remove_file(&self.index_file).unwrap_or(()); let mut file = std::fs::File::create(&self.index_file).unwrap(); for k in self.mount_points.iter() { - let line = format!("{}\n{}\n\n", k.key(), k.value().0); + let line = format!("{}\n{}\n{}\n\n", k.key(), k.value().0, k.value().1); file.write_all(line.as_bytes()).unwrap(); } } @@ -127,11 +140,12 @@ impl SealfsFused { } } let lines: Vec<&str> = content.split('\n').collect(); - for i in 0..lines.len() / 3 { - let mountpoint = lines[i * 3].to_owned(); - let volume_name = lines[i * 3 + 1].to_owned(); + for i in 0..lines.len() / 4 { + let mountpoint = lines[i * 4].to_owned(); + let volume_name = lines[i * 4 + 1].to_owned(); + let read_only = lines[i * 4 + 2].parse::().unwrap(); info!("mounting volume {} to {}", volume_name, mountpoint); - match self.mount(mountpoint, volume_name.clone()).await { + match self.mount(mountpoint, volume_name.clone(), read_only).await { Ok(_) => { info!("mount success"); } @@ -161,9 +175,16 @@ impl Handler for SealfsFused { ) -> anyhow::Result<(i32, u32, usize, usize, Vec, Vec)> { match operation_type { MOUNT => { - let mountpoint = String::from_utf8(path).unwrap(); - let volume_name = String::from_utf8(metadata).unwrap(); - match self.mount(mountpoint, volume_name).await { + let send_meta_data: MountVolumeSendMetaData = + bincode::deserialize(&metadata).unwrap(); + match self + .mount( + send_meta_data.mount_point, + send_meta_data.volume_name, + send_meta_data.read_only, + ) + .await + { Ok(_) => { self.sync_index_file(); Ok((0, 0, 0, 0, vec![], vec![])) @@ -230,21 +251,33 @@ impl LocalCli { }) } - pub async fn mount(&self, volume_name: &str, mount_point: &str) -> Result<(), i32> { + pub async fn mount( + &self, + volume_name: &str, + mount_point: &str, + read_only: bool, + ) -> Result<(), i32> { let mut status = 0i32; let mut rsp_flags = 0u32; let mut recv_meta_data_length = 0usize; let mut recv_data_length = 0usize; + let send_meta_data = bincode::serialize(&MountVolumeSendMetaData { + volume_name: volume_name.to_string(), + mount_point: mount_point.to_string(), + read_only, + }) + .unwrap(); + let result = self .client .call_remote( &self.path, MOUNT, 0, - mount_point, - volume_name.as_bytes(), + "", + &send_meta_data, &[], &mut status, &mut rsp_flags, diff --git a/src/client/mod.rs b/src/client/mod.rs index a9d7126..a006fe9 100644 --- a/src/client/mod.rs +++ b/src/client/mod.rs @@ -89,8 +89,11 @@ enum Commands { #[arg(required = true, name = "volume-name")] volume_name: Option, - #[arg(name = "socket-path")] + #[arg(long = "socket-path", name = "socket-path")] socket_path: Option, + + #[arg(long = "read-only", name = "read-only")] + read_only: bool, }, Umount { /// Unmount FUSE at given path @@ -507,6 +510,7 @@ pub async fn run_command() -> Result<(), Box> { mount_point, volume_name, socket_path, + read_only, } => { let socket_path = match socket_path { Some(path) => path, @@ -519,7 +523,7 @@ pub async fn run_command() -> Result<(), Box> { } let result = local_client - .mount(&volume_name.unwrap(), &mount_point.unwrap()) + .mount(&volume_name.unwrap(), &mount_point.unwrap(), read_only) .await; match result { Ok(_) => info!("mount success"), diff --git a/src/common/serialization.rs b/src/common/serialization.rs index f3c0bda..166889d 100644 --- a/src/common/serialization.rs +++ b/src/common/serialization.rs @@ -871,6 +871,13 @@ pub struct CreateVolumeSendMetaData { pub size: u64, } +#[derive(Serialize, Deserialize, PartialEq)] +pub struct MountVolumeSendMetaData { + pub volume_name: String, + pub mount_point: String, + pub read_only: bool, +} + #[derive(Serialize, Deserialize, PartialEq, Clone)] pub struct Volume { pub name: String, diff --git a/src/rpc/protocol.rs b/src/rpc/protocol.rs index 6a38050..328630c 100644 --- a/src/rpc/protocol.rs +++ b/src/rpc/protocol.rs @@ -7,7 +7,7 @@ pub const MAX_DATA_LENGTH: usize = 65536 * 128; pub const MAX_METADATA_LENGTH: usize = 4096; pub const MAX_COPY_LENGTH: usize = 1024 * 8; -pub const CONNECTION_RETRY_TIMES: i32 = 20; +pub const CONNECTION_RETRY_TIMES: i32 = 100; pub const SEND_RETRY_TIMES: i32 = 3; // request