Skip to main content

strat9_kernel/memory/
cow.rs

1//! Copy-on-Write (COW) support for fork()
2//!
3//! This module provides the core functionality for copy-on-write memory management,
4//! allowing efficient fork() implementation by sharing pages between parent and child
5//! until one of them writes to a shared page.
6//!
7//! # Design
8//!
9//! - Pages are marked as COW by clearing the WRITABLE bit and setting a software COW flag
10//! - The COW flag is stored in bit 9 of the PTE (available for software use on x86_64)
11//! - When a write fault occurs on a COW page:
12//!   1. If refcount > 1: allocate new frame, copy content, update PTE
13//!   2. If refcount == 1: just mark page as writable (no copy needed)
14//!
15//! # SMP Safety
16//!
17//! - Atomic refcount per frame (lock-free inc/dec)
18//! - COW_LOCK protects flag changes and frame free
19//! - TLB shootdown is performed after modifying page table flags
20
21use crate::{
22    memory::frame::{frame_flags, get_meta, PhysFrame},
23    sync::SpinLock,
24};
25use core::sync::atomic::{fence, Ordering};
26
27static COW_LOCK: SpinLock<()> = SpinLock::new(());
28
29/// Performs the frame to pfn operation.
30#[inline]
31fn frame_meta(frame: PhysFrame) -> &'static crate::memory::frame::FrameMeta {
32    get_meta(frame.start_address)
33}
34
35/// Performs the frame inc ref operation.
36pub fn frame_inc_ref(frame: PhysFrame) {
37    frame_meta(frame).inc_ref();
38}
39
40/// Performs the frame dec ref operation.
41pub fn frame_dec_ref(frame: PhysFrame) {
42    let meta = frame_meta(frame);
43    let old = meta.dec_ref();
44    if old == 1 {
45        fence(Ordering::Acquire);
46        crate::sync::with_irqs_disabled(|token| {
47            crate::memory::free_frame(token, frame);
48        });
49    }
50}
51
52/// Performs the frame get refcount operation.
53pub fn frame_get_refcount(frame: PhysFrame) -> u32 {
54    frame_meta(frame).get_refcount()
55}
56
57/// Set COW flag on a frame (SMP-safe).
58pub fn frame_set_cow(frame: PhysFrame) {
59    let _lock = COW_LOCK.lock();
60    let meta = frame_meta(frame);
61    let flags = meta.get_flags() | frame_flags::COW;
62    meta.set_flags(flags);
63}
64
65/// Clear COW flag on a frame (SMP-safe).
66pub fn frame_clear_cow(frame: PhysFrame) {
67    let _lock = COW_LOCK.lock();
68    let meta = frame_meta(frame);
69    let flags = meta.get_flags() & !frame_flags::COW;
70    meta.set_flags(flags);
71}
72
73/// Check if a frame is marked as COW (lock-free read).
74pub fn frame_is_cow(frame: PhysFrame) -> bool {
75    frame_meta(frame).is_cow()
76}
77
78/// Mark a frame as DLL (shared, never COW) (SMP-safe).
79pub fn frame_set_dll(frame: PhysFrame) {
80    let _lock = COW_LOCK.lock();
81    let meta = frame_meta(frame);
82    let flags = meta.get_flags() | frame_flags::DLL;
83    meta.set_flags(flags);
84}
85
86/// Check if a frame is a DLL frame (lock-free read).
87pub fn frame_is_dll(frame: PhysFrame) -> bool {
88    frame_meta(frame).is_dll()
89}