2005-04-17 06:20:36 +08:00
|
|
|
/*
|
|
|
|
* linux/mm/filemap.c
|
|
|
|
*
|
|
|
|
* Copyright (C) 1994-1999 Linus Torvalds
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This file handles the generic file mmap semantics used by
|
|
|
|
* most "normal" filesystems (but you don't /have/ to use this:
|
|
|
|
* the NFS filesystem used to do this differently, for example)
|
|
|
|
*/
|
2011-10-16 14:01:52 +08:00
|
|
|
#include <linux/export.h>
|
2005-04-17 06:20:36 +08:00
|
|
|
#include <linux/compiler.h>
|
2016-01-23 07:10:40 +08:00
|
|
|
#include <linux/dax.h>
|
2005-04-17 06:20:36 +08:00
|
|
|
#include <linux/fs.h>
|
2006-06-23 17:04:16 +08:00
|
|
|
#include <linux/uaccess.h>
|
2006-01-12 04:17:46 +08:00
|
|
|
#include <linux/capability.h>
|
2005-04-17 06:20:36 +08:00
|
|
|
#include <linux/kernel_stat.h>
|
include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit slab.h inclusion from percpu.h
percpu.h is included by sched.h and module.h and thus ends up being
included when building most .c files. percpu.h includes slab.h which
in turn includes gfp.h making everything defined by the two files
universally available and complicating inclusion dependencies.
percpu.h -> slab.h dependency is about to be removed. Prepare for
this change by updating users of gfp and slab facilities include those
headers directly instead of assuming availability. As this conversion
needs to touch large number of source files, the following script is
used as the basis of conversion.
http://userweb.kernel.org/~tj/misc/slabh-sweep.py
The script does the followings.
* Scan files for gfp and slab usages and update includes such that
only the necessary includes are there. ie. if only gfp is used,
gfp.h, if slab is used, slab.h.
* When the script inserts a new include, it looks at the include
blocks and try to put the new include such that its order conforms
to its surrounding. It's put in the include block which contains
core kernel includes, in the same order that the rest are ordered -
alphabetical, Christmas tree, rev-Xmas-tree or at the end if there
doesn't seem to be any matching order.
* If the script can't find a place to put a new include (mostly
because the file doesn't have fitting include block), it prints out
an error message indicating which .h file needs to be added to the
file.
The conversion was done in the following steps.
1. The initial automatic conversion of all .c files updated slightly
over 4000 files, deleting around 700 includes and adding ~480 gfp.h
and ~3000 slab.h inclusions. The script emitted errors for ~400
files.
2. Each error was manually checked. Some didn't need the inclusion,
some needed manual addition while adding it to implementation .h or
embedding .c file was more appropriate for others. This step added
inclusions to around 150 files.
3. The script was run again and the output was compared to the edits
from #2 to make sure no file was left behind.
4. Several build tests were done and a couple of problems were fixed.
e.g. lib/decompress_*.c used malloc/free() wrappers around slab
APIs requiring slab.h to be added manually.
5. The script was run on all .h files but without automatically
editing them as sprinkling gfp.h and slab.h inclusions around .h
files could easily lead to inclusion dependency hell. Most gfp.h
inclusion directives were ignored as stuff from gfp.h was usually
wildly available and often used in preprocessor macros. Each
slab.h inclusion directive was examined and added manually as
necessary.
6. percpu.h was updated not to include slab.h.
7. Build test were done on the following configurations and failures
were fixed. CONFIG_GCOV_KERNEL was turned off for all tests (as my
distributed build env didn't work with gcov compiles) and a few
more options had to be turned off depending on archs to make things
build (like ipr on powerpc/64 which failed due to missing writeq).
* x86 and x86_64 UP and SMP allmodconfig and a custom test config.
* powerpc and powerpc64 SMP allmodconfig
* sparc and sparc64 SMP allmodconfig
* ia64 SMP allmodconfig
* s390 SMP allmodconfig
* alpha SMP allmodconfig
* um on x86_64 SMP allmodconfig
8. percpu.h modifications were reverted so that it could be applied as
a separate patch and serve as bisection point.
Given the fact that I had only a couple of failures from tests on step
6, I'm fairly confident about the coverage of this conversion patch.
If there is a breakage, it's likely to be something in one of the arch
headers which should be easily discoverable easily on most builds of
the specific arch.
Signed-off-by: Tejun Heo <tj@kernel.org>
Guess-its-ok-by: Christoph Lameter <cl@linux-foundation.org>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Lee Schermerhorn <Lee.Schermerhorn@hp.com>
2010-03-24 16:04:11 +08:00
|
|
|
#include <linux/gfp.h>
|
2005-04-17 06:20:36 +08:00
|
|
|
#include <linux/mm.h>
|
|
|
|
#include <linux/swap.h>
|
|
|
|
#include <linux/mman.h>
|
|
|
|
#include <linux/pagemap.h>
|
|
|
|
#include <linux/file.h>
|
|
|
|
#include <linux/uio.h>
|
|
|
|
#include <linux/hash.h>
|
|
|
|
#include <linux/writeback.h>
|
2007-10-19 05:47:32 +08:00
|
|
|
#include <linux/backing-dev.h>
|
2005-04-17 06:20:36 +08:00
|
|
|
#include <linux/pagevec.h>
|
|
|
|
#include <linux/blkdev.h>
|
|
|
|
#include <linux/security.h>
|
2006-03-24 19:16:04 +08:00
|
|
|
#include <linux/cpuset.h>
|
2007-10-16 16:24:59 +08:00
|
|
|
#include <linux/hardirq.h> /* for BUG_ON(!in_atomic()) only */
|
mm: memcontrol: rewrite charge API
These patches rework memcg charge lifetime to integrate more naturally
with the lifetime of user pages. This drastically simplifies the code and
reduces charging and uncharging overhead. The most expensive part of
charging and uncharging is the page_cgroup bit spinlock, which is removed
entirely after this series.
Here are the top-10 profile entries of a stress test that reads a 128G
sparse file on a freshly booted box, without even a dedicated cgroup (i.e.
executing in the root memcg). Before:
15.36% cat [kernel.kallsyms] [k] copy_user_generic_string
13.31% cat [kernel.kallsyms] [k] memset
11.48% cat [kernel.kallsyms] [k] do_mpage_readpage
4.23% cat [kernel.kallsyms] [k] get_page_from_freelist
2.38% cat [kernel.kallsyms] [k] put_page
2.32% cat [kernel.kallsyms] [k] __mem_cgroup_commit_charge
2.18% kswapd0 [kernel.kallsyms] [k] __mem_cgroup_uncharge_common
1.92% kswapd0 [kernel.kallsyms] [k] shrink_page_list
1.86% cat [kernel.kallsyms] [k] __radix_tree_lookup
1.62% cat [kernel.kallsyms] [k] __pagevec_lru_add_fn
After:
15.67% cat [kernel.kallsyms] [k] copy_user_generic_string
13.48% cat [kernel.kallsyms] [k] memset
11.42% cat [kernel.kallsyms] [k] do_mpage_readpage
3.98% cat [kernel.kallsyms] [k] get_page_from_freelist
2.46% cat [kernel.kallsyms] [k] put_page
2.13% kswapd0 [kernel.kallsyms] [k] shrink_page_list
1.88% cat [kernel.kallsyms] [k] __radix_tree_lookup
1.67% cat [kernel.kallsyms] [k] __pagevec_lru_add_fn
1.39% kswapd0 [kernel.kallsyms] [k] free_pcppages_bulk
1.30% cat [kernel.kallsyms] [k] kfree
As you can see, the memcg footprint has shrunk quite a bit.
text data bss dec hex filename
37970 9892 400 48262 bc86 mm/memcontrol.o.old
35239 9892 400 45531 b1db mm/memcontrol.o
This patch (of 4):
The memcg charge API charges pages before they are rmapped - i.e. have an
actual "type" - and so every callsite needs its own set of charge and
uncharge functions to know what type is being operated on. Worse,
uncharge has to happen from a context that is still type-specific, rather
than at the end of the page's lifetime with exclusive access, and so
requires a lot of synchronization.
Rewrite the charge API to provide a generic set of try_charge(),
commit_charge() and cancel_charge() transaction operations, much like
what's currently done for swap-in:
mem_cgroup_try_charge() attempts to reserve a charge, reclaiming
pages from the memcg if necessary.
mem_cgroup_commit_charge() commits the page to the charge once it
has a valid page->mapping and PageAnon() reliably tells the type.
mem_cgroup_cancel_charge() aborts the transaction.
This reduces the charge API and enables subsequent patches to
drastically simplify uncharging.
As pages need to be committed after rmap is established but before they
are added to the LRU, page_add_new_anon_rmap() must stop doing LRU
additions again. Revive lru_cache_add_active_or_unevictable().
[hughd@google.com: fix shmem_unuse]
[hughd@google.com: Add comments on the private use of -EAGAIN]
Signed-off-by: Johannes Weiner <hannes@cmpxchg.org>
Acked-by: Michal Hocko <mhocko@suse.cz>
Cc: Tejun Heo <tj@kernel.org>
Cc: Vladimir Davydov <vdavydov@parallels.com>
Signed-off-by: Hugh Dickins <hughd@google.com>
Cc: Naoya Horiguchi <n-horiguchi@ah.jp.nec.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2014-08-09 05:19:20 +08:00
|
|
|
#include <linux/hugetlb.h>
|
2008-02-07 16:13:53 +08:00
|
|
|
#include <linux/memcontrol.h>
|
2011-05-27 00:01:43 +08:00
|
|
|
#include <linux/cleancache.h>
|
2014-04-08 06:37:19 +08:00
|
|
|
#include <linux/rmap.h>
|
2006-03-22 16:08:33 +08:00
|
|
|
#include "internal.h"
|
|
|
|
|
2013-04-30 06:06:10 +08:00
|
|
|
#define CREATE_TRACE_POINTS
|
|
|
|
#include <trace/events/filemap.h>
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
/*
|
|
|
|
* FIXME: remove all knowledge of the buffer layer from the core VM
|
|
|
|
*/
|
2009-08-18 01:52:36 +08:00
|
|
|
#include <linux/buffer_head.h> /* for try_to_free_buffers */
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
#include <asm/mman.h>
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Shared mappings implemented 30.11.1994. It's not fully working yet,
|
|
|
|
* though.
|
|
|
|
*
|
|
|
|
* Shared mappings now work. 15.8.1995 Bruno.
|
|
|
|
*
|
|
|
|
* finished 'unifying' the page and buffer cache and SMP-threaded the
|
|
|
|
* page-cache, 21.05.1999, Ingo Molnar <mingo@redhat.com>
|
|
|
|
*
|
|
|
|
* SMP-threaded pagemap-LRU 1999, Andrea Arcangeli <andrea@suse.de>
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Lock ordering:
|
|
|
|
*
|
2014-12-13 08:54:24 +08:00
|
|
|
* ->i_mmap_rwsem (truncate_pagecache)
|
2005-04-17 06:20:36 +08:00
|
|
|
* ->private_lock (__free_pte->__set_page_dirty_buffers)
|
[PATCH] swap: swap_lock replace list+device
The idea of a swap_device_lock per device, and a swap_list_lock over them all,
is appealing; but in practice almost every holder of swap_device_lock must
already hold swap_list_lock, which defeats the purpose of the split.
The only exceptions have been swap_duplicate, valid_swaphandles and an
untrodden path in try_to_unuse (plus a few places added in this series).
valid_swaphandles doesn't show up high in profiles, but swap_duplicate does
demand attention. However, with the hold time in get_swap_pages so much
reduced, I've not yet found a load and set of swap device priorities to show
even swap_duplicate benefitting from the split. Certainly the split is mere
overhead in the common case of a single swap device.
So, replace swap_list_lock and swap_device_lock by spinlock_t swap_lock
(generally we seem to prefer an _ in the name, and not hide in a macro).
If someone can show a regression in swap_duplicate, then probably we should
add a hashlock for the swap_map entries alone (shorts being anatomic), so as
to help the case of the single swap device too.
Signed-off-by: Hugh Dickins <hugh@veritas.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
2005-09-04 06:54:41 +08:00
|
|
|
* ->swap_lock (exclusive_swap_page, others)
|
|
|
|
* ->mapping->tree_lock
|
2005-04-17 06:20:36 +08:00
|
|
|
*
|
2006-01-10 07:59:24 +08:00
|
|
|
* ->i_mutex
|
2014-12-13 08:54:24 +08:00
|
|
|
* ->i_mmap_rwsem (truncate->unmap_mapping_range)
|
2005-04-17 06:20:36 +08:00
|
|
|
*
|
|
|
|
* ->mmap_sem
|
2014-12-13 08:54:24 +08:00
|
|
|
* ->i_mmap_rwsem
|
2005-10-30 09:16:41 +08:00
|
|
|
* ->page_table_lock or pte_lock (various, mainly in memory.c)
|
2005-04-17 06:20:36 +08:00
|
|
|
* ->mapping->tree_lock (arch-dependent flush_dcache_mmap_lock)
|
|
|
|
*
|
|
|
|
* ->mmap_sem
|
|
|
|
* ->lock_page (access_process_vm)
|
|
|
|
*
|
2014-02-12 11:36:48 +08:00
|
|
|
* ->i_mutex (generic_perform_write)
|
2006-10-20 14:29:10 +08:00
|
|
|
* ->mmap_sem (fault_in_pages_readable->do_page_fault)
|
2005-04-17 06:20:36 +08:00
|
|
|
*
|
2011-04-22 08:19:44 +08:00
|
|
|
* bdi->wb.list_lock
|
2011-03-22 19:23:41 +08:00
|
|
|
* sb_lock (fs/fs-writeback.c)
|
2005-04-17 06:20:36 +08:00
|
|
|
* ->mapping->tree_lock (__sync_single_inode)
|
|
|
|
*
|
2014-12-13 08:54:24 +08:00
|
|
|
* ->i_mmap_rwsem
|
2005-04-17 06:20:36 +08:00
|
|
|
* ->anon_vma.lock (vma_adjust)
|
|
|
|
*
|
|
|
|
* ->anon_vma.lock
|
2005-10-30 09:16:41 +08:00
|
|
|
* ->page_table_lock or pte_lock (anon_vma_prepare and various)
|
2005-04-17 06:20:36 +08:00
|
|
|
*
|
2005-10-30 09:16:41 +08:00
|
|
|
* ->page_table_lock or pte_lock
|
[PATCH] swap: swap_lock replace list+device
The idea of a swap_device_lock per device, and a swap_list_lock over them all,
is appealing; but in practice almost every holder of swap_device_lock must
already hold swap_list_lock, which defeats the purpose of the split.
The only exceptions have been swap_duplicate, valid_swaphandles and an
untrodden path in try_to_unuse (plus a few places added in this series).
valid_swaphandles doesn't show up high in profiles, but swap_duplicate does
demand attention. However, with the hold time in get_swap_pages so much
reduced, I've not yet found a load and set of swap device priorities to show
even swap_duplicate benefitting from the split. Certainly the split is mere
overhead in the common case of a single swap device.
So, replace swap_list_lock and swap_device_lock by spinlock_t swap_lock
(generally we seem to prefer an _ in the name, and not hide in a macro).
If someone can show a regression in swap_duplicate, then probably we should
add a hashlock for the swap_map entries alone (shorts being anatomic), so as
to help the case of the single swap device too.
Signed-off-by: Hugh Dickins <hugh@veritas.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
2005-09-04 06:54:41 +08:00
|
|
|
* ->swap_lock (try_to_unmap_one)
|
2005-04-17 06:20:36 +08:00
|
|
|
* ->private_lock (try_to_unmap_one)
|
|
|
|
* ->tree_lock (try_to_unmap_one)
|
|
|
|
* ->zone.lru_lock (follow_page->mark_page_accessed)
|
2006-01-19 09:42:27 +08:00
|
|
|
* ->zone.lru_lock (check_pte_range->isolate_lru_page)
|
2005-04-17 06:20:36 +08:00
|
|
|
* ->private_lock (page_remove_rmap->set_page_dirty)
|
|
|
|
* ->tree_lock (page_remove_rmap->set_page_dirty)
|
2011-04-22 08:19:44 +08:00
|
|
|
* bdi.wb->list_lock (page_remove_rmap->set_page_dirty)
|
2011-03-22 19:23:36 +08:00
|
|
|
* ->inode->i_lock (page_remove_rmap->set_page_dirty)
|
memcg: add per cgroup dirty page accounting
When modifying PG_Dirty on cached file pages, update the new
MEM_CGROUP_STAT_DIRTY counter. This is done in the same places where
global NR_FILE_DIRTY is managed. The new memcg stat is visible in the
per memcg memory.stat cgroupfs file. The most recent past attempt at
this was http://thread.gmane.org/gmane.linux.kernel.cgroups/8632
The new accounting supports future efforts to add per cgroup dirty
page throttling and writeback. It also helps an administrator break
down a container's memory usage and provides evidence to understand
memcg oom kills (the new dirty count is included in memcg oom kill
messages).
The ability to move page accounting between memcg
(memory.move_charge_at_immigrate) makes this accounting more
complicated than the global counter. The existing
mem_cgroup_{begin,end}_page_stat() lock is used to serialize move
accounting with stat updates.
Typical update operation:
memcg = mem_cgroup_begin_page_stat(page)
if (TestSetPageDirty()) {
[...]
mem_cgroup_update_page_stat(memcg)
}
mem_cgroup_end_page_stat(memcg)
Summary of mem_cgroup_end_page_stat() overhead:
- Without CONFIG_MEMCG it's a no-op
- With CONFIG_MEMCG and no inter memcg task movement, it's just
rcu_read_lock()
- With CONFIG_MEMCG and inter memcg task movement, it's
rcu_read_lock() + spin_lock_irqsave()
A memcg parameter is added to several routines because their callers
now grab mem_cgroup_begin_page_stat() which returns the memcg later
needed by for mem_cgroup_update_page_stat().
Because mem_cgroup_begin_page_stat() may disable interrupts, some
adjustments are needed:
- move __mark_inode_dirty() from __set_page_dirty() to its caller.
__mark_inode_dirty() locking does not want interrupts disabled.
- use spin_lock_irqsave(tree_lock) rather than spin_lock_irq() in
__delete_from_page_cache(), replace_page_cache_page(),
invalidate_complete_page2(), and __remove_mapping().
text data bss dec hex filename
8925147 1774832 1785856 12485835 be84cb vmlinux-!CONFIG_MEMCG-before
8925339 1774832 1785856 12486027 be858b vmlinux-!CONFIG_MEMCG-after
+192 text bytes
8965977 1784992 1785856 12536825 bf4bf9 vmlinux-CONFIG_MEMCG-before
8966750 1784992 1785856 12537598 bf4efe vmlinux-CONFIG_MEMCG-after
+773 text bytes
Performance tests run on v4.0-rc1-36-g4f671fe2f952. Lower is better for
all metrics, they're all wall clock or cycle counts. The read and write
fault benchmarks just measure fault time, they do not include I/O time.
* CONFIG_MEMCG not set:
baseline patched
kbuild 1m25.030000(+-0.088% 3 samples) 1m25.426667(+-0.120% 3 samples)
dd write 100 MiB 0.859211561 +-15.10% 0.874162885 +-15.03%
dd write 200 MiB 1.670653105 +-17.87% 1.669384764 +-11.99%
dd write 1000 MiB 8.434691190 +-14.15% 8.474733215 +-14.77%
read fault cycles 254.0(+-0.000% 10 samples) 253.0(+-0.000% 10 samples)
write fault cycles 2021.2(+-3.070% 10 samples) 1984.5(+-1.036% 10 samples)
* CONFIG_MEMCG=y root_memcg:
baseline patched
kbuild 1m25.716667(+-0.105% 3 samples) 1m25.686667(+-0.153% 3 samples)
dd write 100 MiB 0.855650830 +-14.90% 0.887557919 +-14.90%
dd write 200 MiB 1.688322953 +-12.72% 1.667682724 +-13.33%
dd write 1000 MiB 8.418601605 +-14.30% 8.673532299 +-15.00%
read fault cycles 266.0(+-0.000% 10 samples) 266.0(+-0.000% 10 samples)
write fault cycles 2051.7(+-1.349% 10 samples) 2049.6(+-1.686% 10 samples)
* CONFIG_MEMCG=y non-root_memcg:
baseline patched
kbuild 1m26.120000(+-0.273% 3 samples) 1m25.763333(+-0.127% 3 samples)
dd write 100 MiB 0.861723964 +-15.25% 0.818129350 +-14.82%
dd write 200 MiB 1.669887569 +-13.30% 1.698645885 +-13.27%
dd write 1000 MiB 8.383191730 +-14.65% 8.351742280 +-14.52%
read fault cycles 265.7(+-0.172% 10 samples) 267.0(+-0.000% 10 samples)
write fault cycles 2070.6(+-1.512% 10 samples) 2084.4(+-2.148% 10 samples)
As expected anon page faults are not affected by this patch.
tj: Updated to apply on top of the recent cancel_dirty_page() changes.
Signed-off-by: Sha Zhengju <handai.szj@gmail.com>
Signed-off-by: Greg Thelen <gthelen@google.com>
Signed-off-by: Tejun Heo <tj@kernel.org>
Signed-off-by: Jens Axboe <axboe@fb.com>
2015-05-23 05:13:16 +08:00
|
|
|
* ->memcg->move_lock (page_remove_rmap->mem_cgroup_begin_page_stat)
|
2011-04-22 08:19:44 +08:00
|
|
|
* bdi.wb->list_lock (zap_pte_range->set_page_dirty)
|
2011-03-22 19:23:36 +08:00
|
|
|
* ->inode->i_lock (zap_pte_range->set_page_dirty)
|
2005-04-17 06:20:36 +08:00
|
|
|
* ->private_lock (zap_pte_range->__set_page_dirty_buffers)
|
|
|
|
*
|
2014-12-13 08:54:24 +08:00
|
|
|
* ->i_mmap_rwsem
|
2012-03-22 07:34:09 +08:00
|
|
|
* ->tasklist_lock (memory_failure, collect_procs_ao)
|
2005-04-17 06:20:36 +08:00
|
|
|
*/
|
|
|
|
|
2014-04-04 05:47:49 +08:00
|
|
|
static void page_cache_tree_delete(struct address_space *mapping,
|
|
|
|
struct page *page, void *shadow)
|
|
|
|
{
|
mm: keep page cache radix tree nodes in check
Previously, page cache radix tree nodes were freed after reclaim emptied
out their page pointers. But now reclaim stores shadow entries in their
place, which are only reclaimed when the inodes themselves are
reclaimed. This is problematic for bigger files that are still in use
after they have a significant amount of their cache reclaimed, without
any of those pages actually refaulting. The shadow entries will just
sit there and waste memory. In the worst case, the shadow entries will
accumulate until the machine runs out of memory.
To get this under control, the VM will track radix tree nodes
exclusively containing shadow entries on a per-NUMA node list. Per-NUMA
rather than global because we expect the radix tree nodes themselves to
be allocated node-locally and we want to reduce cross-node references of
otherwise independent cache workloads. A simple shrinker will then
reclaim these nodes on memory pressure.
A few things need to be stored in the radix tree node to implement the
shadow node LRU and allow tree deletions coming from the list:
1. There is no index available that would describe the reverse path
from the node up to the tree root, which is needed to perform a
deletion. To solve this, encode in each node its offset inside the
parent. This can be stored in the unused upper bits of the same
member that stores the node's height at no extra space cost.
2. The number of shadow entries needs to be counted in addition to the
regular entries, to quickly detect when the node is ready to go to
the shadow node LRU list. The current entry count is an unsigned
int but the maximum number of entries is 64, so a shadow counter
can easily be stored in the unused upper bits.
3. Tree modification needs tree lock and tree root, which are located
in the address space, so store an address_space backpointer in the
node. The parent pointer of the node is in a union with the 2-word
rcu_head, so the backpointer comes at no extra cost as well.
4. The node needs to be linked to an LRU list, which requires a list
head inside the node. This does increase the size of the node, but
it does not change the number of objects that fit into a slab page.
[akpm@linux-foundation.org: export the right function]
Signed-off-by: Johannes Weiner <hannes@cmpxchg.org>
Reviewed-by: Rik van Riel <riel@redhat.com>
Reviewed-by: Minchan Kim <minchan@kernel.org>
Cc: Andrea Arcangeli <aarcange@redhat.com>
Cc: Bob Liu <bob.liu@oracle.com>
Cc: Christoph Hellwig <hch@infradead.org>
Cc: Dave Chinner <david@fromorbit.com>
Cc: Greg Thelen <gthelen@google.com>
Cc: Hugh Dickins <hughd@google.com>
Cc: Jan Kara <jack@suse.cz>
Cc: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
Cc: Luigi Semenzato <semenzato@google.com>
Cc: Mel Gorman <mgorman@suse.de>
Cc: Metin Doslu <metin@citusdata.com>
Cc: Michel Lespinasse <walken@google.com>
Cc: Ozgun Erdogan <ozgun@citusdata.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Roman Gushchin <klamm@yandex-team.ru>
Cc: Ryan Mallon <rmallon@gmail.com>
Cc: Tejun Heo <tj@kernel.org>
Cc: Vlastimil Babka <vbabka@suse.cz>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2014-04-04 05:47:56 +08:00
|
|
|
struct radix_tree_node *node;
|
|
|
|
unsigned long index;
|
|
|
|
unsigned int offset;
|
|
|
|
unsigned int tag;
|
|
|
|
void **slot;
|
2014-04-04 05:47:49 +08:00
|
|
|
|
mm: keep page cache radix tree nodes in check
Previously, page cache radix tree nodes were freed after reclaim emptied
out their page pointers. But now reclaim stores shadow entries in their
place, which are only reclaimed when the inodes themselves are
reclaimed. This is problematic for bigger files that are still in use
after they have a significant amount of their cache reclaimed, without
any of those pages actually refaulting. The shadow entries will just
sit there and waste memory. In the worst case, the shadow entries will
accumulate until the machine runs out of memory.
To get this under control, the VM will track radix tree nodes
exclusively containing shadow entries on a per-NUMA node list. Per-NUMA
rather than global because we expect the radix tree nodes themselves to
be allocated node-locally and we want to reduce cross-node references of
otherwise independent cache workloads. A simple shrinker will then
reclaim these nodes on memory pressure.
A few things need to be stored in the radix tree node to implement the
shadow node LRU and allow tree deletions coming from the list:
1. There is no index available that would describe the reverse path
from the node up to the tree root, which is needed to perform a
deletion. To solve this, encode in each node its offset inside the
parent. This can be stored in the unused upper bits of the same
member that stores the node's height at no extra space cost.
2. The number of shadow entries needs to be counted in addition to the
regular entries, to quickly detect when the node is ready to go to
the shadow node LRU list. The current entry count is an unsigned
int but the maximum number of entries is 64, so a shadow counter
can easily be stored in the unused upper bits.
3. Tree modification needs tree lock and tree root, which are located
in the address space, so store an address_space backpointer in the
node. The parent pointer of the node is in a union with the 2-word
rcu_head, so the backpointer comes at no extra cost as well.
4. The node needs to be linked to an LRU list, which requires a list
head inside the node. This does increase the size of the node, but
it does not change the number of objects that fit into a slab page.
[akpm@linux-foundation.org: export the right function]
Signed-off-by: Johannes Weiner <hannes@cmpxchg.org>
Reviewed-by: Rik van Riel <riel@redhat.com>
Reviewed-by: Minchan Kim <minchan@kernel.org>
Cc: Andrea Arcangeli <aarcange@redhat.com>
Cc: Bob Liu <bob.liu@oracle.com>
Cc: Christoph Hellwig <hch@infradead.org>
Cc: Dave Chinner <david@fromorbit.com>
Cc: Greg Thelen <gthelen@google.com>
Cc: Hugh Dickins <hughd@google.com>
Cc: Jan Kara <jack@suse.cz>
Cc: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
Cc: Luigi Semenzato <semenzato@google.com>
Cc: Mel Gorman <mgorman@suse.de>
Cc: Metin Doslu <metin@citusdata.com>
Cc: Michel Lespinasse <walken@google.com>
Cc: Ozgun Erdogan <ozgun@citusdata.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Roman Gushchin <klamm@yandex-team.ru>
Cc: Ryan Mallon <rmallon@gmail.com>
Cc: Tejun Heo <tj@kernel.org>
Cc: Vlastimil Babka <vbabka@suse.cz>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2014-04-04 05:47:56 +08:00
|
|
|
VM_BUG_ON(!PageLocked(page));
|
|
|
|
|
|
|
|
__radix_tree_lookup(&mapping->page_tree, page->index, &node, &slot);
|
|
|
|
|
|
|
|
if (shadow) {
|
2016-01-23 07:10:40 +08:00
|
|
|
mapping->nrexceptional++;
|
2014-04-04 05:47:49 +08:00
|
|
|
/*
|
2016-01-23 07:10:40 +08:00
|
|
|
* Make sure the nrexceptional update is committed before
|
2014-04-04 05:47:49 +08:00
|
|
|
* the nrpages update so that final truncate racing
|
|
|
|
* with reclaim does not see both counters 0 at the
|
|
|
|
* same time and miss a shadow entry.
|
|
|
|
*/
|
|
|
|
smp_wmb();
|
mm: keep page cache radix tree nodes in check
Previously, page cache radix tree nodes were freed after reclaim emptied
out their page pointers. But now reclaim stores shadow entries in their
place, which are only reclaimed when the inodes themselves are
reclaimed. This is problematic for bigger files that are still in use
after they have a significant amount of their cache reclaimed, without
any of those pages actually refaulting. The shadow entries will just
sit there and waste memory. In the worst case, the shadow entries will
accumulate until the machine runs out of memory.
To get this under control, the VM will track radix tree nodes
exclusively containing shadow entries on a per-NUMA node list. Per-NUMA
rather than global because we expect the radix tree nodes themselves to
be allocated node-locally and we want to reduce cross-node references of
otherwise independent cache workloads. A simple shrinker will then
reclaim these nodes on memory pressure.
A few things need to be stored in the radix tree node to implement the
shadow node LRU and allow tree deletions coming from the list:
1. There is no index available that would describe the reverse path
from the node up to the tree root, which is needed to perform a
deletion. To solve this, encode in each node its offset inside the
parent. This can be stored in the unused upper bits of the same
member that stores the node's height at no extra space cost.
2. The number of shadow entries needs to be counted in addition to the
regular entries, to quickly detect when the node is ready to go to
the shadow node LRU list. The current entry count is an unsigned
int but the maximum number of entries is 64, so a shadow counter
can easily be stored in the unused upper bits.
3. Tree modification needs tree lock and tree root, which are located
in the address space, so store an address_space backpointer in the
node. The parent pointer of the node is in a union with the 2-word
rcu_head, so the backpointer comes at no extra cost as well.
4. The node needs to be linked to an LRU list, which requires a list
head inside the node. This does increase the size of the node, but
it does not change the number of objects that fit into a slab page.
[akpm@linux-foundation.org: export the right function]
Signed-off-by: Johannes Weiner <hannes@cmpxchg.org>
Reviewed-by: Rik van Riel <riel@redhat.com>
Reviewed-by: Minchan Kim <minchan@kernel.org>
Cc: Andrea Arcangeli <aarcange@redhat.com>
Cc: Bob Liu <bob.liu@oracle.com>
Cc: Christoph Hellwig <hch@infradead.org>
Cc: Dave Chinner <david@fromorbit.com>
Cc: Greg Thelen <gthelen@google.com>
Cc: Hugh Dickins <hughd@google.com>
Cc: Jan Kara <jack@suse.cz>
Cc: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
Cc: Luigi Semenzato <semenzato@google.com>
Cc: Mel Gorman <mgorman@suse.de>
Cc: Metin Doslu <metin@citusdata.com>
Cc: Michel Lespinasse <walken@google.com>
Cc: Ozgun Erdogan <ozgun@citusdata.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Roman Gushchin <klamm@yandex-team.ru>
Cc: Ryan Mallon <rmallon@gmail.com>
Cc: Tejun Heo <tj@kernel.org>
Cc: Vlastimil Babka <vbabka@suse.cz>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2014-04-04 05:47:56 +08:00
|
|
|
}
|
2014-04-04 05:47:49 +08:00
|
|
|
mapping->nrpages--;
|
mm: keep page cache radix tree nodes in check
Previously, page cache radix tree nodes were freed after reclaim emptied
out their page pointers. But now reclaim stores shadow entries in their
place, which are only reclaimed when the inodes themselves are
reclaimed. This is problematic for bigger files that are still in use
after they have a significant amount of their cache reclaimed, without
any of those pages actually refaulting. The shadow entries will just
sit there and waste memory. In the worst case, the shadow entries will
accumulate until the machine runs out of memory.
To get this under control, the VM will track radix tree nodes
exclusively containing shadow entries on a per-NUMA node list. Per-NUMA
rather than global because we expect the radix tree nodes themselves to
be allocated node-locally and we want to reduce cross-node references of
otherwise independent cache workloads. A simple shrinker will then
reclaim these nodes on memory pressure.
A few things need to be stored in the radix tree node to implement the
shadow node LRU and allow tree deletions coming from the list:
1. There is no index available that would describe the reverse path
from the node up to the tree root, which is needed to perform a
deletion. To solve this, encode in each node its offset inside the
parent. This can be stored in the unused upper bits of the same
member that stores the node's height at no extra space cost.
2. The number of shadow entries needs to be counted in addition to the
regular entries, to quickly detect when the node is ready to go to
the shadow node LRU list. The current entry count is an unsigned
int but the maximum number of entries is 64, so a shadow counter
can easily be stored in the unused upper bits.
3. Tree modification needs tree lock and tree root, which are located
in the address space, so store an address_space backpointer in the
node. The parent pointer of the node is in a union with the 2-word
rcu_head, so the backpointer comes at no extra cost as well.
4. The node needs to be linked to an LRU list, which requires a list
head inside the node. This does increase the size of the node, but
it does not change the number of objects that fit into a slab page.
[akpm@linux-foundation.org: export the right function]
Signed-off-by: Johannes Weiner <hannes@cmpxchg.org>
Reviewed-by: Rik van Riel <riel@redhat.com>
Reviewed-by: Minchan Kim <minchan@kernel.org>
Cc: Andrea Arcangeli <aarcange@redhat.com>
Cc: Bob Liu <bob.liu@oracle.com>
Cc: Christoph Hellwig <hch@infradead.org>
Cc: Dave Chinner <david@fromorbit.com>
Cc: Greg Thelen <gthelen@google.com>
Cc: Hugh Dickins <hughd@google.com>
Cc: Jan Kara <jack@suse.cz>
Cc: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
Cc: Luigi Semenzato <semenzato@google.com>
Cc: Mel Gorman <mgorman@suse.de>
Cc: Metin Doslu <metin@citusdata.com>
Cc: Michel Lespinasse <walken@google.com>
Cc: Ozgun Erdogan <ozgun@citusdata.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Roman Gushchin <klamm@yandex-team.ru>
Cc: Ryan Mallon <rmallon@gmail.com>
Cc: Tejun Heo <tj@kernel.org>
Cc: Vlastimil Babka <vbabka@suse.cz>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2014-04-04 05:47:56 +08:00
|
|
|
|
|
|
|
if (!node) {
|
|
|
|
/* Clear direct pointer tags in root node */
|
|
|
|
mapping->page_tree.gfp_mask &= __GFP_BITS_MASK;
|
|
|
|
radix_tree_replace_slot(slot, shadow);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Clear tree tags for the removed page */
|
|
|
|
index = page->index;
|
|
|
|
offset = index & RADIX_TREE_MAP_MASK;
|
|
|
|
for (tag = 0; tag < RADIX_TREE_MAX_TAGS; tag++) {
|
|
|
|
if (test_bit(offset, node->tags[tag]))
|
|
|
|
radix_tree_tag_clear(&mapping->page_tree, index, tag);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Delete page, swap shadow entry */
|
|
|
|
radix_tree_replace_slot(slot, shadow);
|
|
|
|
workingset_node_pages_dec(node);
|
|
|
|
if (shadow)
|
|
|
|
workingset_node_shadows_inc(node);
|
|
|
|
else
|
|
|
|
if (__radix_tree_delete_node(&mapping->page_tree, node))
|
|
|
|
return;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Track node that only contains shadow entries.
|
|
|
|
*
|
|
|
|
* Avoid acquiring the list_lru lock if already tracked. The
|
|
|
|
* list_empty() test is safe as node->private_list is
|
|
|
|
* protected by mapping->tree_lock.
|
|
|
|
*/
|
|
|
|
if (!workingset_node_pages(node) &&
|
|
|
|
list_empty(&node->private_list)) {
|
|
|
|
node->private_data = mapping;
|
|
|
|
list_lru_add(&workingset_shadow_nodes, &node->private_list);
|
|
|
|
}
|
2014-04-04 05:47:49 +08:00
|
|
|
}
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
/*
|
2011-03-23 07:32:44 +08:00
|
|
|
* Delete a page from the page cache and free it. Caller has to make
|
2005-04-17 06:20:36 +08:00
|
|
|
* sure the page is locked and that nobody else uses it - or that usage
|
memcg: add per cgroup dirty page accounting
When modifying PG_Dirty on cached file pages, update the new
MEM_CGROUP_STAT_DIRTY counter. This is done in the same places where
global NR_FILE_DIRTY is managed. The new memcg stat is visible in the
per memcg memory.stat cgroupfs file. The most recent past attempt at
this was http://thread.gmane.org/gmane.linux.kernel.cgroups/8632
The new accounting supports future efforts to add per cgroup dirty
page throttling and writeback. It also helps an administrator break
down a container's memory usage and provides evidence to understand
memcg oom kills (the new dirty count is included in memcg oom kill
messages).
The ability to move page accounting between memcg
(memory.move_charge_at_immigrate) makes this accounting more
complicated than the global counter. The existing
mem_cgroup_{begin,end}_page_stat() lock is used to serialize move
accounting with stat updates.
Typical update operation:
memcg = mem_cgroup_begin_page_stat(page)
if (TestSetPageDirty()) {
[...]
mem_cgroup_update_page_stat(memcg)
}
mem_cgroup_end_page_stat(memcg)
Summary of mem_cgroup_end_page_stat() overhead:
- Without CONFIG_MEMCG it's a no-op
- With CONFIG_MEMCG and no inter memcg task movement, it's just
rcu_read_lock()
- With CONFIG_MEMCG and inter memcg task movement, it's
rcu_read_lock() + spin_lock_irqsave()
A memcg parameter is added to several routines because their callers
now grab mem_cgroup_begin_page_stat() which returns the memcg later
needed by for mem_cgroup_update_page_stat().
Because mem_cgroup_begin_page_stat() may disable interrupts, some
adjustments are needed:
- move __mark_inode_dirty() from __set_page_dirty() to its caller.
__mark_inode_dirty() locking does not want interrupts disabled.
- use spin_lock_irqsave(tree_lock) rather than spin_lock_irq() in
__delete_from_page_cache(), replace_page_cache_page(),
invalidate_complete_page2(), and __remove_mapping().
text data bss dec hex filename
8925147 1774832 1785856 12485835 be84cb vmlinux-!CONFIG_MEMCG-before
8925339 1774832 1785856 12486027 be858b vmlinux-!CONFIG_MEMCG-after
+192 text bytes
8965977 1784992 1785856 12536825 bf4bf9 vmlinux-CONFIG_MEMCG-before
8966750 1784992 1785856 12537598 bf4efe vmlinux-CONFIG_MEMCG-after
+773 text bytes
Performance tests run on v4.0-rc1-36-g4f671fe2f952. Lower is better for
all metrics, they're all wall clock or cycle counts. The read and write
fault benchmarks just measure fault time, they do not include I/O time.
* CONFIG_MEMCG not set:
baseline patched
kbuild 1m25.030000(+-0.088% 3 samples) 1m25.426667(+-0.120% 3 samples)
dd write 100 MiB 0.859211561 +-15.10% 0.874162885 +-15.03%
dd write 200 MiB 1.670653105 +-17.87% 1.669384764 +-11.99%
dd write 1000 MiB 8.434691190 +-14.15% 8.474733215 +-14.77%
read fault cycles 254.0(+-0.000% 10 samples) 253.0(+-0.000% 10 samples)
write fault cycles 2021.2(+-3.070% 10 samples) 1984.5(+-1.036% 10 samples)
* CONFIG_MEMCG=y root_memcg:
baseline patched
kbuild 1m25.716667(+-0.105% 3 samples) 1m25.686667(+-0.153% 3 samples)
dd write 100 MiB 0.855650830 +-14.90% 0.887557919 +-14.90%
dd write 200 MiB 1.688322953 +-12.72% 1.667682724 +-13.33%
dd write 1000 MiB 8.418601605 +-14.30% 8.673532299 +-15.00%
read fault cycles 266.0(+-0.000% 10 samples) 266.0(+-0.000% 10 samples)
write fault cycles 2051.7(+-1.349% 10 samples) 2049.6(+-1.686% 10 samples)
* CONFIG_MEMCG=y non-root_memcg:
baseline patched
kbuild 1m26.120000(+-0.273% 3 samples) 1m25.763333(+-0.127% 3 samples)
dd write 100 MiB 0.861723964 +-15.25% 0.818129350 +-14.82%
dd write 200 MiB 1.669887569 +-13.30% 1.698645885 +-13.27%
dd write 1000 MiB 8.383191730 +-14.65% 8.351742280 +-14.52%
read fault cycles 265.7(+-0.172% 10 samples) 267.0(+-0.000% 10 samples)
write fault cycles 2070.6(+-1.512% 10 samples) 2084.4(+-2.148% 10 samples)
As expected anon page faults are not affected by this patch.
tj: Updated to apply on top of the recent cancel_dirty_page() changes.
Signed-off-by: Sha Zhengju <handai.szj@gmail.com>
Signed-off-by: Greg Thelen <gthelen@google.com>
Signed-off-by: Tejun Heo <tj@kernel.org>
Signed-off-by: Jens Axboe <axboe@fb.com>
2015-05-23 05:13:16 +08:00
|
|
|
* is safe. The caller must hold the mapping's tree_lock and
|
|
|
|
* mem_cgroup_begin_page_stat().
|
2005-04-17 06:20:36 +08:00
|
|
|
*/
|
memcg: add per cgroup dirty page accounting
When modifying PG_Dirty on cached file pages, update the new
MEM_CGROUP_STAT_DIRTY counter. This is done in the same places where
global NR_FILE_DIRTY is managed. The new memcg stat is visible in the
per memcg memory.stat cgroupfs file. The most recent past attempt at
this was http://thread.gmane.org/gmane.linux.kernel.cgroups/8632
The new accounting supports future efforts to add per cgroup dirty
page throttling and writeback. It also helps an administrator break
down a container's memory usage and provides evidence to understand
memcg oom kills (the new dirty count is included in memcg oom kill
messages).
The ability to move page accounting between memcg
(memory.move_charge_at_immigrate) makes this accounting more
complicated than the global counter. The existing
mem_cgroup_{begin,end}_page_stat() lock is used to serialize move
accounting with stat updates.
Typical update operation:
memcg = mem_cgroup_begin_page_stat(page)
if (TestSetPageDirty()) {
[...]
mem_cgroup_update_page_stat(memcg)
}
mem_cgroup_end_page_stat(memcg)
Summary of mem_cgroup_end_page_stat() overhead:
- Without CONFIG_MEMCG it's a no-op
- With CONFIG_MEMCG and no inter memcg task movement, it's just
rcu_read_lock()
- With CONFIG_MEMCG and inter memcg task movement, it's
rcu_read_lock() + spin_lock_irqsave()
A memcg parameter is added to several routines because their callers
now grab mem_cgroup_begin_page_stat() which returns the memcg later
needed by for mem_cgroup_update_page_stat().
Because mem_cgroup_begin_page_stat() may disable interrupts, some
adjustments are needed:
- move __mark_inode_dirty() from __set_page_dirty() to its caller.
__mark_inode_dirty() locking does not want interrupts disabled.
- use spin_lock_irqsave(tree_lock) rather than spin_lock_irq() in
__delete_from_page_cache(), replace_page_cache_page(),
invalidate_complete_page2(), and __remove_mapping().
text data bss dec hex filename
8925147 1774832 1785856 12485835 be84cb vmlinux-!CONFIG_MEMCG-before
8925339 1774832 1785856 12486027 be858b vmlinux-!CONFIG_MEMCG-after
+192 text bytes
8965977 1784992 1785856 12536825 bf4bf9 vmlinux-CONFIG_MEMCG-before
8966750 1784992 1785856 12537598 bf4efe vmlinux-CONFIG_MEMCG-after
+773 text bytes
Performance tests run on v4.0-rc1-36-g4f671fe2f952. Lower is better for
all metrics, they're all wall clock or cycle counts. The read and write
fault benchmarks just measure fault time, they do not include I/O time.
* CONFIG_MEMCG not set:
baseline patched
kbuild 1m25.030000(+-0.088% 3 samples) 1m25.426667(+-0.120% 3 samples)
dd write 100 MiB 0.859211561 +-15.10% 0.874162885 +-15.03%
dd write 200 MiB 1.670653105 +-17.87% 1.669384764 +-11.99%
dd write 1000 MiB 8.434691190 +-14.15% 8.474733215 +-14.77%
read fault cycles 254.0(+-0.000% 10 samples) 253.0(+-0.000% 10 samples)
write fault cycles 2021.2(+-3.070% 10 samples) 1984.5(+-1.036% 10 samples)
* CONFIG_MEMCG=y root_memcg:
baseline patched
kbuild 1m25.716667(+-0.105% 3 samples) 1m25.686667(+-0.153% 3 samples)
dd write 100 MiB 0.855650830 +-14.90% 0.887557919 +-14.90%
dd write 200 MiB 1.688322953 +-12.72% 1.667682724 +-13.33%
dd write 1000 MiB 8.418601605 +-14.30% 8.673532299 +-15.00%
read fault cycles 266.0(+-0.000% 10 samples) 266.0(+-0.000% 10 samples)
write fault cycles 2051.7(+-1.349% 10 samples) 2049.6(+-1.686% 10 samples)
* CONFIG_MEMCG=y non-root_memcg:
baseline patched
kbuild 1m26.120000(+-0.273% 3 samples) 1m25.763333(+-0.127% 3 samples)
dd write 100 MiB 0.861723964 +-15.25% 0.818129350 +-14.82%
dd write 200 MiB 1.669887569 +-13.30% 1.698645885 +-13.27%
dd write 1000 MiB 8.383191730 +-14.65% 8.351742280 +-14.52%
read fault cycles 265.7(+-0.172% 10 samples) 267.0(+-0.000% 10 samples)
write fault cycles 2070.6(+-1.512% 10 samples) 2084.4(+-2.148% 10 samples)
As expected anon page faults are not affected by this patch.
tj: Updated to apply on top of the recent cancel_dirty_page() changes.
Signed-off-by: Sha Zhengju <handai.szj@gmail.com>
Signed-off-by: Greg Thelen <gthelen@google.com>
Signed-off-by: Tejun Heo <tj@kernel.org>
Signed-off-by: Jens Axboe <axboe@fb.com>
2015-05-23 05:13:16 +08:00
|
|
|
void __delete_from_page_cache(struct page *page, void *shadow,
|
|
|
|
struct mem_cgroup *memcg)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
|
|
|
struct address_space *mapping = page->mapping;
|
|
|
|
|
2013-04-30 06:06:10 +08:00
|
|
|
trace_mm_filemap_delete_from_page_cache(page);
|
2011-05-27 00:01:43 +08:00
|
|
|
/*
|
|
|
|
* if we're uptodate, flush out into the cleancache, otherwise
|
|
|
|
* invalidate any existing cleancache entries. We can't leave
|
|
|
|
* stale data around in the cleancache once our page is gone
|
|
|
|
*/
|
|
|
|
if (PageUptodate(page) && PageMappedToDisk(page))
|
|
|
|
cleancache_put_page(page);
|
|
|
|
else
|
2011-09-21 23:56:28 +08:00
|
|
|
cleancache_invalidate_page(mapping, page);
|
2011-05-27 00:01:43 +08:00
|
|
|
|
mm: __delete_from_page_cache show Bad page if mapped
Commit e1534ae95004 ("mm: differentiate page_mapped() from
page_mapcount() for compound pages") changed the famous
BUG_ON(page_mapped(page)) in __delete_from_page_cache() to
VM_BUG_ON_PAGE(page_mapped(page)): which gives us more info when
CONFIG_DEBUG_VM=y, but nothing at all when not.
Although it has not usually been very helpul, being hit long after the
error in question, we do need to know if it actually happens on users'
systems; but reinstating a crash there is likely to be opposed :)
In the non-debug case, pr_alert("BUG: Bad page cache") plus dump_page(),
dump_stack(), add_taint() - I don't really believe LOCKDEP_NOW_UNRELIABLE,
but that seems to be the standard procedure now. Move that, or the
VM_BUG_ON_PAGE(), up before the deletion from tree: so that the
unNULLified page->mapping gives a little more information.
If the inode is being evicted (rather than truncated), it won't have any
vmas left, so it's safe(ish) to assume that the raised mapcount is
erroneous, and we can discount it from page_count to avoid leaking the
page (I'm less worried by leaking the occasional 4kB, than losing a
potential 2MB page with each 4kB page leaked).
Signed-off-by: Hugh Dickins <hughd@google.com>
Acked-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Cc: Joonsoo Kim <iamjoonsoo.kim@lge.com>
Cc: Sasha Levin <sasha.levin@oracle.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2016-03-10 06:08:07 +08:00
|
|
|
VM_BUG_ON_PAGE(page_mapped(page), page);
|
|
|
|
if (!IS_ENABLED(CONFIG_DEBUG_VM) && unlikely(page_mapped(page))) {
|
|
|
|
int mapcount;
|
|
|
|
|
|
|
|
pr_alert("BUG: Bad page cache in process %s pfn:%05lx\n",
|
|
|
|
current->comm, page_to_pfn(page));
|
|
|
|
dump_page(page, "still mapped when deleted");
|
|
|
|
dump_stack();
|
|
|
|
add_taint(TAINT_BAD_PAGE, LOCKDEP_NOW_UNRELIABLE);
|
|
|
|
|
|
|
|
mapcount = page_mapcount(page);
|
|
|
|
if (mapping_exiting(mapping) &&
|
|
|
|
page_count(page) >= mapcount + 2) {
|
|
|
|
/*
|
|
|
|
* All vmas have already been torn down, so it's
|
|
|
|
* a good bet that actually the page is unmapped,
|
|
|
|
* and we'd prefer not to leak it: if we're wrong,
|
|
|
|
* some other bad page check should catch it later.
|
|
|
|
*/
|
|
|
|
page_mapcount_reset(page);
|
|
|
|
atomic_sub(mapcount, &page->_count);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-04-04 05:47:49 +08:00
|
|
|
page_cache_tree_delete(mapping, page, shadow);
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
page->mapping = NULL;
|
2011-07-26 08:12:25 +08:00
|
|
|
/* Leave page->index set: truncation lookup relies upon it */
|
2014-04-04 05:47:49 +08:00
|
|
|
|
2015-06-25 07:57:24 +08:00
|
|
|
/* hugetlb pages do not participate in page cache accounting. */
|
|
|
|
if (!PageHuge(page))
|
|
|
|
__dec_zone_page_state(page, NR_FILE_PAGES);
|
2009-09-22 08:01:33 +08:00
|
|
|
if (PageSwapBacked(page))
|
|
|
|
__dec_zone_page_state(page, NR_SHMEM);
|
2007-12-20 06:05:13 +08:00
|
|
|
|
|
|
|
/*
|
2015-04-15 06:45:27 +08:00
|
|
|
* At this point page must be either written or cleaned by truncate.
|
|
|
|
* Dirty page here signals a bug and loss of unwritten data.
|
2007-12-20 06:05:13 +08:00
|
|
|
*
|
2015-04-15 06:45:27 +08:00
|
|
|
* This fixes dirty accounting after removing the page entirely but
|
|
|
|
* leaves PageDirty set: it has no effect for truncated page and
|
|
|
|
* anyway will be cleared before returning page into buddy allocator.
|
2007-12-20 06:05:13 +08:00
|
|
|
*/
|
2015-04-15 06:45:27 +08:00
|
|
|
if (WARN_ON_ONCE(PageDirty(page)))
|
writeback: implement unlocked_inode_to_wb transaction and use it for stat updates
The mechanism for detecting whether an inode should switch its wb
(bdi_writeback) association is now in place. This patch build the
framework for the actual switching.
This patch adds a new inode flag I_WB_SWITCHING, which has two
functions. First, the easy one, it ensures that there's only one
switching in progress for a give inode. Second, it's used as a
mechanism to synchronize wb stat updates.
The two stats, WB_RECLAIMABLE and WB_WRITEBACK, aren't event counters
but track the current number of dirty pages and pages under writeback
respectively. As such, when an inode is moved from one wb to another,
the inode's portion of those stats have to be transferred together;
unfortunately, this is a bit tricky as those stat updates are percpu
operations which are performed without holding any lock in some
places.
This patch solves the problem in a similar way as memcg. Each such
lockless stat updates are wrapped in transaction surrounded by
unlocked_inode_to_wb_begin/end(). During normal operation, they map
to rcu_read_lock/unlock(); however, if I_WB_SWITCHING is asserted,
mapping->tree_lock is grabbed across the transaction.
In turn, the switching path sets I_WB_SWITCHING and waits for a RCU
grace period to pass before actually starting to switch, which
guarantees that all stat update paths are synchronizing against
mapping->tree_lock.
This patch still doesn't implement the actual switching.
v3: Updated on top of the recent cancel_dirty_page() updates.
unlocked_inode_to_wb_begin() now nests inside
mem_cgroup_begin_page_stat() to match the locking order.
v2: The i_wb access transaction will be used for !stat accesses too.
Function names and comments updated accordingly.
s/inode_wb_stat_unlocked_{begin|end}/unlocked_inode_to_wb_{begin|end}/
s/switch_wb/switch_wbs/
Signed-off-by: Tejun Heo <tj@kernel.org>
Cc: Jens Axboe <axboe@kernel.dk>
Cc: Jan Kara <jack@suse.cz>
Cc: Wu Fengguang <fengguang.wu@intel.com>
Cc: Greg Thelen <gthelen@google.com>
Signed-off-by: Jens Axboe <axboe@fb.com>
2015-05-29 02:50:53 +08:00
|
|
|
account_page_cleaned(page, mapping, memcg,
|
|
|
|
inode_to_wb(mapping->host));
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
2011-03-23 07:32:43 +08:00
|
|
|
/**
|
|
|
|
* delete_from_page_cache - delete page from page cache
|
|
|
|
* @page: the page which the kernel is trying to remove from page cache
|
|
|
|
*
|
|
|
|
* This must be called only on pages that have been verified to be in the page
|
|
|
|
* cache and locked. It will never put the page into the free list, the caller
|
|
|
|
* has a reference on the page.
|
|
|
|
*/
|
|
|
|
void delete_from_page_cache(struct page *page)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
|
|
|
struct address_space *mapping = page->mapping;
|
memcg: add per cgroup dirty page accounting
When modifying PG_Dirty on cached file pages, update the new
MEM_CGROUP_STAT_DIRTY counter. This is done in the same places where
global NR_FILE_DIRTY is managed. The new memcg stat is visible in the
per memcg memory.stat cgroupfs file. The most recent past attempt at
this was http://thread.gmane.org/gmane.linux.kernel.cgroups/8632
The new accounting supports future efforts to add per cgroup dirty
page throttling and writeback. It also helps an administrator break
down a container's memory usage and provides evidence to understand
memcg oom kills (the new dirty count is included in memcg oom kill
messages).
The ability to move page accounting between memcg
(memory.move_charge_at_immigrate) makes this accounting more
complicated than the global counter. The existing
mem_cgroup_{begin,end}_page_stat() lock is used to serialize move
accounting with stat updates.
Typical update operation:
memcg = mem_cgroup_begin_page_stat(page)
if (TestSetPageDirty()) {
[...]
mem_cgroup_update_page_stat(memcg)
}
mem_cgroup_end_page_stat(memcg)
Summary of mem_cgroup_end_page_stat() overhead:
- Without CONFIG_MEMCG it's a no-op
- With CONFIG_MEMCG and no inter memcg task movement, it's just
rcu_read_lock()
- With CONFIG_MEMCG and inter memcg task movement, it's
rcu_read_lock() + spin_lock_irqsave()
A memcg parameter is added to several routines because their callers
now grab mem_cgroup_begin_page_stat() which returns the memcg later
needed by for mem_cgroup_update_page_stat().
Because mem_cgroup_begin_page_stat() may disable interrupts, some
adjustments are needed:
- move __mark_inode_dirty() from __set_page_dirty() to its caller.
__mark_inode_dirty() locking does not want interrupts disabled.
- use spin_lock_irqsave(tree_lock) rather than spin_lock_irq() in
__delete_from_page_cache(), replace_page_cache_page(),
invalidate_complete_page2(), and __remove_mapping().
text data bss dec hex filename
8925147 1774832 1785856 12485835 be84cb vmlinux-!CONFIG_MEMCG-before
8925339 1774832 1785856 12486027 be858b vmlinux-!CONFIG_MEMCG-after
+192 text bytes
8965977 1784992 1785856 12536825 bf4bf9 vmlinux-CONFIG_MEMCG-before
8966750 1784992 1785856 12537598 bf4efe vmlinux-CONFIG_MEMCG-after
+773 text bytes
Performance tests run on v4.0-rc1-36-g4f671fe2f952. Lower is better for
all metrics, they're all wall clock or cycle counts. The read and write
fault benchmarks just measure fault time, they do not include I/O time.
* CONFIG_MEMCG not set:
baseline patched
kbuild 1m25.030000(+-0.088% 3 samples) 1m25.426667(+-0.120% 3 samples)
dd write 100 MiB 0.859211561 +-15.10% 0.874162885 +-15.03%
dd write 200 MiB 1.670653105 +-17.87% 1.669384764 +-11.99%
dd write 1000 MiB 8.434691190 +-14.15% 8.474733215 +-14.77%
read fault cycles 254.0(+-0.000% 10 samples) 253.0(+-0.000% 10 samples)
write fault cycles 2021.2(+-3.070% 10 samples) 1984.5(+-1.036% 10 samples)
* CONFIG_MEMCG=y root_memcg:
baseline patched
kbuild 1m25.716667(+-0.105% 3 samples) 1m25.686667(+-0.153% 3 samples)
dd write 100 MiB 0.855650830 +-14.90% 0.887557919 +-14.90%
dd write 200 MiB 1.688322953 +-12.72% 1.667682724 +-13.33%
dd write 1000 MiB 8.418601605 +-14.30% 8.673532299 +-15.00%
read fault cycles 266.0(+-0.000% 10 samples) 266.0(+-0.000% 10 samples)
write fault cycles 2051.7(+-1.349% 10 samples) 2049.6(+-1.686% 10 samples)
* CONFIG_MEMCG=y non-root_memcg:
baseline patched
kbuild 1m26.120000(+-0.273% 3 samples) 1m25.763333(+-0.127% 3 samples)
dd write 100 MiB 0.861723964 +-15.25% 0.818129350 +-14.82%
dd write 200 MiB 1.669887569 +-13.30% 1.698645885 +-13.27%
dd write 1000 MiB 8.383191730 +-14.65% 8.351742280 +-14.52%
read fault cycles 265.7(+-0.172% 10 samples) 267.0(+-0.000% 10 samples)
write fault cycles 2070.6(+-1.512% 10 samples) 2084.4(+-2.148% 10 samples)
As expected anon page faults are not affected by this patch.
tj: Updated to apply on top of the recent cancel_dirty_page() changes.
Signed-off-by: Sha Zhengju <handai.szj@gmail.com>
Signed-off-by: Greg Thelen <gthelen@google.com>
Signed-off-by: Tejun Heo <tj@kernel.org>
Signed-off-by: Jens Axboe <axboe@fb.com>
2015-05-23 05:13:16 +08:00
|
|
|
struct mem_cgroup *memcg;
|
|
|
|
unsigned long flags;
|
|
|
|
|
2010-12-02 02:35:19 +08:00
|
|
|
void (*freepage)(struct page *);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2005-05-01 23:59:01 +08:00
|
|
|
BUG_ON(!PageLocked(page));
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2010-12-02 02:35:19 +08:00
|
|
|
freepage = mapping->a_ops->freepage;
|
memcg: add per cgroup dirty page accounting
When modifying PG_Dirty on cached file pages, update the new
MEM_CGROUP_STAT_DIRTY counter. This is done in the same places where
global NR_FILE_DIRTY is managed. The new memcg stat is visible in the
per memcg memory.stat cgroupfs file. The most recent past attempt at
this was http://thread.gmane.org/gmane.linux.kernel.cgroups/8632
The new accounting supports future efforts to add per cgroup dirty
page throttling and writeback. It also helps an administrator break
down a container's memory usage and provides evidence to understand
memcg oom kills (the new dirty count is included in memcg oom kill
messages).
The ability to move page accounting between memcg
(memory.move_charge_at_immigrate) makes this accounting more
complicated than the global counter. The existing
mem_cgroup_{begin,end}_page_stat() lock is used to serialize move
accounting with stat updates.
Typical update operation:
memcg = mem_cgroup_begin_page_stat(page)
if (TestSetPageDirty()) {
[...]
mem_cgroup_update_page_stat(memcg)
}
mem_cgroup_end_page_stat(memcg)
Summary of mem_cgroup_end_page_stat() overhead:
- Without CONFIG_MEMCG it's a no-op
- With CONFIG_MEMCG and no inter memcg task movement, it's just
rcu_read_lock()
- With CONFIG_MEMCG and inter memcg task movement, it's
rcu_read_lock() + spin_lock_irqsave()
A memcg parameter is added to several routines because their callers
now grab mem_cgroup_begin_page_stat() which returns the memcg later
needed by for mem_cgroup_update_page_stat().
Because mem_cgroup_begin_page_stat() may disable interrupts, some
adjustments are needed:
- move __mark_inode_dirty() from __set_page_dirty() to its caller.
__mark_inode_dirty() locking does not want interrupts disabled.
- use spin_lock_irqsave(tree_lock) rather than spin_lock_irq() in
__delete_from_page_cache(), replace_page_cache_page(),
invalidate_complete_page2(), and __remove_mapping().
text data bss dec hex filename
8925147 1774832 1785856 12485835 be84cb vmlinux-!CONFIG_MEMCG-before
8925339 1774832 1785856 12486027 be858b vmlinux-!CONFIG_MEMCG-after
+192 text bytes
8965977 1784992 1785856 12536825 bf4bf9 vmlinux-CONFIG_MEMCG-before
8966750 1784992 1785856 12537598 bf4efe vmlinux-CONFIG_MEMCG-after
+773 text bytes
Performance tests run on v4.0-rc1-36-g4f671fe2f952. Lower is better for
all metrics, they're all wall clock or cycle counts. The read and write
fault benchmarks just measure fault time, they do not include I/O time.
* CONFIG_MEMCG not set:
baseline patched
kbuild 1m25.030000(+-0.088% 3 samples) 1m25.426667(+-0.120% 3 samples)
dd write 100 MiB 0.859211561 +-15.10% 0.874162885 +-15.03%
dd write 200 MiB 1.670653105 +-17.87% 1.669384764 +-11.99%
dd write 1000 MiB 8.434691190 +-14.15% 8.474733215 +-14.77%
read fault cycles 254.0(+-0.000% 10 samples) 253.0(+-0.000% 10 samples)
write fault cycles 2021.2(+-3.070% 10 samples) 1984.5(+-1.036% 10 samples)
* CONFIG_MEMCG=y root_memcg:
baseline patched
kbuild 1m25.716667(+-0.105% 3 samples) 1m25.686667(+-0.153% 3 samples)
dd write 100 MiB 0.855650830 +-14.90% 0.887557919 +-14.90%
dd write 200 MiB 1.688322953 +-12.72% 1.667682724 +-13.33%
dd write 1000 MiB 8.418601605 +-14.30% 8.673532299 +-15.00%
read fault cycles 266.0(+-0.000% 10 samples) 266.0(+-0.000% 10 samples)
write fault cycles 2051.7(+-1.349% 10 samples) 2049.6(+-1.686% 10 samples)
* CONFIG_MEMCG=y non-root_memcg:
baseline patched
kbuild 1m26.120000(+-0.273% 3 samples) 1m25.763333(+-0.127% 3 samples)
dd write 100 MiB 0.861723964 +-15.25% 0.818129350 +-14.82%
dd write 200 MiB 1.669887569 +-13.30% 1.698645885 +-13.27%
dd write 1000 MiB 8.383191730 +-14.65% 8.351742280 +-14.52%
read fault cycles 265.7(+-0.172% 10 samples) 267.0(+-0.000% 10 samples)
write fault cycles 2070.6(+-1.512% 10 samples) 2084.4(+-2.148% 10 samples)
As expected anon page faults are not affected by this patch.
tj: Updated to apply on top of the recent cancel_dirty_page() changes.
Signed-off-by: Sha Zhengju <handai.szj@gmail.com>
Signed-off-by: Greg Thelen <gthelen@google.com>
Signed-off-by: Tejun Heo <tj@kernel.org>
Signed-off-by: Jens Axboe <axboe@fb.com>
2015-05-23 05:13:16 +08:00
|
|
|
|
|
|
|
memcg = mem_cgroup_begin_page_stat(page);
|
|
|
|
spin_lock_irqsave(&mapping->tree_lock, flags);
|
|
|
|
__delete_from_page_cache(page, NULL, memcg);
|
|
|
|
spin_unlock_irqrestore(&mapping->tree_lock, flags);
|
|
|
|
mem_cgroup_end_page_stat(memcg);
|
2010-12-02 02:35:19 +08:00
|
|
|
|
|
|
|
if (freepage)
|
|
|
|
freepage(page);
|
2011-03-23 07:30:53 +08:00
|
|
|
page_cache_release(page);
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(delete_from_page_cache);
|
|
|
|
|
2013-04-30 06:08:42 +08:00
|
|
|
static int filemap_check_errors(struct address_space *mapping)
|
|
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
/* Check for outstanding write errors */
|
2014-05-23 02:54:16 +08:00
|
|
|
if (test_bit(AS_ENOSPC, &mapping->flags) &&
|
|
|
|
test_and_clear_bit(AS_ENOSPC, &mapping->flags))
|
2013-04-30 06:08:42 +08:00
|
|
|
ret = -ENOSPC;
|
2014-05-23 02:54:16 +08:00
|
|
|
if (test_bit(AS_EIO, &mapping->flags) &&
|
|
|
|
test_and_clear_bit(AS_EIO, &mapping->flags))
|
2013-04-30 06:08:42 +08:00
|
|
|
ret = -EIO;
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
/**
|
2006-06-23 17:03:49 +08:00
|
|
|
* __filemap_fdatawrite_range - start writeback on mapping dirty pages in range
|
2005-05-01 23:59:26 +08:00
|
|
|
* @mapping: address space structure to write
|
|
|
|
* @start: offset in bytes where the range starts
|
2006-03-24 19:17:45 +08:00
|
|
|
* @end: offset in bytes where the range ends (inclusive)
|
2005-05-01 23:59:26 +08:00
|
|
|
* @sync_mode: enable synchronous operation
|
2005-04-17 06:20:36 +08:00
|
|
|
*
|
2006-06-23 17:03:49 +08:00
|
|
|
* Start writeback against all of a mapping's dirty pages that lie
|
|
|
|
* within the byte offsets <start, end> inclusive.
|
|
|
|
*
|
2005-04-17 06:20:36 +08:00
|
|
|
* If sync_mode is WB_SYNC_ALL then this is a "data integrity" operation, as
|
2006-06-23 17:03:49 +08:00
|
|
|
* opposed to a regular memory cleansing writeback. The difference between
|
2005-04-17 06:20:36 +08:00
|
|
|
* these two operations is that if a dirty page/buffer is encountered, it must
|
|
|
|
* be waited upon, and not just skipped over.
|
|
|
|
*/
|
[PATCH] fadvise(): write commands
Add two new linux-specific fadvise extensions():
LINUX_FADV_ASYNC_WRITE: start async writeout of any dirty pages between file
offsets `offset' and `offset+len'. Any pages which are currently under
writeout are skipped, whether or not they are dirty.
LINUX_FADV_WRITE_WAIT: wait upon writeout of any dirty pages between file
offsets `offset' and `offset+len'.
By combining these two operations the application may do several things:
LINUX_FADV_ASYNC_WRITE: push some or all of the dirty pages at the disk.
LINUX_FADV_WRITE_WAIT, LINUX_FADV_ASYNC_WRITE: push all of the currently dirty
pages at the disk.
LINUX_FADV_WRITE_WAIT, LINUX_FADV_ASYNC_WRITE, LINUX_FADV_WRITE_WAIT: push all
of the currently dirty pages at the disk, wait until they have been written.
It should be noted that none of these operations write out the file's
metadata. So unless the application is strictly performing overwrites of
already-instantiated disk blocks, there are no guarantees here that the data
will be available after a crash.
To complete this suite of operations I guess we should have a "sync file
metadata only" operation. This gives applications access to all the building
blocks needed for all sorts of sync operations. But sync-metadata doesn't fit
well with the fadvise() interface. Probably it should be a new syscall:
sys_fmetadatasync().
The patch also diddles with the meaning of `endbyte' in sys_fadvise64_64().
It is made to represent that last affected byte in the file (ie: it is
inclusive). Generally, all these byterange and pagerange functions are
inclusive so we can easily represent EOF with -1.
As Ulrich notes, these two functions are somewhat abusive of the fadvise()
concept, which appears to be "set the future policy for this fd".
But these commands are a perfect fit with the fadvise() impementation, and
several of the existing fadvise() commands are synchronous and don't affect
future policy either. I think we can live with the slight incongruity.
Cc: Michael Kerrisk <mtk-manpages@gmx.net>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
2006-03-24 19:18:04 +08:00
|
|
|
int __filemap_fdatawrite_range(struct address_space *mapping, loff_t start,
|
|
|
|
loff_t end, int sync_mode)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
struct writeback_control wbc = {
|
|
|
|
.sync_mode = sync_mode,
|
mm: write_cache_pages integrity fix
In write_cache_pages, nr_to_write is heeded even for data-integrity syncs,
so the function will return success after writing out nr_to_write pages,
even if that was not sufficient to guarantee data integrity.
The callers tend to set it to values that could break data interity
semantics easily in practice. For example, nr_to_write can be set to
mapping->nr_pages * 2, however if a file has a single, dirty page, then
fsync is called, subsequent pages might be concurrently added and dirtied,
then write_cache_pages might writeout two of these newly dirty pages,
while not writing out the old page that should have been written out.
Fix this by ignoring nr_to_write if it is a data integrity sync.
This is a data integrity bug.
The reason this has been done in the past is to avoid stalling sync
operations behind page dirtiers.
"If a file has one dirty page at offset 1000000000000000 then someone
does an fsync() and someone else gets in first and starts madly writing
pages at offset 0, we want to write that page at 1000000000000000.
Somehow."
What we do today is return success after an arbitrary amount of pages are
written, whether or not we have provided the data-integrity semantics that
the caller has asked for. Even this doesn't actually fix all stall cases
completely: in the above situation, if the file has a huge number of pages
in pagecache (but not dirty), then mapping->nrpages is going to be huge,
even if pages are being dirtied.
This change does indeed make the possibility of long stalls lager, and
that's not a good thing, but lying about data integrity is even worse. We
have to either perform the sync, or return -ELINUXISLAME so at least the
caller knows what has happened.
There are subsequent competing approaches in the works to solve the stall
problems properly, without compromising data integrity.
Signed-off-by: Nick Piggin <npiggin@suse.de>
Cc: Chris Mason <chris.mason@oracle.com>
Cc: Dave Chinner <david@fromorbit.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2009-01-07 06:39:08 +08:00
|
|
|
.nr_to_write = LONG_MAX,
|
[PATCH] writeback: fix range handling
When a writeback_control's `start' and `end' fields are used to
indicate a one-byte-range starting at file offset zero, the required
values of .start=0,.end=0 mean that the ->writepages() implementation
has no way of telling that it is being asked to perform a range
request. Because we're currently overloading (start == 0 && end == 0)
to mean "this is not a write-a-range request".
To make all this sane, the patch changes range of writeback_control.
So caller does: If it is calling ->writepages() to write pages, it
sets range (range_start/end or range_cyclic) always.
And if range_cyclic is true, ->writepages() thinks the range is
cyclic, otherwise it just uses range_start and range_end.
This patch does,
- Add LLONG_MAX, LLONG_MIN, ULLONG_MAX to include/linux/kernel.h
-1 is usually ok for range_end (type is long long). But, if someone did,
range_end += val; range_end is "val - 1"
u64val = range_end >> bits; u64val is "~(0ULL)"
or something, they are wrong. So, this adds LLONG_MAX to avoid nasty
things, and uses LLONG_MAX for range_end.
- All callers of ->writepages() sets range_start/end or range_cyclic.
- Fix updates of ->writeback_index. It seems already bit strange.
If it starts at 0 and ended by check of nr_to_write, this last
index may reduce chance to scan end of file. So, this updates
->writeback_index only if range_cyclic is true or whole-file is
scanned.
Signed-off-by: OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>
Cc: Nathan Scott <nathans@sgi.com>
Cc: Anton Altaparmakov <aia21@cantab.net>
Cc: Steven French <sfrench@us.ibm.com>
Cc: "Vladimir V. Saveliev" <vs@namesys.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
2006-06-23 17:03:26 +08:00
|
|
|
.range_start = start,
|
|
|
|
.range_end = end,
|
2005-04-17 06:20:36 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
if (!mapping_cap_writeback_dirty(mapping))
|
|
|
|
return 0;
|
|
|
|
|
2015-06-02 22:39:48 +08:00
|
|
|
wbc_attach_fdatawrite_inode(&wbc, mapping->host);
|
2005-04-17 06:20:36 +08:00
|
|
|
ret = do_writepages(mapping, &wbc);
|
2015-06-02 22:39:48 +08:00
|
|
|
wbc_detach_inode(&wbc);
|
2005-04-17 06:20:36 +08:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline int __filemap_fdatawrite(struct address_space *mapping,
|
|
|
|
int sync_mode)
|
|
|
|
{
|
[PATCH] writeback: fix range handling
When a writeback_control's `start' and `end' fields are used to
indicate a one-byte-range starting at file offset zero, the required
values of .start=0,.end=0 mean that the ->writepages() implementation
has no way of telling that it is being asked to perform a range
request. Because we're currently overloading (start == 0 && end == 0)
to mean "this is not a write-a-range request".
To make all this sane, the patch changes range of writeback_control.
So caller does: If it is calling ->writepages() to write pages, it
sets range (range_start/end or range_cyclic) always.
And if range_cyclic is true, ->writepages() thinks the range is
cyclic, otherwise it just uses range_start and range_end.
This patch does,
- Add LLONG_MAX, LLONG_MIN, ULLONG_MAX to include/linux/kernel.h
-1 is usually ok for range_end (type is long long). But, if someone did,
range_end += val; range_end is "val - 1"
u64val = range_end >> bits; u64val is "~(0ULL)"
or something, they are wrong. So, this adds LLONG_MAX to avoid nasty
things, and uses LLONG_MAX for range_end.
- All callers of ->writepages() sets range_start/end or range_cyclic.
- Fix updates of ->writeback_index. It seems already bit strange.
If it starts at 0 and ended by check of nr_to_write, this last
index may reduce chance to scan end of file. So, this updates
->writeback_index only if range_cyclic is true or whole-file is
scanned.
Signed-off-by: OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>
Cc: Nathan Scott <nathans@sgi.com>
Cc: Anton Altaparmakov <aia21@cantab.net>
Cc: Steven French <sfrench@us.ibm.com>
Cc: "Vladimir V. Saveliev" <vs@namesys.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
2006-06-23 17:03:26 +08:00
|
|
|
return __filemap_fdatawrite_range(mapping, 0, LLONG_MAX, sync_mode);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
int filemap_fdatawrite(struct address_space *mapping)
|
|
|
|
{
|
|
|
|
return __filemap_fdatawrite(mapping, WB_SYNC_ALL);
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(filemap_fdatawrite);
|
|
|
|
|
2008-07-12 07:27:31 +08:00
|
|
|
int filemap_fdatawrite_range(struct address_space *mapping, loff_t start,
|
[PATCH] fadvise(): write commands
Add two new linux-specific fadvise extensions():
LINUX_FADV_ASYNC_WRITE: start async writeout of any dirty pages between file
offsets `offset' and `offset+len'. Any pages which are currently under
writeout are skipped, whether or not they are dirty.
LINUX_FADV_WRITE_WAIT: wait upon writeout of any dirty pages between file
offsets `offset' and `offset+len'.
By combining these two operations the application may do several things:
LINUX_FADV_ASYNC_WRITE: push some or all of the dirty pages at the disk.
LINUX_FADV_WRITE_WAIT, LINUX_FADV_ASYNC_WRITE: push all of the currently dirty
pages at the disk.
LINUX_FADV_WRITE_WAIT, LINUX_FADV_ASYNC_WRITE, LINUX_FADV_WRITE_WAIT: push all
of the currently dirty pages at the disk, wait until they have been written.
It should be noted that none of these operations write out the file's
metadata. So unless the application is strictly performing overwrites of
already-instantiated disk blocks, there are no guarantees here that the data
will be available after a crash.
To complete this suite of operations I guess we should have a "sync file
metadata only" operation. This gives applications access to all the building
blocks needed for all sorts of sync operations. But sync-metadata doesn't fit
well with the fadvise() interface. Probably it should be a new syscall:
sys_fmetadatasync().
The patch also diddles with the meaning of `endbyte' in sys_fadvise64_64().
It is made to represent that last affected byte in the file (ie: it is
inclusive). Generally, all these byterange and pagerange functions are
inclusive so we can easily represent EOF with -1.
As Ulrich notes, these two functions are somewhat abusive of the fadvise()
concept, which appears to be "set the future policy for this fd".
But these commands are a perfect fit with the fadvise() impementation, and
several of the existing fadvise() commands are synchronous and don't affect
future policy either. I think we can live with the slight incongruity.
Cc: Michael Kerrisk <mtk-manpages@gmx.net>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
2006-03-24 19:18:04 +08:00
|
|
|
loff_t end)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
|
|
|
return __filemap_fdatawrite_range(mapping, start, end, WB_SYNC_ALL);
|
|
|
|
}
|
2008-07-12 07:27:31 +08:00
|
|
|
EXPORT_SYMBOL(filemap_fdatawrite_range);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2006-06-23 17:03:49 +08:00
|
|
|
/**
|
|
|
|
* filemap_flush - mostly a non-blocking flush
|
|
|
|
* @mapping: target address_space
|
|
|
|
*
|
2005-04-17 06:20:36 +08:00
|
|
|
* This is a mostly non-blocking flush. Not suitable for data-integrity
|
|
|
|
* purposes - I/O may not be started against all dirty pages.
|
|
|
|
*/
|
|
|
|
int filemap_flush(struct address_space *mapping)
|
|
|
|
{
|
|
|
|
return __filemap_fdatawrite(mapping, WB_SYNC_NONE);
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(filemap_flush);
|
|
|
|
|
2015-11-06 10:47:23 +08:00
|
|
|
static int __filemap_fdatawait_range(struct address_space *mapping,
|
|
|
|
loff_t start_byte, loff_t end_byte)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2009-10-01 04:16:33 +08:00
|
|
|
pgoff_t index = start_byte >> PAGE_CACHE_SHIFT;
|
|
|
|
pgoff_t end = end_byte >> PAGE_CACHE_SHIFT;
|
2005-04-17 06:20:36 +08:00
|
|
|
struct pagevec pvec;
|
|
|
|
int nr_pages;
|
2015-11-06 10:47:23 +08:00
|
|
|
int ret = 0;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2009-10-01 04:16:33 +08:00
|
|
|
if (end_byte < start_byte)
|
2013-04-30 06:08:42 +08:00
|
|
|
goto out;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
pagevec_init(&pvec, 0);
|
|
|
|
while ((index <= end) &&
|
|
|
|
(nr_pages = pagevec_lookup_tag(&pvec, mapping, &index,
|
|
|
|
PAGECACHE_TAG_WRITEBACK,
|
|
|
|
min(end - index, (pgoff_t)PAGEVEC_SIZE-1) + 1)) != 0) {
|
|
|
|
unsigned i;
|
|
|
|
|
|
|
|
for (i = 0; i < nr_pages; i++) {
|
|
|
|
struct page *page = pvec.pages[i];
|
|
|
|
|
|
|
|
/* until radix tree lookup accepts end_index */
|
|
|
|
if (page->index > end)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
wait_on_page_writeback(page);
|
2011-01-14 07:46:06 +08:00
|
|
|
if (TestClearPageError(page))
|
2005-04-17 06:20:36 +08:00
|
|
|
ret = -EIO;
|
|
|
|
}
|
|
|
|
pagevec_release(&pvec);
|
|
|
|
cond_resched();
|
|
|
|
}
|
2013-04-30 06:08:42 +08:00
|
|
|
out:
|
2015-11-06 10:47:23 +08:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* filemap_fdatawait_range - wait for writeback to complete
|
|
|
|
* @mapping: address space structure to wait for
|
|
|
|
* @start_byte: offset in bytes where the range starts
|
|
|
|
* @end_byte: offset in bytes where the range ends (inclusive)
|
|
|
|
*
|
|
|
|
* Walk the list of under-writeback pages of the given address space
|
|
|
|
* in the given range and wait for all of them. Check error status of
|
|
|
|
* the address space and return it.
|
|
|
|
*
|
|
|
|
* Since the error status of the address space is cleared by this function,
|
|
|
|
* callers are responsible for checking the return value and handling and/or
|
|
|
|
* reporting the error.
|
|
|
|
*/
|
|
|
|
int filemap_fdatawait_range(struct address_space *mapping, loff_t start_byte,
|
|
|
|
loff_t end_byte)
|
|
|
|
{
|
|
|
|
int ret, ret2;
|
|
|
|
|
|
|
|
ret = __filemap_fdatawait_range(mapping, start_byte, end_byte);
|
2013-04-30 06:08:42 +08:00
|
|
|
ret2 = filemap_check_errors(mapping);
|
|
|
|
if (!ret)
|
|
|
|
ret = ret2;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
2009-08-18 01:30:27 +08:00
|
|
|
EXPORT_SYMBOL(filemap_fdatawait_range);
|
|
|
|
|
2015-11-06 10:47:23 +08:00
|
|
|
/**
|
|
|
|
* filemap_fdatawait_keep_errors - wait for writeback without clearing errors
|
|
|
|
* @mapping: address space structure to wait for
|
|
|
|
*
|
|
|
|
* Walk the list of under-writeback pages of the given address space
|
|
|
|
* and wait for all of them. Unlike filemap_fdatawait(), this function
|
|
|
|
* does not clear error status of the address space.
|
|
|
|
*
|
|
|
|
* Use this function if callers don't handle errors themselves. Expected
|
|
|
|
* call sites are system-wide / filesystem-wide data flushers: e.g. sync(2),
|
|
|
|
* fsfreeze(8)
|
|
|
|
*/
|
|
|
|
void filemap_fdatawait_keep_errors(struct address_space *mapping)
|
|
|
|
{
|
|
|
|
loff_t i_size = i_size_read(mapping->host);
|
|
|
|
|
|
|
|
if (i_size == 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
__filemap_fdatawait_range(mapping, 0, i_size - 1);
|
|
|
|
}
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
/**
|
2006-06-23 17:03:49 +08:00
|
|
|
* filemap_fdatawait - wait for all under-writeback pages to complete
|
2005-04-17 06:20:36 +08:00
|
|
|
* @mapping: address space structure to wait for
|
2006-06-23 17:03:49 +08:00
|
|
|
*
|
|
|
|
* Walk the list of under-writeback pages of the given address space
|
2015-11-06 10:47:23 +08:00
|
|
|
* and wait for all of them. Check error status of the address space
|
|
|
|
* and return it.
|
|
|
|
*
|
|
|
|
* Since the error status of the address space is cleared by this function,
|
|
|
|
* callers are responsible for checking the return value and handling and/or
|
|
|
|
* reporting the error.
|
2005-04-17 06:20:36 +08:00
|
|
|
*/
|
|
|
|
int filemap_fdatawait(struct address_space *mapping)
|
|
|
|
{
|
|
|
|
loff_t i_size = i_size_read(mapping->host);
|
|
|
|
|
|
|
|
if (i_size == 0)
|
|
|
|
return 0;
|
|
|
|
|
2009-10-01 04:16:33 +08:00
|
|
|
return filemap_fdatawait_range(mapping, 0, i_size - 1);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(filemap_fdatawait);
|
|
|
|
|
|
|
|
int filemap_write_and_wait(struct address_space *mapping)
|
|
|
|
{
|
[PATCH] Fix and add EXPORT_SYMBOL(filemap_write_and_wait)
This patch add EXPORT_SYMBOL(filemap_write_and_wait) and use it.
See mm/filemap.c:
And changes the filemap_write_and_wait() and filemap_write_and_wait_range().
Current filemap_write_and_wait() doesn't wait if filemap_fdatawrite()
returns error. However, even if filemap_fdatawrite() returned an
error, it may have submitted the partially data pages to the device.
(e.g. in the case of -ENOSPC)
<quotation>
Andrew Morton writes,
If filemap_fdatawrite() returns an error, this might be due to some
I/O problem: dead disk, unplugged cable, etc. Given the generally
crappy quality of the kernel's handling of such exceptions, there's a
good chance that the filemap_fdatawait() will get stuck in D state
forever.
</quotation>
So, this patch doesn't wait if filemap_fdatawrite() returns the -EIO.
Trond, could you please review the nfs part? Especially I'm not sure,
nfs must use the "filemap_fdatawrite(inode->i_mapping) == 0", or not.
Acked-by: Trond Myklebust <trond.myklebust@fys.uio.no>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
2006-01-08 17:02:14 +08:00
|
|
|
int err = 0;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2016-02-27 07:19:55 +08:00
|
|
|
if ((!dax_mapping(mapping) && mapping->nrpages) ||
|
|
|
|
(dax_mapping(mapping) && mapping->nrexceptional)) {
|
[PATCH] Fix and add EXPORT_SYMBOL(filemap_write_and_wait)
This patch add EXPORT_SYMBOL(filemap_write_and_wait) and use it.
See mm/filemap.c:
And changes the filemap_write_and_wait() and filemap_write_and_wait_range().
Current filemap_write_and_wait() doesn't wait if filemap_fdatawrite()
returns error. However, even if filemap_fdatawrite() returned an
error, it may have submitted the partially data pages to the device.
(e.g. in the case of -ENOSPC)
<quotation>
Andrew Morton writes,
If filemap_fdatawrite() returns an error, this might be due to some
I/O problem: dead disk, unplugged cable, etc. Given the generally
crappy quality of the kernel's handling of such exceptions, there's a
good chance that the filemap_fdatawait() will get stuck in D state
forever.
</quotation>
So, this patch doesn't wait if filemap_fdatawrite() returns the -EIO.
Trond, could you please review the nfs part? Especially I'm not sure,
nfs must use the "filemap_fdatawrite(inode->i_mapping) == 0", or not.
Acked-by: Trond Myklebust <trond.myklebust@fys.uio.no>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
2006-01-08 17:02:14 +08:00
|
|
|
err = filemap_fdatawrite(mapping);
|
|
|
|
/*
|
|
|
|
* Even if the above returned error, the pages may be
|
|
|
|
* written partially (e.g. -ENOSPC), so we wait for it.
|
|
|
|
* But the -EIO is special case, it may indicate the worst
|
|
|
|
* thing (e.g. bug) happened, so we avoid waiting for it.
|
|
|
|
*/
|
|
|
|
if (err != -EIO) {
|
|
|
|
int err2 = filemap_fdatawait(mapping);
|
|
|
|
if (!err)
|
|
|
|
err = err2;
|
|
|
|
}
|
2013-04-30 06:08:42 +08:00
|
|
|
} else {
|
|
|
|
err = filemap_check_errors(mapping);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
[PATCH] Fix and add EXPORT_SYMBOL(filemap_write_and_wait)
This patch add EXPORT_SYMBOL(filemap_write_and_wait) and use it.
See mm/filemap.c:
And changes the filemap_write_and_wait() and filemap_write_and_wait_range().
Current filemap_write_and_wait() doesn't wait if filemap_fdatawrite()
returns error. However, even if filemap_fdatawrite() returned an
error, it may have submitted the partially data pages to the device.
(e.g. in the case of -ENOSPC)
<quotation>
Andrew Morton writes,
If filemap_fdatawrite() returns an error, this might be due to some
I/O problem: dead disk, unplugged cable, etc. Given the generally
crappy quality of the kernel's handling of such exceptions, there's a
good chance that the filemap_fdatawait() will get stuck in D state
forever.
</quotation>
So, this patch doesn't wait if filemap_fdatawrite() returns the -EIO.
Trond, could you please review the nfs part? Especially I'm not sure,
nfs must use the "filemap_fdatawrite(inode->i_mapping) == 0", or not.
Acked-by: Trond Myklebust <trond.myklebust@fys.uio.no>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
2006-01-08 17:02:14 +08:00
|
|
|
return err;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
[PATCH] Fix and add EXPORT_SYMBOL(filemap_write_and_wait)
This patch add EXPORT_SYMBOL(filemap_write_and_wait) and use it.
See mm/filemap.c:
And changes the filemap_write_and_wait() and filemap_write_and_wait_range().
Current filemap_write_and_wait() doesn't wait if filemap_fdatawrite()
returns error. However, even if filemap_fdatawrite() returned an
error, it may have submitted the partially data pages to the device.
(e.g. in the case of -ENOSPC)
<quotation>
Andrew Morton writes,
If filemap_fdatawrite() returns an error, this might be due to some
I/O problem: dead disk, unplugged cable, etc. Given the generally
crappy quality of the kernel's handling of such exceptions, there's a
good chance that the filemap_fdatawait() will get stuck in D state
forever.
</quotation>
So, this patch doesn't wait if filemap_fdatawrite() returns the -EIO.
Trond, could you please review the nfs part? Especially I'm not sure,
nfs must use the "filemap_fdatawrite(inode->i_mapping) == 0", or not.
Acked-by: Trond Myklebust <trond.myklebust@fys.uio.no>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
2006-01-08 17:02:14 +08:00
|
|
|
EXPORT_SYMBOL(filemap_write_and_wait);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2006-06-23 17:03:49 +08:00
|
|
|
/**
|
|
|
|
* filemap_write_and_wait_range - write out & wait on a file range
|
|
|
|
* @mapping: the address_space for the pages
|
|
|
|
* @lstart: offset in bytes where the range starts
|
|
|
|
* @lend: offset in bytes where the range ends (inclusive)
|
|
|
|
*
|
2006-03-24 19:17:45 +08:00
|
|
|
* Write out and wait upon file offsets lstart->lend, inclusive.
|
|
|
|
*
|
|
|
|
* Note that `lend' is inclusive (describes the last byte to be written) so
|
|
|
|
* that this function can be used to write to the very end-of-file (end = -1).
|
|
|
|
*/
|
2005-04-17 06:20:36 +08:00
|
|
|
int filemap_write_and_wait_range(struct address_space *mapping,
|
|
|
|
loff_t lstart, loff_t lend)
|
|
|
|
{
|
[PATCH] Fix and add EXPORT_SYMBOL(filemap_write_and_wait)
This patch add EXPORT_SYMBOL(filemap_write_and_wait) and use it.
See mm/filemap.c:
And changes the filemap_write_and_wait() and filemap_write_and_wait_range().
Current filemap_write_and_wait() doesn't wait if filemap_fdatawrite()
returns error. However, even if filemap_fdatawrite() returned an
error, it may have submitted the partially data pages to the device.
(e.g. in the case of -ENOSPC)
<quotation>
Andrew Morton writes,
If filemap_fdatawrite() returns an error, this might be due to some
I/O problem: dead disk, unplugged cable, etc. Given the generally
crappy quality of the kernel's handling of such exceptions, there's a
good chance that the filemap_fdatawait() will get stuck in D state
forever.
</quotation>
So, this patch doesn't wait if filemap_fdatawrite() returns the -EIO.
Trond, could you please review the nfs part? Especially I'm not sure,
nfs must use the "filemap_fdatawrite(inode->i_mapping) == 0", or not.
Acked-by: Trond Myklebust <trond.myklebust@fys.uio.no>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
2006-01-08 17:02:14 +08:00
|
|
|
int err = 0;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2016-02-27 07:19:55 +08:00
|
|
|
if ((!dax_mapping(mapping) && mapping->nrpages) ||
|
|
|
|
(dax_mapping(mapping) && mapping->nrexceptional)) {
|
[PATCH] Fix and add EXPORT_SYMBOL(filemap_write_and_wait)
This patch add EXPORT_SYMBOL(filemap_write_and_wait) and use it.
See mm/filemap.c:
And changes the filemap_write_and_wait() and filemap_write_and_wait_range().
Current filemap_write_and_wait() doesn't wait if filemap_fdatawrite()
returns error. However, even if filemap_fdatawrite() returned an
error, it may have submitted the partially data pages to the device.
(e.g. in the case of -ENOSPC)
<quotation>
Andrew Morton writes,
If filemap_fdatawrite() returns an error, this might be due to some
I/O problem: dead disk, unplugged cable, etc. Given the generally
crappy quality of the kernel's handling of such exceptions, there's a
good chance that the filemap_fdatawait() will get stuck in D state
forever.
</quotation>
So, this patch doesn't wait if filemap_fdatawrite() returns the -EIO.
Trond, could you please review the nfs part? Especially I'm not sure,
nfs must use the "filemap_fdatawrite(inode->i_mapping) == 0", or not.
Acked-by: Trond Myklebust <trond.myklebust@fys.uio.no>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
2006-01-08 17:02:14 +08:00
|
|
|
err = __filemap_fdatawrite_range(mapping, lstart, lend,
|
|
|
|
WB_SYNC_ALL);
|
|
|
|
/* See comment of filemap_write_and_wait() */
|
|
|
|
if (err != -EIO) {
|
2009-10-01 04:16:33 +08:00
|
|
|
int err2 = filemap_fdatawait_range(mapping,
|
|
|
|
lstart, lend);
|
[PATCH] Fix and add EXPORT_SYMBOL(filemap_write_and_wait)
This patch add EXPORT_SYMBOL(filemap_write_and_wait) and use it.
See mm/filemap.c:
And changes the filemap_write_and_wait() and filemap_write_and_wait_range().
Current filemap_write_and_wait() doesn't wait if filemap_fdatawrite()
returns error. However, even if filemap_fdatawrite() returned an
error, it may have submitted the partially data pages to the device.
(e.g. in the case of -ENOSPC)
<quotation>
Andrew Morton writes,
If filemap_fdatawrite() returns an error, this might be due to some
I/O problem: dead disk, unplugged cable, etc. Given the generally
crappy quality of the kernel's handling of such exceptions, there's a
good chance that the filemap_fdatawait() will get stuck in D state
forever.
</quotation>
So, this patch doesn't wait if filemap_fdatawrite() returns the -EIO.
Trond, could you please review the nfs part? Especially I'm not sure,
nfs must use the "filemap_fdatawrite(inode->i_mapping) == 0", or not.
Acked-by: Trond Myklebust <trond.myklebust@fys.uio.no>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
2006-01-08 17:02:14 +08:00
|
|
|
if (!err)
|
|
|
|
err = err2;
|
|
|
|
}
|
2013-04-30 06:08:42 +08:00
|
|
|
} else {
|
|
|
|
err = filemap_check_errors(mapping);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
[PATCH] Fix and add EXPORT_SYMBOL(filemap_write_and_wait)
This patch add EXPORT_SYMBOL(filemap_write_and_wait) and use it.
See mm/filemap.c:
And changes the filemap_write_and_wait() and filemap_write_and_wait_range().
Current filemap_write_and_wait() doesn't wait if filemap_fdatawrite()
returns error. However, even if filemap_fdatawrite() returned an
error, it may have submitted the partially data pages to the device.
(e.g. in the case of -ENOSPC)
<quotation>
Andrew Morton writes,
If filemap_fdatawrite() returns an error, this might be due to some
I/O problem: dead disk, unplugged cable, etc. Given the generally
crappy quality of the kernel's handling of such exceptions, there's a
good chance that the filemap_fdatawait() will get stuck in D state
forever.
</quotation>
So, this patch doesn't wait if filemap_fdatawrite() returns the -EIO.
Trond, could you please review the nfs part? Especially I'm not sure,
nfs must use the "filemap_fdatawrite(inode->i_mapping) == 0", or not.
Acked-by: Trond Myklebust <trond.myklebust@fys.uio.no>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
2006-01-08 17:02:14 +08:00
|
|
|
return err;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
2009-04-16 01:22:37 +08:00
|
|
|
EXPORT_SYMBOL(filemap_write_and_wait_range);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2011-03-23 07:30:52 +08:00
|
|
|
/**
|
|
|
|
* replace_page_cache_page - replace a pagecache page with a new one
|
|
|
|
* @old: page to be replaced
|
|
|
|
* @new: page to replace with
|
|
|
|
* @gfp_mask: allocation mode
|
|
|
|
*
|
|
|
|
* This function replaces a page in the pagecache with a new one. On
|
|
|
|
* success it acquires the pagecache reference for the new page and
|
|
|
|
* drops it for the old page. Both the old and new pages must be
|
|
|
|
* locked. This function does not add the new page to the LRU, the
|
|
|
|
* caller must do that.
|
|
|
|
*
|
|
|
|
* The remove + add is atomic. The only way this function can fail is
|
|
|
|
* memory allocation failure.
|
|
|
|
*/
|
|
|
|
int replace_page_cache_page(struct page *old, struct page *new, gfp_t gfp_mask)
|
|
|
|
{
|
|
|
|
int error;
|
|
|
|
|
2014-01-24 07:52:54 +08:00
|
|
|
VM_BUG_ON_PAGE(!PageLocked(old), old);
|
|
|
|
VM_BUG_ON_PAGE(!PageLocked(new), new);
|
|
|
|
VM_BUG_ON_PAGE(new->mapping, new);
|
2011-03-23 07:30:52 +08:00
|
|
|
|
|
|
|
error = radix_tree_preload(gfp_mask & ~__GFP_HIGHMEM);
|
|
|
|
if (!error) {
|
|
|
|
struct address_space *mapping = old->mapping;
|
|
|
|
void (*freepage)(struct page *);
|
memcg: add per cgroup dirty page accounting
When modifying PG_Dirty on cached file pages, update the new
MEM_CGROUP_STAT_DIRTY counter. This is done in the same places where
global NR_FILE_DIRTY is managed. The new memcg stat is visible in the
per memcg memory.stat cgroupfs file. The most recent past attempt at
this was http://thread.gmane.org/gmane.linux.kernel.cgroups/8632
The new accounting supports future efforts to add per cgroup dirty
page throttling and writeback. It also helps an administrator break
down a container's memory usage and provides evidence to understand
memcg oom kills (the new dirty count is included in memcg oom kill
messages).
The ability to move page accounting between memcg
(memory.move_charge_at_immigrate) makes this accounting more
complicated than the global counter. The existing
mem_cgroup_{begin,end}_page_stat() lock is used to serialize move
accounting with stat updates.
Typical update operation:
memcg = mem_cgroup_begin_page_stat(page)
if (TestSetPageDirty()) {
[...]
mem_cgroup_update_page_stat(memcg)
}
mem_cgroup_end_page_stat(memcg)
Summary of mem_cgroup_end_page_stat() overhead:
- Without CONFIG_MEMCG it's a no-op
- With CONFIG_MEMCG and no inter memcg task movement, it's just
rcu_read_lock()
- With CONFIG_MEMCG and inter memcg task movement, it's
rcu_read_lock() + spin_lock_irqsave()
A memcg parameter is added to several routines because their callers
now grab mem_cgroup_begin_page_stat() which returns the memcg later
needed by for mem_cgroup_update_page_stat().
Because mem_cgroup_begin_page_stat() may disable interrupts, some
adjustments are needed:
- move __mark_inode_dirty() from __set_page_dirty() to its caller.
__mark_inode_dirty() locking does not want interrupts disabled.
- use spin_lock_irqsave(tree_lock) rather than spin_lock_irq() in
__delete_from_page_cache(), replace_page_cache_page(),
invalidate_complete_page2(), and __remove_mapping().
text data bss dec hex filename
8925147 1774832 1785856 12485835 be84cb vmlinux-!CONFIG_MEMCG-before
8925339 1774832 1785856 12486027 be858b vmlinux-!CONFIG_MEMCG-after
+192 text bytes
8965977 1784992 1785856 12536825 bf4bf9 vmlinux-CONFIG_MEMCG-before
8966750 1784992 1785856 12537598 bf4efe vmlinux-CONFIG_MEMCG-after
+773 text bytes
Performance tests run on v4.0-rc1-36-g4f671fe2f952. Lower is better for
all metrics, they're all wall clock or cycle counts. The read and write
fault benchmarks just measure fault time, they do not include I/O time.
* CONFIG_MEMCG not set:
baseline patched
kbuild 1m25.030000(+-0.088% 3 samples) 1m25.426667(+-0.120% 3 samples)
dd write 100 MiB 0.859211561 +-15.10% 0.874162885 +-15.03%
dd write 200 MiB 1.670653105 +-17.87% 1.669384764 +-11.99%
dd write 1000 MiB 8.434691190 +-14.15% 8.474733215 +-14.77%
read fault cycles 254.0(+-0.000% 10 samples) 253.0(+-0.000% 10 samples)
write fault cycles 2021.2(+-3.070% 10 samples) 1984.5(+-1.036% 10 samples)
* CONFIG_MEMCG=y root_memcg:
baseline patched
kbuild 1m25.716667(+-0.105% 3 samples) 1m25.686667(+-0.153% 3 samples)
dd write 100 MiB 0.855650830 +-14.90% 0.887557919 +-14.90%
dd write 200 MiB 1.688322953 +-12.72% 1.667682724 +-13.33%
dd write 1000 MiB 8.418601605 +-14.30% 8.673532299 +-15.00%
read fault cycles 266.0(+-0.000% 10 samples) 266.0(+-0.000% 10 samples)
write fault cycles 2051.7(+-1.349% 10 samples) 2049.6(+-1.686% 10 samples)
* CONFIG_MEMCG=y non-root_memcg:
baseline patched
kbuild 1m26.120000(+-0.273% 3 samples) 1m25.763333(+-0.127% 3 samples)
dd write 100 MiB 0.861723964 +-15.25% 0.818129350 +-14.82%
dd write 200 MiB 1.669887569 +-13.30% 1.698645885 +-13.27%
dd write 1000 MiB 8.383191730 +-14.65% 8.351742280 +-14.52%
read fault cycles 265.7(+-0.172% 10 samples) 267.0(+-0.000% 10 samples)
write fault cycles 2070.6(+-1.512% 10 samples) 2084.4(+-2.148% 10 samples)
As expected anon page faults are not affected by this patch.
tj: Updated to apply on top of the recent cancel_dirty_page() changes.
Signed-off-by: Sha Zhengju <handai.szj@gmail.com>
Signed-off-by: Greg Thelen <gthelen@google.com>
Signed-off-by: Tejun Heo <tj@kernel.org>
Signed-off-by: Jens Axboe <axboe@fb.com>
2015-05-23 05:13:16 +08:00
|
|
|
struct mem_cgroup *memcg;
|
|
|
|
unsigned long flags;
|
2011-03-23 07:30:52 +08:00
|
|
|
|
|
|
|
pgoff_t offset = old->index;
|
|
|
|
freepage = mapping->a_ops->freepage;
|
|
|
|
|
|
|
|
page_cache_get(new);
|
|
|
|
new->mapping = mapping;
|
|
|
|
new->index = offset;
|
|
|
|
|
memcg: add per cgroup dirty page accounting
When modifying PG_Dirty on cached file pages, update the new
MEM_CGROUP_STAT_DIRTY counter. This is done in the same places where
global NR_FILE_DIRTY is managed. The new memcg stat is visible in the
per memcg memory.stat cgroupfs file. The most recent past attempt at
this was http://thread.gmane.org/gmane.linux.kernel.cgroups/8632
The new accounting supports future efforts to add per cgroup dirty
page throttling and writeback. It also helps an administrator break
down a container's memory usage and provides evidence to understand
memcg oom kills (the new dirty count is included in memcg oom kill
messages).
The ability to move page accounting between memcg
(memory.move_charge_at_immigrate) makes this accounting more
complicated than the global counter. The existing
mem_cgroup_{begin,end}_page_stat() lock is used to serialize move
accounting with stat updates.
Typical update operation:
memcg = mem_cgroup_begin_page_stat(page)
if (TestSetPageDirty()) {
[...]
mem_cgroup_update_page_stat(memcg)
}
mem_cgroup_end_page_stat(memcg)
Summary of mem_cgroup_end_page_stat() overhead:
- Without CONFIG_MEMCG it's a no-op
- With CONFIG_MEMCG and no inter memcg task movement, it's just
rcu_read_lock()
- With CONFIG_MEMCG and inter memcg task movement, it's
rcu_read_lock() + spin_lock_irqsave()
A memcg parameter is added to several routines because their callers
now grab mem_cgroup_begin_page_stat() which returns the memcg later
needed by for mem_cgroup_update_page_stat().
Because mem_cgroup_begin_page_stat() may disable interrupts, some
adjustments are needed:
- move __mark_inode_dirty() from __set_page_dirty() to its caller.
__mark_inode_dirty() locking does not want interrupts disabled.
- use spin_lock_irqsave(tree_lock) rather than spin_lock_irq() in
__delete_from_page_cache(), replace_page_cache_page(),
invalidate_complete_page2(), and __remove_mapping().
text data bss dec hex filename
8925147 1774832 1785856 12485835 be84cb vmlinux-!CONFIG_MEMCG-before
8925339 1774832 1785856 12486027 be858b vmlinux-!CONFIG_MEMCG-after
+192 text bytes
8965977 1784992 1785856 12536825 bf4bf9 vmlinux-CONFIG_MEMCG-before
8966750 1784992 1785856 12537598 bf4efe vmlinux-CONFIG_MEMCG-after
+773 text bytes
Performance tests run on v4.0-rc1-36-g4f671fe2f952. Lower is better for
all metrics, they're all wall clock or cycle counts. The read and write
fault benchmarks just measure fault time, they do not include I/O time.
* CONFIG_MEMCG not set:
baseline patched
kbuild 1m25.030000(+-0.088% 3 samples) 1m25.426667(+-0.120% 3 samples)
dd write 100 MiB 0.859211561 +-15.10% 0.874162885 +-15.03%
dd write 200 MiB 1.670653105 +-17.87% 1.669384764 +-11.99%
dd write 1000 MiB 8.434691190 +-14.15% 8.474733215 +-14.77%
read fault cycles 254.0(+-0.000% 10 samples) 253.0(+-0.000% 10 samples)
write fault cycles 2021.2(+-3.070% 10 samples) 1984.5(+-1.036% 10 samples)
* CONFIG_MEMCG=y root_memcg:
baseline patched
kbuild 1m25.716667(+-0.105% 3 samples) 1m25.686667(+-0.153% 3 samples)
dd write 100 MiB 0.855650830 +-14.90% 0.887557919 +-14.90%
dd write 200 MiB 1.688322953 +-12.72% 1.667682724 +-13.33%
dd write 1000 MiB 8.418601605 +-14.30% 8.673532299 +-15.00%
read fault cycles 266.0(+-0.000% 10 samples) 266.0(+-0.000% 10 samples)
write fault cycles 2051.7(+-1.349% 10 samples) 2049.6(+-1.686% 10 samples)
* CONFIG_MEMCG=y non-root_memcg:
baseline patched
kbuild 1m26.120000(+-0.273% 3 samples) 1m25.763333(+-0.127% 3 samples)
dd write 100 MiB 0.861723964 +-15.25% 0.818129350 +-14.82%
dd write 200 MiB 1.669887569 +-13.30% 1.698645885 +-13.27%
dd write 1000 MiB 8.383191730 +-14.65% 8.351742280 +-14.52%
read fault cycles 265.7(+-0.172% 10 samples) 267.0(+-0.000% 10 samples)
write fault cycles 2070.6(+-1.512% 10 samples) 2084.4(+-2.148% 10 samples)
As expected anon page faults are not affected by this patch.
tj: Updated to apply on top of the recent cancel_dirty_page() changes.
Signed-off-by: Sha Zhengju <handai.szj@gmail.com>
Signed-off-by: Greg Thelen <gthelen@google.com>
Signed-off-by: Tejun Heo <tj@kernel.org>
Signed-off-by: Jens Axboe <axboe@fb.com>
2015-05-23 05:13:16 +08:00
|
|
|
memcg = mem_cgroup_begin_page_stat(old);
|
|
|
|
spin_lock_irqsave(&mapping->tree_lock, flags);
|
|
|
|
__delete_from_page_cache(old, NULL, memcg);
|
2011-03-23 07:30:52 +08:00
|
|
|
error = radix_tree_insert(&mapping->page_tree, offset, new);
|
|
|
|
BUG_ON(error);
|
|
|
|
mapping->nrpages++;
|
2015-06-25 07:57:24 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* hugetlb pages do not participate in page cache accounting.
|
|
|
|
*/
|
|
|
|
if (!PageHuge(new))
|
|
|
|
__inc_zone_page_state(new, NR_FILE_PAGES);
|
2011-03-23 07:30:52 +08:00
|
|
|
if (PageSwapBacked(new))
|
|
|
|
__inc_zone_page_state(new, NR_SHMEM);
|
memcg: add per cgroup dirty page accounting
When modifying PG_Dirty on cached file pages, update the new
MEM_CGROUP_STAT_DIRTY counter. This is done in the same places where
global NR_FILE_DIRTY is managed. The new memcg stat is visible in the
per memcg memory.stat cgroupfs file. The most recent past attempt at
this was http://thread.gmane.org/gmane.linux.kernel.cgroups/8632
The new accounting supports future efforts to add per cgroup dirty
page throttling and writeback. It also helps an administrator break
down a container's memory usage and provides evidence to understand
memcg oom kills (the new dirty count is included in memcg oom kill
messages).
The ability to move page accounting between memcg
(memory.move_charge_at_immigrate) makes this accounting more
complicated than the global counter. The existing
mem_cgroup_{begin,end}_page_stat() lock is used to serialize move
accounting with stat updates.
Typical update operation:
memcg = mem_cgroup_begin_page_stat(page)
if (TestSetPageDirty()) {
[...]
mem_cgroup_update_page_stat(memcg)
}
mem_cgroup_end_page_stat(memcg)
Summary of mem_cgroup_end_page_stat() overhead:
- Without CONFIG_MEMCG it's a no-op
- With CONFIG_MEMCG and no inter memcg task movement, it's just
rcu_read_lock()
- With CONFIG_MEMCG and inter memcg task movement, it's
rcu_read_lock() + spin_lock_irqsave()
A memcg parameter is added to several routines because their callers
now grab mem_cgroup_begin_page_stat() which returns the memcg later
needed by for mem_cgroup_update_page_stat().
Because mem_cgroup_begin_page_stat() may disable interrupts, some
adjustments are needed:
- move __mark_inode_dirty() from __set_page_dirty() to its caller.
__mark_inode_dirty() locking does not want interrupts disabled.
- use spin_lock_irqsave(tree_lock) rather than spin_lock_irq() in
__delete_from_page_cache(), replace_page_cache_page(),
invalidate_complete_page2(), and __remove_mapping().
text data bss dec hex filename
8925147 1774832 1785856 12485835 be84cb vmlinux-!CONFIG_MEMCG-before
8925339 1774832 1785856 12486027 be858b vmlinux-!CONFIG_MEMCG-after
+192 text bytes
8965977 1784992 1785856 12536825 bf4bf9 vmlinux-CONFIG_MEMCG-before
8966750 1784992 1785856 12537598 bf4efe vmlinux-CONFIG_MEMCG-after
+773 text bytes
Performance tests run on v4.0-rc1-36-g4f671fe2f952. Lower is better for
all metrics, they're all wall clock or cycle counts. The read and write
fault benchmarks just measure fault time, they do not include I/O time.
* CONFIG_MEMCG not set:
baseline patched
kbuild 1m25.030000(+-0.088% 3 samples) 1m25.426667(+-0.120% 3 samples)
dd write 100 MiB 0.859211561 +-15.10% 0.874162885 +-15.03%
dd write 200 MiB 1.670653105 +-17.87% 1.669384764 +-11.99%
dd write 1000 MiB 8.434691190 +-14.15% 8.474733215 +-14.77%
read fault cycles 254.0(+-0.000% 10 samples) 253.0(+-0.000% 10 samples)
write fault cycles 2021.2(+-3.070% 10 samples) 1984.5(+-1.036% 10 samples)
* CONFIG_MEMCG=y root_memcg:
baseline patched
kbuild 1m25.716667(+-0.105% 3 samples) 1m25.686667(+-0.153% 3 samples)
dd write 100 MiB 0.855650830 +-14.90% 0.887557919 +-14.90%
dd write 200 MiB 1.688322953 +-12.72% 1.667682724 +-13.33%
dd write 1000 MiB 8.418601605 +-14.30% 8.673532299 +-15.00%
read fault cycles 266.0(+-0.000% 10 samples) 266.0(+-0.000% 10 samples)
write fault cycles 2051.7(+-1.349% 10 samples) 2049.6(+-1.686% 10 samples)
* CONFIG_MEMCG=y non-root_memcg:
baseline patched
kbuild 1m26.120000(+-0.273% 3 samples) 1m25.763333(+-0.127% 3 samples)
dd write 100 MiB 0.861723964 +-15.25% 0.818129350 +-14.82%
dd write 200 MiB 1.669887569 +-13.30% 1.698645885 +-13.27%
dd write 1000 MiB 8.383191730 +-14.65% 8.351742280 +-14.52%
read fault cycles 265.7(+-0.172% 10 samples) 267.0(+-0.000% 10 samples)
write fault cycles 2070.6(+-1.512% 10 samples) 2084.4(+-2.148% 10 samples)
As expected anon page faults are not affected by this patch.
tj: Updated to apply on top of the recent cancel_dirty_page() changes.
Signed-off-by: Sha Zhengju <handai.szj@gmail.com>
Signed-off-by: Greg Thelen <gthelen@google.com>
Signed-off-by: Tejun Heo <tj@kernel.org>
Signed-off-by: Jens Axboe <axboe@fb.com>
2015-05-23 05:13:16 +08:00
|
|
|
spin_unlock_irqrestore(&mapping->tree_lock, flags);
|
|
|
|
mem_cgroup_end_page_stat(memcg);
|
2015-11-06 10:49:40 +08:00
|
|
|
mem_cgroup_replace_page(old, new);
|
2011-03-23 07:30:52 +08:00
|
|
|
radix_tree_preload_end();
|
|
|
|
if (freepage)
|
|
|
|
freepage(old);
|
|
|
|
page_cache_release(old);
|
|
|
|
}
|
|
|
|
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(replace_page_cache_page);
|
|
|
|
|
2014-04-04 05:47:46 +08:00
|
|
|
static int page_cache_tree_insert(struct address_space *mapping,
|
2014-04-04 05:47:51 +08:00
|
|
|
struct page *page, void **shadowp)
|
2014-04-04 05:47:46 +08:00
|
|
|
{
|
mm: keep page cache radix tree nodes in check
Previously, page cache radix tree nodes were freed after reclaim emptied
out their page pointers. But now reclaim stores shadow entries in their
place, which are only reclaimed when the inodes themselves are
reclaimed. This is problematic for bigger files that are still in use
after they have a significant amount of their cache reclaimed, without
any of those pages actually refaulting. The shadow entries will just
sit there and waste memory. In the worst case, the shadow entries will
accumulate until the machine runs out of memory.
To get this under control, the VM will track radix tree nodes
exclusively containing shadow entries on a per-NUMA node list. Per-NUMA
rather than global because we expect the radix tree nodes themselves to
be allocated node-locally and we want to reduce cross-node references of
otherwise independent cache workloads. A simple shrinker will then
reclaim these nodes on memory pressure.
A few things need to be stored in the radix tree node to implement the
shadow node LRU and allow tree deletions coming from the list:
1. There is no index available that would describe the reverse path
from the node up to the tree root, which is needed to perform a
deletion. To solve this, encode in each node its offset inside the
parent. This can be stored in the unused upper bits of the same
member that stores the node's height at no extra space cost.
2. The number of shadow entries needs to be counted in addition to the
regular entries, to quickly detect when the node is ready to go to
the shadow node LRU list. The current entry count is an unsigned
int but the maximum number of entries is 64, so a shadow counter
can easily be stored in the unused upper bits.
3. Tree modification needs tree lock and tree root, which are located
in the address space, so store an address_space backpointer in the
node. The parent pointer of the node is in a union with the 2-word
rcu_head, so the backpointer comes at no extra cost as well.
4. The node needs to be linked to an LRU list, which requires a list
head inside the node. This does increase the size of the node, but
it does not change the number of objects that fit into a slab page.
[akpm@linux-foundation.org: export the right function]
Signed-off-by: Johannes Weiner <hannes@cmpxchg.org>
Reviewed-by: Rik van Riel <riel@redhat.com>
Reviewed-by: Minchan Kim <minchan@kernel.org>
Cc: Andrea Arcangeli <aarcange@redhat.com>
Cc: Bob Liu <bob.liu@oracle.com>
Cc: Christoph Hellwig <hch@infradead.org>
Cc: Dave Chinner <david@fromorbit.com>
Cc: Greg Thelen <gthelen@google.com>
Cc: Hugh Dickins <hughd@google.com>
Cc: Jan Kara <jack@suse.cz>
Cc: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
Cc: Luigi Semenzato <semenzato@google.com>
Cc: Mel Gorman <mgorman@suse.de>
Cc: Metin Doslu <metin@citusdata.com>
Cc: Michel Lespinasse <walken@google.com>
Cc: Ozgun Erdogan <ozgun@citusdata.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Roman Gushchin <klamm@yandex-team.ru>
Cc: Ryan Mallon <rmallon@gmail.com>
Cc: Tejun Heo <tj@kernel.org>
Cc: Vlastimil Babka <vbabka@suse.cz>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2014-04-04 05:47:56 +08:00
|
|
|
struct radix_tree_node *node;
|
2014-04-04 05:47:46 +08:00
|
|
|
void **slot;
|
|
|
|
int error;
|
|
|
|
|
mm: keep page cache radix tree nodes in check
Previously, page cache radix tree nodes were freed after reclaim emptied
out their page pointers. But now reclaim stores shadow entries in their
place, which are only reclaimed when the inodes themselves are
reclaimed. This is problematic for bigger files that are still in use
after they have a significant amount of their cache reclaimed, without
any of those pages actually refaulting. The shadow entries will just
sit there and waste memory. In the worst case, the shadow entries will
accumulate until the machine runs out of memory.
To get this under control, the VM will track radix tree nodes
exclusively containing shadow entries on a per-NUMA node list. Per-NUMA
rather than global because we expect the radix tree nodes themselves to
be allocated node-locally and we want to reduce cross-node references of
otherwise independent cache workloads. A simple shrinker will then
reclaim these nodes on memory pressure.
A few things need to be stored in the radix tree node to implement the
shadow node LRU and allow tree deletions coming from the list:
1. There is no index available that would describe the reverse path
from the node up to the tree root, which is needed to perform a
deletion. To solve this, encode in each node its offset inside the
parent. This can be stored in the unused upper bits of the same
member that stores the node's height at no extra space cost.
2. The number of shadow entries needs to be counted in addition to the
regular entries, to quickly detect when the node is ready to go to
the shadow node LRU list. The current entry count is an unsigned
int but the maximum number of entries is 64, so a shadow counter
can easily be stored in the unused upper bits.
3. Tree modification needs tree lock and tree root, which are located
in the address space, so store an address_space backpointer in the
node. The parent pointer of the node is in a union with the 2-word
rcu_head, so the backpointer comes at no extra cost as well.
4. The node needs to be linked to an LRU list, which requires a list
head inside the node. This does increase the size of the node, but
it does not change the number of objects that fit into a slab page.
[akpm@linux-foundation.org: export the right function]
Signed-off-by: Johannes Weiner <hannes@cmpxchg.org>
Reviewed-by: Rik van Riel <riel@redhat.com>
Reviewed-by: Minchan Kim <minchan@kernel.org>
Cc: Andrea Arcangeli <aarcange@redhat.com>
Cc: Bob Liu <bob.liu@oracle.com>
Cc: Christoph Hellwig <hch@infradead.org>
Cc: Dave Chinner <david@fromorbit.com>
Cc: Greg Thelen <gthelen@google.com>
Cc: Hugh Dickins <hughd@google.com>
Cc: Jan Kara <jack@suse.cz>
Cc: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
Cc: Luigi Semenzato <semenzato@google.com>
Cc: Mel Gorman <mgorman@suse.de>
Cc: Metin Doslu <metin@citusdata.com>
Cc: Michel Lespinasse <walken@google.com>
Cc: Ozgun Erdogan <ozgun@citusdata.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Roman Gushchin <klamm@yandex-team.ru>
Cc: Ryan Mallon <rmallon@gmail.com>
Cc: Tejun Heo <tj@kernel.org>
Cc: Vlastimil Babka <vbabka@suse.cz>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2014-04-04 05:47:56 +08:00
|
|
|
error = __radix_tree_create(&mapping->page_tree, page->index,
|
|
|
|
&node, &slot);
|
|
|
|
if (error)
|
|
|
|
return error;
|
|
|
|
if (*slot) {
|
2014-04-04 05:47:46 +08:00
|
|
|
void *p;
|
|
|
|
|
|
|
|
p = radix_tree_deref_slot_protected(slot, &mapping->tree_lock);
|
|
|
|
if (!radix_tree_exceptional_entry(p))
|
|
|
|
return -EEXIST;
|
2016-01-23 07:10:40 +08:00
|
|
|
|
|
|
|
if (WARN_ON(dax_mapping(mapping)))
|
|
|
|
return -EINVAL;
|
|
|
|
|
2014-04-04 05:47:51 +08:00
|
|
|
if (shadowp)
|
|
|
|
*shadowp = p;
|
2016-01-23 07:10:40 +08:00
|
|
|
mapping->nrexceptional--;
|
mm: keep page cache radix tree nodes in check
Previously, page cache radix tree nodes were freed after reclaim emptied
out their page pointers. But now reclaim stores shadow entries in their
place, which are only reclaimed when the inodes themselves are
reclaimed. This is problematic for bigger files that are still in use
after they have a significant amount of their cache reclaimed, without
any of those pages actually refaulting. The shadow entries will just
sit there and waste memory. In the worst case, the shadow entries will
accumulate until the machine runs out of memory.
To get this under control, the VM will track radix tree nodes
exclusively containing shadow entries on a per-NUMA node list. Per-NUMA
rather than global because we expect the radix tree nodes themselves to
be allocated node-locally and we want to reduce cross-node references of
otherwise independent cache workloads. A simple shrinker will then
reclaim these nodes on memory pressure.
A few things need to be stored in the radix tree node to implement the
shadow node LRU and allow tree deletions coming from the list:
1. There is no index available that would describe the reverse path
from the node up to the tree root, which is needed to perform a
deletion. To solve this, encode in each node its offset inside the
parent. This can be stored in the unused upper bits of the same
member that stores the node's height at no extra space cost.
2. The number of shadow entries needs to be counted in addition to the
regular entries, to quickly detect when the node is ready to go to
the shadow node LRU list. The current entry count is an unsigned
int but the maximum number of entries is 64, so a shadow counter
can easily be stored in the unused upper bits.
3. Tree modification needs tree lock and tree root, which are located
in the address space, so store an address_space backpointer in the
node. The parent pointer of the node is in a union with the 2-word
rcu_head, so the backpointer comes at no extra cost as well.
4. The node needs to be linked to an LRU list, which requires a list
head inside the node. This does increase the size of the node, but
it does not change the number of objects that fit into a slab page.
[akpm@linux-foundation.org: export the right function]
Signed-off-by: Johannes Weiner <hannes@cmpxchg.org>
Reviewed-by: Rik van Riel <riel@redhat.com>
Reviewed-by: Minchan Kim <minchan@kernel.org>
Cc: Andrea Arcangeli <aarcange@redhat.com>
Cc: Bob Liu <bob.liu@oracle.com>
Cc: Christoph Hellwig <hch@infradead.org>
Cc: Dave Chinner <david@fromorbit.com>
Cc: Greg Thelen <gthelen@google.com>
Cc: Hugh Dickins <hughd@google.com>
Cc: Jan Kara <jack@suse.cz>
Cc: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
Cc: Luigi Semenzato <semenzato@google.com>
Cc: Mel Gorman <mgorman@suse.de>
Cc: Metin Doslu <metin@citusdata.com>
Cc: Michel Lespinasse <walken@google.com>
Cc: Ozgun Erdogan <ozgun@citusdata.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Roman Gushchin <klamm@yandex-team.ru>
Cc: Ryan Mallon <rmallon@gmail.com>
Cc: Tejun Heo <tj@kernel.org>
Cc: Vlastimil Babka <vbabka@suse.cz>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2014-04-04 05:47:56 +08:00
|
|
|
if (node)
|
|
|
|
workingset_node_shadows_dec(node);
|
2014-04-04 05:47:46 +08:00
|
|
|
}
|
mm: keep page cache radix tree nodes in check
Previously, page cache radix tree nodes were freed after reclaim emptied
out their page pointers. But now reclaim stores shadow entries in their
place, which are only reclaimed when the inodes themselves are
reclaimed. This is problematic for bigger files that are still in use
after they have a significant amount of their cache reclaimed, without
any of those pages actually refaulting. The shadow entries will just
sit there and waste memory. In the worst case, the shadow entries will
accumulate until the machine runs out of memory.
To get this under control, the VM will track radix tree nodes
exclusively containing shadow entries on a per-NUMA node list. Per-NUMA
rather than global because we expect the radix tree nodes themselves to
be allocated node-locally and we want to reduce cross-node references of
otherwise independent cache workloads. A simple shrinker will then
reclaim these nodes on memory pressure.
A few things need to be stored in the radix tree node to implement the
shadow node LRU and allow tree deletions coming from the list:
1. There is no index available that would describe the reverse path
from the node up to the tree root, which is needed to perform a
deletion. To solve this, encode in each node its offset inside the
parent. This can be stored in the unused upper bits of the same
member that stores the node's height at no extra space cost.
2. The number of shadow entries needs to be counted in addition to the
regular entries, to quickly detect when the node is ready to go to
the shadow node LRU list. The current entry count is an unsigned
int but the maximum number of entries is 64, so a shadow counter
can easily be stored in the unused upper bits.
3. Tree modification needs tree lock and tree root, which are located
in the address space, so store an address_space backpointer in the
node. The parent pointer of the node is in a union with the 2-word
rcu_head, so the backpointer comes at no extra cost as well.
4. The node needs to be linked to an LRU list, which requires a list
head inside the node. This does increase the size of the node, but
it does not change the number of objects that fit into a slab page.
[akpm@linux-foundation.org: export the right function]
Signed-off-by: Johannes Weiner <hannes@cmpxchg.org>
Reviewed-by: Rik van Riel <riel@redhat.com>
Reviewed-by: Minchan Kim <minchan@kernel.org>
Cc: Andrea Arcangeli <aarcange@redhat.com>
Cc: Bob Liu <bob.liu@oracle.com>
Cc: Christoph Hellwig <hch@infradead.org>
Cc: Dave Chinner <david@fromorbit.com>
Cc: Greg Thelen <gthelen@google.com>
Cc: Hugh Dickins <hughd@google.com>
Cc: Jan Kara <jack@suse.cz>
Cc: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
Cc: Luigi Semenzato <semenzato@google.com>
Cc: Mel Gorman <mgorman@suse.de>
Cc: Metin Doslu <metin@citusdata.com>
Cc: Michel Lespinasse <walken@google.com>
Cc: Ozgun Erdogan <ozgun@citusdata.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Roman Gushchin <klamm@yandex-team.ru>
Cc: Ryan Mallon <rmallon@gmail.com>
Cc: Tejun Heo <tj@kernel.org>
Cc: Vlastimil Babka <vbabka@suse.cz>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2014-04-04 05:47:56 +08:00
|
|
|
radix_tree_replace_slot(slot, page);
|
|
|
|
mapping->nrpages++;
|
|
|
|
if (node) {
|
|
|
|
workingset_node_pages_inc(node);
|
|
|
|
/*
|
|
|
|
* Don't track node that contains actual pages.
|
|
|
|
*
|
|
|
|
* Avoid acquiring the list_lru lock if already
|
|
|
|
* untracked. The list_empty() test is safe as
|
|
|
|
* node->private_list is protected by
|
|
|
|
* mapping->tree_lock.
|
|
|
|
*/
|
|
|
|
if (!list_empty(&node->private_list))
|
|
|
|
list_lru_del(&workingset_shadow_nodes,
|
|
|
|
&node->private_list);
|
|
|
|
}
|
|
|
|
return 0;
|
2014-04-04 05:47:46 +08:00
|
|
|
}
|
|
|
|
|
2014-04-04 05:47:51 +08:00
|
|
|
static int __add_to_page_cache_locked(struct page *page,
|
|
|
|
struct address_space *mapping,
|
|
|
|
pgoff_t offset, gfp_t gfp_mask,
|
|
|
|
void **shadowp)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
mm: memcontrol: rewrite charge API
These patches rework memcg charge lifetime to integrate more naturally
with the lifetime of user pages. This drastically simplifies the code and
reduces charging and uncharging overhead. The most expensive part of
charging and uncharging is the page_cgroup bit spinlock, which is removed
entirely after this series.
Here are the top-10 profile entries of a stress test that reads a 128G
sparse file on a freshly booted box, without even a dedicated cgroup (i.e.
executing in the root memcg). Before:
15.36% cat [kernel.kallsyms] [k] copy_user_generic_string
13.31% cat [kernel.kallsyms] [k] memset
11.48% cat [kernel.kallsyms] [k] do_mpage_readpage
4.23% cat [kernel.kallsyms] [k] get_page_from_freelist
2.38% cat [kernel.kallsyms] [k] put_page
2.32% cat [kernel.kallsyms] [k] __mem_cgroup_commit_charge
2.18% kswapd0 [kernel.kallsyms] [k] __mem_cgroup_uncharge_common
1.92% kswapd0 [kernel.kallsyms] [k] shrink_page_list
1.86% cat [kernel.kallsyms] [k] __radix_tree_lookup
1.62% cat [kernel.kallsyms] [k] __pagevec_lru_add_fn
After:
15.67% cat [kernel.kallsyms] [k] copy_user_generic_string
13.48% cat [kernel.kallsyms] [k] memset
11.42% cat [kernel.kallsyms] [k] do_mpage_readpage
3.98% cat [kernel.kallsyms] [k] get_page_from_freelist
2.46% cat [kernel.kallsyms] [k] put_page
2.13% kswapd0 [kernel.kallsyms] [k] shrink_page_list
1.88% cat [kernel.kallsyms] [k] __radix_tree_lookup
1.67% cat [kernel.kallsyms] [k] __pagevec_lru_add_fn
1.39% kswapd0 [kernel.kallsyms] [k] free_pcppages_bulk
1.30% cat [kernel.kallsyms] [k] kfree
As you can see, the memcg footprint has shrunk quite a bit.
text data bss dec hex filename
37970 9892 400 48262 bc86 mm/memcontrol.o.old
35239 9892 400 45531 b1db mm/memcontrol.o
This patch (of 4):
The memcg charge API charges pages before they are rmapped - i.e. have an
actual "type" - and so every callsite needs its own set of charge and
uncharge functions to know what type is being operated on. Worse,
uncharge has to happen from a context that is still type-specific, rather
than at the end of the page's lifetime with exclusive access, and so
requires a lot of synchronization.
Rewrite the charge API to provide a generic set of try_charge(),
commit_charge() and cancel_charge() transaction operations, much like
what's currently done for swap-in:
mem_cgroup_try_charge() attempts to reserve a charge, reclaiming
pages from the memcg if necessary.
mem_cgroup_commit_charge() commits the page to the charge once it
has a valid page->mapping and PageAnon() reliably tells the type.
mem_cgroup_cancel_charge() aborts the transaction.
This reduces the charge API and enables subsequent patches to
drastically simplify uncharging.
As pages need to be committed after rmap is established but before they
are added to the LRU, page_add_new_anon_rmap() must stop doing LRU
additions again. Revive lru_cache_add_active_or_unevictable().
[hughd@google.com: fix shmem_unuse]
[hughd@google.com: Add comments on the private use of -EAGAIN]
Signed-off-by: Johannes Weiner <hannes@cmpxchg.org>
Acked-by: Michal Hocko <mhocko@suse.cz>
Cc: Tejun Heo <tj@kernel.org>
Cc: Vladimir Davydov <vdavydov@parallels.com>
Signed-off-by: Hugh Dickins <hughd@google.com>
Cc: Naoya Horiguchi <n-horiguchi@ah.jp.nec.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2014-08-09 05:19:20 +08:00
|
|
|
int huge = PageHuge(page);
|
|
|
|
struct mem_cgroup *memcg;
|
2008-07-26 10:45:30 +08:00
|
|
|
int error;
|
|
|
|
|
2014-01-24 07:52:54 +08:00
|
|
|
VM_BUG_ON_PAGE(!PageLocked(page), page);
|
|
|
|
VM_BUG_ON_PAGE(PageSwapBacked(page), page);
|
2008-07-26 10:45:30 +08:00
|
|
|
|
mm: memcontrol: rewrite charge API
These patches rework memcg charge lifetime to integrate more naturally
with the lifetime of user pages. This drastically simplifies the code and
reduces charging and uncharging overhead. The most expensive part of
charging and uncharging is the page_cgroup bit spinlock, which is removed
entirely after this series.
Here are the top-10 profile entries of a stress test that reads a 128G
sparse file on a freshly booted box, without even a dedicated cgroup (i.e.
executing in the root memcg). Before:
15.36% cat [kernel.kallsyms] [k] copy_user_generic_string
13.31% cat [kernel.kallsyms] [k] memset
11.48% cat [kernel.kallsyms] [k] do_mpage_readpage
4.23% cat [kernel.kallsyms] [k] get_page_from_freelist
2.38% cat [kernel.kallsyms] [k] put_page
2.32% cat [kernel.kallsyms] [k] __mem_cgroup_commit_charge
2.18% kswapd0 [kernel.kallsyms] [k] __mem_cgroup_uncharge_common
1.92% kswapd0 [kernel.kallsyms] [k] shrink_page_list
1.86% cat [kernel.kallsyms] [k] __radix_tree_lookup
1.62% cat [kernel.kallsyms] [k] __pagevec_lru_add_fn
After:
15.67% cat [kernel.kallsyms] [k] copy_user_generic_string
13.48% cat [kernel.kallsyms] [k] memset
11.42% cat [kernel.kallsyms] [k] do_mpage_readpage
3.98% cat [kernel.kallsyms] [k] get_page_from_freelist
2.46% cat [kernel.kallsyms] [k] put_page
2.13% kswapd0 [kernel.kallsyms] [k] shrink_page_list
1.88% cat [kernel.kallsyms] [k] __radix_tree_lookup
1.67% cat [kernel.kallsyms] [k] __pagevec_lru_add_fn
1.39% kswapd0 [kernel.kallsyms] [k] free_pcppages_bulk
1.30% cat [kernel.kallsyms] [k] kfree
As you can see, the memcg footprint has shrunk quite a bit.
text data bss dec hex filename
37970 9892 400 48262 bc86 mm/memcontrol.o.old
35239 9892 400 45531 b1db mm/memcontrol.o
This patch (of 4):
The memcg charge API charges pages before they are rmapped - i.e. have an
actual "type" - and so every callsite needs its own set of charge and
uncharge functions to know what type is being operated on. Worse,
uncharge has to happen from a context that is still type-specific, rather
than at the end of the page's lifetime with exclusive access, and so
requires a lot of synchronization.
Rewrite the charge API to provide a generic set of try_charge(),
commit_charge() and cancel_charge() transaction operations, much like
what's currently done for swap-in:
mem_cgroup_try_charge() attempts to reserve a charge, reclaiming
pages from the memcg if necessary.
mem_cgroup_commit_charge() commits the page to the charge once it
has a valid page->mapping and PageAnon() reliably tells the type.
mem_cgroup_cancel_charge() aborts the transaction.
This reduces the charge API and enables subsequent patches to
drastically simplify uncharging.
As pages need to be committed after rmap is established but before they
are added to the LRU, page_add_new_anon_rmap() must stop doing LRU
additions again. Revive lru_cache_add_active_or_unevictable().
[hughd@google.com: fix shmem_unuse]
[hughd@google.com: Add comments on the private use of -EAGAIN]
Signed-off-by: Johannes Weiner <hannes@cmpxchg.org>
Acked-by: Michal Hocko <mhocko@suse.cz>
Cc: Tejun Heo <tj@kernel.org>
Cc: Vladimir Davydov <vdavydov@parallels.com>
Signed-off-by: Hugh Dickins <hughd@google.com>
Cc: Naoya Horiguchi <n-horiguchi@ah.jp.nec.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2014-08-09 05:19:20 +08:00
|
|
|
if (!huge) {
|
|
|
|
error = mem_cgroup_try_charge(page, current->mm,
|
2016-01-16 08:52:20 +08:00
|
|
|
gfp_mask, &memcg, false);
|
mm: memcontrol: rewrite charge API
These patches rework memcg charge lifetime to integrate more naturally
with the lifetime of user pages. This drastically simplifies the code and
reduces charging and uncharging overhead. The most expensive part of
charging and uncharging is the page_cgroup bit spinlock, which is removed
entirely after this series.
Here are the top-10 profile entries of a stress test that reads a 128G
sparse file on a freshly booted box, without even a dedicated cgroup (i.e.
executing in the root memcg). Before:
15.36% cat [kernel.kallsyms] [k] copy_user_generic_string
13.31% cat [kernel.kallsyms] [k] memset
11.48% cat [kernel.kallsyms] [k] do_mpage_readpage
4.23% cat [kernel.kallsyms] [k] get_page_from_freelist
2.38% cat [kernel.kallsyms] [k] put_page
2.32% cat [kernel.kallsyms] [k] __mem_cgroup_commit_charge
2.18% kswapd0 [kernel.kallsyms] [k] __mem_cgroup_uncharge_common
1.92% kswapd0 [kernel.kallsyms] [k] shrink_page_list
1.86% cat [kernel.kallsyms] [k] __radix_tree_lookup
1.62% cat [kernel.kallsyms] [k] __pagevec_lru_add_fn
After:
15.67% cat [kernel.kallsyms] [k] copy_user_generic_string
13.48% cat [kernel.kallsyms] [k] memset
11.42% cat [kernel.kallsyms] [k] do_mpage_readpage
3.98% cat [kernel.kallsyms] [k] get_page_from_freelist
2.46% cat [kernel.kallsyms] [k] put_page
2.13% kswapd0 [kernel.kallsyms] [k] shrink_page_list
1.88% cat [kernel.kallsyms] [k] __radix_tree_lookup
1.67% cat [kernel.kallsyms] [k] __pagevec_lru_add_fn
1.39% kswapd0 [kernel.kallsyms] [k] free_pcppages_bulk
1.30% cat [kernel.kallsyms] [k] kfree
As you can see, the memcg footprint has shrunk quite a bit.
text data bss dec hex filename
37970 9892 400 48262 bc86 mm/memcontrol.o.old
35239 9892 400 45531 b1db mm/memcontrol.o
This patch (of 4):
The memcg charge API charges pages before they are rmapped - i.e. have an
actual "type" - and so every callsite needs its own set of charge and
uncharge functions to know what type is being operated on. Worse,
uncharge has to happen from a context that is still type-specific, rather
than at the end of the page's lifetime with exclusive access, and so
requires a lot of synchronization.
Rewrite the charge API to provide a generic set of try_charge(),
commit_charge() and cancel_charge() transaction operations, much like
what's currently done for swap-in:
mem_cgroup_try_charge() attempts to reserve a charge, reclaiming
pages from the memcg if necessary.
mem_cgroup_commit_charge() commits the page to the charge once it
has a valid page->mapping and PageAnon() reliably tells the type.
mem_cgroup_cancel_charge() aborts the transaction.
This reduces the charge API and enables subsequent patches to
drastically simplify uncharging.
As pages need to be committed after rmap is established but before they
are added to the LRU, page_add_new_anon_rmap() must stop doing LRU
additions again. Revive lru_cache_add_active_or_unevictable().
[hughd@google.com: fix shmem_unuse]
[hughd@google.com: Add comments on the private use of -EAGAIN]
Signed-off-by: Johannes Weiner <hannes@cmpxchg.org>
Acked-by: Michal Hocko <mhocko@suse.cz>
Cc: Tejun Heo <tj@kernel.org>
Cc: Vladimir Davydov <vdavydov@parallels.com>
Signed-off-by: Hugh Dickins <hughd@google.com>
Cc: Naoya Horiguchi <n-horiguchi@ah.jp.nec.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2014-08-09 05:19:20 +08:00
|
|
|
if (error)
|
|
|
|
return error;
|
|
|
|
}
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2013-09-12 05:26:05 +08:00
|
|
|
error = radix_tree_maybe_preload(gfp_mask & ~__GFP_HIGHMEM);
|
2013-09-13 06:13:59 +08:00
|
|
|
if (error) {
|
mm: memcontrol: rewrite charge API
These patches rework memcg charge lifetime to integrate more naturally
with the lifetime of user pages. This drastically simplifies the code and
reduces charging and uncharging overhead. The most expensive part of
charging and uncharging is the page_cgroup bit spinlock, which is removed
entirely after this series.
Here are the top-10 profile entries of a stress test that reads a 128G
sparse file on a freshly booted box, without even a dedicated cgroup (i.e.
executing in the root memcg). Before:
15.36% cat [kernel.kallsyms] [k] copy_user_generic_string
13.31% cat [kernel.kallsyms] [k] memset
11.48% cat [kernel.kallsyms] [k] do_mpage_readpage
4.23% cat [kernel.kallsyms] [k] get_page_from_freelist
2.38% cat [kernel.kallsyms] [k] put_page
2.32% cat [kernel.kallsyms] [k] __mem_cgroup_commit_charge
2.18% kswapd0 [kernel.kallsyms] [k] __mem_cgroup_uncharge_common
1.92% kswapd0 [kernel.kallsyms] [k] shrink_page_list
1.86% cat [kernel.kallsyms] [k] __radix_tree_lookup
1.62% cat [kernel.kallsyms] [k] __pagevec_lru_add_fn
After:
15.67% cat [kernel.kallsyms] [k] copy_user_generic_string
13.48% cat [kernel.kallsyms] [k] memset
11.42% cat [kernel.kallsyms] [k] do_mpage_readpage
3.98% cat [kernel.kallsyms] [k] get_page_from_freelist
2.46% cat [kernel.kallsyms] [k] put_page
2.13% kswapd0 [kernel.kallsyms] [k] shrink_page_list
1.88% cat [kernel.kallsyms] [k] __radix_tree_lookup
1.67% cat [kernel.kallsyms] [k] __pagevec_lru_add_fn
1.39% kswapd0 [kernel.kallsyms] [k] free_pcppages_bulk
1.30% cat [kernel.kallsyms] [k] kfree
As you can see, the memcg footprint has shrunk quite a bit.
text data bss dec hex filename
37970 9892 400 48262 bc86 mm/memcontrol.o.old
35239 9892 400 45531 b1db mm/memcontrol.o
This patch (of 4):
The memcg charge API charges pages before they are rmapped - i.e. have an
actual "type" - and so every callsite needs its own set of charge and
uncharge functions to know what type is being operated on. Worse,
uncharge has to happen from a context that is still type-specific, rather
than at the end of the page's lifetime with exclusive access, and so
requires a lot of synchronization.
Rewrite the charge API to provide a generic set of try_charge(),
commit_charge() and cancel_charge() transaction operations, much like
what's currently done for swap-in:
mem_cgroup_try_charge() attempts to reserve a charge, reclaiming
pages from the memcg if necessary.
mem_cgroup_commit_charge() commits the page to the charge once it
has a valid page->mapping and PageAnon() reliably tells the type.
mem_cgroup_cancel_charge() aborts the transaction.
This reduces the charge API and enables subsequent patches to
drastically simplify uncharging.
As pages need to be committed after rmap is established but before they
are added to the LRU, page_add_new_anon_rmap() must stop doing LRU
additions again. Revive lru_cache_add_active_or_unevictable().
[hughd@google.com: fix shmem_unuse]
[hughd@google.com: Add comments on the private use of -EAGAIN]
Signed-off-by: Johannes Weiner <hannes@cmpxchg.org>
Acked-by: Michal Hocko <mhocko@suse.cz>
Cc: Tejun Heo <tj@kernel.org>
Cc: Vladimir Davydov <vdavydov@parallels.com>
Signed-off-by: Hugh Dickins <hughd@google.com>
Cc: Naoya Horiguchi <n-horiguchi@ah.jp.nec.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2014-08-09 05:19:20 +08:00
|
|
|
if (!huge)
|
2016-01-16 08:52:20 +08:00
|
|
|
mem_cgroup_cancel_charge(page, memcg, false);
|
2013-09-13 06:13:59 +08:00
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
|
|
|
page_cache_get(page);
|
|
|
|
page->mapping = mapping;
|
|
|
|
page->index = offset;
|
|
|
|
|
|
|
|
spin_lock_irq(&mapping->tree_lock);
|
2014-04-04 05:47:51 +08:00
|
|
|
error = page_cache_tree_insert(mapping, page, shadowp);
|
2013-09-13 06:13:59 +08:00
|
|
|
radix_tree_preload_end();
|
|
|
|
if (unlikely(error))
|
|
|
|
goto err_insert;
|
2015-06-25 07:57:24 +08:00
|
|
|
|
|
|
|
/* hugetlb pages do not participate in page cache accounting. */
|
|
|
|
if (!huge)
|
|
|
|
__inc_zone_page_state(page, NR_FILE_PAGES);
|
2013-09-13 06:13:59 +08:00
|
|
|
spin_unlock_irq(&mapping->tree_lock);
|
mm: memcontrol: rewrite charge API
These patches rework memcg charge lifetime to integrate more naturally
with the lifetime of user pages. This drastically simplifies the code and
reduces charging and uncharging overhead. The most expensive part of
charging and uncharging is the page_cgroup bit spinlock, which is removed
entirely after this series.
Here are the top-10 profile entries of a stress test that reads a 128G
sparse file on a freshly booted box, without even a dedicated cgroup (i.e.
executing in the root memcg). Before:
15.36% cat [kernel.kallsyms] [k] copy_user_generic_string
13.31% cat [kernel.kallsyms] [k] memset
11.48% cat [kernel.kallsyms] [k] do_mpage_readpage
4.23% cat [kernel.kallsyms] [k] get_page_from_freelist
2.38% cat [kernel.kallsyms] [k] put_page
2.32% cat [kernel.kallsyms] [k] __mem_cgroup_commit_charge
2.18% kswapd0 [kernel.kallsyms] [k] __mem_cgroup_uncharge_common
1.92% kswapd0 [kernel.kallsyms] [k] shrink_page_list
1.86% cat [kernel.kallsyms] [k] __radix_tree_lookup
1.62% cat [kernel.kallsyms] [k] __pagevec_lru_add_fn
After:
15.67% cat [kernel.kallsyms] [k] copy_user_generic_string
13.48% cat [kernel.kallsyms] [k] memset
11.42% cat [kernel.kallsyms] [k] do_mpage_readpage
3.98% cat [kernel.kallsyms] [k] get_page_from_freelist
2.46% cat [kernel.kallsyms] [k] put_page
2.13% kswapd0 [kernel.kallsyms] [k] shrink_page_list
1.88% cat [kernel.kallsyms] [k] __radix_tree_lookup
1.67% cat [kernel.kallsyms] [k] __pagevec_lru_add_fn
1.39% kswapd0 [kernel.kallsyms] [k] free_pcppages_bulk
1.30% cat [kernel.kallsyms] [k] kfree
As you can see, the memcg footprint has shrunk quite a bit.
text data bss dec hex filename
37970 9892 400 48262 bc86 mm/memcontrol.o.old
35239 9892 400 45531 b1db mm/memcontrol.o
This patch (of 4):
The memcg charge API charges pages before they are rmapped - i.e. have an
actual "type" - and so every callsite needs its own set of charge and
uncharge functions to know what type is being operated on. Worse,
uncharge has to happen from a context that is still type-specific, rather
than at the end of the page's lifetime with exclusive access, and so
requires a lot of synchronization.
Rewrite the charge API to provide a generic set of try_charge(),
commit_charge() and cancel_charge() transaction operations, much like
what's currently done for swap-in:
mem_cgroup_try_charge() attempts to reserve a charge, reclaiming
pages from the memcg if necessary.
mem_cgroup_commit_charge() commits the page to the charge once it
has a valid page->mapping and PageAnon() reliably tells the type.
mem_cgroup_cancel_charge() aborts the transaction.
This reduces the charge API and enables subsequent patches to
drastically simplify uncharging.
As pages need to be committed after rmap is established but before they
are added to the LRU, page_add_new_anon_rmap() must stop doing LRU
additions again. Revive lru_cache_add_active_or_unevictable().
[hughd@google.com: fix shmem_unuse]
[hughd@google.com: Add comments on the private use of -EAGAIN]
Signed-off-by: Johannes Weiner <hannes@cmpxchg.org>
Acked-by: Michal Hocko <mhocko@suse.cz>
Cc: Tejun Heo <tj@kernel.org>
Cc: Vladimir Davydov <vdavydov@parallels.com>
Signed-off-by: Hugh Dickins <hughd@google.com>
Cc: Naoya Horiguchi <n-horiguchi@ah.jp.nec.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2014-08-09 05:19:20 +08:00
|
|
|
if (!huge)
|
2016-01-16 08:52:20 +08:00
|
|
|
mem_cgroup_commit_charge(page, memcg, false, false);
|
2013-09-13 06:13:59 +08:00
|
|
|
trace_mm_filemap_add_to_page_cache(page);
|
|
|
|
return 0;
|
|
|
|
err_insert:
|
|
|
|
page->mapping = NULL;
|
|
|
|
/* Leave page->index set: truncation relies upon it */
|
|
|
|
spin_unlock_irq(&mapping->tree_lock);
|
mm: memcontrol: rewrite charge API
These patches rework memcg charge lifetime to integrate more naturally
with the lifetime of user pages. This drastically simplifies the code and
reduces charging and uncharging overhead. The most expensive part of
charging and uncharging is the page_cgroup bit spinlock, which is removed
entirely after this series.
Here are the top-10 profile entries of a stress test that reads a 128G
sparse file on a freshly booted box, without even a dedicated cgroup (i.e.
executing in the root memcg). Before:
15.36% cat [kernel.kallsyms] [k] copy_user_generic_string
13.31% cat [kernel.kallsyms] [k] memset
11.48% cat [kernel.kallsyms] [k] do_mpage_readpage
4.23% cat [kernel.kallsyms] [k] get_page_from_freelist
2.38% cat [kernel.kallsyms] [k] put_page
2.32% cat [kernel.kallsyms] [k] __mem_cgroup_commit_charge
2.18% kswapd0 [kernel.kallsyms] [k] __mem_cgroup_uncharge_common
1.92% kswapd0 [kernel.kallsyms] [k] shrink_page_list
1.86% cat [kernel.kallsyms] [k] __radix_tree_lookup
1.62% cat [kernel.kallsyms] [k] __pagevec_lru_add_fn
After:
15.67% cat [kernel.kallsyms] [k] copy_user_generic_string
13.48% cat [kernel.kallsyms] [k] memset
11.42% cat [kernel.kallsyms] [k] do_mpage_readpage
3.98% cat [kernel.kallsyms] [k] get_page_from_freelist
2.46% cat [kernel.kallsyms] [k] put_page
2.13% kswapd0 [kernel.kallsyms] [k] shrink_page_list
1.88% cat [kernel.kallsyms] [k] __radix_tree_lookup
1.67% cat [kernel.kallsyms] [k] __pagevec_lru_add_fn
1.39% kswapd0 [kernel.kallsyms] [k] free_pcppages_bulk
1.30% cat [kernel.kallsyms] [k] kfree
As you can see, the memcg footprint has shrunk quite a bit.
text data bss dec hex filename
37970 9892 400 48262 bc86 mm/memcontrol.o.old
35239 9892 400 45531 b1db mm/memcontrol.o
This patch (of 4):
The memcg charge API charges pages before they are rmapped - i.e. have an
actual "type" - and so every callsite needs its own set of charge and
uncharge functions to know what type is being operated on. Worse,
uncharge has to happen from a context that is still type-specific, rather
than at the end of the page's lifetime with exclusive access, and so
requires a lot of synchronization.
Rewrite the charge API to provide a generic set of try_charge(),
commit_charge() and cancel_charge() transaction operations, much like
what's currently done for swap-in:
mem_cgroup_try_charge() attempts to reserve a charge, reclaiming
pages from the memcg if necessary.
mem_cgroup_commit_charge() commits the page to the charge once it
has a valid page->mapping and PageAnon() reliably tells the type.
mem_cgroup_cancel_charge() aborts the transaction.
This reduces the charge API and enables subsequent patches to
drastically simplify uncharging.
As pages need to be committed after rmap is established but before they
are added to the LRU, page_add_new_anon_rmap() must stop doing LRU
additions again. Revive lru_cache_add_active_or_unevictable().
[hughd@google.com: fix shmem_unuse]
[hughd@google.com: Add comments on the private use of -EAGAIN]
Signed-off-by: Johannes Weiner <hannes@cmpxchg.org>
Acked-by: Michal Hocko <mhocko@suse.cz>
Cc: Tejun Heo <tj@kernel.org>
Cc: Vladimir Davydov <vdavydov@parallels.com>
Signed-off-by: Hugh Dickins <hughd@google.com>
Cc: Naoya Horiguchi <n-horiguchi@ah.jp.nec.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2014-08-09 05:19:20 +08:00
|
|
|
if (!huge)
|
2016-01-16 08:52:20 +08:00
|
|
|
mem_cgroup_cancel_charge(page, memcg, false);
|
2013-09-13 06:13:59 +08:00
|
|
|
page_cache_release(page);
|
2005-04-17 06:20:36 +08:00
|
|
|
return error;
|
|
|
|
}
|
2014-04-04 05:47:51 +08:00
|
|
|
|
|
|
|
/**
|
|
|
|
* add_to_page_cache_locked - add a locked page to the pagecache
|
|
|
|
* @page: page to add
|
|
|
|
* @mapping: the page's address_space
|
|
|
|
* @offset: page index
|
|
|
|
* @gfp_mask: page allocation mode
|
|
|
|
*
|
|
|
|
* This function is used to add a page to the pagecache. It must be locked.
|
|
|
|
* This function does not add the page to the LRU. The caller must do that.
|
|
|
|
*/
|
|
|
|
int add_to_page_cache_locked(struct page *page, struct address_space *mapping,
|
|
|
|
pgoff_t offset, gfp_t gfp_mask)
|
|
|
|
{
|
|
|
|
return __add_to_page_cache_locked(page, mapping, offset,
|
|
|
|
gfp_mask, NULL);
|
|
|
|
}
|
2008-07-26 10:45:30 +08:00
|
|
|
EXPORT_SYMBOL(add_to_page_cache_locked);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
int add_to_page_cache_lru(struct page *page, struct address_space *mapping,
|
2005-10-21 15:18:50 +08:00
|
|
|
pgoff_t offset, gfp_t gfp_mask)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2014-04-04 05:47:51 +08:00
|
|
|
void *shadow = NULL;
|
2008-10-19 11:26:32 +08:00
|
|
|
int ret;
|
|
|
|
|
2016-01-16 08:51:24 +08:00
|
|
|
__SetPageLocked(page);
|
2014-04-04 05:47:51 +08:00
|
|
|
ret = __add_to_page_cache_locked(page, mapping, offset,
|
|
|
|
gfp_mask, &shadow);
|
|
|
|
if (unlikely(ret))
|
2016-01-16 08:51:24 +08:00
|
|
|
__ClearPageLocked(page);
|
2014-04-04 05:47:51 +08:00
|
|
|
else {
|
|
|
|
/*
|
|
|
|
* The page might have been evicted from cache only
|
|
|
|
* recently, in which case it should be activated like
|
|
|
|
* any other repeatedly accessed page.
|
|
|
|
*/
|
|
|
|
if (shadow && workingset_refault(shadow)) {
|
|
|
|
SetPageActive(page);
|
|
|
|
workingset_activation(page);
|
|
|
|
} else
|
|
|
|
ClearPageActive(page);
|
|
|
|
lru_cache_add(page);
|
|
|
|
}
|
2005-04-17 06:20:36 +08:00
|
|
|
return ret;
|
|
|
|
}
|
2009-02-09 22:02:42 +08:00
|
|
|
EXPORT_SYMBOL_GPL(add_to_page_cache_lru);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2006-03-24 19:16:04 +08:00
|
|
|
#ifdef CONFIG_NUMA
|
2006-10-29 01:38:23 +08:00
|
|
|
struct page *__page_cache_alloc(gfp_t gfp)
|
2006-03-24 19:16:04 +08:00
|
|
|
{
|
2010-05-25 05:32:08 +08:00
|
|
|
int n;
|
|
|
|
struct page *page;
|
|
|
|
|
2006-03-24 19:16:04 +08:00
|
|
|
if (cpuset_do_page_mem_spread()) {
|
cpuset: mm: reduce large amounts of memory barrier related damage v3
Commit c0ff7453bb5c ("cpuset,mm: fix no node to alloc memory when
changing cpuset's mems") wins a super prize for the largest number of
memory barriers entered into fast paths for one commit.
[get|put]_mems_allowed is incredibly heavy with pairs of full memory
barriers inserted into a number of hot paths. This was detected while
investigating at large page allocator slowdown introduced some time
after 2.6.32. The largest portion of this overhead was shown by
oprofile to be at an mfence introduced by this commit into the page
allocator hot path.
For extra style points, the commit introduced the use of yield() in an
implementation of what looks like a spinning mutex.
This patch replaces the full memory barriers on both read and write
sides with a sequence counter with just read barriers on the fast path
side. This is much cheaper on some architectures, including x86. The
main bulk of the patch is the retry logic if the nodemask changes in a
manner that can cause a false failure.
While updating the nodemask, a check is made to see if a false failure
is a risk. If it is, the sequence number gets bumped and parallel
allocators will briefly stall while the nodemask update takes place.
In a page fault test microbenchmark, oprofile samples from
__alloc_pages_nodemask went from 4.53% of all samples to 1.15%. The
actual results were
3.3.0-rc3 3.3.0-rc3
rc3-vanilla nobarrier-v2r1
Clients 1 UserTime 0.07 ( 0.00%) 0.08 (-14.19%)
Clients 2 UserTime 0.07 ( 0.00%) 0.07 ( 2.72%)
Clients 4 UserTime 0.08 ( 0.00%) 0.07 ( 3.29%)
Clients 1 SysTime 0.70 ( 0.00%) 0.65 ( 6.65%)
Clients 2 SysTime 0.85 ( 0.00%) 0.82 ( 3.65%)
Clients 4 SysTime 1.41 ( 0.00%) 1.41 ( 0.32%)
Clients 1 WallTime 0.77 ( 0.00%) 0.74 ( 4.19%)
Clients 2 WallTime 0.47 ( 0.00%) 0.45 ( 3.73%)
Clients 4 WallTime 0.38 ( 0.00%) 0.37 ( 1.58%)
Clients 1 Flt/sec/cpu 497620.28 ( 0.00%) 520294.53 ( 4.56%)
Clients 2 Flt/sec/cpu 414639.05 ( 0.00%) 429882.01 ( 3.68%)
Clients 4 Flt/sec/cpu 257959.16 ( 0.00%) 258761.48 ( 0.31%)
Clients 1 Flt/sec 495161.39 ( 0.00%) 517292.87 ( 4.47%)
Clients 2 Flt/sec 820325.95 ( 0.00%) 850289.77 ( 3.65%)
Clients 4 Flt/sec 1020068.93 ( 0.00%) 1022674.06 ( 0.26%)
MMTests Statistics: duration
Sys Time Running Test (seconds) 135.68 132.17
User+Sys Time Running Test (seconds) 164.2 160.13
Total Elapsed Time (seconds) 123.46 120.87
The overall improvement is small but the System CPU time is much
improved and roughly in correlation to what oprofile reported (these
performance figures are without profiling so skew is expected). The
actual number of page faults is noticeably improved.
For benchmarks like kernel builds, the overall benefit is marginal but
the system CPU time is slightly reduced.
To test the actual bug the commit fixed I opened two terminals. The
first ran within a cpuset and continually ran a small program that
faulted 100M of anonymous data. In a second window, the nodemask of the
cpuset was continually randomised in a loop.
Without the commit, the program would fail every so often (usually
within 10 seconds) and obviously with the commit everything worked fine.
With this patch applied, it also worked fine so the fix should be
functionally equivalent.
Signed-off-by: Mel Gorman <mgorman@suse.de>
Cc: Miao Xie <miaox@cn.fujitsu.com>
Cc: David Rientjes <rientjes@google.com>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Christoph Lameter <cl@linux.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2012-03-22 07:34:11 +08:00
|
|
|
unsigned int cpuset_mems_cookie;
|
|
|
|
do {
|
2014-04-04 05:47:24 +08:00
|
|
|
cpuset_mems_cookie = read_mems_allowed_begin();
|
cpuset: mm: reduce large amounts of memory barrier related damage v3
Commit c0ff7453bb5c ("cpuset,mm: fix no node to alloc memory when
changing cpuset's mems") wins a super prize for the largest number of
memory barriers entered into fast paths for one commit.
[get|put]_mems_allowed is incredibly heavy with pairs of full memory
barriers inserted into a number of hot paths. This was detected while
investigating at large page allocator slowdown introduced some time
after 2.6.32. The largest portion of this overhead was shown by
oprofile to be at an mfence introduced by this commit into the page
allocator hot path.
For extra style points, the commit introduced the use of yield() in an
implementation of what looks like a spinning mutex.
This patch replaces the full memory barriers on both read and write
sides with a sequence counter with just read barriers on the fast path
side. This is much cheaper on some architectures, including x86. The
main bulk of the patch is the retry logic if the nodemask changes in a
manner that can cause a false failure.
While updating the nodemask, a check is made to see if a false failure
is a risk. If it is, the sequence number gets bumped and parallel
allocators will briefly stall while the nodemask update takes place.
In a page fault test microbenchmark, oprofile samples from
__alloc_pages_nodemask went from 4.53% of all samples to 1.15%. The
actual results were
3.3.0-rc3 3.3.0-rc3
rc3-vanilla nobarrier-v2r1
Clients 1 UserTime 0.07 ( 0.00%) 0.08 (-14.19%)
Clients 2 UserTime 0.07 ( 0.00%) 0.07 ( 2.72%)
Clients 4 UserTime 0.08 ( 0.00%) 0.07 ( 3.29%)
Clients 1 SysTime 0.70 ( 0.00%) 0.65 ( 6.65%)
Clients 2 SysTime 0.85 ( 0.00%) 0.82 ( 3.65%)
Clients 4 SysTime 1.41 ( 0.00%) 1.41 ( 0.32%)
Clients 1 WallTime 0.77 ( 0.00%) 0.74 ( 4.19%)
Clients 2 WallTime 0.47 ( 0.00%) 0.45 ( 3.73%)
Clients 4 WallTime 0.38 ( 0.00%) 0.37 ( 1.58%)
Clients 1 Flt/sec/cpu 497620.28 ( 0.00%) 520294.53 ( 4.56%)
Clients 2 Flt/sec/cpu 414639.05 ( 0.00%) 429882.01 ( 3.68%)
Clients 4 Flt/sec/cpu 257959.16 ( 0.00%) 258761.48 ( 0.31%)
Clients 1 Flt/sec 495161.39 ( 0.00%) 517292.87 ( 4.47%)
Clients 2 Flt/sec 820325.95 ( 0.00%) 850289.77 ( 3.65%)
Clients 4 Flt/sec 1020068.93 ( 0.00%) 1022674.06 ( 0.26%)
MMTests Statistics: duration
Sys Time Running Test (seconds) 135.68 132.17
User+Sys Time Running Test (seconds) 164.2 160.13
Total Elapsed Time (seconds) 123.46 120.87
The overall improvement is small but the System CPU time is much
improved and roughly in correlation to what oprofile reported (these
performance figures are without profiling so skew is expected). The
actual number of page faults is noticeably improved.
For benchmarks like kernel builds, the overall benefit is marginal but
the system CPU time is slightly reduced.
To test the actual bug the commit fixed I opened two terminals. The
first ran within a cpuset and continually ran a small program that
faulted 100M of anonymous data. In a second window, the nodemask of the
cpuset was continually randomised in a loop.
Without the commit, the program would fail every so often (usually
within 10 seconds) and obviously with the commit everything worked fine.
With this patch applied, it also worked fine so the fix should be
functionally equivalent.
Signed-off-by: Mel Gorman <mgorman@suse.de>
Cc: Miao Xie <miaox@cn.fujitsu.com>
Cc: David Rientjes <rientjes@google.com>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Christoph Lameter <cl@linux.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2012-03-22 07:34:11 +08:00
|
|
|
n = cpuset_mem_spread_node();
|
mm: rename alloc_pages_exact_node() to __alloc_pages_node()
alloc_pages_exact_node() was introduced in commit 6484eb3e2a81 ("page
allocator: do not check NUMA node ID when the caller knows the node is
valid") as an optimized variant of alloc_pages_node(), that doesn't
fallback to current node for nid == NUMA_NO_NODE. Unfortunately the
name of the function can easily suggest that the allocation is
restricted to the given node and fails otherwise. In truth, the node is
only preferred, unless __GFP_THISNODE is passed among the gfp flags.
The misleading name has lead to mistakes in the past, see for example
commits 5265047ac301 ("mm, thp: really limit transparent hugepage
allocation to local node") and b360edb43f8e ("mm, mempolicy:
migrate_to_node should only migrate to node").
Another issue with the name is that there's a family of
alloc_pages_exact*() functions where 'exact' means exact size (instead
of page order), which leads to more confusion.
To prevent further mistakes, this patch effectively renames
alloc_pages_exact_node() to __alloc_pages_node() to better convey that
it's an optimized variant of alloc_pages_node() not intended for general
usage. Both functions get described in comments.
It has been also considered to really provide a convenience function for
allocations restricted to a node, but the major opinion seems to be that
__GFP_THISNODE already provides that functionality and we shouldn't
duplicate the API needlessly. The number of users would be small
anyway.
Existing callers of alloc_pages_exact_node() are simply converted to
call __alloc_pages_node(), with the exception of sba_alloc_coherent()
which open-codes the check for NUMA_NO_NODE, so it is converted to use
alloc_pages_node() instead. This means it no longer performs some
VM_BUG_ON checks, and since the current check for nid in
alloc_pages_node() uses a 'nid < 0' comparison (which includes
NUMA_NO_NODE), it may hide wrong values which would be previously
exposed.
Both differences will be rectified by the next patch.
To sum up, this patch makes no functional changes, except temporarily
hiding potentially buggy callers. Restricting the checks in
alloc_pages_node() is left for the next patch which can in turn expose
more existing buggy callers.
Signed-off-by: Vlastimil Babka <vbabka@suse.cz>
Acked-by: Johannes Weiner <hannes@cmpxchg.org>
Acked-by: Robin Holt <robinmholt@gmail.com>
Acked-by: Michal Hocko <mhocko@suse.com>
Acked-by: Christoph Lameter <cl@linux.com>
Acked-by: Michael Ellerman <mpe@ellerman.id.au>
Cc: Mel Gorman <mgorman@suse.de>
Cc: David Rientjes <rientjes@google.com>
Cc: Greg Thelen <gthelen@google.com>
Cc: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
Cc: Pekka Enberg <penberg@kernel.org>
Cc: Joonsoo Kim <iamjoonsoo.kim@lge.com>
Cc: Naoya Horiguchi <n-horiguchi@ah.jp.nec.com>
Cc: Tony Luck <tony.luck@intel.com>
Cc: Fenghua Yu <fenghua.yu@intel.com>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Gleb Natapov <gleb@kernel.org>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: "H. Peter Anvin" <hpa@zytor.com>
Cc: Cliff Whickman <cpw@sgi.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2015-09-09 06:03:50 +08:00
|
|
|
page = __alloc_pages_node(n, gfp, 0);
|
2014-04-04 05:47:24 +08:00
|
|
|
} while (!page && read_mems_allowed_retry(cpuset_mems_cookie));
|
cpuset: mm: reduce large amounts of memory barrier related damage v3
Commit c0ff7453bb5c ("cpuset,mm: fix no node to alloc memory when
changing cpuset's mems") wins a super prize for the largest number of
memory barriers entered into fast paths for one commit.
[get|put]_mems_allowed is incredibly heavy with pairs of full memory
barriers inserted into a number of hot paths. This was detected while
investigating at large page allocator slowdown introduced some time
after 2.6.32. The largest portion of this overhead was shown by
oprofile to be at an mfence introduced by this commit into the page
allocator hot path.
For extra style points, the commit introduced the use of yield() in an
implementation of what looks like a spinning mutex.
This patch replaces the full memory barriers on both read and write
sides with a sequence counter with just read barriers on the fast path
side. This is much cheaper on some architectures, including x86. The
main bulk of the patch is the retry logic if the nodemask changes in a
manner that can cause a false failure.
While updating the nodemask, a check is made to see if a false failure
is a risk. If it is, the sequence number gets bumped and parallel
allocators will briefly stall while the nodemask update takes place.
In a page fault test microbenchmark, oprofile samples from
__alloc_pages_nodemask went from 4.53% of all samples to 1.15%. The
actual results were
3.3.0-rc3 3.3.0-rc3
rc3-vanilla nobarrier-v2r1
Clients 1 UserTime 0.07 ( 0.00%) 0.08 (-14.19%)
Clients 2 UserTime 0.07 ( 0.00%) 0.07 ( 2.72%)
Clients 4 UserTime 0.08 ( 0.00%) 0.07 ( 3.29%)
Clients 1 SysTime 0.70 ( 0.00%) 0.65 ( 6.65%)
Clients 2 SysTime 0.85 ( 0.00%) 0.82 ( 3.65%)
Clients 4 SysTime 1.41 ( 0.00%) 1.41 ( 0.32%)
Clients 1 WallTime 0.77 ( 0.00%) 0.74 ( 4.19%)
Clients 2 WallTime 0.47 ( 0.00%) 0.45 ( 3.73%)
Clients 4 WallTime 0.38 ( 0.00%) 0.37 ( 1.58%)
Clients 1 Flt/sec/cpu 497620.28 ( 0.00%) 520294.53 ( 4.56%)
Clients 2 Flt/sec/cpu 414639.05 ( 0.00%) 429882.01 ( 3.68%)
Clients 4 Flt/sec/cpu 257959.16 ( 0.00%) 258761.48 ( 0.31%)
Clients 1 Flt/sec 495161.39 ( 0.00%) 517292.87 ( 4.47%)
Clients 2 Flt/sec 820325.95 ( 0.00%) 850289.77 ( 3.65%)
Clients 4 Flt/sec 1020068.93 ( 0.00%) 1022674.06 ( 0.26%)
MMTests Statistics: duration
Sys Time Running Test (seconds) 135.68 132.17
User+Sys Time Running Test (seconds) 164.2 160.13
Total Elapsed Time (seconds) 123.46 120.87
The overall improvement is small but the System CPU time is much
improved and roughly in correlation to what oprofile reported (these
performance figures are without profiling so skew is expected). The
actual number of page faults is noticeably improved.
For benchmarks like kernel builds, the overall benefit is marginal but
the system CPU time is slightly reduced.
To test the actual bug the commit fixed I opened two terminals. The
first ran within a cpuset and continually ran a small program that
faulted 100M of anonymous data. In a second window, the nodemask of the
cpuset was continually randomised in a loop.
Without the commit, the program would fail every so often (usually
within 10 seconds) and obviously with the commit everything worked fine.
With this patch applied, it also worked fine so the fix should be
functionally equivalent.
Signed-off-by: Mel Gorman <mgorman@suse.de>
Cc: Miao Xie <miaox@cn.fujitsu.com>
Cc: David Rientjes <rientjes@google.com>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Christoph Lameter <cl@linux.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2012-03-22 07:34:11 +08:00
|
|
|
|
2010-05-25 05:32:08 +08:00
|
|
|
return page;
|
2006-03-24 19:16:04 +08:00
|
|
|
}
|
2006-10-29 01:38:23 +08:00
|
|
|
return alloc_pages(gfp, 0);
|
2006-03-24 19:16:04 +08:00
|
|
|
}
|
2006-10-29 01:38:23 +08:00
|
|
|
EXPORT_SYMBOL(__page_cache_alloc);
|
2006-03-24 19:16:04 +08:00
|
|
|
#endif
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
/*
|
|
|
|
* In order to wait for pages to become available there must be
|
|
|
|
* waitqueues associated with pages. By using a hash table of
|
|
|
|
* waitqueues where the bucket discipline is to maintain all
|
|
|
|
* waiters on the same queue and wake all when any of the pages
|
|
|
|
* become available, and for the woken contexts to check to be
|
|
|
|
* sure the appropriate page became available, this saves space
|
|
|
|
* at a cost of "thundering herd" phenomena during rare hash
|
|
|
|
* collisions.
|
|
|
|
*/
|
2014-09-24 09:28:32 +08:00
|
|
|
wait_queue_head_t *page_waitqueue(struct page *page)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
|
|
|
const struct zone *zone = page_zone(page);
|
|
|
|
|
|
|
|
return &zone->wait_table[hash_ptr(page, zone->wait_table_bits)];
|
|
|
|
}
|
2014-09-24 09:28:32 +08:00
|
|
|
EXPORT_SYMBOL(page_waitqueue);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2008-02-05 14:29:26 +08:00
|
|
|
void wait_on_page_bit(struct page *page, int bit_nr)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
|
|
|
DEFINE_WAIT_BIT(wait, &page->flags, bit_nr);
|
|
|
|
|
|
|
|
if (test_bit(bit_nr, &page->flags))
|
sched: Remove proliferation of wait_on_bit() action functions
The current "wait_on_bit" interface requires an 'action'
function to be provided which does the actual waiting.
There are over 20 such functions, many of them identical.
Most cases can be satisfied by one of just two functions, one
which uses io_schedule() and one which just uses schedule().
So:
Rename wait_on_bit and wait_on_bit_lock to
wait_on_bit_action and wait_on_bit_lock_action
to make it explicit that they need an action function.
Introduce new wait_on_bit{,_lock} and wait_on_bit{,_lock}_io
which are *not* given an action function but implicitly use
a standard one.
The decision to error-out if a signal is pending is now made
based on the 'mode' argument rather than being encoded in the action
function.
All instances of the old wait_on_bit and wait_on_bit_lock which
can use the new version have been changed accordingly and their
action functions have been discarded.
wait_on_bit{_lock} does not return any specific error code in the
event of a signal so the caller must check for non-zero and
interpolate their own error code as appropriate.
The wait_on_bit() call in __fscache_wait_on_invalidate() was
ambiguous as it specified TASK_UNINTERRUPTIBLE but used
fscache_wait_bit_interruptible as an action function.
David Howells confirms this should be uniformly
"uninterruptible"
The main remaining user of wait_on_bit{,_lock}_action is NFS
which needs to use a freezer-aware schedule() call.
A comment in fs/gfs2/glock.c notes that having multiple 'action'
functions is useful as they display differently in the 'wchan'
field of 'ps'. (and /proc/$PID/wchan).
As the new bit_wait{,_io} functions are tagged "__sched", they
will not show up at all, but something higher in the stack. So
the distinction will still be visible, only with different
function names (gds2_glock_wait versus gfs2_glock_dq_wait in the
gfs2/glock.c case).
Since first version of this patch (against 3.15) two new action
functions appeared, on in NFS and one in CIFS. CIFS also now
uses an action function that makes the same freezer aware
schedule call as NFS.
Signed-off-by: NeilBrown <neilb@suse.de>
Acked-by: David Howells <dhowells@redhat.com> (fscache, keys)
Acked-by: Steven Whitehouse <swhiteho@redhat.com> (gfs2)
Acked-by: Peter Zijlstra <peterz@infradead.org>
Cc: Oleg Nesterov <oleg@redhat.com>
Cc: Steve French <sfrench@samba.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Link: http://lkml.kernel.org/r/20140707051603.28027.72349.stgit@notabene.brown
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2014-07-07 13:16:04 +08:00
|
|
|
__wait_on_bit(page_waitqueue(page), &wait, bit_wait_io,
|
2005-04-17 06:20:36 +08:00
|
|
|
TASK_UNINTERRUPTIBLE);
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(wait_on_page_bit);
|
|
|
|
|
2011-05-25 08:11:29 +08:00
|
|
|
int wait_on_page_bit_killable(struct page *page, int bit_nr)
|
|
|
|
{
|
|
|
|
DEFINE_WAIT_BIT(wait, &page->flags, bit_nr);
|
|
|
|
|
|
|
|
if (!test_bit(bit_nr, &page->flags))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
return __wait_on_bit(page_waitqueue(page), &wait,
|
sched: Remove proliferation of wait_on_bit() action functions
The current "wait_on_bit" interface requires an 'action'
function to be provided which does the actual waiting.
There are over 20 such functions, many of them identical.
Most cases can be satisfied by one of just two functions, one
which uses io_schedule() and one which just uses schedule().
So:
Rename wait_on_bit and wait_on_bit_lock to
wait_on_bit_action and wait_on_bit_lock_action
to make it explicit that they need an action function.
Introduce new wait_on_bit{,_lock} and wait_on_bit{,_lock}_io
which are *not* given an action function but implicitly use
a standard one.
The decision to error-out if a signal is pending is now made
based on the 'mode' argument rather than being encoded in the action
function.
All instances of the old wait_on_bit and wait_on_bit_lock which
can use the new version have been changed accordingly and their
action functions have been discarded.
wait_on_bit{_lock} does not return any specific error code in the
event of a signal so the caller must check for non-zero and
interpolate their own error code as appropriate.
The wait_on_bit() call in __fscache_wait_on_invalidate() was
ambiguous as it specified TASK_UNINTERRUPTIBLE but used
fscache_wait_bit_interruptible as an action function.
David Howells confirms this should be uniformly
"uninterruptible"
The main remaining user of wait_on_bit{,_lock}_action is NFS
which needs to use a freezer-aware schedule() call.
A comment in fs/gfs2/glock.c notes that having multiple 'action'
functions is useful as they display differently in the 'wchan'
field of 'ps'. (and /proc/$PID/wchan).
As the new bit_wait{,_io} functions are tagged "__sched", they
will not show up at all, but something higher in the stack. So
the distinction will still be visible, only with different
function names (gds2_glock_wait versus gfs2_glock_dq_wait in the
gfs2/glock.c case).
Since first version of this patch (against 3.15) two new action
functions appeared, on in NFS and one in CIFS. CIFS also now
uses an action function that makes the same freezer aware
schedule call as NFS.
Signed-off-by: NeilBrown <neilb@suse.de>
Acked-by: David Howells <dhowells@redhat.com> (fscache, keys)
Acked-by: Steven Whitehouse <swhiteho@redhat.com> (gfs2)
Acked-by: Peter Zijlstra <peterz@infradead.org>
Cc: Oleg Nesterov <oleg@redhat.com>
Cc: Steve French <sfrench@samba.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Link: http://lkml.kernel.org/r/20140707051603.28027.72349.stgit@notabene.brown
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2014-07-07 13:16:04 +08:00
|
|
|
bit_wait_io, TASK_KILLABLE);
|
2011-05-25 08:11:29 +08:00
|
|
|
}
|
|
|
|
|
2014-09-25 11:55:19 +08:00
|
|
|
int wait_on_page_bit_killable_timeout(struct page *page,
|
|
|
|
int bit_nr, unsigned long timeout)
|
|
|
|
{
|
|
|
|
DEFINE_WAIT_BIT(wait, &page->flags, bit_nr);
|
|
|
|
|
|
|
|
wait.key.timeout = jiffies + timeout;
|
|
|
|
if (!test_bit(bit_nr, &page->flags))
|
|
|
|
return 0;
|
|
|
|
return __wait_on_bit(page_waitqueue(page), &wait,
|
|
|
|
bit_wait_io_timeout, TASK_KILLABLE);
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(wait_on_page_bit_killable_timeout);
|
|
|
|
|
2009-04-03 23:42:39 +08:00
|
|
|
/**
|
|
|
|
* add_page_wait_queue - Add an arbitrary waiter to a page's wait queue
|
2009-04-14 05:39:54 +08:00
|
|
|
* @page: Page defining the wait queue of interest
|
|
|
|
* @waiter: Waiter to add to the queue
|
2009-04-03 23:42:39 +08:00
|
|
|
*
|
|
|
|
* Add an arbitrary @waiter to the wait queue for the nominated @page.
|
|
|
|
*/
|
|
|
|
void add_page_wait_queue(struct page *page, wait_queue_t *waiter)
|
|
|
|
{
|
|
|
|
wait_queue_head_t *q = page_waitqueue(page);
|
|
|
|
unsigned long flags;
|
|
|
|
|
|
|
|
spin_lock_irqsave(&q->lock, flags);
|
|
|
|
__add_wait_queue(q, waiter);
|
|
|
|
spin_unlock_irqrestore(&q->lock, flags);
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(add_page_wait_queue);
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
/**
|
2006-06-23 17:03:49 +08:00
|
|
|
* unlock_page - unlock a locked page
|
2005-04-17 06:20:36 +08:00
|
|
|
* @page: the page
|
|
|
|
*
|
|
|
|
* Unlocks the page and wakes up sleepers in ___wait_on_page_locked().
|
|
|
|
* Also wakes sleepers in wait_on_page_writeback() because the wakeup
|
2014-09-09 00:27:23 +08:00
|
|
|
* mechanism between PageLocked pages and PageWriteback pages is shared.
|
2005-04-17 06:20:36 +08:00
|
|
|
* But that's OK - sleepers in wait_on_page_writeback() just go back to sleep.
|
|
|
|
*
|
2008-10-19 11:26:59 +08:00
|
|
|
* The mb is necessary to enforce ordering between the clear_bit and the read
|
|
|
|
* of the waitqueue (to avoid SMP races with a parallel wait_on_page_locked()).
|
2005-04-17 06:20:36 +08:00
|
|
|
*/
|
2008-02-05 14:29:26 +08:00
|
|
|
void unlock_page(struct page *page)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2016-01-16 08:51:24 +08:00
|
|
|
page = compound_head(page);
|
2014-01-24 07:52:54 +08:00
|
|
|
VM_BUG_ON_PAGE(!PageLocked(page), page);
|
2008-10-19 11:26:59 +08:00
|
|
|
clear_bit_unlock(PG_locked, &page->flags);
|
2014-03-18 01:06:10 +08:00
|
|
|
smp_mb__after_atomic();
|
2005-04-17 06:20:36 +08:00
|
|
|
wake_up_page(page, PG_locked);
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(unlock_page);
|
|
|
|
|
2006-06-23 17:03:49 +08:00
|
|
|
/**
|
|
|
|
* end_page_writeback - end writeback against a page
|
|
|
|
* @page: the page
|
2005-04-17 06:20:36 +08:00
|
|
|
*/
|
|
|
|
void end_page_writeback(struct page *page)
|
|
|
|
{
|
2014-06-05 07:10:34 +08:00
|
|
|
/*
|
|
|
|
* TestClearPageReclaim could be used here but it is an atomic
|
|
|
|
* operation and overkill in this particular case. Failing to
|
|
|
|
* shuffle a page marked for immediate reclaim is too mild to
|
|
|
|
* justify taking an atomic operation penalty at the end of
|
|
|
|
* ever page writeback.
|
|
|
|
*/
|
|
|
|
if (PageReclaim(page)) {
|
|
|
|
ClearPageReclaim(page);
|
2008-04-28 17:12:38 +08:00
|
|
|
rotate_reclaimable_page(page);
|
2014-06-05 07:10:34 +08:00
|
|
|
}
|
2008-04-28 17:12:38 +08:00
|
|
|
|
|
|
|
if (!test_clear_page_writeback(page))
|
|
|
|
BUG();
|
|
|
|
|
2014-03-18 01:06:10 +08:00
|
|
|
smp_mb__after_atomic();
|
2005-04-17 06:20:36 +08:00
|
|
|
wake_up_page(page, PG_writeback);
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(end_page_writeback);
|
|
|
|
|
2014-06-05 07:07:45 +08:00
|
|
|
/*
|
|
|
|
* After completing I/O on a page, call this routine to update the page
|
|
|
|
* flags appropriately
|
|
|
|
*/
|
|
|
|
void page_endio(struct page *page, int rw, int err)
|
|
|
|
{
|
|
|
|
if (rw == READ) {
|
|
|
|
if (!err) {
|
|
|
|
SetPageUptodate(page);
|
|
|
|
} else {
|
|
|
|
ClearPageUptodate(page);
|
|
|
|
SetPageError(page);
|
|
|
|
}
|
|
|
|
unlock_page(page);
|
|
|
|
} else { /* rw == WRITE */
|
|
|
|
if (err) {
|
|
|
|
SetPageError(page);
|
|
|
|
if (page->mapping)
|
|
|
|
mapping_set_error(page->mapping, err);
|
|
|
|
}
|
|
|
|
end_page_writeback(page);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(page_endio);
|
|
|
|
|
2006-06-23 17:03:49 +08:00
|
|
|
/**
|
|
|
|
* __lock_page - get a lock on the page, assuming we need to sleep to get it
|
|
|
|
* @page: the page to lock
|
2005-04-17 06:20:36 +08:00
|
|
|
*/
|
2008-02-05 14:29:26 +08:00
|
|
|
void __lock_page(struct page *page)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2016-01-16 08:51:24 +08:00
|
|
|
struct page *page_head = compound_head(page);
|
|
|
|
DEFINE_WAIT_BIT(wait, &page_head->flags, PG_locked);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2016-01-16 08:51:24 +08:00
|
|
|
__wait_on_bit_lock(page_waitqueue(page_head), &wait, bit_wait_io,
|
2005-04-17 06:20:36 +08:00
|
|
|
TASK_UNINTERRUPTIBLE);
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(__lock_page);
|
|
|
|
|
2008-02-14 07:03:16 +08:00
|
|
|
int __lock_page_killable(struct page *page)
|
2007-12-07 00:18:49 +08:00
|
|
|
{
|
2016-01-16 08:51:24 +08:00
|
|
|
struct page *page_head = compound_head(page);
|
|
|
|
DEFINE_WAIT_BIT(wait, &page_head->flags, PG_locked);
|
2007-12-07 00:18:49 +08:00
|
|
|
|
2016-01-16 08:51:24 +08:00
|
|
|
return __wait_on_bit_lock(page_waitqueue(page_head), &wait,
|
sched: Remove proliferation of wait_on_bit() action functions
The current "wait_on_bit" interface requires an 'action'
function to be provided which does the actual waiting.
There are over 20 such functions, many of them identical.
Most cases can be satisfied by one of just two functions, one
which uses io_schedule() and one which just uses schedule().
So:
Rename wait_on_bit and wait_on_bit_lock to
wait_on_bit_action and wait_on_bit_lock_action
to make it explicit that they need an action function.
Introduce new wait_on_bit{,_lock} and wait_on_bit{,_lock}_io
which are *not* given an action function but implicitly use
a standard one.
The decision to error-out if a signal is pending is now made
based on the 'mode' argument rather than being encoded in the action
function.
All instances of the old wait_on_bit and wait_on_bit_lock which
can use the new version have been changed accordingly and their
action functions have been discarded.
wait_on_bit{_lock} does not return any specific error code in the
event of a signal so the caller must check for non-zero and
interpolate their own error code as appropriate.
The wait_on_bit() call in __fscache_wait_on_invalidate() was
ambiguous as it specified TASK_UNINTERRUPTIBLE but used
fscache_wait_bit_interruptible as an action function.
David Howells confirms this should be uniformly
"uninterruptible"
The main remaining user of wait_on_bit{,_lock}_action is NFS
which needs to use a freezer-aware schedule() call.
A comment in fs/gfs2/glock.c notes that having multiple 'action'
functions is useful as they display differently in the 'wchan'
field of 'ps'. (and /proc/$PID/wchan).
As the new bit_wait{,_io} functions are tagged "__sched", they
will not show up at all, but something higher in the stack. So
the distinction will still be visible, only with different
function names (gds2_glock_wait versus gfs2_glock_dq_wait in the
gfs2/glock.c case).
Since first version of this patch (against 3.15) two new action
functions appeared, on in NFS and one in CIFS. CIFS also now
uses an action function that makes the same freezer aware
schedule call as NFS.
Signed-off-by: NeilBrown <neilb@suse.de>
Acked-by: David Howells <dhowells@redhat.com> (fscache, keys)
Acked-by: Steven Whitehouse <swhiteho@redhat.com> (gfs2)
Acked-by: Peter Zijlstra <peterz@infradead.org>
Cc: Oleg Nesterov <oleg@redhat.com>
Cc: Steve French <sfrench@samba.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Link: http://lkml.kernel.org/r/20140707051603.28027.72349.stgit@notabene.brown
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2014-07-07 13:16:04 +08:00
|
|
|
bit_wait_io, TASK_KILLABLE);
|
2007-12-07 00:18:49 +08:00
|
|
|
}
|
2009-02-09 22:02:42 +08:00
|
|
|
EXPORT_SYMBOL_GPL(__lock_page_killable);
|
2007-12-07 00:18:49 +08:00
|
|
|
|
2014-08-07 07:07:24 +08:00
|
|
|
/*
|
|
|
|
* Return values:
|
|
|
|
* 1 - page is locked; mmap_sem is still held.
|
|
|
|
* 0 - page is not locked.
|
|
|
|
* mmap_sem has been released (up_read()), unless flags had both
|
|
|
|
* FAULT_FLAG_ALLOW_RETRY and FAULT_FLAG_RETRY_NOWAIT set, in
|
|
|
|
* which case mmap_sem is still held.
|
|
|
|
*
|
|
|
|
* If neither ALLOW_RETRY nor KILLABLE are set, will always return 1
|
|
|
|
* with the page locked and the mmap_sem unperturbed.
|
|
|
|
*/
|
2010-10-27 05:21:57 +08:00
|
|
|
int __lock_page_or_retry(struct page *page, struct mm_struct *mm,
|
|
|
|
unsigned int flags)
|
|
|
|
{
|
2011-05-25 08:11:30 +08:00
|
|
|
if (flags & FAULT_FLAG_ALLOW_RETRY) {
|
|
|
|
/*
|
|
|
|
* CAUTION! In this case, mmap_sem is not released
|
|
|
|
* even though return 0.
|
|
|
|
*/
|
|
|
|
if (flags & FAULT_FLAG_RETRY_NOWAIT)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
up_read(&mm->mmap_sem);
|
|
|
|
if (flags & FAULT_FLAG_KILLABLE)
|
|
|
|
wait_on_page_locked_killable(page);
|
|
|
|
else
|
2011-03-23 07:30:51 +08:00
|
|
|
wait_on_page_locked(page);
|
2010-10-27 05:21:57 +08:00
|
|
|
return 0;
|
2011-05-25 08:11:30 +08:00
|
|
|
} else {
|
|
|
|
if (flags & FAULT_FLAG_KILLABLE) {
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
ret = __lock_page_killable(page);
|
|
|
|
if (ret) {
|
|
|
|
up_read(&mm->mmap_sem);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
} else
|
|
|
|
__lock_page(page);
|
|
|
|
return 1;
|
2010-10-27 05:21:57 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-04-04 05:47:44 +08:00
|
|
|
/**
|
|
|
|
* page_cache_next_hole - find the next hole (not-present entry)
|
|
|
|
* @mapping: mapping
|
|
|
|
* @index: index
|
|
|
|
* @max_scan: maximum range to search
|
|
|
|
*
|
|
|
|
* Search the set [index, min(index+max_scan-1, MAX_INDEX)] for the
|
|
|
|
* lowest indexed hole.
|
|
|
|
*
|
|
|
|
* Returns: the index of the hole if found, otherwise returns an index
|
|
|
|
* outside of the set specified (in which case 'return - index >=
|
|
|
|
* max_scan' will be true). In rare cases of index wrap-around, 0 will
|
|
|
|
* be returned.
|
|
|
|
*
|
|
|
|
* page_cache_next_hole may be called under rcu_read_lock. However,
|
|
|
|
* like radix_tree_gang_lookup, this will not atomically search a
|
|
|
|
* snapshot of the tree at a single point in time. For example, if a
|
|
|
|
* hole is created at index 5, then subsequently a hole is created at
|
|
|
|
* index 10, page_cache_next_hole covering both indexes may return 10
|
|
|
|
* if called under rcu_read_lock.
|
|
|
|
*/
|
|
|
|
pgoff_t page_cache_next_hole(struct address_space *mapping,
|
|
|
|
pgoff_t index, unsigned long max_scan)
|
|
|
|
{
|
|
|
|
unsigned long i;
|
|
|
|
|
|
|
|
for (i = 0; i < max_scan; i++) {
|
2014-04-04 05:47:46 +08:00
|
|
|
struct page *page;
|
|
|
|
|
|
|
|
page = radix_tree_lookup(&mapping->page_tree, index);
|
|
|
|
if (!page || radix_tree_exceptional_entry(page))
|
2014-04-04 05:47:44 +08:00
|
|
|
break;
|
|
|
|
index++;
|
|
|
|
if (index == 0)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return index;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(page_cache_next_hole);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* page_cache_prev_hole - find the prev hole (not-present entry)
|
|
|
|
* @mapping: mapping
|
|
|
|
* @index: index
|
|
|
|
* @max_scan: maximum range to search
|
|
|
|
*
|
|
|
|
* Search backwards in the range [max(index-max_scan+1, 0), index] for
|
|
|
|
* the first hole.
|
|
|
|
*
|
|
|
|
* Returns: the index of the hole if found, otherwise returns an index
|
|
|
|
* outside of the set specified (in which case 'index - return >=
|
|
|
|
* max_scan' will be true). In rare cases of wrap-around, ULONG_MAX
|
|
|
|
* will be returned.
|
|
|
|
*
|
|
|
|
* page_cache_prev_hole may be called under rcu_read_lock. However,
|
|
|
|
* like radix_tree_gang_lookup, this will not atomically search a
|
|
|
|
* snapshot of the tree at a single point in time. For example, if a
|
|
|
|
* hole is created at index 10, then subsequently a hole is created at
|
|
|
|
* index 5, page_cache_prev_hole covering both indexes may return 5 if
|
|
|
|
* called under rcu_read_lock.
|
|
|
|
*/
|
|
|
|
pgoff_t page_cache_prev_hole(struct address_space *mapping,
|
|
|
|
pgoff_t index, unsigned long max_scan)
|
|
|
|
{
|
|
|
|
unsigned long i;
|
|
|
|
|
|
|
|
for (i = 0; i < max_scan; i++) {
|
2014-04-04 05:47:46 +08:00
|
|
|
struct page *page;
|
|
|
|
|
|
|
|
page = radix_tree_lookup(&mapping->page_tree, index);
|
|
|
|
if (!page || radix_tree_exceptional_entry(page))
|
2014-04-04 05:47:44 +08:00
|
|
|
break;
|
|
|
|
index--;
|
|
|
|
if (index == ULONG_MAX)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return index;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(page_cache_prev_hole);
|
|
|
|
|
2006-06-23 17:03:49 +08:00
|
|
|
/**
|
2014-04-04 05:47:46 +08:00
|
|
|
* find_get_entry - find and get a page cache entry
|
2006-06-23 17:03:49 +08:00
|
|
|
* @mapping: the address_space to search
|
2014-04-04 05:47:46 +08:00
|
|
|
* @offset: the page cache index
|
|
|
|
*
|
|
|
|
* Looks up the page cache slot at @mapping & @offset. If there is a
|
|
|
|
* page cache page, it is returned with an increased refcount.
|
2006-06-23 17:03:49 +08:00
|
|
|
*
|
2014-05-07 03:50:05 +08:00
|
|
|
* If the slot holds a shadow entry of a previously evicted page, or a
|
|
|
|
* swap entry from shmem/tmpfs, it is returned.
|
2014-04-04 05:47:46 +08:00
|
|
|
*
|
|
|
|
* Otherwise, %NULL is returned.
|
2005-04-17 06:20:36 +08:00
|
|
|
*/
|
2014-04-04 05:47:46 +08:00
|
|
|
struct page *find_get_entry(struct address_space *mapping, pgoff_t offset)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2008-07-26 10:45:31 +08:00
|
|
|
void **pagep;
|
2005-04-17 06:20:36 +08:00
|
|
|
struct page *page;
|
|
|
|
|
2008-07-26 10:45:31 +08:00
|
|
|
rcu_read_lock();
|
|
|
|
repeat:
|
|
|
|
page = NULL;
|
|
|
|
pagep = radix_tree_lookup_slot(&mapping->page_tree, offset);
|
|
|
|
if (pagep) {
|
|
|
|
page = radix_tree_deref_slot(pagep);
|
2010-11-12 06:05:19 +08:00
|
|
|
if (unlikely(!page))
|
|
|
|
goto out;
|
mm: let swap use exceptional entries
If swap entries are to be stored along with struct page pointers in a
radix tree, they need to be distinguished as exceptional entries.
Most of the handling of swap entries in radix tree will be contained in
shmem.c, but a few functions in filemap.c's common code need to check
for their appearance: find_get_page(), find_lock_page(),
find_get_pages() and find_get_pages_contig().
So as not to slow their fast paths, tuck those checks inside the
existing checks for unlikely radix_tree_deref_slot(); except for
find_lock_page(), where it is an added test. And make it a BUG in
find_get_pages_tag(), which is not applied to tmpfs files.
A part of the reason for eliminating shmem_readpage() earlier, was to
minimize the places where common code would need to allow for swap
entries.
The swp_entry_t known to swapfile.c must be massaged into a slightly
different form when stored in the radix tree, just as it gets massaged
into a pte_t when stored in page tables.
In an i386 kernel this limits its information (type and page offset) to
30 bits: given 32 "types" of swapfile and 4kB pagesize, that's a maximum
swapfile size of 128GB. Which is less than the 512GB we previously
allowed with X86_PAE (where the swap entry can occupy the entire upper
32 bits of a pte_t), but not a new limitation on 32-bit without PAE; and
there's not a new limitation on 64-bit (where swap filesize is already
limited to 16TB by a 32-bit page offset). Thirty areas of 128GB is
probably still enough swap for a 64GB 32-bit machine.
Provide swp_to_radix_entry() and radix_to_swp_entry() conversions, and
enforce filesize limit in read_swap_header(), just as for ptes.
Signed-off-by: Hugh Dickins <hughd@google.com>
Acked-by: Rik van Riel <riel@redhat.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2011-08-04 07:21:19 +08:00
|
|
|
if (radix_tree_exception(page)) {
|
2011-08-04 07:21:28 +08:00
|
|
|
if (radix_tree_deref_retry(page))
|
|
|
|
goto repeat;
|
|
|
|
/*
|
2014-05-07 03:50:05 +08:00
|
|
|
* A shadow entry of a recently evicted page,
|
|
|
|
* or a swap entry from shmem/tmpfs. Return
|
|
|
|
* it without attempting to raise page count.
|
2011-08-04 07:21:28 +08:00
|
|
|
*/
|
|
|
|
goto out;
|
mm: let swap use exceptional entries
If swap entries are to be stored along with struct page pointers in a
radix tree, they need to be distinguished as exceptional entries.
Most of the handling of swap entries in radix tree will be contained in
shmem.c, but a few functions in filemap.c's common code need to check
for their appearance: find_get_page(), find_lock_page(),
find_get_pages() and find_get_pages_contig().
So as not to slow their fast paths, tuck those checks inside the
existing checks for unlikely radix_tree_deref_slot(); except for
find_lock_page(), where it is an added test. And make it a BUG in
find_get_pages_tag(), which is not applied to tmpfs files.
A part of the reason for eliminating shmem_readpage() earlier, was to
minimize the places where common code would need to allow for swap
entries.
The swp_entry_t known to swapfile.c must be massaged into a slightly
different form when stored in the radix tree, just as it gets massaged
into a pte_t when stored in page tables.
In an i386 kernel this limits its information (type and page offset) to
30 bits: given 32 "types" of swapfile and 4kB pagesize, that's a maximum
swapfile size of 128GB. Which is less than the 512GB we previously
allowed with X86_PAE (where the swap entry can occupy the entire upper
32 bits of a pte_t), but not a new limitation on 32-bit without PAE; and
there's not a new limitation on 64-bit (where swap filesize is already
limited to 16TB by a 32-bit page offset). Thirty areas of 128GB is
probably still enough swap for a 64GB 32-bit machine.
Provide swp_to_radix_entry() and radix_to_swp_entry() conversions, and
enforce filesize limit in read_swap_header(), just as for ptes.
Signed-off-by: Hugh Dickins <hughd@google.com>
Acked-by: Rik van Riel <riel@redhat.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2011-08-04 07:21:19 +08:00
|
|
|
}
|
2008-07-26 10:45:31 +08:00
|
|
|
if (!page_cache_get_speculative(page))
|
|
|
|
goto repeat;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Has the page moved?
|
|
|
|
* This is part of the lockless pagecache protocol. See
|
|
|
|
* include/linux/pagemap.h for details.
|
|
|
|
*/
|
|
|
|
if (unlikely(page != *pagep)) {
|
|
|
|
page_cache_release(page);
|
|
|
|
goto repeat;
|
|
|
|
}
|
|
|
|
}
|
2010-11-12 06:05:19 +08:00
|
|
|
out:
|
2008-07-26 10:45:31 +08:00
|
|
|
rcu_read_unlock();
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
return page;
|
|
|
|
}
|
2014-04-04 05:47:46 +08:00
|
|
|
EXPORT_SYMBOL(find_get_entry);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2014-04-04 05:47:46 +08:00
|
|
|
/**
|
|
|
|
* find_lock_entry - locate, pin and lock a page cache entry
|
|
|
|
* @mapping: the address_space to search
|
|
|
|
* @offset: the page cache index
|
|
|
|
*
|
|
|
|
* Looks up the page cache slot at @mapping & @offset. If there is a
|
|
|
|
* page cache page, it is returned locked and with an increased
|
|
|
|
* refcount.
|
|
|
|
*
|
2014-05-07 03:50:05 +08:00
|
|
|
* If the slot holds a shadow entry of a previously evicted page, or a
|
|
|
|
* swap entry from shmem/tmpfs, it is returned.
|
2014-04-04 05:47:46 +08:00
|
|
|
*
|
|
|
|
* Otherwise, %NULL is returned.
|
|
|
|
*
|
|
|
|
* find_lock_entry() may sleep.
|
|
|
|
*/
|
|
|
|
struct page *find_lock_entry(struct address_space *mapping, pgoff_t offset)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
|
|
|
struct page *page;
|
|
|
|
|
|
|
|
repeat:
|
2014-04-04 05:47:46 +08:00
|
|
|
page = find_get_entry(mapping, offset);
|
mm: let swap use exceptional entries
If swap entries are to be stored along with struct page pointers in a
radix tree, they need to be distinguished as exceptional entries.
Most of the handling of swap entries in radix tree will be contained in
shmem.c, but a few functions in filemap.c's common code need to check
for their appearance: find_get_page(), find_lock_page(),
find_get_pages() and find_get_pages_contig().
So as not to slow their fast paths, tuck those checks inside the
existing checks for unlikely radix_tree_deref_slot(); except for
find_lock_page(), where it is an added test. And make it a BUG in
find_get_pages_tag(), which is not applied to tmpfs files.
A part of the reason for eliminating shmem_readpage() earlier, was to
minimize the places where common code would need to allow for swap
entries.
The swp_entry_t known to swapfile.c must be massaged into a slightly
different form when stored in the radix tree, just as it gets massaged
into a pte_t when stored in page tables.
In an i386 kernel this limits its information (type and page offset) to
30 bits: given 32 "types" of swapfile and 4kB pagesize, that's a maximum
swapfile size of 128GB. Which is less than the 512GB we previously
allowed with X86_PAE (where the swap entry can occupy the entire upper
32 bits of a pte_t), but not a new limitation on 32-bit without PAE; and
there's not a new limitation on 64-bit (where swap filesize is already
limited to 16TB by a 32-bit page offset). Thirty areas of 128GB is
probably still enough swap for a 64GB 32-bit machine.
Provide swp_to_radix_entry() and radix_to_swp_entry() conversions, and
enforce filesize limit in read_swap_header(), just as for ptes.
Signed-off-by: Hugh Dickins <hughd@google.com>
Acked-by: Rik van Riel <riel@redhat.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2011-08-04 07:21:19 +08:00
|
|
|
if (page && !radix_tree_exception(page)) {
|
2008-07-26 10:45:31 +08:00
|
|
|
lock_page(page);
|
|
|
|
/* Has the page been truncated? */
|
|
|
|
if (unlikely(page->mapping != mapping)) {
|
|
|
|
unlock_page(page);
|
|
|
|
page_cache_release(page);
|
|
|
|
goto repeat;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
2014-01-24 07:52:54 +08:00
|
|
|
VM_BUG_ON_PAGE(page->index != offset, page);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
return page;
|
|
|
|
}
|
2014-04-04 05:47:46 +08:00
|
|
|
EXPORT_SYMBOL(find_lock_entry);
|
|
|
|
|
|
|
|
/**
|
2014-06-05 07:10:31 +08:00
|
|
|
* pagecache_get_page - find and get a page reference
|
2014-04-04 05:47:46 +08:00
|
|
|
* @mapping: the address_space to search
|
|
|
|
* @offset: the page index
|
2014-06-05 07:10:31 +08:00
|
|
|
* @fgp_flags: PCG flags
|
2014-12-30 03:30:35 +08:00
|
|
|
* @gfp_mask: gfp mask to use for the page cache data page allocation
|
2014-04-04 05:47:46 +08:00
|
|
|
*
|
2014-06-05 07:10:31 +08:00
|
|
|
* Looks up the page cache slot at @mapping & @offset.
|
2005-04-17 06:20:36 +08:00
|
|
|
*
|
2014-07-31 07:08:37 +08:00
|
|
|
* PCG flags modify how the page is returned.
|
2014-04-04 05:47:46 +08:00
|
|
|
*
|
2014-06-05 07:10:31 +08:00
|
|
|
* FGP_ACCESSED: the page will be marked accessed
|
|
|
|
* FGP_LOCK: Page is return locked
|
|
|
|
* FGP_CREAT: If page is not present then a new page is allocated using
|
2014-12-30 03:30:35 +08:00
|
|
|
* @gfp_mask and added to the page cache and the VM's LRU
|
|
|
|
* list. The page is returned locked and with an increased
|
|
|
|
* refcount. Otherwise, %NULL is returned.
|
2005-04-17 06:20:36 +08:00
|
|
|
*
|
2014-06-05 07:10:31 +08:00
|
|
|
* If FGP_LOCK or FGP_CREAT are specified then the function may sleep even
|
|
|
|
* if the GFP flags specified for FGP_CREAT are atomic.
|
2005-04-17 06:20:36 +08:00
|
|
|
*
|
2014-06-05 07:10:31 +08:00
|
|
|
* If there is a page cache page, it is returned with an increased refcount.
|
2005-04-17 06:20:36 +08:00
|
|
|
*/
|
2014-06-05 07:10:31 +08:00
|
|
|
struct page *pagecache_get_page(struct address_space *mapping, pgoff_t offset,
|
2014-12-30 03:30:35 +08:00
|
|
|
int fgp_flags, gfp_t gfp_mask)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2007-10-16 16:24:57 +08:00
|
|
|
struct page *page;
|
2014-06-05 07:10:31 +08:00
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
repeat:
|
2014-06-05 07:10:31 +08:00
|
|
|
page = find_get_entry(mapping, offset);
|
|
|
|
if (radix_tree_exceptional_entry(page))
|
|
|
|
page = NULL;
|
|
|
|
if (!page)
|
|
|
|
goto no_page;
|
|
|
|
|
|
|
|
if (fgp_flags & FGP_LOCK) {
|
|
|
|
if (fgp_flags & FGP_NOWAIT) {
|
|
|
|
if (!trylock_page(page)) {
|
|
|
|
page_cache_release(page);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
lock_page(page);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Has the page been truncated? */
|
|
|
|
if (unlikely(page->mapping != mapping)) {
|
|
|
|
unlock_page(page);
|
|
|
|
page_cache_release(page);
|
|
|
|
goto repeat;
|
|
|
|
}
|
|
|
|
VM_BUG_ON_PAGE(page->index != offset, page);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (page && (fgp_flags & FGP_ACCESSED))
|
|
|
|
mark_page_accessed(page);
|
|
|
|
|
|
|
|
no_page:
|
|
|
|
if (!page && (fgp_flags & FGP_CREAT)) {
|
|
|
|
int err;
|
|
|
|
if ((fgp_flags & FGP_WRITE) && mapping_cap_account_dirty(mapping))
|
2014-12-30 03:30:35 +08:00
|
|
|
gfp_mask |= __GFP_WRITE;
|
|
|
|
if (fgp_flags & FGP_NOFS)
|
|
|
|
gfp_mask &= ~__GFP_FS;
|
2014-06-05 07:10:31 +08:00
|
|
|
|
2014-12-30 03:30:35 +08:00
|
|
|
page = __page_cache_alloc(gfp_mask);
|
2007-10-16 16:24:57 +08:00
|
|
|
if (!page)
|
|
|
|
return NULL;
|
2014-06-05 07:10:31 +08:00
|
|
|
|
|
|
|
if (WARN_ON_ONCE(!(fgp_flags & FGP_LOCK)))
|
|
|
|
fgp_flags |= FGP_LOCK;
|
|
|
|
|
2014-08-07 07:06:43 +08:00
|
|
|
/* Init accessed so avoid atomic mark_page_accessed later */
|
2014-06-05 07:10:31 +08:00
|
|
|
if (fgp_flags & FGP_ACCESSED)
|
2014-08-07 07:06:43 +08:00
|
|
|
__SetPageReferenced(page);
|
2014-06-05 07:10:31 +08:00
|
|
|
|
2014-12-30 03:30:35 +08:00
|
|
|
err = add_to_page_cache_lru(page, mapping, offset,
|
|
|
|
gfp_mask & GFP_RECLAIM_MASK);
|
2007-10-16 16:24:57 +08:00
|
|
|
if (unlikely(err)) {
|
|
|
|
page_cache_release(page);
|
|
|
|
page = NULL;
|
|
|
|
if (err == -EEXIST)
|
|
|
|
goto repeat;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
}
|
2014-06-05 07:10:31 +08:00
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
return page;
|
|
|
|
}
|
2014-06-05 07:10:31 +08:00
|
|
|
EXPORT_SYMBOL(pagecache_get_page);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2014-04-04 05:47:46 +08:00
|
|
|
/**
|
|
|
|
* find_get_entries - gang pagecache lookup
|
|
|
|
* @mapping: The address_space to search
|
|
|
|
* @start: The starting page cache index
|
|
|
|
* @nr_entries: The maximum number of entries
|
|
|
|
* @entries: Where the resulting entries are placed
|
|
|
|
* @indices: The cache indices corresponding to the entries in @entries
|
|
|
|
*
|
|
|
|
* find_get_entries() will search for and return a group of up to
|
|
|
|
* @nr_entries entries in the mapping. The entries are placed at
|
|
|
|
* @entries. find_get_entries() takes a reference against any actual
|
|
|
|
* pages it returns.
|
|
|
|
*
|
|
|
|
* The search returns a group of mapping-contiguous page cache entries
|
|
|
|
* with ascending indexes. There may be holes in the indices due to
|
|
|
|
* not-present pages.
|
|
|
|
*
|
2014-05-07 03:50:05 +08:00
|
|
|
* Any shadow entries of evicted pages, or swap entries from
|
|
|
|
* shmem/tmpfs, are included in the returned array.
|
2014-04-04 05:47:46 +08:00
|
|
|
*
|
|
|
|
* find_get_entries() returns the number of pages and shadow entries
|
|
|
|
* which were found.
|
|
|
|
*/
|
|
|
|
unsigned find_get_entries(struct address_space *mapping,
|
|
|
|
pgoff_t start, unsigned int nr_entries,
|
|
|
|
struct page **entries, pgoff_t *indices)
|
|
|
|
{
|
|
|
|
void **slot;
|
|
|
|
unsigned int ret = 0;
|
|
|
|
struct radix_tree_iter iter;
|
|
|
|
|
|
|
|
if (!nr_entries)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
rcu_read_lock();
|
|
|
|
restart:
|
|
|
|
radix_tree_for_each_slot(slot, &mapping->page_tree, &iter, start) {
|
|
|
|
struct page *page;
|
|
|
|
repeat:
|
|
|
|
page = radix_tree_deref_slot(slot);
|
|
|
|
if (unlikely(!page))
|
|
|
|
continue;
|
|
|
|
if (radix_tree_exception(page)) {
|
|
|
|
if (radix_tree_deref_retry(page))
|
|
|
|
goto restart;
|
|
|
|
/*
|
2016-01-23 07:10:40 +08:00
|
|
|
* A shadow entry of a recently evicted page, a swap
|
|
|
|
* entry from shmem/tmpfs or a DAX entry. Return it
|
|
|
|
* without attempting to raise page count.
|
2014-04-04 05:47:46 +08:00
|
|
|
*/
|
|
|
|
goto export;
|
|
|
|
}
|
|
|
|
if (!page_cache_get_speculative(page))
|
|
|
|
goto repeat;
|
|
|
|
|
|
|
|
/* Has the page moved? */
|
|
|
|
if (unlikely(page != *slot)) {
|
|
|
|
page_cache_release(page);
|
|
|
|
goto repeat;
|
|
|
|
}
|
|
|
|
export:
|
|
|
|
indices[ret] = iter.index;
|
|
|
|
entries[ret] = page;
|
|
|
|
if (++ret == nr_entries)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
rcu_read_unlock();
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
/**
|
|
|
|
* find_get_pages - gang pagecache lookup
|
|
|
|
* @mapping: The address_space to search
|
|
|
|
* @start: The starting page index
|
|
|
|
* @nr_pages: The maximum number of pages
|
|
|
|
* @pages: Where the resulting pages are placed
|
|
|
|
*
|
|
|
|
* find_get_pages() will search for and return a group of up to
|
|
|
|
* @nr_pages pages in the mapping. The pages are placed at @pages.
|
|
|
|
* find_get_pages() takes a reference against the returned pages.
|
|
|
|
*
|
|
|
|
* The search returns a group of mapping-contiguous pages with ascending
|
|
|
|
* indexes. There may be holes in the indices due to not-present pages.
|
|
|
|
*
|
|
|
|
* find_get_pages() returns the number of pages which were found.
|
|
|
|
*/
|
|
|
|
unsigned find_get_pages(struct address_space *mapping, pgoff_t start,
|
|
|
|
unsigned int nr_pages, struct page **pages)
|
|
|
|
{
|
2012-03-29 05:42:54 +08:00
|
|
|
struct radix_tree_iter iter;
|
|
|
|
void **slot;
|
|
|
|
unsigned ret = 0;
|
|
|
|
|
|
|
|
if (unlikely(!nr_pages))
|
|
|
|
return 0;
|
2008-07-26 10:45:31 +08:00
|
|
|
|
|
|
|
rcu_read_lock();
|
|
|
|
restart:
|
2012-03-29 05:42:54 +08:00
|
|
|
radix_tree_for_each_slot(slot, &mapping->page_tree, &iter, start) {
|
2008-07-26 10:45:31 +08:00
|
|
|
struct page *page;
|
|
|
|
repeat:
|
2012-03-29 05:42:54 +08:00
|
|
|
page = radix_tree_deref_slot(slot);
|
2008-07-26 10:45:31 +08:00
|
|
|
if (unlikely(!page))
|
|
|
|
continue;
|
2011-03-23 07:33:06 +08:00
|
|
|
|
mm: let swap use exceptional entries
If swap entries are to be stored along with struct page pointers in a
radix tree, they need to be distinguished as exceptional entries.
Most of the handling of swap entries in radix tree will be contained in
shmem.c, but a few functions in filemap.c's common code need to check
for their appearance: find_get_page(), find_lock_page(),
find_get_pages() and find_get_pages_contig().
So as not to slow their fast paths, tuck those checks inside the
existing checks for unlikely radix_tree_deref_slot(); except for
find_lock_page(), where it is an added test. And make it a BUG in
find_get_pages_tag(), which is not applied to tmpfs files.
A part of the reason for eliminating shmem_readpage() earlier, was to
minimize the places where common code would need to allow for swap
entries.
The swp_entry_t known to swapfile.c must be massaged into a slightly
different form when stored in the radix tree, just as it gets massaged
into a pte_t when stored in page tables.
In an i386 kernel this limits its information (type and page offset) to
30 bits: given 32 "types" of swapfile and 4kB pagesize, that's a maximum
swapfile size of 128GB. Which is less than the 512GB we previously
allowed with X86_PAE (where the swap entry can occupy the entire upper
32 bits of a pte_t), but not a new limitation on 32-bit without PAE; and
there's not a new limitation on 64-bit (where swap filesize is already
limited to 16TB by a 32-bit page offset). Thirty areas of 128GB is
probably still enough swap for a 64GB 32-bit machine.
Provide swp_to_radix_entry() and radix_to_swp_entry() conversions, and
enforce filesize limit in read_swap_header(), just as for ptes.
Signed-off-by: Hugh Dickins <hughd@google.com>
Acked-by: Rik van Riel <riel@redhat.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2011-08-04 07:21:19 +08:00
|
|
|
if (radix_tree_exception(page)) {
|
2011-08-04 07:21:28 +08:00
|
|
|
if (radix_tree_deref_retry(page)) {
|
|
|
|
/*
|
|
|
|
* Transient condition which can only trigger
|
|
|
|
* when entry at index 0 moves out of or back
|
|
|
|
* to root: none yet gotten, safe to restart.
|
|
|
|
*/
|
2012-03-29 05:42:54 +08:00
|
|
|
WARN_ON(iter.index);
|
2011-08-04 07:21:28 +08:00
|
|
|
goto restart;
|
|
|
|
}
|
mm: let swap use exceptional entries
If swap entries are to be stored along with struct page pointers in a
radix tree, they need to be distinguished as exceptional entries.
Most of the handling of swap entries in radix tree will be contained in
shmem.c, but a few functions in filemap.c's common code need to check
for their appearance: find_get_page(), find_lock_page(),
find_get_pages() and find_get_pages_contig().
So as not to slow their fast paths, tuck those checks inside the
existing checks for unlikely radix_tree_deref_slot(); except for
find_lock_page(), where it is an added test. And make it a BUG in
find_get_pages_tag(), which is not applied to tmpfs files.
A part of the reason for eliminating shmem_readpage() earlier, was to
minimize the places where common code would need to allow for swap
entries.
The swp_entry_t known to swapfile.c must be massaged into a slightly
different form when stored in the radix tree, just as it gets massaged
into a pte_t when stored in page tables.
In an i386 kernel this limits its information (type and page offset) to
30 bits: given 32 "types" of swapfile and 4kB pagesize, that's a maximum
swapfile size of 128GB. Which is less than the 512GB we previously
allowed with X86_PAE (where the swap entry can occupy the entire upper
32 bits of a pte_t), but not a new limitation on 32-bit without PAE; and
there's not a new limitation on 64-bit (where swap filesize is already
limited to 16TB by a 32-bit page offset). Thirty areas of 128GB is
probably still enough swap for a 64GB 32-bit machine.
Provide swp_to_radix_entry() and radix_to_swp_entry() conversions, and
enforce filesize limit in read_swap_header(), just as for ptes.
Signed-off-by: Hugh Dickins <hughd@google.com>
Acked-by: Rik van Riel <riel@redhat.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2011-08-04 07:21:19 +08:00
|
|
|
/*
|
2014-05-07 03:50:05 +08:00
|
|
|
* A shadow entry of a recently evicted page,
|
|
|
|
* or a swap entry from shmem/tmpfs. Skip
|
|
|
|
* over it.
|
mm: let swap use exceptional entries
If swap entries are to be stored along with struct page pointers in a
radix tree, they need to be distinguished as exceptional entries.
Most of the handling of swap entries in radix tree will be contained in
shmem.c, but a few functions in filemap.c's common code need to check
for their appearance: find_get_page(), find_lock_page(),
find_get_pages() and find_get_pages_contig().
So as not to slow their fast paths, tuck those checks inside the
existing checks for unlikely radix_tree_deref_slot(); except for
find_lock_page(), where it is an added test. And make it a BUG in
find_get_pages_tag(), which is not applied to tmpfs files.
A part of the reason for eliminating shmem_readpage() earlier, was to
minimize the places where common code would need to allow for swap
entries.
The swp_entry_t known to swapfile.c must be massaged into a slightly
different form when stored in the radix tree, just as it gets massaged
into a pte_t when stored in page tables.
In an i386 kernel this limits its information (type and page offset) to
30 bits: given 32 "types" of swapfile and 4kB pagesize, that's a maximum
swapfile size of 128GB. Which is less than the 512GB we previously
allowed with X86_PAE (where the swap entry can occupy the entire upper
32 bits of a pte_t), but not a new limitation on 32-bit without PAE; and
there's not a new limitation on 64-bit (where swap filesize is already
limited to 16TB by a 32-bit page offset). Thirty areas of 128GB is
probably still enough swap for a 64GB 32-bit machine.
Provide swp_to_radix_entry() and radix_to_swp_entry() conversions, and
enforce filesize limit in read_swap_header(), just as for ptes.
Signed-off-by: Hugh Dickins <hughd@google.com>
Acked-by: Rik van Riel <riel@redhat.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2011-08-04 07:21:19 +08:00
|
|
|
*/
|
2011-08-04 07:21:28 +08:00
|
|
|
continue;
|
2010-11-12 06:05:19 +08:00
|
|
|
}
|
2008-07-26 10:45:31 +08:00
|
|
|
|
|
|
|
if (!page_cache_get_speculative(page))
|
|
|
|
goto repeat;
|
|
|
|
|
|
|
|
/* Has the page moved? */
|
2012-03-29 05:42:54 +08:00
|
|
|
if (unlikely(page != *slot)) {
|
2008-07-26 10:45:31 +08:00
|
|
|
page_cache_release(page);
|
|
|
|
goto repeat;
|
|
|
|
}
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2008-07-26 10:45:31 +08:00
|
|
|
pages[ret] = page;
|
2012-03-29 05:42:54 +08:00
|
|
|
if (++ret == nr_pages)
|
|
|
|
break;
|
2008-07-26 10:45:31 +08:00
|
|
|
}
|
2011-03-23 07:33:07 +08:00
|
|
|
|
2008-07-26 10:45:31 +08:00
|
|
|
rcu_read_unlock();
|
2005-04-17 06:20:36 +08:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2006-04-27 14:46:01 +08:00
|
|
|
/**
|
|
|
|
* find_get_pages_contig - gang contiguous pagecache lookup
|
|
|
|
* @mapping: The address_space to search
|
|
|
|
* @index: The starting page index
|
|
|
|
* @nr_pages: The maximum number of pages
|
|
|
|
* @pages: Where the resulting pages are placed
|
|
|
|
*
|
|
|
|
* find_get_pages_contig() works exactly like find_get_pages(), except
|
|
|
|
* that the returned number of pages are guaranteed to be contiguous.
|
|
|
|
*
|
|
|
|
* find_get_pages_contig() returns the number of pages which were found.
|
|
|
|
*/
|
|
|
|
unsigned find_get_pages_contig(struct address_space *mapping, pgoff_t index,
|
|
|
|
unsigned int nr_pages, struct page **pages)
|
|
|
|
{
|
2012-03-29 05:42:54 +08:00
|
|
|
struct radix_tree_iter iter;
|
|
|
|
void **slot;
|
|
|
|
unsigned int ret = 0;
|
|
|
|
|
|
|
|
if (unlikely(!nr_pages))
|
|
|
|
return 0;
|
2008-07-26 10:45:31 +08:00
|
|
|
|
|
|
|
rcu_read_lock();
|
|
|
|
restart:
|
2012-03-29 05:42:54 +08:00
|
|
|
radix_tree_for_each_contig(slot, &mapping->page_tree, &iter, index) {
|
2008-07-26 10:45:31 +08:00
|
|
|
struct page *page;
|
|
|
|
repeat:
|
2012-03-29 05:42:54 +08:00
|
|
|
page = radix_tree_deref_slot(slot);
|
|
|
|
/* The hole, there no reason to continue */
|
2008-07-26 10:45:31 +08:00
|
|
|
if (unlikely(!page))
|
2012-03-29 05:42:54 +08:00
|
|
|
break;
|
2011-03-23 07:33:06 +08:00
|
|
|
|
mm: let swap use exceptional entries
If swap entries are to be stored along with struct page pointers in a
radix tree, they need to be distinguished as exceptional entries.
Most of the handling of swap entries in radix tree will be contained in
shmem.c, but a few functions in filemap.c's common code need to check
for their appearance: find_get_page(), find_lock_page(),
find_get_pages() and find_get_pages_contig().
So as not to slow their fast paths, tuck those checks inside the
existing checks for unlikely radix_tree_deref_slot(); except for
find_lock_page(), where it is an added test. And make it a BUG in
find_get_pages_tag(), which is not applied to tmpfs files.
A part of the reason for eliminating shmem_readpage() earlier, was to
minimize the places where common code would need to allow for swap
entries.
The swp_entry_t known to swapfile.c must be massaged into a slightly
different form when stored in the radix tree, just as it gets massaged
into a pte_t when stored in page tables.
In an i386 kernel this limits its information (type and page offset) to
30 bits: given 32 "types" of swapfile and 4kB pagesize, that's a maximum
swapfile size of 128GB. Which is less than the 512GB we previously
allowed with X86_PAE (where the swap entry can occupy the entire upper
32 bits of a pte_t), but not a new limitation on 32-bit without PAE; and
there's not a new limitation on 64-bit (where swap filesize is already
limited to 16TB by a 32-bit page offset). Thirty areas of 128GB is
probably still enough swap for a 64GB 32-bit machine.
Provide swp_to_radix_entry() and radix_to_swp_entry() conversions, and
enforce filesize limit in read_swap_header(), just as for ptes.
Signed-off-by: Hugh Dickins <hughd@google.com>
Acked-by: Rik van Riel <riel@redhat.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2011-08-04 07:21:19 +08:00
|
|
|
if (radix_tree_exception(page)) {
|
2011-08-04 07:21:28 +08:00
|
|
|
if (radix_tree_deref_retry(page)) {
|
|
|
|
/*
|
|
|
|
* Transient condition which can only trigger
|
|
|
|
* when entry at index 0 moves out of or back
|
|
|
|
* to root: none yet gotten, safe to restart.
|
|
|
|
*/
|
|
|
|
goto restart;
|
|
|
|
}
|
mm: let swap use exceptional entries
If swap entries are to be stored along with struct page pointers in a
radix tree, they need to be distinguished as exceptional entries.
Most of the handling of swap entries in radix tree will be contained in
shmem.c, but a few functions in filemap.c's common code need to check
for their appearance: find_get_page(), find_lock_page(),
find_get_pages() and find_get_pages_contig().
So as not to slow their fast paths, tuck those checks inside the
existing checks for unlikely radix_tree_deref_slot(); except for
find_lock_page(), where it is an added test. And make it a BUG in
find_get_pages_tag(), which is not applied to tmpfs files.
A part of the reason for eliminating shmem_readpage() earlier, was to
minimize the places where common code would need to allow for swap
entries.
The swp_entry_t known to swapfile.c must be massaged into a slightly
different form when stored in the radix tree, just as it gets massaged
into a pte_t when stored in page tables.
In an i386 kernel this limits its information (type and page offset) to
30 bits: given 32 "types" of swapfile and 4kB pagesize, that's a maximum
swapfile size of 128GB. Which is less than the 512GB we previously
allowed with X86_PAE (where the swap entry can occupy the entire upper
32 bits of a pte_t), but not a new limitation on 32-bit without PAE; and
there's not a new limitation on 64-bit (where swap filesize is already
limited to 16TB by a 32-bit page offset). Thirty areas of 128GB is
probably still enough swap for a 64GB 32-bit machine.
Provide swp_to_radix_entry() and radix_to_swp_entry() conversions, and
enforce filesize limit in read_swap_header(), just as for ptes.
Signed-off-by: Hugh Dickins <hughd@google.com>
Acked-by: Rik van Riel <riel@redhat.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2011-08-04 07:21:19 +08:00
|
|
|
/*
|
2014-05-07 03:50:05 +08:00
|
|
|
* A shadow entry of a recently evicted page,
|
|
|
|
* or a swap entry from shmem/tmpfs. Stop
|
|
|
|
* looking for contiguous pages.
|
mm: let swap use exceptional entries
If swap entries are to be stored along with struct page pointers in a
radix tree, they need to be distinguished as exceptional entries.
Most of the handling of swap entries in radix tree will be contained in
shmem.c, but a few functions in filemap.c's common code need to check
for their appearance: find_get_page(), find_lock_page(),
find_get_pages() and find_get_pages_contig().
So as not to slow their fast paths, tuck those checks inside the
existing checks for unlikely radix_tree_deref_slot(); except for
find_lock_page(), where it is an added test. And make it a BUG in
find_get_pages_tag(), which is not applied to tmpfs files.
A part of the reason for eliminating shmem_readpage() earlier, was to
minimize the places where common code would need to allow for swap
entries.
The swp_entry_t known to swapfile.c must be massaged into a slightly
different form when stored in the radix tree, just as it gets massaged
into a pte_t when stored in page tables.
In an i386 kernel this limits its information (type and page offset) to
30 bits: given 32 "types" of swapfile and 4kB pagesize, that's a maximum
swapfile size of 128GB. Which is less than the 512GB we previously
allowed with X86_PAE (where the swap entry can occupy the entire upper
32 bits of a pte_t), but not a new limitation on 32-bit without PAE; and
there's not a new limitation on 64-bit (where swap filesize is already
limited to 16TB by a 32-bit page offset). Thirty areas of 128GB is
probably still enough swap for a 64GB 32-bit machine.
Provide swp_to_radix_entry() and radix_to_swp_entry() conversions, and
enforce filesize limit in read_swap_header(), just as for ptes.
Signed-off-by: Hugh Dickins <hughd@google.com>
Acked-by: Rik van Riel <riel@redhat.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2011-08-04 07:21:19 +08:00
|
|
|
*/
|
2011-08-04 07:21:28 +08:00
|
|
|
break;
|
mm: let swap use exceptional entries
If swap entries are to be stored along with struct page pointers in a
radix tree, they need to be distinguished as exceptional entries.
Most of the handling of swap entries in radix tree will be contained in
shmem.c, but a few functions in filemap.c's common code need to check
for their appearance: find_get_page(), find_lock_page(),
find_get_pages() and find_get_pages_contig().
So as not to slow their fast paths, tuck those checks inside the
existing checks for unlikely radix_tree_deref_slot(); except for
find_lock_page(), where it is an added test. And make it a BUG in
find_get_pages_tag(), which is not applied to tmpfs files.
A part of the reason for eliminating shmem_readpage() earlier, was to
minimize the places where common code would need to allow for swap
entries.
The swp_entry_t known to swapfile.c must be massaged into a slightly
different form when stored in the radix tree, just as it gets massaged
into a pte_t when stored in page tables.
In an i386 kernel this limits its information (type and page offset) to
30 bits: given 32 "types" of swapfile and 4kB pagesize, that's a maximum
swapfile size of 128GB. Which is less than the 512GB we previously
allowed with X86_PAE (where the swap entry can occupy the entire upper
32 bits of a pte_t), but not a new limitation on 32-bit without PAE; and
there's not a new limitation on 64-bit (where swap filesize is already
limited to 16TB by a 32-bit page offset). Thirty areas of 128GB is
probably still enough swap for a 64GB 32-bit machine.
Provide swp_to_radix_entry() and radix_to_swp_entry() conversions, and
enforce filesize limit in read_swap_header(), just as for ptes.
Signed-off-by: Hugh Dickins <hughd@google.com>
Acked-by: Rik van Riel <riel@redhat.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2011-08-04 07:21:19 +08:00
|
|
|
}
|
2006-04-27 14:46:01 +08:00
|
|
|
|
2008-07-26 10:45:31 +08:00
|
|
|
if (!page_cache_get_speculative(page))
|
|
|
|
goto repeat;
|
|
|
|
|
|
|
|
/* Has the page moved? */
|
2012-03-29 05:42:54 +08:00
|
|
|
if (unlikely(page != *slot)) {
|
2008-07-26 10:45:31 +08:00
|
|
|
page_cache_release(page);
|
|
|
|
goto repeat;
|
|
|
|
}
|
|
|
|
|
2011-01-14 07:45:51 +08:00
|
|
|
/*
|
|
|
|
* must check mapping and index after taking the ref.
|
|
|
|
* otherwise we can get both false positives and false
|
|
|
|
* negatives, which is just confusing to the caller.
|
|
|
|
*/
|
2012-03-29 05:42:54 +08:00
|
|
|
if (page->mapping == NULL || page->index != iter.index) {
|
2011-01-14 07:45:51 +08:00
|
|
|
page_cache_release(page);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2008-07-26 10:45:31 +08:00
|
|
|
pages[ret] = page;
|
2012-03-29 05:42:54 +08:00
|
|
|
if (++ret == nr_pages)
|
|
|
|
break;
|
2006-04-27 14:46:01 +08:00
|
|
|
}
|
2008-07-26 10:45:31 +08:00
|
|
|
rcu_read_unlock();
|
|
|
|
return ret;
|
2006-04-27 14:46:01 +08:00
|
|
|
}
|
2007-05-09 17:33:44 +08:00
|
|
|
EXPORT_SYMBOL(find_get_pages_contig);
|
2006-04-27 14:46:01 +08:00
|
|
|
|
2006-06-23 17:03:49 +08:00
|
|
|
/**
|
|
|
|
* find_get_pages_tag - find and return pages that match @tag
|
|
|
|
* @mapping: the address_space to search
|
|
|
|
* @index: the starting page index
|
|
|
|
* @tag: the tag index
|
|
|
|
* @nr_pages: the maximum number of pages
|
|
|
|
* @pages: where the resulting pages are placed
|
|
|
|
*
|
2005-04-17 06:20:36 +08:00
|
|
|
* Like find_get_pages, except we only return pages which are tagged with
|
2006-06-23 17:03:49 +08:00
|
|
|
* @tag. We update @index to index the next page for the traversal.
|
2005-04-17 06:20:36 +08:00
|
|
|
*/
|
|
|
|
unsigned find_get_pages_tag(struct address_space *mapping, pgoff_t *index,
|
|
|
|
int tag, unsigned int nr_pages, struct page **pages)
|
|
|
|
{
|
2012-03-29 05:42:54 +08:00
|
|
|
struct radix_tree_iter iter;
|
|
|
|
void **slot;
|
|
|
|
unsigned ret = 0;
|
|
|
|
|
|
|
|
if (unlikely(!nr_pages))
|
|
|
|
return 0;
|
2008-07-26 10:45:31 +08:00
|
|
|
|
|
|
|
rcu_read_lock();
|
|
|
|
restart:
|
2012-03-29 05:42:54 +08:00
|
|
|
radix_tree_for_each_tagged(slot, &mapping->page_tree,
|
|
|
|
&iter, *index, tag) {
|
2008-07-26 10:45:31 +08:00
|
|
|
struct page *page;
|
|
|
|
repeat:
|
2012-03-29 05:42:54 +08:00
|
|
|
page = radix_tree_deref_slot(slot);
|
2008-07-26 10:45:31 +08:00
|
|
|
if (unlikely(!page))
|
|
|
|
continue;
|
2011-03-23 07:33:06 +08:00
|
|
|
|
mm: let swap use exceptional entries
If swap entries are to be stored along with struct page pointers in a
radix tree, they need to be distinguished as exceptional entries.
Most of the handling of swap entries in radix tree will be contained in
shmem.c, but a few functions in filemap.c's common code need to check
for their appearance: find_get_page(), find_lock_page(),
find_get_pages() and find_get_pages_contig().
So as not to slow their fast paths, tuck those checks inside the
existing checks for unlikely radix_tree_deref_slot(); except for
find_lock_page(), where it is an added test. And make it a BUG in
find_get_pages_tag(), which is not applied to tmpfs files.
A part of the reason for eliminating shmem_readpage() earlier, was to
minimize the places where common code would need to allow for swap
entries.
The swp_entry_t known to swapfile.c must be massaged into a slightly
different form when stored in the radix tree, just as it gets massaged
into a pte_t when stored in page tables.
In an i386 kernel this limits its information (type and page offset) to
30 bits: given 32 "types" of swapfile and 4kB pagesize, that's a maximum
swapfile size of 128GB. Which is less than the 512GB we previously
allowed with X86_PAE (where the swap entry can occupy the entire upper
32 bits of a pte_t), but not a new limitation on 32-bit without PAE; and
there's not a new limitation on 64-bit (where swap filesize is already
limited to 16TB by a 32-bit page offset). Thirty areas of 128GB is
probably still enough swap for a 64GB 32-bit machine.
Provide swp_to_radix_entry() and radix_to_swp_entry() conversions, and
enforce filesize limit in read_swap_header(), just as for ptes.
Signed-off-by: Hugh Dickins <hughd@google.com>
Acked-by: Rik van Riel <riel@redhat.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2011-08-04 07:21:19 +08:00
|
|
|
if (radix_tree_exception(page)) {
|
2011-08-04 07:21:28 +08:00
|
|
|
if (radix_tree_deref_retry(page)) {
|
|
|
|
/*
|
|
|
|
* Transient condition which can only trigger
|
|
|
|
* when entry at index 0 moves out of or back
|
|
|
|
* to root: none yet gotten, safe to restart.
|
|
|
|
*/
|
|
|
|
goto restart;
|
|
|
|
}
|
mm: let swap use exceptional entries
If swap entries are to be stored along with struct page pointers in a
radix tree, they need to be distinguished as exceptional entries.
Most of the handling of swap entries in radix tree will be contained in
shmem.c, but a few functions in filemap.c's common code need to check
for their appearance: find_get_page(), find_lock_page(),
find_get_pages() and find_get_pages_contig().
So as not to slow their fast paths, tuck those checks inside the
existing checks for unlikely radix_tree_deref_slot(); except for
find_lock_page(), where it is an added test. And make it a BUG in
find_get_pages_tag(), which is not applied to tmpfs files.
A part of the reason for eliminating shmem_readpage() earlier, was to
minimize the places where common code would need to allow for swap
entries.
The swp_entry_t known to swapfile.c must be massaged into a slightly
different form when stored in the radix tree, just as it gets massaged
into a pte_t when stored in page tables.
In an i386 kernel this limits its information (type and page offset) to
30 bits: given 32 "types" of swapfile and 4kB pagesize, that's a maximum
swapfile size of 128GB. Which is less than the 512GB we previously
allowed with X86_PAE (where the swap entry can occupy the entire upper
32 bits of a pte_t), but not a new limitation on 32-bit without PAE; and
there's not a new limitation on 64-bit (where swap filesize is already
limited to 16TB by a 32-bit page offset). Thirty areas of 128GB is
probably still enough swap for a 64GB 32-bit machine.
Provide swp_to_radix_entry() and radix_to_swp_entry() conversions, and
enforce filesize limit in read_swap_header(), just as for ptes.
Signed-off-by: Hugh Dickins <hughd@google.com>
Acked-by: Rik van Riel <riel@redhat.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2011-08-04 07:21:19 +08:00
|
|
|
/*
|
2014-05-07 03:50:05 +08:00
|
|
|
* A shadow entry of a recently evicted page.
|
|
|
|
*
|
|
|
|
* Those entries should never be tagged, but
|
|
|
|
* this tree walk is lockless and the tags are
|
|
|
|
* looked up in bulk, one radix tree node at a
|
|
|
|
* time, so there is a sizable window for page
|
|
|
|
* reclaim to evict a page we saw tagged.
|
|
|
|
*
|
|
|
|
* Skip over it.
|
mm: let swap use exceptional entries
If swap entries are to be stored along with struct page pointers in a
radix tree, they need to be distinguished as exceptional entries.
Most of the handling of swap entries in radix tree will be contained in
shmem.c, but a few functions in filemap.c's common code need to check
for their appearance: find_get_page(), find_lock_page(),
find_get_pages() and find_get_pages_contig().
So as not to slow their fast paths, tuck those checks inside the
existing checks for unlikely radix_tree_deref_slot(); except for
find_lock_page(), where it is an added test. And make it a BUG in
find_get_pages_tag(), which is not applied to tmpfs files.
A part of the reason for eliminating shmem_readpage() earlier, was to
minimize the places where common code would need to allow for swap
entries.
The swp_entry_t known to swapfile.c must be massaged into a slightly
different form when stored in the radix tree, just as it gets massaged
into a pte_t when stored in page tables.
In an i386 kernel this limits its information (type and page offset) to
30 bits: given 32 "types" of swapfile and 4kB pagesize, that's a maximum
swapfile size of 128GB. Which is less than the 512GB we previously
allowed with X86_PAE (where the swap entry can occupy the entire upper
32 bits of a pte_t), but not a new limitation on 32-bit without PAE; and
there's not a new limitation on 64-bit (where swap filesize is already
limited to 16TB by a 32-bit page offset). Thirty areas of 128GB is
probably still enough swap for a 64GB 32-bit machine.
Provide swp_to_radix_entry() and radix_to_swp_entry() conversions, and
enforce filesize limit in read_swap_header(), just as for ptes.
Signed-off-by: Hugh Dickins <hughd@google.com>
Acked-by: Rik van Riel <riel@redhat.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2011-08-04 07:21:19 +08:00
|
|
|
*/
|
2014-05-07 03:50:05 +08:00
|
|
|
continue;
|
mm: let swap use exceptional entries
If swap entries are to be stored along with struct page pointers in a
radix tree, they need to be distinguished as exceptional entries.
Most of the handling of swap entries in radix tree will be contained in
shmem.c, but a few functions in filemap.c's common code need to check
for their appearance: find_get_page(), find_lock_page(),
find_get_pages() and find_get_pages_contig().
So as not to slow their fast paths, tuck those checks inside the
existing checks for unlikely radix_tree_deref_slot(); except for
find_lock_page(), where it is an added test. And make it a BUG in
find_get_pages_tag(), which is not applied to tmpfs files.
A part of the reason for eliminating shmem_readpage() earlier, was to
minimize the places where common code would need to allow for swap
entries.
The swp_entry_t known to swapfile.c must be massaged into a slightly
different form when stored in the radix tree, just as it gets massaged
into a pte_t when stored in page tables.
In an i386 kernel this limits its information (type and page offset) to
30 bits: given 32 "types" of swapfile and 4kB pagesize, that's a maximum
swapfile size of 128GB. Which is less than the 512GB we previously
allowed with X86_PAE (where the swap entry can occupy the entire upper
32 bits of a pte_t), but not a new limitation on 32-bit without PAE; and
there's not a new limitation on 64-bit (where swap filesize is already
limited to 16TB by a 32-bit page offset). Thirty areas of 128GB is
probably still enough swap for a 64GB 32-bit machine.
Provide swp_to_radix_entry() and radix_to_swp_entry() conversions, and
enforce filesize limit in read_swap_header(), just as for ptes.
Signed-off-by: Hugh Dickins <hughd@google.com>
Acked-by: Rik van Riel <riel@redhat.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2011-08-04 07:21:19 +08:00
|
|
|
}
|
2008-07-26 10:45:31 +08:00
|
|
|
|
|
|
|
if (!page_cache_get_speculative(page))
|
|
|
|
goto repeat;
|
|
|
|
|
|
|
|
/* Has the page moved? */
|
2012-03-29 05:42:54 +08:00
|
|
|
if (unlikely(page != *slot)) {
|
2008-07-26 10:45:31 +08:00
|
|
|
page_cache_release(page);
|
|
|
|
goto repeat;
|
|
|
|
}
|
|
|
|
|
|
|
|
pages[ret] = page;
|
2012-03-29 05:42:54 +08:00
|
|
|
if (++ret == nr_pages)
|
|
|
|
break;
|
2008-07-26 10:45:31 +08:00
|
|
|
}
|
2011-03-23 07:33:07 +08:00
|
|
|
|
2008-07-26 10:45:31 +08:00
|
|
|
rcu_read_unlock();
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
if (ret)
|
|
|
|
*index = pages[ret - 1]->index + 1;
|
2008-07-26 10:45:31 +08:00
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
return ret;
|
|
|
|
}
|
2007-05-09 17:33:44 +08:00
|
|
|
EXPORT_SYMBOL(find_get_pages_tag);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2016-01-23 07:10:44 +08:00
|
|
|
/**
|
|
|
|
* find_get_entries_tag - find and return entries that match @tag
|
|
|
|
* @mapping: the address_space to search
|
|
|
|
* @start: the starting page cache index
|
|
|
|
* @tag: the tag index
|
|
|
|
* @nr_entries: the maximum number of entries
|
|
|
|
* @entries: where the resulting entries are placed
|
|
|
|
* @indices: the cache indices corresponding to the entries in @entries
|
|
|
|
*
|
|
|
|
* Like find_get_entries, except we only return entries which are tagged with
|
|
|
|
* @tag.
|
|
|
|
*/
|
|
|
|
unsigned find_get_entries_tag(struct address_space *mapping, pgoff_t start,
|
|
|
|
int tag, unsigned int nr_entries,
|
|
|
|
struct page **entries, pgoff_t *indices)
|
|
|
|
{
|
|
|
|
void **slot;
|
|
|
|
unsigned int ret = 0;
|
|
|
|
struct radix_tree_iter iter;
|
|
|
|
|
|
|
|
if (!nr_entries)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
rcu_read_lock();
|
|
|
|
restart:
|
|
|
|
radix_tree_for_each_tagged(slot, &mapping->page_tree,
|
|
|
|
&iter, start, tag) {
|
|
|
|
struct page *page;
|
|
|
|
repeat:
|
|
|
|
page = radix_tree_deref_slot(slot);
|
|
|
|
if (unlikely(!page))
|
|
|
|
continue;
|
|
|
|
if (radix_tree_exception(page)) {
|
|
|
|
if (radix_tree_deref_retry(page)) {
|
|
|
|
/*
|
|
|
|
* Transient condition which can only trigger
|
|
|
|
* when entry at index 0 moves out of or back
|
|
|
|
* to root: none yet gotten, safe to restart.
|
|
|
|
*/
|
|
|
|
goto restart;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* A shadow entry of a recently evicted page, a swap
|
|
|
|
* entry from shmem/tmpfs or a DAX entry. Return it
|
|
|
|
* without attempting to raise page count.
|
|
|
|
*/
|
|
|
|
goto export;
|
|
|
|
}
|
|
|
|
if (!page_cache_get_speculative(page))
|
|
|
|
goto repeat;
|
|
|
|
|
|
|
|
/* Has the page moved? */
|
|
|
|
if (unlikely(page != *slot)) {
|
|
|
|
page_cache_release(page);
|
|
|
|
goto repeat;
|
|
|
|
}
|
|
|
|
export:
|
|
|
|
indices[ret] = iter.index;
|
|
|
|
entries[ret] = page;
|
|
|
|
if (++ret == nr_entries)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
rcu_read_unlock();
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(find_get_entries_tag);
|
|
|
|
|
[PATCH] readahead: backoff on I/O error
Backoff readahead size exponentially on I/O error.
Michael Tokarev <mjt@tls.msk.ru> described the problem as:
[QUOTE]
Suppose there's a CD-rom with a scratch/etc, one sector is unreadable.
In order to "fix" it, one have to read it and write to another CD-rom,
or something.. or just ignore the error (if it's just a skip in a video
stream). Let's assume the unreadable block is number U.
But current behavior is just insane. An application requests block
number N, which is before U. Kernel tries to read-ahead blocks N..U.
Cdrom drive tries to read it, re-read it.. for some time. Finally,
when all the N..U-1 blocks are read, kernel returns block number N
(as requested) to an application, successefully.
Now an app requests block number N+1, and kernel tries to read
blocks N+1..U+1. Retrying again as in previous step.
And so on, up to when an app requests block number U-1. And when,
finally, it requests block U, it receives read error.
So, kernel currentry tries to re-read the same failing block as
many times as the current readahead value (256 (times?) by default).
This whole process already killed my cdrom drive (I posted about it
to LKML several months ago) - literally, the drive has fried, and
does not work anymore. Ofcourse that problem was a bug in firmware
(or whatever) of the drive *too*, but.. main problem with that is
current readahead logic as described above.
[/QUOTE]
Which was confirmed by Jens Axboe <axboe@suse.de>:
[QUOTE]
For ide-cd, it tends do only end the first part of the request on a
medium error. So you may see a lot of repeats :/
[/QUOTE]
With this patch, retries are expected to be reduced from, say, 256, to 5.
[akpm@osdl.org: cleanups]
Signed-off-by: Wu Fengguang <wfg@mail.ustc.edu.cn>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
2006-06-25 20:48:43 +08:00
|
|
|
/*
|
|
|
|
* CD/DVDs are error prone. When a medium error occurs, the driver may fail
|
|
|
|
* a _large_ part of the i/o request. Imagine the worst scenario:
|
|
|
|
*
|
|
|
|
* ---R__________________________________________B__________
|
|
|
|
* ^ reading here ^ bad block(assume 4k)
|
|
|
|
*
|
|
|
|
* read(R) => miss => readahead(R...B) => media error => frustrating retries
|
|
|
|
* => failing the whole request => read(R) => read(R+1) =>
|
|
|
|
* readahead(R+1...B+1) => bang => read(R+2) => read(R+3) =>
|
|
|
|
* readahead(R+3...B+2) => bang => read(R+3) => read(R+4) =>
|
|
|
|
* readahead(R+4...B+3) => bang => read(R+4) => read(R+5) => ......
|
|
|
|
*
|
|
|
|
* It is going insane. Fix it by quickly scaling down the readahead size.
|
|
|
|
*/
|
|
|
|
static void shrink_readahead_size_eio(struct file *filp,
|
|
|
|
struct file_ra_state *ra)
|
|
|
|
{
|
|
|
|
ra->ra_pages /= 4;
|
|
|
|
}
|
|
|
|
|
2006-06-23 17:03:49 +08:00
|
|
|
/**
|
2008-02-08 20:21:24 +08:00
|
|
|
* do_generic_file_read - generic file read routine
|
2006-06-23 17:03:49 +08:00
|
|
|
* @filp: the file to read
|
|
|
|
* @ppos: current file position
|
2014-02-04 06:07:03 +08:00
|
|
|
* @iter: data destination
|
|
|
|
* @written: already copied
|
2006-06-23 17:03:49 +08:00
|
|
|
*
|
2005-04-17 06:20:36 +08:00
|
|
|
* This is a generic file read routine, and uses the
|
2006-06-23 17:03:49 +08:00
|
|
|
* mapping->a_ops->readpage() function for the actual low-level stuff.
|
2005-04-17 06:20:36 +08:00
|
|
|
*
|
|
|
|
* This is really ugly. But the goto's actually try to clarify some
|
|
|
|
* of the logic when it comes to error handling etc.
|
|
|
|
*/
|
2014-02-04 06:07:03 +08:00
|
|
|
static ssize_t do_generic_file_read(struct file *filp, loff_t *ppos,
|
|
|
|
struct iov_iter *iter, ssize_t written)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2008-02-08 20:21:24 +08:00
|
|
|
struct address_space *mapping = filp->f_mapping;
|
2005-04-17 06:20:36 +08:00
|
|
|
struct inode *inode = mapping->host;
|
2008-02-08 20:21:24 +08:00
|
|
|
struct file_ra_state *ra = &filp->f_ra;
|
2007-10-16 16:24:37 +08:00
|
|
|
pgoff_t index;
|
|
|
|
pgoff_t last_index;
|
|
|
|
pgoff_t prev_index;
|
|
|
|
unsigned long offset; /* offset into pagecache page */
|
2007-05-07 05:49:25 +08:00
|
|
|
unsigned int prev_offset;
|
2014-02-04 06:07:03 +08:00
|
|
|
int error = 0;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
index = *ppos >> PAGE_CACHE_SHIFT;
|
2007-10-16 16:24:35 +08:00
|
|
|
prev_index = ra->prev_pos >> PAGE_CACHE_SHIFT;
|
|
|
|
prev_offset = ra->prev_pos & (PAGE_CACHE_SIZE-1);
|
2014-02-04 06:07:03 +08:00
|
|
|
last_index = (*ppos + iter->count + PAGE_CACHE_SIZE-1) >> PAGE_CACHE_SHIFT;
|
2005-04-17 06:20:36 +08:00
|
|
|
offset = *ppos & ~PAGE_CACHE_MASK;
|
|
|
|
|
|
|
|
for (;;) {
|
|
|
|
struct page *page;
|
2007-10-16 16:24:37 +08:00
|
|
|
pgoff_t end_index;
|
2007-07-17 19:03:04 +08:00
|
|
|
loff_t isize;
|
2005-04-17 06:20:36 +08:00
|
|
|
unsigned long nr, ret;
|
|
|
|
|
|
|
|
cond_resched();
|
|
|
|
find_page:
|
|
|
|
page = find_get_page(mapping, index);
|
2007-07-19 16:48:02 +08:00
|
|
|
if (!page) {
|
2007-07-19 16:48:08 +08:00
|
|
|
page_cache_sync_readahead(mapping,
|
2007-10-16 16:24:35 +08:00
|
|
|
ra, filp,
|
2007-07-19 16:48:02 +08:00
|
|
|
index, last_index - index);
|
|
|
|
page = find_get_page(mapping, index);
|
|
|
|
if (unlikely(page == NULL))
|
|
|
|
goto no_cached_page;
|
|
|
|
}
|
|
|
|
if (PageReadahead(page)) {
|
2007-07-19 16:48:08 +08:00
|
|
|
page_cache_async_readahead(mapping,
|
2007-10-16 16:24:35 +08:00
|
|
|
ra, filp, page,
|
2007-07-19 16:48:02 +08:00
|
|
|
index, last_index - index);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
vfs: pagecache usage optimization for pagesize!=blocksize
When we read some part of a file through pagecache, if there is a
pagecache of corresponding index but this page is not uptodate, read IO
is issued and this page will be uptodate.
I think this is good for pagesize == blocksize environment but there is
room for improvement on pagesize != blocksize environment. Because in
this case a page can have multiple buffers and even if a page is not
uptodate, some buffers can be uptodate.
So I suggest that when all buffers which correspond to a part of a file
that we want to read are uptodate, use this pagecache and copy data from
this pagecache to user buffer even if a page is not uptodate. This can
reduce read IO and improve system throughput.
I wrote a benchmark program and got result number with this program.
This benchmark do:
1: mount and open a test file.
2: create a 512MB file.
3: close a file and umount.
4: mount and again open a test file.
5: pwrite randomly 300000 times on a test file. offset is aligned
by IO size(1024bytes).
6: measure time of preading randomly 100000 times on a test file.
The result was:
2.6.26
330 sec
2.6.26-patched
226 sec
Arch:i386
Filesystem:ext3
Blocksize:1024 bytes
Memory: 1GB
On ext3/4, a file is written through buffer/block. So random read/write
mixed workloads or random read after random write workloads are optimized
with this patch under pagesize != blocksize environment. This test result
showed this.
The benchmark program is as follows:
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <time.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mount.h>
#define LEN 1024
#define LOOP 1024*512 /* 512MB */
main(void)
{
unsigned long i, offset, filesize;
int fd;
char buf[LEN];
time_t t1, t2;
if (mount("/dev/sda1", "/root/test1/", "ext3", 0, 0) < 0) {
perror("cannot mount\n");
exit(1);
}
memset(buf, 0, LEN);
fd = open("/root/test1/testfile", O_CREAT|O_RDWR|O_TRUNC);
if (fd < 0) {
perror("cannot open file\n");
exit(1);
}
for (i = 0; i < LOOP; i++)
write(fd, buf, LEN);
close(fd);
if (umount("/root/test1/") < 0) {
perror("cannot umount\n");
exit(1);
}
if (mount("/dev/sda1", "/root/test1/", "ext3", 0, 0) < 0) {
perror("cannot mount\n");
exit(1);
}
fd = open("/root/test1/testfile", O_RDWR);
if (fd < 0) {
perror("cannot open file\n");
exit(1);
}
filesize = LEN * LOOP;
for (i = 0; i < 300000; i++){
offset = (random() % filesize) & (~(LEN - 1));
pwrite(fd, buf, LEN, offset);
}
printf("start test\n");
time(&t1);
for (i = 0; i < 100000; i++){
offset = (random() % filesize) & (~(LEN - 1));
pread(fd, buf, LEN, offset);
}
time(&t2);
printf("%ld sec\n", t2-t1);
close(fd);
if (umount("/root/test1/") < 0) {
perror("cannot umount\n");
exit(1);
}
}
Signed-off-by: Hisashi Hifumi <hifumi.hisashi@oss.ntt.co.jp>
Cc: Nick Piggin <nickpiggin@yahoo.com.au>
Cc: Christoph Hellwig <hch@infradead.org>
Cc: Jan Kara <jack@ucw.cz>
Cc: <linux-ext4@vger.kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2008-07-29 06:46:36 +08:00
|
|
|
if (!PageUptodate(page)) {
|
|
|
|
if (inode->i_blkbits == PAGE_CACHE_SHIFT ||
|
|
|
|
!mapping->a_ops->is_partially_uptodate)
|
|
|
|
goto page_not_up_to_date;
|
2008-08-02 18:01:03 +08:00
|
|
|
if (!trylock_page(page))
|
vfs: pagecache usage optimization for pagesize!=blocksize
When we read some part of a file through pagecache, if there is a
pagecache of corresponding index but this page is not uptodate, read IO
is issued and this page will be uptodate.
I think this is good for pagesize == blocksize environment but there is
room for improvement on pagesize != blocksize environment. Because in
this case a page can have multiple buffers and even if a page is not
uptodate, some buffers can be uptodate.
So I suggest that when all buffers which correspond to a part of a file
that we want to read are uptodate, use this pagecache and copy data from
this pagecache to user buffer even if a page is not uptodate. This can
reduce read IO and improve system throughput.
I wrote a benchmark program and got result number with this program.
This benchmark do:
1: mount and open a test file.
2: create a 512MB file.
3: close a file and umount.
4: mount and again open a test file.
5: pwrite randomly 300000 times on a test file. offset is aligned
by IO size(1024bytes).
6: measure time of preading randomly 100000 times on a test file.
The result was:
2.6.26
330 sec
2.6.26-patched
226 sec
Arch:i386
Filesystem:ext3
Blocksize:1024 bytes
Memory: 1GB
On ext3/4, a file is written through buffer/block. So random read/write
mixed workloads or random read after random write workloads are optimized
with this patch under pagesize != blocksize environment. This test result
showed this.
The benchmark program is as follows:
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <time.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mount.h>
#define LEN 1024
#define LOOP 1024*512 /* 512MB */
main(void)
{
unsigned long i, offset, filesize;
int fd;
char buf[LEN];
time_t t1, t2;
if (mount("/dev/sda1", "/root/test1/", "ext3", 0, 0) < 0) {
perror("cannot mount\n");
exit(1);
}
memset(buf, 0, LEN);
fd = open("/root/test1/testfile", O_CREAT|O_RDWR|O_TRUNC);
if (fd < 0) {
perror("cannot open file\n");
exit(1);
}
for (i = 0; i < LOOP; i++)
write(fd, buf, LEN);
close(fd);
if (umount("/root/test1/") < 0) {
perror("cannot umount\n");
exit(1);
}
if (mount("/dev/sda1", "/root/test1/", "ext3", 0, 0) < 0) {
perror("cannot mount\n");
exit(1);
}
fd = open("/root/test1/testfile", O_RDWR);
if (fd < 0) {
perror("cannot open file\n");
exit(1);
}
filesize = LEN * LOOP;
for (i = 0; i < 300000; i++){
offset = (random() % filesize) & (~(LEN - 1));
pwrite(fd, buf, LEN, offset);
}
printf("start test\n");
time(&t1);
for (i = 0; i < 100000; i++){
offset = (random() % filesize) & (~(LEN - 1));
pread(fd, buf, LEN, offset);
}
time(&t2);
printf("%ld sec\n", t2-t1);
close(fd);
if (umount("/root/test1/") < 0) {
perror("cannot umount\n");
exit(1);
}
}
Signed-off-by: Hisashi Hifumi <hifumi.hisashi@oss.ntt.co.jp>
Cc: Nick Piggin <nickpiggin@yahoo.com.au>
Cc: Christoph Hellwig <hch@infradead.org>
Cc: Jan Kara <jack@ucw.cz>
Cc: <linux-ext4@vger.kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2008-07-29 06:46:36 +08:00
|
|
|
goto page_not_up_to_date;
|
mm/vfs: revalidate page->mapping in do_generic_file_read()
70 hours into some stress tests of a 2.6.32-based enterprise kernel, we
ran into a NULL dereference in here:
int block_is_partially_uptodate(struct page *page, read_descriptor_t *desc,
unsigned long from)
{
----> struct inode *inode = page->mapping->host;
It looks like page->mapping was the culprit. (xmon trace is below).
After closer examination, I realized that do_generic_file_read() does a
find_get_page(), and eventually locks the page before calling
block_is_partially_uptodate(). However, it doesn't revalidate the
page->mapping after the page is locked. So, there's a small window
between the find_get_page() and ->is_partially_uptodate() where the page
could get truncated and page->mapping cleared.
We _have_ a reference, so it can't get reclaimed, but it certainly
can be truncated.
I think the correct thing is to check page->mapping after the
trylock_page(), and jump out if it got truncated. This patch has been
running in the test environment for a month or so now, and we have not
seen this bug pop up again.
xmon info:
1f:mon> e
cpu 0x1f: Vector: 300 (Data Access) at [c0000002ae36f770]
pc: c0000000001e7a6c: .block_is_partially_uptodate+0xc/0x100
lr: c000000000142944: .generic_file_aio_read+0x1e4/0x770
sp: c0000002ae36f9f0
msr: 8000000000009032
dar: 0
dsisr: 40000000
current = 0xc000000378f99e30
paca = 0xc000000000f66300
pid = 21946, comm = bash
1f:mon> r
R00 = 0025c0500000006d R16 = 0000000000000000
R01 = c0000002ae36f9f0 R17 = c000000362cd3af0
R02 = c000000000e8cd80 R18 = ffffffffffffffff
R03 = c0000000031d0f88 R19 = 0000000000000001
R04 = c0000002ae36fa68 R20 = c0000003bb97b8a0
R05 = 0000000000000000 R21 = c0000002ae36fa68
R06 = 0000000000000000 R22 = 0000000000000000
R07 = 0000000000000001 R23 = c0000002ae36fbb0
R08 = 0000000000000002 R24 = 0000000000000000
R09 = 0000000000000000 R25 = c000000362cd3a80
R10 = 0000000000000000 R26 = 0000000000000002
R11 = c0000000001e7b60 R27 = 0000000000000000
R12 = 0000000042000484 R28 = 0000000000000001
R13 = c000000000f66300 R29 = c0000003bb97b9b8
R14 = 0000000000000001 R30 = c000000000e28a08
R15 = 000000000000ffff R31 = c0000000031d0f88
pc = c0000000001e7a6c .block_is_partially_uptodate+0xc/0x100
lr = c000000000142944 .generic_file_aio_read+0x1e4/0x770
msr = 8000000000009032 cr = 22000488
ctr = c0000000001e7a60 xer = 0000000020000000 trap = 300
dar = 0000000000000000 dsisr = 40000000
1f:mon> t
[link register ] c000000000142944 .generic_file_aio_read+0x1e4/0x770
[c0000002ae36f9f0] c000000000142a14 .generic_file_aio_read+0x2b4/0x770 (unreliable)
[c0000002ae36fb40] c0000000001b03e4 .do_sync_read+0xd4/0x160
[c0000002ae36fce0] c0000000001b153c .vfs_read+0xec/0x1f0
[c0000002ae36fd80] c0000000001b1768 .SyS_read+0x58/0xb0
[c0000002ae36fe30] c00000000000852c syscall_exit+0x0/0x40
--- Exception: c00 (System Call) at 00000080a840bc54
SP (fffca15df30) is in userspace
1f:mon> di c0000000001e7a6c
c0000000001e7a6c e9290000 ld r9,0(r9)
c0000000001e7a70 418200c0 beq c0000000001e7b30 # .block_is_partially_uptodate+0xd0/0x100
c0000000001e7a74 e9440008 ld r10,8(r4)
c0000000001e7a78 78a80020 clrldi r8,r5,32
c0000000001e7a7c 3c000001 lis r0,1
c0000000001e7a80 812900a8 lwz r9,168(r9)
c0000000001e7a84 39600001 li r11,1
c0000000001e7a88 7c080050 subf r0,r8,r0
c0000000001e7a8c 7f805040 cmplw cr7,r0,r10
c0000000001e7a90 7d6b4830 slw r11,r11,r9
c0000000001e7a94 796b0020 clrldi r11,r11,32
c0000000001e7a98 419d00a8 bgt cr7,c0000000001e7b40 # .block_is_partially_uptodate+0xe0/0x100
c0000000001e7a9c 7fa55840 cmpld cr7,r5,r11
c0000000001e7aa0 7d004214 add r8,r0,r8
c0000000001e7aa4 79080020 clrldi r8,r8,32
c0000000001e7aa8 419c0078 blt cr7,c0000000001e7b20 # .block_is_partially_uptodate+0xc0/0x100
Signed-off-by: Dave Hansen <dave@linux.vnet.ibm.com>
Reviewed-by: Minchan Kim <minchan.kim@gmail.com>
Reviewed-by: Johannes Weiner <hannes@cmpxchg.org>
Acked-by: Rik van Riel <riel@redhat.com>
Cc: <arunabal@in.ibm.com>
Cc: <sbest@us.ibm.com>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Cc: Minchan Kim <minchan.kim@gmail.com>
Cc: <stable@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2010-11-12 06:05:15 +08:00
|
|
|
/* Did it get truncated before we got the lock? */
|
|
|
|
if (!page->mapping)
|
|
|
|
goto page_not_up_to_date_locked;
|
vfs: pagecache usage optimization for pagesize!=blocksize
When we read some part of a file through pagecache, if there is a
pagecache of corresponding index but this page is not uptodate, read IO
is issued and this page will be uptodate.
I think this is good for pagesize == blocksize environment but there is
room for improvement on pagesize != blocksize environment. Because in
this case a page can have multiple buffers and even if a page is not
uptodate, some buffers can be uptodate.
So I suggest that when all buffers which correspond to a part of a file
that we want to read are uptodate, use this pagecache and copy data from
this pagecache to user buffer even if a page is not uptodate. This can
reduce read IO and improve system throughput.
I wrote a benchmark program and got result number with this program.
This benchmark do:
1: mount and open a test file.
2: create a 512MB file.
3: close a file and umount.
4: mount and again open a test file.
5: pwrite randomly 300000 times on a test file. offset is aligned
by IO size(1024bytes).
6: measure time of preading randomly 100000 times on a test file.
The result was:
2.6.26
330 sec
2.6.26-patched
226 sec
Arch:i386
Filesystem:ext3
Blocksize:1024 bytes
Memory: 1GB
On ext3/4, a file is written through buffer/block. So random read/write
mixed workloads or random read after random write workloads are optimized
with this patch under pagesize != blocksize environment. This test result
showed this.
The benchmark program is as follows:
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <time.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mount.h>
#define LEN 1024
#define LOOP 1024*512 /* 512MB */
main(void)
{
unsigned long i, offset, filesize;
int fd;
char buf[LEN];
time_t t1, t2;
if (mount("/dev/sda1", "/root/test1/", "ext3", 0, 0) < 0) {
perror("cannot mount\n");
exit(1);
}
memset(buf, 0, LEN);
fd = open("/root/test1/testfile", O_CREAT|O_RDWR|O_TRUNC);
if (fd < 0) {
perror("cannot open file\n");
exit(1);
}
for (i = 0; i < LOOP; i++)
write(fd, buf, LEN);
close(fd);
if (umount("/root/test1/") < 0) {
perror("cannot umount\n");
exit(1);
}
if (mount("/dev/sda1", "/root/test1/", "ext3", 0, 0) < 0) {
perror("cannot mount\n");
exit(1);
}
fd = open("/root/test1/testfile", O_RDWR);
if (fd < 0) {
perror("cannot open file\n");
exit(1);
}
filesize = LEN * LOOP;
for (i = 0; i < 300000; i++){
offset = (random() % filesize) & (~(LEN - 1));
pwrite(fd, buf, LEN, offset);
}
printf("start test\n");
time(&t1);
for (i = 0; i < 100000; i++){
offset = (random() % filesize) & (~(LEN - 1));
pread(fd, buf, LEN, offset);
}
time(&t2);
printf("%ld sec\n", t2-t1);
close(fd);
if (umount("/root/test1/") < 0) {
perror("cannot umount\n");
exit(1);
}
}
Signed-off-by: Hisashi Hifumi <hifumi.hisashi@oss.ntt.co.jp>
Cc: Nick Piggin <nickpiggin@yahoo.com.au>
Cc: Christoph Hellwig <hch@infradead.org>
Cc: Jan Kara <jack@ucw.cz>
Cc: <linux-ext4@vger.kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2008-07-29 06:46:36 +08:00
|
|
|
if (!mapping->a_ops->is_partially_uptodate(page,
|
2014-02-04 06:07:03 +08:00
|
|
|
offset, iter->count))
|
vfs: pagecache usage optimization for pagesize!=blocksize
When we read some part of a file through pagecache, if there is a
pagecache of corresponding index but this page is not uptodate, read IO
is issued and this page will be uptodate.
I think this is good for pagesize == blocksize environment but there is
room for improvement on pagesize != blocksize environment. Because in
this case a page can have multiple buffers and even if a page is not
uptodate, some buffers can be uptodate.
So I suggest that when all buffers which correspond to a part of a file
that we want to read are uptodate, use this pagecache and copy data from
this pagecache to user buffer even if a page is not uptodate. This can
reduce read IO and improve system throughput.
I wrote a benchmark program and got result number with this program.
This benchmark do:
1: mount and open a test file.
2: create a 512MB file.
3: close a file and umount.
4: mount and again open a test file.
5: pwrite randomly 300000 times on a test file. offset is aligned
by IO size(1024bytes).
6: measure time of preading randomly 100000 times on a test file.
The result was:
2.6.26
330 sec
2.6.26-patched
226 sec
Arch:i386
Filesystem:ext3
Blocksize:1024 bytes
Memory: 1GB
On ext3/4, a file is written through buffer/block. So random read/write
mixed workloads or random read after random write workloads are optimized
with this patch under pagesize != blocksize environment. This test result
showed this.
The benchmark program is as follows:
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <time.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mount.h>
#define LEN 1024
#define LOOP 1024*512 /* 512MB */
main(void)
{
unsigned long i, offset, filesize;
int fd;
char buf[LEN];
time_t t1, t2;
if (mount("/dev/sda1", "/root/test1/", "ext3", 0, 0) < 0) {
perror("cannot mount\n");
exit(1);
}
memset(buf, 0, LEN);
fd = open("/root/test1/testfile", O_CREAT|O_RDWR|O_TRUNC);
if (fd < 0) {
perror("cannot open file\n");
exit(1);
}
for (i = 0; i < LOOP; i++)
write(fd, buf, LEN);
close(fd);
if (umount("/root/test1/") < 0) {
perror("cannot umount\n");
exit(1);
}
if (mount("/dev/sda1", "/root/test1/", "ext3", 0, 0) < 0) {
perror("cannot mount\n");
exit(1);
}
fd = open("/root/test1/testfile", O_RDWR);
if (fd < 0) {
perror("cannot open file\n");
exit(1);
}
filesize = LEN * LOOP;
for (i = 0; i < 300000; i++){
offset = (random() % filesize) & (~(LEN - 1));
pwrite(fd, buf, LEN, offset);
}
printf("start test\n");
time(&t1);
for (i = 0; i < 100000; i++){
offset = (random() % filesize) & (~(LEN - 1));
pread(fd, buf, LEN, offset);
}
time(&t2);
printf("%ld sec\n", t2-t1);
close(fd);
if (umount("/root/test1/") < 0) {
perror("cannot umount\n");
exit(1);
}
}
Signed-off-by: Hisashi Hifumi <hifumi.hisashi@oss.ntt.co.jp>
Cc: Nick Piggin <nickpiggin@yahoo.com.au>
Cc: Christoph Hellwig <hch@infradead.org>
Cc: Jan Kara <jack@ucw.cz>
Cc: <linux-ext4@vger.kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2008-07-29 06:46:36 +08:00
|
|
|
goto page_not_up_to_date_locked;
|
|
|
|
unlock_page(page);
|
|
|
|
}
|
2005-04-17 06:20:36 +08:00
|
|
|
page_ok:
|
2007-07-17 19:03:04 +08:00
|
|
|
/*
|
|
|
|
* i_size must be checked after we know the page is Uptodate.
|
|
|
|
*
|
|
|
|
* Checking i_size after the check allows us to calculate
|
|
|
|
* the correct value for "nr", which means the zero-filled
|
|
|
|
* part of the page is not copied back to userspace (unless
|
|
|
|
* another truncate extends the file - this is desired though).
|
|
|
|
*/
|
|
|
|
|
|
|
|
isize = i_size_read(inode);
|
|
|
|
end_index = (isize - 1) >> PAGE_CACHE_SHIFT;
|
|
|
|
if (unlikely(!isize || index > end_index)) {
|
|
|
|
page_cache_release(page);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* nr is the maximum number of bytes to copy from this page */
|
|
|
|
nr = PAGE_CACHE_SIZE;
|
|
|
|
if (index == end_index) {
|
|
|
|
nr = ((isize - 1) & ~PAGE_CACHE_MASK) + 1;
|
|
|
|
if (nr <= offset) {
|
|
|
|
page_cache_release(page);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
nr = nr - offset;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
/* If users can be writing to this page using arbitrary
|
|
|
|
* virtual addresses, take care about potential aliasing
|
|
|
|
* before reading the page on the kernel side.
|
|
|
|
*/
|
|
|
|
if (mapping_writably_mapped(mapping))
|
|
|
|
flush_dcache_page(page);
|
|
|
|
|
|
|
|
/*
|
2007-05-07 05:49:25 +08:00
|
|
|
* When a sequential read accesses a page several times,
|
|
|
|
* only mark it as accessed the first time.
|
2005-04-17 06:20:36 +08:00
|
|
|
*/
|
2007-05-07 05:49:25 +08:00
|
|
|
if (prev_index != index || offset != prev_offset)
|
2005-04-17 06:20:36 +08:00
|
|
|
mark_page_accessed(page);
|
|
|
|
prev_index = index;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Ok, we have the page, and it's up-to-date, so
|
|
|
|
* now we can copy it to user space...
|
|
|
|
*/
|
2014-02-04 06:07:03 +08:00
|
|
|
|
|
|
|
ret = copy_page_to_iter(page, offset, nr, iter);
|
2005-04-17 06:20:36 +08:00
|
|
|
offset += ret;
|
|
|
|
index += offset >> PAGE_CACHE_SHIFT;
|
|
|
|
offset &= ~PAGE_CACHE_MASK;
|
2007-05-07 05:49:26 +08:00
|
|
|
prev_offset = offset;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
page_cache_release(page);
|
2014-02-04 06:07:03 +08:00
|
|
|
written += ret;
|
|
|
|
if (!iov_iter_count(iter))
|
|
|
|
goto out;
|
|
|
|
if (ret < nr) {
|
|
|
|
error = -EFAULT;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
continue;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
page_not_up_to_date:
|
|
|
|
/* Get exclusive access to the page ... */
|
do_generic_file_read: s/EINTR/EIO/ if lock_page_killable() fails
If lock_page_killable() fails because the task was killed by SIGKILL or
any other fatal signal, do_generic_file_read() returns -EIO.
This seems to be OK, because in fact the userspace won't see this error,
the task will dequeue SIGKILL and exit.
However, /sbin/init is different, it will dequeue SIGKILL, ignore it, and
return to the user-space with the bogus -EIO.
Change the code to return the error code from lock_page_killable(), -EINTR.
This doesn't fix the bug, but perhaps makes sense anyway. Imho, with this
change the code looks a bit more logical, and the "good" init should handle
the spurious EINTR or short read.
Afaics we can also change lock_page_killable() to return -ERESTARTNOINTR,
but this can't prevent the short reads.
Signed-off-by: Oleg Nesterov <oleg@tv-sign.ru>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
2008-06-09 01:20:43 +08:00
|
|
|
error = lock_page_killable(page);
|
|
|
|
if (unlikely(error))
|
|
|
|
goto readpage_error;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
vfs: pagecache usage optimization for pagesize!=blocksize
When we read some part of a file through pagecache, if there is a
pagecache of corresponding index but this page is not uptodate, read IO
is issued and this page will be uptodate.
I think this is good for pagesize == blocksize environment but there is
room for improvement on pagesize != blocksize environment. Because in
this case a page can have multiple buffers and even if a page is not
uptodate, some buffers can be uptodate.
So I suggest that when all buffers which correspond to a part of a file
that we want to read are uptodate, use this pagecache and copy data from
this pagecache to user buffer even if a page is not uptodate. This can
reduce read IO and improve system throughput.
I wrote a benchmark program and got result number with this program.
This benchmark do:
1: mount and open a test file.
2: create a 512MB file.
3: close a file and umount.
4: mount and again open a test file.
5: pwrite randomly 300000 times on a test file. offset is aligned
by IO size(1024bytes).
6: measure time of preading randomly 100000 times on a test file.
The result was:
2.6.26
330 sec
2.6.26-patched
226 sec
Arch:i386
Filesystem:ext3
Blocksize:1024 bytes
Memory: 1GB
On ext3/4, a file is written through buffer/block. So random read/write
mixed workloads or random read after random write workloads are optimized
with this patch under pagesize != blocksize environment. This test result
showed this.
The benchmark program is as follows:
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <time.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mount.h>
#define LEN 1024
#define LOOP 1024*512 /* 512MB */
main(void)
{
unsigned long i, offset, filesize;
int fd;
char buf[LEN];
time_t t1, t2;
if (mount("/dev/sda1", "/root/test1/", "ext3", 0, 0) < 0) {
perror("cannot mount\n");
exit(1);
}
memset(buf, 0, LEN);
fd = open("/root/test1/testfile", O_CREAT|O_RDWR|O_TRUNC);
if (fd < 0) {
perror("cannot open file\n");
exit(1);
}
for (i = 0; i < LOOP; i++)
write(fd, buf, LEN);
close(fd);
if (umount("/root/test1/") < 0) {
perror("cannot umount\n");
exit(1);
}
if (mount("/dev/sda1", "/root/test1/", "ext3", 0, 0) < 0) {
perror("cannot mount\n");
exit(1);
}
fd = open("/root/test1/testfile", O_RDWR);
if (fd < 0) {
perror("cannot open file\n");
exit(1);
}
filesize = LEN * LOOP;
for (i = 0; i < 300000; i++){
offset = (random() % filesize) & (~(LEN - 1));
pwrite(fd, buf, LEN, offset);
}
printf("start test\n");
time(&t1);
for (i = 0; i < 100000; i++){
offset = (random() % filesize) & (~(LEN - 1));
pread(fd, buf, LEN, offset);
}
time(&t2);
printf("%ld sec\n", t2-t1);
close(fd);
if (umount("/root/test1/") < 0) {
perror("cannot umount\n");
exit(1);
}
}
Signed-off-by: Hisashi Hifumi <hifumi.hisashi@oss.ntt.co.jp>
Cc: Nick Piggin <nickpiggin@yahoo.com.au>
Cc: Christoph Hellwig <hch@infradead.org>
Cc: Jan Kara <jack@ucw.cz>
Cc: <linux-ext4@vger.kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2008-07-29 06:46:36 +08:00
|
|
|
page_not_up_to_date_locked:
|
2006-09-26 14:31:35 +08:00
|
|
|
/* Did it get truncated before we got the lock? */
|
2005-04-17 06:20:36 +08:00
|
|
|
if (!page->mapping) {
|
|
|
|
unlock_page(page);
|
|
|
|
page_cache_release(page);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Did somebody else fill it already? */
|
|
|
|
if (PageUptodate(page)) {
|
|
|
|
unlock_page(page);
|
|
|
|
goto page_ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
readpage:
|
2010-05-26 23:49:40 +08:00
|
|
|
/*
|
|
|
|
* A previous I/O error may have been due to temporary
|
|
|
|
* failures, eg. multipath errors.
|
|
|
|
* PG_error will be set again if readpage fails.
|
|
|
|
*/
|
|
|
|
ClearPageError(page);
|
2005-04-17 06:20:36 +08:00
|
|
|
/* Start the actual read. The read will unlock the page. */
|
|
|
|
error = mapping->a_ops->readpage(filp, page);
|
|
|
|
|
2005-12-16 06:28:17 +08:00
|
|
|
if (unlikely(error)) {
|
|
|
|
if (error == AOP_TRUNCATED_PAGE) {
|
|
|
|
page_cache_release(page);
|
2014-02-04 06:07:03 +08:00
|
|
|
error = 0;
|
2005-12-16 06:28:17 +08:00
|
|
|
goto find_page;
|
|
|
|
}
|
2005-04-17 06:20:36 +08:00
|
|
|
goto readpage_error;
|
2005-12-16 06:28:17 +08:00
|
|
|
}
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
if (!PageUptodate(page)) {
|
do_generic_file_read: s/EINTR/EIO/ if lock_page_killable() fails
If lock_page_killable() fails because the task was killed by SIGKILL or
any other fatal signal, do_generic_file_read() returns -EIO.
This seems to be OK, because in fact the userspace won't see this error,
the task will dequeue SIGKILL and exit.
However, /sbin/init is different, it will dequeue SIGKILL, ignore it, and
return to the user-space with the bogus -EIO.
Change the code to return the error code from lock_page_killable(), -EINTR.
This doesn't fix the bug, but perhaps makes sense anyway. Imho, with this
change the code looks a bit more logical, and the "good" init should handle
the spurious EINTR or short read.
Afaics we can also change lock_page_killable() to return -ERESTARTNOINTR,
but this can't prevent the short reads.
Signed-off-by: Oleg Nesterov <oleg@tv-sign.ru>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
2008-06-09 01:20:43 +08:00
|
|
|
error = lock_page_killable(page);
|
|
|
|
if (unlikely(error))
|
|
|
|
goto readpage_error;
|
2005-04-17 06:20:36 +08:00
|
|
|
if (!PageUptodate(page)) {
|
|
|
|
if (page->mapping == NULL) {
|
|
|
|
/*
|
2010-01-27 00:27:20 +08:00
|
|
|
* invalidate_mapping_pages got it
|
2005-04-17 06:20:36 +08:00
|
|
|
*/
|
|
|
|
unlock_page(page);
|
|
|
|
page_cache_release(page);
|
|
|
|
goto find_page;
|
|
|
|
}
|
|
|
|
unlock_page(page);
|
2007-10-16 16:24:35 +08:00
|
|
|
shrink_readahead_size_eio(filp, ra);
|
do_generic_file_read: s/EINTR/EIO/ if lock_page_killable() fails
If lock_page_killable() fails because the task was killed by SIGKILL or
any other fatal signal, do_generic_file_read() returns -EIO.
This seems to be OK, because in fact the userspace won't see this error,
the task will dequeue SIGKILL and exit.
However, /sbin/init is different, it will dequeue SIGKILL, ignore it, and
return to the user-space with the bogus -EIO.
Change the code to return the error code from lock_page_killable(), -EINTR.
This doesn't fix the bug, but perhaps makes sense anyway. Imho, with this
change the code looks a bit more logical, and the "good" init should handle
the spurious EINTR or short read.
Afaics we can also change lock_page_killable() to return -ERESTARTNOINTR,
but this can't prevent the short reads.
Signed-off-by: Oleg Nesterov <oleg@tv-sign.ru>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
2008-06-09 01:20:43 +08:00
|
|
|
error = -EIO;
|
|
|
|
goto readpage_error;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
unlock_page(page);
|
|
|
|
}
|
|
|
|
|
|
|
|
goto page_ok;
|
|
|
|
|
|
|
|
readpage_error:
|
|
|
|
/* UHHUH! A synchronous read error occurred. Report it */
|
|
|
|
page_cache_release(page);
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
no_cached_page:
|
|
|
|
/*
|
|
|
|
* Ok, it wasn't cached, so we need to create a new
|
|
|
|
* page..
|
|
|
|
*/
|
2007-10-16 16:24:57 +08:00
|
|
|
page = page_cache_alloc_cold(mapping);
|
|
|
|
if (!page) {
|
2014-02-04 06:07:03 +08:00
|
|
|
error = -ENOMEM;
|
2007-10-16 16:24:57 +08:00
|
|
|
goto out;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
2015-06-25 07:58:06 +08:00
|
|
|
error = add_to_page_cache_lru(page, mapping, index,
|
2015-11-07 08:28:49 +08:00
|
|
|
mapping_gfp_constraint(mapping, GFP_KERNEL));
|
2005-04-17 06:20:36 +08:00
|
|
|
if (error) {
|
2007-10-16 16:24:57 +08:00
|
|
|
page_cache_release(page);
|
2014-02-04 06:07:03 +08:00
|
|
|
if (error == -EEXIST) {
|
|
|
|
error = 0;
|
2005-04-17 06:20:36 +08:00
|
|
|
goto find_page;
|
2014-02-04 06:07:03 +08:00
|
|
|
}
|
2005-04-17 06:20:36 +08:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
goto readpage;
|
|
|
|
}
|
|
|
|
|
|
|
|
out:
|
2007-10-16 16:24:35 +08:00
|
|
|
ra->prev_pos = prev_index;
|
|
|
|
ra->prev_pos <<= PAGE_CACHE_SHIFT;
|
|
|
|
ra->prev_pos |= prev_offset;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2007-10-16 16:24:33 +08:00
|
|
|
*ppos = ((loff_t)index << PAGE_CACHE_SHIFT) + offset;
|
2008-10-16 13:01:13 +08:00
|
|
|
file_accessed(filp);
|
2014-02-04 06:07:03 +08:00
|
|
|
return written ? written : error;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
2006-06-23 17:03:49 +08:00
|
|
|
/**
|
2014-04-05 02:20:57 +08:00
|
|
|
* generic_file_read_iter - generic filesystem read routine
|
2006-06-23 17:03:49 +08:00
|
|
|
* @iocb: kernel I/O control block
|
2014-04-05 02:20:57 +08:00
|
|
|
* @iter: destination for the data read
|
2006-06-23 17:03:49 +08:00
|
|
|
*
|
2014-04-05 02:20:57 +08:00
|
|
|
* This is the "read_iter()" routine for all filesystems
|
2005-04-17 06:20:36 +08:00
|
|
|
* that can use the page cache directly.
|
|
|
|
*/
|
|
|
|
ssize_t
|
2014-03-06 11:53:04 +08:00
|
|
|
generic_file_read_iter(struct kiocb *iocb, struct iov_iter *iter)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2014-03-06 11:53:04 +08:00
|
|
|
struct file *file = iocb->ki_filp;
|
2014-03-05 04:24:06 +08:00
|
|
|
ssize_t retval = 0;
|
2006-10-01 14:28:48 +08:00
|
|
|
loff_t *ppos = &iocb->ki_pos;
|
2014-03-06 11:53:04 +08:00
|
|
|
loff_t pos = *ppos;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2015-04-10 01:52:01 +08:00
|
|
|
if (iocb->ki_flags & IOCB_DIRECT) {
|
2014-03-06 11:53:04 +08:00
|
|
|
struct address_space *mapping = file->f_mapping;
|
|
|
|
struct inode *inode = mapping->host;
|
|
|
|
size_t count = iov_iter_count(iter);
|
2006-10-01 14:28:48 +08:00
|
|
|
loff_t size;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
if (!count)
|
|
|
|
goto out; /* skip atime */
|
|
|
|
size = i_size_read(inode);
|
Fix race when checking i_size on direct i/o read
So far I've had one ACK for this, and no other comments. So I think it
is probably time to send this via some suitable tree. I'm guessing that
the vfs tree would be the most appropriate route, but not sure that
there is one at the moment (don't see anything recent at kernel.org)
so in that case I think -mm is the "back up plan". Al, please let me
know if you will take this?
Steve.
---------------------
Following on from the "Re: [PATCH v3] vfs: fix a bug when we do some dio
reads with append dio writes" thread on linux-fsdevel, this patch is my
current version of the fix proposed as option (b) in that thread.
Removing the i_size test from the direct i/o read path at vfs level
means that filesystems now have to deal with requests which are beyond
i_size themselves. These I've divided into three sets:
a) Those with "no op" ->direct_IO (9p, cifs, ceph)
These are obviously not going to be an issue
b) Those with "home brew" ->direct_IO (nfs, fuse)
I've been told that NFS should not have any problem with the larger
i_size, however I've added an extra test to FUSE to duplicate the
original behaviour just to be on the safe side.
c) Those using __blockdev_direct_IO()
These call through to ->get_block() which should deal with the EOF
condition correctly. I've verified that with GFS2 and I believe that
Zheng has verified it for ext4. I've also run the test on XFS and it
passes both before and after this change.
The part of the patch in filemap.c looks a lot larger than it really is
- there are only two lines of real change. The rest is just indentation
of the contained code.
There remains a test of i_size though, which was added for btrfs. It
doesn't cause the other filesystems a problem as the test is performed
after ->direct_IO has been called. It is possible that there is a race
that does matter to btrfs, however this patch doesn't change that, so
its still an overall improvement.
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
Reported-by: Zheng Liu <gnehzuil.liu@gmail.com>
Cc: Jan Kara <jack@suse.cz>
Cc: Dave Chinner <david@fromorbit.com>
Acked-by: Miklos Szeredi <miklos@szeredi.hu>
Cc: Chris Mason <clm@fb.com>
Cc: Josef Bacik <jbacik@fb.com>
Cc: Christoph Hellwig <hch@infradead.org>
Cc: Alexander Viro <viro@zeniv.linux.org.uk>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
2014-01-24 22:42:22 +08:00
|
|
|
retval = filemap_write_and_wait_range(mapping, pos,
|
2014-03-05 11:38:00 +08:00
|
|
|
pos + count - 1);
|
Fix race when checking i_size on direct i/o read
So far I've had one ACK for this, and no other comments. So I think it
is probably time to send this via some suitable tree. I'm guessing that
the vfs tree would be the most appropriate route, but not sure that
there is one at the moment (don't see anything recent at kernel.org)
so in that case I think -mm is the "back up plan". Al, please let me
know if you will take this?
Steve.
---------------------
Following on from the "Re: [PATCH v3] vfs: fix a bug when we do some dio
reads with append dio writes" thread on linux-fsdevel, this patch is my
current version of the fix proposed as option (b) in that thread.
Removing the i_size test from the direct i/o read path at vfs level
means that filesystems now have to deal with requests which are beyond
i_size themselves. These I've divided into three sets:
a) Those with "no op" ->direct_IO (9p, cifs, ceph)
These are obviously not going to be an issue
b) Those with "home brew" ->direct_IO (nfs, fuse)
I've been told that NFS should not have any problem with the larger
i_size, however I've added an extra test to FUSE to duplicate the
original behaviour just to be on the safe side.
c) Those using __blockdev_direct_IO()
These call through to ->get_block() which should deal with the EOF
condition correctly. I've verified that with GFS2 and I believe that
Zheng has verified it for ext4. I've also run the test on XFS and it
passes both before and after this change.
The part of the patch in filemap.c looks a lot larger than it really is
- there are only two lines of real change. The rest is just indentation
of the contained code.
There remains a test of i_size though, which was added for btrfs. It
doesn't cause the other filesystems a problem as the test is performed
after ->direct_IO has been called. It is possible that there is a race
that does matter to btrfs, however this patch doesn't change that, so
its still an overall improvement.
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
Reported-by: Zheng Liu <gnehzuil.liu@gmail.com>
Cc: Jan Kara <jack@suse.cz>
Cc: Dave Chinner <david@fromorbit.com>
Acked-by: Miklos Szeredi <miklos@szeredi.hu>
Cc: Chris Mason <clm@fb.com>
Cc: Josef Bacik <jbacik@fb.com>
Cc: Christoph Hellwig <hch@infradead.org>
Cc: Alexander Viro <viro@zeniv.linux.org.uk>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
2014-01-24 22:42:22 +08:00
|
|
|
if (!retval) {
|
2014-03-06 11:53:04 +08:00
|
|
|
struct iov_iter data = *iter;
|
2015-03-16 19:33:53 +08:00
|
|
|
retval = mapping->a_ops->direct_IO(iocb, &data, pos);
|
Fix race when checking i_size on direct i/o read
So far I've had one ACK for this, and no other comments. So I think it
is probably time to send this via some suitable tree. I'm guessing that
the vfs tree would be the most appropriate route, but not sure that
there is one at the moment (don't see anything recent at kernel.org)
so in that case I think -mm is the "back up plan". Al, please let me
know if you will take this?
Steve.
---------------------
Following on from the "Re: [PATCH v3] vfs: fix a bug when we do some dio
reads with append dio writes" thread on linux-fsdevel, this patch is my
current version of the fix proposed as option (b) in that thread.
Removing the i_size test from the direct i/o read path at vfs level
means that filesystems now have to deal with requests which are beyond
i_size themselves. These I've divided into three sets:
a) Those with "no op" ->direct_IO (9p, cifs, ceph)
These are obviously not going to be an issue
b) Those with "home brew" ->direct_IO (nfs, fuse)
I've been told that NFS should not have any problem with the larger
i_size, however I've added an extra test to FUSE to duplicate the
original behaviour just to be on the safe side.
c) Those using __blockdev_direct_IO()
These call through to ->get_block() which should deal with the EOF
condition correctly. I've verified that with GFS2 and I believe that
Zheng has verified it for ext4. I've also run the test on XFS and it
passes both before and after this change.
The part of the patch in filemap.c looks a lot larger than it really is
- there are only two lines of real change. The rest is just indentation
of the contained code.
There remains a test of i_size though, which was added for btrfs. It
doesn't cause the other filesystems a problem as the test is performed
after ->direct_IO has been called. It is possible that there is a race
that does matter to btrfs, however this patch doesn't change that, so
its still an overall improvement.
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
Reported-by: Zheng Liu <gnehzuil.liu@gmail.com>
Cc: Jan Kara <jack@suse.cz>
Cc: Dave Chinner <david@fromorbit.com>
Acked-by: Miklos Szeredi <miklos@szeredi.hu>
Cc: Chris Mason <clm@fb.com>
Cc: Josef Bacik <jbacik@fb.com>
Cc: Christoph Hellwig <hch@infradead.org>
Cc: Alexander Viro <viro@zeniv.linux.org.uk>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
2014-01-24 22:42:22 +08:00
|
|
|
}
|
2014-03-05 10:27:34 +08:00
|
|
|
|
Fix race when checking i_size on direct i/o read
So far I've had one ACK for this, and no other comments. So I think it
is probably time to send this via some suitable tree. I'm guessing that
the vfs tree would be the most appropriate route, but not sure that
there is one at the moment (don't see anything recent at kernel.org)
so in that case I think -mm is the "back up plan". Al, please let me
know if you will take this?
Steve.
---------------------
Following on from the "Re: [PATCH v3] vfs: fix a bug when we do some dio
reads with append dio writes" thread on linux-fsdevel, this patch is my
current version of the fix proposed as option (b) in that thread.
Removing the i_size test from the direct i/o read path at vfs level
means that filesystems now have to deal with requests which are beyond
i_size themselves. These I've divided into three sets:
a) Those with "no op" ->direct_IO (9p, cifs, ceph)
These are obviously not going to be an issue
b) Those with "home brew" ->direct_IO (nfs, fuse)
I've been told that NFS should not have any problem with the larger
i_size, however I've added an extra test to FUSE to duplicate the
original behaviour just to be on the safe side.
c) Those using __blockdev_direct_IO()
These call through to ->get_block() which should deal with the EOF
condition correctly. I've verified that with GFS2 and I believe that
Zheng has verified it for ext4. I've also run the test on XFS and it
passes both before and after this change.
The part of the patch in filemap.c looks a lot larger than it really is
- there are only two lines of real change. The rest is just indentation
of the contained code.
There remains a test of i_size though, which was added for btrfs. It
doesn't cause the other filesystems a problem as the test is performed
after ->direct_IO has been called. It is possible that there is a race
that does matter to btrfs, however this patch doesn't change that, so
its still an overall improvement.
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
Reported-by: Zheng Liu <gnehzuil.liu@gmail.com>
Cc: Jan Kara <jack@suse.cz>
Cc: Dave Chinner <david@fromorbit.com>
Acked-by: Miklos Szeredi <miklos@szeredi.hu>
Cc: Chris Mason <clm@fb.com>
Cc: Josef Bacik <jbacik@fb.com>
Cc: Christoph Hellwig <hch@infradead.org>
Cc: Alexander Viro <viro@zeniv.linux.org.uk>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
2014-01-24 22:42:22 +08:00
|
|
|
if (retval > 0) {
|
|
|
|
*ppos = pos + retval;
|
2014-03-06 11:53:04 +08:00
|
|
|
iov_iter_advance(iter, retval);
|
Fix race when checking i_size on direct i/o read
So far I've had one ACK for this, and no other comments. So I think it
is probably time to send this via some suitable tree. I'm guessing that
the vfs tree would be the most appropriate route, but not sure that
there is one at the moment (don't see anything recent at kernel.org)
so in that case I think -mm is the "back up plan". Al, please let me
know if you will take this?
Steve.
---------------------
Following on from the "Re: [PATCH v3] vfs: fix a bug when we do some dio
reads with append dio writes" thread on linux-fsdevel, this patch is my
current version of the fix proposed as option (b) in that thread.
Removing the i_size test from the direct i/o read path at vfs level
means that filesystems now have to deal with requests which are beyond
i_size themselves. These I've divided into three sets:
a) Those with "no op" ->direct_IO (9p, cifs, ceph)
These are obviously not going to be an issue
b) Those with "home brew" ->direct_IO (nfs, fuse)
I've been told that NFS should not have any problem with the larger
i_size, however I've added an extra test to FUSE to duplicate the
original behaviour just to be on the safe side.
c) Those using __blockdev_direct_IO()
These call through to ->get_block() which should deal with the EOF
condition correctly. I've verified that with GFS2 and I believe that
Zheng has verified it for ext4. I've also run the test on XFS and it
passes both before and after this change.
The part of the patch in filemap.c looks a lot larger than it really is
- there are only two lines of real change. The rest is just indentation
of the contained code.
There remains a test of i_size though, which was added for btrfs. It
doesn't cause the other filesystems a problem as the test is performed
after ->direct_IO has been called. It is possible that there is a race
that does matter to btrfs, however this patch doesn't change that, so
its still an overall improvement.
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
Reported-by: Zheng Liu <gnehzuil.liu@gmail.com>
Cc: Jan Kara <jack@suse.cz>
Cc: Dave Chinner <david@fromorbit.com>
Acked-by: Miklos Szeredi <miklos@szeredi.hu>
Cc: Chris Mason <clm@fb.com>
Cc: Josef Bacik <jbacik@fb.com>
Cc: Christoph Hellwig <hch@infradead.org>
Cc: Alexander Viro <viro@zeniv.linux.org.uk>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
2014-01-24 22:42:22 +08:00
|
|
|
}
|
2010-05-23 23:00:54 +08:00
|
|
|
|
Fix race when checking i_size on direct i/o read
So far I've had one ACK for this, and no other comments. So I think it
is probably time to send this via some suitable tree. I'm guessing that
the vfs tree would be the most appropriate route, but not sure that
there is one at the moment (don't see anything recent at kernel.org)
so in that case I think -mm is the "back up plan". Al, please let me
know if you will take this?
Steve.
---------------------
Following on from the "Re: [PATCH v3] vfs: fix a bug when we do some dio
reads with append dio writes" thread on linux-fsdevel, this patch is my
current version of the fix proposed as option (b) in that thread.
Removing the i_size test from the direct i/o read path at vfs level
means that filesystems now have to deal with requests which are beyond
i_size themselves. These I've divided into three sets:
a) Those with "no op" ->direct_IO (9p, cifs, ceph)
These are obviously not going to be an issue
b) Those with "home brew" ->direct_IO (nfs, fuse)
I've been told that NFS should not have any problem with the larger
i_size, however I've added an extra test to FUSE to duplicate the
original behaviour just to be on the safe side.
c) Those using __blockdev_direct_IO()
These call through to ->get_block() which should deal with the EOF
condition correctly. I've verified that with GFS2 and I believe that
Zheng has verified it for ext4. I've also run the test on XFS and it
passes both before and after this change.
The part of the patch in filemap.c looks a lot larger than it really is
- there are only two lines of real change. The rest is just indentation
of the contained code.
There remains a test of i_size though, which was added for btrfs. It
doesn't cause the other filesystems a problem as the test is performed
after ->direct_IO has been called. It is possible that there is a race
that does matter to btrfs, however this patch doesn't change that, so
its still an overall improvement.
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
Reported-by: Zheng Liu <gnehzuil.liu@gmail.com>
Cc: Jan Kara <jack@suse.cz>
Cc: Dave Chinner <david@fromorbit.com>
Acked-by: Miklos Szeredi <miklos@szeredi.hu>
Cc: Chris Mason <clm@fb.com>
Cc: Josef Bacik <jbacik@fb.com>
Cc: Christoph Hellwig <hch@infradead.org>
Cc: Alexander Viro <viro@zeniv.linux.org.uk>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
2014-01-24 22:42:22 +08:00
|
|
|
/*
|
|
|
|
* Btrfs can have a short DIO read if we encounter
|
|
|
|
* compressed extents, so if there was an error, or if
|
|
|
|
* we've already read everything we wanted to, or if
|
|
|
|
* there was a short read because we hit EOF, go ahead
|
|
|
|
* and return. Otherwise fallthrough to buffered io for
|
2015-02-17 07:58:53 +08:00
|
|
|
* the rest of the read. Buffered reads will not work for
|
|
|
|
* DAX files, so don't bother trying.
|
Fix race when checking i_size on direct i/o read
So far I've had one ACK for this, and no other comments. So I think it
is probably time to send this via some suitable tree. I'm guessing that
the vfs tree would be the most appropriate route, but not sure that
there is one at the moment (don't see anything recent at kernel.org)
so in that case I think -mm is the "back up plan". Al, please let me
know if you will take this?
Steve.
---------------------
Following on from the "Re: [PATCH v3] vfs: fix a bug when we do some dio
reads with append dio writes" thread on linux-fsdevel, this patch is my
current version of the fix proposed as option (b) in that thread.
Removing the i_size test from the direct i/o read path at vfs level
means that filesystems now have to deal with requests which are beyond
i_size themselves. These I've divided into three sets:
a) Those with "no op" ->direct_IO (9p, cifs, ceph)
These are obviously not going to be an issue
b) Those with "home brew" ->direct_IO (nfs, fuse)
I've been told that NFS should not have any problem with the larger
i_size, however I've added an extra test to FUSE to duplicate the
original behaviour just to be on the safe side.
c) Those using __blockdev_direct_IO()
These call through to ->get_block() which should deal with the EOF
condition correctly. I've verified that with GFS2 and I believe that
Zheng has verified it for ext4. I've also run the test on XFS and it
passes both before and after this change.
The part of the patch in filemap.c looks a lot larger than it really is
- there are only two lines of real change. The rest is just indentation
of the contained code.
There remains a test of i_size though, which was added for btrfs. It
doesn't cause the other filesystems a problem as the test is performed
after ->direct_IO has been called. It is possible that there is a race
that does matter to btrfs, however this patch doesn't change that, so
its still an overall improvement.
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
Reported-by: Zheng Liu <gnehzuil.liu@gmail.com>
Cc: Jan Kara <jack@suse.cz>
Cc: Dave Chinner <david@fromorbit.com>
Acked-by: Miklos Szeredi <miklos@szeredi.hu>
Cc: Chris Mason <clm@fb.com>
Cc: Josef Bacik <jbacik@fb.com>
Cc: Christoph Hellwig <hch@infradead.org>
Cc: Alexander Viro <viro@zeniv.linux.org.uk>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
2014-01-24 22:42:22 +08:00
|
|
|
*/
|
2015-02-17 07:58:53 +08:00
|
|
|
if (retval < 0 || !iov_iter_count(iter) || *ppos >= size ||
|
|
|
|
IS_DAX(inode)) {
|
2014-03-06 11:53:04 +08:00
|
|
|
file_accessed(file);
|
Fix race when checking i_size on direct i/o read
So far I've had one ACK for this, and no other comments. So I think it
is probably time to send this via some suitable tree. I'm guessing that
the vfs tree would be the most appropriate route, but not sure that
there is one at the moment (don't see anything recent at kernel.org)
so in that case I think -mm is the "back up plan". Al, please let me
know if you will take this?
Steve.
---------------------
Following on from the "Re: [PATCH v3] vfs: fix a bug when we do some dio
reads with append dio writes" thread on linux-fsdevel, this patch is my
current version of the fix proposed as option (b) in that thread.
Removing the i_size test from the direct i/o read path at vfs level
means that filesystems now have to deal with requests which are beyond
i_size themselves. These I've divided into three sets:
a) Those with "no op" ->direct_IO (9p, cifs, ceph)
These are obviously not going to be an issue
b) Those with "home brew" ->direct_IO (nfs, fuse)
I've been told that NFS should not have any problem with the larger
i_size, however I've added an extra test to FUSE to duplicate the
original behaviour just to be on the safe side.
c) Those using __blockdev_direct_IO()
These call through to ->get_block() which should deal with the EOF
condition correctly. I've verified that with GFS2 and I believe that
Zheng has verified it for ext4. I've also run the test on XFS and it
passes both before and after this change.
The part of the patch in filemap.c looks a lot larger than it really is
- there are only two lines of real change. The rest is just indentation
of the contained code.
There remains a test of i_size though, which was added for btrfs. It
doesn't cause the other filesystems a problem as the test is performed
after ->direct_IO has been called. It is possible that there is a race
that does matter to btrfs, however this patch doesn't change that, so
its still an overall improvement.
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
Reported-by: Zheng Liu <gnehzuil.liu@gmail.com>
Cc: Jan Kara <jack@suse.cz>
Cc: Dave Chinner <david@fromorbit.com>
Acked-by: Miklos Szeredi <miklos@szeredi.hu>
Cc: Chris Mason <clm@fb.com>
Cc: Josef Bacik <jbacik@fb.com>
Cc: Christoph Hellwig <hch@infradead.org>
Cc: Alexander Viro <viro@zeniv.linux.org.uk>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
2014-01-24 22:42:22 +08:00
|
|
|
goto out;
|
2006-09-28 02:45:07 +08:00
|
|
|
}
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
2014-03-06 11:53:04 +08:00
|
|
|
retval = do_generic_file_read(file, ppos, iter, retval);
|
2005-04-17 06:20:36 +08:00
|
|
|
out:
|
|
|
|
return retval;
|
|
|
|
}
|
2014-03-06 11:53:04 +08:00
|
|
|
EXPORT_SYMBOL(generic_file_read_iter);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
#ifdef CONFIG_MMU
|
2006-06-23 17:03:49 +08:00
|
|
|
/**
|
|
|
|
* page_cache_read - adds requested page to the page cache if not already there
|
|
|
|
* @file: file to read
|
|
|
|
* @offset: page index
|
2016-02-12 08:12:58 +08:00
|
|
|
* @gfp_mask: memory allocation flags
|
2006-06-23 17:03:49 +08:00
|
|
|
*
|
2005-04-17 06:20:36 +08:00
|
|
|
* This adds the requested page to the page cache if it isn't already there,
|
|
|
|
* and schedules an I/O to read in its contents from disk.
|
|
|
|
*/
|
2016-01-15 07:20:12 +08:00
|
|
|
static int page_cache_read(struct file *file, pgoff_t offset, gfp_t gfp_mask)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
|
|
|
struct address_space *mapping = file->f_mapping;
|
2014-10-10 06:29:03 +08:00
|
|
|
struct page *page;
|
2005-12-16 06:28:17 +08:00
|
|
|
int ret;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2005-12-16 06:28:17 +08:00
|
|
|
do {
|
2016-01-15 07:20:12 +08:00
|
|
|
page = __page_cache_alloc(gfp_mask|__GFP_COLD);
|
2005-12-16 06:28:17 +08:00
|
|
|
if (!page)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2016-01-15 07:20:12 +08:00
|
|
|
ret = add_to_page_cache_lru(page, mapping, offset, gfp_mask & GFP_KERNEL);
|
2005-12-16 06:28:17 +08:00
|
|
|
if (ret == 0)
|
|
|
|
ret = mapping->a_ops->readpage(file, page);
|
|
|
|
else if (ret == -EEXIST)
|
|
|
|
ret = 0; /* losing race to add is OK */
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
page_cache_release(page);
|
|
|
|
|
2005-12-16 06:28:17 +08:00
|
|
|
} while (ret == AOP_TRUNCATED_PAGE);
|
2014-10-10 06:29:03 +08:00
|
|
|
|
2005-12-16 06:28:17 +08:00
|
|
|
return ret;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
#define MMAP_LOTSAMISS (100)
|
|
|
|
|
2009-06-17 06:31:25 +08:00
|
|
|
/*
|
|
|
|
* Synchronous readahead happens when we don't even find
|
|
|
|
* a page in the page cache at all.
|
|
|
|
*/
|
|
|
|
static void do_sync_mmap_readahead(struct vm_area_struct *vma,
|
|
|
|
struct file_ra_state *ra,
|
|
|
|
struct file *file,
|
|
|
|
pgoff_t offset)
|
|
|
|
{
|
|
|
|
struct address_space *mapping = file->f_mapping;
|
|
|
|
|
|
|
|
/* If we don't want any read-ahead, don't bother */
|
2013-07-09 07:00:18 +08:00
|
|
|
if (vma->vm_flags & VM_RAND_READ)
|
2009-06-17 06:31:25 +08:00
|
|
|
return;
|
2011-05-25 08:12:28 +08:00
|
|
|
if (!ra->ra_pages)
|
|
|
|
return;
|
2009-06-17 06:31:25 +08:00
|
|
|
|
2013-07-09 07:00:18 +08:00
|
|
|
if (vma->vm_flags & VM_SEQ_READ) {
|
readahead: enforce full sync mmap readahead size
Now that we do readahead for sequential mmap reads, here is a simple
evaluation of the impacts, and one further optimization.
It's an NFS-root debian desktop system, readahead size = 60 pages.
The numbers are grabbed after a fresh boot into console.
approach pgmajfault RA miss ratio mmap IO count avg IO size(pages)
A 383 31.6% 383 11
B 225 32.4% 390 11
C 224 32.6% 307 13
case A: mmap sync/async readahead disabled
case B: mmap sync/async readahead enabled, with enforced full async readahead size
case C: mmap sync/async readahead enabled, with enforced full sync/async readahead size
or:
A = vanilla 2.6.30-rc1
B = A plus mmap readahead
C = B plus this patch
The numbers show that
- there are good possibilities for random mmap reads to trigger readahead
- 'pgmajfault' is reduced by 1/3, due to the _async_ nature of readahead
- case C can further reduce IO count by 1/4
- readahead miss ratios are not quite affected
The theory is
- readahead is _good_ for clustered random reads, and can perform
_better_ than readaround because they could be _async_.
- async readahead size is guaranteed to be larger than readaround
size, and they are _async_, hence will mostly behave better
However for B
- sync readahead size could be smaller than readaround size, hence may
make things worse by produce more smaller IOs
which will be fixed by this patch.
Final conclusion:
- mmap readahead reduced major faults by 1/3 and no obvious overheads;
- mmap io can be further reduced by 1/4 with this patch.
Signed-off-by: Wu Fengguang <fengguang.wu@intel.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2009-06-17 06:31:38 +08:00
|
|
|
page_cache_sync_readahead(mapping, ra, file, offset,
|
|
|
|
ra->ra_pages);
|
2009-06-17 06:31:25 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2011-05-25 08:12:29 +08:00
|
|
|
/* Avoid banging the cache line if not needed */
|
|
|
|
if (ra->mmap_miss < MMAP_LOTSAMISS * 10)
|
2009-06-17 06:31:25 +08:00
|
|
|
ra->mmap_miss++;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Do we miss much more than hit in this file? If so,
|
|
|
|
* stop bothering with read-ahead. It will only hurt.
|
|
|
|
*/
|
|
|
|
if (ra->mmap_miss > MMAP_LOTSAMISS)
|
|
|
|
return;
|
|
|
|
|
2009-06-17 06:31:30 +08:00
|
|
|
/*
|
|
|
|
* mmap read-around
|
|
|
|
*/
|
2015-11-06 10:47:08 +08:00
|
|
|
ra->start = max_t(long, 0, offset - ra->ra_pages / 2);
|
|
|
|
ra->size = ra->ra_pages;
|
|
|
|
ra->async_size = ra->ra_pages / 4;
|
2011-05-25 08:12:28 +08:00
|
|
|
ra_submit(ra, mapping, file);
|
2009-06-17 06:31:25 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Asynchronous readahead happens when we find the page and PG_readahead,
|
|
|
|
* so we want to possibly extend the readahead further..
|
|
|
|
*/
|
|
|
|
static void do_async_mmap_readahead(struct vm_area_struct *vma,
|
|
|
|
struct file_ra_state *ra,
|
|
|
|
struct file *file,
|
|
|
|
struct page *page,
|
|
|
|
pgoff_t offset)
|
|
|
|
{
|
|
|
|
struct address_space *mapping = file->f_mapping;
|
|
|
|
|
|
|
|
/* If we don't want any read-ahead, don't bother */
|
2013-07-09 07:00:18 +08:00
|
|
|
if (vma->vm_flags & VM_RAND_READ)
|
2009-06-17 06:31:25 +08:00
|
|
|
return;
|
|
|
|
if (ra->mmap_miss > 0)
|
|
|
|
ra->mmap_miss--;
|
|
|
|
if (PageReadahead(page))
|
readahead: enforce full readahead size on async mmap readahead
We need this in one particular case and two more general ones.
Now we do async readahead for sequential mmap reads, and do it with the
help of PG_readahead. For normal reads, PG_readahead is the sufficient
condition to do a sequential readahead. But unfortunately, for mmap
reads, there is a tiny nuisance:
[11736.998347] readahead-init0(process: sh/23926, file: sda1/w3m, offset=0:4503599627370495, ra=0+4-3) = 4
[11737.014985] readahead-around(process: w3m/23926, file: sda1/w3m, offset=0:0, ra=290+32-0) = 17
[11737.019488] readahead-around(process: w3m/23926, file: sda1/w3m, offset=0:0, ra=118+32-0) = 32
[11737.024921] readahead-interleaved(process: w3m/23926, file: sda1/w3m, offset=0:2, ra=4+6-6) = 6
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~
An unfavorably small readahead. The original dumb read-around size could
be more efficient.
That happened because ld-linux.so does a read(832) in L1 before mmap(),
which triggers a 4-page readahead, with the second page tagged
PG_readahead.
L0: open("/lib/libc.so.6", O_RDONLY) = 3
L1: read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\340\342"..., 832) = 832
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
L2: fstat(3, {st_mode=S_IFREG|0755, st_size=1420624, ...}) = 0
L3: mmap(NULL, 3527256, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fac6e51d000
L4: mprotect(0x7fac6e671000, 2097152, PROT_NONE) = 0
L5: mmap(0x7fac6e871000, 20480, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x154000) = 0x7fac6e871000
L6: mmap(0x7fac6e876000, 16984, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7fac6e876000
L7: close(3) = 0
In general, the PG_readahead flag will also be hit in cases
- sequential reads
- clustered random reads
A full readahead size is desirable in both cases.
Cc: Nick Piggin <npiggin@suse.de>
Signed-off-by: Wu Fengguang <fengguang.wu@intel.com>
Cc: Ying Han <yinghan@google.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2009-06-17 06:31:29 +08:00
|
|
|
page_cache_async_readahead(mapping, ra, file,
|
|
|
|
page, offset, ra->ra_pages);
|
2009-06-17 06:31:25 +08:00
|
|
|
}
|
|
|
|
|
2006-06-23 17:03:49 +08:00
|
|
|
/**
|
2007-07-19 16:46:59 +08:00
|
|
|
* filemap_fault - read in file data for page fault handling
|
2007-07-19 16:47:03 +08:00
|
|
|
* @vma: vma in which the fault was taken
|
|
|
|
* @vmf: struct vm_fault containing details of the fault
|
2006-06-23 17:03:49 +08:00
|
|
|
*
|
2007-07-19 16:46:59 +08:00
|
|
|
* filemap_fault() is invoked via the vma operations vector for a
|
2005-04-17 06:20:36 +08:00
|
|
|
* mapped memory region to read in file data during a page fault.
|
|
|
|
*
|
|
|
|
* The goto's are kind of ugly, but this streamlines the normal case of having
|
|
|
|
* it in the page cache, and handles the special cases reasonably without
|
|
|
|
* having a lot of duplicated code.
|
2014-08-07 07:07:24 +08:00
|
|
|
*
|
|
|
|
* vma->vm_mm->mmap_sem must be held on entry.
|
|
|
|
*
|
|
|
|
* If our return value has VM_FAULT_RETRY set, it's because
|
|
|
|
* lock_page_or_retry() returned 0.
|
|
|
|
* The mmap_sem has usually been released in this case.
|
|
|
|
* See __lock_page_or_retry() for the exception.
|
|
|
|
*
|
|
|
|
* If our return value does not have VM_FAULT_RETRY set, the mmap_sem
|
|
|
|
* has not been released.
|
|
|
|
*
|
|
|
|
* We never return with VM_FAULT_RETRY and a bit from VM_FAULT_ERROR set.
|
2005-04-17 06:20:36 +08:00
|
|
|
*/
|
2007-07-19 16:47:03 +08:00
|
|
|
int filemap_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
|
|
|
int error;
|
2007-07-19 16:46:59 +08:00
|
|
|
struct file *file = vma->vm_file;
|
2005-04-17 06:20:36 +08:00
|
|
|
struct address_space *mapping = file->f_mapping;
|
|
|
|
struct file_ra_state *ra = &file->f_ra;
|
|
|
|
struct inode *inode = mapping->host;
|
2009-06-17 06:31:25 +08:00
|
|
|
pgoff_t offset = vmf->pgoff;
|
2005-04-17 06:20:36 +08:00
|
|
|
struct page *page;
|
2014-04-08 06:37:21 +08:00
|
|
|
loff_t size;
|
2007-07-19 16:47:05 +08:00
|
|
|
int ret = 0;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2014-04-08 06:37:21 +08:00
|
|
|
size = round_up(i_size_read(inode), PAGE_CACHE_SIZE);
|
|
|
|
if (offset >= size >> PAGE_CACHE_SHIFT)
|
2007-11-01 00:19:46 +08:00
|
|
|
return VM_FAULT_SIGBUS;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
/*
|
2013-10-17 04:46:59 +08:00
|
|
|
* Do we have something in the page cache already?
|
2005-04-17 06:20:36 +08:00
|
|
|
*/
|
2009-06-17 06:31:25 +08:00
|
|
|
page = find_get_page(mapping, offset);
|
2012-10-09 07:32:19 +08:00
|
|
|
if (likely(page) && !(vmf->flags & FAULT_FLAG_TRIED)) {
|
2005-04-17 06:20:36 +08:00
|
|
|
/*
|
2009-06-17 06:31:25 +08:00
|
|
|
* We found the page, so try async readahead before
|
|
|
|
* waiting for the lock.
|
2005-04-17 06:20:36 +08:00
|
|
|
*/
|
2009-06-17 06:31:25 +08:00
|
|
|
do_async_mmap_readahead(vma, ra, file, page, offset);
|
2012-10-09 07:32:19 +08:00
|
|
|
} else if (!page) {
|
2009-06-17 06:31:25 +08:00
|
|
|
/* No page in the page cache at all */
|
|
|
|
do_sync_mmap_readahead(vma, ra, file, offset);
|
|
|
|
count_vm_event(PGMAJFAULT);
|
2011-05-27 07:25:38 +08:00
|
|
|
mem_cgroup_count_vm_event(vma->vm_mm, PGMAJFAULT);
|
2009-06-17 06:31:25 +08:00
|
|
|
ret = VM_FAULT_MAJOR;
|
|
|
|
retry_find:
|
2010-10-27 05:21:56 +08:00
|
|
|
page = find_get_page(mapping, offset);
|
2005-04-17 06:20:36 +08:00
|
|
|
if (!page)
|
|
|
|
goto no_cached_page;
|
|
|
|
}
|
|
|
|
|
2010-11-03 04:05:18 +08:00
|
|
|
if (!lock_page_or_retry(page, vma->vm_mm, vmf->flags)) {
|
|
|
|
page_cache_release(page);
|
2010-10-27 05:21:57 +08:00
|
|
|
return ret | VM_FAULT_RETRY;
|
2010-11-03 04:05:18 +08:00
|
|
|
}
|
2010-10-27 05:21:56 +08:00
|
|
|
|
|
|
|
/* Did it get truncated? */
|
|
|
|
if (unlikely(page->mapping != mapping)) {
|
|
|
|
unlock_page(page);
|
|
|
|
put_page(page);
|
|
|
|
goto retry_find;
|
|
|
|
}
|
2014-01-24 07:52:54 +08:00
|
|
|
VM_BUG_ON_PAGE(page->index != offset, page);
|
2010-10-27 05:21:56 +08:00
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
/*
|
mm: fix fault vs invalidate race for linear mappings
Fix the race between invalidate_inode_pages and do_no_page.
Andrea Arcangeli identified a subtle race between invalidation of pages from
pagecache with userspace mappings, and do_no_page.
The issue is that invalidation has to shoot down all mappings to the page,
before it can be discarded from the pagecache. Between shooting down ptes to
a particular page, and actually dropping the struct page from the pagecache,
do_no_page from any process might fault on that page and establish a new
mapping to the page just before it gets discarded from the pagecache.
The most common case where such invalidation is used is in file truncation.
This case was catered for by doing a sort of open-coded seqlock between the
file's i_size, and its truncate_count.
Truncation will decrease i_size, then increment truncate_count before
unmapping userspace pages; do_no_page will read truncate_count, then find the
page if it is within i_size, and then check truncate_count under the page
table lock and back out and retry if it had subsequently been changed (ptl
will serialise against unmapping, and ensure a potentially updated
truncate_count is actually visible).
Complexity and documentation issues aside, the locking protocol fails in the
case where we would like to invalidate pagecache inside i_size. do_no_page
can come in anytime and filemap_nopage is not aware of the invalidation in
progress (as it is when it is outside i_size). The end result is that
dangling (->mapping == NULL) pages that appear to be from a particular file
may be mapped into userspace with nonsense data. Valid mappings to the same
place will see a different page.
Andrea implemented two working fixes, one using a real seqlock, another using
a page->flags bit. He also proposed using the page lock in do_no_page, but
that was initially considered too heavyweight. However, it is not a global or
per-file lock, and the page cacheline is modified in do_no_page to increment
_count and _mapcount anyway, so a further modification should not be a large
performance hit. Scalability is not an issue.
This patch implements this latter approach. ->nopage implementations return
with the page locked if it is possible for their underlying file to be
invalidated (in that case, they must set a special vm_flags bit to indicate
so). do_no_page only unlocks the page after setting up the mapping
completely. invalidation is excluded because it holds the page lock during
invalidation of each page (and ensures that the page is not mapped while
holding the lock).
This also allows significant simplifications in do_no_page, because we have
the page locked in the right place in the pagecache from the start.
Signed-off-by: Nick Piggin <npiggin@suse.de>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2007-07-19 16:46:57 +08:00
|
|
|
* We have a locked page in the page cache, now we need to check
|
|
|
|
* that it's up-to-date. If not, it is going to be due to an error.
|
2005-04-17 06:20:36 +08:00
|
|
|
*/
|
mm: fix fault vs invalidate race for linear mappings
Fix the race between invalidate_inode_pages and do_no_page.
Andrea Arcangeli identified a subtle race between invalidation of pages from
pagecache with userspace mappings, and do_no_page.
The issue is that invalidation has to shoot down all mappings to the page,
before it can be discarded from the pagecache. Between shooting down ptes to
a particular page, and actually dropping the struct page from the pagecache,
do_no_page from any process might fault on that page and establish a new
mapping to the page just before it gets discarded from the pagecache.
The most common case where such invalidation is used is in file truncation.
This case was catered for by doing a sort of open-coded seqlock between the
file's i_size, and its truncate_count.
Truncation will decrease i_size, then increment truncate_count before
unmapping userspace pages; do_no_page will read truncate_count, then find the
page if it is within i_size, and then check truncate_count under the page
table lock and back out and retry if it had subsequently been changed (ptl
will serialise against unmapping, and ensure a potentially updated
truncate_count is actually visible).
Complexity and documentation issues aside, the locking protocol fails in the
case where we would like to invalidate pagecache inside i_size. do_no_page
can come in anytime and filemap_nopage is not aware of the invalidation in
progress (as it is when it is outside i_size). The end result is that
dangling (->mapping == NULL) pages that appear to be from a particular file
may be mapped into userspace with nonsense data. Valid mappings to the same
place will see a different page.
Andrea implemented two working fixes, one using a real seqlock, another using
a page->flags bit. He also proposed using the page lock in do_no_page, but
that was initially considered too heavyweight. However, it is not a global or
per-file lock, and the page cacheline is modified in do_no_page to increment
_count and _mapcount anyway, so a further modification should not be a large
performance hit. Scalability is not an issue.
This patch implements this latter approach. ->nopage implementations return
with the page locked if it is possible for their underlying file to be
invalidated (in that case, they must set a special vm_flags bit to indicate
so). do_no_page only unlocks the page after setting up the mapping
completely. invalidation is excluded because it holds the page lock during
invalidation of each page (and ensures that the page is not mapped while
holding the lock).
This also allows significant simplifications in do_no_page, because we have
the page locked in the right place in the pagecache from the start.
Signed-off-by: Nick Piggin <npiggin@suse.de>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2007-07-19 16:46:57 +08:00
|
|
|
if (unlikely(!PageUptodate(page)))
|
2005-04-17 06:20:36 +08:00
|
|
|
goto page_not_uptodate;
|
|
|
|
|
2009-06-17 06:31:25 +08:00
|
|
|
/*
|
|
|
|
* Found the page and have a reference on it.
|
|
|
|
* We must recheck i_size under page lock.
|
|
|
|
*/
|
2014-04-08 06:37:21 +08:00
|
|
|
size = round_up(i_size_read(inode), PAGE_CACHE_SIZE);
|
|
|
|
if (unlikely(offset >= size >> PAGE_CACHE_SHIFT)) {
|
mm: fix fault vs invalidate race for linear mappings
Fix the race between invalidate_inode_pages and do_no_page.
Andrea Arcangeli identified a subtle race between invalidation of pages from
pagecache with userspace mappings, and do_no_page.
The issue is that invalidation has to shoot down all mappings to the page,
before it can be discarded from the pagecache. Between shooting down ptes to
a particular page, and actually dropping the struct page from the pagecache,
do_no_page from any process might fault on that page and establish a new
mapping to the page just before it gets discarded from the pagecache.
The most common case where such invalidation is used is in file truncation.
This case was catered for by doing a sort of open-coded seqlock between the
file's i_size, and its truncate_count.
Truncation will decrease i_size, then increment truncate_count before
unmapping userspace pages; do_no_page will read truncate_count, then find the
page if it is within i_size, and then check truncate_count under the page
table lock and back out and retry if it had subsequently been changed (ptl
will serialise against unmapping, and ensure a potentially updated
truncate_count is actually visible).
Complexity and documentation issues aside, the locking protocol fails in the
case where we would like to invalidate pagecache inside i_size. do_no_page
can come in anytime and filemap_nopage is not aware of the invalidation in
progress (as it is when it is outside i_size). The end result is that
dangling (->mapping == NULL) pages that appear to be from a particular file
may be mapped into userspace with nonsense data. Valid mappings to the same
place will see a different page.
Andrea implemented two working fixes, one using a real seqlock, another using
a page->flags bit. He also proposed using the page lock in do_no_page, but
that was initially considered too heavyweight. However, it is not a global or
per-file lock, and the page cacheline is modified in do_no_page to increment
_count and _mapcount anyway, so a further modification should not be a large
performance hit. Scalability is not an issue.
This patch implements this latter approach. ->nopage implementations return
with the page locked if it is possible for their underlying file to be
invalidated (in that case, they must set a special vm_flags bit to indicate
so). do_no_page only unlocks the page after setting up the mapping
completely. invalidation is excluded because it holds the page lock during
invalidation of each page (and ensures that the page is not mapped while
holding the lock).
This also allows significant simplifications in do_no_page, because we have
the page locked in the right place in the pagecache from the start.
Signed-off-by: Nick Piggin <npiggin@suse.de>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2007-07-19 16:46:57 +08:00
|
|
|
unlock_page(page);
|
2007-10-09 01:08:37 +08:00
|
|
|
page_cache_release(page);
|
2007-11-01 00:19:46 +08:00
|
|
|
return VM_FAULT_SIGBUS;
|
mm: fix fault vs invalidate race for linear mappings
Fix the race between invalidate_inode_pages and do_no_page.
Andrea Arcangeli identified a subtle race between invalidation of pages from
pagecache with userspace mappings, and do_no_page.
The issue is that invalidation has to shoot down all mappings to the page,
before it can be discarded from the pagecache. Between shooting down ptes to
a particular page, and actually dropping the struct page from the pagecache,
do_no_page from any process might fault on that page and establish a new
mapping to the page just before it gets discarded from the pagecache.
The most common case where such invalidation is used is in file truncation.
This case was catered for by doing a sort of open-coded seqlock between the
file's i_size, and its truncate_count.
Truncation will decrease i_size, then increment truncate_count before
unmapping userspace pages; do_no_page will read truncate_count, then find the
page if it is within i_size, and then check truncate_count under the page
table lock and back out and retry if it had subsequently been changed (ptl
will serialise against unmapping, and ensure a potentially updated
truncate_count is actually visible).
Complexity and documentation issues aside, the locking protocol fails in the
case where we would like to invalidate pagecache inside i_size. do_no_page
can come in anytime and filemap_nopage is not aware of the invalidation in
progress (as it is when it is outside i_size). The end result is that
dangling (->mapping == NULL) pages that appear to be from a particular file
may be mapped into userspace with nonsense data. Valid mappings to the same
place will see a different page.
Andrea implemented two working fixes, one using a real seqlock, another using
a page->flags bit. He also proposed using the page lock in do_no_page, but
that was initially considered too heavyweight. However, it is not a global or
per-file lock, and the page cacheline is modified in do_no_page to increment
_count and _mapcount anyway, so a further modification should not be a large
performance hit. Scalability is not an issue.
This patch implements this latter approach. ->nopage implementations return
with the page locked if it is possible for their underlying file to be
invalidated (in that case, they must set a special vm_flags bit to indicate
so). do_no_page only unlocks the page after setting up the mapping
completely. invalidation is excluded because it holds the page lock during
invalidation of each page (and ensures that the page is not mapped while
holding the lock).
This also allows significant simplifications in do_no_page, because we have
the page locked in the right place in the pagecache from the start.
Signed-off-by: Nick Piggin <npiggin@suse.de>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2007-07-19 16:46:57 +08:00
|
|
|
}
|
|
|
|
|
2007-07-19 16:47:03 +08:00
|
|
|
vmf->page = page;
|
2007-07-19 16:47:05 +08:00
|
|
|
return ret | VM_FAULT_LOCKED;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
no_cached_page:
|
|
|
|
/*
|
|
|
|
* We're only likely to ever get here if MADV_RANDOM is in
|
|
|
|
* effect.
|
|
|
|
*/
|
2016-01-15 07:20:12 +08:00
|
|
|
error = page_cache_read(file, offset, vmf->gfp_mask);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* The page we want has now been added to the page cache.
|
|
|
|
* In the unlikely event that someone removed it in the
|
|
|
|
* meantime, we'll just come back here and read it again.
|
|
|
|
*/
|
|
|
|
if (error >= 0)
|
|
|
|
goto retry_find;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* An error return from page_cache_read can result if the
|
|
|
|
* system is low on memory, or a problem occurs while trying
|
|
|
|
* to schedule I/O.
|
|
|
|
*/
|
|
|
|
if (error == -ENOMEM)
|
2007-07-19 16:47:03 +08:00
|
|
|
return VM_FAULT_OOM;
|
|
|
|
return VM_FAULT_SIGBUS;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
page_not_uptodate:
|
|
|
|
/*
|
|
|
|
* Umm, take care of errors if the page isn't up-to-date.
|
|
|
|
* Try to re-read it _once_. We do this synchronously,
|
|
|
|
* because there really aren't any performance issues here
|
|
|
|
* and we need to check for errors.
|
|
|
|
*/
|
|
|
|
ClearPageError(page);
|
2005-12-16 06:28:17 +08:00
|
|
|
error = mapping->a_ops->readpage(file, page);
|
2008-05-15 07:05:37 +08:00
|
|
|
if (!error) {
|
|
|
|
wait_on_page_locked(page);
|
|
|
|
if (!PageUptodate(page))
|
|
|
|
error = -EIO;
|
|
|
|
}
|
mm: fix fault vs invalidate race for linear mappings
Fix the race between invalidate_inode_pages and do_no_page.
Andrea Arcangeli identified a subtle race between invalidation of pages from
pagecache with userspace mappings, and do_no_page.
The issue is that invalidation has to shoot down all mappings to the page,
before it can be discarded from the pagecache. Between shooting down ptes to
a particular page, and actually dropping the struct page from the pagecache,
do_no_page from any process might fault on that page and establish a new
mapping to the page just before it gets discarded from the pagecache.
The most common case where such invalidation is used is in file truncation.
This case was catered for by doing a sort of open-coded seqlock between the
file's i_size, and its truncate_count.
Truncation will decrease i_size, then increment truncate_count before
unmapping userspace pages; do_no_page will read truncate_count, then find the
page if it is within i_size, and then check truncate_count under the page
table lock and back out and retry if it had subsequently been changed (ptl
will serialise against unmapping, and ensure a potentially updated
truncate_count is actually visible).
Complexity and documentation issues aside, the locking protocol fails in the
case where we would like to invalidate pagecache inside i_size. do_no_page
can come in anytime and filemap_nopage is not aware of the invalidation in
progress (as it is when it is outside i_size). The end result is that
dangling (->mapping == NULL) pages that appear to be from a particular file
may be mapped into userspace with nonsense data. Valid mappings to the same
place will see a different page.
Andrea implemented two working fixes, one using a real seqlock, another using
a page->flags bit. He also proposed using the page lock in do_no_page, but
that was initially considered too heavyweight. However, it is not a global or
per-file lock, and the page cacheline is modified in do_no_page to increment
_count and _mapcount anyway, so a further modification should not be a large
performance hit. Scalability is not an issue.
This patch implements this latter approach. ->nopage implementations return
with the page locked if it is possible for their underlying file to be
invalidated (in that case, they must set a special vm_flags bit to indicate
so). do_no_page only unlocks the page after setting up the mapping
completely. invalidation is excluded because it holds the page lock during
invalidation of each page (and ensures that the page is not mapped while
holding the lock).
This also allows significant simplifications in do_no_page, because we have
the page locked in the right place in the pagecache from the start.
Signed-off-by: Nick Piggin <npiggin@suse.de>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2007-07-19 16:46:57 +08:00
|
|
|
page_cache_release(page);
|
|
|
|
|
|
|
|
if (!error || error == AOP_TRUNCATED_PAGE)
|
2005-12-16 06:28:17 +08:00
|
|
|
goto retry_find;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
mm: fix fault vs invalidate race for linear mappings
Fix the race between invalidate_inode_pages and do_no_page.
Andrea Arcangeli identified a subtle race between invalidation of pages from
pagecache with userspace mappings, and do_no_page.
The issue is that invalidation has to shoot down all mappings to the page,
before it can be discarded from the pagecache. Between shooting down ptes to
a particular page, and actually dropping the struct page from the pagecache,
do_no_page from any process might fault on that page and establish a new
mapping to the page just before it gets discarded from the pagecache.
The most common case where such invalidation is used is in file truncation.
This case was catered for by doing a sort of open-coded seqlock between the
file's i_size, and its truncate_count.
Truncation will decrease i_size, then increment truncate_count before
unmapping userspace pages; do_no_page will read truncate_count, then find the
page if it is within i_size, and then check truncate_count under the page
table lock and back out and retry if it had subsequently been changed (ptl
will serialise against unmapping, and ensure a potentially updated
truncate_count is actually visible).
Complexity and documentation issues aside, the locking protocol fails in the
case where we would like to invalidate pagecache inside i_size. do_no_page
can come in anytime and filemap_nopage is not aware of the invalidation in
progress (as it is when it is outside i_size). The end result is that
dangling (->mapping == NULL) pages that appear to be from a particular file
may be mapped into userspace with nonsense data. Valid mappings to the same
place will see a different page.
Andrea implemented two working fixes, one using a real seqlock, another using
a page->flags bit. He also proposed using the page lock in do_no_page, but
that was initially considered too heavyweight. However, it is not a global or
per-file lock, and the page cacheline is modified in do_no_page to increment
_count and _mapcount anyway, so a further modification should not be a large
performance hit. Scalability is not an issue.
This patch implements this latter approach. ->nopage implementations return
with the page locked if it is possible for their underlying file to be
invalidated (in that case, they must set a special vm_flags bit to indicate
so). do_no_page only unlocks the page after setting up the mapping
completely. invalidation is excluded because it holds the page lock during
invalidation of each page (and ensures that the page is not mapped while
holding the lock).
This also allows significant simplifications in do_no_page, because we have
the page locked in the right place in the pagecache from the start.
Signed-off-by: Nick Piggin <npiggin@suse.de>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2007-07-19 16:46:57 +08:00
|
|
|
/* Things didn't work out. Return zero to tell the mm layer so. */
|
[PATCH] readahead: backoff on I/O error
Backoff readahead size exponentially on I/O error.
Michael Tokarev <mjt@tls.msk.ru> described the problem as:
[QUOTE]
Suppose there's a CD-rom with a scratch/etc, one sector is unreadable.
In order to "fix" it, one have to read it and write to another CD-rom,
or something.. or just ignore the error (if it's just a skip in a video
stream). Let's assume the unreadable block is number U.
But current behavior is just insane. An application requests block
number N, which is before U. Kernel tries to read-ahead blocks N..U.
Cdrom drive tries to read it, re-read it.. for some time. Finally,
when all the N..U-1 blocks are read, kernel returns block number N
(as requested) to an application, successefully.
Now an app requests block number N+1, and kernel tries to read
blocks N+1..U+1. Retrying again as in previous step.
And so on, up to when an app requests block number U-1. And when,
finally, it requests block U, it receives read error.
So, kernel currentry tries to re-read the same failing block as
many times as the current readahead value (256 (times?) by default).
This whole process already killed my cdrom drive (I posted about it
to LKML several months ago) - literally, the drive has fried, and
does not work anymore. Ofcourse that problem was a bug in firmware
(or whatever) of the drive *too*, but.. main problem with that is
current readahead logic as described above.
[/QUOTE]
Which was confirmed by Jens Axboe <axboe@suse.de>:
[QUOTE]
For ide-cd, it tends do only end the first part of the request on a
medium error. So you may see a lot of repeats :/
[/QUOTE]
With this patch, retries are expected to be reduced from, say, 256, to 5.
[akpm@osdl.org: cleanups]
Signed-off-by: Wu Fengguang <wfg@mail.ustc.edu.cn>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
2006-06-25 20:48:43 +08:00
|
|
|
shrink_readahead_size_eio(file, ra);
|
2007-07-19 16:47:03 +08:00
|
|
|
return VM_FAULT_SIGBUS;
|
2007-07-19 16:46:59 +08:00
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(filemap_fault);
|
|
|
|
|
2014-04-08 06:37:19 +08:00
|
|
|
void filemap_map_pages(struct vm_area_struct *vma, struct vm_fault *vmf)
|
|
|
|
{
|
|
|
|
struct radix_tree_iter iter;
|
|
|
|
void **slot;
|
|
|
|
struct file *file = vma->vm_file;
|
|
|
|
struct address_space *mapping = file->f_mapping;
|
|
|
|
loff_t size;
|
|
|
|
struct page *page;
|
|
|
|
unsigned long address = (unsigned long) vmf->virtual_address;
|
|
|
|
unsigned long addr;
|
|
|
|
pte_t *pte;
|
|
|
|
|
|
|
|
rcu_read_lock();
|
|
|
|
radix_tree_for_each_slot(slot, &mapping->page_tree, &iter, vmf->pgoff) {
|
|
|
|
if (iter.index > vmf->max_pgoff)
|
|
|
|
break;
|
|
|
|
repeat:
|
|
|
|
page = radix_tree_deref_slot(slot);
|
|
|
|
if (unlikely(!page))
|
|
|
|
goto next;
|
|
|
|
if (radix_tree_exception(page)) {
|
|
|
|
if (radix_tree_deref_retry(page))
|
|
|
|
break;
|
|
|
|
else
|
|
|
|
goto next;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!page_cache_get_speculative(page))
|
|
|
|
goto repeat;
|
|
|
|
|
|
|
|
/* Has the page moved? */
|
|
|
|
if (unlikely(page != *slot)) {
|
|
|
|
page_cache_release(page);
|
|
|
|
goto repeat;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!PageUptodate(page) ||
|
|
|
|
PageReadahead(page) ||
|
|
|
|
PageHWPoison(page))
|
|
|
|
goto skip;
|
|
|
|
if (!trylock_page(page))
|
|
|
|
goto skip;
|
|
|
|
|
|
|
|
if (page->mapping != mapping || !PageUptodate(page))
|
|
|
|
goto unlock;
|
|
|
|
|
2014-04-08 06:37:21 +08:00
|
|
|
size = round_up(i_size_read(mapping->host), PAGE_CACHE_SIZE);
|
|
|
|
if (page->index >= size >> PAGE_CACHE_SHIFT)
|
2014-04-08 06:37:19 +08:00
|
|
|
goto unlock;
|
|
|
|
|
|
|
|
pte = vmf->pte + page->index - vmf->pgoff;
|
|
|
|
if (!pte_none(*pte))
|
|
|
|
goto unlock;
|
|
|
|
|
|
|
|
if (file->f_ra.mmap_miss > 0)
|
|
|
|
file->f_ra.mmap_miss--;
|
|
|
|
addr = address + (page->index - vmf->pgoff) * PAGE_SIZE;
|
|
|
|
do_set_pte(vma, addr, page, pte, false, false);
|
|
|
|
unlock_page(page);
|
|
|
|
goto next;
|
|
|
|
unlock:
|
|
|
|
unlock_page(page);
|
|
|
|
skip:
|
|
|
|
page_cache_release(page);
|
|
|
|
next:
|
|
|
|
if (iter.index == vmf->max_pgoff)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
rcu_read_unlock();
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(filemap_map_pages);
|
|
|
|
|
2012-06-12 22:20:29 +08:00
|
|
|
int filemap_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
|
|
|
|
{
|
|
|
|
struct page *page = vmf->page;
|
2013-01-24 06:07:38 +08:00
|
|
|
struct inode *inode = file_inode(vma->vm_file);
|
2012-06-12 22:20:29 +08:00
|
|
|
int ret = VM_FAULT_LOCKED;
|
|
|
|
|
2012-06-12 22:20:37 +08:00
|
|
|
sb_start_pagefault(inode->i_sb);
|
2012-06-12 22:20:29 +08:00
|
|
|
file_update_time(vma->vm_file);
|
|
|
|
lock_page(page);
|
|
|
|
if (page->mapping != inode->i_mapping) {
|
|
|
|
unlock_page(page);
|
|
|
|
ret = VM_FAULT_NOPAGE;
|
|
|
|
goto out;
|
|
|
|
}
|
2012-06-12 22:20:37 +08:00
|
|
|
/*
|
|
|
|
* We mark the page dirty already here so that when freeze is in
|
|
|
|
* progress, we are guaranteed that writeback during freezing will
|
|
|
|
* see the dirty page and writeprotect it again.
|
|
|
|
*/
|
|
|
|
set_page_dirty(page);
|
mm: only enforce stable page writes if the backing device requires it
Create a helper function to check if a backing device requires stable
page writes and, if so, performs the necessary wait. Then, make it so
that all points in the memory manager that handle making pages writable
use the helper function. This should provide stable page write support
to most filesystems, while eliminating unnecessary waiting for devices
that don't require the feature.
Before this patchset, all filesystems would block, regardless of whether
or not it was necessary. ext3 would wait, but still generate occasional
checksum errors. The network filesystems were left to do their own
thing, so they'd wait too.
After this patchset, all the disk filesystems except ext3 and btrfs will
wait only if the hardware requires it. ext3 (if necessary) snapshots
pages instead of blocking, and btrfs provides its own bdi so the mm will
never wait. Network filesystems haven't been touched, so either they
provide their own stable page guarantees or they don't block at all.
The blocking behavior is back to what it was before 3.0 if you don't
have a disk requiring stable page writes.
Here's the result of using dbench to test latency on ext2:
3.8.0-rc3:
Operation Count AvgLat MaxLat
----------------------------------------
WriteX 109347 0.028 59.817
ReadX 347180 0.004 3.391
Flush 15514 29.828 287.283
Throughput 57.429 MB/sec 4 clients 4 procs max_latency=287.290 ms
3.8.0-rc3 + patches:
WriteX 105556 0.029 4.273
ReadX 335004 0.005 4.112
Flush 14982 30.540 298.634
Throughput 55.4496 MB/sec 4 clients 4 procs max_latency=298.650 ms
As you can see, the maximum write latency drops considerably with this
patch enabled. The other filesystems (ext3/ext4/xfs/btrfs) behave
similarly, but see the cover letter for those results.
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Acked-by: Steven Whitehouse <swhiteho@redhat.com>
Reviewed-by: Jan Kara <jack@suse.cz>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Andy Lutomirski <luto@amacapital.net>
Cc: Artem Bityutskiy <dedekind1@gmail.com>
Cc: Joel Becker <jlbec@evilplan.org>
Cc: Mark Fasheh <mfasheh@suse.com>
Cc: Jens Axboe <axboe@kernel.dk>
Cc: Eric Van Hensbergen <ericvh@gmail.com>
Cc: Ron Minnich <rminnich@sandia.gov>
Cc: Latchesar Ionkov <lucho@ionkov.net>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2013-02-22 08:42:51 +08:00
|
|
|
wait_for_stable_page(page);
|
2012-06-12 22:20:29 +08:00
|
|
|
out:
|
2012-06-12 22:20:37 +08:00
|
|
|
sb_end_pagefault(inode->i_sb);
|
2012-06-12 22:20:29 +08:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(filemap_page_mkwrite);
|
|
|
|
|
2009-09-28 02:29:37 +08:00
|
|
|
const struct vm_operations_struct generic_file_vm_ops = {
|
2007-07-19 16:46:59 +08:00
|
|
|
.fault = filemap_fault,
|
2014-04-08 06:37:19 +08:00
|
|
|
.map_pages = filemap_map_pages,
|
2012-06-12 22:20:29 +08:00
|
|
|
.page_mkwrite = filemap_page_mkwrite,
|
2005-04-17 06:20:36 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
/* This is used for a general mmap of a disk file */
|
|
|
|
|
|
|
|
int generic_file_mmap(struct file * file, struct vm_area_struct * vma)
|
|
|
|
{
|
|
|
|
struct address_space *mapping = file->f_mapping;
|
|
|
|
|
|
|
|
if (!mapping->a_ops->readpage)
|
|
|
|
return -ENOEXEC;
|
|
|
|
file_accessed(file);
|
|
|
|
vma->vm_ops = &generic_file_vm_ops;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This is for filesystems which do not implement ->writepage.
|
|
|
|
*/
|
|
|
|
int generic_file_readonly_mmap(struct file *file, struct vm_area_struct *vma)
|
|
|
|
{
|
|
|
|
if ((vma->vm_flags & VM_SHARED) && (vma->vm_flags & VM_MAYWRITE))
|
|
|
|
return -EINVAL;
|
|
|
|
return generic_file_mmap(file, vma);
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
int generic_file_mmap(struct file * file, struct vm_area_struct * vma)
|
|
|
|
{
|
|
|
|
return -ENOSYS;
|
|
|
|
}
|
|
|
|
int generic_file_readonly_mmap(struct file * file, struct vm_area_struct * vma)
|
|
|
|
{
|
|
|
|
return -ENOSYS;
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_MMU */
|
|
|
|
|
|
|
|
EXPORT_SYMBOL(generic_file_mmap);
|
|
|
|
EXPORT_SYMBOL(generic_file_readonly_mmap);
|
|
|
|
|
2014-04-04 05:48:18 +08:00
|
|
|
static struct page *wait_on_page_read(struct page *page)
|
|
|
|
{
|
|
|
|
if (!IS_ERR(page)) {
|
|
|
|
wait_on_page_locked(page);
|
|
|
|
if (!PageUptodate(page)) {
|
|
|
|
page_cache_release(page);
|
|
|
|
page = ERR_PTR(-EIO);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return page;
|
|
|
|
}
|
|
|
|
|
2007-05-07 05:49:04 +08:00
|
|
|
static struct page *__read_cache_page(struct address_space *mapping,
|
2007-10-16 16:24:37 +08:00
|
|
|
pgoff_t index,
|
2011-07-26 08:12:23 +08:00
|
|
|
int (*filler)(void *, struct page *),
|
2010-01-28 01:20:03 +08:00
|
|
|
void *data,
|
|
|
|
gfp_t gfp)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2007-10-16 16:24:57 +08:00
|
|
|
struct page *page;
|
2005-04-17 06:20:36 +08:00
|
|
|
int err;
|
|
|
|
repeat:
|
|
|
|
page = find_get_page(mapping, index);
|
|
|
|
if (!page) {
|
2010-01-28 01:20:03 +08:00
|
|
|
page = __page_cache_alloc(gfp | __GFP_COLD);
|
2007-10-16 16:24:57 +08:00
|
|
|
if (!page)
|
|
|
|
return ERR_PTR(-ENOMEM);
|
2011-12-22 01:05:48 +08:00
|
|
|
err = add_to_page_cache_lru(page, mapping, index, gfp);
|
2007-10-16 16:24:57 +08:00
|
|
|
if (unlikely(err)) {
|
|
|
|
page_cache_release(page);
|
|
|
|
if (err == -EEXIST)
|
|
|
|
goto repeat;
|
2005-04-17 06:20:36 +08:00
|
|
|
/* Presumably ENOMEM for radix tree node */
|
|
|
|
return ERR_PTR(err);
|
|
|
|
}
|
|
|
|
err = filler(data, page);
|
|
|
|
if (err < 0) {
|
|
|
|
page_cache_release(page);
|
|
|
|
page = ERR_PTR(err);
|
2014-04-04 05:48:18 +08:00
|
|
|
} else {
|
|
|
|
page = wait_on_page_read(page);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return page;
|
|
|
|
}
|
|
|
|
|
2010-01-28 01:20:03 +08:00
|
|
|
static struct page *do_read_cache_page(struct address_space *mapping,
|
2007-10-16 16:24:37 +08:00
|
|
|
pgoff_t index,
|
2011-07-26 08:12:23 +08:00
|
|
|
int (*filler)(void *, struct page *),
|
2010-01-28 01:20:03 +08:00
|
|
|
void *data,
|
|
|
|
gfp_t gfp)
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
|
|
|
struct page *page;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
retry:
|
2010-01-28 01:20:03 +08:00
|
|
|
page = __read_cache_page(mapping, index, filler, data, gfp);
|
2005-04-17 06:20:36 +08:00
|
|
|
if (IS_ERR(page))
|
2007-05-09 20:42:20 +08:00
|
|
|
return page;
|
2005-04-17 06:20:36 +08:00
|
|
|
if (PageUptodate(page))
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
lock_page(page);
|
|
|
|
if (!page->mapping) {
|
|
|
|
unlock_page(page);
|
|
|
|
page_cache_release(page);
|
|
|
|
goto retry;
|
|
|
|
}
|
|
|
|
if (PageUptodate(page)) {
|
|
|
|
unlock_page(page);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
err = filler(data, page);
|
|
|
|
if (err < 0) {
|
|
|
|
page_cache_release(page);
|
2007-05-09 20:42:20 +08:00
|
|
|
return ERR_PTR(err);
|
2014-04-04 05:48:18 +08:00
|
|
|
} else {
|
|
|
|
page = wait_on_page_read(page);
|
|
|
|
if (IS_ERR(page))
|
|
|
|
return page;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
2007-05-09 20:42:20 +08:00
|
|
|
out:
|
2007-05-07 05:49:04 +08:00
|
|
|
mark_page_accessed(page);
|
|
|
|
return page;
|
|
|
|
}
|
2010-01-28 01:20:03 +08:00
|
|
|
|
|
|
|
/**
|
2014-04-04 05:48:18 +08:00
|
|
|
* read_cache_page - read into page cache, fill it if needed
|
2010-01-28 01:20:03 +08:00
|
|
|
* @mapping: the page's address_space
|
|
|
|
* @index: the page index
|
|
|
|
* @filler: function to perform the read
|
2011-07-26 08:12:23 +08:00
|
|
|
* @data: first arg to filler(data, page) function, often left as NULL
|
2010-01-28 01:20:03 +08:00
|
|
|
*
|
|
|
|
* Read into the page cache. If a page already exists, and PageUptodate() is
|
2014-04-04 05:48:18 +08:00
|
|
|
* not set, try to fill the page and wait for it to become unlocked.
|
2010-01-28 01:20:03 +08:00
|
|
|
*
|
|
|
|
* If the page does not get brought uptodate, return -EIO.
|
|
|
|
*/
|
2014-04-04 05:48:18 +08:00
|
|
|
struct page *read_cache_page(struct address_space *mapping,
|
2010-01-28 01:20:03 +08:00
|
|
|
pgoff_t index,
|
2011-07-26 08:12:23 +08:00
|
|
|
int (*filler)(void *, struct page *),
|
2010-01-28 01:20:03 +08:00
|
|
|
void *data)
|
|
|
|
{
|
|
|
|
return do_read_cache_page(mapping, index, filler, data, mapping_gfp_mask(mapping));
|
|
|
|
}
|
2014-04-04 05:48:18 +08:00
|
|
|
EXPORT_SYMBOL(read_cache_page);
|
2010-01-28 01:20:03 +08:00
|
|
|
|
|
|
|
/**
|
|
|
|
* read_cache_page_gfp - read into page cache, using specified page allocation flags.
|
|
|
|
* @mapping: the page's address_space
|
|
|
|
* @index: the page index
|
|
|
|
* @gfp: the page allocator flags to use if allocating
|
|
|
|
*
|
|
|
|
* This is the same as "read_mapping_page(mapping, index, NULL)", but with
|
2011-12-22 01:05:48 +08:00
|
|
|
* any new page allocations done using the specified allocation flags.
|
2010-01-28 01:20:03 +08:00
|
|
|
*
|
|
|
|
* If the page does not get brought uptodate, return -EIO.
|
|
|
|
*/
|
|
|
|
struct page *read_cache_page_gfp(struct address_space *mapping,
|
|
|
|
pgoff_t index,
|
|
|
|
gfp_t gfp)
|
|
|
|
{
|
|
|
|
filler_t *filler = (filler_t *)mapping->a_ops->readpage;
|
|
|
|
|
2014-04-04 05:48:18 +08:00
|
|
|
return do_read_cache_page(mapping, index, filler, NULL, gfp);
|
2010-01-28 01:20:03 +08:00
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(read_cache_page_gfp);
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
/*
|
|
|
|
* Performs necessary checks before doing a write
|
|
|
|
*
|
2006-06-23 17:03:49 +08:00
|
|
|
* Can adjust writing position or amount of bytes to write.
|
2005-04-17 06:20:36 +08:00
|
|
|
* Returns appropriate error code that caller should return or
|
|
|
|
* zero in case that write should be allowed.
|
|
|
|
*/
|
2015-04-10 00:55:47 +08:00
|
|
|
inline ssize_t generic_write_checks(struct kiocb *iocb, struct iov_iter *from)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2015-04-10 00:55:47 +08:00
|
|
|
struct file *file = iocb->ki_filp;
|
2005-04-17 06:20:36 +08:00
|
|
|
struct inode *inode = file->f_mapping->host;
|
2010-03-06 05:41:44 +08:00
|
|
|
unsigned long limit = rlimit(RLIMIT_FSIZE);
|
2015-04-10 00:55:47 +08:00
|
|
|
loff_t pos;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2015-04-10 00:55:47 +08:00
|
|
|
if (!iov_iter_count(from))
|
|
|
|
return 0;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2015-04-04 16:05:48 +08:00
|
|
|
/* FIXME: this is for backwards compatibility with 2.4 */
|
2015-04-10 01:52:01 +08:00
|
|
|
if (iocb->ki_flags & IOCB_APPEND)
|
2015-04-10 00:55:47 +08:00
|
|
|
iocb->ki_pos = i_size_read(inode);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2015-04-10 00:55:47 +08:00
|
|
|
pos = iocb->ki_pos;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2015-04-04 16:05:48 +08:00
|
|
|
if (limit != RLIM_INFINITY) {
|
2015-04-10 00:55:47 +08:00
|
|
|
if (iocb->ki_pos >= limit) {
|
2015-04-04 16:05:48 +08:00
|
|
|
send_sig(SIGXFSZ, current, 0);
|
|
|
|
return -EFBIG;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
2015-04-10 00:55:47 +08:00
|
|
|
iov_iter_truncate(from, limit - (unsigned long)pos);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* LFS rule
|
|
|
|
*/
|
2015-04-10 00:55:47 +08:00
|
|
|
if (unlikely(pos + iov_iter_count(from) > MAX_NON_LFS &&
|
2005-04-17 06:20:36 +08:00
|
|
|
!(file->f_flags & O_LARGEFILE))) {
|
2015-04-10 00:55:47 +08:00
|
|
|
if (pos >= MAX_NON_LFS)
|
2005-04-17 06:20:36 +08:00
|
|
|
return -EFBIG;
|
2015-04-10 00:55:47 +08:00
|
|
|
iov_iter_truncate(from, MAX_NON_LFS - (unsigned long)pos);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Are we about to exceed the fs block limit ?
|
|
|
|
*
|
|
|
|
* If we have written data it becomes a short write. If we have
|
|
|
|
* exceeded without writing data we send a signal and return EFBIG.
|
|
|
|
* Linus frestrict idea will clean these up nicely..
|
|
|
|
*/
|
2015-04-10 00:55:47 +08:00
|
|
|
if (unlikely(pos >= inode->i_sb->s_maxbytes))
|
|
|
|
return -EFBIG;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2015-04-10 00:55:47 +08:00
|
|
|
iov_iter_truncate(from, inode->i_sb->s_maxbytes - pos);
|
|
|
|
return iov_iter_count(from);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(generic_write_checks);
|
|
|
|
|
2007-10-16 16:25:01 +08:00
|
|
|
int pagecache_write_begin(struct file *file, struct address_space *mapping,
|
|
|
|
loff_t pos, unsigned len, unsigned flags,
|
|
|
|
struct page **pagep, void **fsdata)
|
|
|
|
{
|
|
|
|
const struct address_space_operations *aops = mapping->a_ops;
|
|
|
|
|
2008-10-30 05:00:55 +08:00
|
|
|
return aops->write_begin(file, mapping, pos, len, flags,
|
2007-10-16 16:25:01 +08:00
|
|
|
pagep, fsdata);
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(pagecache_write_begin);
|
|
|
|
|
|
|
|
int pagecache_write_end(struct file *file, struct address_space *mapping,
|
|
|
|
loff_t pos, unsigned len, unsigned copied,
|
|
|
|
struct page *page, void *fsdata)
|
|
|
|
{
|
|
|
|
const struct address_space_operations *aops = mapping->a_ops;
|
|
|
|
|
2008-10-30 05:00:55 +08:00
|
|
|
return aops->write_end(file, mapping, pos, len, copied, page, fsdata);
|
2007-10-16 16:25:01 +08:00
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(pagecache_write_end);
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
ssize_t
|
2014-03-22 18:51:37 +08:00
|
|
|
generic_file_direct_write(struct kiocb *iocb, struct iov_iter *from, loff_t pos)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
|
|
|
struct file *file = iocb->ki_filp;
|
|
|
|
struct address_space *mapping = file->f_mapping;
|
|
|
|
struct inode *inode = mapping->host;
|
|
|
|
ssize_t written;
|
2008-07-24 12:27:04 +08:00
|
|
|
size_t write_len;
|
|
|
|
pgoff_t end;
|
2014-03-11 02:08:45 +08:00
|
|
|
struct iov_iter data;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2014-03-22 18:51:37 +08:00
|
|
|
write_len = iov_iter_count(from);
|
2008-07-24 12:27:04 +08:00
|
|
|
end = (pos + write_len - 1) >> PAGE_CACHE_SHIFT;
|
|
|
|
|
2009-01-07 06:40:22 +08:00
|
|
|
written = filemap_write_and_wait_range(mapping, pos, pos + write_len - 1);
|
2008-07-24 12:27:04 +08:00
|
|
|
if (written)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* After a write we want buffered reads to be sure to go to disk to get
|
|
|
|
* the new data. We invalidate clean cached page from the region we're
|
|
|
|
* about to write. We do this *before* the write so that we can return
|
2008-09-03 05:35:40 +08:00
|
|
|
* without clobbering -EIOCBQUEUED from ->direct_IO().
|
2008-07-24 12:27:04 +08:00
|
|
|
*/
|
|
|
|
if (mapping->nrpages) {
|
|
|
|
written = invalidate_inode_pages2_range(mapping,
|
|
|
|
pos >> PAGE_CACHE_SHIFT, end);
|
2008-09-03 05:35:40 +08:00
|
|
|
/*
|
|
|
|
* If a page can not be invalidated, return 0 to fall back
|
|
|
|
* to buffered write.
|
|
|
|
*/
|
|
|
|
if (written) {
|
|
|
|
if (written == -EBUSY)
|
|
|
|
return 0;
|
2008-07-24 12:27:04 +08:00
|
|
|
goto out;
|
2008-09-03 05:35:40 +08:00
|
|
|
}
|
2008-07-24 12:27:04 +08:00
|
|
|
}
|
|
|
|
|
2014-03-11 02:08:45 +08:00
|
|
|
data = *from;
|
2015-03-16 19:33:53 +08:00
|
|
|
written = mapping->a_ops->direct_IO(iocb, &data, pos);
|
2008-07-24 12:27:04 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Finally, try again to invalidate clean pages which might have been
|
|
|
|
* cached by non-direct readahead, or faulted in by get_user_pages()
|
|
|
|
* if the source of the write was an mmap'ed region of the file
|
|
|
|
* we're writing. Either one is a pretty crazy thing to do,
|
|
|
|
* so we don't support it 100%. If this invalidation
|
|
|
|
* fails, tough, the write still worked...
|
|
|
|
*/
|
|
|
|
if (mapping->nrpages) {
|
|
|
|
invalidate_inode_pages2_range(mapping,
|
|
|
|
pos >> PAGE_CACHE_SHIFT, end);
|
|
|
|
}
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
if (written > 0) {
|
2010-10-27 05:21:58 +08:00
|
|
|
pos += written;
|
2014-03-04 11:03:20 +08:00
|
|
|
iov_iter_advance(from, written);
|
2010-10-27 05:21:58 +08:00
|
|
|
if (pos > i_size_read(inode) && !S_ISBLK(inode->i_mode)) {
|
|
|
|
i_size_write(inode, pos);
|
2005-04-17 06:20:36 +08:00
|
|
|
mark_inode_dirty(inode);
|
|
|
|
}
|
2014-02-12 09:58:20 +08:00
|
|
|
iocb->ki_pos = pos;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
2008-07-24 12:27:04 +08:00
|
|
|
out:
|
2005-04-17 06:20:36 +08:00
|
|
|
return written;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(generic_file_direct_write);
|
|
|
|
|
2007-10-16 16:24:57 +08:00
|
|
|
/*
|
|
|
|
* Find or create a page at the given pagecache position. Return the locked
|
|
|
|
* page. This function is specifically for buffered writes.
|
|
|
|
*/
|
fs: symlink write_begin allocation context fix
With the write_begin/write_end aops, page_symlink was broken because it
could no longer pass a GFP_NOFS type mask into the point where the
allocations happened. They are done in write_begin, which would always
assume that the filesystem can be entered from reclaim. This bug could
cause filesystem deadlocks.
The funny thing with having a gfp_t mask there is that it doesn't really
allow the caller to arbitrarily tinker with the context in which it can be
called. It couldn't ever be GFP_ATOMIC, for example, because it needs to
take the page lock. The only thing any callers care about is __GFP_FS
anyway, so turn that into a single flag.
Add a new flag for write_begin, AOP_FLAG_NOFS. Filesystems can now act on
this flag in their write_begin function. Change __grab_cache_page to
accept a nofs argument as well, to honour that flag (while we're there,
change the name to grab_cache_page_write_begin which is more instructive
and does away with random leading underscores).
This is really a more flexible way to go in the end anyway -- if a
filesystem happens to want any extra allocations aside from the pagecache
ones in ints write_begin function, it may now use GFP_KERNEL (rather than
GFP_NOFS) for common case allocations (eg. ocfs2_alloc_write_ctxt, for a
random example).
[kosaki.motohiro@jp.fujitsu.com: fix ubifs]
[kosaki.motohiro@jp.fujitsu.com: fix fuse]
Signed-off-by: Nick Piggin <npiggin@suse.de>
Reviewed-by: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
Cc: <stable@kernel.org> [2.6.28.x]
Signed-off-by: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
[ Cleaned up the calling convention: just pass in the AOP flags
untouched to the grab_cache_page_write_begin() function. That
just simplifies everybody, and may even allow future expansion of the
logic. - Linus ]
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2009-01-05 04:00:53 +08:00
|
|
|
struct page *grab_cache_page_write_begin(struct address_space *mapping,
|
|
|
|
pgoff_t index, unsigned flags)
|
2007-10-16 16:24:57 +08:00
|
|
|
{
|
|
|
|
struct page *page;
|
2014-06-05 07:10:31 +08:00
|
|
|
int fgp_flags = FGP_LOCK|FGP_ACCESSED|FGP_WRITE|FGP_CREAT;
|
2012-01-11 07:07:53 +08:00
|
|
|
|
fs: symlink write_begin allocation context fix
With the write_begin/write_end aops, page_symlink was broken because it
could no longer pass a GFP_NOFS type mask into the point where the
allocations happened. They are done in write_begin, which would always
assume that the filesystem can be entered from reclaim. This bug could
cause filesystem deadlocks.
The funny thing with having a gfp_t mask there is that it doesn't really
allow the caller to arbitrarily tinker with the context in which it can be
called. It couldn't ever be GFP_ATOMIC, for example, because it needs to
take the page lock. The only thing any callers care about is __GFP_FS
anyway, so turn that into a single flag.
Add a new flag for write_begin, AOP_FLAG_NOFS. Filesystems can now act on
this flag in their write_begin function. Change __grab_cache_page to
accept a nofs argument as well, to honour that flag (while we're there,
change the name to grab_cache_page_write_begin which is more instructive
and does away with random leading underscores).
This is really a more flexible way to go in the end anyway -- if a
filesystem happens to want any extra allocations aside from the pagecache
ones in ints write_begin function, it may now use GFP_KERNEL (rather than
GFP_NOFS) for common case allocations (eg. ocfs2_alloc_write_ctxt, for a
random example).
[kosaki.motohiro@jp.fujitsu.com: fix ubifs]
[kosaki.motohiro@jp.fujitsu.com: fix fuse]
Signed-off-by: Nick Piggin <npiggin@suse.de>
Reviewed-by: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
Cc: <stable@kernel.org> [2.6.28.x]
Signed-off-by: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
[ Cleaned up the calling convention: just pass in the AOP flags
untouched to the grab_cache_page_write_begin() function. That
just simplifies everybody, and may even allow future expansion of the
logic. - Linus ]
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2009-01-05 04:00:53 +08:00
|
|
|
if (flags & AOP_FLAG_NOFS)
|
2014-06-05 07:10:31 +08:00
|
|
|
fgp_flags |= FGP_NOFS;
|
|
|
|
|
|
|
|
page = pagecache_get_page(mapping, index, fgp_flags,
|
2014-12-30 03:30:35 +08:00
|
|
|
mapping_gfp_mask(mapping));
|
2011-01-14 07:46:18 +08:00
|
|
|
if (page)
|
2014-06-05 07:10:31 +08:00
|
|
|
wait_for_stable_page(page);
|
2007-10-16 16:24:57 +08:00
|
|
|
|
|
|
|
return page;
|
|
|
|
}
|
fs: symlink write_begin allocation context fix
With the write_begin/write_end aops, page_symlink was broken because it
could no longer pass a GFP_NOFS type mask into the point where the
allocations happened. They are done in write_begin, which would always
assume that the filesystem can be entered from reclaim. This bug could
cause filesystem deadlocks.
The funny thing with having a gfp_t mask there is that it doesn't really
allow the caller to arbitrarily tinker with the context in which it can be
called. It couldn't ever be GFP_ATOMIC, for example, because it needs to
take the page lock. The only thing any callers care about is __GFP_FS
anyway, so turn that into a single flag.
Add a new flag for write_begin, AOP_FLAG_NOFS. Filesystems can now act on
this flag in their write_begin function. Change __grab_cache_page to
accept a nofs argument as well, to honour that flag (while we're there,
change the name to grab_cache_page_write_begin which is more instructive
and does away with random leading underscores).
This is really a more flexible way to go in the end anyway -- if a
filesystem happens to want any extra allocations aside from the pagecache
ones in ints write_begin function, it may now use GFP_KERNEL (rather than
GFP_NOFS) for common case allocations (eg. ocfs2_alloc_write_ctxt, for a
random example).
[kosaki.motohiro@jp.fujitsu.com: fix ubifs]
[kosaki.motohiro@jp.fujitsu.com: fix fuse]
Signed-off-by: Nick Piggin <npiggin@suse.de>
Reviewed-by: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
Cc: <stable@kernel.org> [2.6.28.x]
Signed-off-by: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
[ Cleaned up the calling convention: just pass in the AOP flags
untouched to the grab_cache_page_write_begin() function. That
just simplifies everybody, and may even allow future expansion of the
logic. - Linus ]
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2009-01-05 04:00:53 +08:00
|
|
|
EXPORT_SYMBOL(grab_cache_page_write_begin);
|
2007-10-16 16:24:57 +08:00
|
|
|
|
2014-02-12 10:34:08 +08:00
|
|
|
ssize_t generic_perform_write(struct file *file,
|
2007-10-16 16:25:01 +08:00
|
|
|
struct iov_iter *i, loff_t pos)
|
|
|
|
{
|
|
|
|
struct address_space *mapping = file->f_mapping;
|
|
|
|
const struct address_space_operations *a_ops = mapping->a_ops;
|
|
|
|
long status = 0;
|
|
|
|
ssize_t written = 0;
|
2007-10-16 16:25:03 +08:00
|
|
|
unsigned int flags = 0;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Copies from kernel address space cannot fail (NFSD is a big user).
|
|
|
|
*/
|
2014-12-17 17:46:46 +08:00
|
|
|
if (!iter_is_iovec(i))
|
2007-10-16 16:25:03 +08:00
|
|
|
flags |= AOP_FLAG_UNINTERRUPTIBLE;
|
2007-10-16 16:25:01 +08:00
|
|
|
|
|
|
|
do {
|
|
|
|
struct page *page;
|
|
|
|
unsigned long offset; /* Offset into pagecache page */
|
|
|
|
unsigned long bytes; /* Bytes to write to page */
|
|
|
|
size_t copied; /* Bytes copied from user */
|
|
|
|
void *fsdata;
|
|
|
|
|
|
|
|
offset = (pos & (PAGE_CACHE_SIZE - 1));
|
|
|
|
bytes = min_t(unsigned long, PAGE_CACHE_SIZE - offset,
|
|
|
|
iov_iter_count(i));
|
|
|
|
|
|
|
|
again:
|
2015-10-07 15:32:38 +08:00
|
|
|
/*
|
|
|
|
* Bring in the user page that we will copy from _first_.
|
|
|
|
* Otherwise there's a nasty deadlock on copying from the
|
|
|
|
* same page as we're writing to, without it being marked
|
|
|
|
* up-to-date.
|
|
|
|
*
|
|
|
|
* Not only is this an optimisation, but it is also required
|
|
|
|
* to check that the address is actually valid, when atomic
|
|
|
|
* usercopies are used, below.
|
|
|
|
*/
|
|
|
|
if (unlikely(iov_iter_fault_in_readable(i, bytes))) {
|
|
|
|
status = -EFAULT;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
mm: make sendfile(2) killable
Currently a simple program below issues a sendfile(2) system call which
takes about 62 days to complete in my test KVM instance.
int fd;
off_t off = 0;
fd = open("file", O_RDWR | O_TRUNC | O_SYNC | O_CREAT, 0644);
ftruncate(fd, 2);
lseek(fd, 0, SEEK_END);
sendfile(fd, fd, &off, 0xfffffff);
Now you should not ask kernel to do a stupid stuff like copying 256MB in
2-byte chunks and call fsync(2) after each chunk but if you do, sysadmin
should have a way to stop you.
We actually do have a check for fatal_signal_pending() in
generic_perform_write() which triggers in this path however because we
always succeed in writing something before the check is done, we return
value > 0 from generic_perform_write() and thus the information about
signal gets lost.
Fix the problem by doing the signal check before writing anything. That
way generic_perform_write() returns -EINTR, the error gets propagated up
and the sendfile loop terminates early.
Signed-off-by: Jan Kara <jack@suse.com>
Reported-by: Dmitry Vyukov <dvyukov@google.com>
Cc: Al Viro <viro@ZenIV.linux.org.uk>
Cc: <stable@vger.kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2015-10-23 04:32:21 +08:00
|
|
|
if (fatal_signal_pending(current)) {
|
|
|
|
status = -EINTR;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2007-10-16 16:25:03 +08:00
|
|
|
status = a_ops->write_begin(file, mapping, pos, bytes, flags,
|
2007-10-16 16:25:01 +08:00
|
|
|
&page, &fsdata);
|
2014-06-05 07:10:31 +08:00
|
|
|
if (unlikely(status < 0))
|
2007-10-16 16:25:01 +08:00
|
|
|
break;
|
|
|
|
|
mm: flush dcache before writing into page to avoid alias
The cache alias problem will happen if the changes of user shared mapping
is not flushed before copying, then user and kernel mapping may be mapped
into two different cache line, it is impossible to guarantee the coherence
after iov_iter_copy_from_user_atomic. So the right steps should be:
flush_dcache_page(page);
kmap_atomic(page);
write to page;
kunmap_atomic(page);
flush_dcache_page(page);
More precisely, we might create two new APIs flush_dcache_user_page and
flush_dcache_kern_page to replace the two flush_dcache_page accordingly.
Here is a snippet tested on omap2430 with VIPT cache, and I think it is
not ARM-specific:
int val = 0x11111111;
fd = open("abc", O_RDWR);
addr = mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
*(addr+0) = 0x44444444;
tmp = *(addr+0);
*(addr+1) = 0x77777777;
write(fd, &val, sizeof(int));
close(fd);
The results are not always 0x11111111 0x77777777 at the beginning as expected. Sometimes we see 0x44444444 0x77777777.
Signed-off-by: Anfei <anfei.zhou@gmail.com>
Cc: Russell King <rmk@arm.linux.org.uk>
Cc: Miklos Szeredi <miklos@szeredi.hu>
Cc: Nick Piggin <nickpiggin@yahoo.com.au>
Cc: <linux-arch@vger.kernel.org>
Cc: <stable@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2010-02-03 05:44:02 +08:00
|
|
|
if (mapping_writably_mapped(mapping))
|
|
|
|
flush_dcache_page(page);
|
2015-10-07 15:32:38 +08:00
|
|
|
|
2007-10-16 16:25:01 +08:00
|
|
|
copied = iov_iter_copy_from_user_atomic(page, i, offset, bytes);
|
|
|
|
flush_dcache_page(page);
|
|
|
|
|
|
|
|
status = a_ops->write_end(file, mapping, pos, bytes, copied,
|
|
|
|
page, fsdata);
|
|
|
|
if (unlikely(status < 0))
|
|
|
|
break;
|
|
|
|
copied = status;
|
|
|
|
|
|
|
|
cond_resched();
|
|
|
|
|
2008-02-02 22:01:17 +08:00
|
|
|
iov_iter_advance(i, copied);
|
2007-10-16 16:25:01 +08:00
|
|
|
if (unlikely(copied == 0)) {
|
|
|
|
/*
|
|
|
|
* If we were unable to copy any data at all, we must
|
|
|
|
* fall back to a single segment length write.
|
|
|
|
*
|
|
|
|
* If we didn't fallback here, we could livelock
|
|
|
|
* because not all segments in the iov can be copied at
|
|
|
|
* once without a pagefault.
|
|
|
|
*/
|
|
|
|
bytes = min_t(unsigned long, PAGE_CACHE_SIZE - offset,
|
|
|
|
iov_iter_single_seg_count(i));
|
|
|
|
goto again;
|
|
|
|
}
|
|
|
|
pos += copied;
|
|
|
|
written += copied;
|
|
|
|
|
|
|
|
balance_dirty_pages_ratelimited(mapping);
|
|
|
|
} while (iov_iter_count(i));
|
|
|
|
|
|
|
|
return written ? written : status;
|
|
|
|
}
|
2014-02-12 10:34:08 +08:00
|
|
|
EXPORT_SYMBOL(generic_perform_write);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2009-08-18 00:10:06 +08:00
|
|
|
/**
|
2014-04-03 15:17:43 +08:00
|
|
|
* __generic_file_write_iter - write data to a file
|
2009-08-18 00:10:06 +08:00
|
|
|
* @iocb: IO state structure (file, offset, etc.)
|
2014-04-03 15:17:43 +08:00
|
|
|
* @from: iov_iter with data to write
|
2009-08-18 00:10:06 +08:00
|
|
|
*
|
|
|
|
* This function does all the work needed for actually writing data to a
|
|
|
|
* file. It does all basic checks, removes SUID from the file, updates
|
|
|
|
* modification times and calls proper subroutines depending on whether we
|
|
|
|
* do direct IO or a standard buffered write.
|
|
|
|
*
|
|
|
|
* It expects i_mutex to be grabbed unless we work on a block device or similar
|
|
|
|
* object which does not need locking at all.
|
|
|
|
*
|
|
|
|
* This function does *not* take care of syncing data in case of O_SYNC write.
|
|
|
|
* A caller has to handle it. This is mainly due to the fact that we want to
|
|
|
|
* avoid syncing under i_mutex.
|
|
|
|
*/
|
2014-04-03 15:17:43 +08:00
|
|
|
ssize_t __generic_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
|
|
|
struct file *file = iocb->ki_filp;
|
2006-10-20 14:28:13 +08:00
|
|
|
struct address_space * mapping = file->f_mapping;
|
2005-04-17 06:20:36 +08:00
|
|
|
struct inode *inode = mapping->host;
|
2014-02-12 10:34:08 +08:00
|
|
|
ssize_t written = 0;
|
2005-04-17 06:20:36 +08:00
|
|
|
ssize_t err;
|
2014-02-12 10:34:08 +08:00
|
|
|
ssize_t status;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
/* We can write back this queue in page reclaim */
|
2015-01-14 17:42:36 +08:00
|
|
|
current->backing_dev_info = inode_to_bdi(inode);
|
2015-05-21 22:05:53 +08:00
|
|
|
err = file_remove_privs(file);
|
2005-04-17 06:20:36 +08:00
|
|
|
if (err)
|
|
|
|
goto out;
|
|
|
|
|
2012-03-26 21:59:21 +08:00
|
|
|
err = file_update_time(file);
|
|
|
|
if (err)
|
|
|
|
goto out;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2015-04-10 01:52:01 +08:00
|
|
|
if (iocb->ki_flags & IOCB_DIRECT) {
|
2015-04-07 22:22:53 +08:00
|
|
|
loff_t pos, endbyte;
|
2006-10-20 14:28:13 +08:00
|
|
|
|
2015-04-07 22:22:53 +08:00
|
|
|
written = generic_file_direct_write(iocb, from, iocb->ki_pos);
|
2005-04-17 06:20:36 +08:00
|
|
|
/*
|
2015-02-17 07:58:53 +08:00
|
|
|
* If the write stopped short of completing, fall back to
|
|
|
|
* buffered writes. Some filesystems do this for writes to
|
|
|
|
* holes, for example. For DAX files, a buffered write will
|
|
|
|
* not succeed (even if it did, DAX does not handle dirty
|
|
|
|
* page-cache pages correctly).
|
2005-04-17 06:20:36 +08:00
|
|
|
*/
|
2015-04-07 22:22:53 +08:00
|
|
|
if (written < 0 || !iov_iter_count(from) || IS_DAX(inode))
|
2015-02-17 07:58:53 +08:00
|
|
|
goto out;
|
|
|
|
|
2015-04-07 22:22:53 +08:00
|
|
|
status = generic_perform_write(file, from, pos = iocb->ki_pos);
|
2006-10-20 14:28:13 +08:00
|
|
|
/*
|
2014-02-12 10:34:08 +08:00
|
|
|
* If generic_perform_write() returned a synchronous error
|
2006-10-20 14:28:13 +08:00
|
|
|
* then we want to return the number of bytes which were
|
|
|
|
* direct-written, or the error code if that was zero. Note
|
|
|
|
* that this differs from normal direct-io semantics, which
|
|
|
|
* will return -EFOO even if some bytes were written.
|
|
|
|
*/
|
2014-08-09 00:39:16 +08:00
|
|
|
if (unlikely(status < 0)) {
|
2014-02-12 10:34:08 +08:00
|
|
|
err = status;
|
2006-10-20 14:28:13 +08:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* We need to ensure that the page cache pages are written to
|
|
|
|
* disk and invalidated to preserve the expected O_DIRECT
|
|
|
|
* semantics.
|
|
|
|
*/
|
2014-02-12 10:34:08 +08:00
|
|
|
endbyte = pos + status - 1;
|
2015-04-07 22:22:53 +08:00
|
|
|
err = filemap_write_and_wait_range(mapping, pos, endbyte);
|
2006-10-20 14:28:13 +08:00
|
|
|
if (err == 0) {
|
2015-04-07 22:22:53 +08:00
|
|
|
iocb->ki_pos = endbyte + 1;
|
2014-02-12 10:34:08 +08:00
|
|
|
written += status;
|
2006-10-20 14:28:13 +08:00
|
|
|
invalidate_mapping_pages(mapping,
|
|
|
|
pos >> PAGE_CACHE_SHIFT,
|
|
|
|
endbyte >> PAGE_CACHE_SHIFT);
|
|
|
|
} else {
|
|
|
|
/*
|
|
|
|
* We don't know how much we wrote, so just return
|
|
|
|
* the number of bytes which were direct-written
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
} else {
|
2015-04-07 22:22:53 +08:00
|
|
|
written = generic_perform_write(file, from, iocb->ki_pos);
|
|
|
|
if (likely(written > 0))
|
|
|
|
iocb->ki_pos += written;
|
2006-10-20 14:28:13 +08:00
|
|
|
}
|
2005-04-17 06:20:36 +08:00
|
|
|
out:
|
|
|
|
current->backing_dev_info = NULL;
|
|
|
|
return written ? written : err;
|
|
|
|
}
|
2014-04-03 15:17:43 +08:00
|
|
|
EXPORT_SYMBOL(__generic_file_write_iter);
|
2009-08-18 00:10:06 +08:00
|
|
|
|
|
|
|
/**
|
2014-04-03 15:17:43 +08:00
|
|
|
* generic_file_write_iter - write data to a file
|
2009-08-18 00:10:06 +08:00
|
|
|
* @iocb: IO state structure
|
2014-04-03 15:17:43 +08:00
|
|
|
* @from: iov_iter with data to write
|
2009-08-18 00:10:06 +08:00
|
|
|
*
|
2014-04-03 15:17:43 +08:00
|
|
|
* This is a wrapper around __generic_file_write_iter() to be used by most
|
2009-08-18 00:10:06 +08:00
|
|
|
* filesystems. It takes care of syncing the file in case of O_SYNC file
|
|
|
|
* and acquires i_mutex as needed.
|
|
|
|
*/
|
2014-04-03 15:17:43 +08:00
|
|
|
ssize_t generic_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
|
|
|
struct file *file = iocb->ki_filp;
|
2009-08-18 01:52:36 +08:00
|
|
|
struct inode *inode = file->f_mapping->host;
|
2005-04-17 06:20:36 +08:00
|
|
|
ssize_t ret;
|
|
|
|
|
2016-01-23 04:40:57 +08:00
|
|
|
inode_lock(inode);
|
2015-04-10 00:55:47 +08:00
|
|
|
ret = generic_write_checks(iocb, from);
|
|
|
|
if (ret > 0)
|
2015-04-07 23:28:12 +08:00
|
|
|
ret = __generic_file_write_iter(iocb, from);
|
2016-01-23 04:40:57 +08:00
|
|
|
inode_unlock(inode);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2013-09-04 21:04:40 +08:00
|
|
|
if (ret > 0) {
|
2005-04-17 06:20:36 +08:00
|
|
|
ssize_t err;
|
|
|
|
|
2014-02-10 04:18:09 +08:00
|
|
|
err = generic_write_sync(file, iocb->ki_pos - ret, ret);
|
|
|
|
if (err < 0)
|
2005-04-17 06:20:36 +08:00
|
|
|
ret = err;
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
2014-04-03 15:17:43 +08:00
|
|
|
EXPORT_SYMBOL(generic_file_write_iter);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2006-08-30 02:05:54 +08:00
|
|
|
/**
|
|
|
|
* try_to_release_page() - release old fs-specific metadata on a page
|
|
|
|
*
|
|
|
|
* @page: the page which the kernel is trying to free
|
|
|
|
* @gfp_mask: memory allocation flags (and I/O mode)
|
|
|
|
*
|
|
|
|
* The address_space is to try to release any data against the page
|
|
|
|
* (presumably at page->private). If the release was successful, return `1'.
|
|
|
|
* Otherwise return zero.
|
|
|
|
*
|
2009-04-03 23:42:36 +08:00
|
|
|
* This may also be called if PG_fscache is set on a page, indicating that the
|
|
|
|
* page is known to the local caching routines.
|
|
|
|
*
|
2006-08-30 02:05:54 +08:00
|
|
|
* The @gfp_mask argument specifies whether I/O may be performed to release
|
2015-11-07 08:28:28 +08:00
|
|
|
* this page (__GFP_IO), and whether the call may block (__GFP_RECLAIM & __GFP_FS).
|
2006-08-30 02:05:54 +08:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
int try_to_release_page(struct page *page, gfp_t gfp_mask)
|
|
|
|
{
|
|
|
|
struct address_space * const mapping = page->mapping;
|
|
|
|
|
|
|
|
BUG_ON(!PageLocked(page));
|
|
|
|
if (PageWriteback(page))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (mapping && mapping->a_ops->releasepage)
|
|
|
|
return mapping->a_ops->releasepage(page, gfp_mask);
|
|
|
|
return try_to_free_buffers(page);
|
|
|
|
}
|
|
|
|
|
|
|
|
EXPORT_SYMBOL(try_to_release_page);
|