Skip to content

Commit e79b129

Browse files
committed
mm/pmm: KTF must not run out of 4k frames at any point
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.
1 parent 60d2f0d commit e79b129

File tree

1 file changed

+27
-4
lines changed

1 file changed

+27
-4
lines changed

mm/pmm.c

+27-4
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ static frames_array_t early_frames;
4141
static list_head_t free_frames[MAX_PAGE_ORDER + 1];
4242
static list_head_t busy_frames[MAX_PAGE_ORDER + 1];
4343

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

4647
static spinlock_t lock = SPINLOCK_INIT;
@@ -572,19 +573,37 @@ static void merge_frames(frame_t *first) {
572573
merge_frames(first);
573574
}
574575

576+
static inline bool enough_4k_frames(void) {
577+
frame_t *frame;
578+
int count = 0;
579+
580+
list_for_each_entry (frame, &free_frames[PAGE_ORDER_4K], list) {
581+
if (++count >= MIN_NUM_4K_FRAMES)
582+
return true;
583+
}
584+
585+
return false;
586+
}
587+
588+
static void try_create_4k_frames(void) {
589+
while (!enough_4k_frames()) {
590+
frame_t *frame = find_larger_frame(free_frames, PAGE_ORDER_4K);
591+
if (!frame)
592+
panic("No more frames available to create 4K frames");
593+
split_frame(frame);
594+
}
595+
}
596+
575597
/* Reserves and returns the first free frame fulfilling
576598
* the condition specified by the callback.
577599
* This function does not split larger frames.
578600
*/
579601
frame_t *get_free_frames_cond(free_frames_cond_t cb) {
580602
spin_lock(&lock);
603+
try_create_4k_frames();
581604
for_each_order (order) {
582605
frame_t *frame;
583606

584-
if (list_is_empty(&free_frames[order])) {
585-
continue;
586-
}
587-
588607
list_for_each_entry (frame, &free_frames[order], list) {
589608
if (cb(frame)) {
590609
reserve_frame(frame);
@@ -605,7 +624,11 @@ frame_t *get_free_frames(unsigned int order) {
605624
return NULL;
606625

607626
spin_lock(&lock);
627+
if (order == PAGE_ORDER_4K)
628+
try_create_4k_frames();
629+
608630
while (list_is_empty(&free_frames[order])) {
631+
BUG_ON(order == PAGE_ORDER_4K);
609632
frame = find_larger_frame(free_frames, order);
610633
if (!frame) {
611634
spin_unlock(&lock);

0 commit comments

Comments
 (0)