I'm trying to modify xv6-riscv to perform a copy-on-write mapping when executing fork()
, but I'm struggling to determine a concise way to manage the copy-on-write pages.
Most sources I can find online suggest to keep reference counter of how many processes currently are able to read from a given copy-on-write page, storing the counter in the PTE. Only pages with a reference count of 1 may be written to, otherwise you must copy the page and decrement the reference count.
However, it's not clear to me how you would actually implement this. The PTE is of a fixed size, and the vast majority of bits, especially in RISCV, are reserved for other purposes, so storing the number of references in the actual PTE feels impractical, especially if the process calls fork() many times.
Furthermore, how would you synchronize this information across page tables? Each process gets their own PTE for a given physical page. Updating the reference count on the current process's PTE for a physical page will not give any information to the other processes.
My idea was to create a sort of page table tree which would dynamically grow as processes fork()
and shrink as processes call exec()
or kill()
, but this doesn't seem to be mentioned anywhere, and it's pretty convoluted, incurring O( number of procs sharing COW page )
access time on writes to copy-on-write pages, so I wanted to explore simpler options.