2005-04-17 06:20:36 +08:00
|
|
|
/*
|
|
|
|
* linux/mm/madvise.c
|
|
|
|
*
|
|
|
|
* Copyright (C) 1999 Linus Torvalds
|
|
|
|
* Copyright (C) 2002 Christoph Hellwig
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <linux/mman.h>
|
|
|
|
#include <linux/pagemap.h>
|
|
|
|
#include <linux/syscalls.h>
|
2005-06-22 08:14:37 +08:00
|
|
|
#include <linux/mempolicy.h>
|
2009-12-16 19:20:00 +08:00
|
|
|
#include <linux/page-isolation.h>
|
2005-04-17 06:20:36 +08:00
|
|
|
#include <linux/hugetlb.h>
|
2012-05-30 06:06:40 +08:00
|
|
|
#include <linux/falloc.h>
|
Detach sched.h from mm.h
First thing mm.h does is including sched.h solely for can_do_mlock() inline
function which has "current" dereference inside. By dealing with can_do_mlock()
mm.h can be detached from sched.h which is good. See below, why.
This patch
a) removes unconditional inclusion of sched.h from mm.h
b) makes can_do_mlock() normal function in mm/mlock.c
c) exports can_do_mlock() to not break compilation
d) adds sched.h inclusions back to files that were getting it indirectly.
e) adds less bloated headers to some files (asm/signal.h, jiffies.h) that were
getting them indirectly
Net result is:
a) mm.h users would get less code to open, read, preprocess, parse, ... if
they don't need sched.h
b) sched.h stops being dependency for significant number of files:
on x86_64 allmodconfig touching sched.h results in recompile of 4083 files,
after patch it's only 3744 (-8.3%).
Cross-compile tested on
all arm defconfigs, all mips defconfigs, all powerpc defconfigs,
alpha alpha-up
arm
i386 i386-up i386-defconfig i386-allnoconfig
ia64 ia64-up
m68k
mips
parisc parisc-up
powerpc powerpc-up
s390 s390-up
sparc sparc-up
sparc64 sparc64-up
um-x86_64
x86_64 x86_64-up x86_64-defconfig x86_64-allnoconfig
as well as my two usual configs.
Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2007-05-21 05:22:52 +08:00
|
|
|
#include <linux/sched.h>
|
2009-09-22 08:01:57 +08:00
|
|
|
#include <linux/ksm.h>
|
2012-05-30 06:06:40 +08:00
|
|
|
#include <linux/fs.h>
|
2012-07-06 07:00:11 +08:00
|
|
|
#include <linux/file.h>
|
2013-02-23 08:32:31 +08:00
|
|
|
#include <linux/blkdev.h>
|
|
|
|
#include <linux/swap.h>
|
|
|
|
#include <linux/swapops.h>
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2007-05-07 05:49:53 +08:00
|
|
|
/*
|
|
|
|
* Any behaviour which results in changes to the vma->vm_flags needs to
|
|
|
|
* take mmap_sem for writing. Others, which simply traverse vmas, need
|
|
|
|
* to only take it for reading.
|
|
|
|
*/
|
|
|
|
static int madvise_need_mmap_write(int behavior)
|
|
|
|
{
|
|
|
|
switch (behavior) {
|
|
|
|
case MADV_REMOVE:
|
|
|
|
case MADV_WILLNEED:
|
|
|
|
case MADV_DONTNEED:
|
|
|
|
return 0;
|
|
|
|
default:
|
|
|
|
/* be safe, default to 1. list exceptions explicitly */
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
/*
|
|
|
|
* We can potentially split a vm area into separate
|
|
|
|
* areas, each area with its own behavior.
|
|
|
|
*/
|
2013-09-12 05:20:15 +08:00
|
|
|
static long madvise_behavior(struct vm_area_struct *vma,
|
2005-06-22 08:14:37 +08:00
|
|
|
struct vm_area_struct **prev,
|
|
|
|
unsigned long start, unsigned long end, int behavior)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2013-09-12 05:20:15 +08:00
|
|
|
struct mm_struct *mm = vma->vm_mm;
|
2005-04-17 06:20:36 +08:00
|
|
|
int error = 0;
|
2005-06-22 08:14:37 +08:00
|
|
|
pgoff_t pgoff;
|
2009-09-22 08:01:52 +08:00
|
|
|
unsigned long new_flags = vma->vm_flags;
|
2005-06-22 08:14:36 +08:00
|
|
|
|
|
|
|
switch (behavior) {
|
2006-02-15 05:53:08 +08:00
|
|
|
case MADV_NORMAL:
|
|
|
|
new_flags = new_flags & ~VM_RAND_READ & ~VM_SEQ_READ;
|
|
|
|
break;
|
2005-06-22 08:14:36 +08:00
|
|
|
case MADV_SEQUENTIAL:
|
2006-02-15 05:53:08 +08:00
|
|
|
new_flags = (new_flags & ~VM_RAND_READ) | VM_SEQ_READ;
|
2005-06-22 08:14:36 +08:00
|
|
|
break;
|
|
|
|
case MADV_RANDOM:
|
2006-02-15 05:53:08 +08:00
|
|
|
new_flags = (new_flags & ~VM_SEQ_READ) | VM_RAND_READ;
|
2005-06-22 08:14:36 +08:00
|
|
|
break;
|
2006-02-15 05:53:08 +08:00
|
|
|
case MADV_DONTFORK:
|
|
|
|
new_flags |= VM_DONTCOPY;
|
|
|
|
break;
|
|
|
|
case MADV_DOFORK:
|
2009-09-22 08:01:52 +08:00
|
|
|
if (vma->vm_flags & VM_IO) {
|
|
|
|
error = -EINVAL;
|
|
|
|
goto out;
|
|
|
|
}
|
2006-02-15 05:53:08 +08:00
|
|
|
new_flags &= ~VM_DONTCOPY;
|
2005-06-22 08:14:36 +08:00
|
|
|
break;
|
2012-03-24 06:02:51 +08:00
|
|
|
case MADV_DONTDUMP:
|
2012-10-09 07:28:59 +08:00
|
|
|
new_flags |= VM_DONTDUMP;
|
2012-03-24 06:02:51 +08:00
|
|
|
break;
|
|
|
|
case MADV_DODUMP:
|
2012-10-09 07:28:59 +08:00
|
|
|
if (new_flags & VM_SPECIAL) {
|
|
|
|
error = -EINVAL;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
new_flags &= ~VM_DONTDUMP;
|
2012-03-24 06:02:51 +08:00
|
|
|
break;
|
2009-09-22 08:01:57 +08:00
|
|
|
case MADV_MERGEABLE:
|
|
|
|
case MADV_UNMERGEABLE:
|
|
|
|
error = ksm_madvise(vma, start, end, behavior, &new_flags);
|
|
|
|
if (error)
|
|
|
|
goto out;
|
|
|
|
break;
|
2011-01-14 07:46:55 +08:00
|
|
|
case MADV_HUGEPAGE:
|
2011-01-14 07:47:17 +08:00
|
|
|
case MADV_NOHUGEPAGE:
|
2011-01-14 07:47:18 +08:00
|
|
|
error = hugepage_madvise(vma, &new_flags, behavior);
|
2011-01-14 07:46:55 +08:00
|
|
|
if (error)
|
|
|
|
goto out;
|
|
|
|
break;
|
2005-06-22 08:14:36 +08:00
|
|
|
}
|
|
|
|
|
2005-06-22 08:14:37 +08:00
|
|
|
if (new_flags == vma->vm_flags) {
|
|
|
|
*prev = vma;
|
2005-09-04 06:54:53 +08:00
|
|
|
goto out;
|
2005-06-22 08:14:37 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
pgoff = vma->vm_pgoff + ((start - vma->vm_start) >> PAGE_SHIFT);
|
|
|
|
*prev = vma_merge(mm, *prev, start, end, new_flags, vma->anon_vma,
|
|
|
|
vma->vm_file, pgoff, vma_policy(vma));
|
|
|
|
if (*prev) {
|
|
|
|
vma = *prev;
|
|
|
|
goto success;
|
|
|
|
}
|
|
|
|
|
|
|
|
*prev = vma;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
if (start != vma->vm_start) {
|
|
|
|
error = split_vma(mm, vma, start, 1);
|
|
|
|
if (error)
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (end != vma->vm_end) {
|
|
|
|
error = split_vma(mm, vma, end, 0);
|
|
|
|
if (error)
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2005-09-04 06:54:53 +08:00
|
|
|
success:
|
2005-04-17 06:20:36 +08:00
|
|
|
/*
|
|
|
|
* vm_flags is protected by the mmap_sem held in write mode.
|
|
|
|
*/
|
2005-06-22 08:14:36 +08:00
|
|
|
vma->vm_flags = new_flags;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
out:
|
|
|
|
if (error == -ENOMEM)
|
|
|
|
error = -EAGAIN;
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
2013-02-23 08:32:31 +08:00
|
|
|
#ifdef CONFIG_SWAP
|
|
|
|
static int swapin_walk_pmd_entry(pmd_t *pmd, unsigned long start,
|
|
|
|
unsigned long end, struct mm_walk *walk)
|
|
|
|
{
|
|
|
|
pte_t *orig_pte;
|
|
|
|
struct vm_area_struct *vma = walk->private;
|
|
|
|
unsigned long index;
|
|
|
|
|
|
|
|
if (pmd_none_or_trans_huge_or_clear_bad(pmd))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
for (index = start; index != end; index += PAGE_SIZE) {
|
|
|
|
pte_t pte;
|
|
|
|
swp_entry_t entry;
|
|
|
|
struct page *page;
|
|
|
|
spinlock_t *ptl;
|
|
|
|
|
|
|
|
orig_pte = pte_offset_map_lock(vma->vm_mm, pmd, start, &ptl);
|
|
|
|
pte = *(orig_pte + ((index - start) / PAGE_SIZE));
|
|
|
|
pte_unmap_unlock(orig_pte, ptl);
|
|
|
|
|
2015-02-11 06:10:04 +08:00
|
|
|
if (pte_present(pte) || pte_none(pte))
|
2013-02-23 08:32:31 +08:00
|
|
|
continue;
|
|
|
|
entry = pte_to_swp_entry(pte);
|
|
|
|
if (unlikely(non_swap_entry(entry)))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
page = read_swap_cache_async(entry, GFP_HIGHUSER_MOVABLE,
|
|
|
|
vma, index);
|
|
|
|
if (page)
|
|
|
|
page_cache_release(page);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void force_swapin_readahead(struct vm_area_struct *vma,
|
|
|
|
unsigned long start, unsigned long end)
|
|
|
|
{
|
|
|
|
struct mm_walk walk = {
|
|
|
|
.mm = vma->vm_mm,
|
|
|
|
.pmd_entry = swapin_walk_pmd_entry,
|
|
|
|
.private = vma,
|
|
|
|
};
|
|
|
|
|
|
|
|
walk_page_range(start, end, &walk);
|
|
|
|
|
|
|
|
lru_add_drain(); /* Push any new pages onto the LRU now */
|
|
|
|
}
|
|
|
|
|
|
|
|
static void force_shm_swapin_readahead(struct vm_area_struct *vma,
|
|
|
|
unsigned long start, unsigned long end,
|
|
|
|
struct address_space *mapping)
|
|
|
|
{
|
|
|
|
pgoff_t index;
|
|
|
|
struct page *page;
|
|
|
|
swp_entry_t swap;
|
|
|
|
|
|
|
|
for (; start < end; start += PAGE_SIZE) {
|
|
|
|
index = ((start - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff;
|
|
|
|
|
2014-05-23 02:54:17 +08:00
|
|
|
page = find_get_entry(mapping, index);
|
2013-02-23 08:32:31 +08:00
|
|
|
if (!radix_tree_exceptional_entry(page)) {
|
|
|
|
if (page)
|
|
|
|
page_cache_release(page);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
swap = radix_to_swp_entry(page);
|
|
|
|
page = read_swap_cache_async(swap, GFP_HIGHUSER_MOVABLE,
|
|
|
|
NULL, 0);
|
|
|
|
if (page)
|
|
|
|
page_cache_release(page);
|
|
|
|
}
|
|
|
|
|
|
|
|
lru_add_drain(); /* Push any new pages onto the LRU now */
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_SWAP */
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
/*
|
|
|
|
* Schedule all required I/O operations. Do not wait for completion.
|
|
|
|
*/
|
2013-09-12 05:20:15 +08:00
|
|
|
static long madvise_willneed(struct vm_area_struct *vma,
|
|
|
|
struct vm_area_struct **prev,
|
2005-04-17 06:20:36 +08:00
|
|
|
unsigned long start, unsigned long end)
|
|
|
|
{
|
|
|
|
struct file *file = vma->vm_file;
|
|
|
|
|
2013-02-23 08:32:31 +08:00
|
|
|
#ifdef CONFIG_SWAP
|
2015-01-14 17:42:31 +08:00
|
|
|
if (!file) {
|
2013-02-23 08:32:31 +08:00
|
|
|
*prev = vma;
|
2015-01-14 17:42:31 +08:00
|
|
|
force_swapin_readahead(vma, start, end);
|
2013-02-23 08:32:31 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-01-14 17:42:31 +08:00
|
|
|
if (shmem_mapping(file->f_mapping)) {
|
|
|
|
*prev = vma;
|
|
|
|
force_shm_swapin_readahead(vma, start, end,
|
|
|
|
file->f_mapping);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#else
|
2005-10-11 23:29:06 +08:00
|
|
|
if (!file)
|
|
|
|
return -EBADF;
|
2015-01-14 17:42:31 +08:00
|
|
|
#endif
|
2005-10-11 23:29:06 +08:00
|
|
|
|
2008-04-28 17:13:02 +08:00
|
|
|
if (file->f_mapping->a_ops->get_xip_mem) {
|
2005-06-24 13:05:29 +08:00
|
|
|
/* no bad return value, but ignore advice */
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2005-06-22 08:14:37 +08:00
|
|
|
*prev = vma;
|
2005-04-17 06:20:36 +08:00
|
|
|
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;
|
|
|
|
|
2009-06-17 06:31:20 +08:00
|
|
|
force_page_cache_readahead(file->f_mapping, file, start, end - start);
|
2005-04-17 06:20:36 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Application no longer needs these pages. If the pages are dirty,
|
|
|
|
* it's OK to just throw them away. The app will be more careful about
|
|
|
|
* data it wants to keep. Be sure to free swap resources too. The
|
2008-07-30 13:33:39 +08:00
|
|
|
* zap_page_range call sets things up for shrink_active_list to actually free
|
2005-04-17 06:20:36 +08:00
|
|
|
* these pages later if no one else has touched them in the meantime,
|
|
|
|
* although we could add these pages to a global reuse list for
|
2008-07-30 13:33:39 +08:00
|
|
|
* shrink_active_list to pick up before reclaiming other pages.
|
2005-04-17 06:20:36 +08:00
|
|
|
*
|
|
|
|
* NB: This interface discards data rather than pushes it out to swap,
|
|
|
|
* as some implementations do. This has performance implications for
|
|
|
|
* applications like large transactional databases which want to discard
|
|
|
|
* pages in anonymous maps after committing to backing store the data
|
|
|
|
* that was kept in them. There is no reason to write this data out to
|
|
|
|
* the swap area if the application is discarding it.
|
|
|
|
*
|
|
|
|
* An interface that causes the system to free clean pages and flush
|
|
|
|
* dirty pages is already available as msync(MS_INVALIDATE).
|
|
|
|
*/
|
2013-09-12 05:20:15 +08:00
|
|
|
static long madvise_dontneed(struct vm_area_struct *vma,
|
|
|
|
struct vm_area_struct **prev,
|
2005-04-17 06:20:36 +08:00
|
|
|
unsigned long start, unsigned long end)
|
|
|
|
{
|
2005-06-22 08:14:37 +08:00
|
|
|
*prev = vma;
|
2005-11-29 06:34:23 +08:00
|
|
|
if (vma->vm_flags & (VM_LOCKED|VM_HUGETLB|VM_PFNMAP))
|
2005-04-17 06:20:36 +08:00
|
|
|
return -EINVAL;
|
|
|
|
|
2015-02-11 06:09:49 +08:00
|
|
|
zap_page_range(vma, start, end - start, NULL);
|
2005-04-17 06:20:36 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
[PATCH] madvise(MADV_REMOVE): remove pages from tmpfs shm backing store
Here is the patch to implement madvise(MADV_REMOVE) - which frees up a
given range of pages & its associated backing store. Current
implementation supports only shmfs/tmpfs and other filesystems return
-ENOSYS.
"Some app allocates large tmpfs files, then when some task quits and some
client disconnect, some memory can be released. However the only way to
release tmpfs-swap is to MADV_REMOVE". - Andrea Arcangeli
Databases want to use this feature to drop a section of their bufferpool
(shared memory segments) - without writing back to disk/swap space.
This feature is also useful for supporting hot-plug memory on UML.
Concerns raised by Andrew Morton:
- "We have no plan for holepunching! If we _do_ have such a plan (or
might in the future) then what would the API look like? I think
sys_holepunch(fd, start, len), so we should start out with that."
- Using madvise is very weird, because people will ask "why do I need to
mmap my file before I can stick a hole in it?"
- None of the other madvise operations call into the filesystem in this
manner. A broad question is: is this capability an MM operation or a
filesytem operation? truncate, for example, is a filesystem operation
which sometimes has MM side-effects. madvise is an mm operation and with
this patch, it gains FS side-effects, only they're really, really
significant ones."
Comments:
- Andrea suggested the fs operation too but then it's more efficient to
have it as a mm operation with fs side effects, because they don't
immediatly know fd and physical offset of the range. It's possible to
fixup in userland and to use the fs operation but it's more expensive,
the vmas are already in the kernel and we can use them.
Short term plan & Future Direction:
- We seem to need this interface only for shmfs/tmpfs files in the short
term. We have to add hooks into the filesystem for correctness and
completeness. This is what this patch does.
- In the future, plan is to support both fs and mmap apis also. This
also involves (other) filesystem specific functions to be implemented.
- Current patch doesn't support VM_NONLINEAR - which can be addressed in
the future.
Signed-off-by: Badari Pulavarty <pbadari@us.ibm.com>
Cc: Hugh Dickins <hugh@veritas.com>
Cc: Andrea Arcangeli <andrea@suse.de>
Cc: Michael Kerrisk <mtk-manpages@gmx.net>
Cc: Ulrich Drepper <drepper@redhat.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
2006-01-06 16:10:38 +08:00
|
|
|
/*
|
|
|
|
* Application wants to free up the pages and associated backing store.
|
|
|
|
* This is effectively punching a hole into the middle of a file.
|
|
|
|
*/
|
|
|
|
static long madvise_remove(struct vm_area_struct *vma,
|
2007-03-17 05:38:10 +08:00
|
|
|
struct vm_area_struct **prev,
|
[PATCH] madvise(MADV_REMOVE): remove pages from tmpfs shm backing store
Here is the patch to implement madvise(MADV_REMOVE) - which frees up a
given range of pages & its associated backing store. Current
implementation supports only shmfs/tmpfs and other filesystems return
-ENOSYS.
"Some app allocates large tmpfs files, then when some task quits and some
client disconnect, some memory can be released. However the only way to
release tmpfs-swap is to MADV_REMOVE". - Andrea Arcangeli
Databases want to use this feature to drop a section of their bufferpool
(shared memory segments) - without writing back to disk/swap space.
This feature is also useful for supporting hot-plug memory on UML.
Concerns raised by Andrew Morton:
- "We have no plan for holepunching! If we _do_ have such a plan (or
might in the future) then what would the API look like? I think
sys_holepunch(fd, start, len), so we should start out with that."
- Using madvise is very weird, because people will ask "why do I need to
mmap my file before I can stick a hole in it?"
- None of the other madvise operations call into the filesystem in this
manner. A broad question is: is this capability an MM operation or a
filesytem operation? truncate, for example, is a filesystem operation
which sometimes has MM side-effects. madvise is an mm operation and with
this patch, it gains FS side-effects, only they're really, really
significant ones."
Comments:
- Andrea suggested the fs operation too but then it's more efficient to
have it as a mm operation with fs side effects, because they don't
immediatly know fd and physical offset of the range. It's possible to
fixup in userland and to use the fs operation but it's more expensive,
the vmas are already in the kernel and we can use them.
Short term plan & Future Direction:
- We seem to need this interface only for shmfs/tmpfs files in the short
term. We have to add hooks into the filesystem for correctness and
completeness. This is what this patch does.
- In the future, plan is to support both fs and mmap apis also. This
also involves (other) filesystem specific functions to be implemented.
- Current patch doesn't support VM_NONLINEAR - which can be addressed in
the future.
Signed-off-by: Badari Pulavarty <pbadari@us.ibm.com>
Cc: Hugh Dickins <hugh@veritas.com>
Cc: Andrea Arcangeli <andrea@suse.de>
Cc: Michael Kerrisk <mtk-manpages@gmx.net>
Cc: Ulrich Drepper <drepper@redhat.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
2006-01-06 16:10:38 +08:00
|
|
|
unsigned long start, unsigned long end)
|
|
|
|
{
|
2012-05-30 06:06:40 +08:00
|
|
|
loff_t offset;
|
2007-03-29 16:20:38 +08:00
|
|
|
int error;
|
2012-07-06 07:00:11 +08:00
|
|
|
struct file *f;
|
[PATCH] madvise(MADV_REMOVE): remove pages from tmpfs shm backing store
Here is the patch to implement madvise(MADV_REMOVE) - which frees up a
given range of pages & its associated backing store. Current
implementation supports only shmfs/tmpfs and other filesystems return
-ENOSYS.
"Some app allocates large tmpfs files, then when some task quits and some
client disconnect, some memory can be released. However the only way to
release tmpfs-swap is to MADV_REMOVE". - Andrea Arcangeli
Databases want to use this feature to drop a section of their bufferpool
(shared memory segments) - without writing back to disk/swap space.
This feature is also useful for supporting hot-plug memory on UML.
Concerns raised by Andrew Morton:
- "We have no plan for holepunching! If we _do_ have such a plan (or
might in the future) then what would the API look like? I think
sys_holepunch(fd, start, len), so we should start out with that."
- Using madvise is very weird, because people will ask "why do I need to
mmap my file before I can stick a hole in it?"
- None of the other madvise operations call into the filesystem in this
manner. A broad question is: is this capability an MM operation or a
filesytem operation? truncate, for example, is a filesystem operation
which sometimes has MM side-effects. madvise is an mm operation and with
this patch, it gains FS side-effects, only they're really, really
significant ones."
Comments:
- Andrea suggested the fs operation too but then it's more efficient to
have it as a mm operation with fs side effects, because they don't
immediatly know fd and physical offset of the range. It's possible to
fixup in userland and to use the fs operation but it's more expensive,
the vmas are already in the kernel and we can use them.
Short term plan & Future Direction:
- We seem to need this interface only for shmfs/tmpfs files in the short
term. We have to add hooks into the filesystem for correctness and
completeness. This is what this patch does.
- In the future, plan is to support both fs and mmap apis also. This
also involves (other) filesystem specific functions to be implemented.
- Current patch doesn't support VM_NONLINEAR - which can be addressed in
the future.
Signed-off-by: Badari Pulavarty <pbadari@us.ibm.com>
Cc: Hugh Dickins <hugh@veritas.com>
Cc: Andrea Arcangeli <andrea@suse.de>
Cc: Michael Kerrisk <mtk-manpages@gmx.net>
Cc: Ulrich Drepper <drepper@redhat.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
2006-01-06 16:10:38 +08:00
|
|
|
|
2007-03-29 16:20:38 +08:00
|
|
|
*prev = NULL; /* tell sys_madvise we drop mmap_sem */
|
2007-03-17 05:38:10 +08:00
|
|
|
|
2015-02-11 06:10:04 +08:00
|
|
|
if (vma->vm_flags & (VM_LOCKED | VM_HUGETLB))
|
[PATCH] madvise(MADV_REMOVE): remove pages from tmpfs shm backing store
Here is the patch to implement madvise(MADV_REMOVE) - which frees up a
given range of pages & its associated backing store. Current
implementation supports only shmfs/tmpfs and other filesystems return
-ENOSYS.
"Some app allocates large tmpfs files, then when some task quits and some
client disconnect, some memory can be released. However the only way to
release tmpfs-swap is to MADV_REMOVE". - Andrea Arcangeli
Databases want to use this feature to drop a section of their bufferpool
(shared memory segments) - without writing back to disk/swap space.
This feature is also useful for supporting hot-plug memory on UML.
Concerns raised by Andrew Morton:
- "We have no plan for holepunching! If we _do_ have such a plan (or
might in the future) then what would the API look like? I think
sys_holepunch(fd, start, len), so we should start out with that."
- Using madvise is very weird, because people will ask "why do I need to
mmap my file before I can stick a hole in it?"
- None of the other madvise operations call into the filesystem in this
manner. A broad question is: is this capability an MM operation or a
filesytem operation? truncate, for example, is a filesystem operation
which sometimes has MM side-effects. madvise is an mm operation and with
this patch, it gains FS side-effects, only they're really, really
significant ones."
Comments:
- Andrea suggested the fs operation too but then it's more efficient to
have it as a mm operation with fs side effects, because they don't
immediatly know fd and physical offset of the range. It's possible to
fixup in userland and to use the fs operation but it's more expensive,
the vmas are already in the kernel and we can use them.
Short term plan & Future Direction:
- We seem to need this interface only for shmfs/tmpfs files in the short
term. We have to add hooks into the filesystem for correctness and
completeness. This is what this patch does.
- In the future, plan is to support both fs and mmap apis also. This
also involves (other) filesystem specific functions to be implemented.
- Current patch doesn't support VM_NONLINEAR - which can be addressed in
the future.
Signed-off-by: Badari Pulavarty <pbadari@us.ibm.com>
Cc: Hugh Dickins <hugh@veritas.com>
Cc: Andrea Arcangeli <andrea@suse.de>
Cc: Michael Kerrisk <mtk-manpages@gmx.net>
Cc: Ulrich Drepper <drepper@redhat.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
2006-01-06 16:10:38 +08:00
|
|
|
return -EINVAL;
|
|
|
|
|
2012-07-06 07:00:11 +08:00
|
|
|
f = vma->vm_file;
|
|
|
|
|
|
|
|
if (!f || !f->f_mapping || !f->f_mapping->host) {
|
[PATCH] madvise(MADV_REMOVE): remove pages from tmpfs shm backing store
Here is the patch to implement madvise(MADV_REMOVE) - which frees up a
given range of pages & its associated backing store. Current
implementation supports only shmfs/tmpfs and other filesystems return
-ENOSYS.
"Some app allocates large tmpfs files, then when some task quits and some
client disconnect, some memory can be released. However the only way to
release tmpfs-swap is to MADV_REMOVE". - Andrea Arcangeli
Databases want to use this feature to drop a section of their bufferpool
(shared memory segments) - without writing back to disk/swap space.
This feature is also useful for supporting hot-plug memory on UML.
Concerns raised by Andrew Morton:
- "We have no plan for holepunching! If we _do_ have such a plan (or
might in the future) then what would the API look like? I think
sys_holepunch(fd, start, len), so we should start out with that."
- Using madvise is very weird, because people will ask "why do I need to
mmap my file before I can stick a hole in it?"
- None of the other madvise operations call into the filesystem in this
manner. A broad question is: is this capability an MM operation or a
filesytem operation? truncate, for example, is a filesystem operation
which sometimes has MM side-effects. madvise is an mm operation and with
this patch, it gains FS side-effects, only they're really, really
significant ones."
Comments:
- Andrea suggested the fs operation too but then it's more efficient to
have it as a mm operation with fs side effects, because they don't
immediatly know fd and physical offset of the range. It's possible to
fixup in userland and to use the fs operation but it's more expensive,
the vmas are already in the kernel and we can use them.
Short term plan & Future Direction:
- We seem to need this interface only for shmfs/tmpfs files in the short
term. We have to add hooks into the filesystem for correctness and
completeness. This is what this patch does.
- In the future, plan is to support both fs and mmap apis also. This
also involves (other) filesystem specific functions to be implemented.
- Current patch doesn't support VM_NONLINEAR - which can be addressed in
the future.
Signed-off-by: Badari Pulavarty <pbadari@us.ibm.com>
Cc: Hugh Dickins <hugh@veritas.com>
Cc: Andrea Arcangeli <andrea@suse.de>
Cc: Michael Kerrisk <mtk-manpages@gmx.net>
Cc: Ulrich Drepper <drepper@redhat.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
2006-01-06 16:10:38 +08:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2006-04-18 05:46:32 +08:00
|
|
|
if ((vma->vm_flags & (VM_SHARED|VM_WRITE)) != (VM_SHARED|VM_WRITE))
|
|
|
|
return -EACCES;
|
|
|
|
|
[PATCH] madvise(MADV_REMOVE): remove pages from tmpfs shm backing store
Here is the patch to implement madvise(MADV_REMOVE) - which frees up a
given range of pages & its associated backing store. Current
implementation supports only shmfs/tmpfs and other filesystems return
-ENOSYS.
"Some app allocates large tmpfs files, then when some task quits and some
client disconnect, some memory can be released. However the only way to
release tmpfs-swap is to MADV_REMOVE". - Andrea Arcangeli
Databases want to use this feature to drop a section of their bufferpool
(shared memory segments) - without writing back to disk/swap space.
This feature is also useful for supporting hot-plug memory on UML.
Concerns raised by Andrew Morton:
- "We have no plan for holepunching! If we _do_ have such a plan (or
might in the future) then what would the API look like? I think
sys_holepunch(fd, start, len), so we should start out with that."
- Using madvise is very weird, because people will ask "why do I need to
mmap my file before I can stick a hole in it?"
- None of the other madvise operations call into the filesystem in this
manner. A broad question is: is this capability an MM operation or a
filesytem operation? truncate, for example, is a filesystem operation
which sometimes has MM side-effects. madvise is an mm operation and with
this patch, it gains FS side-effects, only they're really, really
significant ones."
Comments:
- Andrea suggested the fs operation too but then it's more efficient to
have it as a mm operation with fs side effects, because they don't
immediatly know fd and physical offset of the range. It's possible to
fixup in userland and to use the fs operation but it's more expensive,
the vmas are already in the kernel and we can use them.
Short term plan & Future Direction:
- We seem to need this interface only for shmfs/tmpfs files in the short
term. We have to add hooks into the filesystem for correctness and
completeness. This is what this patch does.
- In the future, plan is to support both fs and mmap apis also. This
also involves (other) filesystem specific functions to be implemented.
- Current patch doesn't support VM_NONLINEAR - which can be addressed in
the future.
Signed-off-by: Badari Pulavarty <pbadari@us.ibm.com>
Cc: Hugh Dickins <hugh@veritas.com>
Cc: Andrea Arcangeli <andrea@suse.de>
Cc: Michael Kerrisk <mtk-manpages@gmx.net>
Cc: Ulrich Drepper <drepper@redhat.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
2006-01-06 16:10:38 +08:00
|
|
|
offset = (loff_t)(start - vma->vm_start)
|
|
|
|
+ ((loff_t)vma->vm_pgoff << PAGE_SHIFT);
|
2007-03-29 16:20:38 +08:00
|
|
|
|
2012-07-06 07:00:11 +08:00
|
|
|
/*
|
|
|
|
* Filesystem's fallocate may need to take i_mutex. We need to
|
|
|
|
* explicitly grab a reference because the vma (and hence the
|
|
|
|
* vma's reference to the file) can go away as soon as we drop
|
|
|
|
* mmap_sem.
|
|
|
|
*/
|
|
|
|
get_file(f);
|
2007-05-07 05:49:53 +08:00
|
|
|
up_read(¤t->mm->mmap_sem);
|
2014-11-08 03:44:25 +08:00
|
|
|
error = vfs_fallocate(f,
|
2012-05-30 06:06:40 +08:00
|
|
|
FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
|
|
|
|
offset, end - start);
|
2012-07-06 07:00:11 +08:00
|
|
|
fput(f);
|
2007-05-07 05:49:53 +08:00
|
|
|
down_read(¤t->mm->mmap_sem);
|
2007-03-29 16:20:38 +08:00
|
|
|
return error;
|
[PATCH] madvise(MADV_REMOVE): remove pages from tmpfs shm backing store
Here is the patch to implement madvise(MADV_REMOVE) - which frees up a
given range of pages & its associated backing store. Current
implementation supports only shmfs/tmpfs and other filesystems return
-ENOSYS.
"Some app allocates large tmpfs files, then when some task quits and some
client disconnect, some memory can be released. However the only way to
release tmpfs-swap is to MADV_REMOVE". - Andrea Arcangeli
Databases want to use this feature to drop a section of their bufferpool
(shared memory segments) - without writing back to disk/swap space.
This feature is also useful for supporting hot-plug memory on UML.
Concerns raised by Andrew Morton:
- "We have no plan for holepunching! If we _do_ have such a plan (or
might in the future) then what would the API look like? I think
sys_holepunch(fd, start, len), so we should start out with that."
- Using madvise is very weird, because people will ask "why do I need to
mmap my file before I can stick a hole in it?"
- None of the other madvise operations call into the filesystem in this
manner. A broad question is: is this capability an MM operation or a
filesytem operation? truncate, for example, is a filesystem operation
which sometimes has MM side-effects. madvise is an mm operation and with
this patch, it gains FS side-effects, only they're really, really
significant ones."
Comments:
- Andrea suggested the fs operation too but then it's more efficient to
have it as a mm operation with fs side effects, because they don't
immediatly know fd and physical offset of the range. It's possible to
fixup in userland and to use the fs operation but it's more expensive,
the vmas are already in the kernel and we can use them.
Short term plan & Future Direction:
- We seem to need this interface only for shmfs/tmpfs files in the short
term. We have to add hooks into the filesystem for correctness and
completeness. This is what this patch does.
- In the future, plan is to support both fs and mmap apis also. This
also involves (other) filesystem specific functions to be implemented.
- Current patch doesn't support VM_NONLINEAR - which can be addressed in
the future.
Signed-off-by: Badari Pulavarty <pbadari@us.ibm.com>
Cc: Hugh Dickins <hugh@veritas.com>
Cc: Andrea Arcangeli <andrea@suse.de>
Cc: Michael Kerrisk <mtk-manpages@gmx.net>
Cc: Ulrich Drepper <drepper@redhat.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
2006-01-06 16:10:38 +08:00
|
|
|
}
|
|
|
|
|
2009-09-16 17:50:17 +08:00
|
|
|
#ifdef CONFIG_MEMORY_FAILURE
|
|
|
|
/*
|
|
|
|
* Error injection support for memory error handling.
|
|
|
|
*/
|
2009-12-16 19:20:00 +08:00
|
|
|
static int madvise_hwpoison(int bhv, unsigned long start, unsigned long end)
|
2009-09-16 17:50:17 +08:00
|
|
|
{
|
2013-10-01 04:45:21 +08:00
|
|
|
struct page *p;
|
2009-09-16 17:50:17 +08:00
|
|
|
if (!capable(CAP_SYS_ADMIN))
|
|
|
|
return -EPERM;
|
2013-10-01 04:45:21 +08:00
|
|
|
for (; start < end; start += PAGE_SIZE <<
|
|
|
|
compound_order(compound_head(p))) {
|
2013-09-12 05:23:03 +08:00
|
|
|
int ret;
|
|
|
|
|
|
|
|
ret = get_user_pages_fast(start, 1, 0, &p);
|
2009-09-16 17:50:17 +08:00
|
|
|
if (ret != 1)
|
|
|
|
return ret;
|
2013-09-12 05:23:03 +08:00
|
|
|
|
mm/hwpoison.c: fix held reference count after unpoisoning empty zero page
madvise hwpoison inject will poison the read-only empty zero page if there
is no write access before poison. Empty zero page reference count will be
increased for hwpoison, subsequent poison zero page will return directly
since page has already been set PG_hwpoison, however, page reference count
is still increased by get_user_pages_fast. The unpoison process will
unpoison the empty zero page and decrease the reference count successfully
for the fist time, however, subsequent unpoison empty zero page will
return directly since page has already been unpoisoned and without
decrease the page reference count of empty zero page.
This patch fixes it by make madvise_hwpoison() put a page and return
immediately (without calling memory_failure() or soft_offline_page()) when
the page is already hwpoisoned.
Testcase:
#define _GNU_SOURCE
#include <stdlib.h>
#include <stdio.h>
#include <sys/mman.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <errno.h>
#define PAGES_TO_TEST 3
#define PAGE_SIZE 4096
int main(void)
{
char *mem;
int i;
mem = mmap(NULL, PAGES_TO_TEST * PAGE_SIZE,
PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
if (madvise(mem, PAGES_TO_TEST * PAGE_SIZE, MADV_HWPOISON) == -1)
return -1;
munmap(mem, PAGES_TO_TEST * PAGE_SIZE);
return 0;
}
Add printk to dump page reference count:
[ 93.075959] Injecting memory failure for page 0x19d0 at 0xb77d8000
[ 93.076207] MCE 0x19d0: non LRU page recovery: Ignored
[ 93.076209] pfn 0x19d0, page count = 1 after memory failure
[ 93.076220] Injecting memory failure for page 0x19d0 at 0xb77d9000
[ 93.076221] MCE 0x19d0: already hardware poisoned
[ 93.076222] pfn 0x19d0, page count = 2 after memory failure
[ 93.076224] Injecting memory failure for page 0x19d0 at 0xb77da000
[ 93.076224] MCE 0x19d0: already hardware poisoned
[ 93.076225] pfn 0x19d0, page count = 3 after memory failure
Signed-off-by: Wanpeng Li <liwanp@linux.vnet.ibm.com>
Suggested-by: Naoya Horiguchi <n-horiguchi@ah.jp.nec.com>
Cc: Andi Kleen <andi@firstfloor.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2013-09-12 05:22:59 +08:00
|
|
|
if (PageHWPoison(p)) {
|
|
|
|
put_page(p);
|
|
|
|
continue;
|
|
|
|
}
|
2009-12-16 19:20:00 +08:00
|
|
|
if (bhv == MADV_SOFT_OFFLINE) {
|
2013-09-12 05:22:57 +08:00
|
|
|
pr_info("Soft offlining page %#lx at %#lx\n",
|
2009-12-16 19:20:00 +08:00
|
|
|
page_to_pfn(p), start);
|
|
|
|
ret = soft_offline_page(p, MF_COUNT_INCREASED);
|
|
|
|
if (ret)
|
2013-09-12 05:23:02 +08:00
|
|
|
return ret;
|
2009-12-16 19:20:00 +08:00
|
|
|
continue;
|
|
|
|
}
|
2013-09-12 05:22:57 +08:00
|
|
|
pr_info("Injecting memory failure for page %#lx at %#lx\n",
|
2009-09-16 17:50:17 +08:00
|
|
|
page_to_pfn(p), start);
|
|
|
|
/* Ignore return value for now */
|
2011-12-16 02:48:12 +08:00
|
|
|
memory_failure(page_to_pfn(p), 0, MF_COUNT_INCREASED);
|
2009-09-16 17:50:17 +08:00
|
|
|
}
|
2013-09-12 05:23:03 +08:00
|
|
|
return 0;
|
2009-09-16 17:50:17 +08:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2005-07-28 02:43:59 +08:00
|
|
|
static long
|
|
|
|
madvise_vma(struct vm_area_struct *vma, struct vm_area_struct **prev,
|
|
|
|
unsigned long start, unsigned long end, int behavior)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
|
|
|
switch (behavior) {
|
[PATCH] madvise(MADV_REMOVE): remove pages from tmpfs shm backing store
Here is the patch to implement madvise(MADV_REMOVE) - which frees up a
given range of pages & its associated backing store. Current
implementation supports only shmfs/tmpfs and other filesystems return
-ENOSYS.
"Some app allocates large tmpfs files, then when some task quits and some
client disconnect, some memory can be released. However the only way to
release tmpfs-swap is to MADV_REMOVE". - Andrea Arcangeli
Databases want to use this feature to drop a section of their bufferpool
(shared memory segments) - without writing back to disk/swap space.
This feature is also useful for supporting hot-plug memory on UML.
Concerns raised by Andrew Morton:
- "We have no plan for holepunching! If we _do_ have such a plan (or
might in the future) then what would the API look like? I think
sys_holepunch(fd, start, len), so we should start out with that."
- Using madvise is very weird, because people will ask "why do I need to
mmap my file before I can stick a hole in it?"
- None of the other madvise operations call into the filesystem in this
manner. A broad question is: is this capability an MM operation or a
filesytem operation? truncate, for example, is a filesystem operation
which sometimes has MM side-effects. madvise is an mm operation and with
this patch, it gains FS side-effects, only they're really, really
significant ones."
Comments:
- Andrea suggested the fs operation too but then it's more efficient to
have it as a mm operation with fs side effects, because they don't
immediatly know fd and physical offset of the range. It's possible to
fixup in userland and to use the fs operation but it's more expensive,
the vmas are already in the kernel and we can use them.
Short term plan & Future Direction:
- We seem to need this interface only for shmfs/tmpfs files in the short
term. We have to add hooks into the filesystem for correctness and
completeness. This is what this patch does.
- In the future, plan is to support both fs and mmap apis also. This
also involves (other) filesystem specific functions to be implemented.
- Current patch doesn't support VM_NONLINEAR - which can be addressed in
the future.
Signed-off-by: Badari Pulavarty <pbadari@us.ibm.com>
Cc: Hugh Dickins <hugh@veritas.com>
Cc: Andrea Arcangeli <andrea@suse.de>
Cc: Michael Kerrisk <mtk-manpages@gmx.net>
Cc: Ulrich Drepper <drepper@redhat.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
2006-01-06 16:10:38 +08:00
|
|
|
case MADV_REMOVE:
|
2009-09-22 08:01:52 +08:00
|
|
|
return madvise_remove(vma, prev, start, end);
|
2005-04-17 06:20:36 +08:00
|
|
|
case MADV_WILLNEED:
|
2009-09-22 08:01:52 +08:00
|
|
|
return madvise_willneed(vma, prev, start, end);
|
2005-04-17 06:20:36 +08:00
|
|
|
case MADV_DONTNEED:
|
2009-09-22 08:01:52 +08:00
|
|
|
return madvise_dontneed(vma, prev, start, end);
|
2005-04-17 06:20:36 +08:00
|
|
|
default:
|
2009-09-22 08:01:52 +08:00
|
|
|
return madvise_behavior(vma, prev, start, end, behavior);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-06-17 06:32:38 +08:00
|
|
|
static int
|
|
|
|
madvise_behavior_valid(int behavior)
|
|
|
|
{
|
|
|
|
switch (behavior) {
|
|
|
|
case MADV_DOFORK:
|
|
|
|
case MADV_DONTFORK:
|
|
|
|
case MADV_NORMAL:
|
|
|
|
case MADV_SEQUENTIAL:
|
|
|
|
case MADV_RANDOM:
|
|
|
|
case MADV_REMOVE:
|
|
|
|
case MADV_WILLNEED:
|
|
|
|
case MADV_DONTNEED:
|
2009-09-22 08:01:57 +08:00
|
|
|
#ifdef CONFIG_KSM
|
|
|
|
case MADV_MERGEABLE:
|
|
|
|
case MADV_UNMERGEABLE:
|
2011-01-14 07:46:55 +08:00
|
|
|
#endif
|
|
|
|
#ifdef CONFIG_TRANSPARENT_HUGEPAGE
|
|
|
|
case MADV_HUGEPAGE:
|
2011-01-14 07:47:17 +08:00
|
|
|
case MADV_NOHUGEPAGE:
|
2009-09-22 08:01:57 +08:00
|
|
|
#endif
|
2012-03-24 06:02:51 +08:00
|
|
|
case MADV_DONTDUMP:
|
|
|
|
case MADV_DODUMP:
|
2009-06-17 06:32:38 +08:00
|
|
|
return 1;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
2009-09-22 08:01:52 +08:00
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
/*
|
|
|
|
* The madvise(2) system call.
|
|
|
|
*
|
|
|
|
* Applications can use madvise() to advise the kernel how it should
|
|
|
|
* handle paging I/O in this VM area. The idea is to help the kernel
|
|
|
|
* use appropriate read-ahead and caching techniques. The information
|
|
|
|
* provided is advisory only, and can be safely disregarded by the
|
|
|
|
* kernel without affecting the correct operation of the application.
|
|
|
|
*
|
|
|
|
* behavior values:
|
|
|
|
* MADV_NORMAL - the default behavior is to read clusters. This
|
|
|
|
* results in some read-ahead and read-behind.
|
|
|
|
* MADV_RANDOM - the system should read the minimum amount of data
|
|
|
|
* on any access, since it is unlikely that the appli-
|
|
|
|
* cation will need more than what it asks for.
|
|
|
|
* MADV_SEQUENTIAL - pages in the given range will probably be accessed
|
|
|
|
* once, so they can be aggressively read ahead, and
|
|
|
|
* can be freed soon after they are accessed.
|
|
|
|
* MADV_WILLNEED - the application is notifying the system to read
|
|
|
|
* some pages ahead.
|
|
|
|
* MADV_DONTNEED - the application is finished with the given range,
|
|
|
|
* so the kernel can free resources associated with it.
|
[PATCH] madvise(MADV_REMOVE): remove pages from tmpfs shm backing store
Here is the patch to implement madvise(MADV_REMOVE) - which frees up a
given range of pages & its associated backing store. Current
implementation supports only shmfs/tmpfs and other filesystems return
-ENOSYS.
"Some app allocates large tmpfs files, then when some task quits and some
client disconnect, some memory can be released. However the only way to
release tmpfs-swap is to MADV_REMOVE". - Andrea Arcangeli
Databases want to use this feature to drop a section of their bufferpool
(shared memory segments) - without writing back to disk/swap space.
This feature is also useful for supporting hot-plug memory on UML.
Concerns raised by Andrew Morton:
- "We have no plan for holepunching! If we _do_ have such a plan (or
might in the future) then what would the API look like? I think
sys_holepunch(fd, start, len), so we should start out with that."
- Using madvise is very weird, because people will ask "why do I need to
mmap my file before I can stick a hole in it?"
- None of the other madvise operations call into the filesystem in this
manner. A broad question is: is this capability an MM operation or a
filesytem operation? truncate, for example, is a filesystem operation
which sometimes has MM side-effects. madvise is an mm operation and with
this patch, it gains FS side-effects, only they're really, really
significant ones."
Comments:
- Andrea suggested the fs operation too but then it's more efficient to
have it as a mm operation with fs side effects, because they don't
immediatly know fd and physical offset of the range. It's possible to
fixup in userland and to use the fs operation but it's more expensive,
the vmas are already in the kernel and we can use them.
Short term plan & Future Direction:
- We seem to need this interface only for shmfs/tmpfs files in the short
term. We have to add hooks into the filesystem for correctness and
completeness. This is what this patch does.
- In the future, plan is to support both fs and mmap apis also. This
also involves (other) filesystem specific functions to be implemented.
- Current patch doesn't support VM_NONLINEAR - which can be addressed in
the future.
Signed-off-by: Badari Pulavarty <pbadari@us.ibm.com>
Cc: Hugh Dickins <hugh@veritas.com>
Cc: Andrea Arcangeli <andrea@suse.de>
Cc: Michael Kerrisk <mtk-manpages@gmx.net>
Cc: Ulrich Drepper <drepper@redhat.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
2006-01-06 16:10:38 +08:00
|
|
|
* MADV_REMOVE - the application wants to free up the given range of
|
|
|
|
* pages and associated backing store.
|
2009-09-22 08:01:52 +08:00
|
|
|
* MADV_DONTFORK - omit this area from child's address space when forking:
|
|
|
|
* typically, to avoid COWing pages pinned by get_user_pages().
|
|
|
|
* MADV_DOFORK - cancel MADV_DONTFORK: no longer omit this area when forking.
|
2009-09-22 08:01:57 +08:00
|
|
|
* MADV_MERGEABLE - the application recommends that KSM try to merge pages in
|
|
|
|
* this area with pages of identical content from other such areas.
|
|
|
|
* MADV_UNMERGEABLE- cancel MADV_MERGEABLE: no longer merge pages with others.
|
2005-04-17 06:20:36 +08:00
|
|
|
*
|
|
|
|
* return values:
|
|
|
|
* zero - success
|
|
|
|
* -EINVAL - start + len < 0, start is not page-aligned,
|
|
|
|
* "behavior" is not a valid value, or application
|
|
|
|
* is attempting to release locked or shared pages.
|
|
|
|
* -ENOMEM - addresses in the specified range are not currently
|
|
|
|
* mapped, or are outside the AS of the process.
|
|
|
|
* -EIO - an I/O error occurred while paging in data.
|
|
|
|
* -EBADF - map exists, but area maps something that isn't a file.
|
|
|
|
* -EAGAIN - a kernel resource was temporarily unavailable.
|
|
|
|
*/
|
2009-01-14 21:14:16 +08:00
|
|
|
SYSCALL_DEFINE3(madvise, unsigned long, start, size_t, len_in, int, behavior)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2005-06-22 08:14:37 +08:00
|
|
|
unsigned long end, tmp;
|
2013-09-12 05:20:15 +08:00
|
|
|
struct vm_area_struct *vma, *prev;
|
2005-04-17 06:20:36 +08:00
|
|
|
int unmapped_error = 0;
|
|
|
|
int error = -EINVAL;
|
2007-07-16 14:38:21 +08:00
|
|
|
int write;
|
2005-04-17 06:20:36 +08:00
|
|
|
size_t len;
|
2013-02-23 08:32:31 +08:00
|
|
|
struct blk_plug plug;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2009-09-16 17:50:17 +08:00
|
|
|
#ifdef CONFIG_MEMORY_FAILURE
|
2009-12-16 19:20:00 +08:00
|
|
|
if (behavior == MADV_HWPOISON || behavior == MADV_SOFT_OFFLINE)
|
|
|
|
return madvise_hwpoison(behavior, start, start+len_in);
|
2009-09-16 17:50:17 +08:00
|
|
|
#endif
|
2009-06-17 06:32:38 +08:00
|
|
|
if (!madvise_behavior_valid(behavior))
|
|
|
|
return error;
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
if (start & ~PAGE_MASK)
|
2013-04-30 06:08:23 +08:00
|
|
|
return error;
|
2005-04-17 06:20:36 +08:00
|
|
|
len = (len_in + ~PAGE_MASK) & PAGE_MASK;
|
|
|
|
|
|
|
|
/* Check to see whether len was rounded up from small -ve to zero */
|
|
|
|
if (len_in && !len)
|
2013-04-30 06:08:23 +08:00
|
|
|
return error;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
end = start + len;
|
|
|
|
if (end < start)
|
2013-04-30 06:08:23 +08:00
|
|
|
return error;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
error = 0;
|
|
|
|
if (end == start)
|
2013-04-30 06:08:23 +08:00
|
|
|
return error;
|
|
|
|
|
|
|
|
write = madvise_need_mmap_write(behavior);
|
|
|
|
if (write)
|
|
|
|
down_write(¤t->mm->mmap_sem);
|
|
|
|
else
|
|
|
|
down_read(¤t->mm->mmap_sem);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* If the interval [start,end) covers some unmapped address
|
|
|
|
* ranges, just ignore them, but return -ENOMEM at the end.
|
2005-06-22 08:14:37 +08:00
|
|
|
* - different from the way of handling in mlock etc.
|
2005-04-17 06:20:36 +08:00
|
|
|
*/
|
2005-06-22 08:14:37 +08:00
|
|
|
vma = find_vma_prev(current->mm, start, &prev);
|
2005-09-04 06:54:53 +08:00
|
|
|
if (vma && start > vma->vm_start)
|
|
|
|
prev = vma;
|
|
|
|
|
2013-02-23 08:32:31 +08:00
|
|
|
blk_start_plug(&plug);
|
2005-04-17 06:20:36 +08:00
|
|
|
for (;;) {
|
|
|
|
/* Still start < end. */
|
|
|
|
error = -ENOMEM;
|
|
|
|
if (!vma)
|
2013-04-30 06:08:23 +08:00
|
|
|
goto out;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2005-06-22 08:14:37 +08:00
|
|
|
/* Here start < (end|vma->vm_end). */
|
2005-04-17 06:20:36 +08:00
|
|
|
if (start < vma->vm_start) {
|
|
|
|
unmapped_error = -ENOMEM;
|
|
|
|
start = vma->vm_start;
|
2005-06-22 08:14:37 +08:00
|
|
|
if (start >= end)
|
2013-04-30 06:08:23 +08:00
|
|
|
goto out;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
2005-06-22 08:14:37 +08:00
|
|
|
/* Here vma->vm_start <= start < (end|vma->vm_end) */
|
|
|
|
tmp = vma->vm_end;
|
|
|
|
if (end < tmp)
|
|
|
|
tmp = end;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2005-06-22 08:14:37 +08:00
|
|
|
/* Here vma->vm_start <= start < tmp <= (end|vma->vm_end). */
|
|
|
|
error = madvise_vma(vma, &prev, start, tmp, behavior);
|
2005-04-17 06:20:36 +08:00
|
|
|
if (error)
|
2013-04-30 06:08:23 +08:00
|
|
|
goto out;
|
2005-06-22 08:14:37 +08:00
|
|
|
start = tmp;
|
2007-03-29 16:20:38 +08:00
|
|
|
if (prev && start < prev->vm_end)
|
2005-06-22 08:14:37 +08:00
|
|
|
start = prev->vm_end;
|
|
|
|
error = unmapped_error;
|
|
|
|
if (start >= end)
|
2013-04-30 06:08:23 +08:00
|
|
|
goto out;
|
2007-03-29 16:20:38 +08:00
|
|
|
if (prev)
|
|
|
|
vma = prev->vm_next;
|
|
|
|
else /* madvise_remove dropped mmap_sem */
|
|
|
|
vma = find_vma(current->mm, start);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
out:
|
2013-04-30 06:08:23 +08:00
|
|
|
blk_finish_plug(&plug);
|
2007-07-16 14:38:21 +08:00
|
|
|
if (write)
|
2007-05-07 05:49:53 +08:00
|
|
|
up_write(¤t->mm->mmap_sem);
|
|
|
|
else
|
|
|
|
up_read(¤t->mm->mmap_sem);
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
return error;
|
|
|
|
}
|