From: Zi Yan <ziy@nvidia.com>
Hi all,
This patchset tries to remove the MAX_ORDER - 1 alignment requirement for CMA
and alloc_contig_range(). It prepares for my upcoming changes to make MAX_ORDER
adjustable at boot time[1].
The MAX_ORDER - 1 alignment requirement comes from that alloc_contig_range()
isolates pageblocks to remove free memory from buddy allocator but isolating
only a subset of pageblocks within a page spanning across multiple pageblocks
causes free page accounting issues. Isolated page might not be put into the
right free list, since the code assumes the migratetype of the first pageblock
as the whole free page migratetype. This is based on the discussion at [2].
To remove the requirement, this patchset:
1. still isolates pageblocks at MAX_ORDER - 1 granularity;
2. but saves the pageblock migratetypes outside the specified range of
alloc_contig_range() and restores them after all pages within the range
become free after __alloc_contig_migrate_range();
3. splits free pages spanning multiple pageblocks at the beginning and the end
of the range and puts the split pages to the right migratetype free lists
based on the pageblock migratetypes;
4. returns pages not in the range as it did before this patch.
Isolation needs to happen at MAX_ORDER - 1 granularity, because otherwise
1) extra code is needed to detect pages (free, PageHuge, THP, or PageCompound)
to make sure all pageblocks belonging to a single page are isolated together
and later pageblocks outside the range need to have their migratetypes restored;
or 2) extra logic will need to be added during page free time to split a free
page with multi-migratetype pageblocks.
Two optimizations might come later:
1. only check unmovable pages within the range instead of MAX_ORDER - 1 aligned
range during isolation to increase successful rate of alloc_contig_range().
2. make MIGRATE_ISOLATE a separate bit to avoid saving and restoring existing
migratetypes before and after isolation respectively.
Feel free to give comments and suggestions. Thanks.
[1] https://lore.kernel.org/linux-mm/20210805190253.2795604-1-zi.yan@sent.com/
[2] https://lore.kernel.org/linux-mm/d19fb078-cb9b-f60f-e310-fdeea1b947d2@redhat.com/
Zi Yan (7):
mm: page_alloc: avoid merging non-fallbackable pageblocks with others.
mm: compaction: handle non-lru compound pages properly in
isolate_migratepages_block().
mm: migrate: allocate the right size of non hugetlb or THP compound
pages.
mm: make alloc_contig_range work at pageblock granularity
mm: cma: use pageblock_order as the single alignment
drivers: virtio_mem: use pageblock size as the minimum virtio_mem
size.
arch: powerpc: adjust fadump alignment to be pageblock aligned.
arch/powerpc/include/asm/fadump-internal.h | 4 +-
drivers/virtio/virtio_mem.c | 6 +-
include/linux/mmzone.h | 11 +-
kernel/dma/contiguous.c | 2 +-
mm/cma.c | 6 +-
mm/compaction.c | 10 +-
mm/migrate.c | 8 +-
mm/page_alloc.c | 203 +++++++++++++++++----
8 files changed, 196 insertions(+), 54 deletions(-)
--
2.33.0
From: Zi Yan <ziy@nvidia.com>
In isolate_migratepages_block(), a !PageLRU tail page can be encountered
when the page is larger than a pageblock. Use compound head page for the
checks inside and skip the entire compound page when isolation succeeds.
Signed-off-by: Zi Yan <ziy@nvidia.com>
---
mm/compaction.c | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)
From: Zi Yan <ziy@nvidia.com>
This is done in addition to MIGRATE_ISOLATE pageblock merge avoidance.
It prepares for the upcoming removal of the MAX_ORDER-1 alignment
requirement for CMA and alloc_contig_range().
MIGRARTE_HIGHATOMIC should not merge with other migratetypes like
MIGRATE_ISOLATE and MIGRARTE_CMA[1], so this commit prevents that too.
Also add MIGRARTE_HIGHATOMIC to fallbacks array for completeness.
[1] https://lore.kernel.org/linux-mm/20211130100853.GP3366@techsingularity.net/
Signed-off-by: Zi Yan <ziy@nvidia.com>
---
include/linux/mmzone.h | 6 ++++++
mm/page_alloc.c | 28 ++++++++++++++++++----------
2 files changed, 24 insertions(+), 10 deletions(-)
@@ -1041,6 +1041,12 @@ buddy_merge_likely(unsigned long pfn, unsigned long buddy_pfn,returnpage_is_buddy(higher_page,higher_buddy,order+1);}+staticinlineboolhas_non_fallback_pageblock(structzone*zone)+{+returnhas_isolate_pageblock(zone)||zone_cma_pages(zone)!=0||+zone->nr_reserved_highatomic!=0;+}+/**Freeingfunctionforabuddysystemallocator.*
@@ -1116,14 +1122,15 @@ static inline void __free_one_page(struct page *page,}if(order<MAX_ORDER-1){/* If we are here, it means order is >= pageblock_order.-*Wewanttopreventmergebetweenfreepagesonisolate-*pageblockandnormalpageblock.Withoutthis,pageblock-*isolationcouldcauseincorrectfreepageorCMAaccounting.+*Wewanttopreventmergebetweenfreepagesonpageblock+*withoutfallbacksandnormalpageblock.Withoutthis,+*pageblockisolationcouldcauseincorrectfreepageorCMA+*accountingorHIGHATOMICaccounting.**Wedon'twanttohitthiscodeforthemorefrequent*low-ordermerging.*/-if(unlikely(has_isolate_pageblock(zone))){+if(unlikely(has_non_fallback_pageblock(zone))){intbuddy_mt;buddy_pfn=__find_buddy_pfn(pfn,order);
@@ -2483,6 +2490,7 @@ static int fallbacks[MIGRATE_TYPES][3] = {[MIGRATE_UNMOVABLE]={MIGRATE_RECLAIMABLE,MIGRATE_MOVABLE,MIGRATE_TYPES},[MIGRATE_MOVABLE]={MIGRATE_RECLAIMABLE,MIGRATE_UNMOVABLE,MIGRATE_TYPES},[MIGRATE_RECLAIMABLE]={MIGRATE_UNMOVABLE,MIGRATE_MOVABLE,MIGRATE_TYPES},+[MIGRATE_HIGHATOMIC]={MIGRATE_TYPES},/* Never used */#ifdef CONFIG_CMA[MIGRATE_CMA]={MIGRATE_TYPES},/* Never used */#endif
@@ -2794,8 +2802,8 @@ static void reserve_highatomic_pageblock(struct page *page, struct zone *zone,/* Yoink! */mt=get_pageblock_migratetype(page);-if(!is_migrate_highatomic(mt)&&!is_migrate_isolate(mt)-&&!is_migrate_cma(mt)){+/* Only reserve normal pageblock */+if(migratetype_has_fallback(mt)){zone->nr_reserved_highatomic+=pageblock_nr_pages;set_pageblock_migratetype(page,MIGRATE_HIGHATOMIC);move_freepages_block(zone,page,MIGRATE_HIGHATOMIC,NULL);
@@ -3544,8 +3552,8 @@ int __isolate_free_page(struct page *page, unsigned int order)structpage*endpage=page+(1<<order)-1;for(;page<endpage;page+=pageblock_nr_pages){intmt=get_pageblock_migratetype(page);-if(!is_migrate_isolate(mt)&&!is_migrate_cma(mt)-&&!is_migrate_highatomic(mt))+/* Only change normal pageblock */+if(migratetype_has_fallback(mt))set_pageblock_migratetype(page,MIGRATE_MOVABLE);}
From: Zi Yan <ziy@nvidia.com>
This is done in addition to MIGRATE_ISOLATE pageblock merge avoidance.
It prepares for the upcoming removal of the MAX_ORDER-1 alignment
requirement for CMA and alloc_contig_range().
MIGRARTE_HIGHATOMIC should not merge with other migratetypes like
MIGRATE_ISOLATE and MIGRARTE_CMA[1], so this commit prevents that too.
Also add MIGRARTE_HIGHATOMIC to fallbacks array for completeness.
[1] https://lore.kernel.org/linux-mm/20211130100853.GP3366@techsingularity.net/
Signed-off-by: Zi Yan <ziy@nvidia.com>
---
include/linux/mmzone.h | 6 ++++++
mm/page_alloc.c | 28 ++++++++++++++++++----------
2 files changed, 24 insertions(+), 10 deletions(-)
@@ -83,6 +83,12 @@ static inline bool is_migrate_movable(int mt)returnis_migrate_cma(mt)||mt==MIGRATE_MOVABLE;}+/* See fallbacks[MIGRATE_TYPES][3] in page_alloc.c */+staticinlineboolmigratetype_has_fallback(intmt)+{+returnmt<MIGRATE_PCPTYPES;+}+
I would suggest spliting the patch into 2 parts. The first part: no
functioning change, just introduce migratetype_has_fallback()
and replace where it applys to.
quoted hunk
#define for_each_migratetype_order(order, type) \
for (order = 0; order < MAX_ORDER; order++) \
for (type = 0; type < MIGRATE_TYPES; type++)
@@ -1041,6 +1041,12 @@ buddy_merge_likely(unsigned long pfn, unsigned long buddy_pfn,returnpage_is_buddy(higher_page,higher_buddy,order+1);}+staticinlineboolhas_non_fallback_pageblock(structzone*zone)+{+returnhas_isolate_pageblock(zone)||zone_cma_pages(zone)!=0||+zone->nr_reserved_highatomic!=0;
Make zone->nr_reserved_highatomic != 0 a helper as zone_cma_pages()?
quoted hunk
+}
+
/*
* Freeing function for a buddy system allocator.
*
@@ -1116,14 +1122,15 @@ static inline void __free_one_page(struct page *page, } if (order < MAX_ORDER - 1) { /* If we are here, it means order is >= pageblock_order.- * We want to prevent merge between freepages on isolate- * pageblock and normal pageblock. Without this, pageblock- * isolation could cause incorrect freepage or CMA accounting.+ * We want to prevent merge between freepages on pageblock+ * without fallbacks and normal pageblock. Without this,+ * pageblock isolation could cause incorrect freepage or CMA+ * accounting or HIGHATOMIC accounting. * * We don't want to hit this code for the more frequent * low-order merging. */- if (unlikely(has_isolate_pageblock(zone))) {+ if (unlikely(has_non_fallback_pageblock(zone))) {
I'm not familiar with the code details, just wondering if this change
would has side effects on cma
pageblock merging as it the condition stronger?
Thanks,
Eric
quoted hunk
int buddy_mt;
buddy_pfn = __find_buddy_pfn(pfn, order);
From: Zi Yan <ziy@nvidia.com> Date: 2021-12-10 15:40:15
Hi Eric,
Thanks for looking into my patch.
On 10 Dec 2021, at 2:43, Eric Ren wrote:
Hi,
On 2021/12/10 07:04, Zi Yan wrote:
quoted
From: Zi Yan <ziy@nvidia.com>
This is done in addition to MIGRATE_ISOLATE pageblock merge avoidance.
It prepares for the upcoming removal of the MAX_ORDER-1 alignment
requirement for CMA and alloc_contig_range().
MIGRARTE_HIGHATOMIC should not merge with other migratetypes like
MIGRATE_ISOLATE and MIGRARTE_CMA[1], so this commit prevents that too.
Also add MIGRARTE_HIGHATOMIC to fallbacks array for completeness.
[1] https://lore.kernel.org/linux-mm/20211130100853.GP3366@techsingularity.net/
Signed-off-by: Zi Yan <ziy@nvidia.com>
---
include/linux/mmzone.h | 6 ++++++
mm/page_alloc.c | 28 ++++++++++++++++++----------
2 files changed, 24 insertions(+), 10 deletions(-)
@@ -83,6 +83,12 @@ static inline bool is_migrate_movable(int mt)returnis_migrate_cma(mt)||mt==MIGRATE_MOVABLE;}+/* See fallbacks[MIGRATE_TYPES][3] in page_alloc.c */+staticinlineboolmigratetype_has_fallback(intmt)+{+returnmt<MIGRATE_PCPTYPES;+}+
I would suggest spliting the patch into 2 parts. The first part: no functioning change, just introduce migratetype_has_fallback()
and replace where it applys to.
OK. I can do that.
quoted
#define for_each_migratetype_order(order, type) \
for (order = 0; order < MAX_ORDER; order++) \
for (type = 0; type < MIGRATE_TYPES; type++)
@@ -1041,6 +1041,12 @@ buddy_merge_likely(unsigned long pfn, unsigned long buddy_pfn,returnpage_is_buddy(higher_page,higher_buddy,order+1);}+staticinlineboolhas_non_fallback_pageblock(structzone*zone)+{+returnhas_isolate_pageblock(zone)||zone_cma_pages(zone)!=0||+zone->nr_reserved_highatomic!=0;
Make zone->nr_reserved_highatomic != 0 a helper as zone_cma_pages()?
I am not sure. We have zone_cma_pages() because when CMA is not enabled, 0 can be
simply returned. But MIGRATE_HIGHATOMIC is always present, then an helper function
is not that useful.
quoted
+}
+
/*
* Freeing function for a buddy system allocator.
*
@@ -1116,14 +1122,15 @@ static inline void __free_one_page(struct page *page, } if (order < MAX_ORDER - 1) { /* If we are here, it means order is >= pageblock_order.- * We want to prevent merge between freepages on isolate- * pageblock and normal pageblock. Without this, pageblock- * isolation could cause incorrect freepage or CMA accounting.+ * We want to prevent merge between freepages on pageblock+ * without fallbacks and normal pageblock. Without this,+ * pageblock isolation could cause incorrect freepage or CMA+ * accounting or HIGHATOMIC accounting. * * We don't want to hit this code for the more frequent * low-order merging. */- if (unlikely(has_isolate_pageblock(zone))) {+ if (unlikely(has_non_fallback_pageblock(zone))) {
I'm not familiar with the code details, just wondering if this change would has side effects on cma
pageblock merging as it the condition stronger?
No impact on cma pageblock merging, AFAICT.
Thanks,
Eric
quoted
int buddy_mt;
buddy_pfn = __find_buddy_pfn(pfn, order);
From: Zi Yan <ziy@nvidia.com>
alloc_contig_range() worked at MAX_ORDER-1 granularity to avoid merging
pageblocks with different migratetypes. It might unnecessarily convert
extra pageblocks at the beginning and at the end of the range. Change
alloc_contig_range() to work at pageblock granularity.
It is done by restoring pageblock types and split >pageblock_order free
pages after isolating at MAX_ORDER-1 granularity and migrating pages
away at pageblock granularity. The reason for this process is that
during isolation, some pages, either free or in-use, might have >pageblock
sizes and isolating part of them can cause free accounting issues.
Restoring the migratetypes of the pageblocks not in the interesting
range later is much easier.
Signed-off-by: Zi Yan <ziy@nvidia.com>
---
mm/page_alloc.c | 169 ++++++++++++++++++++++++++++++++++++++++++------
1 file changed, 149 insertions(+), 20 deletions(-)
@@ -9071,6 +9071,52 @@ static int __alloc_contig_migrate_range(struct compact_control *cc,return0;}+staticinlineintsave_migratetypes(unsignedchar*migratetypes,+unsignedlongstart_pfn,unsignedlongend_pfn)+{+unsignedlongpfn=start_pfn;+intnum=0;++while(pfn<end_pfn){+migratetypes[num]=get_pageblock_migratetype(pfn_to_page(pfn));+num++;+pfn+=pageblock_nr_pages;+}+returnnum;+}++staticinlineintrestore_migratetypes(unsignedchar*migratetypes,+unsignedlongstart_pfn,unsignedlongend_pfn)+{+unsignedlongpfn=start_pfn;+intnum=0;++while(pfn<end_pfn){+set_pageblock_migratetype(pfn_to_page(pfn),migratetypes[num]);+num++;+pfn+=pageblock_nr_pages;+}+returnnum;+}++staticinlinevoidsplit_free_page_into_pageblocks(structpage*free_page,+intorder,structzone*zone)+{+unsignedlongpfn;++spin_lock(&zone->lock);+del_page_from_free_list(free_page,zone,order);+for(pfn=page_to_pfn(free_page);+pfn<page_to_pfn(free_page)+(1UL<<order);+pfn+=pageblock_nr_pages){+intmt=get_pfnblock_migratetype(pfn_to_page(pfn),pfn);++__free_one_page(pfn_to_page(pfn),pfn,zone,pageblock_order,+mt,FPI_NONE);+}+spin_unlock(&zone->lock);+}+/***alloc_contig_range()--triestoallocategivenrangeofpages*@start:startPFNtoallocate
@@ -9096,8 +9142,15 @@ int alloc_contig_range(unsigned long start, unsigned long end,unsignedmigratetype,gfp_tgfp_mask){unsignedlongouter_start,outer_end;+unsignedlongisolate_start=pfn_max_align_down(start);+unsignedlongisolate_end=pfn_max_align_up(end);+unsignedlongalloc_start=ALIGN_DOWN(start,pageblock_nr_pages);+unsignedlongalloc_end=ALIGN(end,pageblock_nr_pages);+unsignedlongnum_pageblock_to_save;unsignedintorder;intret=0;+unsignedchar*saved_mt;+intnum;structcompact_controlcc={.nr_migratepages=0,
@@ -9111,11 +9164,30 @@ int alloc_contig_range(unsigned long start, unsigned long end,};INIT_LIST_HEAD(&cc.migratepages);+/*+*TODO:makeMIGRATE_ISOLATEastandalonebittoavoidoverwriting+*theexitingmigratetype.Then,wewillnotneedthesaveandrestore+*processhere.+*/++/* Save the migratepages of the pageblocks before start and after end */+num_pageblock_to_save=(alloc_start-isolate_start)/pageblock_nr_pages++(isolate_end-alloc_end)/pageblock_nr_pages;+saved_mt=+kmalloc_array(num_pageblock_to_save,+sizeof(unsignedchar),GFP_KERNEL);+if(!saved_mt)+return-ENOMEM;++num=save_migratetypes(saved_mt,isolate_start,alloc_start);++num=save_migratetypes(&saved_mt[num],alloc_end,isolate_end);+/**Whatwedohereiswemarkallpageblocksinrangeas*MIGRATE_ISOLATE.Becausepageblockandmaxorderpagesmay*havedifferentsizes,andduetothewaypageallocator-*work,wealigntherangetobiggestofthetwopagesso+*work,wealigntheisolationrangetobiggestofthetwoso*thatpageallocatorwon'ttrytomergebuddiesfrom*differentpageblocksandchangeMIGRATE_ISOLATEtosome*othermigrationtype.
@@ -9125,6 +9197,20 @@ int alloc_contig_range(unsigned long start, unsigned long end,*weareinterestedin).Thiswillputallthepagesin*rangebacktopageallocatorasMIGRATE_ISOLATE.*+*Afterwards,werestorethemigratetypesofthepageblocksnot+*inrange,splitfreepagesspanningoutsidetherange,+*andputsplitfreepages(atpageblock_order)totheright+*migratetypelist.+*+*NOTE:theaboveapproachisusedbecauseitcancausefree+*pageaccountingissuesduringisolation,ifapage,either+*freeorin-use,containsmultiplepageblocksandweonly+*isolateasubsetofthem.Forexample,ifonlythesecond+*pageblockisisolatedfromapagewith2pageblocks,after+*thepageisfree,itwillbeputinthefirstpageblock+*migratetypelistinsteadofhaving2pageblocksintwo+*separatemigratetypelists.+**Whenthisisdone,wetakethepagesinrangefrompage*allocatorremovingthemfromthebuddysystem.Thisway*pageallocatorwillneverconsiderusingthem.
@@ -9135,10 +9221,9 @@ int alloc_contig_range(unsigned long start, unsigned long end,*putbacktopageallocatorsothatbuddycanusethem.*/-ret=start_isolate_page_range(pfn_max_align_down(start),-pfn_max_align_up(end),migratetype,0);+ret=start_isolate_page_range(isolate_start,isolate_end,migratetype,0);if(ret)-returnret;+gotodone;drain_all_pages(cc.zone);
@@ -9174,6 +9259,19 @@ int alloc_contig_range(unsigned long start, unsigned long end,*isolatedthustheywon'tgetremovedfrombuddy.*/+/*+*Restoremigratetypesofpageblocksoutside[start,end)+*TODO:removeitwhenMIGRATE_ISOLATEbecomesastandalonebit+*/++num=restore_migratetypes(saved_mt,isolate_start,alloc_start);++num=restore_migratetypes(&saved_mt[num],alloc_end,isolate_end);++/*+*Splitfreepagespanning[isolate_start,alloc_start)andputthe+*pageblocksintherightmigratetypelists.+*/order=0;outer_start=start;while(!PageBuddy(pfn_to_page(outer_start))){
@@ -9188,37 +9286,68 @@ int alloc_contig_range(unsigned long start, unsigned long end,order=buddy_order(pfn_to_page(outer_start));/*-*outer_startpagecouldbesmallorderbuddypageand-*itdoesn'tincludestartpage.Adjustouter_start-*inthiscasetoreportfailedpageproperly-*ontracepointintest_pages_isolated()+*splitthefreepagehasstartpageandputthepageblocks+*intherightmigratetypelist*/-if(outer_start+(1UL<<order)<=start)-outer_start=start;+if(outer_start+(1UL<<order)>start){+structpage*free_page=pfn_to_page(outer_start);++split_free_page_into_pageblocks(free_page,order,cc.zone);+}+}++/*+*Splitfreepagespanning[alloc_end,isolate_end)andputthe+*pageblocksintherightmigratetypelist+*/+order=0;+outer_end=end;+while(!PageBuddy(pfn_to_page(outer_end))){+if(++order>=MAX_ORDER){+outer_end=end;+break;+}+outer_end&=~0UL<<order;+}++if(outer_end!=end){+order=buddy_order(pfn_to_page(outer_end));++/*+*splitthefreepagehasstartpageandputthepageblocks+*intherightmigratetypelist+*/+VM_BUG_ON(outer_end+(1UL<<order)<=end);+{+structpage*free_page=pfn_to_page(outer_end);++split_free_page_into_pageblocks(free_page,order,cc.zone);+}}/* Make sure the range is really isolated. */-if(test_pages_isolated(outer_start,end,0)){+if(test_pages_isolated(alloc_start,alloc_end,0)){ret=-EBUSY;gotodone;}/* Grab isolated pages from freelists. */-outer_end=isolate_freepages_range(&cc,outer_start,end);+outer_end=isolate_freepages_range(&cc,alloc_start,alloc_end);if(!outer_end){ret=-EBUSY;gotodone;}/* Free head and tail (if any) */-if(start!=outer_start)-free_contig_range(outer_start,start-outer_start);-if(end!=outer_end)-free_contig_range(end,outer_end-end);+if(start!=alloc_start)+free_contig_range(alloc_start,start-alloc_start);+if(end!=alloc_end)+free_contig_range(end,alloc_end-end);done:-undo_isolate_page_range(pfn_max_align_down(start),-pfn_max_align_up(end),migratetype);+kfree(saved_mt);+undo_isolate_page_range(alloc_start,+alloc_end,migratetype);returnret;}EXPORT_SYMBOL(alloc_contig_range);
From: Zi Yan <ziy@nvidia.com>
alloc_contig_range() worked at MAX_ORDER-1 granularity to avoid merging
pageblocks with different migratetypes. It might unnecessarily convert
extra pageblocks at the beginning and at the end of the range. Change
alloc_contig_range() to work at pageblock granularity.
It is done by restoring pageblock types and split >pageblock_order free
pages after isolating at MAX_ORDER-1 granularity and migrating pages
away at pageblock granularity. The reason for this process is that
during isolation, some pages, either free or in-use, might have >pageblock
sizes and isolating part of them can cause free accounting issues.
Could you elaborate on how the acconting issue would happen in details?
quoted hunk
Restoring the migratetypes of the pageblocks not in the interesting
range later is much easier.
Signed-off-by: Zi Yan <ziy@nvidia.com>
---
mm/page_alloc.c | 169 ++++++++++++++++++++++++++++++++++++++++++------
1 file changed, 149 insertions(+), 20 deletions(-)
@@ -9071,6 +9071,52 @@ static int __alloc_contig_migrate_range(struct compact_control *cc,return0;}+staticinlineintsave_migratetypes(unsignedchar*migratetypes,+unsignedlongstart_pfn,unsignedlongend_pfn)+{+unsignedlongpfn=start_pfn;+intnum=0;++while(pfn<end_pfn){+migratetypes[num]=get_pageblock_migratetype(pfn_to_page(pfn));+num++;+pfn+=pageblock_nr_pages;+}+returnnum;+}++staticinlineintrestore_migratetypes(unsignedchar*migratetypes,+unsignedlongstart_pfn,unsignedlongend_pfn)+{+unsignedlongpfn=start_pfn;+intnum=0;++while(pfn<end_pfn){+set_pageblock_migratetype(pfn_to_page(pfn),migratetypes[num]);+num++;+pfn+=pageblock_nr_pages;+}+returnnum;+}++staticinlinevoidsplit_free_page_into_pageblocks(structpage*free_page,+intorder,structzone*zone)+{+unsignedlongpfn;++spin_lock(&zone->lock);+del_page_from_free_list(free_page,zone,order);+for(pfn=page_to_pfn(free_page);+pfn<page_to_pfn(free_page)+(1UL<<order);+pfn+=pageblock_nr_pages){+intmt=get_pfnblock_migratetype(pfn_to_page(pfn),pfn);++__free_one_page(pfn_to_page(pfn),pfn,zone,pageblock_order,+mt,FPI_NONE);+}+spin_unlock(&zone->lock);+}+/***alloc_contig_range()--triestoallocategivenrangeofpages*@start:startPFNtoallocate
@@ -9096,8 +9142,15 @@ int alloc_contig_range(unsigned long start, unsigned long end,unsignedmigratetype,gfp_tgfp_mask){unsignedlongouter_start,outer_end;+unsignedlongisolate_start=pfn_max_align_down(start);+unsignedlongisolate_end=pfn_max_align_up(end);+unsignedlongalloc_start=ALIGN_DOWN(start,pageblock_nr_pages);+unsignedlongalloc_end=ALIGN(end,pageblock_nr_pages);
What is the differecence between isolate_* and alloc_*?
quoted hunk
+ unsigned long num_pageblock_to_save;
unsigned int order;
int ret = 0;
+ unsigned char *saved_mt;
+ int num;
struct compact_control cc = {
.nr_migratepages = 0,
@@ -9111,11 +9164,30 @@ int alloc_contig_range(unsigned long start, unsigned long end, }; INIT_LIST_HEAD(&cc.migratepages);+ /*+ * TODO: make MIGRATE_ISOLATE a standalone bit to avoid overwriting+ * the exiting migratetype. Then, we will not need the save and restore+ * process here.+ */++ /* Save the migratepages of the pageblocks before start and after end */+ num_pageblock_to_save = (alloc_start - isolate_start) / pageblock_nr_pages+ + (isolate_end - alloc_end) / pageblock_nr_pages;+ saved_mt =+ kmalloc_array(num_pageblock_to_save,+ sizeof(unsigned char), GFP_KERNEL);+ if (!saved_mt)+ return -ENOMEM;++ num = save_migratetypes(saved_mt, isolate_start, alloc_start);++ num = save_migratetypes(&saved_mt[num], alloc_end, isolate_end);
the two lines above looks confusing to figure out the logic. Could you
help explain a bit?
Thanks,
Eric
quoted hunk
+
/*
* What we do here is we mark all pageblocks in range as
* MIGRATE_ISOLATE. Because pageblock and max order pages may
* have different sizes, and due to the way page allocator
- * work, we align the range to biggest of the two pages so
+ * work, we align the isolation range to biggest of the two so
* that page allocator won't try to merge buddies from
* different pageblocks and change MIGRATE_ISOLATE to some
* other migration type.
@@ -9125,6 +9197,20 @@ int alloc_contig_range(unsigned long start, unsigned long end, * we are interested in). This will put all the pages in * range back to page allocator as MIGRATE_ISOLATE. *+ * Afterwards, we restore the migratetypes of the pageblocks not+ * in range, split free pages spanning outside the range,+ * and put split free pages (at pageblock_order) to the right+ * migratetype list.+ *+ * NOTE: the above approach is used because it can cause free+ * page accounting issues during isolation, if a page, either+ * free or in-use, contains multiple pageblocks and we only+ * isolate a subset of them. For example, if only the second+ * pageblock is isolated from a page with 2 pageblocks, after+ * the page is free, it will be put in the first pageblock+ * migratetype list instead of having 2 pageblocks in two+ * separate migratetype lists.+ * * When this is done, we take the pages in range from page * allocator removing them from the buddy system. This way * page allocator will never consider using them.
@@ -9135,10 +9221,9 @@ int alloc_contig_range(unsigned long start, unsigned long end, * put back to page allocator so that buddy can use them. */- ret = start_isolate_page_range(pfn_max_align_down(start),- pfn_max_align_up(end), migratetype, 0);+ ret = start_isolate_page_range(isolate_start, isolate_end, migratetype, 0); if (ret)- return ret;+ goto done; drain_all_pages(cc.zone);
@@ -9174,6 +9259,19 @@ int alloc_contig_range(unsigned long start, unsigned long end, * isolated thus they won't get removed from buddy. */+ /*+ * Restore migratetypes of pageblocks outside [start, end)+ * TODO: remove it when MIGRATE_ISOLATE becomes a standalone bit+ */++ num = restore_migratetypes(saved_mt, isolate_start, alloc_start);++ num = restore_migratetypes(&saved_mt[num], alloc_end, isolate_end);++ /*+ * Split free page spanning [isolate_start, alloc_start) and put the+ * pageblocks in the right migratetype lists.+ */ order = 0; outer_start = start; while (!PageBuddy(pfn_to_page(outer_start))) {
@@ -9188,37 +9286,68 @@ int alloc_contig_range(unsigned long start, unsigned long end, order = buddy_order(pfn_to_page(outer_start)); /*- * outer_start page could be small order buddy page and- * it doesn't include start page. Adjust outer_start- * in this case to report failed page properly- * on tracepoint in test_pages_isolated()+ * split the free page has start page and put the pageblocks+ * in the right migratetype list */- if (outer_start + (1UL << order) <= start)- outer_start = start;+ if (outer_start + (1UL << order) > start) {+ struct page *free_page = pfn_to_page(outer_start);++ split_free_page_into_pageblocks(free_page, order, cc.zone);+ }+ }++ /*+ * Split free page spanning [alloc_end, isolate_end) and put the+ * pageblocks in the right migratetype list+ */+ order = 0;+ outer_end = end;+ while (!PageBuddy(pfn_to_page(outer_end))) {+ if (++order >= MAX_ORDER) {+ outer_end = end;+ break;+ }+ outer_end &= ~0UL << order;+ }++ if (outer_end != end) {+ order = buddy_order(pfn_to_page(outer_end));++ /*+ * split the free page has start page and put the pageblocks+ * in the right migratetype list+ */+ VM_BUG_ON(outer_end + (1UL << order) <= end);+ {+ struct page *free_page = pfn_to_page(outer_end);++ split_free_page_into_pageblocks(free_page, order, cc.zone);+ } } /* Make sure the range is really isolated. */- if (test_pages_isolated(outer_start, end, 0)) {+ if (test_pages_isolated(alloc_start, alloc_end, 0)) { ret = -EBUSY; goto done; } /* Grab isolated pages from freelists. */- outer_end = isolate_freepages_range(&cc, outer_start, end);+ outer_end = isolate_freepages_range(&cc, alloc_start, alloc_end); if (!outer_end) { ret = -EBUSY; goto done; } /* Free head and tail (if any) */- if (start != outer_start)- free_contig_range(outer_start, start - outer_start);- if (end != outer_end)- free_contig_range(end, outer_end - end);+ if (start != alloc_start)+ free_contig_range(alloc_start, start - alloc_start);+ if (end != alloc_end)+ free_contig_range(end, alloc_end - end); done:- undo_isolate_page_range(pfn_max_align_down(start),- pfn_max_align_up(end), migratetype);+ kfree(saved_mt);+ undo_isolate_page_range(alloc_start,+ alloc_end, migratetype); return ret; } EXPORT_SYMBOL(alloc_contig_range);
From: Zi Yan <ziy@nvidia.com>
alloc_migration_target() is used by alloc_contig_range() and non-LRU
movable compound pages can be migrated. Current code does not allocate the
right page size for such pages. Check THP precisely using
is_transparent_huge() and add allocation support for non-LRU compound
pages.
Signed-off-by: Zi Yan <ziy@nvidia.com>
---
mm/migrate.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
From: Zi Yan <ziy@nvidia.com>
alloc_migration_target() is used by alloc_contig_range() and non-LRU
movable compound pages can be migrated. Current code does not allocate the
right page size for such pages. Check THP precisely using
is_transparent_huge() and add allocation support for non-LRU compound
pages.
Could you elaborate on why the current code doesn't get the right size?
how this patch fixes it.
The description sounds like it's an existing bug, if so, the patch
subject should be changed to
"Fixes ..."?
quoted hunk
Signed-off-by: Zi Yan <ziy@nvidia.com>
---
mm/migrate.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
From: Zi Yan <ziy@nvidia.com> Date: 2021-12-10 15:49:23
On 10 Dec 2021, at 2:53, Eric Ren wrote:
Hi,
On 2021/12/10 07:04, Zi Yan wrote:
quoted
From: Zi Yan <ziy@nvidia.com>
alloc_migration_target() is used by alloc_contig_range() and non-LRU
movable compound pages can be migrated. Current code does not allocate the
right page size for such pages. Check THP precisely using
is_transparent_huge() and add allocation support for non-LRU compound
pages.
Could you elaborate on why the current code doesn't get the right size? how this patch fixes it.
The current code only check PageHuge() and PageTransHuge(). Non-LRU compound
pages will be regarded as PageTransHuge() and an order-9 page is always allocated
regardless of the actual page order. This patch makes the exact check for
THPs using is_transparent_huge() instead of PageTransHuge() and checks PageCompound()
after PageHuge() and is_transparent_huge() for non-LRU compound pages.
The description sounds like it's an existing bug, if so, the patch subject should be changed to
"Fixes ..."?
I have not seen any related bug report.
quoted
Signed-off-by: Zi Yan <ziy@nvidia.com>
---
mm/migrate.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
On Fri, Dec 10, 2021 at 8:08 AM Zi Yan [off-list ref] wrote:
On 10 Dec 2021, at 2:53, Eric Ren wrote:
quoted
Hi,
On 2021/12/10 07:04, Zi Yan wrote:
quoted
From: Zi Yan <ziy@nvidia.com>
alloc_migration_target() is used by alloc_contig_range() and non-LRU
movable compound pages can be migrated. Current code does not allocate the
right page size for such pages. Check THP precisely using
is_transparent_huge() and add allocation support for non-LRU compound
pages.
Could you elaborate on why the current code doesn't get the right size? how this patch fixes it.
The current code only check PageHuge() and PageTransHuge(). Non-LRU compound
pages will be regarded as PageTransHuge() and an order-9 page is always allocated
regardless of the actual page order. This patch makes the exact check for
THPs using is_transparent_huge() instead of PageTransHuge() and checks PageCompound()
after PageHuge() and is_transparent_huge() for non-LRU compound pages.
quoted
The description sounds like it's an existing bug, if so, the patch subject should be changed to
"Fixes ..."?
I have not seen any related bug report.
quoted
quoted
Signed-off-by: Zi Yan <ziy@nvidia.com>
---
mm/migrate.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
if (PageTransHuge(page)) { // just give more code context
...
quoted
gfp_mask |= GFP_TRANSHUGE;
order = HPAGE_PMD_ORDER;
order assigned here
quoted
}
+ if (PageCompound(page)) {
+ gfp_mask |= __GFP_COMP;
+ order = compound_order(page);
re-assinged again as THP is a compound page?
Ah, you are right. Will use else if instead. Thanks.
You don't have to use else if, you could just do:
if (PageCompound(page)) {
gfp_mask |= __GFP_COMP;
order = compound_order(page);
}
if (is_transparent_hugepage(page)) {
/* Manipulate THP specific gfp mask */
....
}
From: Zi Yan <ziy@nvidia.com>
Now alloc_contig_range() works at pageblock granularity. Change CMA
allocation, which uses alloc_contig_range(), to use pageblock_order
alignment.
Signed-off-by: Zi Yan <ziy@nvidia.com>
---
include/linux/mmzone.h | 5 +----
kernel/dma/contiguous.c | 2 +-
mm/cma.c | 6 ++----
mm/page_alloc.c | 6 +++---
4 files changed, 7 insertions(+), 12 deletions(-)
@@ -180,8 +180,7 @@ int __init cma_init_reserved_mem(phys_addr_t base, phys_addr_t size,return-EINVAL;/* ensure minimal alignment required by mm core */-alignment=PAGE_SIZE<<-max_t(unsignedlong,MAX_ORDER-1,pageblock_order);+alignment=PAGE_SIZE<<pageblock_order;/* alignment should be aligned with order_per_bit */if(!IS_ALIGNED(alignment>>PAGE_SHIFT,1<<order_per_bit))
@@ -268,8 +267,7 @@ int __init cma_declare_contiguous_nid(phys_addr_t base,*migratetypepagebypageallocator'sbuddyalgorithm.Inthecase,*youcouldn'tgetacontiguousmemory,whichisnotwhatwewant.*/-alignment=max(alignment,(phys_addr_t)PAGE_SIZE<<-max_t(unsignedlong,MAX_ORDER-1,pageblock_order));+alignment=max(alignment,(phys_addr_t)PAGE_SIZE<<pageblock_order);if(fixed&&base&(alignment-1)){ret=-EINVAL;pr_err("Region at %pa must be aligned to %pa bytes\n",
@@ -9243,7 +9243,7 @@ int alloc_contig_range(unsigned long start, unsigned long end,ret=0;/*-*Pagesfrom[start,end)arewithinaMAX_ORDER_NR_PAGES+*Pagesfrom[start,end)arewithinapageblock_nr_pages*alignedblocksthataremarkedasMIGRATE_ISOLATE.What's*more,allpagesin[start,end)arefreeinpageallocator.*Whatwearegoingtodoistoallocateallpagesfrom
From: Zi Yan <ziy@nvidia.com>
alloc_contig_range() now only needs to be aligned to pageblock_order,
drop virtio_mem size requirement that it needs to be the max of
pageblock_order and MAX_ORDER.
Signed-off-by: Zi Yan <ziy@nvidia.com>
---
drivers/virtio/virtio_mem.c | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
From: Zi Yan <ziy@nvidia.com>
Hi all,
This patchset tries to remove the MAX_ORDER - 1 alignment requirement for CMA
and alloc_contig_range(). It prepares for my upcoming changes to make MAX_ORDER
adjustable at boot time[1].
The MAX_ORDER - 1 alignment requirement comes from that alloc_contig_range()
isolates pageblocks to remove free memory from buddy allocator but isolating
only a subset of pageblocks within a page spanning across multiple pageblocks
causes free page accounting issues. Isolated page might not be put into the
right free list, since the code assumes the migratetype of the first pageblock
as the whole free page migratetype. This is based on the discussion at [2].
To remove the requirement, this patchset:
1. still isolates pageblocks at MAX_ORDER - 1 granularity;
Then, unplug fails if either pageblock of the MAX_ORDER - 1 page has
unmovable page, right?
Thanks,
Eric
2. but saves the pageblock migratetypes outside the specified range of
alloc_contig_range() and restores them after all pages within the range
become free after __alloc_contig_migrate_range();
3. splits free pages spanning multiple pageblocks at the beginning and the end
of the range and puts the split pages to the right migratetype free lists
based on the pageblock migratetypes;
4. returns pages not in the range as it did before this patch.
Isolation needs to happen at MAX_ORDER - 1 granularity, because otherwise
1) extra code is needed to detect pages (free, PageHuge, THP, or PageCompound)
to make sure all pageblocks belonging to a single page are isolated together
and later pageblocks outside the range need to have their migratetypes restored;
or 2) extra logic will need to be added during page free time to split a free
page with multi-migratetype pageblocks.
Two optimizations might come later:
1. only check unmovable pages within the range instead of MAX_ORDER - 1 aligned
range during isolation to increase successful rate of alloc_contig_range().
2. make MIGRATE_ISOLATE a separate bit to avoid saving and restoring existing
migratetypes before and after isolation respectively.
Feel free to give comments and suggestions. Thanks.
[1] https://lore.kernel.org/linux-mm/20210805190253.2795604-1-zi.yan@sent.com/
[2] https://lore.kernel.org/linux-mm/d19fb078-cb9b-f60f-e310-fdeea1b947d2@redhat.com/
Zi Yan (7):
mm: page_alloc: avoid merging non-fallbackable pageblocks with others.
mm: compaction: handle non-lru compound pages properly in
isolate_migratepages_block().
mm: migrate: allocate the right size of non hugetlb or THP compound
pages.
mm: make alloc_contig_range work at pageblock granularity
mm: cma: use pageblock_order as the single alignment
drivers: virtio_mem: use pageblock size as the minimum virtio_mem
size.
arch: powerpc: adjust fadump alignment to be pageblock aligned.
arch/powerpc/include/asm/fadump-internal.h | 4 +-
drivers/virtio/virtio_mem.c | 6 +-
include/linux/mmzone.h | 11 +-
kernel/dma/contiguous.c | 2 +-
mm/cma.c | 6 +-
mm/compaction.c | 10 +-
mm/migrate.c | 8 +-
mm/page_alloc.c | 203 +++++++++++++++++----
8 files changed, 196 insertions(+), 54 deletions(-)
From: Zi Yan <ziy@nvidia.com> Date: 2021-12-10 15:30:39
On 10 Dec 2021, at 2:30, Eric Ren wrote:
Hi Zi Yan,
On 2021/12/10 07:04, Zi Yan wrote:
quoted
From: Zi Yan <ziy@nvidia.com>
Hi all,
This patchset tries to remove the MAX_ORDER - 1 alignment requirement for CMA
and alloc_contig_range(). It prepares for my upcoming changes to make MAX_ORDER
adjustable at boot time[1].
The MAX_ORDER - 1 alignment requirement comes from that alloc_contig_range()
isolates pageblocks to remove free memory from buddy allocator but isolating
only a subset of pageblocks within a page spanning across multiple pageblocks
causes free page accounting issues. Isolated page might not be put into the
right free list, since the code assumes the migratetype of the first pageblock
as the whole free page migratetype. This is based on the discussion at [2].
To remove the requirement, this patchset:
1. still isolates pageblocks at MAX_ORDER - 1 granularity;
Then, unplug fails if either pageblock of the MAX_ORDER - 1 page has unmovable page, right?
Right. One of the optimizations mentioned is targeting this by passing the actual
range instead of the MAX_ORDER-1 aligned range, so that has_unmovable_pages()
will not give false positive, minimizing the isolation failure rates.
Thanks,
Eric
quoted
2. but saves the pageblock migratetypes outside the specified range of
alloc_contig_range() and restores them after all pages within the range
become free after __alloc_contig_migrate_range();
3. splits free pages spanning multiple pageblocks at the beginning and the end
of the range and puts the split pages to the right migratetype free lists
based on the pageblock migratetypes;
4. returns pages not in the range as it did before this patch.
Isolation needs to happen at MAX_ORDER - 1 granularity, because otherwise
1) extra code is needed to detect pages (free, PageHuge, THP, or PageCompound)
to make sure all pageblocks belonging to a single page are isolated together
and later pageblocks outside the range need to have their migratetypes restored;
or 2) extra logic will need to be added during page free time to split a free
page with multi-migratetype pageblocks.
Two optimizations might come later:
1. only check unmovable pages within the range instead of MAX_ORDER - 1 aligned
range during isolation to increase successful rate of alloc_contig_range().
^^^^^^^^^^^^^^
quoted
2. make MIGRATE_ISOLATE a separate bit to avoid saving and restoring existing
migratetypes before and after isolation respectively.
Feel free to give comments and suggestions. Thanks.
[1] https://lore.kernel.org/linux-mm/20210805190253.2795604-1-zi.yan@sent.com/
[2] https://lore.kernel.org/linux-mm/d19fb078-cb9b-f60f-e310-fdeea1b947d2@redhat.com/
Zi Yan (7):
mm: page_alloc: avoid merging non-fallbackable pageblocks with others.
mm: compaction: handle non-lru compound pages properly in
isolate_migratepages_block().
mm: migrate: allocate the right size of non hugetlb or THP compound
pages.
mm: make alloc_contig_range work at pageblock granularity
mm: cma: use pageblock_order as the single alignment
drivers: virtio_mem: use pageblock size as the minimum virtio_mem
size.
arch: powerpc: adjust fadump alignment to be pageblock aligned.
arch/powerpc/include/asm/fadump-internal.h | 4 +-
drivers/virtio/virtio_mem.c | 6 +-
include/linux/mmzone.h | 11 +-
kernel/dma/contiguous.c | 2 +-
mm/cma.c | 6 +-
mm/compaction.c | 10 +-
mm/migrate.c | 8 +-
mm/page_alloc.c | 203 +++++++++++++++++----
8 files changed, 196 insertions(+), 54 deletions(-)
From: David Hildenbrand <hidden> Date: 2021-12-10 18:36:35
On 10.12.21 00:04, Zi Yan wrote:
From: Zi Yan <ziy@nvidia.com>
Hi all,
Hi,
thanks for working on that!
This patchset tries to remove the MAX_ORDER - 1 alignment requirement for CMA
and alloc_contig_range(). It prepares for my upcoming changes to make MAX_ORDER
adjustable at boot time[1].
The MAX_ORDER - 1 alignment requirement comes from that alloc_contig_range()
isolates pageblocks to remove free memory from buddy allocator but isolating
only a subset of pageblocks within a page spanning across multiple pageblocks
causes free page accounting issues. Isolated page might not be put into the
right free list, since the code assumes the migratetype of the first pageblock
as the whole free page migratetype. This is based on the discussion at [2].
To remove the requirement, this patchset:
1. still isolates pageblocks at MAX_ORDER - 1 granularity;
2. but saves the pageblock migratetypes outside the specified range of
alloc_contig_range() and restores them after all pages within the range
become free after __alloc_contig_migrate_range();
3. splits free pages spanning multiple pageblocks at the beginning and the end
of the range and puts the split pages to the right migratetype free lists
based on the pageblock migratetypes;
4. returns pages not in the range as it did before this patch.
Isolation needs to happen at MAX_ORDER - 1 granularity, because otherwise
1) extra code is needed to detect pages (free, PageHuge, THP, or PageCompound)
to make sure all pageblocks belonging to a single page are isolated together
and later pageblocks outside the range need to have their migratetypes restored;
or 2) extra logic will need to be added during page free time to split a free
page with multi-migratetype pageblocks.
Two optimizations might come later:
1. only check unmovable pages within the range instead of MAX_ORDER - 1 aligned
range during isolation to increase successful rate of alloc_contig_range().
The issue with virtio-mem is that we'll need that as soon as we change
the granularity to pageblocks, because otherwise, you can heavily
degrade unplug reliably in sane setups:
Previous:
* Try unplug free 4M range (2 pageblocks): succeeds
Now:
* Try unplug 2M range (first pageblock): succeeds.
* Try unplug next 2M range (second pageblock): fails because first
contains unmovable allcoations.
--
Thanks,
David / dhildenb
From: Zi Yan <ziy@nvidia.com> Date: 2021-12-10 20:18:02
On 10 Dec 2021, at 13:36, David Hildenbrand wrote:
On 10.12.21 00:04, Zi Yan wrote:
quoted
From: Zi Yan <ziy@nvidia.com>
Hi all,
Hi,
thanks for working on that!
quoted
This patchset tries to remove the MAX_ORDER - 1 alignment requirement for CMA
and alloc_contig_range(). It prepares for my upcoming changes to make MAX_ORDER
adjustable at boot time[1].
The MAX_ORDER - 1 alignment requirement comes from that alloc_contig_range()
isolates pageblocks to remove free memory from buddy allocator but isolating
only a subset of pageblocks within a page spanning across multiple pageblocks
causes free page accounting issues. Isolated page might not be put into the
right free list, since the code assumes the migratetype of the first pageblock
as the whole free page migratetype. This is based on the discussion at [2].
To remove the requirement, this patchset:
1. still isolates pageblocks at MAX_ORDER - 1 granularity;
2. but saves the pageblock migratetypes outside the specified range of
alloc_contig_range() and restores them after all pages within the range
become free after __alloc_contig_migrate_range();
3. splits free pages spanning multiple pageblocks at the beginning and the end
of the range and puts the split pages to the right migratetype free lists
based on the pageblock migratetypes;
4. returns pages not in the range as it did before this patch.
Isolation needs to happen at MAX_ORDER - 1 granularity, because otherwise
1) extra code is needed to detect pages (free, PageHuge, THP, or PageCompound)
to make sure all pageblocks belonging to a single page are isolated together
and later pageblocks outside the range need to have their migratetypes restored;
or 2) extra logic will need to be added during page free time to split a free
page with multi-migratetype pageblocks.
Two optimizations might come later:
1. only check unmovable pages within the range instead of MAX_ORDER - 1 aligned
range during isolation to increase successful rate of alloc_contig_range().
The issue with virtio-mem is that we'll need that as soon as we change
the granularity to pageblocks, because otherwise, you can heavily
degrade unplug reliably in sane setups:
Previous:
* Try unplug free 4M range (2 pageblocks): succeeds
Now:
* Try unplug 2M range (first pageblock): succeeds.
* Try unplug next 2M range (second pageblock): fails because first
contains unmovable allcoations.
OK. Make sense. I will add it in the next version.
--
Best Regards,
Yan, Zi