From 07d2d1db02e5f636a77bd9a10774c3db444c3ad1 Mon Sep 17 00:00:00 2001 From: Chen Chengjun Date: Tue, 2 Sep 2025 07:05:24 +0000 Subject: [PATCH] Support MS_PRIVATE flag for mount --- .../file-systems-and-mount-control.md | 1 - kernel/src/fs/path/mod.rs | 24 ++++++++++- kernel/src/fs/path/mount.rs | 36 ++++++++++++++++ kernel/src/syscall/mount.rs | 43 +++++++++++++++---- 4 files changed, 93 insertions(+), 11 deletions(-) diff --git a/book/src/kernel/linux-compatibility/limitations-on-system-calls/file-systems-and-mount-control.md b/book/src/kernel/linux-compatibility/limitations-on-system-calls/file-systems-and-mount-control.md index 574ee8ddc..d3cf6d8c6 100644 --- a/book/src/kernel/linux-compatibility/limitations-on-system-calls/file-systems-and-mount-control.md +++ b/book/src/kernel/linux-compatibility/limitations-on-system-calls/file-systems-and-mount-control.md @@ -58,7 +58,6 @@ Partially supported mount flags: Unsupported mount flags: * `MS_REMOUNT` * `MS_SHARED` -* `MS_PRIVATE` * `MS_SLAVE` * `MS_UNBINDABLE` diff --git a/kernel/src/fs/path/mod.rs b/kernel/src/fs/path/mod.rs index ce87454c7..13c2f1810 100644 --- a/kernel/src/fs/path/mod.rs +++ b/kernel/src/fs/path/mod.rs @@ -5,7 +5,7 @@ use core::time::Duration; use inherit_methods_macro::inherit_methods; -pub use mount::Mount; +pub use mount::{Mount, MountPropType}; pub use mount_namespace::MountNamespace; use crate::{ @@ -321,6 +321,28 @@ impl Path { self.mount.graft_mount_tree(dst_path) } + /// Sets the propagation type of the mount of this `Path`. + pub fn set_mount_propagation( + &self, + prop: MountPropType, + recursive: bool, + ctx: &Context, + ) -> Result<()> { + if !self.is_mount_root() { + return_errno_with_message!(Errno::EINVAL, "the path is not a mount root"); + }; + + let current_ns_proxy = ctx.thread_local.borrow_ns_proxy(); + let current_mnt_ns = current_ns_proxy.unwrap().mnt_ns(); + if !current_mnt_ns.owns(&self.mount) { + return_errno_with_message!(Errno::EINVAL, "the path is not in this mount namespace"); + } + + self.mount.set_propagation(prop, recursive); + + Ok(()) + } + /// Creates a `Path` by making an inode of the `type_` with the `mode`. pub fn mknod(&self, name: &str, mode: InodeMode, type_: MknodType) -> Result { let inner = self.dentry.mknod(name, mode, type_)?; diff --git a/kernel/src/fs/path/mount.rs b/kernel/src/fs/path/mount.rs index da92d21bc..7575752ce 100644 --- a/kernel/src/fs/path/mount.rs +++ b/kernel/src/fs/path/mount.rs @@ -14,6 +14,24 @@ use crate::{ prelude::*, }; +/// Mount propagation types. +/// +/// This type defines how mount and unmount events are propagated +/// from this mount to other mounts. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum MountPropType { + /// A private type is the default mount type. Mount and unmount events + /// do not propagate to or from the private mounts. + Private, + // TODO: Implement other propagation types. +} + +impl Default for MountPropType { + fn default() -> Self { + Self::Private + } +} + /// A `Mount` represents a mounted filesystem instance in the VFS. /// /// Each `Mount` can be viewed as a node in the mount tree, maintaining @@ -32,6 +50,8 @@ pub struct Mount { pub(super) children: RwLock>>, /// The associated mount namespace. mnt_ns: Weak, + /// Propagation type of this mount (e.g., private, shared). + propagation: RwLock, /// Reference to self. this: Weak, } @@ -69,6 +89,7 @@ impl Mount { mountpoint: RwLock::new(None), parent: RwLock::new(parent_mount), children: RwLock::new(HashMap::new()), + propagation: RwLock::new(MountPropType::default()), fs, mnt_ns, this: weak_self.clone(), @@ -135,6 +156,7 @@ impl Mount { mountpoint: RwLock::new(None), parent: RwLock::new(None), children: RwLock::new(HashMap::new()), + propagation: RwLock::new(MountPropType::default()), fs: self.fs.clone(), mnt_ns: new_ns.cloned().unwrap_or_else(|| self.mnt_ns.clone()), this: weak_self.clone(), @@ -190,6 +212,20 @@ impl Mount { new_root_mount } + /// Sets the propagation type of this mount. + pub(super) fn set_propagation(&self, prop: MountPropType, recursive: bool) { + *self.propagation.write() = prop; + if !recursive { + return; + } + + let mut worklist: VecDeque> = self.children.read().values().cloned().collect(); + while let Some(mount) = worklist.pop_front() { + *mount.propagation.write() = prop; + worklist.extend(mount.children.read().values().cloned()); + } + } + /// Detaches the mount node from the parent mount node. pub(super) fn detach_from_parent(&self) { if let Some(parent) = self.parent() { diff --git a/kernel/src/syscall/mount.rs b/kernel/src/syscall/mount.rs index 7a41b3a70..270d405a6 100644 --- a/kernel/src/syscall/mount.rs +++ b/kernel/src/syscall/mount.rs @@ -4,7 +4,7 @@ use super::SyscallReturn; use crate::{ fs::{ fs_resolver::{FsPath, AT_FDCWD}, - path::Path, + path::{MountPropType, Path}, registry::FsProperties, utils::{FileSystem, InodeType}, }, @@ -57,12 +57,8 @@ pub fn sys_mount( mount_flags.contains(MountFlags::MS_REC), ctx, )?; - } else if mount_flags.contains(MountFlags::MS_SHARED) - | mount_flags.contains(MountFlags::MS_PRIVATE) - | mount_flags.contains(MountFlags::MS_SLAVE) - | mount_flags.contains(MountFlags::MS_UNBINDABLE) - { - do_change_type()?; + } else if mount_flags.intersects(MS_PROPAGATION) { + do_change_type(dst_path, mount_flags, ctx)?; } else if mount_flags.contains(MountFlags::MS_MOVE) { do_move_mount_old(devname, dst_path, ctx)?; } else { @@ -106,8 +102,37 @@ fn do_bind_mount(src_name: CString, dst_path: Path, recursive: bool, ctx: &Conte Ok(()) } -fn do_change_type() -> Result<()> { - return_errno_with_message!(Errno::EINVAL, "do_change_type is not supported"); +// All valid propagation flags. +const MS_PROPAGATION: MountFlags = MountFlags::MS_SHARED + .union(MountFlags::MS_PRIVATE) + .union(MountFlags::MS_SLAVE) + .union(MountFlags::MS_UNBINDABLE); + +fn do_change_type(target_path: Path, flags: MountFlags, ctx: &Context) -> Result<()> { + // All flags that are allowed during a propagation change. + const ALLOWED_FLAGS: MountFlags = MS_PROPAGATION + .union(MountFlags::MS_REC) + .union(MountFlags::MS_SILENT); + + if !(flags & !ALLOWED_FLAGS).is_empty() { + return_errno_with_message!(Errno::EINVAL, "the mount propagation flags are unsupported"); + } + + let propagation_flags = flags & MS_PROPAGATION; + if propagation_flags.bits().count_ones() > 1 { + return_errno_with_message!( + Errno::EINVAL, + "mount flags includes more than one of MS_SHARED, MS_PRIVATE, MS_SLAVE, or MS_UNBINDABLE" + ); + } + + if flags.contains(MountFlags::MS_PRIVATE) { + let recursive = flags.contains(MountFlags::MS_REC); + target_path.set_mount_propagation(MountPropType::Private, recursive, ctx)?; + Ok(()) + } else { + return_errno_with_message!(Errno::EINVAL, "the mount propagation type is unsupported"); + } } /// Move a mount from src location to dst location.