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