Skip to content

Commit

Permalink
mm/pmm: KTF must not run out of 4k frames at any point
Browse files Browse the repository at this point in the history
If we run out of 4k frames it becomes impossible to perform a higher
order frames splitting, since new frames creation may need new frames
array, which is 4k as well.
To prevent these kind of situations, always keep at least two free 4k
frames available.
  • Loading branch information
wipawel committed Nov 24, 2023
1 parent 1413e01 commit f91ed53
Showing 1 changed file with 30 additions and 0 deletions.
30 changes: 30 additions & 0 deletions mm/pmm.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ static frames_array_t early_frames;
static list_head_t free_frames[MAX_PAGE_ORDER + 1];
static list_head_t busy_frames[MAX_PAGE_ORDER + 1];

#define MIN_NUM_4K_FRAMES 2
static size_t frames_count[MAX_PAGE_ORDER + 1];

static spinlock_t lock = SPINLOCK_INIT;
Expand Down Expand Up @@ -572,6 +573,27 @@ static void merge_frames(frame_t *first) {
merge_frames(first);
}

static inline bool enough_4k_frames(void) {
frame_t *frame;
int count = 0;

list_for_each_entry (frame, &free_frames[PAGE_ORDER_4K], list) {
if (++count >= MIN_NUM_4K_FRAMES)
return true;
}

return false;
}

static void try_create_4k_frames(void) {
while (!enough_4k_frames()) {
frame_t *frame = find_larger_frame(free_frames, PAGE_ORDER_4K);
if (!frame)
panic("No more frames available to create 4K frames");
split_frame(frame);
}
}

/* Reserves and returns the first free frame fulfilling
* the condition specified by the callback.
* This function does not split larger frames.
Expand All @@ -582,9 +604,13 @@ frame_t *get_free_frames_cond(free_frames_cond_t cb) {
frame_t *frame;

if (list_is_empty(&free_frames[order])) {
BUG_ON(order == PAGE_ORDER_4K);
continue;
}

if (order == PAGE_ORDER_4K)
try_create_4k_frames();

list_for_each_entry (frame, &free_frames[order], list) {
if (cb(frame)) {
reserve_frame(frame);
Expand All @@ -605,7 +631,11 @@ frame_t *get_free_frames(unsigned int order) {
return NULL;

spin_lock(&lock);
if (order == PAGE_ORDER_4K)
try_create_4k_frames();

while (list_is_empty(&free_frames[order])) {
BUG_ON(order == PAGE_ORDER_4K);
frame = find_larger_frame(free_frames, order);
if (!frame) {
spin_unlock(&lock);
Expand Down

0 comments on commit f91ed53

Please sign in to comment.