@@ -41,10 +41,42 @@ static frames_array_t early_frames;
4141static list_head_t free_frames [MAX_PAGE_ORDER + 1 ];
4242static list_head_t busy_frames [MAX_PAGE_ORDER + 1 ];
4343
44- #define MIN_NUM_4K_FRAMES 2
44+ /*
45+ * Worst case: pmm wants to refill while paging just started on another thread
46+ * 1 for pmm refill attempt (new_frames_array)
47+ * 3 for paging currently ongoing
48+ * 4 for refill_from_paging (1 array frame, 3 for mapping it)
49+ */
50+ #define MIN_NUM_4K_FRAMES (1 + 3 + (1 + 3))
51+ /* enough array frames to refill 4K frames in the worst case without needing refill */
52+ #define MIN_NOREFILL_FREE_FRAMES_THRESHOLD \
53+ (MIN_FREE_FRAMES_THRESHOLD + MIN_NUM_4K_FRAMES + (MAX_PAGE_ORDER - PAGE_ORDER_4K))
4554static size_t frames_count [MAX_PAGE_ORDER + 1 ];
4655
56+ /* first lock to serialize normal access to pmm (i.e. not array frame refill) */
4757static spinlock_t lock = SPINLOCK_INIT ;
58+ /**
59+ * second lock to give paging priority access to pmm during array frame refill
60+ *
61+ * Ensure that get_free_frame_norefill and refill_from_paging are only called while
62+ * holding the paging lock.
63+ */
64+ static spinlock_t priority_lock = SPINLOCK_INIT ;
65+
66+ /* avoid recursive refilling after paging */
67+ static bool refill_from_paging_ongoing = false;
68+
69+ static void try_create_4k_frames (void );
70+
71+ static void pmm_lock () {
72+ spin_lock (& lock );
73+ spin_lock (& priority_lock );
74+ }
75+
76+ static void pmm_unlock () {
77+ spin_unlock (& priority_lock );
78+ spin_unlock (& lock );
79+ }
4880
4981void display_frames_count (void ) {
5082 printk ("Avail memory frames: (total size: %lu MB)\n" , total_phys_memory / MB (1 ));
@@ -109,7 +141,49 @@ static frames_array_t *new_frames_array(void) {
109141 if (!boot_flags .virt )
110142 array = (frames_array_t * ) mfn_to_virt_kern (frame -> mfn );
111143 else {
144+ /* switch to special refilling mode to avoid deadlock with paging */
145+ spin_unlock (& priority_lock );
146+
147+ /* only paging is allowed to use pmm with only the priority_lock */
112148 array = vmap_kern_4k (mfn_to_virt_map (frame -> mfn ), frame -> mfn , L1_PROT );
149+
150+ /* switch back to normal mode */
151+ spin_lock (& priority_lock );
152+
153+ if (!array )
154+ goto error ;
155+ }
156+
157+ dprintk ("%s: allocated new frames array: %p\n" , __func__ , array );
158+
159+ init_frames_array (array );
160+
161+ return array ;
162+ error :
163+ panic ("PMM: Unable to allocate new page for frame array" );
164+ UNREACHABLE ();
165+ }
166+
167+ static frames_array_t * new_frames_array_nolock (void ) {
168+ frames_array_t * array ;
169+ frame_t * frame ;
170+
171+ frame = reserve_frame (get_first_frame (free_frames , PAGE_ORDER_4K ));
172+ if (!frame )
173+ goto error ;
174+
175+ if (!boot_flags .virt )
176+ array = (frames_array_t * ) mfn_to_virt_kern (frame -> mfn );
177+ else {
178+ /* switch to special refilling mode to avoid deadlock with paging */
179+ spin_unlock (& priority_lock );
180+
181+ /* only paging is allowed to use pmm with only the priority_lock */
182+ array = vmap_pmm_refill_nolock (mfn_to_virt_map (frame -> mfn ), frame -> mfn , L1_PROT );
183+
184+ /* switch back to normal mode */
185+ spin_lock (& priority_lock );
186+
113187 if (!array )
114188 goto error ;
115189 }
@@ -426,31 +500,31 @@ static frame_t *_find_mfn_frame(list_head_t *list, mfn_t mfn, unsigned int order
426500frame_t * find_free_mfn_frame (mfn_t mfn , unsigned int order ) {
427501 frame_t * frame ;
428502
429- spin_lock ( & lock );
503+ pmm_lock ( );
430504 frame = _find_mfn_frame (free_frames , mfn , order );
431- spin_unlock ( & lock );
505+ pmm_unlock ( );
432506
433507 return frame ;
434508}
435509
436510frame_t * find_busy_mfn_frame (mfn_t mfn , unsigned int order ) {
437511 frame_t * frame ;
438512
439- spin_lock ( & lock );
513+ pmm_lock ( );
440514 frame = _find_mfn_frame (busy_frames , mfn , order );
441- spin_unlock ( & lock );
515+ pmm_unlock ( );
442516
443517 return frame ;
444518}
445519
446520frame_t * find_mfn_frame (mfn_t mfn , unsigned int order ) {
447521 frame_t * frame ;
448522
449- spin_lock ( & lock );
523+ pmm_lock ( );
450524 frame = _find_mfn_frame (busy_frames , mfn , order );
451525 if (!frame )
452526 frame = _find_mfn_frame (free_frames , mfn , order );
453- spin_unlock ( & lock );
527+ pmm_unlock ( );
454528
455529 return frame ;
456530}
@@ -471,31 +545,31 @@ static frame_t *_find_paddr_frame(list_head_t *list, paddr_t paddr) {
471545frame_t * find_free_paddr_frame (paddr_t paddr ) {
472546 frame_t * frame ;
473547
474- spin_lock ( & lock );
548+ pmm_lock ( );
475549 frame = _find_paddr_frame (free_frames , paddr );
476- spin_unlock ( & lock );
550+ pmm_unlock ( );
477551
478552 return frame ;
479553}
480554
481555frame_t * find_busy_paddr_frame (paddr_t paddr ) {
482556 frame_t * frame ;
483557
484- spin_lock ( & lock );
558+ pmm_lock ( );
485559 frame = _find_paddr_frame (busy_frames , paddr );
486- spin_unlock ( & lock );
560+ pmm_unlock ( );
487561
488562 return frame ;
489563}
490564
491565frame_t * find_paddr_frame (paddr_t paddr ) {
492566 frame_t * frame ;
493567
494- spin_lock ( & lock );
568+ pmm_lock ( );
495569 frame = _find_paddr_frame (busy_frames , paddr );
496570 if (!frame )
497571 frame = _find_paddr_frame (free_frames , paddr );
498- spin_unlock ( & lock );
572+ pmm_unlock ( );
499573
500574 return frame ;
501575}
@@ -599,20 +673,20 @@ static void try_create_4k_frames(void) {
599673 * This function does not split larger frames.
600674 */
601675frame_t * get_free_frames_cond (free_frames_cond_t cb ) {
602- spin_lock ( & lock );
676+ pmm_lock ( );
603677 try_create_4k_frames ();
604678 for_each_order (order ) {
605679 frame_t * frame ;
606680
607681 list_for_each_entry (frame , & free_frames [order ], list ) {
608682 if (cb (frame )) {
609683 reserve_frame (frame );
610- spin_unlock ( & lock );
684+ pmm_unlock ( );
611685 return frame ;
612686 }
613687 }
614688 }
615- spin_unlock ( & lock );
689+ pmm_unlock ( );
616690
617691 return NULL ;
618692}
@@ -623,22 +697,22 @@ frame_t *get_free_frames(unsigned int order) {
623697 if (order > MAX_PAGE_ORDER )
624698 return NULL ;
625699
626- spin_lock ( & lock );
700+ pmm_lock ( );
627701 if (order == PAGE_ORDER_4K )
628702 try_create_4k_frames ();
629703
630704 while (list_is_empty (& free_frames [order ])) {
631705 BUG_ON (order == PAGE_ORDER_4K );
632706 frame = find_larger_frame (free_frames , order );
633707 if (!frame ) {
634- spin_unlock ( & lock );
708+ pmm_unlock ( );
635709 return NULL ;
636710 }
637711 split_frame (frame );
638712 }
639713
640714 frame = reserve_frame (get_first_frame (free_frames , order ));
641- spin_unlock ( & lock );
715+ pmm_unlock ( );
642716
643717 return frame ;
644718}
@@ -648,7 +722,7 @@ void put_free_frames(mfn_t mfn, unsigned int order) {
648722
649723 ASSERT (order <= MAX_PAGE_ORDER );
650724
651- spin_lock ( & lock );
725+ pmm_lock ( );
652726 frame = _find_mfn_frame (busy_frames , mfn , order );
653727 if (!frame ) {
654728 warning ("PMM: unable to find frame: %lx, order: %u among busy frames" , mfn ,
@@ -660,7 +734,7 @@ void put_free_frames(mfn_t mfn, unsigned int order) {
660734 merge_frames (frame );
661735
662736unlock :
663- spin_unlock ( & lock );
737+ pmm_unlock ( );
664738}
665739
666740void map_frames_array (void ) {
@@ -674,3 +748,41 @@ void map_frames_array(void) {
674748 BUG_ON (!vmap_kern_4k (va , mfn , L1_PROT ));
675749 }
676750}
751+
752+ /* functions for paging to avoid deadlocks */
753+
754+ frame_t * get_free_frame_norefill (void ) {
755+ frame_t * frame ;
756+
757+ spin_lock (& priority_lock );
758+ frame = reserve_frame (get_first_frame (free_frames , PAGE_ORDER_4K ));
759+ spin_unlock (& priority_lock );
760+
761+ /* we ran out of reserved frames. increase MIN_NUM_4K_FRAMES */
762+ BUG_ON (!frame );
763+
764+ return frame ;
765+ }
766+
767+ void refill_from_paging (void ) {
768+ spin_lock (& priority_lock );
769+
770+ /* avoid refill_from_paging being called from refill_from_paging */
771+ if (!refill_from_paging_ongoing ) {
772+ refill_from_paging_ongoing = true;
773+
774+ /* ensure enough space to refill 4K frames without frame array allocation */
775+ if (total_free_frames < MIN_NOREFILL_FREE_FRAMES_THRESHOLD )
776+ new_frames_array_nolock ();
777+ /* if this fails, increase MIN_NUM_4K_FRAMES to allow for multiple array refills
778+ */
779+ BUG_ON (total_free_frames < MIN_NOREFILL_FREE_FRAMES_THRESHOLD );
780+
781+ /* refill the 4K frames */
782+ try_create_4k_frames ();
783+
784+ refill_from_paging_ongoing = false;
785+ }
786+
787+ spin_unlock (& priority_lock );
788+ }
0 commit comments