xref: /DragonOS/kernel/src/ipc/shm.rs (revision 4b0170bd6bb374d0e9699a0076cc23b976ad6db7)
1 use crate::{
2     arch::mm::LockedFrameAllocator,
3     filesystem::vfs::syscall::ModeType,
4     libs::{
5         align::page_align_up,
6         spinlock::{SpinLock, SpinLockGuard},
7     },
8     mm::{
9         allocator::page_frame::{FrameAllocator, PageFrameCount, PhysPageFrame},
10         page::{page_manager_lock_irqsave, Page},
11         PhysAddr,
12     },
13     process::{Pid, ProcessManager},
14     syscall::user_access::{UserBufferReader, UserBufferWriter},
15     time::PosixTimeSpec,
16 };
17 use alloc::vec::Vec;
18 use core::sync::atomic::{compiler_fence, Ordering};
19 use hashbrown::{HashMap, HashSet};
20 use ida::IdAllocator;
21 use num::ToPrimitive;
22 use system_error::SystemError;
23 
24 pub static mut SHM_MANAGER: Option<SpinLock<ShmManager>> = None;
25 
26 /// 用于创建新的私有IPC对象
27 pub const IPC_PRIVATE: ShmKey = ShmKey::new(0);
28 
29 /// 初始化SHM_MANAGER
30 pub fn shm_manager_init() {
31     kinfo!("shm_manager_init");
32     let shm_manager = SpinLock::new(ShmManager::new());
33 
34     compiler_fence(Ordering::SeqCst);
35     unsafe { SHM_MANAGER = Some(shm_manager) };
36     compiler_fence(Ordering::SeqCst);
37 
38     kinfo!("shm_manager_init done");
39 }
40 
41 pub fn shm_manager_lock() -> SpinLockGuard<'static, ShmManager> {
42     unsafe { SHM_MANAGER.as_ref().unwrap().lock() }
43 }
44 
45 int_like!(ShmId, usize);
46 int_like!(ShmKey, usize);
47 
48 bitflags! {
49     pub struct ShmFlags:u32{
50         const SHM_RDONLY = 0o10000;
51         const SHM_RND = 0o20000;
52         const SHM_REMAP = 0o40000;
53         const SHM_EXEC = 0o100000;
54         const SHM_HUGETLB = 0o4000;
55 
56         const IPC_CREAT = 0o1000;
57         const IPC_EXCL = 0o2000;
58 
59         const SHM_DEST = 0o1000;
60         const SHM_LOCKED = 0o2000;
61     }
62 }
63 
64 /// 管理共享内存段信息的操作码
65 #[derive(Eq, Clone, Copy)]
66 pub enum ShmCtlCmd {
67     /// 删除共享内存段
68     IpcRmid = 0,
69     /// 设置KernIpcPerm选项
70     IpcSet = 1,
71     /// 获取ShmIdDs
72     IpcStat = 2,
73     /// 查看ShmMetaData
74     IpcInfo = 3,
75 
76     /// 不允许共享内存段被置换出物理内存
77     ShmLock = 11,
78     /// 允许共享内存段被置换出物理内存
79     ShmUnlock = 12,
80     /// 查看ShmMetaData
81     ShmStat = 13,
82     /// 查看ShmInfo
83     ShmInfo = 14,
84     /// 查看ShmMetaData
85     ShmtStatAny = 15,
86 
87     Default,
88 }
89 
90 impl From<usize> for ShmCtlCmd {
91     fn from(cmd: usize) -> ShmCtlCmd {
92         match cmd {
93             0 => Self::IpcRmid,
94             1 => Self::IpcSet,
95             2 => Self::IpcStat,
96             3 => Self::IpcInfo,
97             11 => Self::ShmLock,
98             12 => Self::ShmUnlock,
99             13 => Self::ShmStat,
100             14 => Self::ShmInfo,
101             15 => Self::ShmtStatAny,
102             _ => Self::Default,
103         }
104     }
105 }
106 
107 impl PartialEq for ShmCtlCmd {
108     fn eq(&self, other: &ShmCtlCmd) -> bool {
109         *self as usize == *other as usize
110     }
111 }
112 
113 /// 共享内存管理器
114 #[derive(Debug)]
115 pub struct ShmManager {
116     /// ShmId分配器
117     id_allocator: IdAllocator,
118     /// ShmId映射共享内存信息表
119     id2shm: HashMap<ShmId, KernelShm>,
120     /// ShmKey映射ShmId表
121     key2id: HashMap<ShmKey, ShmId>,
122 }
123 
124 impl ShmManager {
125     pub fn new() -> Self {
126         ShmManager {
127             id_allocator: IdAllocator::new(0, usize::MAX - 1),
128             id2shm: HashMap::new(),
129             key2id: HashMap::new(),
130         }
131     }
132 
133     /// # 添加共享内存段
134     ///
135     /// ## 参数
136     ///
137     /// - `key`: 共享内存键值
138     /// - `size`: 共享内存大小
139     /// - `shmflg`: 共享内存标志
140     ///
141     /// ## 返回值
142     ///
143     /// 成功:共享内存id
144     /// 失败:对应错误码
145     pub fn add(
146         &mut self,
147         key: ShmKey,
148         size: usize,
149         shmflg: ShmFlags,
150     ) -> Result<usize, SystemError> {
151         // 判断共享内存大小是否过小或溢出
152         if !(PosixShmMetaInfo::SHMMIN..=PosixShmMetaInfo::SHMMAX).contains(&size) {
153             return Err(SystemError::EINVAL);
154         }
155 
156         let id = self.id_allocator.alloc().expect("No more id to allocate.");
157         let shm_id = ShmId::new(id);
158 
159         // 分配共享内存页面
160         let page_count = PageFrameCount::from_bytes(page_align_up(size)).unwrap();
161         let phys_page =
162             unsafe { LockedFrameAllocator.allocate(page_count) }.ok_or(SystemError::EINVAL)?;
163         // 创建共享内存page,并添加到PAGE_MANAGER中
164         let mut page_manager_guard = page_manager_lock_irqsave();
165         let mut cur_phys = PhysPageFrame::new(phys_page.0);
166         for _ in 0..page_count.data() {
167             let mut page = Page::new(true);
168             page.set_shm_id(shm_id);
169             let paddr = cur_phys.phys_address();
170             page_manager_guard.insert(paddr, page);
171             cur_phys = cur_phys.next();
172         }
173 
174         // 创建共享内存信息结构体
175         let paddr = phys_page.0;
176         let kern_ipc_perm = KernIpcPerm {
177             id: shm_id,
178             key,
179             uid: 0,
180             gid: 0,
181             _cuid: 0,
182             _cgid: 0,
183             mode: shmflg & ShmFlags::from_bits_truncate(ModeType::S_IRWXUGO.bits()),
184             _seq: 0,
185         };
186         let shm_kernel = KernelShm::new(kern_ipc_perm, paddr, size);
187 
188         // 将key、id及其对应KernelShm添加到表中
189         self.id2shm.insert(shm_id, shm_kernel);
190         self.key2id.insert(key, shm_id);
191 
192         return Ok(shm_id.data());
193     }
194 
195     pub fn contains_key(&self, key: &ShmKey) -> Option<&ShmId> {
196         self.key2id.get(key)
197     }
198 
199     pub fn get_mut(&mut self, id: &ShmId) -> Option<&mut KernelShm> {
200         self.id2shm.get_mut(id)
201     }
202 
203     pub fn free_key(&mut self, key: &ShmKey) {
204         self.key2id.remove(key);
205     }
206 
207     pub fn free_id(&mut self, id: &ShmId) {
208         self.id2shm.remove(id);
209         self.id_allocator.free(id.0);
210     }
211 
212     pub fn ipc_info(&self, user_buf: *const u8, from_user: bool) -> Result<usize, SystemError> {
213         let mut user_buffer_writer = UserBufferWriter::new(
214             user_buf as *mut u8,
215             core::mem::size_of::<PosixShmMetaInfo>(),
216             from_user,
217         )?;
218 
219         let shm_meta_info = PosixShmMetaInfo::new();
220         user_buffer_writer.copy_one_to_user(&shm_meta_info, 0)?;
221 
222         return Ok(0);
223     }
224 
225     pub fn shm_info(&self, user_buf: *const u8, from_user: bool) -> Result<usize, SystemError> {
226         // 已使用id数量
227         let used_ids = self.id2shm.len().to_i32().unwrap();
228         // 共享内存总和
229         let shm_tot = self.id2shm.iter().fold(0, |acc, (_, kernel_shm)| {
230             acc + PageFrameCount::from_bytes(page_align_up(kernel_shm.shm_size))
231                 .unwrap()
232                 .data()
233         });
234         let shm_info = PosixShmInfo::new(used_ids, shm_tot, 0, 0, 0, 0);
235 
236         let mut user_buffer_writer = UserBufferWriter::new(
237             user_buf as *mut u8,
238             core::mem::size_of::<PosixShmInfo>(),
239             from_user,
240         )?;
241         user_buffer_writer.copy_one_to_user(&shm_info, 0)?;
242 
243         return Ok(0);
244     }
245 
246     pub fn shm_stat(
247         &self,
248         id: ShmId,
249         cmd: ShmCtlCmd,
250         user_buf: *const u8,
251         from_user: bool,
252     ) -> Result<usize, SystemError> {
253         let kernel_shm = self.id2shm.get(&id).ok_or(SystemError::EINVAL)?;
254         let key = kernel_shm.kern_ipc_perm.key.data().to_i32().unwrap();
255         let mode = kernel_shm.kern_ipc_perm.mode.bits();
256 
257         let shm_perm = PosixIpcPerm::new(key, 0, 0, 0, 0, mode);
258         let shm_segsz = kernel_shm.shm_size;
259         let shm_atime = kernel_shm.shm_atim.total_nanos();
260         let shm_dtime = kernel_shm.shm_dtim.total_nanos();
261         let shm_ctime = kernel_shm.shm_ctim.total_nanos();
262         let shm_cpid = kernel_shm.shm_cprid.data().to_u32().unwrap();
263         let shm_lpid = kernel_shm.shm_lprid.data().to_u32().unwrap();
264         let shm_map_count = kernel_shm.map_count();
265         let shm_id_ds = PosixShmIdDs {
266             shm_perm,
267             shm_segsz,
268             shm_atime,
269             shm_dtime,
270             shm_ctime,
271             shm_cpid,
272             shm_lpid,
273             shm_map_count,
274             _unused1: 0,
275             _unused2: 0,
276         };
277 
278         let mut user_buffer_writer = UserBufferWriter::new(
279             user_buf as *mut u8,
280             core::mem::size_of::<PosixShmIdDs>(),
281             from_user,
282         )?;
283         user_buffer_writer.copy_one_to_user(&shm_id_ds, 0)?;
284 
285         let r: usize = if cmd == ShmCtlCmd::IpcStat {
286             0
287         } else {
288             id.data()
289         };
290 
291         return Ok(r);
292     }
293 
294     pub fn ipc_set(
295         &mut self,
296         id: ShmId,
297         user_buf: *const u8,
298         from_user: bool,
299     ) -> Result<usize, SystemError> {
300         let kernel_shm = self.id2shm.get_mut(&id).ok_or(SystemError::EINVAL)?;
301 
302         let user_buffer_reader =
303             UserBufferReader::new(user_buf, core::mem::size_of::<PosixShmIdDs>(), from_user)?;
304         let mut shm_id_ds = PosixShmIdDs::default();
305         user_buffer_reader.copy_one_from_user(&mut shm_id_ds, 0)?;
306 
307         kernel_shm.copy_from(shm_id_ds);
308 
309         return Ok(0);
310     }
311 
312     pub fn ipc_rmid(&mut self, id: ShmId) -> Result<usize, SystemError> {
313         let kernel_shm = self.id2shm.get_mut(&id).ok_or(SystemError::EINVAL)?;
314         kernel_shm.set_mode(ShmFlags::SHM_DEST, true);
315 
316         let mut cur_phys = PhysPageFrame::new(kernel_shm.shm_start_paddr);
317         let count = PageFrameCount::from_bytes(page_align_up(kernel_shm.shm_size)).unwrap();
318         let key = kernel_shm.kern_ipc_perm.key;
319         let id = kernel_shm.kern_ipc_perm.id;
320         let map_count = kernel_shm.map_count();
321 
322         let mut page_manager_guard = page_manager_lock_irqsave();
323         if map_count > 0 {
324             // 设置共享内存物理页当映射计数等于0时可被回收
325             for _ in 0..count.data() {
326                 let page = page_manager_guard.get_mut(&cur_phys.phys_address());
327                 page.set_dealloc_when_zero(true);
328 
329                 cur_phys = cur_phys.next();
330             }
331 
332             // 释放key,不让后续进程连接
333             self.free_key(&key);
334         } else {
335             // 释放共享内存物理页
336             for _ in 0..count.data() {
337                 let paddr = cur_phys.phys_address();
338                 unsafe {
339                     LockedFrameAllocator.free(paddr, PageFrameCount::new(1));
340                 }
341                 // 将已回收的物理页面对应的Page从PAGE_MANAGER中删去
342                 page_manager_guard.remove_page(&paddr);
343                 cur_phys = cur_phys.next();
344             }
345 
346             // 释放key和id
347             self.free_id(&id);
348             self.free_key(&key)
349         }
350 
351         return Ok(0);
352     }
353 
354     pub fn shm_lock(&mut self, id: ShmId) -> Result<usize, SystemError> {
355         let kernel_shm = self.id2shm.get_mut(&id).ok_or(SystemError::EINVAL)?;
356         kernel_shm.set_mode(ShmFlags::SHM_LOCKED, true);
357 
358         return Ok(0);
359     }
360 
361     pub fn shm_unlock(&mut self, id: ShmId) -> Result<usize, SystemError> {
362         let kernel_shm = self.id2shm.get_mut(&id).ok_or(SystemError::EINVAL)?;
363         kernel_shm.set_mode(ShmFlags::SHM_LOCKED, false);
364 
365         return Ok(0);
366     }
367 }
368 /// 共享内存信息
369 #[derive(Debug)]
370 pub struct KernelShm {
371     /// 权限信息
372     kern_ipc_perm: KernIpcPerm,
373     /// 共享内存起始物理地址
374     shm_start_paddr: PhysAddr,
375     /// 共享内存大小(bytes),注意是用户指定的大小(未经过页面对齐)
376     shm_size: usize,
377     /// 最后一次连接的时间
378     shm_atim: PosixTimeSpec,
379     /// 最后一次断开连接的时间
380     shm_dtim: PosixTimeSpec,
381     /// 最后一次更改信息的时间
382     shm_ctim: PosixTimeSpec,
383     /// 创建者进程id
384     shm_cprid: Pid,
385     /// 最后操作者进程id
386     shm_lprid: Pid,
387 }
388 
389 impl KernelShm {
390     pub fn new(kern_ipc_perm: KernIpcPerm, shm_start_paddr: PhysAddr, shm_size: usize) -> Self {
391         let shm_cprid = ProcessManager::current_pid();
392         KernelShm {
393             kern_ipc_perm,
394             shm_start_paddr,
395             shm_size,
396             shm_atim: PosixTimeSpec::new(0, 0),
397             shm_dtim: PosixTimeSpec::new(0, 0),
398             shm_ctim: PosixTimeSpec::now(),
399             shm_cprid,
400             shm_lprid: shm_cprid,
401         }
402     }
403 
404     pub fn start_paddr(&self) -> PhysAddr {
405         self.shm_start_paddr
406     }
407 
408     pub fn size(&self) -> usize {
409         self.shm_size
410     }
411 
412     /// 更新最后连接时间
413     pub fn update_atim(&mut self) {
414         // 更新最后一次连接时间
415         self.shm_atim = PosixTimeSpec::now();
416 
417         // 更新最后操作当前共享内存的进程ID
418         self.shm_lprid = ProcessManager::current_pid();
419     }
420 
421     /// 更新最后断开连接时间
422     pub fn update_dtim(&mut self) {
423         // 更新最后一次断开连接时间
424         self.shm_dtim = PosixTimeSpec::now();
425 
426         // 更新最后操作当前共享内存的进程ID
427         self.shm_lprid = ProcessManager::current_pid();
428     }
429 
430     /// 更新最后一次修改信息的时间
431     pub fn update_ctim(&mut self) {
432         // 更新最后一次修改信息的时间
433         self.shm_ctim = PosixTimeSpec::now();
434     }
435 
436     /// 共享内存段的映射计数(有多少个不同的VMA映射)
437     pub fn map_count(&self) -> usize {
438         let page_manager_guard = page_manager_lock_irqsave();
439         let mut id_set: HashSet<usize> = HashSet::new();
440         let mut cur_phys = PhysPageFrame::new(self.shm_start_paddr);
441         let page_count = PageFrameCount::from_bytes(page_align_up(self.shm_size)).unwrap();
442 
443         for _ in 0..page_count.data() {
444             let page = page_manager_guard.get(&cur_phys.phys_address()).unwrap();
445             id_set.extend(
446                 page.anon_vma()
447                     .iter()
448                     .map(|vma| vma.id())
449                     .collect::<Vec<_>>(),
450             );
451 
452             cur_phys = cur_phys.next();
453         }
454 
455         // 由于LockedVMA的id是独一无二的,因此有多少个不同的id,就代表着有多少个不同的VMA映射到共享内存段
456         return id_set.len();
457     }
458 
459     pub fn copy_from(&mut self, shm_id_ds: PosixShmIdDs) {
460         self.kern_ipc_perm.uid = shm_id_ds.uid() as usize;
461         self.kern_ipc_perm.gid = shm_id_ds.gid() as usize;
462         self.kern_ipc_perm.mode = ShmFlags::from_bits_truncate(shm_id_ds.mode());
463         self.update_ctim();
464     }
465 
466     pub fn set_mode(&mut self, shmflg: ShmFlags, set: bool) {
467         if set {
468             self.kern_ipc_perm.mode.insert(shmflg);
469         } else {
470             self.kern_ipc_perm.mode.remove(shmflg);
471         }
472 
473         self.update_ctim();
474     }
475 }
476 
477 /// 共享内存权限信息
478 #[derive(Debug)]
479 pub struct KernIpcPerm {
480     /// 共享内存id
481     id: ShmId,
482     /// 共享内存键值,由创建共享内存用户指定
483     key: ShmKey,
484     /// 共享内存拥有者用户id
485     uid: usize,
486     /// 共享内存拥有者所在组id
487     gid: usize,
488     /// 共享内存创建者用户id
489     _cuid: usize,
490     /// 共享内存创建者所在组id
491     _cgid: usize,
492     /// 共享内存区权限模式
493     mode: ShmFlags,
494     _seq: usize,
495 }
496 
497 /// 共享内存元信息,符合POSIX标准
498 #[repr(C)]
499 #[derive(Debug, Clone, Copy)]
500 pub struct PosixShmMetaInfo {
501     /// 最大共享内存段的大小(bytes)
502     shmmax: usize,
503     /// 最小共享内存段的大小(bytes)
504     shmmin: usize,
505     /// 最大共享内存标识符数量
506     shmmni: usize,
507     /// 单个进程可以拥有的最大共享内存段的数量,和最大共享内存标识符数量相同
508     shmseg: usize,
509     /// 所有共享内存段总共可以使用的最大内存量(pages)
510     shmall: usize,
511     _unused1: usize,
512     _unused2: usize,
513     _unused3: usize,
514     _unused4: usize,
515 }
516 
517 impl PosixShmMetaInfo {
518     /// 最小共享内存段的大小(bytes)
519     pub const SHMMIN: usize = 1;
520     /// 最大共享内存标识符数量
521     pub const SHMMNI: usize = 4096;
522     /// 最大共享内存段的大小(bytes)
523     pub const SHMMAX: usize = usize::MAX - (1 << 24);
524     /// 所有共享内存段总共可以使用的最大内存量(pages)
525     pub const SHMALL: usize = usize::MAX - (1 << 24);
526     /// 单个进程可以拥有的最大共享内存段的数量,和最大共享内存标识符数量相同
527     pub const SHMSEG: usize = 4096;
528 
529     pub fn new() -> Self {
530         PosixShmMetaInfo {
531             shmmax: Self::SHMMAX,
532             shmmin: Self::SHMMIN,
533             shmmni: Self::SHMMNI,
534             shmseg: Self::SHMSEG,
535             shmall: Self::SHMALL,
536             _unused1: 0,
537             _unused2: 0,
538             _unused3: 0,
539             _unused4: 0,
540         }
541     }
542 }
543 
544 /// 共享内存信息,符合POSIX标准
545 #[repr(C)]
546 #[derive(Clone, Copy)]
547 pub struct PosixShmInfo {
548     /// 已使用id数
549     used_ids: i32,
550     /// 共享内存总量(pages)
551     shm_tot: usize,
552     /// 保留在内存中的共享内存大小
553     shm_rss: usize,
554     /// 被置换出的共享内存大小
555     shm_swp: usize,
556     /// 尝试置换次数
557     swap_attempts: usize,
558     /// 成功置换次数
559     swap_successes: usize,
560 }
561 
562 impl PosixShmInfo {
563     pub fn new(
564         used_ids: i32,
565         shm_tot: usize,
566         shm_rss: usize,
567         shm_swp: usize,
568         swap_attempts: usize,
569         swap_successes: usize,
570     ) -> Self {
571         PosixShmInfo {
572             used_ids,
573             shm_tot,
574             shm_rss,
575             shm_swp,
576             swap_attempts,
577             swap_successes,
578         }
579     }
580 }
581 
582 /// 共享内存段属性信息,符合POSIX标准
583 #[repr(C)]
584 #[derive(Debug, Clone, Copy, Default)]
585 pub struct PosixShmIdDs {
586     /// 共享内存段权限
587     shm_perm: PosixIpcPerm,
588     /// 共享内存大小(bytes)
589     shm_segsz: usize,
590     /// 最后一次连接的时间
591     shm_atime: i64,
592     /// 最后一次断开连接的时间
593     shm_dtime: i64,
594     /// 最后一次更改信息的时间
595     shm_ctime: i64,
596     /// 创建者进程id
597     shm_cpid: u32,
598     /// 最后操作者进程id
599     shm_lpid: u32,
600     /// 链接数
601     shm_map_count: usize,
602     _unused1: usize,
603     _unused2: usize,
604 }
605 
606 impl PosixShmIdDs {
607     pub fn uid(&self) -> u32 {
608         self.shm_perm.uid
609     }
610 
611     pub fn gid(&self) -> u32 {
612         self.shm_perm.gid
613     }
614 
615     pub fn mode(&self) -> u32 {
616         self.shm_perm.mode
617     }
618 }
619 
620 /// 共享内存段权限,符合POSIX标准
621 #[repr(C)]
622 #[derive(Debug, Clone, Copy, Default)]
623 pub struct PosixIpcPerm {
624     /// IPC对象键值
625     key: i32,
626     /// 当前用户id
627     uid: u32,
628     /// 当前用户组id
629     gid: u32,
630     /// 创建者用户id
631     cuid: u32,
632     /// 创建者组id
633     cgid: u32,
634     /// 权限
635     mode: u32,
636     /// 序列号
637     seq: i32,
638     _pad1: i32,
639     _unused1: usize,
640     _unused2: usize,
641 }
642 
643 impl PosixIpcPerm {
644     pub fn new(key: i32, uid: u32, gid: u32, cuid: u32, cgid: u32, mode: u32) -> Self {
645         PosixIpcPerm {
646             key,
647             uid,
648             gid,
649             cuid,
650             cgid,
651             mode,
652             seq: 0,
653             _pad1: 0,
654             _unused1: 0,
655             _unused2: 0,
656         }
657     }
658 }
659