[kernel] Allow unmapping non-fully-mapped areas
The buffer cache will try to clean up a returned buffer by unmapping it, but it may have only been committed without ever getting mapped. Allow for page_out to handle non-fully mapped regions.
This commit is contained in:
@@ -395,42 +395,75 @@ page_manager::page_out(page_table *pml4, uintptr_t virt_addr, size_t count, bool
|
|||||||
page_table_indices idx{virt_addr};
|
page_table_indices idx{virt_addr};
|
||||||
page_table *tables[4] = {pml4, nullptr, nullptr, nullptr};
|
page_table *tables[4] = {pml4, nullptr, nullptr, nullptr};
|
||||||
|
|
||||||
bool found = false;
|
|
||||||
uintptr_t free_start = 0;
|
uintptr_t free_start = 0;
|
||||||
unsigned free_count = 0;
|
unsigned free_count = 0;
|
||||||
|
|
||||||
for (; idx[0] < table_entries; idx[0] += 1) {
|
for (; idx[0] < table_entries; idx[0] += 1) {
|
||||||
tables[1] = tables[0]->get(idx[0]);
|
page_table *table = tables[0]->get(idx[0]);
|
||||||
|
if (!table) {
|
||||||
|
constexpr size_t skip = 512 * 512 * 512;
|
||||||
|
if (count > skip) {
|
||||||
|
count -= skip;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
goto page_out_end;
|
||||||
|
}
|
||||||
|
|
||||||
|
tables[1] = table;
|
||||||
|
|
||||||
for (; idx[1] < table_entries; idx[1] += 1) {
|
for (; idx[1] < table_entries; idx[1] += 1) {
|
||||||
tables[2] = tables[1]->get(idx[1]);
|
page_table *table = tables[1]->get(idx[1]);
|
||||||
|
if (!table) {
|
||||||
|
constexpr size_t skip = 512 * 512;
|
||||||
|
if (count > skip) {
|
||||||
|
count -= skip;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
goto page_out_end;
|
||||||
|
}
|
||||||
|
|
||||||
|
tables[2] = table;
|
||||||
|
|
||||||
for (; idx[2] < table_entries; idx[2] += 1) {
|
for (; idx[2] < table_entries; idx[2] += 1) {
|
||||||
tables[3] = tables[2]->get(idx[2]);
|
page_table *table = tables[2]->get(idx[2]);
|
||||||
|
if (!table) {
|
||||||
|
constexpr size_t skip = 512;
|
||||||
|
if (count > skip) {
|
||||||
|
count -= skip;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
goto page_out_end;
|
||||||
|
}
|
||||||
|
|
||||||
|
tables[3] = table;
|
||||||
|
|
||||||
for (; idx[3] < table_entries; idx[3] += 1) {
|
for (; idx[3] < table_entries; idx[3] += 1) {
|
||||||
uintptr_t entry = tables[3]->entries[idx[3]] & ~0xfffull;
|
uintptr_t entry = tables[3]->entries[idx[3]];
|
||||||
if (!found || entry != free_start + free_count * frame_size) {
|
bool present = entry & 1;
|
||||||
if (found && free) m_frames.free(free_start, free_count);
|
|
||||||
|
if (present) {
|
||||||
|
entry &= ~0xfffull;
|
||||||
|
if (!free_count || entry != free_start + free_count * frame_size) {
|
||||||
|
if (free_count && free) m_frames.free(free_start, free_count);
|
||||||
free_start = tables[3]->entries[idx[3]] & ~0xfffull;
|
free_start = tables[3]->entries[idx[3]] & ~0xfffull;
|
||||||
free_count = 1;
|
free_count = 1;
|
||||||
found = true;
|
|
||||||
} else {
|
} else {
|
||||||
free_count++;
|
free_count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
tables[3]->entries[idx[3]] = 0;
|
tables[3]->entries[idx[3]] = 0;
|
||||||
|
|
||||||
if (--count == 0) {
|
|
||||||
if (free) m_frames.free(free_start, free_count);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (--count == 0)
|
||||||
|
goto page_out_end;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
kassert(0, "Ran to end of page_out");
|
page_out_end:
|
||||||
|
if (free && free_count)
|
||||||
|
m_frames.free(free_start, free_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|||||||
Reference in New Issue
Block a user