实现SystemV共享内存 (#690)

* 实现SystemV共享内存

* 测试shm

* 添加测试程序

* 完善细节

* 修正shm的时间数据错误的问题

* fix: devfs的metadata权限为0x777的错误

---------

Co-authored-by: longjin <longjin@DragonOS.org>
This commit is contained in:
Jomo
2024-04-07 14:04:19 +08:00
committed by GitHub
parent eb49bb993a
commit 6fc066ac11
49 changed files with 1567 additions and 202 deletions

View File

@ -1,4 +1,5 @@
pub mod pipe;
pub mod shm;
pub mod signal;
pub mod signal_types;
pub mod syscall;

View File

@ -12,7 +12,7 @@ use crate::{
net::event_poll::{EPollEventType, EPollItem, EventPoll},
process::ProcessState,
sched::{schedule, SchedMode},
time::TimeSpec,
time::PosixTimeSpec,
};
use alloc::{
@ -121,9 +121,9 @@ impl LockedPipeInode {
size: PIPE_BUFF_SIZE as i64,
blk_size: 0,
blocks: 0,
atime: TimeSpec::default(),
mtime: TimeSpec::default(),
ctime: TimeSpec::default(),
atime: PosixTimeSpec::default(),
mtime: PosixTimeSpec::default(),
ctime: PosixTimeSpec::default(),
file_type: FileType::Pipe,
mode: ModeType::from_bits_truncate(0o666),
nlinks: 1,

658
kernel/src/ipc/shm.rs Normal file
View File

@ -0,0 +1,658 @@
use crate::{
arch::mm::LockedFrameAllocator,
filesystem::vfs::syscall::ModeType,
libs::{
align::page_align_up,
spinlock::{SpinLock, SpinLockGuard},
},
mm::{
allocator::page_frame::{FrameAllocator, PageFrameCount, PhysPageFrame},
page::{page_manager_lock_irqsave, Page},
PhysAddr,
},
process::{Pid, ProcessManager},
syscall::user_access::{UserBufferReader, UserBufferWriter},
time::PosixTimeSpec,
};
use alloc::vec::Vec;
use core::sync::atomic::{compiler_fence, Ordering};
use hashbrown::{HashMap, HashSet};
use ida::IdAllocator;
use num::ToPrimitive;
use system_error::SystemError;
pub static mut SHM_MANAGER: Option<SpinLock<ShmManager>> = None;
/// 用于创建新的私有IPC对象
pub const IPC_PRIVATE: ShmKey = ShmKey::new(0);
/// 初始化SHM_MANAGER
pub fn shm_manager_init() {
kinfo!("shm_manager_init");
let shm_manager = SpinLock::new(ShmManager::new());
compiler_fence(Ordering::SeqCst);
unsafe { SHM_MANAGER = Some(shm_manager) };
compiler_fence(Ordering::SeqCst);
kinfo!("shm_manager_init done");
}
pub fn shm_manager_lock() -> SpinLockGuard<'static, ShmManager> {
unsafe { SHM_MANAGER.as_ref().unwrap().lock() }
}
int_like!(ShmId, usize);
int_like!(ShmKey, usize);
bitflags! {
pub struct ShmFlags:u32{
const SHM_RDONLY = 0o10000;
const SHM_RND = 0o20000;
const SHM_REMAP = 0o40000;
const SHM_EXEC = 0o100000;
const SHM_HUGETLB = 0o4000;
const IPC_CREAT = 0o1000;
const IPC_EXCL = 0o2000;
const SHM_DEST = 0o1000;
const SHM_LOCKED = 0o2000;
}
}
/// 管理共享内存段信息的操作码
#[derive(Eq, Clone, Copy)]
pub enum ShmCtlCmd {
/// 删除共享内存段
IpcRmid = 0,
/// 设置KernIpcPerm选项
IpcSet = 1,
/// 获取ShmIdDs
IpcStat = 2,
/// 查看ShmMetaData
IpcInfo = 3,
/// 不允许共享内存段被置换出物理内存
ShmLock = 11,
/// 允许共享内存段被置换出物理内存
ShmUnlock = 12,
/// 查看ShmMetaData
ShmStat = 13,
/// 查看ShmInfo
ShmInfo = 14,
/// 查看ShmMetaData
ShmtStatAny = 15,
Default,
}
impl From<usize> for ShmCtlCmd {
fn from(cmd: usize) -> ShmCtlCmd {
match cmd {
0 => Self::IpcRmid,
1 => Self::IpcSet,
2 => Self::IpcStat,
3 => Self::IpcInfo,
11 => Self::ShmLock,
12 => Self::ShmUnlock,
13 => Self::ShmStat,
14 => Self::ShmInfo,
15 => Self::ShmtStatAny,
_ => Self::Default,
}
}
}
impl PartialEq for ShmCtlCmd {
fn eq(&self, other: &ShmCtlCmd) -> bool {
*self as usize == *other as usize
}
}
/// 共享内存管理器
#[derive(Debug)]
pub struct ShmManager {
/// ShmId分配器
id_allocator: IdAllocator,
/// ShmId映射共享内存信息表
id2shm: HashMap<ShmId, KernelShm>,
/// ShmKey映射ShmId表
key2id: HashMap<ShmKey, ShmId>,
}
impl ShmManager {
pub fn new() -> Self {
ShmManager {
id_allocator: IdAllocator::new(0, usize::MAX - 1),
id2shm: HashMap::new(),
key2id: HashMap::new(),
}
}
/// # 添加共享内存段
///
/// ## 参数
///
/// - `key`: 共享内存键值
/// - `size`: 共享内存大小
/// - `shmflg`: 共享内存标志
///
/// ## 返回值
///
/// 成功共享内存id
/// 失败:对应错误码
pub fn add(
&mut self,
key: ShmKey,
size: usize,
shmflg: ShmFlags,
) -> Result<usize, SystemError> {
// 判断共享内存大小是否过小或溢出
if !(PosixShmMetaInfo::SHMMIN..=PosixShmMetaInfo::SHMMAX).contains(&size) {
return Err(SystemError::EINVAL);
}
let id = self.id_allocator.alloc().expect("No more id to allocate.");
let shm_id = ShmId::new(id);
// 分配共享内存页面
let page_count = PageFrameCount::from_bytes(page_align_up(size)).unwrap();
let phys_page =
unsafe { LockedFrameAllocator.allocate(page_count) }.ok_or(SystemError::EINVAL)?;
// 创建共享内存page并添加到PAGE_MANAGER中
let mut page_manager_guard = page_manager_lock_irqsave();
let mut cur_phys = PhysPageFrame::new(phys_page.0);
for _ in 0..page_count.data() {
let mut page = Page::new(true);
page.set_shm_id(shm_id);
let paddr = cur_phys.phys_address();
page_manager_guard.insert(paddr, page);
cur_phys = cur_phys.next();
}
// 创建共享内存信息结构体
let paddr = phys_page.0;
let kern_ipc_perm = KernIpcPerm {
id: shm_id,
key,
uid: 0,
gid: 0,
_cuid: 0,
_cgid: 0,
mode: shmflg & ShmFlags::from_bits_truncate(ModeType::S_IRWXUGO.bits()),
_seq: 0,
};
let shm_kernel = KernelShm::new(kern_ipc_perm, paddr, size);
// 将key、id及其对应KernelShm添加到表中
self.id2shm.insert(shm_id, shm_kernel);
self.key2id.insert(key, shm_id);
return Ok(shm_id.data());
}
pub fn contains_key(&self, key: &ShmKey) -> Option<&ShmId> {
self.key2id.get(key)
}
pub fn get_mut(&mut self, id: &ShmId) -> Option<&mut KernelShm> {
self.id2shm.get_mut(id)
}
pub fn free_key(&mut self, key: &ShmKey) {
self.key2id.remove(key);
}
pub fn free_id(&mut self, id: &ShmId) {
self.id2shm.remove(id);
self.id_allocator.free(id.0);
}
pub fn ipc_info(&self, user_buf: *const u8, from_user: bool) -> Result<usize, SystemError> {
let mut user_buffer_writer = UserBufferWriter::new(
user_buf as *mut u8,
core::mem::size_of::<PosixShmMetaInfo>(),
from_user,
)?;
let shm_meta_info = PosixShmMetaInfo::new();
user_buffer_writer.copy_one_to_user(&shm_meta_info, 0)?;
return Ok(0);
}
pub fn shm_info(&self, user_buf: *const u8, from_user: bool) -> Result<usize, SystemError> {
// 已使用id数量
let used_ids = self.id2shm.len().to_i32().unwrap();
// 共享内存总和
let shm_tot = self.id2shm.iter().fold(0, |acc, (_, kernel_shm)| {
acc + PageFrameCount::from_bytes(page_align_up(kernel_shm.shm_size))
.unwrap()
.data()
});
let shm_info = PosixShmInfo::new(used_ids, shm_tot, 0, 0, 0, 0);
let mut user_buffer_writer = UserBufferWriter::new(
user_buf as *mut u8,
core::mem::size_of::<PosixShmInfo>(),
from_user,
)?;
user_buffer_writer.copy_one_to_user(&shm_info, 0)?;
return Ok(0);
}
pub fn shm_stat(
&self,
id: ShmId,
cmd: ShmCtlCmd,
user_buf: *const u8,
from_user: bool,
) -> Result<usize, SystemError> {
let kernel_shm = self.id2shm.get(&id).ok_or(SystemError::EINVAL)?;
let key = kernel_shm.kern_ipc_perm.key.data().to_i32().unwrap();
let mode = kernel_shm.kern_ipc_perm.mode.bits();
let shm_perm = PosixIpcPerm::new(key, 0, 0, 0, 0, mode);
let shm_segsz = kernel_shm.shm_size;
let shm_atime = kernel_shm.shm_atim.total_nanos();
let shm_dtime = kernel_shm.shm_dtim.total_nanos();
let shm_ctime = kernel_shm.shm_ctim.total_nanos();
let shm_cpid = kernel_shm.shm_cprid.data().to_u32().unwrap();
let shm_lpid = kernel_shm.shm_lprid.data().to_u32().unwrap();
let shm_map_count = kernel_shm.map_count();
let shm_id_ds = PosixShmIdDs {
shm_perm,
shm_segsz,
shm_atime,
shm_dtime,
shm_ctime,
shm_cpid,
shm_lpid,
shm_map_count,
_unused1: 0,
_unused2: 0,
};
let mut user_buffer_writer = UserBufferWriter::new(
user_buf as *mut u8,
core::mem::size_of::<PosixShmIdDs>(),
from_user,
)?;
user_buffer_writer.copy_one_to_user(&shm_id_ds, 0)?;
let r: usize = if cmd == ShmCtlCmd::IpcStat {
0
} else {
id.data()
};
return Ok(r);
}
pub fn ipc_set(
&mut self,
id: ShmId,
user_buf: *const u8,
from_user: bool,
) -> Result<usize, SystemError> {
let kernel_shm = self.id2shm.get_mut(&id).ok_or(SystemError::EINVAL)?;
let user_buffer_reader =
UserBufferReader::new(user_buf, core::mem::size_of::<PosixShmIdDs>(), from_user)?;
let mut shm_id_ds = PosixShmIdDs::default();
user_buffer_reader.copy_one_from_user(&mut shm_id_ds, 0)?;
kernel_shm.copy_from(shm_id_ds);
return Ok(0);
}
pub fn ipc_rmid(&mut self, id: ShmId) -> Result<usize, SystemError> {
let kernel_shm = self.id2shm.get_mut(&id).ok_or(SystemError::EINVAL)?;
kernel_shm.set_mode(ShmFlags::SHM_DEST, true);
let mut cur_phys = PhysPageFrame::new(kernel_shm.shm_start_paddr);
let count = PageFrameCount::from_bytes(page_align_up(kernel_shm.shm_size)).unwrap();
let key = kernel_shm.kern_ipc_perm.key;
let id = kernel_shm.kern_ipc_perm.id;
let map_count = kernel_shm.map_count();
let mut page_manager_guard = page_manager_lock_irqsave();
if map_count > 0 {
// 设置共享内存物理页当映射计数等于0时可被回收
for _ in 0..count.data() {
let page = page_manager_guard.get_mut(&cur_phys.phys_address());
page.set_dealloc_when_zero(true);
cur_phys = cur_phys.next();
}
// 释放key不让后续进程连接
self.free_key(&key);
} else {
// 释放共享内存物理页
for _ in 0..count.data() {
let paddr = cur_phys.phys_address();
unsafe {
LockedFrameAllocator.free(paddr, PageFrameCount::new(1));
}
// 将已回收的物理页面对应的Page从PAGE_MANAGER中删去
page_manager_guard.remove_page(&paddr);
cur_phys = cur_phys.next();
}
// 释放key和id
self.free_id(&id);
self.free_key(&key)
}
return Ok(0);
}
pub fn shm_lock(&mut self, id: ShmId) -> Result<usize, SystemError> {
let kernel_shm = self.id2shm.get_mut(&id).ok_or(SystemError::EINVAL)?;
kernel_shm.set_mode(ShmFlags::SHM_LOCKED, true);
return Ok(0);
}
pub fn shm_unlock(&mut self, id: ShmId) -> Result<usize, SystemError> {
let kernel_shm = self.id2shm.get_mut(&id).ok_or(SystemError::EINVAL)?;
kernel_shm.set_mode(ShmFlags::SHM_LOCKED, false);
return Ok(0);
}
}
/// 共享内存信息
#[derive(Debug)]
pub struct KernelShm {
/// 权限信息
kern_ipc_perm: KernIpcPerm,
/// 共享内存起始物理地址
shm_start_paddr: PhysAddr,
/// 共享内存大小(bytes),注意是用户指定的大小(未经过页面对齐)
shm_size: usize,
/// 最后一次连接的时间
shm_atim: PosixTimeSpec,
/// 最后一次断开连接的时间
shm_dtim: PosixTimeSpec,
/// 最后一次更改信息的时间
shm_ctim: PosixTimeSpec,
/// 创建者进程id
shm_cprid: Pid,
/// 最后操作者进程id
shm_lprid: Pid,
}
impl KernelShm {
pub fn new(kern_ipc_perm: KernIpcPerm, shm_start_paddr: PhysAddr, shm_size: usize) -> Self {
let shm_cprid = ProcessManager::current_pid();
KernelShm {
kern_ipc_perm,
shm_start_paddr,
shm_size,
shm_atim: PosixTimeSpec::new(0, 0),
shm_dtim: PosixTimeSpec::new(0, 0),
shm_ctim: PosixTimeSpec::now(),
shm_cprid,
shm_lprid: shm_cprid,
}
}
pub fn start_paddr(&self) -> PhysAddr {
self.shm_start_paddr
}
pub fn size(&self) -> usize {
self.shm_size
}
/// 更新最后连接时间
pub fn update_atim(&mut self) {
// 更新最后一次连接时间
self.shm_atim = PosixTimeSpec::now();
// 更新最后操作当前共享内存的进程ID
self.shm_lprid = ProcessManager::current_pid();
}
/// 更新最后断开连接时间
pub fn update_dtim(&mut self) {
// 更新最后一次断开连接时间
self.shm_dtim = PosixTimeSpec::now();
// 更新最后操作当前共享内存的进程ID
self.shm_lprid = ProcessManager::current_pid();
}
/// 更新最后一次修改信息的时间
pub fn update_ctim(&mut self) {
// 更新最后一次修改信息的时间
self.shm_ctim = PosixTimeSpec::now();
}
/// 共享内存段的映射计数有多少个不同的VMA映射
pub fn map_count(&self) -> usize {
let page_manager_guard = page_manager_lock_irqsave();
let mut id_set: HashSet<usize> = HashSet::new();
let mut cur_phys = PhysPageFrame::new(self.shm_start_paddr);
let page_count = PageFrameCount::from_bytes(page_align_up(self.shm_size)).unwrap();
for _ in 0..page_count.data() {
let page = page_manager_guard.get(&cur_phys.phys_address()).unwrap();
id_set.extend(
page.anon_vma()
.iter()
.map(|vma| vma.id())
.collect::<Vec<_>>(),
);
cur_phys = cur_phys.next();
}
// 由于LockedVMA的id是独一无二的因此有多少个不同的id就代表着有多少个不同的VMA映射到共享内存段
return id_set.len();
}
pub fn copy_from(&mut self, shm_id_ds: PosixShmIdDs) {
self.kern_ipc_perm.uid = shm_id_ds.uid() as usize;
self.kern_ipc_perm.gid = shm_id_ds.gid() as usize;
self.kern_ipc_perm.mode = ShmFlags::from_bits_truncate(shm_id_ds.mode());
self.update_ctim();
}
pub fn set_mode(&mut self, shmflg: ShmFlags, set: bool) {
if set {
self.kern_ipc_perm.mode.insert(shmflg);
} else {
self.kern_ipc_perm.mode.remove(shmflg);
}
self.update_ctim();
}
}
/// 共享内存权限信息
#[derive(Debug)]
pub struct KernIpcPerm {
/// 共享内存id
id: ShmId,
/// 共享内存键值,由创建共享内存用户指定
key: ShmKey,
/// 共享内存拥有者用户id
uid: usize,
/// 共享内存拥有者所在组id
gid: usize,
/// 共享内存创建者用户id
_cuid: usize,
/// 共享内存创建者所在组id
_cgid: usize,
/// 共享内存区权限模式
mode: ShmFlags,
_seq: usize,
}
/// 共享内存元信息符合POSIX标准
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct PosixShmMetaInfo {
/// 最大共享内存段的大小(bytes)
shmmax: usize,
/// 最小共享内存段的大小(bytes)
shmmin: usize,
/// 最大共享内存标识符数量
shmmni: usize,
/// 单个进程可以拥有的最大共享内存段的数量,和最大共享内存标识符数量相同
shmseg: usize,
/// 所有共享内存段总共可以使用的最大内存量(pages)
shmall: usize,
_unused1: usize,
_unused2: usize,
_unused3: usize,
_unused4: usize,
}
impl PosixShmMetaInfo {
/// 最小共享内存段的大小(bytes)
pub const SHMMIN: usize = 1;
/// 最大共享内存标识符数量
pub const SHMMNI: usize = 4096;
/// 最大共享内存段的大小(bytes)
pub const SHMMAX: usize = usize::MAX - (1 << 24);
/// 所有共享内存段总共可以使用的最大内存量(pages)
pub const SHMALL: usize = usize::MAX - (1 << 24);
/// 单个进程可以拥有的最大共享内存段的数量,和最大共享内存标识符数量相同
pub const SHMSEG: usize = 4096;
pub fn new() -> Self {
PosixShmMetaInfo {
shmmax: Self::SHMMAX,
shmmin: Self::SHMMIN,
shmmni: Self::SHMMNI,
shmseg: Self::SHMSEG,
shmall: Self::SHMALL,
_unused1: 0,
_unused2: 0,
_unused3: 0,
_unused4: 0,
}
}
}
/// 共享内存信息符合POSIX标准
#[repr(C)]
#[derive(Clone, Copy)]
pub struct PosixShmInfo {
/// 已使用id数
used_ids: i32,
/// 共享内存总量(pages)
shm_tot: usize,
/// 保留在内存中的共享内存大小
shm_rss: usize,
/// 被置换出的共享内存大小
shm_swp: usize,
/// 尝试置换次数
swap_attempts: usize,
/// 成功置换次数
swap_successes: usize,
}
impl PosixShmInfo {
pub fn new(
used_ids: i32,
shm_tot: usize,
shm_rss: usize,
shm_swp: usize,
swap_attempts: usize,
swap_successes: usize,
) -> Self {
PosixShmInfo {
used_ids,
shm_tot,
shm_rss,
shm_swp,
swap_attempts,
swap_successes,
}
}
}
/// 共享内存段属性信息符合POSIX标准
#[repr(C)]
#[derive(Debug, Clone, Copy, Default)]
pub struct PosixShmIdDs {
/// 共享内存段权限
shm_perm: PosixIpcPerm,
/// 共享内存大小(bytes)
shm_segsz: usize,
/// 最后一次连接的时间
shm_atime: i64,
/// 最后一次断开连接的时间
shm_dtime: i64,
/// 最后一次更改信息的时间
shm_ctime: i64,
/// 创建者进程id
shm_cpid: u32,
/// 最后操作者进程id
shm_lpid: u32,
/// 链接数
shm_map_count: usize,
_unused1: usize,
_unused2: usize,
}
impl PosixShmIdDs {
pub fn uid(&self) -> u32 {
self.shm_perm.uid
}
pub fn gid(&self) -> u32 {
self.shm_perm.gid
}
pub fn mode(&self) -> u32 {
self.shm_perm.mode
}
}
/// 共享内存段权限符合POSIX标准
#[repr(C)]
#[derive(Debug, Clone, Copy, Default)]
pub struct PosixIpcPerm {
/// IPC对象键值
key: i32,
/// 当前用户id
uid: u32,
/// 当前用户组id
gid: u32,
/// 创建者用户id
cuid: u32,
/// 创建者组id
cgid: u32,
/// 权限
mode: u32,
/// 序列号
seq: i32,
_pad1: i32,
_unused1: usize,
_unused2: usize,
}
impl PosixIpcPerm {
pub fn new(key: i32, uid: u32, gid: u32, cuid: u32, cgid: u32, mode: u32) -> Self {
PosixIpcPerm {
key,
uid,
gid,
cuid,
cgid,
mode,
seq: 0,
_pad1: 0,
_unused1: 0,
_unused2: 0,
}
}
}

View File

@ -6,20 +6,35 @@ use core::{
use system_error::SystemError;
use crate::{
arch::ipc::signal::{SigCode, SigFlags, SigSet, Signal},
arch::{
ipc::signal::{SigCode, SigFlags, SigSet, Signal},
MMArch,
},
filesystem::vfs::{
file::{File, FileMode},
FilePrivateData,
},
ipc::shm::{shm_manager_lock, IPC_PRIVATE},
kerror, kwarn,
libs::align::page_align_up,
libs::spinlock::SpinLock,
mm::VirtAddr,
mm::{
allocator::page_frame::{PageFrameCount, PhysPageFrame, VirtPageFrame},
page::{page_manager_lock_irqsave, PageFlags, PageFlushAll},
syscall::ProtFlags,
ucontext::{AddressSpace, VMA},
VirtAddr, VmFlags,
},
process::{Pid, ProcessManager},
syscall::{user_access::UserBufferWriter, Syscall},
syscall::{
user_access::{UserBufferReader, UserBufferWriter},
Syscall,
},
};
use super::{
pipe::{LockedPipeInode, PipeFsPrivateData},
shm::{ShmCtlCmd, ShmFlags, ShmId, ShmKey},
signal_types::{
SaHandlerType, SigInfo, SigType, Sigaction, SigactionType, UserSigaction, USER_SIG_DFL,
USER_SIG_ERR, USER_SIG_IGN,
@ -230,4 +245,262 @@ impl Syscall {
}
return retval.map(|_| 0);
}
/// # SYS_SHMGET系统调用函数用于获取共享内存
///
/// ## 参数
///
/// - `key`: 共享内存键值
/// - `size`: 共享内存大小(bytes)
/// - `shmflg`: 共享内存标志
///
/// ## 返回值
///
/// 成功共享内存id
/// 失败:错误码
pub fn shmget(key: ShmKey, size: usize, shmflg: ShmFlags) -> Result<usize, SystemError> {
// 暂不支持巨页
if shmflg.contains(ShmFlags::SHM_HUGETLB) {
kerror!("shmget: not support huge page");
return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP);
}
let mut shm_manager_guard = shm_manager_lock();
match key {
// 创建共享内存段
IPC_PRIVATE => shm_manager_guard.add(key, size, shmflg),
_ => {
// 查找key对应的共享内存段是否存在
let id = shm_manager_guard.contains_key(&key);
if let Some(id) = id {
// 不能重复创建
if shmflg.contains(ShmFlags::IPC_CREAT | ShmFlags::IPC_EXCL) {
return Err(SystemError::EEXIST);
}
// key值存在说明有对应共享内存返回该共享内存id
return Ok(id.data());
} else {
// key不存在且shm_flags不包含IPC_CREAT创建IPC对象标志则返回错误码
if !shmflg.contains(ShmFlags::IPC_CREAT) {
return Err(SystemError::ENOENT);
}
// 存在创建IPC对象标志
return shm_manager_guard.add(key, size, shmflg);
}
}
}
}
/// # SYS_SHMAT系统调用函数用于连接共享内存段
///
/// ## 参数
///
/// - `id`: 共享内存id
/// - `vaddr`: 连接共享内存的进程虚拟内存区域起始地址
/// - `shmflg`: 共享内存标志
///
/// ## 返回值
///
/// 成功:映射到共享内存的虚拟内存区域起始地址
/// 失败:错误码
pub fn shmat(id: ShmId, vaddr: VirtAddr, shmflg: ShmFlags) -> Result<usize, SystemError> {
let mut shm_manager_guard = shm_manager_lock();
let current_address_space = AddressSpace::current()?;
let mut address_write_guard = current_address_space.write();
let kernel_shm = shm_manager_guard.get_mut(&id).ok_or(SystemError::EINVAL)?;
let size = page_align_up(kernel_shm.size());
let mut phys = PhysPageFrame::new(kernel_shm.start_paddr());
let count = PageFrameCount::from_bytes(size).unwrap();
let r = match vaddr.data() {
// 找到空闲区域并映射到共享内存
0 => {
// 找到空闲区域
let region = address_write_guard
.mappings
.find_free(vaddr, size)
.ok_or(SystemError::EINVAL)?;
let vm_flags = VmFlags::from(shmflg);
let destination = VirtPageFrame::new(region.start());
let page_flags: PageFlags<MMArch> =
PageFlags::from_prot_flags(ProtFlags::from(vm_flags), true);
let flusher: PageFlushAll<MMArch> = PageFlushAll::new();
// 将共享内存映射到对应虚拟区域
let vma = VMA::physmap(
phys,
destination,
count,
vm_flags,
page_flags,
&mut address_write_guard.user_mapper.utable,
flusher,
)?;
// 将VMA加入到当前进程的VMA列表中
address_write_guard.mappings.insert_vma(vma);
region.start().data()
}
// 指定虚拟地址
_ => {
// 获取对应vma
let vma = address_write_guard
.mappings
.contains(vaddr)
.ok_or(SystemError::EINVAL)?;
if vma.lock().region().start() != vaddr {
return Err(SystemError::EINVAL);
}
// 验证用户虚拟内存区域是否有效
let _ = UserBufferReader::new(vaddr.data() as *const u8, size, true)?;
// 必须在取消映射前获取到PageFlags
let page_flags = address_write_guard
.user_mapper
.utable
.translate(vaddr)
.ok_or(SystemError::EINVAL)?
.1;
// 取消原映射
let flusher: PageFlushAll<MMArch> = PageFlushAll::new();
vma.unmap(&mut address_write_guard.user_mapper.utable, flusher);
// 将该虚拟内存区域映射到共享内存区域
let mut page_manager_guard = page_manager_lock_irqsave();
let mut virt = VirtPageFrame::new(vaddr);
for _ in 0..count.data() {
let r = unsafe {
address_write_guard.user_mapper.utable.map_phys(
virt.virt_address(),
phys.phys_address(),
page_flags,
)
}
.expect("Failed to map zero, may be OOM error");
r.flush();
// 将vma加入到对应Page的anon_vma
page_manager_guard
.get_mut(&phys.phys_address())
.insert_vma(vma.clone());
phys = phys.next();
virt = virt.next();
}
// 更新vma的映射状态
vma.lock().set_mapped(true);
vaddr.data()
}
};
// 更新最后一次连接时间
kernel_shm.update_atim();
Ok(r)
}
/// # SYS_SHMDT系统调用函数用于取消对共享内存的连接
///
/// ## 参数
///
/// - `vaddr`: 需要取消映射的虚拟内存区域起始地址
///
/// ## 返回值
///
/// 成功0
/// 失败:错误码
pub fn shmdt(vaddr: VirtAddr) -> Result<usize, SystemError> {
let current_address_space = AddressSpace::current()?;
let mut address_write_guard = current_address_space.write();
// 获取vma
let vma = address_write_guard
.mappings
.contains(vaddr)
.ok_or(SystemError::EINVAL)?;
// 判断vaddr是否为起始地址
if vma.lock().region().start() != vaddr {
return Err(SystemError::EINVAL);
}
// 获取映射的物理地址
let paddr = address_write_guard
.user_mapper
.utable
.translate(vaddr)
.ok_or(SystemError::EINVAL)?
.0;
// 如果物理页的shm_id为None代表不是共享页
let page_manager_guard = page_manager_lock_irqsave();
let page = page_manager_guard.get(&paddr).ok_or(SystemError::EINVAL)?;
let shm_id = page.shm_id().ok_or(SystemError::EINVAL)?;
drop(page_manager_guard);
// 获取对应共享页管理信息
let mut shm_manager_guard = shm_manager_lock();
let kernel_shm = shm_manager_guard
.get_mut(&shm_id)
.ok_or(SystemError::EINVAL)?;
// 更新最后一次断开连接时间
kernel_shm.update_dtim();
drop(shm_manager_guard);
// 取消映射
let flusher: PageFlushAll<MMArch> = PageFlushAll::new();
vma.unmap(&mut address_write_guard.user_mapper.utable, flusher);
return Ok(0);
}
/// # SYS_SHMCTL系统调用函数用于管理共享内存段
///
/// ## 参数
///
/// - `id`: 共享内存id
/// - `cmd`: 操作码
/// - `user_buf`: 用户缓冲区
/// - `from_user`: buf_vaddr是否来自用户地址空间
///
/// ## 返回值
///
/// 成功0
/// 失败:错误码
pub fn shmctl(
id: ShmId,
cmd: ShmCtlCmd,
user_buf: *const u8,
from_user: bool,
) -> Result<usize, SystemError> {
let mut shm_manager_guard = shm_manager_lock();
match cmd {
// 查看共享内存元信息
ShmCtlCmd::IpcInfo => shm_manager_guard.ipc_info(user_buf, from_user),
// 查看共享内存使用信息
ShmCtlCmd::ShmInfo => shm_manager_guard.shm_info(user_buf, from_user),
// 查看id对应的共享内存信息
ShmCtlCmd::ShmStat | ShmCtlCmd::ShmtStatAny | ShmCtlCmd::IpcStat => {
shm_manager_guard.shm_stat(id, cmd, user_buf, from_user)
}
// 设置KernIpcPerm
ShmCtlCmd::IpcSet => shm_manager_guard.ipc_set(id, user_buf, from_user),
// 将共享内存段设置为可回收状态
ShmCtlCmd::IpcRmid => shm_manager_guard.ipc_rmid(id),
// 锁住共享内存段,不允许内存置换
ShmCtlCmd::ShmLock => shm_manager_guard.shm_lock(id),
// 解锁共享内存段,允许内存置换
ShmCtlCmd::ShmUnlock => shm_manager_guard.shm_unlock(id),
// 无效操作码
ShmCtlCmd::Default => Err(SystemError::EINVAL),
}
}
}