Updated from v4 as
- avoid to add new arguments to vm_normal_page().
vm_normal_page() always returns NULL if ZERO_PAGE is found.
- follow_page() directly handles pte_special and ANON_ZERO_PAGE.
Then, amount of changes are reduced. Thanks for advices.
Concerns pointed out:
- Does use_zero_page() cover all cases ?
I think yes..
- All get_user_pages() callers, which may find ZERO_PAGE is safe ?
need tests.
- All follow_pages() callers, which may find ZERO_PAGE is safe ?
I think yes.
Thanks,
-Kame
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
no changes from v4.
==
From: KAMEZAWA Hiroyuki <redacted>
Kconfig for using ZERO_PAGE or not. Using ZERO_PAGE or not is depends on
- arch has pte_special() or not.
- arch allows to use ZERO_PAGE or not.
In this patch, generic-config for /mm and arch-specific config for x86
is added. Other archs ?
Signed-off-by: KAMEZAWA Hiroyuki <redacted>
---
arch/x86/Kconfig | 3 +++
mm/Kconfig | 18 ++++++++++++++++++
2 files changed, 21 insertions(+)
Index: mmotm-2.6.31-Aug4/mm/Kconfig
===================================================================
@@ -225,6 +225,24 @@ config KSMsavingmemoryuntiloneoranotherappneedstomodifythecontent.RecommendedforusewithKVM,orwithotherduplicativeapplications.+configSUPPORT_ANON_ZERO_PAGE+bool"Use anon zero page"+defaultyifARCH_SUPPORT_ANON_ZERO_PAGE+help+Inanonymousprivatemapping(MAP_ANONYMOUSand/dev/zero),aread+pagefaultwillallocateanewzero-clearedpage.Ifthefirstpage+faultiswrite,allocatinganewpageisnecessary.Butifitis+read,wecanuseZERO_PAGEuntilawritecomes.Ifyousetthistoy,+thekerneluseZERO_PAGEanddelaysallocatingnewmemoryinprivate+anonmappinguntilthefirstwrite.Ifapplicationsuselargemmap+andmostofaccessesareread,thisreducesmemoryusageandcache+usagetosomeextent.Tosupportthis,yourarchitectureshouldhave+_PAGE_SPECIALbitinpte.Andthiswillbenohelptocpucacheif+thearch'scacheisvirtuallytagged.+Todevelopper:+ThisZERO_PAGEchangesbehavioroffollow_page().pleasecheck+usageoffollow_page()inyourarchbeforesupportingthis.+configDEFAULT_MMAP_MIN_ADDRint"Low address space to protect from user allocation"default4096
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
From: KAMEZAWA Hiroyuki <redacted>
updated against: mmotm-Jul-30-2009.
ZERO_PAGE for anonymous private mapping is useful when an application
requires large continuous memory but write sparsely or some other usages.
It was removed in 2.6.24 but this patch tries to re-add it.
(Because there are some use cases..)
In past, ZERO_PAGE was removed because heavy cache line contention in
ZERO_PAGE's refcounting, this version of ZERO_PAGE avoid to refcnt it.
Then, implementation is changed as following.
- Use of ZERO_PAGE is limited to PRIVATE mapping. Then, VM_MAYSHARE is
checked as VM_SHARED.
- pte_special(), _PAGE_SPECIAL bit in pte is used for indicating ZERO_PAGE.
- follow_page() eats FOLL_XXX flag. If FOLL_NOZERO is set,
NULL is returned even if ZERO_PAGE is found.
- vm_normal_page() returns NULL if ZERO_PAGE is found.
- __get_user_pages() eats one more flag as GUP_FLAGS_IGNORE_ZERO. If set,
__get_user_page() returns NULL even if ZERO_PAGE is found.
Changelog v4.1 -> v5
- removed new arguments to vm_normal_page()
- follow_page() handles ZERO_PAGE directly.
Changelog v4 -> v4.1
- removed nexted "if" in get_user_pages() for readability
Changelog v3->v4
- FOLL_NOZERO is directly passed to vm_normal_page()
Changelog v2->v3
- totally renewed.
- use pte_special()
- added new argument to vm_normal_page().
- MAYSHARE is checked.
Signed-off-by: KAMEZAWA Hiroyuki <redacted>
---
include/linux/mm.h | 1
mm/internal.h | 1
mm/memory.c | 123 +++++++++++++++++++++++++++++++++++++++++++----------
mm/migrate.c | 6 +-
mm/mlock.c | 2
5 files changed, 108 insertions(+), 25 deletions(-)
Index: mmotm-2.6.31-Aug4/mm/memory.c
===================================================================
@@ -1143,7 +1178,16 @@ struct page *follow_page(struct vm_area_gotono_page;if((flags&FOLL_WRITE)&&!pte_write(pte))gotounlock;-page=vm_normal_page(vma,address,pte);++if(HAVE_ANON_ZERO&&pte_special(pte)&&use_zero_page(vma)){+/* This page is ZERO_PAGE */+if(flags&FOLL_NOZERO)+page=NULL;+else+page=ZERO_PAGE(0);+}else+page=vm_normal_page(vma,address,pte);+if(unlikely(!page))gotobad_page;
@@ -1188,23 +1232,6 @@ no_page_table:returnpage;}-/* Can we do the FOLL_ANON optimization? */-staticinlineintuse_zero_page(structvm_area_struct*vma)-{-/*-*Wedon'twanttooptimizeFOLL_ANONformake_pages_present()-*whenittriestopageinaVM_LOCKEDregion.AstoVM_SHARED,-*wewanttogetthepagefromthepagetablestomakesure-*thatweserializeandupdatewithanyotheruserofthat-*mapping.-*/-if(vma->vm_flags&(VM_LOCKED|VM_SHARED))-return0;-/*-*Andifwehaveafaultroutine,it'snotananonymousregion.-*/-return!vma->vm_ops||!vma->vm_ops->fault;-}
@@ -1218,6 +1245,7 @@ int __get_user_pages(struct task_struct intforce=!!(flags&GUP_FLAGS_FORCE);intignore=!!(flags&GUP_FLAGS_IGNORE_VMA_PERMISSIONS);intignore_sigkill=!!(flags&GUP_FLAGS_IGNORE_SIGKILL);+intignore_zero=!!(flags&GUP_FLAGS_IGNORE_ZERO);if(nr_pages<=0)return0;
@@ -1261,7 +1289,11 @@ int __get_user_pages(struct task_struct returni?:-EFAULT;}if(pages){-structpage*page=vm_normal_page(gate_vma,start,*pte);+structpage*page;+/*+*thisisnotanonvma...don'tcarezeropage.+*/+page=vm_normal_page(gate_vma,start,*pte);pages[i]=page;if(page)get_page(page);
@@ -1291,6 +1323,8 @@ int __get_user_pages(struct task_struct foll_flags|=FOLL_GET;if(!write&&use_zero_page(vma))foll_flags|=FOLL_ANON;+else+ignore_zero=0;do{structpage*page;
@@ -1309,9 +1343,17 @@ int __get_user_pages(struct task_struct if(write)foll_flags|=FOLL_WRITE;+if(ignore_zero)+foll_flags|=FOLL_NOZERO;+cond_resched();while(!(page=follow_page(vma,start,foll_flags))){intret;+/*+*Whenweignorezeropages,nomoreopstodo.+*/+if(ignore_zero)+break;ret=handle_mm_fault(mm,vma,start,(foll_flags&FOLL_WRITE)?
@@ -2617,6 +2659,41 @@ out_page:returnret;}+#ifdef CONFIG_SUPPORT_ANON_ZERO_PAGE+staticbooldo_anon_zeromap(structmm_struct*mm,structvm_area_struct*vma,+unsignedlongaddress,pmd_t*pmd)+{+spinlock_t*ptl;+pte_tentry;+pte_t*page_table;+boolret=false;++if(!use_zero_page(vma))+returnret;+/*+*Weuse_PAGE_SPECIALbitinptetoindicatethispageisZEROPAGE.+*/+entry=pte_mkspecial(mk_pte(ZERO_PAGE(0),vma->vm_page_prot));+page_table=pte_offset_map_lock(mm,pmd,address,&ptl);+if(!pte_none(*page_table))+gotoout_unlock;+set_pte_at(mm,address,page_table,entry);+/* No need to invalidate - it was non-present before */+update_mmu_cache(vma,address,entry);+ret=true;+out_unlock:+pte_unmap_unlock(page_table,ptl);+returnret;+}+#else+staticbooldo_anon_zeromap(structmm_struct*mm,structvm_area_struct*vma,+unsignedlongaddress,pmd_t*pmd)+{+/* We don't use ZERO PAGE */+returnfalse;+}+#endif /* CONFIG_SUPPORT_ANON_ZERO_PAGE */+/**Weenterwithnon-exclusivemmap_sem(toexcludevmachanges,*butallowconcurrentfaults),andptemappedbutnotyetlocked.
@@ -2633,6 +2710,10 @@ static int do_anonymous_page(struct mm_s/* Allocate our own private page. */pte_unmap(page_table);+if(unlikely(!(flags&FAULT_FLAG_WRITE)))+if(do_anon_zeromap(mm,vma,address,pmd))+return0;+if(unlikely(anon_vma_prepare(vma)))gotooom;page=alloc_zeroed_user_highpage_movable(vma,address);
@@ -1246,6 +1246,7 @@ struct page *follow_page(struct vm_area_#define FOLL_TOUCH 0x02 /* mark page accessed */#define FOLL_GET 0x04 /* do get_page on page */#define FOLL_ANON 0x08 /* give ZERO_PAGE if no pgtable */+#define FOLL_NOZERO 0x10 /* returns NULL if ZERO_PAGE is found */typedefint(*pte_fn_t)(pte_t*pte,pgtable_ttoken,unsignedlongaddr,void*data);
@@ -850,7 +850,7 @@ static int do_move_page_to_node_array(stif(!vma||!vma_migratable(vma))gotoset_status;-page=follow_page(vma,pp->addr,FOLL_GET);+page=follow_page(vma,pp->addr,FOLL_GET|FOLL_NOZERO);err=PTR_ERR(page);if(IS_ERR(page))
@@ -1007,14 +1007,14 @@ static void do_pages_stat_array(struct mif(!vma)gotoset_status;-page=follow_page(vma,addr,0);+page=follow_page(vma,addr,FOLL_NOZERO);err=PTR_ERR(page);if(IS_ERR(page))gotoset_status;err=-ENOENT;-/* Use PageReserved to check for zero page */+/* if zero page, page is NULL. */if(!page||PageReserved(page))gotoset_status;
@@ -162,7 +162,7 @@ static long __mlock_vma_pages_range(strustructpage*pages[16];/* 16 gives a reasonable batch */intnr_pages=(end-start)/PAGE_SIZE;intret=0;-intgup_flags=0;+intgup_flags=GUP_FLAGS_IGNORE_ZERO;VM_BUG_ON(start&~PAGE_MASK);VM_BUG_ON(end&~PAGE_MASK);--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
Updated from v4 as
- avoid to add new arguments to vm_normal_page().
vm_normal_page() always returns NULL if ZERO_PAGE is found.
- follow_page() directly handles pte_special and ANON_ZERO_PAGE.
Then, amount of changes are reduced. Thanks for advices.
Concerns pointed out:
- Does use_zero_page() cover all cases ?
I think yes..
- All get_user_pages() callers, which may find ZERO_PAGE is safe ?
need tests.
- All follow_pages() callers, which may find ZERO_PAGE is safe ?
I think yes.
Sorry, KAMEZAWA-san, I'm afraid this is still some way off being right.
Certainly the extent of the v5 patch is much more to my taste than v4
was, thank you.
Something that's missing, which we can get away with but probably
need to reinstate, is the shortcut when COWing: not to copy the
ZERO_PAGE, but just do a memset.
But just try mlock'ing a private readonly anon area into which you've
faulted a zero page, and the "BUG: Bad page map" message tells us
it's quite wrong to be trying use_zero_page() there.
Actually, I don't understand ignore_zero at all: it's used solely by
the mlock case, yet its effect seems to be precisely not to fault in
pages if they're missing - I wonder if you've got in a muddle between
the two very different awkward cases, mlocking and coredumps of
sparsely populated areas.
And I don't at all like the way you flush_dcache_page(page) on a
page which may now be NULL: okay, you're only encouraging x86 to
say Yes to the Kconfig option, but that's a landmine for the first
arch with a real flush_dcache_page(page) which says Yes to it.
Actually, the Kconfig stuff seems silly to me (who's going to know
how to choose on or off?): the only architecture which wanted more
than one ZERO_PAGE was MIPS, and it doesn't __HAVE_ARCH_PTE_SPECIAL
yet, so I think I'm going to drop all the Kconfig end of it.
Because I hate reviewing things and trying to direct other people
by remote control: what usually happens is I send them off in some
direction which, once I try to do it myself, turns out to have been
the wrong direction. I do need to try to do this myself, instead of
standing on the sidelines criticizing.
In fairness, I think Linus himself was a little confused when he
separated off use_zero_page(): I think we've all got confused around
there (as we noticed a month or so ago when discussing its hugetlb
equivalent), and I need to think it through again at last.
I'll get on to it now.
Hugh
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
On Sun, 9 Aug 2009 18:28:48 +0100 (BST)
Hugh Dickins [off-list ref] wrote:
On Wed, 5 Aug 2009, KAMEZAWA Hiroyuki wrote:
quoted
Updated from v4 as
- avoid to add new arguments to vm_normal_page().
vm_normal_page() always returns NULL if ZERO_PAGE is found.
- follow_page() directly handles pte_special and ANON_ZERO_PAGE.
Then, amount of changes are reduced. Thanks for advices.
Concerns pointed out:
- Does use_zero_page() cover all cases ?
I think yes..
- All get_user_pages() callers, which may find ZERO_PAGE is safe ?
need tests.
- All follow_pages() callers, which may find ZERO_PAGE is safe ?
I think yes.
Sorry, KAMEZAWA-san, I'm afraid this is still some way off being right.
Certainly the extent of the v5 patch is much more to my taste than v4
was, thank you.
At first, thank you for review.
Something that's missing, which we can get away with but probably
need to reinstate, is the shortcut when COWing: not to copy the
ZERO_PAGE, but just do a memset.
But just try mlock'ing a private readonly anon area into which you've
faulted a zero page, and the "BUG: Bad page map" message tells us
it's quite wrong to be trying use_zero_page() there.
Actually, I don't understand ignore_zero at all: it's used solely by
the mlock case, yet its effect seems to be precisely not to fault in
pages if they're missing - I wonder if you've got in a muddle between
the two very different awkward cases, mlocking and coredumps of
sparsely populated areas.
Ah, then, you say mlock() should allocate 'real' page if zero page
is mapped. Right ?
"How to handle mlock" is a concern for me, too. But I selected this
to allow the same behavior to old kernels.
And I don't at all like the way you flush_dcache_page(page) on a
page which may now be NULL: okay, you're only encouraging x86 to
say Yes to the Kconfig option, but that's a landmine for the first
arch with a real flush_dcache_page(page) which says Yes to it.
do_wp_page()
-> cow_user_page()
-> (src is NULL)
Ah....ok, it's bug. I added ....Sorry, I didn't see this in older version
and missed this.
Actually, the Kconfig stuff seems silly to me (who's going to know
how to choose on or off?): the only architecture which wanted more
than one ZERO_PAGE was MIPS, and it doesn't __HAVE_ARCH_PTE_SPECIAL
yet, so I think I'm going to drop all the Kconfig end of it.
ok, I have no strong demands on it.
Because I hate reviewing things and trying to direct other people
by remote control: what usually happens is I send them off in some
direction which, once I try to do it myself, turns out to have been
the wrong direction. I do need to try to do this myself, instead of
standing on the sidelines criticizing.
In fairness, I think Linus himself was a little confused when he
separated off use_zero_page(): I think we've all got confused around
there (as we noticed a month or so ago when discussing its hugetlb
equivalent), and I need to think it through again at last.
I'll get on to it now.
Thank you for comments. I'll go to a trip until Aug/17, programming-camp,
I'll be able to consider this patch and the whole things aroung paging in calm
enviroment. I'll try to restart from scratch.
Thanks,
-Kame
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
On Sun, 9 Aug 2009 18:28:48 +0100 (BST)
Hugh Dickins [off-list ref] wrote:
quoted
Actually, I don't understand ignore_zero at all: it's used solely by
the mlock case, yet its effect seems to be precisely not to fault in
pages if they're missing - I wonder if you've got in a muddle between
the two very different awkward cases, mlocking and coredumps of
sparsely populated areas.
Ah, then, you say mlock() should allocate 'real' page if zero page
is mapped. Right ?
No.
(That would be a possibility if it gets us out of some difficulty
with the newer mlocking code, but it's not something we ever did or
wanted to do in the past.)
What I was saying in that paragraph was that (it appears to me that)
in your patch only __mlock_vma_pages_range sets GUP_FLAGS_IGNORE_ZERO,
that __get_user_pages sets ignore_zero according to that flag, some
conditions may clear it, but then it goes on to say
while (!(page = follow_page(vma, start, foll_flags))) {
/*
* When we ignore zero pages, no more ops to do.
*/
if (ignore_zero)
break;
which means that when ignore_zero is set and follow_page returns NULL,
we emerge from the loop with NULL page, don't we? Whereas when mlocking,
we want to fault in any pages which were not already there.
Or am I just reading this all wrong?
quoted
And I don't at all like the way you flush_dcache_page(page) on a
page which may now be NULL: okay, you're only encouraging x86 to
say Yes to the Kconfig option, but that's a landmine for the first
arch with a real flush_dcache_page(page) which says Yes to it.
do_wp_page()
-> cow_user_page()
-> (src is NULL)
Ah....ok, it's bug. I added ....Sorry, I didn't see this in older version
and missed this.
That's an entirely different issue, and I don't see that it's a bug,
just the inefficiency I mentioned elsewhere that we'd be better off
doing a memset than trying to memcpy the ZERO_PAGE.
What I was saying in that paragraph is that when you break from the
loop in __get_user_pages with ignore_zero and NULL page, you reach
if (IS_ERR(page))
return i ? i : PTR_ERR(page);
if (pages) {
pages[i] = page;
flush_anon_page(vma, page, start);
flush_dcache_page(page);
}
which inserts a NULL into pages[i] (which may be okay if the other
end is prepared for it, as I think __mlock_vma_pages_range is),
then passes a NULL page to flush_anon_page and flush_dcache_page.
I looked up one of the non-empty implementations of flush_dcache_page
and saw it testing a bit in page->flags, assuming (very reasonably!)
that the page pointer is not NULL. Oops.
quoted
Because I hate reviewing things and trying to direct other people
by remote control: what usually happens is I send them off in some
direction which, once I try to do it myself, turns out to have been
the wrong direction. I do need to try to do this myself, instead of
standing on the sidelines criticizing.
In fairness, I think Linus himself was a little confused when he
separated off use_zero_page(): I think we've all got confused around
there (as we noticed a month or so ago when discussing its hugetlb
equivalent), and I need to think it through again at last.
I'll get on to it now.
Thank you for comments. I'll go to a trip until Aug/17, programming-camp,
Sorry for not getting to all this sooner, yes I'd seen your warning in
another mail that you'd be away, but I just didn't get here fast enough.
I'll be able to consider this patch and the whole things aroung paging in calm
enviroment. I'll try to restart from scratch.
What I'm saying above is that I'd much prefer to try doing the patch
myself and have you review that, than us to keep on going back and
forth with different versions like this.
I am not confident that you've grasped all the issues, and I am sure
that there's a least one issue which I have not grasped: maybe it'll
end up irrelevant, but I do need to understand Linus's Fix ZERO_PAGE
breakage with vmware, 672ca28e300c17bf8d792a2a7a8631193e580c74
But I'll discuss that separately, probably offlist; or, if I'm lucky,
just composing the mail will bring me to answer my own question!
Hugh
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>