On 24 May 2022, at 16:23, Andrew Morton wrote: > On Tue, 24 May 2022 15:47:56 -0400 Zi Yan <zi.yan@xxxxxxxx> wrote: > >> From: Zi Yan <ziy@xxxxxxxxxx> >> >> In isolate_single_pageblock() called by start_isolate_page_range(), >> there are some pageblock isolation issues causing a potential >> infinite loop when isolating a page range. This is reported by Qian Cai. >> >> 1. the pageblock was isolated by just changing pageblock migratetype >> without checking unmovable pages. Calling set_migratetype_isolate() to >> isolate pageblock properly. >> 2. an off-by-one error caused migrating pages unnecessarily, since the page >> is not crossing pageblock boundary. >> 3. migrating a compound page across pageblock boundary then splitting the >> free page later has a small race window that the free page might be >> allocated again, so that the code will try again, causing an potential >> infinite loop. Temporarily set the to-be-migrated page's pageblock to >> MIGRATE_ISOLATE to prevent that and bail out early if no free page is >> found after page migration. >> >> An additional fix to split_free_page() aims to avoid crashing in >> __free_one_page(). When the free page is split at the specified >> split_pfn_offset, free_page_order should check both the first bit of >> free_page_pfn and the last bit of split_pfn_offset and use the smaller one. >> For example, if free_page_pfn=0x10000, split_pfn_offset=0xc000, >> free_page_order should first be 0x8000 then 0x4000, instead of 0x4000 then >> 0x8000, which the original algorithm did. >> >> ... >> >> --- a/mm/page_alloc.c >> +++ b/mm/page_alloc.c >> @@ -1114,13 +1114,16 @@ void split_free_page(struct page *free_page, >> unsigned long flags; >> int free_page_order; >> >> + if (split_pfn_offset == 0) >> + return; >> + >> spin_lock_irqsave(&zone->lock, flags); >> del_page_from_free_list(free_page, zone, order); >> for (pfn = free_page_pfn; >> pfn < free_page_pfn + (1UL << order);) { >> int mt = get_pfnblock_migratetype(pfn_to_page(pfn), pfn); >> >> - free_page_order = ffs(split_pfn_offset) - 1; >> + free_page_order = min(pfn ? __ffs(pfn) : order, __fls(split_pfn_offset)); > > Why is it testing the zeroness of `pfn' here? Can pfn==0 even happen? > If so, it's a legitimate value so why does it get special-cased? __ffs() and __fls() are undefined if no bit exists, based on their comments. I checked both pfn and split_pfn_offset against 0 just in case, even if pfn most likely is not going to be 0. -- Best Regards, Yan, Zi
Attachment:
signature.asc
Description: OpenPGP digital signature