pmm: fix refcounting race

This commit is contained in:
Matheus
2026-04-22 19:50:17 -03:00
parent d8297b990c
commit dfce89c1ff
+8 -7
View File
@@ -110,12 +110,14 @@ static void removefromfreelist(page_t *page) {
else else
*tail = page->freeprev; *tail = page->freeprev;
page->freenext = NULL;
page->freeprev = NULL;
--freepagecount; --freepagecount;
} }
static void internalhold(page_t *page) { static void internalhold(page_t *page) {
__atomic_add_fetch(&page->refcount, 1, __ATOMIC_SEQ_CST); if (++page->refcount == 1) {
if (page->refcount == 1) {
// this is only valid on standby pages, in case of free pages its an use after free // this is only valid on standby pages, in case of free pages its an use after free
__assert((page->flags & PAGE_FLAGS_FREE) == 0); __assert((page->flags & PAGE_FLAGS_FREE) == 0);
removefromfreelist(page); removefromfreelist(page);
@@ -140,17 +142,16 @@ void pmm_hold(void *addr) {
void pmm_release(void *addr) { void pmm_release(void *addr) {
page_t *page = &pages[(uintptr_t)addr / PAGE_SIZE]; page_t *page = &pages[(uintptr_t)addr / PAGE_SIZE];
__assert(page->refcount != 0);
uintmax_t newrefcount = __atomic_sub_fetch(&page->refcount, 1, __ATOMIC_SEQ_CST); MUTEX_ACQUIRE(&freelistmutex);
if (newrefcount == 0) { __assert(page->refcount != 0);
if (--page->refcount == 0) {
__assert((page->flags & PAGE_FLAGS_DIRTY) == 0); __assert((page->flags & PAGE_FLAGS_DIRTY) == 0);
MUTEX_ACQUIRE(&freelistmutex);
insertinfreelist(page); insertinfreelist(page);
if (page->backing == NULL) if (page->backing == NULL)
page->flags |= PAGE_FLAGS_FREE; page->flags |= PAGE_FLAGS_FREE;
MUTEX_RELEASE(&freelistmutex);
} }
MUTEX_RELEASE(&freelistmutex);
} }
static void doalloc(page_t *page) { static void doalloc(page_t *page) {