mm: madvise(WILLNEED) for anonymous memory
Subsystems (3)
RFC PATCH 1/1 mm: madvise(WILLNEED) for anonymous memory
Hi,
Lennart asked for madvise(WILLNEED) to work on anonymous pages, he plans to use this to pre-fault pages. He currently uses: mlock/munlock for this purpose.
[ compile tested only ]
---
mm/madvise.c +19 -1
@@ -100,6 +100,24 @@ out:return error; } +static long madvice_willneed_anon (struct vm_area_struct *vma, +struct vm_area_struct **prev, +unsigned long start,unsigned long end) +{ +int ret, len; + + *prev = vma; +if (end > vma->vm_end) + end = vma->vm_end; + + len = end - start; + ret =get_user_pages (current, current->mm, start, len, +0 ,0 ,NULL ,NULL ); +if (ret <0 ) +return ret; +return ret == len ?0 :-1 ; +} +/* * Schedule all required I/O operations. Do not wait for completion. */
@@ -110,7 +128,7 @@ static long madvise_willneed(struct vm_area_struct * vma,struct file *file = vma->vm_file;if (!file) -return -EBADF ; +return madvice_willneed_anon (vma, prev, start, end);if (file->f_mapping->a_ops->get_xip_page) {/* no bad return value, but ignore advice */
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 4 lines · Peter Zijlstra
Lennart asked for madvise(WILLNEED) to work on anonymous pages, he plans to use this to pre-fault pages. He currently uses: mlock/munlock for this purpose.
I certainly agree with this in principle: it just seems an unnecessary and surprising restriction to refuse on anonymous vmas; I guess the only reason for not adding this was not having anyone asking for it until now. Though, does Lennart realize he could use MAP_POPULATE in the mmap?
Quoted 2 lines
[ compile tested only ]
I haven't tried it either, but generally it looks plausible.
Quoted 8 lines
Signed-off-by Peter Zijlstra <[email protected]>---
mm/madvise.c +0
-0
mm/madvise.c out: · line 105
Quoted 6 lines
mm/madvise.c +3
-0@@ -100,6 +100,24 @@ out:return error; } +static long madvice_willneed_anon (struct vm_area_struct *vma, +struct vm_area_struct **prev, +unsigned long start,unsigned long end)
mavise.c uses "madvise_" rather than " madvice_" throughout, so please go with the flow.
mm/madvise.c out: · line 111
Quoted 6 lines
mm/madvise.c +6
-0+{ +int ret, len; + + *prev = vma; +if (end > vma->vm_end) + end = vma->vm_end;
Please check, but I think the upper level ensures end is within range.
mm/madvise.c out: · line 118
Quoted 7 lines
mm/madvise.c +7
-0+ + len = end - start; + ret =get_user_pages (current, current->mm, start, len, +0 ,0 ,NULL ,NULL ); +if (ret <0 ) +return ret; +return ret == len ?0 :-1 ;
It's not good to return -1 as an alternative to a real errno:
it'll look like -EPERM. If you copied that from somewhere, better send a patch to fix the somewhere! Ah, yes, make_pages_present: it happens that nobody is interested in its return value, so we could make it a void; but that'd just be a cleanup. What to do here if non-negative ret less than len? Oh, just return 0, that's good enough in this case (the file case always returns 0).
Hmm, might it be better to use make_pages_present itself, fixing its retval, rather than using get_user_pages directly? (I'd hope the caching makes its repeat of find_vma not an overhead.)
Interesting divergence: make_pages_present faults in writable pages in a writable vma, whereas the file case's force_page_cache_readahead doesn't even insert the pages into the mm.
Quoted 6 lines
mm/madvise.c +2
-0+} +/* * Schedule all required I/O operations. Do not wait for completion. */
mm/madvise.c static long madvise_willneed(struct vm_area_struct * vma, · line 134
Quoted 8 lines
mm/madvise.c +1
-1@@ -110,7 +128,7 @@ static long madvise_willneed(struct vm_area_struct * vma,struct file *file = vma->vm_file;if (!file) -return -EBADF ; +return madvice_willneed_anon (vma, prev, start, end);if (file->f_mapping->a_ops->get_xip_page) {/* no bad return value, but ignore advice */
And there's a correctly invisible hunk to the patch too: this extension of MADV_WILLNEED also does not require down_write of mmap_sem, so madvise_need_mmap_write can remain unchanged.
Hugh
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 10 lines · Hugh Dickins
Quoted 4 lines · Peter Zijlstra
Lennart asked for madvise(WILLNEED) to work on anonymous pages, he plans to use this to pre-fault pages. He currently uses: mlock/munlock for this purpose.
I certainly agree with this in principle: it just seems an unnecessary and surprising restriction to refuse on anonymous vmas; I guess the only reason for not adding this was not having anyone asking for it until now. Though, does Lennart realize he could use
MAP_POPULATEin the mmap?
I think he's trying to get his data swapped-in.
Quoted 11 lines
Quoted 11 lines
Signed-off-by Peter Zijlstra <[email protected]>---
mm/madvise.c +0
-0@@ -100,6 +100,24 @@ out:return error; }
Quoted 6 lines
mm/madvise.c out: · line 105
Quoted 3 lines
mm/madvise.c +3
-0+static long madvice_willneed_anon (struct vm_area_struct *vma, +struct vm_area_struct **prev, +unsigned long start,unsigned long end)
mavise.cuses "madvise_" rather than "madvice_" throughout, so please go with the flow.
Ah, quite. I hadn't noticed this, will fix.
Quoted 8 lines
mm/madvise.c out: · line 111
Quoted 6 lines
mm/madvise.c +6
-0+{ +int ret, len; + + *prev = vma; +if (end > vma->vm_end) + end = vma->vm_end;Please check, but I think the upper level ensures end is within range.
It certainly looks like it, but I since the file case did this check I thought it prudent to also do it. I guess I might as well remove both.
Quoted 8 lines
mm/madvise.c out: · line 118
Quoted 7 lines
mm/madvise.c +7
-0+ + len = end - start; + ret =get_user_pages (current, current->mm, start, len, +0 ,0 ,NULL ,NULL ); +if (ret <0 ) +return ret; +return ret == len ?0 :-1 ;
Quoted 7 lines
It's not good to return -1 as an alternative to a real errno:
it'll look like-EPERM. If you copied that from somewhere, better send a patch to fix the somewhere! Ah, yes,make_pages_present: it happens that nobody is interested in its return value, so we could make it a void; but that'd just be a cleanup. What to do here if non-negative ret less than len? Oh, just return 0, that's good enough in this case (the file case always returns 0).
ok, return 0; it is.
Quoted 7 lines
Hmm, might it be better to use
make_pages_presentitself, fixing its retval, rather than usingget_user_pagesdirectly? (I'd hope the caching makes its repeat offind_vmanot an overhead.)Interesting divergence:
make_pages_presentfaults in writable pages in a writable vma, whereas the file case'sforce_page_cache_readaheaddoesn't even insert the pages into the mm.
Yeah, the find_vma and write fault thing are the reason I didn't use make_pages_present.
I had noticed the difference in pte population between force_page_cache_readahead and make_pages_present, but it seemed to me that writing a function to walk the page tables and populate the swapcache but not populate the ptes wasn't worth the effort.
Quoted 12 lines
Quoted 12 lines
mm/madvise.c +3
-1+} +/* * Schedule all required I/O operations. Do not wait for completion. */ @@ -110,7 +128,7 @@ static long madvise_willneed(struct vm_area_struct * vma,struct file *file = vma->vm_file;if (!file) -return -EBADF ; +return madvice_willneed_anon (vma, prev, start, end);
Quoted 6 lines
mm/madvise.c static long madvise_willneed(struct vm_area_struct * vma, · line 134
Quoted 2 lines
mm/madvise.c +0
-0if (file->f_mapping->a_ops->get_xip_page) {/* no bad return value, but ignore advice */ And there's a correctly invisible hunk to the patch too: this extension of
MADV_WILLNEEDalso does not requiredown_writeofmmap_sem, somadvise_need_mmap_writecan remain unchanged.
Indeed, I did check that :-)
---
mm/madvise.c +16 -3
@@ -100,6 +100,21 @@ out:return error; } +static long madvise_willneed_anon (struct vm_area_struct *vma, +struct vm_area_struct **prev, +unsigned long start,unsigned long end) +{ +int ret; + + *prev = vma; + ret =get_user_pages (current, current->mm, start, end - start, +0 ,0 ,NULL ,NULL ); +if (ret <0 ) +return ret; + +return 0 ; +} +/* * Schedule all required I/O operations. Do not wait for completion. */
@@ -110,7 +125,7 @@ static long madvise_willneed(struct vm_area_struct * vma,struct file *file = vma->vm_file;if (!file) -return -EBADF ; +return madvise_willneed_anon (vma, prev, start, end);if (file->f_mapping->a_ops->get_xip_page) {/* no bad return value, but ignore advice */
@@ -119,8 +134,6 @@ static long madvise_willneed(struct vm_area_struct * vma, *prev = vma; start = ((start - vma->vm_start) >>PAGE_SHIFT ) + vma->vm_pgoff; -if (end > vma->vm_end) - end = vma->vm_end; end = ((end - vma->vm_start) >>PAGE_SHIFT ) + vma->vm_pgoff; force_page_cache_readahead(file->f_mapping,
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 6 lines · Peter Zijlstra
Quoted 3 lines · Hugh Dickins
Interesting divergence:
make_pages_presentfaults in writable pages in a writable vma, whereas the file case'sforce_page_cache_readaheaddoesn't even insert the pages into the mm.
Quoted 7 lines
Yeah, the
find_vmaand write fault thing are the reason I didn't usemake_pages_present.I had noticed the difference in pte population between
force_page_cache_readaheadandmake_pages_present, but it seemed to me that writing a function to walk the page tables and populate the swapcache but not populate the ptes wasn't worth the effort.
Ah, another, more important difference:
force_page_cache_readahead will not wait for the read to complete, whereas get_user_pages() will be fully synchronous.
I think I'd better come up with something else then,..
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 15 lines · Peter Zijlstra
Quoted 6 lines · Peter Zijlstra
Quoted 3 lines · Hugh Dickins
Interesting divergence:
make_pages_presentfaults in writable pages in a writable vma, whereas the file case'sforce_page_cache_readaheaddoesn't even insert the pages into the mm.Quoted 7 lines
Yeah, the
find_vmaand write fault thing are the reason I didn't usemake_pages_present.I had noticed the difference in pte population between
force_page_cache_readaheadandmake_pages_present, but it seemed to me that writing a function to walk the page tables and populate the swapcache but not populate the ptes wasn't worth the effort.
Quoted 6 lines
Ah, another, more important difference:
force_page_cache_readaheadwill not wait for the read to complete, whereasget_user_pages()will be fully synchronous.I think I'd better come up with something else then,..
Depending on the page table walk from -mm
---
A best effort implementation of madvise(WILLNEED) for anonymous pages.
---
mm/madvise.c +31 -1
@@ -11,6 +11,8 @@#include <linux/mempolicy.h> #include <linux/hugetlb.h> #include <linux/sched.h> +#include <linux/swap.h> +#include <linux/swapops.h> /* * Any behaviour which results in changes to the vma->vm_flags needs to
@@ -100,6 +102,34 @@ out:return error; } +static int madvise_willneed_anon_pte (pte_t *ptep, +unsigned long start,unsigned long end,void *arg) +{ +struct vm_area_struct *vma = arg; +struct page *page; + + page =read_swap_cache_async (pte_to_swp_entry (*ptep),GFP_KERNEL , + vma, start); +if (page) +page_cache_release (page); + +return 0 ; +} + +static long madvise_willneed_anon (struct vm_area_struct * vma, +struct vm_area_struct ** prev, +unsigned long start,unsigned long end) +{ +struct mm_walk walk = { + .pte_entry = madvise_willneed_anon_pte, + }; + + *prev = vma; +walk_page_range (vma->vm_mm, start, end, &walk, vma); + +return 0 ; +} +/* * Schedule all required I/O operations. Do not wait for completion. */
@@ -110,7 +140,7 @@ static long madvise_willneed(struct vm_area_struct * vma,struct file *file = vma->vm_file;if (!file) -return -EBADF ; +return madvise_willneed_anon (vma, prev, start, end);if (file->f_mapping->a_ops->get_xip_page) {/* no bad return value, but ignore advice */
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
mm/madvise.c out: · line 111
Quoted 7 lines · Peter Zijlstra
mm/madvise.c +7
-0+static int madvise_willneed_anon_pte (pte_t *ptep, +unsigned long start,unsigned long end,void *arg) +{ +struct vm_area_struct *vma = arg; +struct page *page; + + page = read_swap_cache_async(pte_to_swp_entry(*ptep), GFP_KERNEL,
Argh, with HIGHPTE this is done inside a kmap_atomic.
/me goes complicate the code with page pre-allocation..
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 9 lines · Peter Zijlstra
Quoted 6 lines · Hugh Dickins
On Thu, 20 Dec 2007, Peter Zijlstra wrote:
I certainly agree with this in principle: it just seems an unnecessary and surprising restriction to refuse on anonymous vmas; I guess the only reason for not adding this was not having anyone asking for it until now. Though, does Lennart realize he could use
MAP_POPULATEin the mmap?I think he's trying to get his data swapped-in.
That's perfectly reasonable, fair enough.
Quoted 11 lines
Quoted 8 lines
mm/madvise.c out:
Quoted 6 lines
mm/madvise.c +6
-0+{ +int ret, len; + + *prev = vma; +if (end > vma->vm_end) + end = vma->vm_end;Please check, but I think the upper level ensures end is within range.
It certainly looks like it, but I since the file case did this check I thought it prudent to also do it. I guess I might as well remove both.
Ah, so it does. Yes, please do remove both.
Quoted 10 lines
Quoted 7 lines
Hmm, might it be better to use
make_pages_presentitself, fixing its retval, rather than usingget_user_pagesdirectly? (I'd hope the caching makes its repeat offind_vmanot an overhead.)Interesting divergence:
make_pages_presentfaults in writable pages in a writable vma, whereas the file case'sforce_page_cache_readaheaddoesn't even insert the pages into the mm.Yeah, the
find_vmaand write fault thing are the reason I didn't usemake_pages_present.
The write fault thing is irrelevant now, actually: now do_anonymous_page doesn't use ZERO_PAGE, it puts in a writable page if the vma flags permit, even when it's just a read fault (and its write_access arg is redundant).
Quoted 5 lines
I had noticed the difference in pte population between
force_page_cache_readaheadandmake_pages_present, but it seemed to me that writing a function to walk the page tables and populate the swapcache but not populate the ptes wasn't worth the effort.
I was about to agree with you, when you made the observation:
Quoted 6 lines
Ah, another, more important difference:
force_page_cache_readaheadwill not wait for the read to complete, whereasget_user_pages()will be fully synchronous.I think I'd better come up with something else then,..
Yes, that's an interesting point. Maybe first put in what you have, to stop it from saying -EBADF on anon; then make it asynch later.
The asynch code: perhaps not worth doing for MADV_WILLNEED alone, but might prove useful for more general use when swapping in. Not really the same as Con's swap prefetch, but worth looking at that for reference. But I guess this becomes a much bigger issue than you were intending to get into here.
Hugh
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 5 lines · Hugh Dickins
The asynch code: perhaps not worth doing for
MADV_WILLNEEDalone, but might prove useful for more general use when swapping in. Not really the same as Con's swap prefetch, but worth looking at that for reference. But I guess this becomes a much bigger issue than you were intending to get into here.
heh, yeah, got somewhat more complex that I'd hoped for.
last patch for today (not even compile tested), will do a proper patch and test it tomorrow.
---
A best effort MADV_WILLNEED implementation for anonymous memory.
It adds a batch method to the page table walk routines so we can copy a few ptes while holding the kmap, which makes it possible to allocate the backing pages using GFP_KERNEL.
---
include/linux/mm.h +9 -0
@@ -726,6 +726,7 @@ unsigned long unmap_vmas(struct mmu_gather **tlb,* @pmd_entry: if set, called for each non-empty PMD (3rd-level) entry * @pte_entry: if set, called for each non-empty PTE (4th-level) entry * @pte_hole: if set, called for each hole at all levels +* @pte_batch: if set, called for each %WALK_BATCH_SIZE PTE entries. * * (see walk_page_range for more details) */
@@ -735,8 +736,16 @@ struct mm_walk {int (*pmd_entry)(pmd_t *,unsigned long ,unsigned long ,void *);int (*pte_entry)(pte_t *,unsigned long ,unsigned long ,void *);int (*pte_hole)(unsigned long ,unsigned long ,void *); +int (*pte_batch)(unsigned long ,unsigned long ,void *); }; +#define WALK_BATCH_SIZE 32 + +static inline walk_addr_index(unsigned long addr) +{ +return (addr >>PAGE_SHIFT ) %WALK_BATCH_SIZE ; +} +int walk_page_range (const struct mm_struct *,unsigned long addr,unsigned long end,const struct mm_walk *walk,void *private);
mm/madvise.c +61 -7
100 lines not on this page · raw message
mm/pagewalk.c +33 -0
@@ -2,12 +2,45 @@#include <linux/highmem.h> #include <linux/sched.h> +static int walk_pte_range_batch (pmd_t *pmd,unsigned long addr,unsigned long end, +const struct mm_walk *walk,void *private) +{ +int err =0 ; + +do { +unsigned int i; +pte_t *pte; +unsigned long start = addr; +int err2; + + pte =pte_offset_map (pmd, addr); +for (i =0 ; i <WALK_BATCH_SIZE && addr != end; + i++, pte++, addr +=PAGE_SIZE ) { + err = walk->pte_entry (pte, addr, addr +PAGE_SIZE , private); +if (err) +break ; + } +pte_unmap (pte); + + err2 = walk->pte_batch (start, end, private); +if (!err) + err = err2; +if (err) +break ; + }while (addr != end); + +return err; +} +static int walk_pte_range (pmd_t *pmd,unsigned long addr,unsigned long end,const struct mm_walk *walk,void *private) {pte_t *pte;int err =0 ; +if (walk->pte_batch) +return walk_pte_range_batch (pmd, addr, end, walk, private); + pte =pte_offset_map (pmd, addr); do { err = walk->pte_entry(pte, addr, addr + PAGE_SIZE, private);
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 14 lines · Peter Zijlstra
Quoted 5 lines · Hugh Dickins
The asynch code: perhaps not worth doing for
MADV_WILLNEEDalone, but might prove useful for more general use when swapping in. Not really the same as Con's swap prefetch, but worth looking at that for reference. But I guess this becomes a much bigger issue than you were intending to get into here.heh, yeah, got somewhat more complex that I'd hoped for.
last patch for today (not even compile tested), will do a proper patch and test it tomorrow.
Quoted 6 lines
---
A best effortMADV_WILLNEEDimplementation for anonymous memory.It adds a batch method to the page table walk routines so we can copy a few ptes while holding the kmap, which makes it possible to allocate the backing pages using
GFP_KERNEL.
Yuck. We actually need to just fix the atomic kmap issue in the existing pagemap code rather than add a new method, I think.
If performance of map/unmap is too slow at a granularity of 1, we can add some internal batching in the CONFIG_HIGHPTE case.
Signature · 7 lines
Mathematics is the supreme nostalgia of our time. -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 22 lines · Matt Mackall
Quoted 14 lines · Peter Zijlstra
Quoted 5 lines · Hugh Dickins
The asynch code: perhaps not worth doing for
MADV_WILLNEEDalone, but might prove useful for more general use when swapping in. Not really the same as Con's swap prefetch, but worth looking at that for reference. But I guess this becomes a much bigger issue than you were intending to get into here.heh, yeah, got somewhat more complex that I'd hoped for.
last patch for today (not even compile tested), will do a proper patch and test it tomorrow.
Quoted 6 lines
---
A best effortMADV_WILLNEEDimplementation for anonymous memory.It adds a batch method to the page table walk routines so we can copy a few ptes while holding the kmap, which makes it possible to allocate the backing pages using
GFP_KERNEL.
Quoted 5 lines
Yuck. We actually need to just fix the atomic kmap issue in the existing pagemap code rather than add a new method, I think.
If performance of map/unmap is too slow at a granularity of 1, we can add some internal batching in the
CONFIG_HIGHPTEcase.
OK, sounds like a much better idea indeed. Will implement that.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 8 lines · Hugh Dickins
Quoted 3 lines
Lennart asked for madvise(WILLNEED) to work on anonymous pages, he plans to use this to pre-fault pages. He currently uses: mlock/munlock for this purpose.
I certainly agree with this in principle: it just seems an unnecessary and surprising restriction to refuse on anonymous vmas; I guess the only reason for not adding this was not having anyone asking for it until now. Though, does Lennart realize he could use
MAP_POPULATEin the mmap?
Not really. First, if the mmap() is hidden somewhere in glibc (i.e. as part of malloc() or whatever) it's not really possible to do MAP_POPULATE. Also, I need this for some memory that is allocated during the whole runtime but only seldomly used. Thus I am happy if it is swapped out, but everytime I want to use it I want to make sure it is paged in before I pass it on to the RT thread. So, there's a mmap() during startup only, and then, during the whole runtime of my program I want to page in the memory again and again, with long intervals in between, but with no call to mmap()/munmap().
Lennart
Signature · 9 lines
Lennart Poettering Red Hat, Inc. lennart [at] poettering [dot] net ICQ# 11060553 http://0pointer.net/lennart/ GnuPG 0x1A015CC4 -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>