diff --git a/Makefile b/Makefile index bde1a50be..6653e41ab 100644 --- a/Makefile +++ b/Makefile @@ -55,9 +55,3 @@ smoke-macos: check-macos docker-smoke: docker run --env RUST_BACKTRACE=1 --rm --privileged --volume ${current_dir}:/fuse-rs rust:1.68 sh -c "rustup component add clippy rustfmt; cd /fuse-rs; make smoke-all" -testoverlay: - cd tests/testoverlay && cargo build - -# Setup xfstests env and run. -xfstests: - ./tests/scripts/xfstests.sh \ No newline at end of file diff --git a/src/api/filesystem/overlay.rs b/src/api/filesystem/overlay.rs index cf2c3d1fc..e58d6d609 100644 --- a/src/api/filesystem/overlay.rs +++ b/src/api/filesystem/overlay.rs @@ -4,11 +4,11 @@ #![allow(missing_docs)] -use crate::abi::fuse_abi::stat64; use std::ffi::{CStr, CString}; use std::io::{Error, ErrorKind, Result}; use super::{Context, Entry, FileSystem, GetxattrReply}; +use crate::abi::fuse_abi::stat64; pub const OPAQUE_XATTR_LEN: u32 = 16; pub const OPAQUE_XATTR: &str = "user.fuseoverlayfs.opaque"; @@ -21,30 +21,29 @@ pub trait Layer: FileSystem { fn root_inode(&self) -> Self::Inode; /// Create whiteout file with name . - #[allow(clippy::unnecessary_cast)] + /// + /// If this call is successful then the lookup count of the `Inode` associated with the returned + /// `Entry` must be increased by 1. fn create_whiteout(&self, ctx: &Context, parent: Self::Inode, name: &CStr) -> Result { // Use temp value to avoid moved 'parent'. let ino: u64 = parent.into(); match self.lookup(ctx, ino.into(), name) { Ok(v) => { - if v.inode != 0 { - // Decrease the refcount. - self.forget(ctx, v.inode.into(), 1); - } - // Find whiteout char dev. if is_whiteout(v.attr) { return Ok(v); } - // Negative entry with inode 0 indicates no entry. + // Non-negative entry with inode larger than 0 indicates file exists. if v.inode != 0 { + // Decrease the refcount. + self.forget(ctx, v.inode.into(), 1); // File exists with same name, create whiteout file is not allowed. return Err(Error::from_raw_os_error(libc::EEXIST)); } } Err(e) => match e.raw_os_error() { Some(raw_error) => { - // We expect ENOENT or ENAMETOOLONG error. + // We expect ENOENT error. if raw_error != libc::ENOENT { return Err(e); } @@ -56,7 +55,7 @@ pub trait Layer: FileSystem { // Try to create whiteout char device with 0/0 device number. let dev = libc::makedev(0, 0); let mode = libc::S_IFCHR | 0o777; - self.mknod(ctx, ino.into(), name, mode as u32, dev as u32, 0) + self.mknod(ctx, ino.into(), name, mode, dev as u32, 0) } /// Delete whiteout file with name . @@ -66,7 +65,7 @@ pub trait Layer: FileSystem { match self.lookup(ctx, ino.into(), name) { Ok(v) => { if v.inode != 0 { - // Decrease the refcount. + // Decrease the refcount since we make a lookup call. self.forget(ctx, v.inode.into(), 1); } @@ -74,7 +73,7 @@ pub trait Layer: FileSystem { if is_whiteout(v.attr) { return self.unlink(ctx, ino.into(), name); } - // Negative entry with inode 0 indicates no entry. + // Non-negative entry with inode larger than 0 indicates file exists. if v.inode != 0 { // File exists but not whiteout file. return Err(Error::from_raw_os_error(libc::EINVAL)); @@ -82,7 +81,7 @@ pub trait Layer: FileSystem { } Err(e) => match e.raw_os_error() { Some(raw_error) => { - // ENOENT and ENAMETOOLONG are good. + // ENOENT is acceptable. if raw_error != libc::ENOENT { return Err(e); } @@ -101,13 +100,29 @@ pub trait Layer: FileSystem { Ok(is_whiteout(st)) } + /// Set the directory to opaque. fn set_opaque(&self, ctx: &Context, inode: Self::Inode) -> Result<()> { + // Use temp value to avoid moved 'parent'. + let ino: u64 = inode.into(); + + // Get attributes and check if it's directory. + let (st, _d) = self.getattr(ctx, ino.into(), None)?; + if !is_dir(st) { + // Only directory can be set to opaque. + return Err(Error::from_raw_os_error(libc::ENOTDIR)); + } // A directory is made opaque by setting the xattr "trusted.overlay.opaque" to "y". // See ref: https://docs.kernel.org/filesystems/overlayfs.html#whiteouts-and-opaque-directories - self.setxattr(ctx, inode, to_cstring(OPAQUE_XATTR)?.as_c_str(), b"y", 0) + self.setxattr( + ctx, + ino.into(), + to_cstring(OPAQUE_XATTR)?.as_c_str(), + b"y", + 0, + ) } - // Check if the directory is opaque. + /// Check if the directory is opaque. fn is_opaque(&self, ctx: &Context, inode: Self::Inode) -> Result { // Use temp value to avoid moved 'parent'. let ino: u64 = inode.into(); @@ -118,10 +133,9 @@ pub trait Layer: FileSystem { return Err(Error::from_raw_os_error(libc::ENOTDIR)); } - // Return Result<(is_opaque, break)>, if 'break' is true, stop and return the is_opaque value. + // Return Result<(is_opaque, break)>, if 'break' is true, stop the whole function. let check_attr = |inode: Self::Inode, attr_name: &str, attr_size: u32| -> Result<(bool, bool)> { - // TODO: map error? let cname = CString::new(attr_name)?; match self.getxattr(ctx, inode, cname.as_c_str(), attr_size) { Ok(v) => { @@ -131,18 +145,11 @@ pub trait Layer: FileSystem { return Ok((true, true)); } } - // no value found, go on to next check. + // No value found, go on to next check. Ok((false, false)) } Err(e) => { if let Some(raw_error) = e.raw_os_error() { - // Overlay rely on getxattr, so if getxattr is not supported, we needs to error out. - // if raw_error == libc::ENOTSUP - // || raw_error == libc::ENOSYS - // { - // return Ok((false, true)); - // } - if raw_error == libc::ENODATA { return Ok((false, false)); } @@ -153,22 +160,24 @@ pub trait Layer: FileSystem { } }; - // A directory is made opaque by setting the xattr "trusted.overlay.opaque" to "y". + // A directory is made opaque by setting some specific xattr to "y". // See ref: https://docs.kernel.org/filesystems/overlayfs.html#whiteouts-and-opaque-directories - let (is_opaque, stop) = check_attr(ino.into(), PRIVILEGED_OPAQUE_XATTR, OPAQUE_XATTR_LEN)?; + + // Check our customized version of the xattr "user.fuseoverlayfs.opaque". + let (is_opaque, stop) = check_attr(ino.into(), OPAQUE_XATTR, OPAQUE_XATTR_LEN)?; if stop { return Ok(is_opaque); } - // Also check for the unprivileged version of the xattr. - let (is_opaque, stop) = - check_attr(ino.into(), UNPRIVILEGED_OPAQUE_XATTR, OPAQUE_XATTR_LEN)?; + // Also check for the unprivileged version of the xattr "trusted.overlay.opaque". + let (is_opaque, stop) = check_attr(ino.into(), PRIVILEGED_OPAQUE_XATTR, OPAQUE_XATTR_LEN)?; if stop { return Ok(is_opaque); } - // And our customized version of the xattr. - let (is_opaque, stop) = check_attr(ino.into(), OPAQUE_XATTR, OPAQUE_XATTR_LEN)?; + // Also check for the unprivileged version of the xattr "user.overlay.opaque". + let (is_opaque, stop) = + check_attr(ino.into(), UNPRIVILEGED_OPAQUE_XATTR, OPAQUE_XATTR_LEN)?; if stop { return Ok(is_opaque); } diff --git a/src/api/server/sync_io.rs b/src/api/server/sync_io.rs index 9cf56d514..ba2606fca 100644 --- a/src/api/server/sync_io.rs +++ b/src/api/server/sync_io.rs @@ -63,7 +63,6 @@ impl Server { /// invokes filesystem drivers to server the requests, and eventually send back the result to /// the transport layer. #[allow(unused_variables)] - #[allow(unused_must_use)] pub fn handle_message( &self, mut r: Reader<'_, S>, diff --git a/src/overlayfs/config.rs b/src/overlayfs/config.rs index debf5d172..37312bf5d 100644 --- a/src/overlayfs/config.rs +++ b/src/overlayfs/config.rs @@ -16,8 +16,6 @@ pub struct Config { pub no_opendir: bool, pub killpriv_v2: bool, pub no_readdir: bool, - // pub xattr: bool, - // pub xattr_permissions: bool, pub perfile_dax: bool, pub cache_policy: CachePolicy, pub attr_timeout: Duration, diff --git a/src/overlayfs/mod.rs b/src/overlayfs/mod.rs index 940f29615..4fddc445f 100644 --- a/src/overlayfs/mod.rs +++ b/src/overlayfs/mod.rs @@ -4,13 +4,13 @@ #![allow(missing_docs)] pub mod config; pub mod sync_io; -mod utils; +pub mod utils; use core::panic; use std::collections::HashMap; use std::ffi::{CStr, CString}; use std::fs::File; -use std::io::{Result, Seek, SeekFrom}; +use std::io::{Error, ErrorKind, Result, Seek, SeekFrom}; use std::sync::atomic::{AtomicBool, AtomicU64, Ordering}; use std::sync::{Arc, Mutex, Weak}; @@ -27,13 +27,9 @@ use crate::common::file_traits::FileReadWriteVolatile; use vmm_sys_util::tempfile::TempFile; use self::config::Config; -use std::io::{Error, ErrorKind}; pub type Inode = u64; pub type Handle = u64; -pub const OPAQUE_XATTR: &str = "user.fuseoverlayfs.opaque"; -pub const UNPRIVILEGED_OPAQUE_XATTR: &str = "user.overlay.opaque"; -pub const PRIVILEGED_OPAQUE_XATTR: &str = "trusted.overlay.opaque"; pub const MAXNAMELEN: usize = 256; pub const CURRENT_DIR: &str = "."; pub const PARENT_DIR: &str = ".."; @@ -44,7 +40,8 @@ pub type BoxedLayer = Box + Send + Syn // RealInode represents one inode object in specific layer. // Also, each RealInode maps to one Entry, which should be 'forgotten' after drop. -pub struct RealInode { +// Important note: do not impl Clone trait for it or refcount will be messed up. +struct RealInode { pub layer: Arc, pub in_upper_layer: bool, pub inode: u64, @@ -57,7 +54,7 @@ pub struct RealInode { // OverlayInode must be protected by lock, it can be operated by multiple threads. #[derive(Default)] -pub struct OverlayInode { +struct OverlayInode { // Inode hash table, map from 'name' to 'OverlayInode'. pub childrens: Mutex>>, pub parent: Mutex>, @@ -65,10 +62,6 @@ pub struct OverlayInode { pub real_inodes: Mutex>, // Inode number. pub inode: u64, - // pub st_ino: ino64_t, - // pub st_dev: libc::dev_t, - // pub mode: libc::mode_t, - // pub entry_type: u32, pub path: String, pub name: String, pub lookups: AtomicU64, @@ -87,40 +80,38 @@ pub enum CachePolicy { } pub struct OverlayFs { // should be in daemon structure - pub config: Config, - pub lower_layers: Vec>, - pub upper_layer: Option>, + config: Config, + lower_layers: Vec>, + upper_layer: Option>, // inode management.. - pub root: Option>, + root: Option>, // Active inodes. - pub inodes: Mutex>>, + inodes: Mutex>>, // Deleted inodes are unlinked inodes with non zero lookup count. - pub deleted_inodes: Mutex>>, - pub next_inode: AtomicU64, + deleted_inodes: Mutex>>, + next_inode: AtomicU64, // manage opened fds. - pub handles: Mutex>>, - pub next_handle: AtomicU64, - pub writeback: AtomicBool, - pub no_open: AtomicBool, - pub no_opendir: AtomicBool, - pub killpriv_v2: AtomicBool, - pub perfile_dax: AtomicBool, + handles: Mutex>>, + next_handle: AtomicU64, + writeback: AtomicBool, + no_open: AtomicBool, + no_opendir: AtomicBool, + killpriv_v2: AtomicBool, + perfile_dax: AtomicBool, } -pub struct RealHandle { - pub layer: Arc, - pub in_upper_layer: bool, - pub inode: u64, - pub handle: AtomicU64, - // Invalid handle. - pub invalid: AtomicBool, +struct RealHandle { + layer: Arc, + in_upper_layer: bool, + inode: u64, + handle: AtomicU64, } -pub struct HandleData { - pub node: Arc, - pub offset: libc::off_t, - pub real_handle: Option, +struct HandleData { + node: Arc, + //offset: libc::off_t, + real_handle: Option, } // RealInode is a wrapper of one inode in specific layer. @@ -128,7 +119,7 @@ pub struct HandleData { // so that we can increase the refcount(lookup count) of each inode and decrease it after Drop. // Important: do not impl 'Copy' trait for it or refcount will be messed up. impl RealInode { - pub(crate) fn new( + fn new( layer: Arc, in_upper_layer: bool, inode: u64, @@ -154,7 +145,7 @@ impl RealInode { ri } - pub(crate) fn stat64(&self, ctx: &Context) -> Result { + fn stat64(&self, ctx: &Context) -> Result { let layer = self.layer.as_ref(); if self.inode == 0 { return Err(Error::from_raw_os_error(libc::ENOENT)); @@ -166,7 +157,7 @@ impl RealInode { } } - pub(crate) fn stat64_ignore_enoent(&self, ctx: &Context) -> Result> { + fn stat64_ignore_enoent(&self, ctx: &Context) -> Result> { match self.stat64(ctx) { Ok(v1) => Ok(Some(v1)), Err(e) => match e.raw_os_error() { @@ -208,7 +199,7 @@ impl RealInode { // Find child inode in same layer under this directory(Self). // Return None if not found. - pub(crate) fn lookup_child(&self, ctx: &Context, name: &str) -> Result> { + fn lookup_child(&self, ctx: &Context, name: &str) -> Result> { if self.whiteout { return Ok(None); } @@ -239,7 +230,7 @@ impl RealInode { } // Read directory entries from specific RealInode, error out if it's not directory. - pub(crate) fn readdir(&self, ctx: &Context) -> Result> { + fn readdir(&self, ctx: &Context) -> Result> { // Deleted inode should not be read. if self.whiteout { return Err(Error::from_raw_os_error(libc::ENOENT)); @@ -341,7 +332,7 @@ impl RealInode { Ok(child_real_inodes) } - pub(crate) fn create_whiteout(&self, ctx: &Context, name: &str) -> Result { + fn create_whiteout(&self, ctx: &Context, name: &str) -> Result { if !self.in_upper_layer { return Err(Error::from_raw_os_error(libc::EROFS)); } @@ -351,7 +342,7 @@ impl RealInode { .layer .create_whiteout(ctx, self.inode, cname.as_c_str())?; - // update node's first_layer + // Wrap whiteout to RealInode. Ok(RealInode { layer: self.layer.clone(), in_upper_layer: true, @@ -362,13 +353,7 @@ impl RealInode { }) } - pub(crate) fn mkdir( - &self, - ctx: &Context, - name: &str, - mode: u32, - umask: u32, - ) -> Result { + fn mkdir(&self, ctx: &Context, name: &str, mode: u32, umask: u32) -> Result { if !self.in_upper_layer { return Err(Error::from_raw_os_error(libc::EROFS)); } @@ -389,7 +374,7 @@ impl RealInode { }) } - pub(crate) fn create( + fn create( &self, ctx: &Context, name: &str, @@ -416,7 +401,7 @@ impl RealInode { )) } - pub(crate) fn mknod( + fn mknod( &self, ctx: &Context, name: &str, @@ -446,7 +431,7 @@ impl RealInode { }) } - pub(crate) fn link(&self, ctx: &Context, ino: u64, name: &str) -> Result { + fn link(&self, ctx: &Context, ino: u64, name: &str) -> Result { if !self.in_upper_layer { return Err(Error::from_raw_os_error(libc::EROFS)); } @@ -470,13 +455,8 @@ impl RealInode { }) } - // Create a symlink in dir(self). - pub(crate) fn symlink( - &self, - ctx: &Context, - link_name: &str, - filename: &str, - ) -> Result { + // Create a symlink in self directory. + fn symlink(&self, ctx: &Context, link_name: &str, filename: &str) -> Result { if !self.in_upper_layer { return Err(Error::from_raw_os_error(libc::EROFS)); } @@ -762,7 +742,7 @@ impl OverlayInode { } // Add new upper RealInode to OverlayInode, clear all lower RealInodes if 'clear_lowers' is true. - pub(crate) fn add_upper_inode(self: &Arc, ri: RealInode, clear_lowers: bool) { + fn add_upper_inode(self: &Arc, ri: RealInode, clear_lowers: bool) { let mut inodes = self.real_inodes.lock().unwrap(); // Update self according to upper attribute. self.whiteout.store(ri.whiteout, Ordering::Relaxed); @@ -1002,12 +982,7 @@ impl OverlayFs { // Lookup child OverlayInode with under directory. // If name is empty, return parent itself. // Parent dir will be loaded, but returned OverlayInode won't. - pub fn lookup_node( - &self, - ctx: &Context, - parent: Inode, - name: &str, - ) -> Result> { + fn lookup_node(&self, ctx: &Context, parent: Inode, name: &str) -> Result> { if name.contains([SLASH_ASCII as char]) { return Err(Error::from_raw_os_error(libc::EINVAL)); } @@ -1059,7 +1034,7 @@ impl OverlayFs { trace!("all inodes: {:?}", all_inodes); } - pub fn lookup_node_ignore_enoent( + fn lookup_node_ignore_enoent( &self, ctx: &Context, parent: u64, @@ -1078,16 +1053,8 @@ impl OverlayFs { } } - pub fn get_node_from_inode(&self, inode: u64) -> Option> { - if let Some(v) = self.get_inode(inode) { - return Some(v); - } - - None - } - // Load entries of the directory from all layers, if node is not directory, return directly. - pub fn load_directory(&self, ctx: &Context, node: &Arc) -> Result<()> { + fn load_directory(&self, ctx: &Context, node: &Arc) -> Result<()> { if node.loaded.load(Ordering::Relaxed) { return Ok(()); } @@ -1128,23 +1095,7 @@ impl OverlayFs { Ok(()) } - pub fn get_first_lower_layer(&self) -> Option> { - if !self.lower_layers.is_empty() { - Some(Arc::clone(&self.lower_layers[0])) - } else { - None - } - } - - pub fn get_first_layer(&self) -> Option> { - if let Some(ref l) = self.upper_layer { - return Some(Arc::clone(l)); - } - - self.get_first_lower_layer() - } - - pub fn forget_one(&self, inode: Inode, count: u64) { + fn forget_one(&self, inode: Inode, count: u64) { if inode == self.root_inode() || inode == 0 { return; } @@ -1185,7 +1136,7 @@ impl OverlayFs { } } - pub fn do_lookup(&self, ctx: &Context, parent: Inode, name: &str) -> Result { + fn do_lookup(&self, ctx: &Context, parent: Inode, name: &str) -> Result { let node = self.lookup_node(ctx, parent, name)?; if node.whiteout.load(Ordering::Relaxed) { @@ -1211,7 +1162,7 @@ impl OverlayFs { }) } - pub fn do_statvfs(&self, ctx: &Context, inode: Inode) -> Result { + fn do_statvfs(&self, ctx: &Context, inode: Inode) -> Result { match self.get_inode(inode) { Some(ovi) => { let all_inodes = ovi.real_inodes.lock().unwrap(); @@ -1224,15 +1175,8 @@ impl OverlayFs { } } - pub fn get_fs_namemax(&self, ctx: &Context) -> u64 { - match self.do_statvfs(ctx, self.root_inode()) { - Ok(sfs) => sfs.f_namemax, - Err(_) => 255, - } - } - #[allow(clippy::too_many_arguments)] - pub fn do_readdir( + fn do_readdir( &self, ctx: &Context, inode: Inode, @@ -1252,11 +1196,6 @@ impl OverlayFs { return Ok(()); } - // FIXME: if offset == 0, need to reconstruct dir for this handle - // if offset == 0 { - // reconstruct directory - // } - // lookup the directory let ovl_inode = match self.handles.lock().unwrap().get(&handle) { Some(dir) => dir.node.clone(), @@ -1349,7 +1288,7 @@ impl OverlayFs { Ok(()) } - pub fn do_mkdir( + fn do_mkdir( &self, ctx: &Context, parent_node: &Arc, @@ -1361,7 +1300,7 @@ impl OverlayFs { return Err(Error::from_raw_os_error(libc::EROFS)); } - // no entry or whiteout + // Parent node was deleted. if parent_node.whiteout.load(Ordering::Relaxed) { return Err(Error::from_raw_os_error(libc::ENOENT)); } @@ -1436,7 +1375,7 @@ impl OverlayFs { Ok(()) } - pub fn do_mknod( + fn do_mknod( &self, ctx: &Context, parent_node: &Arc, @@ -1449,7 +1388,7 @@ impl OverlayFs { return Err(Error::from_raw_os_error(libc::EROFS)); } - // no entry or whiteout + // Parent node was deleted. if parent_node.whiteout.load(Ordering::Relaxed) { return Err(Error::from_raw_os_error(libc::ENOENT)); } @@ -1519,7 +1458,7 @@ impl OverlayFs { Ok(()) } - pub fn do_create( + fn do_create( &self, ctx: &Context, parent_node: &Arc, @@ -1532,7 +1471,7 @@ impl OverlayFs { .cloned() .ok_or_else(|| Error::from_raw_os_error(libc::EROFS))?; - // no entry or whiteout + // Parent node was deleted. if parent_node.whiteout.load(Ordering::Relaxed) { return Err(Error::from_raw_os_error(libc::ENOENT)); } @@ -1615,13 +1554,11 @@ impl OverlayFs { let handle = self.next_handle.fetch_add(1, Ordering::Relaxed); let handle_data = HandleData { node: new_ovi, - offset: 0, real_handle: Some(RealHandle { layer: upper.clone(), in_upper_layer: true, inode: real_ino, handle: AtomicU64::new(hd), - invalid: AtomicBool::new(false), }), }; self.handles @@ -1636,7 +1573,7 @@ impl OverlayFs { Ok(final_handle) } - pub fn do_link( + fn do_link( &self, ctx: &Context, src_node: &Arc, @@ -1670,7 +1607,7 @@ impl OverlayFs { return Err(Error::from_raw_os_error(libc::EEXIST)); } - // n is definitely a whiteout now. + // Node is definitely a whiteout now. new_parent.handle_upper_inode_locked(&mut |parent_real_inode| -> Result { let parent_real_inode = match parent_real_inode { Some(inode) => inode, @@ -1727,7 +1664,7 @@ impl OverlayFs { Ok(()) } - pub fn do_symlink( + fn do_symlink( &self, ctx: &Context, linkname: &str, @@ -1808,11 +1745,7 @@ impl OverlayFs { Ok(()) } - pub fn copy_symlink_up( - &self, - ctx: &Context, - node: Arc, - ) -> Result> { + fn copy_symlink_up(&self, ctx: &Context, node: Arc) -> Result> { if node.in_upper_layer() { return Ok(node); } @@ -1823,11 +1756,6 @@ impl OverlayFs { return Err(Error::new(ErrorKind::Other, "no parent?")); }; - // // Why lookup again? @weizhang555 - // let parent_node = self.lookup_node(ctx, parent_node.inode, "")?; - - // // TODO: why lookup again? @weizhang555 - // let self_node = self.lookup_node(ctx, parent_node.inode, node.name.as_str())?; let (self_layer, _, self_inode) = node.first_layer_inode(); if !parent_node.in_upper_layer() { @@ -1859,11 +1787,7 @@ impl OverlayFs { // Copy regular file from lower layer to upper layer. // Caller must ensure node doesn't have upper layer. - pub fn copy_regfile_up( - &self, - ctx: &Context, - node: Arc, - ) -> Result> { + fn copy_regfile_up(&self, ctx: &Context, node: Arc) -> Result> { if node.in_upper_layer() { return Ok(node); } @@ -1875,12 +1799,6 @@ impl OverlayFs { }; let st = node.stat64(ctx)?; - - // // FIXME: why lookup again? @weizhang555 - // let parent_node = self.lookup_node(ctx, parent_node.inode, "")?; - - // // FIXME: why lookup again? @weizhang555 - // let node = self.lookup_node(ctx, parent_node.inode, node.name.as_str())?; let (lower_layer, _, lower_inode) = node.first_layer_inode(); if !parent_node.in_upper_layer() { @@ -1912,6 +1830,11 @@ impl OverlayFs { let lower_handle = h.unwrap_or(0); + // need to use work directory and then rename file to + // final destination for atomic reasons.. not deal with it for now, + // use stupid copy at present. + // FIXME: this need a lot of work here, ntimes, xattr, etc. + // Copy from lower real inode to upper real inode. let mut file = TempFile::new().unwrap().into_file(); let mut offset: usize = 0; @@ -1973,11 +1896,7 @@ impl OverlayFs { Ok(Arc::clone(&node)) } - pub fn copy_node_up( - &self, - ctx: &Context, - node: Arc, - ) -> Result> { + fn copy_node_up(&self, ctx: &Context, node: Arc) -> Result> { if node.in_upper_layer() { return Ok(node); } @@ -1989,22 +1908,16 @@ impl OverlayFs { return Ok(Arc::clone(&node)); } - // other kind of files - - // symlink + // For symlink. if st.st_mode & libc::S_IFMT == libc::S_IFLNK { return self.copy_symlink_up(ctx, Arc::clone(&node)); } - // reg file - // need to use work directory and then rename file to - // final destination for atomic reasons.. not deal with it for now, - // use stupid copy at present. FIXME: - // this need a lot of work here, ntimes, xattr, etc + // For regular file. self.copy_regfile_up(ctx, Arc::clone(&node)) } - pub fn do_rm(&self, ctx: &Context, parent: u64, name: &CStr, dir: bool) -> Result<()> { + fn do_rm(&self, ctx: &Context, parent: u64, name: &CStr, dir: bool) -> Result<()> { if self.upper_layer.is_none() { return Err(Error::from_raw_os_error(libc::EROFS)); } @@ -2141,26 +2054,20 @@ impl OverlayFs { } } - pub fn node_upper_layer_only(&self, node: Arc) -> bool { - node.upper_layer_only() - } - // Delete everything in the directory only on upper layer, ignore lower layers. - pub fn empty_node_directory(&self, ctx: &Context, node: Arc) -> Result<()> { + fn empty_node_directory(&self, ctx: &Context, node: Arc) -> Result<()> { let st = node.stat64(ctx)?; if !utils::is_dir(st) { // This function can only be called on directories. return Err(Error::from_raw_os_error(libc::ENOTDIR)); } - // self.reload_directory(ctx, Arc::clone(&node))?; - let (layer, in_upper, inode) = node.first_layer_inode(); if !in_upper { return Ok(()); } - // Copy node.childrens Hashmap to Vec, the Vec is also used as temp storage, + // Copy node.childrens Hashmap to Vector, the Vector is also used as temp storage, // Without this, Rust won't allow us to remove them from node.childrens. let iter = node .childrens @@ -2203,40 +2110,7 @@ impl OverlayFs { Ok(()) } - pub fn delete_whiteout_node(&self, ctx: &Context, node: Arc) -> Result<()> { - if !node.whiteout.load(Ordering::Relaxed) { - return Ok(()); - } - - if !node.in_upper_layer() { - return Ok(()); - } - - let (layer, real_parent, pnode) = { - let pnode = if let Some(ref n) = node.parent.lock().unwrap().upgrade() { - Arc::clone(n) - } else { - return Err(Error::new(ErrorKind::Other, "no parent")); - }; - - let (first_layer, _, first_inode) = pnode.first_layer_inode(); - (first_layer, first_inode, Arc::clone(&pnode)) - }; - - // delete white out and update hash - layer.delete_whiteout( - ctx, - real_parent, - utils::to_cstring(node.name.as_str())?.as_c_str(), - )?; - - self.remove_inode(node.inode); - pnode.remove_child(node.name.as_str()); - - Ok(()) - } - - pub fn find_real_info_from_handle( + fn find_real_info_from_handle( &self, handle: Handle, ) -> Result<(Arc, Inode, Handle)> { @@ -2254,7 +2128,7 @@ impl OverlayFs { } } - pub fn find_real_inode(&self, inode: Inode) -> Result<(Arc, Inode)> { + fn find_real_inode(&self, inode: Inode) -> Result<(Arc, Inode)> { if let Some(n) = self.inodes.lock().unwrap().get(&inode) { let (first_layer, _, first_inode) = n.first_layer_inode(); return Ok((first_layer, first_inode)); @@ -2263,7 +2137,7 @@ impl OverlayFs { Err(Error::from_raw_os_error(libc::ENOENT)) } - pub fn get_data( + fn get_data( &self, ctx: &Context, handle: Option, @@ -2303,24 +2177,17 @@ impl OverlayFs { self.copy_node_up(ctx, Arc::clone(&node))?; } - // assign a handle in overlayfs and open it - //let (_l, h, _) = node.open(ctx, flags as u32, fuse_flags)?; - //if let Some(handle) = h { - //let hd = self.next_handle.fetch_add(1, Ordering::Relaxed); let (layer, in_upper_layer, inode) = node.first_layer_inode(); let handle_data = HandleData { node: Arc::clone(&node), - offset: 0, real_handle: Some(RealHandle { layer, in_upper_layer, inode, handle: AtomicU64::new(0), - invalid: AtomicBool::new(true), }), }; return Ok(Arc::new(handle_data)); - //} } Err(Error::from_raw_os_error(libc::ENOENT)) diff --git a/src/overlayfs/sync_io.rs b/src/overlayfs/sync_io.rs index 6ceef8726..57d111f42 100644 --- a/src/overlayfs/sync_io.rs +++ b/src/overlayfs/sync_io.rs @@ -5,7 +5,7 @@ use super::*; use std::ffi::CStr; use std::io::Result; -use std::sync::atomic::{AtomicBool, AtomicU64, Ordering}; +use std::sync::atomic::{AtomicU64, Ordering}; use std::sync::Arc; use std::time::Duration; @@ -131,45 +131,10 @@ impl FileSystem for OverlayFs { let handle = self.next_handle.fetch_add(1, Ordering::Relaxed); - //let mut cs = Vec::new(); - //add myself as "." - //let mut self_node = Arc::clone(&node); - // self_node.name = ".".to_string(); - // cs.push(self_node); - - // //add parent - // let mut parent_node = match node.parent.lock().unwrap().upgrade() { - // Some(p) => p.clone(), - // None => Arc::clone(self.root.as_ref().ok_or_else(|| { - // error!("OPENDIR: root is none"); - // Error::from_raw_os_error(libc::ENOENT) - // })?), - // }; - // parent_node.name = "..".to_string(); - // cs.push(parent_node); - - // for (_, child) in node.childrens.lock().unwrap().iter() { - // // skip whiteout node - // if child.whiteout.load(Ordering::Relaxed) || child.hidden.load(Ordering::Relaxed) { - // continue; - // } - // // *child.lookups.lock().unwrap() += 1; - // cs.push(Arc::clone(child)); - // } - - // TODO: is this necessary to increase lookup count? @weizhang555 - // for c in cs.iter() { - // c.lookups.fetch_add(1, Ordering::Relaxed); - // } - - //node.lookups.fetch_add(1, Ordering::Relaxed); - self.handles.lock().unwrap().insert( handle, Arc::new(HandleData { node: Arc::clone(&node), - // childrens: Some(cs), - offset: 0, real_handle: None, }), ); @@ -183,15 +148,6 @@ impl FileSystem for OverlayFs { info!("fuse: releasedir is not supported."); return Err(Error::from_raw_os_error(libc::ENOSYS)); } - // { - // if let Some(v) = self.handles.lock().unwrap().get(&handle) { - // for child in v.node.childrens().values() { - // self.forget_one(child.inode, 1); - // } - - // self.forget_one(v.node.inode, 1); - // } - // } self.handles.lock().unwrap().remove(&handle); @@ -306,11 +262,6 @@ impl FileSystem for OverlayFs { flags |= libc::O_NOFOLLOW; - // FIXME: why need this? @weizhang555 - // if cfg!(target_os = "linux") { - // flags &= !libc::O_DIRECT; - // } - if self.config.writeback { if flags & libc::O_ACCMODE == libc::O_WRONLY { flags &= !libc::O_ACCMODE; @@ -343,14 +294,11 @@ impl FileSystem for OverlayFs { let (layer, in_upper_layer, inode) = node.first_layer_inode(); let handle_data = HandleData { node: Arc::clone(&node), - // childrens: None, - offset: 0, real_handle: Some(RealHandle { layer, in_upper_layer, inode, handle: AtomicU64::new(handle), - invalid: AtomicBool::new(false), }), }; @@ -543,21 +491,18 @@ impl FileSystem for OverlayFs { match data.real_handle { None => Err(Error::from_raw_os_error(libc::ENOENT)), - Some(ref hd) => { - hd.layer.write( - ctx, - hd.inode, - hd.handle.load(Ordering::Relaxed), - r, - size, - offset, - lock_owner, - delayed_write, - flags, - fuse_flags, - ) - // remove whiteout node from child and inode hash - } + Some(ref hd) => hd.layer.write( + ctx, + hd.inode, + hd.handle.load(Ordering::Relaxed), + r, + size, + offset, + lock_owner, + delayed_write, + flags, + fuse_flags, + ), } } @@ -634,7 +579,6 @@ impl FileSystem for OverlayFs { let mut node = self.lookup_node(ctx, inode, "")?; - //layer is upper layer if !node.in_upper_layer() { node = self.copy_node_up(ctx, Arc::clone(&node))? } @@ -761,14 +705,6 @@ impl FileSystem for OverlayFs { return Err(Error::from_raw_os_error(libc::ENOENT)); } - // readonly file can also be flushed, pass flush request - // to lower layer instead of return EROFS here - // if !self.node_in_upper_layer(Arc::clone(&node))? { - // in lower layer, error out or just success? - // FIXME: - // return Err(Error::from_raw_os_error(libc::EROFS)); - // } - let (layer, real_inode, real_handle) = self.find_real_info_from_handle(handle)?; // FIXME: need to test if inode matches corresponding handle? @@ -840,12 +776,7 @@ impl FileSystem for OverlayFs { layer.setxattr(ctx, real_inode, name, value, flags) - // TODO: refresh node since setxattr may made dir opaque. - // let st = node.stat64(ctx)?; - // if utils::is_dir(st) { - // // Setxattr may made the dir opaque, reload it if necessary. - // self.lookup_node(ctx, inode, "")?; - // } + // TODO: recreate node since setxattr may made dir opaque. @weizhang555.zw } fn getxattr( @@ -905,13 +836,7 @@ impl FileSystem for OverlayFs { let (layer, _, ino) = node.first_layer_inode(); layer.removexattr(ctx, ino, name) - // TODO: refresh the node since removexattr may remove the opaque xattr. - // let st = node.stat64(ctx)?; - // if utils::is_dir(st) { - // // removexattr may remove the opaque xattr so we have to reload the node itself. - // node.loaded.store(false, Ordering::Relaxed); - // self.lookup_node(ctx, inode, "")?; - // } + // TODO: recreate the node since removexattr may remove the opaque xattr. @weizhang555.zw } fn fallocate( diff --git a/src/overlayfs/utils.rs b/src/overlayfs/utils.rs index f743a0d56..bf7d050a5 100644 --- a/src/overlayfs/utils.rs +++ b/src/overlayfs/utils.rs @@ -5,10 +5,10 @@ use crate::abi::fuse_abi::stat64; use std::ffi::CString; use std::io::{self, Error, Result}; -pub(crate) fn is_dir(st: stat64) -> bool { +pub(super) fn is_dir(st: stat64) -> bool { st.st_mode & libc::S_IFMT == libc::S_IFDIR } -pub(crate) fn to_cstring(name: &str) -> Result { +pub(super) fn to_cstring(name: &str) -> Result { CString::new(name).map_err(|e| Error::new(io::ErrorKind::InvalidData, e)) }