Skip to content

Commit f5b2038

Browse files
authored
ospp project (feature) add namespace overlayfs cgroup (#949)
## 开发进展: ## namespace - pid_namespace 基本实现,基于pid_struct等数据结构实现隔离 - mnt_namespace 基本实现,挂载点的隔离通过不同的挂载树来实现 - usernamespace 作为支持性的namespace,目前受限实现全局静态 ## overlayfs - 实现若干个文件系统的叠加,在mount中传入多个路径作为多个fs的mount路径以及最后merge层的fs路径 - copy-up机制的,除最上层外其他层为只读层,满足写时拷贝,需要修改的时候copy到上层修改 - whiteout特殊文件,用于标记在下层需要被删除的文件用来掩盖需要删除的文件 ## cgroups - 目前cgroups还处于框架阶段,之后具体实现具体的内存、CPU等子系统
1 parent 84c528f commit f5b2038

File tree

43 files changed

+2279
-56
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+2279
-56
lines changed

docs/index.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,12 @@
3030
kernel/debug/index
3131
kernel/ktest/index
3232
kernel/cpu_arch/index
33+
kernel/container/index
3334
kernel/libs/index
3435
kernel/trace/index
3536

3637

38+
3739
.. toctree::
3840
:maxdepth: 1
3941
:caption: 应用层

docs/kernel/container/index.rst

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
====================================
2+
容器化
3+
====================================
4+
5+
这里是DragonOS中,与容器化相关的说明文档。
6+
7+
主要包括namespace,overlayfs和cgroup
8+
9+
.. toctree::
10+
:maxdepth: 2
11+
12+
namespaces/index
13+
filesystem/unionfs/index
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
====================================
2+
名称空间
3+
====================================
4+
5+
DragonOS的namespaces目前支持pid_namespace和mnt_namespace 预计之后会继续完善
6+
namespace是容器化实现过程中的重要组成部分
7+
8+
由于目前os是单用户,user_namespace为全局静态
9+
10+
.. toctree::
11+
:maxdepth: 1
12+
13+
pid_namespace
14+
mnt_namespace
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# 挂载名称空间
2+
3+
## 底层架构
4+
5+
pcb -> nsproxy -> mnt_namespace
6+
7+
每一个挂载文件系统都有自立独立的挂载点,表现在数据结构上是一个挂载的红黑树,每一个名称空间中挂载是独立的,所以文件系统的挂载和卸载不会影响别的
8+
9+
## 系统调用接口
10+
11+
12+
- clone
13+
- CLONE_NEWNS用于创建一个新的 MNT 命名空间。提供独立的文件系统挂载点
14+
- unshare
15+
- 使用 CLONE_NEWPID 标志调用 unshare() 后,后续创建的所有子进程都将在新的命名空间中运行。
16+
- setns
17+
- 将进程加入到指定的名称空间
18+
- chroot
19+
- 将当前进程的根目录更改为指定的路径,提供文件系统隔离。
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# 进程名称空间
2+
:::{note} 本文作者:操丰毅 [email protected]
3+
4+
2024年10月30日 :::
5+
pid_namespace 是内核中的一种名称空间,用于实现进程隔离,允许在不同的名称空间中运行的进程有独立的pid试图
6+
7+
## 底层架构
8+
9+
pcb -> nsproxy -> pid_namespace
10+
- pid_namespace 内有独立的一套进程分配器,以及孤儿进程回收器,独立管理内部的pid
11+
- 不同进程的详细信息都存放在proc文件系统中,里面的找到对应的pid号里面的信息都在pid中,记录的是pid_namespace中的信息
12+
- pid_namespace等限制由ucount来控制管理
13+
14+
## 系统调用接口
15+
16+
- clone
17+
- CLONE_NEWPID用于创建一个新的 PID 命名空间。使用这个标志时,子进程将在新的 PID 命名空间内运行,进程 ID 从 1 开始。
18+
- unshare
19+
- 使用 CLONE_NEWPID 标志调用 unshare() 后,后续创建的所有子进程都将在新的命名空间中运行。
20+
- getpid
21+
- 在命名空间中调用 getpid() 会返回进程在当前 PID 命名空间中的进程 ID

docs/kernel/filesystem/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,5 @@ todo: 由于文件系统模块重构,文档暂时不可用,预计在2023年4
1313
vfs/index
1414
sysfs
1515
kernfs
16+
unionfs/index
1617

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
====================================
2+
联合文件系统
3+
====================================
4+
Union Filesystem:
5+
OverlayFS 将多个文件系统(称为“层”)合并为一个逻辑文件系统,使用户看到一个统一的目录结构。
6+
7+
.. toctree::
8+
:maxdepth: 1
9+
10+
overlayfs
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# overlayfs
2+
3+
OverlayFs是目前使用最多的联合文件系统,原理简单方便使用,主要用于容器中
4+
在 Docker 中,OverlayFS 是默认的存储驱动之一。Docker 为每个容器创建一个独立的上层目录,而所有容器共享同一个下层镜像文件。这样的设计使得容器之间的资源共享更加高效,同时减少了存储需求。
5+
## 架构设计
6+
overlayfs主要有两个层,以及一个虚拟的合并层
7+
- Lower Layer(下层):通常是 只读 文件系统。可以包含多层。
8+
- Upper Layer(上层):为 可写层,所有的写操作都会在这一层上进行。
9+
- Merged Layer(合并层):上层和下层的逻辑视图合并后,向用户呈现的最终文件系统。
10+
11+
12+
## 工作原理
13+
- 读取操作:
14+
- OverlayFS 会优先从 Upper Layer 读取文件。如果文件不存在于上层,则读取 Lower Layer 中的内容。
15+
- 写入操作:
16+
- 如果一个文件位于 Lower Layer 中,并尝试写入该文件,系统会将其 copy-up 到 Upper Layer 并在上层写入。如果文件已经存在于 Upper Layer,则直接在该层写入。
17+
- 删除操作:
18+
- 当删除文件时,OverlayFS 会在上层创建一个标记为 whiteout 的条目,这会隐藏下层的文件。
19+
20+
## Copy-up
21+
- 写时拷贝
22+
当一个文件从 下层 被修改时,它会被复制到 上层(称为 copy-up)。之后的所有修改都会发生在上层的文件副本上。
23+
24+
25+
## 实现逻辑
26+
通过构建ovlInode来实现indexnode这个trait来代表上层或者下层的inode,具体的有关文件文件夹的操作都在

kernel/crates/ida/src/lib.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,11 @@ impl IdAllocator {
140140
pub fn used(&self) -> usize {
141141
self.used
142142
}
143+
144+
/// 返回最大id数
145+
pub fn get_max_id(&self) -> usize {
146+
self.max_id
147+
}
143148
}
144149

145150
impl core::fmt::Debug for IdAllocator {

kernel/src/arch/riscv64/process/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ impl ProcessManager {
104104
pub fn copy_thread(
105105
current_pcb: &Arc<ProcessControlBlock>,
106106
new_pcb: &Arc<ProcessControlBlock>,
107-
clone_args: KernelCloneArgs,
107+
clone_args: &KernelCloneArgs,
108108
current_trapframe: &TrapFrame,
109109
) -> Result<(), SystemError> {
110110
let clone_flags = clone_args.flags;

kernel/src/arch/x86_64/process/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -299,7 +299,7 @@ impl ProcessManager {
299299
pub fn copy_thread(
300300
current_pcb: &Arc<ProcessControlBlock>,
301301
new_pcb: &Arc<ProcessControlBlock>,
302-
clone_args: KernelCloneArgs,
302+
clone_args: &KernelCloneArgs,
303303
current_trapframe: &TrapFrame,
304304
) -> Result<(), SystemError> {
305305
let clone_flags = clone_args.flags;

kernel/src/cgroup/mem_cgroup.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
use super::CgroupSubsysState;
2+
3+
struct MemCgroup {
4+
css: CgroupSubsysState,
5+
id: u32,
6+
}

kernel/src/cgroup/mod.rs

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
#![allow(dead_code, unused_variables, unused_imports)]
2+
pub mod mem_cgroup;
3+
4+
use alloc::{collections::LinkedList, rc::Weak, sync::Arc, vec::Vec};
5+
6+
use alloc::boxed::Box;
7+
8+
use crate::filesystem::vfs::IndexNode;
9+
10+
pub struct Cgroup {
11+
css: Weak<CgroupSubsysState>,
12+
/// 当前所在的深度
13+
level: u32,
14+
/// 支持的最大深度
15+
max_depth: u32,
16+
/// 可见后代数量
17+
nr_descendants: u32,
18+
/// 正在死亡后代数量
19+
nr_dying_descendants: u32,
20+
/// 允许的最大后代数量
21+
max_descendants: u32,
22+
/// css_set的数量
23+
nr_populated_csets: u32,
24+
/// 子group中有任务的记数
25+
nr_populated_domain_children: u32,
26+
/// 线程子group中有任务的记数
27+
nr_populated_threaded_children: u32,
28+
/// 活跃线程子cgroup数量
29+
nr_threaded_children: u32,
30+
/// 关联cgroup的inode
31+
kernfs_node: Box<dyn IndexNode>,
32+
}
33+
34+
/// 控制资源的统计信息
35+
pub struct CgroupSubsysState {
36+
cgroup: Arc<Cgroup>,
37+
/// 兄弟节点
38+
sibling: LinkedList<Arc<Cgroup>>,
39+
/// 孩子节点
40+
children: LinkedList<Arc<Cgroup>>,
41+
}
42+
43+
pub struct CgroupSubsys {}
44+
45+
/// cgroup_sub_state 的集合
46+
pub struct CssSet {
47+
subsys: Vec<Arc<CgroupSubsysState>>,
48+
}

kernel/src/filesystem/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ pub mod eventfd;
44
pub mod fat;
55
pub mod kernfs;
66
pub mod mbr;
7+
pub mod overlayfs;
78
pub mod procfs;
89
pub mod ramfs;
910
pub mod sysfs;
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
use super::OvlInode;
2+
use crate::{
3+
filesystem::vfs::{IndexNode, Metadata},
4+
libs::spinlock::SpinLock,
5+
};
6+
use alloc::sync::Arc;
7+
use system_error::SystemError;
8+
9+
impl OvlInode {
10+
pub fn copy_up(&self) -> Result<(), SystemError> {
11+
let mut upper_inode = self.upper_inode.lock();
12+
if upper_inode.is_some() {
13+
return Ok(());
14+
}
15+
16+
let lower_inode = self.lower_inode.as_ref().ok_or(SystemError::ENOENT)?;
17+
18+
let metadata = lower_inode.metadata()?;
19+
let new_upper_inode = self.create_upper_inode(metadata.clone())?;
20+
21+
let mut buffer = vec![0u8; metadata.size as usize];
22+
let lock = SpinLock::new(crate::filesystem::vfs::FilePrivateData::Unused);
23+
lower_inode.read_at(0, metadata.size as usize, &mut buffer, lock.lock())?;
24+
25+
new_upper_inode.write_at(0, metadata.size as usize, &buffer, lock.lock())?;
26+
27+
*upper_inode = Some(new_upper_inode);
28+
29+
Ok(())
30+
}
31+
32+
fn create_upper_inode(&self, metadata: Metadata) -> Result<Arc<dyn IndexNode>, SystemError> {
33+
let upper_inode = self.upper_inode.lock();
34+
let upper_root_inode = upper_inode
35+
.as_ref()
36+
.ok_or(SystemError::ENOSYS)?
37+
.fs()
38+
.root_inode();
39+
upper_root_inode.create_with_data(&self.dname()?.0, metadata.file_type, metadata.mode, 0)
40+
}
41+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
use alloc::sync::Arc;
2+
3+
use alloc::vec::Vec;
4+
5+
use crate::filesystem::vfs::IndexNode;
6+
7+
use super::{OvlInode, OvlSuperBlock};
8+
#[derive(Debug)]
9+
pub struct OvlEntry {
10+
numlower: usize, // 下层数量
11+
lowerstack: Vec<OvlPath>,
12+
}
13+
14+
impl OvlEntry {
15+
pub fn new() -> Self {
16+
Self {
17+
numlower: 2,
18+
lowerstack: Vec::new(),
19+
}
20+
}
21+
}
22+
#[derive(Debug)]
23+
pub struct OvlPath {
24+
layer: Arc<OvlLayer>,
25+
inode: Arc<dyn IndexNode>,
26+
}
27+
#[derive(Debug)]
28+
pub struct OvlLayer {
29+
pub mnt: Arc<OvlInode>, // 挂载点
30+
pub index: u32, // 0 是上层读写层,>0 是下层只读层
31+
pub fsid: u32, // 文件系统标识符
32+
}

0 commit comments

Comments
 (0)